| OLD | NEW |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 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/filters/audio_timestamp_validator.h" | 5 #include "media/filters/audio_timestamp_validator.h" |
| 6 | 6 |
| 7 namespace media { | 7 namespace media { |
| 8 | 8 |
| 9 // Defines how many milliseconds of DecoderBuffer timestamp gap will be allowed | 9 // Defines how many milliseconds of DecoderBuffer timestamp gap will be allowed |
| 10 // before warning the user. See CheckForTimestampGap(). Value of 50 chosen, as | 10 // before warning the user. See CheckForTimestampGap(). Value of 50 chosen, as |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 43 if (buffer->end_of_stream()) | 43 if (buffer->end_of_stream()) |
| 44 return; | 44 return; |
| 45 DCHECK_NE(kNoTimestamp, buffer->timestamp()); | 45 DCHECK_NE(kNoTimestamp, buffer->timestamp()); |
| 46 | 46 |
| 47 // If audio_base_ts_ == kNoTimestamp, we are processing our first buffer. | 47 // If audio_base_ts_ == kNoTimestamp, we are processing our first buffer. |
| 48 // If stream has neither codec delay nor discard padding, we should expect | 48 // If stream has neither codec delay nor discard padding, we should expect |
| 49 // timestamps and output durations to line up from the start (i.e. be stable). | 49 // timestamps and output durations to line up from the start (i.e. be stable). |
| 50 if (audio_base_ts_ == kNoTimestamp && !has_codec_delay_ && | 50 if (audio_base_ts_ == kNoTimestamp && !has_codec_delay_ && |
| 51 buffer->discard_padding().first == base::TimeDelta() && | 51 buffer->discard_padding().first == base::TimeDelta() && |
| 52 buffer->discard_padding().second == base::TimeDelta()) { | 52 buffer->discard_padding().second == base::TimeDelta()) { |
| 53 DVLOG(3) << __FUNCTION__ | 53 DVLOG(3) << __func__ << " Expecting stable timestamps - stream has neither " |
| 54 << " Expecting stable timestamps - stream has neither codec delay" | 54 << "codec delay nor discard padding."; |
| 55 << " nor discard padding."; | |
| 56 limit_unstable_audio_tries_ = 0; | 55 limit_unstable_audio_tries_ = 0; |
| 57 } | 56 } |
| 58 | 57 |
| 59 // Don't continue checking timestamps if we've exhausted tries to reach stable | 58 // Don't continue checking timestamps if we've exhausted tries to reach stable |
| 60 // state. This suggests the media's encoded timestamps are way off. | 59 // state. This suggests the media's encoded timestamps are way off. |
| 61 if (num_unstable_audio_tries_ > limit_unstable_audio_tries_) | 60 if (num_unstable_audio_tries_ > limit_unstable_audio_tries_) |
| 62 return; | 61 return; |
| 63 | 62 |
| 64 // Keep resetting encode base ts until we start getting decode output. Some | 63 // Keep resetting encode base ts until we start getting decode output. Some |
| 65 // codecs/containers (e.g. chained Ogg) will take several encoded buffers | 64 // codecs/containers (e.g. chained Ogg) will take several encoded buffers |
| 66 // before producing the first decoded output. | 65 // before producing the first decoded output. |
| 67 if (!audio_output_ts_helper_) { | 66 if (!audio_output_ts_helper_) { |
| 68 audio_base_ts_ = buffer->timestamp(); | 67 audio_base_ts_ = buffer->timestamp(); |
| 69 DVLOG(3) << __FUNCTION__ | 68 DVLOG(3) << __func__ |
| 70 << " setting audio_base:" << audio_base_ts_.InMicroseconds(); | 69 << " setting audio_base:" << audio_base_ts_.InMicroseconds(); |
| 71 return; | 70 return; |
| 72 } | 71 } |
| 73 | 72 |
| 74 base::TimeDelta expected_ts = audio_output_ts_helper_->GetTimestamp(); | 73 base::TimeDelta expected_ts = audio_output_ts_helper_->GetTimestamp(); |
| 75 base::TimeDelta ts_delta = buffer->timestamp() - expected_ts; | 74 base::TimeDelta ts_delta = buffer->timestamp() - expected_ts; |
| 76 | 75 |
| 77 // Reconciling encoded buffer timestamps with decoded output often requires | 76 // Reconciling encoded buffer timestamps with decoded output often requires |
| 78 // adjusting expectations by some offset. This accounts for varied (and at | 77 // adjusting expectations by some offset. This accounts for varied (and at |
| 79 // this point unknown) handling of front trimming and codec delay. Codec delay | 78 // this point unknown) handling of front trimming and codec delay. Codec delay |
| 80 // and skip trimming may or may not be accounted for in the encoded timestamps | 79 // and skip trimming may or may not be accounted for in the encoded timestamps |
| 81 // depending on the codec (e.g. MP3 vs Opus) and demuxers used (e.g. FFmpeg | 80 // depending on the codec (e.g. MP3 vs Opus) and demuxers used (e.g. FFmpeg |
| 82 // vs MSE stream parsers). | 81 // vs MSE stream parsers). |
| 83 if (!reached_stable_state_) { | 82 if (!reached_stable_state_) { |
| 84 if (std::abs(ts_delta.InMilliseconds()) < kStableTimeGapThrsholdMsec) { | 83 if (std::abs(ts_delta.InMilliseconds()) < kStableTimeGapThrsholdMsec) { |
| 85 reached_stable_state_ = true; | 84 reached_stable_state_ = true; |
| 86 DVLOG(3) << __FUNCTION__ | 85 DVLOG(3) << __func__ << " stabilized! tries:" << num_unstable_audio_tries_ |
| 87 << " stabilized! tries:" << num_unstable_audio_tries_ | |
| 88 << " offset:" | 86 << " offset:" |
| 89 << audio_output_ts_helper_->base_timestamp().InMicroseconds(); | 87 << audio_output_ts_helper_->base_timestamp().InMicroseconds(); |
| 90 } else { | 88 } else { |
| 91 base::TimeDelta orig_offset = audio_output_ts_helper_->base_timestamp(); | 89 base::TimeDelta orig_offset = audio_output_ts_helper_->base_timestamp(); |
| 92 | 90 |
| 93 // Save since this gets reset when we set new base time. | 91 // Save since this gets reset when we set new base time. |
| 94 int64_t decoded_frame_count = audio_output_ts_helper_->frame_count(); | 92 int64_t decoded_frame_count = audio_output_ts_helper_->frame_count(); |
| 95 audio_output_ts_helper_->SetBaseTimestamp(orig_offset + ts_delta); | 93 audio_output_ts_helper_->SetBaseTimestamp(orig_offset + ts_delta); |
| 96 audio_output_ts_helper_->AddFrames(decoded_frame_count); | 94 audio_output_ts_helper_->AddFrames(decoded_frame_count); |
| 97 | 95 |
| 98 DVLOG(3) << __FUNCTION__ | 96 DVLOG(3) << __func__ |
| 99 << " NOT stabilized. tries:" << num_unstable_audio_tries_ | 97 << " NOT stabilized. tries:" << num_unstable_audio_tries_ |
| 100 << " offset was:" << orig_offset.InMicroseconds() << " now:" | 98 << " offset was:" << orig_offset.InMicroseconds() << " now:" |
| 101 << audio_output_ts_helper_->base_timestamp().InMicroseconds(); | 99 << audio_output_ts_helper_->base_timestamp().InMicroseconds(); |
| 102 num_unstable_audio_tries_++; | 100 num_unstable_audio_tries_++; |
| 103 | 101 |
| 104 // Let developers know if their files timestamps are way off from | 102 // Let developers know if their files timestamps are way off from |
| 105 if (num_unstable_audio_tries_ > limit_unstable_audio_tries_) { | 103 if (num_unstable_audio_tries_ > limit_unstable_audio_tries_) { |
| 106 MEDIA_LOG(ERROR, media_log_) | 104 MEDIA_LOG(ERROR, media_log_) |
| 107 << "Failed to reconcile encoded audio times with decoded output."; | 105 << "Failed to reconcile encoded audio times with decoded output."; |
| 108 } | 106 } |
| 109 } | 107 } |
| 110 | 108 |
| 111 // Don't bother with further checking until we reach stable state. | 109 // Don't bother with further checking until we reach stable state. |
| 112 return; | 110 return; |
| 113 } | 111 } |
| 114 | 112 |
| 115 if (std::abs(ts_delta.InMilliseconds()) > drift_warning_threshold_msec_) { | 113 if (std::abs(ts_delta.InMilliseconds()) > drift_warning_threshold_msec_) { |
| 116 MEDIA_LOG(ERROR, media_log_) | 114 MEDIA_LOG(ERROR, media_log_) |
| 117 << " Large timestamp gap detected; may cause AV sync to drift." | 115 << " Large timestamp gap detected; may cause AV sync to drift." |
| 118 << " time:" << buffer->timestamp().InMicroseconds() << "us" | 116 << " time:" << buffer->timestamp().InMicroseconds() << "us" |
| 119 << " expected:" << expected_ts.InMicroseconds() << "us" | 117 << " expected:" << expected_ts.InMicroseconds() << "us" |
| 120 << " delta:" << ts_delta.InMicroseconds() << "us"; | 118 << " delta:" << ts_delta.InMicroseconds() << "us"; |
| 121 // Increase threshold to avoid log spam but, let us know if gap widens. | 119 // Increase threshold to avoid log spam but, let us know if gap widens. |
| 122 drift_warning_threshold_msec_ = std::abs(ts_delta.InMilliseconds()); | 120 drift_warning_threshold_msec_ = std::abs(ts_delta.InMilliseconds()); |
| 123 } | 121 } |
| 124 DVLOG(3) << __FUNCTION__ << " delta:" << ts_delta.InMicroseconds() | 122 DVLOG(3) << __func__ << " delta:" << ts_delta.InMicroseconds() |
| 125 << " expected_ts:" << expected_ts.InMicroseconds() | 123 << " expected_ts:" << expected_ts.InMicroseconds() |
| 126 << " actual_ts:" << buffer->timestamp().InMicroseconds() | 124 << " actual_ts:" << buffer->timestamp().InMicroseconds() |
| 127 << " audio_ts_offset:" | 125 << " audio_ts_offset:" |
| 128 << audio_output_ts_helper_->base_timestamp().InMicroseconds(); | 126 << audio_output_ts_helper_->base_timestamp().InMicroseconds(); |
| 129 } | 127 } |
| 130 | 128 |
| 131 void AudioTimestampValidator::RecordOutputDuration( | 129 void AudioTimestampValidator::RecordOutputDuration( |
| 132 const scoped_refptr<AudioBuffer>& audio_buffer) { | 130 const scoped_refptr<AudioBuffer>& audio_buffer) { |
| 133 if (!audio_output_ts_helper_) { | 131 if (!audio_output_ts_helper_) { |
| 134 DCHECK_NE(audio_base_ts_, kNoTimestamp); | 132 DCHECK_NE(audio_base_ts_, kNoTimestamp); |
| 135 // SUBTLE: deliberately creating this with output buffer sample rate because | 133 // SUBTLE: deliberately creating this with output buffer sample rate because |
| 136 // demuxer stream config is potentially stale for implicit AAC. | 134 // demuxer stream config is potentially stale for implicit AAC. |
| 137 audio_output_ts_helper_.reset( | 135 audio_output_ts_helper_.reset( |
| 138 new AudioTimestampHelper(audio_buffer->sample_rate())); | 136 new AudioTimestampHelper(audio_buffer->sample_rate())); |
| 139 audio_output_ts_helper_->SetBaseTimestamp(audio_base_ts_); | 137 audio_output_ts_helper_->SetBaseTimestamp(audio_base_ts_); |
| 140 } | 138 } |
| 141 | 139 |
| 142 DVLOG(3) << __FUNCTION__ << " " << audio_buffer->frame_count() << " frames"; | 140 DVLOG(3) << __func__ << " " << audio_buffer->frame_count() << " frames"; |
| 143 audio_output_ts_helper_->AddFrames(audio_buffer->frame_count()); | 141 audio_output_ts_helper_->AddFrames(audio_buffer->frame_count()); |
| 144 } | 142 } |
| 145 | 143 |
| 146 } // namespace media | 144 } // namespace media |
| OLD | NEW |