Quite low latency streaming would enjoy sparing the muxer setup time when possible. The segment muxer would be simplified a lot and the mpegts corner case would be solved clearly. Any application using more than once a muxer could spare a deinit/init cycle. ---
Now with documentation and both ends covered libavformat/avformat.h | 73 +++++++++++++++++++++++++++++++ libavformat/mux.c | 115 ++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 177 insertions(+), 11 deletions(-) diff --git a/libavformat/avformat.h b/libavformat/avformat.h index f9f39a6..32db1b3 100644 --- a/libavformat/avformat.h +++ b/libavformat/avformat.h @@ -407,7 +407,22 @@ typedef struct AVOutputFormat { */ int priv_data_size; + /** + * Initialize the muxer context and write the header. + * @deprecated implement the split functions below. + */ int (*write_header)(struct AVFormatContext *); + + /** + * Initialize the muxer context. + */ + int (*init)(struct AVFormatContext *); + + /** + * Write the header, requires an initialized context. + */ + int (*write_header2)(struct AVFormatContext *); + /** * Write a packet. If AVFMT_ALLOW_FLUSH is set in flags, * pkt can be NULL in order to flush data buffered in the muxer. @@ -416,7 +431,13 @@ typedef struct AVOutputFormat { * data. */ int (*write_packet)(struct AVFormatContext *, AVPacket *pkt); + int (*write_trailer)(struct AVFormatContext *); + + int (*write_trailer2)(struct AVFormatContext *); + + int (*deinit)(struct AVFormatContext *); + /** * Currently only used to set pixel format if not YUV420P. */ @@ -1427,6 +1448,35 @@ void avformat_close_input(AVFormatContext **s); int avformat_write_header(AVFormatContext *s, AVDictionary **options); /** + * Allocate the stream private data. + * + * @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 openened 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 0 on success, negative AVERROR on failure. + * + * @see av_opt_find, av_dict_set, avio_open, av_oformat_next. + */ +int avformat_mux_init(AVFormatContext *s, AVDictionary **options); + +/** + * Write the stream header to an output media file. + * + * @param s Media file handle, must be initialized by avformat_mux_init(). + * Its oformat field must be set to the desired output format; + * Its pb field must be set to an already openened AVIOContext. + * + * @return 0 on success, negative AVERROR on failure. + * + * @see avio_open, av_oformat_next, avformat_mux_init. + */ +int avformat_mux_header(AVFormatContext *s); + +/** * Write a packet to an output media file. * * The packet shall contain one audio or video frame. @@ -1494,6 +1544,29 @@ int av_interleave_packet_per_dts(AVFormatContext *s, AVPacket *out, int av_write_trailer(AVFormatContext *s); /** + * Write the stream trailer to an output media file. + * + * May only be called after a successful call to av_write_header or + * avformat_mux_init. + * + * Can be safely called multiple times. + * + * @param s media file handle + * @return 0 if OK, AVERROR_xxx on error + */ +int avformat_mux_trailer(AVFormatContext *s); + +/** + * Free the file private data. + * + * May only be called after a successful call to av_write_header or + * avformat_mux_init. + * + * @param s media file handle + */ +void avformat_mux_deinit(AVFormatContext *s); + +/** * Return the output format in the list of registered output formats * which best matches the provided parameters, or return NULL if * there is no match. diff --git a/libavformat/mux.c b/libavformat/mux.c index 96eecb5..28074fa 100644 --- a/libavformat/mux.c +++ b/libavformat/mux.c @@ -303,6 +303,17 @@ int avformat_write_header(AVFormatContext *s, AVDictionary **options) ret = s->oformat->write_header(s); if (ret < 0) return ret; + } else { + if (s->oformat->init) { + ret = s->oformat->init(s); + if (ret < 0) + return ret; + } + if (s->oformat->write_header2) { + ret = s->oformat->write_header2(s); + if (ret < 0) + return ret; + } } if ((ret = init_pts(s) < 0)) @@ -311,6 +322,38 @@ int avformat_write_header(AVFormatContext *s, AVDictionary **options) return 0; } +int avformat_mux_init(AVFormatContext *s, AVDictionary **options) +{ + int ret = 0; + + if (ret = init_muxer(s, options)) + return ret; + + if (s->oformat->init) { + ret = s->oformat->init(s); + if (ret < 0) + return ret; + } + + if ((ret = init_pts(s) < 0)) + return ret; + + return 0; +} + +int avformat_mux_header(AVFormatContext *s) +{ + int ret = 0; + + if (s->oformat->write_header2) { + ret = s->oformat->write_header2(s); + if (ret < 0) + return ret; + } + + return 0; +} + //FIXME merge with compute_pkt_fields static int compute_pkt_fields2(AVFormatContext *s, AVStream *st, AVPacket *pkt) { @@ -562,15 +605,14 @@ int av_interleaved_write_frame(AVFormatContext *s, AVPacket *pkt) } } -int av_write_trailer(AVFormatContext *s) +static int flush_trailing_packets(AVFormatContext *s) { - int ret, i; + int ret = 0; - for (;; ) { + for (;;) { AVPacket pkt; ret = interleave_packet(s, &pkt, NULL, 1); - if (ret < 0) //FIXME cleanup needed for ret<0 ? - goto fail; + //FIXME cleanup needed for ret < 0 ? if (!ret) break; @@ -581,22 +623,73 @@ int av_write_trailer(AVFormatContext *s) av_free_packet(&pkt); if (ret < 0) - goto fail; + break; } - if (s->oformat->write_trailer) - ret = s->oformat->write_trailer(s); + return ret; +} - if (!(s->oformat->flags & AVFMT_NOFILE)) - avio_flush(s->pb); +void avformat_mux_deinit(AVFormatContext *s) +{ + int i; + + if (s->oformat->deinit) { + s->oformat->deinit(s); + } -fail: for (i = 0; i < s->nb_streams; i++) { av_freep(&s->streams[i]->priv_data); av_freep(&s->streams[i]->index_entries); } + if (s->oformat->priv_class) av_opt_free(s->priv_data); av_freep(&s->priv_data); +} + +int avformat_mux_trailer(AVFormatContext *s) +{ + int ret; + + ret = flush_trailing_packets(s); + if (ret < 0) + return ret; + + if (s->oformat->write_trailer2) { + ret = s->oformat->write_trailer2(s); + if (ret < 0) + return ret; + } + + if (!(s->oformat->flags & AVFMT_NOFILE)) + avio_flush(s->pb); + return ret; } + +int av_write_trailer(AVFormatContext *s) +{ + int ret; + + ret = flush_trailing_packets(s); + if (ret < 0) + goto fail; + + if (s->oformat->write_trailer) + ret = s->oformat->write_trailer(s); + else { + if (s->oformat->write_trailer2) { + ret = s->oformat->write_trailer2(s); + if (ret < 0) + goto fail; + } + } + + if (!(s->oformat->flags & AVFMT_NOFILE)) + avio_flush(s->pb); + +fail: + avformat_mux_deinit(s); + return ret; +} + -- 1.7.12 _______________________________________________ libav-devel mailing list libav-devel@libav.org https://lists.libav.org/mailman/listinfo/libav-devel