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 4D2734DD65 for ; Mon, 5 Jan 2026 16:53:36 +0000 (UTC) Authentication-Results: ffbox; dkim=fail (body hash mismatch (got b'f4furN84wBSoaGSb0RdaIvzRWmyFKIjJLIQWDwHcWPk=', expected b'SJtmgrqUuV3P8oLjNzbvd9+zGjYs3p7x/advBaiWf6c=')) 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=1767632000; 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=PQY0ep0eT8KL/MvQNtLG5ylxnVsKJlxY1vOiEknqmzw=; b=PEcm0AcvIPyiQ4xSlWeb3Vui2tpAW47urtDxE8uhdJICHslbijujBmrjOXA5sQYvovBPA +0tpfnUb2pYCXyBQLEk/aVc1i8NOVAVIVg5FqZwbKC1+pf0lWC4qFkKRSREXimbJlZAGgUp 2eGqQ2w9AXgabBJeF9rUhdsmvxgpYqH50nUetqeYNL6SIa0p8jbJjiGHUyiYN5WUYz3Q4I9 8M+Bcz1qcr7AHpRXhtbXozug5ryKxa1eKx1qEALs4GWHD9U+Ns8uDsNS2cFjVOb2KTzRn7v 8HfEOz8e3jMfqHoHyWLVxYwXgxbuPewYU2zJvxqdLelz5YgLS+WRyrtw53tA== Received: from [172.20.0.4] (unknown [172.20.0.4]) by ffbox0-bg.ffmpeg.org (Postfix) with ESMTP id 10AB9690D78; Mon, 5 Jan 2026 18:53:20 +0200 (EET) ARC-Seal: i=1; cv=none; a=rsa-sha256; d=ffmpeg.org; s=arc; t=1767631982; b=c+X5nBdCVRwyfTHyM7RbYQi/tc7sdgRiIbAbiODegu41P9U1k+14rHwVssvi0Em3hSsgK hl1dZa2uw+ze5mz8zICPEtTG9J1T58O4/7RXBP5/xUKOc+4+KFngPl0f2Af/F9xB2iv9eBz uKUd1vhnZ9Uon1XFKG4IctmvOMKUSfDmuTvI7Lhkif3VeOLSpEl8GIO1folW9fyUGiEGUim 4s3A+at30i2uUC3YiAbFQjTqk7WY8B/JipfoovP5colBWD5ccdAoBpo2S4zPIcwATuuoc1G TAWKAc0Hs5Zw0kXcMWXjAkmttjp7gmU5RW3REvNNiCIM4xTE9KT+ztcM2AlQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=ffmpeg.org; s=arc; t=1767631982; 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=f4furN84wBSoaGSb0RdaIvzRWmyFKIjJLIQWDwHcWPk=; b=Mkpofe6pJ+3d7lQo7V7Xi6aEdWBwgHTkfVXLS3lrJx8Cf3iotDBr14uyY875hjdJaqyi2 0AGUSht0jy4H2d1ea+Shv/o6F6wG4G7ZElR34Kc/JQOLduApYytnT/1LW6Z/9Fl+cFGljTO xlEGOseOEzPlrC03SpIexyx5MXXi0y/zn4qhd5xFedCULR0fwir+cqxJ0TSqulcTY1xjm5e vT+phCjwpsqn5t8iZ3nYQbzWDkxeqZmVw01wWQahdYIH6TGxyfvXHRsE8cfg/eW/OtJXBYP zoj96qySZyab3Ut/3CoFkZnpIkLGmeYJf87su7gr0QegLfX6xvNRdYSPZpaw== 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-f180.google.com (mail-pl1-f180.google.com [209.85.214.180]) by ffbox0-bg.ffmpeg.org (Postfix) with ESMTPS id 594CB68F436 for ; Mon, 5 Jan 2026 18:52:49 +0200 (EET) Received: by mail-pl1-f180.google.com with SMTP id d9443c01a7336-2a0834769f0so994145ad.2 for ; Mon, 05 Jan 2026 08:52:49 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1767631967; x=1768236767; 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=SJtmgrqUuV3P8oLjNzbvd9+zGjYs3p7x/advBaiWf6c=; b=FaWfm3Lz8DhGGbzi9Hc7mUnzQx5NMcCJd5qbFW03VT4osYmAjNCubuRqSg0+7lf2hQ 8h8fgKY5tvGt5CO6sQ6FW+qZHIocmfJz5bRpjbt9lkU2mBfTQVEnC7nizM8O6He8JCHk W/B1Abc7JbvJeujqLmPYDDvS4Dfwoshow/vAl4exfucHZGdZS1ROqPx8IgJTFG45uIqU nGrm2ha1heW6VjPjdgnmIvtCzSq1U17TcYWt7H8hO7UtnHthfugTGCF+zij3aCtQT5oe CzID0oFy6yXPwElv8XJrLJqfgYaeWHbgzJpk2kqc2yZ49ESzED5II2H8CeoyHgh3Hr4b sBNg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1767631967; x=1768236767; 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=SJtmgrqUuV3P8oLjNzbvd9+zGjYs3p7x/advBaiWf6c=; b=NCukhHJ+TSRJJ6jB6bpvA7CRUdCTghvO9L29cwRDn5DucaZGKKBjnC/QGcNvk0Pppk 6faPGm/RAHRl7u+yfdWRKqQVMqO0dp8LSv/b7UlBzkg4s13qyt3ewudxrr7i/9ex5VeW H6QHpHDqpx/N2iNlh3xEZxmv4jCiSlsXnES7SeixHFxc4rUxFD+ajbpDT8x3G8JN2pRE tsKmFPo37y/Q4exNaiaCG0ao6E8eXxEiVZp27PV8OO+/xfBNhICjw3jMkF7uUglNMTn8 E7w51PzlLAlzMi5zeQExVuxrNN0uUWrnVy/ugnA7UtHuVsS224tLatDKV6g7g9hcj4MO 7Q2Q== X-Gm-Message-State: AOJu0YyHEJisuEYpyU6sprJ5cReD6KTOljgXMU9FG00NYaodfMqw7kXf nO4f7gv/Gdd42A0+Qs0ZGMaQ91PbXjAjLd+IiKrIdLXOGwo42S09ereTToz+kWPK93c= X-Gm-Gg: AY/fxX5Scoc/UL9mi3KkFeEtKd+xTdu9U5trS4JkHEB4uA/eikFjrd7gTM+mtNBwEqM e4D/uzQNaZiiCz8f8WvfTOr2nxCE6El/jOu/0E5D1EoDJPUjFCp/EsXnPHmDBAS5FXjNtHDnOLn pmYPHy9FOHGHo+xV3sHMtJwrV4ln9A/bwNh2tPlCLpmXB4gCAFl1MP8KTYOIzHP4JNgPUXr4clT CXWeO8DSONaId+np1+TLvhiP4qF2RfgxwEKU1T4SXqpuNolKhcgZNtjuqDbMdt5mvweqLeEEL7K iPF0CZIJdiw0g03rB6UI4mIJMJUf3FIOfiJls1TYrd3xsjxXbyHSevNRJi2AZE3Lyyr3G+HPf7L vzKWF/s9avvDIs8bbkcNYEEVFw1s6z6NaqCtvzKrpAfHw85gPSoZrV/XVfQYZSVlHukiuhzJTZg iiqOrRiDU6TQ22QdVAredW X-Google-Smtp-Source: AGHT+IHc9JL+G2hOEA3As2NbghRCsstTjlVi9LWjkEL1fu++Mvtm6MvVAOeIk3/MRGmW5ANZKqp9vw== X-Received: by 2002:a17:90b:3d45:b0:340:b572:3b7d with SMTP id 98e67ed59e1d1-34f5f2fb245mr18029a91.19.1767631967099; Mon, 05 Jan 2026 08:52:47 -0800 (PST) Received: from Family.localdomain ([49.43.26.123]) by smtp.gmail.com with ESMTPSA id 98e67ed59e1d1-34f5ef29da5sm83354a91.15.2026.01.05.08.52.45 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 05 Jan 2026 08:52:46 -0800 (PST) To: ffmpeg-devel@ffmpeg.org Date: Mon, 5 Jan 2026 22:22:39 +0530 Message-Id: <20260105165239.7590-1-cordacct2001@gmail.com> X-Mailer: git-send-email 2.34.1 MIME-Version: 1.0 Message-ID-Hash: X7SESEGVOVKZ5D5CNULW6DVRAPCSMYWR X-Message-ID-Hash: X7SESEGVOVKZ5D5CNULW6DVRAPCSMYWR 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: add 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 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Archived-At: List-Archive: List-Post: 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 --- 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.34.1 _______________________________________________ ffmpeg-devel mailing list -- ffmpeg-devel@ffmpeg.org To unsubscribe send an email to ffmpeg-devel-leave@ffmpeg.org