Compare commits
2 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5039144660 | ||
|
|
e4b93e9cfa |
2 changed files with 211 additions and 0 deletions
207
retroarch-ffmpeg9.patch
Normal file
207
retroarch-ffmpeg9.patch
Normal file
|
|
@ -0,0 +1,207 @@
|
|||
From f5b422d5a81f0b4d263e2f52c8419ea9ce7467f6 Mon Sep 17 00:00:00 2001
|
||||
From: LibretroAdmin <LibretroAdmin@users.noreply.github.com>
|
||||
Date: Mon, 10 Aug 2026 21:42:29 +0000
|
||||
Subject: [PATCH] ffmpeg: support FFmpeg 9 (lavc 63), version-gated back to
|
||||
existing floor
|
||||
|
||||
MSYS2 updated mingw-w64-ffmpeg to 9.0, which removes the deprecated
|
||||
AVCodec.sample_fmts / AVCodec.supported_samplerates arrays and breaks
|
||||
the MSYS2 CI build in record_ffmpeg.c.
|
||||
|
||||
record_ffmpeg: add accessors that use avcodec_get_supported_config()
|
||||
where available (lavc >= 61.13.100, FFmpeg 7.1+) and fall back to the
|
||||
legacy AVCodec struct members on older versions. NULL now means
|
||||
unrestricted instead of being dereferenced, hardening both paths.
|
||||
|
||||
camera/ffmpeg: version-gate const-ness of the AVInputFormat/AVCodec
|
||||
pointers; lavf 59 (FFmpeg 5.0) made that API const-correct, lavf 58
|
||||
(FFmpeg 4.x, the driver's minimum) warns on const pointers.
|
||||
|
||||
Verified: compile matrix with production flags against FFmpeg 3.4.13,
|
||||
4.4.5, 5.1.6, 6.1.2, 7.1.1, 8.1.2 and 9.0 all clean; full configure +
|
||||
make against FFmpeg 9.0 builds and links; resolver logic runtime-tested
|
||||
under ASan/UBSan against FFmpeg 9.0 (new path) and 6.1.2 (legacy path)
|
||||
with identical results and no sanitizer findings.
|
||||
---
|
||||
camera/drivers/ffmpeg.c | 17 +++++++-
|
||||
record/drivers/record_ffmpeg.c | 71 +++++++++++++++++++++++++++++-----
|
||||
2 files changed, 76 insertions(+), 12 deletions(-)
|
||||
|
||||
diff --git a/camera/drivers/ffmpeg.c b/camera/drivers/ffmpeg.c
|
||||
index 2c0e68adade4..f12f55690465 100644
|
||||
--- a/camera/drivers/ffmpeg.c
|
||||
+++ b/camera/drivers/ffmpeg.c
|
||||
@@ -58,13 +58,26 @@ extern "C" {
|
||||
#define FFMPEG_CAMERA_DEFAULT_BACKEND "lavfi"
|
||||
#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;
|
||||
diff --git a/record/drivers/record_ffmpeg.c b/record/drivers/record_ffmpeg.c
|
||||
index fc801af0b34e..5f72f2b87241 100644
|
||||
--- a/record/drivers/record_ffmpeg.c
|
||||
+++ b/record/drivers/record_ffmpeg.c
|
||||
@@ -79,6 +79,15 @@ extern "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
|
||||
@@ -216,11 +225,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;
|
||||
@@ -230,30 +276,32 @@ static bool ffmpeg_codec_has_sample_format(enum AVSampleFormat fmt,
|
||||
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;
|
||||
@@ -268,21 +316,24 @@ static void ffmpeg_audio_resolve_sample_rate(ffmpeg_t *handle,
|
||||
{
|
||||
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);
|
||||
@@ -291,7 +342,7 @@ static void ffmpeg_audio_resolve_sample_rate(ffmpeg_t *handle,
|
||||
|
||||
if (better_rate)
|
||||
{
|
||||
- best_rate = codec->supported_samplerates[i];
|
||||
+ best_rate = supported_samplerates[i];
|
||||
best_diff = diff;
|
||||
}
|
||||
}
|
||||
|
|
@ -126,6 +126,10 @@ Patch: 0003_use_system_zstd.patch
|
|||
# https://github.com/libretro/RetroArch/pull/17563
|
||||
Patch: https://github.com/libretro/RetroArch/pull/17563.patch#/0002-Support-for-newer-glslang-versions-without-SPIRV-and-HLSL-libraries.patch
|
||||
|
||||
# Support FFmpeg 9
|
||||
# https://github.com/libretro/RetroArch/issues/19351
|
||||
Patch: https://github.com/libretro/RetroArch/commit/f5b422d5a81f0b4d263e2f52c8419ea9ce7467f6.patch#/retroarch-ffmpeg9.patch
|
||||
|
||||
BuildRequires: desktop-file-utils
|
||||
BuildRequires: gcc-c++ >= 7
|
||||
BuildRequires: git-core
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue