mirror of
https://git.ffmpeg.org/ffmpeg.git
synced 2024-12-28 10:22:10 +00:00
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Ⓜ️language:eng to select the English language
audio stream from program 204.
Signed-off-by: Marton Balint <cus@passwd.hu>
This commit is contained in:
parent
b35843e391
commit
dbfd042983
@ -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.
|
||||
@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
|
||||
@var{stream_index} from the matching streams.
|
||||
@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.
|
||||
@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
|
||||
@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
|
||||
@var{additional_stream_specifier}. Otherwise, it matches all streams of the
|
||||
specified type.
|
||||
@item p:@var{program_id}[:@var{additional_stream_specifier}]
|
||||
Matches streams which are in the program with the id @var{program_id}. If
|
||||
@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).
|
||||
|
@ -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);
|
||||
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;
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
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[] = {
|
||||
|
Loading…
Reference in New Issue
Block a user