[FFmpeg-devel] [PATCH 05/14] lavf/mux: add avformat_init_output

Rodger Combs rodger.combs at gmail.com
Sun Jun 12 22:34:10 CEST 2016


This allows a consumer to run the muxer's init function without actually
writing the header, which is useful in chained muxers that support
automatic bitstream filtering.
---
 libavformat/avformat.h | 34 +++++++++++++++++++++++++--
 libavformat/internal.h | 10 ++++++++
 libavformat/mux.c      | 64 +++++++++++++++++++++++++++++++++++++++-----------
 libavformat/version.h  |  4 ++--
 4 files changed, 94 insertions(+), 18 deletions(-)

diff --git a/libavformat/avformat.h b/libavformat/avformat.h
index d659ee4..d6b0b26 100644
--- a/libavformat/avformat.h
+++ b/libavformat/avformat.h
@@ -616,6 +616,8 @@ typedef struct AVOutputFormat {
      * AVStream parameters that need to be set before packets are sent.
      * This method must not write output.
      *
+     * Return 0 if streams were fully configured, 1 if not, negative AVERROR on failure
+     *
      * Any allocations made here must be freed in deinit().
      */
     int (*init)(struct AVFormatContext *);
@@ -2363,6 +2365,10 @@ void avformat_close_input(AVFormatContext **s);
  * @addtogroup lavf_encoding
  * @{
  */
+
+#define AVSTREAM_INIT_IN_WRITE_HEADER 0 ///< stream parameters initialized in avformat_write_header
+#define AVSTREAM_INIT_IN_INIT_OUTPUT  1 ///< stream parameters initialized in avformat_init_output
+
 /**
  * Allocate the stream private data and write the stream header to
  * an output media file.
@@ -2374,14 +2380,38 @@ void avformat_close_input(AVFormatContext **s);
  *                 On return this parameter will be destroyed and replaced with a dict containing
  *                 options that were not found. May be NULL.
  *
- * @return 0 on success, negative AVERROR on failure.
+ * @return AVSTREAM_INIT_IN_WRITE_HEADER on success if the codec had not already been fully initialized in avformat_init,
+ *         AVSTREAM_INIT_IN_INIT_OUTPUT  on success if the codec had already been fully initialized in avformat_init,
+ *         negative AVERROR on failure.
  *
- * @see av_opt_find, av_dict_set, avio_open, av_oformat_next.
+ * @see av_opt_find, av_dict_set, avio_open, av_oformat_next, avformat_init_output.
  */
 av_warn_unused_result
 int avformat_write_header(AVFormatContext *s, AVDictionary **options);
 
 /**
+ * Allocate the stream private data and initialize the codec, but do not write the header.
+ * May optionally be used before avformat_write_header to initialize stream parameters
+ * before actually writing the header.
+ * If using this function, do not pass the same options to avformat_write_header.
+ *
+ * @param s Media file handle, must be allocated with avformat_alloc_context().
+ *          Its oformat field must be set to the desired output format;
+ *          Its pb field must be set to an already opened AVIOContext.
+ * @param options  An AVDictionary filled with AVFormatContext and muxer-private options.
+ *                 On return this parameter will be destroyed and replaced with a dict containing
+ *                 options that were not found. May be NULL.
+ *
+ * @return AVSTREAM_INIT_IN_WRITE_HEADER on success if the codec requires avformat_write_header to fully initialize,
+ *         AVSTREAM_INIT_IN_INIT_OUTPUT  on success if the codec has been fully initialized,
+ *         negative AVERROR on failure.
+ *
+ * @see av_opt_find, av_dict_set, avio_open, av_oformat_next, avformat_write_header.
+ */
+av_warn_unused_result
+int avformat_init_output(AVFormatContext *s, AVDictionary **options);
+
+/**
  * Write a packet to an output media file.
  *
  * This function passes the packet directly to the muxer, without any buffering
diff --git a/libavformat/internal.h b/libavformat/internal.h
index 52f9eb6..b5966ff 100644
--- a/libavformat/internal.h
+++ b/libavformat/internal.h
@@ -124,6 +124,16 @@ struct AVFormatInternal {
      * Whether or not a header has already been written
      */
     int header_written;
+
+    /**
+     * Whether or not avformat_init_output has already been called
+     */
+    int initialized;
+
+    /**
+     * Whether or not avformat_init_output fully initialized streams
+     */
+    int streams_initialized;
 };
 
 struct AVStreamInternal {
diff --git a/libavformat/mux.c b/libavformat/mux.c
index 071eac1..3d618d8 100644
--- a/libavformat/mux.c
+++ b/libavformat/mux.c
@@ -423,10 +423,13 @@ FF_ENABLE_DEPRECATION_WARNINGS
          *options = tmp;
     }
 
-    if (s->oformat->init && (ret = s->oformat->init(s)) < 0) {
-        if (s->oformat->deinit)
-            s->oformat->deinit(s);
-        goto fail;
+    if (s->oformat->init) {
+        if ((ret = s->oformat->init(s)) < 0) {
+            if (s->oformat->deinit)
+                s->oformat->deinit(s);
+            return ret;
+        }
+        return ret == 0;
     }
 
     return 0;
@@ -473,13 +476,44 @@ static int init_pts(AVFormatContext *s)
     return 0;
 }
 
-int avformat_write_header(AVFormatContext *s, AVDictionary **options)
+int avformat_init_output(AVFormatContext *s, AVDictionary **options)
 {
     int ret = 0;
 
     if ((ret = init_muxer(s, options)) < 0)
         return ret;
 
+    s->internal->initialized = 1;
+    s->internal->streams_initialized = ret;
+
+    if (s->oformat->init && ret) {
+        if ((ret = init_pts(s)) < 0)
+            return ret;
+
+        if (s->avoid_negative_ts < 0) {
+            av_assert2(s->avoid_negative_ts == AVFMT_AVOID_NEG_TS_AUTO);
+            if (s->oformat->flags & (AVFMT_TS_NEGATIVE | AVFMT_NOTIMESTAMPS)) {
+                s->avoid_negative_ts = 0;
+            } else
+                s->avoid_negative_ts = AVFMT_AVOID_NEG_TS_MAKE_NON_NEGATIVE;
+        }
+
+        return AVSTREAM_INIT_IN_INIT_OUTPUT;
+    }
+
+    return AVSTREAM_INIT_IN_WRITE_HEADER;
+}
+
+int avformat_write_header(AVFormatContext *s, AVDictionary **options)
+{
+    int ret = 0;
+    int already_initialized = s->internal->initialized;
+    int streams_already_initialized = s->internal->streams_initialized;
+
+    if (!already_initialized)
+        if ((ret = avformat_init_output(s, options)) < 0)
+            return ret;
+
     if (s->oformat->write_header && !(s->oformat->check_bitstream && s->flags & AVFMT_FLAG_AUTO_BSF)) {
         ret = s->oformat->write_header(s);
         if (ret >= 0 && s->pb && s->pb->error < 0)
@@ -494,18 +528,20 @@ int avformat_write_header(AVFormatContext *s, AVDictionary **options)
         s->internal->header_written = 1;
     }
 
-    if ((ret = init_pts(s)) < 0)
-        return ret;
+    if (!s->internal->streams_initialized) {
+        if ((ret = init_pts(s)) < 0)
+            return ret;
 
-    if (s->avoid_negative_ts < 0) {
-        av_assert2(s->avoid_negative_ts == AVFMT_AVOID_NEG_TS_AUTO);
-        if (s->oformat->flags & (AVFMT_TS_NEGATIVE | AVFMT_NOTIMESTAMPS)) {
-            s->avoid_negative_ts = 0;
-        } else
-            s->avoid_negative_ts = AVFMT_AVOID_NEG_TS_MAKE_NON_NEGATIVE;
+        if (s->avoid_negative_ts < 0) {
+            av_assert2(s->avoid_negative_ts == AVFMT_AVOID_NEG_TS_AUTO);
+            if (s->oformat->flags & (AVFMT_TS_NEGATIVE | AVFMT_NOTIMESTAMPS)) {
+                s->avoid_negative_ts = 0;
+            } else
+                s->avoid_negative_ts = AVFMT_AVOID_NEG_TS_MAKE_NON_NEGATIVE;
+        }
     }
 
-    return 0;
+    return streams_already_initialized;
 }
 
 #define AV_PKT_FLAG_UNCODED_FRAME 0x2000
diff --git a/libavformat/version.h b/libavformat/version.h
index c92a23f..11fbbb3 100644
--- a/libavformat/version.h
+++ b/libavformat/version.h
@@ -32,8 +32,8 @@
 // When bumping major check Ticket5467, 5421 for regressing
 // Also please add any ticket numbers that you belive might regress here
 #define LIBAVFORMAT_VERSION_MAJOR  57
-#define LIBAVFORMAT_VERSION_MINOR  37
-#define LIBAVFORMAT_VERSION_MICRO 101
+#define LIBAVFORMAT_VERSION_MINOR  38
+#define LIBAVFORMAT_VERSION_MICRO 100
 
 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \
                                                LIBAVFORMAT_VERSION_MINOR, \
-- 
2.8.3



More information about the ffmpeg-devel mailing list