lavf: add automatic bitstream filtering; bump version
authorRodger Combs <rodger.combs@gmail.com>
Thu, 8 Oct 2015 02:32:14 +0000 (21:32 -0500)
committerRodger Combs <rodger.combs@gmail.com>
Mon, 28 Dec 2015 14:40:35 +0000 (08:40 -0600)
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
doc/APIchanges
libavformat/avformat.h
libavformat/internal.h
libavformat/mux.c
libavformat/version.h

index bc025ca..d9c2ea8 100644 (file)
--- 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:
index 013e870..e0d5e84 100644 (file)
@@ -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,
index 39aedb5..95a645b 100644 (file)
@@ -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;
 /**
  * @}
index 4297cb8..0e59da0 100644 (file)
@@ -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__
index 05d4170..2da8cf2 100644 (file)
@@ -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)
index 7a4e61c..a57eb12 100644 (file)
@@ -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, \