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

Submitted by Steven Liu on Aug. 5, 2019, 2:29 a.m.

Details

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

Commit Message

Steven Liu Aug. 5, 2019, 2:29 a.m.
just remove the 'i' of the v3 mail subject.
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 | 251 +++++++++++++++++++++----------------------
 1 file changed, 124 insertions(+), 127 deletions(-)

Comments

Steven Liu Aug. 9, 2019, 9:30 a.m.
> 在 2019年8月5日,上午10:29,Steven Liu <lq@chinaffmpeg.org> 写道:
> 
> just remove the 'i' of the v3 mail subject.
> 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 | 251 +++++++++++++++++++++----------------------
> 1 file changed, 124 insertions(+), 127 deletions(-)
> 
> diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c
> index 51310fb528..f6f9c8161d 100644
> --- a/libavformat/hlsenc.c
> +++ b/libavformat/hlsenc.c
> @@ -815,7 +815,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 +824,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 +866,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 +1439,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 +1474,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 +1486,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 +1522,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 +1549,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);
> @@ -1694,42 +1697,13 @@ static int hls_start(AVFormatContext *s, VariantStream *vs)
>             }
>             c->encrypt_started = 1;
>         }
> -        if ((err = av_dict_set(&options, "encryption_key", c->key_string, 0))
> -                < 0)
> -            goto fail;
>         err = av_strlcpy(iv_string, c->iv_string, sizeof(iv_string));
> -        if (!err)
> +        if (!err) {
>             snprintf(iv_string, sizeof(iv_string), "%032"PRIx64, vs->sequence);
> -        if ((err = av_dict_set(&options, "encryption_iv", iv_string, 0)) < 0)
> -           goto fail;
> -
> -        filename = av_asprintf("crypto:%s", oc->url);
> -        if (!filename) {
> -            err = AVERROR(ENOMEM);
> -            goto fail;
> -        }
> -        err = hlsenc_io_open(s, &oc->pb, filename, &options);
> -        av_free(filename);
> -        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;
> +            memset(c->iv_string, 0, sizeof(c->iv_string));
> +            memcpy(c->iv_string, iv_string, sizeof(iv_string));
>         }
>     }
> -    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 +1715,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 +2333,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);
> @@ -2365,14 +2347,10 @@ static int hls_write_packet(AVFormatContext *s, AVPacket *pkt)
>                 vs->packets_written = 0;
>                 vs->start_pos = range_length;
>                 if (!byterange_mode) {
> -                    ff_format_io_close(s, &vs->out);
> +//                    ff_format_io_close(s, &vs->out);
>                     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 +2365,44 @@ 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;
> +        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) {
> +                char *filename = NULL;
> +                if (hls->key_info_file || hls->encrypt) {
> +                    av_dict_set(&options, "encryption_key", hls->key_string, 0);
> +                    av_dict_set(&options, "encryption_iv", hls->iv_string, 0);
> +                    filename = av_asprintf("crypto:%s", oc->url);
> +                } else {
> +                    filename = av_asprintf("%s", oc->url);
>                 }
> -                vs->size = range_length;
> -            } else {
> -                set_http_options(s, &options, hls);
> -                ret = hlsenc_io_open(s, &vs->out, vs->avf->url, &options);
> +                if (!filename) {
> +                    return AVERROR(ENOMEM);
> +                }
> +                ret = hlsenc_io_open(s, &vs->out, filename, &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", filename);
>                     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, filename);
> +                av_free(filename);
>             }
>         }
> 
> @@ -2420,7 +2410,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 +2425,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 +2434,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 +2448,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);
>         }
> @@ -2475,13 +2463,12 @@ static int hls_write_packet(AVFormatContext *s, AVPacket *pkt)
>     vs->packets_written++;
>     if (oc->pb) {
>         ret = ff_write_chained(oc, stream_index, pkt, s, 0);
> +        vs->video_keyframe_size += pkt->size;
>         if ((st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) && (pkt->flags & AV_PKT_FLAG_KEY)) {
> -            vs->video_keyframe_size = avio_tell(oc->pb) - vs->video_lastpos;
> -            vs->video_keyframe_pos = vs->start_pos;
> +            vs->video_keyframe_size = avio_tell(oc->pb);
>         } else {
> -            vs->video_lastpos = avio_tell(oc->pb);
> +            vs->video_keyframe_pos = avio_tell(vs->out);
>         }
> -
>         if (hls->ignore_io_errors)
>             ret = 0;
>     }
> @@ -2530,10 +2517,12 @@ 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++) {
> +        char *filename = NULL;
>         vs = &hls->var_streams[i];
> -
>         oc = vs->avf;
>         vtt_oc = vs->vtt_avf;
>         old_filename = av_strdup(vs->avf->url);
> @@ -2542,11 +2531,22 @@ static int hls_write_trailer(struct AVFormatContext *s)
>         if (!old_filename) {
>             return AVERROR(ENOMEM);
>         }
> +        if (hls->key_info_file || hls->encrypt) {
> +            av_dict_set(&options, "encryption_key", hls->key_string, 0);
> +            av_dict_set(&options, "encryption_iv", hls->iv_string, 0);
> +            filename = av_asprintf("crypto:%s", vs->avf->url);
> +        } else {
> +            filename = av_asprintf("%s", vs->avf->url);
> +        }
> +        if (!filename) {
> +            return AVERROR(ENOMEM);
> +        }
> +
> +
>         if ( hls->segment_type == SEGMENT_TYPE_FMP4) {
>             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 +2563,25 @@ 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, filename, &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, filename);
> +        av_free(filename);
> +
> 
> failed:
>         av_write_trailer(oc);
> @@ -2587,12 +2591,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 +2604,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);
> 
> -- 
> 2.17.2 (Apple Git-113)
> 
> 
> 
> _______________________________________________
> 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".


