12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file.
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "media/base/audio_splicer.h"
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <cstdlib>
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/logging.h"
107dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "media/base/audio_buffer.h"
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "media/base/audio_decoder_config.h"
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "media/base/audio_timestamp_helper.h"
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "media/base/buffers.h"
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace media {
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Largest gap or overlap allowed by this class. Anything
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// larger than this will trigger an error.
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// This is an arbitrary value, but the initial selection of 50ms
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// roughly represents the duration of 2 compressed AAC or MP3 frames.
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)static const int kMaxTimeDeltaInMilliseconds = 50;
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
237dbb3d5cf0c15f500944d211057644d6a2f37371Ben MurdochAudioSplicer::AudioSplicer(int samples_per_second)
247dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    : output_timestamp_helper_(samples_per_second),
257dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      min_gap_size_(2),
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      received_end_of_stream_(false) {
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)AudioSplicer::~AudioSplicer() {
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AudioSplicer::Reset() {
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  output_timestamp_helper_.SetBaseTimestamp(kNoTimestamp());
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  output_buffers_.clear();
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  received_end_of_stream_ = false;
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
387dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochbool AudioSplicer::AddInput(const scoped_refptr<AudioBuffer>& input) {
39eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  DCHECK(!received_end_of_stream_ || input->end_of_stream());
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
41eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (input->end_of_stream()) {
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    output_buffers_.push_back(input);
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    received_end_of_stream_ = true;
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return true;
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
47eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  DCHECK(input->timestamp() != kNoTimestamp());
48eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  DCHECK(input->duration() > base::TimeDelta());
497dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  DCHECK_GT(input->frame_count(), 0);
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (output_timestamp_helper_.base_timestamp() == kNoTimestamp())
52eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    output_timestamp_helper_.SetBaseTimestamp(input->timestamp());
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
54eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (output_timestamp_helper_.base_timestamp() > input->timestamp()) {
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DVLOG(1) << "Input timestamp is before the base timestamp.";
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
59eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  base::TimeDelta timestamp = input->timestamp();
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::TimeDelta expected_timestamp = output_timestamp_helper_.GetTimestamp();
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::TimeDelta delta = timestamp - expected_timestamp;
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (std::abs(delta.InMilliseconds()) > kMaxTimeDeltaInMilliseconds) {
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DVLOG(1) << "Timestamp delta too large: " << delta.InMicroseconds() << "us";
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
687dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  int frames_to_fill = 0;
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (delta != base::TimeDelta())
707dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    frames_to_fill = output_timestamp_helper_.GetFramesToTarget(timestamp);
712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
727dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (frames_to_fill == 0 || std::abs(frames_to_fill) < min_gap_size_) {
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    AddOutputBuffer(input);
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return true;
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
777dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (frames_to_fill > 0) {
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DVLOG(1) << "Gap detected @ " << expected_timestamp.InMicroseconds()
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)             << " us: " << delta.InMicroseconds() << " us";
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Create a buffer with enough silence samples to fill the gap and
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // add it to the output buffer.
837dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    scoped_refptr<AudioBuffer> gap = AudioBuffer::CreateEmptyBuffer(
847dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        input->channel_count(),
857dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        frames_to_fill,
867dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        expected_timestamp,
877dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        output_timestamp_helper_.GetFrameDuration(frames_to_fill));
882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    AddOutputBuffer(gap);
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Add the input buffer now that the gap has been filled.
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    AddOutputBuffer(input);
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return true;
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
957dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  int frames_to_skip = -frames_to_fill;
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DVLOG(1) << "Overlap detected @ " << expected_timestamp.InMicroseconds()
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)           << " us: "  << -delta.InMicroseconds() << " us";
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1007dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (input->frame_count() <= frames_to_skip) {
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DVLOG(1) << "Dropping whole buffer";
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return true;
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Copy the trailing samples that do not overlap samples already output
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // into a new buffer. Add this new buffer to the output queue.
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // TODO(acolwell): Implement a cross-fade here so the transition is less
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // jarring.
1107dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  input->TrimStart(frames_to_skip);
1117dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  AddOutputBuffer(input);
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool AudioSplicer::HasNextBuffer() const {
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return !output_buffers_.empty();
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1197dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochscoped_refptr<AudioBuffer> AudioSplicer::GetNextBuffer() {
1207dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  scoped_refptr<AudioBuffer> ret = output_buffers_.front();
1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  output_buffers_.pop_front();
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return ret;
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1257dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid AudioSplicer::AddOutputBuffer(const scoped_refptr<AudioBuffer>& buffer) {
1267dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  output_timestamp_helper_.AddFrames(buffer->frame_count());
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  output_buffers_.push_back(buffer);
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace media
131