diff options
author | wjia@chromium.org <wjia@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-06-14 17:42:09 +0000 |
---|---|---|
committer | wjia@chromium.org <wjia@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-06-14 17:42:09 +0000 |
commit | c305d38efe2c3d1328537e97676911e2aed20885 (patch) | |
tree | 73f2f77ef7e4952e0a35f56c5d7097899744ba1c /content | |
parent | bdf9d3684346fdfa99c49a8f43a294b9e63b2e95 (diff) | |
download | chromium_src-c305d38efe2c3d1328537e97676911e2aed20885.zip chromium_src-c305d38efe2c3d1328537e97676911e2aed20885.tar.gz chromium_src-c305d38efe2c3d1328537e97676911e2aed20885.tar.bz2 |
use SharedMemory for buffer sharing in video capture
BUG=none
TEST=try bots
Review URL: http://codereview.chromium.org/6995148
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@89020 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content')
12 files changed, 270 insertions, 142 deletions
diff --git a/content/browser/renderer_host/video_capture_controller.cc b/content/browser/renderer_host/video_capture_controller.cc index dce342d..c36232b 100644 --- a/content/browser/renderer_host/video_capture_controller.cc +++ b/content/browser/renderer_host/video_capture_controller.cc @@ -4,16 +4,11 @@ #include "content/browser/renderer_host/video_capture_controller.h" -#include "base/logging.h" #include "base/stl_util-inl.h" #include "content/browser/browser_thread.h" #include "content/browser/media_stream/video_capture_manager.h" #include "media/base/yuv_convert.h" -#if defined(OS_WIN) -#include "content/common/section_util_win.h" -#endif - // The number of TransportDIBs VideoCaptureController allocate. static const size_t kNoOfDIBS = 3; @@ -54,13 +49,13 @@ void VideoCaptureController::StopCapture(Task* stopped_task) { stopped_task)); } -void VideoCaptureController::ReturnTransportDIB(TransportDIB::Handle handle) { +void VideoCaptureController::ReturnBuffer(int buffer_id) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); bool ready_to_delete; { base::AutoLock lock(lock_); - free_dibs_.push_back(handle); + free_dibs_.push_back(buffer_id); ready_to_delete = (free_dibs_.size() == owned_dibs_.size()); } if (report_ready_to_delete_ && ready_to_delete) { @@ -75,16 +70,16 @@ void VideoCaptureController::ReturnTransportDIB(TransportDIB::Handle handle) { void VideoCaptureController::OnIncomingCapturedFrame(const uint8* data, int length, base::Time timestamp) { - TransportDIB::Handle handle; - TransportDIB* dib = NULL; + int buffer_id = 0; + base::SharedMemory* dib = NULL; // Check if there is a TransportDIB to fill. bool buffer_exist = false; { base::AutoLock lock(lock_); if (!report_ready_to_delete_ && free_dibs_.size() > 0) { - handle = free_dibs_.back(); - free_dibs_.pop_back(); - DIBMap::iterator it = owned_dibs_.find(handle); + buffer_id = free_dibs_.front(); + free_dibs_.pop_front(); + DIBMap::iterator it = owned_dibs_.find(buffer_id); if (it != owned_dibs_.end()) { dib = it->second; buffer_exist = true; @@ -96,16 +91,10 @@ void VideoCaptureController::OnIncomingCapturedFrame(const uint8* data, return; } - if (!dib->Map()) { - VLOG(1) << "OnIncomingCapturedFrame - Failed to map handle."; - base::AutoLock lock(lock_); - free_dibs_.push_back(handle); - return; - } uint8* target = static_cast<uint8*>(dib->memory()); - CHECK(dib->size() >= static_cast<size_t> (frame_info_.width * - frame_info_.height * 3) / - 2); + CHECK(dib->created_size() >= static_cast<size_t> (frame_info_.width * + frame_info_.height * 3) / + 2); // Do color conversion from the camera format to I420. switch (frame_info_.color) { @@ -160,7 +149,7 @@ void VideoCaptureController::OnIncomingCapturedFrame(const uint8* data, NOTREACHED(); } - event_handler_->OnBufferReady(id_, handle, timestamp); + event_handler_->OnBufferReady(id_, buffer_id, timestamp); } void VideoCaptureController::OnError() { @@ -172,24 +161,21 @@ void VideoCaptureController::OnFrameInfo( DCHECK(owned_dibs_.empty()); bool frames_created = true; const size_t needed_size = (info.width * info.height * 3) / 2; - for (size_t i = 0; i < kNoOfDIBS; ++i) { - TransportDIB* dib = TransportDIB::Create(needed_size, i); - if (!dib) { + for (size_t i = 1; i <= kNoOfDIBS; ++i) { + base::SharedMemory* shared_memory = new base::SharedMemory(); + if (!shared_memory->CreateAndMapAnonymous(needed_size)) { frames_created = false; break; } - // Lock needed since the buffers are used in OnIncomingFrame - // and we need to use it there in order to avoid memcpy of complete frames. + base::SharedMemoryHandle remote_handle; + shared_memory->ShareToProcess(render_handle_, &remote_handle); + base::AutoLock lock(lock_); -#if defined(OS_WIN) - // On Windows we need to get a handle the can be used in the render process. - TransportDIB::Handle handle = chrome::GetSectionForProcess( - dib->handle(), render_handle_, false); -#else - TransportDIB::Handle handle = dib->handle(); -#endif - owned_dibs_.insert(std::make_pair(handle, dib)); - free_dibs_.push_back(handle); + owned_dibs_.insert(std::make_pair(i, shared_memory)); + free_dibs_.push_back(i); + event_handler_->OnBufferCreated(id_, remote_handle, + static_cast<int>(needed_size), + static_cast<int>(i)); } frame_info_= info; @@ -197,8 +183,7 @@ void VideoCaptureController::OnFrameInfo( if (!frames_created) { event_handler_->OnError(id_); } - event_handler_->OnFrameInfo(id_, info.width, info.height, - info.frame_rate); + event_handler_->OnFrameInfo(id_, info.width, info.height, info.frame_rate); } /////////////////////////////////////////////////////////////////////////////// diff --git a/content/browser/renderer_host/video_capture_controller.h b/content/browser/renderer_host/video_capture_controller.h index 9eae8c7..4879492 100644 --- a/content/browser/renderer_host/video_capture_controller.h +++ b/content/browser/renderer_host/video_capture_controller.h @@ -50,9 +50,9 @@ class VideoCaptureController // device is stopped. void StopCapture(Task* stopped_task); - // Return a DIB previously given in + // Return a buffer previously given in // VideoCaptureControllerEventHandler::OnBufferReady. - void ReturnTransportDIB(TransportDIB::Handle handle); + void ReturnBuffer(int buffer_id); // Implement media::VideoCaptureDevice::EventHandler. virtual void OnIncomingCapturedFrame(const uint8* data, @@ -70,8 +70,8 @@ class VideoCaptureController // Handle to the render process that will receive the DIBs. base::ProcessHandle render_handle_; bool report_ready_to_delete_; - typedef std::list<TransportDIB::Handle> DIBHandleList; - typedef std::map<TransportDIB::Handle, TransportDIB*> DIBMap; + typedef std::list<int> DIBHandleList; + typedef std::map<int, base::SharedMemory*> DIBMap; // Free DIBS that can be filled with video frames. DIBHandleList free_dibs_; diff --git a/content/browser/renderer_host/video_capture_controller_event_handler.h b/content/browser/renderer_host/video_capture_controller_event_handler.h index 0467941..397e5ae 100644 --- a/content/browser/renderer_host/video_capture_controller_event_handler.h +++ b/content/browser/renderer_host/video_capture_controller_event_handler.h @@ -5,10 +5,8 @@ #ifndef CONTENT_BROWSER_RENDERER_HOST_VIDEO_CAPTURE_CONTROLLER_EVENT_HANDLER_H_ #define CONTENT_BROWSER_RENDERER_HOST_VIDEO_CAPTURE_CONTROLLER_EVENT_HANDLER_H_ -#include <map> - +#include "base/shared_memory.h" #include "base/time.h" -#include "ui/gfx/surface/transport_dib.h" // ID used for identifying an object of VideoCaptureController. struct VideoCaptureControllerID { @@ -25,12 +23,17 @@ struct VideoCaptureControllerID { // BufferReady, FrameInfo, Error, etc. class VideoCaptureControllerEventHandler { public: - // An Error have occurred in the VideoCaptureDevice. + // An Error has occurred in the VideoCaptureDevice. virtual void OnError(const VideoCaptureControllerID& id) = 0; - // An TransportDIB have been filled with I420 video. + // A buffer has been newly created. + virtual void OnBufferCreated(const VideoCaptureControllerID& id, + base::SharedMemoryHandle handle, + int length, int buffer_id) = 0; + + // A buffer has been filled with I420 video. virtual void OnBufferReady(const VideoCaptureControllerID& id, - TransportDIB::Handle handle, + int buffer_id, base::Time timestamp) = 0; // The frame resolution the VideoCaptureDevice capture video in. diff --git a/content/browser/renderer_host/video_capture_host.cc b/content/browser/renderer_host/video_capture_host.cc index 8f7fa4a..f4e4011 100644 --- a/content/browser/renderer_host/video_capture_host.cc +++ b/content/browser/renderer_host/video_capture_host.cc @@ -39,14 +39,26 @@ void VideoCaptureHost::OnError(const VideoCaptureControllerID& id) { id.device_id)); } +void VideoCaptureHost::OnBufferCreated( + const VideoCaptureControllerID& id, + base::SharedMemoryHandle handle, + int length, + int buffer_id) { + BrowserThread::PostTask( + BrowserThread::IO, FROM_HERE, + NewRunnableMethod(this, &VideoCaptureHost::DoSendNewBuffer, + id.routing_id, id.device_id, handle, length, + buffer_id)); +} + void VideoCaptureHost::OnBufferReady( const VideoCaptureControllerID& id, - TransportDIB::Handle handle, + int buffer_id, base::Time timestamp) { BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, NewRunnableMethod(this, &VideoCaptureHost::DoSendFilledBuffer, - id.routing_id, id.device_id, handle, timestamp)); + id.routing_id, id.device_id, buffer_id, timestamp)); } void VideoCaptureHost::OnFrameInfo(const VideoCaptureControllerID& id, @@ -66,13 +78,20 @@ void VideoCaptureHost::OnReadyToDelete(const VideoCaptureControllerID& id) { id)); } -void VideoCaptureHost::DoSendFilledBuffer(int32 routing_id, - int device_id, - TransportDIB::Handle handle, - base::Time timestamp) { +void VideoCaptureHost::DoSendNewBuffer( + int32 routing_id, int device_id, base::SharedMemoryHandle handle, + int length, int buffer_id) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + + Send(new VideoCaptureMsg_NewBuffer(routing_id, device_id, handle, + length, buffer_id)); +} + +void VideoCaptureHost::DoSendFilledBuffer( + int32 routing_id, int device_id, int buffer_id, base::Time timestamp) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - Send(new VideoCaptureMsg_BufferReady(routing_id, device_id, handle, + Send(new VideoCaptureMsg_BufferReady(routing_id, device_id, buffer_id, timestamp)); } @@ -158,16 +177,15 @@ void VideoCaptureHost::OnPauseCapture(const IPC::Message& msg, int device_id) { media::VideoCapture::kError)); } -void VideoCaptureHost::OnReceiveEmptyBuffer(const IPC::Message& msg, - int device_id, - TransportDIB::Handle handle) { +void VideoCaptureHost::OnReceiveEmptyBuffer( + const IPC::Message& msg, int device_id, int buffer_id) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); VideoCaptureControllerID controller_id(msg.routing_id(), device_id); EntryMap::iterator it = entries_.find(controller_id); if (it != entries_.end()) { scoped_refptr<VideoCaptureController> controller = it->second; - controller->ReturnTransportDIB(handle); + controller->ReturnBuffer(buffer_id); } } diff --git a/content/browser/renderer_host/video_capture_host.h b/content/browser/renderer_host/video_capture_host.h index d907944..d2f611f05 100644 --- a/content/browser/renderer_host/video_capture_host.h +++ b/content/browser/renderer_host/video_capture_host.h @@ -56,8 +56,11 @@ class VideoCaptureHost : public BrowserMessageFilter, // VideoCaptureControllerEventHandler implementation. virtual void OnError(const VideoCaptureControllerID& id); + virtual void OnBufferCreated(const VideoCaptureControllerID& id, + base::SharedMemoryHandle handle, + int length, int buffer_id); virtual void OnBufferReady(const VideoCaptureControllerID& id, - TransportDIB::Handle handle, + int buffer_id, base::Time timestamp); virtual void OnFrameInfo(const VideoCaptureControllerID& id, int width, @@ -90,17 +93,24 @@ class VideoCaptureHost : public BrowserMessageFilter, // referenced by |device_id|. void OnReceiveEmptyBuffer(const IPC::Message& msg, int device_id, - TransportDIB::Handle handle); + int buffer_id); // Called on the IO thread when VideoCaptureController have // reported that all DIBs have been returned. void DoDeleteVideoCaptureController(const VideoCaptureControllerID& id); + // Send a newly created buffer to the VideoCaptureMessageFilter. + void DoSendNewBuffer(int32 routing_id, + int device_id, + base::SharedMemoryHandle handle, + int length, + int buffer_id); + // Send a filled buffer to the VideoCaptureMessageFilter. void DoSendFilledBuffer(int32 routing_id, int device_id, - TransportDIB::Handle handle, + int buffer_id, base::Time timestamp); // Send a information about frame resolution and frame rate diff --git a/content/browser/renderer_host/video_capture_host_unittest.cc b/content/browser/renderer_host/video_capture_host_unittest.cc index 8751ec4..e9986ca 100644 --- a/content/browser/renderer_host/video_capture_host_unittest.cc +++ b/content/browser/renderer_host/video_capture_host_unittest.cc @@ -2,13 +2,14 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include <list> +#include <map> #include <string> #include "base/file_util.h" #include "base/memory/scoped_ptr.h" #include "base/message_loop.h" #include "base/process_util.h" +#include "base/stl_util-inl.h" #include "base/stringprintf.h" #include "content/browser/browser_thread.h" #include "content/browser/media_stream/video_capture_manager.h" @@ -70,11 +71,18 @@ class DumpVideo { class MockVideoCaptureHost : public VideoCaptureHost { public: MockVideoCaptureHost() : return_buffers_(false), dump_video_(false) {} - virtual ~MockVideoCaptureHost() {} + virtual ~MockVideoCaptureHost() { + STLDeleteContainerPairSecondPointers(filled_dib_.begin(), + filled_dib_.end()); + } // A list of mock methods. + MOCK_METHOD5(OnNewBufferCreated, + void(int routing_id, int device_id, + base::SharedMemoryHandle handle, + int length, int buffer_id)); MOCK_METHOD3(OnBufferFilled, - void(int routing_id, int device_id, TransportDIB::Handle)); + void(int routing_id, int device_id, int buffer_id)); MOCK_METHOD3(OnStateChanged, void(int routing_id, int device_id, media::VideoCapture::State state)); @@ -90,19 +98,21 @@ class MockVideoCaptureHost : public VideoCaptureHost { // Return Dibs we currently have received. void ReturnReceivedDibs(int device_id) { - TransportDIB::Handle handle = GetReceivedDib(); - while (TransportDIB::is_valid_handle(handle)) { + int handle = GetReceivedDib(); + while (handle) { IPC::Message msg; msg.set_routing_id(kRouteId); this->OnReceiveEmptyBuffer(msg, device_id, handle); handle = GetReceivedDib(); } } - TransportDIB::Handle GetReceivedDib() { + int GetReceivedDib() { if (filled_dib_.empty()) - return TransportDIB::DefaultHandleValue(); - TransportDIB::Handle h = filled_dib_.front(); - filled_dib_.pop_front(); + return 0; + std::map<int, base::SharedMemory*>::iterator it = filled_dib_.begin(); + int h = it->first; + delete it->second; + filled_dib_.erase(it); return h; } @@ -118,6 +128,7 @@ class MockVideoCaptureHost : public VideoCaptureHost { // we are the renderer. bool handled = true; IPC_BEGIN_MESSAGE_MAP(MockVideoCaptureHost, *message) + IPC_MESSAGE_HANDLER(VideoCaptureMsg_NewBuffer, OnNewBufferCreated) IPC_MESSAGE_HANDLER(VideoCaptureMsg_BufferReady, OnBufferFilled) IPC_MESSAGE_HANDLER(VideoCaptureMsg_StateChanged, OnStateChanged) IPC_MESSAGE_HANDLER(VideoCaptureMsg_DeviceInfo, OnDeviceInfo) @@ -130,19 +141,26 @@ class MockVideoCaptureHost : public VideoCaptureHost { } // These handler methods do minimal things and delegate to the mock methods. + void OnNewBufferCreated(const IPC::Message& msg, int device_id, + base::SharedMemoryHandle handle, + int length, int buffer_id) { + OnNewBufferCreated(msg.routing_id(), device_id, handle, length, buffer_id); + base::SharedMemory* dib = new base::SharedMemory(handle, false); + dib->Map(length); + filled_dib_[buffer_id] = dib; + } + void OnBufferFilled(const IPC::Message& msg, int device_id, - TransportDIB::Handle dib_handle) { + int buffer_id) { if (dump_video_) { - TransportDIB* dib = TransportDIB::Map(dib_handle); + base::SharedMemory* dib = filled_dib_[buffer_id]; ASSERT_TRUE(dib != NULL); dumper_.NewVideoFrame(dib->memory()); } - OnBufferFilled(msg.routing_id(), device_id, dib_handle); + OnBufferFilled(msg.routing_id(), device_id, buffer_id); if (return_buffers_) { - VideoCaptureHost::OnReceiveEmptyBuffer(msg, device_id, dib_handle); - } else { - filled_dib_.push_back(dib_handle); + VideoCaptureHost::OnReceiveEmptyBuffer(msg, device_id, buffer_id); } } @@ -159,7 +177,7 @@ class MockVideoCaptureHost : public VideoCaptureHost { OnDeviceInfo(msg.routing_id(), device_id); } - std::list<TransportDIB::Handle> filled_dib_; + std::map<int, base::SharedMemory*> filled_dib_; bool return_buffers_; bool dump_video_; DumpVideo dumper_; @@ -237,14 +255,19 @@ class VideoCaptureHostTest : public testing::Test { void StartCapture() { InSequence s; - // 1. First - get info about the new resolution + // 1. Newly created buffers will arrive. + EXPECT_CALL(*host_, OnNewBufferCreated(kRouteId, kDeviceId, _, _, _)) + .Times(AnyNumber()) + .WillRepeatedly(Return()); + + // 2. First - get info about the new resolution EXPECT_CALL(*host_, OnDeviceInfo(kRouteId, kDeviceId)); - // 2. Change state to started + // 3. Change state to started EXPECT_CALL(*host_, OnStateChanged(kRouteId, kDeviceId, media::VideoCapture::kStarted)); - // 3. First filled buffer will arrive. + // 4. First filled buffer will arrive. EXPECT_CALL(*host_, OnBufferFilled(kRouteId, kDeviceId, _)) .Times(AnyNumber()) .WillOnce(ExitMessageLoop(message_loop_.get())); diff --git a/content/common/video_capture_messages.h b/content/common/video_capture_messages.h index 67b714d..7b5b8d9 100644 --- a/content/common/video_capture_messages.h +++ b/content/common/video_capture_messages.h @@ -23,10 +23,17 @@ IPC_MESSAGE_ROUTED2(VideoCaptureMsg_StateChanged, int /* device id */, media::VideoCapture::State /* new state */) +// Tell the renderer process that a new buffer is allocated for video capture. +IPC_MESSAGE_ROUTED4(VideoCaptureMsg_NewBuffer, + int /* device id */, + base::SharedMemoryHandle /* handle */, + int /* length */, + int /* buffer_id */) + // Tell the renderer process that a buffer is available from video capture. IPC_MESSAGE_ROUTED3(VideoCaptureMsg_BufferReady, int /* device id */, - TransportDIB::Handle /* DIB */, + int /* buffer_id */, base::Time /* timestamp */) // Tell the renderer process the width, height and frame rate the camera use. @@ -51,4 +58,4 @@ IPC_MESSAGE_ROUTED1(VideoCaptureHostMsg_Stop, // device (routing_id, device_id) to fill up. IPC_MESSAGE_ROUTED2(VideoCaptureHostMsg_BufferReady, int /* device_id */, - TransportDIB::Handle /* handle */) + int /* buffer_id */) diff --git a/content/renderer/media/video_capture_impl.cc b/content/renderer/media/video_capture_impl.cc index aed3ef7..54ccded 100644 --- a/content/renderer/media/video_capture_impl.cc +++ b/content/renderer/media/video_capture_impl.cc @@ -4,11 +4,12 @@ #include "content/renderer/media/video_capture_impl.h" +#include "base/stl_util-inl.h" #include "content/common/child_process.h" #include "content/common/video_capture_messages.h" VideoCaptureImpl::DIBBuffer::DIBBuffer( - TransportDIB* d, media::VideoCapture::VideoFrameBuffer* ptr) + base::SharedMemory* d, media::VideoCapture::VideoFrameBuffer* ptr) : dib(d), mapped_memory(ptr) {} @@ -51,7 +52,10 @@ VideoCaptureImpl::VideoCaptureImpl( DCHECK(filter); } -VideoCaptureImpl::~VideoCaptureImpl() {} +VideoCaptureImpl::~VideoCaptureImpl() { + STLDeleteContainerPairSecondPointers(cached_dibs_.begin(), + cached_dibs_.end()); +} void VideoCaptureImpl::Init() { base::MessageLoopProxy* io_message_loop_proxy = @@ -127,8 +131,9 @@ void VideoCaptureImpl::StartCapture( (capability.width != width_ || capability.height != height_)) { new_width_ = capability.width; new_height_ = capability.height; - DLOG(INFO) << "StartCapture: Got master client with new resolution " - "during started, try to restart."; + DLOG(INFO) << "StartCapture: Got master client with new resolution (" + << new_width_ << ", " << new_height_ << ") " + << "during started, try to restart."; StopDevice(); } handler->OnStarted(this); @@ -139,7 +144,9 @@ void VideoCaptureImpl::StartCapture( if (capability.resolution_fixed || !pending_start()) { new_width_ = capability.width; new_height_ = capability.height; - DLOG(INFO) << "StartCapture: Got new resolution, already in stopping."; + DLOG(INFO) << "StartCapture: Got new resolution (" + << new_width_ << ", " << new_height_ << ") " + << ", already in stopping."; } handler->OnStarted(this); return; @@ -151,6 +158,8 @@ void VideoCaptureImpl::StartCapture( new_height_ = 0; width_ = capability.width; height_ = capability.height; + DLOG(INFO) << "StartCapture: resolution (" + << width_ << ", " << height_ << "). "; StartCaptureInternal(); } @@ -199,7 +208,9 @@ void VideoCaptureImpl::StopCapture(media::VideoCapture::EventHandler* handler) { if (maxw < width_ && maxh < height_) { new_width_ = maxw; new_height_ = maxh; - DLOG(INFO) << "StopCapture: New smaller resolution, stopping ..."; + DLOG(INFO) << "StopCapture: New smaller resolution (" + << new_width_ << ", " << new_height_ << ") " + << "), stopping ..."; StopDevice(); } return; @@ -208,7 +219,9 @@ void VideoCaptureImpl::StopCapture(media::VideoCapture::EventHandler* handler) { if (state_ == kStopping) { new_width_ = maxw; new_height_ = maxh; - DLOG(INFO) << "StopCapture: New resolution, during stopping."; + DLOG(INFO) << "StopCapture: New resolution (" + << new_width_ << ", " << new_height_ << ") " + << "), during stopping."; return; } } else { @@ -219,46 +232,54 @@ void VideoCaptureImpl::StopCapture(media::VideoCapture::EventHandler* handler) { } } -void VideoCaptureImpl::OnBufferReceived(TransportDIB::Handle handle, - base::Time timestamp) { +void VideoCaptureImpl::OnBufferCreated( + base::SharedMemoryHandle handle, + int length, int buffer_id) { + if (!ml_proxy_->BelongsToCurrentThread()) { + ml_proxy_->PostTask(FROM_HERE, + NewRunnableMethod(this, &VideoCaptureImpl::OnBufferCreated, + handle, length, buffer_id)); + return; + } + + media::VideoCapture::VideoFrameBuffer* buffer; + DCHECK(cached_dibs_.find(buffer_id) == cached_dibs_.end()); + + base::SharedMemory* dib = new base::SharedMemory(handle, false); + dib->Map(length); + buffer = new VideoFrameBuffer(); + buffer->memory_pointer = dib->memory(); + buffer->buffer_size = length; + buffer->width = width_; + buffer->height = height_; + + DIBBuffer* dib_buffer = new DIBBuffer(dib, buffer); + cached_dibs_[buffer_id] = dib_buffer; +} + +void VideoCaptureImpl::OnBufferReceived(int buffer_id, base::Time timestamp) { if (!ml_proxy_->BelongsToCurrentThread()) { ml_proxy_->PostTask(FROM_HERE, NewRunnableMethod(this, &VideoCaptureImpl::OnBufferReceived, - handle, timestamp)); + buffer_id, timestamp)); return; } if (state_ != kStarted) { - Send(new VideoCaptureHostMsg_BufferReady(0, device_id_, handle)); + Send(new VideoCaptureHostMsg_BufferReady(0, device_id_, buffer_id)); return; } media::VideoCapture::VideoFrameBuffer* buffer; - CachedDIB::iterator it; - for (it = cached_dibs_.begin(); it != cached_dibs_.end(); it++) { - if ((*it)->dib->handle() == handle) - break; - } - if (it == cached_dibs_.end()) { - TransportDIB* dib = TransportDIB::Map(handle); - buffer = new VideoFrameBuffer(); - buffer->memory_pointer = dib->memory(); - buffer->buffer_size = dib->size(); - buffer->width = width_; - buffer->height = height_; - - DIBBuffer* dib_buffer = new DIBBuffer(dib, buffer); - cached_dibs_.push_back(dib_buffer); - } else { - buffer = (*it)->mapped_memory; - } + DCHECK(cached_dibs_.find(buffer_id) != cached_dibs_.end()); + buffer = cached_dibs_[buffer_id]->mapped_memory; // TODO(wjia): handle buffer sharing with downstream modules. for (ClientInfo::iterator it = clients_.begin(); it != clients_.end(); it++) { it->first->OnBufferReady(this, buffer); } - Send(new VideoCaptureHostMsg_BufferReady(0, device_id_, handle)); + Send(new VideoCaptureHostMsg_BufferReady(0, device_id_, buffer_id)); } void VideoCaptureImpl::OnStateChanged( @@ -342,6 +363,9 @@ void VideoCaptureImpl::StopDevice() { state_ = kStopping; Send(new VideoCaptureHostMsg_Stop(0, device_id_)); width_ = height_ = 0; + STLDeleteContainerPairSecondPointers(cached_dibs_.begin(), + cached_dibs_.end()); + cached_dibs_.clear(); } } diff --git a/content/renderer/media/video_capture_impl.h b/content/renderer/media/video_capture_impl.h index fd4750c..2d5e49d 100644 --- a/content/renderer/media/video_capture_impl.h +++ b/content/renderer/media/video_capture_impl.h @@ -34,8 +34,9 @@ class VideoCaptureImpl virtual int CaptureFrameRate(); // VideoCaptureMessageFilter::Delegate interface. - virtual void OnBufferReceived(TransportDIB::Handle handle, - base::Time timestamp); + virtual void OnBufferCreated(base::SharedMemoryHandle handle, + int length, int buffer_id); + virtual void OnBufferReceived(int buffer_id, base::Time timestamp); virtual void OnStateChanged(const media::VideoCapture::State& state); virtual void OnDeviceInfoReceived( const media::VideoCaptureParams& device_info); @@ -57,10 +58,11 @@ class VideoCaptureImpl struct DIBBuffer { public: - DIBBuffer(TransportDIB* d, media::VideoCapture::VideoFrameBuffer* ptr); + DIBBuffer(base::SharedMemory* d, + media::VideoCapture::VideoFrameBuffer* ptr); ~DIBBuffer(); - TransportDIB* dib; + base::SharedMemory* dib; scoped_refptr<media::VideoCapture::VideoFrameBuffer> mapped_memory; }; @@ -84,7 +86,7 @@ class VideoCaptureImpl int device_id_; // Pool of DIBs. - typedef std::list<DIBBuffer*> CachedDIB; + typedef std::map<int, DIBBuffer*> CachedDIB; CachedDIB cached_dibs_; typedef std::map<media::VideoCapture::EventHandler*, VideoCaptureCapability> diff --git a/content/renderer/video_capture_message_filter.cc b/content/renderer/video_capture_message_filter.cc index 05ca8bb..bfb8d87 100644 --- a/content/renderer/video_capture_message_filter.cc +++ b/content/renderer/video_capture_message_filter.cc @@ -35,6 +35,7 @@ bool VideoCaptureMessageFilter::OnMessageReceived(const IPC::Message& message) { IPC_BEGIN_MESSAGE_MAP(VideoCaptureMessageFilter, message) IPC_MESSAGE_HANDLER(VideoCaptureMsg_BufferReady, OnBufferReceived) IPC_MESSAGE_HANDLER(VideoCaptureMsg_StateChanged, OnDeviceStateChanged) + IPC_MESSAGE_HANDLER(VideoCaptureMsg_NewBuffer, OnBufferCreated) IPC_MESSAGE_HANDLER(VideoCaptureMsg_DeviceInfo, OnDeviceInfoReceived) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() @@ -63,10 +64,33 @@ void VideoCaptureMessageFilter::OnChannelClosing() { channel_ = NULL; } +void VideoCaptureMessageFilter::OnBufferCreated(const IPC::Message& msg, + int device_id, + base::SharedMemoryHandle handle, + int length, + int buffer_id) { + Delegate* delegate = NULL; + if (delegates_.find(device_id) != delegates_.end()) + delegate = delegates_.find(device_id)->second; + + if (!delegate) { + DLOG(WARNING) << "OnBufferCreated: Got video frame buffer for a " + "non-existent or removed video capture."; + + // Send the buffer back to Host in case it's waiting for all buffers + // to be returned. + base::SharedMemory::CloseHandle(handle); + Send(new VideoCaptureHostMsg_BufferReady(0, device_id, buffer_id)); + return; + } + + delegate->OnBufferCreated(handle, length, buffer_id); +} + void VideoCaptureMessageFilter::OnBufferReceived(const IPC::Message& msg, - int device_id, - TransportDIB::Handle handle, - base::Time timestamp) { + int device_id, + int buffer_id, + base::Time timestamp) { Delegate* delegate = NULL; if (delegates_.find(device_id) != delegates_.end()) delegate = delegates_.find(device_id)->second; @@ -77,11 +101,11 @@ void VideoCaptureMessageFilter::OnBufferReceived(const IPC::Message& msg, // Send the buffer back to Host in case it's waiting for all buffers // to be returned. - Send(new VideoCaptureHostMsg_BufferReady(0, device_id, handle)); + Send(new VideoCaptureHostMsg_BufferReady(0, device_id, buffer_id)); return; } - delegate->OnBufferReceived(handle, timestamp); + delegate->OnBufferReceived(buffer_id, timestamp); } void VideoCaptureMessageFilter::OnDeviceStateChanged( @@ -143,4 +167,3 @@ void VideoCaptureMessageFilter::RemoveDelegate(Delegate* delegate) { } } } - diff --git a/content/renderer/video_capture_message_filter.h b/content/renderer/video_capture_message_filter.h index 7ca67be..8fb8d65 100644 --- a/content/renderer/video_capture_message_filter.h +++ b/content/renderer/video_capture_message_filter.h @@ -13,17 +13,20 @@ #include <map> #include "base/message_loop_proxy.h" +#include "base/shared_memory.h" #include "ipc/ipc_channel_proxy.h" #include "media/video/capture/video_capture.h" -#include "ui/gfx/surface/transport_dib.h" class VideoCaptureMessageFilter : public IPC::ChannelProxy::MessageFilter { public: class Delegate { public: + // Called when a video frame buffer is created in the browser process. + virtual void OnBufferCreated(base::SharedMemoryHandle handle, + int length, int buffer_id) = 0; + // Called when a video frame buffer is received from the browser process. - virtual void OnBufferReceived(TransportDIB::Handle handle, - base::Time timestamp) = 0; + virtual void OnBufferReceived(int buffer_id, base::Time timestamp) = 0; // Called when state of a video capture device has changed in the browser // process. @@ -66,10 +69,14 @@ class VideoCaptureMessageFilter : public IPC::ChannelProxy::MessageFilter { virtual void OnFilterRemoved(); virtual void OnChannelClosing(); + // Receive a newly created buffer from browser process. + void OnBufferCreated(const IPC::Message& msg, int device_id, + base::SharedMemoryHandle handle, + int length, int buffer_id); + // Receive a buffer from browser process. void OnBufferReceived(const IPC::Message& msg, int device_id, - TransportDIB::Handle handle, - base::Time timestamp); + int buffer_id, base::Time timestamp); // State of browser process' video capture device has changed. void OnDeviceStateChanged(int device_id, diff --git a/content/renderer/video_capture_message_filter_unittest.cc b/content/renderer/video_capture_message_filter_unittest.cc index 1d647db..99dbeba 100644 --- a/content/renderer/video_capture_message_filter_unittest.cc +++ b/content/renderer/video_capture_message_filter_unittest.cc @@ -3,6 +3,7 @@ // found in the LICENSE file. #include "base/message_loop.h" +#include "base/shared_memory.h" #include "content/common/video_capture_messages.h" #include "content/renderer/video_capture_message_filter.h" #include "testing/gtest/include/gtest/gtest.h" @@ -17,10 +18,16 @@ class MockVideoCaptureDelegate : public VideoCaptureMessageFilter::Delegate { device_id_ = 0; } - virtual void OnBufferReceived(TransportDIB::Handle handle, - base::Time timestamp) { - buffer_received_ = true; + virtual void OnBufferCreated(base::SharedMemoryHandle handle, + int length, int buffer_id) { + buffer_created_ = true; handle_ = handle; + } + + // Called when a video frame buffer is received from the browser process. + virtual void OnBufferReceived(int buffer_id, base::Time timestamp) { + buffer_received_ = true; + buffer_id_ = buffer_id; timestamp_ = timestamp; } @@ -42,8 +49,11 @@ class MockVideoCaptureDelegate : public VideoCaptureMessageFilter::Delegate { } void Reset() { + buffer_created_ = false; + handle_ = base::SharedMemory::NULLHandle(); + buffer_received_ = false; - handle_ = TransportDIB::DefaultHandleValue(); + buffer_id_ = -1; timestamp_ = base::Time(); state_changed_received_ = false; @@ -55,8 +65,11 @@ class MockVideoCaptureDelegate : public VideoCaptureMessageFilter::Delegate { params_.frame_per_second = 0; } + bool buffer_created() { return buffer_created_; } + base::SharedMemoryHandle received_buffer_handle() { return handle_; } + bool buffer_received() { return buffer_received_; } - TransportDIB::Handle received_buffer_handle() { return handle_; } + int received_buffer_id() { return buffer_id_; } base::Time received_buffer_ts() { return timestamp_; } bool state_changed_received() { return state_changed_received_; } @@ -69,8 +82,11 @@ class MockVideoCaptureDelegate : public VideoCaptureMessageFilter::Delegate { int32 device_id() { return device_id_; } private: + bool buffer_created_; + base::SharedMemoryHandle handle_; + bool buffer_received_; - TransportDIB::Handle handle_; + int buffer_id_; base::Time timestamp_; bool state_changed_received_; @@ -107,19 +123,29 @@ TEST(VideoCaptureMessageFilterTest, Basic) { EXPECT_TRUE(media::VideoCapture::kStarted == delegate.state()); delegate.Reset(); + // VideoCaptureMsg_NewBuffer + const base::SharedMemoryHandle handle = +#if defined(OS_WIN) + reinterpret_cast<base::SharedMemoryHandle>(10); +#else + base::SharedMemoryHandle(10, true); +#endif + EXPECT_FALSE(delegate.buffer_created()); + filter->OnMessageReceived(VideoCaptureMsg_NewBuffer( + kRouteId, delegate.device_id(), handle, 1, 1)); + EXPECT_TRUE(delegate.buffer_created()); + EXPECT_EQ(handle, delegate.received_buffer_handle()); + delegate.Reset(); + // VideoCaptureMsg_BufferReady - const TransportDIB::Handle handle = TransportDIB::GetFakeHandleForTest(); + int buffer_id = 1; base::Time timestamp = base::Time::FromInternalValue(1); EXPECT_FALSE(delegate.buffer_received()); filter->OnMessageReceived(VideoCaptureMsg_BufferReady( - kRouteId, delegate.device_id(), handle, timestamp)); + kRouteId, delegate.device_id(), buffer_id, timestamp)); EXPECT_TRUE(delegate.buffer_received()); -#if defined(OS_MACOSX) - EXPECT_EQ(handle.fd, delegate.received_buffer_handle().fd); -#else - EXPECT_EQ(handle, delegate.received_buffer_handle()); -#endif // defined(OS_MACOSX) + EXPECT_EQ(buffer_id, delegate.received_buffer_id()); EXPECT_TRUE(timestamp == delegate.received_buffer_ts()); delegate.Reset(); |