| 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 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 103 frame_buffer_pool_(frame_buffer_pool), | 103 frame_buffer_pool_(frame_buffer_pool), |
| 104 max_consumer_utilization_( | 104 max_consumer_utilization_( |
| 105 media::VideoFrameConsumerFeedbackObserver::kNoUtilizationRecorded), | 105 media::VideoFrameConsumerFeedbackObserver::kNoUtilizationRecorded), |
| 106 consumer_hold_count_(0) {} | 106 consumer_hold_count_(0) {} |
| 107 | 107 |
| 108 VideoCaptureController::BufferState::~BufferState() = default; | 108 VideoCaptureController::BufferState::~BufferState() = default; |
| 109 | 109 |
| 110 VideoCaptureController::BufferState::BufferState( | 110 VideoCaptureController::BufferState::BufferState( |
| 111 const VideoCaptureController::BufferState& other) = default; | 111 const VideoCaptureController::BufferState& other) = default; |
| 112 | 112 |
| 113 VideoCaptureController::BufferState& VideoCaptureController::BufferState:: |
| 114 operator=(const BufferState& other) = default; |
| 115 |
| 113 void VideoCaptureController::BufferState::RecordConsumerUtilization( | 116 void VideoCaptureController::BufferState::RecordConsumerUtilization( |
| 114 double utilization) { | 117 double utilization) { |
| 115 if (std::isfinite(utilization) && utilization >= 0.0) { | 118 if (std::isfinite(utilization) && utilization >= 0.0) { |
| 116 max_consumer_utilization_ = | 119 max_consumer_utilization_ = |
| 117 std::max(max_consumer_utilization_, utilization); | 120 std::max(max_consumer_utilization_, utilization); |
| 118 } | 121 } |
| 119 } | 122 } |
| 120 | 123 |
| 121 void VideoCaptureController::BufferState::IncreaseConsumerCount() { | 124 void VideoCaptureController::BufferState::IncreaseConsumerCount() { |
| 122 if (consumer_hold_count_ == 0) | 125 if (consumer_hold_count_ == 0) |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 171 base::WeakPtr<VideoCaptureController> | 174 base::WeakPtr<VideoCaptureController> |
| 172 VideoCaptureController::GetWeakPtrForIOThread() { | 175 VideoCaptureController::GetWeakPtrForIOThread() { |
| 173 return weak_ptr_factory_.GetWeakPtr(); | 176 return weak_ptr_factory_.GetWeakPtr(); |
| 174 } | 177 } |
| 175 | 178 |
| 176 void VideoCaptureController::SetFrameBufferPool( | 179 void VideoCaptureController::SetFrameBufferPool( |
| 177 std::unique_ptr<media::FrameBufferPool> frame_buffer_pool) { | 180 std::unique_ptr<media::FrameBufferPool> frame_buffer_pool) { |
| 178 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 181 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 179 frame_buffer_pool_ = std::move(frame_buffer_pool); | 182 frame_buffer_pool_ = std::move(frame_buffer_pool); |
| 180 // Update existing BufferState entries. | 183 // Update existing BufferState entries. |
| 181 for (auto& entry : buffer_id_to_state_map_) | 184 for (auto& entry : buffer_states_) |
| 182 entry.second.SetFrameBufferPool(frame_buffer_pool_.get()); | 185 entry.SetFrameBufferPool(frame_buffer_pool_.get()); |
| 183 } | 186 } |
| 184 | 187 |
| 185 void VideoCaptureController::SetConsumerFeedbackObserver( | 188 void VideoCaptureController::SetConsumerFeedbackObserver( |
| 186 std::unique_ptr<media::VideoFrameConsumerFeedbackObserver> | 189 std::unique_ptr<media::VideoFrameConsumerFeedbackObserver> |
| 187 consumer_feedback_observer) { | 190 consumer_feedback_observer) { |
| 188 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 191 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 189 consumer_feedback_observer_ = std::move(consumer_feedback_observer); | 192 consumer_feedback_observer_ = std::move(consumer_feedback_observer); |
| 190 // Update existing BufferState entries. | 193 // Update existing BufferState entries. |
| 191 for (auto& entry : buffer_id_to_state_map_) | 194 for (auto& entry : buffer_states_) |
| 192 entry.second.SetConsumerFeedbackObserver(consumer_feedback_observer_.get()); | 195 entry.SetConsumerFeedbackObserver(consumer_feedback_observer_.get()); |
| 193 } | 196 } |
| 194 | 197 |
| 195 void VideoCaptureController::AddClient( | 198 void VideoCaptureController::AddClient( |
| 196 VideoCaptureControllerID id, | 199 VideoCaptureControllerID id, |
| 197 VideoCaptureControllerEventHandler* event_handler, | 200 VideoCaptureControllerEventHandler* event_handler, |
| 198 media::VideoCaptureSessionId session_id, | 201 media::VideoCaptureSessionId session_id, |
| 199 const media::VideoCaptureParams& params) { | 202 const media::VideoCaptureParams& params) { |
| 200 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 203 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 201 DVLOG(1) << "VideoCaptureController::AddClient() -- id=" << id | 204 DVLOG(1) << "VideoCaptureController::AddClient() -- id=" << id |
| 202 << ", session_id=" << session_id | 205 << ", session_id=" << session_id |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 244 int VideoCaptureController::RemoveClient( | 247 int VideoCaptureController::RemoveClient( |
| 245 VideoCaptureControllerID id, | 248 VideoCaptureControllerID id, |
| 246 VideoCaptureControllerEventHandler* event_handler) { | 249 VideoCaptureControllerEventHandler* event_handler) { |
| 247 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 250 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 248 DVLOG(1) << "VideoCaptureController::RemoveClient, id " << id; | 251 DVLOG(1) << "VideoCaptureController::RemoveClient, id " << id; |
| 249 | 252 |
| 250 ControllerClient* client = FindClient(id, event_handler, controller_clients_); | 253 ControllerClient* client = FindClient(id, event_handler, controller_clients_); |
| 251 if (!client) | 254 if (!client) |
| 252 return kInvalidMediaCaptureSessionId; | 255 return kInvalidMediaCaptureSessionId; |
| 253 | 256 |
| 254 // Take back all buffers held by the |client|. | 257 for (const auto& buffer_id : client->buffers_in_use) { |
| 255 for (const auto& buffer_id : client->buffers_in_use) | 258 OnClientFinishedConsumingBuffer( |
| 256 buffer_id_to_state_map_.at(buffer_id).DecreaseConsumerCount(); | 259 client, buffer_id, |
| 260 media::VideoFrameConsumerFeedbackObserver::kNoUtilizationRecorded); |
| 261 } |
| 257 client->buffers_in_use.clear(); | 262 client->buffers_in_use.clear(); |
| 258 | 263 |
| 259 int session_id = client->session_id; | 264 int session_id = client->session_id; |
| 260 controller_clients_.remove_if( | 265 controller_clients_.remove_if( |
| 261 [client](const std::unique_ptr<ControllerClient>& ptr) { | 266 [client](const std::unique_ptr<ControllerClient>& ptr) { |
| 262 return ptr.get() == client; | 267 return ptr.get() == client; |
| 263 }); | 268 }); |
| 264 | 269 |
| 265 return session_id; | 270 return session_id; |
| 266 } | 271 } |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 349 NOTREACHED(); | 354 NOTREACHED(); |
| 350 return; | 355 return; |
| 351 } | 356 } |
| 352 auto buffers_in_use_entry_iter = | 357 auto buffers_in_use_entry_iter = |
| 353 std::find(std::begin(client->buffers_in_use), | 358 std::find(std::begin(client->buffers_in_use), |
| 354 std::end(client->buffers_in_use), buffer_id); | 359 std::end(client->buffers_in_use), buffer_id); |
| 355 if (buffers_in_use_entry_iter == std::end(client->buffers_in_use)) { | 360 if (buffers_in_use_entry_iter == std::end(client->buffers_in_use)) { |
| 356 NOTREACHED(); | 361 NOTREACHED(); |
| 357 return; | 362 return; |
| 358 } | 363 } |
| 364 client->buffers_in_use.erase(buffers_in_use_entry_iter); |
| 359 | 365 |
| 360 BufferState& buffer_state = buffer_id_to_state_map_.at(buffer_id); | 366 OnClientFinishedConsumingBuffer(client, buffer_id, |
| 361 buffer_state.RecordConsumerUtilization(consumer_resource_utilization); | 367 consumer_resource_utilization); |
| 362 buffer_state.DecreaseConsumerCount(); | |
| 363 client->buffers_in_use.erase(buffers_in_use_entry_iter); | |
| 364 } | 368 } |
| 365 | 369 |
| 366 const media::VideoCaptureFormat& | 370 const media::VideoCaptureFormat& |
| 367 VideoCaptureController::GetVideoCaptureFormat() const { | 371 VideoCaptureController::GetVideoCaptureFormat() const { |
| 368 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 372 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 369 return video_capture_format_; | 373 return video_capture_format_; |
| 370 } | 374 } |
| 371 | 375 |
| 372 void VideoCaptureController::OnIncomingCapturedVideoFrame( | 376 void VideoCaptureController::OnIncomingCapturedVideoFrame( |
| 373 media::VideoCaptureDevice::Client::Buffer buffer, | 377 media::VideoCaptureDevice::Client::Buffer buffer, |
| 374 scoped_refptr<VideoFrame> frame) { | 378 scoped_refptr<VideoFrame> frame) { |
| 375 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 379 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 376 const int buffer_id = buffer.id(); | 380 const int buffer_id = buffer.id(); |
| 377 DCHECK_NE(buffer_id, media::VideoCaptureBufferPool::kInvalidId); | 381 DCHECK_NE(buffer_id, media::VideoCaptureBufferPool::kInvalidId); |
| 378 | 382 auto buffer_state_iter = FindBufferState(buffer_id); |
| 379 // Insert if not exists. | 383 if (buffer_state_iter == buffer_states_.end()) { |
| 380 const auto it = | 384 buffer_states_.emplace_back(buffer_id, buffer.frame_feedback_id(), |
| 381 buffer_id_to_state_map_ | 385 consumer_feedback_observer_.get(), |
| 382 .insert(std::make_pair( | 386 frame_buffer_pool_.get()); |
| 383 buffer_id, BufferState(buffer_id, buffer.frame_feedback_id(), | 387 buffer_state_iter = buffer_states_.end() - 1; |
| 384 consumer_feedback_observer_.get(), | 388 } |
| 385 frame_buffer_pool_.get()))) | 389 DCHECK(buffer_state_iter->HasZeroConsumerHoldCount()); |
| 386 .first; | |
| 387 BufferState& buffer_state = it->second; | |
| 388 DCHECK(buffer_state.HasZeroConsumerHoldCount()); | |
| 389 | 390 |
| 390 if (state_ == VIDEO_CAPTURE_STATE_STARTED) { | 391 if (state_ == VIDEO_CAPTURE_STATE_STARTED) { |
| 391 if (!frame->metadata()->HasKey(VideoFrameMetadata::FRAME_RATE)) { | 392 if (!frame->metadata()->HasKey(VideoFrameMetadata::FRAME_RATE)) { |
| 392 frame->metadata()->SetDouble(VideoFrameMetadata::FRAME_RATE, | 393 frame->metadata()->SetDouble(VideoFrameMetadata::FRAME_RATE, |
| 393 video_capture_format_.frame_rate); | 394 video_capture_format_.frame_rate); |
| 394 } | 395 } |
| 395 std::unique_ptr<base::DictionaryValue> metadata = | 396 std::unique_ptr<base::DictionaryValue> metadata = |
| 396 frame->metadata()->CopyInternalValues(); | 397 frame->metadata()->CopyInternalValues(); |
| 397 | 398 |
| 398 // Only I420 and Y16 pixel formats are currently supported. | 399 // Only I420 and Y16 pixel formats are currently supported. |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 433 client->event_handler->OnBufferReady(client->controller_id, buffer_id, | 434 client->event_handler->OnBufferReady(client->controller_id, buffer_id, |
| 434 frame); | 435 frame); |
| 435 | 436 |
| 436 auto buffers_in_use_entry_iter = | 437 auto buffers_in_use_entry_iter = |
| 437 std::find(std::begin(client->buffers_in_use), | 438 std::find(std::begin(client->buffers_in_use), |
| 438 std::end(client->buffers_in_use), buffer_id); | 439 std::end(client->buffers_in_use), buffer_id); |
| 439 if (buffers_in_use_entry_iter == std::end(client->buffers_in_use)) | 440 if (buffers_in_use_entry_iter == std::end(client->buffers_in_use)) |
| 440 client->buffers_in_use.push_back(buffer_id); | 441 client->buffers_in_use.push_back(buffer_id); |
| 441 else | 442 else |
| 442 DCHECK(false) << "Unexpected duplicate buffer: " << buffer_id; | 443 DCHECK(false) << "Unexpected duplicate buffer: " << buffer_id; |
| 443 buffer_state.IncreaseConsumerCount(); | 444 buffer_state_iter->IncreaseConsumerCount(); |
| 444 } | 445 } |
| 445 } | 446 } |
| 446 | 447 |
| 447 if (!has_received_frames_) { | 448 if (!has_received_frames_) { |
| 448 UMA_HISTOGRAM_COUNTS("Media.VideoCapture.Width", | 449 UMA_HISTOGRAM_COUNTS("Media.VideoCapture.Width", |
| 449 frame->visible_rect().width()); | 450 frame->visible_rect().width()); |
| 450 UMA_HISTOGRAM_COUNTS("Media.VideoCapture.Height", | 451 UMA_HISTOGRAM_COUNTS("Media.VideoCapture.Height", |
| 451 frame->visible_rect().height()); | 452 frame->visible_rect().height()); |
| 452 UMA_HISTOGRAM_ASPECT_RATIO("Media.VideoCapture.AspectRatio", | 453 UMA_HISTOGRAM_ASPECT_RATIO("Media.VideoCapture.AspectRatio", |
| 453 frame->visible_rect().width(), | 454 frame->visible_rect().width(), |
| 454 frame->visible_rect().height()); | 455 frame->visible_rect().height()); |
| 455 double frame_rate = 0.0f; | 456 double frame_rate = 0.0f; |
| 456 if (!frame->metadata()->GetDouble(VideoFrameMetadata::FRAME_RATE, | 457 if (!frame->metadata()->GetDouble(VideoFrameMetadata::FRAME_RATE, |
| 457 &frame_rate)) { | 458 &frame_rate)) { |
| 458 frame_rate = video_capture_format_.frame_rate; | 459 frame_rate = video_capture_format_.frame_rate; |
| 459 } | 460 } |
| 460 UMA_HISTOGRAM_COUNTS("Media.VideoCapture.FrameRate", frame_rate); | 461 UMA_HISTOGRAM_COUNTS("Media.VideoCapture.FrameRate", frame_rate); |
| 461 has_received_frames_ = true; | 462 has_received_frames_ = true; |
| 462 } | 463 } |
| 463 } | 464 } |
| 464 | 465 |
| 465 void VideoCaptureController::OnError() { | 466 void VideoCaptureController::OnError() { |
| 466 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 467 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 467 state_ = VIDEO_CAPTURE_STATE_ERROR; | 468 state_ = VIDEO_CAPTURE_STATE_ERROR; |
| 468 | 469 |
| 469 for (const auto& client : controller_clients_) { | 470 for (const auto& client : controller_clients_) { |
| 470 if (client->session_closed) | 471 if (client->session_closed) |
| 471 continue; | 472 continue; |
| 472 client->event_handler->OnError(client->controller_id); | 473 client->event_handler->OnError(client->controller_id); |
| 473 } | 474 } |
| 474 } | 475 } |
| 475 | 476 |
| 476 void VideoCaptureController::OnLog(const std::string& message) { | 477 void VideoCaptureController::OnLog(const std::string& message) { |
| 477 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 478 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 478 MediaStreamManager::SendMessageToNativeLog("Video capture: " + message); | 479 MediaStreamManager::SendMessageToNativeLog("Video capture: " + message); |
| 479 } | 480 } |
| 480 | 481 |
| 481 void VideoCaptureController::OnBufferDestroyed(int buffer_id_to_drop) { | 482 void VideoCaptureController::OnBufferRetired(int buffer_id) { |
| 482 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 483 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 483 | 484 |
| 484 for (const auto& client : controller_clients_) { | 485 auto buffer_state_iter = FindBufferState(buffer_id); |
| 485 if (client->session_closed) | 486 DCHECK(buffer_state_iter != buffer_states_.end()); |
| 486 continue; | |
| 487 | 487 |
| 488 auto known_buffers_entry_iter = | 488 // If there are any clients still using the buffer, we need to allow them |
| 489 std::find(std::begin(client->known_buffers), | 489 // to finish up. We need to hold on to the BufferState entry until then, |
| 490 std::end(client->known_buffers), buffer_id_to_drop); | 490 // because it contains the consumer hold. |
| 491 if (known_buffers_entry_iter != std::end(client->known_buffers)) { | 491 if (buffer_state_iter->HasZeroConsumerHoldCount()) |
| 492 client->known_buffers.erase(known_buffers_entry_iter); | 492 ReleaseBufferState(buffer_state_iter); |
| 493 client->event_handler->OnBufferDestroyed(client->controller_id, | 493 else |
| 494 buffer_id_to_drop); | 494 buffer_state_iter->set_is_retired(); |
| 495 } | |
| 496 } | |
| 497 | |
| 498 buffer_id_to_state_map_.erase(buffer_id_to_drop); | |
| 499 } | 495 } |
| 500 | 496 |
| 501 VideoCaptureController::ControllerClient* VideoCaptureController::FindClient( | 497 VideoCaptureController::ControllerClient* VideoCaptureController::FindClient( |
| 502 VideoCaptureControllerID id, | 498 VideoCaptureControllerID id, |
| 503 VideoCaptureControllerEventHandler* handler, | 499 VideoCaptureControllerEventHandler* handler, |
| 504 const ControllerClients& clients) { | 500 const ControllerClients& clients) { |
| 505 for (const auto& client : clients) { | 501 for (const auto& client : clients) { |
| 506 if (client->controller_id == id && client->event_handler == handler) | 502 if (client->controller_id == id && client->event_handler == handler) |
| 507 return client.get(); | 503 return client.get(); |
| 508 } | 504 } |
| 509 return nullptr; | 505 return nullptr; |
| 510 } | 506 } |
| 511 | 507 |
| 512 VideoCaptureController::ControllerClient* VideoCaptureController::FindClient( | 508 VideoCaptureController::ControllerClient* VideoCaptureController::FindClient( |
| 513 int session_id, | 509 int session_id, |
| 514 const ControllerClients& clients) { | 510 const ControllerClients& clients) { |
| 515 for (const auto& client : clients) { | 511 for (const auto& client : clients) { |
| 516 if (client->session_id == session_id) | 512 if (client->session_id == session_id) |
| 517 return client.get(); | 513 return client.get(); |
| 518 } | 514 } |
| 519 return nullptr; | 515 return nullptr; |
| 520 } | 516 } |
| 521 | 517 |
| 518 std::vector<VideoCaptureController::BufferState>::iterator |
| 519 VideoCaptureController::FindBufferState(int buffer_id) { |
| 520 auto buffer_state_iter = |
| 521 std::find_if(buffer_states_.begin(), buffer_states_.end(), |
| 522 [buffer_id](const BufferState& entry) { |
| 523 return entry.buffer_id() == buffer_id; |
| 524 }); |
| 525 return buffer_state_iter; |
| 526 } |
| 527 |
| 528 void VideoCaptureController::OnClientFinishedConsumingBuffer( |
| 529 ControllerClient* client, |
| 530 int buffer_id, |
| 531 double consumer_resource_utilization) { |
| 532 auto buffer_state_iter = FindBufferState(buffer_id); |
| 533 DCHECK(buffer_state_iter != buffer_states_.end()); |
| 534 |
| 535 buffer_state_iter->RecordConsumerUtilization(consumer_resource_utilization); |
| 536 buffer_state_iter->DecreaseConsumerCount(); |
| 537 if (buffer_state_iter->HasZeroConsumerHoldCount() && |
| 538 buffer_state_iter->is_retired()) { |
| 539 ReleaseBufferState(buffer_state_iter); |
| 540 } |
| 541 } |
| 542 |
| 543 void VideoCaptureController::ReleaseBufferState( |
| 544 const std::vector<BufferState>::iterator& buffer_state_iter) { |
| 545 for (const auto& client : controller_clients_) { |
| 546 if (client->session_closed) |
| 547 continue; |
| 548 |
| 549 auto known_buffers_entry_iter = std::find(std::begin(client->known_buffers), |
| 550 std::end(client->known_buffers), |
| 551 buffer_state_iter->buffer_id()); |
| 552 if (known_buffers_entry_iter != std::end(client->known_buffers)) { |
| 553 client->known_buffers.erase(known_buffers_entry_iter); |
| 554 client->event_handler->OnBufferDestroyed(client->controller_id, |
| 555 buffer_state_iter->buffer_id()); |
| 556 } |
| 557 } |
| 558 buffer_states_.erase(buffer_state_iter); |
| 559 } |
| 560 |
| 522 } // namespace content | 561 } // namespace content |
| OLD | NEW |