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

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

Powered by Google App Engine
This is Rietveld 408576698