| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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 "media/cast/video_receiver/video_receiver.h" | 5 #include "media/cast/video_receiver/video_receiver.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "base/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/logging.h" | 10 #include "base/logging.h" |
| 11 #include "base/message_loop/message_loop.h" | 11 #include "base/message_loop/message_loop.h" |
| 12 #include "media/cast/cast_defines.h" | 12 #include "media/cast/cast_defines.h" |
| 13 #include "media/cast/framer/framer.h" | 13 #include "media/cast/framer/framer.h" |
| 14 #include "media/cast/rtcp/receiver_rtcp_event_subscriber.h" | 14 #include "media/cast/rtcp/receiver_rtcp_event_subscriber.h" |
| 15 #include "media/cast/rtcp/rtcp_sender.h" | 15 #include "media/cast/rtcp/rtcp_sender.h" |
| 16 #include "media/cast/video_receiver/video_decoder.h" | 16 #include "media/cast/video_receiver/video_decoder.h" |
| 17 | 17 |
| 18 namespace { | 18 namespace { |
| 19 | 19 |
| 20 static const int64 kMinSchedulingDelayMs = 1; | 20 static const int64 kMinSchedulingDelayMs = 1; |
| 21 static const int64 kMinTimeBetweenOffsetUpdatesMs = 2000; | 21 static const int64 kMinTimeBetweenOffsetUpdatesMs = 1000; |
| 22 static const int kTimeOffsetFilter = 8; | 22 static const int kTimeOffsetMaxCounter = 10; |
| 23 static const int64_t kMinProcessIntervalMs = 5; | 23 static const int64_t kMinProcessIntervalMs = 5; |
| 24 | 24 |
| 25 } // namespace | 25 } // namespace |
| 26 | 26 |
| 27 namespace media { | 27 namespace media { |
| 28 namespace cast { | 28 namespace cast { |
| 29 | 29 |
| 30 // Local implementation of RtpData (defined in rtp_rtcp_defines.h). | 30 // Local implementation of RtpData (defined in rtp_rtcp_defines.h). |
| 31 // Used to pass payload data into the video receiver. | 31 // Used to pass payload data into the video receiver. |
| 32 class LocalRtpVideoData : public RtpData { | 32 class LocalRtpVideoData : public RtpData { |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 100 frame_delay_(base::TimeDelta::FromMilliseconds( | 100 frame_delay_(base::TimeDelta::FromMilliseconds( |
| 101 1000 / video_config.max_frame_rate)), | 101 1000 / video_config.max_frame_rate)), |
| 102 incoming_payload_callback_(new LocalRtpVideoData(this)), | 102 incoming_payload_callback_(new LocalRtpVideoData(this)), |
| 103 incoming_payload_feedback_(new LocalRtpVideoFeedback(this)), | 103 incoming_payload_feedback_(new LocalRtpVideoFeedback(this)), |
| 104 rtp_receiver_(cast_environment_->Clock(), | 104 rtp_receiver_(cast_environment_->Clock(), |
| 105 NULL, | 105 NULL, |
| 106 &video_config, | 106 &video_config, |
| 107 incoming_payload_callback_.get()), | 107 incoming_payload_callback_.get()), |
| 108 rtp_video_receiver_statistics_( | 108 rtp_video_receiver_statistics_( |
| 109 new LocalRtpReceiverStatistics(&rtp_receiver_)), | 109 new LocalRtpReceiverStatistics(&rtp_receiver_)), |
| 110 time_offset_counter_(0), |
| 110 decryptor_(), | 111 decryptor_(), |
| 111 time_incoming_packet_updated_(false), | 112 time_incoming_packet_updated_(false), |
| 112 incoming_rtp_timestamp_(0), | 113 incoming_rtp_timestamp_(0), |
| 113 weak_factory_(this) { | 114 weak_factory_(this) { |
| 114 int max_unacked_frames = | 115 int max_unacked_frames = |
| 115 video_config.rtp_max_delay_ms * video_config.max_frame_rate / 1000; | 116 video_config.rtp_max_delay_ms * video_config.max_frame_rate / 1000; |
| 116 DCHECK(max_unacked_frames) << "Invalid argument"; | 117 DCHECK(max_unacked_frames) << "Invalid argument"; |
| 117 | 118 |
| 118 decryptor_.Initialize(video_config.aes_key, video_config.aes_iv_mask); | 119 decryptor_.Initialize(video_config.aes_key, video_config.aes_iv_mask); |
| 119 framer_.reset(new Framer(cast_environment->Clock(), | 120 framer_.reset(new Framer(cast_environment->Clock(), |
| (...skipping 229 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 349 } | 350 } |
| 350 | 351 |
| 351 base::TimeTicks VideoReceiver::GetRenderTime(base::TimeTicks now, | 352 base::TimeTicks VideoReceiver::GetRenderTime(base::TimeTicks now, |
| 352 uint32 rtp_timestamp) { | 353 uint32 rtp_timestamp) { |
| 353 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 354 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); |
| 354 // Senders time in ms when this frame was captured. | 355 // Senders time in ms when this frame was captured. |
| 355 // Note: the senders clock and our local clock might not be synced. | 356 // Note: the senders clock and our local clock might not be synced. |
| 356 base::TimeTicks rtp_timestamp_in_ticks; | 357 base::TimeTicks rtp_timestamp_in_ticks; |
| 357 | 358 |
| 358 // Compute the time offset_in_ticks based on the incoming_rtp_timestamp_. | 359 // Compute the time offset_in_ticks based on the incoming_rtp_timestamp_. |
| 359 if (time_offset_.InMilliseconds() == 0) { | 360 if (time_offset_counter_ == 0) { |
| 360 if (!rtcp_->RtpTimestampInSenderTime(kVideoFrequency, | 361 // Check for received RTCP to sync the stream play it out asap. |
| 362 if (rtcp_->RtpTimestampInSenderTime(kVideoFrequency, |
| 361 incoming_rtp_timestamp_, | 363 incoming_rtp_timestamp_, |
| 362 &rtp_timestamp_in_ticks)) { | 364 &rtp_timestamp_in_ticks)) { |
| 363 // We have not received any RTCP to sync the stream play it out as soon as | 365 |
| 364 // possible. | 366 ++time_offset_counter_; |
| 365 return now; | |
| 366 } | 367 } |
| 367 time_offset_ = time_incoming_packet_ - rtp_timestamp_in_ticks; | 368 return now; |
| 368 } else if (time_incoming_packet_updated_) { | 369 } else if (time_incoming_packet_updated_) { |
| 369 if (rtcp_->RtpTimestampInSenderTime(kVideoFrequency, | 370 if (rtcp_->RtpTimestampInSenderTime(kVideoFrequency, |
| 370 incoming_rtp_timestamp_, | 371 incoming_rtp_timestamp_, |
| 371 &rtp_timestamp_in_ticks)) { | 372 &rtp_timestamp_in_ticks)) { |
| 372 // Time to update the time_offset. | 373 // Time to update the time_offset. |
| 373 base::TimeDelta time_offset = | 374 base::TimeDelta time_offset = |
| 374 time_incoming_packet_ - rtp_timestamp_in_ticks; | 375 time_incoming_packet_ - rtp_timestamp_in_ticks; |
| 375 time_offset_ = ((kTimeOffsetFilter - 1) * time_offset_ + time_offset) / | 376 // Taking the minimum of the first kTimeOffsetMaxCounter values. We are |
| 376 kTimeOffsetFilter; | 377 // assuming that we are looking for the minimum offset, which will occur |
| 378 // when network conditions are the best. This should occur at least once |
| 379 // within the first kTimeOffsetMaxCounter samples. Any drift should be |
| 380 // very slow, and negligible for this use case. |
| 381 if (time_offset_counter_ == 1) |
| 382 time_offset_ = time_offset; |
| 383 else if (time_offset_counter_ < kTimeOffsetMaxCounter) { |
| 384 time_offset_ = std::min(time_offset_, time_offset); |
| 385 } |
| 386 ++time_offset_counter_; |
| 377 } | 387 } |
| 378 } | 388 } |
| 379 // Reset |time_incoming_packet_updated_| to enable a future measurement. | 389 // Reset |time_incoming_packet_updated_| to enable a future measurement. |
| 380 time_incoming_packet_updated_ = false; | 390 time_incoming_packet_updated_ = false; |
| 381 // Compute the actual rtp_timestamp_in_ticks based on the current timestamp. | 391 // Compute the actual rtp_timestamp_in_ticks based on the current timestamp. |
| 382 if (!rtcp_->RtpTimestampInSenderTime( | 392 if (!rtcp_->RtpTimestampInSenderTime( |
| 383 kVideoFrequency, rtp_timestamp, &rtp_timestamp_in_ticks)) { | 393 kVideoFrequency, rtp_timestamp, &rtp_timestamp_in_ticks)) { |
| 384 // This can fail if we have not received any RTCP packets in a long time. | 394 // This can fail if we have not received any RTCP packets in a long time. |
| 385 return now; | 395 return now; |
| 386 } | 396 } |
| (...skipping 19 matching lines...) Expand all Loading... |
| 406 const RtpCastHeader& rtp_header) { | 416 const RtpCastHeader& rtp_header) { |
| 407 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 417 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); |
| 408 | 418 |
| 409 base::TimeTicks now = cast_environment_->Clock()->NowTicks(); | 419 base::TimeTicks now = cast_environment_->Clock()->NowTicks(); |
| 410 if (time_incoming_packet_.is_null() || | 420 if (time_incoming_packet_.is_null() || |
| 411 now - time_incoming_packet_ > | 421 now - time_incoming_packet_ > |
| 412 base::TimeDelta::FromMilliseconds(kMinTimeBetweenOffsetUpdatesMs)) { | 422 base::TimeDelta::FromMilliseconds(kMinTimeBetweenOffsetUpdatesMs)) { |
| 413 if (time_incoming_packet_.is_null()) | 423 if (time_incoming_packet_.is_null()) |
| 414 InitializeTimers(); | 424 InitializeTimers(); |
| 415 incoming_rtp_timestamp_ = rtp_header.webrtc.header.timestamp; | 425 incoming_rtp_timestamp_ = rtp_header.webrtc.header.timestamp; |
| 416 time_incoming_packet_ = now; | 426 // The following incoming packet info is used for syncing sender and |
| 417 time_incoming_packet_updated_ = true; | 427 // receiver clock. Use only the first packet of every frame to obtain a |
| 428 // minimal value. |
| 429 if (rtp_header.packet_id == 0) { |
| 430 time_incoming_packet_ = now; |
| 431 time_incoming_packet_updated_ = true; |
| 432 } |
| 418 } | 433 } |
| 419 | 434 |
| 420 frame_id_to_rtp_timestamp_[rtp_header.frame_id & 0xff] = | 435 frame_id_to_rtp_timestamp_[rtp_header.frame_id & 0xff] = |
| 421 rtp_header.webrtc.header.timestamp; | 436 rtp_header.webrtc.header.timestamp; |
| 422 cast_environment_->Logging()->InsertPacketEvent( | 437 cast_environment_->Logging()->InsertPacketEvent( |
| 423 now, | 438 now, |
| 424 kVideoPacketReceived, | 439 kVideoPacketReceived, |
| 425 rtp_header.webrtc.header.timestamp, | 440 rtp_header.webrtc.header.timestamp, |
| 426 rtp_header.frame_id, | 441 rtp_header.frame_id, |
| 427 rtp_header.packet_id, | 442 rtp_header.packet_id, |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 515 } | 530 } |
| 516 | 531 |
| 517 void VideoReceiver::SendNextRtcpReport() { | 532 void VideoReceiver::SendNextRtcpReport() { |
| 518 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 533 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); |
| 519 rtcp_->SendRtcpFromRtpReceiver(NULL, NULL); | 534 rtcp_->SendRtcpFromRtpReceiver(NULL, NULL); |
| 520 ScheduleNextRtcpReport(); | 535 ScheduleNextRtcpReport(); |
| 521 } | 536 } |
| 522 | 537 |
| 523 } // namespace cast | 538 } // namespace cast |
| 524 } // namespace media | 539 } // namespace media |
| OLD | NEW |