OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/browser/renderer_host/media/video_capture_controller.h" | 5 #include "content/browser/renderer_host/media/video_capture_controller.h" |
6 | 6 |
7 #include <set> | 7 #include <set> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/debug/trace_event.h" | 10 #include "base/debug/trace_event.h" |
11 #include "base/memory/scoped_ptr.h" | 11 #include "base/memory/scoped_ptr.h" |
12 #include "base/stl_util.h" | 12 #include "base/stl_util.h" |
13 #include "content/browser/renderer_host/media/media_stream_manager.h" | 13 #include "content/browser/renderer_host/media/media_stream_manager.h" |
14 #include "content/browser/renderer_host/media/video_capture_manager.h" | 14 #include "content/browser/renderer_host/media/video_capture_manager.h" |
15 #include "content/public/browser/browser_thread.h" | 15 #include "content/public/browser/browser_thread.h" |
16 #include "media/base/video_frame.h" | 16 #include "media/base/video_frame.h" |
17 #include "media/base/video_util.h" | 17 #include "media/base/video_util.h" |
18 #include "media/base/yuv_convert.h" | 18 #include "media/base/yuv_convert.h" |
19 | 19 |
20 #if !defined(OS_IOS) && !defined(OS_ANDROID) | |
21 #include "third_party/libyuv/include/libyuv.h" | 20 #include "third_party/libyuv/include/libyuv.h" |
22 #endif | |
23 | |
24 namespace { | |
25 | |
26 #if defined(OS_IOS) || defined(OS_ANDROID) | |
27 // TODO(wjia): Support stride. | |
28 void RotatePackedYV12Frame( | |
29 const uint8* src, | |
30 uint8* dest_yplane, | |
31 uint8* dest_uplane, | |
32 uint8* dest_vplane, | |
33 int width, | |
34 int height, | |
35 int rotation, | |
36 bool flip_vert, | |
37 bool flip_horiz) { | |
38 media::RotatePlaneByPixels( | |
39 src, dest_yplane, width, height, rotation, flip_vert, flip_horiz); | |
40 int y_size = width * height; | |
41 src += y_size; | |
42 media::RotatePlaneByPixels( | |
43 src, dest_uplane, width/2, height/2, rotation, flip_vert, flip_horiz); | |
44 src += y_size/4; | |
45 media::RotatePlaneByPixels( | |
46 src, dest_vplane, width/2, height/2, rotation, flip_vert, flip_horiz); | |
47 } | |
48 #endif // #if defined(OS_IOS) || defined(OS_ANDROID) | |
49 | |
50 } // namespace | |
51 | 21 |
52 namespace content { | 22 namespace content { |
53 | 23 |
54 // The number of buffers that VideoCaptureBufferPool should allocate. | 24 // The number of buffers that VideoCaptureBufferPool should allocate. |
55 static const int kNoOfBuffers = 3; | 25 static const int kNoOfBuffers = 3; |
56 | 26 |
57 struct VideoCaptureController::ControllerClient { | 27 struct VideoCaptureController::ControllerClient { |
58 ControllerClient( | 28 ControllerClient( |
59 const VideoCaptureControllerID& id, | 29 const VideoCaptureControllerID& id, |
60 VideoCaptureControllerEventHandler* handler, | 30 VideoCaptureControllerEventHandler* handler, |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
132 // The pool of shared-memory buffers used for capturing. | 102 // The pool of shared-memory buffers used for capturing. |
133 scoped_refptr<VideoCaptureBufferPool> buffer_pool_; | 103 scoped_refptr<VideoCaptureBufferPool> buffer_pool_; |
134 | 104 |
135 // Chopped pixels in width/height in case video capture device has odd | 105 // Chopped pixels in width/height in case video capture device has odd |
136 // numbers for width/height. | 106 // numbers for width/height. |
137 int chopped_width_; | 107 int chopped_width_; |
138 int chopped_height_; | 108 int chopped_height_; |
139 | 109 |
140 // Tracks the current frame format. | 110 // Tracks the current frame format. |
141 media::VideoCaptureCapability frame_info_; | 111 media::VideoCaptureCapability frame_info_; |
142 | 112 scoped_ptr<uint8[]> rotation_temp_buffer_; |
143 // For NV21 we have to do color conversion into the intermediate buffer and | |
144 // from there the rotations. This variable won't be needed after | |
145 // http://crbug.com/292400 | |
146 #if defined(OS_IOS) || defined(OS_ANDROID) | |
147 scoped_ptr<uint8[]> i420_intermediate_buffer_; | |
148 #endif // #if defined(OS_IOS) || defined(OS_ANDROID) | |
149 }; | 113 }; |
150 | 114 |
151 VideoCaptureController::VideoCaptureController() | 115 VideoCaptureController::VideoCaptureController() |
152 : state_(VIDEO_CAPTURE_STATE_STARTED), | 116 : state_(VIDEO_CAPTURE_STATE_STARTED), |
153 weak_ptr_factory_(this) { | 117 weak_ptr_factory_(this) { |
154 memset(¤t_params_, 0, sizeof(current_params_)); | 118 memset(¤t_params_, 0, sizeof(current_params_)); |
155 } | 119 } |
156 | 120 |
157 VideoCaptureController::VideoCaptureDeviceClient::VideoCaptureDeviceClient( | 121 VideoCaptureController::VideoCaptureDeviceClient::VideoCaptureDeviceClient( |
158 const base::WeakPtr<VideoCaptureController>& controller) | 122 const base::WeakPtr<VideoCaptureController>& controller) |
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
269 buffer_pool_->RelinquishConsumerHold(buffer_id, 1); | 233 buffer_pool_->RelinquishConsumerHold(buffer_id, 1); |
270 } | 234 } |
271 | 235 |
272 scoped_refptr<media::VideoFrame> | 236 scoped_refptr<media::VideoFrame> |
273 VideoCaptureController::VideoCaptureDeviceClient::ReserveOutputBuffer() { | 237 VideoCaptureController::VideoCaptureDeviceClient::ReserveOutputBuffer() { |
274 return buffer_pool_->ReserveI420VideoFrame(gfx::Size(frame_info_.width, | 238 return buffer_pool_->ReserveI420VideoFrame(gfx::Size(frame_info_.width, |
275 frame_info_.height), | 239 frame_info_.height), |
276 0); | 240 0); |
277 } | 241 } |
278 | 242 |
279 #if !defined(OS_IOS) && !defined(OS_ANDROID) | |
280 void VideoCaptureController::VideoCaptureDeviceClient::OnIncomingCapturedFrame( | 243 void VideoCaptureController::VideoCaptureDeviceClient::OnIncomingCapturedFrame( |
281 const uint8* data, | 244 const uint8* data, |
282 int length, | 245 int length, |
283 base::Time timestamp, | 246 base::Time timestamp, |
284 int rotation, | 247 int rotation, |
285 bool flip_vert, | 248 bool flip_vert, |
286 bool flip_horiz) { | 249 bool flip_horiz) { |
287 TRACE_EVENT0("video", "VideoCaptureController::OnIncomingCapturedFrame"); | 250 TRACE_EVENT0("video", "VideoCaptureController::OnIncomingCapturedFrame"); |
288 | 251 |
289 if (!buffer_pool_.get()) | 252 if (!buffer_pool_.get()) |
290 return; | 253 return; |
291 scoped_refptr<media::VideoFrame> dst = buffer_pool_->ReserveI420VideoFrame( | 254 scoped_refptr<media::VideoFrame> dst = buffer_pool_->ReserveI420VideoFrame( |
292 gfx::Size(frame_info_.width, frame_info_.height), rotation); | 255 gfx::Size(frame_info_.width, frame_info_.height), rotation); |
293 | 256 |
294 if (!dst.get()) | 257 if (!dst.get()) |
295 return; | 258 return; |
296 | 259 |
297 uint8* yplane = dst->data(media::VideoFrame::kYPlane); | 260 uint8* yplane = dst->data(media::VideoFrame::kYPlane); |
298 uint8* uplane = dst->data(media::VideoFrame::kUPlane); | 261 uint8* uplane = dst->data(media::VideoFrame::kUPlane); |
299 uint8* vplane = dst->data(media::VideoFrame::kVPlane); | 262 uint8* vplane = dst->data(media::VideoFrame::kVPlane); |
300 int yplane_stride = frame_info_.width; | 263 int yplane_stride = frame_info_.width; |
301 int uv_plane_stride = (frame_info_.width + 1) / 2; | 264 int uv_plane_stride = (frame_info_.width + 1) / 2; |
302 int crop_x = 0; | 265 int crop_x = 0; |
303 int crop_y = 0; | 266 int crop_y = 0; |
267 int destination_width = frame_info_.width; | |
268 int destination_height = frame_info_.height; | |
304 libyuv::FourCC origin_colorspace = libyuv::FOURCC_ANY; | 269 libyuv::FourCC origin_colorspace = libyuv::FOURCC_ANY; |
305 // Assuming rotation happens first and flips next, we can consolidate both | 270 // Assuming rotation happens first and flips next, we can consolidate both |
306 // vertical and horizontal flips together with rotation into two variables: | 271 // vertical and horizontal flips together with rotation into two variables: |
307 // new_rotation = (rotation + 180 * vertical_flip) modulo 360 | 272 // new_rotation = (rotation + 180 * vertical_flip) modulo 360 |
308 // new_vertical_flip = horizontal_flip XOR vertical_flip | 273 // new_vertical_flip = horizontal_flip XOR vertical_flip |
309 int new_rotation_angle = (rotation + 180 * flip_vert) % 360; | 274 int new_rotation_angle = (rotation + 180 * flip_vert) % 360; |
310 libyuv::RotationMode rotation_mode = libyuv::kRotate0; | 275 libyuv::RotationMode rotation_mode = libyuv::kRotate0; |
311 if (new_rotation_angle == 90) | 276 if (new_rotation_angle == 90) |
312 rotation_mode = libyuv::kRotate90; | 277 rotation_mode = libyuv::kRotate90; |
313 else if (new_rotation_angle == 180) | 278 else if (new_rotation_angle == 180) |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
369 media::ConvertRGB24ToYUV(rgb_src, | 334 media::ConvertRGB24ToYUV(rgb_src, |
370 yplane, | 335 yplane, |
371 uplane, | 336 uplane, |
372 vplane, | 337 vplane, |
373 frame_info_.width, | 338 frame_info_.width, |
374 frame_info_.height, | 339 frame_info_.height, |
375 rgb_stride, | 340 rgb_stride, |
376 yplane_stride, | 341 yplane_stride, |
377 uv_plane_stride); | 342 uv_plane_stride); |
378 } else { | 343 } else { |
344 if (new_rotation_angle==90 || new_rotation_angle==270){ | |
345 // To be compatible with non-libyuv code in RotatePlaneByPixels, when | |
346 // rotating by 90/270, only the maximum square portion located in the | |
347 // center of the image is rotated. F.i. 640x480 pixels, only the central | |
348 // 480 pixels would be rotated and the leftmost and rightmost 80 columns | |
349 // would be ignored. | |
350 destination_width = destination_height; | |
351 int letterbox_width = abs(frame_info_.width - frame_info_.height)/2; | |
352 yplane += letterbox_width; | |
353 uplane += letterbox_width/2; | |
354 vplane += letterbox_width/2; | |
wjia(left Chromium)
2013/09/23 18:43:49
This handles only landscape case. What about portr
mcasas
2013/09/24 07:17:06
The landscape case needs all these extra modificat
wjia(left Chromium)
2013/09/25 00:38:19
Sorry, I wasn't clear. My question is: what if the
| |
355 } | |
379 libyuv::ConvertToI420( | 356 libyuv::ConvertToI420( |
380 data, | 357 data, length, |
381 length, | 358 yplane, yplane_stride, |
382 yplane, | 359 uplane, uv_plane_stride, |
383 yplane_stride, | 360 vplane, uv_plane_stride, |
384 uplane, | 361 crop_x, crop_y, |
385 uv_plane_stride, | 362 frame_info_.width + chopped_width_, |
386 vplane, | 363 frame_info_.height * (flip_vert ^ flip_horiz ? -1 : 1), |
387 uv_plane_stride, | 364 destination_width, |
388 crop_x, | 365 destination_height, |
389 crop_y, | 366 rotation_mode, |
390 frame_info_.width + chopped_width_, | 367 origin_colorspace); |
391 frame_info_.height * (flip_vert ^ flip_horiz ? -1 : 1), | |
392 frame_info_.width, | |
393 frame_info_.height, | |
394 rotation_mode, | |
395 origin_colorspace); | |
396 } | 368 } |
397 BrowserThread::PostTask( | 369 BrowserThread::PostTask( |
398 BrowserThread::IO, | 370 BrowserThread::IO, |
399 FROM_HERE, | 371 FROM_HERE, |
400 base::Bind(&VideoCaptureController::DoIncomingCapturedFrameOnIOThread, | 372 base::Bind(&VideoCaptureController::DoIncomingCapturedFrameOnIOThread, |
401 controller_, | 373 controller_, |
402 dst, | 374 dst, |
403 timestamp)); | 375 timestamp)); |
404 } | 376 } |
405 #else | |
406 void VideoCaptureController::VideoCaptureDeviceClient::OnIncomingCapturedFrame( | |
407 const uint8* data, | |
408 int length, | |
409 base::Time timestamp, | |
410 int rotation, | |
411 bool flip_vert, | |
412 bool flip_horiz) { | |
413 DCHECK(frame_info_.color == media::PIXEL_FORMAT_I420 || | |
414 frame_info_.color == media::PIXEL_FORMAT_YV12 || | |
415 frame_info_.color == media::PIXEL_FORMAT_NV21 || | |
416 (rotation == 0 && !flip_vert && !flip_horiz)); | |
417 | |
418 TRACE_EVENT0("video", "VideoCaptureController::OnIncomingCapturedFrame"); | |
419 | |
420 if (!buffer_pool_) | |
421 return; | |
422 scoped_refptr<media::VideoFrame> dst = | |
423 buffer_pool_->ReserveI420VideoFrame(gfx::Size(frame_info_.width, | |
424 frame_info_.height), | |
425 rotation); | |
426 | |
427 if (!dst.get()) | |
428 return; | |
429 | |
430 uint8* yplane = dst->data(media::VideoFrame::kYPlane); | |
431 uint8* uplane = dst->data(media::VideoFrame::kUPlane); | |
432 uint8* vplane = dst->data(media::VideoFrame::kVPlane); | |
433 | |
434 // Do color conversion from the camera format to I420. | |
435 switch (frame_info_.color) { | |
436 case media::PIXEL_FORMAT_UNKNOWN: // Color format not set. | |
437 break; | |
438 case media::PIXEL_FORMAT_I420: | |
439 DCHECK(!chopped_width_ && !chopped_height_); | |
440 RotatePackedYV12Frame( | |
441 data, yplane, uplane, vplane, frame_info_.width, frame_info_.height, | |
442 rotation, flip_vert, flip_horiz); | |
443 break; | |
444 case media::PIXEL_FORMAT_YV12: | |
445 DCHECK(!chopped_width_ && !chopped_height_); | |
446 RotatePackedYV12Frame( | |
447 data, yplane, vplane, uplane, frame_info_.width, frame_info_.height, | |
448 rotation, flip_vert, flip_horiz); | |
449 break; | |
450 case media::PIXEL_FORMAT_NV21: { | |
451 DCHECK(!chopped_width_ && !chopped_height_); | |
452 int num_pixels = frame_info_.width * frame_info_.height; | |
453 media::ConvertNV21ToYUV(data, | |
454 &i420_intermediate_buffer_[0], | |
455 &i420_intermediate_buffer_[num_pixels], | |
456 &i420_intermediate_buffer_[num_pixels * 5 / 4], | |
457 frame_info_.width, | |
458 frame_info_.height); | |
459 RotatePackedYV12Frame( | |
460 i420_intermediate_buffer_.get(), yplane, uplane, vplane, | |
461 frame_info_.width, frame_info_.height, | |
462 rotation, flip_vert, flip_horiz); | |
463 break; | |
464 } | |
465 case media::PIXEL_FORMAT_YUY2: | |
466 DCHECK(!chopped_width_ && !chopped_height_); | |
467 if (frame_info_.width * frame_info_.height * 2 != length) { | |
468 // If |length| of |data| does not match the expected width and height | |
469 // we can't convert the frame to I420. YUY2 is 2 bytes per pixel. | |
470 break; | |
471 } | |
472 | |
473 media::ConvertYUY2ToYUV(data, yplane, uplane, vplane, frame_info_.width, | |
474 frame_info_.height); | |
475 break; | |
476 case media::PIXEL_FORMAT_RGB24: { | |
477 int ystride = frame_info_.width; | |
478 int uvstride = frame_info_.width / 2; | |
479 int rgb_stride = 3 * (frame_info_.width + chopped_width_); | |
480 const uint8* rgb_src = data; | |
481 media::ConvertRGB24ToYUV(rgb_src, yplane, uplane, vplane, | |
482 frame_info_.width, frame_info_.height, | |
483 rgb_stride, ystride, uvstride); | |
484 break; | |
485 } | |
486 case media::PIXEL_FORMAT_ARGB: | |
487 media::ConvertRGB32ToYUV(data, yplane, uplane, vplane, frame_info_.width, | |
488 frame_info_.height, | |
489 (frame_info_.width + chopped_width_) * 4, | |
490 frame_info_.width, frame_info_.width / 2); | |
491 break; | |
492 default: | |
493 NOTREACHED(); | |
494 } | |
495 | |
496 BrowserThread::PostTask(BrowserThread::IO, | |
497 FROM_HERE, | |
498 base::Bind(&VideoCaptureController::DoIncomingCapturedFrameOnIOThread, | |
499 controller_, dst, timestamp)); | |
500 } | |
501 #endif // #if !defined(OS_IOS) && !defined(OS_ANDROID) | |
502 | 377 |
503 void | 378 void |
504 VideoCaptureController::VideoCaptureDeviceClient::OnIncomingCapturedVideoFrame( | 379 VideoCaptureController::VideoCaptureDeviceClient::OnIncomingCapturedVideoFrame( |
505 const scoped_refptr<media::VideoFrame>& frame, | 380 const scoped_refptr<media::VideoFrame>& frame, |
506 base::Time timestamp) { | 381 base::Time timestamp) { |
507 if (!buffer_pool_) | 382 if (!buffer_pool_) |
508 return; | 383 return; |
509 | 384 |
510 // If this is a frame that belongs to the buffer pool, we can forward it | 385 // If this is a frame that belongs to the buffer pool, we can forward it |
511 // directly to the IO thread and be done. | 386 // directly to the IO thread and be done. |
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
629 chopped_width_ = 1; | 504 chopped_width_ = 1; |
630 } else { | 505 } else { |
631 chopped_width_ = 0; | 506 chopped_width_ = 0; |
632 } | 507 } |
633 if (info.height & 1) { | 508 if (info.height & 1) { |
634 --frame_info_.height; | 509 --frame_info_.height; |
635 chopped_height_ = 1; | 510 chopped_height_ = 1; |
636 } else { | 511 } else { |
637 chopped_height_ = 0; | 512 chopped_height_ = 0; |
638 } | 513 } |
639 #if defined(OS_IOS) || defined(OS_ANDROID) | 514 if (!rotation_temp_buffer_.get()) |
640 if (frame_info_.color == media::PIXEL_FORMAT_NV21 && | 515 rotation_temp_buffer_.reset(new uint8[frame_info_.width * frame_info_.heig ht * 12 / 8]); |
wjia(left Chromium)
2013/09/23 18:43:49
80 chars per line.
2 space indent for a new line.
mcasas
2013/09/24 07:17:06
Absolutely, I removed it locally but forgot to cl
| |
641 !i420_intermediate_buffer_) { | |
642 i420_intermediate_buffer_.reset( | |
643 new uint8[frame_info_.width * frame_info_.height * 12 / 8]); | |
644 } | |
645 #endif // #if defined(OS_IOS) || defined(OS_ANDROID) | |
646 | 516 |
647 DCHECK(!buffer_pool_.get()); | 517 DCHECK(!buffer_pool_.get()); |
648 | 518 |
649 // TODO(nick): Give BufferPool the same lifetime as the controller, have it | 519 // TODO(nick): Give BufferPool the same lifetime as the controller, have it |
650 // support frame size changes, and stop checking it for NULL everywhere. | 520 // support frame size changes, and stop checking it for NULL everywhere. |
651 // http://crbug.com/266082 | 521 // http://crbug.com/266082 |
652 buffer_pool_ = new VideoCaptureBufferPool( | 522 buffer_pool_ = new VideoCaptureBufferPool( |
653 media::VideoFrame::AllocationSize( | 523 media::VideoFrame::AllocationSize( |
654 media::VideoFrame::I420, | 524 media::VideoFrame::I420, |
655 gfx::Size(frame_info_.width, frame_info_.height)), | 525 gfx::Size(frame_info_.width, frame_info_.height)), |
(...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
811 } | 681 } |
812 return NULL; | 682 return NULL; |
813 } | 683 } |
814 | 684 |
815 int VideoCaptureController::GetClientCount() { | 685 int VideoCaptureController::GetClientCount() { |
816 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 686 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
817 return controller_clients_.size(); | 687 return controller_clients_.size(); |
818 } | 688 } |
819 | 689 |
820 } // namespace content | 690 } // namespace content |
OLD | NEW |