Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(14)

Side by Side Diff: remoting/client/plugin/client.cc

Issue 2690003: Copy the (early prototype of) remoting in Chrome into the public tree.... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 10 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « remoting/client/plugin/client.h ('k') | remoting/client/plugin/compression.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Property Changes:
Added: svn:eol-style
+ LF
OLDNEW
(Empty)
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "remoting/client/plugin/client.h"
6
7 #include <string>
8 #include <iostream> // TODO(garykac): Remove this or replace with debug log.
9
10 #include "base/logging.h"
11 #include "media/base/yuv_convert.h"
12 #include "remoting/client/plugin/chromoting_plugin.h"
13 #include "remoting/client/plugin/chromotocol.h"
14 #include "remoting/client/plugin/compression.h"
15 #include "remoting/client/plugin/decoder.h"
16 #include "remoting/client/plugin/host_connection.h"
17
18 namespace remoting {
19
20 ChromotingClient::ChromotingClient(ChromotingPlugin* plugin) {
21 plugin_ = plugin;
22 host_ = new HostConnection();
23 verbose_ = true;
24 }
25
26 ChromotingClient::~ChromotingClient() {
27 }
28
29 void ChromotingClient::hexdump(void* ptr, int buflen) {
30 unsigned char* buf = static_cast<unsigned char*>(ptr);
31 int i, j;
32 for (int i = 0; i < buflen; i += 16) {
33 printf("%06x: ", i);
34 for (int j = 0; j < 16; j ++)
35 if ((i + j) < buflen)
36 printf("%02x ", buf[i + j]);
37 else
38 printf(" ");
39 printf(" ");
40 for (int j = 0; j < 16; j++)
41 if ((i + j) < buflen)
42 printf("%c", isprint(buf[i + j]) ? buf[i + j] : '.');
43 printf("\n");
44 }
45 }
46
47 void ChromotingClient::merge_image(BinaryImageHeader* header, char* data) {
48 // Merge this image into the current image.
49 // Src bitmap starts at lower left.
50 int bytes_per_pixel = 3;
51 uint8* src_bitmap = reinterpret_cast<uint8*>(data);
52 int src_bytes_per_row = header->width * bytes_per_pixel;
53
54 // Dst bitmap starts at lower left.
55 uint8* dst_bitmap = reinterpret_cast<uint8*>(screen_->data.get());
56 dst_bitmap += ((header->y * screen_->header.width)
57 + header->x) * bytes_per_pixel;
58 int dst_bytes_per_row = screen_->header.width * bytes_per_pixel;
59
60 for (int y = 0; y < header->height; ++y) {
61 memcpy(dst_bitmap, src_bitmap, src_bytes_per_row);
62
63 src_bitmap += src_bytes_per_row;
64 dst_bitmap += dst_bytes_per_row;
65 }
66 }
67
68 // Draw the current image into the given device context.
69 void ChromotingClient::draw(int width, int height, NPDeviceContext2D* context) {
70 if (screen_ != NULL) {
71 int max_width = width;
72 if (max_width > screen_->header.width) {
73 max_width = screen_->header.width;
74 }
75 int max_height = height;
76 if (max_height > screen_->header.height) {
77 max_height = screen_->header.height;
78 }
79
80 // Src bitmap starts at lower left.
81 int bytes_per_pixel = 3;
82 int src_bytes_per_row = screen_->header.width * bytes_per_pixel;
83 uint8* src_bitmap = reinterpret_cast<uint8*>(screen_->data.get());
84 src_bitmap += ((max_height - 1) * src_bytes_per_row);
85 uint8* src_row_start = reinterpret_cast<uint8*>(src_bitmap);
86
87 // Dst bitmap (window) starts at upper left.
88 uint32* dst_bitmap = static_cast<uint32*>(context->region);
89 uint8* dst_row_start = reinterpret_cast<uint8*>(dst_bitmap);
90 int dst_bytes_per_row = context->stride;
91
92 for (int y = 0; y < max_height; ++y) {
93 for (int x = 0; x < max_width; ++x) {
94 uint8 b = (*src_bitmap++ & 0xff);
95 uint8 g = (*src_bitmap++ & 0xff);
96 uint8 r = (*src_bitmap++ & 0xff);
97 uint8 alpha = 0xff;
98 *dst_bitmap++ = ((alpha << 24) | (r << 16) | (g << 8) | b);
99 }
100 src_row_start -= src_bytes_per_row;
101 src_bitmap = src_row_start;
102 dst_row_start += dst_bytes_per_row;
103 dst_bitmap = reinterpret_cast<uint32*>(dst_row_start);
104 }
105 }
106 }
107
108 bool ChromotingClient::connect_to_host(const std::string ip) {
109 if (!host_->connect(ip.c_str())) {
110 return false;
111 }
112
113 // Process init command.
114 InitMessage init_message;
115 host_->read_data(reinterpret_cast<char*>(&init_message),
116 sizeof(init_message));
117 if (verbose_) {
118 std::cout << "Received message " << init_message.message << std::endl;
119 }
120 if (init_message.message != MessageInit) {
121 std::cout << "Expected MessageInit" << std::endl;
122 return false;
123 }
124 if (verbose_) {
125 std::cout << "Compression: " << init_message.compression << std::endl;
126 std::cout << "Width x height: " << init_message.width << " x "
127 << init_message.height << std::endl;
128 }
129
130 screen_.reset(new BinaryImage());
131 if (!read_image(screen_.get())) {
132 return false;
133 }
134
135 plugin_->draw();
136 return true;
137 }
138
139 void ChromotingClient::print_host_ip_prompt() {
140 std::cout << "IP address of host machine: ";
141 }
142
143 // This is called whenever the window changes geometry.
144 // Currently, we only worry about the first call so we can display our
145 // login prompt.
146 void ChromotingClient::set_window() {
147 if (!host_->connected()) {
148 print_host_ip_prompt();
149 std::cout.flush();
150 }
151 }
152
153 // Process char input.
154 void ChromotingClient::handle_char_event(NPPepperEvent* npevent) {
155 if (!host_->connected()) {
156 handle_login_char(static_cast<char>(npevent->u.character.text[0]));
157 }
158 }
159
160 // Process char input before the connection to the host has been made.
161 // This currently reads the IP address of the host but will eventually
162 // be changed to read GAIA login credentials.
163 // Later this will be removed once we have an appropriate web interface for
164 // discovering hosts.
165 void ChromotingClient::handle_login_char(char ch) {
166 if (ch == 0x0d) {
167 std::cout << std::endl;
168 if (host_ip_address_.length() == 0) {
169 host_ip_address_ = "172.31.11.205";
170 }
171 if (!connect_to_host(host_ip_address_)) {
172 host_ip_address_ = "";
173 std::cout << "Unable to connect to host!" << std::endl;
174 print_host_ip_prompt();
175 } else {
176 std::cout << "Connected to " << host_ip_address_ << std::endl;
177 }
178 } else {
179 host_ip_address_ += ch;
180 std::cout << ch;
181 }
182 std::cout.flush();
183 }
184
185 // Process the Pepper mouse event.
186 void ChromotingClient::handle_mouse_event(NPPepperEvent* npevent) {
187 if (host_->connected()) {
188 send_mouse_message(npevent);
189 if (handle_update_message()) {
190 plugin_->draw();
191 }
192 }
193 }
194
195 // Pass the given Pepper mouse event along to the host.
196 void ChromotingClient::send_mouse_message(NPPepperEvent* event) {
197 NPMouseEvent* mouse_event = &event->u.mouse;
198 MouseMessage mouse_msg;
199
200 mouse_msg.message = MessageMouse;
201 mouse_msg.x = mouse_event->x;
202 mouse_msg.y = mouse_event->y;
203
204 mouse_msg.flags = 0;
205 int32 type = event->type;
206 int32 button = mouse_event->button;
207 if (type == NPEventType_MouseDown) {
208 if (button == NPMouseButton_Left) {
209 mouse_msg.flags |= LeftDown;
210 } else if (button == NPMouseButton_Right) {
211 mouse_msg.flags |= RightDown;
212 }
213 } else if (type == NPEventType_MouseUp) {
214 if (button == NPMouseButton_Left) {
215 mouse_msg.flags |= LeftUp;
216 } else if (button == NPMouseButton_Right) {
217 mouse_msg.flags |= RightUp;
218 }
219 }
220 host_->write_data((const char*)&mouse_msg, sizeof(mouse_msg));
221 }
222
223 // Process the pending update command from the host.
224 // Return true if the screen image has been updated.
225 bool ChromotingClient::handle_update_message() {
226 UpdateMessage update_message;
227 int result = host_->read_data(reinterpret_cast<char*>(&update_message),
228 sizeof(update_message));
229 if (!result) {
230 std::cout << "Failed to get update command" << std::endl;
231 return false;
232 }
233
234 if (update_message.message != MessageUpdate) {
235 std::cout << "Expected MessageUpdate" << std::endl;
236 return false;
237 }
238
239 if (verbose_) {
240 std::cout << "message: " << update_message.message << std::endl;
241 }
242
243 if (update_message.compression == CompressionZlib) {
244 // Read all data.
245 ZDecompressor decomp;
246 char buffer[4096];
247 int size = update_message.compressed_size;
248 while (size > 0) {
249 // Determine how much we should read from network.
250 int read = std::min(static_cast<int>(sizeof(buffer)), size);
251 result = host_->read_data(buffer, read);
252 decomp.Write(buffer, read);
253 size -= read;
254 }
255 decomp.Flush();
256
257 // Decompress raw image data and break into individual images.
258 char* raw_buffer = decomp.GetRawData();
259 int raw_size = decomp.GetRawSize();
260 int read = 0;
261 BinaryImageHeader header;
262 while (read < raw_size) {
263 memcpy(&header, raw_buffer, sizeof(BinaryImageHeader));
264 if (!check_image_header(&header)) {
265 return false;
266 }
267 read += sizeof(BinaryImageHeader);
268 raw_buffer += sizeof(BinaryImageHeader);
269
270 // Merge this image fragment into the screen bitmap.
271 merge_image(&header, raw_buffer);
272
273 read += header.size;
274 raw_buffer += header.size;
275 }
276 } else if (update_message.compression == CompressionNone) {
277 printf("compressionNone\n");
278 for (int i = 0; i < update_message.num_diffs; i++) {
279 BinaryImage* image = new BinaryImage();
280 read_image(image);
281
282 // Merge this image update into the screen image.
283 merge_image(&image->header, image->data.get());
284
285 delete image;
286 }
287 } else {
288 return false;
289 }
290
291 return true;
292 }
293
294 // Check the validity of the image header.
295 bool ChromotingClient::check_image_header(BinaryImageHeader* header) {
296 if (header == NULL) {
297 std::cout << "Invalid image" << std::endl;
298 return false;
299 }
300
301 if (header->format != FormatRaw && header->format != FormatVp8) {
302 std::cout << "Wrong image format : " << header->format << std::endl;
303 return false;
304 }
305
306 if (verbose_) {
307 std::cout << "Image:" << std::endl;
308 std::cout << " Format " << header->format << std::endl;
309 std::cout << " X,Y " << header->x << ", "
310 << header->y << std::endl;
311 std::cout << " WxH " << header->width << " x "
312 << header->height << std::endl;
313 std::cout << " Size " << header->size << std::endl;
314 }
315
316 return true;
317 }
318
319 // Read an image from the host and store it in the given BinaryImage.
320 bool ChromotingClient::read_image(BinaryImage* image) {
321 int result = host_->read_data(reinterpret_cast<char*>(&image->header),
322 sizeof(image->header));
323 if (!result) {
324 std::cout << "Failed to receive image header" << std::endl;
325 return false;
326 }
327
328 if (!check_image_header(&image->header)) {
329 return false;
330 }
331
332 char* raw_data = new char[image->header.size];
333 result = host_->read_data(raw_data, image->header.size);
334 if (!result) {
335 std::cout << "Failed to receive image data" << std::endl;
336 return false;
337 }
338
339 if (image->header.format == FormatRaw) {
340 // Raw image - all we need to do is load the data, so we're done.
341 image->data.reset(raw_data);
342 return true;
343 } else if (image->header.format == FormatVp8) {
344 return false;
345 // TODO(hclam): Enable this block of code when we have VP8.
346 #if 0
347 // Vp8 encoded - need to convert YUV image data to RGB.
348 static VP8VideoDecoder decoder;
349 uint8* planes[3];
350 int strides[3];
351 printf("decoder.DecodeFrame\n");
352 if (!decoder.DecodeFrame(raw_data, image->header.size)) {
353 std::cout << "Unable to decode frame" << std::endl;
354 return false;
355 }
356 printf("decoder.GetDecodedFrame\n");
357 if (!decoder.GetDecodedFrame(reinterpret_cast<char**>(planes), strides)) {
358 std::cout << "Unable to get decoded frame" << std::endl;
359 return false;
360 }
361 printf("width = %d\n", image->header.width);
362 for (int i=0; i<3; i++) {
363 printf("stride[%d] = %d\n", i, strides[0]);
364 }
365
366 // Convert YUV to RGB.
367 int width = image->header.width;
368 int height = image->header.height;
369 char* rgb_data = new char[width * height * sizeof(int32)];
370 printf("ConvertYUVToRGB32\n");
371 ConvertYUVToRGB32(planes[0], planes[1], planes[2],
372 reinterpret_cast<uint8*>(rgb_data),
373 width,
374 image->header.height,
375 width, // y stride,
376 width / 2, // uv stride,
377 width * sizeof(int32), // rgb stride
378 media::YV12);
379 printf("conversion done\n");
380
381 image->data.reset(rgb_data);
382
383 // Raw YUV data is no longer needed.
384 delete raw_data;
385 return true;
386 #endif
387 }
388
389 return false;
390 }
391
392 } // namespace remoting
OLDNEW
« no previous file with comments | « remoting/client/plugin/client.h ('k') | remoting/client/plugin/compression.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698