PR #21206 opened by mkver
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/21206
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/21206.patch

Alternative to #21205.


>From 6d5108484f151b95b0e31edd58003999a6548cb9 Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <[email protected]>
Date: Mon, 15 Dec 2025 15:39:05 +0100
Subject: [PATCH 1/9] avformat/mux: Allow to add list of supported codecs to
 muxers

This allows to check generically for supported codecs in
avformat_init_output() and avformat_query_codec().

Notice that using a union of codec_list and query_codec
is fine ABI-wise: Given that both members are pointers,
the offsets won't be affected (in practice); because
the information in which state the union is is given
by a flag contained in the FFOutputFormat, it works
to even use this for devices without a major ABI bump.

Signed-off-by: Andreas Rheinhardt <[email protected]>
---
 libavformat/mux.c       | 14 ++++++++++++++
 libavformat/mux.h       | 37 +++++++++++++++++++++++++++++--------
 libavformat/mux_utils.c |  9 ++++++++-
 3 files changed, 51 insertions(+), 9 deletions(-)

diff --git a/libavformat/mux.c b/libavformat/mux.c
index db3b6c2bfe..d2f6914eac 100644
--- a/libavformat/mux.c
+++ b/libavformat/mux.c
@@ -294,6 +294,20 @@ static int init_muxer(AVFormatContext *s, AVDictionary 
**options)
                 goto fail;
             }
         }
+        if (of->flags_internal & FF_OFMT_FLAG_CODEC_ID_LIST) {
+            const enum AVCodecID *codec_list = of->codec_list;
+            av_assert2(codec_list && *codec_list != AV_CODEC_ID_NONE);
+            while (1) {
+                if (par->codec_id == *codec_list)
+                    break;
+                if (*++codec_list == AV_CODEC_ID_NONE) {
+                    av_log(s, AV_LOG_ERROR, "%s muxer does not support codec 
%s\n",
+                           of->p.name, avcodec_get_name(par->codec_id));
+                    ret = AVERROR(EINVAL);
+                    goto fail;
+                }
+            }
+        }
 
         desc = avcodec_descriptor_get(par->codec_id);
         if (desc && desc->props & AV_CODEC_PROP_REORDER)
diff --git a/libavformat/mux.h b/libavformat/mux.h
index 0b69109174..24cd4d92ac 100644
--- a/libavformat/mux.h
+++ b/libavformat/mux.h
@@ -57,6 +57,11 @@ struct AVDeviceInfoList;
  * are disallowed.
  */
 #define FF_OFMT_FLAG_ONLY_DEFAULT_CODECS            (1 << 3)
+/**
+ * If this flag is set, it means that FFOutputFormat.codec_list
+ * is set; otherwise, the union is in query_codec state (which may be NULL).
+ */
+#define FF_OFMT_FLAG_CODEC_ID_LIST                  (1 << 4)
 
 typedef struct FFOutputFormat {
     /**
@@ -101,14 +106,27 @@ typedef struct FFOutputFormat {
      */
     int (*interleave_packet)(AVFormatContext *s, AVPacket *pkt,
                              int flush, int has_packet);
-    /**
-     * Test if the given codec can be stored in this container.
-     *
-     * @return 1 if the codec is supported, 0 if it is not.
-     *         A negative number if unknown.
-     *         MKTAG('A', 'P', 'I', 'C') if the codec is only supported as 
AV_DISPOSITION_ATTACHED_PIC
-     */
-    int (*query_codec)(enum AVCodecID id, int std_compliance);
+    union {
+        /**
+         * Test if the given codec can be stored in this container.
+         * The union is in this state when the FF_OFMT_FLAG_CODEC_ID_LIST flag
+         * is not set.
+         *
+         * @return 1 if the codec is supported, 0 if it is not.
+         *         A negative number if unknown.
+         *         MKTAG('A', 'P', 'I', 'C') if the codec is only supported as 
AV_DISPOSITION_ATTACHED_PIC
+         */
+        int (*query_codec)(enum AVCodecID id, int std_compliance);
+        /**
+         * A list of supported codecs by this muxer.
+         * The union is in this state iff the FF_OFMT_FLAG_CODEC_ID_LIST flag
+         * is set; in this case, any codec not in this list can't be muxed by
+         * this muxer at all.
+         * The list is delimited by AV_CODEC_ID_NONE which must never be
+         * the only entry in this list.
+         */
+        const enum AVCodecID *codec_list;
+    };
 
     void (*get_output_timestamp)(AVFormatContext *s, int stream,
                                  int64_t *dts, int64_t *wall);
@@ -169,6 +187,9 @@ static inline const FFOutputFormat *ffofmt(const 
AVOutputFormat *fmt)
     return (const FFOutputFormat*)fmt;
 }
 
