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 201 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
226 | 227 |
227 bool VideoTrackAdapter::VideoFrameResolutionAdapter::MaybeDropFrame( | 228 bool VideoTrackAdapter::VideoFrameResolutionAdapter::MaybeDropFrame( |
228 const scoped_refptr<media::VideoFrame>& frame, | 229 const scoped_refptr<media::VideoFrame>& frame, |
229 float source_frame_rate) { | 230 float source_frame_rate) { |
230 DCHECK(io_thread_checker_.CalledOnValidThread()); | 231 DCHECK(io_thread_checker_.CalledOnValidThread()); |
231 | 232 |
232 // Do not drop frames if max frame rate hasn't been specified or the source | 233 // Do not drop frames if max frame rate hasn't been specified or the source |
233 // frame rate is known and is lower than max. | 234 // frame rate is known and is lower than max. |
234 if (max_frame_rate_ == 0.0f || | 235 if (max_frame_rate_ == 0.0f || |
235 (source_frame_rate > 0 && | 236 (source_frame_rate > 0 && |
236 source_frame_rate <= max_frame_rate_)) | 237 source_frame_rate <= max_frame_rate_)) { |
237 return false; | 238 return false; |
| 239 } |
238 | 240 |
239 base::TimeDelta delta = frame->timestamp() - last_time_stamp_; | 241 base::TimeDelta delta = frame->timestamp() - last_time_stamp_; |
240 if (delta.InMilliseconds() < kMinTimeInMsBetweenFrames) { | 242 if (delta.InMilliseconds() < kMinTimeInMsBetweenFrames) { |
241 // We have seen video frames being delivered from camera devices back to | 243 // We have seen video frames being delivered from camera devices back to |
242 // back. The simple AR filter for frame rate calculation is too short to | 244 // back. The simple AR filter for frame rate calculation is too short to |
243 // handle that. http://crbug/394315 | 245 // handle that. http://crbug/394315 |
244 // TODO(perkj): Can we come up with a way to fix the times stamps and the | 246 // TODO(perkj): Can we come up with a way to fix the times stamps and the |
245 // timing when frames are delivered so all frames can be used? | 247 // timing when frames are delivered so all frames can be used? |
246 // The time stamps are generated by Chrome and not the actual device. | 248 // The time stamps are generated by Chrome and not the actual device. |
247 // Most likely the back to back problem is caused by software and not the | 249 // Most likely the back to back problem is caused by software and not the |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
327 | 329 |
328 bool VideoTrackAdapter::VideoFrameResolutionAdapter::IsEmpty() const { | 330 bool VideoTrackAdapter::VideoFrameResolutionAdapter::IsEmpty() const { |
329 DCHECK(io_thread_checker_.CalledOnValidThread()); | 331 DCHECK(io_thread_checker_.CalledOnValidThread()); |
330 return callbacks_.empty(); | 332 return callbacks_.empty(); |
331 } | 333 } |
332 | 334 |
333 VideoTrackAdapter::VideoTrackAdapter( | 335 VideoTrackAdapter::VideoTrackAdapter( |
334 const scoped_refptr<base::MessageLoopProxy>& io_message_loop) | 336 const scoped_refptr<base::MessageLoopProxy>& io_message_loop) |
335 : io_message_loop_(io_message_loop), | 337 : io_message_loop_(io_message_loop), |
336 renderer_task_runner_(base::MessageLoopProxy::current()), | 338 renderer_task_runner_(base::MessageLoopProxy::current()), |
| 339 monitoring_frame_rate_(false), |
| 340 muted_state_(false), |
337 frame_counter_(0), | 341 frame_counter_(0), |
338 source_frame_rate_(0.0f) { | 342 source_frame_rate_(0.0f) { |
339 DCHECK(io_message_loop_.get()); | 343 DCHECK(io_message_loop_.get()); |
340 } | 344 } |
341 | 345 |
342 VideoTrackAdapter::~VideoTrackAdapter() { | 346 VideoTrackAdapter::~VideoTrackAdapter() { |
343 DCHECK(adapters_.empty()); | 347 DCHECK(adapters_.empty()); |
344 UMA_HISTOGRAM_BOOLEAN("Media.VideoTrackAdapter.FramesReceived", | 348 UMA_HISTOGRAM_BOOLEAN("Media.VideoTrackAdapter.FramesReceived", |
345 frame_counter_ > 0); | 349 frame_counter_ > 0); |
346 } | 350 } |
347 | 351 |
348 void VideoTrackAdapter::AddTrack( | 352 void VideoTrackAdapter::AddTrack( |
349 const MediaStreamVideoTrack* track, | 353 const MediaStreamVideoTrack* track, |
350 VideoCaptureDeliverFrameCB frame_callback, | 354 VideoCaptureDeliverFrameCB frame_callback, |
351 int max_width, | 355 int max_width, |
352 int max_height, | 356 int max_height, |
353 double min_aspect_ratio, | 357 double min_aspect_ratio, |
354 double max_aspect_ratio, | 358 double max_aspect_ratio, |
355 double max_frame_rate, | 359 double max_frame_rate) { |
356 double source_frame_rate, | |
357 const OnMutedCallback& on_muted_state_callback) { | |
358 DCHECK(thread_checker_.CalledOnValidThread()); | 360 DCHECK(thread_checker_.CalledOnValidThread()); |
359 // Track monitoring should be scheduled before AddTrackOnIO() so it can find | 361 |
360 // |adapters_| empty. | |
361 io_message_loop_->PostTask( | |
362 FROM_HERE, | |
363 base::Bind(&VideoTrackAdapter::StartTrackMonitoringOnIO, | |
364 this, on_muted_state_callback, source_frame_rate)); | |
365 io_message_loop_->PostTask( | 362 io_message_loop_->PostTask( |
366 FROM_HERE, | 363 FROM_HERE, |
367 base::Bind(&VideoTrackAdapter::AddTrackOnIO, | 364 base::Bind(&VideoTrackAdapter::AddTrackOnIO, |
368 this, track, frame_callback, gfx::Size(max_width, max_height), | 365 this, track, frame_callback, gfx::Size(max_width, max_height), |
369 min_aspect_ratio, max_aspect_ratio, max_frame_rate)); | 366 min_aspect_ratio, max_aspect_ratio, max_frame_rate)); |
370 } | 367 } |
371 | 368 |
372 void VideoTrackAdapter::AddTrackOnIO( | 369 void VideoTrackAdapter::AddTrackOnIO( |
373 const MediaStreamVideoTrack* track, | 370 const MediaStreamVideoTrack* track, |
374 VideoCaptureDeliverFrameCB frame_callback, | 371 VideoCaptureDeliverFrameCB frame_callback, |
(...skipping 23 matching lines...) Expand all Loading... |
398 adapter->AddCallback(track, frame_callback); | 395 adapter->AddCallback(track, frame_callback); |
399 } | 396 } |
400 | 397 |
401 void VideoTrackAdapter::RemoveTrack(const MediaStreamVideoTrack* track) { | 398 void VideoTrackAdapter::RemoveTrack(const MediaStreamVideoTrack* track) { |
402 DCHECK(thread_checker_.CalledOnValidThread()); | 399 DCHECK(thread_checker_.CalledOnValidThread()); |
403 io_message_loop_->PostTask( | 400 io_message_loop_->PostTask( |
404 FROM_HERE, | 401 FROM_HERE, |
405 base::Bind(&VideoTrackAdapter::RemoveTrackOnIO, this, track)); | 402 base::Bind(&VideoTrackAdapter::RemoveTrackOnIO, this, track)); |
406 } | 403 } |
407 | 404 |
408 void VideoTrackAdapter::StartTrackMonitoringOnIO( | 405 void VideoTrackAdapter::StartFrameMonitoring( |
409 const OnMutedCallback& on_muted_state_callback, | 406 double source_frame_rate, |
| 407 const OnMutedCallback& on_muted_callback) { |
| 408 DCHECK(thread_checker_.CalledOnValidThread()); |
| 409 |
| 410 VideoTrackAdapter::OnMutedCallback bound_on_muted_callback = |
| 411 media::BindToCurrentLoop(on_muted_callback); |
| 412 |
| 413 io_message_loop_->PostTask( |
| 414 FROM_HERE, |
| 415 base::Bind(&VideoTrackAdapter::StartFrameMonitoringOnIO, |
| 416 this, bound_on_muted_callback, source_frame_rate)); |
| 417 } |
| 418 |
| 419 void VideoTrackAdapter::StartFrameMonitoringOnIO( |
| 420 const OnMutedCallback& on_muted_callback, |
410 double source_frame_rate) { | 421 double source_frame_rate) { |
411 DCHECK(io_message_loop_->BelongsToCurrentThread()); | 422 DCHECK(io_message_loop_->BelongsToCurrentThread()); |
412 // Only trigger monitoring for the first Track. | 423 DCHECK(!monitoring_frame_rate_); |
413 if (!adapters_.empty()) | 424 |
414 return; | 425 monitoring_frame_rate_ = true; |
| 426 |
415 // If the source does not know the frame rate, set one by default. | 427 // If the source does not know the frame rate, set one by default. |
416 if (source_frame_rate == 0.0f) | 428 if (source_frame_rate == 0.0f) |
417 source_frame_rate = MediaStreamVideoSource::kDefaultFrameRate; | 429 source_frame_rate = MediaStreamVideoSource::kDefaultFrameRate; |
418 source_frame_rate_ = source_frame_rate; | 430 source_frame_rate_ = source_frame_rate; |
419 DVLOG(1) << "Monitoring frame creation, first (large) delay: " | 431 DVLOG(1) << "Monitoring frame creation, first (large) delay: " |
420 << (kFirstFrameTimeoutInFrameIntervals / source_frame_rate_) << "s"; | 432 << (kFirstFrameTimeoutInFrameIntervals / source_frame_rate_) << "s"; |
421 io_message_loop_->PostDelayedTask(FROM_HERE, | 433 io_message_loop_->PostDelayedTask(FROM_HERE, |
422 base::Bind(&VideoTrackAdapter::CheckFramesReceivedOnIO, this, | 434 base::Bind(&VideoTrackAdapter::CheckFramesReceivedOnIO, this, |
423 on_muted_state_callback, frame_counter_), | 435 on_muted_callback, frame_counter_), |
424 base::TimeDelta::FromSecondsD(kFirstFrameTimeoutInFrameIntervals / | 436 base::TimeDelta::FromSecondsD(kFirstFrameTimeoutInFrameIntervals / |
425 source_frame_rate_)); | 437 source_frame_rate_)); |
426 } | 438 } |
427 | 439 |
| 440 void VideoTrackAdapter::StopFrameMonitoring() { |
| 441 DCHECK(thread_checker_.CalledOnValidThread()); |
| 442 io_message_loop_->PostTask( |
| 443 FROM_HERE, |
| 444 base::Bind(&VideoTrackAdapter::StopFrameMonitoringOnIO, this)); |
| 445 } |
| 446 |
| 447 void VideoTrackAdapter::StopFrameMonitoringOnIO() { |
| 448 DCHECK(io_message_loop_->BelongsToCurrentThread()); |
| 449 monitoring_frame_rate_ = false; |
| 450 } |
| 451 |
428 void VideoTrackAdapter::RemoveTrackOnIO(const MediaStreamVideoTrack* track) { | 452 void VideoTrackAdapter::RemoveTrackOnIO(const MediaStreamVideoTrack* track) { |
429 DCHECK(io_message_loop_->BelongsToCurrentThread()); | 453 DCHECK(io_message_loop_->BelongsToCurrentThread()); |
430 for (FrameAdapters::iterator it = adapters_.begin(); | 454 for (FrameAdapters::iterator it = adapters_.begin(); |
431 it != adapters_.end(); ++it) { | 455 it != adapters_.end(); ++it) { |
432 (*it)->RemoveCallback(track); | 456 (*it)->RemoveCallback(track); |
433 if ((*it)->IsEmpty()) { | 457 if ((*it)->IsEmpty()) { |
434 adapters_.erase(it); | 458 adapters_.erase(it); |
435 break; | 459 break; |
436 } | 460 } |
437 } | 461 } |
438 } | 462 } |
439 | 463 |
440 void VideoTrackAdapter::DeliverFrameOnIO( | 464 void VideoTrackAdapter::DeliverFrameOnIO( |
441 const scoped_refptr<media::VideoFrame>& frame, | 465 const scoped_refptr<media::VideoFrame>& frame, |
442 const media::VideoCaptureFormat& format, | 466 const media::VideoCaptureFormat& format, |
443 const base::TimeTicks& estimated_capture_time) { | 467 const base::TimeTicks& estimated_capture_time) { |
444 DCHECK(io_message_loop_->BelongsToCurrentThread()); | 468 DCHECK(io_message_loop_->BelongsToCurrentThread()); |
445 TRACE_EVENT0("video", "VideoTrackAdapter::DeliverFrameOnIO"); | 469 TRACE_EVENT0("video", "VideoTrackAdapter::DeliverFrameOnIO"); |
446 ++frame_counter_; | 470 ++frame_counter_; |
447 for (FrameAdapters::iterator it = adapters_.begin(); | 471 for (FrameAdapters::iterator it = adapters_.begin(); |
448 it != adapters_.end(); ++it) { | 472 it != adapters_.end(); ++it) { |
449 (*it)->DeliverFrame(frame, format, estimated_capture_time); | 473 (*it)->DeliverFrame(frame, format, estimated_capture_time); |
450 } | 474 } |
451 } | 475 } |
452 | 476 |
453 void VideoTrackAdapter::CheckFramesReceivedOnIO( | 477 void VideoTrackAdapter::CheckFramesReceivedOnIO( |
454 const OnMutedCallback& set_muted_state_callback, | 478 const OnMutedCallback& set_muted_state_callback, |
455 uint64 old_frame_counter_snapshot) { | 479 uint64 old_frame_counter_snapshot) { |
456 DCHECK(io_message_loop_->BelongsToCurrentThread()); | 480 DCHECK(io_message_loop_->BelongsToCurrentThread()); |
| 481 |
| 482 if (!monitoring_frame_rate_) |
| 483 return; |
| 484 |
457 DVLOG_IF(1, old_frame_counter_snapshot == frame_counter_) | 485 DVLOG_IF(1, old_frame_counter_snapshot == frame_counter_) |
458 << "No frames have passed, setting source as Muted."; | 486 << "No frames have passed, setting source as Muted."; |
459 set_muted_state_callback.Run(old_frame_counter_snapshot == frame_counter_); | |
460 | 487 |
461 // Rearm the monitoring while there are active Tracks, i.e. as long as the | 488 bool muted_state = old_frame_counter_snapshot == frame_counter_; |
462 // owner MediaStreamSource is active. | 489 if (muted_state_ != muted_state) { |
| 490 set_muted_state_callback.Run(muted_state); |
| 491 muted_state_ = muted_state; |
| 492 } |
| 493 |
463 io_message_loop_->PostDelayedTask(FROM_HERE, | 494 io_message_loop_->PostDelayedTask(FROM_HERE, |
464 base::Bind(&VideoTrackAdapter::CheckFramesReceivedOnIO, this, | 495 base::Bind(&VideoTrackAdapter::CheckFramesReceivedOnIO, this, |
465 set_muted_state_callback, frame_counter_), | 496 set_muted_state_callback, frame_counter_), |
466 base::TimeDelta::FromSecondsD(kNormalFrameTimeoutInFrameIntervals / | 497 base::TimeDelta::FromSecondsD(kNormalFrameTimeoutInFrameIntervals / |
467 source_frame_rate_)); | 498 source_frame_rate_)); |
468 } | 499 } |
469 | 500 |
470 } // namespace content | 501 } // namespace content |
OLD | NEW |