| 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/browser/renderer_host/media/video_capture_controller.h" | 5 #include "content/browser/renderer_host/media/video_capture_controller.h" |
| 6 | 6 |
| 7 #include <stddef.h> | 7 #include <stddef.h> |
| 8 #include <stdint.h> | 8 #include <stdint.h> |
| 9 | 9 |
| 10 #include <map> | 10 #include <map> |
| (...skipping 24 matching lines...) Expand all Loading... |
| 35 using media::VideoFrame; | 35 using media::VideoFrame; |
| 36 using media::VideoFrameMetadata; | 36 using media::VideoFrameMetadata; |
| 37 | 37 |
| 38 namespace content { | 38 namespace content { |
| 39 | 39 |
| 40 namespace { | 40 namespace { |
| 41 | 41 |
| 42 static const int kInfiniteRatio = 99999; | 42 static const int kInfiniteRatio = 99999; |
| 43 | 43 |
| 44 #define UMA_HISTOGRAM_ASPECT_RATIO(name, width, height) \ | 44 #define UMA_HISTOGRAM_ASPECT_RATIO(name, width, height) \ |
| 45 UMA_HISTOGRAM_SPARSE_SLOWLY( \ | 45 UMA_HISTOGRAM_SPARSE_SLOWLY( \ |
| 46 name, \ | 46 name, (height) ? ((width)*100) / (height) : kInfiniteRatio); |
| 47 (height) ? ((width) * 100) / (height) : kInfiniteRatio); | |
| 48 | 47 |
| 49 } // anonymous namespace | 48 } // anonymous namespace |
| 50 | 49 |
| 51 struct VideoCaptureController::ControllerClient { | 50 struct VideoCaptureController::ControllerClient { |
| 52 ControllerClient(VideoCaptureControllerID id, | 51 ControllerClient(VideoCaptureControllerID id, |
| 53 VideoCaptureControllerEventHandler* handler, | 52 VideoCaptureControllerEventHandler* handler, |
| 54 media::VideoCaptureSessionId session_id, | 53 media::VideoCaptureSessionId session_id, |
| 55 const media::VideoCaptureParams& params) | 54 const media::VideoCaptureParams& params) |
| 56 : controller_id(id), | 55 : controller_id(id), |
| 57 event_handler(handler), | 56 event_handler(handler), |
| 58 session_id(session_id), | 57 session_id(session_id), |
| 59 parameters(params), | 58 parameters(params), |
| 60 session_closed(false), | 59 session_closed(false), |
| 61 paused(false) {} | 60 paused(false) {} |
| 62 | 61 |
| 63 ~ControllerClient() {} | 62 ~ControllerClient() {} |
| 64 | 63 |
| 65 // ID used for identifying this object. | 64 // ID used for identifying this object. |
| 66 const VideoCaptureControllerID controller_id; | 65 const VideoCaptureControllerID controller_id; |
| 67 VideoCaptureControllerEventHandler* const event_handler; | 66 VideoCaptureControllerEventHandler* const event_handler; |
| 68 | 67 |
| 69 const media::VideoCaptureSessionId session_id; | 68 const media::VideoCaptureSessionId session_id; |
| 70 const media::VideoCaptureParams parameters; | 69 const media::VideoCaptureParams parameters; |
| 71 | 70 |
| 72 // Buffers that are currently known to this client. | 71 std::vector<int> known_buffer_context_ids; |
| 73 std::vector<int> known_buffers; | 72 // |buffer_context_id|s of buffers currently being consumed by this client. |
| 74 | |
| 75 // Buffers currently held by this client. | |
| 76 std::vector<int> buffers_in_use; | 73 std::vector<int> buffers_in_use; |
| 77 | 74 |
| 78 // State of capture session, controlled by VideoCaptureManager directly. This | 75 // State of capture session, controlled by VideoCaptureManager directly. This |
| 79 // transitions to true as soon as StopSession() occurs, at which point the | 76 // transitions to true as soon as StopSession() occurs, at which point the |
| 80 // client is sent an OnEnded() event. However, because the client retains a | 77 // client is sent an OnEnded() event. However, because the client retains a |
| 81 // VideoCaptureController* pointer, its ControllerClient entry lives on until | 78 // VideoCaptureController* pointer, its ControllerClient entry lives on until |
| 82 // it unregisters itself via RemoveClient(), which may happen asynchronously. | 79 // it unregisters itself via RemoveClient(), which may happen asynchronously. |
| 83 // | 80 // |
| 84 // TODO(nick): If we changed the semantics of VideoCaptureHost so that | 81 // TODO(nick): If we changed the semantics of VideoCaptureHost so that |
| 85 // OnEnded() events were processed synchronously (with the RemoveClient() done | 82 // OnEnded() events were processed synchronously (with the RemoveClient() done |
| 86 // implicitly), we could avoid tracking this state here in the Controller, and | 83 // implicitly), we could avoid tracking this state here in the Controller, and |
| 87 // simplify the code in both places. | 84 // simplify the code in both places. |
| 88 bool session_closed; | 85 bool session_closed; |
| 89 | 86 |
| 90 // Indicates whether the client is paused, if true, VideoCaptureController | 87 // Indicates whether the client is paused, if true, VideoCaptureController |
| 91 // stops updating its buffer. | 88 // stops updating its buffer. |
| 92 bool paused; | 89 bool paused; |
| 93 }; | 90 }; |
| 94 | 91 |
| 95 VideoCaptureController::BufferState::BufferState( | 92 VideoCaptureController::BufferContext::BufferContext( |
| 93 int buffer_context_id, |
| 96 int buffer_id, | 94 int buffer_id, |
| 97 int frame_feedback_id, | |
| 98 media::VideoFrameConsumerFeedbackObserver* consumer_feedback_observer, | 95 media::VideoFrameConsumerFeedbackObserver* consumer_feedback_observer, |
| 99 media::FrameBufferPool* frame_buffer_pool) | 96 media::FrameBufferPool* frame_buffer_pool) |
| 100 : buffer_id_(buffer_id), | 97 : buffer_context_id_(buffer_context_id), |
| 101 frame_feedback_id_(frame_feedback_id), | 98 buffer_id_(buffer_id), |
| 99 is_retired_(false), |
| 100 frame_feedback_id_(0), |
| 102 consumer_feedback_observer_(consumer_feedback_observer), | 101 consumer_feedback_observer_(consumer_feedback_observer), |
| 103 frame_buffer_pool_(frame_buffer_pool), | 102 frame_buffer_pool_(frame_buffer_pool), |
| 104 max_consumer_utilization_( | 103 max_consumer_utilization_( |
| 105 media::VideoFrameConsumerFeedbackObserver::kNoUtilizationRecorded), | 104 media::VideoFrameConsumerFeedbackObserver::kNoUtilizationRecorded), |
| 106 consumer_hold_count_(0) {} | 105 consumer_hold_count_(0) {} |
| 107 | 106 |
| 108 VideoCaptureController::BufferState::~BufferState() = default; | 107 VideoCaptureController::BufferContext::~BufferContext() = default; |
| 109 | 108 |
| 110 VideoCaptureController::BufferState::BufferState( | 109 VideoCaptureController::BufferContext::BufferContext( |
| 111 const VideoCaptureController::BufferState& other) = default; | 110 const VideoCaptureController::BufferContext& other) = default; |
| 112 | 111 |
| 113 void VideoCaptureController::BufferState::RecordConsumerUtilization( | 112 VideoCaptureController::BufferContext& VideoCaptureController::BufferContext:: |
| 113 operator=(const BufferContext& other) = default; |
| 114 |
| 115 void VideoCaptureController::BufferContext::RecordConsumerUtilization( |
| 114 double utilization) { | 116 double utilization) { |
| 115 if (std::isfinite(utilization) && utilization >= 0.0) { | 117 if (std::isfinite(utilization) && utilization >= 0.0) { |
| 116 max_consumer_utilization_ = | 118 max_consumer_utilization_ = |
| 117 std::max(max_consumer_utilization_, utilization); | 119 std::max(max_consumer_utilization_, utilization); |
| 118 } | 120 } |
| 119 } | 121 } |
| 120 | 122 |
| 121 void VideoCaptureController::BufferState::IncreaseConsumerCount() { | 123 void VideoCaptureController::BufferContext::IncreaseConsumerCount() { |
| 122 if (consumer_hold_count_ == 0) | 124 if (consumer_hold_count_ == 0) |
| 123 if (frame_buffer_pool_ != nullptr) | 125 if (frame_buffer_pool_ != nullptr) |
| 124 frame_buffer_pool_->SetBufferHold(buffer_id_); | 126 frame_buffer_pool_->SetBufferHold(buffer_id_); |
| 125 consumer_hold_count_++; | 127 consumer_hold_count_++; |
| 126 } | 128 } |
| 127 | 129 |
| 128 void VideoCaptureController::BufferState::DecreaseConsumerCount() { | 130 void VideoCaptureController::BufferContext::DecreaseConsumerCount() { |
| 129 consumer_hold_count_--; | 131 consumer_hold_count_--; |
| 130 if (consumer_hold_count_ == 0) { | 132 if (consumer_hold_count_ == 0) { |
| 131 if (consumer_feedback_observer_ != nullptr && | 133 if (consumer_feedback_observer_ != nullptr && |
| 132 max_consumer_utilization_ != | 134 max_consumer_utilization_ != |
| 133 media::VideoFrameConsumerFeedbackObserver::kNoUtilizationRecorded) { | 135 media::VideoFrameConsumerFeedbackObserver::kNoUtilizationRecorded) { |
| 134 consumer_feedback_observer_->OnUtilizationReport( | 136 consumer_feedback_observer_->OnUtilizationReport( |
| 135 frame_feedback_id_, max_consumer_utilization_); | 137 frame_feedback_id_, max_consumer_utilization_); |
| 136 } | 138 } |
| 137 if (frame_buffer_pool_ != nullptr) | 139 if (frame_buffer_pool_ != nullptr) |
| 138 frame_buffer_pool_->ReleaseBufferHold(buffer_id_); | 140 frame_buffer_pool_->ReleaseBufferHold(buffer_id_); |
| 139 max_consumer_utilization_ = | 141 max_consumer_utilization_ = |
| 140 media::VideoFrameConsumerFeedbackObserver::kNoUtilizationRecorded; | 142 media::VideoFrameConsumerFeedbackObserver::kNoUtilizationRecorded; |
| 141 } | 143 } |
| 142 } | 144 } |
| 143 | 145 |
| 144 bool VideoCaptureController::BufferState::HasZeroConsumerHoldCount() { | 146 bool VideoCaptureController::BufferContext::HasZeroConsumerHoldCount() { |
| 145 return consumer_hold_count_ == 0; | 147 return consumer_hold_count_ == 0; |
| 146 } | 148 } |
| 147 | 149 |
| 148 void VideoCaptureController::BufferState::SetFrameFeedbackId(int id) { | |
| 149 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
| 150 frame_feedback_id_ = id; | |
| 151 } | |
| 152 | |
| 153 void VideoCaptureController::BufferState::SetConsumerFeedbackObserver( | |
| 154 media::VideoFrameConsumerFeedbackObserver* consumer_feedback_observer) { | |
| 155 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
| 156 consumer_feedback_observer_ = consumer_feedback_observer; | |
| 157 } | |
| 158 | |
| 159 void VideoCaptureController::BufferState::SetFrameBufferPool( | |
| 160 media::FrameBufferPool* frame_buffer_pool) { | |
| 161 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
| 162 frame_buffer_pool_ = frame_buffer_pool; | |
| 163 } | |
| 164 | |
| 165 VideoCaptureController::VideoCaptureController() | 150 VideoCaptureController::VideoCaptureController() |
| 166 : frame_buffer_pool_(nullptr), | 151 : frame_buffer_pool_(nullptr), |
| 167 consumer_feedback_observer_(nullptr), | 152 consumer_feedback_observer_(nullptr), |
| 168 state_(VIDEO_CAPTURE_STATE_STARTED), | 153 state_(VIDEO_CAPTURE_STATE_STARTED), |
| 169 has_received_frames_(false), | 154 has_received_frames_(false), |
| 170 weak_ptr_factory_(this) { | 155 weak_ptr_factory_(this) { |
| 171 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 156 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 172 } | 157 } |
| 173 | 158 |
| 174 VideoCaptureController::~VideoCaptureController() = default; | 159 VideoCaptureController::~VideoCaptureController() = default; |
| 175 | 160 |
| 176 base::WeakPtr<VideoCaptureController> | 161 base::WeakPtr<VideoCaptureController> |
| 177 VideoCaptureController::GetWeakPtrForIOThread() { | 162 VideoCaptureController::GetWeakPtrForIOThread() { |
| 178 return weak_ptr_factory_.GetWeakPtr(); | 163 return weak_ptr_factory_.GetWeakPtr(); |
| 179 } | 164 } |
| 180 | 165 |
| 181 void VideoCaptureController::SetFrameBufferPool( | 166 void VideoCaptureController::SetFrameBufferPool( |
| 182 std::unique_ptr<media::FrameBufferPool> frame_buffer_pool) { | 167 std::unique_ptr<media::FrameBufferPool> frame_buffer_pool) { |
| 183 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 168 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 184 frame_buffer_pool_ = std::move(frame_buffer_pool); | 169 frame_buffer_pool_ = std::move(frame_buffer_pool); |
| 185 // Update existing BufferState entries. | 170 // Update existing BufferContext entries. |
| 186 for (auto& entry : buffer_id_to_state_map_) | 171 for (auto& entry : buffer_contexts_) |
| 187 entry.second.SetFrameBufferPool(frame_buffer_pool_.get()); | 172 entry.set_frame_buffer_pool(frame_buffer_pool_.get()); |
| 188 } | 173 } |
| 189 | 174 |
| 190 void VideoCaptureController::SetConsumerFeedbackObserver( | 175 void VideoCaptureController::SetConsumerFeedbackObserver( |
| 191 std::unique_ptr<media::VideoFrameConsumerFeedbackObserver> | 176 std::unique_ptr<media::VideoFrameConsumerFeedbackObserver> |
| 192 consumer_feedback_observer) { | 177 consumer_feedback_observer) { |
| 193 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 178 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 194 consumer_feedback_observer_ = std::move(consumer_feedback_observer); | 179 consumer_feedback_observer_ = std::move(consumer_feedback_observer); |
| 195 // Update existing BufferState entries. | 180 // Update existing BufferContext entries. |
| 196 for (auto& entry : buffer_id_to_state_map_) | 181 for (auto& entry : buffer_contexts_) |
| 197 entry.second.SetConsumerFeedbackObserver(consumer_feedback_observer_.get()); | 182 entry.set_consumer_feedback_observer(consumer_feedback_observer_.get()); |
| 198 } | 183 } |
| 199 | 184 |
| 200 void VideoCaptureController::AddClient( | 185 void VideoCaptureController::AddClient( |
| 201 VideoCaptureControllerID id, | 186 VideoCaptureControllerID id, |
| 202 VideoCaptureControllerEventHandler* event_handler, | 187 VideoCaptureControllerEventHandler* event_handler, |
| 203 media::VideoCaptureSessionId session_id, | 188 media::VideoCaptureSessionId session_id, |
| 204 const media::VideoCaptureParams& params) { | 189 const media::VideoCaptureParams& params) { |
| 205 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 190 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 206 DVLOG(1) << "VideoCaptureController::AddClient() -- id=" << id | 191 DVLOG(1) << "VideoCaptureController::AddClient() -- id=" << id |
| 207 << ", session_id=" << session_id | 192 << ", session_id=" << session_id << ", params.requested_format=" |
| 208 << ", params.requested_format=" | |
| 209 << media::VideoCaptureFormat::ToString(params.requested_format); | 193 << media::VideoCaptureFormat::ToString(params.requested_format); |
| 210 | 194 |
| 211 // Check that requested VideoCaptureParams are valid and supported. If not, | 195 // Check that requested VideoCaptureParams are valid and supported. If not, |
| 212 // report an error immediately and punt. | 196 // report an error immediately and punt. |
| 213 if (!params.IsValid() || | 197 if (!params.IsValid() || |
| 214 !(params.requested_format.pixel_format == media::PIXEL_FORMAT_I420 || | 198 !(params.requested_format.pixel_format == media::PIXEL_FORMAT_I420 || |
| 215 params.requested_format.pixel_format == media::PIXEL_FORMAT_Y16) || | 199 params.requested_format.pixel_format == media::PIXEL_FORMAT_Y16) || |
| 216 params.requested_format.pixel_storage != media::PIXEL_STORAGE_CPU) { | 200 params.requested_format.pixel_storage != media::PIXEL_STORAGE_CPU) { |
| 217 // Crash in debug builds since the renderer should not have asked for | 201 // Crash in debug builds since the renderer should not have asked for |
| 218 // invalid or unsupported parameters. | 202 // invalid or unsupported parameters. |
| (...skipping 30 matching lines...) Expand all Loading... |
| 249 int VideoCaptureController::RemoveClient( | 233 int VideoCaptureController::RemoveClient( |
| 250 VideoCaptureControllerID id, | 234 VideoCaptureControllerID id, |
| 251 VideoCaptureControllerEventHandler* event_handler) { | 235 VideoCaptureControllerEventHandler* event_handler) { |
| 252 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 236 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 253 DVLOG(1) << "VideoCaptureController::RemoveClient, id " << id; | 237 DVLOG(1) << "VideoCaptureController::RemoveClient, id " << id; |
| 254 | 238 |
| 255 ControllerClient* client = FindClient(id, event_handler, controller_clients_); | 239 ControllerClient* client = FindClient(id, event_handler, controller_clients_); |
| 256 if (!client) | 240 if (!client) |
| 257 return kInvalidMediaCaptureSessionId; | 241 return kInvalidMediaCaptureSessionId; |
| 258 | 242 |
| 259 // Take back all buffers held by the |client|. | 243 for (const auto& buffer_id : client->buffers_in_use) { |
| 260 for (const auto& buffer_id : client->buffers_in_use) | 244 OnClientFinishedConsumingBuffer( |
| 261 buffer_id_to_state_map_.at(buffer_id).DecreaseConsumerCount(); | 245 client, buffer_id, |
| 246 media::VideoFrameConsumerFeedbackObserver::kNoUtilizationRecorded); |
| 247 } |
| 262 client->buffers_in_use.clear(); | 248 client->buffers_in_use.clear(); |
| 263 | 249 |
| 264 int session_id = client->session_id; | 250 int session_id = client->session_id; |
| 265 controller_clients_.remove_if( | 251 controller_clients_.remove_if( |
| 266 [client](const std::unique_ptr<ControllerClient>& ptr) { | 252 [client](const std::unique_ptr<ControllerClient>& ptr) { |
| 267 return ptr.get() == client; | 253 return ptr.get() == client; |
| 268 }); | 254 }); |
| 269 | 255 |
| 270 return session_id; | 256 return session_id; |
| 271 } | 257 } |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 354 NOTREACHED(); | 340 NOTREACHED(); |
| 355 return; | 341 return; |
| 356 } | 342 } |
| 357 auto buffers_in_use_entry_iter = | 343 auto buffers_in_use_entry_iter = |
| 358 std::find(std::begin(client->buffers_in_use), | 344 std::find(std::begin(client->buffers_in_use), |
| 359 std::end(client->buffers_in_use), buffer_id); | 345 std::end(client->buffers_in_use), buffer_id); |
| 360 if (buffers_in_use_entry_iter == std::end(client->buffers_in_use)) { | 346 if (buffers_in_use_entry_iter == std::end(client->buffers_in_use)) { |
| 361 NOTREACHED(); | 347 NOTREACHED(); |
| 362 return; | 348 return; |
| 363 } | 349 } |
| 350 client->buffers_in_use.erase(buffers_in_use_entry_iter); |
| 364 | 351 |
| 365 BufferState& buffer_state = buffer_id_to_state_map_.at(buffer_id); | 352 OnClientFinishedConsumingBuffer(client, buffer_id, |
| 366 buffer_state.RecordConsumerUtilization(consumer_resource_utilization); | 353 consumer_resource_utilization); |
| 367 buffer_state.DecreaseConsumerCount(); | |
| 368 client->buffers_in_use.erase(buffers_in_use_entry_iter); | |
| 369 } | 354 } |
| 370 | 355 |
| 371 const media::VideoCaptureFormat& | 356 const media::VideoCaptureFormat& VideoCaptureController::GetVideoCaptureFormat() |
| 372 VideoCaptureController::GetVideoCaptureFormat() const { | 357 const { |
| 373 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 358 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 374 return video_capture_format_; | 359 return video_capture_format_; |
| 375 } | 360 } |
| 376 | 361 |
| 377 void VideoCaptureController::OnIncomingCapturedVideoFrame( | 362 void VideoCaptureController::OnIncomingCapturedVideoFrame( |
| 378 media::VideoCaptureDevice::Client::Buffer buffer, | 363 media::VideoCaptureDevice::Client::Buffer buffer, |
| 379 scoped_refptr<VideoFrame> frame) { | 364 scoped_refptr<VideoFrame> frame) { |
| 380 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 365 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 381 const int buffer_id = buffer.id(); | 366 const int buffer_id_from_producer = buffer.id(); |
| 382 DCHECK_NE(buffer_id, media::VideoCaptureBufferPool::kInvalidId); | 367 DCHECK_NE(buffer_id_from_producer, media::VideoCaptureBufferPool::kInvalidId); |
| 383 | 368 auto buffer_context_iter = |
| 384 // Insert if not exists. | 369 FindUnretiredBufferContextFromBufferId(buffer_id_from_producer); |
| 385 const auto insert_result = buffer_id_to_state_map_.insert(std::make_pair( | 370 if (buffer_context_iter == buffer_contexts_.end()) { |
| 386 buffer_id, BufferState(buffer_id, buffer.frame_feedback_id(), | 371 // A new buffer has been shared with us. Create new BufferContext. |
| 387 consumer_feedback_observer_.get(), | 372 buffer_contexts_.emplace_back( |
| 388 frame_buffer_pool_.get()))); | 373 next_buffer_context_id_++, buffer_id_from_producer, |
| 389 BufferState& buffer_state = insert_result.first->second; | 374 consumer_feedback_observer_.get(), frame_buffer_pool_.get()); |
| 390 DCHECK(buffer_state.HasZeroConsumerHoldCount()); | 375 buffer_context_iter = buffer_contexts_.end() - 1; |
| 391 // If a BufferState for |buffer_id| already existed, we must update the | 376 } |
| 392 // |frame_feedback_id| of the existing entry. | 377 buffer_context_iter->set_frame_feedback_id(buffer.frame_feedback_id()); |
| 393 if (!insert_result.second) | 378 DCHECK(buffer_context_iter->HasZeroConsumerHoldCount()); |
| 394 buffer_state.SetFrameFeedbackId(buffer.frame_feedback_id()); | |
| 395 | 379 |
| 396 if (state_ == VIDEO_CAPTURE_STATE_STARTED) { | 380 if (state_ == VIDEO_CAPTURE_STATE_STARTED) { |
| 397 if (!frame->metadata()->HasKey(VideoFrameMetadata::FRAME_RATE)) { | 381 if (!frame->metadata()->HasKey(VideoFrameMetadata::FRAME_RATE)) { |
| 398 frame->metadata()->SetDouble(VideoFrameMetadata::FRAME_RATE, | 382 frame->metadata()->SetDouble(VideoFrameMetadata::FRAME_RATE, |
| 399 video_capture_format_.frame_rate); | 383 video_capture_format_.frame_rate); |
| 400 } | 384 } |
| 401 std::unique_ptr<base::DictionaryValue> metadata = | 385 std::unique_ptr<base::DictionaryValue> metadata = |
| 402 frame->metadata()->CopyInternalValues(); | 386 frame->metadata()->CopyInternalValues(); |
| 403 | 387 |
| 404 // Only I420 and Y16 pixel formats are currently supported. | 388 // Only I420 and Y16 pixel formats are currently supported. |
| 405 DCHECK(frame->format() == media::PIXEL_FORMAT_I420 || | 389 DCHECK(frame->format() == media::PIXEL_FORMAT_I420 || |
| 406 frame->format() == media::PIXEL_FORMAT_Y16) | 390 frame->format() == media::PIXEL_FORMAT_Y16) |
| 407 << "Unsupported pixel format: " | 391 << "Unsupported pixel format: " |
| 408 << media::VideoPixelFormatToString(frame->format()); | 392 << media::VideoPixelFormatToString(frame->format()); |
| 409 | 393 |
| 410 // Sanity-checks to confirm |frame| is actually being backed by |buffer|. | 394 // Sanity-checks to confirm |frame| is actually being backed by |buffer|. |
| 411 auto buffer_access = | 395 auto buffer_access = |
| 412 buffer.handle_provider()->GetHandleForInProcessAccess(); | 396 buffer.handle_provider()->GetHandleForInProcessAccess(); |
| 413 DCHECK(frame->storage_type() == media::VideoFrame::STORAGE_SHMEM); | 397 DCHECK(frame->storage_type() == media::VideoFrame::STORAGE_SHMEM); |
| 414 DCHECK(frame->data(media::VideoFrame::kYPlane) >= buffer_access->data() && | 398 DCHECK(frame->data(media::VideoFrame::kYPlane) >= buffer_access->data() && |
| 415 (frame->data(media::VideoFrame::kYPlane) < | 399 (frame->data(media::VideoFrame::kYPlane) < |
| 416 (buffer_access->data() + buffer_access->mapped_size()))) | 400 (buffer_access->data() + buffer_access->mapped_size()))) |
| 417 << "VideoFrame does not appear to be backed by Buffer"; | 401 << "VideoFrame does not appear to be backed by Buffer"; |
| 418 | 402 |
| 403 const int buffer_context_id = buffer_context_iter->buffer_context_id(); |
| 419 for (const auto& client : controller_clients_) { | 404 for (const auto& client : controller_clients_) { |
| 420 if (client->session_closed || client->paused) | 405 if (client->session_closed || client->paused) |
| 421 continue; | 406 continue; |
| 422 | 407 |
| 423 // On the first use of a buffer on a client, share the memory handles. | 408 // On the first use of a BufferContext on a client, share the memory |
| 424 auto known_buffers_entry_iter = | 409 // handles. |
| 425 std::find(std::begin(client->known_buffers), | 410 auto known_buffers_entry_iter = std::find( |
| 426 std::end(client->known_buffers), buffer_id); | 411 std::begin(client->known_buffer_context_ids), |
| 412 std::end(client->known_buffer_context_ids), buffer_context_id); |
| 427 bool is_new_buffer = false; | 413 bool is_new_buffer = false; |
| 428 if (known_buffers_entry_iter == std::end(client->known_buffers)) { | 414 if (known_buffers_entry_iter == |
| 429 client->known_buffers.push_back(buffer_id); | 415 std::end(client->known_buffer_context_ids)) { |
| 416 client->known_buffer_context_ids.push_back(buffer_context_id); |
| 430 is_new_buffer = true; | 417 is_new_buffer = true; |
| 431 } | 418 } |
| 432 if (is_new_buffer) { | 419 if (is_new_buffer) { |
| 433 mojo::ScopedSharedBufferHandle handle = | 420 mojo::ScopedSharedBufferHandle handle = |
| 434 buffer.handle_provider()->GetHandleForInterProcessTransit(); | 421 buffer.handle_provider()->GetHandleForInterProcessTransit(); |
| 435 client->event_handler->OnBufferCreated( | 422 client->event_handler->OnBufferCreated( |
| 436 client->controller_id, std::move(handle), | 423 client->controller_id, std::move(handle), |
| 437 buffer_access->mapped_size(), buffer_id); | 424 buffer_access->mapped_size(), buffer_context_id); |
| 438 } | 425 } |
| 439 client->event_handler->OnBufferReady(client->controller_id, buffer_id, | 426 client->event_handler->OnBufferReady(client->controller_id, |
| 440 frame); | 427 buffer_context_id, frame); |
| 441 | 428 |
| 442 auto buffers_in_use_entry_iter = | 429 auto buffers_in_use_entry_iter = |
| 443 std::find(std::begin(client->buffers_in_use), | 430 std::find(std::begin(client->buffers_in_use), |
| 444 std::end(client->buffers_in_use), buffer_id); | 431 std::end(client->buffers_in_use), buffer_context_id); |
| 445 if (buffers_in_use_entry_iter == std::end(client->buffers_in_use)) | 432 if (buffers_in_use_entry_iter == std::end(client->buffers_in_use)) |
| 446 client->buffers_in_use.push_back(buffer_id); | 433 client->buffers_in_use.push_back(buffer_context_id); |
| 447 else | 434 else |
| 448 DCHECK(false) << "Unexpected duplicate buffer: " << buffer_id; | 435 DCHECK(false) << "Unexpected duplicate buffer: " << buffer_context_id; |
| 449 buffer_state.IncreaseConsumerCount(); | 436 buffer_context_iter->IncreaseConsumerCount(); |
| 450 } | 437 } |
| 451 } | 438 } |
| 452 | 439 |
| 453 if (!has_received_frames_) { | 440 if (!has_received_frames_) { |
| 454 UMA_HISTOGRAM_COUNTS("Media.VideoCapture.Width", | 441 UMA_HISTOGRAM_COUNTS("Media.VideoCapture.Width", |
| 455 frame->visible_rect().width()); | 442 frame->visible_rect().width()); |
| 456 UMA_HISTOGRAM_COUNTS("Media.VideoCapture.Height", | 443 UMA_HISTOGRAM_COUNTS("Media.VideoCapture.Height", |
| 457 frame->visible_rect().height()); | 444 frame->visible_rect().height()); |
| 458 UMA_HISTOGRAM_ASPECT_RATIO("Media.VideoCapture.AspectRatio", | 445 UMA_HISTOGRAM_ASPECT_RATIO("Media.VideoCapture.AspectRatio", |
| 459 frame->visible_rect().width(), | 446 frame->visible_rect().width(), |
| 460 frame->visible_rect().height()); | 447 frame->visible_rect().height()); |
| 461 double frame_rate = 0.0f; | 448 double frame_rate = 0.0f; |
| 462 if (!frame->metadata()->GetDouble(VideoFrameMetadata::FRAME_RATE, | 449 if (!frame->metadata()->GetDouble(VideoFrameMetadata::FRAME_RATE, |
| 463 &frame_rate)) { | 450 &frame_rate)) { |
| 464 frame_rate = video_capture_format_.frame_rate; | 451 frame_rate = video_capture_format_.frame_rate; |
| 465 } | 452 } |
| 466 UMA_HISTOGRAM_COUNTS("Media.VideoCapture.FrameRate", frame_rate); | 453 UMA_HISTOGRAM_COUNTS("Media.VideoCapture.FrameRate", frame_rate); |
| 467 has_received_frames_ = true; | 454 has_received_frames_ = true; |
| 468 } | 455 } |
| 469 } | 456 } |
| 470 | 457 |
| 471 void VideoCaptureController::OnError() { | 458 void VideoCaptureController::OnError() { |
| 472 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 459 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 473 state_ = VIDEO_CAPTURE_STATE_ERROR; | 460 state_ = VIDEO_CAPTURE_STATE_ERROR; |
| 474 | 461 |
| 475 for (const auto& client : controller_clients_) { | 462 for (const auto& client : controller_clients_) { |
| 476 if (client->session_closed) | 463 if (client->session_closed) |
| 477 continue; | 464 continue; |
| 478 client->event_handler->OnError(client->controller_id); | 465 client->event_handler->OnError(client->controller_id); |
| 479 } | 466 } |
| 480 } | 467 } |
| 481 | 468 |
| 482 void VideoCaptureController::OnLog(const std::string& message) { | 469 void VideoCaptureController::OnLog(const std::string& message) { |
| 483 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 470 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 484 MediaStreamManager::SendMessageToNativeLog("Video capture: " + message); | 471 MediaStreamManager::SendMessageToNativeLog("Video capture: " + message); |
| 485 } | 472 } |
| 486 | 473 |
| 487 void VideoCaptureController::OnBufferDestroyed(int buffer_id_to_drop) { | 474 void VideoCaptureController::OnBufferRetired(int buffer_id) { |
| 488 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 475 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 489 | 476 |
| 490 for (const auto& client : controller_clients_) { | 477 auto buffer_context_iter = FindUnretiredBufferContextFromBufferId(buffer_id); |
| 491 if (client->session_closed) | 478 DCHECK(buffer_context_iter != buffer_contexts_.end()); |
| 492 continue; | |
| 493 | 479 |
| 494 auto known_buffers_entry_iter = | 480 // If there are any clients still using the buffer, we need to allow them |
| 495 std::find(std::begin(client->known_buffers), | 481 // to finish up. We need to hold on to the BufferContext entry until then, |
| 496 std::end(client->known_buffers), buffer_id_to_drop); | 482 // because it contains the consumer hold. |
| 497 if (known_buffers_entry_iter != std::end(client->known_buffers)) { | 483 if (buffer_context_iter->HasZeroConsumerHoldCount()) |
| 498 client->known_buffers.erase(known_buffers_entry_iter); | 484 ReleaseBufferContext(buffer_context_iter); |
| 499 client->event_handler->OnBufferDestroyed(client->controller_id, | 485 else |
| 500 buffer_id_to_drop); | 486 buffer_context_iter->set_is_retired(); |
| 501 } | |
| 502 } | |
| 503 | |
| 504 buffer_id_to_state_map_.erase(buffer_id_to_drop); | |
| 505 } | 487 } |
| 506 | 488 |
| 507 VideoCaptureController::ControllerClient* VideoCaptureController::FindClient( | 489 VideoCaptureController::ControllerClient* VideoCaptureController::FindClient( |
| 508 VideoCaptureControllerID id, | 490 VideoCaptureControllerID id, |
| 509 VideoCaptureControllerEventHandler* handler, | 491 VideoCaptureControllerEventHandler* handler, |
| 510 const ControllerClients& clients) { | 492 const ControllerClients& clients) { |
| 511 for (const auto& client : clients) { | 493 for (const auto& client : clients) { |
| 512 if (client->controller_id == id && client->event_handler == handler) | 494 if (client->controller_id == id && client->event_handler == handler) |
| 513 return client.get(); | 495 return client.get(); |
| 514 } | 496 } |
| 515 return nullptr; | 497 return nullptr; |
| 516 } | 498 } |
| 517 | 499 |
| 518 VideoCaptureController::ControllerClient* VideoCaptureController::FindClient( | 500 VideoCaptureController::ControllerClient* VideoCaptureController::FindClient( |
| 519 int session_id, | 501 int session_id, |
| 520 const ControllerClients& clients) { | 502 const ControllerClients& clients) { |
| 521 for (const auto& client : clients) { | 503 for (const auto& client : clients) { |
| 522 if (client->session_id == session_id) | 504 if (client->session_id == session_id) |
| 523 return client.get(); | 505 return client.get(); |
| 524 } | 506 } |
| 525 return nullptr; | 507 return nullptr; |
| 526 } | 508 } |
| 527 | 509 |
| 510 std::vector<VideoCaptureController::BufferContext>::iterator |
| 511 VideoCaptureController::FindBufferContextFromBufferContextId( |
| 512 int buffer_context_id) { |
| 513 return std::find_if(buffer_contexts_.begin(), buffer_contexts_.end(), |
| 514 [buffer_context_id](const BufferContext& entry) { |
| 515 return entry.buffer_context_id() == buffer_context_id; |
| 516 }); |
| 517 } |
| 518 |
| 519 std::vector<VideoCaptureController::BufferContext>::iterator |
| 520 VideoCaptureController::FindUnretiredBufferContextFromBufferId(int buffer_id) { |
| 521 return std::find_if(buffer_contexts_.begin(), buffer_contexts_.end(), |
| 522 [buffer_id](const BufferContext& entry) { |
| 523 return (entry.buffer_id() == buffer_id) && |
| 524 (entry.is_retired() == false); |
| 525 }); |
| 526 } |
| 527 |
| 528 void VideoCaptureController::OnClientFinishedConsumingBuffer( |
| 529 ControllerClient* client, |
| 530 int buffer_context_id, |
| 531 double consumer_resource_utilization) { |
| 532 auto buffer_context_iter = |
| 533 FindBufferContextFromBufferContextId(buffer_context_id); |
| 534 DCHECK(buffer_context_iter != buffer_contexts_.end()); |
| 535 |
| 536 buffer_context_iter->RecordConsumerUtilization(consumer_resource_utilization); |
| 537 buffer_context_iter->DecreaseConsumerCount(); |
| 538 if (buffer_context_iter->HasZeroConsumerHoldCount() && |
| 539 buffer_context_iter->is_retired()) { |
| 540 ReleaseBufferContext(buffer_context_iter); |
| 541 } |
| 542 } |
| 543 |
| 544 void VideoCaptureController::ReleaseBufferContext( |
| 545 const std::vector<BufferContext>::iterator& buffer_context_iter) { |
| 546 for (const auto& client : controller_clients_) { |
| 547 if (client->session_closed) |
| 548 continue; |
| 549 auto entry_iter = std::find(std::begin(client->known_buffer_context_ids), |
| 550 std::end(client->known_buffer_context_ids), |
| 551 buffer_context_iter->buffer_context_id()); |
| 552 if (entry_iter != std::end(client->known_buffer_context_ids)) { |
| 553 client->known_buffer_context_ids.erase(entry_iter); |
| 554 client->event_handler->OnBufferDestroyed( |
| 555 client->controller_id, buffer_context_iter->buffer_context_id()); |
| 556 } |
| 557 } |
| 558 buffer_contexts_.erase(buffer_context_iter); |
| 559 } |
| 560 |
| 528 } // namespace content | 561 } // namespace content |
| OLD | NEW |