+#define OFMT_CODEC_LIST(...) \
+    .codec_list = (const enum AVCodecID []){ __VA_ARGS__, AV_CODEC_ID_NONE }
+
 /**
  * Add packet to an AVFormatContext's packet_buffer list, determining its
  * interleaved position using compare() function argument.
diff --git a/libavformat/mux_utils.c b/libavformat/mux_utils.c
index 86d333dbe7..d41bbe4a14 100644
--- a/libavformat/mux_utils.c
+++ b/libavformat/mux_utils.c
@@ -34,7 +34,14 @@ int avformat_query_codec(const AVOutputFormat *ofmt, enum 
AVCodecID codec_id,
 {
     if (ofmt) {
         unsigned int codec_tag;
-        if (ffofmt(ofmt)->query_codec)
+        if (ffofmt(ofmt)->flags_internal & FF_OFMT_FLAG_CODEC_ID_LIST) {
+            const enum AVCodecID *codec_list = ffofmt(ofmt)->codec_list;
+            do {
+                if (codec_id == *codec_list)
+                    return 1;
+            } while (*++codec_list != AV_CODEC_ID_NONE);
+            return 0;
+        } else if (ffofmt(ofmt)->query_codec)
             return ffofmt(ofmt)->query_codec(codec_id, std_compliance);
         else if (ofmt->codec_tag)
             return !!av_codec_get_tag2(ofmt->codec_tag, codec_id, &codec_tag);
-- 
2.49.1


>From 72464569574ff88bd9014c40915b66307981c065 Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <[email protected]>
Date: Mon, 15 Dec 2025 16:20:55 +0100
Subject: [PATCH 2/9] avformat/a64: Check codec ids generically

Signed-off-by: Andreas Rheinhardt <[email protected]>
---
 libavformat/a64.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/libavformat/a64.c b/libavformat/a64.c
index 6e722c7e9f..a4ca4d6817 100644
--- a/libavformat/a64.c
+++ b/libavformat/a64.c
@@ -19,6 +19,7 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
+#include "libavutil/avassert.h"
 #include "libavutil/intreadwrite.h"
 #include "libavcodec/codec_id.h"
 #include "libavcodec/codec_par.h"
@@ -54,7 +55,7 @@ static int a64_write_header(AVFormatContext *s)
         header[4] = 3;
         break;
     default:
-        return AVERROR_INVALIDDATA;
+        av_unreachable("Already checked via codec_list");
     }
     avio_write(s->pb, header, 2);
     return 0;
@@ -67,7 +68,8 @@ const FFOutputFormat ff_a64_muxer = {
     .p.video_codec  = AV_CODEC_ID_A64_MULTI,
     .p.audio_codec    = AV_CODEC_ID_NONE,
     .p.subtitle_codec = AV_CODEC_ID_NONE,
-    .flags_internal   = FF_OFMT_FLAG_MAX_ONE_OF_EACH,
+    .flags_internal   = FF_OFMT_FLAG_MAX_ONE_OF_EACH | 
FF_OFMT_FLAG_CODEC_ID_LIST,
+    OFMT_CODEC_LIST(AV_CODEC_ID_A64_MULTI, AV_CODEC_ID_A64_MULTI5),
     .write_header   = a64_write_header,
     .write_packet   = ff_raw_write_packet,
 };
-- 
2.49.1


>From 581535fc4cb3f0dc5d624344f191c5934677a2bd Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <[email protected]>
Date: Mon, 15 Dec 2025 16:22:48 +0100
Subject: [PATCH 3/9] avformat/amr: Check codec ids generically

Signed-off-by: Andreas Rheinhardt <[email protected]>
---
 libavformat/amr.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/libavformat/amr.c b/libavformat/amr.c
index 9cc61baf55..ad4538aeaa 100644
--- a/libavformat/amr.c
+++ b/libavformat/amr.c
@@ -25,6 +25,7 @@ Write and read amr data according to RFC3267, 
http://www.ietf.org/rfc/rfc3267.tx
 
 #include "config_components.h"
 
+#include "libavutil/avassert.h"
 #include "libavutil/channel_layout.h"
 #include "libavutil/intreadwrite.h"
 #include "avformat.h"
@@ -261,7 +262,7 @@ static int amr_write_header(AVFormatContext *s)
     } else if (par->codec_id == AV_CODEC_ID_AMR_WB) {
         avio_write(pb, AMRWB_header, sizeof(AMRWB_header)); /* magic number */
     } else {
-        return -1;
+        av_unreachable("Already checked via codec_list");
     }
     return 0;
 }
