Chromium Code Reviews| 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 |