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

Side by Side Diff: content/renderer/media/video_capture_impl.cc

Issue 6902166: Add VideoCaptureImpl (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: add time out for StartCapture Created 9 years, 7 months 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 | Annotate | Revision Log
Property Changes:
Added: svn:eol-style
+ LF
OLDNEW
(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 "content/renderer/media/video_capture_impl.h"
6
7 #include "content/common/child_process.h"
8 #include "content/common/video_capture_messages.h"
9 #include "content/common/view_messages.h"
jam 2011/05/24 19:15:41 nit: why add this?
wjia(left Chromium) 2011/05/24 20:47:15 removed.
10
11 namespace {
12
13 // Timeout setting for StartCapture.
14 enum {
15 kTryTimes = 1000,
jam 2011/05/24 19:15:41 seems odd to put these two different constants in
wjia(left Chromium) 2011/05/24 20:47:15 split.
16 kDelayInMillisecond = 1
17 };
18
19 } // namespace
20
21 VideoCaptureImpl::DIBBuffer::DIBBuffer(
22 TransportDIB* d, media::VideoCapture::VideoFrameBuffer* ptr)
23 : dib(d),
24 mapped_memory(ptr) {}
25
26 VideoCaptureImpl::DIBBuffer::~DIBBuffer() {
27 delete dib;
28 }
29
30 bool VideoCaptureImpl::CaptureStarted() {
31 return state_ == kStarted;
32 }
33
34 int VideoCaptureImpl::CaptureWidth() {
35 return width_;
36 }
37
38 int VideoCaptureImpl::CaptureHeight() {
39 return height_;
40 }
41
42 int VideoCaptureImpl::CaptureFrameRate() {
43 return frame_rate_;
44 }
45
46 VideoCaptureImpl::VideoCaptureImpl(
47 const media::VideoCaptureSessionId id,
48 scoped_refptr<base::MessageLoopProxy> ml_proxy,
49 VideoCaptureMessageFilter* filter)
50 : VideoCapture(),
51 message_filter_(filter),
52 session_id_(id),
53 ml_proxy_(ml_proxy),
54 device_id_(0),
55 width_(0),
56 height_(0),
57 frame_rate_(0),
58 video_type_(media::VideoFrame::I420),
59 new_width_(0),
60 new_height_(0),
61 state_(kStopped) {
62 DCHECK(filter);
63 }
64
65 VideoCaptureImpl::~VideoCaptureImpl() {}
66
67 void VideoCaptureImpl::Init() {
68 DCHECK(ChildProcess::current()) << "Must be in the renderer";
jam 2011/05/24 19:15:41 this will return true if you're in any childproces
wjia(left Chromium) 2011/05/24 20:47:15 removed.
69 base::MessageLoopProxy* message_loop_proxy =
70 ChildProcess::current()->io_message_loop_proxy();
71 DCHECK(message_loop_proxy);
jam 2011/05/24 19:15:41 nit: this dcheck is unnecessary. in release build
wjia(left Chromium) 2011/05/24 20:47:15 changed to condition checking.
72
73 if (!message_loop_proxy->BelongsToCurrentThread()) {
74 message_loop_proxy->PostTask(FROM_HERE,
75 NewRunnableMethod(this, &VideoCaptureImpl::AddDelegateOnIOThread));
76 return;
77 }
78
79 AddDelegateOnIOThread();
80 }
81
82 void VideoCaptureImpl::DeInit(Task* task) {
83 DCHECK(ChildProcess::current()) << "Must be in the renderer";
84 base::MessageLoopProxy* message_loop_proxy =
85 ChildProcess::current()->io_message_loop_proxy();
86 DCHECK(message_loop_proxy);
87
88 if (state_ == kStarted)
89 message_filter_->Send(new VideoCaptureHostMsg_Stop(0, device_id_));
90
91 if (!message_loop_proxy->BelongsToCurrentThread()) {
92 message_loop_proxy->PostTask(FROM_HERE,
93 NewRunnableMethod(this, &VideoCaptureImpl::RemoveDelegateOnIOThread,
94 task));
95 return;
96 }
97
98 RemoveDelegateOnIOThread(task);
99 }
100
101 void VideoCaptureImpl::StartCapture(
102 media::VideoCapture::EventHandler* handler,
103 const VideoCaptureCapability& capability) {
104 DCHECK_EQ(capability.raw_type, media::VideoFrame::I420);
105
106 if (!ml_proxy_->BelongsToCurrentThread()) {
107 ml_proxy_->PostTask(FROM_HERE,
108 NewRunnableMethod(this, &VideoCaptureImpl::StartCapture, handler,
109 capability));
110 return;
111 }
112
113 PendingClient::iterator it = pending_clients_.find(handler);
114 if (!device_id_ || !message_filter_->ReadyToSend()) {
115 if (it != pending_clients_.end() && it->second <= 0) {
116 if (it->second == 0) {
117 handler->OnError(this, 2);
118 }
119 pending_clients_.erase(it);
120 } else {
121 if (it == pending_clients_.end())
122 pending_clients_[handler] = kTryTimes;
123 else
124 it->second--;
125
126 ml_proxy_->PostDelayedTask(FROM_HERE,
127 NewRunnableMethod(this, &VideoCaptureImpl::StartCapture, handler,
128 capability), kDelayInMillisecond);
129 }
130 return;
131 }
132
133 if (it != pending_clients_.end())
134 pending_clients_.erase(it);
135
136 if (capability.resolution_fixed && master_clients_.size() &&
137 (capability.width != width_ || capability.height != height_)) {
138 // Can't have 2 master clients with different resolutions.
139 handler->OnError(this, 1);
140 return;
141 }
142
143 clients_[handler] = capability;
144 if (capability.resolution_fixed) {
145 master_clients_.push_back(handler);
146 if (master_clients_.size() > 1)
147 return;
148 }
149
150 if (state_ == kStarted) {
151 // Take the resolution of master client.
152 if (capability.resolution_fixed &&
153 (capability.width != width_ || capability.height != height_)) {
154 new_width_ = capability.width;
155 new_height_ = capability.height;
156 DLOG(INFO) << "StartCapture: Got master client with new resolution "
157 "during started, try to restart.";
158 StopDevice();
159 }
160 handler->OnStarted(this);
161 return;
162 }
163
164 if (state_ == kStopping) {
165 if (capability.resolution_fixed || !pending_start()) {
166 new_width_ = capability.width;
167 new_height_ = capability.height;
168 DLOG(INFO) << "StartCapture: Got new resolution, already in stopping.";
169 }
170 handler->OnStarted(this);
171 return;
172 }
173
174 DCHECK_EQ(clients_.size(), 1ul);
175 video_type_ = capability.raw_type;
176 new_width_ = 0;
177 new_height_ = 0;
178 width_ = capability.width;
179 height_ = capability.height;
180
181 StartCaptureInternal();
182 }
183
184 void VideoCaptureImpl::StopCapture(media::VideoCapture::EventHandler* handler) {
185 if (!ml_proxy_->BelongsToCurrentThread()) {
186 ml_proxy_->PostTask(FROM_HERE,
187 NewRunnableMethod(this, &VideoCaptureImpl::StopCapture, handler));
188 return;
189 }
190
191 PendingClient::iterator it = pending_clients_.find(handler);
192 if (it != pending_clients_.end()) {
193 handler->OnStopped(this);
194 it->second = -1;
195 return;
196 }
197
198 if (clients_.find(handler) == clients_.end())
199 return;
200
201 handler->OnStopped(this);
202 clients_.erase(handler);
203 master_clients_.remove(handler);
204
205 // Still have at least one master client.
206 if (master_clients_.size() > 0)
207 return;
208
209 // TODO(wjia): Is it really needed to handle resolution change for non-master
210 // clients, except no client case?
211 if (clients_.size() > 0) {
212 DLOG(INFO) << "StopCapture: No master client.";
213 int maxw = 0;
214 int maxh = 0;
215 for (ClientInfo::iterator it = clients_.begin();
216 it != clients_.end(); it++) {
217 if (it->second.width > maxw && it->second.height > maxh) {
218 maxw = it->second.width;
219 maxh = it->second.height;
220 }
221 }
222
223 if (state_ == kStarted) {
224 // Only handle resolution reduction.
225 if (maxw < width_ && maxh < height_) {
226 new_width_ = maxw;
227 new_height_ = maxh;
228 DLOG(INFO) << "StopCapture: New smaller resolution, stopping ...";
229 StopDevice();
230 }
231 return;
232 }
233
234 if (state_ == kStopping) {
235 new_width_ = maxw;
236 new_height_ = maxh;
237 DLOG(INFO) << "StopCapture: New resolution, during stopping.";
238 return;
239 }
240 } else {
241 new_width_ = width_ = 0;
242 new_height_ = height_ = 0;
243 DLOG(INFO) << "StopCapture: No more client, stopping ...";
244 StopDevice();
245 }
246 }
247
248 void VideoCaptureImpl::OnBufferReceived(TransportDIB::Handle handle,
249 base::Time timestamp) {
250 if (!ml_proxy_->BelongsToCurrentThread()) {
251 ml_proxy_->PostTask(FROM_HERE,
252 NewRunnableMethod(this, &VideoCaptureImpl::OnBufferReceived,
253 handle, timestamp));
254 return;
255 }
256
257 if (state_ != kStarted) {
258 message_filter_->Send(
259 new VideoCaptureHostMsg_BufferReady(0, device_id_, handle));
260 return;
261 }
262
263 media::VideoCapture::VideoFrameBuffer* buffer;
264 CachedDIB::iterator it;
265 for (it = cached_dibs_.begin(); it != cached_dibs_.end(); it++) {
266 if ((*it)->dib->handle() == handle)
267 break;
268 }
269 if (it == cached_dibs_.end()) {
270 TransportDIB* dib = TransportDIB::Map(handle);
271 buffer = new VideoFrameBuffer();
272 buffer->memory_pointer = dib->memory();
273 buffer->buffer_size = dib->size();
274 buffer->width = width_;
275 buffer->height = height_;
276
277 DIBBuffer* dib_buffer = new DIBBuffer(dib, buffer);
278 cached_dibs_.push_back(dib_buffer);
279 } else {
280 buffer = (*it)->mapped_memory;
281 }
282
283 // TODO(wjia): handle buffer sharing with downstream modules.
284 for (ClientInfo::iterator it = clients_.begin(); it != clients_.end(); it++) {
285 it->first->OnBufferReady(this, buffer);
286 }
287
288 message_filter_->Send(
289 new VideoCaptureHostMsg_BufferReady(0, device_id_, handle));
290 }
291
292 void VideoCaptureImpl::OnStateChanged(
293 const media::VideoCapture::State& state) {
294 if (!ml_proxy_->BelongsToCurrentThread()) {
295 ml_proxy_->PostTask(FROM_HERE,
296 NewRunnableMethod(this, &VideoCaptureImpl::OnStateChanged, state));
297 return;
298 }
299
300 switch (state) {
301 case media::VideoCapture::kStarted:
302 for (ClientInfo::iterator it = clients_.begin();
303 it != clients_.end(); it++) {
304 it->first->OnStarted(this);
305 }
306 break;
307 case media::VideoCapture::kStopped:
308 state_ = kStopped;
309 DLOG(INFO) << "OnStateChanged: stopped!, device_id = " << device_id_;
310 if (pending_start())
311 RestartCapture();
312 break;
313 case media::VideoCapture::kPaused:
314 for (ClientInfo::iterator it = clients_.begin();
315 it != clients_.end(); it++) {
316 it->first->OnPaused(this);
317 }
318 break;
319 case media::VideoCapture::kError:
320 for (ClientInfo::iterator it = clients_.begin();
321 it != clients_.end(); it++) {
322 // TODO(wjia): browser process would send error code.
323 it->first->OnError(this, 1);
324 }
325 break;
326 default:
327 break;
328 }
329 }
330
331 void VideoCaptureImpl::OnDeviceInfoReceived(
332 const media::VideoCaptureParams& device_info) {
333 if (!ml_proxy_->BelongsToCurrentThread()) {
334 ml_proxy_->PostTask(FROM_HERE,
335 NewRunnableMethod(this, &VideoCaptureImpl::OnDeviceInfoReceived,
336 device_info));
337 return;
338 }
339
340 for (ClientInfo::iterator it = clients_.begin(); it != clients_.end(); it++) {
341 it->first->OnDeviceInfoReceived(this, device_info);
342 }
343 }
344
345 void VideoCaptureImpl::StopDevice() {
346 if (!ml_proxy_->BelongsToCurrentThread()) {
347 ml_proxy_->PostTask(FROM_HERE,
348 NewRunnableMethod(this, &VideoCaptureImpl::StopDevice));
349 return;
350 }
351
352 if (state_ == kStarted) {
353 state_ = kStopping;
354 message_filter_->Send(new VideoCaptureHostMsg_Stop(0, device_id_));
355 width_ = height_ = 0;
356 }
357 }
358
359 void VideoCaptureImpl::RestartCapture() {
360 DCHECK(ml_proxy_->BelongsToCurrentThread());
361 DCHECK_EQ(state_, kStopped);
362
363 width_ = new_width_;
364 height_ = new_height_;
365 new_width_ = 0;
366 new_height_ = 0;
367
368 DLOG(INFO) << "RestartCapture, " << width_ << ", " << height_;
369 StartCaptureInternal();
370 }
371
372 void VideoCaptureImpl::StartCaptureInternal() {
373 DCHECK(ml_proxy_->BelongsToCurrentThread());
374 DCHECK(device_id_);
375 DCHECK(message_filter_->ReadyToSend());
376
377 media::VideoCaptureParams params;
378 params.width = width_;
379 params.height = height_;
380 params.session_id = session_id_;
381
382 message_filter_->Send(new VideoCaptureHostMsg_Start(0, device_id_, params));
383 state_ = kStarted;
384 for (ClientInfo::iterator it = clients_.begin(); it != clients_.end(); it++) {
385 it->first->OnStarted(this);
386 }
387 }
388
389 void VideoCaptureImpl::AddDelegateOnIOThread() {
390 // |device_id_| is modified only on io thread.
391 device_id_ = message_filter_->AddDelegate(this);
392 }
393
394 void VideoCaptureImpl::RemoveDelegateOnIOThread(Task* task) {
395 message_filter_->RemoveDelegate(this);
396 media::AutoTaskRunner auto_runner(task);
397 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698