X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=fftools%2Fffmpeg_opt.c;h=680f0f1dfb73e55779bafed6a55a3f18a6be1edf;hb=67e957b43a2fdc197018968b0adc2f6a9c04e961;hp=c44ed637302b54ff476414a11685d50ed7e2f112;hpb=f4cf6ba8c9646814af842a99335c6ee312ded299;p=ffmpeg diff --git a/fftools/ffmpeg_opt.c b/fftools/ffmpeg_opt.c index c44ed637302..680f0f1dfb7 100644 --- a/fftools/ffmpeg_opt.c +++ b/fftools/ffmpeg_opt.c @@ -1,3 +1,4 @@ + /* * ffmpeg option parsing * @@ -43,16 +44,80 @@ #define DEFAULT_PASS_LOGFILENAME_PREFIX "ffmpeg2pass" +#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" + +static const char *opt_name_codec_names[] = {"c", "codec", "acodec", "vcodec", "scodec", "dcodec", NULL}; +static const char *opt_name_audio_channels[] = {"ac", NULL}; +static const char *opt_name_audio_sample_rate[] = {"ar", NULL}; +static const char *opt_name_frame_rates[] = {"r", NULL}; +static const char *opt_name_frame_sizes[] = {"s", NULL}; +static const char *opt_name_frame_pix_fmts[] = {"pix_fmt", NULL}; +static const char *opt_name_ts_scale[] = {"itsscale", NULL}; +static const char *opt_name_hwaccels[] = {"hwaccel", NULL}; +static const char *opt_name_hwaccel_devices[] = {"hwaccel_device", NULL}; +static const char *opt_name_hwaccel_output_formats[] = {"hwaccel_output_format", NULL}; +static const char *opt_name_autorotate[] = {"autorotate", NULL}; +static const char *opt_name_max_frames[] = {"frames", "aframes", "vframes", "dframes", NULL}; +static const char *opt_name_bitstream_filters[] = {"bsf", "absf", "vbsf", NULL}; +static const char *opt_name_codec_tags[] = {"tag", "atag", "vtag", "stag", NULL}; +static const char *opt_name_sample_fmts[] = {"sample_fmt", NULL}; +static const char *opt_name_qscale[] = {"q", "qscale", NULL}; +static const char *opt_name_forced_key_frames[] = {"forced_key_frames", NULL}; +static const char *opt_name_force_fps[] = {"force_fps", NULL}; +static const char *opt_name_frame_aspect_ratios[] = {"aspect", NULL}; +static const char *opt_name_rc_overrides[] = {"rc_override", NULL}; +static const char *opt_name_intra_matrices[] = {"intra_matrix", NULL}; +static const char *opt_name_inter_matrices[] = {"inter_matrix", NULL}; +static const char *opt_name_chroma_intra_matrices[] = {"chroma_intra_matrix", NULL}; +static const char *opt_name_top_field_first[] = {"top", NULL}; +static const char *opt_name_presets[] = {"pre", "apre", "vpre", "spre", NULL}; +static const char *opt_name_copy_initial_nonkeyframes[] = {"copyinkfr", NULL}; +static const char *opt_name_copy_prior_start[] = {"copypriorss", NULL}; +static const char *opt_name_filters[] = {"filter", "af", "vf", NULL}; +static const char *opt_name_filter_scripts[] = {"filter_script", NULL}; +static const char *opt_name_reinit_filters[] = {"reinit_filter", NULL}; +static const char *opt_name_fix_sub_duration[] = {"fix_sub_duration", NULL}; +static const char *opt_name_canvas_sizes[] = {"canvas_size", NULL}; +static const char *opt_name_pass[] = {"pass", NULL}; +static const char *opt_name_passlogfiles[] = {"passlogfile", NULL}; +static const char *opt_name_max_muxing_queue_size[] = {"max_muxing_queue_size", NULL}; +static const char *opt_name_guess_layout_max[] = {"guess_layout_max", NULL}; +static const char *opt_name_apad[] = {"apad", NULL}; +static const char *opt_name_discard[] = {"discard", NULL}; +static const char *opt_name_disposition[] = {"disposition", NULL}; +static const char *opt_name_time_bases[] = {"time_base", NULL}; +static const char *opt_name_enc_time_bases[] = {"enc_time_base", NULL}; + +#define WARN_MULTIPLE_OPT_USAGE(name, type, so, st)\ +{\ + char namestr[128] = "";\ + const char *spec = so->specifier && so->specifier[0] ? so->specifier : "";\ + for (i = 0; opt_name_##name[i]; i++)\ + av_strlcatf(namestr, sizeof(namestr), "-%s%s", opt_name_##name[i], opt_name_##name[i+1] ? (opt_name_##name[i+2] ? ", " : " or ") : "");\ + 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, opt_name_##name[0], spec[0] ? ":" : "", spec, so->u.type);\ +} + #define MATCH_PER_STREAM_OPT(name, type, outvar, fmtctx, st)\ {\ - int i, ret;\ + int i, ret, matches = 0;\ + SpecifierOpt *so;\ for (i = 0; i < o->nb_ ## name; i++) {\ char *spec = o->name[i].specifier;\ - if ((ret = check_stream_specifier(fmtctx, st, spec)) > 0)\ + if ((ret = check_stream_specifier(fmtctx, st, spec)) > 0) {\ outvar = o->name[i].u.type;\ - else if (ret < 0)\ + so = &o->name[i];\ + matches++;\ + } else if (ret < 0)\ exit_program(1);\ }\ + if (matches > 1)\ + WARN_MULTIPLE_OPT_USAGE(name, type, so, st);\ } #define MATCH_PER_TYPE_OPT(name, type, outvar, fmtctx, mediatype)\ @@ -71,9 +136,6 @@ const HWAccel hwaccels[] = { #endif #if CONFIG_LIBMFX { "qsv", qsv_init, HWACCEL_QSV, AV_PIX_FMT_QSV }, -#endif -#if CONFIG_CUVID - { "cuvid", cuvid_init, HWACCEL_CUVID, AV_PIX_FMT_CUDA }, #endif { 0 }, }; @@ -171,14 +233,11 @@ static void init_options(OptionsContext *o) static int show_hwaccels(void *optctx, const char *opt, const char *arg) { enum AVHWDeviceType type = AV_HWDEVICE_TYPE_NONE; - int i; printf("Hardware acceleration methods:\n"); while ((type = av_hwdevice_iterate_types(type)) != AV_HWDEVICE_TYPE_NONE) printf("%s\n", av_hwdevice_get_type_name(type)); - for (i = 0; hwaccels[i].name; i++) - printf("%s\n", hwaccels[i].name); printf("\n"); return 0; } @@ -268,7 +327,7 @@ static int opt_map(void *optctx, const char *opt, const char *arg) { OptionsContext *o = optctx; StreamMap *m = NULL; - int i, negative = 0, file_idx; + int i, negative = 0, file_idx, disabled = 0; int sync_file_idx = -1, sync_stream_idx = 0; char *p, *sync; char *map; @@ -303,6 +362,11 @@ static int opt_map(void *optctx, const char *opt, const char *arg) "match any streams.\n", arg); exit_program(1); } + if (input_streams[input_files[sync_file_idx]->ist_index + sync_stream_idx]->user_set_discard == AVDISCARD_ALL) { + av_log(NULL, AV_LOG_FATAL, "Sync stream specification in map %s matches a disabled input " + "stream.\n", arg); + exit_program(1); + } } @@ -339,6 +403,10 @@ static int opt_map(void *optctx, const char *opt, const char *arg) if (check_stream_specifier(input_files[file_idx]->ctx, input_files[file_idx]->ctx->streams[i], *p == ':' ? p + 1 : p) <= 0) continue; + if (input_streams[input_files[file_idx]->ist_index + i]->user_set_discard == AVDISCARD_ALL) { + disabled = 1; + continue; + } GROW_ARRAY(o->stream_maps, o->nb_stream_maps); m = &o->stream_maps[o->nb_stream_maps - 1]; @@ -358,6 +426,10 @@ static int opt_map(void *optctx, const char *opt, const char *arg) if (!m) { if (allow_unused) { av_log(NULL, AV_LOG_VERBOSE, "Stream map '%s' matches no streams; ignoring.\n", arg); + } else if (disabled) { + av_log(NULL, AV_LOG_FATAL, "Stream map '%s' matches disabled streams.\n" + "To ignore this, add a trailing '?' to the map.\n", arg); + exit_program(1); } else { av_log(NULL, AV_LOG_FATAL, "Stream map '%s' matches no streams.\n" "To ignore this, add a trailing '?' to the map.\n", arg); @@ -437,7 +509,8 @@ static int opt_map_channel(void *optctx, const char *opt, const char *arg) /* allow trailing ? to map_channel */ if (allow_unused = strchr(mapchan, '?')) *allow_unused = 0; - if (m->channel_idx < 0 || m->channel_idx >= st->codecpar->channels) { + if (m->channel_idx < 0 || m->channel_idx >= st->codecpar->channels || + input_streams[input_files[m->file_idx]->ist_index + m->stream_idx]->user_set_discard == AVDISCARD_ALL) { if (allow_unused) { av_log(NULL, AV_LOG_VERBOSE, "mapchan: invalid audio channel #%d.%d.%d\n", m->file_idx, m->stream_idx, m->channel_idx); @@ -746,6 +819,13 @@ static void add_input_streams(OptionsContext *o, AVFormatContext *ic) MATCH_PER_STREAM_OPT(discard, str, discard_str, ic, st); ist->user_set_discard = AVDISCARD_NONE; + + if ((o->video_disable && ist->st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) || + (o->audio_disable && ist->st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) || + (o->subtitle_disable && ist->st->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE) || + (o->data_disable && ist->st->codecpar->codec_type == AVMEDIA_TYPE_DATA)) + ist->user_set_discard = AVDISCARD_ALL; + if (discard_str && av_opt_eval_int(&cc, discard_opt, discard_str, &ist->user_set_discard) < 0) { av_log(NULL, AV_LOG_ERROR, "Error parsing discard %s.\n", discard_str); @@ -798,9 +878,28 @@ static void add_input_streams(OptionsContext *o, AVFormatContext *ic) MATCH_PER_STREAM_OPT(top_field_first, i, ist->top_field_first, ic, st); MATCH_PER_STREAM_OPT(hwaccels, str, hwaccel, ic, st); + MATCH_PER_STREAM_OPT(hwaccel_output_formats, str, + hwaccel_output_format, ic, st); + + if (!hwaccel_output_format && hwaccel && !strcmp(hwaccel, "cuvid")) { + av_log(NULL, AV_LOG_WARNING, + "WARNING: defaulting hwaccel_output_format to cuda for compatibility " + "with old commandlines. This behaviour is DEPRECATED and will be removed " + "in the future. Please explicitly set \"-hwaccel_output_format cuda\".\n"); + ist->hwaccel_output_format = AV_PIX_FMT_CUDA; + } else if (hwaccel_output_format) { + ist->hwaccel_output_format = av_get_pix_fmt(hwaccel_output_format); + if (ist->hwaccel_output_format == AV_PIX_FMT_NONE) { + av_log(NULL, AV_LOG_FATAL, "Unrecognised hwaccel output " + "format: %s", hwaccel_output_format); + } + } else { + ist->hwaccel_output_format = AV_PIX_FMT_NONE; + } + if (hwaccel) { // The NVDEC hwaccels use a CUDA device, so remap the name here. - if (!strcmp(hwaccel, "nvdec")) + if (!strcmp(hwaccel, "nvdec") || !strcmp(hwaccel, "cuvid")) hwaccel = "cuda"; if (!strcmp(hwaccel, "none")) @@ -834,8 +933,6 @@ static void add_input_streams(OptionsContext *o, AVFormatContext *ic) AV_HWDEVICE_TYPE_NONE) av_log(NULL, AV_LOG_FATAL, "%s ", av_hwdevice_get_type_name(type)); - for (i = 0; hwaccels[i].name; i++) - av_log(NULL, AV_LOG_FATAL, "%s ", hwaccels[i].name); av_log(NULL, AV_LOG_FATAL, "\n"); exit_program(1); } @@ -849,18 +946,6 @@ static void add_input_streams(OptionsContext *o, AVFormatContext *ic) exit_program(1); } - MATCH_PER_STREAM_OPT(hwaccel_output_formats, str, - hwaccel_output_format, ic, st); - if (hwaccel_output_format) { - ist->hwaccel_output_format = av_get_pix_fmt(hwaccel_output_format); - if (ist->hwaccel_output_format == AV_PIX_FMT_NONE) { - av_log(NULL, AV_LOG_FATAL, "Unrecognised hwaccel output " - "format: %s", hwaccel_output_format); - } - } else { - ist->hwaccel_output_format = AV_PIX_FMT_NONE; - } - ist->hwaccel_pix_fmt = AV_PIX_FMT_NONE; break; @@ -910,7 +995,7 @@ static void assert_file_overwrite(const char *filename) if (!file_overwrite) { if (proto_name && !strcmp(proto_name, "file") && avio_check(filename, 0) == 0) { if (stdin_interaction && !no_file_overwrite) { - fprintf(stderr,"File '%s' already exists. Overwrite ? [y/N] ", filename); + fprintf(stderr,"File '%s' already exists. Overwrite? [y/N] ", filename); fflush(stderr); term_exit(); signal(SIGINT, SIG_DFL); @@ -1149,8 +1234,10 @@ static int open_input_file(OptionsContext *o, const char *filename) int dts_heuristic = 0; for (i=0; inb_streams; i++) { const AVCodecParameters *par = ic->streams[i]->codecpar; - if (par->video_delay) + if (par->video_delay) { dts_heuristic = 1; + break; + } } if (dts_heuristic) { seek_timestamp -= 3*AV_TIME_BASE / 23; @@ -2171,7 +2258,10 @@ static int open_output_file(OptionsContext *o, const char *filename) for (i = 0; i < nb_input_streams; i++) { int new_area; ist = input_streams[i]; - new_area = ist->st->codecpar->width * ist->st->codecpar->height + 100000000*!!ist->st->codec_info_nb_frames; + new_area = ist->st->codecpar->width * ist->st->codecpar->height + 100000000*!!ist->st->codec_info_nb_frames + + 5000000*!!(ist->st->disposition & AV_DISPOSITION_DEFAULT); + if (ist->user_set_discard == AVDISCARD_ALL) + continue; if((qcr!=MKTAG('A', 'P', 'I', 'C')) && (ist->st->disposition & AV_DISPOSITION_ATTACHED_PIC)) new_area = 1; if (ist->st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && @@ -2192,7 +2282,10 @@ static int open_output_file(OptionsContext *o, const char *filename) for (i = 0; i < nb_input_streams; i++) { int score; ist = input_streams[i]; - score = ist->st->codecpar->channels + 100000000*!!ist->st->codec_info_nb_frames; + score = ist->st->codecpar->channels + 100000000*!!ist->st->codec_info_nb_frames + + 5000000*!!(ist->st->disposition & AV_DISPOSITION_DEFAULT); + if (ist->user_set_discard == AVDISCARD_ALL) + continue; if (ist->st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && score > best_score) { best_score = score; @@ -2214,6 +2307,8 @@ static int open_output_file(OptionsContext *o, const char *filename) AVCodec const *output_codec = avcodec_find_encoder(oc->oformat->subtitle_codec); int input_props = 0, output_props = 0; + if (input_streams[i]->user_set_discard == AVDISCARD_ALL) + continue; if (output_codec) output_descriptor = avcodec_descriptor_get(output_codec->id); if (input_descriptor) @@ -2235,6 +2330,8 @@ static int open_output_file(OptionsContext *o, const char *filename) if (!o->data_disable ) { enum AVCodecID codec_id = av_guess_codec(oc->oformat, NULL, filename, NULL, AVMEDIA_TYPE_DATA); for (i = 0; codec_id != AV_CODEC_ID_NONE && i < nb_input_streams; i++) { + if (input_streams[i]->user_set_discard == AVDISCARD_ALL) + continue; if (input_streams[i]->st->codecpar->codec_type == AVMEDIA_TYPE_DATA && input_streams[i]->st->codecpar->codec_id == codec_id ) new_data_stream(o, oc, i); @@ -2273,6 +2370,11 @@ loop_end: int src_idx = input_files[map->file_index]->ist_index + map->stream_index; ist = input_streams[input_files[map->file_index]->ist_index + map->stream_index]; + if (ist->user_set_discard == AVDISCARD_ALL) { + av_log(NULL, AV_LOG_FATAL, "Stream #%d:%d is disabled and cannot be mapped.\n", + map->file_index, map->stream_index); + exit_program(1); + } if(o->subtitle_disable && ist->st->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE) continue; if(o-> audio_disable && ist->st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) @@ -2330,12 +2432,14 @@ loop_end: o->attachments[i]); exit_program(1); } - if (!(attachment = av_malloc(len))) { - av_log(NULL, AV_LOG_FATAL, "Attachment %s too large to fit into memory.\n", + if (len > INT_MAX - AV_INPUT_BUFFER_PADDING_SIZE || + !(attachment = av_malloc(len + AV_INPUT_BUFFER_PADDING_SIZE))) { + av_log(NULL, AV_LOG_FATAL, "Attachment %s too large.\n", o->attachments[i]); exit_program(1); } avio_read(pb, attachment, len); + memset(attachment + len, 0, AV_INPUT_BUFFER_PADDING_SIZE); ost = new_attachment_stream(o, oc, -1); ost->stream_copy = 0; @@ -2727,13 +2831,14 @@ static int opt_target(void *optctx, const char *opt, const char *arg) } else { /* Try to determine PAL/NTSC by peeking in the input files */ if (nb_input_files) { - int i, j, fr; + int i, j; for (j = 0; j < nb_input_files; j++) { for (i = 0; i < input_files[j]->nb_streams; i++) { AVStream *st = input_files[j]->ctx->streams[i]; + int64_t fr; if (st->codecpar->codec_type != AVMEDIA_TYPE_VIDEO) continue; - fr = st->time_base.den * 1000 / st->time_base.num; + fr = st->time_base.den * 1000LL / st->time_base.num; if (fr == 25000) { norm = PAL; break; @@ -2963,8 +3068,11 @@ static int opt_preset(void *optctx, const char *opt, const char *arg) static int opt_old2new(void *optctx, const char *opt, const char *arg) { OptionsContext *o = optctx; + int ret; char *s = av_asprintf("%s:%c", opt + 1, *opt); - int ret = parse_option(o, s, arg, options); + if (!s) + return AVERROR(ENOMEM); + ret = parse_option(o, s, arg, options); av_free(s); return ret; } @@ -2995,6 +3103,8 @@ static int opt_qscale(void *optctx, const char *opt, const char *arg) return parse_option(o, "q:v", arg, options); } s = av_asprintf("q%s", opt + 6); + if (!s) + return AVERROR(ENOMEM); ret = parse_option(o, s, arg, options); av_free(s); return ret; @@ -3039,8 +3149,11 @@ static int opt_vsync(void *optctx, const char *opt, const char *arg) static int opt_timecode(void *optctx, const char *opt, const char *arg) { OptionsContext *o = optctx; + int ret; char *tcr = av_asprintf("timecode=%s", arg); - int ret = parse_option(o, "metadata:g", tcr, options); + if (!tcr) + return AVERROR(ENOMEM); + ret = parse_option(o, "metadata:g", tcr, options); if (ret >= 0) ret = av_dict_set(&o->g->codec_opts, "gop_timecode", arg, 0); av_free(tcr); @@ -3142,7 +3255,7 @@ void show_help_default(const char *opt, const char *arg) " -h -- print basic options\n" " -h long -- print more options\n" " -h full -- print all options (including all format and codec specific options, very long)\n" - " -h type=name -- print all options for the named decoder/encoder/demuxer/muxer/filter/bsf\n" + " -h type=name -- print all options for the named decoder/encoder/demuxer/muxer/filter/bsf/protocol\n" " See man %s for detailed description of the options.\n" "\n", program_name); @@ -3150,7 +3263,7 @@ void show_help_default(const char *opt, const char *arg) OPT_EXIT, 0, 0); show_help_options(options, "Global options (affect whole program " - "instead of just one file:", + "instead of just one file):", 0, per_file | OPT_EXIT | OPT_EXPERT, 0); if (show_advanced) show_help_options(options, "Advanced global options:", OPT_EXPERT, @@ -3226,6 +3339,7 @@ static int open_files(OptionGroupList *l, const char *inout, if (ret < 0) { av_log(NULL, AV_LOG_ERROR, "Error parsing options for %s file " "%s.\n", inout, g->arg); + uninit_options(&o); return ret; } @@ -3399,7 +3513,7 @@ const OptionDef options[] = { { "stdin", OPT_BOOL | OPT_EXPERT, { &stdin_interaction }, "enable or disable interaction on standard input" }, { "timelimit", HAS_ARG | OPT_EXPERT, { .func_arg = opt_timelimit }, - "set max runtime in seconds", "limit" }, + "set max runtime in seconds in CPU user time", "limit" }, { "dump", OPT_BOOL | OPT_EXPERT, { &do_pkt_dump }, "dump each input packet" }, { "hex", OPT_BOOL | OPT_EXPERT, { &do_hex_dump },