Chromium Code Reviews| Index: webkit/plugins/ppapi/ppb_video_capture_impl.cc |
| diff --git a/webkit/plugins/ppapi/ppb_video_capture_impl.cc b/webkit/plugins/ppapi/ppb_video_capture_impl.cc |
| index f2cb26cd87ab95516792e47f40bc078db904a5e9..a628d8b819315b0f4590acabf27966b54861ca10 100644 |
| --- a/webkit/plugins/ppapi/ppb_video_capture_impl.cc |
| +++ b/webkit/plugins/ppapi/ppb_video_capture_impl.cc |
| @@ -1,4 +1,4 @@ |
| -// Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| +// Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| @@ -7,12 +7,15 @@ |
| #include <algorithm> |
| #include <string> |
| +#include "base/bind.h" |
| #include "base/logging.h" |
| +#include "base/memory/scoped_ptr.h" |
| #include "ppapi/c/dev/pp_video_capture_dev.h" |
| #include "ppapi/c/dev/ppb_video_capture_dev.h" |
| #include "ppapi/c/pp_completion_callback.h" |
| #include "ppapi/c/pp_errors.h" |
| #include "ppapi/shared_impl/ppapi_globals.h" |
| +#include "ppapi/shared_impl/ppb_device_ref_shared.h" |
| #include "ppapi/shared_impl/resource_tracker.h" |
| #include "ppapi/thunk/enter.h" |
| #include "webkit/plugins/ppapi/common.h" |
| @@ -21,10 +24,12 @@ |
| #include "webkit/plugins/ppapi/ppb_buffer_impl.h" |
| #include "webkit/plugins/ppapi/resource_helper.h" |
| +using ppapi::DeviceRefData; |
| using ppapi::PpapiGlobals; |
| using ppapi::thunk::EnterResourceNoLock; |
| using ppapi::thunk::PPB_Buffer_API; |
| using ppapi::thunk::PPB_VideoCapture_API; |
| +using ppapi::TrackedCallback; |
| namespace { |
| @@ -41,14 +46,19 @@ PPB_VideoCapture_Impl::PPB_VideoCapture_Impl(PP_Instance instance) |
| buffer_count_hint_(0), |
| ppp_videocapture_(NULL), |
| status_(PP_VIDEO_CAPTURE_STATUS_STOPPED), |
| - is_dead_(false) { |
| + ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)), |
| + devices_(0), |
| + capability_() { |
| } |
| PPB_VideoCapture_Impl::~PPB_VideoCapture_Impl() { |
| + StopCapture(); |
| + DCHECK(buffers_.empty()); |
| + ClearCachedDeviceResourceArray(); |
| + DetachPlatformVideoCapture(); |
| } |
| bool PPB_VideoCapture_Impl::Init() { |
| - DCHECK(!is_dead_); |
| PluginInstance* instance = ResourceHelper::GetPluginInstance(this); |
| if (!instance) |
| return false; |
| @@ -57,59 +67,83 @@ bool PPB_VideoCapture_Impl::Init() { |
| if (!ppp_videocapture_) |
| return false; |
| - platform_video_capture_.reset( |
| - instance->delegate()->CreateVideoCapture(this)); |
| - return !!platform_video_capture_.get(); |
| + return true; |
| } |
| PPB_VideoCapture_API* PPB_VideoCapture_Impl::AsPPB_VideoCapture_API() { |
| return this; |
| } |
| -void PPB_VideoCapture_Impl::LastPluginRefWasDeleted() { |
| - if (platform_video_capture_.get()) |
| - StopCapture(); |
| - DCHECK(buffers_.empty()); |
| - ppp_videocapture_ = NULL; |
| - is_dead_ = true; |
| +int32_t PPB_VideoCapture_Impl::EnumerateDevices( |
| + PP_CompletionCallback callback) { |
| + if (!callback.func) |
| + return PP_ERROR_BLOCKS_MAIN_THREAD; |
| + if (TrackedCallback::IsPending(enumerate_devices_callback_)) |
| + return PP_ERROR_INPROGRESS; |
| - ::ppapi::Resource::LastPluginRefWasDeleted(); |
| + PluginInstance* instance = ResourceHelper::GetPluginInstance(this); |
| + if (!instance) |
| + return PP_ERROR_FAILED; |
| + |
| + enumerate_devices_callback_ = new TrackedCallback(this, callback); |
| + instance->delegate()->EnumerateDevices( |
| + PP_DEVICETYPE_DEV_VIDEOCAPTURE, |
| + base::Bind(&PPB_VideoCapture_Impl::OnEnumerateDevicesComplete, |
| + weak_ptr_factory_.GetWeakPtr())); |
| + return PP_OK_COMPLETIONPENDING; |
| +} |
| + |
| +PP_Resource PPB_VideoCapture_Impl::GetDevices() { |
| + if (devices_) |
| + PpapiGlobals::Get()->GetResourceTracker()->AddRefResource(devices_); |
| + return devices_; |
| } |
| int32_t PPB_VideoCapture_Impl::StartCapture( |
| + const std::string& device_id, |
| const PP_VideoCaptureDeviceInfo_Dev& requested_info, |
| uint32_t buffer_count) { |
| - DCHECK(!is_dead_); |
| switch (status_) { |
| case PP_VIDEO_CAPTURE_STATUS_STARTING: |
| case PP_VIDEO_CAPTURE_STATUS_STARTED: |
| case PP_VIDEO_CAPTURE_STATUS_PAUSED: |
| + case PP_VIDEO_CAPTURE_STATUS_STOPPING: |
| default: |
| return PP_ERROR_FAILED; |
| case PP_VIDEO_CAPTURE_STATUS_STOPPED: |
| - case PP_VIDEO_CAPTURE_STATUS_STOPPING: |
| break; |
| } |
| + |
| + PluginInstance* instance = ResourceHelper::GetPluginInstance(this); |
| + if (!instance) |
| + return PP_ERROR_FAILED; |
| + |
| DCHECK(buffers_.empty()); |
| // Clamp the buffer count to between 1 and |kMaxBuffers|. |
| buffer_count_hint_ = std::min(std::max(buffer_count, 1U), kMaxBuffers); |
| - media::VideoCapture::VideoCaptureCapability capability = { |
| - requested_info.width, |
| - requested_info.height, |
| - requested_info.frames_per_second, |
| - 0, // ignored. |
| - media::VideoFrame::I420, |
| - false, // ignored |
| - }; |
| + |
| + capability_.width = requested_info.width; |
| + capability_.height = requested_info.height; |
| + capability_.max_fps = requested_info.frames_per_second; |
| + capability_.expected_capture_delay = 0; // Ignored. |
| + capability_.raw_type = media::VideoFrame::I420; |
| + capability_.interlaced = false; // Ignored. |
|
wjia(left Chromium)
2012/01/27 06:13:09
is it possible Pepper client would call StartCaptu
yzshen1
2012/01/27 18:00:24
If the status_ is not PP_VIDEO_CAPTURE_STATUS_STOP
|
| + |
| status_ = PP_VIDEO_CAPTURE_STATUS_STARTING; |
| - AddRef(); // Balanced in |OnRemoved()|. |
| - platform_video_capture_->StartCapture(this, capability); |
| + |
| + DetachPlatformVideoCapture(); |
|
wjia(left Chromium)
2012/01/27 06:13:09
same question as above.
yzshen1
2012/01/27 18:00:24
Please see above.
On 2012/01/27 06:13:09, wjia wr
|
| + platform_video_capture_ = |
| + instance->delegate()->CreateVideoCapture(device_id, this); |
| + // If |device_id| is not empty, StartCapture() will be performed in the |
| + // OnInitialized() handler. |
| + if (device_id.empty()) |
| + platform_video_capture_->StartCapture(this, capability_); |
| + |
| return PP_OK; |
| } |
| int32_t PPB_VideoCapture_Impl::ReuseBuffer(uint32_t buffer) { |
| - DCHECK(!is_dead_); |
| if (buffer >= buffers_.size() || !buffers_[buffer].in_use) |
| return PP_ERROR_BADARGUMENT; |
| buffers_[buffer].in_use = false; |
| @@ -117,7 +151,6 @@ int32_t PPB_VideoCapture_Impl::ReuseBuffer(uint32_t buffer) { |
| } |
| int32_t PPB_VideoCapture_Impl::StopCapture() { |
| - DCHECK(!is_dead_); |
| switch (status_) { |
| case PP_VIDEO_CAPTURE_STATUS_STOPPED: |
| case PP_VIDEO_CAPTURE_STATUS_STOPPING: |
| @@ -128,16 +161,20 @@ int32_t PPB_VideoCapture_Impl::StopCapture() { |
| case PP_VIDEO_CAPTURE_STATUS_PAUSED: |
| break; |
| } |
| + DCHECK(platform_video_capture_.get()); |
| + |
| ReleaseBuffers(); |
| status_ = PP_VIDEO_CAPTURE_STATUS_STOPPING; |
| platform_video_capture_->StopCapture(this); |
| return PP_OK; |
| } |
| -void PPB_VideoCapture_Impl::OnStarted(media::VideoCapture* capture) { |
| - if (is_dead_) |
| - return; |
| +const std::vector<DeviceRefData>& |
| + PPB_VideoCapture_Impl::GetDeviceRefData() const { |
| + return devices_data_; |
| +} |
| +void PPB_VideoCapture_Impl::OnStarted(media::VideoCapture* capture) { |
| switch (status_) { |
| case PP_VIDEO_CAPTURE_STATUS_STARTING: |
| case PP_VIDEO_CAPTURE_STATUS_PAUSED: |
| @@ -153,9 +190,6 @@ void PPB_VideoCapture_Impl::OnStarted(media::VideoCapture* capture) { |
| } |
| void PPB_VideoCapture_Impl::OnStopped(media::VideoCapture* capture) { |
| - if (is_dead_) |
| - return; |
| - |
| switch (status_) { |
| case PP_VIDEO_CAPTURE_STATUS_STOPPING: |
| break; |
| @@ -166,14 +200,12 @@ void PPB_VideoCapture_Impl::OnStopped(media::VideoCapture* capture) { |
| default: |
| return; |
| } |
| + |
| status_ = PP_VIDEO_CAPTURE_STATUS_STOPPED; |
| SendStatus(); |
| } |
| void PPB_VideoCapture_Impl::OnPaused(media::VideoCapture* capture) { |
| - if (is_dead_) |
| - return; |
| - |
| switch (status_) { |
| case PP_VIDEO_CAPTURE_STATUS_STARTING: |
| case PP_VIDEO_CAPTURE_STATUS_STARTED: |
| @@ -190,9 +222,6 @@ void PPB_VideoCapture_Impl::OnPaused(media::VideoCapture* capture) { |
| void PPB_VideoCapture_Impl::OnError(media::VideoCapture* capture, |
| int error_code) { |
| - if (is_dead_) |
| - return; |
| - |
| // Today, the media layer only sends "1" as an error. |
| DCHECK(error_code == 1); |
| // It either comes because some error was detected while starting (e.g. 2 |
| @@ -203,42 +232,31 @@ void PPB_VideoCapture_Impl::OnError(media::VideoCapture* capture, |
| } |
| void PPB_VideoCapture_Impl::OnRemoved(media::VideoCapture* capture) { |
| - Release(); |
| } |
| void PPB_VideoCapture_Impl::OnBufferReady( |
| media::VideoCapture* capture, |
| scoped_refptr<media::VideoCapture::VideoFrameBuffer> buffer) { |
| - if (!is_dead_) { |
| - DCHECK(buffer.get()); |
| - for (uint32_t i = 0; i < buffers_.size(); ++i) { |
| - if (!buffers_[i].in_use) { |
| - // TODO(ihf): Switch to a size calculation based on stride. |
| - // Stride is filled out now but not more meaningful than size |
| - // until wjia unifies VideoFrameBuffer and media::VideoFrame. |
| - size_t size = std::min(static_cast<size_t>(buffers_[i].buffer->size()), |
| - buffer->buffer_size); |
| - memcpy(buffers_[i].data, buffer->memory_pointer, size); |
| - buffers_[i].in_use = true; |
| - platform_video_capture_->FeedBuffer(buffer); |
| - ppp_videocapture_->OnBufferReady(pp_instance(), pp_resource(), i); |
| - return; |
| - } |
| + DCHECK(buffer.get()); |
| + for (uint32_t i = 0; i < buffers_.size(); ++i) { |
| + if (!buffers_[i].in_use) { |
| + // TODO(ihf): Switch to a size calculation based on stride. |
| + // Stride is filled out now but not more meaningful than size |
| + // until wjia unifies VideoFrameBuffer and media::VideoFrame. |
| + size_t size = std::min(static_cast<size_t>(buffers_[i].buffer->size()), |
| + buffer->buffer_size); |
| + memcpy(buffers_[i].data, buffer->memory_pointer, size); |
| + buffers_[i].in_use = true; |
| + platform_video_capture_->FeedBuffer(buffer); |
| + ppp_videocapture_->OnBufferReady(pp_instance(), pp_resource(), i); |
| + return; |
| } |
| } |
| - // Even after we have stopped and are dead we have to return buffers that |
| - // are in flight to us. Otherwise VideoCaptureController will not tear down. |
| - platform_video_capture_->FeedBuffer(buffer); |
| } |
| void PPB_VideoCapture_Impl::OnDeviceInfoReceived( |
| media::VideoCapture* capture, |
| const media::VideoCaptureParams& device_info) { |
| - // No need to call |ReleaseBuffers()|: if we're dead, |StopCapture()| should |
| - // already have been called. |
| - if (is_dead_) |
| - return; |
| - |
| PP_VideoCaptureDeviceInfo_Dev info = { |
| device_info.width, |
| device_info.height, |
| @@ -286,8 +304,22 @@ void PPB_VideoCapture_Impl::OnDeviceInfoReceived( |
| buffers_.size(), resources.get()); |
| } |
| +void PPB_VideoCapture_Impl::OnInitialized(media::VideoCapture* capture, |
| + bool succeeded) { |
| + DCHECK(capture == platform_video_capture_.get()); |
| + |
| + if (status_ != PP_VIDEO_CAPTURE_STATUS_STARTING) |
| + return; |
| + |
| + if (succeeded) { |
| + platform_video_capture_->StartCapture(this, capability_); |
| + } else { |
| + status_ = PP_VIDEO_CAPTURE_STATUS_STOPPED; |
| + SendStatus(); |
| + } |
| +} |
| + |
| void PPB_VideoCapture_Impl::ReleaseBuffers() { |
| - DCHECK(!is_dead_); |
| ::ppapi::ResourceTracker* tracker = PpapiGlobals::Get()->GetResourceTracker(); |
| for (size_t i = 0; i < buffers_.size(); ++i) { |
| buffers_[i].buffer->Unmap(); |
| @@ -297,10 +329,43 @@ void PPB_VideoCapture_Impl::ReleaseBuffers() { |
| } |
| void PPB_VideoCapture_Impl::SendStatus() { |
| - DCHECK(!is_dead_); |
| ppp_videocapture_->OnStatus(pp_instance(), pp_resource(), status_); |
| } |
| +void PPB_VideoCapture_Impl::ClearCachedDeviceResourceArray() { |
| + if (devices_) |
| + PpapiGlobals::Get()->GetResourceTracker()->ReleaseResource(devices_); |
| + devices_ = 0; |
| + |
| + devices_data_.clear(); |
| +} |
| + |
| +void PPB_VideoCapture_Impl::DetachPlatformVideoCapture() { |
| + if (platform_video_capture_.get()) { |
| + platform_video_capture_->DetachEventHandler(); |
| + platform_video_capture_ = NULL; |
| + } |
| +} |
| + |
| +void PPB_VideoCapture_Impl::OnEnumerateDevicesComplete( |
| + int request_id, |
| + bool succeeded, |
| + const std::vector<::ppapi::DeviceRefData>& devices) { |
| + ClearCachedDeviceResourceArray(); |
| + if (succeeded) { |
| + devices_data_ = devices; |
| + devices_ = ::ppapi::PPB_DeviceRef_Shared::CreateResourceArray( |
| + true, pp_instance(), devices_data_); |
| + } |
| + |
| + if (!TrackedCallback::IsPending(enumerate_devices_callback_)) { |
| + NOTREACHED(); |
| + return; |
| + } |
| + TrackedCallback::ClearAndRun(&enumerate_devices_callback_, |
| + succeeded ? PP_OK : PP_ERROR_FAILED); |
| +} |
| + |
| PPB_VideoCapture_Impl::BufferInfo::BufferInfo() |
| : in_use(false), |
| data(NULL), |