Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(191)

Side by Side Diff: media/cast/video_receiver/video_receiver.cc

Issue 280993002: [Cast] Repair receiver playout time calculations and frame skip logic. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: rebase Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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/debug/trace_event.h" 10 #include "base/debug/trace_event.h"
11 #include "base/logging.h" 11 #include "base/logging.h"
12 #include "base/message_loop/message_loop.h" 12 #include "base/message_loop/message_loop.h"
13 #include "media/base/video_frame.h" 13 #include "media/base/video_frame.h"
14 #include "media/cast/logging/logging_defines.h" 14 #include "media/cast/logging/logging_defines.h"
15 #include "media/cast/transport/cast_transport_defines.h" 15 #include "media/cast/transport/cast_transport_defines.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 const int kMinSchedulingDelayMs = 1; 19 const int kMinSchedulingDelayMs = 1;
20 const int kMinTimeBetweenOffsetUpdatesMs = 1000;
21 const int kTimeOffsetMaxCounter = 10;
22 } // namespace 20 } // namespace
23 21
24 namespace media { 22 namespace media {
25 namespace cast { 23 namespace cast {
26 24
27 VideoReceiver::VideoReceiver(scoped_refptr<CastEnvironment> cast_environment, 25 VideoReceiver::VideoReceiver(scoped_refptr<CastEnvironment> cast_environment,
28 const VideoReceiverConfig& video_config, 26 const VideoReceiverConfig& video_config,
29 transport::PacedPacketSender* const packet_sender) 27 transport::PacedPacketSender* const packet_sender)
30 : RtpReceiver(cast_environment->Clock(), NULL, &video_config), 28 : RtpReceiver(cast_environment->Clock(), NULL, &video_config),
31 cast_environment_(cast_environment), 29 cast_environment_(cast_environment),
32 event_subscriber_(kReceiverRtcpEventHistorySize, VIDEO_EVENT), 30 event_subscriber_(kReceiverRtcpEventHistorySize, VIDEO_EVENT),
33 codec_(video_config.codec), 31 codec_(video_config.codec),
34 target_delay_delta_( 32 target_playout_delay_(
35 base::TimeDelta::FromMilliseconds(video_config.rtp_max_delay_ms)), 33 base::TimeDelta::FromMilliseconds(video_config.rtp_max_delay_ms)),
36 expected_frame_duration_( 34 expected_frame_duration_(
37 base::TimeDelta::FromSeconds(1) / video_config.max_frame_rate), 35 base::TimeDelta::FromSeconds(1) / video_config.max_frame_rate),
36 reports_are_scheduled_(false),
38 framer_(cast_environment->Clock(), 37 framer_(cast_environment->Clock(),
39 this, 38 this,
40 video_config.incoming_ssrc, 39 video_config.incoming_ssrc,
41 video_config.decoder_faster_than_max_frame_rate, 40 video_config.decoder_faster_than_max_frame_rate,
42 video_config.rtp_max_delay_ms * video_config.max_frame_rate / 41 video_config.rtp_max_delay_ms * video_config.max_frame_rate /
43 1000), 42 1000),
44 rtcp_(cast_environment_, 43 rtcp_(cast_environment_,
45 NULL, 44 NULL,
46 NULL, 45 NULL,
47 packet_sender, 46 packet_sender,
48 GetStatistics(), 47 GetStatistics(),
49 video_config.rtcp_mode, 48 video_config.rtcp_mode,
50 base::TimeDelta::FromMilliseconds(video_config.rtcp_interval), 49 base::TimeDelta::FromMilliseconds(video_config.rtcp_interval),
51 video_config.feedback_ssrc, 50 video_config.feedback_ssrc,
52 video_config.incoming_ssrc, 51 video_config.incoming_ssrc,
53 video_config.rtcp_c_name, 52 video_config.rtcp_c_name,
54 false), 53 false),
55 time_offset_counter_(0),
56 time_incoming_packet_updated_(false),
57 incoming_rtp_timestamp_(0),
58 is_waiting_for_consecutive_frame_(false), 54 is_waiting_for_consecutive_frame_(false),
55 lip_sync_drift_(ClockDriftSmoother::GetDefaultTimeConstant()),
59 weak_factory_(this) { 56 weak_factory_(this) {
60 DCHECK_GT(video_config.rtp_max_delay_ms, 0); 57 DCHECK_GT(video_config.rtp_max_delay_ms, 0);
61 DCHECK_GT(video_config.max_frame_rate, 0); 58 DCHECK_GT(video_config.max_frame_rate, 0);
62 if (!video_config.use_external_decoder) { 59 if (!video_config.use_external_decoder) {
63 video_decoder_.reset(new VideoDecoder(cast_environment, video_config)); 60 video_decoder_.reset(new VideoDecoder(cast_environment, video_config));
64 } 61 }
65 decryptor_.Initialize(video_config.aes_key, video_config.aes_iv_mask); 62 decryptor_.Initialize(video_config.aes_key, video_config.aes_iv_mask);
66 rtcp_.SetTargetDelay(target_delay_delta_); 63 rtcp_.SetTargetDelay(target_playout_delay_);
67 cast_environment_->Logging()->AddRawEventSubscriber(&event_subscriber_); 64 cast_environment_->Logging()->AddRawEventSubscriber(&event_subscriber_);
68 memset(frame_id_to_rtp_timestamp_, 0, sizeof(frame_id_to_rtp_timestamp_)); 65 memset(frame_id_to_rtp_timestamp_, 0, sizeof(frame_id_to_rtp_timestamp_));
69 } 66 }
70 67
71 VideoReceiver::~VideoReceiver() { 68 VideoReceiver::~VideoReceiver() {
72 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); 69 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
73 cast_environment_->Logging()->RemoveRawEventSubscriber(&event_subscriber_); 70 cast_environment_->Logging()->RemoveRawEventSubscriber(&event_subscriber_);
74 } 71 }
75 72
76 void VideoReceiver::InitializeTimers() {
77 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
78 ScheduleNextRtcpReport();
79 ScheduleNextCastMessage();
80 }
81
82 void VideoReceiver::GetRawVideoFrame( 73 void VideoReceiver::GetRawVideoFrame(
83 const VideoFrameDecodedCallback& callback) { 74 const VideoFrameDecodedCallback& callback) {
84 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); 75 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
85 DCHECK(!callback.is_null()); 76 DCHECK(!callback.is_null());
86 DCHECK(video_decoder_.get()); 77 DCHECK(video_decoder_.get());
87 GetEncodedVideoFrame(base::Bind( 78 GetEncodedVideoFrame(base::Bind(
88 &VideoReceiver::DecodeEncodedVideoFrame, 79 &VideoReceiver::DecodeEncodedVideoFrame,
89 // Note: Use of Unretained is safe since this Closure is guaranteed to be 80 // Note: Use of Unretained is safe since this Closure is guaranteed to be
90 // invoked before destruction of |this|. 81 // invoked before destruction of |this|.
91 base::Unretained(this), 82 base::Unretained(this),
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
159 150
160 if (!framer_.GetEncodedFrame(encoded_frame.get(), 151 if (!framer_.GetEncodedFrame(encoded_frame.get(),
161 &is_consecutively_next_frame, 152 &is_consecutively_next_frame,
162 &have_multiple_complete_frames)) { 153 &have_multiple_complete_frames)) {
163 VLOG(1) << "Wait for more video packets to produce a completed frame."; 154 VLOG(1) << "Wait for more video packets to produce a completed frame.";
164 return; // OnReceivedPayloadData() will invoke this method in the future. 155 return; // OnReceivedPayloadData() will invoke this method in the future.
165 } 156 }
166 157
167 const base::TimeTicks now = cast_environment_->Clock()->NowTicks(); 158 const base::TimeTicks now = cast_environment_->Clock()->NowTicks();
168 const base::TimeTicks playout_time = 159 const base::TimeTicks playout_time =
169 GetPlayoutTime(now, encoded_frame->rtp_timestamp); 160 GetPlayoutTime(encoded_frame->rtp_timestamp);
170 161
171 // If we have multiple decodable frames, and the current frame is 162 // If we have multiple decodable frames, and the current frame is
172 // too old, then skip it and decode the next frame instead. 163 // too old, then skip it and decode the next frame instead.
173 if (have_multiple_complete_frames && now > playout_time) { 164 if (have_multiple_complete_frames && now > playout_time) {
174 framer_.ReleaseFrame(encoded_frame->frame_id); 165 framer_.ReleaseFrame(encoded_frame->frame_id);
175 continue; 166 continue;
176 } 167 }
177 168
178 // If |framer_| has a frame ready that is out of sequence, examine the 169 // If |framer_| has a frame ready that is out of sequence, examine the
179 // playout time to determine whether it's acceptable to continue, thereby 170 // playout time to determine whether it's acceptable to continue, thereby
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
230 } 221 }
231 } 222 }
232 223
233 void VideoReceiver::EmitAvailableEncodedFramesAfterWaiting() { 224 void VideoReceiver::EmitAvailableEncodedFramesAfterWaiting() {
234 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); 225 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
235 DCHECK(is_waiting_for_consecutive_frame_); 226 DCHECK(is_waiting_for_consecutive_frame_);
236 is_waiting_for_consecutive_frame_ = false; 227 is_waiting_for_consecutive_frame_ = false;
237 EmitAvailableEncodedFrames(); 228 EmitAvailableEncodedFrames();
238 } 229 }
239 230
240 base::TimeTicks VideoReceiver::GetPlayoutTime(base::TimeTicks now, 231 base::TimeTicks VideoReceiver::GetPlayoutTime(uint32 rtp_timestamp) const {
241 uint32 rtp_timestamp) { 232 return lip_sync_reference_time_ +
242 // TODO(miu): This and AudioReceiver::GetPlayoutTime() need to be reconciled! 233 lip_sync_drift_.Current() +
243 234 RtpDeltaToTimeDelta(
244 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); 235 static_cast<int32>(rtp_timestamp - lip_sync_rtp_timestamp_),
245 // Senders time in ms when this frame was captured. 236 kVideoFrequency) +
246 // Note: the senders clock and our local clock might not be synced. 237 target_playout_delay_;
247 base::TimeTicks rtp_timestamp_in_ticks;
248
249 // Compute the time offset_in_ticks based on the incoming_rtp_timestamp_.
250 if (time_offset_counter_ == 0) {
251 // Check for received RTCP to sync the stream play it out asap.
252 if (rtcp_.RtpTimestampInSenderTime(kVideoFrequency,
253 incoming_rtp_timestamp_,
254 &rtp_timestamp_in_ticks)) {
255 ++time_offset_counter_;
256 }
257 } else if (time_incoming_packet_updated_) {
258 if (rtcp_.RtpTimestampInSenderTime(kVideoFrequency,
259 incoming_rtp_timestamp_,
260 &rtp_timestamp_in_ticks)) {
261 // Time to update the time_offset.
262 base::TimeDelta time_offset =
263 time_incoming_packet_ - rtp_timestamp_in_ticks;
264 // Taking the minimum of the first kTimeOffsetMaxCounter values. We are
265 // assuming that we are looking for the minimum offset, which will occur
266 // when network conditions are the best. This should occur at least once
267 // within the first kTimeOffsetMaxCounter samples. Any drift should be
268 // very slow, and negligible for this use case.
269 if (time_offset_counter_ == 1)
270 time_offset_ = time_offset;
271 else if (time_offset_counter_ < kTimeOffsetMaxCounter) {
272 time_offset_ = std::min(time_offset_, time_offset);
273 }
274 if (time_offset_counter_ < kTimeOffsetMaxCounter)
275 ++time_offset_counter_;
276 }
277 }
278 // Reset |time_incoming_packet_updated_| to enable a future measurement.
279 time_incoming_packet_updated_ = false;
280 // Compute the actual rtp_timestamp_in_ticks based on the current timestamp.
281 if (!rtcp_.RtpTimestampInSenderTime(
282 kVideoFrequency, rtp_timestamp, &rtp_timestamp_in_ticks)) {
283 // This can fail if we have not received any RTCP packets in a long time.
284 // BUG: These calculations are a placeholder, and to be revisited in a
285 // soon-upcoming change. http://crbug.com/356942
286 const int frequency_khz = kVideoFrequency / 1000;
287 const base::TimeDelta delta_based_on_rtp_timestamps =
288 base::TimeDelta::FromMilliseconds(
289 static_cast<int32>(rtp_timestamp - incoming_rtp_timestamp_) /
290 frequency_khz);
291 return time_incoming_packet_ + delta_based_on_rtp_timestamps;
292 }
293
294 base::TimeTicks render_time =
295 rtp_timestamp_in_ticks + time_offset_ + target_delay_delta_;
296 // TODO(miu): This is broken since this "getter" method may be called on
297 // frames received out-of-order, which means the playout times for earlier
298 // frames will be computed incorrectly.
299 #if 0
300 if (last_render_time_ > render_time)
301 render_time = last_render_time_;
302 last_render_time_ = render_time;
303 #endif
304
305 return render_time;
306 } 238 }
307 239
308 void VideoReceiver::IncomingPacket(scoped_ptr<Packet> packet) { 240 void VideoReceiver::IncomingPacket(scoped_ptr<Packet> packet) {
309 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); 241 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
310 if (Rtcp::IsRtcpPacket(&packet->front(), packet->size())) { 242 if (Rtcp::IsRtcpPacket(&packet->front(), packet->size())) {
311 rtcp_.IncomingRtcpPacket(&packet->front(), packet->size()); 243 rtcp_.IncomingRtcpPacket(&packet->front(), packet->size());
312 } else { 244 } else {
313 ReceivedPacket(&packet->front(), packet->size()); 245 ReceivedPacket(&packet->front(), packet->size());
314 } 246 }
247 if (!reports_are_scheduled_) {
248 ScheduleNextRtcpReport();
249 ScheduleNextCastMessage();
250 reports_are_scheduled_ = true;
251 }
315 } 252 }
316 253
317 void VideoReceiver::OnReceivedPayloadData(const uint8* payload_data, 254 void VideoReceiver::OnReceivedPayloadData(const uint8* payload_data,
318 size_t payload_size, 255 size_t payload_size,
319 const RtpCastHeader& rtp_header) { 256 const RtpCastHeader& rtp_header) {
320 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); 257 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
321 258
322 base::TimeTicks now = cast_environment_->Clock()->NowTicks(); 259 const base::TimeTicks now = cast_environment_->Clock()->NowTicks();
323 if (time_incoming_packet_.is_null() ||
324 now - time_incoming_packet_ >
325 base::TimeDelta::FromMilliseconds(kMinTimeBetweenOffsetUpdatesMs)) {
326 if (time_incoming_packet_.is_null())
327 InitializeTimers();
328 incoming_rtp_timestamp_ = rtp_header.rtp_timestamp;
329 // The following incoming packet info is used for syncing sender and
330 // receiver clock. Use only the first packet of every frame to obtain a
331 // minimal value.
332 if (rtp_header.packet_id == 0) {
333 time_incoming_packet_ = now;
334 time_incoming_packet_updated_ = true;
335 }
336 }
337 260
338 frame_id_to_rtp_timestamp_[rtp_header.frame_id & 0xff] = 261 frame_id_to_rtp_timestamp_[rtp_header.frame_id & 0xff] =
339 rtp_header.rtp_timestamp; 262 rtp_header.rtp_timestamp;
340 cast_environment_->Logging()->InsertPacketEvent( 263 cast_environment_->Logging()->InsertPacketEvent(
341 now, 264 now,
342 PACKET_RECEIVED, 265 PACKET_RECEIVED,
343 VIDEO_EVENT, 266 VIDEO_EVENT,
344 rtp_header.rtp_timestamp, 267 rtp_header.rtp_timestamp,
345 rtp_header.frame_id, 268 rtp_header.frame_id,
346 rtp_header.packet_id, 269 rtp_header.packet_id,
347 rtp_header.max_packet_id, 270 rtp_header.max_packet_id,
348 payload_size); 271 payload_size);
349 272
350 bool duplicate = false; 273 bool duplicate = false;
351 const bool complete = 274 const bool complete =
352 framer_.InsertPacket(payload_data, payload_size, rtp_header, &duplicate); 275 framer_.InsertPacket(payload_data, payload_size, rtp_header, &duplicate);
353 276
354 // Duplicate packets are ignored. 277 // Duplicate packets are ignored.
355 if (duplicate) 278 if (duplicate)
356 return; 279 return;
357 280
281 // Update lip-sync values upon receiving the first packet of each frame, or if
282 // they have never been set yet.
283 if (rtp_header.packet_id == 0 || lip_sync_reference_time_.is_null()) {
284 RtpTimestamp fresh_sync_rtp;
285 base::TimeTicks fresh_sync_reference;
286 if (!rtcp_.GetLatestLipSyncTimes(&fresh_sync_rtp, &fresh_sync_reference)) {
287 // HACK: The sender should have provided Sender Reports before the first
288 // frame was sent. However, the spec does not currently require this.
289 // Therefore, when the data is missing, the local clock is used to
290 // generate reference timestamps.
291 VLOG(2) << "Lip sync info missing. Falling-back to local clock.";
292 fresh_sync_rtp = rtp_header.rtp_timestamp;
293 fresh_sync_reference = now;
294 }
295 // |lip_sync_reference_time_| is always incremented according to the time
296 // delta computed from the difference in RTP timestamps. Then,
297 // |lip_sync_drift_| accounts for clock drift and also smoothes-out any
298 // sudden/discontinuous shifts in the series of reference time values.
299 if (lip_sync_reference_time_.is_null()) {
300 lip_sync_reference_time_ = fresh_sync_reference;
301 } else {
302 lip_sync_reference_time_ += RtpDeltaToTimeDelta(
303 static_cast<int32>(fresh_sync_rtp - lip_sync_rtp_timestamp_),
304 kVideoFrequency);
305 }
306 lip_sync_rtp_timestamp_ = fresh_sync_rtp;
307 lip_sync_drift_.Update(
308 now, fresh_sync_reference - lip_sync_reference_time_);
309 }
310
358 // Video frame not complete; wait for more packets. 311 // Video frame not complete; wait for more packets.
359 if (!complete) 312 if (!complete)
360 return; 313 return;
361 314
362 EmitAvailableEncodedFrames(); 315 EmitAvailableEncodedFrames();
363 } 316 }
364 317
365 // Send a cast feedback message. Actual message created in the framer (cast 318 // Send a cast feedback message. Actual message created in the framer (cast
366 // message builder). 319 // message builder).
367 void VideoReceiver::CastFeedback(const RtcpCastMessage& cast_message) { 320 void VideoReceiver::CastFeedback(const RtcpCastMessage& cast_message) {
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
420 } 373 }
421 374
422 void VideoReceiver::SendNextRtcpReport() { 375 void VideoReceiver::SendNextRtcpReport() {
423 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); 376 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
424 rtcp_.SendRtcpFromRtpReceiver(NULL, NULL); 377 rtcp_.SendRtcpFromRtpReceiver(NULL, NULL);
425 ScheduleNextRtcpReport(); 378 ScheduleNextRtcpReport();
426 } 379 }
427 380
428 } // namespace cast 381 } // namespace cast
429 } // namespace media 382 } // namespace media
OLDNEW
« no previous file with comments | « media/cast/video_receiver/video_receiver.h ('k') | media/cast/video_receiver/video_receiver_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698