ping?


Thanks
Steven
Steven Liu Aug. 18, 2019, 12:23 a.m.
> 在 2019年8月9日,下午5:30,Liu Steven <lq@chinaffmpeg.org> 写道:
> 
> 
> 
>> 在 2019年8月5日,上午10:29,Steven Liu <lq@chinaffmpeg.org> 写道:
>> 
>> just remove the 'i' of the v3 mail subject.
>> 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 | 251 +++++++++++++++++++++----------------------
>> 1 file changed, 124 insertions(+), 127 deletions(-)
>> 
>> diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c
>> index 51310fb528..f6f9c8161d 100644
>> --- a/libavformat/hlsenc.c
>> +++ b/libavformat/hlsenc.c
>> @@ -815,7 +815,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 +824,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 +866,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 +1439,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 +1474,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 +1486,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 +1522,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 +1549,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);
>> @@ -1694,42 +1697,13 @@ static int hls_start(AVFormatContext *s, VariantStream *vs)
>>            }
>>            c->encrypt_started = 1;
>>        }
>> -        if ((err = av_dict_set(&options, "encryption_key", c->key_string, 0))
>> -                < 0)
>> -            goto fail;
>>        err = av_strlcpy(iv_string, c->iv_string, sizeof(iv_string));
>> -        if (!err)
>> +        if (!err) {
>>            snprintf(iv_string, sizeof(iv_string), "%032"PRIx64, vs->sequence);
>> -        if ((err = av_dict_set(&options, "encryption_iv", iv_string, 0)) < 0)
>> -           goto fail;
>> -
>> -        filename = av_asprintf("crypto:%s", oc->url);
>> -        if (!filename) {
>> -            err = AVERROR(ENOMEM);
>> -            goto fail;
>> -        }
>> -        err = hlsenc_io_open(s, &oc->pb, filename, &options);
>> -        av_free(filename);
>> -        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;
>> +            memset(c->iv_string, 0, sizeof(c->iv_string));
>> +            memcpy(c->iv_string, iv_string, sizeof(iv_string));
>>        }
>>    }
>> -    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 +1715,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 +2333,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);
>> @@ -2365,14 +2347,10 @@ static int hls_write_packet(AVFormatContext *s, AVPacket *pkt)
>>                vs->packets_written = 0;
>>                vs->start_pos = range_length;
>>                if (!byterange_mode) {
>> -                    ff_format_io_close(s, &vs->out);
>> +//                    ff_format_io_close(s, &vs->out);
>>                    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 +2365,44 @@ 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;
>> +        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) {
>> +                char *filename = NULL;
>> +                if (hls->key_info_file || hls->encrypt) {
>> +                    av_dict_set(&options, "encryption_key", hls->key_string, 0);
>> +                    av_dict_set(&options, "encryption_iv", hls->iv_string, 0);
>> +                    filename = av_asprintf("crypto:%s", oc->url);
>> +                } else {
>> +                    filename = av_asprintf("%s", oc->url);
>>                }
>> -                vs->size = range_length;
>> -            } else {
>> -                set_http_options(s, &options, hls);
>> -                ret = hlsenc_io_open(s, &vs->out, vs->avf->url, &options);
>> +                if (!filename) {
>> +                    return AVERROR(ENOMEM);
>> +                }
>> +                ret = hlsenc_io_open(s, &vs->out, filename, &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", filename);
>>                    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, filename);
>> +                av_free(filename);
>>            }
>>        }
>> 
>> @@ -2420,7 +2410,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 +2425,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 +2434,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 +2448,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);
>>        }
>> @@ -2475,13 +2463,12 @@ static int hls_write_packet(AVFormatContext *s, AVPacket *pkt)
>>    vs->packets_written++;
>>    if (oc->pb) {
>>        ret = ff_write_chained(oc, stream_index, pkt, s, 0);
>> +        vs->video_keyframe_size += pkt->size;
>>        if ((st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) && (pkt->flags & AV_PKT_FLAG_KEY)) {
>> -            vs->video_keyframe_size = avio_tell(oc->pb) - vs->video_lastpos;
>> -            vs->video_keyframe_pos = vs->start_pos;
>> +            vs->video_keyframe_size = avio_tell(oc->pb);
>>        } else {
>> -            vs->video_lastpos = avio_tell(oc->pb);
>> +            vs->video_keyframe_pos = avio_tell(vs->out);
>>        }
>> -
>>        if (hls->ignore_io_errors)
>>            ret = 0;
>>    }
>> @@ -2530,10 +2517,12 @@ 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++) {
>> +        char *filename = NULL;
>>        vs = &hls->var_streams[i];
>> -
>>        oc = vs->avf;
>>        vtt_oc = vs->vtt_avf;
>>        old_filename = av_strdup(vs->avf->url);
>> @@ -2542,11 +2531,22 @@ static int hls_write_trailer(struct AVFormatContext *s)
>>        if (!old_filename) {
>>            return AVERROR(ENOMEM);
>>        }
>> +        if (hls->key_info_file || hls->encrypt) {
>> +            av_dict_set(&options, "encryption_key", hls->key_string, 0);
>> +            av_dict_set(&options, "encryption_iv", hls->iv_string, 0);
>> +            filename = av_asprintf("crypto:%s", vs->avf->url);
>> +        } else {
>> +            filename = av_asprintf("%s", vs->avf->url);
>> +        }
>> +        if (!filename) {
>> +            return AVERROR(ENOMEM);
>> +        }
>> +
>> +
>>        if ( hls->segment_type == SEGMENT_TYPE_FMP4) {
>>            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 +2563,25 @@ 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, filename, &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, filename);
>> +        av_free(filename);
>> +
>> 
>> failed:
>>        av_write_trailer(oc);
>> @@ -2587,12 +2591,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 +2604,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);
>> 
>> -- 
>> 2.17.2 (Apple Git-113)
>> 
>> 
>> 
>> _______________________________________________
>> 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".
> 
> 
> ping?
> 
Pushed
> 
> Thanks
> Steven
> 
> _______________________________________________
> 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".
Andreas Rheinhardt Sept. 8, 2019, 6:55 a.m.
Liu Steven:
> 
> 
>> 在 2019年8月9日,下午5:30,Liu Steven <lq@chinaffmpeg.org> 写道:
>>
>>
>>
>>> 在 2019年8月5日,上午10:29,Steven Liu <lq@chinaffmpeg.org> 写道:
>>>
>>> just remove the 'i' of the v3 mail subject.
>>> 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>
>>
>> ping?
>>
> Pushed

