Index | Thread | Search

From:
Kirill A. Korinsky <kirill@korins.ky>
Subject:
emulators/citra: compatibility with ffmpeg 9.0
To:
OpenBSD ports <ports@openbsd.org>
Date:
Thu, 13 Aug 2026 02:39:17 +0200

Download raw body.

Thread
  • Kirill A. Korinsky:

    emulators/citra: compatibility with ffmpeg 9.0

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