Browse code

avconv: do not silently ignore unused codec AVOptions.

Print an error and abort when the option is of the wrong type (decoding
for output file or vice versa), since this could never be correct for
any input or output configuration.

Print a warning and continue when the option is of the correct type,
just unused, so same commandlines can be reused for different kinds of
input or output files.

Anton Khirnov authored on 2013/02/21 18:58:46
Showing 2 changed files
... ...
@@ -5,6 +5,8 @@ version 10:
5 5
 - av_strnstr
6 6
 - support ID3v2 tags in ASF files
7 7
 - reference-counting for AVFrame and AVPacket data
8
+- avconv now fails when input options are used for output file
9
+  or vice versa
8 10
 
9 11
 
10 12
 version 9:
... ...
@@ -119,6 +119,24 @@ static void init_options(OptionsContext *o)
119 119
     o->chapters_input_file = INT_MAX;
120 120
 }
121 121
 
122
+/* return a copy of the input with the stream specifiers removed from the keys */
123
+static AVDictionary *strip_specifiers(AVDictionary *dict)
124
+{
125
+    AVDictionaryEntry *e = NULL;
126
+    AVDictionary    *ret = NULL;
127
+
128
+    while ((e = av_dict_get(dict, "", e, AV_DICT_IGNORE_SUFFIX))) {
129
+        char *p = strchr(e->key, ':');
130
+
131
+        if (p)
132
+            *p = 0;
133
+        av_dict_set(&ret, e->key, e->value, 0);
134
+        if (p)
135
+            *p = ':';
136
+    }
137
+    return ret;
138
+}
139
+
122 140
 static double parse_frame_aspect_ratio(const char *arg)
123 141
 {
124 142
     int x = 0, y = 0;
... ...
@@ -553,6 +571,8 @@ static int open_input_file(OptionsContext *o, const char *filename)
553 553
     int64_t timestamp;
554 554
     uint8_t buf[128];
555 555
     AVDictionary **opts;
556
+    AVDictionary *unused_opts = NULL;
557
+    AVDictionaryEntry *e = NULL;
556 558
     int orig_nb_streams;                     // number of streams before avformat_find_stream_info
557 559
 
558 560
     if (o->format) {
... ...
@@ -666,6 +686,39 @@ static int open_input_file(OptionsContext *o, const char *filename)
666 666
     f->nb_streams = ic->nb_streams;
667 667
     f->rate_emu   = o->rate_emu;
668 668
 
669
+    /* check if all codec options have been used */
670
+    unused_opts = strip_specifiers(o->g->codec_opts);
671
+    for (i = f->ist_index; i < nb_input_streams; i++) {
672
+        e = NULL;
673
+        while ((e = av_dict_get(input_streams[i]->opts, "", e,
674
+                                AV_DICT_IGNORE_SUFFIX)))
675
+            av_dict_set(&unused_opts, e->key, NULL, 0);
676
+    }
677
+
678
+    e = NULL;
679
+    while ((e = av_dict_get(unused_opts, "", e, AV_DICT_IGNORE_SUFFIX))) {
680
+        const AVClass *class = avcodec_get_class();
681
+        const AVOption *option = av_opt_find(&class, e->key, NULL, 0,
682
+                                             AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ);
683
+        if (!option)
684
+            continue;
685
+        if (!(option->flags & AV_OPT_FLAG_DECODING_PARAM)) {
686
+            av_log(NULL, AV_LOG_ERROR, "Codec AVOption %s (%s) specified for "
687
+                   "input file #%d (%s) is not a decoding option.\n", e->key,
688
+                   option->help ? option->help : "", nb_input_files - 1,
689
+                   filename);
690
+            exit(1);
691
+        }
692
+
693
+        av_log(NULL, AV_LOG_WARNING, "Codec AVOption %s (%s) specified for "
694
+               "input file #%d (%s) has not been used for any stream. The most "
695
+               "likely reason is either wrong type (e.g. a video option with "
696
+               "no video streams) or that it is a private option of some decoder "
697
+               "which was not actually used for any stream.\n", e->key,
698
+               option->help ? option->help : "", nb_input_files - 1, filename);
699
+    }
700
+    av_dict_free(&unused_opts);
701
+
669 702
     for (i = 0; i < o->nb_dump_attachment; i++) {
670 703
         int j;
671 704
 
... ...
@@ -1179,6 +1232,8 @@ static int open_output_file(OptionsContext *o, const char *filename)
1179 1179
     OutputFile *of;
1180 1180
     OutputStream *ost;
1181 1181
     InputStream  *ist;
1182
+    AVDictionary *unused_opts = NULL;
1183
+    AVDictionaryEntry *e = NULL;
1182 1184
 
1183 1185
     if (configure_complex_filters() < 0) {
1184 1186
         av_log(NULL, AV_LOG_FATAL, "Error configuring filters.\n");
... ...
@@ -1384,6 +1439,40 @@ loop_end:
1384 1384
     of->shortest       = o->shortest;
1385 1385
     av_dict_copy(&of->opts, o->g->format_opts, 0);
1386 1386
 
1387
+
1388
+    /* check if all codec options have been used */
1389
+    unused_opts = strip_specifiers(o->g->codec_opts);
1390
+    for (i = of->ost_index; i < nb_output_streams; i++) {
1391
+        e = NULL;
1392
+        while ((e = av_dict_get(output_streams[i]->opts, "", e,
1393
+                                AV_DICT_IGNORE_SUFFIX)))
1394
+            av_dict_set(&unused_opts, e->key, NULL, 0);
1395
+    }
1396
+
1397
+    e = NULL;
1398
+    while ((e = av_dict_get(unused_opts, "", e, AV_DICT_IGNORE_SUFFIX))) {
1399
+        const AVClass *class = avcodec_get_class();
1400
+        const AVOption *option = av_opt_find(&class, e->key, NULL, 0,
1401
+                                             AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ);
1402
+        if (!option)
1403
+            continue;
1404
+        if (!(option->flags & AV_OPT_FLAG_ENCODING_PARAM)) {
1405
+            av_log(NULL, AV_LOG_ERROR, "Codec AVOption %s (%s) specified for "
1406
+                   "output file #%d (%s) is not an encoding option.\n", e->key,
1407
+                   option->help ? option->help : "", nb_output_files - 1,
1408
+                   filename);
1409
+            exit(1);
1410
+        }
1411
+
1412
+        av_log(NULL, AV_LOG_WARNING, "Codec AVOption %s (%s) specified for "
1413
+               "output file #%d (%s) has not been used for any stream. The most "
1414
+               "likely reason is either wrong type (e.g. a video option with "
1415
+               "no video streams) or that it is a private option of some encoder "
1416
+               "which was not actually used for any stream.\n", e->key,
1417
+               option->help ? option->help : "", nb_output_files - 1, filename);
1418
+    }
1419
+    av_dict_free(&unused_opts);
1420
+
1387 1421
     /* check filename in case of an image number is expected */
1388 1422
     if (oc->oformat->flags & AVFMT_NEEDNUMBER) {
1389 1423
         if (!av_filename_number_test(oc->filename)) {