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