diff --git a/rwengine/src/audio/SoundSource.cpp b/rwengine/src/audio/SoundSource.cpp index d355cab74..819688e44 100644 --- a/rwengine/src/audio/SoundSource.cpp +++ b/rwengine/src/audio/SoundSource.cpp @@ -10,17 +10,12 @@ extern "C" { #include } -// Rename some functions for older libavcodec/ffmpeg versions (e.g. Ubuntu -// Trusty) -#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(55, 28, 1) -#define av_frame_alloc avcodec_alloc_frame -#define av_frame_free avcodec_free_frame -#endif - #if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(57, 80, 100) #define avio_context_free av_freep #endif +#define HAVE_CH_LAYOUT (LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(57, 28, 100)) + constexpr int kNumOutputChannels = 2; constexpr AVSampleFormat kOutputFMT = AV_SAMPLE_FMT_S16; constexpr size_t kNrFramesToPreload = 50; @@ -207,7 +202,6 @@ bool SoundSource::prepareCodecContext() { // Fill the codecCtx with the parameters of the codec used in the read file. if (avcodec_parameters_to_context(codecContext, audioStream->codecpar) != 0) { - avcodec_close(codecContext); avcodec_free_context(&codecContext); avformat_close_input(&formatContext); RW_ERROR("Couldn't find parametrs for context"); @@ -216,7 +210,6 @@ bool SoundSource::prepareCodecContext() { // Initialize the decoder. if (avcodec_open2(codecContext, codec, nullptr) != 0) { - avcodec_close(codecContext); avcodec_free_context(&codecContext); avformat_close_input(&formatContext); RW_ERROR("Couldn't open the audio codec context"); @@ -250,7 +243,6 @@ bool SoundSource::prepareCodecContextSfx() { 0) { av_free(formatContext->pb->buffer); avio_context_free(&formatContext->pb); - avcodec_close(codecContext); avcodec_free_context(&codecContext); avformat_close_input(&formatContext); RW_ERROR("Couldn't find parametrs for context"); @@ -261,7 +253,6 @@ bool SoundSource::prepareCodecContextSfx() { if (avcodec_open2(codecContext, codec, nullptr) != 0) { av_free(formatContext->pb->buffer); avio_context_free(&formatContext->pb); - avcodec_close(codecContext); avcodec_free_context(&codecContext); avformat_close_input(&formatContext); RW_ERROR("Couldn't open the audio codec context"); @@ -274,9 +265,9 @@ bool SoundSource::prepareCodecContextSfx() { #if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(57, 37, 100) void SoundSource::decodeFramesLegacy(size_t framesToDecode) { while ((framesToDecode == 0 || decodedFrames < framesToDecode) && - av_read_frame(formatContext, &readingPacket) == 0) { - if (readingPacket.stream_index == audioStream->index) { - AVPacket decodingPacket = readingPacket; + av_read_frame(formatContext, readingPacket) == 0) { + if (readingPacket->stream_index == audioStream->index) { + AVPacket decodingPacket = *readingPacket; while (decodingPacket.size > 0) { // Decode audio packet @@ -306,7 +297,7 @@ void SoundSource::decodeFramesLegacy(size_t framesToDecode) { } } } - av_free_packet(&readingPacket); + av_free_packet(readingPacket); ++decodedFrames; } } @@ -322,9 +313,9 @@ void SoundSource::decodeFramesSfxWrap() { void SoundSource::decodeFrames(size_t framesToDecode) { while ((framesToDecode == 0 || decodedFrames < framesToDecode) && - av_read_frame(formatContext, &readingPacket) == 0) { - if (readingPacket.stream_index == audioStream->index) { - AVPacket decodingPacket = readingPacket; + av_read_frame(formatContext, readingPacket) == 0) { + if (readingPacket->stream_index == audioStream->index) { + AVPacket decodingPacket = *readingPacket; int sendPacket = avcodec_send_packet(codecContext, &decodingPacket); int receiveFrame = 0; @@ -349,7 +340,7 @@ void SoundSource::decodeFrames(size_t framesToDecode) { } } } - av_packet_unref(&readingPacket); + av_packet_unref(readingPacket); ++decodedFrames; } } @@ -366,21 +357,38 @@ void SoundSource::decodeAndResampleFrames(const std::filesystem::path& filePath, size_t framesToDecode) { RW_UNUSED(filePath); // it's used by macro AVFrame* resampled = av_frame_alloc(); + int err = 0; while ((framesToDecode == 0 || decodedFrames < framesToDecode) && - av_read_frame(formatContext, &readingPacket) == 0) { - if (readingPacket.stream_index == audioStream->index) { - int sendPacket = avcodec_send_packet(codecContext, &readingPacket); - av_packet_unref(&readingPacket); + av_read_frame(formatContext, readingPacket) == 0) { + if (readingPacket->stream_index == audioStream->index) { + int sendPacket = avcodec_send_packet(codecContext, readingPacket); + av_packet_unref(readingPacket); int receiveFrame = 0; while ((receiveFrame = avcodec_receive_frame(codecContext, frame)) == 0) { if (!swr) { - if (frame->channels == 1 || frame->channel_layout == 0) { +#if HAVE_CH_LAYOUT + AVChannelLayout out_chlayout = AV_CHANNEL_LAYOUT_STEREO; + err = swr_alloc_set_opts2( + &swr, &out_chlayout, kOutputFMT, frame->sample_rate, + &frame->ch_layout, // input channel layout + static_cast( + frame->format), // input format + frame->sample_rate, // input sample rate + 0, nullptr); + + if (err < 0) { + RW_ERROR( + "Resampler has not been successfully allocated."); + return; + } +#else + if (frame->channels == 1 || frame->channel_layout == 0) frame->channel_layout = av_get_default_channel_layout(1); - } + swr = swr_alloc_set_opts( nullptr, AV_CH_LAYOUT_STEREO, // output channel layout @@ -391,6 +399,7 @@ void SoundSource::decodeAndResampleFrames(const std::filesystem::path& filePath, frame->format), // input format frame->sample_rate, // input sample rate 0, nullptr); +#endif if (!swr) { RW_ERROR( "Resampler has not been successfully allocated."); @@ -407,10 +416,14 @@ void SoundSource::decodeAndResampleFrames(const std::filesystem::path& filePath, // Decode audio packet if (receiveFrame == 0 && sendPacket == 0) { // Write samples to audio buffer +#if HAVE_CH_LAYOUT + resampled->ch_layout = AV_CHANNEL_LAYOUT_STEREO; +#else resampled->channel_layout = AV_CH_LAYOUT_STEREO; + resampled->channels = kNumOutputChannels; +#endif resampled->sample_rate = frame->sample_rate; resampled->format = kOutputFMT; - resampled->channels = kNumOutputChannels; swr_config_frame(swr, resampled, frame); @@ -445,10 +458,6 @@ void SoundSource::cleanupAfterSoundLoading() { /// Free all data used by the frame. av_frame_free(&frame); - /// Close the context and free all data associated to it, but not the - /// context itself. - avcodec_close(codecContext); - /// Free the context itself. avcodec_free_context(&codecContext); @@ -460,10 +469,6 @@ void SoundSource::cleanupAfterSfxLoading() { /// Free all data used by the frame. av_frame_free(&frame); - /// Close the context and free all data associated to it, but not the - /// context itself. - avcodec_close(codecContext); - /// Free the context itself. avcodec_free_context(&codecContext); @@ -481,7 +486,11 @@ void SoundSource::exposeSoundMetadata() { } void SoundSource::exposeSfxMetadata(LoaderSDT& sdt) { +#if HAVE_CH_LAYOUT + channels = static_cast(codecContext->ch_layout.nb_channels); +#else channels = static_cast(codecContext->channels); +#endif sampleRate = sdt.assetInfo.sampleRate; } @@ -509,7 +518,7 @@ void SoundSource::loadFromFile(const std::filesystem::path& filePath, bool strea if (allocateAudioFrame() && allocateFormatContext(filePath) && findAudioStream(filePath) && prepareCodecContextWrap()) { exposeSoundMetadata(); - av_init_packet(&readingPacket); + readingPacket = av_packet_alloc(); decodeFramesWrap(filePath); @@ -528,7 +537,7 @@ void SoundSource::loadSfx(LoaderSDT& sdt, size_t index, bool asWave, if (allocateAudioFrame() && prepareFormatContextSfx(sdt, index, asWave) && findAudioStreamSfx() && prepareCodecContextSfxWrap()) { exposeSfxMetadata(sdt); - av_init_packet(&readingPacket); + readingPacket = av_packet_alloc(); decodeFramesSfxWrap(); diff --git a/rwengine/src/audio/SoundSource.hpp b/rwengine/src/audio/SoundSource.hpp index bd618e06b..96d64bb96 100644 --- a/rwengine/src/audio/SoundSource.hpp +++ b/rwengine/src/audio/SoundSource.hpp @@ -93,7 +93,7 @@ class SoundSource { const AVCodec* codec = nullptr; SwrContext* swr = nullptr; AVCodecContext* codecContext = nullptr; - AVPacket readingPacket; + AVPacket* readingPacket; // For sfx AVIOContext* avioContext;