[FFmpeg-devel] [PATCH] avformat/utils: parse some stream specifiers recursively
Marton Balint
cus at passwd.hu
Mon Feb 11 23:22:02 EET 2019
On Tue, 5 Feb 2019, Marton Balint wrote:
> 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.
Ping... Will apply soon.
Thanks,
Marton
>
> Signed-off-by: Marton Balint <cus at passwd.hu>
> ---
> doc/fftools-common-opts.texi | 30 +++-----
> libavformat/utils.c | 172 +++++++++++++------------------------------
> 2 files changed, 65 insertions(+), 137 deletions(-)
>
> diff --git a/doc/fftools-common-opts.texi b/doc/fftools-common-opts.texi
> index 84705c0b68..43c1f4d2d6 100644
> --- a/doc/fftools-common-opts.texi
> +++ b/doc/fftools-common-opts.texi
> @@ -34,27 +34,21 @@ Possible forms of stream specifiers are:
> @table @option
> @item @var{stream_index}
> Matches the stream with this index. E.g. @code{-threads:1 4} would set the
> -thread count for the second stream to 4.
> - at item @var{stream_type}[:@var{stream_index}]
> +thread count for the second stream to 4. If @var{stream_index} is used as an
> +additional stream specifier (see below), then it selects stream number
> + at var{stream_index} from the matching streams.
> + at item @var{stream_type}[:@var{additional_stream_specifier}]
> @var{stream_type} is one of following: 'v' or 'V' for video, 'a' for audio, 's'
> for subtitle, 'd' for data, and 't' for attachments. 'v' matches all video
> streams, 'V' only matches video streams which are not attached pictures, video
> -thumbnails or cover arts. If @var{stream_index} is given, then it matches
> -stream number @var{stream_index} of this type. Otherwise, it matches all
> -streams of this type.
> - at item p:@var{program_id}[:@var{stream_index}] or p:@var{program_id}[:@var{stream_type}[:@var{stream_index}]] or
> -p:@var{program_id}:m:@var{key}[:@var{value}]
> -In first version, if @var{stream_index} is given, then it matches the stream with number @var{stream_index}
> -in the program with the id @var{program_id}. Otherwise, it matches all streams in the
> -program. In the second version, @var{stream_type} is one of following: 'v' for video, 'a' for audio, 's'
> -for subtitle, 'd' for data. If @var{stream_index} is also given, then it matches
> -stream number @var{stream_index} of this type in the program with the id @var{program_id}.
> -Otherwise, if only @var{stream_type} is given, it matches all
> -streams of this type in the program with the id @var{program_id}.
> -In the third version matches streams in the program with the id @var{program_id} with the metadata
> -tag @var{key} having the specified value. If
> - at var{value} is not given, matches streams that contain the given tag with any
> -value.
> +thumbnails or cover arts. If @var{additional_stream_specifier} is used, then
> +it matches streams which both have this type and match the
> + at var{additional_stream_specifier}. Otherwise, it matches all streams of the
> +specified type.
> + at item p:@var{program_id}[:@var{additional_stream_specifier}]
> +Matches streams which are in the program with the id @var{program_id}. If
> + at var{additional_stream_specifier} is used, then it matches streams which both
> +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).
> diff --git a/libavformat/utils.c b/libavformat/utils.c
> index 7afef545fe..b3c30fe14c 100644
> --- a/libavformat/utils.c
> +++ b/libavformat/utils.c
> @@ -5097,13 +5097,21 @@ 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)
> -{
> - 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] */
> +/* Matches a stream specifier (but ignores requested index)
> + * Returns:
> + * - negative on error
> + * - 0 if st is NOT a matching stream
> + * - >0 if st is a matching stream
> + * *index is set if a specific index is requested from the matching streams. */
> +static int match_stream_specifier(AVFormatContext *s, AVStream *st,
> + const char *spec, int *index)
> +{
> + 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 +5136,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 +5148,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;
> + 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;
> }
> -
> - } 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);
> - }
> -
> - 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 +5238,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[] = {
> --
> 2.16.4
>
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel at ffmpeg.org
> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
More information about the ffmpeg-devel
mailing list