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 |
new file mode 100644 |
index 0000000000000000000000000000000000000000..22fdfc9422cdd23e5812a14c21a0464ccf29c2ee |
--- /dev/null |
+++ b/webkit/plugins/ppapi/ppb_video_capture_impl.cc |
@@ -0,0 +1,258 @@ |
+// Copyright (c) 2011 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. |
+ |
+#include "webkit/plugins/ppapi/ppb_video_capture_impl.h" |
+ |
+#include <algorithm> |
+#include <string> |
+ |
+#include "base/logging.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/thunk/enter.h" |
+#include "webkit/plugins/ppapi/common.h" |
+#include "webkit/plugins/ppapi/plugin_module.h" |
+#include "webkit/plugins/ppapi/ppapi_plugin_instance.h" |
+#include "webkit/plugins/ppapi/ppb_buffer_impl.h" |
+#include "webkit/plugins/ppapi/resource_tracker.h" |
+ |
+using ppapi::thunk::EnterResourceNoLock; |
+using ppapi::thunk::PPB_Buffer_API; |
+using ppapi::thunk::PPB_VideoCapture_API; |
+ |
+namespace webkit { |
+namespace ppapi { |
+ |
+PPB_VideoCapture_Impl::PPB_VideoCapture_Impl(PluginInstance* instance) |
+ : Resource(instance), |
+ buffer_count_hint_(0), |
+ status_(PP_VIDEO_CAPTURE_STATUS_STOPPED) { |
+ ppp_videocapture_ = |
brettw
2011/08/02 17:17:44
I'd initialize this to null in the initializer lis
piman
2011/08/03 00:44:41
Done.
|
+ static_cast<const PPP_VideoCapture_Dev*>(instance->module()-> |
+ GetPluginInterface(PPP_VIDEO_CAPTURE_DEV_INTERFACE)); |
+} |
+ |
+PPB_VideoCapture_Impl::~PPB_VideoCapture_Impl() { |
+ if (platform_video_capture_.get()) |
+ StopCapture(); |
+} |
+ |
+bool PPB_VideoCapture_Impl::Init() { |
+ platform_video_capture_.reset( |
+ instance()->delegate()->CreateVideoCapture(this)); |
+ return ppp_videocapture_ && platform_video_capture_.get(); |
+} |
+ |
+PPB_VideoCapture_API* PPB_VideoCapture_Impl::AsPPB_VideoCapture_API() { |
+ return this; |
+} |
+ |
+int32_t PPB_VideoCapture_Impl::StartCapture( |
+ const PP_VideoCaptureDeviceInfo_Dev& requested_info, |
+ uint32_t buffer_count) { |
+ switch (status_) { |
+ case PP_VIDEO_CAPTURE_STATUS_STARTING: |
+ case PP_VIDEO_CAPTURE_STATUS_STARTED: |
+ case PP_VIDEO_CAPTURE_STATUS_PAUSED: |
+ default: |
+ return PP_ERROR_FAILED; |
+ case PP_VIDEO_CAPTURE_STATUS_STOPPED: |
+ case PP_VIDEO_CAPTURE_STATUS_STOPPING: |
+ break; |
+ } |
+ DCHECK(buffers_.empty()); |
+ |
+ buffer_count_hint_ = std::min(buffer_count, 1U); |
+ media::VideoCapture::VideoCaptureCapability capability = { |
+ requested_info.width, |
+ requested_info.height, |
+ requested_info.frames_per_second, |
+ 0, // ignored. |
+ media::VideoFrame::I420, |
+ false, // ignored |
+ false // resolution_fixed |
+ }; |
+ status_ = PP_VIDEO_CAPTURE_STATUS_STARTING; |
+ platform_video_capture_->StartCapture(this, capability); |
+ return PP_OK; |
+} |
+ |
+int32_t PPB_VideoCapture_Impl::ReuseBuffer(uint32_t buffer) { |
+ if (buffer >= buffers_.size() || !buffers_[buffer].in_use) |
+ return PP_ERROR_BADARGUMENT; |
+ buffers_[buffer].in_use = false; |
+ return PP_OK; |
+} |
+ |
+int32_t PPB_VideoCapture_Impl::StopCapture() { |
+ switch (status_) { |
+ case PP_VIDEO_CAPTURE_STATUS_STOPPED: |
+ case PP_VIDEO_CAPTURE_STATUS_STOPPING: |
+ default: |
+ return PP_ERROR_FAILED; |
wjia(left Chromium)
2011/08/02 16:22:28
Is this a fatal error, or just warning? It might b
piman
2011/08/03 00:44:41
It's essentially silent, except if the plugin look
|
+ case PP_VIDEO_CAPTURE_STATUS_STARTING: |
+ case PP_VIDEO_CAPTURE_STATUS_STARTED: |
+ case PP_VIDEO_CAPTURE_STATUS_PAUSED: |
+ break; |
+ } |
+ FreeBuffers(); |
+ status_ = PP_VIDEO_CAPTURE_STATUS_STOPPING; |
+ platform_video_capture_->StopCapture(this); |
+ return PP_OK; |
+} |
+ |
+void PPB_VideoCapture_Impl::OnStarted(media::VideoCapture* capture) { |
+ switch (status_) { |
+ case PP_VIDEO_CAPTURE_STATUS_STARTING: |
+ case PP_VIDEO_CAPTURE_STATUS_PAUSED: |
+ break; |
+ case PP_VIDEO_CAPTURE_STATUS_STOPPED: |
+ case PP_VIDEO_CAPTURE_STATUS_STOPPING: |
+ case PP_VIDEO_CAPTURE_STATUS_STARTED: |
+ default: |
+ return; |
+ } |
+ status_ = PP_VIDEO_CAPTURE_STATUS_STARTED; |
+ SendStatus(); |
+} |
+ |
+void PPB_VideoCapture_Impl::OnStopped(media::VideoCapture* capture) { |
+ switch (status_) { |
+ case PP_VIDEO_CAPTURE_STATUS_STOPPING: |
+ break; |
+ case PP_VIDEO_CAPTURE_STATUS_STARTING: |
+ case PP_VIDEO_CAPTURE_STATUS_PAUSED: |
+ case PP_VIDEO_CAPTURE_STATUS_STOPPED: |
+ case PP_VIDEO_CAPTURE_STATUS_STARTED: |
+ default: |
+ return; |
+ } |
+ status_ = PP_VIDEO_CAPTURE_STATUS_STOPPED; |
+ SendStatus(); |
+} |
+ |
+void PPB_VideoCapture_Impl::OnPaused(media::VideoCapture* capture) { |
+ switch (status_) { |
+ case PP_VIDEO_CAPTURE_STATUS_STARTING: |
+ case PP_VIDEO_CAPTURE_STATUS_STARTED: |
+ break; |
+ case PP_VIDEO_CAPTURE_STATUS_STOPPED: |
+ case PP_VIDEO_CAPTURE_STATUS_STOPPING: |
+ case PP_VIDEO_CAPTURE_STATUS_PAUSED: |
+ default: |
+ return; |
+ } |
+ status_ = PP_VIDEO_CAPTURE_STATUS_PAUSED; |
+ SendStatus(); |
+} |
+ |
+void PPB_VideoCapture_Impl::OnError(media::VideoCapture* capture, |
+ int error_code) { |
+ // 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 |
+ // conflicting "master" resolution), or because the browser failed to start |
+ // the capture. |
+ status_ = PP_VIDEO_CAPTURE_STATUS_STOPPED; |
+ ppp_videocapture_->OnError(instance()->pp_instance(), |
+ ScopedResourceId(this).id, |
+ PP_ERROR_FAILED); |
+} |
+ |
+void PPB_VideoCapture_Impl::OnBufferReady( |
+ media::VideoCapture* capture, |
wjia(left Chromium)
2011/08/02 16:22:28
This |capture| looks like an alien since PPB_Video
piman
2011/08/03 00:44:41
So, I was kinda wondering about that, but decided
|
+ scoped_refptr<media::VideoCapture::VideoFrameBuffer> buffer) { |
wjia(left Chromium)
2011/08/02 16:22:28
it would be good to check buffer (not a NULL point
piman
2011/08/03 00:44:41
Is there a reason the VideoCaptureImpl would send
wjia(left Chromium)
2011/08/03 02:40:00
I meant DCHECK which has been added.
|
+ if (!buffers_.empty()) { |
+ for (uint32_t i = 0; i < buffers_.size(); ++i) { |
+ if (!buffers_[i].in_use) { |
+ // TODO(piman): it looks like stride isn't actually used/filled. |
+ DCHECK(buffer->stride == 0); |
+ size_t size = std::min(buffers_[i].buffer->size(), buffer->buffer_size); |
+ memcpy(buffers_[i].data, buffer->memory_pointer, size); |
wjia(left Chromium)
2011/08/02 16:22:28
would it be good to call "platform_video_capture_-
piman
2011/08/03 00:44:41
Done.
|
+ ppp_videocapture_->OnBufferReady(instance()->pp_instance(), |
+ ScopedResourceId(this).id, |
+ i); |
+ break; |
+ } |
+ } |
+ } |
+ // TODO(piman): signal dropped buffers ? |
+ platform_video_capture_->FeedBuffer(buffer); |
+} |
+ |
+void PPB_VideoCapture_Impl::OnDeviceInfoReceived( |
+ media::VideoCapture* capture, |
+ const media::VideoCaptureParams& device_info) { |
+ PP_VideoCaptureDeviceInfo_Dev info = { |
+ device_info.width, |
+ device_info.height, |
+ device_info.frame_per_second |
+ }; |
+ FreeBuffers(); |
wjia(left Chromium)
2011/08/02 16:22:28
is it guaranteed that no buffer is in use by plugi
piman
2011/08/03 00:44:41
The plugin is responsible for keeping its own refe
|
+ |
+ // Allocate buffers. We keep a reference to them, that is released in |
+ // FreeBuffers. |
+ // YUV 4:2:0 |
+ int uv_width = info.width / 2; |
+ int uv_height = info.height / 2; |
+ size_t size = info.width * info.height + 2 * uv_width * uv_height; |
+ scoped_array<PP_Resource> resources(new PP_Resource[buffer_count_hint_]); |
+ |
+ buffers_.reserve(buffer_count_hint_); |
+ for (size_t i = 0; i < buffer_count_hint_; ++i) { |
+ resources[i] = PPB_Buffer_Impl::Create(instance(), size); |
+ if (!resources[i]) { |
+ break; |
+ } |
+ |
+ EnterResourceNoLock<PPB_Buffer_API> enter(resources[i], true); |
+ DCHECK(enter.succeeded()); |
+ |
+ BufferInfo info; |
+ info.buffer = static_cast<PPB_Buffer_Impl*>(enter.object()); |
+ info.data = info.buffer->Map(); |
+ if (!info.data) { |
+ ResourceTracker::Get()->UnrefResource(resources[i]); |
+ break; |
+ } |
+ buffers_.push_back(info); |
+ } |
+ |
+ if (buffers_.empty()) { |
+ // We couldn't allocate/map buffers at all. Send an error and stop the |
+ // capture. |
+ ppp_videocapture_->OnError(instance()->pp_instance(), |
+ ScopedResourceId(this).id, |
+ PP_ERROR_NOMEMORY); |
+ status_ = PP_VIDEO_CAPTURE_STATUS_STOPPING; |
+ platform_video_capture_->StopCapture(this); |
+ return; |
+ } |
+ |
+ ppp_videocapture_->OnDeviceInfo(instance()->pp_instance(), |
+ ScopedResourceId(this).id, |
+ &info, |
+ buffers_.size(), |
+ resources.get()); |
+} |
+ |
+void PPB_VideoCapture_Impl::FreeBuffers() { |
+ ResourceTracker *tracker = ResourceTracker::Get(); |
+ for (size_t i = 0; i < buffers_.size(); ++i) { |
+ buffers_[i].buffer->Unmap(); |
+ tracker->UnrefResource(buffers_[i].buffer->GetReferenceNoAddRef()); |
+ } |
+ buffers_.clear(); |
+} |
+ |
+void PPB_VideoCapture_Impl::SendStatus() { |
+ ppp_videocapture_->OnStatus(instance()->pp_instance(), |
+ ScopedResourceId(this).id, |
+ status_); |
+} |
+ |
+} // namespace ppapi |
+} // namespace webkit |