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

Side by Side Diff: content/browser/renderer_host/media/video_capture_controller.cc

Issue 23444072: Use libyuv in Android VideoCaptureController (not for Android WebView) (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Make explicit no libyuv for iOS builds. Created 7 years, 2 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
« no previous file with comments | « no previous file | content/content_browser.gypi » ('j') | content/content_browser.gypi » ('J')
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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) 20 #if !defined(AVOID_LIBYUV_FOR_ANDROID_WEBVIEW)
21 #include "third_party/libyuv/include/libyuv.h" 21 #include "third_party/libyuv/include/libyuv.h"
22 #endif 22 #endif
23 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
52 namespace content { 24 namespace content {
53 25
54 // The number of buffers that VideoCaptureBufferPool should allocate. 26 // The number of buffers that VideoCaptureBufferPool should allocate.
55 static const int kNoOfBuffers = 3; 27 static const int kNoOfBuffers = 3;
56 28
57 struct VideoCaptureController::ControllerClient { 29 struct VideoCaptureController::ControllerClient {
58 ControllerClient( 30 ControllerClient(
59 const VideoCaptureControllerID& id, 31 const VideoCaptureControllerID& id,
60 VideoCaptureControllerEventHandler* handler, 32 VideoCaptureControllerEventHandler* handler,
61 base::ProcessHandle render_process, 33 base::ProcessHandle render_process,
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
132 // The pool of shared-memory buffers used for capturing. 104 // The pool of shared-memory buffers used for capturing.
133 scoped_refptr<VideoCaptureBufferPool> buffer_pool_; 105 scoped_refptr<VideoCaptureBufferPool> buffer_pool_;
134 106
135 // Chopped pixels in width/height in case video capture device has odd 107 // Chopped pixels in width/height in case video capture device has odd
136 // numbers for width/height. 108 // numbers for width/height.
137 int chopped_width_; 109 int chopped_width_;
138 int chopped_height_; 110 int chopped_height_;
139 111
140 // Tracks the current frame format. 112 // Tracks the current frame format.
141 media::VideoCaptureCapability frame_info_; 113 media::VideoCaptureCapability frame_info_;
142
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 }; 114 };
150 115
151 VideoCaptureController::VideoCaptureController() 116 VideoCaptureController::VideoCaptureController()
152 : state_(VIDEO_CAPTURE_STATE_STARTED), 117 : state_(VIDEO_CAPTURE_STATE_STARTED),
153 weak_ptr_factory_(this) { 118 weak_ptr_factory_(this) {
154 memset(&current_params_, 0, sizeof(current_params_)); 119 memset(&current_params_, 0, sizeof(current_params_));
155 } 120 }
156 121
157 VideoCaptureController::VideoCaptureDeviceClient::VideoCaptureDeviceClient( 122 VideoCaptureController::VideoCaptureDeviceClient::VideoCaptureDeviceClient(
158 const base::WeakPtr<VideoCaptureController>& controller) 123 const base::WeakPtr<VideoCaptureController>& controller)
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after
269 buffer_pool_->RelinquishConsumerHold(buffer_id, 1); 234 buffer_pool_->RelinquishConsumerHold(buffer_id, 1);
270 } 235 }
271 236
272 scoped_refptr<media::VideoFrame> 237 scoped_refptr<media::VideoFrame>
273 VideoCaptureController::VideoCaptureDeviceClient::ReserveOutputBuffer() { 238 VideoCaptureController::VideoCaptureDeviceClient::ReserveOutputBuffer() {
274 return buffer_pool_->ReserveI420VideoFrame(gfx::Size(frame_info_.width, 239 return buffer_pool_->ReserveI420VideoFrame(gfx::Size(frame_info_.width,
275 frame_info_.height), 240 frame_info_.height),
276 0); 241 0);
277 } 242 }
278 243
279 #if !defined(OS_IOS) && !defined(OS_ANDROID)
280 void VideoCaptureController::VideoCaptureDeviceClient::OnIncomingCapturedFrame( 244 void VideoCaptureController::VideoCaptureDeviceClient::OnIncomingCapturedFrame(
281 const uint8* data, 245 const uint8* data,
282 int length, 246 int length,
283 base::Time timestamp, 247 base::Time timestamp,
284 int rotation, 248 int rotation,
285 bool flip_vert, 249 bool flip_vert,
286 bool flip_horiz) { 250 bool flip_horiz) {
287 TRACE_EVENT0("video", "VideoCaptureController::OnIncomingCapturedFrame"); 251 TRACE_EVENT0("video", "VideoCaptureController::OnIncomingCapturedFrame");
288 252
289 if (!buffer_pool_.get()) 253 if (!buffer_pool_.get())
290 return; 254 return;
291 scoped_refptr<media::VideoFrame> dst = buffer_pool_->ReserveI420VideoFrame( 255 scoped_refptr<media::VideoFrame> dst = buffer_pool_->ReserveI420VideoFrame(
292 gfx::Size(frame_info_.width, frame_info_.height), rotation); 256 gfx::Size(frame_info_.width, frame_info_.height), rotation);
293 257
294 if (!dst.get()) 258 if (!dst.get())
295 return; 259 return;
260 #if !defined(AVOID_LIBYUV_FOR_ANDROID_WEBVIEW)
wjia(left Chromium) 2013/09/25 18:50:25 The exclusion here will create video frames with i
mcasas 2013/09/25 19:14:38 After much debate with the WebView team, we agreed
296 261
297 uint8* yplane = dst->data(media::VideoFrame::kYPlane); 262 uint8* yplane = dst->data(media::VideoFrame::kYPlane);
298 uint8* uplane = dst->data(media::VideoFrame::kUPlane); 263 uint8* uplane = dst->data(media::VideoFrame::kUPlane);
299 uint8* vplane = dst->data(media::VideoFrame::kVPlane); 264 uint8* vplane = dst->data(media::VideoFrame::kVPlane);
300 int yplane_stride = frame_info_.width; 265 int yplane_stride = frame_info_.width;
301 int uv_plane_stride = (frame_info_.width + 1) / 2; 266 int uv_plane_stride = (frame_info_.width + 1) / 2;
302 int crop_x = 0; 267 int crop_x = 0;
303 int crop_y = 0; 268 int crop_y = 0;
269 int destination_width = frame_info_.width;
270 int destination_height = frame_info_.height;
304 libyuv::FourCC origin_colorspace = libyuv::FOURCC_ANY; 271 libyuv::FourCC origin_colorspace = libyuv::FOURCC_ANY;
305 // Assuming rotation happens first and flips next, we can consolidate both 272 // Assuming rotation happens first and flips next, we can consolidate both
306 // vertical and horizontal flips together with rotation into two variables: 273 // vertical and horizontal flips together with rotation into two variables:
307 // new_rotation = (rotation + 180 * vertical_flip) modulo 360 274 // new_rotation = (rotation + 180 * vertical_flip) modulo 360
308 // new_vertical_flip = horizontal_flip XOR vertical_flip 275 // new_vertical_flip = horizontal_flip XOR vertical_flip
309 int new_rotation_angle = (rotation + 180 * flip_vert) % 360; 276 int new_rotation_angle = (rotation + 180 * flip_vert) % 360;
310 libyuv::RotationMode rotation_mode = libyuv::kRotate0; 277 libyuv::RotationMode rotation_mode = libyuv::kRotate0;
311 if (new_rotation_angle == 90) 278 if (new_rotation_angle == 90)
312 rotation_mode = libyuv::kRotate90; 279 rotation_mode = libyuv::kRotate90;
313 else if (new_rotation_angle == 180) 280 else if (new_rotation_angle == 180)
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
369 media::ConvertRGB24ToYUV(rgb_src, 336 media::ConvertRGB24ToYUV(rgb_src,
370 yplane, 337 yplane,
371 uplane, 338 uplane,
372 vplane, 339 vplane,
373 frame_info_.width, 340 frame_info_.width,
374 frame_info_.height, 341 frame_info_.height,
375 rgb_stride, 342 rgb_stride,
376 yplane_stride, 343 yplane_stride,
377 uv_plane_stride); 344 uv_plane_stride);
378 } else { 345 } else {
346 if (new_rotation_angle==90 || new_rotation_angle==270){
347 // To be compatible with non-libyuv code in RotatePlaneByPixels, when
348 // rotating by 90/270, only the maximum square portion located in the
349 // center of the image is rotated. F.i. 640x480 pixels, only the central
350 // 480 pixels would be rotated and the leftmost and rightmost 80 columns
351 // would be ignored. This process is called letterboxing.
352 int letterbox_thickness = abs(frame_info_.width - frame_info_.height)/2;
353 if (destination_width > destination_height){
354 yplane += letterbox_thickness;
355 uplane += letterbox_thickness/2;
wjia(left Chromium) 2013/09/25 18:50:25 nit: one space before and after operator "/". This
mcasas 2013/09/26 11:28:56 Done.
356 vplane += letterbox_thickness/2;
357 destination_width = destination_height;
358 } else {
359 yplane += letterbox_thickness * destination_width;
360 uplane += (letterbox_thickness * destination_width)/2;
361 vplane += (letterbox_thickness * destination_width)/2;
362 destination_height = destination_width;
363 }
wjia(left Chromium) 2013/09/25 18:50:25 Please make sure both cases are tested and work co
mcasas 2013/09/25 19:14:38 They do, but if I understand it correctly, in norm
364 }
379 libyuv::ConvertToI420( 365 libyuv::ConvertToI420(
380 data, 366 data, length,
381 length, 367 yplane, yplane_stride,
382 yplane, 368 uplane, uv_plane_stride,
383 yplane_stride, 369 vplane, uv_plane_stride,
384 uplane, 370 crop_x, crop_y,
385 uv_plane_stride,
386 vplane,
387 uv_plane_stride,
388 crop_x,
389 crop_y,
390 frame_info_.width + chopped_width_, 371 frame_info_.width + chopped_width_,
391 frame_info_.height * (flip_vert ^ flip_horiz ? -1 : 1), 372 frame_info_.height * (flip_vert ^ flip_horiz ? -1 : 1),
392 frame_info_.width, 373 destination_width,
393 frame_info_.height, 374 destination_height,
394 rotation_mode, 375 rotation_mode,
395 origin_colorspace); 376 origin_colorspace);
396 } 377 }
378 #endif // if defined(AVOID_LIBYUV_FOR_ANDROID_WEBVIEW)
397 BrowserThread::PostTask( 379 BrowserThread::PostTask(
398 BrowserThread::IO, 380 BrowserThread::IO,
399 FROM_HERE, 381 FROM_HERE,
400 base::Bind(&VideoCaptureController::DoIncomingCapturedFrameOnIOThread, 382 base::Bind(&VideoCaptureController::DoIncomingCapturedFrameOnIOThread,
401 controller_, 383 controller_,
402 dst, 384 dst,
403 timestamp)); 385 timestamp));
404 } 386 }
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 387
503 void 388 void
504 VideoCaptureController::VideoCaptureDeviceClient::OnIncomingCapturedVideoFrame( 389 VideoCaptureController::VideoCaptureDeviceClient::OnIncomingCapturedVideoFrame(
505 const scoped_refptr<media::VideoFrame>& frame, 390 const scoped_refptr<media::VideoFrame>& frame,
506 base::Time timestamp) { 391 base::Time timestamp) {
507 if (!buffer_pool_) 392 if (!buffer_pool_)
508 return; 393 return;
509 394
510 // If this is a frame that belongs to the buffer pool, we can forward it 395 // If this is a frame that belongs to the buffer pool, we can forward it
511 // directly to the IO thread and be done. 396 // directly to the IO thread and be done.
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after
629 chopped_width_ = 1; 514 chopped_width_ = 1;
630 } else { 515 } else {
631 chopped_width_ = 0; 516 chopped_width_ = 0;
632 } 517 }
633 if (info.height & 1) { 518 if (info.height & 1) {
634 --frame_info_.height; 519 --frame_info_.height;
635 chopped_height_ = 1; 520 chopped_height_ = 1;
636 } else { 521 } else {
637 chopped_height_ = 0; 522 chopped_height_ = 0;
638 } 523 }
639 #if defined(OS_IOS) || defined(OS_ANDROID)
640 if (frame_info_.color == media::PIXEL_FORMAT_NV21 &&
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 524
647 DCHECK(!buffer_pool_.get()); 525 DCHECK(!buffer_pool_.get());
648 526
649 // TODO(nick): Give BufferPool the same lifetime as the controller, have it 527 // TODO(nick): Give BufferPool the same lifetime as the controller, have it
650 // support frame size changes, and stop checking it for NULL everywhere. 528 // support frame size changes, and stop checking it for NULL everywhere.
651 // http://crbug.com/266082 529 // http://crbug.com/266082
652 buffer_pool_ = new VideoCaptureBufferPool( 530 buffer_pool_ = new VideoCaptureBufferPool(
653 media::VideoFrame::AllocationSize( 531 media::VideoFrame::AllocationSize(
654 media::VideoFrame::I420, 532 media::VideoFrame::I420,
655 gfx::Size(frame_info_.width, frame_info_.height)), 533 gfx::Size(frame_info_.width, frame_info_.height)),
(...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after
811 } 689 }
812 return NULL; 690 return NULL;
813 } 691 }
814 692
815 int VideoCaptureController::GetClientCount() { 693 int VideoCaptureController::GetClientCount() {
816 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 694 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
817 return controller_clients_.size(); 695 return controller_clients_.size();
818 } 696 }
819 697
820 } // namespace content 698 } // namespace content
OLDNEW
« no previous file with comments | « no previous file | content/content_browser.gypi » ('j') | content/content_browser.gypi » ('J')

Powered by Google App Engine
This is Rietveld 408576698