Chromium Code Reviews| 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); | |
| 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 -= decoder_delay_; | |
| 211 } else { | |
| 212 delayed_end_discard_ = decoder_delay_ - end_frames_to_discard; | |
|
acolwell GONE FROM CHROMIUM
2014/07/24 19:22:14
Can you just store end_frames_to_discard here and
DaleCurtis
2014/07/29 01:35:09
Done.
| |
| 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 |