From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from ffbox0-bg.ffmpeg.org (ffbox0-bg.ffmpeg.org [79.124.17.100]) by master.gitmailbox.com (Postfix) with ESMTPS id C065D4EF43 for ; Fri, 20 Feb 2026 12:28:40 +0000 (UTC) Authentication-Results: ffbox; dkim=fail (body hash mismatch (got b'fhvvBDCj0CdcFsH04Q+pn9sTxPO3KjCrQlwmBg7ngiQ=', expected b'uaqU8DOIwv2D/tFUYBH4Ns3uxJAum8L+rQpo6GZFe0s=')) header.d=ffmpeg.org header.i=@ffmpeg.org header.a=rsa-sha256 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ffmpeg.org; i=@ffmpeg.org; q=dns/txt; s=mail; t=1771590499; h=mime-version : to : date : message-id : reply-to : subject : list-id : list-archive : list-archive : list-help : list-owner : list-post : list-subscribe : list-unsubscribe : from : cc : content-type : content-transfer-encoding : from; bh=fhvvBDCj0CdcFsH04Q+pn9sTxPO3KjCrQlwmBg7ngiQ=; b=0UGGoYnsvM5/fFSH8Rur+yr/lN89LyHN4csCQ4l8CZMX9ZcLwcOOChezkxja+IBn78sGd Lvemz9B36OuYgch+wtY5LgGEZraEIL7sQdsesIFdwpX9GnLQSkCsSTmOa/lWO6EjOaeoJrb 6UFCrWQApw5hcA0LI/sZvRbR2FKn+ssplUjMoZUoeqyt3gvRn4/lV2e3sKaTIvAMZE9ns8a 7y3gsRisgQgSS9frtgJxIHQLCL+s4fvz2X2193CisEfW1UXGf0KXeSJ95We+clZ3C9F+Sxq AY+toY7XNWzqEKSLsfdsWMC0yeaM6mgrda2Lv/uQEy0Nr450s0r/yd/qpkAQ== Received: from [172.18.0.3] (unknown [172.18.0.3]) by ffbox0-bg.ffmpeg.org (Postfix) with ESMTP id 034C769128C; Fri, 20 Feb 2026 14:28:19 +0200 (EET) ARC-Seal: i=1; cv=none; a=rsa-sha256; d=ffmpeg.org; s=arc; t=1771590487; b=lQovpIOh3XhcUqG6LTnVw1RLxTOJ2s+Jrwlz8n4R+8WSpRcPiSf5bUdRFSGXU+CGgEzez cTs+eZd0H1q4DL771Uy3rPgq6zQAUVkHF4xF2mJWYvz2RxWmyLEw2XCbWiZFUFdn4pGYd1r NXa+M2xDBlhNSQweAYmbfWm6cAqloeR/6VBlQ67vpVLDeckKcM8oXKXKfanIrWEeTOBBzpI U7/34T0EVdpSk/P4npY4Zn3Eag921l+lRC4wXNJl1w+A3w8bHWxHVSYKimRyld2kk6fis4D KKd1oVJjoj6jeFMTIC86ciKZRJnZ84nyrMcOMx4CjpVqRxNoH0stzfakh3YA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=ffmpeg.org; s=arc; t=1771590487; h=from : sender : reply-to : subject : date : message-id : to : cc : mime-version : content-type : content-transfer-encoding : content-id : content-description : resent-date : resent-from : resent-sender : resent-to : resent-cc : resent-message-id : in-reply-to : references : list-id : list-help : list-unsubscribe : list-subscribe : list-post : list-owner : list-archive; bh=bEiXuSCjYH9qZ5rBEnxGriY38/ET7xiYNs0g0XGKWV4=; b=bbfjFr91kwW/to7W3cH3z9RBwf1+ul0vMuH0HoVzTecLxBLBmzImhxrV+fNNtqPxDfmQ+ eP7BhA0S2YgnH1oHVfkzYSLaq9g+pCQTbv7/qA+/0Y6t8NcK69gbGicnA2Yv1JRLVsdrcno whdoLBkKkGzl0jQ7Y8C8d/D+jYWV7RVuuLhhYV76rHaexr+N222Cjq8HFVHDM4GxeVAfW8+ YABFStz8SOegVXxBuEo1cS8YV7NkkIAKG+BbZok6VpQo7uFctOJNAJtufj9xLfxmvQynmBc Glp2koBqZXTA2LYRHet6BdfixWePPdapC+7uuh/8v6K8/sa+zXDqkO4CfIGA== ARC-Authentication-Results: i=1; ffmpeg.org; dkim=pass header.d=ffmpeg.org header.i=@ffmpeg.org; arc=none; dmarc=pass header.from=ffmpeg.org policy.dmarc=quarantine Authentication-Results: ffmpeg.org; dkim=pass header.d=ffmpeg.org header.i=@ffmpeg.org; arc=none (Message is not ARC signed); dmarc=pass (Used From Domain Record) header.from=ffmpeg.org policy.dmarc=quarantine DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ffmpeg.org; i=@ffmpeg.org; q=dns/txt; s=mail; t=1771590479; h=content-type : mime-version : content-transfer-encoding : from : to : reply-to : subject : date : from; bh=uaqU8DOIwv2D/tFUYBH4Ns3uxJAum8L+rQpo6GZFe0s=; b=Z5l26aBp+gZy5VK946TaXiqFiNwJBQuSWrS7h6gX06mammeWc42MTrbtYtvjZfTUr+fYe RqyT944tEmrRM1DrZisp5gPmgQyJ+60F7x7PMUcnAuYJmshcB6d5jVIZkNm40cme0xd5JWa dOrgkp7+DfDjVNLF6h3v1h+QcvVZ7/oSPJOWVqzW2zYrVC5u1aKJx7cPRU4RJ3GU6MtmvWv I/1o3R0Fgo+L2v5EfZRgIOs+cX3yFanOzzUP3nTl7Vgk5nbE5vtYSW2Nhjtd8qq2NKKHAne gUQyyP2h43Y2qNLYViJkdTnQKZZcIAzNYEw1B3sgF2H3LzOV1zplLZcVRrWQ== MIME-Version: 1.0 To: ffmpeg-devel@ffmpeg.org Date: Fri, 20 Feb 2026 12:27:59 -0000 Message-ID: <177159047989.25.17262515333075404447@29965ddac10e> Message-ID-Hash: K6P76M6CHQJJT5EVQLEN2TXAZR5IY4VH X-Message-ID-Hash: K6P76M6CHQJJT5EVQLEN2TXAZR5IY4VH X-MailFrom: code@ffmpeg.org X-Mailman-Rule-Hits: nonmember-moderation X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; header-match-ffmpeg-devel.ffmpeg.org-0; header-match-ffmpeg-devel.ffmpeg.org-1; header-match-ffmpeg-devel.ffmpeg.org-2; header-match-ffmpeg-devel.ffmpeg.org-3; emergency; member-moderation X-Mailman-Version: 3.3.10 Precedence: list Reply-To: FFmpeg development discussions and patches Subject: [FFmpeg-devel] [PR] [PATCH] fftools: add optional index selector to metadata stream specifier (PR #21812) List-Id: FFmpeg development discussions and patches Archived-At: Archived-At: List-Archive: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: From: Practice2001 via ffmpeg-devel Cc: Practice2001 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Archived-At: List-Archive: List-Post: PR #21812 opened by Practice2001 URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/21812 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/21812.patch This patch introduces an optional index selector to the metadata stream specifier (e.g., -map 0:s:m:language:fre:0). Currently, mapping streams by metadata (like language) selects all matching streams. This is problematic in files with multiple streams of the same language (e.g., a full French subtitle track and a forced/SDH French track). While users can currently find the absolute stream index via ffprobe, this is cumbersome for batch processing where indices vary across files. By adding a trailing index, users can now select a specific occurrence from the subset of streams that matched the metadata criteria. Example: -map 0:s:m:language:fre:0 # Selects only the first French subtitle -map 0:s:m:language:fre:1 # Selects only the second French subtitle I have verified this change with the following commands: ffmpeg -i /home/family/ffmpeg_sources/ffmpeg/fate-suite/mkv/dummy_multistream.mkv -map 0:s:m:language:fre:0 -c:s ass output.ass ffmpeg -i /home/family/ffmpeg_sources/ffmpeg/fate-suite/mkv/dummy_multistream.mkv -map 0:s:m:language:fre:0 -c:s srt output.srt This selects the first French subtitle stream in my test file. **Note**: the mapping works independently of the output codec; the -c copy or compatible subtitle encoder must be used for writing the file format. Example: ffmpeg -i /home/family/ffmpeg_sources/ffmpeg/fate-suite/mkv/dummy_multistream.mkv -map 0:s:m:language:fre:0 -c:s hdmv_pgs_subtitle output.sup All current FATE tests(original + new tests in this PR) pass on my local machine. I have added those tests as comments, since the attached sample file is not present in the FATE suite. I did send a couple of requests to add that file. Closes: #20149 >>From d8f401c70fed82861f7ece430182b64b5e52862d Mon Sep 17 00:00:00 2001 From: Practice2001 <40858007+Jarvis2001@users.noreply.github.com> Date: Fri, 20 Feb 2026 15:26:17 +0530 Subject: [PATCH] [PATCH] fftools: add index selector to metadata stream specifier --- doc/fftools-common-opts.texi | 7 ++++--- fftools/cmdutils.c | 28 +++++++++++++++++++++++++--- tests/fate/ffmpeg.mak | 15 +++++++++++++++ 3 files changed, 44 insertions(+), 6 deletions(-) diff --git a/doc/fftools-common-opts.texi b/doc/fftools-common-opts.texi index 7b5a11b634..a42e85d91b 100644 --- a/doc/fftools-common-opts.texi +++ b/doc/fftools-common-opts.texi @@ -75,11 +75,12 @@ are part of the program and match the @var{additional_stream_specifier}. @item #@var{stream_id} or i:@var{stream_id} Match the stream by stream id (e.g. PID in MPEG-TS container). -@item m:@var{key}[:@var{value}] +@item m:@var{key}[:@var{value}][:@var{stream_index}] 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. The colon character ':' in @var{key} or @var{value} needs to be -backslash-escaped. +value. If @var{stream_index} is given, matches the @var{stream_index}-th stream +among those matching the key/value criteria. The colon character ':' in +@var{key} or @var{value} needs to be backslash-escaped. @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) diff --git a/fftools/cmdutils.c b/fftools/cmdutils.c index 9a365c228d..0dc8e3c5e9 100644 --- a/fftools/cmdutils.c +++ b/fftools/cmdutils.c @@ -1023,7 +1023,7 @@ int stream_specifier_parse(StreamSpecifier *ss, const char *spec, av_log(logctx, AV_LOG_TRACE, "Parsing stream specifier: %s\n", spec); while (*spec) { - if (*spec <= '9' && *spec >= '0') { /* opt:index */ + if (ss->idx == -1 && *spec <= '9' && *spec >= '0') { /* opt:index */ ss->idx = strtol(spec, &endptr, 0); av_assert0(endptr > spec); @@ -1175,8 +1175,9 @@ int stream_specifier_parse(StreamSpecifier *ss, const char *spec, "Parsed metadata: %s:%s; remainder: %s", ss->meta_key, ss->meta_val ? ss->meta_val : "", spec); - // this terminates the specifier - break; + if (*spec == ':') spec++; + + // continue parsing for possible index } else if (*spec == 'u' && (*(spec + 1) == '\0' || *(spec + 1) == ':')) { ss->usable_only = 1; spec++; @@ -1190,6 +1191,27 @@ int stream_specifier_parse(StreamSpecifier *ss, const char *spec, if (*spec == ':') spec++; } + + if (*spec >= '0' && *spec <= '9') { + char *endptr; + + ss->idx = strtol(spec, &endptr, 0); + + av_log(logctx, AV_LOG_TRACE, + "Parsed trailing index: %d; remainder: %s\n", ss->idx, endptr); + + spec = endptr; + } else if (*spec == ':' && *(spec + 1) >= '0' && *(spec + 1) <= '9') { + char *endptr; + + spec++; + ss->idx = strtol(spec, &endptr, 0); + + av_log(logctx, AV_LOG_TRACE, + "Parsed trailing index: %d; remainder: %s\n", ss->idx, endptr); + + spec = endptr; + } if (*spec) { if (!allow_remainder) { diff --git a/tests/fate/ffmpeg.mak b/tests/fate/ffmpeg.mak index cd00275638..5851fd8903 100644 --- a/tests/fate/ffmpeg.mak +++ b/tests/fate/ffmpeg.mak @@ -290,3 +290,18 @@ FATE_SAMPLES_FFMPEG-$(call FRAMECRC, MOV, HEVC, HEVC_PARSER) += fate-ffmpeg-heif # binding the internal filtegraph with a caller defined filtergraph fate-ffmpeg-heif-merge-filtergraph: CMD = framecrc -i $(TARGET_SAMPLES)/heif-conformance/C007.heic -filter_complex "sws_flags=+accurate_rnd+bitexact\;[0:g:0]scale=w=1280:h=720[out]" -map "[out]" FATE_SAMPLES_FFMPEG-$(call FRAMECRC, MOV, HEVC, HEVC_PARSER SCALE_FILTER) += fate-ffmpeg-heif-merge-filtergraph + +# # Test: Select first French subtitle from multiple French subtitles +# FATE_FFMPEG += fate-ffmpeg-map-metadata-index-0 +# fate-ffmpeg-map-metadata-index-0: CMD = ffmpeg -i $(TARGET_SAMPLES)/mkv/dummy_multistream.mkv \ +# -map 0:s:m:language:fre:0 -c copy -f null - + +# # Test: Select second French subtitle +# FATE_FFMPEG += fate-ffmpeg-map-metadata-index-1 +# fate-ffmpeg-map-metadata-index-1: CMD = ffmpeg -i $(TARGET_SAMPLES)/mkv/dummy_multistream.mkv \ +# -map 0:s:m:language:fre:1 -c copy -f null - + +# # Test: Error on out-of-range index +# FATE_FFMPEG += fate-ffmpeg-map-metadata-index-error +# fate-ffmpeg-map-metadata-index-error: CMD = ffmpeg -i $(TARGET_SAMPLES)/mkv/dummy_multistream.mkv \ +# -map 0:s:m:language:fre:99 -c copy -f null - ; test $$? -ne 0 -- 2.52.0 _______________________________________________ ffmpeg-devel mailing list -- ffmpeg-devel@ffmpeg.org To unsubscribe send an email to ffmpeg-devel-leave@ffmpeg.org