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 |