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) | 20 #if !defined(OS_IOS) && !defined(OS_ANDROID) |
| 21 #include "third_party/libyuv/include/libyuv.h" | 21 #include "third_party/libyuv/include/libyuv.h" |
| 22 #endif | 22 #endif |
| 23 | 23 |
| 24 namespace { | 24 namespace { |
| 25 | 25 |
| 26 #if defined(OS_IOS) || defined(OS_ANDROID) | |
| 26 // TODO(wjia): Support stride. | 27 // TODO(wjia): Support stride. |
| 27 void RotatePackedYV12Frame( | 28 void RotatePackedYV12Frame( |
| 28 const uint8* src, | 29 const uint8* src, |
| 29 uint8* dest_yplane, | 30 uint8* dest_yplane, |
| 30 uint8* dest_uplane, | 31 uint8* dest_uplane, |
| 31 uint8* dest_vplane, | 32 uint8* dest_vplane, |
| 32 int width, | 33 int width, |
| 33 int height, | 34 int height, |
| 34 int rotation, | 35 int rotation, |
| 35 bool flip_vert, | 36 bool flip_vert, |
| 36 bool flip_horiz) { | 37 bool flip_horiz) { |
| 37 media::RotatePlaneByPixels( | 38 media::RotatePlaneByPixels( |
| 38 src, dest_yplane, width, height, rotation, flip_vert, flip_horiz); | 39 src, dest_yplane, width, height, rotation, flip_vert, flip_horiz); |
| 39 int y_size = width * height; | 40 int y_size = width * height; |
| 40 src += y_size; | 41 src += y_size; |
| 41 media::RotatePlaneByPixels( | 42 media::RotatePlaneByPixels( |
| 42 src, dest_uplane, width/2, height/2, rotation, flip_vert, flip_horiz); | 43 src, dest_uplane, width/2, height/2, rotation, flip_vert, flip_horiz); |
| 43 src += y_size/4; | 44 src += y_size/4; |
| 44 media::RotatePlaneByPixels( | 45 media::RotatePlaneByPixels( |
| 45 src, dest_vplane, width/2, height/2, rotation, flip_vert, flip_horiz); | 46 src, dest_vplane, width/2, height/2, rotation, flip_vert, flip_horiz); |
| 46 } | 47 } |
| 48 #endif // #if defined(OS_IOS) || defined(OS_ANDROID) | |
| 47 | 49 |
| 48 } // namespace | 50 } // namespace |
| 49 | 51 |
| 50 namespace content { | 52 namespace content { |
| 51 | 53 |
| 52 // The number of buffers that VideoCaptureBufferPool should allocate. | 54 // The number of buffers that VideoCaptureBufferPool should allocate. |
| 53 static const int kNoOfBuffers = 3; | 55 static const int kNoOfBuffers = 3; |
| 54 | 56 |
| 55 struct VideoCaptureController::ControllerClient { | 57 struct VideoCaptureController::ControllerClient { |
| 56 ControllerClient( | 58 ControllerClient( |
| (...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 251 if (!buffer_pool_.get()) | 253 if (!buffer_pool_.get()) |
| 252 return NULL; | 254 return NULL; |
| 253 return buffer_pool_->ReserveI420VideoFrame(gfx::Size(frame_info_.width, | 255 return buffer_pool_->ReserveI420VideoFrame(gfx::Size(frame_info_.width, |
| 254 frame_info_.height), | 256 frame_info_.height), |
| 255 0); | 257 0); |
| 256 } | 258 } |
| 257 | 259 |
| 258 // Implements VideoCaptureDevice::EventHandler. | 260 // Implements VideoCaptureDevice::EventHandler. |
| 259 // OnIncomingCapturedFrame is called the thread running the capture device. | 261 // OnIncomingCapturedFrame is called the thread running the capture device. |
| 260 // I.e.- DirectShow thread on windows and v4l2_thread on Linux. | 262 // I.e.- DirectShow thread on windows and v4l2_thread on Linux. |
| 263 #if !defined(OS_IOS) && !defined(OS_ANDROID) | |
| 261 void VideoCaptureController::OnIncomingCapturedFrame( | 264 void VideoCaptureController::OnIncomingCapturedFrame( |
| 262 const uint8* data, | 265 const uint8* data, |
| 263 int length, | 266 int length, |
| 267 base::Time timestamp, | |
| 268 int rotation, | |
| 269 bool flip_vert, | |
| 270 bool flip_horiz) { | |
| 271 TRACE_EVENT0("video", "VideoCaptureController::OnIncomingCapturedFrame"); | |
| 272 | |
| 273 scoped_refptr<media::VideoFrame> dst; | |
| 274 { | |
| 275 base::AutoLock lock(buffer_pool_lock_); | |
| 276 if (!buffer_pool_.get()) | |
| 277 return; | |
| 278 dst = buffer_pool_->ReserveI420VideoFrame( | |
| 279 gfx::Size(frame_info_.width, frame_info_.height), rotation); | |
| 280 } | |
| 281 | |
| 282 if (!dst.get()) | |
| 283 return; | |
| 284 | |
| 285 uint8* yplane = dst->data(media::VideoFrame::kYPlane); | |
| 286 uint8* uplane = dst->data(media::VideoFrame::kUPlane); | |
| 287 uint8* vplane = dst->data(media::VideoFrame::kVPlane); | |
| 288 int yplane_stride = frame_info_.width; | |
| 289 int uv_plane_stride = (frame_info_.width + 1) / 2; | |
| 290 int crop_x = 0; | |
| 291 int crop_y = 0; | |
| 292 libyuv::FourCC origin_colorspace = libyuv::FOURCC_ANY; | |
| 293 // Assuming flips happen before rotations (as in libyuv), we consolidate both | |
|
wjia(left Chromium)
2013/09/03 23:23:45
I should have added some comments for this functio
mcasas
2013/09/04 08:47:46
In that case the equations and the comment should
| |
| 294 // vertical and horizontal flips together with rotation into two: | |
| 295 // new_rotation = (rotation + 180 * horizontal_flip) modulo 360 | |
| 296 // new_vertical_flip = horizontal_flip XOR vertical_flip | |
| 297 int new_rotation_angle = (rotation + 180 * flip_horiz) % 360; | |
| 298 libyuv::RotationMode rotation_mode = libyuv::kRotate0; | |
| 299 if (new_rotation_angle == 90) | |
| 300 rotation_mode = libyuv::kRotate90; | |
| 301 else if (new_rotation_angle == 180) | |
| 302 rotation_mode = libyuv::kRotate180; | |
| 303 else if (new_rotation_angle == 270) | |
| 304 rotation_mode = libyuv::kRotate270; | |
| 305 | |
| 306 switch (frame_info_.color) { | |
| 307 case media::VideoCaptureCapability::kColorUnknown: // Color format not set. | |
| 308 break; | |
| 309 case media::VideoCaptureCapability::kI420: | |
| 310 DCHECK(!chopped_width_ && !chopped_height_); | |
| 311 origin_colorspace = libyuv::FOURCC_I420; | |
| 312 break; | |
| 313 case media::VideoCaptureCapability::kYV12: | |
| 314 DCHECK(!chopped_width_ && !chopped_height_); | |
| 315 origin_colorspace = libyuv::FOURCC_YV12; | |
| 316 break; | |
| 317 case media::VideoCaptureCapability::kNV21: | |
| 318 DCHECK(!chopped_width_ && !chopped_height_); | |
| 319 origin_colorspace = libyuv::FOURCC_NV12; | |
| 320 break; | |
| 321 case media::VideoCaptureCapability::kYUY2: | |
| 322 DCHECK(!chopped_width_ && !chopped_height_); | |
| 323 origin_colorspace = libyuv::FOURCC_YUY2; | |
| 324 break; | |
| 325 case media::VideoCaptureCapability::kRGB24: | |
| 326 #if defined(OS_WIN) | |
| 327 // RGB on Windows start at the bottom line and has a negative stride. This | |
| 328 // is not supported by libyuv, so the media API is used instead. | |
| 329 { | |
| 330 int rgb_stride = -3 * (frame_info_.width + chopped_width_); | |
| 331 const uint8* rgb_src = | |
| 332 data + 3 * (frame_info_.width + chopped_width_) * | |
| 333 (frame_info_.height - 1 + chopped_height_); | |
| 334 media::ConvertRGB24ToYUV(rgb_src, | |
| 335 yplane, | |
| 336 uplane, | |
| 337 vplane, | |
| 338 frame_info_.width, | |
| 339 frame_info_.height, | |
| 340 rgb_stride, | |
| 341 yplane_stride, | |
| 342 uv_plane_stride); | |
| 343 } | |
| 344 origin_colorspace = libyuv::FOURCC_ANY; | |
| 345 #else | |
| 346 origin_colorspace = libyuv::FOURCC_RAW; | |
| 347 #endif | |
| 348 break; | |
| 349 case media::VideoCaptureCapability::kARGB: | |
| 350 origin_colorspace = libyuv::FOURCC_ARGB; | |
| 351 break; | |
| 352 case media::VideoCaptureCapability::kMJPEG: | |
| 353 origin_colorspace = libyuv::FOURCC_MJPG; | |
| 354 break; | |
| 355 default: | |
| 356 NOTREACHED(); | |
| 357 } | |
| 358 // Destination colorspace is always YUV I420. If destination_colorspace is | |
| 359 // libyuv::FOURCC_ANY, then ConvertToI420 just returns -1. | |
| 360 libyuv::ConvertToI420(data, | |
|
wjia(left Chromium)
2013/09/03 23:23:45
When origin_colorspace = libyuv::FOURCC_ANY, does
mcasas
2013/09/04 08:47:46
When FOURCC_ANY is used as origin colorspace, a ro
| |
| 361 length, | |
| 362 yplane, | |
| 363 yplane_stride, | |
| 364 uplane, | |
| 365 uv_plane_stride, | |
| 366 vplane, | |
| 367 uv_plane_stride, | |
| 368 crop_x, | |
| 369 crop_y, | |
| 370 frame_info_.width, | |
| 371 frame_info_.height * (flip_vert ^ flip_horiz ? -1 : 1), | |
| 372 frame_info_.width, | |
| 373 frame_info_.height, | |
| 374 rotation_mode, | |
| 375 origin_colorspace); | |
| 376 | |
| 377 BrowserThread::PostTask( | |
| 378 BrowserThread::IO, | |
| 379 FROM_HERE, | |
| 380 base::Bind(&VideoCaptureController::DoIncomingCapturedFrameOnIOThread, | |
| 381 this, | |
| 382 dst, | |
| 383 timestamp)); | |
| 384 } | |
| 385 #else | |
| 386 void VideoCaptureController::OnIncomingCapturedFrame( | |
| 387 const uint8* data, | |
| 388 int length, | |
| 264 base::Time timestamp, | 389 base::Time timestamp, |
| 265 int rotation, | 390 int rotation, |
| 266 bool flip_vert, | 391 bool flip_vert, |
| 267 bool flip_horiz) { | 392 bool flip_horiz) { |
| 268 DCHECK(frame_info_.color == media::VideoCaptureCapability::kI420 || | 393 DCHECK(frame_info_.color == media::VideoCaptureCapability::kI420 || |
| 269 frame_info_.color == media::VideoCaptureCapability::kYV12 || | 394 frame_info_.color == media::VideoCaptureCapability::kYV12 || |
| 270 (rotation == 0 && !flip_vert && !flip_horiz)); | 395 (rotation == 0 && !flip_vert && !flip_horiz)); |
| 271 | 396 |
| 272 TRACE_EVENT0("video", "VideoCaptureController::OnIncomingCapturedFrame"); | 397 TRACE_EVENT0("video", "VideoCaptureController::OnIncomingCapturedFrame"); |
| 273 | 398 |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 309 media::ConvertNV21ToYUV(data, yplane, uplane, vplane, frame_info_.width, | 434 media::ConvertNV21ToYUV(data, yplane, uplane, vplane, frame_info_.width, |
| 310 frame_info_.height); | 435 frame_info_.height); |
| 311 break; | 436 break; |
| 312 case media::VideoCaptureCapability::kYUY2: | 437 case media::VideoCaptureCapability::kYUY2: |
| 313 DCHECK(!chopped_width_ && !chopped_height_); | 438 DCHECK(!chopped_width_ && !chopped_height_); |
| 314 if (frame_info_.width * frame_info_.height * 2 != length) { | 439 if (frame_info_.width * frame_info_.height * 2 != length) { |
| 315 // If |length| of |data| does not match the expected width and height | 440 // If |length| of |data| does not match the expected width and height |
| 316 // we can't convert the frame to I420. YUY2 is 2 bytes per pixel. | 441 // we can't convert the frame to I420. YUY2 is 2 bytes per pixel. |
| 317 break; | 442 break; |
| 318 } | 443 } |
| 319 | |
| 320 media::ConvertYUY2ToYUV(data, yplane, uplane, vplane, frame_info_.width, | 444 media::ConvertYUY2ToYUV(data, yplane, uplane, vplane, frame_info_.width, |
| 321 frame_info_.height); | 445 frame_info_.height); |
| 322 break; | 446 break; |
| 323 case media::VideoCaptureCapability::kRGB24: { | 447 case media::VideoCaptureCapability::kRGB24: { |
| 324 int ystride = frame_info_.width; | 448 int ystride = frame_info_.width; |
| 325 int uvstride = frame_info_.width / 2; | 449 int uvstride = frame_info_.width / 2; |
| 326 #if defined(OS_WIN) // RGB on Windows start at the bottom line. | |
| 327 int rgb_stride = -3 * (frame_info_.width + chopped_width_); | |
| 328 const uint8* rgb_src = data + 3 * (frame_info_.width + chopped_width_) * | |
| 329 (frame_info_.height -1 + chopped_height_); | |
| 330 #else | |
| 331 int rgb_stride = 3 * (frame_info_.width + chopped_width_); | 450 int rgb_stride = 3 * (frame_info_.width + chopped_width_); |
| 332 const uint8* rgb_src = data; | 451 const uint8* rgb_src = data; |
| 333 #endif | |
| 334 media::ConvertRGB24ToYUV(rgb_src, yplane, uplane, vplane, | 452 media::ConvertRGB24ToYUV(rgb_src, yplane, uplane, vplane, |
| 335 frame_info_.width, frame_info_.height, | 453 frame_info_.width, frame_info_.height, |
| 336 rgb_stride, ystride, uvstride); | 454 rgb_stride, ystride, uvstride); |
| 337 break; | 455 break; |
| 338 } | 456 } |
| 339 case media::VideoCaptureCapability::kARGB: | 457 case media::VideoCaptureCapability::kARGB: |
| 340 media::ConvertRGB32ToYUV(data, yplane, uplane, vplane, frame_info_.width, | 458 media::ConvertRGB32ToYUV(data, yplane, uplane, vplane, frame_info_.width, |
| 341 frame_info_.height, | 459 frame_info_.height, |
| 342 (frame_info_.width + chopped_width_) * 4, | 460 (frame_info_.width + chopped_width_) * 4, |
| 343 frame_info_.width, frame_info_.width / 2); | 461 frame_info_.width, frame_info_.width / 2); |
| 344 break; | 462 break; |
| 345 #if !defined(OS_IOS) && !defined(OS_ANDROID) | |
| 346 case media::VideoCaptureCapability::kMJPEG: { | |
| 347 int yplane_stride = frame_info_.width; | |
| 348 int uv_plane_stride = (frame_info_.width + 1) / 2; | |
| 349 int crop_x = 0; | |
| 350 int crop_y = 0; | |
| 351 libyuv::ConvertToI420(data, length, yplane, yplane_stride, uplane, | |
| 352 uv_plane_stride, vplane, uv_plane_stride, crop_x, | |
| 353 crop_y, frame_info_.width, frame_info_.height, | |
| 354 frame_info_.width, frame_info_.height, | |
| 355 libyuv::kRotate0, libyuv::FOURCC_MJPG); | |
| 356 break; | |
| 357 } | |
| 358 #endif | |
| 359 default: | 463 default: |
| 360 NOTREACHED(); | 464 NOTREACHED(); |
| 361 } | 465 } |
| 362 | 466 |
| 363 BrowserThread::PostTask(BrowserThread::IO, | 467 BrowserThread::PostTask(BrowserThread::IO, |
| 364 FROM_HERE, | 468 FROM_HERE, |
| 365 base::Bind(&VideoCaptureController::DoIncomingCapturedFrameOnIOThread, | 469 base::Bind(&VideoCaptureController::DoIncomingCapturedFrameOnIOThread, |
| 366 this, dst, timestamp)); | 470 this, dst, timestamp)); |
| 367 } | 471 } |
| 472 #endif // #if !defined(OS_IOS) && !defined(OS_ANDROID) | |
| 368 | 473 |
| 369 // OnIncomingCapturedVideoFrame is called the thread running the capture device. | 474 // OnIncomingCapturedVideoFrame is called the thread running the capture device. |
| 370 void VideoCaptureController::OnIncomingCapturedVideoFrame( | 475 void VideoCaptureController::OnIncomingCapturedVideoFrame( |
| 371 const scoped_refptr<media::VideoFrame>& frame, | 476 const scoped_refptr<media::VideoFrame>& frame, |
| 372 base::Time timestamp) { | 477 base::Time timestamp) { |
| 373 | 478 |
| 374 scoped_refptr<media::VideoFrame> target; | 479 scoped_refptr<media::VideoFrame> target; |
| 375 { | 480 { |
| 376 base::AutoLock lock(buffer_pool_lock_); | 481 base::AutoLock lock(buffer_pool_lock_); |
| 377 | 482 |
| (...skipping 351 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 729 controller_clients_.push_back((*client_it)); | 834 controller_clients_.push_back((*client_it)); |
| 730 pending_clients_.erase(client_it++); | 835 pending_clients_.erase(client_it++); |
| 731 } | 836 } |
| 732 // Request the manager to start the actual capture. | 837 // Request the manager to start the actual capture. |
| 733 video_capture_manager_->Start(current_params_, this); | 838 video_capture_manager_->Start(current_params_, this); |
| 734 state_ = VIDEO_CAPTURE_STATE_STARTED; | 839 state_ = VIDEO_CAPTURE_STATE_STARTED; |
| 735 device_in_use_ = true; | 840 device_in_use_ = true; |
| 736 } | 841 } |
| 737 | 842 |
| 738 } // namespace content | 843 } // namespace content |
| OLD | NEW |