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
3 // found in the LICENSE file.
5 #include "media/base/audio_splicer.h"
9 #include "base/logging.h"
10 #include "media/base/audio_buffer.h"
11 #include "media/base/audio_decoder_config.h"
12 #include "media/base/audio_timestamp_helper.h"
13 #include "media/base/buffers.h"
17 // Largest gap or overlap allowed by this class. Anything
18 // larger than this will trigger an error.
19 // This is an arbitrary value, but the initial selection of 50ms
20 // roughly represents the duration of 2 compressed AAC or MP3 frames.
21 static const int kMaxTimeDeltaInMilliseconds
= 50;
23 AudioSplicer::AudioSplicer(int samples_per_second
)
24 : output_timestamp_helper_(samples_per_second
),
26 received_end_of_stream_(false) {
29 AudioSplicer::~AudioSplicer() {
32 void AudioSplicer::Reset() {
33 output_timestamp_helper_
.SetBaseTimestamp(kNoTimestamp());
34 output_buffers_
.clear();
35 received_end_of_stream_
= false;
38 bool AudioSplicer::AddInput(const scoped_refptr
<AudioBuffer
>& input
) {
39 DCHECK(!received_end_of_stream_
|| input
->end_of_stream());
41 if (input
->end_of_stream()) {
42 output_buffers_
.push_back(input
);
43 received_end_of_stream_
= true;
47 DCHECK(input
->timestamp() != kNoTimestamp());
48 DCHECK(input
->duration() > base::TimeDelta());
49 DCHECK_GT(input
->frame_count(), 0);
51 if (output_timestamp_helper_
.base_timestamp() == kNoTimestamp())
52 output_timestamp_helper_
.SetBaseTimestamp(input
->timestamp());
54 if (output_timestamp_helper_
.base_timestamp() > input
->timestamp()) {
55 DVLOG(1) << "Input timestamp is before the base timestamp.";
59 base::TimeDelta timestamp
= input
->timestamp();
60 base::TimeDelta expected_timestamp
= output_timestamp_helper_
.GetTimestamp();
61 base::TimeDelta delta
= timestamp
- expected_timestamp
;
63 if (std::abs(delta
.InMilliseconds()) > kMaxTimeDeltaInMilliseconds
) {
64 DVLOG(1) << "Timestamp delta too large: " << delta
.InMicroseconds() << "us";
68 int frames_to_fill
= 0;
69 if (delta
!= base::TimeDelta())
70 frames_to_fill
= output_timestamp_helper_
.GetFramesToTarget(timestamp
);
72 if (frames_to_fill
== 0 || std::abs(frames_to_fill
) < min_gap_size_
) {
73 AddOutputBuffer(input
);
77 if (frames_to_fill
> 0) {
78 DVLOG(1) << "Gap detected @ " << expected_timestamp
.InMicroseconds()
79 << " us: " << delta
.InMicroseconds() << " us";
81 // Create a buffer with enough silence samples to fill the gap and
82 // add it to the output buffer.
83 scoped_refptr
<AudioBuffer
> gap
= AudioBuffer::CreateEmptyBuffer(
84 input
->channel_count(),
87 output_timestamp_helper_
.GetFrameDuration(frames_to_fill
));
90 // Add the input buffer now that the gap has been filled.
91 AddOutputBuffer(input
);
95 int frames_to_skip
= -frames_to_fill
;
97 DVLOG(1) << "Overlap detected @ " << expected_timestamp
.InMicroseconds()
98 << " us: " << -delta
.InMicroseconds() << " us";
100 if (input
->frame_count() <= frames_to_skip
) {
101 DVLOG(1) << "Dropping whole buffer";
105 // Copy the trailing samples that do not overlap samples already output
106 // into a new buffer. Add this new buffer to the output queue.
108 // TODO(acolwell): Implement a cross-fade here so the transition is less
110 input
->TrimStart(frames_to_skip
);
111 AddOutputBuffer(input
);
115 bool AudioSplicer::HasNextBuffer() const {
116 return !output_buffers_
.empty();
119 scoped_refptr
<AudioBuffer
> AudioSplicer::GetNextBuffer() {
120 scoped_refptr
<AudioBuffer
> ret
= output_buffers_
.front();
121 output_buffers_
.pop_front();
125 void AudioSplicer::AddOutputBuffer(const scoped_refptr
<AudioBuffer
>& buffer
) {
126 output_timestamp_helper_
.AddFrames(buffer
->frame_count());
127 output_buffers_
.push_back(buffer
);