@@ -275,7 +276,8 @@ const FFOutputFormat ff_amr_muxer = {
     .p.video_codec     = AV_CODEC_ID_NONE,
     .p.subtitle_codec  = AV_CODEC_ID_NONE,
     .p.flags           = AVFMT_NOTIMESTAMPS,
-    .flags_internal    = FF_OFMT_FLAG_MAX_ONE_OF_EACH,
+    .flags_internal    = FF_OFMT_FLAG_MAX_ONE_OF_EACH | 
FF_OFMT_FLAG_CODEC_ID_LIST,
+    OFMT_CODEC_LIST(AV_CODEC_ID_AMR_NB, AV_CODEC_ID_AMR_WB),
     .write_header      = amr_write_header,
     .write_packet      = ff_raw_write_packet,
 };
-- 
2.49.1


>From 1077e0445ef99197613485d30cd848cb2bc721e7 Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <[email protected]>
Date: Mon, 15 Dec 2025 16:31:33 +0100
Subject: [PATCH 4/9] avformat/icoenc: Check codec ids generically

Signed-off-by: Andreas Rheinhardt <[email protected]>
---
 libavformat/icoenc.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/libavformat/icoenc.c b/libavformat/icoenc.c
index 9eba9e7926..f7292a5aeb 100644
--- a/libavformat/icoenc.c
+++ b/libavformat/icoenc.c
@@ -24,6 +24,7 @@
  * Microsoft Windows ICO muxer
  */
 
+#include "libavutil/avassert.h"
 #include "libavutil/intreadwrite.h"
 #include "libavutil/mem.h"
 
