diff --git a/avconv.c b/avconv.c index 444e74d8d9..dd998ab40c 100644 --- a/avconv.c +++ b/avconv.c @@ -2345,22 +2345,13 @@ static int64_t getmaxrss(void) #endif } -static void parse_cpuflags(int argc, char **argv, const OptionDef *options) -{ - int idx = locate_option(argc, argv, options, "cpuflags"); - if (idx && argv[idx + 1]) - opt_cpuflags(NULL, "cpuflags", argv[idx + 1]); -} - int main(int argc, char **argv) { - OptionsContext o = { 0 }; + int ret; int64_t ti; atexit(exit_program); - reset_options(&o); - av_log_set_flags(AV_LOG_SKIP_REPEATED); parse_loglevel(argc, argv, options); @@ -2374,10 +2365,10 @@ int main(int argc, char **argv) show_banner(); - parse_cpuflags(argc, argv, options); - - /* parse options */ - parse_options(&o, argc, argv, options, opt_output_file); + /* parse options and open all input/output files */ + ret = avconv_parse_options(argc, argv); + if (ret < 0) + exit(1); if (nb_output_files <= 0 && nb_input_files == 0) { show_usage(); diff --git a/avconv.h b/avconv.h index 11e846261f..defdf59c4a 100644 --- a/avconv.h +++ b/avconv.h @@ -67,6 +67,8 @@ typedef struct MetadataMap { } MetadataMap; typedef struct OptionsContext { + OptionGroup *g; + /* input/output options */ int64_t start_time; const char *format; @@ -361,4 +363,6 @@ int configure_output_filter(FilterGraph *fg, OutputFilter *ofilter, AVFilterInOu int ist_in_filtergraph(FilterGraph *fg, InputStream *ist); FilterGraph *init_simple_filtergraph(InputStream *ist, OutputStream *ost); +int avconv_parse_options(int argc, char **argv); + #endif /* AVCONV_H */ diff --git a/avconv_opt.c b/avconv_opt.c index a4e64e6320..7f9e5e7415 100644 --- a/avconv_opt.c +++ b/avconv_opt.c @@ -78,7 +78,7 @@ static int intra_dc_precision = 8; static int using_stdin = 0; static int input_sync; -void reset_options(OptionsContext *o) +static void uninit_options(OptionsContext *o) { const OptionDef *po = options; int i; @@ -107,19 +107,18 @@ void reset_options(OptionsContext *o) av_freep(&o->stream_maps); av_freep(&o->meta_data_maps); av_freep(&o->streamid_map); +} +static void init_options(OptionsContext *o) +{ memset(o, 0, sizeof(*o)); o->mux_max_delay = 0.7; o->recording_time = INT64_MAX; o->limit_filesize = UINT64_MAX; o->chapters_input_file = INT_MAX; - - uninit_opts(); - init_opts(); } - static double parse_frame_aspect_ratio(const char *arg) { int x = 0, y = 0; @@ -449,7 +448,7 @@ static void add_input_streams(OptionsContext *o, AVFormatContext *ic) ist->file_index = nb_input_files; ist->discard = 1; st->discard = AVDISCARD_ALL; - ist->opts = filter_codec_opts(codec_opts, ist->st->codec->codec_id, ic, st, NULL); + ist->opts = filter_codec_opts(o->g->codec_opts, ist->st->codec->codec_id, ic, st, NULL); ist->ts_scale = 1.0; MATCH_PER_STREAM_OPT(ts_scale, dbl, ist->ts_scale, ic, st); @@ -545,9 +544,8 @@ static void dump_attachment(AVStream *st, const char *filename) avio_close(out); } -static int opt_input_file(void *optctx, const char *opt, const char *filename) +static int open_input_file(OptionsContext *o, const char *filename) { - OptionsContext *o = optctx; AVFormatContext *ic; AVInputFormat *file_iformat = NULL; int err, i, ret; @@ -577,7 +575,7 @@ static int opt_input_file(void *optctx, const char *opt, const char *filename) } if (o->nb_audio_sample_rate) { snprintf(buf, sizeof(buf), "%d", o->audio_sample_rate[o->nb_audio_sample_rate - 1].u.i); - av_dict_set(&format_opts, "sample_rate", buf, 0); + av_dict_set(&o->g->format_opts, "sample_rate", buf, 0); } if (o->nb_audio_channels) { /* because we set audio_channels based on both the "ac" and @@ -588,7 +586,7 @@ static int opt_input_file(void *optctx, const char *opt, const char *filename) AV_OPT_SEARCH_FAKE_OBJ)) { snprintf(buf, sizeof(buf), "%d", o->audio_channels[o->nb_audio_channels - 1].u.i); - av_dict_set(&format_opts, "channels", buf, 0); + av_dict_set(&o->g->format_opts, "channels", buf, 0); } } if (o->nb_frame_rates) { @@ -597,33 +595,33 @@ static int opt_input_file(void *optctx, const char *opt, const char *filename) if (file_iformat && file_iformat->priv_class && av_opt_find(&file_iformat->priv_class, "framerate", NULL, 0, AV_OPT_SEARCH_FAKE_OBJ)) { - av_dict_set(&format_opts, "framerate", + av_dict_set(&o->g->format_opts, "framerate", o->frame_rates[o->nb_frame_rates - 1].u.str, 0); } } if (o->nb_frame_sizes) { - av_dict_set(&format_opts, "video_size", o->frame_sizes[o->nb_frame_sizes - 1].u.str, 0); + av_dict_set(&o->g->format_opts, "video_size", o->frame_sizes[o->nb_frame_sizes - 1].u.str, 0); } if (o->nb_frame_pix_fmts) - av_dict_set(&format_opts, "pixel_format", o->frame_pix_fmts[o->nb_frame_pix_fmts - 1].u.str, 0); + av_dict_set(&o->g->format_opts, "pixel_format", o->frame_pix_fmts[o->nb_frame_pix_fmts - 1].u.str, 0); ic->flags |= AVFMT_FLAG_NONBLOCK; ic->interrupt_callback = int_cb; /* open the input file with generic libav function */ - err = avformat_open_input(&ic, filename, file_iformat, &format_opts); + err = avformat_open_input(&ic, filename, file_iformat, &o->g->format_opts); if (err < 0) { print_error(filename, err); exit(1); } - assert_avoptions(format_opts); + assert_avoptions(o->g->format_opts); /* apply forced codec ids */ for (i = 0; i < ic->nb_streams; i++) choose_decoder(o, ic, ic->streams[i]); /* Set AVCodecContext options for avformat_find_stream_info */ - opts = setup_find_stream_info_opts(ic, codec_opts); + opts = setup_find_stream_info_opts(ic, o->g->codec_opts); orig_nb_streams = ic->nb_streams; /* If not enough info to get the stream parameters, we decode the @@ -680,7 +678,6 @@ static int opt_input_file(void *optctx, const char *opt, const char *filename) av_dict_free(&opts[i]); av_freep(&opts); - reset_options(o); return 0; } @@ -777,7 +774,7 @@ static OutputStream *new_output_stream(OptionsContext *o, AVFormatContext *oc, e AVIOContext *s = NULL; char *buf = NULL, *arg = NULL, *preset = NULL; - ost->opts = filter_codec_opts(codec_opts, ost->enc->id, oc, st, ost->enc); + ost->opts = filter_codec_opts(o->g->codec_opts, ost->enc->id, oc, st, ost->enc); MATCH_PER_STREAM_OPT(presets, str, preset, oc, st); if (preset && (!(ret = get_preset_file_2(preset, ost->enc->name, &s)))) { @@ -845,7 +842,7 @@ static OutputStream *new_output_stream(OptionsContext *o, AVFormatContext *oc, e if (oc->oformat->flags & AVFMT_GLOBALHEADER) st->codec->flags |= CODEC_FLAG_GLOBAL_HEADER; - av_opt_get_int(sws_opts, "sws_flags", 0, &ost->sws_flags); + av_opt_get_int(o->g->sws_opts, "sws_flags", 0, &ost->sws_flags); ost->pix_fmts[0] = ost->pix_fmts[1] = AV_PIX_FMT_NONE; @@ -1169,9 +1166,8 @@ static int configure_complex_filters(void) return 0; } -void opt_output_file(void *optctx, const char *filename) +static int open_output_file(OptionsContext *o, const char *filename) { - OptionsContext *o = optctx; AVFormatContext *oc; int i, j, err; AVOutputFormat *file_oformat; @@ -1378,7 +1374,7 @@ loop_end: output_files[nb_output_files - 1]->start_time = o->start_time; output_files[nb_output_files - 1]->limit_filesize = o->limit_filesize; output_files[nb_output_files - 1]->shortest = o->shortest; - av_dict_copy(&output_files[nb_output_files - 1]->opts, format_opts, 0); + av_dict_copy(&output_files[nb_output_files - 1]->opts, o->g->format_opts, 0); /* check filename in case of an image number is expected */ if (oc->oformat->flags & AVFMT_NEEDNUMBER) { @@ -1500,7 +1496,7 @@ loop_end: } } - reset_options(o); + return 0; } static int opt_target(void *optctx, const char *opt, const char *arg) @@ -1858,6 +1854,94 @@ void show_usage(void) printf("\n"); } +enum OptGroup { + GROUP_OUTFILE, + GROUP_INFILE, +}; + +static const OptionGroupDef groups[] = { + [GROUP_OUTFILE] = { "output file", NULL }, + [GROUP_INFILE] = { "input file", "i" }, + { 0 }, +}; + +static int open_files(OptionGroupList *l, const char *inout, + int (*open_file)(OptionsContext*, const char*)) +{ + int i, ret; + + for (i = 0; i < l->nb_groups; i++) { + OptionGroup *g = &l->groups[i]; + OptionsContext o; + + init_options(&o); + o.g = g; + + ret = parse_optgroup(&o, g); + if (ret < 0) { + av_log(NULL, AV_LOG_ERROR, "Error parsing options for %s file " + "%s.\n", inout, g->arg); + return ret; + } + + av_log(NULL, AV_LOG_DEBUG, "Opening an %s file: %s.\n", inout, g->arg); + ret = open_file(&o, g->arg); + uninit_options(&o); + if (ret < 0) { + av_log(NULL, AV_LOG_ERROR, "Error opening %s file %s.\n", + inout, g->arg); + return ret; + } + av_log(NULL, AV_LOG_DEBUG, "Successfully openened the file.\n"); + } + + return 0; +} + +int avconv_parse_options(int argc, char **argv) +{ + OptionParseContext octx; + uint8_t error[128]; + int ret; + + memset(&octx, 0, sizeof(octx)); + + /* split the commandline into an internal representation */ + ret = split_commandline(&octx, argc, argv, options, groups); + if (ret < 0) { + av_log(NULL, AV_LOG_FATAL, "Error splitting the argument list: "); + goto fail; + } + + /* apply global options */ + ret = parse_optgroup(NULL, &octx.global_opts); + if (ret < 0) { + av_log(NULL, AV_LOG_FATAL, "Error parsing global options: "); + goto fail; + } + + /* open input files */ + ret = open_files(&octx.groups[GROUP_INFILE], "input", open_input_file); + if (ret < 0) { + av_log(NULL, AV_LOG_FATAL, "Error opening input files: "); + goto fail; + } + + /* open output files */ + ret = open_files(&octx.groups[GROUP_OUTFILE], "output", open_output_file); + if (ret < 0) { + av_log(NULL, AV_LOG_FATAL, "Error opening output files: "); + goto fail; + } + +fail: + uninit_parse_context(&octx); + if (ret < 0) { + av_strerror(ret, error, sizeof(error)); + av_log(NULL, AV_LOG_FATAL, "%s\n", error); + } + return ret; +} #define OFFSET(x) offsetof(OptionsContext, x) const OptionDef options[] = { @@ -1865,8 +1949,6 @@ const OptionDef options[] = { #include "cmdutils_common_opts.h" { "f", HAS_ARG | OPT_STRING | OPT_OFFSET, { .off = OFFSET(format) }, "force format", "fmt" }, - { "i", HAS_ARG | OPT_PERFILE, { .func_arg = opt_input_file }, - "input file name", "filename" }, { "y", OPT_BOOL, { &file_overwrite }, "overwrite output files" }, { "c", HAS_ARG | OPT_STRING | OPT_SPEC, { .off = OFFSET(codec_names) }, @@ -2048,7 +2130,5 @@ const OptionDef options[] = { { "dcodec", HAS_ARG | OPT_DATA | OPT_PERFILE | OPT_EXPERT, { .func_arg = opt_data_codec }, "force data codec ('copy' to copy stream)", "codec" }, - { "default", HAS_ARG | OPT_AUDIO | OPT_VIDEO | OPT_EXPERT, { .func_arg = opt_default }, - "generic catch all option", "" }, { NULL, }, };