| 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 |