From patchwork Sat May 7 11:28:18 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andreas Rheinhardt X-Patchwork-Id: 35665 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a05:6a20:a885:b0:7f:4be2:bd17 with SMTP id ca5csp2122722pzb; Sat, 7 May 2022 04:34:12 -0700 (PDT) X-Google-Smtp-Source: ABdhPJyGPcUqEL914t8qVd1KoJRQNjSBpXtg4ehvXEJhXsQiqWDI1BUIvoYzW4aQ8Rsg3L6YHRBH X-Received: by 2002:a05:6402:51d0:b0:427:dfa3:1a46 with SMTP id r16-20020a05640251d000b00427dfa31a46mr7996762edd.107.1651923252203; Sat, 07 May 2022 04:34:12 -0700 (PDT) Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id z15-20020a50cd0f000000b00427b431e10asi6531108edi.469.2022.05.07.04.34.11; Sat, 07 May 2022 04:34:12 -0700 (PDT) Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@outlook.com header.s=selector1 header.b=onK446Hr; arc=fail (body hash mismatch); spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org; dmarc=fail (p=NONE sp=QUARANTINE dis=NONE) header.from=outlook.com Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 30B3668B4BB; Sat, 7 May 2022 14:30:41 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from EUR04-HE1-obe.outbound.protection.outlook.com (mail-oln040092073064.outbound.protection.outlook.com [40.92.73.64]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 4172068B3EE for ; Sat, 7 May 2022 14:30:39 +0300 (EEST) ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=jbGve7dTX9mFomv9doTiWSQyihqJuVqO2y3Jmzf9QpiXy6X7JiPm7eynjY3i+R6rAgEPSgH8QUPQQMJFZBtPXWVjUze9/Juc/IClmg8pOraEockSJ7s81wgi3Jq/Ck7w4NSyCT3TTXs8WCYvpp9nA+vzMnLETcNqTgqSChzFHBTOMmVAzGT3kQIODaxIeRh4vf1PqEeOdSCqH/+yEVuErZ0wa1szcOvBrWwqvgT5tNyG+4A9nW/IQcSrLRnG2lQV0UPUR3bPhYfmrsrGFyTae+KquVzm29Yz2G4CKL4zz4hctX8QvGpEFncK37sgODedvuvnqL+prOlXc216QmqDAg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=xEL8n4oEdlnk0f/Qyc+ZF+OAd4dRKItH8iND3ULCJpQ=; b=UZKeSkQg0LvjxUm8gKPQV85ceSs/5yRcXj3O0Qs8wHHbhMnrpGLCSCtMpb2uIWQl95Wj/DElXD/TaXyfIGrrcKYdq429tQCU9Ey1FrbagYufcy+TglN0kGh4yMWRMkhQo+4K10pOWY1832gF1DfEqF0r77RlT6Lvst2d0JAWz7muuq3CNsNjbUfTTYMlgu7R5OwauPLlWevU5+i5VOA7pc0B6GlUiXGA1nbVuve7AC/N8BTXAWOZntHk5Y9VrCNVJjovu1dpsUhO/q2FaOUBvY2FK8ne39TvwAP5wzxkarBp9vkgp+ONEJrIJUI1TQcXq7MSnR8AFbqqF0HNXuYmOg== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=none; dmarc=none; dkim=none; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=outlook.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=xEL8n4oEdlnk0f/Qyc+ZF+OAd4dRKItH8iND3ULCJpQ=; b=onK446Hr57py/6O8gQY4WH0YNnwaBWQHE49VCaIJ+Q0On3QG2U/LFXYoVgJqWmzsNGrCEctX13iidEyY22/DZ6lEW4cS3Ph03SxsboYkYzBS5fw+NOF62DG//uxPEbVIXztdS851WhaNB0Id6z/q+b2s2if/V6ZxfUKBnBnDLUAYO30kzCJegCFFDsyJkoFAF8+qaL93MWvHHcphnd0Tr8d41WFG022SSNM6i+fPv0kBbCiTYri4mGmKRlmvCr0eaEy6+TLE1HuI/dlxZtVBXndHszbQ0kY0ApWJTPT/FtRmMf5ifxhMX1VCdK7SiWMyYmhc+XC9a9N2ebGjl9/+Ig== Received: from AS8PR01MB7944.eurprd01.prod.exchangelabs.com (2603:10a6:20b:373::5) by DB6PR01MB3895.eurprd01.prod.exchangelabs.com (2603:10a6:6:4b::10) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.5206.24; Sat, 7 May 2022 11:30:38 +0000 Received: from AS8PR01MB7944.eurprd01.prod.exchangelabs.com ([fe80::1854:2c30:7ba1:c431]) by AS8PR01MB7944.eurprd01.prod.exchangelabs.com ([fe80::1854:2c30:7ba1:c431%6]) with mapi id 15.20.5206.024; Sat, 7 May 2022 11:30:38 +0000 From: Andreas Rheinhardt To: ffmpeg-devel@ffmpeg.org Date: Sat, 7 May 2022 13:28:18 +0200 Message-ID: X-Mailer: git-send-email 2.32.0 In-Reply-To: References: X-TMN: [90RqvNdHD6ZUak26qxT255CiQjjCaEQU] X-ClientProxiedBy: ZRAP278CA0004.CHEP278.PROD.OUTLOOK.COM (2603:10a6:910:10::14) To AS8PR01MB7944.eurprd01.prod.exchangelabs.com (2603:10a6:20b:373::5) X-Microsoft-Original-Message-ID: <20220507112830.406162-31-andreas.rheinhardt@outlook.com> MIME-Version: 1.0 X-MS-Exchange-MessageSentRepresentingType: 1 X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: 27bb0d5a-9067-48ff-dee5-08da301cfe7e X-MS-Exchange-SLBlob-MailProps: gjx25WM8ZNVZjuqTokTVdg9S7+crVfX8llYh5b6hJTs9UzQX4bc4ySN7PluJyNWV66F/ZqUqd0l5YC6msg4LSQ5ohsbopeTQUXrvtJeF8sbkiylahgfqFHvfbvfGUOa7P0zRm8sKT748OqgkjOWL6/d5ip/lUKPl9N8ABl3Y9NQ2YOIpFl1eZD3NHadk5XX9AtztpJdk1jxG6iDhZN2R+tSMFSQkJJlM/BUG/CXpevrHzBtcljb0GnkKKHrk/S0mcHiTwnVvJegKyOsYDTUqML2ERAyyupoqrMdo1qaBbQH1l4mcQYV9t+pNm12ranlTg75IofXw/pwc/RHxZqCjWw8h0qJnOH2twcTIWHFaeSgCsztuk9tq6Ihsbrdz8mmU76LAFVGPMlXqPy1uXiFR6y4JzzGaG+QFfFBa1vrK4E3Hzn6TV0vs8fsP3atcz5CRl8mXnBpNg1ULn7Wt/rYAN/WSdfpSF0LufcwIMHuqu8iIUTD7RuIoVGWsuJ4QbPeqmjjRo3bBOrjA+iwvt/JUfmfIhJKJeSMC47zFiVjZZrxO5m/W+aJQWHKADY7pVEbGCDQPio0fcYunBCHirjZu1ptreO4uzr7uXpXtqJ8TVRRcEO7HkmMUTEH2gWG3pC952/iXn+B//7pMQ1HlrgJ0PtbfH3XVpE9V8NzBJE5Fw/t3E/bqiq+IrJFw+Dlkc9ja6MSH+n439hWY1oCcaklQuhlgTA/0QmrGHu4QDAGuCBE= X-MS-TrafficTypeDiagnostic: DB6PR01MB3895:EE_ X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: /J/ChCUmpP1TLEJBrslXVO2T5NFiXhGRfpZvLyIwlgnJLEx9ZvLGBptRVKIpvIYFHSngRRyavbOuEqAcot87++5HLG9DJSGs9+STrlD5KkZBCYZKtqFTKWj/CbuoBy1thrtRjtD5BVilgnywnFlTsTYCu70w/9okLyRMSQBJy4tEKIGkSdiTwdppIpYsZDAAwygKFvoQQBmZiFrRHHbPiKgjabT4JFIgiLtPY3ZsN3QUemDHd+KcMQa12awEamVk3FaCy6ulk5xHEeUOUDytQ7cNehU0yYb3cC/J+/SFMLZPnUY8a2i70Rno852kXUnWT5GjQzScQTkG0DIlTieekdT9+ytzmcnM1FFc5THF22ZDJ02OPO+qGNbd3KdWLHO+IPm4CGi5HWm60n/p9fcXAtOuh8SJ0OBcGGTTOvBQfs9muc1O0IQvdy4l7JZfo8g+QyYYBQR6JAQWd7pUsA4PWskLy9en/8UQRS8572kyOkhhFvBM5u7IRtlbDWAUV6VLF9GTIoOpDvhhIrHp4GDqccKT/TGCrfCYoQWG7D+glOa8MICuJqrg/T3Rvzh0xLEVW5Nnw5b1TcNhP86UX4HhER5GOTWO3q7eTy52E4T8W5QGz+omtVQl4Ce9h4Am6D/u X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: nvy/Thryf7rlAvrkiaNh4ok3lmJIZ89N9bW8k9MlVQfUS4V3VqltOODja3yLe2853jCJtwvnhn1Xa7YTG2IZFPpIopy6ZRPUBb31XihA8Qb0ld46pzO0ljgxc/lsgXp/gN/s0BG8teVDMJqIhvNIA2CNx37upBK1TR5zbXqZ0B9t6buLsOsdJEsI0Umb+lbrRYnWx5e35Q1Elhp2fpVUk3Nxk9ZSayTQS8px2HtI+C8XhbVWl/qXsjYxTx8L3iTPBo9LIWvba2AE1m1sRGKIbMrgI5HqZlOH0tlWYipO2Z/Z3erXPrNnVPHjHvJwBDoPRh+w0t/q0J+vdmRrKmN4vaO5O72NrT5Drt81aLS7CkBUOBCAbaJTUH/pedU5od3qtzrGmgat2M5MU+W3UVq6IcdODGAeYhQ/rjYJ1y9k/JPRaF6eTHFGzDaUHE+mHhhwqug2dzYtQP7K/l5WA0GVM55RywJHL3ruC84AAD3u2TdIeD8UytCf1BvcY8u+GrdMvx2wJoUt8w4AmlwYVSpCuw+wGW692Ynj16mQ0OcdbD3DzveiqIuZ+784jlhU9L8a5JdRlX8B3agnF55fqbf1EChCd67K1LoeNiPXVxsP+7zy+ofhHyyvdGCT9o+/cChkuTnr86reth5W+JSBy9hpAFi35eSyqjIxidQ4PCbY5rbpeponidx1a0W6hWK0JkyJ0TFGf1EQj2W90K5lJTnxqPr7bYvDuGOm5K+fVSaV+rFSZIa5w/9dwue1HBAtD11QsQ6iWkmhN/I1VtChlxS76TZy28kyWrFFTJGNMON3rImkZFTgYF8qLOS3LhIIcXQc6any1YbumCKsb07N9cyMpx1Z0sTBeT2nrsXduzHxgUwqdH6WhMCAnF54dKE2ejt30H8ec/ZofAn1bqaPMIT9a/o8SywZVPhmZ//IYgnGFAXKQbOwsSP83coukRRuMcOh9HriVeTuxczGMjkBcmLFutGY65Z/uBjgcs8OgBdjNpINws91PBhFfBBRCcEK6pNxdXK446h+NlwkE5mKOk0XZ2p6G0mfoG4xQ6hdjXiVZINFUTZT2hk9hcpsmj8DyakBpDiBiz8mwk5eWYn8GymVqLjJFOwyWFjna21nXnUErlN0WunxHTvZeWshuyE/V/d8uDyv76Uoq2imvboc94ZDQK57DJGK3gLX0UvjEG53SGIc3qqqVyZquhpZv5dfWMBnqFJ9jFDJAX29AjkUJgH6y2ONHiLMDc35sYBYxhDlf+uER+tB41L/PGvz+L5rvzD5i7AnIKkK6hgnOqJvNgi9gWsKTubaFzVjxhQVbjZ+DgiNMr94TAiW1za7f9Vq9A1S24nApFXUcS4F4ptLocgYX1TmVzFF5Mr05HXk38lNzD1f3++1wzstyoj5bLuuhb7zQCUx1q6jmHSDifYoeP735D4Gb7wh54hNpyOBcoJThVcRPQ1TWh4EIzugGOGo3JSF X-OriginatorOrg: outlook.com X-MS-Exchange-CrossTenant-Network-Message-Id: 27bb0d5a-9067-48ff-dee5-08da301cfe7e X-MS-Exchange-CrossTenant-AuthSource: AS8PR01MB7944.eurprd01.prod.exchangelabs.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 07 May 2022 11:30:31.5478 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 84df9e7f-e9f6-40af-b435-aaaaaaaaaaaa X-MS-Exchange-CrossTenant-RMS-PersistedConsumerOrg: 00000000-0000-0000-0000-000000000000 X-MS-Exchange-Transport-CrossTenantHeadersStamped: DB6PR01MB3895 Subject: [FFmpeg-devel] [PATCH 32/44] avformat/utils: Move matching stream specificiers to avformat.c X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Cc: Andreas Rheinhardt Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" X-TUID: nhLqU+uO5lUH It is not to call this with a muxer, so move it to avformat.c and not demux_utils.c. Signed-off-by: Andreas Rheinhardt --- libavformat/avformat.c | 179 +++++++++++++++++++++++++++++++++++++++++ libavformat/utils.c | 179 ----------------------------------------- 2 files changed, 179 insertions(+), 179 deletions(-) diff --git a/libavformat/avformat.c b/libavformat/avformat.c index ac0e28a6a9..7fab0dd99d 100644 --- a/libavformat/avformat.c +++ b/libavformat/avformat.c @@ -21,9 +21,12 @@ #include "libavutil/avassert.h" #include "libavutil/avstring.h" +#include "libavutil/channel_layout.h" #include "libavutil/intreadwrite.h" #include "libavutil/mem.h" #include "libavutil/opt.h" +#include "libavutil/pixfmt.h" +#include "libavutil/samplefmt.h" #include "libavcodec/avcodec.h" #include "libavcodec/bsf.h" #include "libavcodec/packet_internal.h" @@ -257,6 +260,182 @@ void av_program_add_stream_index(AVFormatContext *ac, int progid, unsigned idx) } } +/** + * Matches a stream specifier (but ignores requested index). + * + * @param indexptr set to point to the requested stream index if there is one + * + * @return <0 on error + * 0 if st is NOT a matching stream + * >0 if st is a matching stream + */ +static int match_stream_specifier(const AVFormatContext *s, const AVStream *st, + const char *spec, const char **indexptr, + const AVProgram **p) +{ + int match = 1; /* Stores if the specifier matches so far. */ + while (*spec) { + if (*spec <= '9' && *spec >= '0') { /* opt:index */ + if (indexptr) + *indexptr = spec; + return match; + } else if (*spec == 'v' || *spec == 'a' || *spec == 's' || *spec == 'd' || + *spec == 't' || *spec == 'V') { /* opt:[vasdtV] */ + enum AVMediaType type; + int nopic = 0; + + switch (*spec++) { + case 'v': type = AVMEDIA_TYPE_VIDEO; break; + case 'a': type = AVMEDIA_TYPE_AUDIO; break; + case 's': type = AVMEDIA_TYPE_SUBTITLE; break; + case 'd': type = AVMEDIA_TYPE_DATA; break; + case 't': type = AVMEDIA_TYPE_ATTACHMENT; break; + case 'V': type = AVMEDIA_TYPE_VIDEO; nopic = 1; break; + default: av_assert0(0); + } + if (*spec && *spec++ != ':') /* If we are not at the end, then another specifier must follow. */ + return AVERROR(EINVAL); + + if (type != st->codecpar->codec_type) + match = 0; + if (nopic && (st->disposition & AV_DISPOSITION_ATTACHED_PIC)) + match = 0; + } else if (*spec == 'p' && *(spec + 1) == ':') { + int prog_id; + int found = 0; + char *endptr; + spec += 2; + prog_id = strtol(spec, &endptr, 0); + /* Disallow empty id and make sure that if we are not at the end, then another specifier must follow. */ + if (spec == endptr || (*endptr && *endptr++ != ':')) + return AVERROR(EINVAL); + spec = endptr; + if (match) { + for (unsigned i = 0; i < s->nb_programs; i++) { + if (s->programs[i]->id != prog_id) + continue; + + for (unsigned j = 0; j < s->programs[i]->nb_stream_indexes; j++) { + if (st->index == s->programs[i]->stream_index[j]) { + found = 1; + if (p) + *p = s->programs[i]; + i = s->nb_programs; + break; + } + } + } + } + if (!found) + match = 0; + } else if (*spec == '#' || + (*spec == 'i' && *(spec + 1) == ':')) { + int stream_id; + char *endptr; + spec += 1 + (*spec == 'i'); + stream_id = strtol(spec, &endptr, 0); + if (spec == endptr || *endptr) /* Disallow empty id and make sure we are at the end. */ + return AVERROR(EINVAL); + return match && (stream_id == st->id); + } else if (*spec == 'm' && *(spec + 1) == ':') { + const AVDictionaryEntry *tag; + char *key, *val; + int ret; + + if (match) { + spec += 2; + val = strchr(spec, ':'); + + key = val ? av_strndup(spec, val - spec) : av_strdup(spec); + if (!key) + return AVERROR(ENOMEM); + + tag = av_dict_get(st->metadata, key, NULL, 0); + if (tag) { + if (!val || !strcmp(tag->value, val + 1)) + ret = 1; + else + ret = 0; + } else + ret = 0; + + av_freep(&key); + } + return match && ret; + } else if (*spec == 'u' && *(spec + 1) == '\0') { + const AVCodecParameters *par = st->codecpar; + int val; + switch (par->codec_type) { + case AVMEDIA_TYPE_AUDIO: + val = par->sample_rate && par->ch_layout.nb_channels; + if (par->format == AV_SAMPLE_FMT_NONE) + return 0; + break; + case AVMEDIA_TYPE_VIDEO: + val = par->width && par->height; + if (par->format == AV_PIX_FMT_NONE) + return 0; + break; + case AVMEDIA_TYPE_UNKNOWN: + val = 0; + break; + default: + val = 1; + break; + } + return match && (par->codec_id != AV_CODEC_ID_NONE && val != 0); + } else { + return AVERROR(EINVAL); + } + } + + return match; +} + +int avformat_match_stream_specifier(AVFormatContext *s, AVStream *st, + const char *spec) +{ + int ret, index; + char *endptr; + const char *indexptr = NULL; + const AVProgram *p = NULL; + int nb_streams; + + ret = match_stream_specifier(s, st, spec, &indexptr, &p); + if (ret < 0) + goto error; + + if (!indexptr) + return ret; + + index = strtol(indexptr, &endptr, 0); + if (*endptr) { /* We can't have anything after the requested index. */ + ret = AVERROR(EINVAL); + goto error; + } + + /* This is not really needed but saves us a loop for simple stream index specifiers. */ + if (spec == indexptr) + return (index == st->index); + + /* If we requested a matching stream index, we have to ensure st is that. */ + nb_streams = p ? p->nb_stream_indexes : s->nb_streams; + for (int i = 0; i < nb_streams && index >= 0; i++) { + const AVStream *candidate = s->streams[p ? p->stream_index[i] : i]; + ret = match_stream_specifier(s, candidate, spec, NULL, NULL); + if (ret < 0) + goto error; + if (ret > 0 && index-- == 0 && st == candidate) + return 1; + } + return 0; + +error: + if (ret == AVERROR(EINVAL)) + av_log(s, AV_LOG_ERROR, "Invalid stream specifier: %s.\n", spec); + return ret; +} + int avformat_transfer_internal_stream_timing_info(const AVOutputFormat *ofmt, AVStream *ost, const AVStream *ist, enum AVTimebaseSource copy_tb) diff --git a/libavformat/utils.c b/libavformat/utils.c index f5d24e7a3a..ebee44f47d 100644 --- a/libavformat/utils.c +++ b/libavformat/utils.c @@ -26,9 +26,7 @@ #include "libavutil/avassert.h" #include "libavutil/avstring.h" #include "libavutil/bprint.h" -#include "libavutil/dict.h" #include "libavutil/internal.h" -#include "libavutil/pixfmt.h" #include "libavutil/thread.h" #include "libavutil/time.h" @@ -855,183 +853,6 @@ AVRational av_guess_frame_rate(AVFormatContext *format, AVStream *st, AVFrame *f return fr; } -/** - * Matches a stream specifier (but ignores requested index). - * - * @param indexptr set to point to the requested stream index if there is one - * - * @return <0 on error - * 0 if st is NOT a matching stream - * >0 if st is a matching stream - */ -static int match_stream_specifier(const AVFormatContext *s, const AVStream *st, - const char *spec, const char **indexptr, - const AVProgram **p) -{ - int match = 1; /* Stores if the specifier matches so far. */ - while (*spec) { - if (*spec <= '9' && *spec >= '0') { /* opt:index */ - if (indexptr) - *indexptr = spec; - return match; - } else if (*spec == 'v' || *spec == 'a' || *spec == 's' || *spec == 'd' || - *spec == 't' || *spec == 'V') { /* opt:[vasdtV] */ - enum AVMediaType type; - int nopic = 0; - - switch (*spec++) { - case 'v': type = AVMEDIA_TYPE_VIDEO; break; - case 'a': type = AVMEDIA_TYPE_AUDIO; break; - case 's': type = AVMEDIA_TYPE_SUBTITLE; break; - case 'd': type = AVMEDIA_TYPE_DATA; break; - case 't': type = AVMEDIA_TYPE_ATTACHMENT; break; - case 'V': type = AVMEDIA_TYPE_VIDEO; nopic = 1; break; - default: av_assert0(0); - } - if (*spec && *spec++ != ':') /* If we are not at the end, then another specifier must follow. */ - return AVERROR(EINVAL); - - if (type != st->codecpar->codec_type) - match = 0; - if (nopic && (st->disposition & AV_DISPOSITION_ATTACHED_PIC)) - match = 0; - } else if (*spec == 'p' && *(spec + 1) == ':') { - int prog_id; - int found = 0; - char *endptr; - spec += 2; - prog_id = strtol(spec, &endptr, 0); - /* Disallow empty id and make sure that if we are not at the end, then another specifier must follow. */ - if (spec == endptr || (*endptr && *endptr++ != ':')) - return AVERROR(EINVAL); - spec = endptr; - if (match) { - for (unsigned i = 0; i < s->nb_programs; i++) { - if (s->programs[i]->id != prog_id) - continue; - - for (unsigned j = 0; j < s->programs[i]->nb_stream_indexes; j++) { - if (st->index == s->programs[i]->stream_index[j]) { - found = 1; - if (p) - *p = s->programs[i]; - i = s->nb_programs; - break; - } - } - } - } - if (!found) - match = 0; - } else if (*spec == '#' || - (*spec == 'i' && *(spec + 1) == ':')) { - int stream_id; - char *endptr; - spec += 1 + (*spec == 'i'); - stream_id = strtol(spec, &endptr, 0); - if (spec == endptr || *endptr) /* Disallow empty id and make sure we are at the end. */ - return AVERROR(EINVAL); - return match && (stream_id == st->id); - } else if (*spec == 'm' && *(spec + 1) == ':') { - const AVDictionaryEntry *tag; - char *key, *val; - int ret; - - if (match) { - spec += 2; - val = strchr(spec, ':'); - - key = val ? av_strndup(spec, val - spec) : av_strdup(spec); - if (!key) - return AVERROR(ENOMEM); - - tag = av_dict_get(st->metadata, key, NULL, 0); - if (tag) { - if (!val || !strcmp(tag->value, val + 1)) - ret = 1; - else - ret = 0; - } else - ret = 0; - - av_freep(&key); - } - return match && ret; - } else if (*spec == 'u' && *(spec + 1) == '\0') { - const AVCodecParameters *par = st->codecpar; - int val; - switch (par->codec_type) { - case AVMEDIA_TYPE_AUDIO: - val = par->sample_rate && par->ch_layout.nb_channels; - if (par->format == AV_SAMPLE_FMT_NONE) - return 0; - break; - case AVMEDIA_TYPE_VIDEO: - val = par->width && par->height; - if (par->format == AV_PIX_FMT_NONE) - return 0; - break; - case AVMEDIA_TYPE_UNKNOWN: - val = 0; - break; - default: - val = 1; - break; - } - return match && (par->codec_id != AV_CODEC_ID_NONE && val != 0); - } else { - return AVERROR(EINVAL); - } - } - - return match; -} - - -int avformat_match_stream_specifier(AVFormatContext *s, AVStream *st, - const char *spec) -{ - int ret, index; - char *endptr; - const char *indexptr = NULL; - const AVProgram *p = NULL; - int nb_streams; - - ret = match_stream_specifier(s, st, spec, &indexptr, &p); - if (ret < 0) - goto error; - - if (!indexptr) - return ret; - - index = strtol(indexptr, &endptr, 0); - if (*endptr) { /* We can't have anything after the requested index. */ - ret = AVERROR(EINVAL); - goto error; - } - - /* This is not really needed but saves us a loop for simple stream index specifiers. */ - if (spec == indexptr) - return (index == st->index); - - /* If we requested a matching stream index, we have to ensure st is that. */ - nb_streams = p ? p->nb_stream_indexes : s->nb_streams; - for (int i = 0; i < nb_streams && index >= 0; i++) { - const AVStream *candidate = s->streams[p ? p->stream_index[i] : i]; - ret = match_stream_specifier(s, candidate, spec, NULL, NULL); - if (ret < 0) - goto error; - if (ret > 0 && index-- == 0 && st == candidate) - return 1; - } - return 0; - -error: - if (ret == AVERROR(EINVAL)) - av_log(s, AV_LOG_ERROR, "Invalid stream specifier: %s.\n", spec); - return ret; -} - void ff_format_io_close_default(AVFormatContext *s, AVIOContext *pb) { avio_close(pb);