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

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: Finished libyuv rotation+letterboxing. Created 7 years, 3 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 | « android_webview/all_webview.gyp ('k') | content/content_browser.gypi » ('j') | no next file with comments »
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)
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
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(&current_params_, 0, sizeof(current_params_)); 118 memset(&current_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
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
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
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
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
OLDNEW
« no previous file with comments | « android_webview/all_webview.gyp ('k') | content/content_browser.gypi » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698