diff mbox series

[FFmpeg-devel] fftools/cmdutils: extend stream specifiers to match by disposition

Message ID 20240915203248.17917-1-anton@khirnov.net
State New
Headers show
Series [FFmpeg-devel] fftools/cmdutils: extend stream specifiers to match by disposition | expand

Checks

Context Check Description
yinshiyou/make_loongarch64 success Make finished
yinshiyou/make_fate_loongarch64 success Make fate finished
andriy/make_x86 success Make finished
andriy/make_fate_x86 success Make fate finished

Commit Message

Anton Khirnov Sept. 15, 2024, 8:32 p.m. UTC
---
 Changelog                              |  1 +
 doc/fftools-common-opts.texi           |  4 +++
 fftools/cmdutils.c                     | 41 ++++++++++++++++++++++++++
 fftools/cmdutils.h                     |  2 ++
 tests/fate/ffmpeg.mak                  |  4 +++
 tests/ref/fate/ffmpeg-spec-disposition |  7 +++++
 6 files changed, 59 insertions(+)
 create mode 100644 tests/ref/fate/ffmpeg-spec-disposition
diff mbox series

Patch

diff --git a/Changelog b/Changelog
index b6f91d7c8c..abe99075e8 100644
--- a/Changelog
+++ b/Changelog
@@ -21,6 +21,7 @@  version <next>:
 - MediaCodec AAC/AMR-NB/AMR-WB/MP3 decoding
 - YUV colorspace negotiation for codecs and filters, obsoleting the
   YUVJ pixel format
+- stream specifiers in fftools can now match by stream disposition
 
 
 version 7.0:
diff --git a/doc/fftools-common-opts.texi b/doc/fftools-common-opts.texi
index 1974d79a4c..4e48789def 100644
--- a/doc/fftools-common-opts.texi
+++ b/doc/fftools-common-opts.texi
@@ -79,6 +79,10 @@  Match the stream by stream id (e.g. PID in MPEG-TS container).
 Matches streams with the metadata tag @var{key} having the specified value. If
 @var{value} is not given, matches streams that contain the given tag with any
 value.
+@item disp:@var{dispositions}[:@var{additional_stream_specifier}]
+Matches streams with the given disposition(s). @var{dispositions} is a list of
+one or more dispositions (as printed by the @option{-dispositions} option)
+joined with '+'.
 @item u
 Matches streams with usable configuration, the codec must be defined and the
 essential information such as video dimension or audio sample rate must be present.
diff --git a/fftools/cmdutils.c b/fftools/cmdutils.c
index 1573106d8b..8d06358cac 100644
--- a/fftools/cmdutils.c
+++ b/fftools/cmdutils.c
@@ -1091,6 +1091,43 @@  int stream_specifier_parse(StreamSpecifier *ss, const char *spec,
 
             av_log(logctx, AV_LOG_TRACE,
                    "Parsed program ID: %"PRId64"; remainder: %s\n", ss->list_id, spec);
+        } else if (!strncmp(spec, "disp:", 5)) {
+            const AVClass *st_class = av_stream_get_class();
+            const AVOption       *o = av_opt_find(&st_class, "disposition", NULL, 0, AV_OPT_SEARCH_FAKE_OBJ);
+            char *disp = NULL;
+            size_t len;
+
+            av_assert0(o);
+
+            if (ss->disposition) {
+                av_log(logctx, AV_LOG_ERROR, "Multiple disposition specifiers\n");
+                ret = AVERROR(EINVAL);
+                goto fail;
+            }
+
+            spec += 5;
+
+            for (len = 0; cmdutils_isalnum(spec[len]) ||
+                          spec[len] == '_' || spec[len] == '+'; len++)
+                continue;
+
+            disp = av_strndup(spec, len);
+            if (!disp) {
+                ret = AVERROR(ENOMEM);
+                goto fail;
+            }
+
+            ret = av_opt_eval_flags(&st_class, o, disp, &ss->disposition);
+            av_freep(&disp);
+            if (ret < 0) {
+                av_log(logctx, AV_LOG_ERROR, "Invalid disposition specifier\n");
+                goto fail;
+            }
+
+            spec += len;
+
+            av_log(logctx, AV_LOG_TRACE,
+                   "Parsed disposition: 0x%x; remainder: %s\n", ss->disposition, spec);
         } else if (*spec == '#' ||
                    (*spec == 'i' && *(spec + 1) == ':')) {
             if (ss->stream_list != STREAM_LIST_ALL)
@@ -1281,6 +1318,10 @@  unsigned stream_specifier_match(const StreamSpecifier *ss,
             }
         }
 
+        if (ss->disposition &&
+            (candidate->disposition & ss->disposition) != ss->disposition)
+            continue;
+
         if (st == candidate)
             return ss->idx < 0 || ss->idx == nb_matched;
 
diff --git a/fftools/cmdutils.h b/fftools/cmdutils.h
index 9441d5726b..e74aa2a98d 100644
--- a/fftools/cmdutils.h
+++ b/fftools/cmdutils.h
@@ -130,6 +130,8 @@  typedef struct StreamSpecifier {
 
     uint8_t              usable_only;
 
+    int                  disposition;
+
     char                *meta_key;
     char                *meta_val;
 
diff --git a/tests/fate/ffmpeg.mak b/tests/fate/ffmpeg.mak
index 3ffaaeb295..869376dd18 100644
--- a/tests/fate/ffmpeg.mak
+++ b/tests/fate/ffmpeg.mak
@@ -263,3 +263,7 @@  fate-ffmpeg-loopback-decoding: CMD = transcode \
     "rawvideo -s 352x288 -pix_fmt yuv420p" $(TARGET_PATH)/tests/data/vsynth1.yuv nut \
     "-map 0:v:0 -c:v mpeg2video -f null - -flags +bitexact -idct simple -threads $$threads -dec 0:0 -filter_complex '[0:v][dec:0]hstack[stack]' -map '[stack]' -c:v ffv1" ""
 FATE_FFMPEG-$(call ENCDEC2, MPEG2VIDEO, FFV1, NUT, HSTACK_FILTER PIPE_PROTOCOL FRAMECRC_MUXER) += fate-ffmpeg-loopback-decoding
+
+# test matching by stream disposition
+fate-ffmpeg-spec-disposition: CMD = framecrc -i $(TARGET_SAMPLES)/mpegts/pmtchange.ts -map '0:disp:visual_impaired+descriptions:1' -c copy
+FATE_FFMPEG-$(call FRAMECRC, MPEGTS,,) += fate-ffmpeg-spec-disposition
diff --git a/tests/ref/fate/ffmpeg-spec-disposition b/tests/ref/fate/ffmpeg-spec-disposition
new file mode 100644
index 0000000000..4f24619d2b
--- /dev/null
+++ b/tests/ref/fate/ffmpeg-spec-disposition
@@ -0,0 +1,7 @@ 
+#tb 0: 1/90000
+#media_type 0: audio
+#codec_id 0: ac3
+#sample_rate 0: 48000
+#channel_layout_name 0: stereo
+0,          0,          0,     2880,      768, 0x72b37931, F=0x3, S=1,        1
+0,       2880,       2880,     2880,      690, 0xa84a4ea2