Fix support for building with ffmpeg < 5.0

Seems like the new audio channel api was not as backwards compatible as we thought.
Therefore we need to reintroduce the usage of the old api to make older ffmpeg version be able to compile Blender.

This change is only intended to stick around for two releases or so. After that we hope that most Linux distros ship
ffmpeg >=5.0 so we can switch to it.

Reviewed By: Sergey

Differential Revision: http://developer.blender.org/D16408
This commit is contained in:
Sebastian Parborg 2022-11-07 17:44:14 +01:00
parent 95631c94c4
commit 3e71220efc
Notes: blender-bot 2023-05-22 08:58:32 +02:00
Referenced by issue #100749, Blender LTS: Maintenance Task 3.3
4 changed files with 49 additions and 14 deletions

View File

@ -6,6 +6,7 @@ if(WITH_GTESTS)
tests/ffmpeg_codecs.cc
)
set(TEST_INC
.
)
set(TEST_INC_SYS
${FFMPEG_INCLUDE_DIRS}

View File

@ -36,6 +36,14 @@
# define FFMPEG_INLINE static inline
#endif
#if (LIBAVFORMAT_VERSION_MAJOR < 59)
/* For versions older than ffmpeg 5.0, use the old channel layout variables.
* We intend to only keep this workaround for around two releases (3.5, 3.6).
* If it sticks around any longer, then we should consider refactoring this.
*/
# define FFMPEG_USE_OLD_CHANNEL_VARS
#endif
#if (LIBAVFORMAT_VERSION_MAJOR < 58) || \
((LIBAVFORMAT_VERSION_MAJOR == 58) && (LIBAVFORMAT_VERSION_MINOR < 76))
# define FFMPEG_USE_DURATION_WORKAROUND 1

View File

@ -3,6 +3,8 @@
#include "testing/testing.h"
extern "C" {
#include "ffmpeg_compat.h"
#include <libavcodec/avcodec.h>
#include <libavutil/channel_layout.h>
#include <libavutil/log.h>
@ -40,7 +42,11 @@ bool test_acodec(const AVCodec *codec, AVSampleFormat fmt)
if (ctx) {
ctx->sample_fmt = fmt;
ctx->sample_rate = 48000;
#ifdef FFMPEG_USE_OLD_CHANNEL_VARS
ctx->channel_layout = AV_CH_LAYOUT_MONO;
#else
av_channel_layout_from_mask(&ctx->ch_layout, AV_CH_LAYOUT_MONO);
#endif
ctx->bit_rate = 128000;
int open = avcodec_open2(ctx, codec, NULL);
if (open >= 0) {

View File

@ -141,18 +141,25 @@ static int write_audio_frame(FFMpegContext *context)
frame->pts = context->audio_time / av_q2d(c->time_base);
frame->nb_samples = context->audio_input_samples;
frame->format = c->sample_fmt;
# ifdef FFMPEG_USE_OLD_CHANNEL_VARS
frame->channels = c->channels;
frame->channel_layout = c->channel_layout;
const int num_channels = c->channels;
# else
av_channel_layout_copy(&frame->ch_layout, &c->ch_layout);
const int num_channels = c->ch_layout.nb_channels;
# endif
if (context->audio_deinterleave) {
int channel, i;
uint8_t *temp;
for (channel = 0; channel < c->ch_layout.nb_channels; channel++) {
for (channel = 0; channel < num_channels; channel++) {
for (i = 0; i < frame->nb_samples; i++) {
memcpy(context->audio_deinterleave_buffer +
(i + channel * frame->nb_samples) * context->audio_sample_size,
context->audio_input_buffer +
(c->ch_layout.nb_channels * i + channel) * context->audio_sample_size,
(num_channels * i + channel) * context->audio_sample_size,
context->audio_sample_size);
}
}
@ -163,10 +170,10 @@ static int write_audio_frame(FFMpegContext *context)
}
avcodec_fill_audio_frame(frame,
c->ch_layout.nb_channels,
num_channels,
c->sample_fmt,
context->audio_input_buffer,
context->audio_input_samples * c->ch_layout.nb_channels *
context->audio_input_samples * num_channels *
context->audio_sample_size,
1);
@ -944,25 +951,34 @@ static AVStream *alloc_audio_stream(FFMpegContext *context,
c->sample_rate = rd->ffcodecdata.audio_mixrate;
c->bit_rate = context->ffmpeg_audio_bitrate * 1000;
c->sample_fmt = AV_SAMPLE_FMT_S16;
c->ch_layout.nb_channels = rd->ffcodecdata.audio_channels;
const int num_channels = rd->ffcodecdata.audio_channels;
int channel_layout_mask = 0;
switch (rd->ffcodecdata.audio_channels) {
case FFM_CHANNELS_MONO:
av_channel_layout_from_mask(&c->ch_layout, AV_CH_LAYOUT_MONO);
channel_layout_mask = AV_CH_LAYOUT_MONO;
break;
case FFM_CHANNELS_STEREO:
av_channel_layout_from_mask(&c->ch_layout, AV_CH_LAYOUT_STEREO);
channel_layout_mask = AV_CH_LAYOUT_STEREO;
break;
case FFM_CHANNELS_SURROUND4:
av_channel_layout_from_mask(&c->ch_layout, AV_CH_LAYOUT_QUAD);
channel_layout_mask = AV_CH_LAYOUT_QUAD;
break;
case FFM_CHANNELS_SURROUND51:
av_channel_layout_from_mask(&c->ch_layout, AV_CH_LAYOUT_5POINT1_BACK);
channel_layout_mask = AV_CH_LAYOUT_5POINT1_BACK;
break;
case FFM_CHANNELS_SURROUND71:
av_channel_layout_from_mask(&c->ch_layout, AV_CH_LAYOUT_7POINT1);
channel_layout_mask = AV_CH_LAYOUT_7POINT1;
break;
}
BLI_assert(channel_layout_mask != 0);
# ifdef FFMPEG_USE_OLD_CHANNEL_VARS
c->channels = num_channels;
c->channel_layout = channel_layout_mask;
# else
av_channel_layout_from_mask(&c->ch_layout, channel_layout_mask);
# endif
if (request_float_audio_buffer(codec_id)) {
/* mainly for AAC codec which is experimental */
@ -1027,7 +1043,7 @@ static AVStream *alloc_audio_stream(FFMpegContext *context,
* not sure if that is needed anymore, so let's try out if there are any
* complaints regarding some FFmpeg versions users might have. */
context->audio_input_samples = AV_INPUT_BUFFER_MIN_SIZE * 8 / c->bits_per_coded_sample /
c->ch_layout.nb_channels;
num_channels;
}
else {
context->audio_input_samples = c->frame_size;
@ -1037,11 +1053,11 @@ static AVStream *alloc_audio_stream(FFMpegContext *context,
context->audio_sample_size = av_get_bytes_per_sample(c->sample_fmt);
context->audio_input_buffer = (uint8_t *)av_malloc(
context->audio_input_samples * c->ch_layout.nb_channels * context->audio_sample_size);
context->audio_input_buffer = (uint8_t *)av_malloc(context->audio_input_samples * num_channels *
context->audio_sample_size);
if (context->audio_deinterleave) {
context->audio_deinterleave_buffer = (uint8_t *)av_malloc(
context->audio_input_samples * c->ch_layout.nb_channels * context->audio_sample_size);
context->audio_input_samples * num_channels * context->audio_sample_size);
}
context->audio_time = 0.0f;
@ -1432,7 +1448,11 @@ int BKE_ffmpeg_start(void *context_v,
AVCodecContext *c = context->audio_codec;
AUD_DeviceSpecs specs;
# ifdef FFMPEG_USE_OLD_CHANNEL_VARS
specs.channels = c->channels;
# else
specs.channels = c->ch_layout.nb_channels;
# endif
switch (av_get_packed_sample_fmt(c->sample_fmt)) {
case AV_SAMPLE_FMT_U8: