[FFmpeg-devel,v2] avformat/hlsenc: merge mpegts and fmp4 workflow to one workflow

Submitted by Steven Liu on July 31, 2019, 8:07 a.m.

Details

Message ID 20190731080722.10443-1-lq@chinaffmpeg.org
State New
Headers show

Commit Message

Steven Liu July 31, 2019, 8:07 a.m.
write mpegts or fmp4 context into buffer, and flush the buffer into
output file when split fragment. merge two format split workflow into
one workflow

Signed-off-by: Steven Liu <lq@chinaffmpeg.org>
---
 libavformat/hlsenc.c | 200 ++++++++++++++++++++-----------------------
 1 file changed, 92 insertions(+), 108 deletions(-)

Comments

Michael Niedermayer Aug. 2, 2019, 10:46 a.m.
On Wed, Jul 31, 2019 at 04:07:22PM +0800, Steven Liu wrote:
> write mpegts or fmp4 context into buffer, and flush the buffer into
> output file when split fragment. merge two format split workflow into
> one workflow
> 
> Signed-off-by: Steven Liu <lq@chinaffmpeg.org>
> ---
>  libavformat/hlsenc.c | 200 ++++++++++++++++++++-----------------------
>  1 file changed, 92 insertions(+), 108 deletions(-)

make -j5 ffmpeg && ./ffmpeg -f lavfi -re -i testsrc -c:v h264 -hls_flags delete_segments -hls_key_info_file file.keyinfo -t 2 /tmp/file-hlsencry.m3u8
...
Output #0, hls, to '/tmp/file-hlsencry.m3u8':
  Metadata:
    encoder         : Lavf58.30.100
    Stream #0:0: Video: h264 (libx264), yuv444p, 320x240 [SAR 1:1 DAR 4:3], q=-1--1, 25 fps, 90k tbn, 25 tbc
    Metadata:
      encoder         : Lavc58.56.100 libx264
    Side data:
      cpb: bitrate max/min/avg: 0/0/0 buffer size: 0 vbv_delay: -1
[hls @ 0x24a1800] Opening '/tmp/file-hlsencry0.ts' for writingA speed=   0x    
*** Error in `./ffmpeg': free(): invalid size: 0x0000000002b4aa50 ***
Aborted (core dumped)


[hls @ 0x25662840] Opening '/tmp/file-hlsencry0.ts' for writing speed=   0x    
==13307== Invalid read of size 8
==13307==    at 0x6BD2FE: avio_close_dyn_buf (in ffmpeg/ffmpeg_g)
==13307==    by 0x6F5742: hls_write_trailer (in ffmpeg/ffmpeg_g)
==13307==    by 0x763E0A: av_write_trailer (in ffmpeg/ffmpeg_g)
==13307==    by 0x4D390A: transcode (in ffmpeg/ffmpeg_g)
==13307==    by 0x4B1E1C: main (in ffmpeg/ffmpeg_g)
==13307==  Address 0x3dcc6f50 is 8 bytes after a block of size 8 alloc'd
==13307==    at 0x4C2A6C5: memalign (vg_replace_malloc.c:727)
==13307==    by 0x4C2A760: posix_memalign (vg_replace_malloc.c:876)
==13307==    by 0x116963F: av_mallocz (in ffmpeg/ffmpeg_g)
==13307==    by 0x6BBA37: ffio_open_whitelist (in ffmpeg/ffmpeg_g)
==13307==    by 0x78B1E9: io_open_default (in ffmpeg/ffmpeg_g)
==13307==    by 0x6F353D: hls_start (in ffmpeg/ffmpeg_g)
==13307==    by 0x6F7312: hls_init (in ffmpeg/ffmpeg_g)
==13307==    by 0x761D12: avformat_init_output (in ffmpeg/ffmpeg_g)
==13307==    by 0x762434: avformat_write_header (in ffmpeg/ffmpeg_g)
==13307==    by 0x4C9D58: check_init_output_file (in ffmpeg/ffmpeg_g)
==13307==    by 0x4CB23D: init_output_stream.constprop.23 (in ffmpeg/ffmpeg_g)
==13307==    by 0x4D079F: reap_filters (in ffmpeg/ffmpeg_g)
==13307== 
[hls @ 0x25662840] Opening '/tmp/file-hlsencry.m3u8.tmp' for writing

if you cannot reproduce, tell me and ill rebuild and provide better
debug info

Thanks

[...]
Ian Klassen Aug. 2, 2019, 2:46 p.m.
On Fri, Aug 2, 2019 at 5:46 AM Michael Niedermayer <michael@niedermayer.cc>
wrote:

> On Wed, Jul 31, 2019 at 04:07:22PM +0800, Steven Liu wrote:
> > write mpegts or fmp4 context into buffer, and flush the buffer into
> > output file when split fragment. merge two format split workflow into
> > one workflow
> >
> > Signed-off-by: Steven Liu <lq@chinaffmpeg.org>
> > ---
> >  libavformat/hlsenc.c | 200 ++++++++++++++++++++-----------------------
> >  1 file changed, 92 insertions(+), 108 deletions(-)
>
> make -j5 ffmpeg && ./ffmpeg -f lavfi -re -i testsrc -c:v h264 -hls_flags
> delete_segments -hls_key_info_file file.keyinfo -t 2 /tmp/file-hlsencry.m3u8
> ...
> Output #0, hls, to '/tmp/file-hlsencry.m3u8':
>   Metadata:
>     encoder         : Lavf58.30.100
>     Stream #0:0: Video: h264 (libx264), yuv444p, 320x240 [SAR 1:1 DAR
> 4:3], q=-1--1, 25 fps, 90k tbn, 25 tbc
>     Metadata:
>       encoder         : Lavc58.56.100 libx264
>     Side data:
>       cpb: bitrate max/min/avg: 0/0/0 buffer size: 0 vbv_delay: -1
> [hls @ 0x24a1800] Opening '/tmp/file-hlsencry0.ts' for writingA speed=
>  0x
> *** Error in `./ffmpeg': free(): invalid size: 0x0000000002b4aa50 ***
> Aborted (core dumped)
>
>
> [hls @ 0x25662840] Opening '/tmp/file-hlsencry0.ts' for writing speed=
>  0x
> ==13307== Invalid read of size 8
> ==13307==    at 0x6BD2FE: avio_close_dyn_buf (in ffmpeg/ffmpeg_g)
> ==13307==    by 0x6F5742: hls_write_trailer (in ffmpeg/ffmpeg_g)
> ==13307==    by 0x763E0A: av_write_trailer (in ffmpeg/ffmpeg_g)
> ==13307==    by 0x4D390A: transcode (in ffmpeg/ffmpeg_g)
> ==13307==    by 0x4B1E1C: main (in ffmpeg/ffmpeg_g)
> ==13307==  Address 0x3dcc6f50 is 8 bytes after a block of size 8 alloc'd
> ==13307==    at 0x4C2A6C5: memalign (vg_replace_malloc.c:727)
> ==13307==    by 0x4C2A760: posix_memalign (vg_replace_malloc.c:876)
> ==13307==    by 0x116963F: av_mallocz (in ffmpeg/ffmpeg_g)
> ==13307==    by 0x6BBA37: ffio_open_whitelist (in ffmpeg/ffmpeg_g)
> ==13307==    by 0x78B1E9: io_open_default (in ffmpeg/ffmpeg_g)
> ==13307==    by 0x6F353D: hls_start (in ffmpeg/ffmpeg_g)
> ==13307==    by 0x6F7312: hls_init (in ffmpeg/ffmpeg_g)
> ==13307==    by 0x761D12: avformat_init_output (in ffmpeg/ffmpeg_g)
> ==13307==    by 0x762434: avformat_write_header (in ffmpeg/ffmpeg_g)
> ==13307==    by 0x4C9D58: check_init_output_file (in ffmpeg/ffmpeg_g)
> ==13307==    by 0x4CB23D: init_output_stream.constprop.23 (in
> ffmpeg/ffmpeg_g)
> ==13307==    by 0x4D079F: reap_filters (in ffmpeg/ffmpeg_g)
> ==13307==
> [hls @ 0x25662840] Opening '/tmp/file-hlsencry.m3u8.tmp' for writing
>
> if you cannot reproduce, tell me and ill rebuild and provide better
> debug info
>
> Thanks
>
> [...]
> --
> Michael     GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB
>
> Its not that you shouldnt use gotos but rather that you should write
> readable code and code with gotos often but not always is less readable
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>
> To unsubscribe, visit link above, or email
> ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".


Is this patch to address bug #7975? https://trac.ffmpeg.org/ticket/7975

I tested it on Windows and it still crashes when attempting to write to a
http server that doesn't support persistent connections:

