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 B8EDA4DD58 for ; Mon, 5 Jan 2026 16:45:20 +0000 (UTC) Authentication-Results: ffbox; dkim=fail (body hash mismatch (got b'J7WflqmVlsHKuI1j+dIro96IjiyVU7D01mAp28yt0vU=', expected b'3GZ0en3FaPKLqDc+2kOPUJQBMsJJsuflMzzmLhN6DDk=')) header.d=gmail.com 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=1767631506; h=to : date : message-id : mime-version : 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=QxaScxv2oCwuasz/I4tEWdsZJcfQIgbeFVUjWNKw9q4=; b=5FY5HbhETNJL0gv29BqK7jfTofNrMEw8fFg1jsbOe5BiaZi1jl8ElekKuS2gbIZc9hUxt 8J4pvfhZPmQ3adAuOfwgEtZ5FBc80VIh28CbqGFyP+w7hZj8o/6sfFAne6pRZscsXod1PDA EkDyyJnikCDnOUWLoVRkKH5WjeVg9d/iBWTfUiG6D26gKxQBE1C/cKkpBpI9Vrv2Ale4c79 TjCGz1E5L/t377RTfVfcVEuPD+IrU4bCsLovMchtohu1sKG9TA7lwjc9Z3sUv7+sg9D16f0 boqaSz6+YYyXacVTM5jjoNjhEdNH76YbV1oAuixx8SFEykrYHGxG89IhpbuA== Received: from [172.20.0.4] (unknown [172.20.0.4]) by ffbox0-bg.ffmpeg.org (Postfix) with ESMTP id 9FEBD690D89; Mon, 5 Jan 2026 18:45:06 +0200 (EET) ARC-Seal: i=1; cv=none; a=rsa-sha256; d=ffmpeg.org; s=arc; t=1767631482; b=DRHJ+hE2U5a7jiVypQCxcgiO4pfwYV2dotjsT10pjIuO8lwJWU3nkenScQI4fWyqDG+wo einxQmjswYqCPeJdvrzbpwtgk3PDUjsTJEjc1Jawrf488OVAeM0LMQpQdjNFWuP6mZhWz19 QXupIuUzgbYwpb99ipUOSiCr00NJTqDx+m1HgA8Edqp/297CQXTUFV72kRvhZvH1bbF2nn7 LCdEoi1GgrRVtZ3rzt7nzPWM4xwROUs2O2zjSzwJZz+YjUVLRzqLLbIQgc/y77QYLIQGNIh OaUPCu0r4wGIMZlFSN1ohGO8Ge6/9F4n+yxp6PfQr+c+wt9ZKZmBcoA23kzw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=ffmpeg.org; s=arc; t=1767631482; 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=J7WflqmVlsHKuI1j+dIro96IjiyVU7D01mAp28yt0vU=; b=PDyj/7LOzhVWxDMrN7z2bPwZfw+ybcrDixeBxHqopJbH/0O5lUkERvBMmrR69NTUSG2qJ GINBIIalSp2MTJu1TBuftBRpTFKL6n9cMkO56QXNXkmHlfuwZ9Cax56YF7fS8uLBBLFWC5q XvK2crrMvDG6ueWwx7B9d/FdiGP7IjWt6sP/397qwJyJoz5dkszKYHbnC1wdZ/EZ+Ob6Ckw F0VHZz6dHbVh4aCJnm9Y90QOuZr8ac5LNRBnL1/90+T8eWqz9RTy1oGjUeLyAME21cuLdDo 60HgIlJd6p5qEy6KaIKBWAL4oISSmPgBipprJCLLne5EKR8PNyTxdKYfikow== ARC-Authentication-Results: i=1; ffmpeg.org; dkim=pass header.d=gmail.com; arc=none; dmarc=pass header.from=gmail.com policy.dmarc=quarantine Authentication-Results: ffmpeg.org; dkim=pass header.d=gmail.com; arc=none (Message is not ARC signed); dmarc=pass (Used From Domain Record) header.from=gmail.com policy.dmarc=quarantine Received: from mail-pl1-f182.google.com (mail-pl1-f182.google.com [209.85.214.182]) by ffbox0-bg.ffmpeg.org (Postfix) with ESMTPS id 8F12868E6D7 for ; Mon, 5 Jan 2026 18:44:29 +0200 (EET) Received: by mail-pl1-f182.google.com with SMTP id d9443c01a7336-29f102b013fso953995ad.2 for ; Mon, 05 Jan 2026 08:44:29 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1767631467; x=1768236267; darn=ffmpeg.org; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:from:to:cc:subject:date:message-id:reply-to; bh=3GZ0en3FaPKLqDc+2kOPUJQBMsJJsuflMzzmLhN6DDk=; b=TtFHYF60sLmSch0j/We6cykIg6hIxE5+ydEmUnhWMeCmdi2byjoDXcCRytr7mkxTfS D7jQB8raFX18Ivheaes4crsMznTGryL+5mkH7oKAz9yTPiUAxV5Zh6md2pzLiQB046Ea RKzpgIYfOXXU160d6dg9e8MNzz9ClGoEA8u8tujm8WPtgz8muR/p3n3E0rialOkrZLjo ryl9XKZg9Csd0DNwVko7tZtEQao9ZKFcr9098YjOhfavX+hYJ+IRTEBsT0F4KFCJBnxp imNRsWs1Ik/olRlYvhKpmXnLpu+MtZr3Ie4c3AUhlfIvm1oVRkF+kT9p1T2jUCP8sJXQ gZhA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1767631467; x=1768236267; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-gg:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=3GZ0en3FaPKLqDc+2kOPUJQBMsJJsuflMzzmLhN6DDk=; b=u6PEELJIfCQqjim74PSMFQQV7H/GdJLnWTGjaOEJ1mf7L+VG+xcLXoP+Dq55uc5ckL A3Zovyc1TewsUjVkIvdPHmo/vfOZ88jpNK/F6xqxJHpl4xwEbLGsmn46CK/kJByoB8jg A9AOaPp9miXjxwxnpmwJyQO5l+S6IcoaE3LEhWZik1ojC/817AMvYleHSEcv3fIAOWOD taTpHz5Vt8Iegrw5IowQErcRjq81vez5yAV6Ym3PVo70SJ2hYB76g319gJyK0Lr7OVsY LaSWRsjjVgGT6DUffQAyhipx1jNeAEvIwx6OZO90r2Kr8McTNMRzn1FKgtX/1QN6yWZe On3g== X-Gm-Message-State: AOJu0YwrRg9gv2kjhuctL+hWon/CK5KsOltjsDDzMS/QS+Y/la7KrZwt edGH8K321TJ3QAo5oXt2bcKcv4G9e5ouYjwA7AFNgedrrLnrq+FuljIMDlrQTVb299U= X-Gm-Gg: AY/fxX6wnrrkmfaBivoZL8+weWqc1VcBdtPNAfccOMqwb/wa9bQCXT+GVRLyTq1ayTs Mh+HKm7bLI7uFB9YT8nbRoOETfCgEdfX51DZJKqAAfJTSgq4f1wiA1iZyA83eKuESFg+YSMzrBl Dasdi8+kRy3FM7FijRaJyIiv6khTHP3Tj66Rq0XaatAXrhExeZ+oyU7dpPORSrXLoEuScLGm5K5 +2GJBPDEO5t7fpXJU0o7mrt/vG4LofyE0UHFABFSfjo6OoF0lyd/Zg+K9qPKyr5HKf2fBJTCK/5 4LpF2y56rsyJD8841MSalHndgHymEVylCQ8uwG7I/p+QZdY16jOaWLwDMZ7kRCzsCi4xjyI/K6K cieJwleQ2PHAE7kEhky/BGbzjvwZPlg67FIP4tiP+K21x0XkGYm4K6S0Z6YsmpXYYfuX4jKO5sE QltO3Qetjq18wfM6kWH3VQ X-Google-Smtp-Source: AGHT+IEKiFA6IvxX4HRGsjTjrpagw0fxeuUUXuDKL05Dv8W1vIk5XzgeamdJMTiLCXh4Z6rqnbS7wA== X-Received: by 2002:a17:902:d488:b0:2a0:d33d:a8f0 with SMTP id d9443c01a7336-2a3e2e22ed5mr2538695ad.50.1767631466832; Mon, 05 Jan 2026 08:44:26 -0800 (PST) Received: from Family.localdomain ([49.43.26.123]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2a3e2b91cc6sm2598175ad.85.2026.01.05.08.44.25 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 05 Jan 2026 08:44:26 -0800 (PST) To: ffmpeg-devel@ffmpeg.org Date: Mon, 5 Jan 2026 22:14:19 +0530 Message-Id: <20260105164419.5067-1-cordacct2001@gmail.com> X-Mailer: git-send-email 2.34.1 MIME-Version: 1.0 Message-ID-Hash: RR76BQOX43UNZ5D4JCDU7K55MFSHPARH X-Message-ID-Hash: RR76BQOX43UNZ5D4JCDU7K55MFSHPARH X-MailFrom: SRS0=Vj7b=7K=gmail.com=cordacct2001@ffmpeg.org 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; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.10 Precedence: list Reply-To: FFmpeg development discussions and patches Subject: [FFmpeg-devel] [PATCH] fftools/ffmpeg_opt: addition of index selector to metadata stream specifier 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 <40858007+Jarvis2001@users.noreply.github.com>, Practice2001 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Archived-At: List-Archive: List-Post: From: Practice2001 <40858007+Jarvis2001@users.noreply.github.com> 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 command: ffmpeg -i input.mkv -map 0:s:m:language:fre:0 -c copy output.sup This correctly selects the second French subtitle stream in my test file. All current FATE tests pass. Signed-off-by: Practice2001 <40858007+Jarvis2001@users.noreply.github.com> --- doc/fftools-common-opts.texi | 7 ++++--- fftools/cmdutils.c | 31 ++++++++++++++++++++++++++----- tests/fate/ffmpeg.mak | 15 +++++++++++++++ 3 files changed, 45 insertions(+), 8 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 e906d4506d..ca3641ceed 100644 --- a/fftools/cmdutils.c +++ b/fftools/cmdutils.c @@ -962,8 +962,7 @@ FILE *get_preset_file(char *filename, size_t filename_size, datadir, desired_size, sizeof *datadir); if (new_datadir) { datadir = new_datadir; - datadir[datadir_len] = 0; - strncat(datadir, "/ffpresets", desired_size - 1 - datadir_len); + strcpy(datadir + datadir_len, "/ffpresets"); base[2] = datadir; } } @@ -1024,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); @@ -1176,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++; @@ -1192,6 +1192,27 @@ int stream_specifier_parse(StreamSpecifier *ss, const char *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) { av_log(logctx, AV_LOG_ERROR, diff --git a/tests/fate/ffmpeg.mak b/tests/fate/ffmpeg.mak index 57028a7936..297e9d55ae 100644 --- a/tests/fate/ffmpeg.mak +++ b/tests/fate/ffmpeg.mak @@ -280,3 +280,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)/subtitles/multi-french.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)/subtitles/multi-french.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)/subtitles/multi-french.mkv \ + -map 0:s:m:language:fre:99 -c copy -f null - ; test $$? -ne 0 -- 2.52.0.windows.1 _______________________________________________ ffmpeg-devel mailing list -- ffmpeg-devel@ffmpeg.org To unsubscribe send an email to ffmpeg-devel-leave@ffmpeg.org