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); |