OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2011 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/logging.h" | |
11 #include "ppapi/c/dev/pp_video_capture_dev.h" | |
12 #include "ppapi/c/dev/ppb_video_capture_dev.h" | |
13 #include "ppapi/c/pp_completion_callback.h" | |
14 #include "ppapi/c/pp_errors.h" | |
15 #include "ppapi/thunk/enter.h" | |
16 #include "webkit/plugins/ppapi/common.h" | |
17 #include "webkit/plugins/ppapi/plugin_module.h" | |
18 #include "webkit/plugins/ppapi/ppapi_plugin_instance.h" | |
19 #include "webkit/plugins/ppapi/ppb_buffer_impl.h" | |
20 #include "webkit/plugins/ppapi/resource_tracker.h" | |
21 | |
22 using ppapi::thunk::EnterResourceNoLock; | |
23 using ppapi::thunk::PPB_Buffer_API; | |
24 using ppapi::thunk::PPB_VideoCapture_API; | |
25 | |
26 namespace webkit { | |
27 namespace ppapi { | |
28 | |
29 PPB_VideoCapture_Impl::PPB_VideoCapture_Impl(PluginInstance* instance) | |
30 : Resource(instance), | |
31 buffer_count_hint_(0), | |
32 status_(PP_VIDEO_CAPTURE_STATUS_STOPPED) { | |
33 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.
| |
34 static_cast<const PPP_VideoCapture_Dev*>(instance->module()-> | |
35 GetPluginInterface(PPP_VIDEO_CAPTURE_DEV_INTERFACE)); | |
36 } | |
37 | |
38 PPB_VideoCapture_Impl::~PPB_VideoCapture_Impl() { | |
39 if (platform_video_capture_.get()) | |
40 StopCapture(); | |
41 } | |
42 | |
43 bool PPB_VideoCapture_Impl::Init() { | |
44 platform_video_capture_.reset( | |
45 instance()->delegate()->CreateVideoCapture(this)); | |
46 return ppp_videocapture_ && platform_video_capture_.get(); | |
47 } | |
48 | |
49 PPB_VideoCapture_API* PPB_VideoCapture_Impl::AsPPB_VideoCapture_API() { | |
50 return this; | |
51 } | |
52 | |
53 int32_t PPB_VideoCapture_Impl::StartCapture( | |
54 const PP_VideoCaptureDeviceInfo_Dev& requested_info, | |
55 uint32_t buffer_count) { | |
56 switch (status_) { | |
57 case PP_VIDEO_CAPTURE_STATUS_STARTING: | |
58 case PP_VIDEO_CAPTURE_STATUS_STARTED: | |
59 case PP_VIDEO_CAPTURE_STATUS_PAUSED: | |
60 default: | |
61 return PP_ERROR_FAILED; | |
62 case PP_VIDEO_CAPTURE_STATUS_STOPPED: | |
63 case PP_VIDEO_CAPTURE_STATUS_STOPPING: | |
64 break; | |
65 } | |
66 DCHECK(buffers_.empty()); | |
67 | |
68 buffer_count_hint_ = std::min(buffer_count, 1U); | |
69 media::VideoCapture::VideoCaptureCapability capability = { | |
70 requested_info.width, | |
71 requested_info.height, | |
72 requested_info.frames_per_second, | |
73 0, // ignored. | |
74 media::VideoFrame::I420, | |
75 false, // ignored | |
76 false // resolution_fixed | |
77 }; | |
78 status_ = PP_VIDEO_CAPTURE_STATUS_STARTING; | |
79 platform_video_capture_->StartCapture(this, capability); | |
80 return PP_OK; | |
81 } | |
82 | |
83 int32_t PPB_VideoCapture_Impl::ReuseBuffer(uint32_t buffer) { | |
84 if (buffer >= buffers_.size() || !buffers_[buffer].in_use) | |
85 return PP_ERROR_BADARGUMENT; | |
86 buffers_[buffer].in_use = false; | |
87 return PP_OK; | |
88 } | |
89 | |
90 int32_t PPB_VideoCapture_Impl::StopCapture() { | |
91 switch (status_) { | |
92 case PP_VIDEO_CAPTURE_STATUS_STOPPED: | |
93 case PP_VIDEO_CAPTURE_STATUS_STOPPING: | |
94 default: | |
95 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
| |
96 case PP_VIDEO_CAPTURE_STATUS_STARTING: | |
97 case PP_VIDEO_CAPTURE_STATUS_STARTED: | |
98 case PP_VIDEO_CAPTURE_STATUS_PAUSED: | |
99 break; | |
100 } | |
101 FreeBuffers(); | |
102 status_ = PP_VIDEO_CAPTURE_STATUS_STOPPING; | |
103 platform_video_capture_->StopCapture(this); | |
104 return PP_OK; | |
105 } | |
106 | |
107 void PPB_VideoCapture_Impl::OnStarted(media::VideoCapture* capture) { | |
108 switch (status_) { | |
109 case PP_VIDEO_CAPTURE_STATUS_STARTING: | |
110 case PP_VIDEO_CAPTURE_STATUS_PAUSED: | |
111 break; | |
112 case PP_VIDEO_CAPTURE_STATUS_STOPPED: | |
113 case PP_VIDEO_CAPTURE_STATUS_STOPPING: | |
114 case PP_VIDEO_CAPTURE_STATUS_STARTED: | |
115 default: | |
116 return; | |
117 } | |
118 status_ = PP_VIDEO_CAPTURE_STATUS_STARTED; | |
119 SendStatus(); | |
120 } | |
121 | |
122 void PPB_VideoCapture_Impl::OnStopped(media::VideoCapture* capture) { | |
123 switch (status_) { | |
124 case PP_VIDEO_CAPTURE_STATUS_STOPPING: | |
125 break; | |
126 case PP_VIDEO_CAPTURE_STATUS_STARTING: | |
127 case PP_VIDEO_CAPTURE_STATUS_PAUSED: | |
128 case PP_VIDEO_CAPTURE_STATUS_STOPPED: | |
129 case PP_VIDEO_CAPTURE_STATUS_STARTED: | |
130 default: | |
131 return; | |
132 } | |
133 status_ = PP_VIDEO_CAPTURE_STATUS_STOPPED; | |
134 SendStatus(); | |
135 } | |
136 | |
137 void PPB_VideoCapture_Impl::OnPaused(media::VideoCapture* capture) { | |
138 switch (status_) { | |
139 case PP_VIDEO_CAPTURE_STATUS_STARTING: | |
140 case PP_VIDEO_CAPTURE_STATUS_STARTED: | |
141 break; | |
142 case PP_VIDEO_CAPTURE_STATUS_STOPPED: | |
143 case PP_VIDEO_CAPTURE_STATUS_STOPPING: | |
144 case PP_VIDEO_CAPTURE_STATUS_PAUSED: | |
145 default: | |
146 return; | |
147 } | |
148 status_ = PP_VIDEO_CAPTURE_STATUS_PAUSED; | |
149 SendStatus(); | |
150 } | |
151 | |
152 void PPB_VideoCapture_Impl::OnError(media::VideoCapture* capture, | |
153 int error_code) { | |
154 // Today, the media layer only sends "1" as an error. | |
155 DCHECK(error_code == 1); | |
156 // It either comes because some error was detected while starting (e.g. 2 | |
157 // conflicting "master" resolution), or because the browser failed to start | |
158 // the capture. | |
159 status_ = PP_VIDEO_CAPTURE_STATUS_STOPPED; | |
160 ppp_videocapture_->OnError(instance()->pp_instance(), | |
161 ScopedResourceId(this).id, | |
162 PP_ERROR_FAILED); | |
163 } | |
164 | |
165 void PPB_VideoCapture_Impl::OnBufferReady( | |
166 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
| |
167 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.
| |
168 if (!buffers_.empty()) { | |
169 for (uint32_t i = 0; i < buffers_.size(); ++i) { | |
170 if (!buffers_[i].in_use) { | |
171 // TODO(piman): it looks like stride isn't actually used/filled. | |
172 DCHECK(buffer->stride == 0); | |
173 size_t size = std::min(buffers_[i].buffer->size(), buffer->buffer_size); | |
174 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.
| |
175 ppp_videocapture_->OnBufferReady(instance()->pp_instance(), | |
176 ScopedResourceId(this).id, | |
177 i); | |
178 break; | |
179 } | |
180 } | |
181 } | |
182 // TODO(piman): signal dropped buffers ? | |
183 platform_video_capture_->FeedBuffer(buffer); | |
184 } | |
185 | |
186 void PPB_VideoCapture_Impl::OnDeviceInfoReceived( | |
187 media::VideoCapture* capture, | |
188 const media::VideoCaptureParams& device_info) { | |
189 PP_VideoCaptureDeviceInfo_Dev info = { | |
190 device_info.width, | |
191 device_info.height, | |
192 device_info.frame_per_second | |
193 }; | |
194 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
| |
195 | |
196 // Allocate buffers. We keep a reference to them, that is released in | |
197 // FreeBuffers. | |
198 // YUV 4:2:0 | |
199 int uv_width = info.width / 2; | |
200 int uv_height = info.height / 2; | |
201 size_t size = info.width * info.height + 2 * uv_width * uv_height; | |
202 scoped_array<PP_Resource> resources(new PP_Resource[buffer_count_hint_]); | |
203 | |
204 buffers_.reserve(buffer_count_hint_); | |
205 for (size_t i = 0; i < buffer_count_hint_; ++i) { | |
206 resources[i] = PPB_Buffer_Impl::Create(instance(), size); | |
207 if (!resources[i]) { | |
208 break; | |
209 } | |
210 | |
211 EnterResourceNoLock<PPB_Buffer_API> enter(resources[i], true); | |
212 DCHECK(enter.succeeded()); | |
213 | |
214 BufferInfo info; | |
215 info.buffer = static_cast<PPB_Buffer_Impl*>(enter.object()); | |
216 info.data = info.buffer->Map(); | |
217 if (!info.data) { | |
218 ResourceTracker::Get()->UnrefResource(resources[i]); | |
219 break; | |
220 } | |
221 buffers_.push_back(info); | |
222 } | |
223 | |
224 if (buffers_.empty()) { | |
225 // We couldn't allocate/map buffers at all. Send an error and stop the | |
226 // capture. | |
227 ppp_videocapture_->OnError(instance()->pp_instance(), | |
228 ScopedResourceId(this).id, | |
229 PP_ERROR_NOMEMORY); | |
230 status_ = PP_VIDEO_CAPTURE_STATUS_STOPPING; | |
231 platform_video_capture_->StopCapture(this); | |
232 return; | |
233 } | |
234 | |
235 ppp_videocapture_->OnDeviceInfo(instance()->pp_instance(), | |
236 ScopedResourceId(this).id, | |
237 &info, | |
238 buffers_.size(), | |
239 resources.get()); | |
240 } | |
241 | |
242 void PPB_VideoCapture_Impl::FreeBuffers() { | |
243 ResourceTracker *tracker = ResourceTracker::Get(); | |
244 for (size_t i = 0; i < buffers_.size(); ++i) { | |
245 buffers_[i].buffer->Unmap(); | |
246 tracker->UnrefResource(buffers_[i].buffer->GetReferenceNoAddRef()); | |
247 } | |
248 buffers_.clear(); | |
249 } | |
250 | |
251 void PPB_VideoCapture_Impl::SendStatus() { | |
252 ppp_videocapture_->OnStatus(instance()->pp_instance(), | |
253 ScopedResourceId(this).id, | |
254 status_); | |
255 } | |
256 | |
257 } // namespace ppapi | |
258 } // namespace webkit | |
OLD | NEW |