Download raw body.
emulators/retroarch: compatibility with ffmpeg 9.0
ports@,
I'd like to backport a fix for emulators/retroarch which fixes compatibility
with ffmpeg-9.0
Build tested against ffmpeg-9.0 and ffmpeg-8.1.2
The fix in upstream:
https://github.com/libretro/RetroArch/commit/f5b422d5a81f0b4d263e2f52c8419ea9ce7467f6
Ok?
Index: Makefile
===================================================================
RCS file: /home/cvs/ports/emulators/retroarch/Makefile,v
diff -u -p -r1.34 Makefile
--- Makefile 18 Feb 2026 18:32:50 -0000 1.34
+++ Makefile 12 Aug 2026 17:03:59 -0000
@@ -4,7 +4,7 @@ DISTNAME = retroarch-sourceonly-$V
PKGNAME = retroarch-$V
V = 1.21.0
-REVISION = 0
+REVISION = 1
# crashes when recording videos due to ffmpeg
USE_NOBTCFI-amd64 = Yes
Index: patches/patch-camera_drivers_ffmpeg_c
===================================================================
RCS file: patches/patch-camera_drivers_ffmpeg_c
diff -N patches/patch-camera_drivers_ffmpeg_c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ patches/patch-camera_drivers_ffmpeg_c 12 Aug 2026 17:07:36 -0000
@@ -0,0 +1,34 @@
+https://github.com/libretro/RetroArch/commit/f5b422d5a81f0b4d263e2f52c8419ea9ce7467f6
+
+Index: camera/drivers/ffmpeg.c
+--- camera/drivers/ffmpeg.c.orig
++++ camera/drivers/ffmpeg.c
+@@ -42,13 +42,26 @@
+ #define FFMPEG_CAMERA_DEFAULT_BACKEND "bktr"
+ #endif
+
++/* lavf 59 (FFmpeg 5.0) made the demuxer/codec discovery API const-correct:
++ * av_find_input_format() returns const AVInputFormat*, avformat_open_input()
++ * accepts one, and av_find_best_stream() takes const AVCodec**. Older
++ * versions use mutable pointers throughout, so a single const-qualified
++ * declaration cannot satisfy both. */
++#if LIBAVFORMAT_VERSION_MAJOR >= 59
++typedef const AVInputFormat ffmpeg_camera_input_format_t;
++typedef const AVCodec ffmpeg_camera_codec_t;
++#else
++typedef AVInputFormat ffmpeg_camera_input_format_t;
++typedef AVCodec ffmpeg_camera_codec_t;
++#endif
++
+ typedef struct ffmpeg_camera
+ {
+ sthread_t *poll_thread;
+ AVFormatContext *format_context;
+ AVCodecContext *decoder_context;
+- const AVCodec *decoder;
+- const AVInputFormat *input_format; /* owned by ffmpeg, don't free it */
++ ffmpeg_camera_codec_t *decoder; /* owned by ffmpeg, don't free it */
++ ffmpeg_camera_input_format_t *input_format; /* owned by ffmpeg, don't free it */
+ AVDictionary *options;
+ AVPacket *packet;
+ AVFrame *camera_frame;
Index: patches/patch-record_drivers_record_ffmpeg_c
===================================================================
RCS file: /home/cvs/ports/emulators/retroarch/patches/patch-record_drivers_record_ffmpeg_c,v
diff -u -p -r1.1 patch-record_drivers_record_ffmpeg_c
--- patches/patch-record_drivers_record_ffmpeg_c 21 Oct 2025 12:51:47 -0000 1.1
+++ patches/patch-record_drivers_record_ffmpeg_c 12 Aug 2026 17:06:43 -0000
@@ -1,9 +1,10 @@
https://github.com/libretro/RetroArch/commit/21776a2e59f5f5899ff2198c0df25a95b5020012
+https://github.com/libretro/RetroArch/commit/f5b422d5a81f0b4d263e2f52c8419ea9ce7467f6
Index: record/drivers/record_ffmpeg.c
--- record/drivers/record_ffmpeg.c.orig
+++ record/drivers/record_ffmpeg.c
-@@ -72,6 +72,15 @@ extern "C" {
+@@ -72,6 +72,24 @@ extern "C" {
#ifndef FFMPEG3
#define FFMPEG3 (LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 10, 100))
#endif
@@ -12,6 +13,15 @@ Index: record/drivers/record_ffmpeg.c
+#define FFMPEG8 (LIBAVCODEC_VERSION_MAJOR >= 62)
+#endif
+
++/* avcodec_get_supported_config() was added in lavc 61.13.100 (FFmpeg 7.1)
++ * and the AVCodec.sample_fmts / AVCodec.supported_samplerates arrays it
++ * replaces were deprecated at the same time, then removed entirely in
++ * lavc 63 (FFmpeg 9). Use the new API as soon as it is available so a
++ * single codepath covers FFmpeg 7.1 through 9+, and keep the old struct
++ * members for FFmpeg 7.0 and older. */
++#define HAVE_AVCODEC_GET_SUPPORTED_CONFIG \
++ (LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(61, 13, 100))
++
+#ifndef AV_INPUT_BUFFER_MIN_SIZE
+#define AV_INPUT_BUFFER_MIN_SIZE 16384
+#endif
@@ -19,7 +29,132 @@ Index: record/drivers/record_ffmpeg.c
#define HAVE_CH_LAYOUT (LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(57, 28, 100))
struct ff_video_info
-@@ -951,7 +960,11 @@ static void ffmpeg_free(void *data)
+@@ -200,11 +218,48 @@ typedef struct ffmpeg
+
+ AVFormatContext *ctx;
+
++/* Returns the encoder's list of supported sample formats, terminated by
++ * AV_SAMPLE_FMT_NONE, or NULL if the encoder does not restrict sample
++ * formats (or the list could not be queried). */
++static const enum AVSampleFormat *ffmpeg_codec_sample_formats(
++ const AVCodec *codec)
++{
++#if HAVE_AVCODEC_GET_SUPPORTED_CONFIG
++ const void *fmts = NULL;
++ if (avcodec_get_supported_config(NULL, codec,
++ AV_CODEC_CONFIG_SAMPLE_FORMAT, 0, &fmts, NULL) < 0)
++ return NULL;
++ return (const enum AVSampleFormat*)fmts;
++#else
++ return codec->sample_fmts;
++#endif
++}
++
++/* Returns the encoder's list of supported sample rates, terminated by 0,
++ * or NULL if the encoder does not restrict sample rates (or the list
++ * could not be queried). */
++static const int *ffmpeg_codec_supported_samplerates(const AVCodec *codec)
++{
++#if HAVE_AVCODEC_GET_SUPPORTED_CONFIG
++ const void *rates = NULL;
++ if (avcodec_get_supported_config(NULL, codec,
++ AV_CODEC_CONFIG_SAMPLE_RATE, 0, &rates, NULL) < 0)
++ return NULL;
++ return (const int*)rates;
++#else
++ return codec->supported_samplerates;
++#endif
++}
++
+ static bool ffmpeg_codec_has_sample_format(enum AVSampleFormat fmt,
+ const enum AVSampleFormat *fmts)
+ {
+ unsigned i;
+
++ /* A NULL list means the encoder does not restrict sample formats. */
++ if (!fmts)
++ return true;
++
+ for (i = 0; fmts[i] != AV_SAMPLE_FMT_NONE; i++)
+ if (fmt == fmts[i])
+ return true;
+@@ -214,30 +269,32 @@ static bool ffmpeg_codec_has_sample_format(enum AVSamp
+ static void ffmpeg_audio_resolve_format(struct ff_audio_info *audio,
+ const AVCodec *codec)
+ {
++ const enum AVSampleFormat *sample_fmts = ffmpeg_codec_sample_formats(codec);
++
+ audio->codec->sample_fmt = AV_SAMPLE_FMT_NONE;
+
+- if (ffmpeg_codec_has_sample_format(AV_SAMPLE_FMT_FLTP, codec->sample_fmts))
++ if (ffmpeg_codec_has_sample_format(AV_SAMPLE_FMT_FLTP, sample_fmts))
+ {
+ audio->codec->sample_fmt = AV_SAMPLE_FMT_FLTP;
+ audio->use_float = true;
+ audio->is_planar = true;
+ RARCH_LOG("[FFmpeg]: Using sample format FLTP.\n");
+ }
+- else if (ffmpeg_codec_has_sample_format(AV_SAMPLE_FMT_FLT, codec->sample_fmts))
++ else if (ffmpeg_codec_has_sample_format(AV_SAMPLE_FMT_FLT, sample_fmts))
+ {
+ audio->codec->sample_fmt = AV_SAMPLE_FMT_FLT;
+ audio->use_float = true;
+ audio->is_planar = false;
+ RARCH_LOG("[FFmpeg]: Using sample format FLT.\n");
+ }
+- else if (ffmpeg_codec_has_sample_format(AV_SAMPLE_FMT_S16P, codec->sample_fmts))
++ else if (ffmpeg_codec_has_sample_format(AV_SAMPLE_FMT_S16P, sample_fmts))
+ {
+ audio->codec->sample_fmt = AV_SAMPLE_FMT_S16P;
+ audio->use_float = false;
+ audio->is_planar = true;
+ RARCH_LOG("[FFmpeg]: Using sample format S16P.\n");
+ }
+- else if (ffmpeg_codec_has_sample_format(AV_SAMPLE_FMT_S16, codec->sample_fmts))
++ else if (ffmpeg_codec_has_sample_format(AV_SAMPLE_FMT_S16, sample_fmts))
+ {
+ audio->codec->sample_fmt = AV_SAMPLE_FMT_S16;
+ audio->use_float = false;
+@@ -252,21 +309,24 @@ static void ffmpeg_audio_resolve_sample_rate(ffmpeg_t
+ {
+ struct ff_config_param *params = &handle->config;
+ struct record_params *param = &handle->params;
++ const int *supported_samplerates = ffmpeg_codec_supported_samplerates(codec);
+
+- /* We'll have to force resampling to some supported sampling rate. */
+- if (codec->supported_samplerates && !params->sample_rate)
++ /* We'll have to force resampling to some supported sampling rate.
++ * A NULL list means the encoder accepts any sample rate, in which
++ * case the input rate is kept as-is. */
++ if (supported_samplerates && !params->sample_rate)
+ {
+ unsigned i;
+ int input_rate = (int)param->samplerate;
+
+ /* Favor closest sampling rate, but always prefer ratio > 1.0. */
+- int best_rate = codec->supported_samplerates[0];
++ int best_rate = supported_samplerates[0];
+ int best_diff = best_rate - input_rate;
+
+- for (i = 1; codec->supported_samplerates[i]; i++)
++ for (i = 1; supported_samplerates[i]; i++)
+ {
+ bool better_rate = false;
+- int diff = codec->supported_samplerates[i] - input_rate;
++ int diff = supported_samplerates[i] - input_rate;
+
+ if (best_diff < 0)
+ better_rate = (diff > best_diff);
+@@ -275,7 +335,7 @@ static void ffmpeg_audio_resolve_sample_rate(ffmpeg_t
+
+ if (better_rate)
+ {
+- best_rate = codec->supported_samplerates[i];
++ best_rate = supported_samplerates[i];
+ best_diff = diff;
+ }
+ }
+@@ -951,7 +1011,11 @@ static void ffmpeg_free(void *data)
if (handle->audio.codec)
{
@@ -31,7 +166,7 @@ Index: record/drivers/record_ffmpeg.c
av_free(handle->audio.codec);
}
-@@ -959,7 +972,11 @@ static void ffmpeg_free(void *data)
+@@ -959,7 +1023,11 @@ static void ffmpeg_free(void *data)
if (handle->video.codec)
{
--
wbr, Kirill
emulators/retroarch: compatibility with ffmpeg 9.0