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

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

Issue 156783003: Enhance AudioSplicer to crossfade marked splice frames. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Comments. Created 6 years, 9 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
« no previous file with comments | « media/base/audio_splicer.h ('k') | media/base/audio_splicer_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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_splicer.h" 5 #include "media/base/audio_splicer.h"
6 6
7 #include <cstdlib> 7 #include <cstdlib>
8 #include <deque>
8 9
9 #include "base/logging.h" 10 #include "base/logging.h"
10 #include "media/base/audio_buffer.h" 11 #include "media/base/audio_buffer.h"
12 #include "media/base/audio_bus.h"
11 #include "media/base/audio_decoder_config.h" 13 #include "media/base/audio_decoder_config.h"
12 #include "media/base/audio_timestamp_helper.h" 14 #include "media/base/audio_timestamp_helper.h"
13 #include "media/base/buffers.h" 15 #include "media/base/buffers.h"
16 #include "media/base/vector_math.h"
14 17
15 namespace media { 18 namespace media {
16 19
17 // Largest gap or overlap allowed by this class. Anything 20 // Largest gap or overlap allowed by this class. Anything
18 // larger than this will trigger an error. 21 // larger than this will trigger an error.
19 // This is an arbitrary value, but the initial selection of 50ms 22 // This is an arbitrary value, but the initial selection of 50ms
20 // roughly represents the duration of 2 compressed AAC or MP3 frames. 23 // roughly represents the duration of 2 compressed AAC or MP3 frames.
21 static const int kMaxTimeDeltaInMilliseconds = 50; 24 static const int kMaxTimeDeltaInMilliseconds = 50;
22 25
23 AudioSplicer::AudioSplicer(int samples_per_second) 26 // Minimum gap size needed before the splicer will take action to
24 : output_timestamp_helper_(samples_per_second), 27 // fill a gap. This avoids periodically inserting and then dropping samples
25 min_gap_size_(2), 28 // when the buffer timestamps are slightly off because of timestamp rounding
26 received_end_of_stream_(false) { 29 // in the source content. Unit is frames.
30 static const int kMinGapSize = 2;
31
32 // The number of milliseconds to crossfade before trimming when buffers overlap.
33 static const int kCrossfadeDurationInMilliseconds = 5;
34
35 // AudioBuffer::TrimStart() is not as accurate as the timestamp helper, so
36 // manually adjust the duration and timestamp after trimming.
37 static void AccurateTrimStart(int frames_to_trim,
38 const scoped_refptr<AudioBuffer> buffer,
39 const AudioTimestampHelper& timestamp_helper) {
40 buffer->TrimStart(frames_to_trim);
41 buffer->set_timestamp(timestamp_helper.GetTimestamp());
42 buffer->set_duration(
43 timestamp_helper.GetFrameDuration(buffer->frame_count()));
27 } 44 }
28 45
29 AudioSplicer::~AudioSplicer() { 46 // AudioBuffer::TrimEnd() is not as accurate as the timestamp helper, so
47 // manually adjust the duration after trimming.
48 static void AccurateTrimEnd(int frames_to_trim,
49 const scoped_refptr<AudioBuffer> buffer,
50 const AudioTimestampHelper& timestamp_helper) {
51 DCHECK(buffer->timestamp() == timestamp_helper.GetTimestamp());
52 buffer->TrimEnd(frames_to_trim);
53 buffer->set_duration(
54 timestamp_helper.GetFrameDuration(buffer->frame_count()));
30 } 55 }
31 56
32 void AudioSplicer::Reset() { 57 // Returns an AudioBus whose frame buffer is backed by the provided AudioBuffer.
33 output_timestamp_helper_.SetBaseTimestamp(kNoTimestamp()); 58 static scoped_ptr<AudioBus> CreateAudioBufferWrapper(
59 const scoped_refptr<AudioBuffer>& buffer) {
60 scoped_ptr<AudioBus> wrapper =
61 AudioBus::CreateWrapper(buffer->channel_count());
62 wrapper->set_frames(buffer->frame_count());
63 for (int ch = 0; ch < buffer->channel_count(); ++ch) {
64 wrapper->SetChannelData(
65 ch, reinterpret_cast<float*>(buffer->channel_data()[ch]));
66 }
67 return wrapper.Pass();
68 }
69
70 class AudioStreamSanitizer {
71 public:
72 explicit AudioStreamSanitizer(int samples_per_second);
73 ~AudioStreamSanitizer();
74
75 // Resets the sanitizer state by clearing the output buffers queue, and
76 // resetting the timestamp helper.
77 void Reset();
78
79 // Similar to Reset(), but initializes the timestamp helper with the given
80 // parameters.
81 void ResetTimestampState(int64 frame_count, base::TimeDelta base_timestamp);
82
83 // Adds a new buffer full of samples or end of stream buffer to the splicer.
84 // Returns true if the buffer was accepted. False is returned if an error
85 // occurred.
86 bool AddInput(const scoped_refptr<AudioBuffer>& input);
87
88 // Returns true if the sanitizer has a buffer to return.
89 bool HasNextBuffer() const;
90
91 // Removes the next buffer from the output buffer queue and returns it; should
92 // only be called if HasNextBuffer() returns true.
93 scoped_refptr<AudioBuffer> GetNextBuffer();
94
95 // Returns the total frame count of all buffers available for output.
96 int GetFrameCount() const;
97
98 // Returns the duration of all buffers added to the output queue thus far.
99 base::TimeDelta GetDuration() const;
100
101 const AudioTimestampHelper& timestamp_helper() {
102 return output_timestamp_helper_;
103 }
104
105 private:
106 void AddOutputBuffer(const scoped_refptr<AudioBuffer>& buffer);
107
108 AudioTimestampHelper output_timestamp_helper_;
109 bool received_end_of_stream_;
110
111 typedef std::deque<scoped_refptr<AudioBuffer> > BufferQueue;
112 BufferQueue output_buffers_;
113
114 DISALLOW_ASSIGN(AudioStreamSanitizer);
115 };
116
117 AudioStreamSanitizer::AudioStreamSanitizer(int samples_per_second)
118 : output_timestamp_helper_(samples_per_second),
119 received_end_of_stream_(false) {}
120
121 AudioStreamSanitizer::~AudioStreamSanitizer() {}
122
123 void AudioStreamSanitizer::Reset() {
124 ResetTimestampState(0, kNoTimestamp());
125 }
126
127 void AudioStreamSanitizer::ResetTimestampState(int64 frame_count,
128 base::TimeDelta base_timestamp) {
34 output_buffers_.clear(); 129 output_buffers_.clear();
35 received_end_of_stream_ = false; 130 received_end_of_stream_ = false;
131 output_timestamp_helper_.SetBaseTimestamp(base_timestamp);
132 if (frame_count > 0)
133 output_timestamp_helper_.AddFrames(frame_count);
36 } 134 }
37 135
38 bool AudioSplicer::AddInput(const scoped_refptr<AudioBuffer>& input) { 136 bool AudioStreamSanitizer::AddInput(const scoped_refptr<AudioBuffer>& input) {
39 DCHECK(!received_end_of_stream_ || input->end_of_stream()); 137 DCHECK(!received_end_of_stream_ || input->end_of_stream());
40 138
41 if (input->end_of_stream()) { 139 if (input->end_of_stream()) {
42 output_buffers_.push_back(input); 140 output_buffers_.push_back(input);
43 received_end_of_stream_ = true; 141 received_end_of_stream_ = true;
44 return true; 142 return true;
45 } 143 }
46 144
47 DCHECK(input->timestamp() != kNoTimestamp()); 145 DCHECK(input->timestamp() != kNoTimestamp());
48 DCHECK(input->duration() > base::TimeDelta()); 146 DCHECK(input->duration() > base::TimeDelta());
49 DCHECK_GT(input->frame_count(), 0); 147 DCHECK_GT(input->frame_count(), 0);
50 148
51 if (output_timestamp_helper_.base_timestamp() == kNoTimestamp()) 149 if (output_timestamp_helper_.base_timestamp() == kNoTimestamp())
52 output_timestamp_helper_.SetBaseTimestamp(input->timestamp()); 150 output_timestamp_helper_.SetBaseTimestamp(input->timestamp());
53 151
54 if (output_timestamp_helper_.base_timestamp() > input->timestamp()) { 152 if (output_timestamp_helper_.base_timestamp() > input->timestamp()) {
55 DVLOG(1) << "Input timestamp is before the base timestamp."; 153 DVLOG(1) << "Input timestamp is before the base timestamp.";
56 return false; 154 return false;
57 } 155 }
58 156
59 base::TimeDelta timestamp = input->timestamp(); 157 const base::TimeDelta timestamp = input->timestamp();
60 base::TimeDelta expected_timestamp = output_timestamp_helper_.GetTimestamp(); 158 const base::TimeDelta expected_timestamp =
61 base::TimeDelta delta = timestamp - expected_timestamp; 159 output_timestamp_helper_.GetTimestamp();
160 const base::TimeDelta delta = timestamp - expected_timestamp;
62 161
63 if (std::abs(delta.InMilliseconds()) > kMaxTimeDeltaInMilliseconds) { 162 if (std::abs(delta.InMilliseconds()) > kMaxTimeDeltaInMilliseconds) {
64 DVLOG(1) << "Timestamp delta too large: " << delta.InMicroseconds() << "us"; 163 DVLOG(1) << "Timestamp delta too large: " << delta.InMicroseconds() << "us";
65 return false; 164 return false;
66 } 165 }
67 166
68 int frames_to_fill = 0; 167 int frames_to_fill = 0;
69 if (delta != base::TimeDelta()) 168 if (delta != base::TimeDelta())
70 frames_to_fill = output_timestamp_helper_.GetFramesToTarget(timestamp); 169 frames_to_fill = output_timestamp_helper_.GetFramesToTarget(timestamp);
71 170
72 if (frames_to_fill == 0 || std::abs(frames_to_fill) < min_gap_size_) { 171 if (frames_to_fill == 0 || std::abs(frames_to_fill) < kMinGapSize) {
73 AddOutputBuffer(input); 172 AddOutputBuffer(input);
74 return true; 173 return true;
75 } 174 }
76 175
77 if (frames_to_fill > 0) { 176 if (frames_to_fill > 0) {
78 DVLOG(1) << "Gap detected @ " << expected_timestamp.InMicroseconds() 177 DVLOG(1) << "Gap detected @ " << expected_timestamp.InMicroseconds()
79 << " us: " << delta.InMicroseconds() << " us"; 178 << " us: " << delta.InMicroseconds() << " us";
80 179
81 // Create a buffer with enough silence samples to fill the gap and 180 // Create a buffer with enough silence samples to fill the gap and
82 // add it to the output buffer. 181 // add it to the output buffer.
83 scoped_refptr<AudioBuffer> gap = AudioBuffer::CreateEmptyBuffer( 182 scoped_refptr<AudioBuffer> gap = AudioBuffer::CreateEmptyBuffer(
84 input->channel_count(), 183 input->channel_count(),
85 frames_to_fill, 184 frames_to_fill,
86 expected_timestamp, 185 expected_timestamp,
87 output_timestamp_helper_.GetFrameDuration(frames_to_fill)); 186 output_timestamp_helper_.GetFrameDuration(frames_to_fill));
88 AddOutputBuffer(gap); 187 AddOutputBuffer(gap);
89 188
90 // Add the input buffer now that the gap has been filled. 189 // Add the input buffer now that the gap has been filled.
91 AddOutputBuffer(input); 190 AddOutputBuffer(input);
92 return true; 191 return true;
93 } 192 }
94 193
95 int frames_to_skip = -frames_to_fill; 194 // Overlapping buffers marked as splice frames are handled by AudioSplicer,
96 195 // but decoder and demuxer quirks may sometimes produce overlapping samples
196 // which need to be sanitized.
197 //
198 // A crossfade can't be done here because only the current buffer is available
199 // at this point, not previous buffers.
97 DVLOG(1) << "Overlap detected @ " << expected_timestamp.InMicroseconds() 200 DVLOG(1) << "Overlap detected @ " << expected_timestamp.InMicroseconds()
98 << " us: " << -delta.InMicroseconds() << " us"; 201 << " us: " << -delta.InMicroseconds() << " us";
99 202
203 const int frames_to_skip = -frames_to_fill;
100 if (input->frame_count() <= frames_to_skip) { 204 if (input->frame_count() <= frames_to_skip) {
101 DVLOG(1) << "Dropping whole buffer"; 205 DVLOG(1) << "Dropping whole buffer";
102 return true; 206 return true;
103 } 207 }
104 208
105 // Copy the trailing samples that do not overlap samples already output 209 // Copy the trailing samples that do not overlap samples already output
106 // into a new buffer. Add this new buffer to the output queue. 210 // into a new buffer. Add this new buffer to the output queue.
107 // 211 //
108 // TODO(acolwell): Implement a cross-fade here so the transition is less 212 // TODO(acolwell): Implement a cross-fade here so the transition is less
109 // jarring. 213 // jarring.
110 input->TrimStart(frames_to_skip); 214 AccurateTrimStart(frames_to_skip, input, output_timestamp_helper_);
111 AddOutputBuffer(input); 215 AddOutputBuffer(input);
112 return true; 216 return true;
113 } 217 }
114 218
115 bool AudioSplicer::HasNextBuffer() const { 219 bool AudioStreamSanitizer::HasNextBuffer() const {
116 return !output_buffers_.empty(); 220 return !output_buffers_.empty();
117 } 221 }
118 222
119 scoped_refptr<AudioBuffer> AudioSplicer::GetNextBuffer() { 223 scoped_refptr<AudioBuffer> AudioStreamSanitizer::GetNextBuffer() {
120 scoped_refptr<AudioBuffer> ret = output_buffers_.front(); 224 scoped_refptr<AudioBuffer> ret = output_buffers_.front();
121 output_buffers_.pop_front(); 225 output_buffers_.pop_front();
122 return ret; 226 return ret;
123 } 227 }
124 228
125 void AudioSplicer::AddOutputBuffer(const scoped_refptr<AudioBuffer>& buffer) { 229 void AudioStreamSanitizer::AddOutputBuffer(
230 const scoped_refptr<AudioBuffer>& buffer) {
126 output_timestamp_helper_.AddFrames(buffer->frame_count()); 231 output_timestamp_helper_.AddFrames(buffer->frame_count());
127 output_buffers_.push_back(buffer); 232 output_buffers_.push_back(buffer);
128 } 233 }
129 234
235 int AudioStreamSanitizer::GetFrameCount() const {
236 int frame_count = 0;
237 for (BufferQueue::const_iterator it = output_buffers_.begin();
238 it != output_buffers_.end(); ++it) {
239 frame_count += (*it)->frame_count();
240 }
241 return frame_count;
242 }
243
244 base::TimeDelta AudioStreamSanitizer::GetDuration() const {
245 DCHECK(output_timestamp_helper_.base_timestamp() != kNoTimestamp());
246 return output_timestamp_helper_.GetTimestamp() -
247 output_timestamp_helper_.base_timestamp();
248 }
249
250 AudioSplicer::AudioSplicer(int samples_per_second)
251 : max_crossfade_duration_(
252 base::TimeDelta::FromMilliseconds(kCrossfadeDurationInMilliseconds)),
253 splice_timestamp_(kNoTimestamp()),
254 output_sanitizer_(new AudioStreamSanitizer(samples_per_second)),
255 pre_splice_sanitizer_(new AudioStreamSanitizer(samples_per_second)),
256 post_splice_sanitizer_(new AudioStreamSanitizer(samples_per_second)) {}
257
258 AudioSplicer::~AudioSplicer() {}
259
260 void AudioSplicer::Reset() {
261 output_sanitizer_->Reset();
262 pre_splice_sanitizer_->Reset();
263 post_splice_sanitizer_->Reset();
264 splice_timestamp_ = kNoTimestamp();
265 }
266
267 bool AudioSplicer::AddInput(const scoped_refptr<AudioBuffer>& input) {
268 // If we're not processing a splice, add the input to the output queue.
269 if (splice_timestamp_ == kNoTimestamp()) {
270 DCHECK(!pre_splice_sanitizer_->HasNextBuffer());
271 DCHECK(!post_splice_sanitizer_->HasNextBuffer());
272 return output_sanitizer_->AddInput(input);
273 }
274
275 // If we're still receiving buffers before the splice point figure out which
276 // sanitizer (if any) to put them in.
277 if (!post_splice_sanitizer_->HasNextBuffer()) {
278 DCHECK(!input->end_of_stream());
279
280 // If the provided buffer is entirely before the splice point it can also be
281 // added to the output queue.
282 if (input->timestamp() + input->duration() < splice_timestamp_) {
283 DCHECK(!pre_splice_sanitizer_->HasNextBuffer());
284 return output_sanitizer_->AddInput(input);
285 }
286
287 // If we've encountered the first pre splice buffer, reset the pre splice
288 // sanitizer based on |output_sanitizer_|. This is done so that gaps and
289 // overlaps between buffers across the sanitizers are accounted for prior
290 // to calculating crossfade.
291 if (!pre_splice_sanitizer_->HasNextBuffer()) {
292 pre_splice_sanitizer_->ResetTimestampState(
293 output_sanitizer_->timestamp_helper().frame_count(),
294 output_sanitizer_->timestamp_helper().base_timestamp());
295 }
296
297 // If we're processing a splice and the input buffer does not overlap any of
298 // the existing buffers append it to the |pre_splice_sanitizer_|.
299 //
300 // The first overlapping buffer is expected to have a timestamp of exactly
301 // |splice_timestamp_|. It's not sufficient to check this though, since in
302 // the case of a perfect overlap, the first pre-splice buffer may have the
303 // same timestamp.
304 //
305 // It's also not sufficient to check if the input timestamp is after the
306 // current expected timestamp from |pre_splice_sanitizer_| since the decoder
307 // may have fuzzed the timestamps slightly.
308 if (!pre_splice_sanitizer_->HasNextBuffer() ||
309 input->timestamp() != splice_timestamp_) {
310 return pre_splice_sanitizer_->AddInput(input);
311 }
312
313 // We've received the first overlapping buffer.
314 } else {
315 // TODO(dalecurtis): The pre splice assignment process still leaves the
316 // unlikely case that the decoder fuzzes a later pre splice buffer's
317 // timestamp such that it matches |splice_timestamp_|.
318 //
319 // Watch for these crashes in the field to see if we need a more complicated
320 // assignment process.
321 CHECK(input->timestamp() != splice_timestamp_);
322 }
323
324 // At this point we have all the fade out preroll buffers from the decoder.
325 // We now need to wait until we have enough data to perform the crossfade (or
326 // we receive an end of stream).
327 if (!post_splice_sanitizer_->AddInput(input))
328 return false;
329
330 if (!input->end_of_stream() &&
331 post_splice_sanitizer_->GetDuration() < max_crossfade_duration_) {
332 return true;
333 }
334
335 // Crossfade the pre splice and post splice sections and transfer all relevant
336 // buffers into |output_sanitizer_|.
337 CrossfadePostSplice(ExtractCrossfadeFromPreSplice().Pass());
338
339 // Clear the splice timestamp so new splices can be accepted.
340 splice_timestamp_ = kNoTimestamp();
341 return true;
342 }
343
344 bool AudioSplicer::HasNextBuffer() const {
345 return output_sanitizer_->HasNextBuffer();
346 }
347
348 scoped_refptr<AudioBuffer> AudioSplicer::GetNextBuffer() {
349 return output_sanitizer_->GetNextBuffer();
350 }
351
352 void AudioSplicer::SetSpliceTimestamp(base::TimeDelta splice_timestamp) {
353 DCHECK(splice_timestamp != kNoTimestamp());
354 if (splice_timestamp_ == splice_timestamp)
355 return;
356
357 // TODO(dalecurtis): We may need the concept of a future_splice_timestamp_ to
358 // handle cases where another splice comes in before we've received 5ms of
359 // data from the last one. Leave this as a CHECK for now to figure out if
360 // this case is possible.
361 CHECK(splice_timestamp_ == kNoTimestamp());
362 splice_timestamp_ = splice_timestamp;
363 }
364
365 scoped_ptr<AudioBus> AudioSplicer::ExtractCrossfadeFromPreSplice() {
366 const AudioTimestampHelper& output_ts_helper =
367 output_sanitizer_->timestamp_helper();
368
369 // Ensure |output_sanitizer_| has a valid base timestamp so we can use it for
370 // timestamp calculations.
371 if (output_ts_helper.base_timestamp() == kNoTimestamp()) {
372 output_sanitizer_->ResetTimestampState(
373 0, pre_splice_sanitizer_->timestamp_helper().base_timestamp());
374 }
375
376 int frames_before_splice =
377 output_ts_helper.GetFramesToTarget(splice_timestamp_);
378
379 // Determine crossfade frame count based on available frames in each splicer
380 // and capping to the maximum crossfade duration.
381 const int max_crossfade_frame_count =
382 output_ts_helper.GetFramesToTarget(splice_timestamp_ +
383 max_crossfade_duration_) -
384 frames_before_splice;
385 const int frames_to_crossfade = std::min(
386 max_crossfade_frame_count,
387 std::min(pre_splice_sanitizer_->GetFrameCount() - frames_before_splice,
388 post_splice_sanitizer_->GetFrameCount()));
389
390 int frames_read = 0;
391 scoped_ptr<AudioBus> output_bus;
392 while (pre_splice_sanitizer_->HasNextBuffer() &&
393 frames_read < frames_to_crossfade) {
394 scoped_refptr<AudioBuffer> preroll = pre_splice_sanitizer_->GetNextBuffer();
395
396 // We don't know the channel count until we see the first buffer, so wait
397 // until the first buffer to allocate the output AudioBus.
398 if (!output_bus) {
399 output_bus =
400 AudioBus::Create(preroll->channel_count(), frames_to_crossfade);
401 }
402
403 // There may be enough of a gap introduced during decoding such that an
404 // entire buffer exists before the splice point.
405 if (frames_before_splice >= preroll->frame_count()) {
406 // Adjust the number of frames remaining before the splice. NOTE: This is
407 // safe since |pre_splice_sanitizer_| is a continuation of the timeline in
408 // |output_sanitizer_|. As such we're guaranteed there are no gaps or
409 // overlaps in the timeline between the two sanitizers.
410 frames_before_splice -= preroll->frame_count();
411 CHECK(output_sanitizer_->AddInput(preroll));
412 continue;
413 }
414
415 const int frames_to_read =
416 std::min(preroll->frame_count() - frames_before_splice,
417 output_bus->frames() - frames_read);
418 preroll->ReadFrames(
419 frames_to_read, frames_before_splice, frames_read, output_bus.get());
420 frames_read += frames_to_read;
421
422 // If only part of the buffer was consumed, trim it appropriately and stick
423 // it into the output queue.
424 if (frames_before_splice) {
425 AccurateTrimEnd(preroll->frame_count() - frames_before_splice,
426 preroll,
427 output_ts_helper);
428 CHECK(output_sanitizer_->AddInput(preroll));
429 frames_before_splice = 0;
430 }
431 }
432
433 // All necessary buffers have been processed, it's safe to reset.
434 pre_splice_sanitizer_->Reset();
435 DCHECK_EQ(output_bus->frames(), frames_read);
436 DCHECK_EQ(output_ts_helper.GetFramesToTarget(splice_timestamp_), 0);
437 return output_bus.Pass();
438 }
439
440 void AudioSplicer::CrossfadePostSplice(scoped_ptr<AudioBus> pre_splice_bus) {
441 // Allocate output buffer for crossfade.
442 scoped_refptr<AudioBuffer> crossfade_buffer =
443 AudioBuffer::CreateBuffer(kSampleFormatPlanarF32,
444 pre_splice_bus->channels(),
445 pre_splice_bus->frames());
446
447 // Use the calculated timestamp and duration to ensure there's no extra gaps
448 // or overlaps to process when adding the buffer to |output_sanitizer_|.
449 const AudioTimestampHelper& output_ts_helper =
450 output_sanitizer_->timestamp_helper();
451 crossfade_buffer->set_timestamp(output_ts_helper.GetTimestamp());
452 crossfade_buffer->set_duration(
453 output_ts_helper.GetFrameDuration(pre_splice_bus->frames()));
454
455 // AudioBuffer::ReadFrames() only allows output into an AudioBus, so wrap
456 // our AudioBuffer in one so we can avoid extra data copies.
457 scoped_ptr<AudioBus> output_bus = CreateAudioBufferWrapper(crossfade_buffer);
458
459 // Extract crossfade section from the |post_splice_sanitizer_|.
460 int frames_read = 0, frames_to_trim = 0;
461 scoped_refptr<AudioBuffer> remainder;
462 while (post_splice_sanitizer_->HasNextBuffer() &&
463 frames_read < output_bus->frames()) {
464 scoped_refptr<AudioBuffer> postroll =
465 post_splice_sanitizer_->GetNextBuffer();
466 const int frames_to_read =
467 std::min(postroll->frame_count(), output_bus->frames() - frames_read);
468 postroll->ReadFrames(frames_to_read, 0, frames_read, output_bus.get());
469 frames_read += frames_to_read;
470
471 // If only part of the buffer was consumed, save it for after we've added
472 // the crossfade buffer
473 if (frames_to_read < postroll->frame_count()) {
474 DCHECK(!remainder);
475 remainder.swap(postroll);
476 frames_to_trim = frames_to_read;
477 }
478 }
479
480 DCHECK_EQ(output_bus->frames(), frames_read);
481
482 // Crossfade the audio into |crossfade_buffer|.
483 for (int ch = 0; ch < output_bus->channels(); ++ch) {
484 vector_math::Crossfade(pre_splice_bus->channel(ch),
485 pre_splice_bus->frames(),
486 output_bus->channel(ch));
487 }
488
489 CHECK(output_sanitizer_->AddInput(crossfade_buffer));
490 DCHECK_EQ(crossfade_buffer->frame_count(), output_bus->frames());
491
492 if (remainder) {
493 // Trim off consumed frames.
494 AccurateTrimStart(frames_to_trim, remainder, output_ts_helper);
495 CHECK(output_sanitizer_->AddInput(remainder));
496 }
497
498 // Transfer all remaining buffers out and reset once empty.
499 while (post_splice_sanitizer_->HasNextBuffer())
500 CHECK(output_sanitizer_->AddInput(post_splice_sanitizer_->GetNextBuffer()));
501 post_splice_sanitizer_->Reset();
502 }
503
130 } // namespace media 504 } // namespace media
OLDNEW
« no previous file with comments | « media/base/audio_splicer.h ('k') | media/base/audio_splicer_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698