> On Aug 15, 2018, at 6:46 AM, Liu Steven <[email protected]> wrote:
>
>
>
>>> 在 2018年8月15日,下午6:37,Ronak Patel <[email protected]> 写道:
>>>
>>>
>>> On Aug 14, 2018, at 10:57 PM, Liu Steven <[email protected]> wrote:
>>>
>>>
>>>
>>>> 在 2018年8月15日,上午9:31,Ronak <[email protected]> 写道:
>>>>
>>>> From: "Ronak Patel" <ronak2121@ <mailto:[email protected]>yahoo.com>
>>>>
>>>> This fixes the creation of the hls manifest in hlsenc.c by writing the
>>>> entire manifest at the end for VOD playlists. Live & Event Playlists are
>>>> unaffected.
>>>> This also fixes the behavior with HLS_TEMP_FILE to work correctly when
>>>> -hlsflags temp_file is specified, instead of always relying on use_rename,
>>>> which caused these problems.
>>>>
>>>> Files that would previously take over a week to fragment now take 1 minute
>>>> on the same hardware. This was a 153 hour audio file (2.2GB of audio).
>>>>
>>>> Signed-off-by: Ronak Patel <[email protected]
>>>> <mailto:[email protected]>>
>>>> ---
>>>> libavformat/hlsenc.c | 51
>>>> ++++++++++++++++++++++++++++++++++++---------------
>>>> 1 file changed, 36 insertions(+), 15 deletions(-)
>>>>
>>>> diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c
>>>> index b5644f0..7933b79 100644
>>>> --- a/libavformat/hlsenc.c
>>>> +++ b/libavformat/hlsenc.c
>>>> @@ -1168,7 +1168,6 @@ static int hls_rename_temp_file(AVFormatContext *s,
>>>> AVFormatContext *oc)
>>>> return AVERROR(ENOMEM);
>>>> final_filename[len-4] = '\0';
>>>> ret = ff_rename(oc->url, final_filename, s);
>>>> - oc->url[len-4] = '\0';
>>>> av_freep(&final_filename);
>>>> return ret;
>>>> }
>>>> @@ -1374,7 +1373,7 @@ static int hls_window(AVFormatContext *s, int last,
>>>> VariantStream *vs)
>>>> char temp_filename[1024];
>>>> int64_t sequence = FFMAX(hls->start_sequence, vs->sequence -
>>>> vs->nb_entries);
>>>> const char *proto = avio_find_protocol_name(s->url);
>>>> - int use_rename = proto && !strcmp(proto, "file");
>>>> + int use_temp_file = proto && !strcmp(proto, "file") && (s->flags &
>>>> HLS_TEMP_FILE);
>>>> static unsigned warned_non_file;
>>>> char *key_uri = NULL;
>>>> char *iv_string = NULL;
>>>> @@ -1397,11 +1396,11 @@ static int hls_window(AVFormatContext *s, int
>>>> last, VariantStream *vs)
>>>> hls->version = 7;
>>>> }
>>>> - if (!use_rename && !warned_non_file++)
>>>> + if (!use_temp_file && !warned_non_file++)
>>>> av_log(s, AV_LOG_ERROR, "Cannot use rename on non file protocol, this
>>>> may lead to races and temporary partial files\n");
>>>> set_http_options(s, &options, hls);
>>>> - snprintf(temp_filename, sizeof(temp_filename), use_rename ? "%s.tmp"
>>>> : "%s", vs->m3u8_name);
>>>> + snprintf(temp_filename, sizeof(temp_filename), use_temp_file ?
>>>> "%s.tmp" : "%s", vs->m3u8_name);
>>>> if ((ret = hlsenc_io_open(s, &hls->m3u8_out, temp_filename, &options)) <
>>>> 0)
>>>> goto fail;
>>>> @@ -1472,8 +1471,8 @@ fail:
>>>> av_dict_free(&options);
>>>> hlsenc_io_close(s, &hls->m3u8_out, temp_filename);
>>>> hlsenc_io_close(s, &hls->sub_m3u8_out, vs->vtt_m3u8_name);
>>>> - if (ret >= 0 && use_rename)
>>>> - ff_rename(temp_filename, vs->m3u8_name, s);
>>>> + if (use_temp_file)
>>>> + ff_rename(temp_filename, vs->m3u8_name, s);
>>>> if (ret >= 0 && hls->master_pl_name)
>>>> if (create_master_playlist(s, vs) < 0)
>>>> @@ -1488,6 +1487,8 @@ static int hls_start(AVFormatContext *s,
>>>> VariantStream *vs)
>>>> AVFormatContext *oc = vs->avf;
>>>> AVFormatContext *vtt_oc = vs->vtt_avf;
>>>> AVDictionary *options = NULL;
>>>> + const char *proto = avio_find_protocol_name(s->url);
>>>> + int use_temp_file = proto && !strcmp(proto, "file") && (s->flags &
>>>> HLS_TEMP_FILE);
>>>> char *filename, iv_string[KEYSIZE*2 + 1];
>>>> int err = 0;
>>>> @@ -1583,7 +1584,7 @@ static int hls_start(AVFormatContext *s,
>>>> VariantStream *vs)
>>>> set_http_options(s, &options, c);
>>>> - if (c->flags & HLS_TEMP_FILE) {
>>>> + if (use_temp_file) {
>>>> char *new_name = av_asprintf("%s.tmp", oc->url);
>>>> if (!new_name)
>>>> return AVERROR(ENOMEM);
>>>> @@ -2145,6 +2146,8 @@ static int hls_write_packet(AVFormatContext *s,
>>>> AVPacket *pkt)
>>>> int ret = 0, can_split = 1, i, j;
>>>> int stream_index = 0;
>>>> int range_length = 0;
>>>> + const char *proto = avio_find_protocol_name(s->url);
>>>> + int use_temp_file = proto && !strcmp(proto, "file") && (s->flags &
>>>> HLS_TEMP_FILE);
>>>> uint8_t *buffer = NULL;
>>>> VariantStream *vs = NULL;
>>>> AVDictionary *options = NULL;
>>>> @@ -2214,10 +2217,10 @@ static int hls_write_packet(AVFormatContext *s,
>>>> AVPacket *pkt)
>>>> }
>>>> + char *old_filename = NULL;
>>>> if (vs->packets_written && can_split && av_compare_ts(pkt->pts -
>>>> vs->start_pts, st->time_base,
>>>> end_pts,
>>>> AV_TIME_BASE_Q) >= 0) {
>>>> int64_t new_start_pos;
>>>> - char *old_filename = NULL;
>>>> int byterange_mode = (hls->flags & HLS_SINGLE_FILE) ||
>>>> (hls->max_seg_size > 0);
>>>> av_write_frame(vs->avf, NULL); /* Flush any buffered data */
>>>> @@ -2253,11 +2256,13 @@ static int hls_write_packet(AVFormatContext *s,
>>>> AVPacket *pkt)
>>>> hlsenc_io_close(s, &vs->vtt_avf->pb, vs->vtt_avf->url);
>>>> }
>>>> }
>>>> - if ((hls->flags & HLS_TEMP_FILE) && oc->url[0]) {
>>>> +
>>>> + // look to rename the asset name
>>>> + if (use_temp_file && oc->url[0]) {
>>>> 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);
>>>> - hls_rename_temp_file(s, oc);
>>>> + 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);
>>>> + }
>>>> }
>>>> if (vs->fmp4_init_mode) {
>>>> @@ -2286,6 +2291,17 @@ static int hls_write_packet(AVFormatContext *s,
>>>> AVPacket *pkt)
>>>> return ret;
>>>> }
>>>> ff_format_io_close(s, &vs->out);
>>>> +
>>>> + // rename that segment from .tmp to the real one
>>>> + if (use_temp_file && oc->url[0]) {
>>>> + hls_rename_temp_file(s, oc);
>>>> + av_free(old_filename);
>>>> + old_filename = av_strdup(vs->avf->url);
>>>> +
>>>> + if (!old_filename) {
>>>> + return AVERROR(ENOMEM);
>>>> + }
>>>> + }
>>>> }
>>>> }
>>>> @@ -2334,10 +2350,12 @@ static int hls_write_packet(AVFormatContext *s,
>>>> AVPacket *pkt)
>>>> return ret;
>>>> }
>>>> - if (!vs->fmp4_init_mode || byterange_mode)
>>> why do you remove this line?
>>
>> Because the above code sets fmp4_init_mode to 0 and this is always true. I
>> tested mpegts and fmp4 in single file and multiple file modes and this is
>> always true.
> There have a logic:
>
> 771 if (hls->segment_type == SEGMENT_TYPE_FMP4) {
> 772 if (hls->max_seg_size > 0) {
> 773 av_log(s, AV_LOG_WARNING, "Multi-file byterange mode is
> currently unsupported in the HLS muxer.\n");
> 774 return AVERROR_PATCHWELCOME;
> 775 }
> 776
> 777 vs->packets_written = 0;
> 778 vs->init_range_length = 0;
> 779 vs->fmp4_init_mode = !byterange_mode;
>
This is not called between the lines that sets fmp4_init_mode to 0. It’s also
not called by “hls_start” either. hls_mux_init is not invoked here. It is only
invoked once at init.
Even then, this logic sets fmp4_init_mode to be the converse of byterange_mode.
In the if statement I removed, this will always be true.
>>
>>>> + // 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) {
>>> maybe your mean is just write one time when PLAYLIST_TYPE_VOD, that is
>>> happen at the end of the full list, is that right?
>>
>> Yes. Like I mentioned before there is no need to refresh the whole file
>> every single time.
>>
>> This is not the best fix in my opinion either but it is the simplest. The
>> best way would be to split the code based on the playlist type so it was
>> easier to follow. This is altogether confusing code.
>>
>>>> if ((ret = hls_window(s, 0, vs)) < 0) {
>>>> return ret;
>>>> }
>>>> + }
>>>> }
>>>> vs->packets_written++;
>>>> @@ -2352,6 +2370,8 @@ static int hls_write_trailer(struct AVFormatContext
>>>> *s)
>>>> AVFormatContext *oc = NULL;
>>>> AVFormatContext *vtt_oc = NULL;
>>>> char *old_filename = NULL;
>>>> + const char *proto = avio_find_protocol_name(s->url);
>>>> + int use_temp_file = proto && !strcmp(proto, "file") && (s->flags &
>>>> HLS_TEMP_FILE);
>>>> int i;
>>>> int ret = 0;
>>>> VariantStream *vs = NULL;
>>>> @@ -2394,8 +2414,9 @@ failed:
>>>> if (hls->segment_type != SEGMENT_TYPE_FMP4)
>>>> ff_format_io_close(s, &oc->pb);
>>>> - if ((hls->flags & HLS_TEMP_FILE) && oc->url[0]) {
>>>> - hls_rename_temp_file(s, oc);
>>>> + // rename that segment from .tmp to the real one
>>>> + if (use_temp_file && oc->url[0] && !(hls->flags &
>>>> HLS_SINGLE_FILE)) {
>>>> + hls_rename_temp_file(s, oc);
>>>> av_free(old_filename);
>>>> old_filename = av_strdup(vs->avf->url);
>>>> --
>>>> 2.6.3
>>>> _______________________________________________
>>>> ffmpeg-devel mailing list
>>>> [email protected]
>>>> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>>>
>>>
>>>
>>> _______________________________________________
>>> ffmpeg-devel mailing list
>>> [email protected]
>>> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>
>
>
> _______________________________________________
> ffmpeg-devel mailing list
> [email protected]
> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
_______________________________________________
ffmpeg-devel mailing list
[email protected]
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel