diff --git a/fftools/cmdutils.c b/fftools/cmdutils.c
index a52c7c5ae4..f53c4b7aec 100644
--- a/fftools/cmdutils.c
+++ b/fftools/cmdutils.c
@@ -239,25 +239,23 @@ static int write_option(void *optctx, const OptionDef *po, const char *opt,
      * a global var*/
     void *dst = po->flags & OPT_FLAG_OFFSET ?
                 (uint8_t *)optctx + po->u.off : po->u.dst_ptr;
-    int *dstcount;
     double num;
     int ret;
 
     if (po->flags & OPT_FLAG_SPEC) {
-        SpecifierOpt **so = dst;
+        SpecifierOptList *sol = dst;
         char *p = strchr(opt, ':');
         char *str;
 
-        dstcount = (int *)(so + 1);
-        ret = grow_array((void**)so, sizeof(**so), dstcount, *dstcount + 1);
+        ret = GROW_ARRAY(sol->opt, sol->nb_opt);
         if (ret < 0)
             return ret;
 
         str = av_strdup(p ? p + 1 : "");
         if (!str)
             return AVERROR(ENOMEM);
-        (*so)[*dstcount - 1].specifier = str;
-        dst = &(*so)[*dstcount - 1].u;
+        sol->opt[sol->nb_opt - 1].specifier = str;
+        dst = &sol->opt[sol->nb_opt - 1].u;
     }
 
     if (po->type == OPT_TYPE_STRING) {
diff --git a/fftools/cmdutils.h b/fftools/cmdutils.h
index dc99573d80..8ef9a07e9e 100644
--- a/fftools/cmdutils.h
+++ b/fftools/cmdutils.h
@@ -114,6 +114,11 @@ typedef struct SpecifierOpt {
     } u;
 } SpecifierOpt;
 
+typedef struct SpecifierOptList {
+    SpecifierOpt    *opt;
+    int           nb_opt;
+} SpecifierOptList;
+
 typedef struct OptionDef {
     const char *name;
     enum OptionType type;
@@ -145,9 +150,7 @@ typedef struct OptionDef {
 #define OPT_FLAG_OFFSET (1 << 8)
 #define OPT_OFFSET      (OPT_FLAG_OFFSET | OPT_PERFILE)
 
-/* Option is to be stored in an array of SpecifierOpt.
-   Next element after the offset is an int containing element count in the
-   array.
+/* Option is to be stored in a SpecifierOptList.
    Always use as OPT_SPEC in option definitions. */
 #define OPT_FLAG_SPEC   (1 << 9)
 #define OPT_SPEC        (OPT_FLAG_SPEC | OPT_OFFSET)
diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h
index 33a29b316f..94f70f7efb 100644
--- a/fftools/ffmpeg.h
+++ b/fftools/ffmpeg.h
@@ -138,22 +138,14 @@ typedef struct OptionsContext {
     int seek_timestamp;
     const char *format;
 
-    SpecifierOpt *codec_names;
-    int        nb_codec_names;
-    SpecifierOpt *audio_ch_layouts;
-    int        nb_audio_ch_layouts;
-    SpecifierOpt *audio_channels;
-    int        nb_audio_channels;
-    SpecifierOpt *audio_sample_rate;
-    int        nb_audio_sample_rate;
-    SpecifierOpt *frame_rates;
-    int        nb_frame_rates;
-    SpecifierOpt *max_frame_rates;
-    int        nb_max_frame_rates;
-    SpecifierOpt *frame_sizes;
-    int        nb_frame_sizes;
-    SpecifierOpt *frame_pix_fmts;
-    int        nb_frame_pix_fmts;
+    SpecifierOptList codec_names;
+    SpecifierOptList audio_ch_layouts;
+    SpecifierOptList audio_channels;
+    SpecifierOptList audio_sample_rate;
+    SpecifierOptList frame_rates;
+    SpecifierOptList max_frame_rates;
+    SpecifierOptList frame_sizes;
+    SpecifierOptList frame_pix_fmts;
 
     /* input options */
     int64_t input_ts_offset;
@@ -166,18 +158,12 @@ typedef struct OptionsContext {
     int input_sync_ref;
     int find_stream_info;
 
-    SpecifierOpt *ts_scale;
-    int        nb_ts_scale;
-    SpecifierOpt *dump_attachment;
-    int        nb_dump_attachment;
-    SpecifierOpt *hwaccels;
-    int        nb_hwaccels;
-    SpecifierOpt *hwaccel_devices;
-    int        nb_hwaccel_devices;
-    SpecifierOpt *hwaccel_output_formats;
-    int        nb_hwaccel_output_formats;
-    SpecifierOpt *autorotate;
-    int        nb_autorotate;
+    SpecifierOptList ts_scale;
+    SpecifierOptList dump_attachment;
+    SpecifierOptList hwaccels;
+    SpecifierOptList hwaccel_devices;
+    SpecifierOptList hwaccel_output_formats;
+    SpecifierOptList autorotate;
 
     /* output options */
     StreamMap *stream_maps;
@@ -208,102 +194,55 @@ typedef struct OptionsContext {
     // keys are stream indices
     AVDictionary *streamid;
 
-    SpecifierOpt *metadata;
-    int        nb_metadata;
-    SpecifierOpt *max_frames;
-    int        nb_max_frames;
-    SpecifierOpt *bitstream_filters;
-    int        nb_bitstream_filters;
-    SpecifierOpt *codec_tags;
-    int        nb_codec_tags;
-    SpecifierOpt *sample_fmts;
-    int        nb_sample_fmts;
-    SpecifierOpt *qscale;
-    int        nb_qscale;
-    SpecifierOpt *forced_key_frames;
-    int        nb_forced_key_frames;
-    SpecifierOpt *fps_mode;
-    int        nb_fps_mode;
-    SpecifierOpt *force_fps;
-    int        nb_force_fps;
-    SpecifierOpt *frame_aspect_ratios;
-    int        nb_frame_aspect_ratios;
-    SpecifierOpt *display_rotations;
-    int        nb_display_rotations;
-    SpecifierOpt *display_hflips;
-    int        nb_display_hflips;
-    SpecifierOpt *display_vflips;
-    int        nb_display_vflips;
-    SpecifierOpt *rc_overrides;
-    int        nb_rc_overrides;
-    SpecifierOpt *intra_matrices;
-    int        nb_intra_matrices;
-    SpecifierOpt *inter_matrices;
-    int        nb_inter_matrices;
-    SpecifierOpt *chroma_intra_matrices;
-    int        nb_chroma_intra_matrices;
+    SpecifierOptList metadata;
+    SpecifierOptList max_frames;
+    SpecifierOptList bitstream_filters;
+    SpecifierOptList codec_tags;
+    SpecifierOptList sample_fmts;
+    SpecifierOptList qscale;
+    SpecifierOptList forced_key_frames;
+    SpecifierOptList fps_mode;
+    SpecifierOptList force_fps;
+    SpecifierOptList frame_aspect_ratios;
+    SpecifierOptList display_rotations;
+    SpecifierOptList display_hflips;
+    SpecifierOptList display_vflips;
+    SpecifierOptList rc_overrides;
+    SpecifierOptList intra_matrices;
+    SpecifierOptList inter_matrices;
+    SpecifierOptList chroma_intra_matrices;
 #if FFMPEG_OPT_TOP
-    SpecifierOpt *top_field_first;
-    int        nb_top_field_first;
+    SpecifierOptList top_field_first;
 #endif
-    SpecifierOpt *metadata_map;
-    int        nb_metadata_map;
-    SpecifierOpt *presets;
-    int        nb_presets;
-    SpecifierOpt *copy_initial_nonkeyframes;
-    int        nb_copy_initial_nonkeyframes;
-    SpecifierOpt *copy_prior_start;
-    int        nb_copy_prior_start;
-    SpecifierOpt *filters;
-    int        nb_filters;
-    SpecifierOpt *filter_scripts;
-    int        nb_filter_scripts;
-    SpecifierOpt *reinit_filters;
-    int        nb_reinit_filters;
-    SpecifierOpt *fix_sub_duration;
-    int        nb_fix_sub_duration;
-    SpecifierOpt *fix_sub_duration_heartbeat;
-    int        nb_fix_sub_duration_heartbeat;
-    SpecifierOpt *canvas_sizes;
-    int        nb_canvas_sizes;
-    SpecifierOpt *pass;
-    int        nb_pass;
-    SpecifierOpt *passlogfiles;
-    int        nb_passlogfiles;
-    SpecifierOpt *max_muxing_queue_size;
-    int        nb_max_muxing_queue_size;
-    SpecifierOpt *muxing_queue_data_threshold;
-    int        nb_muxing_queue_data_threshold;
-    SpecifierOpt *guess_layout_max;
-    int        nb_guess_layout_max;
-    SpecifierOpt *apad;
-    int        nb_apad;
-    SpecifierOpt *discard;
-    int        nb_discard;
-    SpecifierOpt *disposition;
-    int        nb_disposition;
-    SpecifierOpt *program;
-    int        nb_program;
-    SpecifierOpt *time_bases;
-    int        nb_time_bases;
-    SpecifierOpt *enc_time_bases;
-    int        nb_enc_time_bases;
-    SpecifierOpt *autoscale;
-    int        nb_autoscale;
-    SpecifierOpt *bits_per_raw_sample;
-    int        nb_bits_per_raw_sample;
-    SpecifierOpt *enc_stats_pre;
-    int        nb_enc_stats_pre;
-    SpecifierOpt *enc_stats_post;
-    int        nb_enc_stats_post;
-    SpecifierOpt *mux_stats;
-    int        nb_mux_stats;
-    SpecifierOpt *enc_stats_pre_fmt;
-    int        nb_enc_stats_pre_fmt;
-    SpecifierOpt *enc_stats_post_fmt;
-    int        nb_enc_stats_post_fmt;
-    SpecifierOpt *mux_stats_fmt;
-    int        nb_mux_stats_fmt;
+    SpecifierOptList metadata_map;
+    SpecifierOptList presets;
+    SpecifierOptList copy_initial_nonkeyframes;
+    SpecifierOptList copy_prior_start;
+    SpecifierOptList filters;
+    SpecifierOptList filter_scripts;
+    SpecifierOptList reinit_filters;
+    SpecifierOptList fix_sub_duration;
+    SpecifierOptList fix_sub_duration_heartbeat;
+    SpecifierOptList canvas_sizes;
+    SpecifierOptList pass;
+    SpecifierOptList passlogfiles;
+    SpecifierOptList max_muxing_queue_size;
+    SpecifierOptList muxing_queue_data_threshold;
+    SpecifierOptList guess_layout_max;
+    SpecifierOptList apad;
+    SpecifierOptList discard;
+    SpecifierOptList disposition;
+    SpecifierOptList program;
+    SpecifierOptList time_bases;
+    SpecifierOptList enc_time_bases;
+    SpecifierOptList autoscale;
+    SpecifierOptList bits_per_raw_sample;
+    SpecifierOptList enc_stats_pre;
+    SpecifierOptList enc_stats_post;
+    SpecifierOptList mux_stats;
+    SpecifierOptList enc_stats_pre_fmt;
+    SpecifierOptList enc_stats_post_fmt;
+    SpecifierOptList mux_stats_fmt;
 } OptionsContext;
 
 typedef struct InputFilter {
@@ -850,11 +789,11 @@ void update_benchmark(const char *fmt, ...);
 {\
     int _ret, _matches = 0;\
     SpecifierOpt *so;\
-    for (int _i = 0; _i < o->nb_ ## name; _i++) {\
-        char *spec = o->name[_i].specifier;\
+    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[_i].u.type;\
-            so = &o->name[_i];\
+            outvar = o->name.opt[_i].u.type;\
+            so = &o->name.opt[_i];\
             _matches++;\
         } else if (_ret < 0)\
             return _ret;\
@@ -866,10 +805,10 @@ void update_benchmark(const char *fmt, ...);
 #define MATCH_PER_TYPE_OPT(name, type, outvar, fmtctx, mediatype)\
 {\
     int i;\
-    for (i = 0; i < o->nb_ ## name; i++) {\
-        char *spec = o->name[i].specifier;\
+    for (i = 0; i < o->name.nb_opt; i++) {\
+        char *spec = o->name.opt[i].specifier;\
         if (!strcmp(spec, mediatype))\
-            outvar = o->name[i].u.type;\
+            outvar = o->name.opt[i].u.type;\
     }\
 }
 
diff --git a/fftools/ffmpeg_demux.c b/fftools/ffmpeg_demux.c
index eca3de709c..6672113bca 100644
--- a/fftools/ffmpeg_demux.c
+++ b/fftools/ffmpeg_demux.c
@@ -1389,28 +1389,28 @@ int ifile_open(const OptionsContext *o, const char *filename, Scheduler *sch)
     ic = avformat_alloc_context();
     if (!ic)
         return AVERROR(ENOMEM);
-    if (o->nb_audio_sample_rate) {
-        av_dict_set_int(&o->g->format_opts, "sample_rate", o->audio_sample_rate[o->nb_audio_sample_rate - 1].u.i, 0);
+    if (o->audio_sample_rate.nb_opt) {
+        av_dict_set_int(&o->g->format_opts, "sample_rate", o->audio_sample_rate.opt[o->audio_sample_rate.nb_opt - 1].u.i, 0);
     }
-    if (o->nb_audio_channels) {
+    if (o->audio_channels.nb_opt) {
         const AVClass *priv_class;
         if (file_iformat && (priv_class = file_iformat->priv_class) &&
             av_opt_find(&priv_class, "ch_layout", NULL, 0,
                         AV_OPT_SEARCH_FAKE_OBJ)) {
             char buf[32];
-            snprintf(buf, sizeof(buf), "%dC", o->audio_channels[o->nb_audio_channels - 1].u.i);
+            snprintf(buf, sizeof(buf), "%dC", o->audio_channels.opt[o->audio_channels.nb_opt - 1].u.i);
             av_dict_set(&o->g->format_opts, "ch_layout", buf, 0);
         }
     }
-    if (o->nb_audio_ch_layouts) {
+    if (o->audio_ch_layouts.nb_opt) {
         const AVClass *priv_class;
         if (file_iformat && (priv_class = file_iformat->priv_class) &&
             av_opt_find(&priv_class, "ch_layout", NULL, 0,
                         AV_OPT_SEARCH_FAKE_OBJ)) {
-            av_dict_set(&o->g->format_opts, "ch_layout", o->audio_ch_layouts[o->nb_audio_ch_layouts - 1].u.str, 0);
+            av_dict_set(&o->g->format_opts, "ch_layout", o->audio_ch_layouts.opt[o->audio_ch_layouts.nb_opt - 1].u.str, 0);
         }
     }
-    if (o->nb_frame_rates) {
+    if (o->frame_rates.nb_opt) {
         const AVClass *priv_class;
         /* set the format-level framerate option;
          * this is important for video grabbers, e.g. x11 */
@@ -1418,14 +1418,14 @@ int ifile_open(const OptionsContext *o, const char *filename, Scheduler *sch)
             av_opt_find(&priv_class, "framerate", NULL, 0,
                         AV_OPT_SEARCH_FAKE_OBJ)) {
             av_dict_set(&o->g->format_opts, "framerate",
-                        o->frame_rates[o->nb_frame_rates - 1].u.str, 0);
+                        o->frame_rates.opt[o->frame_rates.nb_opt - 1].u.str, 0);
         }
     }
-    if (o->nb_frame_sizes) {
-        av_dict_set(&o->g->format_opts, "video_size", o->frame_sizes[o->nb_frame_sizes - 1].u.str, 0);
+    if (o->frame_sizes.nb_opt) {
+        av_dict_set(&o->g->format_opts, "video_size", o->frame_sizes.opt[o->frame_sizes.nb_opt - 1].u.str, 0);
     }
-    if (o->nb_frame_pix_fmts)
-        av_dict_set(&o->g->format_opts, "pixel_format", o->frame_pix_fmts[o->nb_frame_pix_fmts - 1].u.str, 0);
+    if (o->frame_pix_fmts.nb_opt)
+        av_dict_set(&o->g->format_opts, "pixel_format", o->frame_pix_fmts.opt[o->frame_pix_fmts.nb_opt - 1].u.str, 0);
 
     MATCH_PER_TYPE_OPT(codec_names, str,    video_codec_name, ic, "v");
     MATCH_PER_TYPE_OPT(codec_names, str,    audio_codec_name, ic, "a");
@@ -1649,14 +1649,14 @@ int ifile_open(const OptionsContext *o, const char *filename, Scheduler *sch)
     }
     av_dict_free(&unused_opts);
 
-    for (i = 0; i < o->nb_dump_attachment; i++) {
+    for (i = 0; i < o->dump_attachment.nb_opt; i++) {
         int j;
 
         for (j = 0; j < f->nb_streams; j++) {
             InputStream *ist = f->streams[j];
 
-            if (check_stream_specifier(ic, ist->st, o->dump_attachment[i].specifier) == 1) {
-                ret = dump_attachment(ist, o->dump_attachment[i].u.str);
+            if (check_stream_specifier(ic, ist->st, o->dump_attachment.opt[i].specifier) == 1) {
+                ret = dump_attachment(ist, o->dump_attachment.opt[i].u.str);
                 if (ret < 0)
                     return ret;
             }
diff --git a/fftools/ffmpeg_mux_init.c b/fftools/ffmpeg_mux_init.c
index 52eca9f9d5..6e6e8b8b6a 100644
--- a/fftools/ffmpeg_mux_init.c
+++ b/fftools/ffmpeg_mux_init.c
@@ -1362,8 +1362,8 @@ 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);
-    for (i = 0; i<o->nb_max_frames; i++) {
-        char *p = o->max_frames[i].specifier;
+    for (i = 0; i < o->max_frames.nb_opt; i++) {
+        char *p = o->max_frames.opt[i].specifier;
         if (!*p && type != AVMEDIA_TYPE_VIDEO) {
             av_log(ost, AV_LOG_WARNING, "Applying unspecific -frames to non video streams, maybe you meant -vframes ?\n");
             break;
@@ -2018,17 +2018,17 @@ static int of_add_programs(Muxer *mux, const OptionsContext *o)
 {
     AVFormatContext *oc = mux->fc;
     /* process manually set programs */
-    for (int i = 0; i < o->nb_program; i++) {
+    for (int i = 0; i < o->program.nb_opt; i++) {
         AVDictionary *dict = NULL;
         const AVDictionaryEntry *e;
         AVProgram *program;
         int ret, progid = i + 1;
 
-        ret = av_dict_parse_string(&dict, o->program[i].u.str, "=", ":",
+        ret = av_dict_parse_string(&dict, o->program.opt[i].u.str, "=", ":",
                                    AV_DICT_MULTIKEY);
         if (ret < 0) {
             av_log(mux, AV_LOG_ERROR, "Error parsing program specification %s\n",
-                   o->program[i].u.str);
+                   o->program.opt[i].u.str);
             return ret;
         }
 
@@ -2116,21 +2116,21 @@ static int parse_meta_type(void *logctx, const char *arg,
 static int of_add_metadata(OutputFile *of, AVFormatContext *oc,
                            const OptionsContext *o)
 {
-    for (int i = 0; i < o->nb_metadata; i++) {
+    for (int i = 0; i < o->metadata.nb_opt; i++) {
         AVDictionary **m;
         char type, *val;
         const char *stream_spec;
         int index = 0, ret = 0;
 
-        val = strchr(o->metadata[i].u.str, '=');
+        val = strchr(o->metadata.opt[i].u.str, '=');
         if (!val) {
             av_log(of, AV_LOG_FATAL, "No '=' character in metadata string %s.\n",
-                   o->metadata[i].u.str);
+                   o->metadata.opt[i].u.str);
             return AVERROR(EINVAL);
         }
         *val++ = 0;
 
-        ret = parse_meta_type(of, o->metadata[i].specifier, &type, &index, &stream_spec);
+        ret = parse_meta_type(of, o->metadata.opt[i].specifier, &type, &index, &stream_spec);
         if (ret < 0)
             return ret;
 
@@ -2139,7 +2139,7 @@ static int of_add_metadata(OutputFile *of, AVFormatContext *oc,
                 OutputStream *ost = of->streams[j];
                 if ((ret = check_stream_specifier(oc, oc->streams[j], stream_spec)) > 0) {
 #if FFMPEG_ROTATION_METADATA
-                    if (!strcmp(o->metadata[i].u.str, "rotate")) {
+                    if (!strcmp(o->metadata.opt[i].u.str, "rotate")) {
                         char *tail;
                         double theta = av_strtod(val, &tail);
                         if (!*tail) {
@@ -2154,7 +2154,7 @@ static int of_add_metadata(OutputFile *of, AVFormatContext *oc,
                                "instead.");
                     } else {
 #endif
-                        av_dict_set(&oc->streams[j]->metadata, o->metadata[i].u.str, *val ? val : NULL, 0);
+                        av_dict_set(&oc->streams[j]->metadata, o->metadata.opt[i].u.str, *val ? val : NULL, 0);
 #if FFMPEG_ROTATION_METADATA
                     }
 #endif
@@ -2181,10 +2181,10 @@ static int of_add_metadata(OutputFile *of, AVFormatContext *oc,
                 m = &oc->programs[index]->metadata;
                 break;
             default:
-                av_log(of, AV_LOG_FATAL, "Invalid metadata specifier %s.\n", o->metadata[i].specifier);
+                av_log(of, AV_LOG_FATAL, "Invalid metadata specifier %s.\n", o->metadata.opt[i].specifier);
                 return AVERROR(EINVAL);
             }
-            av_dict_set(m, o->metadata[i].u.str, *val ? val : NULL, 0);
+            av_dict_set(m, o->metadata.opt[i].u.str, *val ? val : NULL, 0);
         }
     }
 
@@ -2332,9 +2332,9 @@ static int copy_meta(Muxer *mux, const OptionsContext *o)
     int ret;
 
     /* copy metadata */
-    for (int i = 0; i < o->nb_metadata_map; i++) {
+    for (int i = 0; i < o->metadata_map.nb_opt; i++) {
         char *p;
-        int in_file_index = strtol(o->metadata_map[i].u.str, &p, 0);
+        int in_file_index = strtol(o->metadata_map.opt[i].u.str, &p, 0);
 
         if (in_file_index >= nb_input_files) {
             av_log(mux, AV_LOG_FATAL, "Invalid input file index %d while "
@@ -2343,7 +2343,7 @@ static int copy_meta(Muxer *mux, const OptionsContext *o)
         }
         ret = copy_metadata(mux,
                             in_file_index >= 0 ? input_files[in_file_index]->ctx : NULL,
-                            o->metadata_map[i].specifier, *p ? p + 1 : p,
+                            o->metadata_map.opt[i].specifier, *p ? p + 1 : p,
                             &metadata_global_manual, &metadata_streams_manual,
                             &metadata_chapters_manual);
         if (ret < 0)
diff --git a/fftools/ffmpeg_opt.c b/fftools/ffmpeg_opt.c
index 6f997a803a..653f62770e 100644
--- a/fftools/ffmpeg_opt.c
+++ b/fftools/ffmpeg_opt.c
@@ -110,15 +110,14 @@ static void uninit_options(OptionsContext *o)
         void *dst = (uint8_t*)o + po->u.off;
 
         if (po->flags & OPT_FLAG_SPEC) {
-            SpecifierOpt **so = dst;
-            int i, *count = (int*)(so + 1);
-            for (i = 0; i < *count; i++) {
-                av_freep(&(*so)[i].specifier);
+            SpecifierOptList *so = dst;
+            for (int i = 0; i < so->nb_opt; i++) {
+                av_freep(&so->opt[i].specifier);
                 if (po->type == OPT_TYPE_STRING)
-                    av_freep(&(*so)[i].u.str);
+                    av_freep(&so->opt[i].u.str);
             }
-            av_freep(so);
-            *count = 0;
+            av_freep(&so->opt);
+            so->nb_opt = 0;
         } else if (po->flags & OPT_FLAG_OFFSET && po->type == OPT_TYPE_STRING)
             av_freep(dst);
         po++;
