* [FFmpeg-devel] [PATCH 1/6] fftools/ffmpeg: replace MATCH_PER_STREAM_OPT(.., str, ..) with a function
@ 2024-08-10 17:16 Anton Khirnov
2024-08-10 17:16 ` [FFmpeg-devel] [PATCH 2/6] fftools/ffmpeg: replace remaining uses of MATCH_PER_STREAM_OPT() Anton Khirnov
` (4 more replies)
0 siblings, 5 replies; 6+ messages in thread
From: Anton Khirnov @ 2024-08-10 17:16 UTC (permalink / raw)
To: ffmpeg-devel
This has multiple advantages:
* The macro has multiple parameters that often have similar or identical
values, yet very different meanings (one is the name of the
OptionsContext member where the parsed options are stored, the other
the name of the variable into which the result is written); this
change makes each of these explicit.
* The macro returns on failure, which may cause leaks - this was the
reason for adding MATCH_PER_STREAM_OPT_CLEAN(), also ost_add()
currently leaks encoder_opts. The new function returns failure to its
caller, which decides how to deal with it. While that adds a lot of
error checks/forwards for now, those will be reduced in following
commits.
* new code is type- and const- correct
Invocations of MATCH_PER_STREAM_OPT() with other types will be converted
in following commits.
---
fftools/cmdutils.c | 6 +-
fftools/cmdutils.h | 3 +
fftools/ffmpeg.h | 4 +-
fftools/ffmpeg_demux.c | 74 ++++++++++++------
fftools/ffmpeg_mux.h | 2 +-
fftools/ffmpeg_mux_init.c | 156 +++++++++++++++++++++++++++-----------
fftools/ffmpeg_opt.c | 67 ++++++++++++++++
7 files changed, 242 insertions(+), 70 deletions(-)
diff --git a/fftools/cmdutils.c b/fftools/cmdutils.c
index 9b18cf5e4d..6286fd87f7 100644
--- a/fftools/cmdutils.c
+++ b/fftools/cmdutils.c
@@ -246,6 +246,8 @@ static int write_option(void *optctx, const OptionDef *po, const char *opt,
(uint8_t *)optctx + po->u.off : po->u.dst_ptr;
char *arg_allocated = NULL;
+ enum OptionType so_type = po->type;
+
SpecifierOptList *sol = NULL;
double num;
int ret = 0;
@@ -310,6 +312,7 @@ static int write_option(void *optctx, const OptionDef *po, const char *opt,
goto finish;
*(int *)dst = num;
+ so_type = OPT_TYPE_INT;
} else if (po->type == OPT_TYPE_INT64) {
ret = parse_number(opt, arg, OPT_TYPE_INT64, INT64_MIN, (double)INT64_MAX, &num);
if (ret < 0)
@@ -323,6 +326,7 @@ static int write_option(void *optctx, const OptionDef *po, const char *opt,
opt, arg);
goto finish;
}
+ so_type = OPT_TYPE_INT64;
} else if (po->type == OPT_TYPE_FLOAT) {
ret = parse_number(opt, arg, OPT_TYPE_FLOAT, -INFINITY, INFINITY, &num);
if (ret < 0)
@@ -352,7 +356,7 @@ static int write_option(void *optctx, const OptionDef *po, const char *opt,
}
if (sol) {
- sol->type = po->type;
+ sol->type = so_type;
sol->opt_canon = (po->flags & OPT_HAS_CANON) ?
find_option(defs, po->u1.name_canon) : po;
}
diff --git a/fftools/cmdutils.h b/fftools/cmdutils.h
index 14340dff7d..abc8d26607 100644
--- a/fftools/cmdutils.h
+++ b/fftools/cmdutils.h
@@ -120,6 +120,9 @@ typedef struct SpecifierOptList {
/* Canonical option definition that was parsed into this list. */
const struct OptionDef *opt_canon;
+ /* Type corresponding to the field that should be used from SpecifierOpt.u.
+ * May not match the option type, e.g. OPT_TYPE_BOOL options are stored as
+ * int, so this field would be OPT_TYPE_INT for them */
enum OptionType type;
} SpecifierOptList;
diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h
index d0298d53cf..7d82d7d7c2 100644
--- a/fftools/ffmpeg.h
+++ b/fftools/ffmpeg.h
@@ -593,7 +593,7 @@ typedef struct OutputStream {
KeyframeForceCtx kf;
- char *logfile_prefix;
+ const char *logfile_prefix;
FILE *logfile;
// simple filtergraph feeding this stream, if any
@@ -902,6 +902,8 @@ void update_benchmark(const char *fmt, ...);
const char *opt_match_per_type_str(const SpecifierOptList *sol,
char mediatype);
+int opt_match_per_stream_str(void *logctx, const SpecifierOptList *sol,
+ AVFormatContext *fc, AVStream *st, const char **out);
int muxer_thread(void *arg);
int encoder_thread(void *arg);
diff --git a/fftools/ffmpeg_demux.c b/fftools/ffmpeg_demux.c
index 6f7d78c896..0c92d31c10 100644
--- a/fftools/ffmpeg_demux.c
+++ b/fftools/ffmpeg_demux.c
@@ -1077,14 +1077,19 @@ int ist_filter_add(InputStream *ist, InputFilter *ifilter, int is_simple,
return ds->sch_idx_dec;
}
-static int choose_decoder(const OptionsContext *o, AVFormatContext *s, AVStream *st,
+static int choose_decoder(const OptionsContext *o, void *logctx,
+ AVFormatContext *s, AVStream *st,
enum HWAccelID hwaccel_id, enum AVHWDeviceType hwaccel_device_type,
const AVCodec **pcodec)
{
- char *codec_name = NULL;
+ const char *codec_name = NULL;
+ int ret;
+
+ ret = opt_match_per_stream_str(logctx, &o->codec_names, s, st, &codec_name);
+ if (ret < 0)
+ return ret;
- MATCH_PER_STREAM_OPT(codec_names, str, codec_name, s, st);
if (codec_name) {
int ret = find_codec(NULL, codec_name, st->codecpar->codec_type, 0, pcodec);
if (ret < 0)
@@ -1226,14 +1231,14 @@ static int ist_add(const OptionsContext *o, Demuxer *d, AVStream *st, AVDictiona
AVCodecParameters *par = st->codecpar;
DemuxStream *ds;
InputStream *ist;
- char *framerate = NULL, *hwaccel_device = NULL;
+ const char *framerate = NULL, *hwaccel_device = NULL;
const char *hwaccel = NULL;
const char *apply_cropping = NULL;
- char *hwaccel_output_format = NULL;
- char *codec_tag = NULL;
- char *bsfs = NULL;
+ const char *hwaccel_output_format = NULL;
+ const char *codec_tag = NULL;
+ const char *bsfs = NULL;
char *next;
- char *discard_str = NULL;
+ const char *discard_str = NULL;
int ret;
ds = demux_stream_alloc(d, st);
@@ -1256,7 +1261,9 @@ static int ist_add(const OptionsContext *o, Demuxer *d, AVStream *st, AVDictiona
MATCH_PER_STREAM_OPT(autorotate, i, ds->autorotate, ic, st);
ds->apply_cropping = CROP_ALL;
- MATCH_PER_STREAM_OPT(apply_cropping, str, apply_cropping, ic, st);
+ ret = opt_match_per_stream_str(ist, &o->apply_cropping, ic, st, &apply_cropping);
+ if (ret < 0)
+ return ret;
if (apply_cropping) {
const AVOption opts[] = {
{ "apply_cropping", NULL, 0, AV_OPT_TYPE_INT,
@@ -1282,7 +1289,9 @@ static int ist_add(const OptionsContext *o, Demuxer *d, AVStream *st, AVDictiona
}
}
- MATCH_PER_STREAM_OPT(codec_tags, str, codec_tag, ic, st);
+ ret = opt_match_per_stream_str(ist, &o->codec_tags, ic, st, &codec_tag);
+ if (ret < 0)
+ return ret;
if (codec_tag) {
uint32_t tag = strtol(codec_tag, &next, 0);
if (*next) {
@@ -1299,9 +1308,14 @@ static int ist_add(const OptionsContext *o, Demuxer *d, AVStream *st, AVDictiona
if (ret < 0)
return ret;
- MATCH_PER_STREAM_OPT(hwaccels, str, hwaccel, ic, st);
- MATCH_PER_STREAM_OPT(hwaccel_output_formats, str,
- hwaccel_output_format, ic, st);
+ ret = opt_match_per_stream_str(ist, &o->hwaccels, ic, st, &hwaccel);
+ if (ret < 0)
+ return ret;
+
+ ret = opt_match_per_stream_str(ist, &o->hwaccel_output_formats, ic, st,
+ &hwaccel_output_format);
+ if (ret < 0)
+ return ret;
if (!hwaccel_output_format && hwaccel && !strcmp(hwaccel, "cuvid")) {
av_log(ist, AV_LOG_WARNING,
@@ -1360,7 +1374,9 @@ static int ist_add(const OptionsContext *o, Demuxer *d, AVStream *st, AVDictiona
}
}
- MATCH_PER_STREAM_OPT(hwaccel_devices, str, hwaccel_device, ic, st);
+ ret = opt_match_per_stream_str(ist, &o->hwaccel_devices, ic, st, &hwaccel_device);
+ if (ret < 0)
+ return ret;
if (hwaccel_device) {
ds->dec_opts.hwaccel_device = av_strdup(hwaccel_device);
if (!ds->dec_opts.hwaccel_device)
@@ -1368,7 +1384,7 @@ static int ist_add(const OptionsContext *o, Demuxer *d, AVStream *st, AVDictiona
}
}
- ret = choose_decoder(o, ic, st, ds->dec_opts.hwaccel_id,
+ ret = choose_decoder(o, ist, ic, st, ds->dec_opts.hwaccel_id,
ds->dec_opts.hwaccel_device_type, &ist->dec);
if (ret < 0)
return ret;
@@ -1391,7 +1407,9 @@ static int ist_add(const OptionsContext *o, Demuxer *d, AVStream *st, AVDictiona
(o->data_disable && ist->st->codecpar->codec_type == AVMEDIA_TYPE_DATA))
ist->user_set_discard = AVDISCARD_ALL;
- MATCH_PER_STREAM_OPT(discard, str, discard_str, ic, st);
+ ret = opt_match_per_stream_str(ist, &o->discard, ic, st, &discard_str);
+ if (ret < 0)
+ return ret;
if (discard_str) {
ret = av_opt_set(ist->st, "discard", discard_str, 0);
if (ret < 0) {
@@ -1413,7 +1431,9 @@ static int ist_add(const OptionsContext *o, Demuxer *d, AVStream *st, AVDictiona
switch (par->codec_type) {
case AVMEDIA_TYPE_VIDEO:
- MATCH_PER_STREAM_OPT(frame_rates, str, framerate, ic, st);
+ ret = opt_match_per_stream_str(ist, &o->frame_rates, ic, st, &framerate);
+ if (ret < 0)
+ return ret;
if (framerate) {
ret = av_parse_video_rate(&ist->framerate, framerate);
if (ret < 0) {
@@ -1430,8 +1450,11 @@ static int ist_add(const OptionsContext *o, Demuxer *d, AVStream *st, AVDictiona
break;
case AVMEDIA_TYPE_AUDIO: {
- char *ch_layout_str = NULL;
- MATCH_PER_STREAM_OPT(audio_ch_layouts, str, ch_layout_str, ic, st);
+ const char *ch_layout_str = NULL;
+
+ ret = opt_match_per_stream_str(ist, &o->audio_ch_layouts, ic, st, &ch_layout_str);
+ if (ret < 0)
+ return ret;
if (ch_layout_str) {
AVChannelLayout ch_layout;
ret = av_channel_layout_from_string(&ch_layout, ch_layout_str);
@@ -1458,9 +1481,12 @@ static int ist_add(const OptionsContext *o, Demuxer *d, AVStream *st, AVDictiona
}
case AVMEDIA_TYPE_DATA:
case AVMEDIA_TYPE_SUBTITLE: {
- char *canvas_size = NULL;
+ const char *canvas_size = NULL;
MATCH_PER_STREAM_OPT(fix_sub_duration, i, ist->fix_sub_duration, ic, st);
- MATCH_PER_STREAM_OPT(canvas_sizes, str, canvas_size, ic, st);
+
+ ret = opt_match_per_stream_str(ist, &o->canvas_sizes, ic, st, &canvas_size);
+ if (ret < 0)
+ return ret;
if (canvas_size) {
ret = av_parse_video_size(&par->width, &par->height,
canvas_size);
@@ -1490,7 +1516,9 @@ static int ist_add(const OptionsContext *o, Demuxer *d, AVStream *st, AVDictiona
if (ist->st->sample_aspect_ratio.num)
ist->par->sample_aspect_ratio = ist->st->sample_aspect_ratio;
- MATCH_PER_STREAM_OPT(bitstream_filters, str, bsfs, ic, st);
+ ret = opt_match_per_stream_str(ist, &o->bitstream_filters, ic, st, &bsfs);
+ if (ret < 0)
+ return ret;
if (bsfs) {
ret = av_bsf_list_parse_str(bsfs, &ds->bsf);
if (ret < 0) {
@@ -1752,7 +1780,7 @@ int ifile_open(const OptionsContext *o, const char *filename, Scheduler *sch)
/* apply forced codec ids */
for (i = 0; i < ic->nb_streams; i++) {
const AVCodec *dummy;
- ret = choose_decoder(o, ic, ic->streams[i], HWACCEL_NONE, AV_HWDEVICE_TYPE_NONE,
+ ret = choose_decoder(o, f, ic, ic->streams[i], HWACCEL_NONE, AV_HWDEVICE_TYPE_NONE,
&dummy);
if (ret < 0)
return ret;
diff --git a/fftools/ffmpeg_mux.h b/fftools/ffmpeg_mux.h
index 1c1b407484..22d728a919 100644
--- a/fftools/ffmpeg_mux.h
+++ b/fftools/ffmpeg_mux.h
@@ -79,7 +79,7 @@ typedef struct MuxStream {
int ts_drop;
#endif
- char *apad;
+ const char *apad;
} MuxStream;
typedef struct Muxer {
diff --git a/fftools/ffmpeg_mux_init.c b/fftools/ffmpeg_mux_init.c
index 4a2b5924a4..c7efeda7bf 100644
--- a/fftools/ffmpeg_mux_init.c
+++ b/fftools/ffmpeg_mux_init.c
@@ -70,11 +70,14 @@ static int choose_encoder(const OptionsContext *o, AVFormatContext *s,
OutputStream *ost, const AVCodec **enc)
{
enum AVMediaType type = ost->type;
- char *codec_name = NULL;
+ const char *codec_name = NULL;
+ int ret;
*enc = NULL;
- MATCH_PER_STREAM_OPT(codec_names, str, codec_name, s, ost->st);
+ ret = opt_match_per_stream_str(ost, &o->codec_names, s, ost->st, &codec_name);
+ if (ret < 0)
+ return ret;
if (type != AVMEDIA_TYPE_VIDEO &&
type != AVMEDIA_TYPE_AUDIO &&
@@ -416,12 +419,17 @@ static int ost_get_filters(const OptionsContext *o, AVFormatContext *oc,
OutputStream *ost, char **dst)
{
const char *filters = NULL;
+ int ret;
#if FFMPEG_OPT_FILTER_SCRIPT
const char *filters_script = NULL;
- MATCH_PER_STREAM_OPT(filter_scripts, str, filters_script, oc, ost->st);
+ ret = opt_match_per_stream_str(ost, &o->filter_scripts, oc, ost->st, &filters_script);
+ if (ret < 0)
+ return ret;
#endif
- MATCH_PER_STREAM_OPT(filters, str, filters, oc, ost->st);
+ ret = opt_match_per_stream_str(ost, &o->filters, oc, ost->st, &filters);
+ if (ret < 0)
+ return ret;
if (!ost->enc) {
if (
@@ -586,18 +594,22 @@ static int new_stream_video(Muxer *mux, const OptionsContext *o,
MuxStream *ms = ms_from_ost(ost);
AVFormatContext *oc = mux->fc;
AVStream *st;
- char *frame_rate = NULL, *max_frame_rate = NULL, *frame_aspect_ratio = NULL;
+ const char *frame_rate = NULL, *max_frame_rate = NULL, *frame_aspect_ratio = NULL;
int ret = 0;
st = ost->st;
- MATCH_PER_STREAM_OPT(frame_rates, str, frame_rate, oc, st);
+ ret = opt_match_per_stream_str(ost, &o->frame_rates, oc, st, &frame_rate);
+ if (ret < 0)
+ return ret;
if (frame_rate && av_parse_video_rate(&ost->frame_rate, frame_rate) < 0) {
av_log(ost, AV_LOG_FATAL, "Invalid framerate value: %s\n", frame_rate);
return AVERROR(EINVAL);
}
- MATCH_PER_STREAM_OPT(max_frame_rates, str, max_frame_rate, oc, st);
+ ret = opt_match_per_stream_str(ost, &o->max_frame_rates, oc, st, &max_frame_rate);
+ if (ret < 0)
+ return ret;
if (max_frame_rate && av_parse_video_rate(&ost->max_frame_rate, max_frame_rate) < 0) {
av_log(ost, AV_LOG_FATAL, "Invalid maximum framerate value: %s\n", max_frame_rate);
return AVERROR(EINVAL);
@@ -608,7 +620,9 @@ static int new_stream_video(Muxer *mux, const OptionsContext *o,
return AVERROR(EINVAL);
}
- MATCH_PER_STREAM_OPT(frame_aspect_ratios, str, frame_aspect_ratio, oc, st);
+ ret = opt_match_per_stream_str(ost, &o->frame_aspect_ratios, oc, st, &frame_aspect_ratio);
+ if (ret < 0)
+ return ret;
if (frame_aspect_ratio) {
AVRational q;
if (av_parse_ratio(&q, frame_aspect_ratio, 255, 0, NULL) < 0 ||
@@ -622,14 +636,16 @@ static int new_stream_video(Muxer *mux, const OptionsContext *o,
if (ost->enc_ctx) {
AVCodecContext *video_enc = ost->enc_ctx;
const char *p = NULL, *fps_mode = NULL;
- char *frame_size = NULL;
- char *frame_pix_fmt = NULL;
- char *intra_matrix = NULL, *inter_matrix = NULL;
- char *chroma_intra_matrix = NULL;
+ const char *frame_size = NULL;
+ const char *frame_pix_fmt = NULL;
+ const char *intra_matrix = NULL, *inter_matrix = NULL;
+ const char *chroma_intra_matrix = NULL;
int do_pass = 0;
int i;
- MATCH_PER_STREAM_OPT(frame_sizes, str, frame_size, oc, st);
+ ret = opt_match_per_stream_str(ost, &o->frame_sizes, oc, st, &frame_size);
+ if (ret < 0)
+ return ret;
if (frame_size) {
ret = av_parse_video_size(&video_enc->width, &video_enc->height, frame_size);
if (ret < 0) {
@@ -638,7 +654,9 @@ static int new_stream_video(Muxer *mux, const OptionsContext *o,
}
}
- MATCH_PER_STREAM_OPT(frame_pix_fmts, str, frame_pix_fmt, oc, st);
+ ret = opt_match_per_stream_str(ost, &o->frame_pix_fmts, oc, st, &frame_pix_fmt);
+ if (ret < 0)
+ return ret;
if (frame_pix_fmt && *frame_pix_fmt == '+') {
*keep_pix_fmt = 1;
if (!*++frame_pix_fmt)
@@ -650,7 +668,9 @@ static int new_stream_video(Muxer *mux, const OptionsContext *o,
return AVERROR(EINVAL);
}
- MATCH_PER_STREAM_OPT(intra_matrices, str, intra_matrix, oc, st);
+ ret = opt_match_per_stream_str(ost, &o->intra_matrices, oc, st, &intra_matrix);
+ if (ret < 0)
+ return ret;
if (intra_matrix) {
if (!(video_enc->intra_matrix = av_mallocz(sizeof(*video_enc->intra_matrix) * 64)))
return AVERROR(ENOMEM);
@@ -659,7 +679,9 @@ static int new_stream_video(Muxer *mux, const OptionsContext *o,
if (ret < 0)
return ret;
}
- MATCH_PER_STREAM_OPT(chroma_intra_matrices, str, chroma_intra_matrix, oc, st);
+ ret = opt_match_per_stream_str(ost, &o->chroma_intra_matrices, oc, st, &chroma_intra_matrix);
+ if (ret < 0)
+ return ret;
if (chroma_intra_matrix) {
uint16_t *p = av_mallocz(sizeof(*video_enc->chroma_intra_matrix) * 64);
if (!p)
@@ -669,7 +691,9 @@ static int new_stream_video(Muxer *mux, const OptionsContext *o,
if (ret < 0)
return ret;
}
- MATCH_PER_STREAM_OPT(inter_matrices, str, inter_matrix, oc, st);
+ ret = opt_match_per_stream_str(ost, &o->inter_matrices, oc, st, &inter_matrix);
+ if (ret < 0)
+ return ret;
if (inter_matrix) {
if (!(video_enc->inter_matrix = av_mallocz(sizeof(*video_enc->inter_matrix) * 64)))
return AVERROR(ENOMEM);
@@ -678,7 +702,9 @@ static int new_stream_video(Muxer *mux, const OptionsContext *o,
return ret;
}
- MATCH_PER_STREAM_OPT(rc_overrides, str, p, oc, st);
+ ret = opt_match_per_stream_str(ost, &o->rc_overrides, oc, st, &p);
+ if (ret < 0)
+ return ret;
for (i = 0; p; i++) {
int start, end, q;
int e = sscanf(p, "%d,%d,%d", &start, &end, &q);
@@ -717,7 +743,9 @@ static int new_stream_video(Muxer *mux, const OptionsContext *o,
video_enc->flags |= AV_CODEC_FLAG_PASS2;
}
- MATCH_PER_STREAM_OPT(passlogfiles, str, ost->logfile_prefix, oc, st);
+ ret = opt_match_per_stream_str(ost, &o->passlogfiles, oc, st, &ost->logfile_prefix);
+ if (ret < 0)
+ return ret;
if (ost->logfile_prefix &&
!(ost->logfile_prefix = av_strdup(ost->logfile_prefix)))
return AVERROR(ENOMEM);
@@ -778,7 +806,9 @@ static int new_stream_video(Muxer *mux, const OptionsContext *o,
#else
*vsync_method = VSYNC_AUTO;
#endif
- MATCH_PER_STREAM_OPT(fps_mode, str, fps_mode, oc, st);
+ ret = opt_match_per_stream_str(ost, &o->fps_mode, oc, st, &fps_mode);
+ if (ret < 0)
+ return ret;
if (fps_mode) {
ret = parse_and_set_vsync(fps_mode, vsync_method, ost->file->index, ost->index, 0);
if (ret < 0)
@@ -834,8 +864,9 @@ static int new_stream_audio(Muxer *mux, const OptionsContext *o,
if (ost->enc_ctx) {
AVCodecContext *audio_enc = ost->enc_ctx;
int channels = 0;
- char *layout = NULL;
- char *sample_fmt = NULL;
+ const char *layout = NULL;
+ const char *sample_fmt = NULL;
+ int ret;
MATCH_PER_STREAM_OPT(audio_channels, i, channels, oc, st);
if (channels) {
@@ -843,13 +874,17 @@ static int new_stream_audio(Muxer *mux, const OptionsContext *o,
audio_enc->ch_layout.nb_channels = channels;
}
- MATCH_PER_STREAM_OPT(audio_ch_layouts, str, layout, oc, st);
+ ret = opt_match_per_stream_str(ost, &o->audio_ch_layouts, oc, st, &layout);
+ if (ret < 0)
+ return ret;
if (layout && av_channel_layout_from_string(&audio_enc->ch_layout, layout) < 0) {
av_log(ost, AV_LOG_FATAL, "Unknown channel layout: %s\n", layout);
return AVERROR(EINVAL);
}
- MATCH_PER_STREAM_OPT(sample_fmts, str, sample_fmt, oc, st);
+ ret = opt_match_per_stream_str(ost, &o->sample_fmts, oc, st, &sample_fmt);
+ if (ret < 0)
+ return ret;
if (sample_fmt &&
(audio_enc->sample_fmt = av_get_sample_fmt(sample_fmt)) == AV_SAMPLE_FMT_NONE) {
av_log(ost, AV_LOG_FATAL, "Invalid sample format '%s'\n", sample_fmt);
@@ -858,7 +893,9 @@ static int new_stream_audio(Muxer *mux, const OptionsContext *o,
MATCH_PER_STREAM_OPT(audio_sample_rate, i, audio_enc->sample_rate, oc, st);
- MATCH_PER_STREAM_OPT(apad, str, ms->apad, oc, st);
+ ret = opt_match_per_stream_str(ost, &o->apad, oc, st, &ms->apad);
+ if (ret < 0)
+ return ret;
}
return 0;
@@ -880,9 +917,12 @@ static int new_stream_subtitle(Muxer *mux, const OptionsContext *o,
avcodec_descriptor_get(subtitle_enc->codec_id);
int input_props = 0, output_props = 0;
- char *frame_size = NULL;
+ const char *frame_size = NULL;
+ int ret;
- MATCH_PER_STREAM_OPT(frame_sizes, str, frame_size, mux->fc, st);
+ ret = opt_match_per_stream_str(ost, &o->frame_sizes, mux->fc, st, &frame_size);
+ if (ret < 0)
+ return ret;
if (frame_size) {
int ret = av_parse_video_size(&subtitle_enc->width, &subtitle_enc->height, frame_size);
if (ret < 0) {
@@ -1039,8 +1079,8 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type,
int threads_manual = 0;
AVRational enc_tb = { 0, 0 };
enum VideoSyncMethod vsync_method = VSYNC_AUTO;
- const char *bsfs = NULL, *time_base = NULL;
- char *filters = NULL, *next, *codec_tag = NULL;
+ const char *bsfs = NULL, *time_base = NULL, *codec_tag = NULL;
+ char *filters = NULL, *next;
double qscale = -1;
st = avformat_new_stream(oc, NULL);
@@ -1151,9 +1191,9 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type,
if (ost->enc_ctx) {
AVCodecContext *enc = ost->enc_ctx;
AVIOContext *s = NULL;
- char *buf = NULL, *arg = NULL, *preset = NULL;
+ char *buf = NULL, *arg = NULL;
const char *enc_stats_pre = NULL, *enc_stats_post = NULL, *mux_stats = NULL;
- const char *enc_time_base = NULL;
+ const char *enc_time_base = NULL, *preset = NULL;
ret = filter_codec_opts(o->g->codec_opts, enc->codec_id,
oc, st, enc->codec, &encoder_opts,
@@ -1161,7 +1201,9 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type,
if (ret < 0)
goto fail;
- MATCH_PER_STREAM_OPT(presets, str, preset, oc, st);
+ ret = opt_match_per_stream_str(ost, &o->presets, oc, st, &preset);
+ if (ret < 0)
+ goto fail;
MATCH_PER_STREAM_OPT(autoscale, i, autoscale, oc, st);
if (preset && (!(ret = get_preset_file_2(preset, enc->codec->name, &s)))) {
@@ -1194,43 +1236,57 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type,
goto fail;
}
- MATCH_PER_STREAM_OPT(enc_stats_pre, str, enc_stats_pre, oc, st);
+ ret = opt_match_per_stream_str(ost, &o->enc_stats_pre, oc, st, &enc_stats_pre);
+ if (ret < 0)
+ goto fail;
if (enc_stats_pre &&
(type == AVMEDIA_TYPE_VIDEO || type == AVMEDIA_TYPE_AUDIO)) {
const char *format = "{fidx} {sidx} {n} {t}";
- MATCH_PER_STREAM_OPT(enc_stats_pre_fmt, str, format, oc, st);
+ ret = opt_match_per_stream_str(ost, &o->enc_stats_pre_fmt, oc, st, &format);
+ if (ret < 0)
+ goto fail;
ret = enc_stats_init(ost, &ost->enc_stats_pre, 1, enc_stats_pre, format);
if (ret < 0)
goto fail;
}
- MATCH_PER_STREAM_OPT(enc_stats_post, str, enc_stats_post, oc, st);
+ ret = opt_match_per_stream_str(ost, &o->enc_stats_post, oc, st, &enc_stats_post);
+ if (ret < 0)
+ goto fail;
if (enc_stats_post &&
(type == AVMEDIA_TYPE_VIDEO || type == AVMEDIA_TYPE_AUDIO)) {
const char *format = "{fidx} {sidx} {n} {t}";
- MATCH_PER_STREAM_OPT(enc_stats_post_fmt, str, format, oc, st);
+ ret = opt_match_per_stream_str(ost, &o->enc_stats_post_fmt, oc, st, &format);
+ if (ret < 0)
+ goto fail;
ret = enc_stats_init(ost, &ost->enc_stats_post, 0, enc_stats_post, format);
if (ret < 0)
goto fail;
}
- MATCH_PER_STREAM_OPT(mux_stats, str, mux_stats, oc, st);
+ ret = opt_match_per_stream_str(ost, &o->mux_stats, oc, st, &mux_stats);
+ if (ret < 0)
+ goto fail;
if (mux_stats &&
(type == AVMEDIA_TYPE_VIDEO || type == AVMEDIA_TYPE_AUDIO)) {
const char *format = "{fidx} {sidx} {n} {t}";
- MATCH_PER_STREAM_OPT(mux_stats_fmt, str, format, oc, st);
+ ret = opt_match_per_stream_str(ost, &o->mux_stats_fmt, oc, st, &format);
+ if (ret < 0)
+ goto fail;
ret = enc_stats_init(ost, &ms->stats, 0, mux_stats, format);
if (ret < 0)
goto fail;
}
- MATCH_PER_STREAM_OPT(enc_time_bases, str, enc_time_base, oc, st);
+ ret = opt_match_per_stream_str(ost, &o->enc_time_bases, oc, st, &enc_time_base);
+ if (ret < 0)
+ goto fail;
if (enc_time_base && type == AVMEDIA_TYPE_SUBTITLE)
av_log(ost, AV_LOG_WARNING,
"-enc_time_base not supported for subtitles, ignoring\n");
@@ -1293,7 +1349,9 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type,
ost->bitexact = !!(ost->enc_ctx->flags & AV_CODEC_FLAG_BITEXACT);
}
- MATCH_PER_STREAM_OPT(time_bases, str, time_base, oc, st);
+ ret = opt_match_per_stream_str(ost, &o->time_bases, oc, st, &time_base);
+ if (ret < 0)
+ return ret;
if (time_base) {
AVRational q;
if (av_parse_ratio(&q, time_base, INT_MAX, 0, NULL) < 0 ||
@@ -1318,7 +1376,9 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type,
ms->copy_prior_start = -1;
MATCH_PER_STREAM_OPT(copy_prior_start, i, ms->copy_prior_start, oc ,st);
- MATCH_PER_STREAM_OPT(bitstream_filters, str, bsfs, oc, st);
+ ret = opt_match_per_stream_str(ost, &o->bitstream_filters, oc, st, &bsfs);
+ if (ret < 0)
+ return ret;
if (bsfs && *bsfs) {
ret = av_bsf_list_parse_str(bsfs, &ms->bsf_ctx);
if (ret < 0) {
@@ -1327,7 +1387,9 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type,
}
}
- MATCH_PER_STREAM_OPT(codec_tags, str, codec_tag, oc, st);
+ ret = opt_match_per_stream_str(ost, &o->codec_tags, oc, st, &codec_tag);
+ if (ret < 0)
+ return ret;
if (codec_tag) {
uint32_t tag = strtol(codec_tag, &next, 0);
if (*next) {
@@ -2943,7 +3005,9 @@ static int set_dispositions(Muxer *mux, const OptionsContext *o)
nb_streams[ost->type + 1]++;
- MATCH_PER_STREAM_OPT_CLEAN(disposition, str, dispositions[i], ctx, ost->st, goto finish);
+ ret = opt_match_per_stream_str(ost, &o->disposition, ctx, ost->st, &dispositions[i]);
+ if (ret < 0)
+ goto finish;
have_manual |= !!dispositions[i];
@@ -3088,8 +3152,12 @@ static int process_forced_keyframes(Muxer *mux, const OptionsContext *o)
for (int i = 0; i < mux->of.nb_streams; i++) {
OutputStream *ost = mux->of.streams[i];
const char *forced_keyframes = NULL;
+ int ret;
- MATCH_PER_STREAM_OPT(forced_key_frames, str, forced_keyframes, mux->fc, ost->st);
+ ret = opt_match_per_stream_str(ost, &o->forced_key_frames,
+ mux->fc, ost->st, &forced_keyframes);
+ if (ret < 0)
+ return ret;
if (!(ost->type == AVMEDIA_TYPE_VIDEO &&
ost->enc_ctx && forced_keyframes))
diff --git a/fftools/ffmpeg_opt.c b/fftools/ffmpeg_opt.c
index 2c201c74b2..736b3ee743 100644
--- a/fftools/ffmpeg_opt.c
+++ b/fftools/ffmpeg_opt.c
@@ -164,6 +164,73 @@ const char *opt_match_per_type_str(const SpecifierOptList *sol,
return NULL;
}
+static int opt_match_per_stream(void *logctx, enum OptionType type,
+ const SpecifierOptList *sol,
+ AVFormatContext *fc, AVStream *st)
+{
+ int matches = 0, match_idx = -1;
+
+ av_assert0((type == sol->type) || !sol->nb_opt);
+
+ for (int i = 0; i < sol->nb_opt; i++) {
+ const char *spec = sol->opt[i].specifier;
+ int ret = check_stream_specifier(fc, st, spec);
+ if (ret > 0) {
+ match_idx = i;
+ matches++;
+ } else if (ret < 0)
+ return ret;
+ }
+
+ 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 %d, only the last option '-%s%s%s %s' will be used.\n",
+ namestr, st->index, sol->opt_canon->name, spec[0] ? ":" : "",
+ spec, optval);
+ }
+
+ return match_idx + 1;
+}
+
+#define OPT_MATCH_PER_STREAM(name, type, opt_type, m) \
+int opt_match_per_stream_ ## name(void *logctx, const SpecifierOptList *sol, \
+ AVFormatContext *fc, AVStream *st, type *out) \
+{ \
+ int ret = opt_match_per_stream(logctx, opt_type, sol, fc, st); \
+ \
+ if (ret <= 0) \
+ return ret; \
+ \
+ *out = sol->opt[ret - 1].u.m; \
+ \
+ return 0; \
+}
+
+OPT_MATCH_PER_STREAM(str, const char *, OPT_TYPE_STRING, str);
+
int parse_and_set_vsync(const char *arg, int *vsync_var, int file_idx, int st_idx, int is_global)
{
if (!av_strcasecmp(arg, "cfr")) *vsync_var = VSYNC_CFR;
--
2.43.0
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 6+ messages in thread
* [FFmpeg-devel] [PATCH 2/6] fftools/ffmpeg: replace remaining uses of MATCH_PER_STREAM_OPT()
2024-08-10 17:16 [FFmpeg-devel] [PATCH 1/6] fftools/ffmpeg: replace MATCH_PER_STREAM_OPT(.., str, ..) with a function Anton Khirnov
@ 2024-08-10 17:16 ` Anton Khirnov
2024-08-10 17:16 ` [FFmpeg-devel] [PATCH 3/6] fftools/cmdutils: put stream specifier handling back into cmdutils Anton Khirnov
` (3 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Anton Khirnov @ 2024-08-10 17:16 UTC (permalink / raw)
To: ffmpeg-devel
---
fftools/ffmpeg.h | 49 ++++-----------------------
fftools/ffmpeg_demux.c | 39 ++++++++++++++++-----
fftools/ffmpeg_mux_init.c | 71 ++++++++++++++++++++++++++++-----------
fftools/ffmpeg_opt.c | 5 ++-
4 files changed, 91 insertions(+), 73 deletions(-)
diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h
index 7d82d7d7c2..674ae340f2 100644
--- a/fftools/ffmpeg.h
+++ b/fftools/ffmpeg.h
@@ -857,53 +857,16 @@ OutputStream *ost_iter(OutputStream *prev);
void update_benchmark(const char *fmt, ...);
-#define SPECIFIER_OPT_FMT_str "%s"
-#define SPECIFIER_OPT_FMT_i "%i"
-#define SPECIFIER_OPT_FMT_i64 "%"PRId64
-#define SPECIFIER_OPT_FMT_ui64 "%"PRIu64
-#define SPECIFIER_OPT_FMT_f "%f"
-#define SPECIFIER_OPT_FMT_dbl "%lf"
-
-#define WARN_MULTIPLE_OPT_USAGE(optname, type, idx, st)\
-{\
- char namestr[128] = "";\
- const SpecifierOpt *so = &o->optname.opt[idx];\
- const char *spec = so->specifier && so->specifier[0] ? so->specifier : "";\
- snprintf(namestr, sizeof(namestr), "-%s", o->optname.opt_canon->name);\
- if (o->optname.opt_canon->flags & OPT_HAS_ALT) {\
- const char * const *names_alt = o->optname.opt_canon->u1.names_alt;\
- for (int _i = 0; names_alt[_i]; _i++)\
- av_strlcatf(namestr, sizeof(namestr), "/-%s", names_alt[_i]);\
- }\
- av_log(NULL, AV_LOG_WARNING, "Multiple %s options specified for stream %d, only the last option '-%s%s%s "SPECIFIER_OPT_FMT_##type"' will be used.\n",\
- namestr, st->index, o->optname.opt_canon->name, spec[0] ? ":" : "", spec, so->u.type);\
-}
-
-#define MATCH_PER_STREAM_OPT_CLEAN(name, type, outvar, fmtctx, st, clean)\
-{\
- int _ret, _matches = 0, _match_idx;\
- for (int _i = 0; _i < o->name.nb_opt; _i++) {\
- char *spec = o->name.opt[_i].specifier;\
- if ((_ret = check_stream_specifier(fmtctx, st, spec)) > 0) {\
- outvar = o->name.opt[_i].u.type;\
- _match_idx = _i;\
- _matches++;\
- } else if (_ret < 0)\
- clean;\
- }\
- if (_matches > 1 && o->name.opt_canon)\
- WARN_MULTIPLE_OPT_USAGE(name, type, _match_idx, st);\
-}
-
-#define MATCH_PER_STREAM_OPT(name, type, outvar, fmtctx, st)\
-{\
- MATCH_PER_STREAM_OPT_CLEAN(name, type, outvar, fmtctx, st, return _ret)\
-}
-
const char *opt_match_per_type_str(const SpecifierOptList *sol,
char mediatype);
int opt_match_per_stream_str(void *logctx, const SpecifierOptList *sol,
AVFormatContext *fc, AVStream *st, const char **out);
+int opt_match_per_stream_int(void *logctx, const SpecifierOptList *sol,
+ AVFormatContext *fc, AVStream *st, int *out);
+int opt_match_per_stream_int64(void *logctx, const SpecifierOptList *sol,
+ AVFormatContext *fc, AVStream *st, int64_t *out);
+int opt_match_per_stream_dbl(void *logctx, const SpecifierOptList *sol,
+ AVFormatContext *fc, AVStream *st, double *out);
int muxer_thread(void *arg);
int encoder_thread(void *arg);
diff --git a/fftools/ffmpeg_demux.c b/fftools/ffmpeg_demux.c
index 0c92d31c10..e9a4b5c22a 100644
--- a/fftools/ffmpeg_demux.c
+++ b/fftools/ffmpeg_demux.c
@@ -1153,11 +1153,18 @@ static int add_display_matrix_to_stream(const OptionsContext *o,
double rotation = DBL_MAX;
int hflip = -1, vflip = -1;
int hflip_set = 0, vflip_set = 0, rotation_set = 0;
+ int ret;
int32_t *buf;
- MATCH_PER_STREAM_OPT(display_rotations, dbl, rotation, ctx, st);
- MATCH_PER_STREAM_OPT(display_hflips, i, hflip, ctx, st);
- MATCH_PER_STREAM_OPT(display_vflips, i, vflip, ctx, st);
+ ret = opt_match_per_stream_dbl(ist, &o->display_rotations, ctx, st, &rotation);
+ if (ret < 0)
+ return ret;
+ ret = opt_match_per_stream_int(ist, &o->display_hflips, ctx, st, &hflip);
+ if (ret < 0)
+ return ret;
+ ret = opt_match_per_stream_int(ist, &o->display_vflips, ctx, st, &vflip);
+ if (ret < 0)
+ return ret;
rotation_set = rotation != DBL_MAX;
hflip_set = hflip != -1;
@@ -1255,10 +1262,14 @@ static int ist_add(const OptionsContext *o, Demuxer *d, AVStream *st, AVDictiona
ds->dec_opts.time_base = st->time_base;
ds->ts_scale = 1.0;
- MATCH_PER_STREAM_OPT(ts_scale, dbl, ds->ts_scale, ic, st);
+ ret = opt_match_per_stream_dbl(ist, &o->ts_scale, ic, st, &ds->ts_scale);
+ if (ret < 0)
+ return ret;
ds->autorotate = 1;
- MATCH_PER_STREAM_OPT(autorotate, i, ds->autorotate, ic, st);
+ ret = opt_match_per_stream_int(ist, &o->autorotate, ic, st, &ds->autorotate);
+ if (ret < 0)
+ return ret;
ds->apply_cropping = CROP_ALL;
ret = opt_match_per_stream_str(ist, &o->apply_cropping, ic, st, &apply_cropping);
@@ -1397,7 +1408,9 @@ static int ist_add(const OptionsContext *o, Demuxer *d, AVStream *st, AVDictiona
}
ds->reinit_filters = -1;
- MATCH_PER_STREAM_OPT(reinit_filters, i, ds->reinit_filters, ic, st);
+ ret = opt_match_per_stream_int(ist, &o->reinit_filters, ic, st, &ds->reinit_filters);
+ if (ret < 0)
+ return ret;
ist->user_set_discard = AVDISCARD_NONE;
@@ -1445,7 +1458,9 @@ static int ist_add(const OptionsContext *o, Demuxer *d, AVStream *st, AVDictiona
#if FFMPEG_OPT_TOP
ist->top_field_first = -1;
- MATCH_PER_STREAM_OPT(top_field_first, i, ist->top_field_first, ic, st);
+ ret = opt_match_per_stream_int(ist, &o->top_field_first, ic, st, &ist->top_field_first);
+ if (ret < 0)
+ return ret;
#endif
break;
@@ -1474,7 +1489,10 @@ static int ist_add(const OptionsContext *o, Demuxer *d, AVStream *st, AVDictiona
}
} else {
int guess_layout_max = INT_MAX;
- MATCH_PER_STREAM_OPT(guess_layout_max, i, guess_layout_max, ic, st);
+ ret = opt_match_per_stream_int(ist, &o->guess_layout_max, ic, st, &guess_layout_max);
+ if (ret < 0)
+ return ret;
+
guess_input_channel_layout(ist, par, guess_layout_max);
}
break;
@@ -1482,7 +1500,10 @@ static int ist_add(const OptionsContext *o, Demuxer *d, AVStream *st, AVDictiona
case AVMEDIA_TYPE_DATA:
case AVMEDIA_TYPE_SUBTITLE: {
const char *canvas_size = NULL;
- MATCH_PER_STREAM_OPT(fix_sub_duration, i, ist->fix_sub_duration, ic, st);
+
+ ret = opt_match_per_stream_int(ist, &o->fix_sub_duration, ic, st, &ist->fix_sub_duration);
+ if (ret < 0)
+ return ret;
ret = opt_match_per_stream_str(ist, &o->canvas_sizes, ic, st, &canvas_size);
if (ret < 0)
diff --git a/fftools/ffmpeg_mux_init.c b/fftools/ffmpeg_mux_init.c
index c7efeda7bf..2b3a4ddcf9 100644
--- a/fftools/ffmpeg_mux_init.c
+++ b/fftools/ffmpeg_mux_init.c
@@ -735,7 +735,9 @@ static int new_stream_video(Muxer *mux, const OptionsContext *o,
video_enc->rc_override_count = i;
/* two pass mode */
- MATCH_PER_STREAM_OPT(pass, i, do_pass, oc, st);
+ ret = opt_match_per_stream_int(ost, &o->pass, oc, st, &do_pass);
+ if (ret < 0)
+ return ret;
if (do_pass) {
if (do_pass & 1)
video_enc->flags |= AV_CODEC_FLAG_PASS1;
@@ -792,11 +794,15 @@ static int new_stream_video(Muxer *mux, const OptionsContext *o,
}
}
- MATCH_PER_STREAM_OPT(force_fps, i, ost->force_fps, oc, st);
+ ret = opt_match_per_stream_int(ost, &o->force_fps, oc, st, &ost->force_fps);
+ if (ret < 0)
+ return ret;
#if FFMPEG_OPT_TOP
ost->top_field_first = -1;
- MATCH_PER_STREAM_OPT(top_field_first, i, ost->top_field_first, oc, st);
+ ret = opt_match_per_stream_int(ost, &o->top_field_first, oc, st, &ost->top_field_first);
+ if (ret < 0)
+ return ret;
if (ost->top_field_first >= 0)
av_log(ost, AV_LOG_WARNING, "-top is deprecated, use the setfield filter instead\n");
#endif
@@ -868,7 +874,9 @@ static int new_stream_audio(Muxer *mux, const OptionsContext *o,
const char *sample_fmt = NULL;
int ret;
- MATCH_PER_STREAM_OPT(audio_channels, i, channels, oc, st);
+ ret = opt_match_per_stream_int(ost, &o->audio_channels, oc, st, &channels);
+ if (ret < 0)
+ return ret;
if (channels) {
audio_enc->ch_layout.order = AV_CHANNEL_ORDER_UNSPEC;
audio_enc->ch_layout.nb_channels = channels;
@@ -891,7 +899,9 @@ static int new_stream_audio(Muxer *mux, const OptionsContext *o,
return AVERROR(EINVAL);
}
- MATCH_PER_STREAM_OPT(audio_sample_rate, i, audio_enc->sample_rate, oc, st);
+ ret = opt_match_per_stream_int(ost, &o->audio_sample_rate, oc, st, &audio_enc->sample_rate);
+ if (ret < 0)
+ return ret;
ret = opt_match_per_stream_str(ost, &o->apad, oc, st, &ms->apad);
if (ret < 0)
@@ -1205,7 +1215,9 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type,
if (ret < 0)
goto fail;
- MATCH_PER_STREAM_OPT(autoscale, i, autoscale, oc, st);
+ ret = opt_match_per_stream_int(ost, &o->autoscale, oc, st, &autoscale);
+ if (ret < 0)
+ goto fail;
if (preset && (!(ret = get_preset_file_2(preset, enc->codec->name, &s)))) {
AVBPrint bprint;
av_bprint_init(&bprint, 0, AV_BPRINT_SIZE_UNLIMITED);
@@ -1351,7 +1363,7 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type,
ret = opt_match_per_stream_str(ost, &o->time_bases, oc, st, &time_base);
if (ret < 0)
- return ret;
+ goto fail;
if (time_base) {
AVRational q;
if (av_parse_ratio(&q, time_base, INT_MAX, 0, NULL) < 0 ||
@@ -1364,7 +1376,9 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type,
}
ms->max_frames = INT64_MAX;
- MATCH_PER_STREAM_OPT(max_frames, i64, ms->max_frames, oc, st);
+ ret = opt_match_per_stream_int64(ost, &o->max_frames, oc, st, &ms->max_frames);
+ if (ret < 0)
+ return ret;
for (int i = 0; i < o->max_frames.nb_opt; i++) {
char *p = o->max_frames.opt[i].specifier;
if (!*p && type != AVMEDIA_TYPE_VIDEO) {
@@ -1374,11 +1388,13 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type,
}
ms->copy_prior_start = -1;
- MATCH_PER_STREAM_OPT(copy_prior_start, i, ms->copy_prior_start, oc ,st);
+ ret = opt_match_per_stream_int(ost, &o->copy_prior_start, oc, st, &ms->copy_prior_start);
+ if (ret < 0)
+ goto fail;
ret = opt_match_per_stream_str(ost, &o->bitstream_filters, oc, st, &bsfs);
if (ret < 0)
- return ret;
+ goto fail;
if (bsfs && *bsfs) {
ret = av_bsf_list_parse_str(bsfs, &ms->bsf_ctx);
if (ret < 0) {
@@ -1389,7 +1405,7 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type,
ret = opt_match_per_stream_str(ost, &o->codec_tags, oc, st, &codec_tag);
if (ret < 0)
- return ret;
+ goto fail;
if (codec_tag) {
uint32_t tag = strtol(codec_tag, &next, 0);
if (*next) {
@@ -1403,7 +1419,9 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type,
ost->enc_ctx->codec_tag = tag;
}
- MATCH_PER_STREAM_OPT(qscale, dbl, qscale, oc, st);
+ ret = opt_match_per_stream_dbl(ost, &o->qscale, oc, st, &qscale);
+ if (ret < 0)
+ return ret;
if (ost->enc_ctx && qscale >= 0) {
ost->enc_ctx->flags |= AV_CODEC_FLAG_QSCALE;
ost->enc_ctx->global_quality = FF_QP2LAMBDA * qscale;
@@ -1413,24 +1431,37 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type,
int max_muxing_queue_size = 128;
int muxing_queue_data_threshold = 50 * 1024 * 1024;
- MATCH_PER_STREAM_OPT(max_muxing_queue_size, i, max_muxing_queue_size, oc, st);
- MATCH_PER_STREAM_OPT(muxing_queue_data_threshold, i, muxing_queue_data_threshold, oc, st);
+ ret = opt_match_per_stream_int(ost, &o->max_muxing_queue_size, oc, st,
+ &max_muxing_queue_size);
+ if (ret < 0)
+ goto fail;
+
+ ret = opt_match_per_stream_int(ost, &o->muxing_queue_data_threshold,
+ oc, st, &muxing_queue_data_threshold);
+ if (ret < 0)
+ goto fail;
sch_mux_stream_buffering(mux->sch, mux->sch_idx, ms->sch_idx,
max_muxing_queue_size, muxing_queue_data_threshold);
}
- MATCH_PER_STREAM_OPT(bits_per_raw_sample, i, ost->bits_per_raw_sample,
- oc, st);
+ ret = opt_match_per_stream_int(ost, &o->bits_per_raw_sample, oc, st,
+ &ost->bits_per_raw_sample);
+ if (ret < 0)
+ goto fail;
- MATCH_PER_STREAM_OPT(fix_sub_duration_heartbeat, i, ost->fix_sub_duration_heartbeat,
- oc, st);
+ ret = opt_match_per_stream_int(ost, &o->fix_sub_duration_heartbeat,
+ oc, st, &ost->fix_sub_duration_heartbeat);
+ if (ret < 0)
+ goto fail;
if (oc->oformat->flags & AVFMT_GLOBALHEADER && ost->enc_ctx)
ost->enc_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
- MATCH_PER_STREAM_OPT(copy_initial_nonkeyframes, i,
- ms->copy_initial_nonkeyframes, oc, st);
+ ret = opt_match_per_stream_int(ost, &o->copy_initial_nonkeyframes,
+ oc, st, &ms->copy_initial_nonkeyframes);
+ if (ret < 0)
+ goto fail;
switch (type) {
case AVMEDIA_TYPE_VIDEO: ret = new_stream_video (mux, o, ost, &keep_pix_fmt, &vsync_method); break;
diff --git a/fftools/ffmpeg_opt.c b/fftools/ffmpeg_opt.c
index 736b3ee743..c32d3ddc55 100644
--- a/fftools/ffmpeg_opt.c
+++ b/fftools/ffmpeg_opt.c
@@ -229,7 +229,10 @@ int opt_match_per_stream_ ## name(void *logctx, const SpecifierOptList *sol,
return 0; \
}
-OPT_MATCH_PER_STREAM(str, const char *, OPT_TYPE_STRING, str);
+OPT_MATCH_PER_STREAM(str, const char *, OPT_TYPE_STRING, str);
+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);
int parse_and_set_vsync(const char *arg, int *vsync_var, int file_idx, int st_idx, int is_global)
{
--
2.43.0
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 6+ messages in thread
* [FFmpeg-devel] [PATCH 3/6] fftools/cmdutils: put stream specifier handling back into cmdutils
2024-08-10 17:16 [FFmpeg-devel] [PATCH 1/6] fftools/ffmpeg: replace MATCH_PER_STREAM_OPT(.., str, ..) with a function Anton Khirnov
2024-08-10 17:16 ` [FFmpeg-devel] [PATCH 2/6] fftools/ffmpeg: replace remaining uses of MATCH_PER_STREAM_OPT() Anton Khirnov
@ 2024-08-10 17:16 ` Anton Khirnov
2024-08-10 17:16 ` [FFmpeg-devel] [PATCH 4/6] fftools/cmdutils: split stream specifier parsing and matching Anton Khirnov
` (2 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Anton Khirnov @ 2024-08-10 17:16 UTC (permalink / raw)
To: ffmpeg-devel
Stream specifiers were originally designed exclusively for CLI use and
were not intended to be public API. Handling them in avformat places
major restrictions on how they are used. E.g. if ffmpeg CLI wishes to
override some stream parameters, it has to change the demuxer fields
(since avformat_match_stream_specifier() does not have access to
anything else). However, such fields are supposed to be read-only for
the caller.
Furthermore having this code in avformat restricts extending the
specifier syntax. An example of such an extension will be added in
following commits.
---
fftools/cmdutils.c | 211 ++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 210 insertions(+), 1 deletion(-)
diff --git a/fftools/cmdutils.c b/fftools/cmdutils.c
index 6286fd87f7..ffdcc85494 100644
--- a/fftools/cmdutils.c
+++ b/fftools/cmdutils.c
@@ -980,10 +980,219 @@ FILE *get_preset_file(char *filename, size_t filename_size,
return f;
}
+/**
+ * Matches a stream specifier (but ignores requested index).
+ *
+ * @param indexptr set to point to the requested stream index if there is one
+ *
+ * @return <0 on error
+ * 0 if st is NOT a matching stream
+ * >0 if st is a matching stream
+ */
+static int match_stream_specifier(const AVFormatContext *s, const AVStream *st,
+ const char *spec, const char **indexptr,
+ const AVStreamGroup **g, const AVProgram **p)
+{
+ int match = 1; /* Stores if the specifier matches so far. */
+ while (*spec) {
+ if (*spec <= '9' && *spec >= '0') { /* opt:index */
+ if (indexptr)
+ *indexptr = spec;
+ return match;
+ } else if (*spec == 'v' || *spec == 'a' || *spec == 's' || *spec == 'd' ||
+ *spec == 't' || *spec == 'V') { /* opt:[vasdtV] */
+ enum AVMediaType type;
+ int nopic = 0;
+
+ switch (*spec++) {
+ 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;
+ case 't': type = AVMEDIA_TYPE_ATTACHMENT; break;
+ case 'V': type = AVMEDIA_TYPE_VIDEO; nopic = 1; break;
+ default: av_assert0(0);
+ }
+ if (*spec && *spec++ != ':') /* If we are not at the end, then another specifier must follow. */
+ return AVERROR(EINVAL);
+
+ if (type != st->codecpar->codec_type)
+ match = 0;
+ if (nopic && (st->disposition & AV_DISPOSITION_ATTACHED_PIC))
+ match = 0;
+ } else if (*spec == 'g' && *(spec + 1) == ':') {
+ int64_t group_idx = -1, group_id = -1;
+ int found = 0;
+ char *endptr;
+ spec += 2;
+ if (*spec == '#' || (*spec == 'i' && *(spec + 1) == ':')) {
+ spec += 1 + (*spec == 'i');
+ group_id = strtol(spec, &endptr, 0);
+ if (spec == endptr || (*endptr && *endptr++ != ':'))
+ return AVERROR(EINVAL);
+ spec = endptr;
+ } else {
+ group_idx = strtol(spec, &endptr, 0);
+ /* Disallow empty id and make sure that if we are not at the end, then another specifier must follow. */
+ if (spec == endptr || (*endptr && *endptr++ != ':'))
+ return AVERROR(EINVAL);
+ spec = endptr;
+ }
+ if (match) {
+ if (group_id > 0) {
+ for (unsigned i = 0; i < s->nb_stream_groups; i++) {
+ if (group_id == s->stream_groups[i]->id) {
+ group_idx = i;
+ break;
+ }
+ }
+ }
+ if (group_idx < 0 || group_idx >= s->nb_stream_groups)
+ return AVERROR(EINVAL);
+ for (unsigned j = 0; j < s->stream_groups[group_idx]->nb_streams; j++) {
+ if (st->index == s->stream_groups[group_idx]->streams[j]->index) {
+ found = 1;
+ if (g)
+ *g = s->stream_groups[group_idx];
+ break;
+ }
+ }
+ }
+ if (!found)
+ match = 0;
+ } else if (*spec == 'p' && *(spec + 1) == ':') {
+ int prog_id;
+ int found = 0;
+ char *endptr;
+ spec += 2;
+ prog_id = strtol(spec, &endptr, 0);
+ /* Disallow empty id and make sure that if we are not at the end, then another specifier must follow. */
+ if (spec == endptr || (*endptr && *endptr++ != ':'))
+ return AVERROR(EINVAL);
+ spec = endptr;
+ if (match) {
+ for (unsigned i = 0; i < s->nb_programs; i++) {
+ if (s->programs[i]->id != prog_id)
+ continue;
+
+ for (unsigned j = 0; j < s->programs[i]->nb_stream_indexes; j++) {
+ if (st->index == s->programs[i]->stream_index[j]) {
+ found = 1;
+ if (p)
+ *p = s->programs[i];
+ i = s->nb_programs;
+ break;
+ }
+ }
+ }
+ }
+ if (!found)
+ match = 0;
+ } else if (*spec == '#' ||
+ (*spec == 'i' && *(spec + 1) == ':')) {
+ int stream_id;
+ char *endptr;
+ spec += 1 + (*spec == 'i');
+ stream_id = strtol(spec, &endptr, 0);
+ if (spec == endptr || *endptr) /* Disallow empty id and make sure we are at the end. */
+ return AVERROR(EINVAL);
+ return match && (stream_id == st->id);
+ } else if (*spec == 'm' && *(spec + 1) == ':') {
+ const AVDictionaryEntry *tag;
+ char *key, *val;
+ int ret;
+
+ if (match) {
+ spec += 2;
+ val = strchr(spec, ':');
+
+ key = val ? av_strndup(spec, val - spec) : av_strdup(spec);
+ if (!key)
+ return AVERROR(ENOMEM);
+
+ tag = av_dict_get(st->metadata, key, NULL, 0);
+ if (tag) {
+ if (!val || !strcmp(tag->value, val + 1))
+ ret = 1;
+ else
+ ret = 0;
+ } else
+ ret = 0;
+
+ av_freep(&key);
+ }
+ return match && ret;
+ } else if (*spec == 'u' && *(spec + 1) == '\0') {
+ const AVCodecParameters *par = st->codecpar;
+ int val;
+ switch (par->codec_type) {
+ case AVMEDIA_TYPE_AUDIO:
+ val = par->sample_rate && par->ch_layout.nb_channels;
+ if (par->format == AV_SAMPLE_FMT_NONE)
+ return 0;
+ break;
+ case AVMEDIA_TYPE_VIDEO:
+ val = par->width && par->height;
+ if (par->format == AV_PIX_FMT_NONE)
+ return 0;
+ break;
+ case AVMEDIA_TYPE_UNKNOWN:
+ val = 0;
+ break;
+ default:
+ val = 1;
+ break;
+ }
+ return match && (par->codec_id != AV_CODEC_ID_NONE && val != 0);
+ } else {
+ return AVERROR(EINVAL);
+ }
+ }
+
+ return match;
+}
+
int check_stream_specifier(AVFormatContext *s, AVStream *st, const char *spec)
{
- int ret = avformat_match_stream_specifier(s, st, spec);
+ int ret, index;
+ char *endptr;
+ const char *indexptr = NULL;
+ const AVStreamGroup *g = NULL;
+ const AVProgram *p = NULL;
+ int nb_streams;
+
+ ret = match_stream_specifier(s, st, spec, &indexptr, &g, &p);
if (ret < 0)
+ goto error;
+
+ if (!indexptr)
+ return ret;
+
+ index = strtol(indexptr, &endptr, 0);
+ if (*endptr) { /* We can't have anything after the requested index. */
+ ret = AVERROR(EINVAL);
+ goto error;
+ }
+
+ /* This is not really needed but saves us a loop for simple stream index specifiers. */
+ if (spec == indexptr)
+ return (index == st->index);
+
+ /* If we requested a matching stream index, we have to ensure st is that. */
+ nb_streams = g ? g->nb_streams : (p ? p->nb_stream_indexes : s->nb_streams);
+ for (int i = 0; i < nb_streams && index >= 0; i++) {
+ unsigned idx = g ? g->streams[i]->index : (p ? p->stream_index[i] : i);
+ const AVStream *candidate = s->streams[idx];
+ ret = match_stream_specifier(s, candidate, spec, NULL, NULL, NULL);
+ if (ret < 0)
+ goto error;
+ if (ret > 0 && index-- == 0 && st == candidate)
+ return 1;
+ }
+ return 0;
+
+error:
+ if (ret == AVERROR(EINVAL))
av_log(s, AV_LOG_ERROR, "Invalid stream specifier: %s.\n", spec);
return ret;
}
--
2.43.0
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 6+ messages in thread
* [FFmpeg-devel] [PATCH 4/6] fftools/cmdutils: split stream specifier parsing and matching
2024-08-10 17:16 [FFmpeg-devel] [PATCH 1/6] fftools/ffmpeg: replace MATCH_PER_STREAM_OPT(.., str, ..) with a function Anton Khirnov
2024-08-10 17:16 ` [FFmpeg-devel] [PATCH 2/6] fftools/ffmpeg: replace remaining uses of MATCH_PER_STREAM_OPT() Anton Khirnov
2024-08-10 17:16 ` [FFmpeg-devel] [PATCH 3/6] fftools/cmdutils: put stream specifier handling back into cmdutils Anton Khirnov
@ 2024-08-10 17:16 ` Anton Khirnov
2024-08-10 17:16 ` [FFmpeg-devel] [PATCH 5/6] fftools/ffmpeg: use new stream specifier API in opt_match_per_stream*() Anton Khirnov
2024-08-10 17:16 ` [FFmpeg-devel] [PATCH 6/6] fftools/ffmpeg: switch -map parsing to new stream specifier API Anton Khirnov
4 siblings, 0 replies; 6+ messages in thread
From: Anton Khirnov @ 2024-08-10 17:16 UTC (permalink / raw)
To: ffmpeg-devel
This approach has the major advantage that only parsing can fail (due to
a malformed specifier or memory allocation failure). Since parsing is
done generically, while matching is per-option, this will allow to
remove substantial amounts of error checking code in following commits.
The new code also explicitly allows stream specifiers to be followed by
additional characters, which should allow cleaner handling of optional
maps, i.e. -map <stream_specifier>?, which is currently implemented in a
hacky way that breaks when the stream specifier itself contains the '?'
character (this can happen when matching metadata). It will also allow
further extending the syntax, which will be useful in following commits.
This introduces some minor behaviour changes:
* Matching metadata tags now requires the ':' character in keys or
values to be escaped. Previously it could not be present in keys, and
would be used verbatim in values. The change is required in order to
know where the value terminates.
* Multiple stream types in a single specifier are now rejected - such a
specifier makes no sense.
* Non-existent stream group ID or index is now ignored with a warning
rather than causing a failure. This is consistent with program
handling and is required to make matching fail-free.
---
fftools/cmdutils.c | 454 +++++++++++++++++++++++++++------------------
fftools/cmdutils.h | 56 ++++++
2 files changed, 329 insertions(+), 181 deletions(-)
diff --git a/fftools/cmdutils.c b/fftools/cmdutils.c
index ffdcc85494..b3f501bd56 100644
--- a/fftools/cmdutils.c
+++ b/fftools/cmdutils.c
@@ -980,220 +980,312 @@ FILE *get_preset_file(char *filename, size_t filename_size,
return f;
}
-/**
- * Matches a stream specifier (but ignores requested index).
- *
- * @param indexptr set to point to the requested stream index if there is one
- *
- * @return <0 on error
- * 0 if st is NOT a matching stream
- * >0 if st is a matching stream
- */
-static int match_stream_specifier(const AVFormatContext *s, const AVStream *st,
- const char *spec, const char **indexptr,
- const AVStreamGroup **g, const AVProgram **p)
+
+void stream_specifier_uninit(StreamSpecifier *ss)
{
- int match = 1; /* Stores if the specifier matches so far. */
+ av_freep(&ss->meta_key);
+ av_freep(&ss->meta_val);
+ av_freep(&ss->remainder);
+
+ memset(ss, 0, sizeof(*ss));
+}
+
+int stream_specifier_parse(StreamSpecifier *ss, const char *spec,
+ int allow_remainder, void *logctx)
+{
+ char *endptr;
+ int ret;
+
+ memset(ss, 0, sizeof(*ss));
+
+ ss->idx = -1;
+ ss->media_type = AVMEDIA_TYPE_UNKNOWN;
+ ss->stream_list = STREAM_LIST_ALL;
+
+ av_log(logctx, AV_LOG_TRACE, "Parsing stream specifier: %s\n", spec);
+
while (*spec) {
if (*spec <= '9' && *spec >= '0') { /* opt:index */
- if (indexptr)
- *indexptr = spec;
- return match;
+ ss->idx = strtol(spec, &endptr, 0);
+
+ av_assert0(endptr > spec);
+ spec = endptr;
+
+ av_log(logctx, AV_LOG_TRACE,
+ "Parsed index: %d; remainder: %s\n", ss->idx, spec);
+
+ // this terminates the specifier
+ break;
} else if (*spec == 'v' || *spec == 'a' || *spec == 's' || *spec == 'd' ||
*spec == 't' || *spec == 'V') { /* opt:[vasdtV] */
- enum AVMediaType type;
- int nopic = 0;
+ if (ss->media_type != AVMEDIA_TYPE_UNKNOWN) {
+ av_log(logctx, AV_LOG_ERROR, "Stream type specified multiple times\n");
+ ret = AVERROR(EINVAL);
+ goto fail;
+ }
switch (*spec++) {
- 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;
- case 't': type = AVMEDIA_TYPE_ATTACHMENT; break;
- case 'V': type = AVMEDIA_TYPE_VIDEO; nopic = 1; break;
+ case 'v': ss->media_type = AVMEDIA_TYPE_VIDEO; break;
+ case 'a': ss->media_type = AVMEDIA_TYPE_AUDIO; break;
+ case 's': ss->media_type = AVMEDIA_TYPE_SUBTITLE; break;
+ case 'd': ss->media_type = AVMEDIA_TYPE_DATA; break;
+ case 't': ss->media_type = AVMEDIA_TYPE_ATTACHMENT; break;
+ case 'V': ss->media_type = AVMEDIA_TYPE_VIDEO;
+ ss->no_apic = 1; break;
default: av_assert0(0);
}
- if (*spec && *spec++ != ':') /* If we are not at the end, then another specifier must follow. */
- return AVERROR(EINVAL);
- if (type != st->codecpar->codec_type)
- match = 0;
- if (nopic && (st->disposition & AV_DISPOSITION_ATTACHED_PIC))
- match = 0;
+ av_log(logctx, AV_LOG_TRACE, "Parsed media type: %s; remainder: %s\n",
+ av_get_media_type_string(ss->media_type), spec);
} else if (*spec == 'g' && *(spec + 1) == ':') {
- int64_t group_idx = -1, group_id = -1;
- int found = 0;
- char *endptr;
+ if (ss->stream_list != STREAM_LIST_ALL)
+ goto multiple_stream_lists;
+
spec += 2;
if (*spec == '#' || (*spec == 'i' && *(spec + 1) == ':')) {
- spec += 1 + (*spec == 'i');
- group_id = strtol(spec, &endptr, 0);
- if (spec == endptr || (*endptr && *endptr++ != ':'))
- return AVERROR(EINVAL);
- spec = endptr;
- } else {
- group_idx = strtol(spec, &endptr, 0);
- /* Disallow empty id and make sure that if we are not at the end, then another specifier must follow. */
- if (spec == endptr || (*endptr && *endptr++ != ':'))
- return AVERROR(EINVAL);
- spec = endptr;
- }
- if (match) {
- if (group_id > 0) {
- for (unsigned i = 0; i < s->nb_stream_groups; i++) {
- if (group_id == s->stream_groups[i]->id) {
- group_idx = i;
- break;
- }
- }
- }
- if (group_idx < 0 || group_idx >= s->nb_stream_groups)
- return AVERROR(EINVAL);
- for (unsigned j = 0; j < s->stream_groups[group_idx]->nb_streams; j++) {
- if (st->index == s->stream_groups[group_idx]->streams[j]->index) {
- found = 1;
- if (g)
- *g = s->stream_groups[group_idx];
- break;
- }
- }
- }
- if (!found)
- match = 0;
- } else if (*spec == 'p' && *(spec + 1) == ':') {
- int prog_id;
- int found = 0;
- char *endptr;
- spec += 2;
- prog_id = strtol(spec, &endptr, 0);
- /* Disallow empty id and make sure that if we are not at the end, then another specifier must follow. */
- if (spec == endptr || (*endptr && *endptr++ != ':'))
- return AVERROR(EINVAL);
- spec = endptr;
- if (match) {
- for (unsigned i = 0; i < s->nb_programs; i++) {
- if (s->programs[i]->id != prog_id)
- continue;
+ ss->stream_list = STREAM_LIST_GROUP_ID;
- for (unsigned j = 0; j < s->programs[i]->nb_stream_indexes; j++) {
- if (st->index == s->programs[i]->stream_index[j]) {
- found = 1;
- if (p)
- *p = s->programs[i];
- i = s->nb_programs;
- break;
- }
- }
- }
+ spec += 1 + (*spec == 'i');
+ } else
+ ss->stream_list = STREAM_LIST_GROUP_IDX;
+
+ ss->list_id = strtol(spec, &endptr, 0);
+ if (spec == endptr) {
+ av_log(logctx, AV_LOG_ERROR, "Expected stream group idx/ID, got: %s\n", spec);
+ ret = AVERROR(EINVAL);
+ goto fail;
}
- if (!found)
- match = 0;
+ spec = endptr;
+
+ av_log(logctx, AV_LOG_TRACE, "Parsed stream group %s: %"PRId64"; remainder: %s\n",
+ ss->stream_list == STREAM_LIST_GROUP_ID ? "ID" : "index", ss->list_id, spec);
+ } else if (*spec == 'p' && *(spec + 1) == ':') {
+ if (ss->stream_list != STREAM_LIST_ALL)
+ goto multiple_stream_lists;
+
+ ss->stream_list = STREAM_LIST_PROGRAM;
+
+ spec += 2;
+ ss->list_id = strtol(spec, &endptr, 0);
+ if (spec == endptr) {
+ av_log(logctx, AV_LOG_ERROR, "Expected program ID, got: %s\n", spec);
+ ret = AVERROR(EINVAL);
+ goto fail;
+ }
+ spec = endptr;
+
+ av_log(logctx, AV_LOG_TRACE,
+ "Parsed program ID: %"PRId64"; remainder: %s\n", ss->list_id, spec);
} else if (*spec == '#' ||
(*spec == 'i' && *(spec + 1) == ':')) {
- int stream_id;
- char *endptr;
+ if (ss->stream_list != STREAM_LIST_ALL)
+ goto multiple_stream_lists;
+
+ ss->stream_list = STREAM_LIST_STREAM_ID;
+
spec += 1 + (*spec == 'i');
- stream_id = strtol(spec, &endptr, 0);
- if (spec == endptr || *endptr) /* Disallow empty id and make sure we are at the end. */
- return AVERROR(EINVAL);
- return match && (stream_id == st->id);
+ ss->list_id = strtol(spec, &endptr, 0);
+ if (spec == endptr) {
+ av_log(logctx, AV_LOG_ERROR, "Expected stream ID, got: %s\n", spec);
+ ret = AVERROR(EINVAL);
+ goto fail;
+ }
+ spec = endptr;
+
+ av_log(logctx, AV_LOG_TRACE,
+ "Parsed stream ID: %"PRId64"; remainder: %s\n", ss->list_id, spec);
+
+ // this terminates the specifier
+ break;
} else if (*spec == 'm' && *(spec + 1) == ':') {
- const AVDictionaryEntry *tag;
- char *key, *val;
- int ret;
+ av_assert0(!ss->meta_key && !ss->meta_val);
- if (match) {
- spec += 2;
- val = strchr(spec, ':');
-
- key = val ? av_strndup(spec, val - spec) : av_strdup(spec);
- if (!key)
- return AVERROR(ENOMEM);
-
- tag = av_dict_get(st->metadata, key, NULL, 0);
- if (tag) {
- if (!val || !strcmp(tag->value, val + 1))
- ret = 1;
- else
- ret = 0;
- } else
- ret = 0;
-
- av_freep(&key);
+ spec += 2;
+ ss->meta_key = av_get_token(&spec, ":");
+ if (!ss->meta_key) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
}
- return match && ret;
- } else if (*spec == 'u' && *(spec + 1) == '\0') {
- const AVCodecParameters *par = st->codecpar;
- int val;
- switch (par->codec_type) {
- case AVMEDIA_TYPE_AUDIO:
- val = par->sample_rate && par->ch_layout.nb_channels;
- if (par->format == AV_SAMPLE_FMT_NONE)
- return 0;
- break;
- case AVMEDIA_TYPE_VIDEO:
- val = par->width && par->height;
- if (par->format == AV_PIX_FMT_NONE)
- return 0;
- break;
- case AVMEDIA_TYPE_UNKNOWN:
- val = 0;
- break;
- default:
- val = 1;
- break;
+ if (*spec == ':') {
+ spec++;
+ ss->meta_val = av_get_token(&spec, ":");
+ if (!ss->meta_val) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
}
- return match && (par->codec_id != AV_CODEC_ID_NONE && val != 0);
- } else {
- return AVERROR(EINVAL);
+
+ av_log(logctx, AV_LOG_TRACE,
+ "Parsed metadata: %s:%s; remainder: %s", ss->meta_key,
+ ss->meta_val ? ss->meta_val : "<any value>", spec);
+
+ // this terminates the specifier
+ break;
+ } else if (*spec == 'u' && (*(spec + 1) == '\0' || *(spec + 1) == ':')) {
+ ss->usable_only = 1;
+ spec++;
+ av_log(logctx, AV_LOG_ERROR, "Parsed 'usable only'\n");
+
+ // this terminates the specifier
+ break;
+ } else
+ break;
+
+ if (*spec == ':')
+ spec++;
+ }
+
+ if (*spec) {
+ if (!allow_remainder) {
+ av_log(logctx, AV_LOG_ERROR,
+ "Trailing garbage at the end of a stream specifier: %s\n",
+ spec);
+ ret = AVERROR(EINVAL);
+ goto fail;
+ }
+
+ if (*spec == ':')
+ spec++;
+
+ ss->remainder = av_strdup(spec);
+ if (!ss->remainder) {
+ ret = AVERROR(EINVAL);
+ goto fail;
}
}
- return match;
+ return 0;
+
+multiple_stream_lists:
+ av_log(logctx, AV_LOG_ERROR,
+ "Cannot combine multiple program/group designators in a "
+ "single stream specifier");
+ ret = AVERROR(EINVAL);
+
+fail:
+ stream_specifier_uninit(ss);
+ return ret;
+}
+
+unsigned stream_specifier_match(const StreamSpecifier *ss,
+ const AVFormatContext *s, const AVStream *st,
+ void *logctx)
+{
+ const AVStreamGroup *g = NULL;
+ const AVProgram *p = NULL;
+ int start_stream = 0, nb_streams;
+ int nb_matched = 0;
+
+ switch (ss->stream_list) {
+ case STREAM_LIST_STREAM_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 (st->id != ss->list_id)
+ return 0;
+ start_stream = st->index;
+ nb_streams = st->index + 1;
+ break;
+ case STREAM_LIST_ALL:
+ start_stream = ss->idx >= 0 ? 0 : st->index;
+ nb_streams = st->index + 1;
+ break;
+ case STREAM_LIST_PROGRAM:
+ for (unsigned i = 0; i < s->nb_programs; i++) {
+ if (s->programs[i]->id == ss->list_id) {
+ p = s->programs[i];
+ break;
+ }
+ }
+ if (!p) {
+ av_log(logctx, AV_LOG_WARNING, "No program with ID %"PRId64" exists,"
+ " stream specifier can never match\n", ss->list_id);
+ return 0;
+ }
+ nb_streams = p->nb_stream_indexes;
+ break;
+ case STREAM_LIST_GROUP_ID:
+ for (unsigned i = 0; i < s->nb_stream_groups; i++) {
+ if (ss->list_id == s->stream_groups[i]->id) {
+ g = s->stream_groups[i];
+ break;
+ }
+ }
+ // fall-through
+ case STREAM_LIST_GROUP_IDX:
+ if (ss->stream_list == STREAM_LIST_GROUP_IDX &&
+ ss->list_id >= 0 && ss->list_id < s->nb_stream_groups)
+ g = s->stream_groups[ss->list_id];
+
+ if (!g) {
+ av_log(logctx, AV_LOG_WARNING, "No stream group with group %s %"
+ PRId64" exists, stream specifier can never match\n",
+ ss->stream_list == STREAM_LIST_GROUP_ID ? "ID" : "index",
+ ss->list_id);
+ return 0;
+ }
+ nb_streams = g->nb_streams;
+ break;
+ default: av_assert0(0);
+ }
+
+ for (int i = start_stream; i < nb_streams; i++) {
+ const AVStream *candidate = s->streams[g ? g->streams[i]->index :
+ p ? p->stream_index[i] : i];
+
+ if (ss->media_type != AVMEDIA_TYPE_UNKNOWN &&
+ (ss->media_type != candidate->codecpar->codec_type ||
+ (ss->no_apic && (candidate->disposition & AV_DISPOSITION_ATTACHED_PIC))))
+ continue;
+
+ 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) {
+ const AVCodecParameters *par = candidate->codecpar;
+
+ switch (par->codec_type) {
+ case AVMEDIA_TYPE_AUDIO:
+ if (!par->sample_rate || !par->ch_layout.nb_channels ||
+ par->format == AV_SAMPLE_FMT_NONE)
+ continue;
+ break;
+ case AVMEDIA_TYPE_VIDEO:
+ if (!par->width || !par->height || par->format == AV_PIX_FMT_NONE)
+ continue;
+ break;
+ case AVMEDIA_TYPE_UNKNOWN:
+ continue;
+ }
+ }
+
+ if (st == candidate)
+ return ss->idx < 0 || ss->idx == nb_matched;
+
+ nb_matched++;
+ }
+
+ return 0;
}
int check_stream_specifier(AVFormatContext *s, AVStream *st, const char *spec)
{
- int ret, index;
- char *endptr;
- const char *indexptr = NULL;
- const AVStreamGroup *g = NULL;
- const AVProgram *p = NULL;
- int nb_streams;
+ StreamSpecifier ss;
+ int ret;
- ret = match_stream_specifier(s, st, spec, &indexptr, &g, &p);
+ ret = stream_specifier_parse(&ss, spec, 0, NULL);
if (ret < 0)
- goto error;
-
- if (!indexptr)
return ret;
- index = strtol(indexptr, &endptr, 0);
- if (*endptr) { /* We can't have anything after the requested index. */
- ret = AVERROR(EINVAL);
- goto error;
- }
-
- /* This is not really needed but saves us a loop for simple stream index specifiers. */
- if (spec == indexptr)
- return (index == st->index);
-
- /* If we requested a matching stream index, we have to ensure st is that. */
- nb_streams = g ? g->nb_streams : (p ? p->nb_stream_indexes : s->nb_streams);
- for (int i = 0; i < nb_streams && index >= 0; i++) {
- unsigned idx = g ? g->streams[i]->index : (p ? p->stream_index[i] : i);
- const AVStream *candidate = s->streams[idx];
- ret = match_stream_specifier(s, candidate, spec, NULL, NULL, NULL);
- if (ret < 0)
- goto error;
- if (ret > 0 && index-- == 0 && st == candidate)
- return 1;
- }
- return 0;
-
-error:
- if (ret == AVERROR(EINVAL))
- av_log(s, AV_LOG_ERROR, "Invalid stream specifier: %s.\n", spec);
+ ret = stream_specifier_match(&ss, s, st, NULL);
+ stream_specifier_uninit(&ss);
return ret;
}
diff --git a/fftools/cmdutils.h b/fftools/cmdutils.h
index abc8d26607..f7005aabf9 100644
--- a/fftools/cmdutils.h
+++ b/fftools/cmdutils.h
@@ -102,6 +102,62 @@ enum OptionType {
int parse_number(const char *context, const char *numstr, enum OptionType type,
double min, double max, double *dst);
+enum StreamList {
+ STREAM_LIST_ALL,
+ STREAM_LIST_STREAM_ID,
+ STREAM_LIST_PROGRAM,
+ STREAM_LIST_GROUP_ID,
+ STREAM_LIST_GROUP_IDX,
+};
+
+typedef struct StreamSpecifier {
+ // trailing stream index - pick idx-th stream that matches
+ // all the other constraints; -1 when not present
+ int idx;
+
+ // which stream list to consider
+ enum StreamList stream_list;
+
+ // STREAM_LIST_STREAM_ID: stream ID
+ // STREAM_LIST_GROUP_IDX: group index
+ // STREAM_LIST_GROUP_ID: group ID
+ // STREAM_LIST_PROGRAM: program ID
+ int64_t list_id;
+
+ // when not AVMEDIA_TYPE_UNKNOWN, consider only streams of this type
+ enum AVMediaType media_type;
+ uint8_t no_apic;
+
+ uint8_t usable_only;
+
+ char *meta_key;
+ char *meta_val;
+
+ char *remainder;
+} StreamSpecifier;
+
+/**
+ * Parse a stream specifier string into a form suitable for matching.
+ *
+ * @param ss Parsed specifier will be stored here; must be uninitialized
+ * with stream_specifier_uninit() when no longer needed.
+ * @param spec String containing the stream specifier to be parsed.
+ * @param allow_remainder When 1, the part of spec that is left after parsing
+ * the stream specifier is stored into ss->remainder.
+ * When 0, any remainder will cause parsing to fail.
+ */
+int stream_specifier_parse(StreamSpecifier *ss, const char *spec,
+ int allow_remainder, void *logctx);
+
+/**
+ * @return 1 if st matches the parsed specifier, 0 if it does not
+ */
+unsigned stream_specifier_match(const StreamSpecifier *ss,
+ const AVFormatContext *s, const AVStream *st,
+ void *logctx);
+
+void stream_specifier_uninit(StreamSpecifier *ss);
+
typedef struct SpecifierOpt {
char *specifier; /**< stream/chapter/program/... specifier */
union {
--
2.43.0
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 6+ messages in thread
* [FFmpeg-devel] [PATCH 5/6] fftools/ffmpeg: use new stream specifier API in opt_match_per_stream*()
2024-08-10 17:16 [FFmpeg-devel] [PATCH 1/6] fftools/ffmpeg: replace MATCH_PER_STREAM_OPT(.., str, ..) with a function Anton Khirnov
` (2 preceding siblings ...)
2024-08-10 17:16 ` [FFmpeg-devel] [PATCH 4/6] fftools/cmdutils: split stream specifier parsing and matching Anton Khirnov
@ 2024-08-10 17:16 ` Anton Khirnov
2024-08-10 17:16 ` [FFmpeg-devel] [PATCH 6/6] fftools/ffmpeg: switch -map parsing to new stream specifier API Anton Khirnov
4 siblings, 0 replies; 6+ messages in thread
From: Anton Khirnov @ 2024-08-10 17:16 UTC (permalink / raw)
To: ffmpeg-devel
Removes a lot of error checking code, as matching cannot fail.
---
fftools/cmdutils.c | 8 ++
fftools/cmdutils.h | 6 +-
fftools/ffmpeg.h | 16 +--
fftools/ffmpeg_demux.c | 87 ++++-------------
fftools/ffmpeg_mux_init.c | 198 ++++++++++----------------------------
fftools/ffmpeg_opt.c | 32 +++---
6 files changed, 105 insertions(+), 242 deletions(-)
diff --git a/fftools/cmdutils.c b/fftools/cmdutils.c
index b3f501bd56..f725c31c12 100644
--- a/fftools/cmdutils.c
+++ b/fftools/cmdutils.c
@@ -288,6 +288,14 @@ static int write_option(void *optctx, const OptionDef *po, const char *opt,
goto finish;
}
sol->opt[sol->nb_opt - 1].specifier = str;
+
+ if (po->flags & OPT_FLAG_PERSTREAM) {
+ ret = stream_specifier_parse(&sol->opt[sol->nb_opt - 1].stream_spec,
+ str, 0, NULL);
+ if (ret < 0)
+ goto finish;
+ }
+
dst = &sol->opt[sol->nb_opt - 1].u;
}
diff --git a/fftools/cmdutils.h b/fftools/cmdutils.h
index f7005aabf9..9609c6c739 100644
--- a/fftools/cmdutils.h
+++ b/fftools/cmdutils.h
@@ -159,7 +159,11 @@ unsigned stream_specifier_match(const StreamSpecifier *ss,
void stream_specifier_uninit(StreamSpecifier *ss);
typedef struct SpecifierOpt {
- char *specifier; /**< stream/chapter/program/... specifier */
+ // original specifier or empty string
+ char *specifier;
+ // parsed specifier for OPT_FLAG_PERSTREAM options
+ StreamSpecifier stream_spec;
+
union {
uint8_t *str;
int i;
diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h
index 674ae340f2..3c5d933e17 100644
--- a/fftools/ffmpeg.h
+++ b/fftools/ffmpeg.h
@@ -859,14 +859,14 @@ void update_benchmark(const char *fmt, ...);
const char *opt_match_per_type_str(const SpecifierOptList *sol,
char mediatype);
-int opt_match_per_stream_str(void *logctx, const SpecifierOptList *sol,
- AVFormatContext *fc, AVStream *st, const char **out);
-int opt_match_per_stream_int(void *logctx, const SpecifierOptList *sol,
- AVFormatContext *fc, AVStream *st, int *out);
-int opt_match_per_stream_int64(void *logctx, const SpecifierOptList *sol,
- AVFormatContext *fc, AVStream *st, int64_t *out);
-int opt_match_per_stream_dbl(void *logctx, const SpecifierOptList *sol,
- AVFormatContext *fc, AVStream *st, double *out);
+void opt_match_per_stream_str(void *logctx, const SpecifierOptList *sol,
+ AVFormatContext *fc, AVStream *st, const char **out);
+void opt_match_per_stream_int(void *logctx, const SpecifierOptList *sol,
+ AVFormatContext *fc, AVStream *st, int *out);
+void opt_match_per_stream_int64(void *logctx, const SpecifierOptList *sol,
+ AVFormatContext *fc, AVStream *st, int64_t *out);
+void opt_match_per_stream_dbl(void *logctx, const SpecifierOptList *sol,
+ AVFormatContext *fc, AVStream *st, double *out);
int muxer_thread(void *arg);
int encoder_thread(void *arg);
diff --git a/fftools/ffmpeg_demux.c b/fftools/ffmpeg_demux.c
index e9a4b5c22a..039ee0c785 100644
--- a/fftools/ffmpeg_demux.c
+++ b/fftools/ffmpeg_demux.c
@@ -1084,12 +1084,8 @@ static int choose_decoder(const OptionsContext *o, void *logctx,
{
const char *codec_name = NULL;
- int ret;
-
- ret = opt_match_per_stream_str(logctx, &o->codec_names, s, st, &codec_name);
- if (ret < 0)
- return ret;
+ opt_match_per_stream_str(logctx, &o->codec_names, s, st, &codec_name);
if (codec_name) {
int ret = find_codec(NULL, codec_name, st->codecpar->codec_type, 0, pcodec);
if (ret < 0)
@@ -1153,18 +1149,11 @@ static int add_display_matrix_to_stream(const OptionsContext *o,
double rotation = DBL_MAX;
int hflip = -1, vflip = -1;
int hflip_set = 0, vflip_set = 0, rotation_set = 0;
- int ret;
int32_t *buf;
- ret = opt_match_per_stream_dbl(ist, &o->display_rotations, ctx, st, &rotation);
- if (ret < 0)
- return ret;
- ret = opt_match_per_stream_int(ist, &o->display_hflips, ctx, st, &hflip);
- if (ret < 0)
- return ret;
- ret = opt_match_per_stream_int(ist, &o->display_vflips, ctx, st, &vflip);
- if (ret < 0)
- return ret;
+ opt_match_per_stream_dbl(ist, &o->display_rotations, ctx, st, &rotation);
+ opt_match_per_stream_int(ist, &o->display_hflips, ctx, st, &hflip);
+ opt_match_per_stream_int(ist, &o->display_vflips, ctx, st, &vflip);
rotation_set = rotation != DBL_MAX;
hflip_set = hflip != -1;
@@ -1262,19 +1251,13 @@ static int ist_add(const OptionsContext *o, Demuxer *d, AVStream *st, AVDictiona
ds->dec_opts.time_base = st->time_base;
ds->ts_scale = 1.0;
- ret = opt_match_per_stream_dbl(ist, &o->ts_scale, ic, st, &ds->ts_scale);
- if (ret < 0)
- return ret;
+ opt_match_per_stream_dbl(ist, &o->ts_scale, ic, st, &ds->ts_scale);
ds->autorotate = 1;
- ret = opt_match_per_stream_int(ist, &o->autorotate, ic, st, &ds->autorotate);
- if (ret < 0)
- return ret;
+ opt_match_per_stream_int(ist, &o->autorotate, ic, st, &ds->autorotate);
ds->apply_cropping = CROP_ALL;
- ret = opt_match_per_stream_str(ist, &o->apply_cropping, ic, st, &apply_cropping);
- if (ret < 0)
- return ret;
+ opt_match_per_stream_str(ist, &o->apply_cropping, ic, st, &apply_cropping);
if (apply_cropping) {
const AVOption opts[] = {
{ "apply_cropping", NULL, 0, AV_OPT_TYPE_INT,
@@ -1300,9 +1283,7 @@ static int ist_add(const OptionsContext *o, Demuxer *d, AVStream *st, AVDictiona
}
}
- ret = opt_match_per_stream_str(ist, &o->codec_tags, ic, st, &codec_tag);
- if (ret < 0)
- return ret;
+ opt_match_per_stream_str(ist, &o->codec_tags, ic, st, &codec_tag);
if (codec_tag) {
uint32_t tag = strtol(codec_tag, &next, 0);
if (*next) {
@@ -1319,15 +1300,9 @@ static int ist_add(const OptionsContext *o, Demuxer *d, AVStream *st, AVDictiona
if (ret < 0)
return ret;
- ret = opt_match_per_stream_str(ist, &o->hwaccels, ic, st, &hwaccel);
- if (ret < 0)
- return ret;
-
- ret = opt_match_per_stream_str(ist, &o->hwaccel_output_formats, ic, st,
+ opt_match_per_stream_str(ist, &o->hwaccels, ic, st, &hwaccel);
+ opt_match_per_stream_str(ist, &o->hwaccel_output_formats, ic, st,
&hwaccel_output_format);
- if (ret < 0)
- return ret;
-
if (!hwaccel_output_format && hwaccel && !strcmp(hwaccel, "cuvid")) {
av_log(ist, AV_LOG_WARNING,
"WARNING: defaulting hwaccel_output_format to cuda for compatibility "
@@ -1385,9 +1360,7 @@ static int ist_add(const OptionsContext *o, Demuxer *d, AVStream *st, AVDictiona
}
}
- ret = opt_match_per_stream_str(ist, &o->hwaccel_devices, ic, st, &hwaccel_device);
- if (ret < 0)
- return ret;
+ opt_match_per_stream_str(ist, &o->hwaccel_devices, ic, st, &hwaccel_device);
if (hwaccel_device) {
ds->dec_opts.hwaccel_device = av_strdup(hwaccel_device);
if (!ds->dec_opts.hwaccel_device)
@@ -1408,9 +1381,7 @@ static int ist_add(const OptionsContext *o, Demuxer *d, AVStream *st, AVDictiona
}
ds->reinit_filters = -1;
- ret = opt_match_per_stream_int(ist, &o->reinit_filters, ic, st, &ds->reinit_filters);
- if (ret < 0)
- return ret;
+ opt_match_per_stream_int(ist, &o->reinit_filters, ic, st, &ds->reinit_filters);
ist->user_set_discard = AVDISCARD_NONE;
@@ -1420,9 +1391,7 @@ static int ist_add(const OptionsContext *o, Demuxer *d, AVStream *st, AVDictiona
(o->data_disable && ist->st->codecpar->codec_type == AVMEDIA_TYPE_DATA))
ist->user_set_discard = AVDISCARD_ALL;
- ret = opt_match_per_stream_str(ist, &o->discard, ic, st, &discard_str);
- if (ret < 0)
- return ret;
+ opt_match_per_stream_str(ist, &o->discard, ic, st, &discard_str);
if (discard_str) {
ret = av_opt_set(ist->st, "discard", discard_str, 0);
if (ret < 0) {
@@ -1444,9 +1413,7 @@ static int ist_add(const OptionsContext *o, Demuxer *d, AVStream *st, AVDictiona
switch (par->codec_type) {
case AVMEDIA_TYPE_VIDEO:
- ret = opt_match_per_stream_str(ist, &o->frame_rates, ic, st, &framerate);
- if (ret < 0)
- return ret;
+ opt_match_per_stream_str(ist, &o->frame_rates, ic, st, &framerate);
if (framerate) {
ret = av_parse_video_rate(&ist->framerate, framerate);
if (ret < 0) {
@@ -1458,18 +1425,14 @@ static int ist_add(const OptionsContext *o, Demuxer *d, AVStream *st, AVDictiona
#if FFMPEG_OPT_TOP
ist->top_field_first = -1;
- ret = opt_match_per_stream_int(ist, &o->top_field_first, ic, st, &ist->top_field_first);
- if (ret < 0)
- return ret;
+ opt_match_per_stream_int(ist, &o->top_field_first, ic, st, &ist->top_field_first);
#endif
break;
case AVMEDIA_TYPE_AUDIO: {
const char *ch_layout_str = NULL;
- ret = opt_match_per_stream_str(ist, &o->audio_ch_layouts, ic, st, &ch_layout_str);
- if (ret < 0)
- return ret;
+ opt_match_per_stream_str(ist, &o->audio_ch_layouts, ic, st, &ch_layout_str);
if (ch_layout_str) {
AVChannelLayout ch_layout;
ret = av_channel_layout_from_string(&ch_layout, ch_layout_str);
@@ -1489,10 +1452,7 @@ static int ist_add(const OptionsContext *o, Demuxer *d, AVStream *st, AVDictiona
}
} else {
int guess_layout_max = INT_MAX;
- ret = opt_match_per_stream_int(ist, &o->guess_layout_max, ic, st, &guess_layout_max);
- if (ret < 0)
- return ret;
-
+ opt_match_per_stream_int(ist, &o->guess_layout_max, ic, st, &guess_layout_max);
guess_input_channel_layout(ist, par, guess_layout_max);
}
break;
@@ -1501,13 +1461,8 @@ static int ist_add(const OptionsContext *o, Demuxer *d, AVStream *st, AVDictiona
case AVMEDIA_TYPE_SUBTITLE: {
const char *canvas_size = NULL;
- ret = opt_match_per_stream_int(ist, &o->fix_sub_duration, ic, st, &ist->fix_sub_duration);
- if (ret < 0)
- return ret;
-
- ret = opt_match_per_stream_str(ist, &o->canvas_sizes, ic, st, &canvas_size);
- if (ret < 0)
- return ret;
+ opt_match_per_stream_int(ist, &o->fix_sub_duration, ic, st, &ist->fix_sub_duration);
+ opt_match_per_stream_str(ist, &o->canvas_sizes, ic, st, &canvas_size);
if (canvas_size) {
ret = av_parse_video_size(&par->width, &par->height,
canvas_size);
@@ -1537,9 +1492,7 @@ static int ist_add(const OptionsContext *o, Demuxer *d, AVStream *st, AVDictiona
if (ist->st->sample_aspect_ratio.num)
ist->par->sample_aspect_ratio = ist->st->sample_aspect_ratio;
- ret = opt_match_per_stream_str(ist, &o->bitstream_filters, ic, st, &bsfs);
- if (ret < 0)
- return ret;
+ opt_match_per_stream_str(ist, &o->bitstream_filters, ic, st, &bsfs);
if (bsfs) {
ret = av_bsf_list_parse_str(bsfs, &ds->bsf);
if (ret < 0) {
diff --git a/fftools/ffmpeg_mux_init.c b/fftools/ffmpeg_mux_init.c
index 2b3a4ddcf9..e84fa9719f 100644
--- a/fftools/ffmpeg_mux_init.c
+++ b/fftools/ffmpeg_mux_init.c
@@ -71,13 +71,10 @@ static int choose_encoder(const OptionsContext *o, AVFormatContext *s,
{
enum AVMediaType type = ost->type;
const char *codec_name = NULL;
- int ret;
*enc = NULL;
- ret = opt_match_per_stream_str(ost, &o->codec_names, s, ost->st, &codec_name);
- if (ret < 0)
- return ret;
+ opt_match_per_stream_str(ost, &o->codec_names, s, ost->st, &codec_name);
if (type != AVMEDIA_TYPE_VIDEO &&
type != AVMEDIA_TYPE_AUDIO &&
@@ -419,17 +416,12 @@ static int ost_get_filters(const OptionsContext *o, AVFormatContext *oc,
OutputStream *ost, char **dst)
{
const char *filters = NULL;
- int ret;
#if FFMPEG_OPT_FILTER_SCRIPT
const char *filters_script = NULL;
- ret = opt_match_per_stream_str(ost, &o->filter_scripts, oc, ost->st, &filters_script);
- if (ret < 0)
- return ret;
+ opt_match_per_stream_str(ost, &o->filter_scripts, oc, ost->st, &filters_script);
#endif
- ret = opt_match_per_stream_str(ost, &o->filters, oc, ost->st, &filters);
- if (ret < 0)
- return ret;
+ opt_match_per_stream_str(ost, &o->filters, oc, ost->st, &filters);
if (!ost->enc) {
if (
@@ -599,17 +591,13 @@ static int new_stream_video(Muxer *mux, const OptionsContext *o,
st = ost->st;
- ret = opt_match_per_stream_str(ost, &o->frame_rates, oc, st, &frame_rate);
- if (ret < 0)
- return ret;
+ opt_match_per_stream_str(ost, &o->frame_rates, oc, st, &frame_rate);
if (frame_rate && av_parse_video_rate(&ost->frame_rate, frame_rate) < 0) {
av_log(ost, AV_LOG_FATAL, "Invalid framerate value: %s\n", frame_rate);
return AVERROR(EINVAL);
}
- ret = opt_match_per_stream_str(ost, &o->max_frame_rates, oc, st, &max_frame_rate);
- if (ret < 0)
- return ret;
+ opt_match_per_stream_str(ost, &o->max_frame_rates, oc, st, &max_frame_rate);
if (max_frame_rate && av_parse_video_rate(&ost->max_frame_rate, max_frame_rate) < 0) {
av_log(ost, AV_LOG_FATAL, "Invalid maximum framerate value: %s\n", max_frame_rate);
return AVERROR(EINVAL);
@@ -620,9 +608,7 @@ static int new_stream_video(Muxer *mux, const OptionsContext *o,
return AVERROR(EINVAL);
}
- ret = opt_match_per_stream_str(ost, &o->frame_aspect_ratios, oc, st, &frame_aspect_ratio);
- if (ret < 0)
- return ret;
+ opt_match_per_stream_str(ost, &o->frame_aspect_ratios, oc, st, &frame_aspect_ratio);
if (frame_aspect_ratio) {
AVRational q;
if (av_parse_ratio(&q, frame_aspect_ratio, 255, 0, NULL) < 0 ||
@@ -643,9 +629,7 @@ static int new_stream_video(Muxer *mux, const OptionsContext *o,
int do_pass = 0;
int i;
- ret = opt_match_per_stream_str(ost, &o->frame_sizes, oc, st, &frame_size);
- if (ret < 0)
- return ret;
+ opt_match_per_stream_str(ost, &o->frame_sizes, oc, st, &frame_size);
if (frame_size) {
ret = av_parse_video_size(&video_enc->width, &video_enc->height, frame_size);
if (ret < 0) {
@@ -654,9 +638,7 @@ static int new_stream_video(Muxer *mux, const OptionsContext *o,
}
}
- ret = opt_match_per_stream_str(ost, &o->frame_pix_fmts, oc, st, &frame_pix_fmt);
- if (ret < 0)
- return ret;
+ opt_match_per_stream_str(ost, &o->frame_pix_fmts, oc, st, &frame_pix_fmt);
if (frame_pix_fmt && *frame_pix_fmt == '+') {
*keep_pix_fmt = 1;
if (!*++frame_pix_fmt)
@@ -668,9 +650,7 @@ static int new_stream_video(Muxer *mux, const OptionsContext *o,
return AVERROR(EINVAL);
}
- ret = opt_match_per_stream_str(ost, &o->intra_matrices, oc, st, &intra_matrix);
- if (ret < 0)
- return ret;
+ opt_match_per_stream_str(ost, &o->intra_matrices, oc, st, &intra_matrix);
if (intra_matrix) {
if (!(video_enc->intra_matrix = av_mallocz(sizeof(*video_enc->intra_matrix) * 64)))
return AVERROR(ENOMEM);
@@ -679,9 +659,7 @@ static int new_stream_video(Muxer *mux, const OptionsContext *o,
if (ret < 0)
return ret;
}
- ret = opt_match_per_stream_str(ost, &o->chroma_intra_matrices, oc, st, &chroma_intra_matrix);
- if (ret < 0)
- return ret;
+ opt_match_per_stream_str(ost, &o->chroma_intra_matrices, oc, st, &chroma_intra_matrix);
if (chroma_intra_matrix) {
uint16_t *p = av_mallocz(sizeof(*video_enc->chroma_intra_matrix) * 64);
if (!p)
@@ -691,9 +669,7 @@ static int new_stream_video(Muxer *mux, const OptionsContext *o,
if (ret < 0)
return ret;
}
- ret = opt_match_per_stream_str(ost, &o->inter_matrices, oc, st, &inter_matrix);
- if (ret < 0)
- return ret;
+ opt_match_per_stream_str(ost, &o->inter_matrices, oc, st, &inter_matrix);
if (inter_matrix) {
if (!(video_enc->inter_matrix = av_mallocz(sizeof(*video_enc->inter_matrix) * 64)))
return AVERROR(ENOMEM);
@@ -702,9 +678,7 @@ static int new_stream_video(Muxer *mux, const OptionsContext *o,
return ret;
}
- ret = opt_match_per_stream_str(ost, &o->rc_overrides, oc, st, &p);
- if (ret < 0)
- return ret;
+ opt_match_per_stream_str(ost, &o->rc_overrides, oc, st, &p);
for (i = 0; p; i++) {
int start, end, q;
int e = sscanf(p, "%d,%d,%d", &start, &end, &q);
@@ -735,9 +709,7 @@ static int new_stream_video(Muxer *mux, const OptionsContext *o,
video_enc->rc_override_count = i;
/* two pass mode */
- ret = opt_match_per_stream_int(ost, &o->pass, oc, st, &do_pass);
- if (ret < 0)
- return ret;
+ opt_match_per_stream_int(ost, &o->pass, oc, st, &do_pass);
if (do_pass) {
if (do_pass & 1)
video_enc->flags |= AV_CODEC_FLAG_PASS1;
@@ -745,9 +717,7 @@ static int new_stream_video(Muxer *mux, const OptionsContext *o,
video_enc->flags |= AV_CODEC_FLAG_PASS2;
}
- ret = opt_match_per_stream_str(ost, &o->passlogfiles, oc, st, &ost->logfile_prefix);
- if (ret < 0)
- return ret;
+ opt_match_per_stream_str(ost, &o->passlogfiles, oc, st, &ost->logfile_prefix);
if (ost->logfile_prefix &&
!(ost->logfile_prefix = av_strdup(ost->logfile_prefix)))
return AVERROR(ENOMEM);
@@ -794,15 +764,11 @@ static int new_stream_video(Muxer *mux, const OptionsContext *o,
}
}
- ret = opt_match_per_stream_int(ost, &o->force_fps, oc, st, &ost->force_fps);
- if (ret < 0)
- return ret;
+ opt_match_per_stream_int(ost, &o->force_fps, oc, st, &ost->force_fps);
#if FFMPEG_OPT_TOP
ost->top_field_first = -1;
- ret = opt_match_per_stream_int(ost, &o->top_field_first, oc, st, &ost->top_field_first);
- if (ret < 0)
- return ret;
+ opt_match_per_stream_int(ost, &o->top_field_first, oc, st, &ost->top_field_first);
if (ost->top_field_first >= 0)
av_log(ost, AV_LOG_WARNING, "-top is deprecated, use the setfield filter instead\n");
#endif
@@ -812,9 +778,7 @@ static int new_stream_video(Muxer *mux, const OptionsContext *o,
#else
*vsync_method = VSYNC_AUTO;
#endif
- ret = opt_match_per_stream_str(ost, &o->fps_mode, oc, st, &fps_mode);
- if (ret < 0)
- return ret;
+ opt_match_per_stream_str(ost, &o->fps_mode, oc, st, &fps_mode);
if (fps_mode) {
ret = parse_and_set_vsync(fps_mode, vsync_method, ost->file->index, ost->index, 0);
if (ret < 0)
@@ -872,40 +836,28 @@ static int new_stream_audio(Muxer *mux, const OptionsContext *o,
int channels = 0;
const char *layout = NULL;
const char *sample_fmt = NULL;
- int ret;
- ret = opt_match_per_stream_int(ost, &o->audio_channels, oc, st, &channels);
- if (ret < 0)
- return ret;
+ opt_match_per_stream_int(ost, &o->audio_channels, oc, st, &channels);
if (channels) {
audio_enc->ch_layout.order = AV_CHANNEL_ORDER_UNSPEC;
audio_enc->ch_layout.nb_channels = channels;
}
- ret = opt_match_per_stream_str(ost, &o->audio_ch_layouts, oc, st, &layout);
- if (ret < 0)
- return ret;
+ opt_match_per_stream_str(ost, &o->audio_ch_layouts, oc, st, &layout);
if (layout && av_channel_layout_from_string(&audio_enc->ch_layout, layout) < 0) {
av_log(ost, AV_LOG_FATAL, "Unknown channel layout: %s\n", layout);
return AVERROR(EINVAL);
}
- ret = opt_match_per_stream_str(ost, &o->sample_fmts, oc, st, &sample_fmt);
- if (ret < 0)
- return ret;
+ opt_match_per_stream_str(ost, &o->sample_fmts, oc, st, &sample_fmt);
if (sample_fmt &&
(audio_enc->sample_fmt = av_get_sample_fmt(sample_fmt)) == AV_SAMPLE_FMT_NONE) {
av_log(ost, AV_LOG_FATAL, "Invalid sample format '%s'\n", sample_fmt);
return AVERROR(EINVAL);
}
- ret = opt_match_per_stream_int(ost, &o->audio_sample_rate, oc, st, &audio_enc->sample_rate);
- if (ret < 0)
- return ret;
-
- ret = opt_match_per_stream_str(ost, &o->apad, oc, st, &ms->apad);
- if (ret < 0)
- return ret;
+ opt_match_per_stream_int(ost, &o->audio_sample_rate, oc, st, &audio_enc->sample_rate);
+ opt_match_per_stream_str(ost, &o->apad, oc, st, &ms->apad);
}
return 0;
@@ -928,11 +880,8 @@ static int new_stream_subtitle(Muxer *mux, const OptionsContext *o,
int input_props = 0, output_props = 0;
const char *frame_size = NULL;
- int ret;
- ret = opt_match_per_stream_str(ost, &o->frame_sizes, mux->fc, st, &frame_size);
- if (ret < 0)
- return ret;
+ opt_match_per_stream_str(ost, &o->frame_sizes, mux->fc, st, &frame_size);
if (frame_size) {
int ret = av_parse_video_size(&subtitle_enc->width, &subtitle_enc->height, frame_size);
if (ret < 0) {
@@ -1211,13 +1160,8 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type,
if (ret < 0)
goto fail;
- ret = opt_match_per_stream_str(ost, &o->presets, oc, st, &preset);
- if (ret < 0)
- goto fail;
-
- ret = opt_match_per_stream_int(ost, &o->autoscale, oc, st, &autoscale);
- if (ret < 0)
- goto fail;
+ opt_match_per_stream_str(ost, &o->presets, oc, st, &preset);
+ opt_match_per_stream_int(ost, &o->autoscale, oc, st, &autoscale);
if (preset && (!(ret = get_preset_file_2(preset, enc->codec->name, &s)))) {
AVBPrint bprint;
av_bprint_init(&bprint, 0, AV_BPRINT_SIZE_UNLIMITED);
@@ -1248,14 +1192,12 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type,
goto fail;
}
- ret = opt_match_per_stream_str(ost, &o->enc_stats_pre, oc, st, &enc_stats_pre);
- if (ret < 0)
- goto fail;
+ opt_match_per_stream_str(ost, &o->enc_stats_pre, oc, st, &enc_stats_pre);
if (enc_stats_pre &&
(type == AVMEDIA_TYPE_VIDEO || type == AVMEDIA_TYPE_AUDIO)) {
const char *format = "{fidx} {sidx} {n} {t}";
- ret = opt_match_per_stream_str(ost, &o->enc_stats_pre_fmt, oc, st, &format);
+ opt_match_per_stream_str(ost, &o->enc_stats_pre_fmt, oc, st, &format);
if (ret < 0)
goto fail;
@@ -1264,41 +1206,31 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type,
goto fail;
}
- ret = opt_match_per_stream_str(ost, &o->enc_stats_post, oc, st, &enc_stats_post);
- if (ret < 0)
- goto fail;
+ opt_match_per_stream_str(ost, &o->enc_stats_post, oc, st, &enc_stats_post);
if (enc_stats_post &&
(type == AVMEDIA_TYPE_VIDEO || type == AVMEDIA_TYPE_AUDIO)) {
const char *format = "{fidx} {sidx} {n} {t}";
- ret = opt_match_per_stream_str(ost, &o->enc_stats_post_fmt, oc, st, &format);
- if (ret < 0)
- goto fail;
+ opt_match_per_stream_str(ost, &o->enc_stats_post_fmt, oc, st, &format);
ret = enc_stats_init(ost, &ost->enc_stats_post, 0, enc_stats_post, format);
if (ret < 0)
goto fail;
}
- ret = opt_match_per_stream_str(ost, &o->mux_stats, oc, st, &mux_stats);
- if (ret < 0)
- goto fail;
+ opt_match_per_stream_str(ost, &o->mux_stats, oc, st, &mux_stats);
if (mux_stats &&
(type == AVMEDIA_TYPE_VIDEO || type == AVMEDIA_TYPE_AUDIO)) {
const char *format = "{fidx} {sidx} {n} {t}";
- ret = opt_match_per_stream_str(ost, &o->mux_stats_fmt, oc, st, &format);
- if (ret < 0)
- goto fail;
+ opt_match_per_stream_str(ost, &o->mux_stats_fmt, oc, st, &format);
ret = enc_stats_init(ost, &ms->stats, 0, mux_stats, format);
if (ret < 0)
goto fail;
}
- ret = opt_match_per_stream_str(ost, &o->enc_time_bases, oc, st, &enc_time_base);
- if (ret < 0)
- goto fail;
+ opt_match_per_stream_str(ost, &o->enc_time_bases, oc, st, &enc_time_base);
if (enc_time_base && type == AVMEDIA_TYPE_SUBTITLE)
av_log(ost, AV_LOG_WARNING,
"-enc_time_base not supported for subtitles, ignoring\n");
@@ -1361,9 +1293,7 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type,
ost->bitexact = !!(ost->enc_ctx->flags & AV_CODEC_FLAG_BITEXACT);
}
- ret = opt_match_per_stream_str(ost, &o->time_bases, oc, st, &time_base);
- if (ret < 0)
- goto fail;
+ opt_match_per_stream_str(ost, &o->time_bases, oc, st, &time_base);
if (time_base) {
AVRational q;
if (av_parse_ratio(&q, time_base, INT_MAX, 0, NULL) < 0 ||
@@ -1376,9 +1306,7 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type,
}
ms->max_frames = INT64_MAX;
- ret = opt_match_per_stream_int64(ost, &o->max_frames, oc, st, &ms->max_frames);
- if (ret < 0)
- return ret;
+ opt_match_per_stream_int64(ost, &o->max_frames, oc, st, &ms->max_frames);
for (int i = 0; i < o->max_frames.nb_opt; i++) {
char *p = o->max_frames.opt[i].specifier;
if (!*p && type != AVMEDIA_TYPE_VIDEO) {
@@ -1388,13 +1316,8 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type,
}
ms->copy_prior_start = -1;
- ret = opt_match_per_stream_int(ost, &o->copy_prior_start, oc, st, &ms->copy_prior_start);
- if (ret < 0)
- goto fail;
-
- ret = opt_match_per_stream_str(ost, &o->bitstream_filters, oc, st, &bsfs);
- if (ret < 0)
- goto fail;
+ opt_match_per_stream_int(ost, &o->copy_prior_start, oc, st, &ms->copy_prior_start);
+ opt_match_per_stream_str(ost, &o->bitstream_filters, oc, st, &bsfs);
if (bsfs && *bsfs) {
ret = av_bsf_list_parse_str(bsfs, &ms->bsf_ctx);
if (ret < 0) {
@@ -1403,9 +1326,7 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type,
}
}
- ret = opt_match_per_stream_str(ost, &o->codec_tags, oc, st, &codec_tag);
- if (ret < 0)
- goto fail;
+ opt_match_per_stream_str(ost, &o->codec_tags, oc, st, &codec_tag);
if (codec_tag) {
uint32_t tag = strtol(codec_tag, &next, 0);
if (*next) {
@@ -1419,9 +1340,7 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type,
ost->enc_ctx->codec_tag = tag;
}
- ret = opt_match_per_stream_dbl(ost, &o->qscale, oc, st, &qscale);
- if (ret < 0)
- return ret;
+ opt_match_per_stream_dbl(ost, &o->qscale, oc, st, &qscale);
if (ost->enc_ctx && qscale >= 0) {
ost->enc_ctx->flags |= AV_CODEC_FLAG_QSCALE;
ost->enc_ctx->global_quality = FF_QP2LAMBDA * qscale;
@@ -1431,38 +1350,26 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type,
int max_muxing_queue_size = 128;
int muxing_queue_data_threshold = 50 * 1024 * 1024;
- ret = opt_match_per_stream_int(ost, &o->max_muxing_queue_size, oc, st,
- &max_muxing_queue_size);
- if (ret < 0)
- goto fail;
-
- ret = opt_match_per_stream_int(ost, &o->muxing_queue_data_threshold,
- oc, st, &muxing_queue_data_threshold);
- if (ret < 0)
- goto fail;
+ opt_match_per_stream_int(ost, &o->max_muxing_queue_size, oc, st,
+ &max_muxing_queue_size);
+ opt_match_per_stream_int(ost, &o->muxing_queue_data_threshold,
+ oc, st, &muxing_queue_data_threshold);
sch_mux_stream_buffering(mux->sch, mux->sch_idx, ms->sch_idx,
max_muxing_queue_size, muxing_queue_data_threshold);
}
- ret = opt_match_per_stream_int(ost, &o->bits_per_raw_sample, oc, st,
+ opt_match_per_stream_int(ost, &o->bits_per_raw_sample, oc, st,
&ost->bits_per_raw_sample);
- if (ret < 0)
- goto fail;
- ret = opt_match_per_stream_int(ost, &o->fix_sub_duration_heartbeat,
- oc, st, &ost->fix_sub_duration_heartbeat);
- if (ret < 0)
- goto fail;
+ opt_match_per_stream_int(ost, &o->fix_sub_duration_heartbeat,
+ oc, st, &ost->fix_sub_duration_heartbeat);
if (oc->oformat->flags & AVFMT_GLOBALHEADER && ost->enc_ctx)
ost->enc_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
- ret = opt_match_per_stream_int(ost, &o->copy_initial_nonkeyframes,
- oc, st, &ms->copy_initial_nonkeyframes);
- if (ret < 0)
- goto fail;
-
+ opt_match_per_stream_int(ost, &o->copy_initial_nonkeyframes,
+ oc, st, &ms->copy_initial_nonkeyframes);
switch (type) {
case AVMEDIA_TYPE_VIDEO: ret = new_stream_video (mux, o, ost, &keep_pix_fmt, &vsync_method); break;
case AVMEDIA_TYPE_AUDIO: ret = new_stream_audio (mux, o, ost); break;
@@ -3036,9 +2943,7 @@ static int set_dispositions(Muxer *mux, const OptionsContext *o)
nb_streams[ost->type + 1]++;
- ret = opt_match_per_stream_str(ost, &o->disposition, ctx, ost->st, &dispositions[i]);
- if (ret < 0)
- goto finish;
+ opt_match_per_stream_str(ost, &o->disposition, ctx, ost->st, &dispositions[i]);
have_manual |= !!dispositions[i];
@@ -3183,12 +3088,9 @@ static int process_forced_keyframes(Muxer *mux, const OptionsContext *o)
for (int i = 0; i < mux->of.nb_streams; i++) {
OutputStream *ost = mux->of.streams[i];
const char *forced_keyframes = NULL;
- int ret;
- ret = opt_match_per_stream_str(ost, &o->forced_key_frames,
- mux->fc, ost->st, &forced_keyframes);
- if (ret < 0)
- return ret;
+ opt_match_per_stream_str(ost, &o->forced_key_frames,
+ mux->fc, ost->st, &forced_keyframes);
if (!(ost->type == AVMEDIA_TYPE_VIDEO &&
ost->enc_ctx && forced_keyframes))
diff --git a/fftools/ffmpeg_opt.c b/fftools/ffmpeg_opt.c
index c32d3ddc55..f6df6ae952 100644
--- a/fftools/ffmpeg_opt.c
+++ b/fftools/ffmpeg_opt.c
@@ -101,6 +101,8 @@ static void uninit_options(OptionsContext *o)
SpecifierOptList *so = dst;
for (int i = 0; i < so->nb_opt; i++) {
av_freep(&so->opt[i].specifier);
+ if (po->flags & OPT_FLAG_PERSTREAM)
+ stream_specifier_uninit(&so->opt[i].stream_spec);
if (po->type == OPT_TYPE_STRING)
av_freep(&so->opt[i].u.str);
}
@@ -164,22 +166,21 @@ const char *opt_match_per_type_str(const SpecifierOptList *sol,
return NULL;
}
-static int opt_match_per_stream(void *logctx, enum OptionType type,
- const SpecifierOptList *sol,
- AVFormatContext *fc, AVStream *st)
+static unsigned opt_match_per_stream(void *logctx, enum OptionType type,
+ const SpecifierOptList *sol,
+ AVFormatContext *fc, AVStream *st)
{
int matches = 0, match_idx = -1;
av_assert0((type == sol->type) || !sol->nb_opt);
for (int i = 0; i < sol->nb_opt; i++) {
- const char *spec = sol->opt[i].specifier;
- int ret = check_stream_specifier(fc, st, spec);
- if (ret > 0) {
+ const StreamSpecifier *ss = &sol->opt[i].stream_spec;
+
+ if (stream_specifier_match(ss, fc, st, logctx)) {
match_idx = i;
matches++;
- } else if (ret < 0)
- return ret;
+ }
}
if (matches > 1 && sol->opt_canon) {
@@ -216,17 +217,12 @@ static int opt_match_per_stream(void *logctx, enum OptionType type,
}
#define OPT_MATCH_PER_STREAM(name, type, opt_type, m) \
-int opt_match_per_stream_ ## name(void *logctx, const SpecifierOptList *sol, \
- AVFormatContext *fc, AVStream *st, type *out) \
+void opt_match_per_stream_ ## name(void *logctx, const SpecifierOptList *sol, \
+ AVFormatContext *fc, AVStream *st, type *out) \
{ \
- int ret = opt_match_per_stream(logctx, opt_type, sol, fc, st); \
- \
- if (ret <= 0) \
- return ret; \
- \
- *out = sol->opt[ret - 1].u.m; \
- \
- return 0; \
+ unsigned ret = opt_match_per_stream(logctx, opt_type, sol, fc, st); \
+ if (ret > 0) \
+ *out = sol->opt[ret - 1].u.m; \
}
OPT_MATCH_PER_STREAM(str, const char *, OPT_TYPE_STRING, str);
--
2.43.0
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 6+ messages in thread
* [FFmpeg-devel] [PATCH 6/6] fftools/ffmpeg: switch -map parsing to new stream specifier API
2024-08-10 17:16 [FFmpeg-devel] [PATCH 1/6] fftools/ffmpeg: replace MATCH_PER_STREAM_OPT(.., str, ..) with a function Anton Khirnov
` (3 preceding siblings ...)
2024-08-10 17:16 ` [FFmpeg-devel] [PATCH 5/6] fftools/ffmpeg: use new stream specifier API in opt_match_per_stream*() Anton Khirnov
@ 2024-08-10 17:16 ` Anton Khirnov
4 siblings, 0 replies; 6+ messages in thread
From: Anton Khirnov @ 2024-08-10 17:16 UTC (permalink / raw)
To: ffmpeg-devel
Makes optional map handling less hacky, fixes combining optional maps
with metadata matching on tags/values containing the '?' character/
Forward errors from stream specifier parsing, previously the code would
ignore them.
---
fftools/ffmpeg_opt.c | 54 ++++++++++++++++++++++++++++++--------------
1 file changed, 37 insertions(+), 17 deletions(-)
diff --git a/fftools/ffmpeg_opt.c b/fftools/ffmpeg_opt.c
index f6df6ae952..3cbf0795ac 100644
--- a/fftools/ffmpeg_opt.c
+++ b/fftools/ffmpeg_opt.c
@@ -427,22 +427,20 @@ static int opt_map(void *optctx, const char *opt, const char *arg)
{
OptionsContext *o = optctx;
StreamMap *m = NULL;
+ StreamSpecifier ss;
int i, negative = 0, file_idx, disabled = 0;
- int ret;
- char *map, *p;
- char *allow_unused;
+ int ret, allow_unused = 0;
+
+ memset(&ss, 0, sizeof(ss));
if (*arg == '-') {
negative = 1;
arg++;
}
- map = av_strdup(arg);
- if (!map)
- return AVERROR(ENOMEM);
- if (map[0] == '[') {
+ if (arg[0] == '[') {
/* this mapping refers to lavfi output */
- const char *c = map + 1;
+ const char *c = arg + 1;
ret = GROW_ARRAY(o->stream_maps, o->nb_stream_maps);
if (ret < 0)
@@ -451,33 +449,55 @@ static int opt_map(void *optctx, const char *opt, const char *arg)
m = &o->stream_maps[o->nb_stream_maps - 1];
m->linklabel = av_get_token(&c, "]");
if (!m->linklabel) {
- av_log(NULL, AV_LOG_ERROR, "Invalid output link label: %s.\n", map);
+ av_log(NULL, AV_LOG_ERROR, "Invalid output link label: %s.\n", arg);
ret = AVERROR(EINVAL);
goto fail;
}
} else {
- if (allow_unused = strchr(map, '?'))
- *allow_unused = 0;
- file_idx = strtol(map, &p, 0);
+ char *endptr;
+
+ file_idx = strtol(arg, &endptr, 0);
if (file_idx >= nb_input_files || file_idx < 0) {
av_log(NULL, AV_LOG_FATAL, "Invalid input file index: %d.\n", file_idx);
ret = AVERROR(EINVAL);
goto fail;
}
+ arg = endptr;
+
+ ret = stream_specifier_parse(&ss, *arg == ':' ? arg + 1 : arg, 1, NULL);
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Invalid stream specifier: %s\n", arg);
+ goto fail;
+ }
+
+ if (ss.remainder) {
+ if (!strcmp(ss.remainder, "?"))
+ allow_unused = 1;
+ else {
+ av_log(NULL, AV_LOG_ERROR, "Trailing garbage after stream specifier: %s\n",
+ ss.remainder);
+ ret = AVERROR(EINVAL);
+ goto fail;
+ }
+ }
+
if (negative)
/* disable some already defined maps */
for (i = 0; i < o->nb_stream_maps; i++) {
m = &o->stream_maps[i];
if (file_idx == m->file_index &&
- check_stream_specifier(input_files[m->file_index]->ctx,
+ stream_specifier_match(&ss,
+ input_files[m->file_index]->ctx,
input_files[m->file_index]->ctx->streams[m->stream_index],
- *p == ':' ? p + 1 : p) > 0)
+ NULL))
m->disabled = 1;
}
else
for (i = 0; i < input_files[file_idx]->nb_streams; i++) {
- if (check_stream_specifier(input_files[file_idx]->ctx, input_files[file_idx]->ctx->streams[i],
- *p == ':' ? p + 1 : p) <= 0)
+ if (!stream_specifier_match(&ss,
+ input_files[file_idx]->ctx,
+ input_files[file_idx]->ctx->streams[i],
+ NULL))
continue;
if (input_files[file_idx]->streams[i]->user_set_discard == AVDISCARD_ALL) {
disabled = 1;
@@ -511,7 +531,7 @@ static int opt_map(void *optctx, const char *opt, const char *arg)
}
ret = 0;
fail:
- av_freep(&map);
+ stream_specifier_uninit(&ss);
return ret;
}
--
2.43.0
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2024-08-10 17:17 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-08-10 17:16 [FFmpeg-devel] [PATCH 1/6] fftools/ffmpeg: replace MATCH_PER_STREAM_OPT(.., str, ..) with a function Anton Khirnov
2024-08-10 17:16 ` [FFmpeg-devel] [PATCH 2/6] fftools/ffmpeg: replace remaining uses of MATCH_PER_STREAM_OPT() Anton Khirnov
2024-08-10 17:16 ` [FFmpeg-devel] [PATCH 3/6] fftools/cmdutils: put stream specifier handling back into cmdutils Anton Khirnov
2024-08-10 17:16 ` [FFmpeg-devel] [PATCH 4/6] fftools/cmdutils: split stream specifier parsing and matching Anton Khirnov
2024-08-10 17:16 ` [FFmpeg-devel] [PATCH 5/6] fftools/ffmpeg: use new stream specifier API in opt_match_per_stream*() Anton Khirnov
2024-08-10 17:16 ` [FFmpeg-devel] [PATCH 6/6] fftools/ffmpeg: switch -map parsing to new stream specifier API Anton Khirnov
Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
This inbox may be cloned and mirrored by anyone:
git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git
# If you have public-inbox 1.1+ installed, you may
# initialize and index your mirror using the following commands:
public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \
ffmpegdev@gitmailbox.com
public-inbox-index ffmpegdev
Example config snippet for mirrors.
AGPL code for this site: git clone https://public-inbox.org/public-inbox.git