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

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

Issue 23587018: Replace media::VideoCapture::VideoFrameBuffer with media::VideoFrame. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@git-svn
Patch Set: a1e0098f Reset timestamps on Stop(). Created 7 years, 3 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
OLDNEW
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
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
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,
Ami GONE FROM CHROMIUM 2013/09/12 22:40:41 nit: It's a bit strange to be using iter given you
sheu 2013/09/13 00:15:19 I got confused about insert-with-hint. :-(
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(
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(
Ami GONE FROM CHROMIUM 2013/09/12 22:40:41 You might enjoy media::BindToLoop().
sheu 2013/09/13 00:15:19 Is there any reason why this isn't in base:: ? we
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698