[http @ 0000029C0EBAD080] URL read error: End of file
[http @ 0000029C0D410740] Opening 'http://127.0.0.1/stream2.ts' for writing
[http @ 0000029C0EBAD080] URL read error: Error number -10053 occurred
[http @ 0000029C0D410740] Opening 'http://127.0.0.1/stream.m3u8' for writing
av_interleaved_write_frame(): Unknown error
Steven Liu Aug. 2, 2019, 9:22 p.m.
> 在 2019年8月2日,22:46,Ian Klassen <ian@virtualfunc.com> 写道:
> 
> On Fri, Aug 2, 2019 at 5:46 AM Michael Niedermayer <michael@niedermayer.cc>
> wrote:
> 
>> On Wed, Jul 31, 2019 at 04:07:22PM +0800, Steven Liu wrote:
>>> write mpegts or fmp4 context into buffer, and flush the buffer into
>>> output file when split fragment. merge two format split workflow into
>>> one workflow
>>> 
>>> Signed-off-by: Steven Liu <lq@chinaffmpeg.org>
>>> ---
>>> libavformat/hlsenc.c | 200 ++++++++++++++++++++-----------------------
>>> 1 file changed, 92 insertions(+), 108 deletions(-)
>> 
>> make -j5 ffmpeg && ./ffmpeg -f lavfi -re -i testsrc -c:v h264 -hls_flags
>> delete_segments -hls_key_info_file file.keyinfo -t 2 /tmp/file-hlsencry.m3u8
>> ...
>> Output #0, hls, to '/tmp/file-hlsencry.m3u8':
>>  Metadata:
>>    encoder         : Lavf58.30.100
>>    Stream #0:0: Video: h264 (libx264), yuv444p, 320x240 [SAR 1:1 DAR
>> 4:3], q=-1--1, 25 fps, 90k tbn, 25 tbc
>>    Metadata:
>>      encoder         : Lavc58.56.100 libx264
>>    Side data:
>>      cpb: bitrate max/min/avg: 0/0/0 buffer size: 0 vbv_delay: -1
>> [hls @ 0x24a1800] Opening '/tmp/file-hlsencry0.ts' for writingA speed=
>> 0x
>> *** Error in `./ffmpeg': free(): invalid size: 0x0000000002b4aa50 ***
>> Aborted (core dumped)
>> 
>> 
>> [hls @ 0x25662840] Opening '/tmp/file-hlsencry0.ts' for writing speed=
>> 0x
>> ==13307== Invalid read of size 8
>> ==13307==    at 0x6BD2FE: avio_close_dyn_buf (in ffmpeg/ffmpeg_g)
>> ==13307==    by 0x6F5742: hls_write_trailer (in ffmpeg/ffmpeg_g)
>> ==13307==    by 0x763E0A: av_write_trailer (in ffmpeg/ffmpeg_g)
>> ==13307==    by 0x4D390A: transcode (in ffmpeg/ffmpeg_g)
>> ==13307==    by 0x4B1E1C: main (in ffmpeg/ffmpeg_g)
>> ==13307==  Address 0x3dcc6f50 is 8 bytes after a block of size 8 alloc'd
>> ==13307==    at 0x4C2A6C5: memalign (vg_replace_malloc.c:727)
>> ==13307==    by 0x4C2A760: posix_memalign (vg_replace_malloc.c:876)
>> ==13307==    by 0x116963F: av_mallocz (in ffmpeg/ffmpeg_g)
>> ==13307==    by 0x6BBA37: ffio_open_whitelist (in ffmpeg/ffmpeg_g)
>> ==13307==    by 0x78B1E9: io_open_default (in ffmpeg/ffmpeg_g)
>> ==13307==    by 0x6F353D: hls_start (in ffmpeg/ffmpeg_g)
>> ==13307==    by 0x6F7312: hls_init (in ffmpeg/ffmpeg_g)
>> ==13307==    by 0x761D12: avformat_init_output (in ffmpeg/ffmpeg_g)
>> ==13307==    by 0x762434: avformat_write_header (in ffmpeg/ffmpeg_g)
>> ==13307==    by 0x4C9D58: check_init_output_file (in ffmpeg/ffmpeg_g)
>> ==13307==    by 0x4CB23D: init_output_stream.constprop.23 (in
>> ffmpeg/ffmpeg_g)
>> ==13307==    by 0x4D079F: reap_filters (in ffmpeg/ffmpeg_g)
>> ==13307==
>> [hls @ 0x25662840] Opening '/tmp/file-hlsencry.m3u8.tmp' for writing
>> 
>> if you cannot reproduce, tell me and ill rebuild and provide better
>> debug info
>> 
>> Thanks
>> 
>> [...]
>> --
>> Michael     GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB
>> 
>> Its not that you shouldnt use gotos but rather that you should write
>> readable code and code with gotos often but not always is less readable
>> _______________________________________________
>> ffmpeg-devel mailing list
>> ffmpeg-devel@ffmpeg.org
>> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>> 
>> To unsubscribe, visit link above, or email
>> ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
> 
> 
> Is this patch to address bug #7975? https://trac.ffmpeg.org/ticket/7975

No,

Just merge two workflow into one workflow,
fix 7975 next step, just modify the code block at hlsenc_io_open->flush buffer data->hlsenc_io_close.
modify to hlsenc_io_open->flush buffer data->check status-> reopen (hlsenc_io_open)->reflush data(option retry times)->hlsenc_io_close.
> 
> I tested it on Windows and it still crashes when attempting to write to a
> http server that doesn't support persistent connections:
> 
> [http @ 0000029C0EBAD080] URL read error: End of file
> [http @ 0000029C0D410740] Opening 'http://127.0.0.1/stream2.ts' for writing
> [http @ 0000029C0EBAD080] URL read error: Error number -10053 occurred
> [http @ 0000029C0D410740] Opening 'http://127.0.0.1/stream.m3u8' for writing
> av_interleaved_write_frame(): Unknown error
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
> 
> To unsubscribe, visit link above, or email
> ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

Thanks
Steven
Steven Liu Aug. 2, 2019, 9:24 p.m.
> 在 2019年8月2日,18:46,Michael Niedermayer <michael@niedermayer.cc> 写道:
> 
> On Wed, Jul 31, 2019 at 04:07:22PM +0800, Steven Liu wrote:
>> write mpegts or fmp4 context into buffer, and flush the buffer into
>> output file when split fragment. merge two format split workflow into
>> one workflow
>> 
>> Signed-off-by: Steven Liu <lq@chinaffmpeg.org>
>> ---
>> libavformat/hlsenc.c | 200 ++++++++++++++++++++-----------------------
>> 1 file changed, 92 insertions(+), 108 deletions(-)
> 
> make -j5 ffmpeg && ./ffmpeg -f lavfi -re -i testsrc -c:v h264 -hls_flags delete_segments -hls_key_info_file file.keyinfo -t 2 /tmp/file-hlsencry.m3u8
> ...
> Output #0, hls, to '/tmp/file-hlsencry.m3u8':
>  Metadata:
>    encoder         : Lavf58.30.100
>    Stream #0:0: Video: h264 (libx264), yuv444p, 320x240 [SAR 1:1 DAR 4:3], q=-1--1, 25 fps, 90k tbn, 25 tbc
>    Metadata:
>      encoder         : Lavc58.56.100 libx264
>    Side data:
>      cpb: bitrate max/min/avg: 0/0/0 buffer size: 0 vbv_delay: -1
> [hls @ 0x24a1800] Opening '/tmp/file-hlsencry0.ts' for writingA speed=   0x    
> *** Error in `./ffmpeg': free(): invalid size: 0x0000000002b4aa50 ***
> Aborted (core dumped)
> 
> 
> [hls @ 0x25662840] Opening '/tmp/file-hlsencry0.ts' for writing speed=   0x    
> ==13307== Invalid read of size 8
> ==13307==    at 0x6BD2FE: avio_close_dyn_buf (in ffmpeg/ffmpeg_g)
> ==13307==    by 0x6F5742: hls_write_trailer (in ffmpeg/ffmpeg_g)
> ==13307==    by 0x763E0A: av_write_trailer (in ffmpeg/ffmpeg_g)
> ==13307==    by 0x4D390A: transcode (in ffmpeg/ffmpeg_g)
> ==13307==    by 0x4B1E1C: main (in ffmpeg/ffmpeg_g)
> ==13307==  Address 0x3dcc6f50 is 8 bytes after a block of size 8 alloc'd
> ==13307==    at 0x4C2A6C5: memalign (vg_replace_malloc.c:727)
> ==13307==    by 0x4C2A760: posix_memalign (vg_replace_malloc.c:876)
> ==13307==    by 0x116963F: av_mallocz (in ffmpeg/ffmpeg_g)
> ==13307==    by 0x6BBA37: ffio_open_whitelist (in ffmpeg/ffmpeg_g)
> ==13307==    by 0x78B1E9: io_open_default (in ffmpeg/ffmpeg_g)
> ==13307==    by 0x6F353D: hls_start (in ffmpeg/ffmpeg_g)
> ==13307==    by 0x6F7312: hls_init (in ffmpeg/ffmpeg_g)
> ==13307==    by 0x761D12: avformat_init_output (in ffmpeg/ffmpeg_g)
> ==13307==    by 0x762434: avformat_write_header (in ffmpeg/ffmpeg_g)
> ==13307==    by 0x4C9D58: check_init_output_file (in ffmpeg/ffmpeg_g)
> ==13307==    by 0x4CB23D: init_output_stream.constprop.23 (in ffmpeg/ffmpeg_g)
> ==13307==    by 0x4D079F: reap_filters (in ffmpeg/ffmpeg_g)
> ==13307== 
> [hls @ 0x25662840] Opening '/tmp/file-hlsencry.m3u8.tmp' for writing
> 
> if you cannot reproduce, tell me and ill rebuild and provide better
> debug info


Yes, i have fix it locally, and will send a V3 patch next monday.
> 
> Thanks
> 
> [...]
> -- 
> Michael     GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB
> 
> Its not that you shouldnt use gotos but rather that you should write
> readable code and code with gotos often but not always is less readable
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
> 
> To unsubscribe, visit link above, or email
> ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

Thanks
Steven

Patch hide | download patch | download mbox

diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c
index 51310fb528..543ad4e7df 100644
--- a/libavformat/hlsenc.c
+++ b/libavformat/hlsenc.c
@@ -459,6 +459,7 @@  static int flush_dynbuf(VariantStream *vs, int *range_length)
 
     // write out to file
     *range_length = avio_close_dyn_buf(ctx->pb, &buffer);
+    vs->video_lastpos = 0;
     ctx->pb = NULL;
     avio_write(vs->out, buffer, *range_length);
     av_free(buffer);
@@ -815,7 +816,7 @@  static int hls_mux_init(AVFormatContext *s, VariantStream *vs)
     vs->start_pos = 0;
     vs->new_start = 1;
 
-    if (hls->segment_type == SEGMENT_TYPE_FMP4) {
+    if (hls->segment_type == SEGMENT_TYPE_FMP4 && hls->max_seg_size > 0) {
         if (hls->http_persistent > 0) {
             //TODO: Support fragment fmp4 for http persistent in HLS muxer.
             av_log(s, AV_LOG_WARNING, "http persistent mode is currently unsupported for fragment mp4 in the HLS muxer.\n");
@@ -824,34 +825,38 @@  static int hls_mux_init(AVFormatContext *s, VariantStream *vs)
             av_log(s, AV_LOG_WARNING, "Multi-file byterange mode is currently unsupported in the HLS muxer.\n");
             return AVERROR_PATCHWELCOME;
         }
+    }
 
-        vs->packets_written = 0;
-        vs->init_range_length = 0;
-        set_http_options(s, &options, hls);
-        if ((ret = avio_open_dyn_buf(&oc->pb)) < 0)
-            return ret;
+    vs->packets_written = 0;
+    vs->init_range_length = 0;
+    set_http_options(s, &options, hls);
+    if ((ret = avio_open_dyn_buf(&oc->pb)) < 0)
+        return ret;
 
+    if (hls->segment_type == SEGMENT_TYPE_FMP4) {
         if (byterange_mode) {
             ret = hlsenc_io_open(s, &vs->out, vs->basename, &options);
         } else {
             ret = hlsenc_io_open(s, &vs->out, vs->base_output_dirname, &options);
         }
-        av_dict_free(&options);
+    }
+    av_dict_free(&options);
+    if (ret < 0) {
+        av_log(s, AV_LOG_ERROR, "Failed to open segment '%s'\n", vs->fmp4_init_filename);
+        return ret;
+    }
+
+    if (hls->format_options_str) {
+        ret = av_dict_parse_string(&hls->format_options, hls->format_options_str, "=", ":", 0);
         if (ret < 0) {
-            av_log(s, AV_LOG_ERROR, "Failed to open segment '%s'\n", vs->fmp4_init_filename);
+            av_log(s, AV_LOG_ERROR, "Could not parse format options list '%s'\n",
+                   hls->format_options_str);
             return ret;
         }
+    }
 
-        if (hls->format_options_str) {
-            ret = av_dict_parse_string(&hls->format_options, hls->format_options_str, "=", ":", 0);
-            if (ret < 0) {
-                av_log(s, AV_LOG_ERROR, "Could not parse format options list '%s'\n",
-                       hls->format_options_str);
-                return ret;
-            }
-        }
-
-        av_dict_copy(&options, hls->format_options, 0);
+    av_dict_copy(&options, hls->format_options, 0);
+    if (hls->segment_type == SEGMENT_TYPE_FMP4) {
         av_dict_set(&options, "fflags", "-autobsf", 0);
         av_dict_set(&options, "movflags", "+frag_custom+dash+delay_moov", AV_DICT_APPEND);
         ret = avformat_init_output(oc, &options);
@@ -862,9 +867,9 @@  static int hls_mux_init(AVFormatContext *s, VariantStream *vs)
             av_dict_free(&options);
             return AVERROR(EINVAL);
         }
-        avio_flush(oc->pb);
-        av_dict_free(&options);
     }
