[FFmpeg-devel] [PATCH 4/6] lavf: add automatic bitstream filtering
Michael Niedermayer
michael at niedermayer.cc
Thu Oct 8 13:13:38 CEST 2015
On Wed, Oct 07, 2015 at 09:50:05PM -0500, Rodger Combs wrote:
> 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.
> ---
> libavformat/avformat.h | 29 +++++++++++++++++++++++++++++
> libavformat/mux.c | 31 ++++++++++++++++++++++++++++---
> 2 files changed, 57 insertions(+), 3 deletions(-)
>
> diff --git a/libavformat/avformat.h b/libavformat/avformat.h
> index 5226b0a..f3c8260 100644
> --- a/libavformat/avformat.h
> +++ b/libavformat/avformat.h
> @@ -598,6 +598,21 @@ 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.
> + * Must not write output.
> + *
> + * FIXME: Data allocated here would be leaked if there's a failure before
> + * write_header is called. Ban allocations? Add a `deinit` cleanup function?
> + */
> + int (*init)(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;
> /**
> * @}
> @@ -1167,6 +1182,18 @@ typedef struct AVStream {
> AVRational display_aspect_ratio;
>
> struct FFFrac *priv_pts;
> +
> + /**
> + * bitstream filter to run on stream
> + * - encoding: Set by muxer or user using av_add_bitstream_filter
> + * - decoding: unused
> + */
> + AVBitStreamFilterContext *bsfc;
> +
> + /**
> + * internal check if check_bitstream should still be run on each packet
> + */
> + int bitstream_checked;
> } AVStream;
>
> AVRational av_stream_get_r_frame_rate(const AVStream *s);
> @@ -1782,6 +1809,8 @@ typedef struct AVFormatContext {
> * Demuxing: Set by user.
> */
> int (*open_cb)(struct AVFormatContext *s, AVIOContext **p, const char *url, int flags, const AVIOInterruptCB *int_cb, AVDictionary **options);
> +
> + int header_written;
> } AVFormatContext;
>
> int av_format_get_probe_score(const AVFormatContext *s);
> diff --git a/libavformat/mux.c b/libavformat/mux.c
> index c9ef490..b5b2c8a 100644
> --- a/libavformat/mux.c
> +++ b/libavformat/mux.c
> @@ -400,7 +400,7 @@ FF_ENABLE_DEPRECATION_WARNINGS
> *options = tmp;
> }
>
> - return 0;
> + return s->oformat->init ? s->oformat->init(s) : 0;
>
> fail:
> av_dict_free(&tmp);
> @@ -451,7 +451,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;
> @@ -459,6 +459,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->header_written = 1;
> }
>
> if ((ret = init_pts(s)) < 0)
> @@ -951,6 +952,18 @@ int av_interleaved_write_frame(AVFormatContext *s, AVPacket *pkt)
> ret = AVERROR(EINVAL);
> goto fail;
> }
> +
> + if (s->oformat->check_bitstream) {
> + if (!st->bitstream_checked) {
> + if ((ret = s->oformat->check_bitstream(s, pkt)) < 0)
> + goto fail;
> + else if (ret == 1)
> + st->bitstream_checked = 1;
> + }
> + }
> +
> + if ((ret = av_apply_bitstream_filters(s, pkt, st->bsfc)) < 0)
> + goto fail;
> } else {
> av_log(s, AV_LOG_TRACE, "av_interleaved_write_frame FLUSH\n");
> flush = 1;
> @@ -967,10 +980,22 @@ int av_interleaved_write_frame(AVFormatContext *s, AVPacket *pkt)
> if (ret <= 0) //FIXME cleanup needed for ret<0 ?
> return ret;
>
> + if (!s->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->header_written = 1;
> + }
> +
> ret = write_packet(s, &opkt);
> if (ret >= 0)
> s->streams[opkt.stream_index]->nb_frames++;
>
> +fail2:
> av_free_packet(&opkt);
>
> if (ret < 0)
> @@ -1008,7 +1033,7 @@ int av_write_trailer(AVFormatContext *s)
> }
>
> fail:
> - if (s->oformat->write_trailer)
> + if (s->header_written && s->oformat->write_trailer)
this changes the behavior in case no packets are written
as then also no header or trailer is ever written while previously
a header and trailer was written
[...]
--
Michael GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB
No snowflake in an avalanche ever feels responsible. -- Voltaire
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 181 bytes
Desc: Digital signature
URL: <http://ffmpeg.org/pipermail/ffmpeg-devel/attachments/20151008/1a2772ba/attachment.sig>
More information about the ffmpeg-devel
mailing list