emulators/citra: compatibility with ffmpeg 9.0

Kirill A. Korinsky <[email protected]>
Newsgroups gmane.os.openbsd.ports
Message-ID <[email protected]>
ports@,

Here another mehanical fix for ffmpeg 9.0 compatibility for emulators/citra

Build tested against ffmpeg-9.0 and ffmpeg-8.1.2

Ok?

Index: Makefile
===================================================================
RCS file: /home/cvs/ports/emulators/citra/Makefile,v
diff -u -p -r1.43 Makefile
--- Makefile	11 Aug 2026 09:16:14 -0000	1.43
+++ Makefile	12 Aug 2026 23:52:57 -0000
@@ -9,7 +9,7 @@ DISTNAME =	citra-unified-source-20240303
 
 V =		2104
 PKGNAME =	citra-0.0.0.${V}
-REVISION =	7
+REVISION =	8
 
 CATEGORIES =	emulators
 
Index: patches/patch-src_common_dynamic_library_ffmpeg_cpp
===================================================================
RCS file: patches/patch-src_common_dynamic_library_ffmpeg_cpp
diff -N patches/patch-src_common_dynamic_library_ffmpeg_cpp
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ patches/patch-src_common_dynamic_library_ffmpeg_cpp	13 Aug 2026 00:14:44 -0000
@@ -0,0 +1,53 @@
+ffmpeg-9.0
+
+Index: src/common/dynamic_library/ffmpeg.cpp
+--- src/common/dynamic_library/ffmpeg.cpp.orig
++++ src/common/dynamic_library/ffmpeg.cpp
+@@ -33,14 +33,13 @@ av_hwframe_ctx_alloc_func av_hwframe_ctx_alloc;
+ av_hwframe_ctx_init_func av_hwframe_ctx_init;
+ av_hwframe_get_buffer_func av_hwframe_get_buffer;
+ av_hwframe_transfer_data_func av_hwframe_transfer_data;
+-av_int_list_length_for_size_func av_int_list_length_for_size;
+ #if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(56, 53, 100) // lavu 56.53.100
+ av_opt_child_class_iterate_func av_opt_child_class_iterate;
+ #else
+ av_opt_child_class_next_func av_opt_child_class_next;
+ #endif
+ av_opt_next_func av_opt_next;
+-av_opt_set_bin_func av_opt_set_bin;
++av_opt_set_array_func av_opt_set_array;
+ av_pix_fmt_desc_get_func av_pix_fmt_desc_get;
+ av_pix_fmt_desc_next_func av_pix_fmt_desc_next;
+ av_sample_fmt_is_planar_func av_sample_fmt_is_planar;
+@@ -65,6 +64,7 @@ avcodec_find_encoder_by_name_func avcodec_find_encoder
+ avcodec_free_context_func avcodec_free_context;
+ avcodec_get_class_func avcodec_get_class;
+ avcodec_get_hw_config_func avcodec_get_hw_config;
++avcodec_get_supported_config_func avcodec_get_supported_config;
+ avcodec_open2_func avcodec_open2;
+ avcodec_parameters_from_context_func avcodec_parameters_from_context;
+ avcodec_receive_frame_func avcodec_receive_frame;
+@@ -168,14 +168,13 @@ static bool LoadAVUtil() {
+     LOAD_SYMBOL(avutil, av_hwframe_ctx_init);
+     LOAD_SYMBOL(avutil, av_hwframe_get_buffer);
+     LOAD_SYMBOL(avutil, av_hwframe_transfer_data);
+-    LOAD_SYMBOL(avutil, av_int_list_length_for_size);
+ #if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(56, 53, 100) // lavu 56.53.100
+     LOAD_SYMBOL(avutil, av_opt_child_class_iterate);
+ #else
+     LOAD_SYMBOL(avutil, av_opt_child_class_next);
+ #endif
+     LOAD_SYMBOL(avutil, av_opt_next);
+-    LOAD_SYMBOL(avutil, av_opt_set_bin);
++    LOAD_SYMBOL(avutil, av_opt_set_array);
+     LOAD_SYMBOL(avutil, av_pix_fmt_desc_get);
+     LOAD_SYMBOL(avutil, av_pix_fmt_desc_next);
+     LOAD_SYMBOL(avutil, av_sample_fmt_is_planar);
+@@ -232,6 +231,7 @@ static bool LoadAVCodec() {
+     LOAD_SYMBOL(avcodec, avcodec_free_context);
+     LOAD_SYMBOL(avcodec, avcodec_get_class);
+     LOAD_SYMBOL(avcodec, avcodec_get_hw_config);
++    LOAD_SYMBOL(avcodec, avcodec_get_supported_config);
+     LOAD_SYMBOL(avcodec, avcodec_open2);
+     LOAD_SYMBOL(avcodec, avcodec_parameters_from_context);
+     LOAD_SYMBOL(avcodec, avcodec_receive_frame);
Index: patches/patch-src_common_dynamic_library_ffmpeg_h
===================================================================
RCS file: patches/patch-src_common_dynamic_library_ffmpeg_h
diff -N patches/patch-src_common_dynamic_library_ffmpeg_h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ patches/patch-src_common_dynamic_library_ffmpeg_h	13 Aug 2026 00:14:44 -0000
@@ -0,0 +1,55 @@
+ffmpeg-9.0
+
+Index: src/common/dynamic_library/ffmpeg.h
+--- src/common/dynamic_library/ffmpeg.h.orig
++++ src/common/dynamic_library/ffmpeg.h
+@@ -43,14 +43,14 @@ typedef AVBufferRef* (*av_hwframe_ctx_alloc_func)(AVBu
+ typedef int (*av_hwframe_ctx_init_func)(AVBufferRef*);
+ typedef int (*av_hwframe_get_buffer_func)(AVBufferRef*, AVFrame*, int);
+ typedef int (*av_hwframe_transfer_data_func)(AVFrame*, const AVFrame*, int);
+-typedef unsigned (*av_int_list_length_for_size_func)(unsigned, const void*, uint64_t);
+ #if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(56, 53, 100) // lavu 56.53.100
+ typedef const AVClass* (*av_opt_child_class_iterate_func)(const AVClass*, void**);
+ #else
+ typedef const AVClass* (*av_opt_child_class_next_func)(const AVClass*, const AVClass*);
+ #endif
+ typedef const AVOption* (*av_opt_next_func)(const void*, const AVOption*);
+-typedef int (*av_opt_set_bin_func)(void*, const char*, const uint8_t*, int, int);
++typedef int (*av_opt_set_array_func)(void*, const char*, int, unsigned, unsigned, AVOptionType,
++                                     const void*);
+ typedef const AVPixFmtDescriptor* (*av_pix_fmt_desc_get_func)(AVPixelFormat);
+ typedef const AVPixFmtDescriptor* (*av_pix_fmt_desc_next_func)(const AVPixFmtDescriptor*);
+ typedef int (*av_sample_fmt_is_planar_func)(AVSampleFormat);
+@@ -81,14 +81,13 @@ extern av_hwframe_ctx_alloc_func av_hwframe_ctx_alloc;
+ extern av_hwframe_ctx_init_func av_hwframe_ctx_init;
+ extern av_hwframe_get_buffer_func av_hwframe_get_buffer;
+ extern av_hwframe_transfer_data_func av_hwframe_transfer_data;
+-extern av_int_list_length_for_size_func av_int_list_length_for_size;
+ #if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(56, 53, 100) // lavu 56.53.100
+ extern av_opt_child_class_iterate_func av_opt_child_class_iterate;
+ #else
+ extern av_opt_child_class_next_func av_opt_child_class_next;
+ #endif
+ extern av_opt_next_func av_opt_next;
+-extern av_opt_set_bin_func av_opt_set_bin;
++extern av_opt_set_array_func av_opt_set_array;
+ extern av_pix_fmt_desc_get_func av_pix_fmt_desc_get;
+ extern av_pix_fmt_desc_next_func av_pix_fmt_desc_next;
+ extern av_sample_fmt_is_planar_func av_sample_fmt_is_planar;
+@@ -114,6 +113,8 @@ typedef const AVCodec* (*avcodec_find_encoder_by_name_
+ typedef void (*avcodec_free_context_func)(AVCodecContext**);
+ typedef const AVClass* (*avcodec_get_class_func)();
+ typedef const AVCodecHWConfig* (*avcodec_get_hw_config_func)(const AVCodec*, int);
++typedef int (*avcodec_get_supported_config_func)(const AVCodecContext*, const AVCodec*,
++                                                 enum AVCodecConfig, unsigned, const void**, int*);
+ typedef int (*avcodec_open2_func)(AVCodecContext*, const AVCodec*, AVDictionary**);
+ typedef int (*avcodec_parameters_from_context_func)(AVCodecParameters* par, const AVCodecContext*);
+ typedef int (*avcodec_receive_frame_func)(AVCodecContext*, AVFrame*);
+@@ -138,6 +139,7 @@ extern avcodec_find_encoder_by_name_func avcodec_find_
+ extern avcodec_free_context_func avcodec_free_context;
+ extern avcodec_get_class_func avcodec_get_class;
+ extern avcodec_get_hw_config_func avcodec_get_hw_config;
++extern avcodec_get_supported_config_func avcodec_get_supported_config;
+ extern avcodec_open2_func avcodec_open2;
+ extern avcodec_parameters_from_context_func avcodec_parameters_from_context;
+ extern avcodec_receive_frame_func avcodec_receive_frame;
Index: patches/patch-src_core_dumping_ffmpeg_backend_cpp
===================================================================
RCS file: /home/cvs/ports/emulators/citra/patches/patch-src_core_dumping_ffmpeg_backend_cpp,v
diff -u -p -r1.1 patch-src_core_dumping_ffmpeg_backend_cpp
--- patches/patch-src_core_dumping_ffmpeg_backend_cpp	21 Oct 2025 12:50:42 -0000	1.1
+++ patches/patch-src_core_dumping_ffmpeg_backend_cpp	13 Aug 2026 00:14:44 -0000
@@ -1,7 +1,187 @@
+ffmpeg-9.0
+
 Index: src/core/dumping/ffmpeg_backend.cpp
 --- src/core/dumping/ffmpeg_backend.cpp.orig
 +++ src/core/dumping/ffmpeg_backend.cpp
-@@ -956,7 +956,11 @@ std::string FormatDefaultValue(const AVOption* option,
+@@ -106,9 +106,10 @@ FFmpegVideoStream::~FFmpegVideoStream() {
+ 
+ // This is modified from libavcodec/decode.c
+ // The original version was broken
+-static AVPixelFormat GetPixelFormat(AVCodecContext* avctx, const AVPixelFormat* fmt) {
++static AVPixelFormat GetPixelFormat(AVCodecContext* avctx, const AVPixelFormat* fmt,
++                                    int num_formats) {
+     // Choose a software pixel format if any, prefering those in the front of the list
+-    for (int i = 0; fmt[i] != AV_PIX_FMT_NONE; i++) {
++    for (int i = 0; i < num_formats; i++) {
+         const AVPixFmtDescriptor* desc = FFmpeg::av_pix_fmt_desc_get(fmt[i]);
+         if (!(desc->flags & AV_PIX_FMT_FLAG_HWACCEL)) {
+             return fmt[i];
+@@ -118,7 +119,7 @@ static AVPixelFormat GetPixelFormat(AVCodecContext* av
+     // Finally, traverse the list in order and choose the first entry
+     // with no external dependencies (if there is no hardware configuration
+     // information available then this just picks the first entry).
+-    for (int i = 0; fmt[i] != AV_PIX_FMT_NONE; i++) {
++    for (int i = 0; i < num_formats; i++) {
+         const AVCodecHWConfig* config;
+         for (int j = 0;; j++) {
+             config = FFmpeg::avcodec_get_hw_config(avctx->codec, j);
+@@ -142,6 +143,9 @@ static AVPixelFormat GetPixelFormat(AVCodecContext* av
+ }
+ 
+ bool FFmpegVideoStream::Init(FFmpegMuxer& muxer, const Layout::FramebufferLayout& layout_) {
++    const AVPixelFormat* pixel_formats;
++    int num_pixel_formats, ret;
++
+     InitializeFFmpegLibraries();
+ 
+     if (!FFmpegStream::Init(muxer)) {
+@@ -160,6 +164,14 @@ bool FFmpegVideoStream::Init(FFmpegMuxer& muxer, const
+         return false;
+     }
+ 
++    ret = FFmpeg::avcodec_get_supported_config(codec_context.get(), nullptr,
++                                               AV_CODEC_CONFIG_PIX_FORMAT, 0,
++                                               (const void**)&pixel_formats, &num_pixel_formats);
++    if (ret < 0) {
++        LOG_ERROR(Render, "Could not query video encoder pixel formats");
++        return false;
++    }
++
+     // Configure video codec context
+     codec_context->codec_type = AVMEDIA_TYPE_VIDEO;
+     codec_context->bit_rate = Settings::values.video_bitrate;
+@@ -175,8 +187,8 @@ bool FFmpegVideoStream::Init(FFmpegMuxer& muxer, const
+     auto pixel_format_opt = FFmpeg::av_dict_get(options, "pixel_format", nullptr, 0);
+     if (pixel_format_opt) {
+         sw_pixel_format = FFmpeg::av_get_pix_fmt(pixel_format_opt->value);
+-    } else if (codec->pix_fmts) {
+-        sw_pixel_format = GetPixelFormat(codec_context.get(), codec->pix_fmts);
++    } else if (pixel_formats) {
++        sw_pixel_format = GetPixelFormat(codec_context.get(), pixel_formats, num_pixel_formats);
+     } else {
+         sw_pixel_format = AV_PIX_FMT_YUV420P;
+     }
+@@ -285,11 +297,22 @@ void FFmpegVideoStream::ProcessFrame(VideoFrame& frame
+ }
+ 
+ bool FFmpegVideoStream::InitHWContext(const AVCodec* codec) {
+-    for (std::size_t i = 0; codec->pix_fmts[i] != AV_PIX_FMT_NONE; ++i) {
++    const AVPixelFormat* pixel_formats;
++    int num_pixel_formats, ret;
++
++    ret = FFmpeg::avcodec_get_supported_config(codec_context.get(), nullptr,
++                                               AV_CODEC_CONFIG_PIX_FORMAT, 0,
++                                               (const void**)&pixel_formats, &num_pixel_formats);
++    if (ret < 0 || !pixel_formats) {
++        LOG_ERROR(Render, "Failed to query HW pixel formats");
++        return false;
++    }
++
++    for (int i = 0; i < num_pixel_formats; ++i) {
+         const AVCodecHWConfig* config;
+         for (int j = 0;; ++j) {
+             config = FFmpeg::avcodec_get_hw_config(codec, j);
+-            if (!config || config->pix_fmt == codec->pix_fmts[i]) {
++            if (!config || config->pix_fmt == pixel_formats[i]) {
+                 break;
+             }
+         }
+@@ -303,7 +326,7 @@ bool FFmpegVideoStream::InitHWContext(const AVCodec* c
+             continue;
+         }
+ 
+-        codec_context->pix_fmt = codec->pix_fmts[i];
++        codec_context->pix_fmt = pixel_formats[i];
+ 
+         // Create HW device context
+         AVBufferRef* hw_device_context;
+@@ -351,7 +374,7 @@ bool FFmpegVideoStream::InitHWContext(const AVCodec* c
+ 
+         AVHWFramesContext* hw_frames_context =
+             reinterpret_cast<AVHWFramesContext*>(hw_frames_context_ref->data);
+-        hw_frames_context->format = codec->pix_fmts[i];
++        hw_frames_context->format = pixel_formats[i];
+         hw_frames_context->sw_format = sw_pixel_format;
+         hw_frames_context->width = codec_context->width;
+         hw_frames_context->height = codec_context->height;
+@@ -399,13 +422,9 @@ bool FFmpegVideoStream::InitFilters() {
+         return false;
+     }
+ 
+-    // Point av_opt_set_int_list to correct functions.
+-#define av_int_list_length_for_size FFmpeg::av_int_list_length_for_size
+-#define av_opt_set_bin FFmpeg::av_opt_set_bin
+-
+-    const AVPixelFormat pix_fmts[] = {sw_pixel_format, AV_PIX_FMT_NONE};
+-    if (av_opt_set_int_list(sink_context, "pix_fmts", pix_fmts, AV_PIX_FMT_NONE,
+-                            AV_OPT_SEARCH_CHILDREN) < 0) {
++    const AVPixelFormat pixel_formats[] = {sw_pixel_format};
++    if (FFmpeg::av_opt_set_array(sink_context, "pixel_formats", AV_OPT_SEARCH_CHILDREN, 0, 1,
++                                 AV_OPT_TYPE_PIXEL_FMT, pixel_formats) < 0) {
+         LOG_ERROR(Render, "Could not set output pixel format");
+         return false;
+     }
+@@ -448,6 +467,10 @@ FFmpegAudioStream::~FFmpegAudioStream() {
+ }
+ 
+ bool FFmpegAudioStream::Init(FFmpegMuxer& muxer) {
++    const AVSampleFormat* sample_formats;
++    const int* supported_sample_rates;
++    int num_sample_formats, num_supported_sample_rates, ret;
++
+     InitializeFFmpegLibraries();
+ 
+     if (!FFmpegStream::Init(muxer)) {
+@@ -465,25 +488,40 @@ bool FFmpegAudioStream::Init(FFmpegMuxer& muxer) {
+         return false;
+     }
+ 
++    ret = FFmpeg::avcodec_get_supported_config(codec_context.get(), nullptr,
++                                               AV_CODEC_CONFIG_SAMPLE_FORMAT, 0,
++                                               (const void**)&sample_formats, &num_sample_formats);
++    if (ret < 0) {
++        LOG_ERROR(Render, "Could not query audio encoder sample formats");
++        return false;
++    }
++
++    ret = FFmpeg::avcodec_get_supported_config(codec_context.get(), nullptr,
++                                               AV_CODEC_CONFIG_SAMPLE_RATE, 0,
++                                               (const void**)&supported_sample_rates,
++                                               &num_supported_sample_rates);
++    if (ret < 0) {
++        LOG_ERROR(Render, "Could not query audio encoder sample rates");
++        return false;
++    }
++
+     // Configure audio codec context
+     codec_context->codec_type = AVMEDIA_TYPE_AUDIO;
+     codec_context->bit_rate = Settings::values.audio_bitrate;
+-    if (codec->sample_fmts) {
+-        codec_context->sample_fmt = codec->sample_fmts[0];
++    if (sample_formats && num_sample_formats > 0) {
++        codec_context->sample_fmt = sample_formats[0];
+     } else {
+         codec_context->sample_fmt = AV_SAMPLE_FMT_S16P;
+     }
+ 
+-    if (codec->supported_samplerates) {
+-        codec_context->sample_rate = codec->supported_samplerates[0];
++    if (supported_sample_rates && num_supported_sample_rates > 0) {
++        codec_context->sample_rate = supported_sample_rates[0];
+         // Prefer native sample rate if supported
+-        const int* ptr = codec->supported_samplerates;
+-        while ((*ptr)) {
+-            if ((*ptr) == AudioCore::native_sample_rate) {
++        for (int i = 0; i < num_supported_sample_rates; i++) {
++            if (supported_sample_rates[i] == AudioCore::native_sample_rate) {
+                 codec_context->sample_rate = AudioCore::native_sample_rate;
+                 break;
+             }
+-            ptr++;
+         }
+     } else {
+         codec_context->sample_rate = AudioCore::native_sample_rate;
+@@ -956,7 +994,11 @@ std::string FormatDefaultValue(const AVOption* option,
      case AV_OPT_TYPE_VIDEO_RATE: {
          return ToStdString(option->default_val.str);
      }


-- 
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.