This patch both created and fixed memleaks: Before this patch,
generating hls_segment_size.m3u8 (needed for fate-hls-segment-size)
leaks 792 B directly and 787122 B indirectly. With this patch,
Generating hls_segment_size.m3u8 and hls_init_time.m3u8 leaks 264 B
directly and 1056 B indirectly.
The leaks happen in hls_write_trailer: The last dynamic buffer that is
opened in flush_dynbuf is not freed. I wanted to add a call to
ffio_free_dyn_buf, but then I noticed that it seems that if something
gets written in av_write_trailer(oc) it never leaves the dynamic
buffer, although it probably should. So I leave fixing this to those
who know this code better than I do.

- Andreas

PS: For the fate test run with Valgrind this means that generating the
necessary test files fails. But the tests itself are not counted as
failing on the website [1]. Instead, the number of tests decreased.

[1]: http://fate.ffmpeg.org/history.cgi?slot=x86_64-archlinux-gcc-valgrind
Steven Liu Sept. 9, 2019, 6:19 a.m.
> 在 2019年9月8日,下午2:55,Andreas Rheinhardt <andreas.rheinhardt@gmail.com> 写道:
> 
> Liu Steven:
>> 
>> 
>>> 在 2019年8月9日,下午5:30,Liu Steven <lq@chinaffmpeg.org> 写道:
>>> 
>>> 
>>> 
>>>> 在 2019年8月5日,上午10:29,Steven Liu <lq@chinaffmpeg.org> 写道:
>>>> 
>>>> just remove the 'i' of the v3 mail subject.
>>>> 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>
>>> 
>>> ping?
>>> 
>> Pushed
> 
> This patch both created and fixed memleaks: Before this patch,
> generating hls_segment_size.m3u8 (needed for fate-hls-segment-size)
> leaks 792 B directly and 787122 B indirectly. With this patch,
> Generating hls_segment_size.m3u8 and hls_init_time.m3u8 leaks 264 B
> directly and 1056 B indirectly.
> The leaks happen in hls_write_trailer: The last dynamic buffer that is
> opened in flush_dynbuf is not freed. I wanted to add a call to
> ffio_free_dyn_buf, but then I noticed that it seems that if something
> gets written in av_write_trailer(oc) it never leaves the dynamic
> buffer, although it probably should. So I leave fixing this to those
> who know this code better than I do.

Hi Andreas,

	Do you mean it should be fixed by this patch?

https://patchwork.ffmpeg.org/patch/14984/


> 
> - Andreas
> 
> PS: For the fate test run with Valgrind this means that generating the
> necessary test files fails. But the tests itself are not counted as
> failing on the website [1]. Instead, the number of tests decreased.
> 
> [1]: http://fate.ffmpeg.org/history.cgi?slot=x86_64-archlinux-gcc-valgrind
> _______________________________________________
> 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..f6f9c8161d 100644
--- a/libavformat/hlsenc.c
+++ b/libavformat/hlsenc.c
@@ -815,7 +815,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 +824,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 +866,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 +1439,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 +1474,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 +1486,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 +1522,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 +1549,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);
@@ -1694,42 +1697,13 @@  static int hls_start(AVFormatContext *s, VariantStream *vs)
             }
             c->encrypt_started = 1;
         }
-        if ((err = av_dict_set(&options, "encryption_key", c->key_string, 0))
-                < 0)
-            goto fail;
         err = av_strlcpy(iv_string, c->iv_string, sizeof(iv_string));
-        if (!err)
+        if (!err) {
             snprintf(iv_string, sizeof(iv_string), "%032"PRIx64, vs->sequence);
-        if ((err = av_dict_set(&options, "encryption_iv", iv_string, 0)) < 0)
-           goto fail;
-
-        filename = av_asprintf("crypto:%s", oc->url);
-        if (!filename) {
-            err = AVERROR(ENOMEM);
-            goto fail;
-        }
-        err = hlsenc_io_open(s, &oc->pb, filename, &options);
-        av_free(filename);
-        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;
+            memset(c->iv_string, 0, sizeof(c->iv_string));
+            memcpy(c->iv_string, iv_string, sizeof(iv_string));
         }
     }
