Chromium Code Reviews| 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( |
|
Ami GONE FROM CHROMIUM
2013/06/18 18:35:55
fwiw here and elsewhere you can move and the prece
|
| + &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) { |
|
Ami GONE FROM CHROMIUM
2013/06/18 18:35:55
indent
|
| + 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. |
|
Ami GONE FROM CHROMIUM
2013/06/18 18:35:55
Is it important to support this "legacy" case for
|
| + 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_); |
|
Ami GONE FROM CHROMIUM
2013/06/18 18:35:55
did you mean to DCHECK(encoded_frame_info_availabl
|
| + 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. |