| 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" | |
| 12 #include "base/stl_util.h" | 11 #include "base/stl_util.h" |
| 13 #include "content/browser/renderer_host/media/media_stream_manager.h" | 12 #include "content/browser/renderer_host/media/media_stream_manager.h" |
| 14 #include "content/browser/renderer_host/media/video_capture_manager.h" | 13 #include "content/browser/renderer_host/media/video_capture_manager.h" |
| 15 #include "content/public/browser/browser_thread.h" | 14 #include "content/public/browser/browser_thread.h" |
| 16 #include "media/base/video_frame.h" | 15 #include "media/base/video_frame.h" |
| 17 #include "media/base/video_util.h" | 16 #include "media/base/video_util.h" |
| 18 #include "media/base/yuv_convert.h" | 17 #include "media/base/yuv_convert.h" |
| 19 | 18 |
| 20 #if !defined(AVOID_LIBYUV_FOR_ANDROID_WEBVIEW) | 19 #if !defined(AVOID_LIBYUV_FOR_ANDROID_WEBVIEW) |
| 21 #include "third_party/libyuv/include/libyuv.h" | 20 #include "third_party/libyuv/include/libyuv.h" |
| 22 #endif | 21 #endif |
| 23 | 22 |
| 24 using media::VideoCaptureCapability; | 23 using media::VideoCaptureCapability; |
| 25 | 24 |
| 26 namespace content { | 25 namespace content { |
| 27 | 26 |
| 27 namespace { |
| 28 |
| 28 // The number of buffers that VideoCaptureBufferPool should allocate. | 29 // The number of buffers that VideoCaptureBufferPool should allocate. |
| 29 static const int kNoOfBuffers = 3; | 30 const int kNoOfBuffers = 3; |
| 31 |
| 32 class PoolBuffer : public media::VideoCaptureDevice::Client::Buffer { |
| 33 public: |
| 34 PoolBuffer(const scoped_refptr<VideoCaptureBufferPool>& pool, |
| 35 int buffer_id, |
| 36 void* data, |
| 37 size_t size) |
| 38 : Buffer(buffer_id, data, size), pool_(pool) { |
| 39 DCHECK(pool_); |
| 40 } |
| 41 |
| 42 private: |
| 43 virtual ~PoolBuffer() { pool_->RelinquishProducerReservation(id()); } |
| 44 |
| 45 const scoped_refptr<VideoCaptureBufferPool> pool_; |
| 46 }; |
| 47 |
| 48 } // anonymous namespace |
| 30 | 49 |
| 31 struct VideoCaptureController::ControllerClient { | 50 struct VideoCaptureController::ControllerClient { |
| 32 ControllerClient( | 51 ControllerClient( |
| 33 const VideoCaptureControllerID& id, | 52 const VideoCaptureControllerID& id, |
| 34 VideoCaptureControllerEventHandler* handler, | 53 VideoCaptureControllerEventHandler* handler, |
| 35 base::ProcessHandle render_process, | 54 base::ProcessHandle render_process, |
| 36 const media::VideoCaptureParams& params) | 55 const media::VideoCaptureParams& params) |
| 37 : controller_id(id), | 56 : controller_id(id), |
| 38 event_handler(handler), | 57 event_handler(handler), |
| 39 render_process_handle(render_process), | 58 render_process_handle(render_process), |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 80 // v4l2_thread on Linux, and the UI thread for tab capture. | 99 // v4l2_thread on Linux, and the UI thread for tab capture. |
| 81 class VideoCaptureController::VideoCaptureDeviceClient | 100 class VideoCaptureController::VideoCaptureDeviceClient |
| 82 : public media::VideoCaptureDevice::Client { | 101 : public media::VideoCaptureDevice::Client { |
| 83 public: | 102 public: |
| 84 explicit VideoCaptureDeviceClient( | 103 explicit VideoCaptureDeviceClient( |
| 85 const base::WeakPtr<VideoCaptureController>& controller, | 104 const base::WeakPtr<VideoCaptureController>& controller, |
| 86 const scoped_refptr<VideoCaptureBufferPool>& buffer_pool); | 105 const scoped_refptr<VideoCaptureBufferPool>& buffer_pool); |
| 87 virtual ~VideoCaptureDeviceClient(); | 106 virtual ~VideoCaptureDeviceClient(); |
| 88 | 107 |
| 89 // VideoCaptureDevice::Client implementation. | 108 // VideoCaptureDevice::Client implementation. |
| 90 virtual scoped_refptr<media::VideoFrame> ReserveOutputBuffer( | 109 virtual scoped_refptr<Buffer> ReserveOutputBuffer( |
| 110 media::VideoFrame::Format format, |
| 91 const gfx::Size& size) OVERRIDE; | 111 const gfx::Size& size) OVERRIDE; |
| 92 virtual void OnIncomingCapturedFrame( | 112 virtual void OnIncomingCapturedFrame(const uint8* data, |
| 93 const uint8* data, | 113 int length, |
| 94 int length, | 114 base::Time timestamp, |
| 95 base::Time timestamp, | 115 int rotation, |
| 96 int rotation, | 116 bool flip_vert, |
| 97 bool flip_vert, | 117 bool flip_horiz, |
| 98 bool flip_horiz, | 118 const VideoCaptureCapability& frame_info) |
| 99 const VideoCaptureCapability& frame_info) OVERRIDE; | 119 OVERRIDE; |
| 100 virtual void OnIncomingCapturedVideoFrame( | 120 virtual void OnIncomingCapturedBuffer(const scoped_refptr<Buffer>& buffer, |
| 101 const scoped_refptr<media::VideoFrame>& frame, | 121 media::VideoFrame::Format format, |
| 102 base::Time timestamp, | 122 const gfx::Size& dimensions, |
| 103 int frame_rate) OVERRIDE; | 123 base::Time timestamp, |
| 124 int frame_rate) OVERRIDE; |
| 104 virtual void OnError() OVERRIDE; | 125 virtual void OnError() OVERRIDE; |
| 105 | 126 |
| 106 private: | 127 private: |
| 107 scoped_refptr<media::VideoFrame> DoReserveI420VideoFrame( | 128 scoped_refptr<Buffer> DoReserveOutputBuffer(media::VideoFrame::Format format, |
| 108 const gfx::Size& size, | 129 const gfx::Size& dimensions, |
| 109 int rotation); | 130 int rotation); |
| 110 | 131 |
| 111 // The controller to which we post events. | 132 // The controller to which we post events. |
| 112 const base::WeakPtr<VideoCaptureController> controller_; | 133 const base::WeakPtr<VideoCaptureController> controller_; |
| 113 | 134 |
| 114 // The pool of shared-memory buffers used for capturing. | 135 // The pool of shared-memory buffers used for capturing. |
| 115 const scoped_refptr<VideoCaptureBufferPool> buffer_pool_; | 136 const scoped_refptr<VideoCaptureBufferPool> buffer_pool_; |
| 137 |
| 138 // The set of buffers that have been used for rotated capturing. |
| 139 std::set<int> rotated_buffers_; |
| 116 }; | 140 }; |
| 117 | 141 |
| 118 VideoCaptureController::VideoCaptureController() | 142 VideoCaptureController::VideoCaptureController() |
| 119 : buffer_pool_(new VideoCaptureBufferPool(kNoOfBuffers)), | 143 : buffer_pool_(new VideoCaptureBufferPool(kNoOfBuffers)), |
| 120 state_(VIDEO_CAPTURE_STATE_STARTED), | 144 state_(VIDEO_CAPTURE_STATE_STARTED), |
| 121 weak_ptr_factory_(this) { | 145 weak_ptr_factory_(this) { |
| 122 } | 146 } |
| 123 | 147 |
| 124 VideoCaptureController::VideoCaptureDeviceClient::VideoCaptureDeviceClient( | 148 VideoCaptureController::VideoCaptureDeviceClient::VideoCaptureDeviceClient( |
| 125 const base::WeakPtr<VideoCaptureController>& controller, | 149 const base::WeakPtr<VideoCaptureController>& controller, |
| 126 const scoped_refptr<VideoCaptureBufferPool>& buffer_pool) | 150 const scoped_refptr<VideoCaptureBufferPool>& buffer_pool) |
| 127 : controller_(controller), | 151 : controller_(controller), buffer_pool_(buffer_pool) {} |
| 128 buffer_pool_(buffer_pool) {} | |
| 129 | 152 |
| 130 VideoCaptureController::VideoCaptureDeviceClient::~VideoCaptureDeviceClient() {} | 153 VideoCaptureController::VideoCaptureDeviceClient::~VideoCaptureDeviceClient() {} |
| 131 | 154 |
| 132 base::WeakPtr<VideoCaptureController> VideoCaptureController::GetWeakPtr() { | 155 base::WeakPtr<VideoCaptureController> VideoCaptureController::GetWeakPtr() { |
| 133 return weak_ptr_factory_.GetWeakPtr(); | 156 return weak_ptr_factory_.GetWeakPtr(); |
| 134 } | 157 } |
| 135 | 158 |
| 136 scoped_ptr<media::VideoCaptureDevice::Client> | 159 scoped_ptr<media::VideoCaptureDevice::Client> |
| 137 VideoCaptureController::NewDeviceClient() { | 160 VideoCaptureController::NewDeviceClient() { |
| 138 scoped_ptr<media::VideoCaptureDevice::Client> result( | 161 scoped_ptr<media::VideoCaptureDevice::Client> result( |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 222 // If this buffer is not held by this client, or this client doesn't exist | 245 // If this buffer is not held by this client, or this client doesn't exist |
| 223 // in controller, do nothing. | 246 // in controller, do nothing. |
| 224 if (!client || !client->active_buffers.erase(buffer_id)) { | 247 if (!client || !client->active_buffers.erase(buffer_id)) { |
| 225 NOTREACHED(); | 248 NOTREACHED(); |
| 226 return; | 249 return; |
| 227 } | 250 } |
| 228 | 251 |
| 229 buffer_pool_->RelinquishConsumerHold(buffer_id, 1); | 252 buffer_pool_->RelinquishConsumerHold(buffer_id, 1); |
| 230 } | 253 } |
| 231 | 254 |
| 232 scoped_refptr<media::VideoFrame> | 255 scoped_refptr<media::VideoCaptureDevice::Client::Buffer> |
| 233 VideoCaptureController::VideoCaptureDeviceClient::ReserveOutputBuffer( | 256 VideoCaptureController::VideoCaptureDeviceClient::ReserveOutputBuffer( |
| 257 media::VideoFrame::Format format, |
| 234 const gfx::Size& size) { | 258 const gfx::Size& size) { |
| 235 return DoReserveI420VideoFrame(size, 0); | 259 return DoReserveOutputBuffer(format, size, 0); |
| 236 } | 260 } |
| 237 | 261 |
| 238 void VideoCaptureController::VideoCaptureDeviceClient::OnIncomingCapturedFrame( | 262 void VideoCaptureController::VideoCaptureDeviceClient::OnIncomingCapturedFrame( |
| 239 const uint8* data, | 263 const uint8* data, |
| 240 int length, | 264 int length, |
| 241 base::Time timestamp, | 265 base::Time timestamp, |
| 242 int rotation, | 266 int rotation, |
| 243 bool flip_vert, | 267 bool flip_vert, |
| 244 bool flip_horiz, | 268 bool flip_horiz, |
| 245 const VideoCaptureCapability& frame_info) { | 269 const VideoCaptureCapability& frame_info) { |
| (...skipping 11 matching lines...) Expand all Loading... |
| 257 | 281 |
| 258 if (frame_info.width & 1) { | 282 if (frame_info.width & 1) { |
| 259 --new_width; | 283 --new_width; |
| 260 chopped_width = 1; | 284 chopped_width = 1; |
| 261 } | 285 } |
| 262 if (frame_info.height & 1) { | 286 if (frame_info.height & 1) { |
| 263 --new_height; | 287 --new_height; |
| 264 chopped_height = 1; | 288 chopped_height = 1; |
| 265 } | 289 } |
| 266 | 290 |
| 267 scoped_refptr<media::VideoFrame> dst = DoReserveI420VideoFrame( | 291 const gfx::Size dimensions(new_width, new_height); |
| 268 gfx::Size(new_width, new_height), rotation); | 292 scoped_refptr<Buffer> buffer = |
| 293 DoReserveOutputBuffer(media::VideoFrame::I420, dimensions, rotation); |
| 269 | 294 |
| 270 if (!dst.get()) | 295 if (!buffer) |
| 271 return; | 296 return; |
| 272 #if !defined(AVOID_LIBYUV_FOR_ANDROID_WEBVIEW) | 297 #if !defined(AVOID_LIBYUV_FOR_ANDROID_WEBVIEW) |
| 273 | 298 uint8* yplane = reinterpret_cast<uint8*>(buffer->data()); |
| 274 uint8* yplane = dst->data(media::VideoFrame::kYPlane); | 299 uint8* uplane = |
| 275 uint8* uplane = dst->data(media::VideoFrame::kUPlane); | 300 yplane + |
| 276 uint8* vplane = dst->data(media::VideoFrame::kVPlane); | 301 media::VideoFrame::PlaneAllocationSize( |
| 302 media::VideoFrame::I420, media::VideoFrame::kYPlane, dimensions); |
| 303 uint8* vplane = |
| 304 uplane + |
| 305 media::VideoFrame::PlaneAllocationSize( |
| 306 media::VideoFrame::I420, media::VideoFrame::kUPlane, dimensions); |
| 277 int yplane_stride = new_width; | 307 int yplane_stride = new_width; |
| 278 int uv_plane_stride = (new_width + 1) / 2; | 308 int uv_plane_stride = new_width / 2; |
| 279 int crop_x = 0; | 309 int crop_x = 0; |
| 280 int crop_y = 0; | 310 int crop_y = 0; |
| 281 int destination_width = new_width; | 311 int destination_width = new_width; |
| 282 int destination_height = new_height; | 312 int destination_height = new_height; |
| 283 libyuv::FourCC origin_colorspace = libyuv::FOURCC_ANY; | 313 libyuv::FourCC origin_colorspace = libyuv::FOURCC_ANY; |
| 284 // Assuming rotation happens first and flips next, we can consolidate both | 314 // Assuming rotation happens first and flips next, we can consolidate both |
| 285 // vertical and horizontal flips together with rotation into two variables: | 315 // vertical and horizontal flips together with rotation into two variables: |
| 286 // new_rotation = (rotation + 180 * vertical_flip) modulo 360 | 316 // new_rotation = (rotation + 180 * vertical_flip) modulo 360 |
| 287 // new_vertical_flip = horizontal_flip XOR vertical_flip | 317 // new_vertical_flip = horizontal_flip XOR vertical_flip |
| 288 int new_rotation_angle = (rotation + 180 * flip_vert) % 360; | 318 int new_rotation_angle = (rotation + 180 * flip_vert) % 360; |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 335 // kRGB24 on Windows start at the bottom line and has a negative stride. This | 365 // kRGB24 on Windows start at the bottom line and has a negative stride. This |
| 336 // is not supported by libyuv, so the media API is used instead. | 366 // is not supported by libyuv, so the media API is used instead. |
| 337 if (frame_info.color == media::PIXEL_FORMAT_RGB24) { | 367 if (frame_info.color == media::PIXEL_FORMAT_RGB24) { |
| 338 // Rotation and flipping is not supported in kRGB24 and OS_WIN case. | 368 // Rotation and flipping is not supported in kRGB24 and OS_WIN case. |
| 339 DCHECK(!rotation && !flip_vert && !flip_horiz); | 369 DCHECK(!rotation && !flip_vert && !flip_horiz); |
| 340 need_convert_rgb24_on_win = true; | 370 need_convert_rgb24_on_win = true; |
| 341 } | 371 } |
| 342 #endif | 372 #endif |
| 343 if (need_convert_rgb24_on_win) { | 373 if (need_convert_rgb24_on_win) { |
| 344 int rgb_stride = -3 * (new_width + chopped_width); | 374 int rgb_stride = -3 * (new_width + chopped_width); |
| 345 const uint8* rgb_src = | 375 const uint8* rgb_src = data + 3 * (new_width + chopped_width) * |
| 346 data + 3 * (new_width + chopped_width) * | 376 (new_height - 1 + chopped_height); |
| 347 (new_height - 1 + chopped_height); | |
| 348 media::ConvertRGB24ToYUV(rgb_src, | 377 media::ConvertRGB24ToYUV(rgb_src, |
| 349 yplane, | 378 yplane, |
| 350 uplane, | 379 uplane, |
| 351 vplane, | 380 vplane, |
| 352 new_width, | 381 new_width, |
| 353 new_height, | 382 new_height, |
| 354 rgb_stride, | 383 rgb_stride, |
| 355 yplane_stride, | 384 yplane_stride, |
| 356 uv_plane_stride); | 385 uv_plane_stride); |
| 357 } else { | 386 } else { |
| 358 if (new_rotation_angle==90 || new_rotation_angle==270){ | 387 if (new_rotation_angle==90 || new_rotation_angle==270){ |
| 359 // To be compatible with non-libyuv code in RotatePlaneByPixels, when | 388 // To be compatible with non-libyuv code in RotatePlaneByPixels, when |
| 360 // rotating by 90/270, only the maximum square portion located in the | 389 // rotating by 90/270, only the maximum square portion located in the |
| 361 // center of the image is rotated. F.i. 640x480 pixels, only the central | 390 // center of the image is rotated. F.i. 640x480 pixels, only the central |
| 362 // 480 pixels would be rotated and the leftmost and rightmost 80 columns | 391 // 480 pixels would be rotated and the leftmost and rightmost 80 columns |
| 363 // would be ignored. This process is called letterboxing. | 392 // would be ignored. This process is called letterboxing. |
| 364 int letterbox_thickness = abs(new_width - new_height) / 2; | 393 int letterbox_thickness = abs(new_width - new_height) / 2; |
| 365 if (destination_width > destination_height) { | 394 if (destination_width > destination_height) { |
| 366 yplane += letterbox_thickness; | 395 yplane += letterbox_thickness; |
| 367 uplane += letterbox_thickness / 2; | 396 uplane += letterbox_thickness / 2; |
| 368 vplane += letterbox_thickness / 2; | 397 vplane += letterbox_thickness / 2; |
| 369 destination_width = destination_height; | 398 destination_width = destination_height; |
| 370 } else { | 399 } else { |
| 371 yplane += letterbox_thickness * destination_width; | 400 yplane += letterbox_thickness * destination_width; |
| 372 uplane += (letterbox_thickness * destination_width) / 2; | 401 uplane += (letterbox_thickness * destination_width) / 2; |
| 373 vplane += (letterbox_thickness * destination_width) / 2; | 402 vplane += (letterbox_thickness * destination_width) / 2; |
| 374 destination_height = destination_width; | 403 destination_height = destination_width; |
| 375 } | 404 } |
| 376 } | 405 } |
| 377 libyuv::ConvertToI420( | 406 libyuv::ConvertToI420(data, |
| 378 data, length, | 407 length, |
| 379 yplane, yplane_stride, | 408 yplane, |
| 380 uplane, uv_plane_stride, | 409 yplane_stride, |
| 381 vplane, uv_plane_stride, | 410 uplane, |
| 382 crop_x, crop_y, | 411 uv_plane_stride, |
| 383 new_width + chopped_width, | 412 vplane, |
| 384 new_height * (flip_vert ^ flip_horiz ? -1 : 1), | 413 uv_plane_stride, |
| 385 destination_width, | 414 crop_x, |
| 386 destination_height, | 415 crop_y, |
| 387 rotation_mode, | 416 new_width + chopped_width, |
| 388 origin_colorspace); | 417 new_height * (flip_vert ^ flip_horiz ? -1 : 1), |
| 418 destination_width, |
| 419 destination_height, |
| 420 rotation_mode, |
| 421 origin_colorspace); |
| 389 } | 422 } |
| 390 #else | 423 #else |
| 391 // Libyuv is not linked in for Android WebView builds, but video capture is | 424 // Libyuv is not linked in for Android WebView builds, but video capture is |
| 392 // not used in those builds either. Whenever libyuv is added in that build, | 425 // not used in those builds either. Whenever libyuv is added in that build, |
| 393 // address all these #ifdef parts, see http://crbug.com/299611 . | 426 // address all these #ifdef parts, see http://crbug.com/299611 . |
| 394 NOTREACHED(); | 427 NOTREACHED(); |
| 395 #endif // if !defined(AVOID_LIBYUV_FOR_ANDROID_WEBVIEW) | 428 #endif // if !defined(AVOID_LIBYUV_FOR_ANDROID_WEBVIEW) |
| 396 BrowserThread::PostTask( | 429 BrowserThread::PostTask( |
| 397 BrowserThread::IO, | 430 BrowserThread::IO, |
| 398 FROM_HERE, | 431 FROM_HERE, |
| 399 base::Bind(&VideoCaptureController::DoIncomingCapturedFrameOnIOThread, | 432 base::Bind( |
| 400 controller_, | 433 &VideoCaptureController::DoIncomingCapturedI420BufferOnIOThread, |
| 401 dst, | 434 controller_, |
| 402 frame_info.frame_rate, | 435 buffer, |
| 403 timestamp)); | 436 dimensions, |
| 437 frame_info.frame_rate, |
| 438 timestamp)); |
| 404 } | 439 } |
| 405 | 440 |
| 406 void | 441 void VideoCaptureController::VideoCaptureDeviceClient::OnIncomingCapturedBuffer( |
| 407 VideoCaptureController::VideoCaptureDeviceClient::OnIncomingCapturedVideoFrame( | 442 const scoped_refptr<Buffer>& buffer, |
| 408 const scoped_refptr<media::VideoFrame>& frame, | 443 media::VideoFrame::Format format, |
| 444 const gfx::Size& dimensions, |
| 409 base::Time timestamp, | 445 base::Time timestamp, |
| 410 int frame_rate) { | 446 int frame_rate) { |
| 411 // If this is a frame that belongs to the buffer pool, we can forward it | 447 // The capture pipeline expects I420 for now. |
| 412 // directly to the IO thread and be done. | 448 DCHECK_EQ(format, media::VideoFrame::I420) |
| 413 if (buffer_pool_->RecognizeReservedBuffer( | 449 << "Non-I420 output buffer returned"; |
| 414 frame->shared_memory_handle()) >= 0) { | |
| 415 BrowserThread::PostTask(BrowserThread::IO, | |
| 416 FROM_HERE, | |
| 417 base::Bind(&VideoCaptureController::DoIncomingCapturedFrameOnIOThread, | |
| 418 controller_, frame, frame_rate, timestamp)); | |
| 419 return; | |
| 420 } | |
| 421 | 450 |
| 422 NOTREACHED() << "Frames should always belong to the buffer pool."; | 451 BrowserThread::PostTask( |
| 452 BrowserThread::IO, |
| 453 FROM_HERE, |
| 454 base::Bind( |
| 455 &VideoCaptureController::DoIncomingCapturedI420BufferOnIOThread, |
| 456 controller_, |
| 457 buffer, |
| 458 dimensions, |
| 459 frame_rate, |
| 460 timestamp)); |
| 423 } | 461 } |
| 424 | 462 |
| 425 void VideoCaptureController::VideoCaptureDeviceClient::OnError() { | 463 void VideoCaptureController::VideoCaptureDeviceClient::OnError() { |
| 426 BrowserThread::PostTask(BrowserThread::IO, | 464 BrowserThread::PostTask(BrowserThread::IO, |
| 427 FROM_HERE, | 465 FROM_HERE, |
| 428 base::Bind(&VideoCaptureController::DoErrorOnIOThread, controller_)); | 466 base::Bind(&VideoCaptureController::DoErrorOnIOThread, controller_)); |
| 429 } | 467 } |
| 430 | 468 |
| 431 scoped_refptr<media::VideoFrame> | 469 scoped_refptr<media::VideoCaptureDevice::Client::Buffer> |
| 432 VideoCaptureController::VideoCaptureDeviceClient::DoReserveI420VideoFrame( | 470 VideoCaptureController::VideoCaptureDeviceClient::DoReserveOutputBuffer( |
| 433 const gfx::Size& size, | 471 media::VideoFrame::Format format, |
| 472 const gfx::Size& dimensions, |
| 434 int rotation) { | 473 int rotation) { |
| 474 // The capture pipeline expects I420 for now. |
| 475 DCHECK_EQ(format, media::VideoFrame::I420) |
| 476 << "Non-I420 output buffer requested"; |
| 477 |
| 435 int buffer_id_to_drop = VideoCaptureBufferPool::kInvalidId; | 478 int buffer_id_to_drop = VideoCaptureBufferPool::kInvalidId; |
| 436 scoped_refptr<media::VideoFrame> frame = | 479 const size_t frame_bytes = |
| 437 buffer_pool_->ReserveI420VideoFrame(size, rotation, &buffer_id_to_drop); | 480 media::VideoFrame::AllocationSize(format, dimensions); |
| 481 |
| 482 int buffer_id = |
| 483 buffer_pool_->ReserveForProducer(frame_bytes, &buffer_id_to_drop); |
| 484 if (buffer_id == VideoCaptureBufferPool::kInvalidId) |
| 485 return NULL; |
| 486 void* data; |
| 487 size_t size; |
| 488 buffer_pool_->GetBufferInfo(buffer_id, &data, &size); |
| 489 |
| 490 scoped_refptr<media::VideoCaptureDevice::Client::Buffer> output_buffer( |
| 491 new PoolBuffer(buffer_pool_, buffer_id, data, size)); |
| 492 |
| 438 if (buffer_id_to_drop != VideoCaptureBufferPool::kInvalidId) { | 493 if (buffer_id_to_drop != VideoCaptureBufferPool::kInvalidId) { |
| 439 BrowserThread::PostTask(BrowserThread::IO, | 494 BrowserThread::PostTask(BrowserThread::IO, |
| 440 FROM_HERE, | 495 FROM_HERE, |
| 441 base::Bind(&VideoCaptureController::DoBufferDestroyedOnIOThread, | 496 base::Bind(&VideoCaptureController::DoBufferDestroyedOnIOThread, |
| 442 controller_, buffer_id_to_drop)); | 497 controller_, buffer_id_to_drop)); |
| 498 rotated_buffers_.erase(buffer_id_to_drop); |
| 443 } | 499 } |
| 444 return frame; | 500 |
| 501 // If a 90/270 rotation is required, letterboxing will be required. If the |
| 502 // returned frame has not been rotated before, then the letterbox borders will |
| 503 // not yet have been cleared and we should clear them now. |
| 504 if ((rotation % 180) == 0) { |
| 505 rotated_buffers_.erase(buffer_id); |
| 506 } else { |
| 507 if (rotated_buffers_.insert(buffer_id).second) |
| 508 memset(output_buffer->data(), 0, output_buffer->size()); |
| 509 } |
| 510 |
| 511 return output_buffer; |
| 445 } | 512 } |
| 446 | 513 |
| 447 VideoCaptureController::~VideoCaptureController() { | 514 VideoCaptureController::~VideoCaptureController() { |
| 448 STLDeleteContainerPointers(controller_clients_.begin(), | 515 STLDeleteContainerPointers(controller_clients_.begin(), |
| 449 controller_clients_.end()); | 516 controller_clients_.end()); |
| 450 } | 517 } |
| 451 | 518 |
| 452 void VideoCaptureController::DoIncomingCapturedFrameOnIOThread( | 519 void VideoCaptureController::DoIncomingCapturedI420BufferOnIOThread( |
| 453 const scoped_refptr<media::VideoFrame>& reserved_frame, | 520 scoped_refptr<media::VideoCaptureDevice::Client::Buffer> buffer, |
| 521 const gfx::Size& dimensions, |
| 454 int frame_rate, | 522 int frame_rate, |
| 455 base::Time timestamp) { | 523 base::Time timestamp) { |
| 456 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 524 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 457 | 525 DCHECK_NE(buffer->id(), VideoCaptureBufferPool::kInvalidId); |
| 458 int buffer_id = buffer_pool_->RecognizeReservedBuffer( | |
| 459 reserved_frame->shared_memory_handle()); | |
| 460 if (buffer_id < 0) { | |
| 461 NOTREACHED(); | |
| 462 return; | |
| 463 } | |
| 464 | 526 |
| 465 media::VideoCaptureFormat frame_format( | 527 media::VideoCaptureFormat frame_format( |
| 466 reserved_frame->coded_size().width(), | 528 dimensions.width(), |
| 467 reserved_frame->coded_size().height(), | 529 dimensions.height(), |
| 468 frame_rate, | 530 frame_rate, |
| 469 media::VariableResolutionVideoCaptureDevice); | 531 media::VariableResolutionVideoCaptureDevice); |
| 470 | 532 |
| 471 int count = 0; | 533 int count = 0; |
| 472 if (state_ == VIDEO_CAPTURE_STATE_STARTED) { | 534 if (state_ == VIDEO_CAPTURE_STATE_STARTED) { |
| 473 for (ControllerClients::iterator client_it = controller_clients_.begin(); | 535 for (ControllerClients::iterator client_it = controller_clients_.begin(); |
| 474 client_it != controller_clients_.end(); ++client_it) { | 536 client_it != controller_clients_.end(); ++client_it) { |
| 475 ControllerClient* client = *client_it; | 537 ControllerClient* client = *client_it; |
| 476 if (client->session_closed) | 538 if (client->session_closed) |
| 477 continue; | 539 continue; |
| 478 | 540 |
| 479 bool is_new_buffer = client->known_buffers.insert(buffer_id).second; | 541 bool is_new_buffer = client->known_buffers.insert(buffer->id()).second; |
| 480 if (is_new_buffer) { | 542 if (is_new_buffer) { |
| 481 // On the first use of a buffer on a client, share the memory handle. | 543 // On the first use of a buffer on a client, share the memory handle. |
| 482 size_t memory_size = 0; | 544 size_t memory_size = 0; |
| 483 base::SharedMemoryHandle remote_handle = buffer_pool_->ShareToProcess( | 545 base::SharedMemoryHandle remote_handle = buffer_pool_->ShareToProcess( |
| 484 buffer_id, client->render_process_handle, &memory_size); | 546 buffer->id(), client->render_process_handle, &memory_size); |
| 485 client->event_handler->OnBufferCreated(client->controller_id, | 547 client->event_handler->OnBufferCreated( |
| 486 remote_handle, | 548 client->controller_id, remote_handle, memory_size, buffer->id()); |
| 487 memory_size, | |
| 488 buffer_id); | |
| 489 } | 549 } |
| 490 | 550 |
| 491 client->event_handler->OnBufferReady(client->controller_id, | 551 client->event_handler->OnBufferReady( |
| 492 buffer_id, timestamp, | 552 client->controller_id, buffer->id(), timestamp, frame_format); |
| 493 frame_format); | 553 bool inserted = client->active_buffers.insert(buffer->id()).second; |
| 494 bool inserted = client->active_buffers.insert(buffer_id).second; | 554 DCHECK(inserted) << "Unexpected duplicate buffer: " << buffer->id(); |
| 495 DCHECK(inserted) << "Unexpected duplicate buffer: " << buffer_id; | |
| 496 count++; | 555 count++; |
| 497 } | 556 } |
| 498 } | 557 } |
| 499 | 558 |
| 500 buffer_pool_->HoldForConsumers(buffer_id, count); | 559 buffer_pool_->HoldForConsumers(buffer->id(), count); |
| 501 } | 560 } |
| 502 | 561 |
| 503 void VideoCaptureController::DoErrorOnIOThread() { | 562 void VideoCaptureController::DoErrorOnIOThread() { |
| 504 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 563 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 505 state_ = VIDEO_CAPTURE_STATE_ERROR; | 564 state_ = VIDEO_CAPTURE_STATE_ERROR; |
| 506 | 565 |
| 507 for (ControllerClients::iterator client_it = controller_clients_.begin(); | 566 for (ControllerClients::iterator client_it = controller_clients_.begin(); |
| 508 client_it != controller_clients_.end(); ++client_it) { | 567 client_it != controller_clients_.end(); ++client_it) { |
| 509 ControllerClient* client = *client_it; | 568 ControllerClient* client = *client_it; |
| 510 if (client->session_closed) | 569 if (client->session_closed) |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 558 } | 617 } |
| 559 return NULL; | 618 return NULL; |
| 560 } | 619 } |
| 561 | 620 |
| 562 int VideoCaptureController::GetClientCount() { | 621 int VideoCaptureController::GetClientCount() { |
| 563 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 622 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 564 return controller_clients_.size(); | 623 return controller_clients_.size(); |
| 565 } | 624 } |
| 566 | 625 |
| 567 } // namespace content | 626 } // namespace content |
| OLD | NEW |