summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRodger Combs <rodger.combs@gmail.com>2015-10-07 21:32:14 -0500
committerRodger Combs <rodger.combs@gmail.com>2015-12-28 08:40:35 -0600
commit1f9139b07b8a896b62c1f28f3d04acac33978c0d (patch)
tree343964318a9d131e6dfe0886ac7776463fb69328
parent7a161b74ad13e8005f413770cce8af37bd051d32 (diff)
lavf: add automatic bitstream filtering; bump version
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.
-rw-r--r--Changelog1
-rw-r--r--doc/APIchanges3
-rw-r--r--libavformat/avformat.h23
-rw-r--r--libavformat/internal.h17
-rw-r--r--libavformat/mux.c49
-rw-r--r--libavformat/version.h2
6 files changed, 91 insertions, 4 deletions
diff --git a/Changelog b/Changelog
index bc025cad02..d9c2ea8376 100644
--- a/Changelog
+++ b/Changelog
@@ -48,6 +48,7 @@ version <next>:
- SOFAlizer: virtual binaural acoustics filter
- VAAPI VP9 hwaccel
- audio high-order multiband parametric equalizer
+- automatic bitstream filtering
version 2.8:
diff --git a/doc/APIchanges b/doc/APIchanges
index 013e870b67..e0d5e84cf0 100644
--- a/doc/APIchanges
+++ b/doc/APIchanges
@@ -15,6 +15,9 @@ libavutil: 2015-08-28
API changes, most recent first:
+2015-12-28 - xxxxxxx - lavf 57.21.100 - avformat.h
+ Add automatic bitstream filtering; add av_apply_bitstream_filters()
+
2015-12-22 - xxxxxxx - lavfi 6.21.101 - avfilter.h
Deprecate avfilter_link_set_closed().
Applications are not supposed to mess with links,
diff --git a/libavformat/avformat.h b/libavformat/avformat.h
index 39aedb5c6d..95a645b35c 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 4297cb85d7..0e59da0c2d 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 05d41704e7..2da8cf2287 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)
@@ -668,6 +674,18 @@ static int write_packet(AVFormatContext *s, AVPacket *pkt)
}
did_split = av_packet_split_side_data(pkt);
+
+ 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;
+ }
+
if ((pkt->flags & AV_PKT_FLAG_UNCODED_FRAME)) {
AVFrame *frame = (AVFrame *)pkt->data;
av_assert0(pkt->size == UNCODED_FRAME_PACKET_SIZE);
@@ -684,7 +702,7 @@ static int write_packet(AVFormatContext *s, AVPacket *pkt)
ret = s->pb->error;
}
-
+fail:
if (did_split)
av_packet_merge_side_data(pkt);
@@ -1021,6 +1039,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;
@@ -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 7a4e61cc0e..a57eb12fd6 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 20
+#define LIBAVFORMAT_VERSION_MINOR 21
#define LIBAVFORMAT_VERSION_MICRO 100
#define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \