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. |