|
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 "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 } | |
OLD | NEW |