Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(905)

Side by Side Diff: media/base/audio_discard_helper.cc

Issue 251893002: Support start trimming post-decoding. Use it with FFmpegDemuxer. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Typo. Created 6 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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 <cmath> 7 #include <cmath>
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"
11 #include "media/base/buffers.h" 11 #include "media/base/buffers.h"
12 #include "media/base/decoder_buffer.h" 12 #include "media/base/decoder_buffer.h"
13 13
14 namespace media { 14 namespace media {
15 15
16 static void WarnOnNonMonotonicTimestamps(base::TimeDelta last_timestamp, 16 static void WarnOnNonMonotonicTimestamps(base::TimeDelta last_timestamp,
17 base::TimeDelta current_timestamp) { 17 base::TimeDelta current_timestamp) {
18 if (last_timestamp == kNoTimestamp() || last_timestamp < current_timestamp) 18 if (last_timestamp == kNoTimestamp() || last_timestamp < current_timestamp)
19 return; 19 return;
20 20
21 const base::TimeDelta diff = current_timestamp - last_timestamp; 21 const base::TimeDelta diff = current_timestamp - last_timestamp;
22 DLOG(WARNING) << "Input timestamps are not monotonically increasing! " 22 DLOG(WARNING) << "Input timestamps are not monotonically increasing! "
23 << " ts " << current_timestamp.InMicroseconds() << " us" 23 << " ts " << current_timestamp.InMicroseconds() << " us"
24 << " diff " << diff.InMicroseconds() << " us"; 24 << " diff " << diff.InMicroseconds() << " us";
25 } 25 }
26 26
27 AudioDiscardHelper::AudioDiscardHelper(int sample_rate) 27 AudioDiscardHelper::AudioDiscardHelper(int sample_rate, size_t codec_delay)
28 : sample_rate_(sample_rate), 28 : sample_rate_(sample_rate),
29 codec_delay_(codec_delay),
29 timestamp_helper_(sample_rate_), 30 timestamp_helper_(sample_rate_),
30 discard_frames_(0), 31 discard_frames_(0),
31 last_input_timestamp_(kNoTimestamp()) { 32 last_input_timestamp_(kNoTimestamp()) {
32 } 33 }
33 34
34 AudioDiscardHelper::~AudioDiscardHelper() { 35 AudioDiscardHelper::~AudioDiscardHelper() {
35 } 36 }
36 37
37 int AudioDiscardHelper::TimeDeltaToFrames(base::TimeDelta duration) const { 38 int AudioDiscardHelper::TimeDeltaToFrames(base::TimeDelta duration) const {
38 DCHECK(duration >= base::TimeDelta()); 39 DCHECK(duration >= base::TimeDelta());
39 return std::ceil(duration.InSecondsF() * sample_rate_); 40 return std::ceil(duration.InSecondsF() * sample_rate_);
40 } 41 }
41 42
42 void AudioDiscardHelper::Reset(size_t initial_discard) { 43 void AudioDiscardHelper::Reset(size_t initial_discard) {
43 discard_frames_ = initial_discard; 44 discard_frames_ = initial_discard;
44 last_input_timestamp_ = kNoTimestamp(); 45 last_input_timestamp_ = kNoTimestamp();
45 timestamp_helper_.SetBaseTimestamp(kNoTimestamp()); 46 timestamp_helper_.SetBaseTimestamp(kNoTimestamp());
47 delayed_discard_ = NULL;
46 } 48 }
47 49
48 bool AudioDiscardHelper::ProcessBuffers( 50 bool AudioDiscardHelper::ProcessBuffers(
49 const scoped_refptr<DecoderBuffer>& encoded_buffer, 51 const scoped_refptr<DecoderBuffer>& encoded_buffer,
50 const scoped_refptr<AudioBuffer>& decoded_buffer) { 52 const scoped_refptr<AudioBuffer>& decoded_buffer) {
51 DCHECK(!encoded_buffer->end_of_stream()); 53 DCHECK(!encoded_buffer->end_of_stream());
52 DCHECK(encoded_buffer->timestamp() != kNoTimestamp()); 54 DCHECK(encoded_buffer->timestamp() != kNoTimestamp());
53 55
54 // Issue a debug warning when we see non-monotonic timestamps. Only a warning 56 // Issue a debug warning when we see non-monotonic timestamps. Only a warning
55 // to allow chained OGG playback. 57 // to allow chained OGG playback.
56 WarnOnNonMonotonicTimestamps(last_input_timestamp_, 58 WarnOnNonMonotonicTimestamps(last_input_timestamp_,
57 encoded_buffer->timestamp()); 59 encoded_buffer->timestamp());
58 last_input_timestamp_ = encoded_buffer->timestamp(); 60 last_input_timestamp_ = encoded_buffer->timestamp();
59 61
60 // If this is the first buffer seen, setup the timestamp helper. 62 // If this is the first buffer seen, setup the timestamp helper.
61 if (!initialized()) 63 const bool first_buffer = !initialized();
64 if (first_buffer)
62 timestamp_helper_.SetBaseTimestamp(encoded_buffer->timestamp()); 65 timestamp_helper_.SetBaseTimestamp(encoded_buffer->timestamp());
63 DCHECK(initialized()); 66 DCHECK(initialized());
64 67
65 if (!decoded_buffer || !decoded_buffer->frame_count()) 68 if (!decoded_buffer) {
69 // If there's a one buffer delay for decoding, we need to save it so it can
70 // be processed with the next decoder buffer.
71 if (first_buffer)
72 delayed_discard_ = encoded_buffer;
66 return false; 73 return false;
74 }
75
76 const size_t original_frame_count = decoded_buffer->frame_count();
77
78 // If there's a one buffer delay for decoding, pick up the last encoded buffer
79 // for processing with the current decoded buffer.
80 scoped_refptr<DecoderBuffer> current_encoded_buffer = encoded_buffer;
81 if (delayed_discard_)
82 delayed_discard_.swap(current_encoded_buffer);
67 83
68 if (discard_frames_ > 0) { 84 if (discard_frames_ > 0) {
69 const size_t decoded_frames = decoded_buffer->frame_count(); 85 const size_t decoded_frames = decoded_buffer->frame_count();
70 const size_t frames_to_discard = std::min(discard_frames_, decoded_frames); 86 const size_t frames_to_discard = std::min(discard_frames_, decoded_frames);
71 discard_frames_ -= frames_to_discard; 87 discard_frames_ -= frames_to_discard;
72 88
73 // If everything would be discarded, indicate a new buffer is required. 89 // If everything would be discarded, indicate a new buffer is required.
74 if (frames_to_discard == decoded_frames) 90 if (frames_to_discard == decoded_frames) {
91 // For simplicity disallow cases where a buffer with discard padding is
92 // present. Doing so allows us to avoid complexity around tracking
93 // discards across buffers.
94 DCHECK(current_encoded_buffer->discard_padding().first ==
95 base::TimeDelta());
96 DCHECK(current_encoded_buffer->discard_padding().second ==
97 base::TimeDelta());
75 return false; 98 return false;
99 }
76 100
77 decoded_buffer->TrimStart(frames_to_discard); 101 decoded_buffer->TrimStart(frames_to_discard);
78 } 102 }
79 103
80 // TODO(dalecurtis): Applying the current buffer's discard padding doesn't 104 // Handle front discard padding.
81 // make sense in the Vorbis case because there is a delay of one buffer before 105 if (current_encoded_buffer->discard_padding().first > base::TimeDelta()) {
82 // decoded buffers are returned. Fix and add support for more than just end 106 const size_t decoded_frames = decoded_buffer->frame_count();
83 // trimming. 107 const size_t start_frames_to_discard =
84 if (encoded_buffer->discard_padding() > base::TimeDelta()) { 108 TimeDeltaToFrames(current_encoded_buffer->discard_padding().first);
109
110 // Regardless of the timestamp on the encoded buffer, the corresponding
111 // decoded output will appear |codec_delay_| frames later.
112 size_t discard_start = codec_delay_;
113 if (codec_delay_ > 0) {
114 // If we have a |codec_delay_| and have already discarded frames from this
115 // buffer, the |discard_start| must be adjusted by the number of frames
116 // already discarded.
117 const size_t frames_discarded_so_far =
118 original_frame_count - decoded_buffer->frame_count();
119 CHECK_LE(frames_discarded_so_far, codec_delay_);
120 discard_start -= frames_discarded_so_far;
121 }
122
123 // For simplicity require the start of the discard to be within the current
124 // buffer. Doing so allows us avoid complexity around tracking discards
125 // across buffers.
126 CHECK_LT(discard_start, decoded_frames);
127
128 const size_t frames_to_discard =
129 std::min(start_frames_to_discard, decoded_frames - discard_start);
130
131 // Carry over any frames which need to be discarded from the front of the
132 // next buffer.
133 DCHECK(!discard_frames_);
134 discard_frames_ = start_frames_to_discard - frames_to_discard;
135
136 // If everything would be discarded, indicate a new buffer is required.
137 if (frames_to_discard == decoded_frames) {
138 // The buffer should not have been marked with end discard if the front
139 // discard removes everything.
140 DCHECK(current_encoded_buffer->discard_padding().second ==
141 base::TimeDelta());
142 return false;
143 }
144
145 decoded_buffer->TrimRange(discard_start, discard_start + frames_to_discard);
146 }
147
148 // Handle end discard padding.
149 if (current_encoded_buffer->discard_padding().second > base::TimeDelta()) {
150 // Limit end discarding to when there is no |codec_delay_|, otherwise it's
151 // non-trivial determining where to start discarding end frames.
152 CHECK(!codec_delay_);
153
85 const size_t decoded_frames = decoded_buffer->frame_count(); 154 const size_t decoded_frames = decoded_buffer->frame_count();
86 const size_t end_frames_to_discard = 155 const size_t end_frames_to_discard =
87 TimeDeltaToFrames(encoded_buffer->discard_padding()); 156 TimeDeltaToFrames(current_encoded_buffer->discard_padding().second);
157
88 if (end_frames_to_discard > decoded_frames) { 158 if (end_frames_to_discard > decoded_frames) {
89 DLOG(ERROR) << "Invalid file. Incorrect discard padding value."; 159 DLOG(ERROR) << "Invalid file. Incorrect discard padding value.";
90 return false; 160 return false;
91 } 161 }
92 162
93 // If everything would be discarded, indicate a new buffer is required. 163 // If everything would be discarded, indicate a new buffer is required.
94 if (end_frames_to_discard == decoded_frames) 164 if (end_frames_to_discard == decoded_frames)
95 return false; 165 return false;
96 166
97 decoded_buffer->TrimEnd(end_frames_to_discard); 167 decoded_buffer->TrimEnd(end_frames_to_discard);
98 } else { 168 } else {
99 DCHECK(encoded_buffer->discard_padding() == base::TimeDelta()); 169 DCHECK(current_encoded_buffer->discard_padding().second ==
170 base::TimeDelta());
100 } 171 }
101 172
102 // Assign timestamp and duration to the buffer. 173 // Assign timestamp and duration to the buffer.
103 decoded_buffer->set_timestamp(timestamp_helper_.GetTimestamp()); 174 decoded_buffer->set_timestamp(timestamp_helper_.GetTimestamp());
104 decoded_buffer->set_duration( 175 decoded_buffer->set_duration(
105 timestamp_helper_.GetFrameDuration(decoded_buffer->frame_count())); 176 timestamp_helper_.GetFrameDuration(decoded_buffer->frame_count()));
106 timestamp_helper_.AddFrames(decoded_buffer->frame_count()); 177 timestamp_helper_.AddFrames(decoded_buffer->frame_count());
107 return true; 178 return true;
108 } 179 }
109 180
110 } // namespace media 181 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698