| Index: content/browser/renderer_host/media/video_capture_controller.cc
|
| diff --git a/content/browser/renderer_host/media/video_capture_controller.cc b/content/browser/renderer_host/media/video_capture_controller.cc
|
| index a6a2f0f1b676d887dcffd503b4b88e4c80dd0fa3..550a8b06740a20b8a46a33dcf68687c0470ffa6e 100644
|
| --- a/content/browser/renderer_host/media/video_capture_controller.cc
|
| +++ b/content/browser/renderer_host/media/video_capture_controller.cc
|
| @@ -19,6 +19,7 @@
|
| #include "components/display_compositor/gl_helper.h"
|
| #include "content/browser/renderer_host/media/media_stream_manager.h"
|
| #include "content/browser/renderer_host/media/video_capture_manager.h"
|
| +#include "content/common/video_capture.mojom.h"
|
| #include "content/public/browser/browser_thread.h"
|
| #include "content/public/common/content_switches.h"
|
| #include "media/base/video_frame.h"
|
| @@ -46,6 +47,21 @@ static const int kInfiniteRatio = 99999;
|
| name, \
|
| (height) ? ((width) * 100) / (height) : kInfiniteRatio);
|
|
|
| +// This manual copy routine is needed because base::DictionaryValue does not
|
| +// allow the default copy operator.
|
| +media::mojom::VideoFrameInfoPtr CloneFrameInfo(
|
| + media::mojom::VideoFrameInfoPtr* frame_info) {
|
| + auto result = media::mojom::VideoFrameInfo::New();
|
| + result->timestamp = (*frame_info)->timestamp;
|
| + result->pixel_format = (*frame_info)->pixel_format;
|
| + result->storage_type = (*frame_info)->storage_type;
|
| + result->coded_size = (*frame_info)->coded_size;
|
| + result->visible_rect = (*frame_info)->visible_rect;
|
| + result->metadata = base::MakeUnique<base::DictionaryValue>();
|
| + result->metadata->MergeDictionary((*frame_info)->metadata.get());
|
| + return result;
|
| +}
|
| +
|
| } // anonymous namespace
|
|
|
| struct VideoCaptureController::ControllerClient {
|
| @@ -94,13 +110,12 @@ struct VideoCaptureController::ControllerClient {
|
|
|
| VideoCaptureController::BufferState::BufferState(
|
| int buffer_id,
|
| - int frame_feedback_id,
|
| media::VideoFrameConsumerFeedbackObserver* consumer_feedback_observer,
|
| - media::FrameBufferPool* frame_buffer_pool)
|
| + mojo::ScopedSharedBufferHandle handle)
|
| : buffer_id_(buffer_id),
|
| - frame_feedback_id_(frame_feedback_id),
|
| + frame_feedback_id_(0),
|
| consumer_feedback_observer_(consumer_feedback_observer),
|
| - frame_buffer_pool_(frame_buffer_pool),
|
| + buffer_handle_(std::move(handle)),
|
| max_consumer_utilization_(
|
| media::VideoFrameConsumerFeedbackObserver::kNoUtilizationRecorded),
|
| consumer_hold_count_(0) {}
|
| @@ -108,7 +123,20 @@ VideoCaptureController::BufferState::BufferState(
|
| VideoCaptureController::BufferState::~BufferState() = default;
|
|
|
| VideoCaptureController::BufferState::BufferState(
|
| - const VideoCaptureController::BufferState& other) = default;
|
| + VideoCaptureController::BufferState&& other) = default;
|
| +
|
| +VideoCaptureController::BufferState& VideoCaptureController::BufferState::
|
| +operator=(BufferState&& other) = default;
|
| +
|
| +void VideoCaptureController::BufferState::set_read_permission(
|
| + std::unique_ptr<media::Ownership> buffer_read_permission) {
|
| + buffer_read_permission_ = std::move(buffer_read_permission);
|
| +}
|
| +
|
| +void VideoCaptureController::BufferState::set_frame_feedback_id(
|
| + int frame_feedback_id) {
|
| + frame_feedback_id_ = frame_feedback_id;
|
| +}
|
|
|
| void VideoCaptureController::BufferState::RecordConsumerUtilization(
|
| double utilization) {
|
| @@ -119,13 +147,11 @@ void VideoCaptureController::BufferState::RecordConsumerUtilization(
|
| }
|
|
|
| void VideoCaptureController::BufferState::IncreaseConsumerCount() {
|
| - if (consumer_hold_count_ == 0)
|
| - if (frame_buffer_pool_ != nullptr)
|
| - frame_buffer_pool_->SetBufferHold(buffer_id_);
|
| consumer_hold_count_++;
|
| }
|
|
|
| void VideoCaptureController::BufferState::DecreaseConsumerCount() {
|
| + LOG(ERROR) << "1";
|
| consumer_hold_count_--;
|
| if (consumer_hold_count_ == 0) {
|
| if (consumer_feedback_observer_ != nullptr &&
|
| @@ -134,8 +160,7 @@ void VideoCaptureController::BufferState::DecreaseConsumerCount() {
|
| consumer_feedback_observer_->OnUtilizationReport(
|
| frame_feedback_id_, max_consumer_utilization_);
|
| }
|
| - if (frame_buffer_pool_ != nullptr)
|
| - frame_buffer_pool_->ReleaseBufferHold(buffer_id_);
|
| + buffer_read_permission_.reset();
|
| max_consumer_utilization_ =
|
| media::VideoFrameConsumerFeedbackObserver::kNoUtilizationRecorded;
|
| }
|
| @@ -145,19 +170,18 @@ bool VideoCaptureController::BufferState::HasZeroConsumerHoldCount() {
|
| return consumer_hold_count_ == 0;
|
| }
|
|
|
| +mojo::ScopedSharedBufferHandle
|
| +VideoCaptureController::BufferState::CreateHandleCopy() {
|
| + return buffer_handle_->Clone();
|
| +}
|
| +
|
| void VideoCaptureController::BufferState::SetConsumerFeedbackObserver(
|
| media::VideoFrameConsumerFeedbackObserver* consumer_feedback_observer) {
|
| consumer_feedback_observer_ = consumer_feedback_observer;
|
| }
|
|
|
| -void VideoCaptureController::BufferState::SetFrameBufferPool(
|
| - media::FrameBufferPool* frame_buffer_pool) {
|
| - frame_buffer_pool_ = frame_buffer_pool;
|
| -}
|
| -
|
| VideoCaptureController::VideoCaptureController()
|
| - : frame_buffer_pool_(nullptr),
|
| - consumer_feedback_observer_(nullptr),
|
| + : consumer_feedback_observer_(nullptr),
|
| state_(VIDEO_CAPTURE_STATE_STARTED),
|
| has_received_frames_(false),
|
| weak_ptr_factory_(this) {
|
| @@ -171,23 +195,14 @@ VideoCaptureController::GetWeakPtrForIOThread() {
|
| return weak_ptr_factory_.GetWeakPtr();
|
| }
|
|
|
| -void VideoCaptureController::SetFrameBufferPool(
|
| - std::unique_ptr<media::FrameBufferPool> frame_buffer_pool) {
|
| - DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| - frame_buffer_pool_ = std::move(frame_buffer_pool);
|
| - // Update existing BufferState entries.
|
| - for (auto& entry : buffer_id_to_state_map_)
|
| - entry.second.SetFrameBufferPool(frame_buffer_pool_.get());
|
| -}
|
| -
|
| void VideoCaptureController::SetConsumerFeedbackObserver(
|
| std::unique_ptr<media::VideoFrameConsumerFeedbackObserver>
|
| consumer_feedback_observer) {
|
| DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| consumer_feedback_observer_ = std::move(consumer_feedback_observer);
|
| // Update existing BufferState entries.
|
| - for (auto& entry : buffer_id_to_state_map_)
|
| - entry.second.SetConsumerFeedbackObserver(consumer_feedback_observer_.get());
|
| + for (auto& entry : buffer_states_)
|
| + entry.SetConsumerFeedbackObserver(consumer_feedback_observer_.get());
|
| }
|
|
|
| void VideoCaptureController::AddClient(
|
| @@ -249,9 +264,11 @@ int VideoCaptureController::RemoveClient(
|
| if (!client)
|
| return kInvalidMediaCaptureSessionId;
|
|
|
| - // Take back all buffers held by the |client|.
|
| - for (const auto& buffer_id : client->buffers_in_use)
|
| - buffer_id_to_state_map_.at(buffer_id).DecreaseConsumerCount();
|
| + for (const auto& buffer_id : client->buffers_in_use) {
|
| + OnClientFinishedConsumingBuffer(
|
| + client, buffer_id,
|
| + media::VideoFrameConsumerFeedbackObserver::kNoUtilizationRecorded);
|
| + }
|
| client->buffers_in_use.clear();
|
|
|
| int session_id = client->session_id;
|
| @@ -355,11 +372,10 @@ void VideoCaptureController::ReturnBuffer(
|
| NOTREACHED();
|
| return;
|
| }
|
| -
|
| - BufferState& buffer_state = buffer_id_to_state_map_.at(buffer_id);
|
| - buffer_state.RecordConsumerUtilization(consumer_resource_utilization);
|
| - buffer_state.DecreaseConsumerCount();
|
| client->buffers_in_use.erase(buffers_in_use_entry_iter);
|
| +
|
| + OnClientFinishedConsumingBuffer(client, buffer_id,
|
| + consumer_resource_utilization);
|
| }
|
|
|
| const media::VideoCaptureFormat&
|
| @@ -368,51 +384,42 @@ VideoCaptureController::GetVideoCaptureFormat() const {
|
| return video_capture_format_;
|
| }
|
|
|
| -void VideoCaptureController::OnIncomingCapturedVideoFrame(
|
| - media::VideoCaptureDevice::Client::Buffer buffer,
|
| - scoped_refptr<VideoFrame> frame) {
|
| +void VideoCaptureController::OnNewBufferHandle(
|
| + int buffer_id,
|
| + std::unique_ptr<media::BufferHandleProvider> handle_provider) {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| + DCHECK(std::find_if(buffer_states_.begin(), buffer_states_.end(),
|
| + [buffer_id](const BufferState& entry) {
|
| + return entry.buffer_id() == buffer_id;
|
| + }) == buffer_states_.end());
|
| + buffer_states_.emplace_back(
|
| + buffer_id, consumer_feedback_observer_.get(),
|
| + handle_provider->GetHandleForInterProcessTransit());
|
| +}
|
| +
|
| +void VideoCaptureController::OnFrameReadyInBuffer(
|
| + int buffer_id,
|
| + int frame_feedback_id,
|
| + std::unique_ptr<media::Ownership> buffer_read_permission,
|
| + media::mojom::VideoFrameInfoPtr frame_info) {
|
| DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| - const int buffer_id = buffer.id();
|
| DCHECK_NE(buffer_id, media::VideoCaptureBufferPool::kInvalidId);
|
|
|
| - // Insert if not exists.
|
| - const auto it =
|
| - buffer_id_to_state_map_
|
| - .insert(std::make_pair(
|
| - buffer_id, BufferState(buffer_id, buffer.frame_feedback_id(),
|
| - consumer_feedback_observer_.get(),
|
| - frame_buffer_pool_.get())))
|
| - .first;
|
| - BufferState& buffer_state = it->second;
|
| - DCHECK(buffer_state.HasZeroConsumerHoldCount());
|
| + auto buffer_state_iter =
|
| + std::find_if(buffer_states_.begin(), buffer_states_.end(),
|
| + [buffer_id](const BufferState& entry) {
|
| + return entry.buffer_id() == buffer_id;
|
| + });
|
| + DCHECK(buffer_state_iter != buffer_states_.end());
|
| + DCHECK(buffer_state_iter->HasZeroConsumerHoldCount());
|
| + buffer_state_iter->set_frame_feedback_id(frame_feedback_id);
|
|
|
| if (state_ == VIDEO_CAPTURE_STATE_STARTED) {
|
| - if (!frame->metadata()->HasKey(VideoFrameMetadata::FRAME_RATE)) {
|
| - frame->metadata()->SetDouble(VideoFrameMetadata::FRAME_RATE,
|
| - video_capture_format_.frame_rate);
|
| - }
|
| - std::unique_ptr<base::DictionaryValue> metadata =
|
| - frame->metadata()->CopyInternalValues();
|
| -
|
| - // Only I420 and Y16 pixel formats are currently supported.
|
| - DCHECK(frame->format() == media::PIXEL_FORMAT_I420 ||
|
| - frame->format() == media::PIXEL_FORMAT_Y16)
|
| - << "Unsupported pixel format: "
|
| - << media::VideoPixelFormatToString(frame->format());
|
| -
|
| - // Sanity-checks to confirm |frame| is actually being backed by |buffer|.
|
| - auto buffer_access = buffer.handle_provider->GetHandleForInProcessAccess();
|
| - DCHECK(frame->storage_type() == media::VideoFrame::STORAGE_SHMEM);
|
| - DCHECK(frame->data(media::VideoFrame::kYPlane) >= buffer_access->data() &&
|
| - (frame->data(media::VideoFrame::kYPlane) <
|
| - (buffer_access->data() + buffer_access->mapped_size())))
|
| - << "VideoFrame does not appear to be backed by Buffer";
|
| -
|
| for (const auto& client : controller_clients_) {
|
| if (client->session_closed || client->paused)
|
| continue;
|
|
|
| - // On the first use of a buffer on a client, share the memory handles.
|
| + // On the first use of a buffer on a client, call OnBufferCreated().
|
| auto known_buffers_entry_iter =
|
| std::find(std::begin(client->known_buffers),
|
| std::end(client->known_buffers), buffer_id);
|
| @@ -422,15 +429,19 @@ void VideoCaptureController::OnIncomingCapturedVideoFrame(
|
| is_new_buffer = true;
|
| }
|
| if (is_new_buffer) {
|
| - mojo::ScopedSharedBufferHandle handle =
|
| - buffer.handle_provider->GetHandleForInterProcessTransit();
|
| + size_t mapped_size =
|
| + media::VideoCaptureFormat(frame_info->coded_size, 0.0f,
|
| + frame_info->pixel_format,
|
| + frame_info->storage_type)
|
| + .ImageAllocationSize();
|
| client->event_handler->OnBufferCreated(
|
| - client->controller_id, std::move(handle),
|
| - buffer_access->mapped_size(), buffer_id);
|
| + client->controller_id, buffer_state_iter->CreateHandleCopy(),
|
| + mapped_size, buffer_id);
|
| }
|
| - client->event_handler->OnBufferReady(client->controller_id, buffer_id,
|
| - frame);
|
|
|
| + auto frame_info_copy = CloneFrameInfo(&frame_info);
|
| + client->event_handler->OnBufferReady(client->controller_id, buffer_id,
|
| + std::move(frame_info_copy));
|
| auto buffers_in_use_entry_iter =
|
| std::find(std::begin(client->buffers_in_use),
|
| std::end(client->buffers_in_use), buffer_id);
|
| @@ -438,21 +449,28 @@ void VideoCaptureController::OnIncomingCapturedVideoFrame(
|
| client->buffers_in_use.push_back(buffer_id);
|
| else
|
| DCHECK(false) << "Unexpected duplicate buffer: " << buffer_id;
|
| - buffer_state.IncreaseConsumerCount();
|
| + // Use if-check, because we are in a loop and only want to do this
|
| + // move operation once.
|
| + if (buffer_read_permission) {
|
| + buffer_state_iter->set_read_permission(
|
| + std::move(buffer_read_permission));
|
| + }
|
| + buffer_state_iter->IncreaseConsumerCount();
|
| }
|
| }
|
|
|
| if (!has_received_frames_) {
|
| UMA_HISTOGRAM_COUNTS("Media.VideoCapture.Width",
|
| - frame->visible_rect().width());
|
| + frame_info->coded_size.width());
|
| UMA_HISTOGRAM_COUNTS("Media.VideoCapture.Height",
|
| - frame->visible_rect().height());
|
| + frame_info->coded_size.height());
|
| UMA_HISTOGRAM_ASPECT_RATIO("Media.VideoCapture.AspectRatio",
|
| - frame->visible_rect().width(),
|
| - frame->visible_rect().height());
|
| + frame_info->coded_size.width(),
|
| + frame_info->coded_size.height());
|
| double frame_rate = 0.0f;
|
| - if (!frame->metadata()->GetDouble(VideoFrameMetadata::FRAME_RATE,
|
| - &frame_rate)) {
|
| + media::VideoFrameMetadata metadata;
|
| + metadata.MergeInternalValuesFrom(*frame_info->metadata);
|
| + if (!metadata.GetDouble(VideoFrameMetadata::FRAME_RATE, &frame_rate)) {
|
| frame_rate = video_capture_format_.frame_rate;
|
| }
|
| UMA_HISTOGRAM_COUNTS("Media.VideoCapture.FrameRate", frame_rate);
|
| @@ -460,6 +478,26 @@ void VideoCaptureController::OnIncomingCapturedVideoFrame(
|
| }
|
| }
|
|
|
| +void VideoCaptureController::OnBufferRetired(int buffer_id) {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| +
|
| + auto buffer_state_iter =
|
| + std::find_if(buffer_states_.begin(), buffer_states_.end(),
|
| + [buffer_id](const BufferState& entry) {
|
| + return entry.buffer_id() == buffer_id;
|
| + });
|
| + DCHECK(buffer_state_iter != buffer_states_.end());
|
| +
|
| + // If there are any clients still using the buffer, we need to allow them
|
| + // to finish up. We need to hold on to the BufferState entry until then,
|
| + // because it contains the |read_access_permission|.
|
| + if (buffer_state_iter->HasZeroConsumerHoldCount()) {
|
| + ReleaseBufferState(buffer_state_iter);
|
| + } else {
|
| + buffer_state_iter->set_is_retired();
|
| + }
|
| +}
|
| +
|
| void VideoCaptureController::OnError() {
|
| DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| state_ = VIDEO_CAPTURE_STATE_ERROR;
|
| @@ -476,26 +514,6 @@ void VideoCaptureController::OnLog(const std::string& message) {
|
| MediaStreamManager::SendMessageToNativeLog("Video capture: " + message);
|
| }
|
|
|
| -void VideoCaptureController::OnBufferDestroyed(int buffer_id_to_drop) {
|
| - DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| -
|
| - for (const auto& client : controller_clients_) {
|
| - if (client->session_closed)
|
| - continue;
|
| -
|
| - auto known_buffers_entry_iter =
|
| - std::find(std::begin(client->known_buffers),
|
| - std::end(client->known_buffers), buffer_id_to_drop);
|
| - if (known_buffers_entry_iter != std::end(client->known_buffers)) {
|
| - client->known_buffers.erase(known_buffers_entry_iter);
|
| - client->event_handler->OnBufferDestroyed(client->controller_id,
|
| - buffer_id_to_drop);
|
| - }
|
| - }
|
| -
|
| - buffer_id_to_state_map_.erase(buffer_id_to_drop);
|
| -}
|
| -
|
| VideoCaptureController::ControllerClient* VideoCaptureController::FindClient(
|
| VideoCaptureControllerID id,
|
| VideoCaptureControllerEventHandler* handler,
|
| @@ -517,4 +535,41 @@ VideoCaptureController::ControllerClient* VideoCaptureController::FindClient(
|
| return nullptr;
|
| }
|
|
|
| +void VideoCaptureController::OnClientFinishedConsumingBuffer(
|
| + ControllerClient* client,
|
| + int buffer_id,
|
| + double consumer_resource_utilization) {
|
| + auto buffer_state_iter =
|
| + std::find_if(buffer_states_.begin(), buffer_states_.end(),
|
| + [buffer_id](const BufferState& entry) {
|
| + return entry.buffer_id() == buffer_id;
|
| + });
|
| + DCHECK(buffer_state_iter != buffer_states_.end());
|
| +
|
| + buffer_state_iter->RecordConsumerUtilization(consumer_resource_utilization);
|
| + buffer_state_iter->DecreaseConsumerCount();
|
| + if (buffer_state_iter->HasZeroConsumerHoldCount() &&
|
| + buffer_state_iter->is_retired()) {
|
| + ReleaseBufferState(buffer_state_iter);
|
| + }
|
| +}
|
| +
|
| +void VideoCaptureController::ReleaseBufferState(
|
| + const std::vector<BufferState>::iterator& buffer_state_iter) {
|
| + for (const auto& client : controller_clients_) {
|
| + if (client->session_closed)
|
| + continue;
|
| +
|
| + auto known_buffers_entry_iter = std::find(std::begin(client->known_buffers),
|
| + std::end(client->known_buffers),
|
| + buffer_state_iter->buffer_id());
|
| + if (known_buffers_entry_iter != std::end(client->known_buffers)) {
|
| + client->known_buffers.erase(known_buffers_entry_iter);
|
| + client->event_handler->OnBufferDestroyed(client->controller_id,
|
| + buffer_state_iter->buffer_id());
|
| + }
|
| + }
|
| + buffer_states_.erase(buffer_state_iter);
|
| +}
|
| +
|
| } // namespace content
|
|
|