You've already forked FFmpeg
mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2025-08-15 14:13:16 +02: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:
@@ -34,27 +34,21 @@ Possible forms of stream specifiers are:
|
|||||||
@table @option
|
@table @option
|
||||||
@item @var{stream_index}
|
@item @var{stream_index}
|
||||||
Matches the stream with this index. E.g. @code{-threads:1 4} would set the
|
Matches the stream with this index. E.g. @code{-threads:1 4} would set the
|
||||||
thread count for the second stream to 4.
|
thread count for the second stream to 4. If @var{stream_index} is used as an
|
||||||
@item @var{stream_type}[:@var{stream_index}]
|
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'
|
@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
|
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
|
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
|
thumbnails or cover arts. If @var{additional_stream_specifier} is used, then
|
||||||
stream number @var{stream_index} of this type. Otherwise, it matches all
|
it matches streams which both have this type and match the
|
||||||
streams of this type.
|
@var{additional_stream_specifier}. Otherwise, it matches all streams of the
|
||||||
@item p:@var{program_id}[:@var{stream_index}] or p:@var{program_id}[:@var{stream_type}[:@var{stream_index}]] or
|
specified type.
|
||||||
p:@var{program_id}:m:@var{key}[:@var{value}]
|
@item p:@var{program_id}[:@var{additional_stream_specifier}]
|
||||||
In first version, if @var{stream_index} is given, then it matches the stream with number @var{stream_index}
|
Matches streams which are in the program with the id @var{program_id}. If
|
||||||
in the program with the id @var{program_id}. Otherwise, it matches all streams in the
|
@var{additional_stream_specifier} is used, then it matches streams which both
|
||||||
program. In the second version, @var{stream_type} is one of following: 'v' for video, 'a' for audio, 's'
|
are part of the program and match the @var{additional_stream_specifier}.
|
||||||
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.
|
|
||||||
|
|
||||||
@item #@var{stream_id} or i:@var{stream_id}
|
@item #@var{stream_id} or i:@var{stream_id}
|
||||||
Match the stream by stream id (e.g. PID in MPEG-TS container).
|
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;
|
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 */
|
if (*spec <= '9' && *spec >= '0') { /* opt:index */
|
||||||
return strtol(spec, NULL, 0) == st->index;
|
if (index)
|
||||||
else if (*spec == 'v' || *spec == 'a' || *spec == 's' || *spec == 'd' ||
|
*index = strtol(spec, NULL, 0);
|
||||||
*spec == 't' || *spec == 'V') { /* opt:[vasdtV] */
|
return 1;
|
||||||
|
} else if (*spec == 'v' || *spec == 'a' || *spec == 's' || *spec == 'd' ||
|
||||||
|
*spec == 't' || *spec == 'V') { /* opt:[vasdtV] */
|
||||||
enum AVMediaType type;
|
enum AVMediaType type;
|
||||||
int nopic = 0;
|
int nopic = 0;
|
||||||
|
|
||||||
@@ -5128,27 +5139,8 @@ FF_ENABLE_DEPRECATION_WARNINGS
|
|||||||
#endif
|
#endif
|
||||||
if (nopic && (st->disposition & AV_DISPOSITION_ATTACHED_PIC))
|
if (nopic && (st->disposition & AV_DISPOSITION_ATTACHED_PIC))
|
||||||
return 0;
|
return 0;
|
||||||
if (*spec++ == ':') { /* possibly followed by :index */
|
if (*spec++ == ':') /* possibly followed by another specifier */
|
||||||
int i, index = strtol(spec, NULL, 0);
|
return match_stream_specifier(s, st, spec, index);
|
||||||
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;
|
|
||||||
}
|
|
||||||
return 1;
|
return 1;
|
||||||
} else if (*spec == 'p' && *(spec + 1) == ':') {
|
} else if (*spec == 'p' && *(spec + 1) == ':') {
|
||||||
int prog_id, i, j;
|
int prog_id, i, j;
|
||||||
@@ -5159,99 +5151,15 @@ FF_ENABLE_DEPRECATION_WARNINGS
|
|||||||
if (s->programs[i]->id != prog_id)
|
if (s->programs[i]->id != prog_id)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (*endptr++ == ':') { // p:<id>:....
|
for (j = 0; j < s->programs[i]->nb_stream_indexes; j++) {
|
||||||
if ( *endptr == 'a' || *endptr == 'v' ||
|
if (st->index == s->programs[i]->stream_index[j]) {
|
||||||
*endptr == 's' || *endptr == 'd') { // p:<id>:<st_type>[:<index>]
|
if (*endptr++ == ':') { // p:<id>:....
|
||||||
enum AVMediaType type;
|
return match_stream_specifier(s, st, endptr, index);
|
||||||
|
} else {
|
||||||
switch (*endptr++) {
|
return 1;
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
return 0;
|
||||||
} else if (*spec == '#' ||
|
} else if (*spec == '#' ||
|
||||||
@@ -5333,10 +5241,39 @@ FF_ENABLE_DEPRECATION_WARNINGS
|
|||||||
} else if (!*spec) /* empty specifier, matches everything */
|
} else if (!*spec) /* empty specifier, matches everything */
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
av_log(s, AV_LOG_ERROR, "Invalid stream specifier: %s.\n", spec);
|
|
||||||
return AVERROR(EINVAL);
|
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)
|
int ff_generate_avci_extradata(AVStream *st)
|
||||||
{
|
{
|
||||||
static const uint8_t avci100_1080p_extradata[] = {
|
static const uint8_t avci100_1080p_extradata[] = {
|
||||||
|
Reference in New Issue
Block a user