+    avio_flush(oc->pb);
+    av_dict_free(&options);
     return 0;
 }
 
@@ -1435,7 +1440,6 @@  static int hls_window(AVFormatContext *s, int last, VariantStream *vs)
 {
     HLSContext *hls = s->priv_data;
     HLSSegment *en;
-    AVFormatContext *oc = vs->avf;
     int target_duration = 0;
     int ret = 0;
     char temp_filename[MAX_URL_SIZE];
@@ -1471,7 +1475,7 @@  static int hls_window(AVFormatContext *s, int last, VariantStream *vs)
 
     set_http_options(s, &options, hls);
     snprintf(temp_filename, sizeof(temp_filename), use_temp_file ? "%s.tmp" : "%s", vs->m3u8_name);
-    if ((ret = hlsenc_io_open(s, (byterange_mode || hls->segment_type == SEGMENT_TYPE_FMP4) ? &hls->m3u8_out : &oc->pb, temp_filename, &options)) < 0) {
+    if ((ret = hlsenc_io_open(s, (byterange_mode || hls->segment_type == SEGMENT_TYPE_FMP4) ? &hls->m3u8_out : &vs->out, temp_filename, &options)) < 0) {
         if (hls->ignore_io_errors)
             ret = 0;
         goto fail;
@@ -1483,33 +1487,33 @@  static int hls_window(AVFormatContext *s, int last, VariantStream *vs)
     }
 
     vs->discontinuity_set = 0;
-    ff_hls_write_playlist_header((byterange_mode || hls->segment_type == SEGMENT_TYPE_FMP4) ? hls->m3u8_out : oc->pb, hls->version, hls->allowcache,
+    ff_hls_write_playlist_header((byterange_mode || hls->segment_type == SEGMENT_TYPE_FMP4) ? hls->m3u8_out : vs->out, hls->version, hls->allowcache,
                                  target_duration, sequence, hls->pl_type, hls->flags & HLS_I_FRAMES_ONLY);
 
     if((hls->flags & HLS_DISCONT_START) && sequence==hls->start_sequence && vs->discontinuity_set==0 ){
-        avio_printf((byterange_mode || hls->segment_type == SEGMENT_TYPE_FMP4) ? hls->m3u8_out : oc->pb, "#EXT-X-DISCONTINUITY\n");
+        avio_printf((byterange_mode || hls->segment_type == SEGMENT_TYPE_FMP4) ? hls->m3u8_out : vs->out, "#EXT-X-DISCONTINUITY\n");
         vs->discontinuity_set = 1;
     }
     if (vs->has_video && (hls->flags & HLS_INDEPENDENT_SEGMENTS)) {
-        avio_printf((byterange_mode || hls->segment_type == SEGMENT_TYPE_FMP4) ? hls->m3u8_out : oc->pb, "#EXT-X-INDEPENDENT-SEGMENTS\n");
+        avio_printf((byterange_mode || hls->segment_type == SEGMENT_TYPE_FMP4) ? hls->m3u8_out : vs->out, "#EXT-X-INDEPENDENT-SEGMENTS\n");
     }
     for (en = vs->segments; en; en = en->next) {
         if ((hls->encrypt || hls->key_info_file) && (!key_uri || strcmp(en->key_uri, key_uri) ||
                                     av_strcasecmp(en->iv_string, iv_string))) {
-            avio_printf((byterange_mode || hls->segment_type == SEGMENT_TYPE_FMP4) ? hls->m3u8_out : oc->pb, "#EXT-X-KEY:METHOD=AES-128,URI=\"%s\"", en->key_uri);
+            avio_printf((byterange_mode || hls->segment_type == SEGMENT_TYPE_FMP4) ? hls->m3u8_out : vs->out, "#EXT-X-KEY:METHOD=AES-128,URI=\"%s\"", en->key_uri);
             if (*en->iv_string)
-                avio_printf((byterange_mode || hls->segment_type == SEGMENT_TYPE_FMP4) ? hls->m3u8_out : oc->pb, ",IV=0x%s", en->iv_string);
-            avio_printf((byterange_mode || hls->segment_type == SEGMENT_TYPE_FMP4) ? hls->m3u8_out : oc->pb, "\n");
+                avio_printf((byterange_mode || hls->segment_type == SEGMENT_TYPE_FMP4) ? hls->m3u8_out : vs->out, ",IV=0x%s", en->iv_string);
+            avio_printf((byterange_mode || hls->segment_type == SEGMENT_TYPE_FMP4) ? hls->m3u8_out : vs->out, "\n");
             key_uri = en->key_uri;
             iv_string = en->iv_string;
         }
 
         if ((hls->segment_type == SEGMENT_TYPE_FMP4) && (en == vs->segments)) {
-            ff_hls_write_init_file((byterange_mode || hls->segment_type == SEGMENT_TYPE_FMP4) ? hls->m3u8_out : oc->pb, (hls->flags & HLS_SINGLE_FILE) ? en->filename : vs->fmp4_init_filename,
+            ff_hls_write_init_file((byterange_mode || hls->segment_type == SEGMENT_TYPE_FMP4) ? hls->m3u8_out : vs->out, (hls->flags & HLS_SINGLE_FILE) ? en->filename : vs->fmp4_init_filename,
                                    hls->flags & HLS_SINGLE_FILE, vs->init_range_length, 0);
         }
 
-        ret = ff_hls_write_file_entry((byterange_mode || hls->segment_type == SEGMENT_TYPE_FMP4) ? hls->m3u8_out : oc->pb, en->discont, byterange_mode,
+        ret = ff_hls_write_file_entry((byterange_mode || hls->segment_type == SEGMENT_TYPE_FMP4) ? hls->m3u8_out : vs->out, en->discont, byterange_mode,
                                       en->duration, hls->flags & HLS_ROUND_DURATIONS,
                                       en->size, en->pos, vs->baseurl,
                                       en->filename, prog_date_time_p, en->keyframe_size, en->keyframe_pos, hls->flags & HLS_I_FRAMES_ONLY);
@@ -1519,7 +1523,7 @@  static int hls_window(AVFormatContext *s, int last, VariantStream *vs)
     }
 
     if (last && (hls->flags & HLS_OMIT_ENDLIST)==0)
-        ff_hls_write_end_list((byterange_mode || hls->segment_type == SEGMENT_TYPE_FMP4) ? hls->m3u8_out : oc->pb);
+        ff_hls_write_end_list((byterange_mode || hls->segment_type == SEGMENT_TYPE_FMP4) ? hls->m3u8_out : vs->out);
 
     if (vs->vtt_m3u8_name) {
         snprintf(temp_vtt_filename, sizeof(temp_vtt_filename), use_temp_file ? "%s.tmp" : "%s", vs->vtt_m3u8_name);
@@ -1546,7 +1550,7 @@  static int hls_window(AVFormatContext *s, int last, VariantStream *vs)
 
 fail:
     av_dict_free(&options);
-    hlsenc_io_close(s, (byterange_mode || hls->segment_type == SEGMENT_TYPE_FMP4) ? &hls->m3u8_out : &oc->pb, temp_filename);
+    hlsenc_io_close(s, (byterange_mode || hls->segment_type == SEGMENT_TYPE_FMP4) ? &hls->m3u8_out : &vs->out, temp_filename);
     hlsenc_io_close(s, &hls->sub_m3u8_out, vs->vtt_m3u8_name);
     if (use_temp_file) {
         ff_rename(temp_filename, vs->m3u8_name, s);
@@ -1713,23 +1717,7 @@  static int hls_start(AVFormatContext *s, VariantStream *vs)
         av_dict_free(&options);
         if (err < 0)
             return err;
-    } else if (c->segment_type != SEGMENT_TYPE_FMP4) {
-        if ((err = hlsenc_io_open(s, &oc->pb, oc->url, &options)) < 0) {
-            if (c->ignore_io_errors)
-                err = 0;
-            goto fail;
-        }
     }
-    if (vs->vtt_basename) {
-        set_http_options(s, &options, c);
-        if ((err = hlsenc_io_open(s, &vtt_oc->pb, vtt_oc->url, &options)) < 0) {
-            if (c->ignore_io_errors)
-                err = 0;
-            goto fail;
-        }
-    }
-    av_dict_free(&options);
-
     if (c->segment_type != SEGMENT_TYPE_FMP4) {
         /* We only require one PAT/PMT per segment. */
         if (oc->oformat->priv_class && oc->priv_data) {
@@ -1741,7 +1729,23 @@  static int hls_start(AVFormatContext *s, VariantStream *vs)
             av_opt_set(oc->priv_data, "sdt_period", period, 0);
             av_opt_set(oc->priv_data, "pat_period", period, 0);
         }
+        if (c->flags & HLS_SINGLE_FILE) {
+            if ((err = hlsenc_io_open(s, &vs->out, oc->url, &options)) < 0) {
+                if (c->ignore_io_errors)
+                    err = 0;
+                goto fail;
+            }
+        }
+    }
+    if (vs->vtt_basename) {
+        set_http_options(s, &options, c);
+        if ((err = hlsenc_io_open(s, &vtt_oc->pb, vtt_oc->url, &options)) < 0) {
+            if (c->ignore_io_errors)
+                err = 0;
+            goto fail;
+        }
     }
+    av_dict_free(&options);
 
     if (vs->vtt_basename) {
         err = avformat_write_header(vtt_oc,NULL);
@@ -2343,20 +2347,12 @@  static int hls_write_packet(AVFormatContext *s, AVPacket *pkt)
         int64_t new_start_pos;
         int byterange_mode = (hls->flags & HLS_SINGLE_FILE) || (hls->max_seg_size > 0);
 
-        av_write_frame(vs->avf, NULL); /* Flush any buffered data */
-
-        new_start_pos = avio_tell(vs->avf->pb);
-
-        if (hls->segment_type != SEGMENT_TYPE_FMP4) {
-            avio_flush(oc->pb);
-            vs->size = new_start_pos - vs->start_pos;
-        } else {
-            vs->size = new_start_pos;
-        }
-
+        av_write_frame(oc, NULL); /* Flush any buffered data */
+        new_start_pos = avio_tell(oc->pb);
+        vs->size = new_start_pos - vs->start_pos;
+        avio_flush(oc->pb);
         if (hls->segment_type == SEGMENT_TYPE_FMP4) {
             if (!vs->init_range_length) {
-                avio_flush(oc->pb);
                 range_length = avio_close_dyn_buf(oc->pb, &buffer);
                 avio_write(vs->out, buffer, range_length);
                 av_free(buffer);
@@ -2369,10 +2365,6 @@  static int hls_write_packet(AVFormatContext *s, AVPacket *pkt)
                     hlsenc_io_close(s, &vs->out, vs->base_output_dirname);
                 }
             }
-        } else {
-            if (!byterange_mode) {
-                hlsenc_io_close(s, &oc->pb, oc->url);
-            }
         }
         if (!byterange_mode) {
             if (vs->vtt_avf) {
@@ -2387,32 +2379,32 @@  static int hls_write_packet(AVFormatContext *s, AVPacket *pkt)
 
         // look to rename the asset name
         if (use_temp_file) {
-            if (!(hls->flags & HLS_SINGLE_FILE) || (hls->max_seg_size <= 0))
-                if ((vs->avf->oformat->priv_class && vs->avf->priv_data) && hls->segment_type != SEGMENT_TYPE_FMP4)
-                    av_opt_set(vs->avf->priv_data, "mpegts_flags", "resend_headers", 0);
+            av_dict_set(&options, "mpegts_flags", "resend_headers", 0);
         }
 
-        if (hls->segment_type == SEGMENT_TYPE_FMP4) {
-            if (hls->flags & HLS_SINGLE_FILE) {
-                ret = flush_dynbuf(vs, &range_length);
-                if (ret < 0) {
-                    return ret;
-                }
-                vs->size = range_length;
-            } else {
-                set_http_options(s, &options, hls);
-                ret = hlsenc_io_open(s, &vs->out, vs->avf->url, &options);
+        if (hls->flags & HLS_SINGLE_FILE) {
+            ret = flush_dynbuf(vs, &range_length);
+            if (ret < 0) {
+                return ret;
+            }
+            vs->size = range_length;
+        } else {
+            set_http_options(s, &options, hls);
+            if ((hls->max_seg_size > 0 && (vs->size >= hls->max_seg_size)) || !byterange_mode) {
+                ret = hlsenc_io_open(s, &vs->out, oc->url, &options);
                 if (ret < 0) {
                     av_log(s, hls->ignore_io_errors ? AV_LOG_WARNING : AV_LOG_ERROR,
-                           "Failed to open file '%s'\n", vs->avf->url);
+                           "Failed to open file '%s'\n", oc->url);
                     return hls->ignore_io_errors ? 0 : ret;
                 }
-                write_styp(vs->out);
+                if (hls->segment_type == SEGMENT_TYPE_FMP4) {
+                    write_styp(vs->out);
+                }
                 ret = flush_dynbuf(vs, &range_length);
                 if (ret < 0) {
                     return ret;
                 }
-                ff_format_io_close(s, &vs->out);
+                hlsenc_io_close(s, &vs->out, oc->url);
             }
         }
 
@@ -2420,7 +2412,7 @@  static int hls_write_packet(AVFormatContext *s, AVPacket *pkt)
             hls_rename_temp_file(s, oc);
         }
 
-        old_filename = av_strdup(vs->avf->url);
+        old_filename = av_strdup(oc->url);
         if (!old_filename) {
             return AVERROR(ENOMEM);
         }
@@ -2435,11 +2427,6 @@  static int hls_write_packet(AVFormatContext *s, AVPacket *pkt)
             }
         }
 
-        if (hls->segment_type != SEGMENT_TYPE_FMP4) {
-            vs->start_pos = new_start_pos;
-        } else {
-            vs->start_pos += vs->size;
-        }
         // if we're building a VOD playlist, skip writing the manifest multiple times, and just wait until the end
         if (hls->pl_type != PLAYLIST_TYPE_VOD) {
             if ((ret = hls_window(s, 0, vs)) < 0) {
@@ -2449,8 +2436,10 @@  static int hls_write_packet(AVFormatContext *s, AVPacket *pkt)
 
         if (hls->flags & HLS_SINGLE_FILE) {
             vs->number++;
+            vs->start_pos += vs->size;
         } else if (hls->max_seg_size > 0) {
-            if (vs->start_pos >= hls->max_seg_size) {
+            vs->start_pos = new_start_pos;
+            if (vs->size >= hls->max_seg_size) {
                 vs->sequence++;
                 sls_flag_file_rename(hls, vs, old_filename);
                 ret = hls_start(s, vs);
@@ -2461,6 +2450,7 @@  static int hls_write_packet(AVFormatContext *s, AVPacket *pkt)
             }
             vs->number++;
         } else {
+            vs->start_pos = new_start_pos;
             sls_flag_file_rename(hls, vs, old_filename);
             ret = hls_start(s, vs);
         }
@@ -2481,7 +2471,6 @@  static int hls_write_packet(AVFormatContext *s, AVPacket *pkt)
         } else {
             vs->video_lastpos = avio_tell(oc->pb);
         }
-
         if (hls->ignore_io_errors)
             ret = 0;
     }
@@ -2530,10 +2519,11 @@  static int hls_write_trailer(struct AVFormatContext *s)
     int i;
     int ret = 0;
     VariantStream *vs = NULL;
+    AVDictionary *options = NULL;
+    int range_length, byterange_mode;
 
     for (i = 0; i < hls->nb_varstreams; i++) {
         vs = &hls->var_streams[i];
-
         oc = vs->avf;
         vtt_oc = vs->vtt_avf;
         old_filename = av_strdup(vs->avf->url);
@@ -2546,7 +2536,6 @@  static int hls_write_trailer(struct AVFormatContext *s)
             int range_length = 0;
             if (!vs->init_range_length) {
                 uint8_t *buffer = NULL;
-                int range_length, byterange_mode;
                 av_write_frame(vs->avf, NULL); /* Flush any buffered data */
                 avio_flush(oc->pb);
 
@@ -2563,21 +2552,23 @@  static int hls_write_trailer(struct AVFormatContext *s)
                     hlsenc_io_close(s, &vs->out, vs->base_output_dirname);
                 }
             }
-            if (!(hls->flags & HLS_SINGLE_FILE)) {
-                ret = hlsenc_io_open(s, &vs->out, vs->avf->url, NULL);
-                if (ret < 0) {
-                    av_log(s, AV_LOG_ERROR, "Failed to open file '%s'\n", vs->avf->url);
-                    goto failed;
-                }
-                write_styp(vs->out);
-            }
-            ret = flush_dynbuf(vs, &range_length);
+        }
+        if (!(hls->flags & HLS_SINGLE_FILE)) {
+            set_http_options(s, &options, hls);
+            ret = hlsenc_io_open(s, &vs->out, vs->avf->url, &options);
             if (ret < 0) {
+                av_log(s, AV_LOG_ERROR, "Failed to open file '%s'\n", vs->avf->url);
                 goto failed;
             }
-            vs->size = range_length;
-            ff_format_io_close(s, &vs->out);
+            if (hls->segment_type == SEGMENT_TYPE_FMP4)
+                write_styp(vs->out);
         }
+        ret = flush_dynbuf(vs, &range_length);
+        if (ret < 0)
+            goto failed;
+
+        vs->size = range_length;
+        hlsenc_io_close(s, &vs->out, vs->avf->url);
 
 failed:
         av_write_trailer(oc);
@@ -2587,12 +2578,6 @@  failed:
             use_temp_file = proto && !strcmp(proto, "file") && (hls->flags & HLS_TEMP_FILE);
         }
 
-        if (oc->pb) {
-            if (hls->segment_type != SEGMENT_TYPE_FMP4) {
-                vs->size = avio_tell(vs->avf->pb) - vs->start_pos;
-                hlsenc_io_close(s, &vs->avf->pb, vs->avf->url);
-            }
-
             // rename that segment from .tmp to the real one
             if (use_temp_file && !(hls->flags & HLS_SINGLE_FILE)) {
                 hls_rename_temp_file(s, oc);
@@ -2606,7 +2591,6 @@  failed:
 
             /* after av_write_trailer, then duration + 1 duration per packet */
             hls_append_segment(s, hls, vs, vs->duration + vs->dpp, vs->start_pos, vs->size);
-        }
 
         sls_flag_file_rename(hls, vs, old_filename);