Control: tags 1144240 + patch
Control: tags 1144240 + pending

Dear maintainer,

I've prepared an NMU for cyanrip (versioned as 0.9.3.1-2.1) and uploaded 
it to DELAYED/2. Please feel free to tell me if I should cancel it.

cu
Adrian
diffstat for cyanrip-0.9.3.1 cyanrip-0.9.3.1

 changelog                                                           |    7 
 patches/0001-Support-the-FFmpeg-7.1-codec-and-buffersink-APIs.patch |  240 ++++++++++
 patches/series                                                      |    1 
 3 files changed, 248 insertions(+)

diff -Nru cyanrip-0.9.3.1/debian/changelog cyanrip-0.9.3.1/debian/changelog
--- cyanrip-0.9.3.1/debian/changelog	2026-06-15 23:07:11.000000000 +0300
+++ cyanrip-0.9.3.1/debian/changelog	2026-10-03 18:51:06.000000000 +0300
@@ -1,3 +1,10 @@
+cyanrip (0.9.3.1-2.1) unstable; urgency=medium
+
+  * Non-maintainer upload.
+  * Backport upstream fix for FTBFS with ffmpeg 9. (Closes: #1144240)
+
+ -- Adrian Bunk <[email protected]>  Sat, 03 Oct 2026 18:51:06 +0300
+
 cyanrip (0.9.3.1-2) unstable; urgency=medium
 
   * debian/control:
diff -Nru cyanrip-0.9.3.1/debian/patches/0001-Support-the-FFmpeg-7.1-codec-and-buffersink-APIs.patch cyanrip-0.9.3.1/debian/patches/0001-Support-the-FFmpeg-7.1-codec-and-buffersink-APIs.patch
--- cyanrip-0.9.3.1/debian/patches/0001-Support-the-FFmpeg-7.1-codec-and-buffersink-APIs.patch	1970-01-01 02:00:00.000000000 +0200
+++ cyanrip-0.9.3.1/debian/patches/0001-Support-the-FFmpeg-7.1-codec-and-buffersink-APIs.patch	2026-10-03 18:51:01.000000000 +0300
@@ -0,0 +1,240 @@
+From 63b6fca448bad6ba8a7b6d295f56853c5d0f89e0 Mon Sep 17 00:00:00 2001
+From: Lynne <[email protected]>
+Date: Sun, 12 Jul 2026 19:18:46 +0900
+Subject: Support the FFmpeg 7.1+ codec and buffersink APIs
+
+FFmpeg master (lavc 63) removed AVCodec.ch_layouts/sample_fmts/
+supported_samplerates and the buffersink int-list options that were
+deprecated in 7.1. Query codec capabilities through
+avcodec_get_supported_config() and configure the buffersink via
+av_opt_set_array() on lavc >= 61.13.100/lavfi >= 10.6.100, keeping
+the old paths for older FFmpeg.
+
+The buffersink is now allocated, configured and then initialized
+explicitly, as setting non-runtime options on an initialized object
+is rejected since FFmpeg 8.0. This is what broke -E and HDCD/
+deemphasis ripping in general against FFmpeg 8:
+"Error setting filter sample format: Invalid argument!"
+
+Closes #137
+Closes #142
+
+Co-Authored-By: Claude Fable 5 <[email protected]>
+Claude-Session: https://claude.ai/code/session_014GYNg8856YE285XHQSF1ZV
+---
+ src/cyanrip_encode.c | 115 ++++++++++++++++++++++++++++++++++---------
+ 1 file changed, 92 insertions(+), 23 deletions(-)
+
+diff --git a/src/cyanrip_encode.c b/src/cyanrip_encode.c
+index e3ad09f..915094f 100644
+--- a/src/cyanrip_encode.c
++++ b/src/cyanrip_encode.c
+@@ -132,6 +132,31 @@ const char *cyanrip_fmt_folder(enum cyanrip_output_formats format)
+     return format < CYANRIP_FORMATS_NB ? crip_fmt_info[format].folder_suffix : NULL;
+ }
+ 
++/* The AVCodec.ch_layouts/sample_fmts/supported_samplerates fields were
++ * replaced by avcodec_get_supported_config() in lavc 61.13.100 (FFmpeg 7.1)
++ * and later removed. All lists remain terminated, so NULL still means
++ * "supports anything". */
++#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(61, 13, 100)
++static const void *codec_supported_config(const AVCodec *codec,
++                                          enum AVCodecConfig config)
++{
++    const void *list = NULL;
++    if (avcodec_get_supported_config(NULL, codec, config, 0, &list, NULL) < 0)
++        return NULL;
++    return list;
++}
++#define CODEC_CH_LAYOUTS(codec) \
++    ((const AVChannelLayout *)codec_supported_config(codec, AV_CODEC_CONFIG_CHANNEL_LAYOUT))
++#define CODEC_SAMPLE_FMTS(codec) \
++    ((const enum AVSampleFormat *)codec_supported_config(codec, AV_CODEC_CONFIG_SAMPLE_FORMAT))
++#define CODEC_SAMPLERATES(codec) \
++    ((const int *)codec_supported_config(codec, AV_CODEC_CONFIG_SAMPLE_RATE))
++#else
++#define CODEC_CH_LAYOUTS(codec)  ((codec)->ch_layouts)
++#define CODEC_SAMPLE_FMTS(codec) ((codec)->sample_fmts)
++#define CODEC_SAMPLERATES(codec) ((codec)->supported_samplerates)
++#endif
++
+ static AVChannelLayout pick_codec_channel_layout(const AVCodec *codec)
+ {
+     int i = 0;
+@@ -139,17 +164,18 @@ static AVChannelLayout pick_codec_channel_layout(const AVCodec *codec)
+     AVChannelLayout ilayout = AV_CHANNEL_LAYOUT_STEREO;
+     int in_channels = ilayout.nb_channels;
+     AVChannelLayout best_layout = { 0 };
++    const AVChannelLayout *ch_layouts = CODEC_CH_LAYOUTS(codec);
+ 
+     /* Supports anything */
+-    if (!codec->ch_layouts)
++    if (!ch_layouts)
+         return ilayout;
+ 
+     /* Try to match */
+     while (1) {
+-        if (!codec->ch_layouts[i].nb_channels)
++        if (!ch_layouts[i].nb_channels)
+             break;
+-        if (!av_channel_layout_compare(&codec->ch_layouts[i], &ilayout))
+-            return codec->ch_layouts[i];
++        if (!av_channel_layout_compare(&ch_layouts[i], &ilayout))
++            return ch_layouts[i];
+         i++;
+     }
+ 
+@@ -157,15 +183,15 @@ static AVChannelLayout pick_codec_channel_layout(const AVCodec *codec)
+ 
+     /* Try to match channel counts */
+     while (1) {
+-        if (!codec->ch_layouts[i].nb_channels)
++        if (!ch_layouts[i].nb_channels)
+             break;
+-        int num = codec->ch_layouts[i].nb_channels;
++        int num = ch_layouts[i].nb_channels;
+         if (num > max_channels) {
+             max_channels = num;
+-            best_layout = codec->ch_layouts[i];
++            best_layout = ch_layouts[i];
+         }
+         if (num >= in_channels)
+-            return codec->ch_layouts[i];
++            return ch_layouts[i];
+         i++;
+     }
+ 
+@@ -184,19 +210,21 @@ static enum AVSampleFormat pick_codec_sample_fmt(const AVCodec *codec, int hdcd)
+                                         AV_SAMPLE_FMT_S16P;
+     enum AVSampleFormat max_bps_fmt = AV_SAMPLE_FMT_NONE;
+ 
++    const enum AVSampleFormat *sample_fmts = CODEC_SAMPLE_FMTS(codec);
++
+     ibps = ibps >> 3;
+ 
+     /* Accepts anything */
+-    if (!codec->sample_fmts)
++    if (!sample_fmts)
+         return ifmt;
+ 
+     /* Try to match the input sample format first */
+     while (1) {
+-        if (codec->sample_fmts[i] == AV_SAMPLE_FMT_NONE)
++        if (sample_fmts[i] == AV_SAMPLE_FMT_NONE)
+             break;
+-        if (codec->sample_fmts[i] == ifmt ||
+-            codec->sample_fmts[i] == ifmt_p)
+-            return codec->sample_fmts[i];
++        if (sample_fmts[i] == ifmt ||
++            sample_fmts[i] == ifmt_p)
++            return sample_fmts[i];
+         i++;
+     }
+ 
+@@ -204,15 +232,15 @@ static enum AVSampleFormat pick_codec_sample_fmt(const AVCodec *codec, int hdcd)
+ 
+     /* Try to match bits per sample */
+     while (1) {
+-        if (codec->sample_fmts[i] == -1)
++        if (sample_fmts[i] == -1)
+             break;
+-        int bps = av_get_bytes_per_sample(codec->sample_fmts[i]);
++        int bps = av_get_bytes_per_sample(sample_fmts[i]);
+         if (bps > max_bps) {
+             max_bps = bps;
+-            max_bps_fmt = codec->sample_fmts[i];
++            max_bps_fmt = sample_fmts[i];
+         }
+         if (bps == ibps)
+-            return codec->sample_fmts[i];
++            return sample_fmts[i];
+         i++;
+     }
+ 
+@@ -224,15 +252,16 @@ static int pick_codec_sample_rate(const AVCodec *codec)
+ {
+     int i = 0, ret;
+     int irate = 44100;
++    const int *samplerates = CODEC_SAMPLERATES(codec);
+ 
+-    if (!codec->supported_samplerates)
++    if (!samplerates)
+         return irate;
+ 
+     /* Go to the array terminator (0) */
+-    while (codec->supported_samplerates[++i] > 0);
++    while (samplerates[++i] > 0);
+     /* Alloc, copy and sort array upwards */
+     int *tmp = av_malloc(i*sizeof(int));
+-    memcpy(tmp, codec->supported_samplerates, i*sizeof(int));
++    memcpy(tmp, samplerates, i*sizeof(int));
+     qsort(tmp, i, sizeof(int), cmp_numbers);
+ 
+     /* Pick lowest one above the input rate, otherwise just use the highest one */
+@@ -327,13 +356,46 @@ static int init_filtering(cyanrip_ctx *ctx, cyanrip_filt_ctx *s,
+ 
+     if (!peak) {
+         const AVFilter *abuffersink = avfilter_get_by_name("abuffersink");
+-        ret = avfilter_graph_create_filter(&s->buffersink_ctx, abuffersink, "out",
+-                                           NULL, NULL, s->graph);
+-        if (ret < 0) {
++        /* Options must be set between allocation and init, non-runtime
++         * option changes on initialized objects are rejected */
++        s->buffersink_ctx = avfilter_graph_alloc_filter(s->graph, abuffersink, "out");
++        if (!s->buffersink_ctx) {
++            ret = AVERROR(ENOMEM);
+             cyanrip_log(ctx, 0, "Error creating filter sink: %s!\n", av_err2str(ret));
+             goto fail;
+         }
+ 
++#if LIBAVFILTER_VERSION_INT >= AV_VERSION_INT(10, 6, 100)
++        /* Buffersink switched to array-type options in lavfi 10.6.100
++         * (FFmpeg 7.1); the int-list options were later removed */
++        if (hdcd || deemphasis) {
++            const enum AVSampleFormat out_sample_fmt = hdcd ? AV_SAMPLE_FMT_S32 :
++                                                              AV_SAMPLE_FMT_DBLP;
++            ret = av_opt_set_array(s->buffersink_ctx, "sample_formats",
++                                   AV_OPT_SEARCH_CHILDREN, 0, 1,
++                                   AV_OPT_TYPE_SAMPLE_FMT, &out_sample_fmt);
++            if (ret < 0) {
++                cyanrip_log(ctx, 0, "Error setting filter sample format: %s!\n", av_err2str(ret));
++                goto fail;
++            }
++        }
++
++        ret = av_opt_set(s->buffersink_ctx, "channel_layouts", "stereo",
++                         AV_OPT_SEARCH_CHILDREN);
++        if (ret < 0) {
++            cyanrip_log(ctx, 0, "Error setting filter channel layout: %s!\n", av_err2str(ret));
++            goto fail;
++        }
++
++        const int out_sample_rate = 44100;
++        ret = av_opt_set_array(s->buffersink_ctx, "samplerates",
++                               AV_OPT_SEARCH_CHILDREN, 0, 1,
++                               AV_OPT_TYPE_INT, &out_sample_rate);
++        if (ret < 0) {
++            cyanrip_log(ctx, 0, "Error setting filter sample rate: %s!\n", av_err2str(ret));
++            goto fail;
++        }
++#else
+         static const enum AVSampleFormat out_sample_fmts_hdcd[] = { AV_SAMPLE_FMT_S32, -1 };
+         static const enum AVSampleFormat out_sample_fmts_deemph[] = { AV_SAMPLE_FMT_DBLP, -1 };
+ 
+@@ -360,6 +422,13 @@ static int init_filtering(cyanrip_ctx *ctx, cyanrip_filt_ctx *s,
+             cyanrip_log(ctx, 0, "Error setting filter sample rate: %s!\n", av_err2str(ret));
+             goto fail;
+         }
++#endif
++
++        ret = avfilter_init_str(s->buffersink_ctx, NULL);
++        if (ret < 0) {
++            cyanrip_log(ctx, 0, "Error initializing filter sink: %s!\n", av_err2str(ret));
++            goto fail;
++        }
+     }
+ 
+     outputs = avfilter_inout_alloc();
+-- 
+2.47.3
+
diff -Nru cyanrip-0.9.3.1/debian/patches/series cyanrip-0.9.3.1/debian/patches/series
--- cyanrip-0.9.3.1/debian/patches/series	1970-01-01 02:00:00.000000000 +0200
+++ cyanrip-0.9.3.1/debian/patches/series	2026-10-03 18:51:06.000000000 +0300
@@ -0,0 +1 @@
+0001-Support-the-FFmpeg-7.1-codec-and-buffersink-APIs.patch

Reply via email to