| Index: content/browser/renderer_host/media/video_capture_controller.cc
|
| diff --git a/content/browser/renderer_host/media/video_capture_controller.cc b/content/browser/renderer_host/media/video_capture_controller.cc
|
| index 40e94bd7645b85793f39d5a6cf08fe3a48f4e1fe..c05493e79569d8fe2fe0938ed95d60aa3fadafc9 100644
|
| --- a/content/browser/renderer_host/media/video_capture_controller.cc
|
| +++ b/content/browser/renderer_host/media/video_capture_controller.cc
|
| @@ -1,5 +1,4 @@
|
| // Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
| -// Use of this source code is governed by a BSD-style license that can be
|
| // found in the LICENSE file.
|
|
|
| #include "content/browser/renderer_host/media/video_capture_controller.h"
|
| @@ -23,8 +22,26 @@
|
|
|
| namespace content {
|
|
|
| +namespace {
|
| +
|
| // The number of buffers that VideoCaptureBufferPool should allocate.
|
| -static const int kNoOfBuffers = 3;
|
| +const int kNoOfBuffers = 3;
|
| +
|
| +class PoolBuffer : public media::VideoCaptureDevice::Client::Buffer {
|
| + public:
|
| + PoolBuffer(const scoped_refptr<VideoCaptureBufferPool>& pool,
|
| + int buffer_id,
|
| + void* data,
|
| + size_t size)
|
| + : Buffer(data, size), pool_(pool), buffer_id_(buffer_id) {}
|
| + virtual ~PoolBuffer() { pool_->RelinquishProducerReservation(buffer_id_); }
|
| +
|
| + private:
|
| + const scoped_refptr<VideoCaptureBufferPool> pool_;
|
| + const int buffer_id_;
|
| +};
|
| +
|
| +} // anonymous namespace
|
|
|
| struct VideoCaptureController::ControllerClient {
|
| ControllerClient(
|
| @@ -85,7 +102,8 @@ class VideoCaptureController::VideoCaptureDeviceClient
|
| virtual ~VideoCaptureDeviceClient();
|
|
|
| // VideoCaptureDevice::Client implementation.
|
| - virtual scoped_refptr<media::VideoFrame> ReserveOutputBuffer(
|
| + virtual scoped_ptr<Buffer> ReserveOutputBuffer(
|
| + media::VideoFrame::Format format,
|
| const gfx::Size& size) OVERRIDE;
|
| virtual void OnIncomingCapturedFrame(const uint8* data,
|
| int length,
|
| @@ -93,9 +111,10 @@ class VideoCaptureController::VideoCaptureDeviceClient
|
| int rotation,
|
| bool flip_vert,
|
| bool flip_horiz) OVERRIDE;
|
| - virtual void OnIncomingCapturedVideoFrame(
|
| - const scoped_refptr<media::VideoFrame>& frame,
|
| - base::Time timestamp) OVERRIDE;
|
| + virtual void OnIncomingCapturedBuffer(scoped_ptr<Buffer> buffer,
|
| + media::VideoFrame::Format format,
|
| + const gfx::Size& dimensions,
|
| + base::Time timestamp) OVERRIDE;
|
| virtual void OnError() OVERRIDE;
|
| virtual void OnFrameInfo(
|
| const media::VideoCaptureCapability& info) OVERRIDE;
|
| @@ -103,9 +122,9 @@ class VideoCaptureController::VideoCaptureDeviceClient
|
| const media::VideoCaptureCapability& info) OVERRIDE;
|
|
|
| private:
|
| - scoped_refptr<media::VideoFrame> DoReserveI420VideoFrame(
|
| - const gfx::Size& size,
|
| - int rotation);
|
| + scoped_ptr<Buffer> DoReserveOutputBuffer(media::VideoFrame::Format format,
|
| + const gfx::Size& dimensions,
|
| + int rotation);
|
|
|
| // The controller to which we post events.
|
| const base::WeakPtr<VideoCaptureController> controller_;
|
| @@ -113,6 +132,9 @@ class VideoCaptureController::VideoCaptureDeviceClient
|
| // The pool of shared-memory buffers used for capturing.
|
| const scoped_refptr<VideoCaptureBufferPool> buffer_pool_;
|
|
|
| + // The set of buffers that have been used for rotated capturing.
|
| + std::set<int> rotated_buffers_;
|
| +
|
| // Chopped pixels in width/height in case video capture device has odd
|
| // numbers for width/height.
|
| int chopped_width_;
|
| @@ -238,10 +260,11 @@ void VideoCaptureController::ReturnBuffer(
|
| buffer_pool_->RelinquishConsumerHold(buffer_id, 1);
|
| }
|
|
|
| -scoped_refptr<media::VideoFrame>
|
| +scoped_ptr<media::VideoCaptureDevice::Client::Buffer>
|
| VideoCaptureController::VideoCaptureDeviceClient::ReserveOutputBuffer(
|
| + media::VideoFrame::Format format,
|
| const gfx::Size& size) {
|
| - return DoReserveI420VideoFrame(size, 0);
|
| + return DoReserveOutputBuffer(format, size, 0);
|
| }
|
|
|
| void VideoCaptureController::VideoCaptureDeviceClient::OnIncomingCapturedFrame(
|
| @@ -256,16 +279,22 @@ void VideoCaptureController::VideoCaptureDeviceClient::OnIncomingCapturedFrame(
|
| if (!frame_info_.IsValid())
|
| return;
|
|
|
| - scoped_refptr<media::VideoFrame> dst = DoReserveI420VideoFrame(
|
| - gfx::Size(frame_info_.width, frame_info_.height), rotation);
|
| + const gfx::Size dimensions(frame_info_.width, frame_info_.height);
|
| + scoped_ptr<Buffer> buffer =
|
| + DoReserveOutputBuffer(media::VideoFrame::I420, dimensions, rotation);
|
|
|
| - if (!dst.get())
|
| + if (!buffer)
|
| return;
|
| #if !defined(AVOID_LIBYUV_FOR_ANDROID_WEBVIEW)
|
| -
|
| - uint8* yplane = dst->data(media::VideoFrame::kYPlane);
|
| - uint8* uplane = dst->data(media::VideoFrame::kUPlane);
|
| - uint8* vplane = dst->data(media::VideoFrame::kVPlane);
|
| + uint8* yplane = reinterpret_cast<uint8*>(buffer->data());
|
| + uint8* uplane =
|
| + yplane +
|
| + media::VideoFrame::PlaneAllocationSize(
|
| + media::VideoFrame::I420, media::VideoFrame::kYPlane, dimensions);
|
| + uint8* vplane =
|
| + uplane +
|
| + media::VideoFrame::PlaneAllocationSize(
|
| + media::VideoFrame::I420, media::VideoFrame::kUPlane, dimensions);
|
| int yplane_stride = frame_info_.width;
|
| int uv_plane_stride = (frame_info_.width + 1) / 2;
|
| int crop_x = 0;
|
| @@ -388,30 +417,37 @@ void VideoCaptureController::VideoCaptureDeviceClient::OnIncomingCapturedFrame(
|
| BrowserThread::PostTask(
|
| BrowserThread::IO,
|
| FROM_HERE,
|
| - base::Bind(&VideoCaptureController::DoIncomingCapturedFrameOnIOThread,
|
| - controller_,
|
| - dst,
|
| - frame_info_.frame_rate,
|
| - timestamp));
|
| + base::Bind(
|
| + &VideoCaptureController::DoIncomingCapturedI420BufferOnIOThread,
|
| + controller_,
|
| + base::Passed(&buffer),
|
| + dimensions,
|
| + frame_info_.frame_rate,
|
| + timestamp));
|
| }
|
|
|
| -void
|
| -VideoCaptureController::VideoCaptureDeviceClient::OnIncomingCapturedVideoFrame(
|
| - const scoped_refptr<media::VideoFrame>& frame,
|
| +void VideoCaptureController::VideoCaptureDeviceClient::OnIncomingCapturedBuffer(
|
| + scoped_ptr<Buffer> buffer,
|
| + media::VideoFrame::Format format,
|
| + const gfx::Size& dimensions,
|
| base::Time timestamp) {
|
| + // The capture pipeline expects I420 for now.
|
| + DCHECK_EQ(format, media::VideoFrame::I420)
|
| + << "Non-I420 output buffer returned";
|
| + DCHECK_NE(buffer_pool_->RecognizeReservedBuffer(buffer->data()),
|
| + VideoCaptureBufferPool::kInvalidId)
|
| + << "Non-reserved buffer returned";
|
|
|
| - // If this is a frame that belongs to the buffer pool, we can forward it
|
| - // directly to the IO thread and be done.
|
| - if (buffer_pool_->RecognizeReservedBuffer(
|
| - frame->shared_memory_handle()) >= 0) {
|
| - BrowserThread::PostTask(BrowserThread::IO,
|
| - FROM_HERE,
|
| - base::Bind(&VideoCaptureController::DoIncomingCapturedFrameOnIOThread,
|
| - controller_, frame, frame_info_.frame_rate, timestamp));
|
| - return;
|
| - }
|
| -
|
| - NOTREACHED() << "Frames should always belong to the buffer pool.";
|
| + BrowserThread::PostTask(
|
| + BrowserThread::IO,
|
| + FROM_HERE,
|
| + base::Bind(
|
| + &VideoCaptureController::DoIncomingCapturedI420BufferOnIOThread,
|
| + controller_,
|
| + base::Passed(&buffer),
|
| + dimensions,
|
| + frame_info_.frame_rate,
|
| + timestamp));
|
| }
|
|
|
| void VideoCaptureController::VideoCaptureDeviceClient::OnError() {
|
| @@ -443,20 +479,52 @@ void VideoCaptureController::VideoCaptureDeviceClient::OnFrameInfoChanged(
|
| OnFrameInfo(info);
|
| }
|
|
|
| -scoped_refptr<media::VideoFrame>
|
| -VideoCaptureController::VideoCaptureDeviceClient::DoReserveI420VideoFrame(
|
| - const gfx::Size& size,
|
| +scoped_ptr<media::VideoCaptureDevice::Client::Buffer>
|
| +VideoCaptureController::VideoCaptureDeviceClient::DoReserveOutputBuffer(
|
| + media::VideoFrame::Format format,
|
| + const gfx::Size& dimensions,
|
| int rotation) {
|
| + // The capture pipeline expects I420 for now.
|
| + DCHECK_EQ(format, media::VideoFrame::I420)
|
| + << "Non-I420 output buffer requested";
|
| +
|
| int buffer_id_to_drop = VideoCaptureBufferPool::kInvalidId;
|
| - scoped_refptr<media::VideoFrame> frame =
|
| - buffer_pool_->ReserveI420VideoFrame(size, rotation, &buffer_id_to_drop);
|
| + const size_t frame_bytes =
|
| + media::VideoFrame::AllocationSize(format, dimensions);
|
| +
|
| + int buffer_id =
|
| + buffer_pool_->ReserveForProducer(frame_bytes, &buffer_id_to_drop);
|
| + if (buffer_id == VideoCaptureBufferPool::kInvalidId)
|
| + return scoped_ptr<Buffer>();
|
| + void* data;
|
| + size_t size;
|
| + buffer_pool_->GetBufferInfo(buffer_id, &data, &size);
|
| +
|
| + scoped_ptr<media::VideoCaptureDevice::Client::Buffer> output_buffer(
|
| + new PoolBuffer(buffer_pool_, buffer_id, data, size));
|
| + buffer_id = VideoCaptureBufferPool::kInvalidId;
|
| +
|
| if (buffer_id_to_drop != VideoCaptureBufferPool::kInvalidId) {
|
| BrowserThread::PostTask(BrowserThread::IO,
|
| FROM_HERE,
|
| base::Bind(&VideoCaptureController::DoBufferDestroyedOnIOThread,
|
| controller_, buffer_id_to_drop));
|
| + rotated_buffers_.erase(buffer_id_to_drop);
|
| }
|
| - return frame;
|
| +
|
| + // If rotation is required, and the returned frame has not been rotated,
|
| + // perform a clear to clear the letterbox borders.
|
| + if ((rotation % 180) == 0) {
|
| + rotated_buffers_.erase(buffer_id);
|
| + } else {
|
| + if (!rotated_buffers_.count(buffer_id)) {
|
| + // TODO(jiayl): Generalize the |rotation| mechanism.
|
| + memset(output_buffer->data(), 0, output_buffer->size());
|
| + rotated_buffers_.insert(buffer_id);
|
| + }
|
| + }
|
| +
|
| + return output_buffer.Pass();
|
| }
|
|
|
| VideoCaptureController::~VideoCaptureController() {
|
| @@ -464,22 +532,25 @@ VideoCaptureController::~VideoCaptureController() {
|
| controller_clients_.end());
|
| }
|
|
|
| -void VideoCaptureController::DoIncomingCapturedFrameOnIOThread(
|
| - const scoped_refptr<media::VideoFrame>& reserved_frame,
|
| +void VideoCaptureController::DoIncomingCapturedI420BufferOnIOThread(
|
| + scoped_ptr<media::VideoCaptureDevice::Client::Buffer> buffer,
|
| + const gfx::Size& dimensions,
|
| int frame_rate,
|
| base::Time timestamp) {
|
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
|
|
|
| - int buffer_id = buffer_pool_->RecognizeReservedBuffer(
|
| - reserved_frame->shared_memory_handle());
|
| + int buffer_id = buffer_pool_->RecognizeReservedBuffer(buffer->data());
|
| if (buffer_id < 0) {
|
| NOTREACHED();
|
| return;
|
| }
|
|
|
| + // |buffer_id| will remain valid as long as |buffer| remains valid, so
|
| + // it will be valid for the remainder of this function.
|
| +
|
| media::VideoCaptureFormat frame_format(
|
| - reserved_frame->coded_size().width(),
|
| - reserved_frame->coded_size().height(),
|
| + dimensions.width(),
|
| + dimensions.height(),
|
| frame_rate,
|
| media::VariableResolutionVideoCaptureDevice);
|
|
|
|
|