lavf/mux: add avformat_init_output

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.
This commit is contained in:
Rodger Combs 2016-06-24 22:02:50 -05:00
parent 8a24e03684
commit a246fef163
No known key found for this signature in database
GPG Key ID: E3E54DCDCD3CB843
5 changed files with 100 additions and 17 deletions

View File

@ -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()

View File

@ -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.
*

View File

@ -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 {

View File

@ -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)

View File

@ -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, \