[FFmpeg-devel] [PATCH 5/7] lavf: add automatic bitstream filtering
Rodger Combs
rodger.combs at gmail.com
Thu Oct 8 22:07:39 CEST 2015
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 | 42 +++++++++++++++++++++++++++++++++++++++---
2 files changed, 68 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..ed2e543 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)
@@ -1007,8 +1032,19 @@ int av_write_trailer(AVFormatContext *s)
goto fail;
}
+ 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 fail;
+ if (s->flush_packets && s->pb && s->pb->error >= 0 && s->flags & AVFMT_FLAG_FLUSH_PACKETS)
+ avio_flush(s->pb);
+ s->header_written = 1;
+ }
+
fail:
- if (s->oformat->write_trailer)
+ if (s->header_written && s->oformat->write_trailer)
if (ret >= 0) {
ret = s->oformat->write_trailer(s);
} else {
--
2.6.0
More information about the ffmpeg-devel
mailing list