OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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/renderer/media/video_track_adapter.h" | 5 #include "content/renderer/media/video_track_adapter.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <limits> | 8 #include <limits> |
9 #include <utility> | 9 #include <utility> |
10 | 10 |
11 #include "base/bind.h" | 11 #include "base/bind.h" |
12 #include "base/debug/trace_event.h" | 12 #include "base/debug/trace_event.h" |
13 #include "base/location.h" | 13 #include "base/location.h" |
14 #include "base/metrics/histogram.h" | 14 #include "base/metrics/histogram.h" |
| 15 #include "media/base/bind_to_current_loop.h" |
15 #include "media/base/video_util.h" | 16 #include "media/base/video_util.h" |
16 | 17 |
17 namespace content { | 18 namespace content { |
18 | 19 |
19 namespace { | 20 namespace { |
20 | 21 |
21 // Amount of frame intervals to wait before considering the source as muted, for | 22 // Amount of frame intervals to wait before considering the source as muted, for |
22 // the first frame and under normal conditions, respectively. First frame might | 23 // the first frame and under normal conditions, respectively. First frame might |
23 // take longer to arrive due to source startup. | 24 // take longer to arrive due to source startup. |
24 const float kFirstFrameTimeoutInFrameIntervals = 100.0f; | 25 const float kFirstFrameTimeoutInFrameIntervals = 100.0f; |
(...skipping 277 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
302 | 303 |
303 bool VideoTrackAdapter::VideoFrameResolutionAdapter::IsEmpty() const { | 304 bool VideoTrackAdapter::VideoFrameResolutionAdapter::IsEmpty() const { |
304 DCHECK(io_thread_checker_.CalledOnValidThread()); | 305 DCHECK(io_thread_checker_.CalledOnValidThread()); |
305 return callbacks_.empty(); | 306 return callbacks_.empty(); |
306 } | 307 } |
307 | 308 |
308 VideoTrackAdapter::VideoTrackAdapter( | 309 VideoTrackAdapter::VideoTrackAdapter( |
309 const scoped_refptr<base::MessageLoopProxy>& io_message_loop) | 310 const scoped_refptr<base::MessageLoopProxy>& io_message_loop) |
310 : io_message_loop_(io_message_loop), | 311 : io_message_loop_(io_message_loop), |
311 renderer_task_runner_(base::MessageLoopProxy::current()), | 312 renderer_task_runner_(base::MessageLoopProxy::current()), |
| 313 monitoring_frame_rate_(false), |
| 314 muted_state_(false), |
312 frame_counter_(0), | 315 frame_counter_(0), |
313 source_frame_rate_(0.0f) { | 316 source_frame_rate_(0.0f) { |
314 DCHECK(io_message_loop_); | 317 DCHECK(io_message_loop_); |
315 } | 318 } |
316 | 319 |
317 VideoTrackAdapter::~VideoTrackAdapter() { | 320 VideoTrackAdapter::~VideoTrackAdapter() { |
318 DCHECK(adapters_.empty()); | 321 DCHECK(adapters_.empty()); |
319 UMA_HISTOGRAM_BOOLEAN("Media.VideoTrackAdapter.FramesReceived", | 322 UMA_HISTOGRAM_BOOLEAN("Media.VideoTrackAdapter.FramesReceived", |
320 frame_counter_ > 0); | 323 frame_counter_ > 0); |
321 } | 324 } |
322 | 325 |
323 void VideoTrackAdapter::AddTrack( | 326 void VideoTrackAdapter::AddTrack( |
324 const MediaStreamVideoTrack* track, | 327 const MediaStreamVideoTrack* track, |
325 VideoCaptureDeliverFrameCB frame_callback, | 328 VideoCaptureDeliverFrameCB frame_callback, |
326 int max_width, | 329 int max_width, |
327 int max_height, | 330 int max_height, |
328 double min_aspect_ratio, | 331 double min_aspect_ratio, |
329 double max_aspect_ratio, | 332 double max_aspect_ratio, |
330 double max_frame_rate, | 333 double max_frame_rate) { |
331 double source_frame_rate, | |
332 const OnMutedCallback& on_muted_state_callback) { | |
333 DCHECK(thread_checker_.CalledOnValidThread()); | 334 DCHECK(thread_checker_.CalledOnValidThread()); |
334 // Track monitoring should be scheduled before AddTrackOnIO() so it can find | 335 |
335 // |adapters_| empty. | |
336 io_message_loop_->PostTask( | |
337 FROM_HERE, | |
338 base::Bind(&VideoTrackAdapter::StartTrackMonitoringOnIO, | |
339 this, on_muted_state_callback, source_frame_rate)); | |
340 io_message_loop_->PostTask( | 336 io_message_loop_->PostTask( |
341 FROM_HERE, | 337 FROM_HERE, |
342 base::Bind(&VideoTrackAdapter::AddTrackOnIO, | 338 base::Bind(&VideoTrackAdapter::AddTrackOnIO, |
343 this, track, frame_callback, gfx::Size(max_width, max_height), | 339 this, track, frame_callback, gfx::Size(max_width, max_height), |
344 min_aspect_ratio, max_aspect_ratio, max_frame_rate)); | 340 min_aspect_ratio, max_aspect_ratio, max_frame_rate)); |
345 } | 341 } |
346 | 342 |
347 void VideoTrackAdapter::AddTrackOnIO( | 343 void VideoTrackAdapter::AddTrackOnIO( |
348 const MediaStreamVideoTrack* track, | 344 const MediaStreamVideoTrack* track, |
349 VideoCaptureDeliverFrameCB frame_callback, | 345 VideoCaptureDeliverFrameCB frame_callback, |
(...skipping 23 matching lines...) Expand all Loading... |
373 adapter->AddCallback(track, frame_callback); | 369 adapter->AddCallback(track, frame_callback); |
374 } | 370 } |
375 | 371 |
376 void VideoTrackAdapter::RemoveTrack(const MediaStreamVideoTrack* track) { | 372 void VideoTrackAdapter::RemoveTrack(const MediaStreamVideoTrack* track) { |
377 DCHECK(thread_checker_.CalledOnValidThread()); | 373 DCHECK(thread_checker_.CalledOnValidThread()); |
378 io_message_loop_->PostTask( | 374 io_message_loop_->PostTask( |
379 FROM_HERE, | 375 FROM_HERE, |
380 base::Bind(&VideoTrackAdapter::RemoveTrackOnIO, this, track)); | 376 base::Bind(&VideoTrackAdapter::RemoveTrackOnIO, this, track)); |
381 } | 377 } |
382 | 378 |
383 void VideoTrackAdapter::StartTrackMonitoringOnIO( | 379 void VideoTrackAdapter::StartFrameMonitoring( |
384 const OnMutedCallback& on_muted_state_callback, | 380 double source_frame_rate, |
| 381 const OnMutedCallback& on_muted_callback) { |
| 382 DCHECK(thread_checker_.CalledOnValidThread()); |
| 383 |
| 384 VideoTrackAdapter::OnMutedCallback bound_on_muted_callback = |
| 385 media::BindToCurrentLoop(on_muted_callback); |
| 386 |
| 387 io_message_loop_->PostTask( |
| 388 FROM_HERE, |
| 389 base::Bind(&VideoTrackAdapter::StartFrameMonitoringOnIO, |
| 390 this, bound_on_muted_callback, source_frame_rate)); |
| 391 } |
| 392 |
| 393 void VideoTrackAdapter::StartFrameMonitoringOnIO( |
| 394 const OnMutedCallback& on_muted_callback, |
385 double source_frame_rate) { | 395 double source_frame_rate) { |
386 DCHECK(io_message_loop_->BelongsToCurrentThread()); | 396 DCHECK(io_message_loop_->BelongsToCurrentThread()); |
387 // Only trigger monitoring for the first Track. | 397 DCHECK(!monitoring_frame_rate_); |
388 if (!adapters_.empty()) | 398 |
389 return; | 399 monitoring_frame_rate_ = true; |
| 400 |
390 // If the source does not know the frame rate, set one by default. | 401 // If the source does not know the frame rate, set one by default. |
391 if (source_frame_rate == 0.0f) | 402 if (source_frame_rate == 0.0f) |
392 source_frame_rate = MediaStreamVideoSource::kDefaultFrameRate; | 403 source_frame_rate = MediaStreamVideoSource::kDefaultFrameRate; |
393 source_frame_rate_ = source_frame_rate; | 404 source_frame_rate_ = source_frame_rate; |
394 DVLOG(1) << "Monitoring frame creation, first (large) delay: " | 405 DVLOG(1) << "Monitoring frame creation, first (large) delay: " |
395 << (kFirstFrameTimeoutInFrameIntervals / source_frame_rate_) << "s"; | 406 << (kFirstFrameTimeoutInFrameIntervals / source_frame_rate_) << "s"; |
396 io_message_loop_->PostDelayedTask(FROM_HERE, | 407 io_message_loop_->PostDelayedTask(FROM_HERE, |
397 base::Bind(&VideoTrackAdapter::CheckFramesReceivedOnIO, this, | 408 base::Bind(&VideoTrackAdapter::CheckFramesReceivedOnIO, this, |
398 on_muted_state_callback, frame_counter_), | 409 on_muted_callback, frame_counter_), |
399 base::TimeDelta::FromSecondsD(kFirstFrameTimeoutInFrameIntervals / | 410 base::TimeDelta::FromSecondsD(kFirstFrameTimeoutInFrameIntervals / |
400 source_frame_rate_)); | 411 source_frame_rate_)); |
401 } | 412 } |
402 | 413 |
| 414 void VideoTrackAdapter::StopFrameMonitoring() { |
| 415 DCHECK(thread_checker_.CalledOnValidThread()); |
| 416 io_message_loop_->PostTask( |
| 417 FROM_HERE, |
| 418 base::Bind(&VideoTrackAdapter::StopFrameMonitoringOnIO, this)); |
| 419 } |
| 420 |
| 421 void VideoTrackAdapter::StopFrameMonitoringOnIO() { |
| 422 DCHECK(io_message_loop_->BelongsToCurrentThread()); |
| 423 monitoring_frame_rate_ = false; |
| 424 } |
| 425 |
403 void VideoTrackAdapter::RemoveTrackOnIO(const MediaStreamVideoTrack* track) { | 426 void VideoTrackAdapter::RemoveTrackOnIO(const MediaStreamVideoTrack* track) { |
404 DCHECK(io_message_loop_->BelongsToCurrentThread()); | 427 DCHECK(io_message_loop_->BelongsToCurrentThread()); |
405 for (FrameAdapters::iterator it = adapters_.begin(); | 428 for (FrameAdapters::iterator it = adapters_.begin(); |
406 it != adapters_.end(); ++it) { | 429 it != adapters_.end(); ++it) { |
407 (*it)->RemoveCallback(track); | 430 (*it)->RemoveCallback(track); |
408 if ((*it)->IsEmpty()) { | 431 if ((*it)->IsEmpty()) { |
409 adapters_.erase(it); | 432 adapters_.erase(it); |
410 break; | 433 break; |
411 } | 434 } |
412 } | 435 } |
413 } | 436 } |
414 | 437 |
415 void VideoTrackAdapter::DeliverFrameOnIO( | 438 void VideoTrackAdapter::DeliverFrameOnIO( |
416 const scoped_refptr<media::VideoFrame>& frame, | 439 const scoped_refptr<media::VideoFrame>& frame, |
417 const media::VideoCaptureFormat& format, | 440 const media::VideoCaptureFormat& format, |
418 const base::TimeTicks& estimated_capture_time) { | 441 const base::TimeTicks& estimated_capture_time) { |
419 DCHECK(io_message_loop_->BelongsToCurrentThread()); | 442 DCHECK(io_message_loop_->BelongsToCurrentThread()); |
420 TRACE_EVENT0("video", "VideoTrackAdapter::DeliverFrameOnIO"); | 443 TRACE_EVENT0("video", "VideoTrackAdapter::DeliverFrameOnIO"); |
421 ++frame_counter_; | 444 ++frame_counter_; |
422 for (FrameAdapters::iterator it = adapters_.begin(); | 445 for (FrameAdapters::iterator it = adapters_.begin(); |
423 it != adapters_.end(); ++it) { | 446 it != adapters_.end(); ++it) { |
424 (*it)->DeliverFrame(frame, format, estimated_capture_time); | 447 (*it)->DeliverFrame(frame, format, estimated_capture_time); |
425 } | 448 } |
426 } | 449 } |
427 | 450 |
428 void VideoTrackAdapter::CheckFramesReceivedOnIO( | 451 void VideoTrackAdapter::CheckFramesReceivedOnIO( |
429 const OnMutedCallback& set_muted_state_callback, | 452 const OnMutedCallback& set_muted_state_callback, |
430 uint64 old_frame_counter_snapshot) { | 453 uint64 old_frame_counter_snapshot) { |
431 DCHECK(io_message_loop_->BelongsToCurrentThread()); | 454 DCHECK(io_message_loop_->BelongsToCurrentThread()); |
| 455 |
| 456 if (!monitoring_frame_rate_) |
| 457 return; |
| 458 |
432 DVLOG_IF(1, old_frame_counter_snapshot == frame_counter_) | 459 DVLOG_IF(1, old_frame_counter_snapshot == frame_counter_) |
433 << "No frames have passed, setting source as Muted."; | 460 << "No frames have passed, setting source as Muted."; |
434 set_muted_state_callback.Run(old_frame_counter_snapshot == frame_counter_); | |
435 | 461 |
436 // Rearm the monitoring while there are active Tracks, i.e. as long as the | 462 bool muted_state = old_frame_counter_snapshot == frame_counter_; |
437 // owner MediaStreamSource is active. | 463 if (muted_state_ != muted_state) { |
| 464 set_muted_state_callback.Run(muted_state); |
| 465 muted_state_ = muted_state; |
| 466 } |
| 467 |
438 io_message_loop_->PostDelayedTask(FROM_HERE, | 468 io_message_loop_->PostDelayedTask(FROM_HERE, |
439 base::Bind(&VideoTrackAdapter::CheckFramesReceivedOnIO, this, | 469 base::Bind(&VideoTrackAdapter::CheckFramesReceivedOnIO, this, |
440 set_muted_state_callback, frame_counter_), | 470 set_muted_state_callback, frame_counter_), |
441 base::TimeDelta::FromSecondsD(kNormalFrameTimeoutInFrameIntervals / | 471 base::TimeDelta::FromSecondsD(kNormalFrameTimeoutInFrameIntervals / |
442 source_frame_rate_)); | 472 source_frame_rate_)); |
443 } | 473 } |
444 | 474 |
445 } // namespace content | 475 } // namespace content |
OLD | NEW |