diff --git a/src/debug_utils.h b/src/debug_utils.h index 5bb3bf0ff07f38c8bb4c7c22f8e5edd294eadc9b..3807bae31636b4c10ff2c312589adbcc5805eb2d 100644 --- a/src/debug_utils.h +++ b/src/debug_utils.h @@ -160,6 +160,7 @@ private: output->format = AV_SAMPLE_FMT_S64; output->sample_rate = input->sample_rate; output->channel_layout = input->channel_layout; + output->channels = input->channels; resampler_->resample(input, output); av_frame_unref(input); av_frame_move_ref(frame, output); diff --git a/src/media/audio/audiobuffer.h b/src/media/audio/audiobuffer.h index 47bf07843b5fc8c46c4525b40878192815f9a61b..a79f4cfe4b74524eb51454445c6a53c32c63c67d 100644 --- a/src/media/audio/audiobuffer.h +++ b/src/media/audio/audiobuffer.h @@ -57,6 +57,12 @@ struct AudioFormat { , sampleFormat(AV_SAMPLE_FMT_S16) {} + constexpr AudioFormat(unsigned sr, unsigned c, AVSampleFormat f) + : sample_rate(sr) + , nb_channels(c) + , sampleFormat(f) + {} + inline bool operator == (const AudioFormat &b) const { return ( (b.sample_rate == sample_rate) && (b.nb_channels == nb_channels) && diff --git a/src/media/audio/resampler.cpp b/src/media/audio/resampler.cpp index 3424d5e7085fd9db266f9cc6ea1c920e0c8ff6ca..d61741a6780e14558caf76c327bf59909d2dd5f5 100644 --- a/src/media/audio/resampler.cpp +++ b/src/media/audio/resampler.cpp @@ -35,6 +35,7 @@ namespace ring { Resampler::Resampler() : swrCtx_(swr_alloc()) + , initialized_(false) {} Resampler::~Resampler() @@ -43,29 +44,33 @@ Resampler::~Resampler() } void -Resampler::reinit(const AudioFormat& in, const int inSampleFmt, - const AudioFormat& out, const int outSampleFmt) +Resampler::reinit(const AudioFormat& in, const AudioFormat& out) { - av_opt_set_int(swrCtx_, "ich", 0, 0); + av_opt_set_int(swrCtx_, "ich", in.nb_channels, 0); av_opt_set_int(swrCtx_, "icl", av_get_default_channel_layout(in.nb_channels), 0); av_opt_set_int(swrCtx_, "isr", in.sample_rate, 0); - av_opt_set_sample_fmt(swrCtx_, "isf", static_cast<AVSampleFormat>(inSampleFmt), 0); + av_opt_set_sample_fmt(swrCtx_, "isf", in.sampleFormat, 0); - av_opt_set_int(swrCtx_, "och", 0, 0); + av_opt_set_int(swrCtx_, "och", out.nb_channels, 0); av_opt_set_int(swrCtx_, "ocl", av_get_default_channel_layout(out.nb_channels), 0); av_opt_set_int(swrCtx_, "osr", out.sample_rate, 0); - av_opt_set_sample_fmt(swrCtx_, "osf", static_cast<AVSampleFormat>(outSampleFmt), 0); + av_opt_set_sample_fmt(swrCtx_, "osf", out.sampleFormat, 0); swr_init(swrCtx_); + initialized_ = true; } int Resampler::resample(const AVFrame* input, AVFrame* output) { + const auto inFmt = AudioFormat((unsigned)input->sample_rate, (unsigned)input->channels, (AVSampleFormat)input->format); + const auto outFmt = AudioFormat((unsigned)output->sample_rate, (unsigned)output->channels, (AVSampleFormat)output->format); + if (!initialized_) + reinit(inFmt, outFmt); + int ret = swr_convert_frame(swrCtx_, output, input); if (ret & AVERROR_INPUT_CHANGED || ret & AVERROR_OUTPUT_CHANGED) { - reinit(AudioFormat{(unsigned)input->sample_rate, (unsigned)input->channels}, input->format, - AudioFormat{(unsigned)output->sample_rate, (unsigned)output->channels}, output->format); + reinit(inFmt, outFmt); return resample(input, output); } else if (ret < 0) { RING_ERR() << "Failed to resample frame"; @@ -84,6 +89,7 @@ Resampler::resample(const AudioBuffer& dataIn, AudioBuffer& dataOut) auto output = resampled.pointer(); output->sample_rate = dataOut.getSampleRate(); output->channel_layout = av_get_default_channel_layout(dataOut.channels()); + output->channels = dataOut.channels(); output->format = AV_SAMPLE_FMT_S16; if (resample(input, output) < 0) diff --git a/src/media/audio/resampler.h b/src/media/audio/resampler.h index 57dc99bc6550c984431a125c057c8a99af0aa423..9ab237899edfeef19358b10937b7350495807939 100644 --- a/src/media/audio/resampler.h +++ b/src/media/audio/resampler.h @@ -59,10 +59,10 @@ class Resampler { * output buffers always have the same formats, will never be called, as the first * initialization is done in swr_convert_frame. */ - void reinit(const AudioFormat& in, const int inSampleFmt, - const AudioFormat& out, const int outSampleFmt); + void reinit(const AudioFormat& in, const AudioFormat& out); SwrContext* swrCtx_; // incomplete type, cannot be a unique_ptr + bool initialized_; }; } // namespace ring diff --git a/src/media/audio/sound/audiofile.cpp b/src/media/audio/sound/audiofile.cpp index 214d665b58255f025737b865b6254ab63d50dfc1..e4a5d6cc32988c46497694a20871f5584a3e7eaa 100644 --- a/src/media/audio/sound/audiofile.cpp +++ b/src/media/audio/sound/audiofile.cpp @@ -70,7 +70,8 @@ AudioFile::AudioFile(const std::string &fileName, unsigned int sampleRate) : throw AudioFileException("Decoder setup failed: " + fileName); auto resampler = std::make_unique<Resampler>(); - auto buf = std::make_unique<AudioBuffer>(0, getFormat()); + const auto& format = getFormat(); + auto buf = std::make_unique<AudioBuffer>(0, format); bool done = false; while (!done) { AudioFrame input; @@ -78,9 +79,10 @@ AudioFile::AudioFile(const std::string &fileName, unsigned int sampleRate) : auto resampled = output.pointer(); switch (decoder->decode(input)) { case MediaDecoder::Status::FrameFinished: - resampled->sample_rate = getFormat().sample_rate; - resampled->channel_layout = av_get_default_channel_layout(getFormat().nb_channels); - resampled->format = AV_SAMPLE_FMT_S16; + resampled->sample_rate = format.sample_rate; + resampled->channel_layout = av_get_default_channel_layout(format.nb_channels); + resampled->channels = format.nb_channels; + resampled->format = format.sampleFormat; if (resampler->resample(input.pointer(), resampled) < 0) throw AudioFileException("Frame could not be resampled"); if (buf->append(output) < 0) diff --git a/test/unitTest/media/audio/test_resampler.cpp b/test/unitTest/media/audio/test_resampler.cpp index 90d6ecc5dea17771f3bb355fd77d45060513f1a6..ffa8873d665b04fb425a485a8403c93d7d9e282b 100644 --- a/test/unitTest/media/audio/test_resampler.cpp +++ b/test/unitTest/media/audio/test_resampler.cpp @@ -97,6 +97,7 @@ ResamplerTest::testAudioFrame() output->format = AV_SAMPLE_FMT_FLT; output->sample_rate = 48000; output->channel_layout = AV_CH_LAYOUT_STEREO; + output->channels = 2; int ret = resampler_->resample(input->pointer(), output); CPPUNIT_ASSERT_MESSAGE(libav_utils::getError(ret).c_str(), ret >= 0);