| 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 9b1196285f7ef57668008ccd2771df93462f9e51..4af1b1ae09a75429ee498d64c4d3bc4e144502d9 100644
|
| --- a/content/browser/renderer_host/media/video_capture_controller.cc
|
| +++ b/content/browser/renderer_host/media/video_capture_controller.cc
|
| @@ -12,6 +12,7 @@
|
| #include "content/browser/renderer_host/media/media_stream_manager.h"
|
| #include "content/browser/renderer_host/media/video_capture_manager.h"
|
| #include "content/public/browser/browser_thread.h"
|
| +#include "media/base/encoded_bitstream_buffer.h"
|
| #include "media/base/video_frame.h"
|
| #include "media/base/video_util.h"
|
| #include "media/base/yuv_convert.h"
|
| @@ -86,6 +87,7 @@ VideoCaptureController::VideoCaptureController(
|
| : chopped_width_(0),
|
| chopped_height_(0),
|
| frame_info_available_(false),
|
| + encoded_frame_info_available_(false),
|
| video_capture_manager_(video_capture_manager),
|
| device_in_use_(false),
|
| state_(VIDEO_CAPTURE_STATE_STOPPED) {
|
| @@ -129,6 +131,7 @@ void VideoCaptureController::StartCapture(
|
| video_capture_manager_->Stop(current_params_.session_id,
|
| base::Bind(&VideoCaptureController::OnDeviceStopped, this));
|
| frame_info_available_ = false;
|
| + encoded_frame_info_available_ = false;
|
| state_ = VIDEO_CAPTURE_STATE_STOPPING;
|
| pending_clients_.push_back(client);
|
| return;
|
| @@ -137,7 +140,7 @@ void VideoCaptureController::StartCapture(
|
|
|
| // This client's resolution is no larger than what's currently requested.
|
| // When frame_info has been returned by device, send them to client.
|
| - if (frame_info_available_) {
|
| + if (frame_info_available_ || encoded_frame_info_available_) {
|
| SendFrameInfoAndBuffers(client);
|
| }
|
| controller_clients_.push_back(client);
|
| @@ -199,6 +202,7 @@ void VideoCaptureController::StopCapture(
|
| video_capture_manager_->Stop(session_id,
|
| base::Bind(&VideoCaptureController::OnDeviceStopped, this));
|
| frame_info_available_ = false;
|
| + encoded_frame_info_available_ = false;
|
| state_ = VIDEO_CAPTURE_STATE_STOPPING;
|
| }
|
| }
|
| @@ -245,12 +249,12 @@ void VideoCaptureController::ReturnBuffer(
|
| }
|
| }
|
|
|
| -scoped_refptr<media::VideoFrame> VideoCaptureController::ReserveOutputBuffer() {
|
| - base::AutoLock lock(buffer_pool_lock_);
|
| - if (!buffer_pool_.get())
|
| - return NULL;
|
| - return ReserveI420VideoFrame(buffer_pool_, gfx::Size(frame_info_.width,
|
| - frame_info_.height));
|
| +void VideoCaptureController::TryConfigureEncodedBitstream(
|
| + const media::RuntimeVideoEncodingParameters& params) {
|
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
|
| + video_capture_manager_->TryConfigureEncodedBitstream(
|
| + current_params_.session_id,
|
| + params);
|
| }
|
|
|
| // Implements VideoCaptureDevice::EventHandler.
|
| @@ -357,8 +361,11 @@ void VideoCaptureController::OnIncomingCapturedFrame(
|
|
|
| BrowserThread::PostTask(BrowserThread::IO,
|
| FROM_HERE,
|
| - base::Bind(&VideoCaptureController::DoIncomingCapturedFrameOnIOThread,
|
| - this, dst, timestamp));
|
| + base::Bind(
|
| + &VideoCaptureController::DoIncomingCapturedVideoFrameOnIOThread,
|
| + this,
|
| + dst,
|
| + timestamp));
|
| }
|
|
|
| // OnIncomingCapturedVideoFrame is called the thread running the capture device.
|
| @@ -379,8 +386,11 @@ void VideoCaptureController::OnIncomingCapturedVideoFrame(
|
| frame->shared_memory_handle()) >= 0) {
|
| BrowserThread::PostTask(BrowserThread::IO,
|
| FROM_HERE,
|
| - base::Bind(&VideoCaptureController::DoIncomingCapturedFrameOnIOThread,
|
| - this, frame, timestamp));
|
| + base::Bind(
|
| + &VideoCaptureController::DoIncomingCapturedVideoFrameOnIOThread,
|
| + this,
|
| + frame,
|
| + timestamp));
|
| return;
|
| }
|
| // Otherwise, this is a frame that belongs to the caller, and we must copy
|
| @@ -475,8 +485,58 @@ void VideoCaptureController::OnIncomingCapturedVideoFrame(
|
|
|
| BrowserThread::PostTask(BrowserThread::IO,
|
| FROM_HERE,
|
| - base::Bind(&VideoCaptureController::DoIncomingCapturedFrameOnIOThread,
|
| - this, target, timestamp));
|
| + base::Bind(
|
| + &VideoCaptureController::DoIncomingCapturedVideoFrameOnIOThread,
|
| + this,
|
| + target,
|
| + timestamp));
|
| +}
|
| +
|
| +void VideoCaptureController::OnIncomingCapturedEncodedBitstreamBuffer(
|
| + const scoped_refptr<media::EncodedBitstreamBuffer>& buffer,
|
| + size_t data_size,
|
| + base::Time timestamp) {
|
| +
|
| + scoped_refptr<media::EncodedBitstreamBuffer> target;
|
| + {
|
| + base::AutoLock lock(buffer_pool_lock_);
|
| + if (!buffer_pool_.get())
|
| + return;
|
| + // 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(
|
| + buffer->shared_memory_handle()) >= 0) {
|
| + BrowserThread::PostTask(BrowserThread::IO,
|
| + FROM_HERE,
|
| + base::Bind(
|
| + &VideoCaptureController::
|
| + DoIncomingCapturedEncodedBitstreamBufferOnIOThread,
|
| + this,
|
| + buffer,
|
| + data_size,
|
| + timestamp));
|
| + return;
|
| + }
|
| + // Otherwise, this is a frame that belongs to the caller, and we must copy
|
| + // it to a frame from the buffer pool.
|
| + target = ReserveOutputEncodedBitstreamBuffer();
|
| + }
|
| +
|
| + if (!target.get())
|
| + return;
|
| + if (data_size > target->size())
|
| + return;
|
| + memcpy(buffer_pool_->GetMemory(target->buffer_id()),
|
| + buffer->buffer(), data_size);
|
| + BrowserThread::PostTask(BrowserThread::IO,
|
| + FROM_HERE,
|
| + base::Bind(
|
| + &VideoCaptureController::
|
| + DoIncomingCapturedEncodedBitstreamBufferOnIOThread,
|
| + this,
|
| + target,
|
| + data_size,
|
| + timestamp));
|
| }
|
|
|
| void VideoCaptureController::OnError() {
|
| @@ -501,45 +561,47 @@ void VideoCaptureController::OnFrameInfo(
|
| } else {
|
| chopped_height_ = 0;
|
| }
|
| - BrowserThread::PostTask(BrowserThread::IO,
|
| +
|
| + BrowserThread::PostTask(
|
| + BrowserThread::IO,
|
| FROM_HERE,
|
| - base::Bind(&VideoCaptureController::DoFrameInfoOnIOThread, this));
|
| + base::Bind(&VideoCaptureController::DoFrameInfoOnIOThread, this, false));
|
| }
|
|
|
| -// static
|
| -scoped_refptr<media::VideoFrame> VideoCaptureController::ReserveI420VideoFrame(
|
| - VideoCaptureBufferPool* buffer_pool, const gfx::Size& size) {
|
| - if ((size_t)(size.GetArea() * 3 / 2) > buffer_pool->GetMemorySize())
|
| - return NULL;
|
| +void VideoCaptureController::OnEncodedFrameInfo(
|
| + const media::VideoEncodingParameters& encoded_info) {
|
| + encoded_frame_info_ = encoded_info;
|
|
|
| - int buffer_id = buffer_pool->ReserveForProducer();
|
| - if (buffer_id < 0)
|
| - return NULL;
|
| + BrowserThread::PostTask(
|
| + BrowserThread::IO,
|
| + FROM_HERE,
|
| + base::Bind(&VideoCaptureController::DoFrameInfoOnIOThread, this, true));
|
| +}
|
|
|
| - base::Closure disposal_handler = base::Bind(
|
| - &VideoCaptureBufferPool::RelinquishProducerReservation,
|
| - buffer_pool,
|
| - buffer_id);
|
| +void VideoCaptureController::OnBitstreamConfigChanged(
|
| + const media::RuntimeVideoEncodingParameters& params) {
|
| + BrowserThread::PostTask(BrowserThread::IO,
|
| + FROM_HERE,
|
| + base::Bind(&VideoCaptureController::DoBitstreamConfigChangedOnIOThread,
|
| + this,
|
| + params));
|
| +}
|
|
|
| - // Wrap the buffer in a VideoFrame container.
|
| - uint8* base_ptr = static_cast<uint8*>(buffer_pool->GetMemory(buffer_id));
|
| - size_t u_offset = size.GetArea();
|
| - size_t v_offset = u_offset + u_offset / 4;
|
| - scoped_refptr<media::VideoFrame> frame =
|
| - media::VideoFrame::WrapExternalYuvData(
|
| - buffer_pool->GetHandle(buffer_id),
|
| - media::VideoFrame::YV12, // Actually it's I420, but equivalent here.
|
| - size, gfx::Rect(size), size,
|
| - size.width(), // y stride
|
| - size.width() / 2, // u stride
|
| - size.width() / 2, // v stride
|
| - base_ptr, // y address
|
| - base_ptr + u_offset, // u address
|
| - base_ptr + v_offset, // v address
|
| - base::TimeDelta(), // timestamp (unused).
|
| - disposal_handler);
|
| +scoped_refptr<media::VideoFrame>
|
| +VideoCaptureController::ReserveOutputVideoFrame() {
|
| + base::AutoLock lock(buffer_pool_lock_);
|
| + if (!buffer_pool_.get())
|
| + return NULL;
|
| + return ReserveI420VideoFrame(buffer_pool_, gfx::Size(frame_info_.width,
|
| + frame_info_.height));
|
| +}
|
|
|
| - return frame;
|
| +scoped_refptr<media::EncodedBitstreamBuffer>
|
| +VideoCaptureController::ReserveOutputEncodedBitstreamBuffer() {
|
| + base::AutoLock lock(buffer_pool_lock_);
|
| + if (!buffer_pool_.get())
|
| + return NULL;
|
| + return ReserveEncodedBitstreamBuffer(buffer_pool_);
|
| }
|
|
|
| VideoCaptureController::~VideoCaptureController() {
|
| @@ -557,16 +619,35 @@ void VideoCaptureController::OnDeviceStopped() {
|
| base::Bind(&VideoCaptureController::DoDeviceStoppedOnIOThread, this));
|
| }
|
|
|
| -void VideoCaptureController::DoIncomingCapturedFrameOnIOThread(
|
| - const scoped_refptr<media::VideoFrame>& reserved_frame,
|
| +void VideoCaptureController::DoIncomingCapturedVideoFrameOnIOThread(
|
| + const scoped_refptr<media::VideoFrame>& frame,
|
| + base::Time timestamp) {
|
| + DoIncomingCapturedSharedMemoryOnIOThread(
|
| + frame->shared_memory_handle(),
|
| + frame->coded_size().GetArea() * 3 / 2,
|
| + timestamp);
|
| +}
|
| +
|
| +void VideoCaptureController::DoIncomingCapturedEncodedBitstreamBufferOnIOThread(
|
| + const scoped_refptr<media::EncodedBitstreamBuffer>& buffer,
|
| + size_t data_size,
|
| + base::Time timestamp) {
|
| + DoIncomingCapturedSharedMemoryOnIOThread(
|
| + buffer->shared_memory_handle(),
|
| + data_size,
|
| + timestamp);
|
| +}
|
| +
|
| +void VideoCaptureController::DoIncomingCapturedSharedMemoryOnIOThread(
|
| + base::SharedMemoryHandle reserved_handle,
|
| + size_t data_size,
|
| base::Time timestamp) {
|
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
|
|
|
| if (!buffer_pool_.get())
|
| return;
|
|
|
| - int buffer_id = buffer_pool_->RecognizeReservedBuffer(
|
| - reserved_frame->shared_memory_handle());
|
| + int buffer_id = buffer_pool_->RecognizeReservedBuffer(reserved_handle);
|
| if (buffer_id < 0) {
|
| NOTREACHED();
|
| return;
|
| @@ -580,7 +661,8 @@ void VideoCaptureController::DoIncomingCapturedFrameOnIOThread(
|
| continue;
|
|
|
| (*client_it)->event_handler->OnBufferReady((*client_it)->controller_id,
|
| - buffer_id, timestamp);
|
| + buffer_id, data_size,
|
| + timestamp, false);
|
| (*client_it)->buffers.insert(buffer_id);
|
| count++;
|
| }
|
| @@ -589,7 +671,7 @@ void VideoCaptureController::DoIncomingCapturedFrameOnIOThread(
|
| buffer_pool_->HoldForConsumers(buffer_id, count);
|
| }
|
|
|
| -void VideoCaptureController::DoFrameInfoOnIOThread() {
|
| +void VideoCaptureController::DoFrameInfoOnIOThread(bool encoded) {
|
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
|
| DCHECK(!buffer_pool_.get())
|
| << "Device is restarted without releasing shared memory.";
|
| @@ -598,9 +680,14 @@ void VideoCaptureController::DoFrameInfoOnIOThread() {
|
| if (state_ != VIDEO_CAPTURE_STATE_STARTED)
|
| return;
|
|
|
| - scoped_refptr<VideoCaptureBufferPool> buffer_pool =
|
| - new VideoCaptureBufferPool(frame_info_.width * frame_info_.height * 3 / 2,
|
| - kNoOfBuffers);
|
| + scoped_refptr<VideoCaptureBufferPool> buffer_pool;
|
| + if (encoded) {
|
| + buffer_pool = new VideoCaptureBufferPool(
|
| + encoded_frame_info_.runtime_params.max_bitrate, kNoOfBuffers);
|
| + } else {
|
| + buffer_pool = new VideoCaptureBufferPool(
|
| + frame_info_.width * frame_info_.height * 3 / 2, kNoOfBuffers);
|
| + }
|
|
|
| // Check whether all buffers were created successfully.
|
| if (!buffer_pool->Allocate()) {
|
| @@ -616,7 +703,10 @@ void VideoCaptureController::DoFrameInfoOnIOThread() {
|
| base::AutoLock lock(buffer_pool_lock_);
|
| buffer_pool_ = buffer_pool;
|
| }
|
| - frame_info_available_ = true;
|
| + if (encoded)
|
| + encoded_frame_info_available_ = true;
|
| + else
|
| + frame_info_available_ = true;
|
|
|
| for (ControllerClients::iterator client_it = controller_clients_.begin();
|
| client_it != controller_clients_.end(); ++client_it) {
|
| @@ -624,6 +714,17 @@ void VideoCaptureController::DoFrameInfoOnIOThread() {
|
| }
|
| }
|
|
|
| +void VideoCaptureController::DoBitstreamConfigChangedOnIOThread(
|
| + const media::RuntimeVideoEncodingParameters& params) {
|
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
|
| + for (ControllerClients::iterator client_it = controller_clients_.begin();
|
| + client_it != controller_clients_.end(); ++client_it) {
|
| + (*client_it)->event_handler->OnBitstreamConfigChanged(
|
| + (*client_it)->controller_id,
|
| + params);
|
| + }
|
| +}
|
| +
|
| void VideoCaptureController::DoErrorOnIOThread() {
|
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
|
| state_ = VIDEO_CAPTURE_STATE_ERROR;
|
| @@ -648,21 +749,31 @@ void VideoCaptureController::DoDeviceStoppedOnIOThread() {
|
|
|
| void VideoCaptureController::SendFrameInfoAndBuffers(ControllerClient* client) {
|
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
|
| - DCHECK(frame_info_available_);
|
| - client->event_handler->OnFrameInfo(client->controller_id,
|
| - frame_info_.width, frame_info_.height,
|
| - frame_info_.frame_rate);
|
| - if (!buffer_pool_.get())
|
| - return;
|
| + DCHECK(frame_info_available_ || encoded_frame_info_available_);
|
|
|
| + std::vector<base::SharedMemoryHandle> handles;
|
| for (int buffer_id = 0; buffer_id < buffer_pool_->count(); ++buffer_id) {
|
| base::SharedMemoryHandle remote_handle =
|
| buffer_pool_->ShareToProcess(buffer_id, client->render_process_handle);
|
| -
|
| - client->event_handler->OnBufferCreated(client->controller_id,
|
| - remote_handle,
|
| - buffer_pool_->GetMemorySize(),
|
| - buffer_id);
|
| + handles.push_back(remote_handle);
|
| + }
|
| + if (frame_info_available_) {
|
| + DCHECK(!encoded_frame_info_available_);
|
| + media::VideoCaptureParams params;
|
| + params.width = frame_info_.width;
|
| + params.height = frame_info_.height;
|
| + params.frame_per_second = frame_info_.frame_rate;
|
| + params.session_id = client->parameters.session_id;
|
| + client->event_handler->OnFrameInfo(client->controller_id,
|
| + params,
|
| + handles,
|
| + buffer_pool_->GetMemorySize());
|
| + } else {
|
| + DCHECK(!frame_info_available_);
|
| + client->event_handler->OnEncodedFrameInfo(client->controller_id,
|
| + encoded_frame_info_,
|
| + handles,
|
| + buffer_pool_->GetMemorySize());
|
| }
|
| }
|
|
|
| @@ -694,6 +805,69 @@ VideoCaptureController::FindClient(
|
| return NULL;
|
| }
|
|
|
| +// static
|
| +scoped_refptr<media::VideoFrame> VideoCaptureController::ReserveI420VideoFrame(
|
| + VideoCaptureBufferPool* buffer_pool, const gfx::Size& size) {
|
| + if ((size_t)(size.GetArea() * 3 / 2) > buffer_pool->GetMemorySize())
|
| + return NULL;
|
| +
|
| + int buffer_id = buffer_pool->ReserveForProducer();
|
| + if (buffer_id < 0)
|
| + return NULL;
|
| +
|
| + base::Closure disposal_handler = base::Bind(
|
| + &VideoCaptureBufferPool::RelinquishProducerReservation,
|
| + buffer_pool,
|
| + buffer_id);
|
| +
|
| + // Wrap the buffer in a VideoFrame container.
|
| + uint8* base_ptr = static_cast<uint8*>(buffer_pool->GetMemory(buffer_id));
|
| + size_t u_offset = size.GetArea();
|
| + size_t v_offset = u_offset + u_offset / 4;
|
| + scoped_refptr<media::VideoFrame> frame =
|
| + media::VideoFrame::WrapExternalYuvData(
|
| + buffer_pool->GetHandle(buffer_id),
|
| + media::VideoFrame::YV12, // Actually it's I420, but equivalent here.
|
| + size, gfx::Rect(size), size,
|
| + size.width(), // y stride
|
| + size.width() / 2, // u stride
|
| + size.width() / 2, // v stride
|
| + base_ptr, // y address
|
| + base_ptr + u_offset, // u address
|
| + base_ptr + v_offset, // v address
|
| + base::TimeDelta(), // timestamp (unused).
|
| + disposal_handler);
|
| +
|
| + return frame;
|
| +}
|
| +
|
| +// static
|
| +scoped_refptr<media::EncodedBitstreamBuffer>
|
| +VideoCaptureController::ReserveEncodedBitstreamBuffer(
|
| + VideoCaptureBufferPool* buffer_pool) {
|
| + int buffer_id = buffer_pool->ReserveForProducer();
|
| + if (buffer_id < 0)
|
| + return NULL;
|
| +
|
| + base::Closure disposal_handler = base::Bind(
|
| + &VideoCaptureBufferPool::RelinquishProducerReservation,
|
| + buffer_pool,
|
| + buffer_id);
|
| +
|
| + // Wrap the buffer in a VideoFrame container.
|
| + media::BufferEncodingMetadata metadata;
|
| + metadata.key_frame = false;
|
| + scoped_refptr<media::EncodedBitstreamBuffer> frame =
|
| + new media::EncodedBitstreamBuffer(
|
| + buffer_id,
|
| + reinterpret_cast<uint8*>(buffer_pool->GetMemory(buffer_id)),
|
| + buffer_pool->GetMemorySize(),
|
| + buffer_pool->GetHandle(buffer_id),
|
| + metadata,
|
| + disposal_handler);
|
| + return frame;
|
| +}
|
| +
|
| // This function is called when all buffers have been returned to controller,
|
| // or when device is stopped. It decides whether the device needs to be
|
| // restarted.
|
|
|