diff --git a/doc/APIchanges b/doc/APIchanges index 502ab3f71b..5017eb41fe 100644 --- a/doc/APIchanges +++ b/doc/APIchanges @@ -15,6 +15,9 @@ libavutil: 2015-08-28 API changes, most recent first: +2016-10-24 - xxxxxxx - lavf 57.54.100 - avformat.h + Add avformat_init_output() and AVSTREAM_INIT_IN_ macros + 2016-10-22 - xxxxxxx - lavu 55.33.100 - avassert.h Add av_assert0_fpu() / av_assert2_fpu() diff --git a/libavformat/avformat.h b/libavformat/avformat.h index 057f8c58aa..82ca7277ae 100644 --- a/libavformat/avformat.h +++ b/libavformat/avformat.h @@ -618,6 +618,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 *); @@ -2374,6 +2376,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. @@ -2385,13 +2391,37 @@ 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. * diff --git a/libavformat/internal.h b/libavformat/internal.h index 95776a09f5..da64c641a7 100644 --- a/libavformat/internal.h +++ b/libavformat/internal.h @@ -130,6 +130,16 @@ struct AVFormatInternal { * Timestamp of the end of the shortest stream. */ int64_t shortest_end; + + /** + * 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 bbfc0fccb8..06d87dec7f 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; @@ -493,31 +496,64 @@ static int write_header_internal(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->check_bitstream && s->flags & AVFMT_FLAG_AUTO_BSF)) { ret = write_header_internal(s); if (ret < 0) goto fail; } - if ((ret = init_pts(s)) < 0) - goto fail; + if (!s->internal->streams_initialized) { + if ((ret = init_pts(s)) < 0) + goto fail; - 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; fail: if (s->oformat->deinit) @@ -1292,6 +1328,10 @@ fail: if (s->oformat->deinit) s->oformat->deinit(s); + s->internal->header_written = + s->internal->initialized = + s->internal->streams_initialized = 0; + if (s->pb) avio_flush(s->pb); if (ret == 0) diff --git a/libavformat/version.h b/libavformat/version.h index 88b69e968c..addff03f45 100644 --- a/libavformat/version.h +++ b/libavformat/version.h @@ -32,7 +32,7 @@ // Major bumping may affect Ticket5467, 5421, 5451(compatibility with Chromium) // Also please add any ticket numbers that you believe might be affected here #define LIBAVFORMAT_VERSION_MAJOR 57 -#define LIBAVFORMAT_VERSION_MINOR 53 +#define LIBAVFORMAT_VERSION_MINOR 54 #define LIBAVFORMAT_VERSION_MICRO 100 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \