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 |