blob: 892c2deb3c3e839c571a0fcd98bad249fe9b59aa [file] [log] [blame]
// Copyright 2017 The Cobalt Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "starboard/common/log.h"
#include "starboard/configuration.h"
#include "starboard/shared/starboard/player/filter/audio_resampler.h"
#include "starboard/shared/starboard/player/filter/interleaved_sinc_resampler.h"
namespace starboard {
namespace shared {
namespace starboard {
namespace player {
namespace filter {
namespace {
// CPU based simple AudioResampler implementation. Note that it currently only
// supports resample audio between same storage type and same channels but with
// different sample types.
class AudioResamplerImpl : public AudioResampler {
public:
AudioResamplerImpl(SbMediaAudioSampleType source_sample_type,
SbMediaAudioFrameStorageType source_storage_type,
int source_sample_rate,
SbMediaAudioSampleType destination_sample_type,
SbMediaAudioFrameStorageType destination_storage_type,
int destination_sample_rate,
int channels)
: source_sample_type_(source_sample_type),
source_storage_type_(source_storage_type),
destination_sample_type_(destination_sample_type),
destination_storage_type_(destination_storage_type),
interleaved_resampler_(static_cast<double>(source_sample_rate) /
static_cast<double>(destination_sample_rate),
channels) {}
scoped_refptr<DecodedAudio> Resample(
const scoped_refptr<DecodedAudio>& buffer) override;
scoped_refptr<DecodedAudio> WriteEndOfStream() override;
private:
InterleavedSincResampler interleaved_resampler_;
SbMediaAudioSampleType source_sample_type_;
SbMediaAudioFrameStorageType source_storage_type_;
SbMediaAudioSampleType destination_sample_type_;
SbMediaAudioFrameStorageType destination_storage_type_;
size_t frames_to_resample_ = 0;
size_t frames_resampled_ = 0;
};
} // namespace
// static
scoped_ptr<AudioResampler> AudioResampler::Create(
SbMediaAudioSampleType source_sample_type,
SbMediaAudioFrameStorageType source_storage_type,
int source_sample_rate,
SbMediaAudioSampleType destination_sample_type,
SbMediaAudioFrameStorageType destination_storage_type,
int destination_sample_rate,
int channels) {
return scoped_ptr<AudioResampler>(new AudioResamplerImpl(
source_sample_type, source_storage_type, source_sample_rate,
destination_sample_type, destination_storage_type,
destination_sample_rate, channels));
}
scoped_refptr<DecodedAudio> AudioResamplerImpl::WriteEndOfStream() {
double sample_rate_ratio = interleaved_resampler_.GetSampleRateRatio();
int out_num_of_frames =
round(frames_to_resample_ / sample_rate_ratio) - frames_resampled_;
if (out_num_of_frames > 0) {
interleaved_resampler_.QueueBuffer(nullptr, 0);
int channels = interleaved_resampler_.channels();
int resampled_audio_size = out_num_of_frames * channels * sizeof(float);
scoped_refptr<DecodedAudio> resampled_audio = new DecodedAudio(
channels, kSbMediaAudioSampleTypeFloat32,
kSbMediaAudioFrameStorageTypeInterleaved, 0, resampled_audio_size);
float* dst = reinterpret_cast<float*>(resampled_audio->buffer());
interleaved_resampler_.Resample(dst, out_num_of_frames);
resampled_audio->SwitchFormatTo(destination_sample_type_,
destination_storage_type_);
return resampled_audio;
}
return new DecodedAudio;
}
scoped_refptr<DecodedAudio> AudioResamplerImpl::Resample(
const scoped_refptr<DecodedAudio>& audio_data) {
SB_DCHECK(audio_data->channels() == interleaved_resampler_.channels());
// It does nothing if source sample type is float and source storage type is
// interleaved.
audio_data->SwitchFormatTo(kSbMediaAudioSampleTypeFloat32,
kSbMediaAudioFrameStorageTypeInterleaved);
int num_of_frames = audio_data->frames();
frames_to_resample_ += num_of_frames;
int channels = audio_data->channels();
int out_num_of_frames = static_cast<int>(
ceil(num_of_frames / interleaved_resampler_.GetSampleRateRatio()));
int resampled_audio_size = out_num_of_frames * channels * sizeof(float);
scoped_refptr<DecodedAudio> resampled_audio = nullptr;
float* samples = reinterpret_cast<float*>(audio_data->buffer());
interleaved_resampler_.QueueBuffer(samples, num_of_frames);
if (interleaved_resampler_.HasEnoughData(out_num_of_frames)) {
resampled_audio =
new DecodedAudio(channels, kSbMediaAudioSampleTypeFloat32,
kSbMediaAudioFrameStorageTypeInterleaved,
audio_data->timestamp(), resampled_audio_size);
float* dst = reinterpret_cast<float*>(resampled_audio->buffer());
interleaved_resampler_.Resample(dst, out_num_of_frames);
frames_resampled_ += out_num_of_frames;
resampled_audio->SwitchFormatTo(destination_sample_type_,
destination_storage_type_);
}
return resampled_audio;
}
} // namespace filter
} // namespace player
} // namespace starboard
} // namespace shared
} // namespace starboard