From ff78c63580e9f5bea116507ac943e9540f9e3697 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert-Andr=C3=A9=20Mauchin?= Date: Wed, 8 May 2024 12:16:41 +0200 Subject: [PATCH] Add compatibility with FFMPEG 7.0 channel_layout has been replaced with ch_layout Fix #953 --- src/FFmpegReader.cpp | 29 ++++++++++++++++-- src/FFmpegUtilities.h | 4 ++- src/FFmpegWriter.cpp | 68 +++++++++++++++++++++++++++++++++++++++---- 3 files changed, 91 insertions(+), 10 deletions(-) diff --git a/src/FFmpegReader.cpp b/src/FFmpegReader.cpp index 67647d126..78fa5833c 100644 --- a/src/FFmpegReader.cpp +++ b/src/FFmpegReader.cpp @@ -9,7 +9,7 @@ * @ref License */ -// Copyright (c) 2008-2019 OpenShot Studios, LLC, Fabrice Bellard +// Copyright (c) 2008-2024 OpenShot Studios, LLC, Fabrice Bellard // // SPDX-License-Identifier: LGPL-3.0-or-later @@ -671,8 +671,13 @@ bool FFmpegReader::HasAlbumArt() { void FFmpegReader::UpdateAudioInfo() { // Set default audio channel layout (if needed) +#if HAVE_CH_LAYOUT + if (!AV_GET_CODEC_ATTRIBUTES(aStream, aCodecCtx)->ch_layout.nb_channels) + AV_GET_CODEC_ATTRIBUTES(aStream, aCodecCtx)->ch_layout = (AVChannelLayout) AV_CHANNEL_LAYOUT_STEREO; +#else if (AV_GET_CODEC_ATTRIBUTES(aStream, aCodecCtx)->channel_layout == 0) AV_GET_CODEC_ATTRIBUTES(aStream, aCodecCtx)->channel_layout = av_get_default_channel_layout(AV_GET_CODEC_ATTRIBUTES(aStream, aCodecCtx)->channels); +#endif if (info.sample_rate > 0) { // Skip init - if info struct already populated @@ -683,8 +688,13 @@ void FFmpegReader::UpdateAudioInfo() { info.has_audio = true; info.file_size = pFormatCtx->pb ? avio_size(pFormatCtx->pb) : -1; info.acodec = aCodecCtx->codec->name; +#if HAVE_CH_LAYOUT + info.channels = AV_GET_CODEC_ATTRIBUTES(aStream, aCodecCtx)->ch_layout.nb_channels; + info.channel_layout = (ChannelLayout) AV_GET_CODEC_ATTRIBUTES(aStream, aCodecCtx)->ch_layout.u.mask; +#else info.channels = AV_GET_CODEC_ATTRIBUTES(aStream, aCodecCtx)->channels; info.channel_layout = (ChannelLayout) AV_GET_CODEC_ATTRIBUTES(aStream, aCodecCtx)->channel_layout; +#endif info.sample_rate = AV_GET_CODEC_ATTRIBUTES(aStream, aCodecCtx)->sample_rate; info.audio_bit_rate = AV_GET_CODEC_ATTRIBUTES(aStream, aCodecCtx)->bit_rate; if (info.audio_bit_rate <= 0) { @@ -1593,11 +1603,19 @@ void FFmpegReader::ProcessAudioPacket(int64_t requested_frame) { // determine how many samples were decoded int plane_size = -1; +#if HAVE_CH_LAYOUT + data_size = av_samples_get_buffer_size(&plane_size, AV_GET_CODEC_ATTRIBUTES(aStream, aCodecCtx)->ch_layout.nb_channels, + audio_frame->nb_samples, (AVSampleFormat) (AV_GET_SAMPLE_FORMAT(aStream, aCodecCtx)), 1); + + // Calculate total number of samples + packet_samples = audio_frame->nb_samples * AV_GET_CODEC_ATTRIBUTES(aStream, aCodecCtx)->ch_layout.nb_channels; +#else data_size = av_samples_get_buffer_size(&plane_size, AV_GET_CODEC_ATTRIBUTES(aStream, aCodecCtx)->channels, audio_frame->nb_samples, (AVSampleFormat) (AV_GET_SAMPLE_FORMAT(aStream, aCodecCtx)), 1); // Calculate total number of samples packet_samples = audio_frame->nb_samples * AV_GET_CODEC_ATTRIBUTES(aStream, aCodecCtx)->channels; +#endif } else { if (audio_frame) { // Free audio frame @@ -1655,14 +1673,19 @@ void FFmpegReader::ProcessAudioPacket(int64_t requested_frame) { // setup resample context avr = SWR_ALLOC(); +#if HAVE_CH_LAYOUT + av_opt_set_chlayout(avr, "in_chlayout", &AV_GET_CODEC_ATTRIBUTES(aStream, aCodecCtx)->ch_layout, 0); + av_opt_set_chlayout(avr, "out_chlayout", &AV_GET_CODEC_ATTRIBUTES(aStream, aCodecCtx)->ch_layout, 0); +#else av_opt_set_int(avr, "in_channel_layout", AV_GET_CODEC_ATTRIBUTES(aStream, aCodecCtx)->channel_layout, 0); av_opt_set_int(avr, "out_channel_layout", AV_GET_CODEC_ATTRIBUTES(aStream, aCodecCtx)->channel_layout, 0); + av_opt_set_int(avr, "in_channels", info.channels, 0); + av_opt_set_int(avr, "out_channels", info.channels, 0); +#endif av_opt_set_int(avr, "in_sample_fmt", AV_GET_SAMPLE_FORMAT(aStream, aCodecCtx), 0); av_opt_set_int(avr, "out_sample_fmt", AV_SAMPLE_FMT_FLTP, 0); av_opt_set_int(avr, "in_sample_rate", info.sample_rate, 0); av_opt_set_int(avr, "out_sample_rate", info.sample_rate, 0); - av_opt_set_int(avr, "in_channels", info.channels, 0); - av_opt_set_int(avr, "out_channels", info.channels, 0); SWR_INIT(avr); // Convert audio samples diff --git a/src/FFmpegUtilities.h b/src/FFmpegUtilities.h index f1f424ab4..39018a39b 100644 --- a/src/FFmpegUtilities.h +++ b/src/FFmpegUtilities.h @@ -6,7 +6,7 @@ * @ref License */ -// Copyright (c) 2008-2019 OpenShot Studios, LLC +// Copyright (c) 2008-2024 OpenShot Studios, LLC // // SPDX-License-Identifier: LGPL-3.0-or-later @@ -33,6 +33,8 @@ #define USE_SW FFMPEG_USE_SWRESAMPLE #endif +#define HAVE_CH_LAYOUT (LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(57, 28, 100)) + // Include the FFmpeg headers extern "C" { #include diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp index eea372743..394038131 100644 --- a/src/FFmpegWriter.cpp +++ b/src/FFmpegWriter.cpp @@ -9,7 +9,7 @@ * @ref License */ -// Copyright (c) 2008-2019 OpenShot Studios, LLC, Fabrice Bellard +// Copyright (c) 2008-2024 OpenShot Studios, LLC, Fabrice Bellard // // SPDX-License-Identifier: LGPL-3.0-or-later @@ -1060,6 +1060,24 @@ AVStream *FFmpegWriter::add_audio_stream() { c->sample_rate = info.sample_rate; +#if HAVE_CH_LAYOUT + // Set a valid number of channels (or throw error) + AVChannelLayout ch_layout; + av_channel_layout_from_mask(&ch_layout, info.channel_layout); + if (codec->ch_layouts) { + int i; + for (i = 0; codec->ch_layouts[i].nb_channels; i++) + if (av_channel_layout_compare(&ch_layout, &codec->ch_layouts[i])) { + // Set valid channel layout + av_channel_layout_copy(&c->ch_layout, &ch_layout); + break; + } + if (!codec->ch_layouts[i].nb_channels) + throw InvalidChannels("An invalid channel layout was detected (i.e. MONO / STEREO).", path); + } else + // Set valid channel layout + av_channel_layout_copy(&c->ch_layout, &ch_layout); +#else // Set a valid number of channels (or throw error) const uint64_t channel_layout = info.channel_layout; if (codec->channel_layouts) { @@ -1075,6 +1093,7 @@ AVStream *FFmpegWriter::add_audio_stream() { } else // Set valid channel layout c->channel_layout = channel_layout; +#endif // Choose a valid sample_fmt if (codec->sample_fmts) { @@ -1100,6 +1119,16 @@ AVStream *FFmpegWriter::add_audio_stream() { AV_COPY_PARAMS_FROM_CONTEXT(st, c); +#if HAVE_CH_LAYOUT + ZmqLogger::Instance()->AppendDebugMethod( + "FFmpegWriter::add_audio_stream", + "c->codec_id", c->codec_id, + "c->bit_rate", c->bit_rate, + "c->ch_layout.nb_channels", c->ch_layout.nb_channels, + "c->sample_fmt", c->sample_fmt, + "c->ch_layout.u.mask", c->ch_layout.u.mask, + "c->sample_rate", c->sample_rate); +#else ZmqLogger::Instance()->AppendDebugMethod( "FFmpegWriter::add_audio_stream", "c->codec_id", c->codec_id, @@ -1108,6 +1137,7 @@ AVStream *FFmpegWriter::add_audio_stream() { "c->sample_fmt", c->sample_fmt, "c->channel_layout", c->channel_layout, "c->sample_rate", c->sample_rate); +#endif return st; } @@ -1665,14 +1695,23 @@ void FFmpegWriter::write_audio_packets(bool is_final, std::shared_ptrsample_fmt, 0); // planar not allowed here av_opt_set_int(avr_planar, "in_sample_rate", info.sample_rate, 0); av_opt_set_int(avr_planar, "out_sample_rate", info.sample_rate, 0); - av_opt_set_int(avr_planar, "in_channels", info.channels, 0); - av_opt_set_int(avr_planar, "out_channels", info.channels, 0); SWR_INIT(avr_planar); } @@ -1803,9 +1849,13 @@ void FFmpegWriter::write_audio_packets(bool is_final, std::shared_ptrnb_samples = audio_input_frame_size; +#if HAVE_CH_LAYOUT + av_channel_layout_from_mask(&frame_final->ch_layout, info.channel_layout); +#else frame_final->channels = info.channels; - frame_final->format = audio_codec_ctx->sample_fmt; frame_final->channel_layout = info.channel_layout; +#endif + frame_final->format = audio_codec_ctx->sample_fmt; av_samples_alloc(frame_final->data, frame_final->linesize, info.channels, frame_final->nb_samples, audio_codec_ctx->sample_fmt, 0); @@ -1854,9 +1904,15 @@ void FFmpegWriter::write_audio_packets(bool is_final, std::shared_ptrnb_samples = audio_input_frame_size; // Fill the final_frame AVFrame with audio (non planar) +#if HAVE_CH_LAYOUT + avcodec_fill_audio_frame(frame_final, audio_codec_ctx->ch_layout.nb_channels, + audio_codec_ctx->sample_fmt, (uint8_t *) final_samples, + audio_encoder_buffer_size, 0); +#else avcodec_fill_audio_frame(frame_final, audio_codec_ctx->channels, audio_codec_ctx->sample_fmt, (uint8_t *) final_samples, audio_encoder_buffer_size, 0); +#endif } // Set the AVFrame's PTS