@@ -66,8 +67,7 @@ static int ico_check_attributes(AVFormatContext *s, const 
AVCodecParameters *p)
             return AVERROR(EINVAL);
         }
     } else {
-        av_log(s, AV_LOG_ERROR, "Unsupported codec %s\n", 
avcodec_get_name(p->codec_id));
-        return AVERROR(EINVAL);
+        av_unreachable("Already checked via codec_list");
     }
 
     if (p->width > 256 ||
@@ -207,4 +207,6 @@ const FFOutputFormat ff_ico_muxer = {
     .write_trailer  = ico_write_trailer,
     .deinit         = ico_deinit,
     .p.flags        = AVFMT_NOTIMESTAMPS,
+    .flags_internal = FF_OFMT_FLAG_CODEC_ID_LIST,
+    OFMT_CODEC_LIST(AV_CODEC_ID_BMP, AV_CODEC_ID_PNG),
 };
-- 
2.49.1


>From 5f175d01eeae27d43f92d8bfd5c5b6902e628cd3 Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <[email protected]>
Date: Mon, 15 Dec 2025 16:35:16 +0100
Subject: [PATCH 5/9] avformat/latmenc: Check codec ids generically

Signed-off-by: Andreas Rheinhardt <[email protected]>
---
 libavformat/latmenc.c | 8 +++-----
 1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/libavformat/latmenc.c b/libavformat/latmenc.c
index 05004048aa..6da7864324 100644
--- a/libavformat/latmenc.c
+++ b/libavformat/latmenc.c
@@ -93,10 +93,6 @@ static int latm_write_header(AVFormatContext *s)
 
     if (par->codec_id == AV_CODEC_ID_AAC_LATM)
         return 0;
-    if (par->codec_id != AV_CODEC_ID_AAC && par->codec_id != 
AV_CODEC_ID_MP4ALS) {
-        av_log(s, AV_LOG_ERROR, "Only AAC, LATM and ALS are supported\n");
-        return AVERROR(EINVAL);
-    }
 
     if (par->extradata_size > 0 &&
         latm_decode_extradata(s, par->extradata, par->extradata_size) < 0)
@@ -269,7 +265,9 @@ const FFOutputFormat ff_latm_muxer = {
     .p.audio_codec  = AV_CODEC_ID_AAC,
     .p.video_codec  = AV_CODEC_ID_NONE,
     .p.subtitle_codec = AV_CODEC_ID_NONE,
-    .flags_internal   = FF_OFMT_FLAG_MAX_ONE_OF_EACH,
+    .flags_internal   = FF_OFMT_FLAG_MAX_ONE_OF_EACH |
+                        FF_OFMT_FLAG_CODEC_ID_LIST,
+    OFMT_CODEC_LIST(AV_CODEC_ID_AAC_LATM, AV_CODEC_ID_AAC, AV_CODEC_ID_MP4ALS),
     .write_header   = latm_write_header,
     .write_packet   = latm_write_packet,
     .p.priv_class   = &latm_muxer_class,
-- 
2.49.1


>From 9e62af166607aa304c1a3ace70b692d5ed90d1c0 Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <[email protected]>
Date: Mon, 15 Dec 2025 16:36:59 +0100
Subject: [PATCH 6/9] avformat/lrcenc: Check codec ids generically

Signed-off-by: Andreas Rheinhardt <[email protected]>
---
 libavformat/lrcenc.c | 10 +++-------
 1 file changed, 3 insertions(+), 7 deletions(-)

diff --git a/libavformat/lrcenc.c b/libavformat/lrcenc.c
index bf295dfade..6190dfee6c 100644
--- a/libavformat/lrcenc.c
+++ b/libavformat/lrcenc.c
@@ -43,12 +43,6 @@ static int lrc_write_header(AVFormatContext *s)
 {
     const AVDictionaryEntry *metadata_item;
 
-    if(s->streams[0]->codecpar->codec_id != AV_CODEC_ID_SUBRIP &&
-       s->streams[0]->codecpar->codec_id != AV_CODEC_ID_TEXT) {
-        av_log(s, AV_LOG_ERROR, "Unsupported subtitle codec: %s\n",
-               avcodec_get_name(s->streams[0]->codecpar->codec_id));
-        return AVERROR(EINVAL);
-    }
     avpriv_set_pts_info(s->streams[0], 64, 1, AV_TIME_BASE);
 
     ff_standardize_creation_time(s);
@@ -157,9 +151,11 @@ const FFOutputFormat ff_lrc_muxer = {
     .p.video_codec    = AV_CODEC_ID_NONE,
     .p.audio_codec    = AV_CODEC_ID_NONE,
     .p.subtitle_codec = AV_CODEC_ID_SUBRIP,
-    .flags_internal   = FF_OFMT_FLAG_MAX_ONE_OF_EACH,
+    .flags_internal   = FF_OFMT_FLAG_MAX_ONE_OF_EACH |
+                        FF_OFMT_FLAG_CODEC_ID_LIST,
     .priv_data_size = sizeof(LRCSubtitleContext),
     .write_header   = lrc_write_header,
     .write_packet   = lrc_write_packet,
     .p.priv_class   = &lrcenc_class,
+    OFMT_CODEC_LIST(AV_CODEC_ID_SUBRIP, AV_CODEC_ID_TEXT),
 };
-- 
2.49.1


>From 20b5c4e5031b31a9695185d9086448ffdf70846e Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <[email protected]>
Date: Mon, 15 Dec 2025 16:40:27 +0100
Subject: [PATCH 7/9] avformat/yuv4mpegenc: Check codec ids generically

Signed-off-by: Andreas Rheinhardt <[email protected]>
---
 libavformat/yuv4mpegenc.c | 10 +++-------
 1 file changed, 3 insertions(+), 7 deletions(-)

diff --git a/libavformat/yuv4mpegenc.c b/libavformat/yuv4mpegenc.c
index 371d3745c1..3c3a24aa34 100644
--- a/libavformat/yuv4mpegenc.c
+++ b/libavformat/yuv4mpegenc.c
@@ -221,12 +221,6 @@ static int yuv4_write_packet(AVFormatContext *s, AVPacket 
*pkt)
 
 static int yuv4_init(AVFormatContext *s)
 {
-    if (s->streams[0]->codecpar->codec_id != AV_CODEC_ID_WRAPPED_AVFRAME &&
-        s->streams[0]->codecpar->codec_id != AV_CODEC_ID_RAWVIDEO) {
-        av_log(s, AV_LOG_ERROR, "ERROR: Codec not supported.\n");
-        return AVERROR_INVALIDDATA;
-    }
-
     switch (s->streams[0]->codecpar->format) {
     case AV_PIX_FMT_YUV411P:
         av_log(s, AV_LOG_WARNING, "Warning: generating rarely used 4:1:1 YUV "
@@ -298,5 +292,7 @@ const FFOutputFormat ff_yuv4mpegpipe_muxer = {
     .init              = yuv4_init,
     .write_header      = yuv4_write_header,
     .write_packet      = yuv4_write_packet,
-    .flags_internal    = FF_OFMT_FLAG_MAX_ONE_OF_EACH,
+    .flags_internal    = FF_OFMT_FLAG_MAX_ONE_OF_EACH |
+                         FF_OFMT_FLAG_CODEC_ID_LIST,
+    OFMT_CODEC_LIST(AV_CODEC_ID_WRAPPED_AVFRAME, AV_CODEC_ID_RAWVIDEO),
 };
-- 
2.49.1


>From 051ed8a6ecc3f9f28c2f44d13dbd3f0b59594a9b Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <[email protected]>
Date: Mon, 15 Dec 2025 17:02:37 +0100
Subject: [PATCH 8/9] avformat/segafilmenc: Check codec ids generically

Signed-off-by: Andreas Rheinhardt <[email protected]>
---
 libavformat/segafilmenc.c | 23 +++++++----------------
 1 file changed, 7 insertions(+), 16 deletions(-)

diff --git a/libavformat/segafilmenc.c b/libavformat/segafilmenc.c
index 88a5b9f972..983a3b1a21 100644
--- a/libavformat/segafilmenc.c
+++ b/libavformat/segafilmenc.c
@@ -106,10 +106,9 @@ static int get_audio_codec_id(enum AVCodecID codec_id)
     case AV_CODEC_ID_PCM_S8_PLANAR:
     case AV_CODEC_ID_PCM_S16BE_PLANAR:
         return 0;
+    default:
     case AV_CODEC_ID_ADPCM_ADX:
         return 2;
-    default:
-        return -1;
     }
 }
 
@@ -123,22 +122,10 @@ static int film_init(AVFormatContext *format_context)
 
     for (int i = 0; i < format_context->nb_streams; i++) {
         AVStream *st = format_context->streams[i];
-        if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
-            if (get_audio_codec_id(st->codecpar->codec_id) < 0) {
-                av_log(format_context, AV_LOG_ERROR,
-                       "Incompatible audio stream format.\n");
-                return AVERROR(EINVAL);
-            }
+        if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
             film->audio_index = i;
-        }
 
         if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
-            if (st->codecpar->codec_id != AV_CODEC_ID_CINEPAK &&
-                st->codecpar->codec_id != AV_CODEC_ID_RAWVIDEO) {
-                av_log(format_context, AV_LOG_ERROR,
-                       "Incompatible video stream format.\n");
-                return AVERROR(EINVAL);
-            }
             if (st->codecpar->format != AV_PIX_FMT_RGB24) {
                 av_log(format_context, AV_LOG_ERROR,
                        "Pixel format must be rgb24.\n");
@@ -280,7 +267,11 @@ const FFOutputFormat ff_segafilm_muxer = {
     .p.audio_codec  = AV_CODEC_ID_PCM_S16BE_PLANAR,
     .p.video_codec  = AV_CODEC_ID_CINEPAK,
     .p.subtitle_codec = AV_CODEC_ID_NONE,
-    .flags_internal   = FF_OFMT_FLAG_MAX_ONE_OF_EACH,
+    .flags_internal   = FF_OFMT_FLAG_MAX_ONE_OF_EACH | 
+                        FF_OFMT_FLAG_CODEC_ID_LIST,
+    OFMT_CODEC_LIST(AV_CODEC_ID_CINEPAK, AV_CODEC_ID_RAWVIDEO,
+                    AV_CODEC_ID_PCM_S8_PLANAR, AV_CODEC_ID_PCM_S16BE_PLANAR,
+                    AV_CODEC_ID_ADPCM_ADX),
     .init           = film_init,
     .write_trailer  = film_write_header,
     .write_packet   = film_write_packet,
-- 
2.49.1


>From 6c72e1ffca07dc697118013e9ab19d947e2373bf Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <[email protected]>
Date: Mon, 15 Dec 2025 17:04:42 +0100
Subject: [PATCH 9/9] avformat/supenc: Only allow AV_CODEC_ID_HDMV_PGS_SUBTITLE

Do this by setting the FF_OFMT_FLAG_ONLY_DEFAULT_CODECS flag.

Signed-off-by: Andreas Rheinhardt <[email protected]>
---
 libavformat/supenc.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/libavformat/supenc.c b/libavformat/supenc.c
index c664723bc4..04a21a9e65 100644
--- a/libavformat/supenc.c
+++ b/libavformat/supenc.c
@@ -88,7 +88,8 @@ const FFOutputFormat ff_sup_muxer = {
     .p.audio_codec    = AV_CODEC_ID_NONE,
     .p.subtitle_codec = AV_CODEC_ID_HDMV_PGS_SUBTITLE,
     .p.flags          = AVFMT_VARIABLE_FPS | AVFMT_TS_NONSTRICT,
-    .flags_internal   = FF_OFMT_FLAG_MAX_ONE_OF_EACH,
+    .flags_internal   = FF_OFMT_FLAG_MAX_ONE_OF_EACH |
+                        FF_OFMT_FLAG_ONLY_DEFAULT_CODECS,
     .init             = sup_init,
     .write_packet   = sup_write_packet,
 };
-- 
2.49.1

_______________________________________________
ffmpeg-devel mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to