Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(172)

Side by Side Diff: webkit/plugins/ppapi/ppb_video_capture_impl.cc

Issue 11274036: Refactor video capture to new design (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: export Created 8 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "webkit/plugins/ppapi/ppb_video_capture_impl.h"
6
7 #include <algorithm>
8 #include <string>
9
10 #include "base/bind.h"
11 #include "base/logging.h"
12 #include "base/memory/scoped_ptr.h"
13 #include "ppapi/c/dev/pp_video_capture_dev.h"
14 #include "ppapi/c/dev/ppb_video_capture_dev.h"
15 #include "ppapi/c/pp_completion_callback.h"
16 #include "ppapi/c/pp_errors.h"
17 #include "ppapi/shared_impl/ppapi_globals.h"
18 #include "ppapi/shared_impl/ppb_device_ref_shared.h"
19 #include "ppapi/shared_impl/resource_tracker.h"
20 #include "ppapi/shared_impl/tracked_callback.h"
21 #include "ppapi/thunk/enter.h"
22 #include "webkit/plugins/ppapi/common.h"
23 #include "webkit/plugins/ppapi/plugin_module.h"
24 #include "webkit/plugins/ppapi/ppapi_plugin_instance.h"
25 #include "webkit/plugins/ppapi/ppb_buffer_impl.h"
26 #include "webkit/plugins/ppapi/resource_helper.h"
27
28 using ppapi::DeviceRefData;
29 using ppapi::PpapiGlobals;
30 using ppapi::thunk::EnterResourceNoLock;
31 using ppapi::thunk::PPB_Buffer_API;
32 using ppapi::thunk::PPB_VideoCapture_API;
33 using ppapi::TrackedCallback;
34
35 namespace {
36
37 // Maximum number of buffers to actually allocate.
38 const uint32_t kMaxBuffers = 20;
39
40 } // namespace
41
42 namespace webkit {
43 namespace ppapi {
44
45 PPB_VideoCapture_Impl::PPB_VideoCapture_Impl(PP_Instance instance)
46 : PPB_VideoCapture_Shared(instance),
47 buffer_count_hint_(0),
48 ppp_videocapture_(NULL),
49 capability_() {
50 }
51
52 PPB_VideoCapture_Impl::~PPB_VideoCapture_Impl() {
53 Close();
54 }
55
56 bool PPB_VideoCapture_Impl::Init() {
57 PluginInstance* instance = ResourceHelper::GetPluginInstance(this);
58 if (!instance)
59 return false;
60 ppp_videocapture_ = static_cast<const PPP_VideoCapture_Dev*>(
61 instance->module()->GetPluginInterface(PPP_VIDEO_CAPTURE_DEV_INTERFACE));
62 if (!ppp_videocapture_)
63 return false;
64
65 return true;
66 }
67
68 void PPB_VideoCapture_Impl::OnStarted(media::VideoCapture* capture) {
69 if (SetStatus(PP_VIDEO_CAPTURE_STATUS_STARTED, false))
70 SendStatus();
71 }
72
73 void PPB_VideoCapture_Impl::OnStopped(media::VideoCapture* capture) {
74 if (SetStatus(PP_VIDEO_CAPTURE_STATUS_STOPPED, false))
75 SendStatus();
76 }
77
78 void PPB_VideoCapture_Impl::OnPaused(media::VideoCapture* capture) {
79 if (SetStatus(PP_VIDEO_CAPTURE_STATUS_PAUSED, false))
80 SendStatus();
81 }
82
83 void PPB_VideoCapture_Impl::OnError(media::VideoCapture* capture,
84 int error_code) {
85 // Today, the media layer only sends "1" as an error.
86 DCHECK(error_code == 1);
87 // It either comes because some error was detected while starting (e.g. 2
88 // conflicting "master" resolution), or because the browser failed to start
89 // the capture.
90 SetStatus(PP_VIDEO_CAPTURE_STATUS_STOPPED, true);
91 ppp_videocapture_->OnError(pp_instance(), pp_resource(), PP_ERROR_FAILED);
92 }
93
94 void PPB_VideoCapture_Impl::OnRemoved(media::VideoCapture* capture) {
95 }
96
97 void PPB_VideoCapture_Impl::OnBufferReady(
98 media::VideoCapture* capture,
99 scoped_refptr<media::VideoCapture::VideoFrameBuffer> buffer) {
100 DCHECK(buffer.get());
101 for (uint32_t i = 0; i < buffers_.size(); ++i) {
102 if (!buffers_[i].in_use) {
103 // TODO(ihf): Switch to a size calculation based on stride.
104 // Stride is filled out now but not more meaningful than size
105 // until wjia unifies VideoFrameBuffer and media::VideoFrame.
106 size_t size = std::min(static_cast<size_t>(buffers_[i].buffer->size()),
107 buffer->buffer_size);
108 memcpy(buffers_[i].data, buffer->memory_pointer, size);
109 buffers_[i].in_use = true;
110 platform_video_capture_->FeedBuffer(buffer);
111 ppp_videocapture_->OnBufferReady(pp_instance(), pp_resource(), i);
112 return;
113 }
114 }
115
116 // No free slot, just discard the frame and tell the media layer it can
117 // re-use the buffer.
118 platform_video_capture_->FeedBuffer(buffer);
119 }
120
121 void PPB_VideoCapture_Impl::OnDeviceInfoReceived(
122 media::VideoCapture* capture,
123 const media::VideoCaptureParams& device_info) {
124 PP_VideoCaptureDeviceInfo_Dev info = {
125 static_cast<uint32_t>(device_info.width),
126 static_cast<uint32_t>(device_info.height),
127 static_cast<uint32_t>(device_info.frame_per_second)
128 };
129 ReleaseBuffers();
130
131 // Allocate buffers. We keep a reference to them, that is released in
132 // ReleaseBuffers.
133 // YUV 4:2:0
134 int uv_width = info.width / 2;
135 int uv_height = info.height / 2;
136 size_t size = info.width * info.height + 2 * uv_width * uv_height;
137 scoped_array<PP_Resource> resources(new PP_Resource[buffer_count_hint_]);
138
139 buffers_.reserve(buffer_count_hint_);
140 for (size_t i = 0; i < buffer_count_hint_; ++i) {
141 resources[i] = PPB_Buffer_Impl::Create(pp_instance(), size);
142 if (!resources[i])
143 break;
144
145 EnterResourceNoLock<PPB_Buffer_API> enter(resources[i], true);
146 DCHECK(enter.succeeded());
147
148 BufferInfo info;
149 info.buffer = static_cast<PPB_Buffer_Impl*>(enter.object());
150 info.data = info.buffer->Map();
151 if (!info.data) {
152 PpapiGlobals::Get()->GetResourceTracker()->ReleaseResource(resources[i]);
153 break;
154 }
155 buffers_.push_back(info);
156 }
157
158 if (buffers_.empty()) {
159 // We couldn't allocate/map buffers at all. Send an error and stop the
160 // capture.
161 ppp_videocapture_->OnError(pp_instance(), pp_resource(), PP_ERROR_NOMEMORY);
162 SetStatus(PP_VIDEO_CAPTURE_STATUS_STOPPING, true);
163 platform_video_capture_->StopCapture(this);
164 return;
165 }
166
167 ppp_videocapture_->OnDeviceInfo(pp_instance(), pp_resource(), &info,
168 buffers_.size(), resources.get());
169 }
170
171 void PPB_VideoCapture_Impl::OnInitialized(media::VideoCapture* capture,
172 bool succeeded) {
173 DCHECK(capture == platform_video_capture_.get());
174
175 OnOpenComplete(succeeded ? PP_OK : PP_ERROR_FAILED);
176 }
177
178 int32_t PPB_VideoCapture_Impl::InternalEnumerateDevices(
179 PP_Resource* devices,
180 scoped_refptr<TrackedCallback> callback) {
181 PluginInstance* instance = ResourceHelper::GetPluginInstance(this);
182 if (!instance)
183 return PP_ERROR_FAILED;
184
185 devices_ = devices;
186 enumerate_devices_callback_ = callback;
187 instance->delegate()->EnumerateDevices(
188 PP_DEVICETYPE_DEV_VIDEOCAPTURE,
189 base::Bind(&PPB_VideoCapture_Impl::EnumerateDevicesCallbackFunc,
190 AsWeakPtr()));
191 return PP_OK_COMPLETIONPENDING;
192 }
193
194 int32_t PPB_VideoCapture_Impl::InternalOpen(
195 const std::string& device_id,
196 const PP_VideoCaptureDeviceInfo_Dev& requested_info,
197 uint32_t buffer_count,
198 scoped_refptr<TrackedCallback> callback) {
199 // It is able to complete synchronously if the default device is used.
200 bool sync_completion = device_id.empty();
201
202 PluginInstance* instance = ResourceHelper::GetPluginInstance(this);
203 if (!instance)
204 return PP_ERROR_FAILED;
205
206 SetRequestedInfo(requested_info, buffer_count);
207
208 DCHECK(!platform_video_capture_.get());
209 platform_video_capture_ =
210 instance->delegate()->CreateVideoCapture(device_id, this);
211
212 if (sync_completion) {
213 OnInitialized(platform_video_capture_.get(), true);
214 return PP_OK;
215 } else {
216 open_callback_ = callback;
217 return PP_OK_COMPLETIONPENDING;
218 }
219 }
220
221 int32_t PPB_VideoCapture_Impl::InternalStartCapture() {
222 DCHECK(buffers_.empty());
223 platform_video_capture_->StartCapture(this, capability_);
224 return PP_OK;
225 }
226
227 int32_t PPB_VideoCapture_Impl::InternalReuseBuffer(uint32_t buffer) {
228 if (buffer >= buffers_.size() || !buffers_[buffer].in_use)
229 return PP_ERROR_BADARGUMENT;
230 buffers_[buffer].in_use = false;
231 return PP_OK;
232 }
233
234 int32_t PPB_VideoCapture_Impl::InternalStopCapture() {
235 ReleaseBuffers();
236 platform_video_capture_->StopCapture(this);
237 return PP_OK;
238 }
239
240 void PPB_VideoCapture_Impl::InternalClose() {
241 StopCapture();
242 DCHECK(buffers_.empty());
243
244 DetachPlatformVideoCapture();
245 }
246
247 int32_t PPB_VideoCapture_Impl::InternalStartCapture0_1(
248 const PP_VideoCaptureDeviceInfo_Dev& requested_info,
249 uint32_t buffer_count) {
250 PluginInstance* instance = ResourceHelper::GetPluginInstance(this);
251 if (!instance) {
252 SetStatus(PP_VIDEO_CAPTURE_STATUS_STOPPED, true);
253 return PP_ERROR_FAILED;
254 }
255
256 DCHECK(buffers_.empty());
257
258 SetRequestedInfo(requested_info, buffer_count);
259
260 DetachPlatformVideoCapture();
261 platform_video_capture_ =
262 instance->delegate()->CreateVideoCapture("", this);
263 platform_video_capture_->StartCapture(this, capability_);
264
265 return PP_OK;
266 }
267
268 const PPB_VideoCapture_Impl::DeviceRefDataVector&
269 PPB_VideoCapture_Impl::InternalGetDeviceRefData() const {
270 return devices_data_;
271 }
272
273 void PPB_VideoCapture_Impl::ReleaseBuffers() {
274 ::ppapi::ResourceTracker* tracker = PpapiGlobals::Get()->GetResourceTracker();
275 for (size_t i = 0; i < buffers_.size(); ++i) {
276 buffers_[i].buffer->Unmap();
277 tracker->ReleaseResource(buffers_[i].buffer->pp_resource());
278 }
279 buffers_.clear();
280 }
281
282 void PPB_VideoCapture_Impl::SendStatus() {
283 ppp_videocapture_->OnStatus(pp_instance(), pp_resource(), status_);
284 }
285
286 void PPB_VideoCapture_Impl::SetRequestedInfo(
287 const PP_VideoCaptureDeviceInfo_Dev& device_info,
288 uint32_t buffer_count) {
289 // Clamp the buffer count to between 1 and |kMaxBuffers|.
290 buffer_count_hint_ = std::min(std::max(buffer_count, 1U), kMaxBuffers);
291
292 capability_.width = device_info.width;
293 capability_.height = device_info.height;
294 capability_.frame_rate = device_info.frames_per_second;
295 capability_.expected_capture_delay = 0; // Ignored.
296 capability_.color = media::VideoCaptureCapability::kI420;
297 capability_.interlaced = false; // Ignored.
298 }
299
300 void PPB_VideoCapture_Impl::DetachPlatformVideoCapture() {
301 if (platform_video_capture_.get()) {
302 platform_video_capture_->DetachEventHandler();
303 platform_video_capture_ = NULL;
304 }
305 }
306
307 void PPB_VideoCapture_Impl::EnumerateDevicesCallbackFunc(
308 int request_id,
309 bool succeeded,
310 const DeviceRefDataVector& devices) {
311 devices_data_.clear();
312 if (succeeded)
313 devices_data_ = devices;
314
315 PluginInstance* instance = ResourceHelper::GetPluginInstance(this);
316 if (instance)
317 instance->delegate()->StopEnumerateDevices(request_id);
318
319 OnEnumerateDevicesComplete(succeeded ? PP_OK : PP_ERROR_FAILED, devices);
320 }
321
322 PPB_VideoCapture_Impl::BufferInfo::BufferInfo()
323 : in_use(false),
324 data(NULL),
325 buffer() {
326 }
327
328 PPB_VideoCapture_Impl::BufferInfo::~BufferInfo() {
329 }
330
331 } // namespace ppapi
332 } // namespace webkit
OLDNEW
« no previous file with comments | « webkit/plugins/ppapi/ppb_video_capture_impl.h ('k') | webkit/plugins/ppapi/resource_creation_impl.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698