-    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 +1715,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 +2333,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);
@@ -2365,14 +2347,10 @@  static int hls_write_packet(AVFormatContext *s, AVPacket *pkt)
                 vs->packets_written = 0;
                 vs->start_pos = range_length;
                 if (!byterange_mode) {
-                    ff_format_io_close(s, &vs->out);
+//                    ff_format_io_close(s, &vs->out);
                     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 +2365,44 @@  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;
+        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) {
+                char *filename = NULL;
+                if (hls->key_info_file || hls->encrypt) {
+                    av_dict_set(&options, "encryption_key", hls->key_string, 0);
+                    av_dict_set(&options, "encryption_iv", hls->iv_string, 0);
+                    filename = av_asprintf("crypto:%s", oc->url);
+                } else {
+                    filename = av_asprintf("%s", oc->url);
                 }
-                vs->size = range_length;
-            } else {
-                set_http_options(s, &options, hls);
-                ret = hlsenc_io_open(s, &vs->out, vs->avf->url, &options);
+                if (!filename) {
+                    return AVERROR(ENOMEM);
+                }
+                ret = hlsenc_io_open(s, &vs->out, filename, &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", filename);
                     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, filename);
+                av_free(filename);
             }
         }
 
@@ -2420,7 +2410,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 +2425,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 +2434,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 +2448,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);
         }
@@ -2475,13 +2463,12 @@  static int hls_write_packet(AVFormatContext *s, AVPacket *pkt)
     vs->packets_written++;
     if (oc->pb) {
         ret = ff_write_chained(oc, stream_index, pkt, s, 0);
+        vs->video_keyframe_size += pkt->size;
         if ((st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) && (pkt->flags & AV_PKT_FLAG_KEY)) {
-            vs->video_keyframe_size = avio_tell(oc->pb) - vs->video_lastpos;
-            vs->video_keyframe_pos = vs->start_pos;
+            vs->video_keyframe_size = avio_tell(oc->pb);
         } else {
-            vs->video_lastpos = avio_tell(oc->pb);
+            vs->video_keyframe_pos = avio_tell(vs->out);
         }
-
         if (hls->ignore_io_errors)
             ret = 0;
     }
@@ -2530,10 +2517,12 @@  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++) {
+        char *filename = NULL;
         vs = &hls->var_streams[i];
-
         oc = vs->avf;
         vtt_oc = vs->vtt_avf;
         old_filename = av_strdup(vs->avf->url);
@@ -2542,11 +2531,22 @@  static int hls_write_trailer(struct AVFormatContext *s)
         if (!old_filename) {
             return AVERROR(ENOMEM);
         }
+        if (hls->key_info_file || hls->encrypt) {
+            av_dict_set(&options, "encryption_key", hls->key_string, 0);
+            av_dict_set(&options, "encryption_iv", hls->iv_string, 0);
+            filename = av_asprintf("crypto:%s", vs->avf->url);
+        } else {
+            filename = av_asprintf("%s", vs->avf->url);
+        }
+        if (!filename) {
+            return AVERROR(ENOMEM);
+        }
+
+
         if ( hls->segment_type == SEGMENT_TYPE_FMP4) {
             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 +2563,25 @@  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, filename, &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, filename);
+        av_free(filename);
+
 
 failed:
         av_write_trailer(oc);
@@ -2587,12 +2591,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 +2604,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);