OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/child/child_process.h" | 9 #include "content/child/child_process.h" |
10 #include "content/common/media/video_capture_messages.h" | 10 #include "content/common/media/video_capture_messages.h" |
11 #include "media/base/limits.h" | 11 #include "media/base/limits.h" |
12 | 12 |
13 namespace content { | 13 namespace content { |
14 | 14 |
15 struct VideoCaptureImpl::DIBBuffer { | 15 class VideoCaptureImpl::ClientBuffer : public base::RefCounted<ClientBuffer> { |
16 public: | 16 public: |
17 DIBBuffer( | 17 ClientBuffer(scoped_ptr<base::SharedMemory> buffer, |
18 base::SharedMemory* d, | 18 size_t buffer_size, |
19 media::VideoCapture::VideoFrameBuffer* ptr) | 19 int frame_width, |
20 : dib(d), | 20 int frame_height, |
21 mapped_memory(ptr), | 21 int frame_stride) |
22 references(0) { | 22 : buffer(buffer.Pass()), |
23 } | 23 buffer_size(buffer_size), |
24 ~DIBBuffer() {} | 24 frame_width(frame_width), |
25 frame_height(frame_height), | |
26 frame_stride(frame_stride) {} | |
27 const scoped_ptr<base::SharedMemory> buffer; | |
28 const size_t buffer_size; | |
29 const int frame_width; // In pixels. | |
30 const int frame_height; // In pixels. | |
31 const int frame_stride; // In pixels. | |
25 | 32 |
26 scoped_ptr<base::SharedMemory> dib; | 33 private: |
27 scoped_refptr<media::VideoCapture::VideoFrameBuffer> mapped_memory; | 34 friend class base::RefCounted<ClientBuffer>; |
28 | 35 |
29 // Number of clients which hold this DIB. | 36 virtual ~ClientBuffer() {} |
30 int references; | 37 |
38 DISALLOW_COPY_AND_ASSIGN(ClientBuffer); | |
31 }; | 39 }; |
32 | 40 |
33 bool VideoCaptureImpl::CaptureStarted() { | 41 bool VideoCaptureImpl::CaptureStarted() { |
34 return state_ == VIDEO_CAPTURE_STATE_STARTED; | 42 return state_ == VIDEO_CAPTURE_STATE_STARTED; |
35 } | 43 } |
36 | 44 |
37 int VideoCaptureImpl::CaptureWidth() { | 45 int VideoCaptureImpl::CaptureWidth() { |
38 return capture_format_.width; | 46 return capture_format_.width; |
39 } | 47 } |
40 | 48 |
41 int VideoCaptureImpl::CaptureHeight() { | 49 int VideoCaptureImpl::CaptureHeight() { |
42 return capture_format_.height; | 50 return capture_format_.height; |
43 } | 51 } |
44 | 52 |
45 int VideoCaptureImpl::CaptureFrameRate() { | 53 int VideoCaptureImpl::CaptureFrameRate() { |
46 return capture_format_.frame_rate; | 54 return capture_format_.frame_rate; |
47 } | 55 } |
48 | 56 |
49 VideoCaptureImpl::VideoCaptureImpl( | 57 VideoCaptureImpl::VideoCaptureImpl( |
50 const media::VideoCaptureSessionId id, | 58 const media::VideoCaptureSessionId id, |
51 base::MessageLoopProxy* capture_message_loop_proxy, | 59 base::MessageLoopProxy* capture_message_loop_proxy, |
52 VideoCaptureMessageFilter* filter) | 60 VideoCaptureMessageFilter* filter) |
53 : VideoCapture(), | 61 : VideoCapture(), |
54 message_filter_(filter), | 62 message_filter_(filter), |
55 capture_message_loop_proxy_(capture_message_loop_proxy), | 63 capture_message_loop_proxy_(capture_message_loop_proxy), |
56 io_message_loop_proxy_(ChildProcess::current()->io_message_loop_proxy()), | 64 io_message_loop_proxy_(ChildProcess::current()->io_message_loop_proxy()), |
57 device_id_(0), | 65 device_id_(0), |
66 client_buffer_weak_this_factory_(this), | |
58 video_type_(media::PIXEL_FORMAT_I420), | 67 video_type_(media::PIXEL_FORMAT_I420), |
59 device_info_available_(false), | 68 device_info_available_(false), |
60 suspended_(false), | 69 suspended_(false), |
61 state_(VIDEO_CAPTURE_STATE_STOPPED) { | 70 state_(VIDEO_CAPTURE_STATE_STOPPED) { |
62 DCHECK(filter); | 71 DCHECK(filter); |
63 capture_format_.session_id = id; | 72 capture_format_.session_id = id; |
64 } | 73 } |
65 | 74 |
66 VideoCaptureImpl::~VideoCaptureImpl() { | 75 VideoCaptureImpl::~VideoCaptureImpl() {} |
67 STLDeleteValues(&cached_dibs_); | |
68 } | |
69 | 76 |
70 void VideoCaptureImpl::Init() { | 77 void VideoCaptureImpl::Init() { |
71 if (!io_message_loop_proxy_->BelongsToCurrentThread()) { | 78 if (!io_message_loop_proxy_->BelongsToCurrentThread()) { |
72 io_message_loop_proxy_->PostTask(FROM_HERE, | 79 io_message_loop_proxy_->PostTask(FROM_HERE, |
73 base::Bind(&VideoCaptureImpl::AddDelegateOnIOThread, | 80 base::Bind(&VideoCaptureImpl::AddDelegateOnIOThread, |
74 base::Unretained(this))); | 81 base::Unretained(this))); |
75 } else { | 82 } else { |
76 AddDelegateOnIOThread(); | 83 AddDelegateOnIOThread(); |
77 } | 84 } |
78 } | 85 } |
(...skipping 13 matching lines...) Expand all Loading... | |
92 base::Bind(&VideoCaptureImpl::DoStartCaptureOnCaptureThread, | 99 base::Bind(&VideoCaptureImpl::DoStartCaptureOnCaptureThread, |
93 base::Unretained(this), handler, capability)); | 100 base::Unretained(this), handler, capability)); |
94 } | 101 } |
95 | 102 |
96 void VideoCaptureImpl::StopCapture(media::VideoCapture::EventHandler* handler) { | 103 void VideoCaptureImpl::StopCapture(media::VideoCapture::EventHandler* handler) { |
97 capture_message_loop_proxy_->PostTask(FROM_HERE, | 104 capture_message_loop_proxy_->PostTask(FROM_HERE, |
98 base::Bind(&VideoCaptureImpl::DoStopCaptureOnCaptureThread, | 105 base::Bind(&VideoCaptureImpl::DoStopCaptureOnCaptureThread, |
99 base::Unretained(this), handler)); | 106 base::Unretained(this), handler)); |
100 } | 107 } |
101 | 108 |
102 void VideoCaptureImpl::FeedBuffer(scoped_refptr<VideoFrameBuffer> buffer) { | |
103 capture_message_loop_proxy_->PostTask(FROM_HERE, | |
104 base::Bind(&VideoCaptureImpl::DoFeedBufferOnCaptureThread, | |
105 base::Unretained(this), buffer)); | |
106 } | |
107 | |
108 void VideoCaptureImpl::OnBufferCreated( | 109 void VideoCaptureImpl::OnBufferCreated( |
109 base::SharedMemoryHandle handle, | 110 base::SharedMemoryHandle handle, |
110 int length, int buffer_id) { | 111 int length, int buffer_id) { |
111 capture_message_loop_proxy_->PostTask(FROM_HERE, | 112 capture_message_loop_proxy_->PostTask(FROM_HERE, |
112 base::Bind(&VideoCaptureImpl::DoBufferCreatedOnCaptureThread, | 113 base::Bind(&VideoCaptureImpl::DoBufferCreatedOnCaptureThread, |
113 base::Unretained(this), handle, length, buffer_id)); | 114 base::Unretained(this), handle, length, buffer_id)); |
114 } | 115 } |
115 | 116 |
116 void VideoCaptureImpl::OnBufferReceived(int buffer_id, base::Time timestamp) { | 117 void VideoCaptureImpl::OnBufferReceived(int buffer_id, base::Time timestamp) { |
117 capture_message_loop_proxy_->PostTask(FROM_HERE, | 118 capture_message_loop_proxy_->PostTask(FROM_HERE, |
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
228 // A handler can be in only one client list. | 229 // A handler can be in only one client list. |
229 // If this handler is in any client list, we can just remove it from | 230 // If this handler is in any client list, we can just remove it from |
230 // that client list and don't have to run the other following RemoveClient(). | 231 // that client list and don't have to run the other following RemoveClient(). |
231 RemoveClient(handler, &clients_pending_on_filter_) || | 232 RemoveClient(handler, &clients_pending_on_filter_) || |
232 RemoveClient(handler, &clients_pending_on_restart_) || | 233 RemoveClient(handler, &clients_pending_on_restart_) || |
233 RemoveClient(handler, &clients_); | 234 RemoveClient(handler, &clients_); |
234 | 235 |
235 if (clients_.empty()) { | 236 if (clients_.empty()) { |
236 DVLOG(1) << "StopCapture: No more client, stopping ..."; | 237 DVLOG(1) << "StopCapture: No more client, stopping ..."; |
237 StopDevice(); | 238 StopDevice(); |
239 client_buffers_.clear(); | |
240 client_buffer_weak_this_factory_.InvalidateWeakPtrs(); | |
238 } | 241 } |
239 } | 242 } |
240 | 243 |
241 void VideoCaptureImpl::DoFeedBufferOnCaptureThread( | |
242 scoped_refptr<VideoFrameBuffer> buffer) { | |
243 DCHECK(capture_message_loop_proxy_->BelongsToCurrentThread()); | |
244 | |
245 CachedDIB::iterator it; | |
246 for (it = cached_dibs_.begin(); it != cached_dibs_.end(); ++it) { | |
247 if (buffer.get() == it->second->mapped_memory.get()) | |
248 break; | |
249 } | |
250 | |
251 if (it != cached_dibs_.end() && it->second) { | |
252 DCHECK_GT(it->second->references, 0); | |
253 --it->second->references; | |
254 if (it->second->references == 0) { | |
255 Send(new VideoCaptureHostMsg_BufferReady(device_id_, it->first)); | |
256 } | |
257 } | |
258 } | |
259 | |
260 void VideoCaptureImpl::DoBufferCreatedOnCaptureThread( | 244 void VideoCaptureImpl::DoBufferCreatedOnCaptureThread( |
261 base::SharedMemoryHandle handle, | 245 base::SharedMemoryHandle handle, |
262 int length, int buffer_id) { | 246 int length, int buffer_id) { |
263 DCHECK(capture_message_loop_proxy_->BelongsToCurrentThread()); | 247 DCHECK(capture_message_loop_proxy_->BelongsToCurrentThread()); |
264 | 248 |
265 // In case client calls StopCapture before the arrival of created buffer, | 249 // In case client calls StopCapture before the arrival of created buffer, |
266 // just close this buffer and return. | 250 // just close this buffer and return. |
267 if (state_ != VIDEO_CAPTURE_STATE_STARTED) { | 251 if (state_ != VIDEO_CAPTURE_STATE_STARTED) { |
268 base::SharedMemory::CloseHandle(handle); | 252 base::SharedMemory::CloseHandle(handle); |
269 return; | 253 return; |
270 } | 254 } |
271 | 255 |
272 DCHECK(device_info_available_); | 256 DCHECK(device_info_available_); |
273 | 257 |
274 media::VideoCapture::VideoFrameBuffer* buffer; | 258 ClientBufferMap::iterator iter = client_buffers_.find(buffer_id); |
275 DCHECK(cached_dibs_.find(buffer_id) == cached_dibs_.end()); | 259 DCHECK(iter == client_buffers_.end()); |
276 | 260 |
277 base::SharedMemory* dib = new base::SharedMemory(handle, false); | 261 scoped_ptr<base::SharedMemory> shm(new base::SharedMemory(handle, false)); |
278 dib->Map(length); | 262 if (!shm->Map(length)) { |
279 buffer = new VideoFrameBuffer(); | 263 DLOG(ERROR) << "DoBufferCreatedOnCaptureThread: Map() failed."; |
280 buffer->memory_pointer = static_cast<uint8*>(dib->memory()); | 264 return; |
281 buffer->buffer_size = length; | 265 } |
282 buffer->width = device_info_.width; | |
283 buffer->height = device_info_.height; | |
284 buffer->stride = device_info_.width; | |
285 | 266 |
286 DIBBuffer* dib_buffer = new DIBBuffer(dib, buffer); | 267 client_buffers_.insert( |
287 cached_dibs_[buffer_id] = dib_buffer; | 268 iter, |
269 ClientBufferMap::value_type( | |
270 buffer_id, | |
271 make_scoped_refptr(new ClientBuffer(shm.Pass(), | |
272 length, | |
273 device_info_.width, | |
274 device_info_.height, | |
275 device_info_.width)))); | |
288 } | 276 } |
289 | 277 |
290 void VideoCaptureImpl::DoBufferReceivedOnCaptureThread( | 278 void VideoCaptureImpl::DoBufferReceivedOnCaptureThread( |
291 int buffer_id, base::Time timestamp) { | 279 int buffer_id, base::Time timestamp) { |
292 DCHECK(capture_message_loop_proxy_->BelongsToCurrentThread()); | 280 DCHECK(capture_message_loop_proxy_->BelongsToCurrentThread()); |
293 | 281 |
294 if (state_ != VIDEO_CAPTURE_STATE_STARTED || suspended_) { | 282 if (state_ != VIDEO_CAPTURE_STATE_STARTED || suspended_) { |
295 Send(new VideoCaptureHostMsg_BufferReady(device_id_, buffer_id)); | 283 Send(new VideoCaptureHostMsg_BufferReady(device_id_, buffer_id)); |
296 return; | 284 return; |
297 } | 285 } |
298 | 286 |
299 media::VideoCapture::VideoFrameBuffer* buffer; | 287 ClientBufferMap::iterator iter = client_buffers_.find(buffer_id); |
300 DCHECK(cached_dibs_.find(buffer_id) != cached_dibs_.end()); | 288 DCHECK(iter != client_buffers_.end()); |
301 buffer = cached_dibs_[buffer_id]->mapped_memory.get(); | 289 scoped_refptr<ClientBuffer> buffer = iter->second; |
302 buffer->timestamp = timestamp; | 290 scoped_refptr<media::VideoFrame> frame = |
291 media::VideoFrame::WrapExternalSharedMemory( | |
ncarter (slow)
2013/09/11 18:04:56
Exciting. This is gonna work great with https://co
| |
292 media::VideoFrame::I420, | |
293 gfx::Size(buffer->frame_stride, buffer->frame_height), | |
294 gfx::Rect(0, 0, buffer->frame_width, buffer->frame_height), | |
295 gfx::Size(buffer->frame_width, buffer->frame_height), | |
296 reinterpret_cast<uint8*>(buffer->buffer->memory()), | |
297 buffer->buffer_size, | |
298 buffer->buffer->handle(), | |
299 // TODO(sheu): convert VideoCaptureMessageFilter::Delegate to use | |
300 // base::TimeTicks instead of base::Time. http://crbug.com/249215 | |
301 timestamp - base::Time::UnixEpoch(), | |
302 base::Bind( | |
303 base::IgnoreResult(&base::MessageLoopProxy::PostTask), | |
304 capture_message_loop_proxy_, | |
305 FROM_HERE, | |
306 base::Bind( | |
307 &VideoCaptureImpl::DoClientBufferFinishedOnCaptureThread, | |
308 client_buffer_weak_this_factory_.GetWeakPtr(), | |
309 buffer_id, | |
310 buffer))); | |
303 | 311 |
304 for (ClientInfo::iterator it = clients_.begin(); it != clients_.end(); ++it) { | 312 for (ClientInfo::iterator it = clients_.begin(); it != clients_.end(); ++it) |
305 it->first->OnBufferReady(this, buffer); | 313 it->first->OnFrameReady(this, frame); |
306 } | 314 } |
307 cached_dibs_[buffer_id]->references = clients_.size(); | 315 |
316 void VideoCaptureImpl::DoClientBufferFinishedOnCaptureThread( | |
317 int buffer_id, | |
318 const scoped_refptr<ClientBuffer>& buffer) { | |
319 DCHECK(capture_message_loop_proxy_->BelongsToCurrentThread()); | |
320 Send(new VideoCaptureHostMsg_BufferReady(device_id_, buffer_id)); | |
308 } | 321 } |
309 | 322 |
310 void VideoCaptureImpl::DoStateChangedOnCaptureThread(VideoCaptureState state) { | 323 void VideoCaptureImpl::DoStateChangedOnCaptureThread(VideoCaptureState state) { |
311 DCHECK(capture_message_loop_proxy_->BelongsToCurrentThread()); | 324 DCHECK(capture_message_loop_proxy_->BelongsToCurrentThread()); |
312 | 325 |
313 switch (state) { | 326 switch (state) { |
314 case VIDEO_CAPTURE_STATE_STARTED: | 327 case VIDEO_CAPTURE_STATE_STARTED: |
315 break; | 328 break; |
316 case VIDEO_CAPTURE_STATE_STOPPED: | 329 case VIDEO_CAPTURE_STATE_STOPPED: |
317 state_ = VIDEO_CAPTURE_STATE_STOPPED; | 330 state_ = VIDEO_CAPTURE_STATE_STOPPED; |
318 DVLOG(1) << "OnStateChanged: stopped!, device_id = " << device_id_; | 331 DVLOG(1) << "OnStateChanged: stopped!, device_id = " << device_id_; |
319 STLDeleteValues(&cached_dibs_); | 332 client_buffers_.clear(); |
333 client_buffer_weak_this_factory_.InvalidateWeakPtrs(); | |
320 if (!clients_.empty() || !clients_pending_on_restart_.empty()) | 334 if (!clients_.empty() || !clients_pending_on_restart_.empty()) |
321 RestartCapture(); | 335 RestartCapture(); |
322 break; | 336 break; |
323 case VIDEO_CAPTURE_STATE_PAUSED: | 337 case VIDEO_CAPTURE_STATE_PAUSED: |
324 for (ClientInfo::iterator it = clients_.begin(); | 338 for (ClientInfo::iterator it = clients_.begin(); |
325 it != clients_.end(); ++it) { | 339 it != clients_.end(); ++it) { |
326 it->first->OnPaused(this); | 340 it->first->OnPaused(this); |
327 } | 341 } |
328 break; | 342 break; |
329 case VIDEO_CAPTURE_STATE_ERROR: | 343 case VIDEO_CAPTURE_STATE_ERROR: |
(...skipping 17 matching lines...) Expand all Loading... | |
347 state_ = VIDEO_CAPTURE_STATE_ENDED; | 361 state_ = VIDEO_CAPTURE_STATE_ENDED; |
348 break; | 362 break; |
349 default: | 363 default: |
350 break; | 364 break; |
351 } | 365 } |
352 } | 366 } |
353 | 367 |
354 void VideoCaptureImpl::DoDeviceInfoReceivedOnCaptureThread( | 368 void VideoCaptureImpl::DoDeviceInfoReceivedOnCaptureThread( |
355 const media::VideoCaptureParams& device_info) { | 369 const media::VideoCaptureParams& device_info) { |
356 DCHECK(capture_message_loop_proxy_->BelongsToCurrentThread()); | 370 DCHECK(capture_message_loop_proxy_->BelongsToCurrentThread()); |
357 DCHECK(!ClientHasDIB()); | 371 DCHECK(client_buffers_.empty()); |
358 | |
359 STLDeleteValues(&cached_dibs_); | |
360 | 372 |
361 device_info_ = device_info; | 373 device_info_ = device_info; |
362 device_info_available_ = true; | 374 device_info_available_ = true; |
363 for (ClientInfo::iterator it = clients_.begin(); it != clients_.end(); ++it) { | 375 for (ClientInfo::iterator it = clients_.begin(); it != clients_.end(); ++it) { |
364 it->first->OnDeviceInfoReceived(this, device_info); | 376 it->first->OnDeviceInfoReceived(this, device_info); |
365 } | 377 } |
366 } | 378 } |
367 | 379 |
368 void VideoCaptureImpl::DoDeviceInfoChangedOnCaptureThread( | 380 void VideoCaptureImpl::DoDeviceInfoChangedOnCaptureThread( |
369 const media::VideoCaptureParams& device_info) { | 381 const media::VideoCaptureParams& device_info) { |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
455 message_filter_->RemoveDelegate(this); | 467 message_filter_->RemoveDelegate(this); |
456 capture_message_loop_proxy_->PostTask(FROM_HERE, task); | 468 capture_message_loop_proxy_->PostTask(FROM_HERE, task); |
457 } | 469 } |
458 | 470 |
459 void VideoCaptureImpl::Send(IPC::Message* message) { | 471 void VideoCaptureImpl::Send(IPC::Message* message) { |
460 io_message_loop_proxy_->PostTask(FROM_HERE, | 472 io_message_loop_proxy_->PostTask(FROM_HERE, |
461 base::Bind(base::IgnoreResult(&VideoCaptureMessageFilter::Send), | 473 base::Bind(base::IgnoreResult(&VideoCaptureMessageFilter::Send), |
462 message_filter_.get(), message)); | 474 message_filter_.get(), message)); |
463 } | 475 } |
464 | 476 |
465 bool VideoCaptureImpl::ClientHasDIB() const { | |
466 DCHECK(capture_message_loop_proxy_->BelongsToCurrentThread()); | |
467 for (CachedDIB::const_iterator it = cached_dibs_.begin(); | |
468 it != cached_dibs_.end(); ++it) { | |
469 if (it->second->references > 0) | |
470 return true; | |
471 } | |
472 return false; | |
473 } | |
474 | |
475 bool VideoCaptureImpl::RemoveClient( | 477 bool VideoCaptureImpl::RemoveClient( |
476 media::VideoCapture::EventHandler* handler, | 478 media::VideoCapture::EventHandler* handler, |
477 ClientInfo* clients) { | 479 ClientInfo* clients) { |
478 DCHECK(capture_message_loop_proxy_->BelongsToCurrentThread()); | 480 DCHECK(capture_message_loop_proxy_->BelongsToCurrentThread()); |
479 bool found = false; | 481 bool found = false; |
480 | 482 |
481 ClientInfo::iterator it = clients->find(handler); | 483 ClientInfo::iterator it = clients->find(handler); |
482 if (it != clients->end()) { | 484 if (it != clients->end()) { |
483 handler->OnStopped(this); | 485 handler->OnStopped(this); |
484 handler->OnRemoved(this); | 486 handler->OnRemoved(this); |
485 clients->erase(it); | 487 clients->erase(it); |
486 found = true; | 488 found = true; |
487 } | 489 } |
488 return found; | 490 return found; |
489 } | 491 } |
490 | 492 |
491 } // namespace content | 493 } // namespace content |
OLD | NEW |