avformat_alloc_input_context function analogous to avformat_alloc_output_context2, except that it does not take a filename argument as guessing the format by just the filename does not make sense. avformat_alloc_input_context can be used e.g. with the avdevice capabilities API, which needs an allocated input format with priv_data (and default options) set, but device should not be opened.
Added some checks to avformat_open_input, for the case that a AVFormatContext* allocated by avformat_alloc_input_context is provided: 1. if avformat_open_input's AVInputFormat *fmt argument is not NULL, clean up any already set s->iformat 2. if s->url is already set and avformat_open_input's filename argument is not NULL, free current url and replace by provided filename 3. if s->url is already set and avformat_open_input's filename argument is NULL, do not set s->url to "", but keep current url 4. if s->priv_data has already been allocated, do not do so again. 4b. do reset options to default and apply provided options (if any) 5. add 4b to docs of avformat_open_input Bumping avformat version. Signed-off-by: Diederick Niehorster <dcni...@gmail.com> --- libavformat/avformat.h | 29 +++++++++++++++-- libavformat/utils.c | 74 ++++++++++++++++++++++++++++++++++++++---- 2 files changed, 94 insertions(+), 9 deletions(-) diff --git a/libavformat/avformat.h b/libavformat/avformat.h index a276aad64a..a0a20b9045 100644 --- a/libavformat/avformat.h +++ b/libavformat/avformat.h @@ -1889,6 +1889,26 @@ AVProgram *av_new_program(AVFormatContext *s, int id); * @} */ + /** + * Allocate an AVFormatContext for an input format. + * avformat_free_context() can be used to free the context and + * everything allocated by the framework within it. NB: in general + * the correct format cannot be known (unless the user has extra + * information) until the file is opened. If forcing a format by + * this method, but it turns out not to match the file's format + * upon avformat_open_input(), the latter will throw an error. + * + * @param *ctx is set to the created format context, or to NULL in + * case of failure + * @param iformat format to use for allocating the context, if NULL + * format_name is used instead + * @param format_name the name of input format to use for allocating the + * context + * @return >= 0 in case of success, a negative AVERROR code in case of + * failure + */ +int avformat_alloc_input_context(AVFormatContext **ctx, const AVInputFormat *iformat, + const char *format_name); /** * Allocate an AVFormatContext for an output format. @@ -1984,9 +2004,9 @@ int av_probe_input_buffer(AVIOContext *pb, const AVInputFormat **fmt, * Open an input stream and read the header. The codecs are not opened. * The stream must be closed with avformat_close_input(). * - * @param ps Pointer to user-supplied AVFormatContext (allocated by avformat_alloc_context). - * May be a pointer to NULL, in which case an AVFormatContext is allocated by this - * function and written into ps. + * @param ps Pointer to user-supplied AVFormatContext (allocated by avformat_alloc_context, or + * avformat_alloc_input_context). May be a pointer to NULL, in which case an + * AVFormatContext is allocated by this function and written into ps. * Note that a user-supplied AVFormatContext will be freed on failure. * @param url URL of the stream to open. * @param fmt If non-NULL, this parameter forces a specific input format. @@ -1994,6 +2014,9 @@ int av_probe_input_buffer(AVIOContext *pb, const AVInputFormat **fmt, * @param options A dictionary filled with AVFormatContext and demuxer-private options. * On return this parameter will be destroyed and replaced with a dict containing * options that were not found. May be NULL. + * Note that if a AVFormatContext allocated by avformat_alloc_input_context + * is provided, any demuxer-private options will be overwritten by their defaults + * before applying this new set of demuxer-private options, if any. * * @return 0 on success, a negative AVERROR on failure. * diff --git a/libavformat/utils.c b/libavformat/utils.c index 0df14682a4..34e21d6450 100644 --- a/libavformat/utils.c +++ b/libavformat/utils.c @@ -478,6 +478,56 @@ static int update_stream_avctx(AVFormatContext *s) } +int avformat_alloc_input_context(AVFormatContext **avctx, const AVInputFormat *iformat, + const char *format) +{ + AVFormatContext *s = avformat_alloc_context(); + int ret = 0; + + *avctx = NULL; + if (!s) + goto nomem; + + if (!iformat) { + if (format) { + iformat = av_find_input_format(format); + if (!iformat) { + av_log(s, AV_LOG_ERROR, "Requested input format '%s' not found\n", format); + ret = AVERROR(EINVAL); + goto error; + } + } + else { + av_log(s, AV_LOG_ERROR, "You should provide an input format or the name of an input format when calling this function\n"); + ret = AVERROR(EINVAL); + goto error; + } + } + + s->iformat = iformat; + if (s->iformat->priv_data_size > 0) { + s->priv_data = av_mallocz(s->iformat->priv_data_size); + if (!s->priv_data) + goto nomem; + if (s->iformat->priv_class) { + *(const AVClass **) s->priv_data = s->iformat->priv_class; + av_opt_set_defaults(s->priv_data); + } + } + else + s->priv_data = NULL; + + *avctx = s; + return 0; +nomem: + av_log(s, AV_LOG_ERROR, "Out of memory\n"); + ret = AVERROR(ENOMEM); +error: + avformat_free_context(s); + return ret; +} + + int avformat_open_input(AVFormatContext **ps, const char *filename, const AVInputFormat *fmt, AVDictionary **options) { @@ -492,8 +542,14 @@ int avformat_open_input(AVFormatContext **ps, const char *filename, av_log(NULL, AV_LOG_ERROR, "Input context has not been properly allocated by avformat_alloc_context() and is not NULL either\n"); return AVERROR(EINVAL); } - if (fmt) + if (fmt) { + if (s->iformat) { + if (s->iformat->priv_class && s->priv_data) + av_opt_free(s->priv_data); + av_freep(&s->priv_data); + } s->iformat = fmt; + } if (options) av_dict_copy(&tmp, *options, 0); @@ -504,7 +560,9 @@ int avformat_open_input(AVFormatContext **ps, const char *filename, if ((ret = av_opt_set_dict(s, &tmp)) < 0) goto fail; - if (!(s->url = av_strdup(filename ? filename : ""))) { + if (filename && s->url) + av_freep(&s->url); + if (!s->url && !(s->url = av_strdup(filename ? filename : ""))) { ret = AVERROR(ENOMEM); goto fail; } @@ -547,12 +605,16 @@ int avformat_open_input(AVFormatContext **ps, const char *filename, s->duration = s->start_time = AV_NOPTS_VALUE; - /* Allocate private data. */ + /* Allocate private data and set options. */ if (s->iformat->priv_data_size > 0) { - if (!(s->priv_data = av_mallocz(s->iformat->priv_data_size))) { - ret = AVERROR(ENOMEM); - goto fail; + /* allocate if not already allocated */ + if (!s->priv_data) { + if (!(s->priv_data = av_mallocz(s->iformat->priv_data_size))) { + ret = AVERROR(ENOMEM); + goto fail; + } } + /* Overwrite any options already set (1: back to defaults, 2: apply options, if any) */ if (s->iformat->priv_class) { *(const AVClass **) s->priv_data = s->iformat->priv_class; av_opt_set_defaults(s->priv_data); -- 2.28.0.windows.1 _______________________________________________ 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".