]> git.sesse.net Git - ffmpeg/blobdiff - ffmpeg_opt.c
configure: add decimate filter dependency on avcodec
[ffmpeg] / ffmpeg_opt.c
index ac72b45a893bb773704542d2f15cda0ada28af63..f337a9186c736e27186ba44d6583ed2cb4503bbc 100644 (file)
@@ -54,7 +54,6 @@
     }\
 }
 
-const char *pass_logfilename_prefix;
 char *vstats_filename;
 
 float audio_drift_threshold = 0.1;
@@ -72,7 +71,6 @@ int do_pkt_dump       = 0;
 int copy_ts           = 0;
 int copy_tb           = -1;
 int debug_ts          = 0;
-int opt_shortest      = 0;
 int exit_on_error     = 0;
 int print_stats       = 1;
 int qp_hist           = 0;
@@ -90,7 +88,6 @@ static int no_file_overwrite  = 0;
 static int video_discard      = 0;
 static int intra_dc_precision = 8;
 static int do_psnr            = 0;
-static int do_pass            = 0;
 static int input_sync;
 
 void reset_options(OptionsContext *o, int is_input)
@@ -143,55 +140,60 @@ void reset_options(OptionsContext *o, int is_input)
 }
 
 
-static int opt_frame_crop(const char *opt, const char *arg)
+static int opt_frame_crop(void *optctx, const char *opt, const char *arg)
 {
     av_log(NULL, AV_LOG_FATAL, "Option '%s' has been removed, use the crop filter instead\n", opt);
     return AVERROR(EINVAL);
 }
 
-static int opt_pad(const char *opt, const char *arg)
+static int opt_pad(void *optctx, const char *opt, const char *arg)
 {
     av_log(NULL, AV_LOG_FATAL, "Option '%s' has been removed, use the pad filter instead\n", opt);
     return -1;
 }
 
-static int opt_video_channel(const char *opt, const char *arg)
+static int opt_video_channel(void *optctx, const char *opt, const char *arg)
 {
     av_log(NULL, AV_LOG_WARNING, "This option is deprecated, use -channel.\n");
-    return opt_default("channel", arg);
+    return opt_default(optctx, "channel", arg);
     }
 
-static int opt_video_standard(const char *opt, const char *arg)
+static int opt_video_standard(void *optctx, const char *opt, const char *arg)
 {
     av_log(NULL, AV_LOG_WARNING, "This option is deprecated, use -standard.\n");
-    return opt_default("standard", arg);
+    return opt_default(optctx, "standard", arg);
 }
 
-static int opt_audio_codec(OptionsContext *o, const char *opt, const char *arg)
+static int opt_audio_codec(void *optctx, const char *opt, const char *arg)
 {
+    OptionsContext *o = optctx;
     audio_codec_name = arg;
     return parse_option(o, "codec:a", arg, options);
 }
 
-static int opt_video_codec(OptionsContext *o, const char *opt, const char *arg)
+static int opt_video_codec(void *optctx, const char *opt, const char *arg)
 {
+    OptionsContext *o = optctx;
     video_codec_name = arg;
     return parse_option(o, "codec:v", arg, options);
 }
 
-static int opt_subtitle_codec(OptionsContext *o, const char *opt, const char *arg)
+static int opt_subtitle_codec(void *optctx, const char *opt, const char *arg)
 {
+    OptionsContext *o = optctx;
     subtitle_codec_name = arg;
     return parse_option(o, "codec:s", arg, options);
 }
 
-static int opt_data_codec(OptionsContext *o, const char *opt, const char *arg)
+static int opt_data_codec(void *optctx, const char *opt, const char *arg)
 {
+    OptionsContext *o = optctx;
     return parse_option(o, "codec:d", arg, options);
 }
 
-static int opt_map(OptionsContext *o, const char *opt, const char *arg)
+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 sync_file_idx = -1, sync_stream_idx = 0;
@@ -286,16 +288,18 @@ static int opt_map(OptionsContext *o, const char *opt, const char *arg)
     return 0;
 }
 
-static int opt_attach(OptionsContext *o, const char *opt, const char *arg)
+static int opt_attach(void *optctx, const char *opt, const char *arg)
 {
+    OptionsContext *o = optctx;
     o->attachments = grow_array(o->attachments, sizeof(*o->attachments),
                                 &o->nb_attachments, o->nb_attachments + 1);
     o->attachments[o->nb_attachments - 1] = arg;
     return 0;
 }
 
-static int opt_map_channel(OptionsContext *o, const char *opt, const char *arg)
+static int opt_map_channel(void *optctx, const char *opt, const char *arg)
 {
+    OptionsContext *o = optctx;
     int n;
     AVStream *st;
     AudioChannelMap *m;
@@ -437,6 +441,8 @@ static int copy_metadata(char *outspec, char *inspec, AVFormatContext *oc, AVFor
             meta = &context->programs[index]->metadata;\
             break;\
         default: av_assert0(0);\
+        case 's':\
+            break;\
         }\
 
     SET_DICT(type_in, meta_in, ic, idx_in);
@@ -471,8 +477,9 @@ static int copy_metadata(char *outspec, char *inspec, AVFormatContext *oc, AVFor
     return 0;
 }
 
-static int opt_recording_timestamp(OptionsContext *o, const char *opt, const char *arg)
+static int opt_recording_timestamp(void *optctx, const char *opt, const char *arg)
 {
+    OptionsContext *o = optctx;
     char buf[128];
     int64_t recording_timestamp = parse_time_or_die(opt, arg, 0) / 1E6;
     struct tm time = *gmtime((time_t*)&recording_timestamp);
@@ -486,12 +493,22 @@ static int opt_recording_timestamp(OptionsContext *o, const char *opt, const cha
 
 static AVCodec *find_codec_or_die(const char *name, enum AVMediaType type, int encoder)
 {
+    const AVCodecDescriptor *desc;
     const char *codec_string = encoder ? "encoder" : "decoder";
     AVCodec *codec;
 
     codec = encoder ?
         avcodec_find_encoder_by_name(name) :
         avcodec_find_decoder_by_name(name);
+
+    if (!codec && (desc = avcodec_descriptor_get_by_name(name))) {
+        codec = encoder ? avcodec_find_encoder(desc->id) :
+                          avcodec_find_decoder(desc->id);
+        if (codec)
+            av_log(NULL, AV_LOG_VERBOSE, "Matched %s '%s' for codec '%s'.\n",
+                   codec_string, codec->name, desc->name);
+    }
+
     if (!codec) {
         av_log(NULL, AV_LOG_FATAL, "Unknown %s '%s'\n", codec_string, name);
         exit_program(1);
@@ -661,8 +678,9 @@ static void dump_attachment(AVStream *st, const char *filename)
     avio_close(out);
 }
 
-static int opt_input_file(OptionsContext *o, const char *opt, const char *filename)
+static int opt_input_file(void *optctx, const char *opt, const char *filename)
 {
+    OptionsContext *o = optctx;
     AVFormatContext *ic;
     AVInputFormat *file_iformat = NULL;
     int err, i, ret;
@@ -1020,6 +1038,7 @@ static OutputStream *new_video_stream(OptionsContext *o, AVFormatContext *oc, in
         char *frame_aspect_ratio = NULL, *frame_pix_fmt = NULL;
         char *intra_matrix = NULL, *inter_matrix = NULL;
         const char *filters = "null";
+        int do_pass = 0;
         int i;
 
         MATCH_PER_STREAM_OPT(frame_sizes, str, frame_size, oc, st);
@@ -1105,6 +1124,7 @@ static OutputStream *new_video_stream(OptionsContext *o, AVFormatContext *oc, in
             video_enc->flags|= CODEC_FLAG_PSNR;
 
         /* two pass mode */
+        MATCH_PER_STREAM_OPT(pass, i, do_pass, oc, st);
         if (do_pass) {
             if (do_pass & 1) {
                 video_enc->flags |= CODEC_FLAG_PASS1;
@@ -1114,6 +1134,11 @@ static OutputStream *new_video_stream(OptionsContext *o, AVFormatContext *oc, in
             }
         }
 
+        MATCH_PER_STREAM_OPT(passlogfiles, str, ost->logfile_prefix, oc, st);
+        if (ost->logfile_prefix &&
+            !(ost->logfile_prefix = av_strdup(ost->logfile_prefix)))
+            exit_program(1);
+
         MATCH_PER_STREAM_OPT(forced_key_frames, str, ost->forced_keyframes, oc, st);
         if (ost->forced_keyframes)
             ost->forced_keyframes = av_strdup(ost->forced_keyframes);
@@ -1218,12 +1243,23 @@ static OutputStream *new_subtitle_stream(OptionsContext *o, AVFormatContext *oc,
 
     MATCH_PER_STREAM_OPT(copy_initial_nonkeyframes, i, ost->copy_initial_nonkeyframes, oc, st);
 
+    if (!ost->stream_copy) {
+        char *frame_size = NULL;
+
+        MATCH_PER_STREAM_OPT(frame_sizes, str, frame_size, oc, st);
+        if (frame_size && av_parse_video_size(&subtitle_enc->width, &subtitle_enc->height, frame_size) < 0) {
+            av_log(NULL, AV_LOG_FATAL, "Invalid frame size: %s.\n", frame_size);
+            exit_program(1);
+        }
+    }
+
     return ost;
 }
 
 /* arg format is "output-stream-index:streamid-value". */
-static int opt_streamid(OptionsContext *o, const char *opt, const char *arg)
+static int opt_streamid(void *optctx, const char *opt, const char *arg)
 {
+    OptionsContext *o = optctx;
     int idx;
     char *p;
     char idx_str[16];
@@ -1349,9 +1385,6 @@ static void init_output_filter(OutputFilter *ofilter, OptionsContext *o,
                "cannot be used together.\n", ost->file_index, ost->index);
         exit_program(1);
     }
-    if (o->recording_time != INT64_MAX)
-        av_log(NULL, AV_LOG_WARNING,
-               "-t does not work with -filter_complex (yet).\n");
 
     if (configure_output_filter(ofilter->graph, ofilter, ofilter->out_tmp) < 0) {
         av_log(NULL, AV_LOG_FATAL, "Error configuring filter.\n");
@@ -1603,6 +1636,7 @@ loop_end:
         oc->duration = o->recording_time;
     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);
 
     /* check filename in case of an image number is expected */
@@ -1729,16 +1763,9 @@ loop_end:
     reset_options(o, 0);
 }
 
-/* same option as mencoder */
-static int opt_pass(const char *opt, const char *arg)
-{
-    do_pass = parse_number_or_die(opt, arg, OPT_INT, 1, 3);
-    return 0;
-}
-
-
-static int opt_target(OptionsContext *o, const char *opt, const char *arg)
+static int opt_target(void *optctx, const char *opt, const char *arg)
 {
+    OptionsContext *o = optctx;
     enum { PAL, NTSC, FILM, UNKNOWN } norm = UNKNOWN;
     static const char *const frame_rates[] = { "25", "30000/1001", "24000/1001" };
 
@@ -1791,19 +1818,19 @@ static int opt_target(OptionsContext *o, const char *opt, const char *arg)
 
         parse_option(o, "s", norm == PAL ? "352x288" : "352x240", options);
         parse_option(o, "r", frame_rates[norm], options);
-        opt_default("g", norm == PAL ? "15" : "18");
+        opt_default(NULL, "g", norm == PAL ? "15" : "18");
 
-        opt_default("b:v", "1150000");
-        opt_default("maxrate", "1150000");
-        opt_default("minrate", "1150000");
-        opt_default("bufsize", "327680"); // 40*1024*8;
+        opt_default(NULL, "b:v", "1150000");
+        opt_default(NULL, "maxrate", "1150000");
+        opt_default(NULL, "minrate", "1150000");
+        opt_default(NULL, "bufsize", "327680"); // 40*1024*8;
 
-        opt_default("b:a", "224000");
+        opt_default(NULL, "b:a", "224000");
         parse_option(o, "ar", "44100", options);
         parse_option(o, "ac", "2", options);
 
-        opt_default("packetsize", "2324");
-        opt_default("muxrate", "1411200"); // 2352 * 75 * 8;
+        opt_default(NULL, "packetsize", "2324");
+        opt_default(NULL, "muxrate", "1411200"); // 2352 * 75 * 8;
 
         /* We have to offset the PTS, so that it is consistent with the SCR.
            SCR starts at 36000, but the first two packs contain only padding
@@ -1820,19 +1847,18 @@ static int opt_target(OptionsContext *o, const char *opt, const char *arg)
         parse_option(o, "s", norm == PAL ? "480x576" : "480x480", options);
         parse_option(o, "r", frame_rates[norm], options);
         parse_option(o, "pix_fmt", "yuv420p", options);
-        opt_default("g", norm == PAL ? "15" : "18");
+        opt_default(NULL, "g", norm == PAL ? "15" : "18");
 
-        opt_default("b:v", "2040000");
-        opt_default("maxrate", "2516000");
-        opt_default("minrate", "0"); // 1145000;
-        opt_default("bufsize", "1835008"); // 224*1024*8;
-        opt_default("scan_offset", "1");
+        opt_default(NULL, "b:v", "2040000");
+        opt_default(NULL, "maxrate", "2516000");
+        opt_default(NULL, "minrate", "0"); // 1145000;
+        opt_default(NULL, "bufsize", "1835008"); // 224*1024*8;
+        opt_default(NULL, "scan_offset", "1");
 
-
-        opt_default("b:a", "224000");
+        opt_default(NULL, "b:a", "224000");
         parse_option(o, "ar", "44100", options);
 
-        opt_default("packetsize", "2324");
+        opt_default(NULL, "packetsize", "2324");
 
     } else if (!strcmp(arg, "dvd")) {
 
@@ -1843,17 +1869,17 @@ static int opt_target(OptionsContext *o, const char *opt, const char *arg)
         parse_option(o, "s", norm == PAL ? "720x576" : "720x480", options);
         parse_option(o, "r", frame_rates[norm], options);
         parse_option(o, "pix_fmt", "yuv420p", options);
-        opt_default("g", norm == PAL ? "15" : "18");
+        opt_default(NULL, "g", norm == PAL ? "15" : "18");
 
-        opt_default("b:v", "6000000");
-        opt_default("maxrate", "9000000");
-        opt_default("minrate", "0"); // 1500000;
-        opt_default("bufsize", "1835008"); // 224*1024*8;
+        opt_default(NULL, "b:v", "6000000");
+        opt_default(NULL, "maxrate", "9000000");
+        opt_default(NULL, "minrate", "0"); // 1500000;
+        opt_default(NULL, "bufsize", "1835008"); // 224*1024*8;
 
-        opt_default("packetsize", "2048");  // from www.mpucoder.com: DVD sectors contain 2048 bytes of data, this is also the size of one pack.
-        opt_default("muxrate", "10080000"); // from mplex project: data_rate = 1260000. mux_rate = data_rate * 8
+        opt_default(NULL, "packetsize", "2048");  // from www.mpucoder.com: DVD sectors contain 2048 bytes of data, this is also the size of one pack.
+        opt_default(NULL, "muxrate", "10080000"); // from mplex project: data_rate = 1260000. mux_rate = data_rate * 8
 
-        opt_default("b:a", "448000");
+        opt_default(NULL, "b:a", "448000");
         parse_option(o, "ar", "48000", options);
 
     } else if (!strncmp(arg, "dv", 2)) {
@@ -1875,14 +1901,14 @@ static int opt_target(OptionsContext *o, const char *opt, const char *arg)
     return 0;
 }
 
-static int opt_vstats_file(const char *opt, const char *arg)
+static int opt_vstats_file(void *optctx, const char *opt, const char *arg)
 {
     av_free (vstats_filename);
     vstats_filename = av_strdup (arg);
     return 0;
 }
 
-static int opt_vstats(const char *opt, const char *arg)
+static int opt_vstats(void *optctx, const char *opt, const char *arg)
 {
     char filename[40];
     time_t today2 = time(NULL);
@@ -1890,26 +1916,30 @@ static int opt_vstats(const char *opt, const char *arg)
 
     snprintf(filename, sizeof(filename), "vstats_%02d%02d%02d.log", today->tm_hour, today->tm_min,
              today->tm_sec);
-    return opt_vstats_file(opt, filename);
+    return opt_vstats_file(NULL, opt, filename);
 }
 
-static int opt_video_frames(OptionsContext *o, const char *opt, const char *arg)
+static int opt_video_frames(void *optctx, const char *opt, const char *arg)
 {
+    OptionsContext *o = optctx;
     return parse_option(o, "frames:v", arg, options);
 }
 
-static int opt_audio_frames(OptionsContext *o, const char *opt, const char *arg)
+static int opt_audio_frames(void *optctx, const char *opt, const char *arg)
 {
+    OptionsContext *o = optctx;
     return parse_option(o, "frames:a", arg, options);
 }
 
-static int opt_data_frames(OptionsContext *o, const char *opt, const char *arg)
+static int opt_data_frames(void *optctx, const char *opt, const char *arg)
 {
+    OptionsContext *o = optctx;
     return parse_option(o, "frames:d", arg, options);
 }
 
-static int opt_preset(OptionsContext *o, const char *opt, const char *arg)
+static int opt_preset(void *optctx, const char *opt, const char *arg)
 {
+    OptionsContext *o = optctx;
     FILE *f=NULL;
     char filename[1000], line[1000], tmp_line[1000];
     const char *codec_name = *opt == 'v' ? video_codec_name :
@@ -1941,7 +1971,7 @@ static int opt_preset(OptionsContext *o, const char *opt, const char *arg)
         else if (!strcmp(key, "vcodec")) opt_video_codec   (o, key, value);
         else if (!strcmp(key, "scodec")) opt_subtitle_codec(o, key, value);
         else if (!strcmp(key, "dcodec")) opt_data_codec    (o, key, value);
-        else if (opt_default(key, value) < 0) {
+        else if (opt_default(NULL, key, value) < 0) {
             av_log(NULL, AV_LOG_FATAL, "%s: Invalid option or argument: '%s', parsed as '%s' = '%s'\n",
                    filename, line, key, value);
             exit_program(1);
@@ -1953,35 +1983,28 @@ static int opt_preset(OptionsContext *o, const char *opt, const char *arg)
     return 0;
 }
 
-static int opt_passlogfile(const char *opt, const char *arg)
-{
-    pass_logfilename_prefix = arg;
-#if CONFIG_LIBX264_ENCODER
-    return opt_default(opt, arg);
-#else
-    return 0;
-#endif
-}
-
-static int opt_old2new(OptionsContext *o, const char *opt, const char *arg)
+static int opt_old2new(void *optctx, const char *opt, const char *arg)
 {
+    OptionsContext *o = optctx;
     char *s = av_asprintf("%s:%c", opt + 1, *opt);
     int ret = parse_option(o, s, arg, options);
     av_free(s);
     return ret;
 }
 
-static int opt_bitrate(OptionsContext *o, const char *opt, const char *arg)
+static int opt_bitrate(void *optctx, const char *opt, const char *arg)
 {
+    OptionsContext *o = optctx;
     if(!strcmp(opt, "b")){
         av_log(NULL, AV_LOG_WARNING, "Please use -b:a or -b:v, -b is ambiguous\n");
         return parse_option(o, "b:v", arg, options);
     }
-    return opt_default(opt, arg);
+    return opt_default(optctx, opt, arg);
 }
 
-static int opt_qscale(OptionsContext *o, const char *opt, const char *arg)
+static int opt_qscale(void *optctx, const char *opt, const char *arg)
 {
+    OptionsContext *o = optctx;
     char *s;
     int ret;
     if(!strcmp(opt, "qscale")){
@@ -1994,26 +2017,30 @@ static int opt_qscale(OptionsContext *o, const char *opt, const char *arg)
     return ret;
 }
 
-static int opt_profile(OptionsContext *o, const char *opt, const char *arg)
+static int opt_profile(void *optctx, const char *opt, const char *arg)
 {
+    OptionsContext *o = optctx;
     if(!strcmp(opt, "profile")){
         av_log(NULL, AV_LOG_WARNING, "Please use -profile:a or -profile:v, -profile is ambiguous\n");
         return parse_option(o, "profile:v", arg, options);
     }
-    return opt_default(opt, arg);
+    return opt_default(optctx, opt, arg);
+
 }
 
-static int opt_video_filters(OptionsContext *o, const char *opt, const char *arg)
+static int opt_video_filters(void *optctx, const char *opt, const char *arg)
 {
+    OptionsContext *o = optctx;
     return parse_option(o, "filter:v", arg, options);
 }
 
-static int opt_audio_filters(OptionsContext *o, const char *opt, const char *arg)
+static int opt_audio_filters(void *optctx, const char *opt, const char *arg)
 {
+    OptionsContext *o = optctx;
     return parse_option(o, "filter:a", arg, options);
 }
 
-static int opt_vsync(const char *opt, const char *arg)
+static int opt_vsync(void *optctx, const char *opt, const char *arg)
 {
     if      (!av_strcasecmp(arg, "cfr"))         video_sync_method = VSYNC_CFR;
     else if (!av_strcasecmp(arg, "vfr"))         video_sync_method = VSYNC_VFR;
@@ -2025,25 +2052,27 @@ static int opt_vsync(const char *opt, const char *arg)
     return 0;
 }
 
-static int opt_deinterlace(const char *opt, const char *arg)
+static int opt_deinterlace(void *optctx, const char *opt, const char *arg)
 {
     av_log(NULL, AV_LOG_WARNING, "-%s is deprecated, use -filter:v yadif instead\n", opt);
     do_deinterlace = 1;
     return 0;
 }
 
-static int opt_timecode(OptionsContext *o, const char *opt, const char *arg)
+static int opt_timecode(void *optctx, const char *opt, const char *arg)
 {
+    OptionsContext *o = optctx;
     char *tcr = av_asprintf("timecode=%s", arg);
     int ret = parse_option(o, "metadata:g", tcr, options);
     if (ret >= 0)
-        ret = opt_default("gop_timecode", arg);
+        ret = opt_default(optctx, "gop_timecode", arg);
     av_free(tcr);
     return ret;
 }
 
-static int opt_channel_layout(OptionsContext *o, const char *opt, const char *arg)
+static int opt_channel_layout(void *optctx, const char *opt, const char *arg)
 {
+    OptionsContext *o = optctx;
     char layout_str[32];
     char *stream_str;
     char *ac_str;
@@ -2056,7 +2085,7 @@ static int opt_channel_layout(OptionsContext *o, const char *opt, const char *ar
         return AVERROR(EINVAL);
     }
     snprintf(layout_str, sizeof(layout_str), "%"PRIu64, layout);
-    ret = opt_default(opt, layout_str);
+    ret = opt_default(NULL, opt, layout_str);
     if (ret < 0)
         return ret;
 
@@ -2077,12 +2106,13 @@ static int opt_channel_layout(OptionsContext *o, const char *opt, const char *ar
     return ret;
 }
 
-static int opt_audio_qscale(OptionsContext *o, const char *opt, const char *arg)
+static int opt_audio_qscale(void *optctx, const char *opt, const char *arg)
 {
+    OptionsContext *o = optctx;
     return parse_option(o, "q:a", arg, options);
 }
 
-static int opt_filter_complex(const char *opt, const char *arg)
+static int opt_filter_complex(void *optctx, const char *opt, const char *arg)
 {
     filtergraphs = grow_array(filtergraphs, sizeof(*filtergraphs),
                               &nb_filtergraphs, nb_filtergraphs + 1);
@@ -2093,41 +2123,70 @@ static int opt_filter_complex(const char *opt, const char *arg)
     return 0;
 }
 
-static int opt_help(const char *opt, const char *arg)
+void show_help_default(const char *opt, const char *arg)
 {
-    int flags = AV_OPT_FLAG_DECODING_PARAM | AV_OPT_FLAG_ENCODING_PARAM;
-    av_log_set_callback(log_callback_help);
+    /* per-file options have at least one of those set */
+    const int per_file = OPT_SPEC | OPT_OFFSET | OPT_PERFILE;
+    int show_advanced = 0, show_avoptions = 0;
+
+    if (opt) {
+        if (!strcmp(opt, "long"))
+            show_advanced = 1;
+        else if (!strcmp(opt, "full"))
+            show_advanced = show_avoptions = 1;
+        else
+            av_log(NULL, AV_LOG_ERROR, "Unknown help option '%s'.\n", opt);
+    }
+
     show_usage();
-    show_help_options(options, "Main options:\n",
-                      OPT_EXPERT | OPT_AUDIO | OPT_VIDEO | OPT_SUBTITLE | OPT_GRAB, 0);
-    show_help_options(options, "\nAdvanced options:\n",
-                      OPT_EXPERT | OPT_AUDIO | OPT_VIDEO | OPT_SUBTITLE | OPT_GRAB,
-                      OPT_EXPERT);
-    show_help_options(options, "\nVideo options:\n",
-                      OPT_EXPERT | OPT_AUDIO | OPT_VIDEO | OPT_GRAB,
-                      OPT_VIDEO);
-    show_help_options(options, "\nAdvanced Video options:\n",
-                      OPT_EXPERT | OPT_AUDIO | OPT_VIDEO | OPT_GRAB,
-                      OPT_VIDEO | OPT_EXPERT);
-    show_help_options(options, "\nAudio options:\n",
-                      OPT_EXPERT | OPT_AUDIO | OPT_VIDEO | OPT_GRAB,
-                      OPT_AUDIO);
-    show_help_options(options, "\nAdvanced Audio options:\n",
-                      OPT_EXPERT | OPT_AUDIO | OPT_VIDEO | OPT_GRAB,
-                      OPT_AUDIO | OPT_EXPERT);
-    show_help_options(options, "\nSubtitle options:\n",
-                      OPT_SUBTITLE | OPT_GRAB,
-                      OPT_SUBTITLE);
-    show_help_options(options, "\nAudio/Video grab options:\n",
-                      OPT_GRAB,
-                      OPT_GRAB);
+
+    printf("Getting help:\n"
+           "    -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"
+           "    See man %s for detailed description of the options.\n"
+           "\n", program_name);
+
+    show_help_options(options, "Print help / information / capabilities:",
+                      OPT_EXIT, 0, 0);
+
+    show_help_options(options, "Global options (affect whole program "
+                      "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,
+                          per_file | OPT_EXIT, 0);
+
+    show_help_options(options, "Per-file main options:", 0,
+                      OPT_EXPERT | OPT_AUDIO | OPT_VIDEO | OPT_SUBTITLE |
+                      OPT_EXIT, per_file);
+    if (show_advanced)
+        show_help_options(options, "Advanced per-file options:",
+                          OPT_EXPERT, OPT_AUDIO | OPT_VIDEO | OPT_SUBTITLE, per_file);
+
+    show_help_options(options, "Video options:",
+                      OPT_VIDEO, OPT_EXPERT | OPT_AUDIO, 0);
+    if (show_advanced)
+        show_help_options(options, "Advanced Video options:",
+                          OPT_EXPERT | OPT_VIDEO, OPT_AUDIO, 0);
+
+    show_help_options(options, "Audio options:",
+                      OPT_AUDIO, OPT_EXPERT | OPT_VIDEO, 0);
+    if (show_advanced)
+        show_help_options(options, "Advanced Audio options:",
+                          OPT_EXPERT | OPT_AUDIO, OPT_VIDEO, 0);
+    show_help_options(options, "Subtitle options:",
+                      OPT_SUBTITLE, 0, 0);
     printf("\n");
-    show_help_children(avcodec_get_class(), flags);
-    show_help_children(avformat_get_class(), flags);
-    show_help_children(sws_get_class(), flags);
-    show_help_children(swr_get_class(), AV_OPT_FLAG_AUDIO_PARAM);
 
-    return 0;
+    if (show_avoptions) {
+        int flags = AV_OPT_FLAG_DECODING_PARAM | AV_OPT_FLAG_ENCODING_PARAM;
+        show_help_children(avcodec_get_class(), flags);
+        show_help_children(avformat_get_class(), flags);
+        show_help_children(sws_get_class(), flags);
+        show_help_children(swr_get_class(), AV_OPT_FLAG_AUDIO_PARAM);
+        show_help_children(avfilter_get_class(), AV_OPT_FLAG_FILTERING_PARAM);
+    }
 }
 
 void show_usage(void)
@@ -2138,7 +2197,7 @@ void show_usage(void)
 }
 
 
-static int opt_progress(const char *opt, const char *arg)
+static int opt_progress(void *optctx, const char *opt, const char *arg)
 {
     AVIOContext *avio = NULL;
     int ret;
@@ -2159,147 +2218,261 @@ static int opt_progress(const char *opt, const char *arg)
 const OptionDef options[] = {
     /* main options */
 #include "cmdutils_common_opts.h"
-    { "f", HAS_ARG | OPT_STRING | OPT_OFFSET, {.off = OFFSET(format)}, "force format", "fmt" },
-    { "i", HAS_ARG | OPT_FUNC2, {(void*)opt_input_file}, "input file name", "filename" },
-    { "y", OPT_BOOL, {(void*)&file_overwrite}, "overwrite output files" },
-    { "n", OPT_BOOL, {(void*)&no_file_overwrite}, "do not overwrite output files" },
-    { "c", HAS_ARG | OPT_STRING | OPT_SPEC, {.off = OFFSET(codec_names)}, "codec name", "codec" },
-    { "codec", HAS_ARG | OPT_STRING | OPT_SPEC, {.off = OFFSET(codec_names)}, "codec name", "codec" },
-    { "pre", HAS_ARG | OPT_STRING | OPT_SPEC, {.off = OFFSET(presets)}, "preset name", "preset" },
-    { "map", HAS_ARG | OPT_EXPERT | OPT_FUNC2, {(void*)opt_map}, "set input stream mapping", "[-]input_file_id[:stream_specifier][,sync_file_id[:stream_specifier]]" },
-    { "map_channel", HAS_ARG | OPT_EXPERT | OPT_FUNC2, {(void*)opt_map_channel}, "map an audio channel from one stream to another", "file.stream.channel[:syncfile.syncstream]" },
-    { "map_metadata", HAS_ARG | OPT_STRING | OPT_SPEC, {.off = OFFSET(metadata_map)}, "set metadata information of outfile from infile",
-      "outfile[,metadata]:infile[,metadata]" },
-    { "map_chapters",  OPT_INT | HAS_ARG | OPT_EXPERT | OPT_OFFSET, {.off = OFFSET(chapters_input_file)},  "set chapters mapping", "input_file_index" },
-    { "t", HAS_ARG | OPT_TIME | OPT_OFFSET, {.off = OFFSET(recording_time)}, "record or transcode \"duration\" seconds of audio/video", "duration" },
-    { "fs", HAS_ARG | OPT_INT64 | OPT_OFFSET, {.off = OFFSET(limit_filesize)}, "set the limit file size in bytes", "limit_size" }, //
-    { "ss", HAS_ARG | OPT_TIME | OPT_OFFSET, {.off = OFFSET(start_time)}, "set the start time offset", "time_off" },
-    { "itsoffset", HAS_ARG | OPT_TIME | OPT_OFFSET, {.off = OFFSET(input_ts_offset)}, "set the input ts offset", "time_off" },
-    { "itsscale", HAS_ARG | OPT_DOUBLE | OPT_SPEC, {.off = OFFSET(ts_scale)}, "set the input ts scale", "scale" },
-    { "timestamp", HAS_ARG | OPT_FUNC2, {(void*)opt_recording_timestamp}, "set the recording timestamp ('now' to set the current time)", "time" },
-    { "metadata", HAS_ARG | OPT_STRING | OPT_SPEC, {.off = OFFSET(metadata)}, "add metadata", "string=string" },
-    { "dframes", HAS_ARG | OPT_FUNC2, {(void*)opt_data_frames}, "set the number of data frames to record", "number" },
-    { "benchmark", OPT_BOOL | OPT_EXPERT, {(void*)&do_benchmark},
-      "add timings for benchmarking" },
-    { "benchmark_all", OPT_BOOL | OPT_EXPERT, {(void*)&do_benchmark_all},
+    { "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" },
+    { "n",              OPT_BOOL,                                    {              &no_file_overwrite },
+        "do not overwrite output files" },
+    { "c",              HAS_ARG | OPT_STRING | OPT_SPEC,             { .off       = OFFSET(codec_names) },
+        "codec name", "codec" },
+    { "codec",          HAS_ARG | OPT_STRING | OPT_SPEC,             { .off       = OFFSET(codec_names) },
+        "codec name", "codec" },
+    { "pre",            HAS_ARG | OPT_STRING | OPT_SPEC,             { .off       = OFFSET(presets) },
+        "preset name", "preset" },
+    { "map",            HAS_ARG | OPT_EXPERT | OPT_PERFILE,          { .func_arg = opt_map },
+        "set input stream mapping",
+        "[-]input_file_id[:stream_specifier][,sync_file_id[:stream_specifier]]" },
+    { "map_channel",    HAS_ARG | OPT_EXPERT | OPT_PERFILE,          { .func_arg = opt_map_channel },
+        "map an audio channel from one stream to another", "file.stream.channel[:syncfile.syncstream]" },
+    { "map_metadata",   HAS_ARG | OPT_STRING | OPT_SPEC,             { .off       = OFFSET(metadata_map) },
+        "set metadata information of outfile from infile",
+        "outfile[,metadata]:infile[,metadata]" },
+    { "map_chapters",   HAS_ARG | OPT_INT | OPT_EXPERT | OPT_OFFSET, { .off = OFFSET(chapters_input_file) },
+        "set chapters mapping", "input_file_index" },
+    { "t",              HAS_ARG | OPT_TIME | OPT_OFFSET,             { .off = OFFSET(recording_time) },
+        "record or transcode \"duration\" seconds of audio/video",
+        "duration" },
+    { "fs",             HAS_ARG | OPT_INT64 | OPT_OFFSET,            { .off = OFFSET(limit_filesize) },
+        "set the limit file size in bytes", "limit_size" },
+    { "ss",             HAS_ARG | OPT_TIME | OPT_OFFSET,             { .off = OFFSET(start_time) },
+        "set the start time offset", "time_off" },
+    { "itsoffset",      HAS_ARG | OPT_TIME | OPT_OFFSET | OPT_EXPERT,{ .off = OFFSET(input_ts_offset) },
+        "set the input ts offset", "time_off" },
+    { "itsscale",       HAS_ARG | OPT_DOUBLE | OPT_SPEC | OPT_EXPERT,{ .off = OFFSET(ts_scale) },
+        "set the input ts scale", "scale" },
+    { "timestamp",      HAS_ARG | OPT_PERFILE,                       { .func_arg = opt_recording_timestamp },
+        "set the recording timestamp ('now' to set the current time)", "time" },
+    { "metadata",       HAS_ARG | OPT_STRING | OPT_SPEC,             { .off = OFFSET(metadata) },
+        "add metadata", "string=string" },
+    { "dframes",        HAS_ARG | OPT_PERFILE | OPT_EXPERT,          { .func_arg = opt_data_frames },
+        "set the number of data frames to record", "number" },
+    { "benchmark",      OPT_BOOL | OPT_EXPERT,                       { &do_benchmark },
+        "add timings for benchmarking" },
+    { "benchmark_all",  OPT_BOOL | OPT_EXPERT,                       { &do_benchmark_all },
       "add timings for each task" },
-    { "progress", HAS_ARG | OPT_EXPERT, {(void*)opt_progress},
+    { "progress",       HAS_ARG | OPT_EXPERT,                        { .func_arg = opt_progress },
       "write program-readable progress information", "url" },
-    { "stdin", OPT_BOOL | OPT_EXPERT, {(void*)&stdin_interaction},
+    { "stdin",          OPT_BOOL | OPT_EXPERT,                       { &stdin_interaction },
       "enable or disable interaction on standard input" },
-    { "timelimit", HAS_ARG, {(void*)opt_timelimit}, "set max runtime in seconds", "limit" },
-    { "dump", OPT_BOOL | OPT_EXPERT, {(void*)&do_pkt_dump},
-      "dump each input packet" },
-    { "hex", OPT_BOOL | OPT_EXPERT, {(void*)&do_hex_dump},
-      "when dumping packets, also dump the payload" },
-    { "re", OPT_BOOL | OPT_EXPERT | OPT_OFFSET, {.off = OFFSET(rate_emu)}, "read input at native frame rate", "" },
-    { "target", HAS_ARG | OPT_FUNC2, {(void*)opt_target}, "specify target file type (\"vcd\", \"svcd\", \"dvd\", \"dv\", \"dv50\", \"pal-vcd\", \"ntsc-svcd\", ...)", "type" },
-    { "vsync", HAS_ARG | OPT_EXPERT, {(void*)opt_vsync}, "video sync method", "" },
-    { "async", HAS_ARG | OPT_INT | OPT_EXPERT, {(void*)&audio_sync_method}, "audio sync method", "" },
-    { "adrift_threshold", HAS_ARG | OPT_FLOAT | OPT_EXPERT, {(void*)&audio_drift_threshold}, "audio drift threshold", "threshold" },
-    { "copyts", OPT_BOOL | OPT_EXPERT, {(void*)&copy_ts}, "copy timestamps" },
-    { "copytb", HAS_ARG | OPT_INT | OPT_EXPERT, {(void*)&copy_tb}, "copy input stream time base when stream copying", "mode" },
-    { "shortest", OPT_BOOL | OPT_EXPERT, {(void*)&opt_shortest}, "finish encoding within shortest input" }, //
-    { "dts_delta_threshold", HAS_ARG | OPT_FLOAT | OPT_EXPERT, {(void*)&dts_delta_threshold}, "timestamp discontinuity delta threshold", "threshold" },
-    { "dts_error_threshold", HAS_ARG | OPT_FLOAT | OPT_EXPERT, {(void*)&dts_error_threshold}, "timestamp error delta threshold", "threshold" },
-    { "xerror", OPT_BOOL, {(void*)&exit_on_error}, "exit on error", "error" },
-    { "copyinkf", OPT_BOOL | OPT_EXPERT | OPT_SPEC, {.off = OFFSET(copy_initial_nonkeyframes)}, "copy initial non-keyframes" },
-    { "frames", OPT_INT64 | HAS_ARG | OPT_SPEC, {.off = OFFSET(max_frames)}, "set the number of frames to record", "number" },
-    { "tag",   OPT_STRING | HAS_ARG | OPT_SPEC, {.off = OFFSET(codec_tags)}, "force codec tag/fourcc", "fourcc/tag" },
-    { "q", HAS_ARG | OPT_EXPERT | OPT_DOUBLE | OPT_SPEC, {.off = OFFSET(qscale)}, "use fixed quality scale (VBR)", "q" },
-    { "qscale", HAS_ARG | OPT_EXPERT | OPT_FUNC2, {(void*)opt_qscale}, "use fixed quality scale (VBR)", "q" },
-    { "profile", HAS_ARG | OPT_EXPERT | OPT_FUNC2, {(void*)opt_profile}, "set profile", "profile" },
-    { "filter", HAS_ARG | OPT_STRING | OPT_SPEC, {.off = OFFSET(filters)}, "set stream filterchain", "filter_list" },
-    { "filter_complex", HAS_ARG | OPT_EXPERT, {(void*)opt_filter_complex}, "create a complex filtergraph", "graph_description" },
-    { "stats", OPT_BOOL, {&print_stats}, "print progress report during encoding", },
-    { "attach", HAS_ARG | OPT_FUNC2, {(void*)opt_attach}, "add an attachment to the output file", "filename" },
-    { "dump_attachment", HAS_ARG | OPT_STRING | OPT_SPEC, {.off = OFFSET(dump_attachment)}, "extract an attachment into a file", "filename" },
-    { "debug_ts", OPT_BOOL | OPT_EXPERT, {&debug_ts}, "print timestamp debugging info" },
+    { "timelimit",      HAS_ARG | OPT_EXPERT,                        { .func_arg = opt_timelimit },
+        "set max runtime in seconds", "limit" },
+    { "dump",           OPT_BOOL | OPT_EXPERT,                       { &do_pkt_dump },
+        "dump each input packet" },
+    { "hex",            OPT_BOOL | OPT_EXPERT,                       { &do_hex_dump },
+        "when dumping packets, also dump the payload" },
+    { "re",             OPT_BOOL | OPT_EXPERT | OPT_OFFSET,          { .off = OFFSET(rate_emu) },
+        "read input at native frame rate", "" },
+    { "target",         HAS_ARG | OPT_PERFILE,                       { .func_arg = opt_target },
+        "specify target file type (\"vcd\", \"svcd\", \"dvd\","
+        " \"dv\", \"dv50\", \"pal-vcd\", \"ntsc-svcd\", ...)", "type" },
+    { "vsync",          HAS_ARG | OPT_EXPERT,                        { opt_vsync },
+        "video sync method", "" },
+    { "async",          HAS_ARG | OPT_INT | OPT_EXPERT,              { &audio_sync_method },
+        "audio sync method", "" },
+    { "adrift_threshold", HAS_ARG | OPT_FLOAT | OPT_EXPERT,          { &audio_drift_threshold },
+        "audio drift threshold", "threshold" },
+    { "copyts",         OPT_BOOL | OPT_EXPERT,                       { &copy_ts },
+        "copy timestamps" },
+    { "copytb",         HAS_ARG | OPT_INT | OPT_EXPERT,              { &copy_tb },
+        "copy input stream time base when stream copying", "mode" },
+    { "shortest",       OPT_BOOL | OPT_EXPERT | OPT_OFFSET,          { .off = OFFSET(shortest) },
+        "finish encoding within shortest input" },
+    { "dts_delta_threshold", HAS_ARG | OPT_FLOAT | OPT_EXPERT,       { &dts_delta_threshold },
+        "timestamp discontinuity delta threshold", "threshold" },
+    { "dts_error_threshold", HAS_ARG | OPT_FLOAT | OPT_EXPERT,       { &dts_error_threshold },
+        "timestamp error delta threshold", "threshold" },
+    { "xerror",         OPT_BOOL | OPT_EXPERT,                       { &exit_on_error },
+        "exit on error", "error" },
+    { "copyinkf",       OPT_BOOL | OPT_EXPERT | OPT_SPEC,            { .off = OFFSET(copy_initial_nonkeyframes) },
+        "copy initial non-keyframes" },
+    { "frames",         OPT_INT64 | HAS_ARG | OPT_SPEC,              { .off = OFFSET(max_frames) },
+        "set the number of frames to record", "number" },
+    { "tag",            OPT_STRING | HAS_ARG | OPT_SPEC | OPT_EXPERT,{ .off = OFFSET(codec_tags) },
+        "force codec tag/fourcc", "fourcc/tag" },
+    { "q",              HAS_ARG | OPT_EXPERT | OPT_DOUBLE | OPT_SPEC,{ .off = OFFSET(qscale) },
+        "use fixed quality scale (VBR)", "q" },
+    { "qscale",         HAS_ARG | OPT_EXPERT | OPT_PERFILE,          { .func_arg = opt_qscale },
+        "use fixed quality scale (VBR)", "q" },
+    { "profile",        HAS_ARG | OPT_EXPERT | OPT_PERFILE,          { .func_arg = opt_profile },
+        "set profile", "profile" },
+    { "filter",         HAS_ARG | OPT_STRING | OPT_SPEC,             { .off = OFFSET(filters) },
+        "set stream filterchain", "filter_list" },
+    { "filter_complex", HAS_ARG | OPT_EXPERT,                        { .func_arg = opt_filter_complex },
+        "create a complex filtergraph", "graph_description" },
+    { "stats",          OPT_BOOL,                                    { &print_stats },
+        "print progress report during encoding", },
+    { "attach",         HAS_ARG | OPT_PERFILE | OPT_EXPERT,          { .func_arg = opt_attach },
+        "add an attachment to the output file", "filename" },
+    { "dump_attachment", HAS_ARG | OPT_STRING | OPT_SPEC |OPT_EXPERT,{ .off = OFFSET(dump_attachment) },
+        "extract an attachment into a file", "filename" },
+    { "debug_ts",       OPT_BOOL | OPT_EXPERT,                       { &debug_ts },
+        "print timestamp debugging info" },
 
     /* video options */
-    { "vframes", HAS_ARG | OPT_VIDEO | OPT_FUNC2, {(void*)opt_video_frames}, "set the number of video frames to record", "number" },
-    { "r", HAS_ARG | OPT_VIDEO | OPT_STRING | OPT_SPEC, {.off = OFFSET(frame_rates)}, "set frame rate (Hz value, fraction or abbreviation)", "rate" },
-    { "s", HAS_ARG | OPT_VIDEO | OPT_STRING | OPT_SPEC, {.off = OFFSET(frame_sizes)}, "set frame size (WxH or abbreviation)", "size" },
-    { "aspect", HAS_ARG | OPT_VIDEO | OPT_STRING | OPT_SPEC, {.off = OFFSET(frame_aspect_ratios)}, "set aspect ratio (4:3, 16:9 or 1.3333, 1.7777)", "aspect" },
-    { "pix_fmt", HAS_ARG | OPT_EXPERT | OPT_VIDEO | OPT_STRING | OPT_SPEC, {.off = OFFSET(frame_pix_fmts)}, "set pixel format", "format" },
-    { "bits_per_raw_sample", OPT_INT | HAS_ARG | OPT_VIDEO, {(void*)&frame_bits_per_raw_sample}, "set the number of bits per raw sample", "number" },
-    { "croptop",  HAS_ARG | OPT_VIDEO, {(void*)opt_frame_crop}, "Removed, use the crop filter instead", "size" },
-    { "cropbottom", HAS_ARG | OPT_VIDEO, {(void*)opt_frame_crop}, "Removed, use the crop filter instead", "size" },
-    { "cropleft", HAS_ARG | OPT_VIDEO, {(void*)opt_frame_crop}, "Removed, use the crop filter instead", "size" },
-    { "cropright", HAS_ARG | OPT_VIDEO, {(void*)opt_frame_crop}, "Removed, use the crop filter instead", "size" },
-    { "padtop", HAS_ARG | OPT_VIDEO, {(void*)opt_pad}, "Removed, use the pad filter instead", "size" },
-    { "padbottom", HAS_ARG | OPT_VIDEO, {(void*)opt_pad}, "Removed, use the pad filter instead", "size" },
-    { "padleft", HAS_ARG | OPT_VIDEO, {(void*)opt_pad}, "Removed, use the pad filter instead", "size" },
-    { "padright", HAS_ARG | OPT_VIDEO, {(void*)opt_pad}, "Removed, use the pad filter instead", "size" },
-    { "padcolor", HAS_ARG | OPT_VIDEO, {(void*)opt_pad}, "Removed, use the pad filter instead", "color" },
-    { "intra", OPT_BOOL | OPT_EXPERT | OPT_VIDEO, {(void*)&intra_only}, "deprecated use -g 1"},
-    { "vn", OPT_BOOL | OPT_VIDEO | OPT_OFFSET, {.off = OFFSET(video_disable)}, "disable video" },
-    { "vdt", OPT_INT | HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)&video_discard}, "discard threshold", "n" },
-    { "rc_override", HAS_ARG | OPT_EXPERT | OPT_VIDEO | OPT_STRING | OPT_SPEC, {.off = OFFSET(rc_overrides)}, "rate control override for specific intervals", "override" },
-    { "vcodec", HAS_ARG | OPT_VIDEO | OPT_FUNC2, {(void*)opt_video_codec}, "force video codec ('copy' to copy stream)", "codec" },
-    { "sameq", OPT_BOOL | OPT_VIDEO, {(void*)&same_quant}, "use same quantizer as source (implies VBR)" },
-    { "same_quant", OPT_BOOL | OPT_VIDEO, {(void*)&same_quant},
-      "use same quantizer as source (implies VBR)" },
-    { "timecode", HAS_ARG | OPT_VIDEO | OPT_FUNC2, {(void*)opt_timecode}, "set initial TimeCode value.", "hh:mm:ss[:;.]ff" },
-    { "pass", HAS_ARG | OPT_VIDEO, {(void*)opt_pass}, "select the pass number (1 or 2)", "n" },
-    { "passlogfile", HAS_ARG | OPT_VIDEO, {(void*)&opt_passlogfile}, "select two pass log file name prefix", "prefix" },
-    { "deinterlace", OPT_EXPERT | OPT_VIDEO, {(void*)opt_deinterlace},
-      "this option is deprecated, use the yadif filter instead" },
-    { "psnr", OPT_BOOL | OPT_EXPERT | OPT_VIDEO, {(void*)&do_psnr}, "calculate PSNR of compressed frames" },
-    { "vstats", OPT_EXPERT | OPT_VIDEO, {(void*)&opt_vstats}, "dump video coding statistics to file" },
-    { "vstats_file", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_vstats_file}, "dump video coding statistics to file", "file" },
-    { "vf", HAS_ARG | OPT_VIDEO | OPT_FUNC2, {(void*)opt_video_filters}, "video filters", "filter list" },
-    { "intra_matrix", HAS_ARG | OPT_EXPERT | OPT_VIDEO | OPT_STRING | OPT_SPEC, {.off = OFFSET(intra_matrices)}, "specify intra matrix coeffs", "matrix" },
-    { "inter_matrix", HAS_ARG | OPT_EXPERT | OPT_VIDEO | OPT_STRING | OPT_SPEC, {.off = OFFSET(inter_matrices)}, "specify inter matrix coeffs", "matrix" },
-    { "top", HAS_ARG | OPT_EXPERT | OPT_VIDEO | OPT_INT| OPT_SPEC, {.off = OFFSET(top_field_first)}, "top=1/bottom=0/auto=-1 field first", "" },
-    { "dc", OPT_INT | HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)&intra_dc_precision}, "intra_dc_precision", "precision" },
-    { "vtag", HAS_ARG | OPT_EXPERT | OPT_VIDEO | OPT_FUNC2, {(void*)opt_old2new}, "force video tag/fourcc", "fourcc/tag" },
-    { "qphist", OPT_BOOL | OPT_EXPERT | OPT_VIDEO, { (void *)&qp_hist }, "show QP histogram" },
-    { "force_fps", OPT_BOOL | OPT_EXPERT | OPT_VIDEO | OPT_SPEC, {.off = OFFSET(force_fps)}, "force the selected framerate, disable the best supported framerate selection" },
-    { "streamid", HAS_ARG | OPT_EXPERT | OPT_FUNC2, {(void*)opt_streamid}, "set the value of an outfile streamid", "streamIndex:value" },
-    { "force_key_frames", OPT_STRING | HAS_ARG | OPT_EXPERT | OPT_VIDEO | OPT_SPEC, {.off = OFFSET(forced_key_frames)}, "force key frames at specified timestamps", "timestamps" },
-    { "b", HAS_ARG | OPT_VIDEO | OPT_FUNC2, {(void*)opt_bitrate}, "video bitrate (please use -b:v)", "bitrate" },
+    { "vframes",      OPT_VIDEO | HAS_ARG  | OPT_PERFILE,                        { .func_arg = opt_video_frames },
+        "set the number of video frames to record", "number" },
+    { "r",            OPT_VIDEO | HAS_ARG  | OPT_STRING | OPT_SPEC,              { .off = OFFSET(frame_rates) },
+        "set frame rate (Hz value, fraction or abbreviation)", "rate" },
+    { "s",            OPT_VIDEO | HAS_ARG | OPT_SUBTITLE | OPT_STRING | OPT_SPEC,{ .off = OFFSET(frame_sizes) },
+        "set frame size (WxH or abbreviation)", "size" },
+    { "aspect",       OPT_VIDEO | HAS_ARG  | OPT_STRING | OPT_SPEC,              { .off = OFFSET(frame_aspect_ratios) },
+        "set aspect ratio (4:3, 16:9 or 1.3333, 1.7777)", "aspect" },
+    { "pix_fmt",      OPT_VIDEO | HAS_ARG | OPT_EXPERT  | OPT_STRING | OPT_SPEC, { .off = OFFSET(frame_pix_fmts) },
+        "set pixel format", "format" },
+    { "bits_per_raw_sample", OPT_VIDEO | OPT_INT | HAS_ARG,                      { &frame_bits_per_raw_sample },
+        "set the number of bits per raw sample", "number" },
+    { "croptop",      OPT_VIDEO | HAS_ARG,                                       { .func_arg = opt_frame_crop },
+        "Removed, use the crop filter instead", "size" },
+    { "cropbottom",   OPT_VIDEO | HAS_ARG,                                       { .func_arg = opt_frame_crop },
+        "Removed, use the crop filter instead", "size" },
+    { "cropleft",     OPT_VIDEO | HAS_ARG,                                       { .func_arg = opt_frame_crop },
+        "Removed, use the crop filter instead", "size" },
+    { "cropright",    OPT_VIDEO | HAS_ARG,                                       { .func_arg = opt_frame_crop },
+        "Removed, use the crop filter instead", "size" },
+    { "padtop",       OPT_VIDEO | HAS_ARG,                                       { .func_arg = opt_pad },
+        "Removed, use the pad filter instead", "size" },
+    { "padbottom",    OPT_VIDEO | HAS_ARG,                                       { .func_arg = opt_pad },
+        "Removed, use the pad filter instead", "size" },
+    { "padleft",      OPT_VIDEO | HAS_ARG,                                       { .func_arg = opt_pad },
+        "Removed, use the pad filter instead", "size" },
+    { "padright",     OPT_VIDEO | HAS_ARG,                                       { .func_arg = opt_pad },
+        "Removed, use the pad filter instead", "size" },
+    { "padcolor",     OPT_VIDEO | HAS_ARG,                                       { .func_arg = opt_pad },
+        "Removed, use the pad filter instead", "color" },
+    { "intra",        OPT_VIDEO | OPT_BOOL | OPT_EXPERT,                         { &intra_only },
+        "deprecated use -g 1" },
+    { "vn",           OPT_VIDEO | OPT_BOOL  | OPT_OFFSET,                        { .off = OFFSET(video_disable) },
+        "disable video" },
+    { "vdt",          OPT_VIDEO | OPT_INT | HAS_ARG | OPT_EXPERT ,               { &video_discard },
+        "discard threshold", "n" },
+    { "rc_override",  OPT_VIDEO | HAS_ARG | OPT_EXPERT  | OPT_STRING | OPT_SPEC, { .off = OFFSET(rc_overrides) },
+        "rate control override for specific intervals", "override" },
+    { "vcodec",       OPT_VIDEO | HAS_ARG  | OPT_PERFILE,                        { .func_arg = opt_video_codec },
+        "force video codec ('copy' to copy stream)", "codec" },
+    { "sameq",        OPT_VIDEO | OPT_BOOL | OPT_EXPERT ,                        { &same_quant },
+        "use same quantizer as source (implies VBR)" },
+    { "same_quant",   OPT_VIDEO | OPT_BOOL | OPT_EXPERT,                         { &same_quant },
+        "use same quantizer as source (implies VBR)" },
+    { "timecode",     OPT_VIDEO | HAS_ARG | OPT_PERFILE,                         { .func_arg = opt_timecode },
+        "set initial TimeCode value.", "hh:mm:ss[:;.]ff" },
+    { "pass",         OPT_VIDEO | HAS_ARG | OPT_SPEC | OPT_INT,                  { .off = OFFSET(pass) },
+        "select the pass number (1 to 3)", "n" },
+    { "passlogfile",  OPT_VIDEO | HAS_ARG | OPT_STRING | OPT_EXPERT | OPT_SPEC,  { .off = OFFSET(passlogfiles) },
+        "select two pass log file name prefix", "prefix" },
+    { "deinterlace",  OPT_VIDEO | OPT_EXPERT ,                                   { .func_arg = opt_deinterlace },
+        "this option is deprecated, use the yadif filter instead" },
+    { "psnr",         OPT_VIDEO | OPT_BOOL | OPT_EXPERT,                         { &do_psnr },
+        "calculate PSNR of compressed frames" },
+    { "vstats",       OPT_VIDEO | OPT_EXPERT ,                                   { &opt_vstats },
+        "dump video coding statistics to file" },
+    { "vstats_file",  OPT_VIDEO | HAS_ARG | OPT_EXPERT ,                         { opt_vstats_file },
+        "dump video coding statistics to file", "file" },
+    { "vf",           OPT_VIDEO | HAS_ARG  | OPT_PERFILE,                        { .func_arg = opt_video_filters },
+        "video filters", "filter list" },
+    { "intra_matrix", OPT_VIDEO | HAS_ARG | OPT_EXPERT  | OPT_STRING | OPT_SPEC, { .off = OFFSET(intra_matrices) },
+        "specify intra matrix coeffs", "matrix" },
+    { "inter_matrix", OPT_VIDEO | HAS_ARG | OPT_EXPERT  | OPT_STRING | OPT_SPEC, { .off = OFFSET(inter_matrices) },
+        "specify inter matrix coeffs", "matrix" },
+    { "top",          OPT_VIDEO | HAS_ARG | OPT_EXPERT  | OPT_INT| OPT_SPEC,     { .off = OFFSET(top_field_first) },
+        "top=1/bottom=0/auto=-1 field first", "" },
+    { "dc",           OPT_VIDEO | OPT_INT | HAS_ARG | OPT_EXPERT ,               { &intra_dc_precision },
+        "intra_dc_precision", "precision" },
+    { "vtag",         OPT_VIDEO | HAS_ARG | OPT_EXPERT  | OPT_PERFILE,           { .func_arg = opt_old2new },
+        "force video tag/fourcc", "fourcc/tag" },
+    { "qphist",       OPT_VIDEO | OPT_BOOL | OPT_EXPERT ,                        { &qp_hist },
+        "show QP histogram" },
+    { "force_fps",    OPT_VIDEO | OPT_BOOL | OPT_EXPERT  | OPT_SPEC,             { .off = OFFSET(force_fps) },
+        "force the selected framerate, disable the best supported framerate selection" },
+    { "streamid",     OPT_VIDEO | HAS_ARG | OPT_EXPERT | OPT_PERFILE,            { .func_arg = opt_streamid },
+        "set the value of an outfile streamid", "streamIndex:value" },
+    { "force_key_frames", OPT_VIDEO | OPT_STRING | HAS_ARG | OPT_EXPERT  | OPT_SPEC,
+        { .off = OFFSET(forced_key_frames) },
+        "force key frames at specified timestamps", "timestamps" },
+    { "b",            OPT_VIDEO | HAS_ARG | OPT_PERFILE,                         { .func_arg = opt_bitrate },
+        "video bitrate (please use -b:v)", "bitrate" },
 
     /* audio options */
-    { "aframes", HAS_ARG | OPT_AUDIO | OPT_FUNC2, {(void*)opt_audio_frames}, "set the number of audio frames to record", "number" },
-    { "aq", HAS_ARG | OPT_AUDIO | OPT_FUNC2, {(void*)opt_audio_qscale}, "set audio quality (codec-specific)", "quality", },
-    { "ar", HAS_ARG | OPT_AUDIO | OPT_INT | OPT_SPEC, {.off = OFFSET(audio_sample_rate)}, "set audio sampling rate (in Hz)", "rate" },
-    { "ac", HAS_ARG | OPT_AUDIO | OPT_INT | OPT_SPEC, {.off = OFFSET(audio_channels)}, "set number of audio channels", "channels" },
-    { "an", OPT_BOOL | OPT_AUDIO | OPT_OFFSET, {.off = OFFSET(audio_disable)}, "disable audio" },
-    { "acodec", HAS_ARG | OPT_AUDIO | OPT_FUNC2, {(void*)opt_audio_codec}, "force audio codec ('copy' to copy stream)", "codec" },
-    { "atag", HAS_ARG | OPT_EXPERT | OPT_AUDIO | OPT_FUNC2, {(void*)opt_old2new}, "force audio tag/fourcc", "fourcc/tag" },
-    { "vol", OPT_INT | HAS_ARG | OPT_AUDIO, {(void*)&audio_volume}, "change audio volume (256=normal)" , "volume" }, //
-    { "sample_fmt", HAS_ARG | OPT_EXPERT | OPT_AUDIO | OPT_SPEC | OPT_STRING, {.off = OFFSET(sample_fmts)}, "set sample format", "format" },
-    { "channel_layout", HAS_ARG | OPT_EXPERT | OPT_AUDIO | OPT_FUNC2, {(void*)opt_channel_layout}, "set channel layout", "layout" },
-    { "af", HAS_ARG | OPT_AUDIO | OPT_FUNC2, {(void*)opt_audio_filters}, "audio filters", "filter list" },
+    { "aframes",        OPT_AUDIO | HAS_ARG  | OPT_PERFILE,                        { .func_arg = opt_audio_frames },
+        "set the number of audio frames to record", "number" },
+    { "aq",             OPT_AUDIO | HAS_ARG  | OPT_PERFILE,                        { .func_arg = opt_audio_qscale },
+        "set audio quality (codec-specific)", "quality", },
+    { "ar",             OPT_AUDIO | HAS_ARG  | OPT_INT | OPT_SPEC,                 { .off = OFFSET(audio_sample_rate) },
+        "set audio sampling rate (in Hz)", "rate" },
+    { "ac",             OPT_AUDIO | HAS_ARG  | OPT_INT | OPT_SPEC,                 { .off = OFFSET(audio_channels) },
+        "set number of audio channels", "channels" },
+    { "an",             OPT_AUDIO | OPT_BOOL | OPT_OFFSET,                         { .off = OFFSET(audio_disable) },
+        "disable audio" },
+    { "acodec",         OPT_AUDIO | HAS_ARG  | OPT_PERFILE,                        { .func_arg = opt_audio_codec },
+        "force audio codec ('copy' to copy stream)", "codec" },
+    { "atag",           OPT_AUDIO | HAS_ARG  | OPT_EXPERT | OPT_PERFILE,           { .func_arg = opt_old2new },
+        "force audio tag/fourcc", "fourcc/tag" },
+    { "vol",            OPT_AUDIO | HAS_ARG  | OPT_INT,                            { &audio_volume },
+        "change audio volume (256=normal)" , "volume" },
+    { "sample_fmt",     OPT_AUDIO | HAS_ARG  | OPT_EXPERT | OPT_SPEC | OPT_STRING, { .off = OFFSET(sample_fmts) },
+        "set sample format", "format" },
+    { "channel_layout", OPT_AUDIO | HAS_ARG  | OPT_EXPERT | OPT_PERFILE,           { .func_arg = opt_channel_layout },
+        "set channel layout", "layout" },
+    { "af",             OPT_AUDIO | HAS_ARG  | OPT_PERFILE,                        { .func_arg = opt_audio_filters },
+        "audio filters", "filter list" },
 
     /* subtitle options */
-    { "sn", OPT_BOOL | OPT_SUBTITLE | OPT_OFFSET, {.off = OFFSET(subtitle_disable)}, "disable subtitle" },
-    { "scodec", HAS_ARG | OPT_SUBTITLE | OPT_FUNC2, {(void*)opt_subtitle_codec}, "force subtitle codec ('copy' to copy stream)", "codec" },
-    { "stag", HAS_ARG | OPT_EXPERT | OPT_SUBTITLE | OPT_FUNC2, {(void*)opt_old2new}, "force subtitle tag/fourcc", "fourcc/tag" },
-    { "fix_sub_duration", OPT_BOOL | OPT_EXPERT | OPT_SUBTITLE | OPT_SPEC, {.off = OFFSET(fix_sub_duration)}, "fix subtitles duration" },
+    { "sn",     OPT_SUBTITLE | OPT_BOOL | OPT_OFFSET, { .off = OFFSET(subtitle_disable) },
+        "disable subtitle" },
+    { "scodec", OPT_SUBTITLE | HAS_ARG  | OPT_PERFILE, { .func_arg = opt_subtitle_codec },
+        "force subtitle codec ('copy' to copy stream)", "codec" },
+    { "stag",   OPT_SUBTITLE | HAS_ARG  | OPT_EXPERT  | OPT_PERFILE, { .func_arg = opt_old2new }
+        , "force subtitle tag/fourcc", "fourcc/tag" },
+    { "fix_sub_duration", OPT_BOOL | OPT_EXPERT | OPT_SUBTITLE | OPT_SPEC, { .off = OFFSET(fix_sub_duration) },
+        "fix subtitles duration" },
 
     /* grab options */
-    { "vc", HAS_ARG | OPT_EXPERT | OPT_VIDEO | OPT_GRAB, {(void*)opt_video_channel}, "deprecated, use -channel", "channel" },
-    { "tvstd", HAS_ARG | OPT_EXPERT | OPT_VIDEO | OPT_GRAB, {(void*)opt_video_standard}, "deprecated, use -standard", "standard" },
-    { "isync", OPT_BOOL | OPT_EXPERT | OPT_GRAB, {(void*)&input_sync}, "sync read on input", "" },
+    { "vc", HAS_ARG | OPT_EXPERT | OPT_VIDEO, { .func_arg = opt_video_channel },
+        "deprecated, use -channel", "channel" },
+    { "tvstd", HAS_ARG | OPT_EXPERT | OPT_VIDEO, { .func_arg = opt_video_standard },
+        "deprecated, use -standard", "standard" },
+    { "isync", OPT_BOOL | OPT_EXPERT, { &input_sync }, "this option is deprecated and does nothing", "" },
 
     /* muxer options */
-    { "muxdelay", OPT_FLOAT | HAS_ARG | OPT_EXPERT   | OPT_OFFSET, {.off = OFFSET(mux_max_delay)}, "set the maximum demux-decode delay", "seconds" },
-    { "muxpreload", OPT_FLOAT | HAS_ARG | OPT_EXPERT | OPT_OFFSET, {.off = OFFSET(mux_preload)},   "set the initial demux-decode delay", "seconds" },
-
-    { "bsf", HAS_ARG | OPT_STRING | OPT_SPEC, {.off = OFFSET(bitstream_filters)}, "A comma-separated list of bitstream filters", "bitstream_filters" },
-    { "absf", HAS_ARG | OPT_AUDIO | OPT_EXPERT| OPT_FUNC2, {(void*)opt_old2new}, "deprecated", "audio bitstream_filters" },
-    { "vbsf", HAS_ARG | OPT_VIDEO | OPT_EXPERT| OPT_FUNC2, {(void*)opt_old2new}, "deprecated", "video bitstream_filters" },
-
-    { "apre", HAS_ARG | OPT_AUDIO | OPT_EXPERT| OPT_FUNC2, {(void*)opt_preset}, "set the audio options to the indicated preset", "preset" },
-    { "vpre", HAS_ARG | OPT_VIDEO | OPT_EXPERT| OPT_FUNC2, {(void*)opt_preset}, "set the video options to the indicated preset", "preset" },
-    { "spre", HAS_ARG | OPT_SUBTITLE | OPT_EXPERT| OPT_FUNC2, {(void*)opt_preset}, "set the subtitle options to the indicated preset", "preset" },
-    { "fpre", HAS_ARG | OPT_EXPERT| OPT_FUNC2, {(void*)opt_preset}, "set options from indicated preset file", "filename" },
+    { "muxdelay",   OPT_FLOAT | HAS_ARG | OPT_EXPERT | OPT_OFFSET, { .off = OFFSET(mux_max_delay) },
+        "set the maximum demux-decode delay", "seconds" },
+    { "muxpreload", OPT_FLOAT | HAS_ARG | OPT_EXPERT | OPT_OFFSET, { .off = OFFSET(mux_preload) },
+        "set the initial demux-decode delay", "seconds" },
+
+    { "bsf", HAS_ARG | OPT_STRING | OPT_SPEC | OPT_EXPERT, { .off = OFFSET(bitstream_filters) },
+        "A comma-separated list of bitstream filters", "bitstream_filters" },
+    { "absf", HAS_ARG | OPT_AUDIO | OPT_EXPERT| OPT_PERFILE, { .func_arg = opt_old2new },
+        "deprecated", "audio bitstream_filters" },
+    { "vbsf", OPT_VIDEO | HAS_ARG | OPT_EXPERT| OPT_PERFILE, { .func_arg = opt_old2new },
+        "deprecated", "video bitstream_filters" },
+
+    { "apre", HAS_ARG | OPT_AUDIO | OPT_EXPERT| OPT_PERFILE,    { .func_arg = opt_preset },
+        "set the audio options to the indicated preset", "preset" },
+    { "vpre", OPT_VIDEO | HAS_ARG | OPT_EXPERT| OPT_PERFILE,    { .func_arg = opt_preset },
+        "set the video options to the indicated preset", "preset" },
+    { "spre", HAS_ARG | OPT_SUBTITLE | OPT_EXPERT| OPT_PERFILE, { .func_arg = opt_preset },
+        "set the subtitle options to the indicated preset", "preset" },
+    { "fpre", HAS_ARG | OPT_EXPERT| OPT_PERFILE,                { .func_arg = opt_preset },
+        "set options from indicated preset file", "filename" },
     /* data codec support */
-    { "dcodec", HAS_ARG | OPT_DATA | OPT_FUNC2, {(void*)opt_data_codec}, "force data codec ('copy' to copy stream)", "codec" },
-    { "dn", OPT_BOOL | OPT_VIDEO | OPT_OFFSET, {.off = OFFSET(data_disable)}, "disable data" },
+    { "dcodec", HAS_ARG | OPT_DATA | OPT_PERFILE | OPT_EXPERT, { .func_arg = opt_data_codec },
+        "force data codec ('copy' to copy stream)", "codec" },
+    { "dn", OPT_BOOL | OPT_VIDEO | OPT_OFFSET, { .off = OFFSET(data_disable) },
+        "disable data" },
 
-    { "default", HAS_ARG | OPT_AUDIO | OPT_VIDEO | OPT_EXPERT, {(void*)opt_default}, "generic catch all option", "" },
+    { "default", HAS_ARG | OPT_AUDIO | OPT_VIDEO | OPT_EXPERT, { .func_arg = opt_default },
+        "generic catch all option", "" },
     { NULL, },
 };