* [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