audio_splicer.cc revision eb525c5499e34cc9c4b825d6d9e75bb07cc06ace
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.
4
5#include "media/base/audio_splicer.h"
6
7#include <cstdlib>
8
9#include "base/logging.h"
10#include "media/base/audio_decoder_config.h"
11#include "media/base/audio_timestamp_helper.h"
12#include "media/base/buffers.h"
13#include "media/base/data_buffer.h"
14
15namespace media {
16
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.
21static const int kMaxTimeDeltaInMilliseconds = 50;
22
23AudioSplicer::AudioSplicer(int bytes_per_frame, int samples_per_second)
24    : output_timestamp_helper_(bytes_per_frame, samples_per_second),
25      min_gap_size_(2 * bytes_per_frame),
26      received_end_of_stream_(false) {
27}
28
29AudioSplicer::~AudioSplicer() {
30}
31
32void AudioSplicer::Reset() {
33  output_timestamp_helper_.SetBaseTimestamp(kNoTimestamp());
34  output_buffers_.clear();
35  received_end_of_stream_ = false;
36}
37
38bool AudioSplicer::AddInput(const scoped_refptr<DataBuffer>& input){
39  DCHECK(!received_end_of_stream_ || input->end_of_stream());
40
41  if (input->end_of_stream()) {
42    output_buffers_.push_back(input);
43    received_end_of_stream_ = true;
44    return true;
45  }
46
47  DCHECK(input->timestamp() != kNoTimestamp());
48  DCHECK(input->duration() > base::TimeDelta());
49  DCHECK_GT(input->data_size(), 0);
50
51  if (output_timestamp_helper_.base_timestamp() == kNoTimestamp())
52    output_timestamp_helper_.SetBaseTimestamp(input->timestamp());
53
54  if (output_timestamp_helper_.base_timestamp() > input->timestamp()) {
55    DVLOG(1) << "Input timestamp is before the base timestamp.";
56    return false;
57  }
58
59  base::TimeDelta timestamp = input->timestamp();
60  base::TimeDelta expected_timestamp = output_timestamp_helper_.GetTimestamp();
61  base::TimeDelta delta = timestamp - expected_timestamp;
62
63  if (std::abs(delta.InMilliseconds()) > kMaxTimeDeltaInMilliseconds) {
64    DVLOG(1) << "Timestamp delta too large: " << delta.InMicroseconds() << "us";
65    return false;
66  }
67
68  int bytes_to_fill = 0;
69  if (delta != base::TimeDelta())
70    bytes_to_fill = output_timestamp_helper_.GetBytesToTarget(timestamp);
71
72  if (bytes_to_fill == 0 || std::abs(bytes_to_fill) < min_gap_size_) {
73    AddOutputBuffer(input);
74    return true;
75  }
76
77  if (bytes_to_fill > 0) {
78    DVLOG(1) << "Gap detected @ " << expected_timestamp.InMicroseconds()
79             << " us: " << delta.InMicroseconds() << " us";
80
81    // Create a buffer with enough silence samples to fill the gap and
82    // add it to the output buffer.
83    scoped_refptr<DataBuffer> gap = new DataBuffer(bytes_to_fill);
84    gap->set_data_size(bytes_to_fill);
85    memset(gap->writable_data(), 0, bytes_to_fill);
86    gap->set_timestamp(expected_timestamp);
87    gap->set_duration(output_timestamp_helper_.GetDuration(bytes_to_fill));
88    AddOutputBuffer(gap);
89
90    // Add the input buffer now that the gap has been filled.
91    AddOutputBuffer(input);
92    return true;
93  }
94
95  int bytes_to_skip = -bytes_to_fill;
96
97  DVLOG(1) << "Overlap detected @ " << expected_timestamp.InMicroseconds()
98           << " us: "  << -delta.InMicroseconds() << " us";
99
100  if (input->data_size() <= bytes_to_skip) {
101    DVLOG(1) << "Dropping whole buffer";
102    return true;
103  }
104
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.
107  //
108  // TODO(acolwell): Implement a cross-fade here so the transition is less
109  // jarring.
110  int new_buffer_size = input->data_size() - bytes_to_skip;
111
112  scoped_refptr<DataBuffer> new_buffer = new DataBuffer(new_buffer_size);
113  new_buffer->set_data_size(new_buffer_size);
114  memcpy(new_buffer->writable_data(),
115         input->data() + bytes_to_skip,
116         new_buffer_size);
117  new_buffer->set_timestamp(expected_timestamp);
118  new_buffer->set_duration(
119      output_timestamp_helper_.GetDuration(new_buffer_size));
120  AddOutputBuffer(new_buffer);
121  return true;
122}
123
124bool AudioSplicer::HasNextBuffer() const {
125  return !output_buffers_.empty();
126}
127
128scoped_refptr<DataBuffer> AudioSplicer::GetNextBuffer() {
129  scoped_refptr<DataBuffer> ret = output_buffers_.front();
130  output_buffers_.pop_front();
131  return ret;
132}
133
134void AudioSplicer::AddOutputBuffer(const scoped_refptr<DataBuffer>& buffer) {
135  output_timestamp_helper_.AddBytes(buffer->data_size());
136  output_buffers_.push_back(buffer);
137}
138
139}  // namespace media
140