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

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

Issue 8304017: enable video capture to support sharing across multiple renderer processes (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: rebase Created 9 years, 1 month 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
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/renderer/media/video_capture_impl.h" 5 #include "content/renderer/media/video_capture_impl.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/stl_util.h" 8 #include "base/stl_util.h"
9 #include "content/common/child_process.h" 9 #include "content/common/child_process.h"
10 #include "content/common/media/video_capture_messages.h" 10 #include "content/common/media/video_capture_messages.h"
11 11
12 VideoCaptureImpl::DIBBuffer::DIBBuffer( 12 struct VideoCaptureImpl::DIBBuffer {
13 base::SharedMemory* d, media::VideoCapture::VideoFrameBuffer* ptr) 13 public:
14 : dib(d), 14 DIBBuffer(
15 mapped_memory(ptr) {} 15 base::SharedMemory* d,
16 media::VideoCapture::VideoFrameBuffer* ptr)
17 : dib(d),
18 mapped_memory(ptr) {
19 }
20 ~DIBBuffer() {
21 delete dib;
22 }
16 23
17 VideoCaptureImpl::DIBBuffer::~DIBBuffer() { 24 base::SharedMemory* dib;
18 delete dib; 25 scoped_refptr<media::VideoCapture::VideoFrameBuffer> mapped_memory;
19 } 26 };
20 27
21 bool VideoCaptureImpl::CaptureStarted() { 28 bool VideoCaptureImpl::CaptureStarted() {
22 return state_ == kStarted; 29 return state_ == kStarted;
23 } 30 }
24 31
25 int VideoCaptureImpl::CaptureWidth() { 32 int VideoCaptureImpl::CaptureWidth() {
26 return current_params_.width; 33 return current_params_.width;
27 } 34 }
28 35
29 int VideoCaptureImpl::CaptureHeight() { 36 int VideoCaptureImpl::CaptureHeight() {
(...skipping 10 matching lines...) Expand all
40 VideoCaptureMessageFilter* filter) 47 VideoCaptureMessageFilter* filter)
41 : VideoCapture(), 48 : VideoCapture(),
42 message_filter_(filter), 49 message_filter_(filter),
43 ml_proxy_(ml_proxy), 50 ml_proxy_(ml_proxy),
44 device_id_(0), 51 device_id_(0),
45 video_type_(media::VideoFrame::I420), 52 video_type_(media::VideoFrame::I420),
46 device_info_available_(false), 53 device_info_available_(false),
47 state_(kStopped) { 54 state_(kStopped) {
48 DCHECK(filter); 55 DCHECK(filter);
49 memset(&current_params_, 0, sizeof(current_params_)); 56 memset(&current_params_, 0, sizeof(current_params_));
50 memset(&new_params_, 0, sizeof(new_params_)); 57 current_params_.session_id = id;
51 current_params_.session_id = new_params_.session_id = id;
52 } 58 }
53 59
54 VideoCaptureImpl::~VideoCaptureImpl() { 60 VideoCaptureImpl::~VideoCaptureImpl() {
55 STLDeleteContainerPairSecondPointers(cached_dibs_.begin(), 61 STLDeleteContainerPairSecondPointers(cached_dibs_.begin(),
56 cached_dibs_.end()); 62 cached_dibs_.end());
57 } 63 }
58 64
59 void VideoCaptureImpl::Init() { 65 void VideoCaptureImpl::Init() {
60 base::MessageLoopProxy* io_message_loop_proxy = 66 base::MessageLoopProxy* io_message_loop_proxy =
61 ChildProcess::current()->io_message_loop_proxy(); 67 ChildProcess::current()->io_message_loop_proxy();
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
140 ml_proxy_->PostTask(FROM_HERE, 146 ml_proxy_->PostTask(FROM_HERE,
141 base::Bind(&VideoCaptureImpl::DoDelegateAdded, 147 base::Bind(&VideoCaptureImpl::DoDelegateAdded,
142 base::Unretained(this), device_id)); 148 base::Unretained(this), device_id));
143 } 149 }
144 150
145 void VideoCaptureImpl::DoStartCapture( 151 void VideoCaptureImpl::DoStartCapture(
146 media::VideoCapture::EventHandler* handler, 152 media::VideoCapture::EventHandler* handler,
147 const VideoCaptureCapability& capability) { 153 const VideoCaptureCapability& capability) {
148 DCHECK(ml_proxy_->BelongsToCurrentThread()); 154 DCHECK(ml_proxy_->BelongsToCurrentThread());
149 155
156 if (state_ == kError) {
157 handler->OnError(this, 1);
158 handler->OnRemoved(this);
159 return;
160 }
161
150 if (pending_clients_.find(handler) != pending_clients_.end() || 162 if (pending_clients_.find(handler) != pending_clients_.end() ||
151 clients_.find(handler) != clients_.end() ) { 163 clients_.find(handler) != clients_.end() ) {
152 // This client has started. 164 // This client has started.
153 return; 165 return;
154 } 166 }
155 167
156 if (!device_id_) { 168 if (!device_id_) {
157 pending_clients_[handler] = capability; 169 pending_clients_[handler] = capability;
158 return; 170 return;
159 } 171 }
160 172
161 if (capability.resolution_fixed && master_clients_.size()) { 173 clients_[handler] = capability;
162 bool matches_current_params = 174 handler->OnStarted(this);
163 CapabilityMatchesParameters(capability, current_params_); 175 if (state_ == kStarted) {
164 bool matches_new_params = 176 if (!device_info_available_) {
165 CapabilityMatchesParameters(capability, new_params_);
166 if ((state_ == kStarted && !matches_current_params) ||
167 (state_ == kStopping && !matches_new_params)) {
168 // Can't have 2 master clients with different resolutions.
169 handler->OnError(this, 1);
170 handler->OnRemoved(this);
171 return; 177 return;
172 } 178 }
173 }
174 179
175 handler->OnStarted(this); 180 if (capability.width > device_info_.width ||
176 clients_[handler] = capability; 181 capability.height > device_info_.height) {
177 if (capability.resolution_fixed) { 182 StopDevice();
178 master_clients_.push_back(handler); 183 DLOG(INFO) << "StartCapture: Got client with higher resolution ("
179 if (master_clients_.size() > 1) { 184 << capability.width << ", " << capability.height << ") "
180 if (device_info_available_) 185 << "after started, try to restart.";
181 handler->OnDeviceInfoReceived(this, device_info_);
182 return; 186 return;
183 } 187 }
184 }
185 188
186 if (state_ == kStarted) { 189 handler->OnDeviceInfoReceived(this, device_info_);
187 // Take the resolution of master client.
188 if (capability.resolution_fixed &&
189 !CapabilityMatchesParameters(capability, current_params_)) {
190 new_params_.width = capability.width;
191 new_params_.height = capability.height;
192 new_params_.frame_per_second = capability.max_fps;
193 DLOG(INFO) << "StartCapture: Got master client with new resolution ("
194 << new_params_.width << ", " << new_params_.height << ") "
195 << "during started, try to restart.";
196 StopDevice();
197 } else if (device_info_available_) {
198 handler->OnDeviceInfoReceived(this, device_info_);
199 }
200 return; 190 return;
201 } 191 }
202 192
203 if (state_ == kStopping) { 193 if (state_ == kStopping) {
204 if (capability.resolution_fixed || !pending_start()) { 194 DLOG(INFO) << "StartCapture: Got new resolution ("
205 new_params_.width = capability.width; 195 << capability.width << ", " << capability.height << ") "
206 new_params_.height = capability.height; 196 << ", during stopping.";
207 new_params_.frame_per_second = capability.max_fps;
208 DLOG(INFO) << "StartCapture: Got new resolution ("
209 << new_params_.width << ", " << new_params_.height << ") "
210 << ", already in stopping.";
211 }
212 return; 197 return;
213 } 198 }
214 199
215 DCHECK_EQ(clients_.size(), 1ul); 200 DCHECK_EQ(clients_.size(), 1ul);
216 video_type_ = capability.raw_type; 201 video_type_ = capability.raw_type;
217 new_params_.width = 0;
218 new_params_.height = 0;
219 new_params_.frame_per_second = 0;
220 current_params_.width = capability.width; 202 current_params_.width = capability.width;
221 current_params_.height = capability.height; 203 current_params_.height = capability.height;
222 current_params_.frame_per_second = capability.max_fps; 204 current_params_.frame_per_second = capability.max_fps;
223 DLOG(INFO) << "StartCapture: resolution (" 205 DLOG(INFO) << "StartCapture: starting with first resolution ("
224 << current_params_.width << ", " << current_params_.height << ")"; 206 << current_params_.width << ", " << current_params_.height << ")";
225 207
226 StartCaptureInternal(); 208 StartCaptureInternal();
227 } 209 }
228 210
229 void VideoCaptureImpl::DoStopCapture( 211 void VideoCaptureImpl::DoStopCapture(
230 media::VideoCapture::EventHandler* handler) { 212 media::VideoCapture::EventHandler* handler) {
231 DCHECK(ml_proxy_->BelongsToCurrentThread()); 213 DCHECK(ml_proxy_->BelongsToCurrentThread());
232 214
233 ClientInfo::iterator it = pending_clients_.find(handler); 215 ClientInfo::iterator it = pending_clients_.find(handler);
234 if (it != pending_clients_.end()) { 216 if (it != pending_clients_.end()) {
235 handler->OnStopped(this); 217 handler->OnStopped(this);
236 handler->OnRemoved(this); 218 handler->OnRemoved(this);
237 pending_clients_.erase(it); 219 pending_clients_.erase(it);
238 return; 220 return;
239 } 221 }
240 222
241 if (clients_.find(handler) == clients_.end()) 223 if (clients_.find(handler) == clients_.end())
242 return; 224 return;
243 225
244 handler->OnStopped(this); 226 handler->OnStopped(this);
245 handler->OnRemoved(this); 227 handler->OnRemoved(this);
246 clients_.erase(handler); 228 clients_.erase(handler);
247 master_clients_.remove(handler);
248 229
249 // Still have at least one master client. 230 if (clients_.size() == 0) {
250 if (master_clients_.size() > 0)
251 return;
252
253 // TODO(wjia): Is it really needed to handle resolution change for non-master
254 // clients, except no client case?
255 if (clients_.size() > 0) {
256 DLOG(INFO) << "StopCapture: No master client.";
257 int max_width = 0;
258 int max_height = 0;
259 int frame_rate = 0;
260 for (ClientInfo::iterator it = clients_.begin();
261 it != clients_.end(); it++) {
262 if (it->second.width > max_width && it->second.height > max_height) {
263 max_width = it->second.width;
264 max_height = it->second.height;
265 frame_rate = it->second.max_fps;
266 }
267 }
268
269 if (state_ == kStarted) {
270 // Only handle resolution reduction.
271 if (max_width < current_params_.width &&
272 max_height < current_params_.height) {
273 new_params_.width = max_width;
274 new_params_.height = max_height;
275 new_params_.frame_per_second = frame_rate;
276 DLOG(INFO) << "StopCapture: New smaller resolution ("
277 << new_params_.width << ", " << new_params_.height << ") "
278 << "), stopping ...";
279 StopDevice();
280 }
281 return;
282 }
283
284 if (state_ == kStopping) {
285 new_params_.width = max_width;
286 new_params_.height = max_height;
287 new_params_.frame_per_second = frame_rate;
288 DLOG(INFO) << "StopCapture: New resolution ("
289 << new_params_.width << ", " << new_params_.height << ") "
290 << "), during stopping.";
291 return;
292 }
293 } else {
294 new_params_.width = current_params_.width = 0;
295 new_params_.height = current_params_.height = 0;
296 new_params_.frame_per_second = current_params_.frame_per_second = 0;
297 DLOG(INFO) << "StopCapture: No more client, stopping ..."; 231 DLOG(INFO) << "StopCapture: No more client, stopping ...";
298 StopDevice(); 232 StopDevice();
299 } 233 }
300 } 234 }
301 235
302 void VideoCaptureImpl::DoFeedBuffer(scoped_refptr<VideoFrameBuffer> buffer) { 236 void VideoCaptureImpl::DoFeedBuffer(scoped_refptr<VideoFrameBuffer> buffer) {
303 DCHECK(ml_proxy_->BelongsToCurrentThread()); 237 DCHECK(ml_proxy_->BelongsToCurrentThread());
304 DCHECK(client_side_dibs_.find(buffer) != client_side_dibs_.end()); 238 DCHECK(client_side_dibs_.find(buffer) != client_side_dibs_.end());
305 239
306 CachedDIB::iterator it; 240 CachedDIB::iterator it;
307 for (it = cached_dibs_.begin(); it != cached_dibs_.end(); it++) { 241 for (it = cached_dibs_.begin(); it != cached_dibs_.end(); it++) {
308 if (buffer == it->second->mapped_memory) 242 if (buffer == it->second->mapped_memory)
309 break; 243 break;
310 } 244 }
311 245
312 DCHECK(it != cached_dibs_.end()); 246 DCHECK(it != cached_dibs_.end());
313 if (client_side_dibs_[buffer] <= 1) { 247 if (client_side_dibs_[buffer] <= 1) {
314 client_side_dibs_.erase(buffer); 248 client_side_dibs_.erase(buffer);
315 Send(new VideoCaptureHostMsg_BufferReady(device_id_, it->first)); 249 Send(new VideoCaptureHostMsg_BufferReady(device_id_, it->first));
316 } else { 250 } else {
317 client_side_dibs_[buffer]--; 251 client_side_dibs_[buffer]--;
318 } 252 }
319 } 253 }
320 254
321 void VideoCaptureImpl::DoBufferCreated( 255 void VideoCaptureImpl::DoBufferCreated(
322 base::SharedMemoryHandle handle, 256 base::SharedMemoryHandle handle,
323 int length, int buffer_id) { 257 int length, int buffer_id) {
324 DCHECK(ml_proxy_->BelongsToCurrentThread()); 258 DCHECK(ml_proxy_->BelongsToCurrentThread());
259 DCHECK(device_info_available_);
325 260
326 media::VideoCapture::VideoFrameBuffer* buffer; 261 media::VideoCapture::VideoFrameBuffer* buffer;
327 DCHECK(cached_dibs_.find(buffer_id) == cached_dibs_.end()); 262 DCHECK(cached_dibs_.find(buffer_id) == cached_dibs_.end());
328 263
329 base::SharedMemory* dib = new base::SharedMemory(handle, false); 264 base::SharedMemory* dib = new base::SharedMemory(handle, false);
330 dib->Map(length); 265 dib->Map(length);
331 buffer = new VideoFrameBuffer(); 266 buffer = new VideoFrameBuffer();
332 buffer->memory_pointer = static_cast<uint8*>(dib->memory()); 267 buffer->memory_pointer = static_cast<uint8*>(dib->memory());
333 buffer->buffer_size = length; 268 buffer->buffer_size = length;
334 buffer->width = current_params_.width; 269 buffer->width = device_info_.width;
335 buffer->height = current_params_.height; 270 buffer->height = device_info_.height;
271 buffer->stride = device_info_.width;
336 272
337 DIBBuffer* dib_buffer = new DIBBuffer(dib, buffer); 273 DIBBuffer* dib_buffer = new DIBBuffer(dib, buffer);
338 cached_dibs_[buffer_id] = dib_buffer; 274 cached_dibs_[buffer_id] = dib_buffer;
339 } 275 }
340 276
341 void VideoCaptureImpl::DoBufferReceived(int buffer_id, base::Time timestamp) { 277 void VideoCaptureImpl::DoBufferReceived(int buffer_id, base::Time timestamp) {
342 DCHECK(ml_proxy_->BelongsToCurrentThread()); 278 DCHECK(ml_proxy_->BelongsToCurrentThread());
343 279
344 if (state_ != kStarted) { 280 if (state_ != kStarted) {
345 Send(new VideoCaptureHostMsg_BufferReady(device_id_, buffer_id)); 281 Send(new VideoCaptureHostMsg_BufferReady(device_id_, buffer_id));
(...skipping 13 matching lines...) Expand all
359 void VideoCaptureImpl::DoStateChanged(const media::VideoCapture::State& state) { 295 void VideoCaptureImpl::DoStateChanged(const media::VideoCapture::State& state) {
360 DCHECK(ml_proxy_->BelongsToCurrentThread()); 296 DCHECK(ml_proxy_->BelongsToCurrentThread());
361 297
362 switch (state) { 298 switch (state) {
363 case media::VideoCapture::kStarted: 299 case media::VideoCapture::kStarted:
364 break; 300 break;
365 case media::VideoCapture::kStopped: 301 case media::VideoCapture::kStopped:
366 state_ = kStopped; 302 state_ = kStopped;
367 DLOG(INFO) << "OnStateChanged: stopped!, device_id = " << device_id_; 303 DLOG(INFO) << "OnStateChanged: stopped!, device_id = " << device_id_;
368 STLDeleteValues(&cached_dibs_); 304 STLDeleteValues(&cached_dibs_);
369 if (pending_start()) 305 if (clients_.size() > 0)
370 RestartCapture(); 306 RestartCapture();
371 break; 307 break;
372 case media::VideoCapture::kPaused: 308 case media::VideoCapture::kPaused:
373 for (ClientInfo::iterator it = clients_.begin(); 309 for (ClientInfo::iterator it = clients_.begin();
374 it != clients_.end(); it++) { 310 it != clients_.end(); it++) {
375 it->first->OnPaused(this); 311 it->first->OnPaused(this);
376 } 312 }
377 break; 313 break;
378 case media::VideoCapture::kError: 314 case media::VideoCapture::kError:
315 DLOG(INFO) << "OnStateChanged: error!, device_id = " << device_id_;
379 for (ClientInfo::iterator it = clients_.begin(); 316 for (ClientInfo::iterator it = clients_.begin();
380 it != clients_.end(); it++) { 317 it != clients_.end(); it++) {
381 // TODO(wjia): browser process would send error code. 318 // TODO(wjia): browser process would send error code.
382 it->first->OnError(this, 1); 319 it->first->OnError(this, 1);
383 it->first->OnRemoved(this); 320 it->first->OnRemoved(this);
384 } 321 }
385 clients_.clear(); 322 clients_.clear();
386 master_clients_.clear(); 323 state_ = kError;
387 state_ = kStopped;
388 current_params_.width = current_params_.height = 0;
389 break; 324 break;
390 default: 325 default:
391 break; 326 break;
392 } 327 }
393 } 328 }
394 329
395 void VideoCaptureImpl::DoDeviceInfoReceived( 330 void VideoCaptureImpl::DoDeviceInfoReceived(
396 const media::VideoCaptureParams& device_info) { 331 const media::VideoCaptureParams& device_info) {
397 DCHECK(ml_proxy_->BelongsToCurrentThread()); 332 DCHECK(ml_proxy_->BelongsToCurrentThread());
398 if (state_ != kStarted) 333 DCHECK(!ClientHasDIB());
334
335 STLDeleteValues(&cached_dibs_);
336
337 GetMaxWidthHeight(current_params_.width, current_params_.height);
338 if (current_params_.width > device_info.width ||
339 current_params_.height > device_info.height) {
340 StopDevice();
399 return; 341 return;
342 }
400 343
401 device_info_ = device_info; 344 device_info_ = device_info;
402 device_info_available_ = true; 345 device_info_available_ = true;
403 for (ClientInfo::iterator it = clients_.begin(); it != clients_.end(); it++) { 346 for (ClientInfo::iterator it = clients_.begin(); it != clients_.end(); it++) {
404 it->first->OnDeviceInfoReceived(this, device_info); 347 it->first->OnDeviceInfoReceived(this, device_info);
405 } 348 }
406 } 349 }
407 350
408 void VideoCaptureImpl::DoDelegateAdded(int32 device_id) { 351 void VideoCaptureImpl::DoDelegateAdded(int32 device_id) {
409 DLOG(INFO) << "DoDelegateAdded: device_id " << device_id; 352 DLOG(INFO) << "DoDelegateAdded: device_id " << device_id;
(...skipping 17 matching lines...) Expand all
427 state_ = kStopping; 370 state_ = kStopping;
428 Send(new VideoCaptureHostMsg_Stop(device_id_)); 371 Send(new VideoCaptureHostMsg_Stop(device_id_));
429 current_params_.width = current_params_.height = 0; 372 current_params_.width = current_params_.height = 0;
430 } 373 }
431 } 374 }
432 375
433 void VideoCaptureImpl::RestartCapture() { 376 void VideoCaptureImpl::RestartCapture() {
434 DCHECK(ml_proxy_->BelongsToCurrentThread()); 377 DCHECK(ml_proxy_->BelongsToCurrentThread());
435 DCHECK_EQ(state_, kStopped); 378 DCHECK_EQ(state_, kStopped);
436 379
437 current_params_.width = new_params_.width; 380 GetMaxWidthHeight(current_params_.width, current_params_.height);
438 current_params_.height = new_params_.height;
439 current_params_.frame_per_second = new_params_.frame_per_second;
440
441 new_params_.width = 0;
442 new_params_.height = 0;
443 new_params_.frame_per_second = 0;
444
445 DLOG(INFO) << "RestartCapture, " << current_params_.width << ", " 381 DLOG(INFO) << "RestartCapture, " << current_params_.width << ", "
446 << current_params_.height; 382 << current_params_.height;
447 StartCaptureInternal(); 383 StartCaptureInternal();
448 } 384 }
449 385
450 void VideoCaptureImpl::StartCaptureInternal() { 386 void VideoCaptureImpl::StartCaptureInternal() {
451 DCHECK(ml_proxy_->BelongsToCurrentThread()); 387 DCHECK(ml_proxy_->BelongsToCurrentThread());
452 DCHECK(device_id_); 388 DCHECK(device_id_);
453 389
454 Send(new VideoCaptureHostMsg_Start(device_id_, current_params_)); 390 Send(new VideoCaptureHostMsg_Start(device_id_, current_params_));
(...skipping 11 matching lines...) Expand all
466 402
467 void VideoCaptureImpl::Send(IPC::Message* message) { 403 void VideoCaptureImpl::Send(IPC::Message* message) {
468 base::MessageLoopProxy* io_message_loop_proxy = 404 base::MessageLoopProxy* io_message_loop_proxy =
469 ChildProcess::current()->io_message_loop_proxy(); 405 ChildProcess::current()->io_message_loop_proxy();
470 406
471 io_message_loop_proxy->PostTask(FROM_HERE, 407 io_message_loop_proxy->PostTask(FROM_HERE,
472 base::IgnoreReturn<bool>(base::Bind(&VideoCaptureMessageFilter::Send, 408 base::IgnoreReturn<bool>(base::Bind(&VideoCaptureMessageFilter::Send,
473 message_filter_.get(), message))); 409 message_filter_.get(), message)));
474 } 410 }
475 411
476 bool VideoCaptureImpl::CapabilityMatchesParameters( 412 bool VideoCaptureImpl::ClientHasDIB() {
477 const VideoCaptureCapability& capability, 413 for (ClientSideDIB::iterator dit = client_side_dibs_.begin();
478 const media::VideoCaptureParams& params) { 414 dit != client_side_dibs_.end(); dit++) {
479 return (capability.width == params.width && 415 if (dit->second > 0)
480 capability.height == params.height && 416 return true;
481 capability.max_fps == params.frame_per_second); 417 }
418 return false;
482 } 419 }
420
421 void VideoCaptureImpl::GetMaxWidthHeight(int& width, int& height) {
422 width = height = 0;
423 for (ClientInfo::iterator it = clients_.begin();
424 it != clients_.end(); it++) {
425 if (it->second.width > width)
426 width = it->second.width;
427 if (it->second.height > height)
428 height = it->second.height;
429 }
430 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698