| 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 |