|
|
@@ -151,6 +151,24 @@ static void init_options(OptionsContext *o, int is_input) |
|
|
|
o->chapters_input_file = INT_MAX; |
|
|
|
} |
|
|
|
|
|
|
|
/* return a copy of the input with the stream specifiers removed from the keys */ |
|
|
|
static AVDictionary *strip_specifiers(AVDictionary *dict) |
|
|
|
{ |
|
|
|
AVDictionaryEntry *e = NULL; |
|
|
|
AVDictionary *ret = NULL; |
|
|
|
|
|
|
|
while ((e = av_dict_get(dict, "", e, AV_DICT_IGNORE_SUFFIX))) { |
|
|
|
char *p = strchr(e->key, ':'); |
|
|
|
|
|
|
|
if (p) |
|
|
|
*p = 0; |
|
|
|
av_dict_set(&ret, e->key, e->value, 0); |
|
|
|
if (p) |
|
|
|
*p = ':'; |
|
|
|
} |
|
|
|
return ret; |
|
|
|
} |
|
|
|
|
|
|
|
static int opt_sameq(void *optctx, const char *opt, const char *arg) |
|
|
|
{ |
|
|
|
av_log(NULL, AV_LOG_ERROR, "Option '%s' was removed. " |
|
|
@@ -705,6 +723,8 @@ static int open_input_file(OptionsContext *o, const char *filename) |
|
|
|
int64_t timestamp; |
|
|
|
uint8_t buf[128]; |
|
|
|
AVDictionary **opts; |
|
|
|
AVDictionary *unused_opts = NULL; |
|
|
|
AVDictionaryEntry *e = NULL; |
|
|
|
int orig_nb_streams; // number of streams before avformat_find_stream_info |
|
|
|
char * video_codec_name = NULL; |
|
|
|
char * audio_codec_name = NULL; |
|
|
@@ -831,6 +851,39 @@ static int open_input_file(OptionsContext *o, const char *filename) |
|
|
|
f->nb_streams = ic->nb_streams; |
|
|
|
f->rate_emu = o->rate_emu; |
|
|
|
|
|
|
|
/* check if all codec options have been used */ |
|
|
|
unused_opts = strip_specifiers(o->g->codec_opts); |
|
|
|
for (i = f->ist_index; i < nb_input_streams; i++) { |
|
|
|
e = NULL; |
|
|
|
while ((e = av_dict_get(input_streams[i]->opts, "", e, |
|
|
|
AV_DICT_IGNORE_SUFFIX))) |
|
|
|
av_dict_set(&unused_opts, e->key, NULL, 0); |
|
|
|
} |
|
|
|
|
|
|
|
e = NULL; |
|
|
|
while ((e = av_dict_get(unused_opts, "", e, AV_DICT_IGNORE_SUFFIX))) { |
|
|
|
const AVClass *class = avcodec_get_class(); |
|
|
|
const AVOption *option = av_opt_find(&class, e->key, NULL, 0, |
|
|
|
AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ); |
|
|
|
if (!option) |
|
|
|
continue; |
|
|
|
if (!(option->flags & AV_OPT_FLAG_DECODING_PARAM)) { |
|
|
|
av_log(NULL, AV_LOG_ERROR, "Codec AVOption %s (%s) specified for " |
|
|
|
"input file #%d (%s) is not a decoding option.\n", e->key, |
|
|
|
option->help ? option->help : "", nb_input_files - 1, |
|
|
|
filename); |
|
|
|
exit(1); |
|
|
|
} |
|
|
|
|
|
|
|
av_log(NULL, AV_LOG_WARNING, "Codec AVOption %s (%s) specified for " |
|
|
|
"input file #%d (%s) has not been used for any stream. The most " |
|
|
|
"likely reason is either wrong type (e.g. a video option with " |
|
|
|
"no video streams) or that it is a private option of some decoder " |
|
|
|
"which was not actually used for any stream.\n", e->key, |
|
|
|
option->help ? option->help : "", nb_input_files - 1, filename); |
|
|
|
} |
|
|
|
av_dict_free(&unused_opts); |
|
|
|
|
|
|
|
for (i = 0; i < o->nb_dump_attachment; i++) { |
|
|
|
int j; |
|
|
|
|
|
|
@@ -1452,6 +1505,8 @@ static int open_output_file(OptionsContext *o, const char *filename) |
|
|
|
OutputFile *of; |
|
|
|
OutputStream *ost; |
|
|
|
InputStream *ist; |
|
|
|
AVDictionary *unused_opts = NULL; |
|
|
|
AVDictionaryEntry *e = NULL; |
|
|
|
|
|
|
|
if (configure_complex_filters() < 0) { |
|
|
|
av_log(NULL, AV_LOG_FATAL, "Error configuring filters.\n"); |
|
|
@@ -1701,6 +1756,40 @@ loop_end: |
|
|
|
of->shortest = o->shortest; |
|
|
|
av_dict_copy(&of->opts, o->g->format_opts, 0); |
|
|
|
|
|
|
|
|
|
|
|
/* check if all codec options have been used */ |
|
|
|
unused_opts = strip_specifiers(o->g->codec_opts); |
|
|
|
for (i = of->ost_index; i < nb_output_streams; i++) { |
|
|
|
e = NULL; |
|
|
|
while ((e = av_dict_get(output_streams[i]->opts, "", e, |
|
|
|
AV_DICT_IGNORE_SUFFIX))) |
|
|
|
av_dict_set(&unused_opts, e->key, NULL, 0); |
|
|
|
} |
|
|
|
|
|
|
|
e = NULL; |
|
|
|
while ((e = av_dict_get(unused_opts, "", e, AV_DICT_IGNORE_SUFFIX))) { |
|
|
|
const AVClass *class = avcodec_get_class(); |
|
|
|
const AVOption *option = av_opt_find(&class, e->key, NULL, 0, |
|
|
|
AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ); |
|
|
|
if (!option) |
|
|
|
continue; |
|
|
|
if (!(option->flags & AV_OPT_FLAG_ENCODING_PARAM)) { |
|
|
|
av_log(NULL, AV_LOG_ERROR, "Codec AVOption %s (%s) specified for " |
|
|
|
"output file #%d (%s) is not an encoding option.\n", e->key, |
|
|
|
option->help ? option->help : "", nb_output_files - 1, |
|
|
|
filename); |
|
|
|
exit(1); |
|
|
|
} |
|
|
|
|
|
|
|
av_log(NULL, AV_LOG_WARNING, "Codec AVOption %s (%s) specified for " |
|
|
|
"output file #%d (%s) has not been used for any stream. The most " |
|
|
|
"likely reason is either wrong type (e.g. a video option with " |
|
|
|
"no video streams) or that it is a private option of some encoder " |
|
|
|
"which was not actually used for any stream.\n", e->key, |
|
|
|
option->help ? option->help : "", nb_output_files - 1, filename); |
|
|
|
} |
|
|
|
av_dict_free(&unused_opts); |
|
|
|
|
|
|
|
/* check filename in case of an image number is expected */ |
|
|
|
if (oc->oformat->flags & AVFMT_NEEDNUMBER) { |
|
|
|
if (!av_filename_number_test(oc->filename)) { |
|
|
|