Skip to content

Commit

Permalink
Add compatibility with FFMPEG 7.0
Browse files Browse the repository at this point in the history
channel_layout has been replaced with ch_layout

Fix #953
  • Loading branch information
eclipseo committed May 9, 2024
1 parent a9e34a9 commit 08d7f33
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 15 deletions.
30 changes: 25 additions & 5 deletions src/FFmpegReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -671,8 +671,13 @@ bool FFmpegReader::HasAlbumArt() {

void FFmpegReader::UpdateAudioInfo() {
// Set default audio channel layout (if needed)
#if HAVE_CH_LAYOUT
if (!av_channel_layout_check(&(AV_GET_CODEC_ATTRIBUTES(aStream, aCodecCtx)->ch_layout)))
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
Expand All @@ -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) {
Expand Down Expand Up @@ -1593,11 +1603,16 @@ void FFmpegReader::ProcessAudioPacket(int64_t requested_frame) {

// determine how many samples were decoded
int plane_size = -1;
data_size = av_samples_get_buffer_size(&plane_size, AV_GET_CODEC_ATTRIBUTES(aStream, aCodecCtx)->channels,
#if HAVE_CH_LAYOUT
int nb_channels = AV_GET_CODEC_ATTRIBUTES(aStream, aCodecCtx)->ch_layout.nb_channels;
#else
int nb_channels = AV_GET_CODEC_ATTRIBUTES(aStream, aCodecCtx)->channels;
#endif
data_size = av_samples_get_buffer_size(&plane_size, 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)->channels;
packet_samples = audio_frame->nb_samples * nb_channels;
} else {
if (audio_frame) {
// Free audio frame
Expand Down Expand Up @@ -1655,14 +1670,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
Expand Down
4 changes: 3 additions & 1 deletion src/FFmpegUtilities.h
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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 <libavcodec/avcodec.h>
Expand Down
81 changes: 72 additions & 9 deletions src/FFmpegWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -1042,7 +1042,9 @@ AVStream *FFmpegWriter::add_audio_stream() {

// Set the sample parameters
c->bit_rate = info.audio_bit_rate;
#if !HAVE_CH_LAYOUT
c->channels = info.channels;
#endif

// Set valid sample rate (or throw error)
if (codec->supported_samplerates) {
Expand All @@ -1060,6 +1062,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; av_channel_layout_check(&codec->ch_layouts[i]); 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 (!av_channel_layout_check(&codec->ch_layouts[i]))
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) {
Expand All @@ -1075,6 +1095,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) {
Expand All @@ -1100,13 +1121,30 @@ AVStream *FFmpegWriter::add_audio_stream() {

AV_COPY_PARAMS_FROM_CONTEXT(st, c);

int nb_channels;
uint64_t channel_layout;
const char* nb_channels_label;
const char* channel_layout_label;

#if HAVE_CH_LAYOUT
nb_channels = c->ch_layout.nb_channels;
channel_layout = c->ch_layout.u.mask;
nb_channels_label = "c->ch_layout.nb_channels";
channel_layout_label = "c->ch_layout.u.mask";
#else
nb_channels = c->channels;
channel_layout = c->channel_layout;
nb_channels_label = "c->channels";
channel_layout_label = "c->channel_layout";
#endif

ZmqLogger::Instance()->AppendDebugMethod(
"FFmpegWriter::add_audio_stream",
"c->codec_id", c->codec_id,
"c->bit_rate", c->bit_rate,
"c->channels", c->channels,
nb_channels_label, nb_channels,
"c->sample_fmt", c->sample_fmt,
"c->channel_layout", c->channel_layout,
channel_layout_label, channel_layout,
"c->sample_rate", c->sample_rate);

return st;
Expand Down Expand Up @@ -1665,14 +1703,23 @@ void FFmpegWriter::write_audio_packets(bool is_final, std::shared_ptr<openshot::
// setup resample context
if (!avr) {
avr = SWR_ALLOC();
#if HAVE_CH_LAYOUT
AVChannelLayout in_chlayout;
AVChannelLayout out_chlayout;
av_channel_layout_from_mask(&in_chlayout, channel_layout_in_frame);
av_channel_layout_from_mask(&out_chlayout, info.channel_layout);
av_opt_set_chlayout(avr, "in_chlayout", &in_chlayout, 0);
av_opt_set_chlayout(avr, "out_chlayout", &out_chlayout, 0);
#else
av_opt_set_int(avr, "in_channel_layout", channel_layout_in_frame, 0);
av_opt_set_int(avr, "out_channel_layout", info.channel_layout, 0);
av_opt_set_int(avr, "in_channels", channels_in_frame, 0);
av_opt_set_int(avr, "out_channels", info.channels, 0);
#endif
av_opt_set_int(avr, "in_sample_fmt", AV_SAMPLE_FMT_S16, 0);
av_opt_set_int(avr, "out_sample_fmt", output_sample_fmt, 0); // planar not allowed here
av_opt_set_int(avr, "in_sample_rate", sample_rate_in_frame, 0);
av_opt_set_int(avr, "out_sample_rate", info.sample_rate, 0);
av_opt_set_int(avr, "in_channels", channels_in_frame, 0);
av_opt_set_int(avr, "out_channels", info.channels, 0);
SWR_INIT(avr);
}
// Convert audio samples
Expand Down Expand Up @@ -1768,14 +1815,21 @@ void FFmpegWriter::write_audio_packets(bool is_final, std::shared_ptr<openshot::
// setup resample context
if (!avr_planar) {
avr_planar = SWR_ALLOC();
#if HAVE_CH_LAYOUT
AVChannelLayout layout;
av_channel_layout_from_mask(&layout, info.channel_layout);
av_opt_set_chlayout(avr_planar, "in_chlayout", &layout, 0);
av_opt_set_chlayout(avr_planar, "out_chlayout", &layout, 0);
#else
av_opt_set_int(avr_planar, "in_channel_layout", info.channel_layout, 0);
av_opt_set_int(avr_planar, "out_channel_layout", info.channel_layout, 0);
av_opt_set_int(avr_planar, "in_channels", info.channels, 0);
av_opt_set_int(avr_planar, "out_channels", info.channels, 0);
#endif
av_opt_set_int(avr_planar, "in_sample_fmt", output_sample_fmt, 0);
av_opt_set_int(avr_planar, "out_sample_fmt", audio_codec_ctx->sample_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);
}

Expand Down Expand Up @@ -1803,9 +1857,13 @@ void FFmpegWriter::write_audio_packets(bool is_final, std::shared_ptr<openshot::

// Create output frame (and allocate arrays)
frame_final->nb_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);

Expand Down Expand Up @@ -1854,7 +1912,12 @@ void FFmpegWriter::write_audio_packets(bool is_final, std::shared_ptr<openshot::
frame_final->nb_samples = audio_input_frame_size;

// Fill the final_frame AVFrame with audio (non planar)
avcodec_fill_audio_frame(frame_final, audio_codec_ctx->channels,
#if HAVE_CH_LAYOUT
int nb_channels = audio_codec_ctx->ch_layout.nb_channels;
#else
int nb_channels = audio_codec_ctx->channels;
#endif
avcodec_fill_audio_frame(frame_final, nb_channels,
audio_codec_ctx->sample_fmt, (uint8_t *) final_samples,
audio_encoder_buffer_size, 0);
}
Expand Down

0 comments on commit 08d7f33

Please sign in to comment.