diff options
author | Marton Balint <cus@passwd.hu> | 2019-02-05 00:16:36 +0100 |
---|---|---|
committer | Marton Balint <cus@passwd.hu> | 2019-02-13 23:21:53 +0100 |
commit | dbfd042983eed8586d4048795c00af820f5b6b1f (patch) | |
tree | 244bb5167f25cadaf26f0a8813b8516f9e66a391 /libavformat/utils.c | |
parent | b35843e3913df57da3a6bb0ce80a4f2b75d374b4 (diff) | |
download | ffmpeg-dbfd042983eed8586d4048795c00af820f5b6b1f.tar.gz |
avformat/utils: parse some stream specifiers recursively
This removes lots of code duplication and also allows more complex specifiers,
for example you can use p:204:a:m:language:eng to select the English language
audio stream from program 204.
Signed-off-by: Marton Balint <cus@passwd.hu>
Diffstat (limited to 'libavformat/utils.c')
-rw-r--r-- | libavformat/utils.c | 173 |
1 files changed, 55 insertions, 118 deletions
diff --git a/libavformat/utils.c b/libavformat/utils.c index 7afef545fe..d113a16c80 100644 --- a/libavformat/utils.c +++ b/libavformat/utils.c @@ -5097,13 +5097,24 @@ AVRational av_guess_frame_rate(AVFormatContext *format, AVStream *st, AVFrame *f return fr; } -int avformat_match_stream_specifier(AVFormatContext *s, AVStream *st, - const char *spec) +/** + * Matches a stream specifier (but ignores requested index). + * + * @param index set if a specific index is requested from the matching streams + * + * @return <0 on error + * 0 if st is NOT a matching stream + * >0 if st is a matching stream + */ +static int match_stream_specifier(AVFormatContext *s, AVStream *st, + const char *spec, int *index) { - if (*spec <= '9' && *spec >= '0') /* opt:index */ - return strtol(spec, NULL, 0) == st->index; - else if (*spec == 'v' || *spec == 'a' || *spec == 's' || *spec == 'd' || - *spec == 't' || *spec == 'V') { /* opt:[vasdtV] */ + if (*spec <= '9' && *spec >= '0') { /* opt:index */ + if (index) + *index = strtol(spec, NULL, 0); + return 1; + } else if (*spec == 'v' || *spec == 'a' || *spec == 's' || *spec == 'd' || + *spec == 't' || *spec == 'V') { /* opt:[vasdtV] */ enum AVMediaType type; int nopic = 0; @@ -5128,27 +5139,8 @@ FF_ENABLE_DEPRECATION_WARNINGS #endif if (nopic && (st->disposition & AV_DISPOSITION_ATTACHED_PIC)) return 0; - if (*spec++ == ':') { /* possibly followed by :index */ - int i, index = strtol(spec, NULL, 0); - for (i = 0; i < s->nb_streams; i++) { -#if FF_API_LAVF_AVCTX -FF_DISABLE_DEPRECATION_WARNINGS - if ((s->streams[i]->codecpar->codec_type == type - || s->streams[i]->codec->codec_type == type - ) && - !(nopic && (st->disposition & AV_DISPOSITION_ATTACHED_PIC)) && - index-- == 0) - return i == st->index; -FF_ENABLE_DEPRECATION_WARNINGS -#else - if ((s->streams[i]->codecpar->codec_type == type) && - !(nopic && (st->disposition & AV_DISPOSITION_ATTACHED_PIC)) && - index-- == 0) - return i == st->index; -#endif - } - return 0; - } + if (*spec++ == ':') /* possibly followed by another specifier */ + return match_stream_specifier(s, st, spec, index); return 1; } else if (*spec == 'p' && *(spec + 1) == ':') { int prog_id, i, j; @@ -5159,99 +5151,15 @@ FF_ENABLE_DEPRECATION_WARNINGS if (s->programs[i]->id != prog_id) continue; - if (*endptr++ == ':') { // p:<id>:.... - if ( *endptr == 'a' || *endptr == 'v' || - *endptr == 's' || *endptr == 'd') { // p:<id>:<st_type>[:<index>] - enum AVMediaType type; - - switch (*endptr++) { - 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; - default: av_assert0(0); - } - if (*endptr++ == ':') { // p:<id>:<st_type>:<index> - int stream_idx = strtol(endptr, NULL, 0), type_counter = 0; - for (j = 0; j < s->programs[i]->nb_stream_indexes; j++) { - int stream_index = s->programs[i]->stream_index[j]; - if (st->index == s->programs[i]->stream_index[j]) { -#if FF_API_LAVF_AVCTX -FF_DISABLE_DEPRECATION_WARNINGS - return type_counter == stream_idx && - (type == st->codecpar->codec_type || - type == st->codec->codec_type); -FF_ENABLE_DEPRECATION_WARNINGS -#else - return type_counter == stream_idx && - type == st->codecpar->codec_type; -#endif - } -#if FF_API_LAVF_AVCTX -FF_DISABLE_DEPRECATION_WARNINGS - if (type == s->streams[stream_index]->codecpar->codec_type || - type == s->streams[stream_index]->codec->codec_type) - type_counter++; -FF_ENABLE_DEPRECATION_WARNINGS -#else - if (type == s->streams[stream_index]->codecpar->codec_type) - type_counter++; -#endif - } - return 0; - } else { // p:<id>:<st_type> - for (j = 0; j < s->programs[i]->nb_stream_indexes; j++) - if (st->index == s->programs[i]->stream_index[j]) { -#if FF_API_LAVF_AVCTX -FF_DISABLE_DEPRECATION_WARNINGS - return type == st->codecpar->codec_type || - type == st->codec->codec_type; -FF_ENABLE_DEPRECATION_WARNINGS -#else - return type == st->codecpar->codec_type; -#endif - } - return 0; - } - - } else if ( *endptr == 'm') { // p:<id>:m:<metadata_spec> - AVDictionaryEntry *tag; - char *key, *val; - int ret = 0; - - if (*(++endptr) != ':') { - av_log(s, AV_LOG_ERROR, "Invalid stream specifier syntax, missing ':' sign after :m.\n"); - return AVERROR(EINVAL); + for (j = 0; j < s->programs[i]->nb_stream_indexes; j++) { + if (st->index == s->programs[i]->stream_index[j]) { + if (*endptr++ == ':') { // p:<id>:.... + return match_stream_specifier(s, st, endptr, index); + } else { + return 1; } - - val = strchr(++endptr, ':'); - key = val ? av_strndup(endptr, val - endptr) : av_strdup(endptr); - if (!key) - return AVERROR(ENOMEM); - - for (j = 0; j < s->programs[i]->nb_stream_indexes; j++) - if (st->index == s->programs[i]->stream_index[j]) { - tag = av_dict_get(st->metadata, key, NULL, 0); - if (tag && (!val || !strcmp(tag->value, val + 1))) - ret = 1; - - break; - } - - av_freep(&key); - return ret; - - } else { // p:<id>:<index> - int stream_idx = strtol(endptr, NULL, 0); - return stream_idx >= 0 && - stream_idx < s->programs[i]->nb_stream_indexes && - st->index == s->programs[i]->stream_index[stream_idx]; } } - - for (j = 0; j < s->programs[i]->nb_stream_indexes; j++) - if (st->index == s->programs[i]->stream_index[j]) - return 1; } return 0; } else if (*spec == '#' || @@ -5333,10 +5241,39 @@ FF_ENABLE_DEPRECATION_WARNINGS } else if (!*spec) /* empty specifier, matches everything */ return 1; - av_log(s, AV_LOG_ERROR, "Invalid stream specifier: %s.\n", spec); return AVERROR(EINVAL); } + +int avformat_match_stream_specifier(AVFormatContext *s, AVStream *st, + const char *spec) +{ + int ret; + int index = -1; + + /* This is not really needed but saves us a loop for simple stream index specifiers. */ + if (*spec <= '9' && *spec >= '0') /* opt:index */ + return strtol(spec, NULL, 0) == st->index; + + ret = match_stream_specifier(s, st, spec, &index); + if (ret < 0) { + av_log(s, AV_LOG_ERROR, "Invalid stream specifier: %s.\n", spec); + return ret; + } + if (!ret || index < 0) + return ret; + + /* If we requested a matching stream index, we have to ensure st is that. */ + for (int i = 0; i < s->nb_streams && index >= 0; i++) { + int ret = match_stream_specifier(s, s->streams[i], spec, NULL); + if (ret < 0) + return ret; + if (ret > 0 && index-- == 0 && st == s->streams[i]) + return 1; + } + return 0; +} + int ff_generate_avci_extradata(AVStream *st) { static const uint8_t avci100_1080p_extradata[] = { |