From 205db2105d5edb7aaff1f76529b1c9954459a4e3 Mon Sep 17 00:00:00 2001
From: Steven Liu <lingjiujianke@gmail.com>
Date: Fri, 30 Sep 2016 13:16:55 +0800
Subject: [PATCH] avformat/flvenc: add flv stream seekable flag

If the flv format is used for live stream on publish
ffmpeg should not update dutration and filesize at the end
if the stream non-seekable

Reviewed-by: Carl Eugen Hoyos <cehoyos@ag.or.at>
Reviewed-by: Michael Niedermayer <michael@niedermayer.cc>
Signed-off-by: Steven Liu <lingjiujianke@gmail.com>
---
 doc/muxers.texi      |  3 +++
 libavformat/flvenc.c | 54 ++++++++++++++++++++++++++++++----------------------
 2 files changed, 34 insertions(+), 23 deletions(-)

diff --git a/doc/muxers.texi b/doc/muxers.texi
index 27d1038..2890a8a 100644
--- a/doc/muxers.texi
+++ b/doc/muxers.texi
@@ -147,6 +147,9 @@ Place AAC sequence header based on audio stream data.
 
 @item no_sequence_end
 Disable sequence end tag.
+
+@item flv_stream_seekable
+create the duration and filesize in the flv metadata.
 @end table
 @end table
 
diff --git a/libavformat/flvenc.c b/libavformat/flvenc.c
index 99903f5..7c00cf1 100644
--- a/libavformat/flvenc.c
+++ b/libavformat/flvenc.c
@@ -64,6 +64,7 @@ static const AVCodecTag flv_audio_codec_ids[] = {
 typedef enum {
     FLV_AAC_SEQ_HEADER_DETECT = (1 << 0),
     FLV_NO_SEQUENCE_END = (1 << 1),
+    FLV_STREAM_SEEKABLE = (1 << 2),
 } FLVFlags;
 
 typedef struct FLVContext {
@@ -234,17 +235,18 @@ static void write_metadata(AVFormatContext *s, unsigned int ts)
     metadata_count_pos = avio_tell(pb);
     metadata_count = 4 * !!flv->video_par +
                      5 * !!flv->audio_par +
-                     1 * !!flv->data_par  +
-                     2; // +2 for duration and file size
+                     1 * !!flv->data_par;
 
     avio_wb32(pb, metadata_count);
 
-    put_amf_string(pb, "duration");
-    flv->duration_offset = avio_tell(pb);
-
-    // fill in the guessed duration, it'll be corrected later if incorrect
-    put_amf_double(pb, s->duration / AV_TIME_BASE);
+    if (flv->flags & FLV_STREAM_SEEKABLE) {
+        put_amf_string(pb, "duration");
+        flv->duration_offset = avio_tell(pb);
 
+        // fill in the guessed duration, it'll be corrected later if incorrect
+        put_amf_double(pb, s->duration / AV_TIME_BASE);
+        metadata_count++;
+    }
     if (flv->video_par) {
         put_amf_string(pb, "width");
         put_amf_double(pb, flv->video_par->width);
@@ -319,10 +321,12 @@ static void write_metadata(AVFormatContext *s, unsigned int ts)
         metadata_count++;
     }
 
-    put_amf_string(pb, "filesize");
-    flv->filesize_offset = avio_tell(pb);
-    put_amf_double(pb, 0); // delayed write
-
+    if (flv->flags & FLV_STREAM_SEEKABLE) {
+        put_amf_string(pb, "filesize");
+        flv->filesize_offset = avio_tell(pb);
+        put_amf_double(pb, 0); // delayed write
+        metadata_count++;
+    }
     put_amf_string(pb, "");
     avio_w8(pb, AMF_END_OF_OBJECT);
 
@@ -541,19 +545,22 @@ static int flv_write_trailer(AVFormatContext *s)
         }
     }
 
-    file_size = avio_tell(pb);
-
-    /* update information */
-    if (avio_seek(pb, flv->duration_offset, SEEK_SET) < 0)
-        av_log(s, AV_LOG_WARNING, "Failed to update header with correct duration.\n");
-    else
-        put_amf_double(pb, flv->duration / (double)1000);
-    if (avio_seek(pb, flv->filesize_offset, SEEK_SET) < 0)
-        av_log(s, AV_LOG_WARNING, "Failed to update header with correct filesize.\n");
-    else
-        put_amf_double(pb, file_size);
+    if (flv->flags & FLV_STREAM_SEEKABLE) {
+        file_size = avio_tell(pb);
 
-    avio_seek(pb, file_size, SEEK_SET);
+        /* update information */
+        if (avio_seek(pb, flv->duration_offset, SEEK_SET) < 0) {
+            av_log(s, AV_LOG_WARNING, "Failed to update header with correct duration.\n");
+        } else {
+            put_amf_double(pb, flv->duration / (double)1000);
+        }
+        if (avio_seek(pb, flv->filesize_offset, SEEK_SET) < 0) {
+            av_log(s, AV_LOG_WARNING, "Failed to update header with correct filesize.\n");
+        } else {
+            put_amf_double(pb, file_size);
+        }
+        avio_seek(pb, file_size, SEEK_SET);
+    }
     return 0;
 }
 
@@ -729,6 +736,7 @@ static const AVOption options[] = {
     { "flvflags", "FLV muxer flags", offsetof(FLVContext, flags), AV_OPT_TYPE_FLAGS, {.i64 = 0}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "flvflags" },
     { "aac_seq_header_detect", "Put AAC sequence header based on stream data", 0, AV_OPT_TYPE_CONST, {.i64 = FLV_AAC_SEQ_HEADER_DETECT}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "flvflags" },
     { "no_sequence_end", "disable sequence end for FLV", 0, AV_OPT_TYPE_CONST, {.i64 = FLV_NO_SEQUENCE_END}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "flvflags" },
+    { "flv_stream_seekable", "used to create flv file mode", 0, AV_OPT_TYPE_CONST, {.i64 = FLV_STREAM_SEEKABLE}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "flvflags" },
     { NULL },
 };
 
-- 
2.8.4 (Apple Git-73)

