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) | |
|
wjia(left Chromium)
2013/09/02 17:11:35
Is it possible to add color conversion for Android
mcasas
2013/09/03 08:10:41
That'll be cool indeed, I can follow through with
| |
| 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) { | |
|
wjia(left Chromium)
2013/09/02 17:11:35
Do we need to support rotation for desktop platfor
mcasas
2013/09/03 08:10:41
I don't know. But why would we change this generic
| |
| 271 DCHECK(frame_info_.color == media::VideoCaptureCapability::kI420 || | |
| 272 frame_info_.color == media::VideoCaptureCapability::kYV12 || | |
| 273 (rotation == 0 && !flip_vert && !flip_horiz)); | |
| 274 | |
| 275 TRACE_EVENT0("video", "VideoCaptureController::OnIncomingCapturedFrame"); | |
| 276 | |
| 277 scoped_refptr<media::VideoFrame> dst; | |
| 278 { | |
| 279 base::AutoLock lock(buffer_pool_lock_); | |
| 280 if (!buffer_pool_.get()) | |
| 281 return; | |
| 282 dst = buffer_pool_->ReserveI420VideoFrame(gfx::Size(frame_info_.width, | |
| 283 frame_info_.height), | |
|
wjia(left Chromium)
2013/09/02 17:11:35
It's more readable to drop "gfx::Size" to a new li
mcasas
2013/09/03 08:10:41
Indeed. Done.
| |
| 284 rotation); | |
| 285 } | |
| 286 | |
| 287 if (!dst.get()) | |
| 288 return; | |
| 289 | |
| 290 uint8* yplane = dst->data(media::VideoFrame::kYPlane); | |
| 291 uint8* uplane = dst->data(media::VideoFrame::kUPlane); | |
| 292 uint8* vplane = dst->data(media::VideoFrame::kVPlane); | |
| 293 int yplane_stride = frame_info_.width; | |
| 294 int uv_plane_stride = (frame_info_.width + 1) / 2; | |
| 295 int crop_x = 0; | |
| 296 int crop_y = 0; | |
| 297 libyuv::FourCC destination_colorspace = libyuv::FOURCC_ANY; | |
|
mcasas
2013/09/03 08:10:41
Actually I made a mistake here, this variable shou
| |
| 298 libyuv::RotationMode rotation_mode = libyuv::kRotate0; | |
| 299 | |
| 300 if (rotation == 90) | |
| 301 rotation_mode = libyuv::kRotate90; | |
| 302 else if (rotation == 180) | |
| 303 rotation_mode = libyuv::kRotate180; | |
| 304 else if (rotation == 270) | |
| 305 rotation_mode = libyuv::kRotate270; | |
|
wjia(left Chromium)
2013/09/02 17:11:35
Is this mapping correct? How do you test it?
flip
mcasas
2013/09/03 08:10:41
I missed two things indeed:
1) using horizontal fl
| |
| 306 | |
| 307 switch (frame_info_.color) { | |
| 308 case media::VideoCaptureCapability::kColorUnknown: // Color format not set. | |
| 309 break; | |
| 310 case media::VideoCaptureCapability::kI420: | |
| 311 DCHECK(!chopped_width_ && !chopped_height_); | |
| 312 destination_colorspace = libyuv::FOURCC_I420; | |
| 313 break; | |
| 314 case media::VideoCaptureCapability::kYV12: | |
| 315 DCHECK(!chopped_width_ && !chopped_height_); | |
| 316 destination_colorspace = libyuv::FOURCC_YV12; | |
| 317 break; | |
| 318 case media::VideoCaptureCapability::kNV21: | |
| 319 DCHECK(!chopped_width_ && !chopped_height_); | |
| 320 destination_colorspace = libyuv::FOURCC_NV12; | |
| 321 break; | |
| 322 case media::VideoCaptureCapability::kYUY2: | |
| 323 DCHECK(!chopped_width_ && !chopped_height_); | |
| 324 destination_colorspace = libyuv::FOURCC_YUY2; | |
| 325 break; | |
| 326 case media::VideoCaptureCapability::kRGB24: | |
| 327 #if defined(OS_WIN) | |
| 328 // RGB on Windows start at the bottom line and has a negative stride. This | |
| 329 // is not supported by libyuv, so the media API is used instead. | |
| 330 { | |
| 331 int rgb_stride = -3 * (frame_info_.width + chopped_width_); | |
| 332 const uint8* rgb_src = | |
| 333 data + 3 * (frame_info_.width + chopped_width_) * | |
| 334 (frame_info_.height - 1 + chopped_height_); | |
| 335 media::ConvertRGB24ToYUV(rgb_src, | |
| 336 yplane, | |
| 337 uplane, | |
| 338 vplane, | |
| 339 frame_info_.width, | |
| 340 frame_info_.height, | |
| 341 rgb_stride, | |
| 342 yplane_stride, | |
| 343 uv_plane_stride); | |
| 344 } | |
| 345 destination_colorspace = libyuv::FOURCC_ANY; | |
| 346 #else | |
| 347 destination_colorspace = libyuv::FOURCC_RAW; | |
| 348 #endif | |
| 349 break; | |
| 350 case media::VideoCaptureCapability::kARGB: | |
| 351 destination_colorspace = libyuv::FOURCC_ARGB; | |
| 352 break; | |
| 353 case media::VideoCaptureCapability::kMJPEG: | |
| 354 destination_colorspace = libyuv::FOURCC_MJPG; | |
| 355 break; | |
| 356 default: | |
| 357 NOTREACHED(); | |
| 358 } | |
| 359 // Destination colorspace is always YUV I420. If destination_colorspace is | |
| 360 // libyuv::FOURCC_ANY, then ConvertToI420 just returns -1. | |
| 361 libyuv::ConvertToI420(data, | |
|
wjia(left Chromium)
2013/09/02 17:11:35
Do you need to call this for kRGB24 on WIN (it has
mcasas
2013/09/03 08:10:41
It would be called with a destination_colorspace =
| |
| 362 length, | |
| 363 yplane, | |
| 364 yplane_stride, | |
| 365 uplane, | |
| 366 uv_plane_stride, | |
| 367 vplane, | |
| 368 uv_plane_stride, | |
| 369 crop_x, | |
| 370 crop_y, | |
| 371 frame_info_.width, | |
| 372 frame_info_.height, | |
| 373 frame_info_.width, | |
| 374 frame_info_.height, | |
| 375 rotation_mode, | |
| 376 destination_colorspace); | |
| 377 | |
| 378 BrowserThread::PostTask( | |
| 379 BrowserThread::IO, | |
| 380 FROM_HERE, | |
| 381 base::Bind(&VideoCaptureController::DoIncomingCapturedFrameOnIOThread, | |
| 382 this, | |
| 383 dst, | |
| 384 timestamp)); | |
| 385 } | |
| 386 #else | |
| 387 void VideoCaptureController::OnIncomingCapturedFrame( | |
| 388 const uint8* data, | |
| 389 int length, | |
| 264 base::Time timestamp, | 390 base::Time timestamp, |
| 265 int rotation, | 391 int rotation, |
| 266 bool flip_vert, | 392 bool flip_vert, |
| 267 bool flip_horiz) { | 393 bool flip_horiz) { |
| 268 DCHECK(frame_info_.color == media::VideoCaptureCapability::kI420 || | 394 DCHECK(frame_info_.color == media::VideoCaptureCapability::kI420 || |
| 269 frame_info_.color == media::VideoCaptureCapability::kYV12 || | 395 frame_info_.color == media::VideoCaptureCapability::kYV12 || |
| 270 (rotation == 0 && !flip_vert && !flip_horiz)); | 396 (rotation == 0 && !flip_vert && !flip_horiz)); |
| 271 | 397 |
| 272 TRACE_EVENT0("video", "VideoCaptureController::OnIncomingCapturedFrame"); | 398 TRACE_EVENT0("video", "VideoCaptureController::OnIncomingCapturedFrame"); |
| 273 | 399 |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 309 media::ConvertNV21ToYUV(data, yplane, uplane, vplane, frame_info_.width, | 435 media::ConvertNV21ToYUV(data, yplane, uplane, vplane, frame_info_.width, |
| 310 frame_info_.height); | 436 frame_info_.height); |
| 311 break; | 437 break; |
| 312 case media::VideoCaptureCapability::kYUY2: | 438 case media::VideoCaptureCapability::kYUY2: |
| 313 DCHECK(!chopped_width_ && !chopped_height_); | 439 DCHECK(!chopped_width_ && !chopped_height_); |
| 314 if (frame_info_.width * frame_info_.height * 2 != length) { | 440 if (frame_info_.width * frame_info_.height * 2 != length) { |
| 315 // If |length| of |data| does not match the expected width and height | 441 // 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. | 442 // we can't convert the frame to I420. YUY2 is 2 bytes per pixel. |
| 317 break; | 443 break; |
| 318 } | 444 } |
| 319 | |
| 320 media::ConvertYUY2ToYUV(data, yplane, uplane, vplane, frame_info_.width, | 445 media::ConvertYUY2ToYUV(data, yplane, uplane, vplane, frame_info_.width, |
| 321 frame_info_.height); | 446 frame_info_.height); |
| 322 break; | 447 break; |
| 323 case media::VideoCaptureCapability::kRGB24: { | 448 case media::VideoCaptureCapability::kRGB24: { |
| 324 int ystride = frame_info_.width; | 449 int ystride = frame_info_.width; |
| 325 int uvstride = frame_info_.width / 2; | 450 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_); | 451 int rgb_stride = 3 * (frame_info_.width + chopped_width_); |
| 332 const uint8* rgb_src = data; | 452 const uint8* rgb_src = data; |
| 333 #endif | |
| 334 media::ConvertRGB24ToYUV(rgb_src, yplane, uplane, vplane, | 453 media::ConvertRGB24ToYUV(rgb_src, yplane, uplane, vplane, |
| 335 frame_info_.width, frame_info_.height, | 454 frame_info_.width, frame_info_.height, |
| 336 rgb_stride, ystride, uvstride); | 455 rgb_stride, ystride, uvstride); |
| 337 break; | 456 break; |
| 338 } | 457 } |
| 339 case media::VideoCaptureCapability::kARGB: | 458 case media::VideoCaptureCapability::kARGB: |
| 340 media::ConvertRGB32ToYUV(data, yplane, uplane, vplane, frame_info_.width, | 459 media::ConvertRGB32ToYUV(data, yplane, uplane, vplane, frame_info_.width, |
| 341 frame_info_.height, | 460 frame_info_.height, |
| 342 (frame_info_.width + chopped_width_) * 4, | 461 (frame_info_.width + chopped_width_) * 4, |
| 343 frame_info_.width, frame_info_.width / 2); | 462 frame_info_.width, frame_info_.width / 2); |
| 344 break; | 463 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: | 464 default: |
| 360 NOTREACHED(); | 465 NOTREACHED(); |
| 361 } | 466 } |
| 362 | 467 |
| 363 BrowserThread::PostTask(BrowserThread::IO, | 468 BrowserThread::PostTask(BrowserThread::IO, |
| 364 FROM_HERE, | 469 FROM_HERE, |
| 365 base::Bind(&VideoCaptureController::DoIncomingCapturedFrameOnIOThread, | 470 base::Bind(&VideoCaptureController::DoIncomingCapturedFrameOnIOThread, |
| 366 this, dst, timestamp)); | 471 this, dst, timestamp)); |
| 367 } | 472 } |
| 473 #endif // #if !defined(OS_IOS) && !defined(OS_ANDROID) | |
| 368 | 474 |
| 369 // OnIncomingCapturedVideoFrame is called the thread running the capture device. | 475 // OnIncomingCapturedVideoFrame is called the thread running the capture device. |
| 370 void VideoCaptureController::OnIncomingCapturedVideoFrame( | 476 void VideoCaptureController::OnIncomingCapturedVideoFrame( |
| 371 const scoped_refptr<media::VideoFrame>& frame, | 477 const scoped_refptr<media::VideoFrame>& frame, |
| 372 base::Time timestamp) { | 478 base::Time timestamp) { |
| 373 | 479 |
| 374 scoped_refptr<media::VideoFrame> target; | 480 scoped_refptr<media::VideoFrame> target; |
| 375 { | 481 { |
| 376 base::AutoLock lock(buffer_pool_lock_); | 482 base::AutoLock lock(buffer_pool_lock_); |
| 377 | 483 |
| (...skipping 351 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 729 controller_clients_.push_back((*client_it)); | 835 controller_clients_.push_back((*client_it)); |
| 730 pending_clients_.erase(client_it++); | 836 pending_clients_.erase(client_it++); |
| 731 } | 837 } |
| 732 // Request the manager to start the actual capture. | 838 // Request the manager to start the actual capture. |
| 733 video_capture_manager_->Start(current_params_, this); | 839 video_capture_manager_->Start(current_params_, this); |
| 734 state_ = VIDEO_CAPTURE_STATE_STARTED; | 840 state_ = VIDEO_CAPTURE_STATE_STARTED; |
| 735 device_in_use_ = true; | 841 device_in_use_ = true; |
| 736 } | 842 } |
| 737 | 843 |
| 738 } // namespace content | 844 } // namespace content |
| OLD | NEW |