[FFmpeg-devel] [PATCH 4/7] lavf: add automatic bitstream filtering; bump version

Rodger Combs rodger.combs at gmail.com
Fri Dec 4 12:31:30 CET 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.
---
 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



More information about the ffmpeg-devel mailing list