This allows a consumer to run the muxer's init function without actually writing the header, which is useful in chained muxers that support automatic bitstream filtering. --- libavformat/avformat.h | 34 +++++++++++++++++++++++++-- libavformat/internal.h | 10 ++++++++ libavformat/mux.c | 64 +++++++++++++++++++++++++++++++++++++++----------- libavformat/version.h | 4 ++-- 4 files changed, 94 insertions(+), 18 deletions(-)
diff --git a/libavformat/avformat.h b/libavformat/avformat.h index d659ee4..d6b0b26 100644 --- a/libavformat/avformat.h +++ b/libavformat/avformat.h @@ -616,6 +616,8 @@ typedef struct AVOutputFormat { * AVStream parameters that need to be set before packets are sent. * This method must not write output. * + * Return 0 if streams were fully configured, 1 if not, negative AVERROR on failure + * * Any allocations made here must be freed in deinit(). */ int (*init)(struct AVFormatContext *); @@ -2363,6 +2365,10 @@ void avformat_close_input(AVFormatContext **s); * @addtogroup lavf_encoding * @{ */ + +#define AVSTREAM_INIT_IN_WRITE_HEADER 0 ///< stream parameters initialized in avformat_write_header +#define AVSTREAM_INIT_IN_INIT_OUTPUT 1 ///< stream parameters initialized in avformat_init_output + /** * Allocate the stream private data and write the stream header to * an output media file. @@ -2374,14 +2380,38 @@ void avformat_close_input(AVFormatContext **s); * On return this parameter will be destroyed and replaced with a dict containing * options that were not found. May be NULL. * - * @return 0 on success, negative AVERROR on failure. + * @return AVSTREAM_INIT_IN_WRITE_HEADER on success if the codec had not already been fully initialized in avformat_init, + * AVSTREAM_INIT_IN_INIT_OUTPUT on success if the codec had already been fully initialized in avformat_init, + * negative AVERROR on failure. * - * @see av_opt_find, av_dict_set, avio_open, av_oformat_next. + * @see av_opt_find, av_dict_set, avio_open, av_oformat_next, avformat_init_output. */ av_warn_unused_result int avformat_write_header(AVFormatContext *s, AVDictionary **options); /** + * Allocate the stream private data and initialize the codec, but do not write the header. + * May optionally be used before avformat_write_header to initialize stream parameters + * before actually writing the header. + * If using this function, do not pass the same options to avformat_write_header. + * + * @param s Media file handle, must be allocated with avformat_alloc_context(). + * Its oformat field must be set to the desired output format; + * Its pb field must be set to an already opened AVIOContext. + * @param options An AVDictionary filled with AVFormatContext and muxer-private options. + * On return this parameter will be destroyed and replaced with a dict containing + * options that were not found. May be NULL. + * + * @return AVSTREAM_INIT_IN_WRITE_HEADER on success if the codec requires avformat_write_header to fully initialize, + * AVSTREAM_INIT_IN_INIT_OUTPUT on success if the codec has been fully initialized, + * negative AVERROR on failure. + * + * @see av_opt_find, av_dict_set, avio_open, av_oformat_next, avformat_write_header. + */ +av_warn_unused_result +int avformat_init_output(AVFormatContext *s, AVDictionary **options); + +/** * Write a packet to an output media file. * * This function passes the packet directly to the muxer, without any buffering diff --git a/libavformat/internal.h b/libavformat/internal.h index 52f9eb6..b5966ff 100644 --- a/libavformat/internal.h +++ b/libavformat/internal.h @@ -124,6 +124,16 @@ struct AVFormatInternal { * Whether or not a header has already been written */ int header_written; + + /** + * Whether or not avformat_init_output has already been called + */ + int initialized; + + /** + * Whether or not avformat_init_output fully initialized streams + */ + int streams_initialized; }; struct AVStreamInternal { diff --git a/libavformat/mux.c b/libavformat/mux.c index 071eac1..3d618d8 100644 --- a/libavformat/mux.c +++ b/libavformat/mux.c @@ -423,10 +423,13 @@ FF_ENABLE_DEPRECATION_WARNINGS *options = tmp; } - if (s->oformat->init && (ret = s->oformat->init(s)) < 0) { - if (s->oformat->deinit) - s->oformat->deinit(s); - goto fail; + if (s->oformat->init) { + if ((ret = s->oformat->init(s)) < 0) { + if (s->oformat->deinit) + s->oformat->deinit(s); + return ret; + } + return ret == 0; } return 0; @@ -473,13 +476,44 @@ static int init_pts(AVFormatContext *s) return 0; } -int avformat_write_header(AVFormatContext *s, AVDictionary **options) +int avformat_init_output(AVFormatContext *s, AVDictionary **options) { int ret = 0; if ((ret = init_muxer(s, options)) < 0) return ret; + s->internal->initialized = 1; + s->internal->streams_initialized = ret; + + if (s->oformat->init && ret) { + if ((ret = init_pts(s)) < 0) + return ret; + + if (s->avoid_negative_ts < 0) { + av_assert2(s->avoid_negative_ts == AVFMT_AVOID_NEG_TS_AUTO); + if (s->oformat->flags & (AVFMT_TS_NEGATIVE | AVFMT_NOTIMESTAMPS)) { + s->avoid_negative_ts = 0; + } else + s->avoid_negative_ts = AVFMT_AVOID_NEG_TS_MAKE_NON_NEGATIVE; + } + + return AVSTREAM_INIT_IN_INIT_OUTPUT; + } + + return AVSTREAM_INIT_IN_WRITE_HEADER; +} + +int avformat_write_header(AVFormatContext *s, AVDictionary **options) +{ + int ret = 0; + int already_initialized = s->internal->initialized; + int streams_already_initialized = s->internal->streams_initialized; + + if (!already_initialized) + if ((ret = avformat_init_output(s, options)) < 0) + return ret; + if (s->oformat->write_header && !(s->oformat->check_bitstream && s->flags & AVFMT_FLAG_AUTO_BSF)) { ret = s->oformat->write_header(s); if (ret >= 0 && s->pb && s->pb->error < 0) @@ -494,18 +528,20 @@ int avformat_write_header(AVFormatContext *s, AVDictionary **options) s->internal->header_written = 1; } - if ((ret = init_pts(s)) < 0) - return ret; + if (!s->internal->streams_initialized) { + if ((ret = init_pts(s)) < 0) + return ret; - if (s->avoid_negative_ts < 0) { - av_assert2(s->avoid_negative_ts == AVFMT_AVOID_NEG_TS_AUTO); - if (s->oformat->flags & (AVFMT_TS_NEGATIVE | AVFMT_NOTIMESTAMPS)) { - s->avoid_negative_ts = 0; - } else - s->avoid_negative_ts = AVFMT_AVOID_NEG_TS_MAKE_NON_NEGATIVE; + if (s->avoid_negative_ts < 0) { + av_assert2(s->avoid_negative_ts == AVFMT_AVOID_NEG_TS_AUTO); + if (s->oformat->flags & (AVFMT_TS_NEGATIVE | AVFMT_NOTIMESTAMPS)) { + s->avoid_negative_ts = 0; + } else + s->avoid_negative_ts = AVFMT_AVOID_NEG_TS_MAKE_NON_NEGATIVE; + } } - return 0; + return streams_already_initialized; } #define AV_PKT_FLAG_UNCODED_FRAME 0x2000 diff --git a/libavformat/version.h b/libavformat/version.h index c92a23f..11fbbb3 100644 --- a/libavformat/version.h +++ b/libavformat/version.h @@ -32,8 +32,8 @@ // When bumping major check Ticket5467, 5421 for regressing // Also please add any ticket numbers that you belive might regress here #define LIBAVFORMAT_VERSION_MAJOR 57 -#define LIBAVFORMAT_VERSION_MINOR 37 -#define LIBAVFORMAT_VERSION_MICRO 101 +#define LIBAVFORMAT_VERSION_MINOR 38 +#define LIBAVFORMAT_VERSION_MICRO 100 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \ LIBAVFORMAT_VERSION_MINOR, \ -- 2.8.3 _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel