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 |