From 7f5ff0d89c19e1683f91befb77ba4a7bf7b66252 Mon Sep 17 00:00:00 2001
From: Steven Liu <lingjiujianke@gmail.com>
Date: Thu, 29 Sep 2016 21:20:34 +0800
Subject: [PATCH] avformat/flvenc: add flv live stream flag

If the flv format is used for live stream on publish
ffmpeg should not update dutration and filesize at the end.
because the live stream is sent metadata at first step.

Reviewed-by: Carl Eugen Hoyos <cehoyos@ag.or.at>
Signed-off-by: Steven Liu <lingjiujianke@gmail.com>
---
 doc/muxers.texi      |  5 +++++
 libavformat/flvenc.c | 50 +++++++++++++++++++++++++++++---------------------
 2 files changed, 34 insertions(+), 21 deletions(-)

diff --git a/doc/muxers.texi b/doc/muxers.texi
index 27d1038..aa20656 100644
--- a/doc/muxers.texi
+++ b/doc/muxers.texi
@@ -148,6 +148,11 @@ Place AAC sequence header based on audio stream data.
 @item no_sequence_end
 Disable sequence end tag.
 @end table
+
+@item live_stream
+Disable the duration and filesize update in the flv metadata.
+@end table
+
 @end table
 
 @anchor{framecrc}
diff --git a/libavformat/flvenc.c b/libavformat/flvenc.c
index 99903f5..cd9ca84 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_LIVE_STREAM = (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_LIVE_STREAM)) {
+        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_LIVE_STREAM)) {
+        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);
 
@@ -543,16 +547,19 @@ 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_LIVE_STREAM)) {
+        /* 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" },
+    { "live_stream", "used for flv live stream mode", 0, AV_OPT_TYPE_CONST, {.i64 = FLV_LIVE_STREAM}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "flvflags" },
     { NULL },
 };
 
-- 
2.8.4 (Apple Git-73)

