Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
88 changes: 74 additions & 14 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 @@ -1059,9 +1061,26 @@ AVStream *FFmpegWriter::add_audio_stream() {
// Set sample rate
c->sample_rate = info.sample_rate;


uint64_t channel_layout = info.channel_layout;
#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) {
int i;
for (i = 0; codec->channel_layouts[i] != 0; i++)
Expand All @@ -1072,9 +1091,10 @@ AVStream *FFmpegWriter::add_audio_stream() {
}
if (codec->channel_layouts[i] == 0)
throw InvalidChannels("An invalid channel layout was detected (i.e. MONO / STEREO).", path);
} else
// Set valid channel layout
c->channel_layout = channel_layout;
} else
// Set valid channel layout
c->channel_layout = channel_layout;
#endif

// Choose a valid sample_fmt
if (codec->sample_fmts) {
Expand All @@ -1100,13 +1120,28 @@ AVStream *FFmpegWriter::add_audio_stream() {

AV_COPY_PARAMS_FROM_CONTEXT(st, c);

int nb_channels;
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;
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 +1700,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 +1812,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 +1854,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 +1909,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