| 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 9778a9c491260df5054420e182fd6d347491a1ce..293014174a6f3411d046003ce520b5aca8e7ea32 100644
|
| --- a/content/browser/renderer_host/media/video_capture_controller.cc
|
| +++ b/content/browser/renderer_host/media/video_capture_controller.cc
|
| @@ -8,7 +8,6 @@
|
|
|
| #include "base/bind.h"
|
| #include "base/debug/trace_event.h"
|
| -#include "base/memory/scoped_ptr.h"
|
| #include "base/stl_util.h"
|
| #include "content/browser/renderer_host/media/media_stream_manager.h"
|
| #include "content/browser/renderer_host/media/video_capture_manager.h"
|
| @@ -25,8 +24,28 @@ using media::VideoCaptureCapability;
|
|
|
| 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(buffer_id, data, size), pool_(pool) {
|
| + DCHECK(pool_);
|
| + }
|
| +
|
| + private:
|
| + virtual ~PoolBuffer() { pool_->RelinquishProducerReservation(id()); }
|
| +
|
| + const scoped_refptr<VideoCaptureBufferPool> pool_;
|
| +};
|
| +
|
| +} // anonymous namespace
|
|
|
| struct VideoCaptureController::ControllerClient {
|
| ControllerClient(
|
| @@ -87,32 +106,37 @@ class VideoCaptureController::VideoCaptureDeviceClient
|
| virtual ~VideoCaptureDeviceClient();
|
|
|
| // VideoCaptureDevice::Client implementation.
|
| - virtual scoped_refptr<media::VideoFrame> ReserveOutputBuffer(
|
| + virtual scoped_refptr<Buffer> ReserveOutputBuffer(
|
| + media::VideoFrame::Format format,
|
| const gfx::Size& size) OVERRIDE;
|
| - virtual void OnIncomingCapturedFrame(
|
| - const uint8* data,
|
| - int length,
|
| - base::Time timestamp,
|
| - int rotation,
|
| - bool flip_vert,
|
| - bool flip_horiz,
|
| - const VideoCaptureCapability& frame_info) OVERRIDE;
|
| - virtual void OnIncomingCapturedVideoFrame(
|
| - const scoped_refptr<media::VideoFrame>& frame,
|
| - base::Time timestamp,
|
| - int frame_rate) OVERRIDE;
|
| + virtual void OnIncomingCapturedFrame(const uint8* data,
|
| + int length,
|
| + base::Time timestamp,
|
| + int rotation,
|
| + bool flip_vert,
|
| + bool flip_horiz,
|
| + const VideoCaptureCapability& frame_info)
|
| + OVERRIDE;
|
| + virtual void OnIncomingCapturedBuffer(const scoped_refptr<Buffer>& buffer,
|
| + media::VideoFrame::Format format,
|
| + const gfx::Size& dimensions,
|
| + base::Time timestamp,
|
| + int frame_rate) OVERRIDE;
|
| virtual void OnError() OVERRIDE;
|
|
|
| private:
|
| - scoped_refptr<media::VideoFrame> DoReserveI420VideoFrame(
|
| - const gfx::Size& size,
|
| - int rotation);
|
| + scoped_refptr<Buffer> DoReserveOutputBuffer(media::VideoFrame::Format format,
|
| + const gfx::Size& dimensions,
|
| + int rotation);
|
|
|
| // The controller to which we post events.
|
| const base::WeakPtr<VideoCaptureController> controller_;
|
|
|
| // 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_;
|
| };
|
|
|
| VideoCaptureController::VideoCaptureController()
|
| @@ -124,8 +148,7 @@ VideoCaptureController::VideoCaptureController()
|
| VideoCaptureController::VideoCaptureDeviceClient::VideoCaptureDeviceClient(
|
| const base::WeakPtr<VideoCaptureController>& controller,
|
| const scoped_refptr<VideoCaptureBufferPool>& buffer_pool)
|
| - : controller_(controller),
|
| - buffer_pool_(buffer_pool) {}
|
| + : controller_(controller), buffer_pool_(buffer_pool) {}
|
|
|
| VideoCaptureController::VideoCaptureDeviceClient::~VideoCaptureDeviceClient() {}
|
|
|
| @@ -229,10 +252,11 @@ void VideoCaptureController::ReturnBuffer(
|
| buffer_pool_->RelinquishConsumerHold(buffer_id, 1);
|
| }
|
|
|
| -scoped_refptr<media::VideoFrame>
|
| +scoped_refptr<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(
|
| @@ -264,18 +288,24 @@ void VideoCaptureController::VideoCaptureDeviceClient::OnIncomingCapturedFrame(
|
| chopped_height = 1;
|
| }
|
|
|
| - scoped_refptr<media::VideoFrame> dst = DoReserveI420VideoFrame(
|
| - gfx::Size(new_width, new_height), rotation);
|
| + const gfx::Size dimensions(new_width, new_height);
|
| + scoped_refptr<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 = new_width;
|
| - int uv_plane_stride = (new_width + 1) / 2;
|
| + int uv_plane_stride = new_width / 2;
|
| int crop_x = 0;
|
| int crop_y = 0;
|
| int destination_width = new_width;
|
| @@ -342,9 +372,8 @@ void VideoCaptureController::VideoCaptureDeviceClient::OnIncomingCapturedFrame(
|
| #endif
|
| if (need_convert_rgb24_on_win) {
|
| int rgb_stride = -3 * (new_width + chopped_width);
|
| - const uint8* rgb_src =
|
| - data + 3 * (new_width + chopped_width) *
|
| - (new_height - 1 + chopped_height);
|
| + const uint8* rgb_src = data + 3 * (new_width + chopped_width) *
|
| + (new_height - 1 + chopped_height);
|
| media::ConvertRGB24ToYUV(rgb_src,
|
| yplane,
|
| uplane,
|
| @@ -374,18 +403,22 @@ void VideoCaptureController::VideoCaptureDeviceClient::OnIncomingCapturedFrame(
|
| destination_height = destination_width;
|
| }
|
| }
|
| - libyuv::ConvertToI420(
|
| - data, length,
|
| - yplane, yplane_stride,
|
| - uplane, uv_plane_stride,
|
| - vplane, uv_plane_stride,
|
| - crop_x, crop_y,
|
| - new_width + chopped_width,
|
| - new_height * (flip_vert ^ flip_horiz ? -1 : 1),
|
| - destination_width,
|
| - destination_height,
|
| - rotation_mode,
|
| - origin_colorspace);
|
| + libyuv::ConvertToI420(data,
|
| + length,
|
| + yplane,
|
| + yplane_stride,
|
| + uplane,
|
| + uv_plane_stride,
|
| + vplane,
|
| + uv_plane_stride,
|
| + crop_x,
|
| + crop_y,
|
| + new_width + chopped_width,
|
| + new_height * (flip_vert ^ flip_horiz ? -1 : 1),
|
| + destination_width,
|
| + destination_height,
|
| + rotation_mode,
|
| + origin_colorspace);
|
| }
|
| #else
|
| // Libyuv is not linked in for Android WebView builds, but video capture is
|
| @@ -396,30 +429,35 @@ 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_,
|
| + buffer,
|
| + dimensions,
|
| + frame_info.frame_rate,
|
| + timestamp));
|
| }
|
|
|
| -void
|
| -VideoCaptureController::VideoCaptureDeviceClient::OnIncomingCapturedVideoFrame(
|
| - const scoped_refptr<media::VideoFrame>& frame,
|
| +void VideoCaptureController::VideoCaptureDeviceClient::OnIncomingCapturedBuffer(
|
| + const scoped_refptr<Buffer>& buffer,
|
| + media::VideoFrame::Format format,
|
| + const gfx::Size& dimensions,
|
| base::Time timestamp,
|
| int frame_rate) {
|
| - // 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_rate, timestamp));
|
| - return;
|
| - }
|
| + // The capture pipeline expects I420 for now.
|
| + DCHECK_EQ(format, media::VideoFrame::I420)
|
| + << "Non-I420 output buffer returned";
|
|
|
| - NOTREACHED() << "Frames should always belong to the buffer pool.";
|
| + BrowserThread::PostTask(
|
| + BrowserThread::IO,
|
| + FROM_HERE,
|
| + base::Bind(
|
| + &VideoCaptureController::DoIncomingCapturedI420BufferOnIOThread,
|
| + controller_,
|
| + buffer,
|
| + dimensions,
|
| + frame_rate,
|
| + timestamp));
|
| }
|
|
|
| void VideoCaptureController::VideoCaptureDeviceClient::OnError() {
|
| @@ -428,20 +466,49 @@ void VideoCaptureController::VideoCaptureDeviceClient::OnError() {
|
| base::Bind(&VideoCaptureController::DoErrorOnIOThread, controller_));
|
| }
|
|
|
| -scoped_refptr<media::VideoFrame>
|
| -VideoCaptureController::VideoCaptureDeviceClient::DoReserveI420VideoFrame(
|
| - const gfx::Size& size,
|
| +scoped_refptr<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 NULL;
|
| + void* data;
|
| + size_t size;
|
| + buffer_pool_->GetBufferInfo(buffer_id, &data, &size);
|
| +
|
| + scoped_refptr<media::VideoCaptureDevice::Client::Buffer> output_buffer(
|
| + new PoolBuffer(buffer_pool_, buffer_id, data, size));
|
| +
|
| 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 a 90/270 rotation is required, letterboxing will be required. If the
|
| + // returned frame has not been rotated before, then the letterbox borders will
|
| + // not yet have been cleared and we should clear them now.
|
| + if ((rotation % 180) == 0) {
|
| + rotated_buffers_.erase(buffer_id);
|
| + } else {
|
| + if (rotated_buffers_.insert(buffer_id).second)
|
| + memset(output_buffer->data(), 0, output_buffer->size());
|
| + }
|
| +
|
| + return output_buffer;
|
| }
|
|
|
| VideoCaptureController::~VideoCaptureController() {
|
| @@ -449,22 +516,17 @@ VideoCaptureController::~VideoCaptureController() {
|
| controller_clients_.end());
|
| }
|
|
|
| -void VideoCaptureController::DoIncomingCapturedFrameOnIOThread(
|
| - const scoped_refptr<media::VideoFrame>& reserved_frame,
|
| +void VideoCaptureController::DoIncomingCapturedI420BufferOnIOThread(
|
| + scoped_refptr<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());
|
| - if (buffer_id < 0) {
|
| - NOTREACHED();
|
| - return;
|
| - }
|
| + DCHECK_NE(buffer->id(), VideoCaptureBufferPool::kInvalidId);
|
|
|
| media::VideoCaptureFormat frame_format(
|
| - reserved_frame->coded_size().width(),
|
| - reserved_frame->coded_size().height(),
|
| + dimensions.width(),
|
| + dimensions.height(),
|
| frame_rate,
|
| media::VariableResolutionVideoCaptureDevice);
|
|
|
| @@ -476,28 +538,25 @@ void VideoCaptureController::DoIncomingCapturedFrameOnIOThread(
|
| if (client->session_closed)
|
| continue;
|
|
|
| - bool is_new_buffer = client->known_buffers.insert(buffer_id).second;
|
| + bool is_new_buffer = client->known_buffers.insert(buffer->id()).second;
|
| if (is_new_buffer) {
|
| // On the first use of a buffer on a client, share the memory handle.
|
| size_t memory_size = 0;
|
| base::SharedMemoryHandle remote_handle = buffer_pool_->ShareToProcess(
|
| - buffer_id, client->render_process_handle, &memory_size);
|
| - client->event_handler->OnBufferCreated(client->controller_id,
|
| - remote_handle,
|
| - memory_size,
|
| - buffer_id);
|
| + buffer->id(), client->render_process_handle, &memory_size);
|
| + client->event_handler->OnBufferCreated(
|
| + client->controller_id, remote_handle, memory_size, buffer->id());
|
| }
|
|
|
| - client->event_handler->OnBufferReady(client->controller_id,
|
| - buffer_id, timestamp,
|
| - frame_format);
|
| - bool inserted = client->active_buffers.insert(buffer_id).second;
|
| - DCHECK(inserted) << "Unexpected duplicate buffer: " << buffer_id;
|
| + client->event_handler->OnBufferReady(
|
| + client->controller_id, buffer->id(), timestamp, frame_format);
|
| + bool inserted = client->active_buffers.insert(buffer->id()).second;
|
| + DCHECK(inserted) << "Unexpected duplicate buffer: " << buffer->id();
|
| count++;
|
| }
|
| }
|
|
|
| - buffer_pool_->HoldForConsumers(buffer_id, count);
|
| + buffer_pool_->HoldForConsumers(buffer->id(), count);
|
| }
|
|
|
| void VideoCaptureController::DoErrorOnIOThread() {
|
|
|