This solves the problem discussed in https://ffmpeg.org/pipermail/ffmpeg-devel/2015-September/179238.html by allowing AVCodec::write_header to be delayed until after packets have been run through required bitstream filters in order to generate global extradata.
It also provides a mechanism by which a muxer can add a bitstream filter to a stream automatically, rather than prompting the user to do so. --- Changelog | 1 + doc/APIchanges | 3 +++ libavformat/avformat.h | 23 +++++++++++++++++++++++ libavformat/internal.h | 17 +++++++++++++++++ libavformat/mux.c | 47 +++++++++++++++++++++++++++++++++++++++++++++-- libavformat/version.h | 2 +- 6 files changed, 90 insertions(+), 3 deletions(-) diff --git a/Changelog b/Changelog index 98927cc..74f1a91 100644 --- a/Changelog +++ b/Changelog @@ -37,6 +37,7 @@ version <next>: - compensationdelay filter - acompressor filter - support encoding 16-bit RLE SGI images +- automatic bitstream filtering version 2.8: diff --git a/doc/APIchanges b/doc/APIchanges index 5b91bb4..eb017d4 100644 --- a/doc/APIchanges +++ b/doc/APIchanges @@ -14,6 +14,9 @@ libavutil: 2015-08-28 API changes, most recent first: +2015-11-30 - xxxxxxx - lavf 57.20.100 - avformat.h + Add automatic bitstream filtering; add av_apply_bitstream_filters() + 2015-11-29 - xxxxxxx - lavc 57.16.101 - avcodec.h Deprecate rtp_callback without replacement, i.e. it won't be possible to get image slices before the full frame is encoded any more. The libavformat diff --git a/libavformat/avformat.h b/libavformat/avformat.h index d94191e..edbf4cf 100644 --- a/libavformat/avformat.h +++ b/libavformat/avformat.h @@ -600,6 +600,29 @@ typedef struct AVOutputFormat { */ int (*free_device_capabilities)(struct AVFormatContext *s, struct AVDeviceCapabilitiesQuery *caps); enum AVCodecID data_codec; /**< default data codec */ + /** + * Initialize format. May allocate data here, and set any AVFormatContext or + * AVStream parameters that need to be set before packets are sent. + * This method must not write output. + * + * Any allocations made here must be freed in deinit(). + */ + int (*init)(struct AVFormatContext *); + /** + * Deinitialize format. If present, this is called whenever the muxer is being + * destroyed, regardless of whether or not the header has been written. + * + * If a trailer is being written, this is called after write_trailer(). + * + * This is called if init() fails as well. + */ + void (*deinit)(struct AVFormatContext *); + /** + * Set up any necessary bitstream filtering and extract any extra data needed + * for the global header. + * Return 0 if more packets from this stream must be checked; 1 if not. + */ + int (*check_bitstream)(struct AVFormatContext *, const AVPacket *pkt); } AVOutputFormat; /** * @} diff --git a/libavformat/internal.h b/libavformat/internal.h index ee86094..5ed548e 100644 --- a/libavformat/internal.h +++ b/libavformat/internal.h @@ -117,6 +117,11 @@ struct AVFormatInternal { int inject_global_side_data; int avoid_negative_ts_use_pts; + + /** + * Whether or not a header has already been written + */ + int header_written; }; struct AVStreamInternal { @@ -125,6 +130,18 @@ struct AVStreamInternal { * from dts. */ int reorder; + + /** + * bitstream filter to run on stream + * - encoding: Set by muxer using ff_stream_add_bitstream_filter + * - decoding: unused + */ + AVBitStreamFilterContext *bsfc; + + /** + * Whether or not check_bitstream should still be run on each packet + */ + int bitstream_checked; }; #ifdef __GNUC__ diff --git a/libavformat/mux.c b/libavformat/mux.c index 05d4170..f3abe0d 100644 --- a/libavformat/mux.c +++ b/libavformat/mux.c @@ -405,6 +405,11 @@ FF_ENABLE_DEPRECATION_WARNINGS *options = tmp; } + if (s->oformat->init && (ret = s->oformat->init(s)) < 0) { + s->oformat->deinit(s); + goto fail; + } + return 0; fail: @@ -456,7 +461,7 @@ int avformat_write_header(AVFormatContext *s, AVDictionary **options) if ((ret = init_muxer(s, options)) < 0) return ret; - if (s->oformat->write_header) { + if (s->oformat->write_header && !s->oformat->check_bitstream) { ret = s->oformat->write_header(s); if (ret >= 0 && s->pb && s->pb->error < 0) ret = s->pb->error; @@ -464,6 +469,7 @@ int avformat_write_header(AVFormatContext *s, AVDictionary **options) return ret; if (s->flush_packets && s->pb && s->pb->error >= 0 && s->flags & AVFMT_FLAG_FLUSH_PACKETS) avio_flush(s->pb); + s->internal->header_written = 1; } if ((ret = init_pts(s)) < 0) @@ -1021,6 +1027,17 @@ int av_interleaved_write_frame(AVFormatContext *s, AVPacket *pkt) ret = AVERROR(EINVAL); goto fail; } + + if (s->oformat->check_bitstream) { + if (!st->internal->bitstream_checked) { + if ((ret = s->oformat->check_bitstream(s, pkt)) < 0) + goto fail; + else if (ret == 1) + st->internal->bitstream_checked = 1; + } + } + + av_apply_bitstream_filters(st->codec, pkt, st->internal->bsfc); } else { av_log(s, AV_LOG_TRACE, "av_interleaved_write_frame FLUSH\n"); flush = 1; @@ -1037,10 +1054,22 @@ int av_interleaved_write_frame(AVFormatContext *s, AVPacket *pkt) if (ret <= 0) //FIXME cleanup needed for ret<0 ? return ret; + if (!s->internal->header_written && s->oformat->write_header) { + ret = s->oformat->write_header(s); + if (ret >= 0 && s->pb && s->pb->error < 0) + ret = s->pb->error; + if (ret < 0) + goto fail2; + if (s->flush_packets && s->pb && s->pb->error >= 0 && s->flags & AVFMT_FLAG_FLUSH_PACKETS) + avio_flush(s->pb); + s->internal->header_written = 1; + } + ret = write_packet(s, &opkt); if (ret >= 0) s->streams[opkt.stream_index]->nb_frames++; +fail2: av_packet_unref(&opkt); if (ret < 0) @@ -1077,14 +1106,28 @@ int av_write_trailer(AVFormatContext *s) goto fail; } + if (!s->internal->header_written && s->oformat->write_header) { + ret = s->oformat->write_header(s); + if (ret >= 0 && s->pb && s->pb->error < 0) + ret = s->pb->error; + if (ret < 0) + goto fail; + if (s->flush_packets && s->pb && s->pb->error >= 0 && s->flags & AVFMT_FLAG_FLUSH_PACKETS) + avio_flush(s->pb); + s->internal->header_written = 1; + } + fail: - if (s->oformat->write_trailer) + if ((s->internal->header_written || !s->oformat->write_header) && s->oformat->write_trailer) if (ret >= 0) { ret = s->oformat->write_trailer(s); } else { s->oformat->write_trailer(s); } + if (s->oformat->deinit) + s->oformat->deinit(s); + if (s->pb) avio_flush(s->pb); if (ret == 0) diff --git a/libavformat/version.h b/libavformat/version.h index 99ae17d..7a4e61c 100644 --- a/libavformat/version.h +++ b/libavformat/version.h @@ -30,7 +30,7 @@ #include "libavutil/version.h" #define LIBAVFORMAT_VERSION_MAJOR 57 -#define LIBAVFORMAT_VERSION_MINOR 19 +#define LIBAVFORMAT_VERSION_MINOR 20 #define LIBAVFORMAT_VERSION_MICRO 100 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \ -- 2.6.3 _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel