emulators/retroarch: compatibility with ffmpeg 9.0

Kirill A. Korinsky <[email protected]>
Newsgroups gmane.os.openbsd.ports
Message-ID <[email protected]>
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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.