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

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

Powered by Google App Engine
This is Rietveld 408576698