OLD | NEW |
(Empty) | |
| 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 |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "media/base/audio_discard_helper.h" |
| 6 |
| 7 #include <algorithm> |
| 8 |
| 9 #include "base/logging.h" |
| 10 #include "media/base/audio_buffer.h" |
| 11 #include "media/base/buffers.h" |
| 12 #include "media/base/decoder_buffer.h" |
| 13 |
| 14 namespace media { |
| 15 |
| 16 static void WarnOnNonMonotonicTimestamps(base::TimeDelta last_timestamp, |
| 17 base::TimeDelta current_timestamp) { |
| 18 if (last_timestamp == kNoTimestamp() || last_timestamp < current_timestamp) |
| 19 return; |
| 20 |
| 21 const base::TimeDelta diff = current_timestamp - last_timestamp; |
| 22 DLOG(WARNING) << "Input timestamps are not monotonically increasing! " |
| 23 << " ts " << current_timestamp.InMicroseconds() << " us" |
| 24 << " diff " << diff.InMicroseconds() << " us"; |
| 25 } |
| 26 |
| 27 AudioDiscardHelper::AudioDiscardHelper(int sample_rate) |
| 28 : sample_rate_(sample_rate), |
| 29 timestamp_helper_(sample_rate_), |
| 30 discard_frames_(0), |
| 31 last_input_timestamp_(kNoTimestamp()) { |
| 32 DCHECK_GT(sample_rate_, 0); |
| 33 } |
| 34 |
| 35 AudioDiscardHelper::~AudioDiscardHelper() { |
| 36 } |
| 37 |
| 38 size_t AudioDiscardHelper::TimeDeltaToFrames(base::TimeDelta duration) const { |
| 39 DCHECK(duration >= base::TimeDelta()); |
| 40 return duration.InSecondsF() * sample_rate_ + 0.5; |
| 41 } |
| 42 |
| 43 void AudioDiscardHelper::Reset(size_t initial_discard) { |
| 44 discard_frames_ = initial_discard; |
| 45 last_input_timestamp_ = kNoTimestamp(); |
| 46 timestamp_helper_.SetBaseTimestamp(kNoTimestamp()); |
| 47 } |
| 48 |
| 49 bool AudioDiscardHelper::ProcessBuffers( |
| 50 const scoped_refptr<DecoderBuffer>& encoded_buffer, |
| 51 const scoped_refptr<AudioBuffer>& decoded_buffer) { |
| 52 DCHECK(!encoded_buffer->end_of_stream()); |
| 53 DCHECK(encoded_buffer->timestamp() != kNoTimestamp()); |
| 54 |
| 55 // Issue a debug warning when we see non-monotonic timestamps. Only a warning |
| 56 // to allow chained OGG playback. |
| 57 WarnOnNonMonotonicTimestamps(last_input_timestamp_, |
| 58 encoded_buffer->timestamp()); |
| 59 last_input_timestamp_ = encoded_buffer->timestamp(); |
| 60 |
| 61 // If this is the first buffer seen, setup the timestamp helper. |
| 62 if (!initialized()) { |
| 63 // Clamp the base timestamp to zero. |
| 64 timestamp_helper_.SetBaseTimestamp( |
| 65 std::max(base::TimeDelta(), encoded_buffer->timestamp())); |
| 66 } |
| 67 DCHECK(initialized()); |
| 68 |
| 69 if (!decoded_buffer || !decoded_buffer->frame_count()) |
| 70 return false; |
| 71 |
| 72 if (discard_frames_ > 0) { |
| 73 const size_t decoded_frames = decoded_buffer->frame_count(); |
| 74 const size_t frames_to_discard = std::min(discard_frames_, decoded_frames); |
| 75 discard_frames_ -= frames_to_discard; |
| 76 |
| 77 // If everything would be discarded, indicate a new buffer is required. |
| 78 if (frames_to_discard == decoded_frames) |
| 79 return false; |
| 80 |
| 81 decoded_buffer->TrimStart(frames_to_discard); |
| 82 } |
| 83 |
| 84 // TODO(dalecurtis): Applying the current buffer's discard padding doesn't |
| 85 // make sense in the Vorbis case because there is a delay of one buffer before |
| 86 // decoded buffers are returned. Fix and add support for more than just end |
| 87 // trimming. See http://crbug.com/360961. |
| 88 if (encoded_buffer->discard_padding() > base::TimeDelta()) { |
| 89 const size_t decoded_frames = decoded_buffer->frame_count(); |
| 90 const size_t end_frames_to_discard = |
| 91 TimeDeltaToFrames(encoded_buffer->discard_padding()); |
| 92 if (end_frames_to_discard > decoded_frames) { |
| 93 DLOG(ERROR) << "Encountered invalid discard padding value."; |
| 94 return false; |
| 95 } |
| 96 |
| 97 // If everything would be discarded, indicate a new buffer is required. |
| 98 if (end_frames_to_discard == decoded_frames) |
| 99 return false; |
| 100 |
| 101 decoded_buffer->TrimEnd(end_frames_to_discard); |
| 102 } else { |
| 103 DCHECK(encoded_buffer->discard_padding() == base::TimeDelta()); |
| 104 } |
| 105 |
| 106 // Assign timestamp and duration to the buffer. |
| 107 decoded_buffer->set_timestamp(timestamp_helper_.GetTimestamp()); |
| 108 decoded_buffer->set_duration( |
| 109 timestamp_helper_.GetFrameDuration(decoded_buffer->frame_count())); |
| 110 timestamp_helper_.AddFrames(decoded_buffer->frame_count()); |
| 111 return true; |
| 112 } |
| 113 |
| 114 } // namespace media |
OLD | NEW |