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