This way protocol or format related options can be set for all of the files opened during concatenation both globally as well as per-file. --- doc/demuxers.texi | 12 +++++++ libavformat/concatdec.c | 69 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 80 insertions(+), 1 deletion(-)
diff --git a/doc/demuxers.texi b/doc/demuxers.texi index 3c15ab9eee..0b4ce9a36c 100644 --- a/doc/demuxers.texi +++ b/doc/demuxers.texi @@ -149,6 +149,14 @@ Metadata of the packets of the file. The specified metadata will be set for each file packet. You can specify this directive multiple times to add multiple metadata entries. +@item @code{input_options @var{key=value:key2=value2}} +Input options passed on when reading a specific file, using a :-separated list +of key=value pairs. Requires @code{safe} to be non-positive. Global options for +all files can be set with the @code{input_options} demuxer option. When using +both options on the list of files as well as globally via the demuxer option, +the global ones get applied first and the file-specific options are then applied +on top of them. + @item @code{stream} Introduce a stream in the virtual file. All subsequent stream-related directives apply to the last introduced @@ -204,6 +212,10 @@ expressed in microseconds. The duration metadata is only set if it is known based on the concat file. The default is 0. +@item input_options +Input options to be passed on for all opened inputs using a :-separated list of +key=value pairs. + @end table @subsection Examples diff --git a/libavformat/concatdec.c b/libavformat/concatdec.c index 6d5b9914f9..f4e6609f12 100644 --- a/libavformat/concatdec.c +++ b/libavformat/concatdec.c @@ -52,6 +52,7 @@ typedef struct { int64_t outpoint; AVDictionary *metadata; int nb_streams; + AVDictionary *input_options; } ConcatFile; typedef struct { @@ -66,6 +67,7 @@ typedef struct { ConcatMatchMode stream_match_mode; unsigned auto_convert; int segment_time_metadata; + AVDictionary *input_options; } ConcatContext; static int concat_probe(const AVProbeData *probe) @@ -329,6 +331,7 @@ static int open_file(AVFormatContext *avf, unsigned fileno) { ConcatContext *cat = avf->priv_data; ConcatFile *file = &cat->files[fileno]; + AVDictionary *options = NULL; int ret; if (cat->avf) @@ -344,12 +347,37 @@ static int open_file(AVFormatContext *avf, unsigned fileno) if ((ret = ff_copy_whiteblacklists(cat->avf, avf)) < 0) return ret; - if ((ret = avformat_open_input(&cat->avf, file->url, NULL, NULL)) < 0 || + // Apply global AVOptions first + if (cat->input_options && + (ret = av_dict_copy(&options, cat->input_options, 0) < 0)) + return ret; + + // then apply file-specific AVOptions + if (file->input_options && + (ret = av_dict_copy(&options, file->input_options, 0) < 0)) + return ret; + + if ((ret = avformat_open_input(&cat->avf, file->url, NULL, &options)) < 0 || (ret = avformat_find_stream_info(cat->avf, NULL)) < 0) { av_log(avf, AV_LOG_ERROR, "Impossible to open '%s'\n", file->url); avformat_close_input(&cat->avf); + av_dict_free(&options); return ret; } + + if (av_dict_count(options)) { + AVDictionaryEntry *en = NULL; + + while ((en = av_dict_get(options, "", en, AV_DICT_IGNORE_SUFFIX))) { + av_log(avf, AV_LOG_WARNING, + "Option '%s' set to '%s' was ignored when opening %s " + "with the %s reader!\n", + en->key, en->value, file->url, cat->avf->iformat->name); + } + } + + av_dict_free(&options); + cat->cur_file = file; file->start_time = !fileno ? 0 : cat->files[fileno - 1].start_time + @@ -386,6 +414,7 @@ static int concat_read_close(AVFormatContext *avf) } av_freep(&cat->files[i].streams); av_dict_free(&cat->files[i].metadata); + av_dict_free(&cat->files[i].input_options); } if (cat->avf) avformat_close_input(&cat->avf); @@ -457,6 +486,41 @@ static int concat_read_header(AVFormatContext *avf) FAIL(AVERROR_INVALIDDATA); } av_freep(&metadata); + } else if (!strncmp(keyword, "input_options", 13)) { + if (!file) { + av_log(avf, AV_LOG_ERROR, "Line %d: %s without file\n", + line, keyword); + FAIL(AVERROR_INVALIDDATA); + } + + if (cat->safe > 0) { + av_log(avf, AV_LOG_ERROR, + "Line %d: Input options cannot be set in file list in " + " safe mode!\n", line); + FAIL(AVERROR(EPERM)); + } + + { + char *input_options = av_get_token((const char **)&cursor, + SPACE_CHARS); + if (!input_options) { + av_log(avf, AV_LOG_ERROR, + "Line %d: key=value pairs required!\n", line); + FAIL(AVERROR_INVALIDDATA); + } + + if ((ret = + av_dict_parse_string(&file->input_options, input_options, + "=", ":", 0)) < 0) { + av_log(avf, AV_LOG_ERROR, + "Line %d: failed to parse input options string\n", + line); + av_freep(&input_options); + FAIL(AVERROR_INVALIDDATA); + } + + av_freep(&input_options); + } } else if (!strcmp(keyword, "stream")) { if (!avformat_new_stream(avf, NULL)) FAIL(AVERROR(ENOMEM)); @@ -764,6 +828,9 @@ static const AVOption options[] = { OFFSET(auto_convert), AV_OPT_TYPE_BOOL, {.i64 = 1}, 0, 1, DEC }, { "segment_time_metadata", "output file segment start time and duration as packet metadata", OFFSET(segment_time_metadata), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, DEC }, + { "input_options", + "set options for all opened inputs using a :-separated list of key=value pairs", + OFFSET(input_options), AV_OPT_TYPE_DICT, { .str = NULL }, 0, 0, DEC }, { NULL } }; -- 2.29.2 _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".