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 "media/base/audio_discard_helper.h" | 5 #include "media/base/audio_discard_helper.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 | 8 |
9 #include "base/logging.h" | 9 #include "base/logging.h" |
10 #include "media/base/audio_buffer.h" | 10 #include "media/base/audio_buffer.h" |
(...skipping 11 matching lines...) Expand all Loading... | |
22 << " ts " << current_timestamp.InMicroseconds() << " us" | 22 << " ts " << current_timestamp.InMicroseconds() << " us" |
23 << " diff " << diff.InMicroseconds() << " us"; | 23 << " diff " << diff.InMicroseconds() << " us"; |
24 } | 24 } |
25 | 25 |
26 AudioDiscardHelper::AudioDiscardHelper(int sample_rate, size_t decoder_delay) | 26 AudioDiscardHelper::AudioDiscardHelper(int sample_rate, size_t decoder_delay) |
27 : sample_rate_(sample_rate), | 27 : sample_rate_(sample_rate), |
28 decoder_delay_(decoder_delay), | 28 decoder_delay_(decoder_delay), |
29 timestamp_helper_(sample_rate_), | 29 timestamp_helper_(sample_rate_), |
30 discard_frames_(0), | 30 discard_frames_(0), |
31 last_input_timestamp_(kNoTimestamp()), | 31 last_input_timestamp_(kNoTimestamp()), |
32 delayed_discard_(false) { | 32 delayed_discard_(false), |
33 delayed_end_discard_(0) { | |
33 DCHECK_GT(sample_rate_, 0); | 34 DCHECK_GT(sample_rate_, 0); |
34 } | 35 } |
35 | 36 |
36 AudioDiscardHelper::~AudioDiscardHelper() { | 37 AudioDiscardHelper::~AudioDiscardHelper() { |
37 } | 38 } |
38 | 39 |
39 size_t AudioDiscardHelper::TimeDeltaToFrames(base::TimeDelta duration) const { | 40 size_t AudioDiscardHelper::TimeDeltaToFrames(base::TimeDelta duration) const { |
40 DCHECK(duration >= base::TimeDelta()); | 41 DCHECK(duration >= base::TimeDelta()); |
41 return duration.InSecondsF() * sample_rate_ + 0.5; | 42 return duration.InSecondsF() * sample_rate_ + 0.5; |
42 } | 43 } |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
92 // around endpoint tracking when handling complete buffer discards. | 93 // around endpoint tracking when handling complete buffer discards. |
93 DCHECK_EQ(decoder_delay_, 0u); | 94 DCHECK_EQ(decoder_delay_, 0u); |
94 std::swap(current_discard_padding, delayed_discard_padding_); | 95 std::swap(current_discard_padding, delayed_discard_padding_); |
95 } | 96 } |
96 | 97 |
97 if (discard_frames_ > 0) { | 98 if (discard_frames_ > 0) { |
98 const size_t decoded_frames = decoded_buffer->frame_count(); | 99 const size_t decoded_frames = decoded_buffer->frame_count(); |
99 const size_t frames_to_discard = std::min(discard_frames_, decoded_frames); | 100 const size_t frames_to_discard = std::min(discard_frames_, decoded_frames); |
100 discard_frames_ -= frames_to_discard; | 101 discard_frames_ -= frames_to_discard; |
101 | 102 |
103 DVLOG(1) << "Initial discard of " << frames_to_discard << " out of " | |
104 << decoded_frames << " frames."; | |
105 | |
102 // If everything would be discarded, indicate a new buffer is required. | 106 // If everything would be discarded, indicate a new buffer is required. |
103 if (frames_to_discard == decoded_frames) { | 107 if (frames_to_discard == decoded_frames) { |
104 // For simplicity disallow cases where a buffer with discard padding is | 108 // For simplicity disallow cases where a buffer with discard padding is |
105 // present. Doing so allows us to avoid complexity around tracking | 109 // present. Doing so allows us to avoid complexity around tracking |
106 // discards across buffers. | 110 // discards across buffers. |
107 DCHECK(current_discard_padding.first == base::TimeDelta()); | 111 DCHECK(current_discard_padding.first == base::TimeDelta()); |
108 DCHECK(current_discard_padding.second == base::TimeDelta()); | 112 DCHECK(current_discard_padding.second == base::TimeDelta()); |
109 return false; | 113 return false; |
110 } | 114 } |
111 | 115 |
112 decoded_buffer->TrimStart(frames_to_discard); | 116 decoded_buffer->TrimStart(frames_to_discard); |
113 } | 117 } |
114 | 118 |
119 // Process any delayed end discard from the previous buffer. | |
120 if (delayed_end_discard_ > 0) { | |
121 DCHECK_GT(decoder_delay_, 0u); | |
122 DCHECK_LT(delayed_end_discard_, decoder_delay_); | |
123 | |
124 const size_t decoded_frames = decoded_buffer->frame_count(); | |
125 const size_t frames_to_discard = decoder_delay_ - delayed_end_discard_; | |
126 DCHECK_LT(frames_to_discard, decoded_frames); | |
127 | |
128 DVLOG(1) << "Delayed end discard of " << frames_to_discard << " out of " | |
129 << decoded_frames << " frames starting at " | |
130 << delayed_end_discard_; | |
131 | |
132 decoded_buffer->TrimRange(delayed_end_discard_, | |
133 delayed_end_discard_ + frames_to_discard); | |
134 delayed_end_discard_ = 0; | |
135 } | |
136 | |
115 // Handle front discard padding. | 137 // Handle front discard padding. |
116 if (current_discard_padding.first > base::TimeDelta()) { | 138 if (current_discard_padding.first > base::TimeDelta()) { |
117 const size_t decoded_frames = decoded_buffer->frame_count(); | 139 const size_t decoded_frames = decoded_buffer->frame_count(); |
118 | 140 |
119 // If a complete buffer discard is requested and there's no decoder delay, | 141 // If a complete buffer discard is requested and there's no decoder delay, |
120 // just discard all remaining frames from this buffer. With decoder delay | 142 // just discard all remaining frames from this buffer. With decoder delay |
121 // we have to estimate the correct number of frames to discard based on the | 143 // we have to estimate the correct number of frames to discard based on the |
122 // duration of the encoded buffer. | 144 // duration of the encoded buffer. |
123 const size_t start_frames_to_discard = | 145 const size_t start_frames_to_discard = |
124 current_discard_padding.first == kInfiniteDuration() | 146 current_discard_padding.first == kInfiniteDuration() |
(...skipping 21 matching lines...) Expand all Loading... | |
146 CHECK_LT(discard_start, decoded_frames); | 168 CHECK_LT(discard_start, decoded_frames); |
147 | 169 |
148 const size_t frames_to_discard = | 170 const size_t frames_to_discard = |
149 std::min(start_frames_to_discard, decoded_frames - discard_start); | 171 std::min(start_frames_to_discard, decoded_frames - discard_start); |
150 | 172 |
151 // Carry over any frames which need to be discarded from the front of the | 173 // Carry over any frames which need to be discarded from the front of the |
152 // next buffer. | 174 // next buffer. |
153 DCHECK(!discard_frames_); | 175 DCHECK(!discard_frames_); |
154 discard_frames_ = start_frames_to_discard - frames_to_discard; | 176 discard_frames_ = start_frames_to_discard - frames_to_discard; |
155 | 177 |
178 DVLOG(1) << "Front discard of " << frames_to_discard << " out of " | |
179 << decoded_frames << " frames starting at " << discard_start; | |
180 | |
156 // If everything would be discarded, indicate a new buffer is required. | 181 // If everything would be discarded, indicate a new buffer is required. |
157 if (frames_to_discard == decoded_frames) { | 182 if (frames_to_discard == decoded_frames) { |
158 // The buffer should not have been marked with end discard if the front | 183 // The buffer should not have been marked with end discard if the front |
159 // discard removes everything. | 184 // discard removes everything. |
160 DCHECK(current_discard_padding.second == base::TimeDelta()); | 185 DCHECK(current_discard_padding.second == base::TimeDelta()); |
161 return false; | 186 return false; |
162 } | 187 } |
163 | 188 |
164 decoded_buffer->TrimRange(discard_start, discard_start + frames_to_discard); | 189 decoded_buffer->TrimRange(discard_start, discard_start + frames_to_discard); |
165 } else { | 190 } else { |
166 DCHECK(current_discard_padding.first == base::TimeDelta()); | 191 DCHECK(current_discard_padding.first == base::TimeDelta()); |
167 } | 192 } |
168 | 193 |
169 // Handle end discard padding. | 194 // Handle end discard padding. |
170 if (current_discard_padding.second > base::TimeDelta()) { | 195 if (current_discard_padding.second > base::TimeDelta()) { |
171 // Limit end discarding to when there is no |decoder_delay_|, otherwise it's | 196 const size_t decoded_frames = decoded_buffer->frame_count(); |
172 // non-trivial determining where to start discarding end frames. | 197 size_t end_frames_to_discard = |
173 CHECK(!decoder_delay_); | 198 TimeDeltaToFrames(current_discard_padding.second); |
174 | 199 |
175 const size_t decoded_frames = decoded_buffer->frame_count(); | 200 if (decoder_delay_) { |
176 const size_t end_frames_to_discard = | 201 // Delayed end discard only works if the decoder delay is less than a |
177 TimeDeltaToFrames(current_discard_padding.second); | 202 // single buffer. |
203 DCHECK_LT(decoder_delay_, original_frame_count); | |
acolwell GONE FROM CHROMIUM
2014/07/23 00:15:42
Will this blow up on Opus & Vorbis then?
DaleCurtis
2014/07/23 01:50:41
No, they don't have any decoder delay; only MP3 do
| |
204 | |
205 // If the discard is >= the decoder delay, trim everything we can off the | |
206 // end of this buffer and the rest from the start of the next. | |
207 if (end_frames_to_discard >= decoder_delay_) { | |
208 DCHECK(!discard_frames_); | |
209 discard_frames_ = decoder_delay_; | |
210 end_frames_to_discard = end_frames_to_discard - decoder_delay_; | |
acolwell GONE FROM CHROMIUM
2014/07/23 00:15:41
nit: -= here?
DaleCurtis
2014/07/23 01:50:41
Done.
| |
211 } else { | |
212 delayed_end_discard_ = decoder_delay_ - end_frames_to_discard; | |
213 end_frames_to_discard = 0; | |
214 } | |
215 } | |
178 | 216 |
179 if (end_frames_to_discard > decoded_frames) { | 217 if (end_frames_to_discard > decoded_frames) { |
180 DLOG(ERROR) << "Encountered invalid discard padding value."; | 218 DLOG(ERROR) << "Encountered invalid discard padding value."; |
181 return false; | 219 return false; |
182 } | 220 } |
183 | 221 |
184 // If everything would be discarded, indicate a new buffer is required. | 222 if (end_frames_to_discard > 0) { |
185 if (end_frames_to_discard == decoded_frames) | 223 DVLOG(1) << "End discard of " << end_frames_to_discard << " out of " |
186 return false; | 224 << decoded_frames; |
187 | 225 |
188 decoded_buffer->TrimEnd(end_frames_to_discard); | 226 // If everything would be discarded, indicate a new buffer is required. |
227 if (end_frames_to_discard == decoded_frames) | |
228 return false; | |
229 | |
230 decoded_buffer->TrimEnd(end_frames_to_discard); | |
231 } | |
189 } else { | 232 } else { |
190 DCHECK(current_discard_padding.second == base::TimeDelta()); | 233 DCHECK(current_discard_padding.second == base::TimeDelta()); |
191 } | 234 } |
192 | 235 |
193 // Assign timestamp to the buffer. | 236 // Assign timestamp to the buffer. |
194 decoded_buffer->set_timestamp(timestamp_helper_.GetTimestamp()); | 237 decoded_buffer->set_timestamp(timestamp_helper_.GetTimestamp()); |
195 timestamp_helper_.AddFrames(decoded_buffer->frame_count()); | 238 timestamp_helper_.AddFrames(decoded_buffer->frame_count()); |
196 return true; | 239 return true; |
197 } | 240 } |
198 | 241 |
199 } // namespace media | 242 } // namespace media |
OLD | NEW |