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/callback_helpers.h" | |
9 #include "base/stl_util.h" | 8 #include "base/stl_util.h" |
10 #include "content/child/child_process.h" | 9 #include "content/child/child_process.h" |
11 #include "content/common/media/encoded_video_capture_messages.h" | |
12 #include "content/common/media/video_capture_messages.h" | 10 #include "content/common/media/video_capture_messages.h" |
13 #include "media/base/limits.h" | 11 #include "media/base/limits.h" |
14 | 12 |
15 namespace content { | 13 namespace content { |
16 | 14 |
17 struct VideoCaptureImpl::DIBBuffer { | 15 struct VideoCaptureImpl::DIBBuffer { |
18 public: | 16 public: |
19 DIBBuffer( | 17 DIBBuffer( |
20 base::SharedMemory* d, | 18 base::SharedMemory* d, |
21 media::VideoCapture::VideoFrameBuffer* ptr) | 19 media::VideoCapture::VideoFrameBuffer* ptr) |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
53 base::MessageLoopProxy* capture_message_loop_proxy, | 51 base::MessageLoopProxy* capture_message_loop_proxy, |
54 VideoCaptureMessageFilter* filter) | 52 VideoCaptureMessageFilter* filter) |
55 : VideoCapture(), | 53 : VideoCapture(), |
56 message_filter_(filter), | 54 message_filter_(filter), |
57 capture_message_loop_proxy_(capture_message_loop_proxy), | 55 capture_message_loop_proxy_(capture_message_loop_proxy), |
58 io_message_loop_proxy_(ChildProcess::current()->io_message_loop_proxy()), | 56 io_message_loop_proxy_(ChildProcess::current()->io_message_loop_proxy()), |
59 device_id_(0), | 57 device_id_(0), |
60 video_type_(media::VideoCaptureCapability::kI420), | 58 video_type_(media::VideoCaptureCapability::kI420), |
61 device_info_available_(false), | 59 device_info_available_(false), |
62 suspended_(false), | 60 suspended_(false), |
63 state_(VIDEO_CAPTURE_STATE_STOPPED), | 61 state_(VIDEO_CAPTURE_STATE_STOPPED) { |
64 encoded_video_source_client_(NULL), | |
65 bitstream_open_(false) { | |
66 DCHECK(filter); | 62 DCHECK(filter); |
67 capture_format_.session_id = id; | 63 capture_format_.session_id = id; |
68 } | 64 } |
69 | 65 |
70 VideoCaptureImpl::~VideoCaptureImpl() { | 66 VideoCaptureImpl::~VideoCaptureImpl() { |
71 STLDeleteValues(&cached_dibs_); | 67 STLDeleteValues(&cached_dibs_); |
72 } | 68 } |
73 | 69 |
74 void VideoCaptureImpl::Init() { | 70 void VideoCaptureImpl::Init() { |
75 if (!io_message_loop_proxy_->BelongsToCurrentThread()) { | 71 if (!io_message_loop_proxy_->BelongsToCurrentThread()) { |
(...skipping 20 matching lines...) Expand all Loading... |
96 base::Bind(&VideoCaptureImpl::DoStartCaptureOnCaptureThread, | 92 base::Bind(&VideoCaptureImpl::DoStartCaptureOnCaptureThread, |
97 base::Unretained(this), handler, capability)); | 93 base::Unretained(this), handler, capability)); |
98 } | 94 } |
99 | 95 |
100 void VideoCaptureImpl::StopCapture(media::VideoCapture::EventHandler* handler) { | 96 void VideoCaptureImpl::StopCapture(media::VideoCapture::EventHandler* handler) { |
101 capture_message_loop_proxy_->PostTask(FROM_HERE, | 97 capture_message_loop_proxy_->PostTask(FROM_HERE, |
102 base::Bind(&VideoCaptureImpl::DoStopCaptureOnCaptureThread, | 98 base::Bind(&VideoCaptureImpl::DoStopCaptureOnCaptureThread, |
103 base::Unretained(this), handler)); | 99 base::Unretained(this), handler)); |
104 } | 100 } |
105 | 101 |
106 void VideoCaptureImpl::RequestCapabilities( | |
107 const media::EncodedVideoSource::RequestCapabilitiesCallback& callback) { | |
108 capture_message_loop_proxy_->PostTask(FROM_HERE, | |
109 base::Bind(&VideoCaptureImpl::DoRequestCapabilitiesOnCaptureThread, | |
110 base::Unretained(this), callback)); | |
111 } | |
112 | |
113 void VideoCaptureImpl::StartFetchCapabilities() { | |
114 Send(new EncodedVideoCaptureHostMsg_GetCapabilities( | |
115 device_id_, capture_format_.session_id)); | |
116 } | |
117 | |
118 void VideoCaptureImpl::OpenBitstream( | |
119 media::EncodedVideoSource::Client* client, | |
120 const media::VideoEncodingParameters& params) { | |
121 capture_message_loop_proxy_->PostTask(FROM_HERE, | |
122 base::Bind(&VideoCaptureImpl::DoOpenBitstreamOnCaptureThread, | |
123 base::Unretained(this), client, params)); | |
124 } | |
125 | |
126 void VideoCaptureImpl::CloseBitstream() { | |
127 capture_message_loop_proxy_->PostTask(FROM_HERE, | |
128 base::Bind(&VideoCaptureImpl::DoCloseBitstreamOnCaptureThread, | |
129 base::Unretained(this))); | |
130 } | |
131 | |
132 void VideoCaptureImpl::ReturnBitstreamBuffer( | |
133 scoped_refptr<const media::EncodedBitstreamBuffer> buffer) { | |
134 Send(new EncodedVideoCaptureHostMsg_BitstreamBufferConsumed( | |
135 device_id_, buffer->buffer_id())); | |
136 } | |
137 | |
138 void VideoCaptureImpl::TrySetBitstreamConfig( | |
139 const media::RuntimeVideoEncodingParameters& params) { | |
140 Send(new EncodedVideoCaptureHostMsg_TryConfigureBitstream( | |
141 device_id_, params)); | |
142 } | |
143 | |
144 void VideoCaptureImpl::RequestKeyFrame() { | |
145 Send(new EncodedVideoCaptureHostMsg_RequestKeyFrame(device_id_)); | |
146 } | |
147 | |
148 void VideoCaptureImpl::OnEncodingCapabilitiesAvailable( | |
149 const media::VideoEncodingCapabilities& capabilities) { | |
150 capture_message_loop_proxy_->PostTask(FROM_HERE, base::Bind( | |
151 &VideoCaptureImpl::DoNotifyCapabilitiesAvailableOnCaptureThread, | |
152 base::Unretained(this), capabilities)); | |
153 } | |
154 | |
155 void VideoCaptureImpl::OnEncodedBitstreamOpened( | |
156 const media::VideoEncodingParameters& params, | |
157 const std::vector<base::SharedMemoryHandle>& buffers, | |
158 uint32 buffer_size) { | |
159 capture_message_loop_proxy_->PostTask(FROM_HERE, | |
160 base::Bind(&VideoCaptureImpl::DoNotifyBitstreamOpenedOnCaptureThread, | |
161 base::Unretained(this), params, buffers, buffer_size)); | |
162 } | |
163 | |
164 void VideoCaptureImpl::OnEncodedBitstreamClosed() { | |
165 capture_message_loop_proxy_->PostTask(FROM_HERE, | |
166 base::Bind(&VideoCaptureImpl::DoNotifyBitstreamClosedOnCaptureThread, | |
167 base::Unretained(this))); | |
168 } | |
169 | |
170 void VideoCaptureImpl::OnEncodingConfigChanged( | |
171 const media::RuntimeVideoEncodingParameters& params) { | |
172 capture_message_loop_proxy_->PostTask(FROM_HERE, | |
173 base::Bind( | |
174 &VideoCaptureImpl::DoNotifyBitstreamConfigChangedOnCaptureThread, | |
175 base::Unretained(this), params)); | |
176 } | |
177 | |
178 void VideoCaptureImpl::OnEncodedBufferReady( | |
179 int buffer_id, | |
180 uint32 size, | |
181 const media::BufferEncodingMetadata& metadata) { | |
182 capture_message_loop_proxy_->PostTask(FROM_HERE, | |
183 base::Bind(&VideoCaptureImpl::DoNotifyBitstreamBufferReadyOnCaptureThread, | |
184 base::Unretained(this), buffer_id, size, metadata)); | |
185 } | |
186 | |
187 void VideoCaptureImpl::FeedBuffer(scoped_refptr<VideoFrameBuffer> buffer) { | 102 void VideoCaptureImpl::FeedBuffer(scoped_refptr<VideoFrameBuffer> buffer) { |
188 capture_message_loop_proxy_->PostTask(FROM_HERE, | 103 capture_message_loop_proxy_->PostTask(FROM_HERE, |
189 base::Bind(&VideoCaptureImpl::DoFeedBufferOnCaptureThread, | 104 base::Bind(&VideoCaptureImpl::DoFeedBufferOnCaptureThread, |
190 base::Unretained(this), buffer)); | 105 base::Unretained(this), buffer)); |
191 } | 106 } |
192 | 107 |
193 void VideoCaptureImpl::OnBufferCreated( | 108 void VideoCaptureImpl::OnBufferCreated( |
194 base::SharedMemoryHandle handle, | 109 base::SharedMemoryHandle handle, |
195 int length, int buffer_id) { | 110 int length, int buffer_id) { |
196 capture_message_loop_proxy_->PostTask(FROM_HERE, | 111 capture_message_loop_proxy_->PostTask(FROM_HERE, |
(...skipping 193 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
390 it->first->OnBufferReady(this, buffer); | 305 it->first->OnBufferReady(this, buffer); |
391 } | 306 } |
392 cached_dibs_[buffer_id]->references = clients_.size(); | 307 cached_dibs_[buffer_id]->references = clients_.size(); |
393 } | 308 } |
394 | 309 |
395 void VideoCaptureImpl::DoStateChangedOnCaptureThread(VideoCaptureState state) { | 310 void VideoCaptureImpl::DoStateChangedOnCaptureThread(VideoCaptureState state) { |
396 DCHECK(capture_message_loop_proxy_->BelongsToCurrentThread()); | 311 DCHECK(capture_message_loop_proxy_->BelongsToCurrentThread()); |
397 | 312 |
398 switch (state) { | 313 switch (state) { |
399 case VIDEO_CAPTURE_STATE_STARTED: | 314 case VIDEO_CAPTURE_STATE_STARTED: |
400 if (!encoding_caps_callback_.is_null()) { | |
401 StartFetchCapabilities(); | |
402 } | |
403 break; | 315 break; |
404 case VIDEO_CAPTURE_STATE_STOPPED: | 316 case VIDEO_CAPTURE_STATE_STOPPED: |
405 state_ = VIDEO_CAPTURE_STATE_STOPPED; | 317 state_ = VIDEO_CAPTURE_STATE_STOPPED; |
406 DVLOG(1) << "OnStateChanged: stopped!, device_id = " << device_id_; | 318 DVLOG(1) << "OnStateChanged: stopped!, device_id = " << device_id_; |
407 STLDeleteValues(&cached_dibs_); | 319 STLDeleteValues(&cached_dibs_); |
408 if (!clients_.empty() || !clients_pending_on_restart_.empty()) | 320 if (!clients_.empty() || !clients_pending_on_restart_.empty()) |
409 RestartCapture(); | 321 RestartCapture(); |
410 break; | 322 break; |
411 case VIDEO_CAPTURE_STATE_PAUSED: | 323 case VIDEO_CAPTURE_STATE_PAUSED: |
412 for (ClientInfo::iterator it = clients_.begin(); | 324 for (ClientInfo::iterator it = clients_.begin(); |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
476 } | 388 } |
477 } | 389 } |
478 | 390 |
479 void VideoCaptureImpl::DoSuspendCaptureOnCaptureThread(bool suspend) { | 391 void VideoCaptureImpl::DoSuspendCaptureOnCaptureThread(bool suspend) { |
480 DVLOG(1) << "DoSuspendCapture: suspend " << (suspend ? "yes" : "no"); | 392 DVLOG(1) << "DoSuspendCapture: suspend " << (suspend ? "yes" : "no"); |
481 DCHECK(capture_message_loop_proxy_->BelongsToCurrentThread()); | 393 DCHECK(capture_message_loop_proxy_->BelongsToCurrentThread()); |
482 | 394 |
483 suspended_ = suspend; | 395 suspended_ = suspend; |
484 } | 396 } |
485 | 397 |
486 void VideoCaptureImpl::DoRequestCapabilitiesOnCaptureThread( | |
487 const RequestCapabilitiesCallback& callback) { | |
488 DCHECK(capture_message_loop_proxy_->BelongsToCurrentThread()); | |
489 DCHECK(encoding_caps_callback_.is_null()); | |
490 encoding_caps_callback_ = callback; | |
491 | |
492 // Invoke callback immediately if capabilities are already available. | |
493 if (!encoding_caps_.empty()) | |
494 base::ResetAndReturn(&encoding_caps_callback_).Run(encoding_caps_); | |
495 } | |
496 | |
497 void VideoCaptureImpl::DoOpenBitstreamOnCaptureThread( | |
498 media::EncodedVideoSource::Client* client, | |
499 const media::VideoEncodingParameters& params) { | |
500 DCHECK(capture_message_loop_proxy_->BelongsToCurrentThread()); | |
501 DCHECK(!encoded_video_source_client_); | |
502 encoded_video_source_client_ = client; | |
503 Send(new EncodedVideoCaptureHostMsg_OpenBitstream( | |
504 device_id_, capture_format_.session_id, params)); | |
505 } | |
506 | |
507 void VideoCaptureImpl::DoCloseBitstreamOnCaptureThread() { | |
508 DCHECK(capture_message_loop_proxy_->BelongsToCurrentThread()); | |
509 DCHECK(bitstream_open_); | |
510 | |
511 // Immediately clear EVS client pointer and release bitstream buffers if the | |
512 // client requests to close bitstream. Any further encoded capture messages | |
513 // from the browser process will be ignored. | |
514 bitstream_open_ = false; | |
515 for (size_t i = 0; i < bitstream_buffers_.size(); ++i) { | |
516 bitstream_buffers_[i]->Close(); | |
517 delete bitstream_buffers_[i]; | |
518 } | |
519 bitstream_buffers_.clear(); | |
520 encoded_video_source_client_ = NULL; | |
521 | |
522 Send(new EncodedVideoCaptureHostMsg_CloseBitstream(device_id_)); | |
523 } | |
524 | |
525 void VideoCaptureImpl::DoNotifyBitstreamOpenedOnCaptureThread( | |
526 const media::VideoEncodingParameters& params, | |
527 const std::vector<base::SharedMemoryHandle>& buffers, | |
528 uint32 buffer_size) { | |
529 DCHECK(capture_message_loop_proxy_->BelongsToCurrentThread()); | |
530 DCHECK(!bitstream_open_ && bitstream_buffers_.empty()); | |
531 if (!encoded_video_source_client_) | |
532 return; | |
533 bitstream_open_ = true; | |
534 for (size_t i = 0; i < buffers.size(); ++i) { | |
535 base::SharedMemory* shm = new base::SharedMemory(buffers[i], true); | |
536 CHECK(shm->Map(buffer_size)); | |
537 bitstream_buffers_.push_back(shm); | |
538 } | |
539 encoded_video_source_client_->OnOpened(params); | |
540 } | |
541 | |
542 void VideoCaptureImpl::DoNotifyBitstreamClosedOnCaptureThread() { | |
543 DCHECK(capture_message_loop_proxy_->BelongsToCurrentThread()); | |
544 | |
545 // Ignore the BitstreamClosed message if bitstream has already been closed | |
546 // by the EVS client. | |
547 if (!bitstream_open_) | |
548 return; | |
549 | |
550 // The bitstream may still be open when we receive BitstreamClosed message | |
551 // if the request to close bitstream comes from the browser process. | |
552 bitstream_open_ = false; | |
553 for (size_t i = 0; i < bitstream_buffers_.size(); ++i) { | |
554 bitstream_buffers_[i]->Close(); | |
555 delete bitstream_buffers_[i]; | |
556 } | |
557 bitstream_buffers_.clear(); | |
558 if (encoded_video_source_client_) { | |
559 encoded_video_source_client_->OnClosed(); | |
560 encoded_video_source_client_ = NULL; | |
561 } | |
562 } | |
563 | |
564 void VideoCaptureImpl::DoNotifyBitstreamConfigChangedOnCaptureThread( | |
565 const media::RuntimeVideoEncodingParameters& params) { | |
566 DCHECK(capture_message_loop_proxy_->BelongsToCurrentThread()); | |
567 if (!encoded_video_source_client_) | |
568 return; | |
569 encoded_video_source_client_->OnConfigChanged(params); | |
570 } | |
571 | |
572 void VideoCaptureImpl::DoNotifyBitstreamBufferReadyOnCaptureThread( | |
573 int buffer_id, | |
574 uint32 size, | |
575 const media::BufferEncodingMetadata& metadata) { | |
576 DCHECK(capture_message_loop_proxy_->BelongsToCurrentThread()); | |
577 if (!encoded_video_source_client_) | |
578 return; | |
579 if (buffer_id >= 0 && | |
580 static_cast<size_t>(buffer_id) < bitstream_buffers_.size()) { | |
581 base::SharedMemory* shm = bitstream_buffers_.at(buffer_id); | |
582 scoped_refptr<media::EncodedBitstreamBuffer> buffer = | |
583 new media::EncodedBitstreamBuffer( | |
584 buffer_id, (uint8*)shm->memory(), size, shm->handle(), | |
585 metadata, base::Bind(&base::DoNothing)); | |
586 encoded_video_source_client_->OnBufferReady(buffer); | |
587 } | |
588 } | |
589 | |
590 void VideoCaptureImpl::DoNotifyCapabilitiesAvailableOnCaptureThread( | |
591 const media::VideoEncodingCapabilities& capabilities) { | |
592 DCHECK(capture_message_loop_proxy_->BelongsToCurrentThread()); | |
593 encoding_caps_ = capabilities; | |
594 if (!encoding_caps_callback_.is_null()) | |
595 base::ResetAndReturn(&encoding_caps_callback_).Run(encoding_caps_); | |
596 } | |
597 | |
598 void VideoCaptureImpl::StopDevice() { | 398 void VideoCaptureImpl::StopDevice() { |
599 DCHECK(capture_message_loop_proxy_->BelongsToCurrentThread()); | 399 DCHECK(capture_message_loop_proxy_->BelongsToCurrentThread()); |
600 | 400 |
601 device_info_available_ = false; | 401 device_info_available_ = false; |
602 if (state_ == VIDEO_CAPTURE_STATE_STARTED) { | 402 if (state_ == VIDEO_CAPTURE_STATE_STARTED) { |
603 state_ = VIDEO_CAPTURE_STATE_STOPPING; | 403 state_ = VIDEO_CAPTURE_STATE_STOPPING; |
604 Send(new VideoCaptureHostMsg_Stop(device_id_)); | 404 Send(new VideoCaptureHostMsg_Stop(device_id_)); |
605 capture_format_.width = capture_format_.height = 0; | 405 capture_format_.width = capture_format_.height = 0; |
606 } | 406 } |
607 } | 407 } |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
682 if (it != clients->end()) { | 482 if (it != clients->end()) { |
683 handler->OnStopped(this); | 483 handler->OnStopped(this); |
684 handler->OnRemoved(this); | 484 handler->OnRemoved(this); |
685 clients->erase(it); | 485 clients->erase(it); |
686 found = true; | 486 found = true; |
687 } | 487 } |
688 return found; | 488 return found; |
689 } | 489 } |
690 | 490 |
691 } // namespace content | 491 } // namespace content |
OLD | NEW |