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 83f264cd0ec5687db042e9ec5300c65f62bcb45b..5f226b65422b880d21a94c1fe6795ede553eb2a5 100644 |
--- a/content/browser/renderer_host/media/video_capture_controller.cc |
+++ b/content/browser/renderer_host/media/video_capture_controller.cc |
@@ -46,40 +46,6 @@ static const int kInfiniteRatio = 99999; |
name, \ |
(height) ? ((width) * 100) / (height) : kInfiniteRatio); |
-class SyncTokenClientImpl : public VideoFrame::SyncTokenClient { |
- public: |
- explicit SyncTokenClientImpl(display_compositor::GLHelper* gl_helper) |
- : gl_helper_(gl_helper) {} |
- ~SyncTokenClientImpl() override {} |
- void GenerateSyncToken(gpu::SyncToken* sync_token) override { |
- gl_helper_->GenerateSyncToken(sync_token); |
- } |
- void WaitSyncToken(const gpu::SyncToken& sync_token) override { |
- gl_helper_->WaitSyncToken(sync_token); |
- } |
- |
- private: |
- display_compositor::GLHelper* gl_helper_; |
-}; |
- |
-void ReturnVideoFrame(const scoped_refptr<VideoFrame>& video_frame, |
- const gpu::SyncToken& sync_token) { |
- DCHECK_CURRENTLY_ON(BrowserThread::UI); |
-#if defined(OS_ANDROID) |
- NOTREACHED(); |
-#else |
- display_compositor::GLHelper* gl_helper = |
- ImageTransportFactory::GetInstance()->GetGLHelper(); |
- // UpdateReleaseSyncToken() creates a new sync_token using |gl_helper|, so |
- // wait the given |sync_token| using |gl_helper|. |
- if (gl_helper) { |
- gl_helper->WaitSyncToken(sync_token); |
- SyncTokenClientImpl client(gl_helper); |
- video_frame->UpdateReleaseSyncToken(&client); |
- } |
-#endif |
-} |
- |
std::unique_ptr<media::VideoCaptureJpegDecoder> CreateGpuJpegDecoder( |
const media::VideoCaptureJpegDecoder::DecodeDoneCB& decode_done_cb) { |
return base::MakeUnique<VideoCaptureGpuJpegDecoder>(decode_done_cb); |
@@ -148,12 +114,10 @@ struct VideoCaptureController::ControllerClient { |
const media::VideoCaptureParams parameters; |
// Buffers that are currently known to this client. |
- std::set<int> known_buffers; |
+ std::vector<int> known_buffers; |
- // Buffers currently held by this client, and sync token callback to call when |
- // they are returned from the client. |
- typedef std::map<int, scoped_refptr<VideoFrame>> ActiveBufferMap; |
- ActiveBufferMap active_buffers; |
+ // Buffers currently held by this client. |
+ std::vector<int> buffers_in_use; |
// State of capture session, controlled by VideoCaptureManager directly. This |
// transitions to true as soon as StopSession() occurs, at which point the |
@@ -172,10 +136,69 @@ struct VideoCaptureController::ControllerClient { |
bool paused; |
}; |
+VideoCaptureController::BufferState::BufferState( |
+ int buffer_id, |
+ int frame_feedback_id, |
+ media::VideoFrameConsumerFeedbackObserver* consumer_feedback_observer, |
+ scoped_refptr<media::VideoCaptureBufferPool> buffer_pool, |
+ scoped_refptr<media::VideoFrame> frame) |
+ : buffer_id_(buffer_id), |
+ frame_feedback_id_(frame_feedback_id), |
+ consumer_feedback_observer_(consumer_feedback_observer), |
+ buffer_pool_(std::move(buffer_pool)), |
+ frame_(std::move(frame)), |
+ max_consumer_utilization_( |
+ media::VideoFrameConsumerFeedbackObserver::kNoUtilizationRecorded), |
+ consumer_hold_count_(0) {} |
+ |
+VideoCaptureController::BufferState::~BufferState() = default; |
+ |
+VideoCaptureController::BufferState::BufferState( |
+ const VideoCaptureController::BufferState& other) = default; |
+ |
+void VideoCaptureController::BufferState::RecordConsumerUtilization( |
+ double utilization) { |
+ if (std::isfinite(utilization) && utilization >= 0.0) { |
+ max_consumer_utilization_ = |
+ std::max(max_consumer_utilization_, utilization); |
+ } |
+} |
+ |
+void VideoCaptureController::BufferState::IncreaseConsumerCount() { |
+ if (consumer_hold_count_ == 0) |
+ buffer_pool_->HoldForConsumers(buffer_id_, 1); |
+ consumer_hold_count_++; |
+} |
+ |
+void VideoCaptureController::BufferState::DecreaseConsumerCount() { |
+ consumer_hold_count_--; |
+ if (consumer_hold_count_ == 0) { |
+ if (consumer_feedback_observer_ != nullptr && |
+ max_consumer_utilization_ != |
+ media::VideoFrameConsumerFeedbackObserver::kNoUtilizationRecorded) { |
+ consumer_feedback_observer_->OnUtilizationReport( |
+ frame_feedback_id_, max_consumer_utilization_); |
+ } |
+ buffer_pool_->RelinquishConsumerHold(buffer_id_, 1); |
+ max_consumer_utilization_ = |
+ media::VideoFrameConsumerFeedbackObserver::kNoUtilizationRecorded; |
+ } |
+} |
+ |
+bool VideoCaptureController::BufferState::HasZeroConsumerHoldCount() { |
+ return consumer_hold_count_ == 0; |
+} |
+ |
+void VideoCaptureController::BufferState::SetConsumerFeedbackObserver( |
+ media::VideoFrameConsumerFeedbackObserver* consumer_feedback_observer) { |
+ consumer_feedback_observer_ = consumer_feedback_observer; |
+} |
+ |
VideoCaptureController::VideoCaptureController(int max_buffers) |
: buffer_pool_(new media::VideoCaptureBufferPoolImpl( |
base::MakeUnique<media::VideoCaptureBufferTrackerFactoryImpl>(), |
max_buffers)), |
+ consumer_feedback_observer_(nullptr), |
state_(VIDEO_CAPTURE_STATE_STARTED), |
has_received_frames_(false), |
weak_ptr_factory_(this) { |
@@ -187,6 +210,16 @@ VideoCaptureController::GetWeakPtrForIOThread() { |
return weak_ptr_factory_.GetWeakPtr(); |
} |
+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()); |
+} |
+ |
std::unique_ptr<media::VideoCaptureDevice::Client> |
VideoCaptureController::NewDeviceClient() { |
DCHECK_CURRENTLY_ON(BrowserThread::IO); |
@@ -259,9 +292,9 @@ int VideoCaptureController::RemoveClient( |
return kInvalidMediaCaptureSessionId; |
// Take back all buffers held by the |client|. |
- for (const auto& buffer : client->active_buffers) |
- buffer_pool_->RelinquishConsumerHold(buffer.first, 1); |
- client->active_buffers.clear(); |
+ for (const auto& buffer_id : client->buffers_in_use) |
+ buffer_id_to_state_map_.at(buffer_id).DecreaseConsumerCount(); |
+ client->buffers_in_use.clear(); |
int session_id = client->session_id; |
controller_clients_.remove_if( |
@@ -353,42 +386,22 @@ void VideoCaptureController::ReturnBuffer( |
// If this buffer is not held by this client, or this client doesn't exist |
// in controller, do nothing. |
- ControllerClient::ActiveBufferMap::iterator iter; |
- if (!client || (iter = client->active_buffers.find(buffer_id)) == |
- client->active_buffers.end()) { |
+ if (!client) { |
NOTREACHED(); |
return; |
} |
- |
- // Set the RESOURCE_UTILIZATION to the maximum of those provided by each |
- // consumer (via separate calls to this method that refer to the same |
- // VideoFrame). The producer of this VideoFrame may check this value, after |
- // all consumer holds are relinquished, to make quality versus performance |
- // trade-off decisions. |
- scoped_refptr<VideoFrame> frame = iter->second; |
- if (std::isfinite(consumer_resource_utilization) && |
- consumer_resource_utilization >= 0.0) { |
- double resource_utilization = -1.0; |
- if (frame->metadata()->GetDouble(VideoFrameMetadata::RESOURCE_UTILIZATION, |
- &resource_utilization)) { |
- frame->metadata()->SetDouble(VideoFrameMetadata::RESOURCE_UTILIZATION, |
- std::max(consumer_resource_utilization, |
- resource_utilization)); |
- } else { |
- frame->metadata()->SetDouble(VideoFrameMetadata::RESOURCE_UTILIZATION, |
- consumer_resource_utilization); |
- } |
+ auto buffers_in_use_entry_iter = |
+ std::find(std::begin(client->buffers_in_use), |
+ std::end(client->buffers_in_use), buffer_id); |
+ if (buffers_in_use_entry_iter == std::end(client->buffers_in_use)) { |
+ NOTREACHED(); |
+ return; |
} |
- client->active_buffers.erase(iter); |
- buffer_pool_->RelinquishConsumerHold(buffer_id, 1); |
- |
-#if defined(OS_ANDROID) |
- DCHECK(!sync_token.HasData()); |
-#endif |
- if (sync_token.HasData()) |
- BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
- base::Bind(&ReturnVideoFrame, frame, sync_token)); |
+ 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); |
} |
const media::VideoCaptureFormat& |
@@ -407,7 +420,17 @@ void VideoCaptureController::OnIncomingCapturedVideoFrame( |
const int buffer_id = buffer->id(); |
DCHECK_NE(buffer_id, media::VideoCaptureBufferPool::kInvalidId); |
- int count = 0; |
+ // 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(), |
+ buffer_pool_, frame))) |
+ .first; |
+ BufferState& buffer_state = it->second; |
+ DCHECK(buffer_state.HasZeroConsumerHoldCount()); |
+ |
if (state_ == VIDEO_CAPTURE_STATE_STARTED) { |
if (!frame->metadata()->HasKey(VideoFrameMetadata::FRAME_RATE)) { |
frame->metadata()->SetDouble(VideoFrameMetadata::FRAME_RATE, |
@@ -436,17 +459,28 @@ void VideoCaptureController::OnIncomingCapturedVideoFrame( |
continue; |
// On the first use of a buffer on a client, share the memory handles. |
- const bool is_new_buffer = client->known_buffers.insert(buffer_id).second; |
+ auto known_buffers_entry_iter = |
+ std::find(std::begin(client->known_buffers), |
+ std::end(client->known_buffers), buffer_id); |
+ bool is_new_buffer = false; |
+ if (known_buffers_entry_iter == std::end(client->known_buffers)) { |
+ client->known_buffers.push_back(buffer_id); |
+ is_new_buffer = true; |
+ } |
if (is_new_buffer) |
DoNewBufferOnIOThread(client.get(), buffer.get(), frame); |
client->event_handler->OnBufferReady(client->controller_id, buffer_id, |
frame); |
- const bool inserted = |
- client->active_buffers.insert(std::make_pair(buffer_id, frame)) |
- .second; |
- DCHECK(inserted) << "Unexpected duplicate buffer: " << buffer_id; |
- count++; |
+ |
+ auto buffers_in_use_entry_iter = |
+ std::find(std::begin(client->buffers_in_use), |
+ std::end(client->buffers_in_use), buffer_id); |
+ if (buffers_in_use_entry_iter == std::end(client->buffers_in_use)) |
+ client->buffers_in_use.push_back(buffer_id); |
+ else |
+ DCHECK(false) << "Unexpected duplicate buffer: " << buffer_id; |
+ buffer_state.IncreaseConsumerCount(); |
} |
} |
@@ -466,8 +500,6 @@ void VideoCaptureController::OnIncomingCapturedVideoFrame( |
UMA_HISTOGRAM_COUNTS("Media.VideoCapture.FrameRate", frame_rate); |
has_received_frames_ = true; |
} |
- |
- buffer_pool_->HoldForConsumers(buffer_id, count); |
} |
void VideoCaptureController::OnError() { |
@@ -493,11 +525,17 @@ void VideoCaptureController::OnBufferDestroyed(int buffer_id_to_drop) { |
if (client->session_closed) |
continue; |
- if (client->known_buffers.erase(buffer_id_to_drop)) { |
+ 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); |
} |
void VideoCaptureController::DoNewBufferOnIOThread( |