mirror of
https://git.ffmpeg.org/ffmpeg.git
synced 2026-06-16 04:32:47 +02:00
fftools/ffmpeg_opt: add helpers to match stream groups
Will be used to check for specifiers that match a given stream group and not a stream within one. Signed-off-by: James Almer <jamrial@gmail.com>
This commit is contained in:
@@ -1350,6 +1350,77 @@ int check_stream_specifier(AVFormatContext *s, AVStream *st, const char *spec)
|
||||
return ret;
|
||||
}
|
||||
|
||||
unsigned stream_group_specifier_match(const StreamSpecifier *ss,
|
||||
const AVFormatContext *s, const AVStreamGroup *stg,
|
||||
void *logctx)
|
||||
{
|
||||
int start_stream_group = 0, nb_stream_groups;
|
||||
int nb_matched = 0;
|
||||
|
||||
if (ss->idx >= 0)
|
||||
return 0;
|
||||
|
||||
switch (ss->stream_list) {
|
||||
case STREAM_LIST_STREAM_ID:
|
||||
case STREAM_LIST_ALL:
|
||||
case STREAM_LIST_PROGRAM:
|
||||
return 0;
|
||||
case STREAM_LIST_GROUP_ID:
|
||||
// <n-th> stream with given ID makes no sense and should be impossible to request
|
||||
av_assert0(ss->idx < 0);
|
||||
// return early if we know for sure the stream does not match
|
||||
if (stg->id != ss->list_id)
|
||||
return 0;
|
||||
start_stream_group = stg->index;
|
||||
nb_stream_groups = stg->index + 1;
|
||||
break;
|
||||
case STREAM_LIST_GROUP_IDX:
|
||||
start_stream_group = ss->list_id >= 0 ? 0 : stg->index;
|
||||
nb_stream_groups = stg->index + 1;
|
||||
break;
|
||||
default: av_assert0(0);
|
||||
}
|
||||
|
||||
for (int i = start_stream_group; i < nb_stream_groups; i++) {
|
||||
const AVStreamGroup *candidate = s->stream_groups[i];
|
||||
|
||||
if (ss->meta_key) {
|
||||
const AVDictionaryEntry *tag = av_dict_get(candidate->metadata,
|
||||
ss->meta_key, NULL, 0);
|
||||
|
||||
if (!tag)
|
||||
continue;
|
||||
if (ss->meta_val && strcmp(tag->value, ss->meta_val))
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ss->usable_only) {
|
||||
switch (candidate->type) {
|
||||
case AV_STREAM_GROUP_PARAMS_TILE_GRID: {
|
||||
const AVStreamGroupTileGrid *tg = candidate->params.tile_grid;
|
||||
if (!tg->coded_width || !tg->coded_height || !tg->nb_tiles ||
|
||||
!tg->width || !tg->height || !tg->nb_tiles)
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (ss->disposition &&
|
||||
(candidate->disposition & ss->disposition) != ss->disposition)
|
||||
continue;
|
||||
|
||||
if (stg == candidate)
|
||||
return ss->list_id < 0 || ss->list_id == nb_matched;
|
||||
|
||||
nb_matched++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int filter_codec_opts(const AVDictionary *opts, enum AVCodecID codec_id,
|
||||
AVFormatContext *s, AVStream *st, const AVCodec *codec,
|
||||
AVDictionary **dst, AVDictionary **opts_used)
|
||||
|
||||
@@ -158,6 +158,10 @@ unsigned stream_specifier_match(const StreamSpecifier *ss,
|
||||
const AVFormatContext *s, const AVStream *st,
|
||||
void *logctx);
|
||||
|
||||
unsigned stream_group_specifier_match(const StreamSpecifier *ss,
|
||||
const AVFormatContext *s, const AVStreamGroup *stg,
|
||||
void *logctx);
|
||||
|
||||
void stream_specifier_uninit(StreamSpecifier *ss);
|
||||
|
||||
typedef struct SpecifierOpt {
|
||||
|
||||
@@ -136,6 +136,7 @@ typedef struct StreamMap {
|
||||
int disabled; /* 1 is this mapping is disabled by a negative map */
|
||||
int file_index;
|
||||
int stream_index;
|
||||
int group_index;
|
||||
char *linklabel; /* name of an output link, for mapping lavfi outputs */
|
||||
|
||||
ViewSpecifier vs;
|
||||
@@ -932,6 +933,15 @@ void opt_match_per_stream_int64(void *logctx, const SpecifierOptList *sol,
|
||||
void opt_match_per_stream_dbl(void *logctx, const SpecifierOptList *sol,
|
||||
AVFormatContext *fc, AVStream *st, double *out);
|
||||
|
||||
void opt_match_per_stream_group_str(void *logctx, const SpecifierOptList *sol,
|
||||
AVFormatContext *fc, AVStreamGroup *stg, const char **out);
|
||||
void opt_match_per_stream_group_int(void *logctx, const SpecifierOptList *sol,
|
||||
AVFormatContext *fc, AVStreamGroup *stg, int *out);
|
||||
void opt_match_per_stream_group_int64(void *logctx, const SpecifierOptList *sol,
|
||||
AVFormatContext *fc, AVStreamGroup *stg, int64_t *out);
|
||||
void opt_match_per_stream_group_dbl(void *logctx, const SpecifierOptList *sol,
|
||||
AVFormatContext *fc, AVStreamGroup *stg, double *out);
|
||||
|
||||
int view_specifier_parse(const char **pspec, ViewSpecifier *vs);
|
||||
|
||||
int muxer_thread(void *arg);
|
||||
|
||||
@@ -242,6 +242,70 @@ OPT_MATCH_PER_STREAM(int, int, OPT_TYPE_INT, i);
|
||||
OPT_MATCH_PER_STREAM(int64, int64_t, OPT_TYPE_INT64, i64);
|
||||
OPT_MATCH_PER_STREAM(dbl, double, OPT_TYPE_DOUBLE, dbl);
|
||||
|
||||
static unsigned opt_match_per_stream_group(void *logctx, enum OptionType type,
|
||||
const SpecifierOptList *sol,
|
||||
AVFormatContext *fc, AVStreamGroup *stg)
|
||||
{
|
||||
int matches = 0, match_idx = -1;
|
||||
|
||||
av_assert0((type == sol->type) || !sol->nb_opt);
|
||||
|
||||
for (int i = 0; i < sol->nb_opt; i++) {
|
||||
const StreamSpecifier *ss = &sol->opt[i].stream_spec;
|
||||
|
||||
if (stream_group_specifier_match(ss, fc, stg, logctx)) {
|
||||
match_idx = i;
|
||||
matches++;
|
||||
}
|
||||
}
|
||||
|
||||
if (matches > 1 && sol->opt_canon) {
|
||||
const SpecifierOpt *so = &sol->opt[match_idx];
|
||||
const char *spec = so->specifier && so->specifier[0] ? so->specifier : "";
|
||||
|
||||
char namestr[128] = "";
|
||||
char optval_buf[32];
|
||||
const char *optval = optval_buf;
|
||||
|
||||
snprintf(namestr, sizeof(namestr), "-%s", sol->opt_canon->name);
|
||||
if (sol->opt_canon->flags & OPT_HAS_ALT) {
|
||||
const char * const *names_alt = sol->opt_canon->u1.names_alt;
|
||||
for (int i = 0; names_alt[i]; i++)
|
||||
av_strlcatf(namestr, sizeof(namestr), "/-%s", names_alt[i]);
|
||||
}
|
||||
|
||||
switch (sol->type) {
|
||||
case OPT_TYPE_STRING: optval = so->u.str; break;
|
||||
case OPT_TYPE_INT: snprintf(optval_buf, sizeof(optval_buf), "%d", so->u.i); break;
|
||||
case OPT_TYPE_INT64: snprintf(optval_buf, sizeof(optval_buf), "%"PRId64, so->u.i64); break;
|
||||
case OPT_TYPE_FLOAT: snprintf(optval_buf, sizeof(optval_buf), "%f", so->u.f); break;
|
||||
case OPT_TYPE_DOUBLE: snprintf(optval_buf, sizeof(optval_buf), "%f", so->u.dbl); break;
|
||||
default: av_assert0(0);
|
||||
}
|
||||
|
||||
av_log(logctx, AV_LOG_WARNING, "Multiple %s options specified for "
|
||||
"stream group %d, only the last option '-%s%s%s %s' will be used.\n",
|
||||
namestr, stg->index, sol->opt_canon->name, spec[0] ? ":" : "",
|
||||
spec, optval);
|
||||
}
|
||||
|
||||
return match_idx + 1;
|
||||
}
|
||||
|
||||
#define OPT_MATCH_PER_STREAM_GROUP(name, type, opt_type, m) \
|
||||
void opt_match_per_stream_group_ ## name(void *logctx, const SpecifierOptList *sol, \
|
||||
AVFormatContext *fc, AVStreamGroup *stg, type *out) \
|
||||
{ \
|
||||
unsigned ret = opt_match_per_stream_group(logctx, opt_type, sol, fc, stg); \
|
||||
if (ret > 0) \
|
||||
*out = sol->opt[ret - 1].u.m; \
|
||||
}
|
||||
|
||||
OPT_MATCH_PER_STREAM_GROUP(str, const char *, OPT_TYPE_STRING, str);
|
||||
OPT_MATCH_PER_STREAM_GROUP(int, int, OPT_TYPE_INT, i);
|
||||
OPT_MATCH_PER_STREAM_GROUP(int64, int64_t, OPT_TYPE_INT64, i64);
|
||||
OPT_MATCH_PER_STREAM_GROUP(dbl, double, OPT_TYPE_DOUBLE, dbl);
|
||||
|
||||
int view_specifier_parse(const char **pspec, ViewSpecifier *vs)
|
||||
{
|
||||
const char *spec = *pspec;
|
||||
@@ -504,8 +568,10 @@ static int opt_map(void *optctx, const char *opt, const char *arg)
|
||||
}
|
||||
|
||||
if (arg[0] == '[') {
|
||||
ViewSpecifier vs;
|
||||
/* this mapping refers to lavfi output */
|
||||
const char *c = arg + 1;
|
||||
char *endptr;
|
||||
|
||||
ret = GROW_ARRAY(o->stream_maps, o->nb_stream_maps);
|
||||
if (ret < 0)
|
||||
@@ -518,6 +584,27 @@ static int opt_map(void *optctx, const char *opt, const char *arg)
|
||||
ret = AVERROR(EINVAL);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
arg++;
|
||||
|
||||
m->group_index = -1;
|
||||
file_idx = strtol(arg, &endptr, 0);
|
||||
if (file_idx >= nb_input_files || file_idx < 0)
|
||||
goto end;
|
||||
|
||||
arg = endptr;
|
||||
ret = stream_specifier_parse(&ss, *arg == ':' ? arg + 1 : arg, 1, NULL);
|
||||
if (ret < 0)
|
||||
goto end;
|
||||
|
||||
arg = ss.remainder ? ss.remainder : "";
|
||||
ret = view_specifier_parse(&arg, &vs);
|
||||
if (ret < 0 || (*arg && strcmp(arg, "]")))
|
||||
goto end;
|
||||
|
||||
m->file_index = file_idx;
|
||||
m->stream_index = ss.idx;
|
||||
m->group_index = ss.stream_list == STREAM_LIST_GROUP_IDX ? ss.list_id : -1;
|
||||
} else {
|
||||
ViewSpecifier vs;
|
||||
char *endptr;
|
||||
@@ -583,6 +670,7 @@ static int opt_map(void *optctx, const char *opt, const char *arg)
|
||||
|
||||
m->file_index = file_idx;
|
||||
m->stream_index = i;
|
||||
m->group_index = ss.stream_list == STREAM_LIST_GROUP_IDX ? ss.list_id : -1;
|
||||
m->vs = vs;
|
||||
}
|
||||
}
|
||||
@@ -602,6 +690,7 @@ static int opt_map(void *optctx, const char *opt, const char *arg)
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
end:
|
||||
ret = 0;
|
||||
fail:
|
||||
stream_specifier_uninit(&ss);
|
||||
|
||||
Reference in New Issue
Block a user