From patchwork Mon Aug 6 02:54:05 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Liu Steven X-Patchwork-Id: 9909 Delivered-To: ffmpegpatchwork@gmail.com Received: by 2002:a02:104:0:0:0:0:0 with SMTP id c4-v6csp2767890jad; Sun, 5 Aug 2018 19:54:27 -0700 (PDT) X-Google-Smtp-Source: AAOMgpcce2IOR9gqKqzQ2P92dATwaWp8zXrZQBROIgLWL5iHNNaMVjj6U9X9cMHYkL2eFyBeZRTD X-Received: by 2002:a1c:7908:: with SMTP id l8-v6mr10041247wme.80.1533524067237; Sun, 05 Aug 2018 19:54:27 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1533524067; cv=none; d=google.com; s=arc-20160816; b=VIOYVL8qqbTCjG7GARhs4Uj0hP3GPCJxVUj8TqHgbOP6ZBn21QGDV1E/oNLsoxvsbS rwppU9hRHQkIc7nDcyYBC1DB+34Dt2kSsFHfCGNnq6HgkXAi1qbIwuPiQi2Ma2/fqHCr lNEvPg1xrYAN/TYrw6Az9Tx1JG6nYIBEVjgF1EQMA94WPc/DaHk7ZrGit6Kig9HDNb+V b76UJdK149Bu8Hl/hs6KWNemC4vM4YK/IUtVNG4yzRlubt6940rpeN3DbMybmDTy6EXp NtvwMMvMWwkJHIkXZK9ygFLqEBqJa15QVbeASKCsy3CNZ5ai6MOXP/iEBq1oYKKyuiFa 0BsA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:cc:reply-to :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:feedback-id:to:references:message-id :date:in-reply-to:from:mime-version:delivered-to :arc-authentication-results; bh=WN99dJKCZ4rUB+Hhi9FG9H+PrvnSLlq7VKlEBa5gazA=; b=0VOWpsLFd+7+De4Iy+qvI0MpaiINEmdyNiWtdFZ+BbO/AXwt/us2eR1PoCkT4qar7w XWrbeKBXRJOqZ1nwPjkLO5n8rru8moOwXA8Jt3FY/l/hv0r/aTTAqv3FgoC6SAFJqiB0 KSsOT8DrM1bXNqeKt/UqE/x49/0cZZT7HvDwh6omG8SD1tLtX+BoXj8q3KYv6LLSbVlk vQE2z5Ib4/JExXF27rC1rSfYr0NG9zeOSgZ5vWQf8up3ktOkTL3P7u8anWkw2fQlGCmA zRzSHSwtZSPAGJodAvJqgcof01zNiiVY8cXc8hEM1V3lpZBJsgDc4gY7mAiTQi5H8ipL mUbw== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id e13-v6si8612992wrq.339.2018.08.05.19.54.26; Sun, 05 Aug 2018 19:54:27 -0700 (PDT) Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100; Authentication-Results: mx.google.com; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id A6F3368A3B3; Mon, 6 Aug 2018 05:54:04 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from smtpbgeu2.qq.com (smtpbgeu2.qq.com [18.194.254.142]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 1D09B68A145 for ; Mon, 6 Aug 2018 05:53:57 +0300 (EEST) X-QQ-mid: bizesmtp6t1533524051tb7p44ufk Received: from [172.16.0.16] (unknown [36.102.208.210]) by esmtp6.qq.com (ESMTP) with id ; Mon, 06 Aug 2018 10:54:08 +0800 (CST) X-QQ-SSF: 00100000000000F0FLF0B00A0000000 X-QQ-FEAT: nidABUdh40qD2jkqUA4XXkfHGkEXvEV2ZmEXpltQnMFrwGzC7IVWPN5sm+IaF +pyH49qx68JPjInkJK/FSGsLbiqjTDlnaO+I6qd9qkc5uPbw9RkUFAdR08qqH0TIszDf1CV eX7x+jUNJ3ayItIj/ZfG5hIubv1imL/bSsPU8QHMNyK5N9O3k5ZhUI2JBywhK6zl0mbxZ3U 4PZQjjYGUQh/K7ccJ7C7/zP0jtNdvsRsjFSuqRN46U+g2nMqZQNLPnJHywrKNgyQjr+C/4B tXwxYeTuJYw4OL5MxN13loAsiYaET4xY1yKilIPqnHp9IlaypcFjCf7Dc= X-QQ-GoodBg: 0 Mime-Version: 1.0 (Mac OS X Mail 11.3 \(3445.6.18\)) From: Liu Steven In-Reply-To: Date: Mon, 6 Aug 2018 10:54:05 +0800 Message-Id: <279D2022-59BA-4338-A187-B51C6781CD59@chinaffmpeg.org> References: <0AF864E1-BEEF-41B7-98F1-49A8C6B04A10@yahoo.com> <81C29710-A67A-4C1E-B8B0-2B03262A7F89@yahoo.com> <22784362-DEB5-401B-A33A-351B92510839@yahoo.com> <1C18C326-1863-4176-AF3F-E446F4CA90C8@chinaffmpeg.org> <2230A2E9-D27E-4010-9EC2-0E713ED3ACFE@chinaffmpeg.org> <5C35A275-E784-4096-8412-081C688BF1F3@yahoo.com> <4409D11F-3611-4065-ADC9-2D177F0F7CAE@yahoo.com> To: Ronak X-Mailer: Apple Mail (2.3445.6.18) X-QQ-SENDSIZE: 520 Feedback-ID: bizesmtp:chinaffmpeg.org:qybgforeign:qybgforeign1 X-QQ-Bgrelay: 1 Subject: Re: [FFmpeg-devel] First Patch for hlsenc.c for https://trac.ffmpeg.org/ticket/7281 X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Cc: Liu Steven , FFmpeg development discussions and patches Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" > 在 2018年8月4日,上午2:17,Ronak 写道: > >>>>>>> I have read this patch some problem for this patch. >>>>>>> >>>>>>> 1. maybe there will have a problem when duration is not same when every fragment, for example: >>>>>>> liuqideMacBook-Pro:xxx liuqi$ ./ffmpeg -v quiet -i ~/Movies/Test/bbb_sunflower_1080p_30fps_normal.mp4 -c copy -f hls -hls_list_size 0 output_test.m3u8 >>>>>>> liuqideMacBook-Pro:xxx liuqi$ head -n 10 output_test.m3u8 >>>>>>> #EXTM3U >>>>>>> #EXT-X-VERSION:3 >>>>>>> #EXT-X-TARGETDURATION:8 >>>>>>> #EXT-X-MEDIA-SEQUENCE:0 >>>>>>> #EXTINF:3.866667, >>>>>>> output_test0.ts >>>>>>> #EXTINF:7.300000, >>>>>>> output_test1.ts >>>>>>> #EXTINF:8.333333, >>>>>>> output_test2.ts >>>>>>> >>>>>>> the output_test0.ts’s duration is short than output_test1.ts, the #EXT-X-TARGETDURATION need update to the longest duration. >>>>>>> this operation (check the longest duration) will happen at every fragment write complete. >>>>>>> it will not update when move the update option to the hls_write_header, >>>>>>> >>>>>> >>>>>> This is a problem in the code that splits the mpegts files. I've filed a separate issue for this here: https://trac.ffmpeg.org/ticket/7341. Mpegts segmentation should be following the hls_time parameter (or the default length). >>>>> This is whatever hls_time, is decide by keyframe position, this is happen when GOP size is not a permanent t position. >>>>> >> >>>>>> This is happening now with fMP4 assets, but not with mpegts. >>>>> Whatever fmp4 or mpegts, all of them need fix the problem of duration refresh. >>>>> >>>>> for example: >>>>> >>>>> liuqideMacBook-Pro:xxx liuqi$ ./ffmpeg -ss -v quiet -i ~/Movies/Test/bbb_sunflower_1080p_30fps_normal.mp4 -c copy -f hls -hls_list_size 0 -hls_segment_type fmp4 -hls_time 3 output_test.m3u8 >>>>> liuqideMacBook-Pro:xxx liuqi$ head -n 10 output_test.m3u8 >>>>> #EXTM3U >>>>> #EXT-X-VERSION:7 >>>>> #EXT-X-TARGETDURATION:8 >>>>> #EXT-X-MEDIA-SEQUENCE:0 >>>>> #EXT-X-MAP:URI="init.mp4" >>>>> #EXTINF:3.866667, >>>>> output_test0.m4s >>>>> #EXTINF:7.300000, >>>>> output_test1.m4s >>>>> #EXTINF:8.333333, >>>>> liuqideMacBook-Pro:xxx liuqi$ >>>> >>>> This is after your patch: >>>> liuqideMacBook-Pro:xxx liuqi$ ./ffmpeg -ss 17 -v quiet -i ~/Movies/Test/bbb_sunflower_1080p_30fps_normal.mp4 -c copy -f hls -hls_list_size 0 -hls_segment_type fmp4 -hls_time 3 output_test.m3u8 >>>> liuqideMacBook-Pro:xxx liuqi$ head -n 10 output_test.m3u8 >>>> #EXTM3U >>>> #EXT-X-VERSION:7 >>>> #EXT-X-TARGETDURATION:3 >>>> #EXT-X-MEDIA-SEQUENCE:0 >>>> #EXT-X-MAP:URI="init.mp4" >>>> #EXTINF:3.866667, >>>> output_test0.m4s >>>> #EXTINF:7.300000, >>>> output_test1.m4s >>>> #EXTINF:8.333333, >>>> >>>> The RFC https://www.rfc-editor.org/rfc/rfc8216.txt describe: >>>> >>>> 4.3.3.1. EXT-X-TARGETDURATION >>>> >>>> The EXT-X-TARGETDURATION tag specifies the maximum Media Segment >>>> duration. The EXTINF duration of each Media Segment in the Playlist >>>> file, when rounded to the nearest integer, MUST be less than or equal >>>> to the target duration; longer segments can trigger playback stalls >>>> or other errors. It applies to the entire Playlist file. Its format >>>> is: >>>> >>>> #EXT-X-TARGETDURATION: >>>> >>>> where s is a decimal-integer indicating the target duration in >>>> seconds. The EXT-X-TARGETDURATION tag is REQUIRED. >>>> >>>> your patch make the EXT-X-TARGETDURATION less than EXTINF:7.300000 EXTINF:8.333333 >>> >>> >>>>>>> 2. the version maybe will update when use hls_segment_type or append_list etc. when the operation is support from different version m3u8. >>>>>> >>>>>> I don't follow what you mean here. The version number is known up front, based on the options that were passed in. It should be illegal to switch between versions when trying to update an existing manifest. When can this legitimately happen? >>>>> there maybe have some player cannot support high version of m3u8, for example old parser or player just support the VERSION 3, >>>>> this must think about all of the player or parser, because ffmpeg is not used only by myself. >>>>> >>>>> Or what about get the #EXT-X-VERSION position, to update it? looks like flvenc.c or movenc.c date shift >>>>> >>>>>> >>>>>>> 3. need update segments vs->segments when hls_list_size option is set. >>>>>>> >>>>>> >>>>>> What do you mean by this and where should I do it? >>>>> for example, hls_list_size is 4, the m3u8 list should refresh every time when make a new fragment. >>>>> >>>>> first time: >>>>> 1.m4s >>>>> 2.m4s >>>>> 3.m4s >>>>> 4.m4s >>>>> >>>>> sencond time: >>>>> 2.m4s >>>>> 3.m4s >>>>> 4.m4s >>>>> 5.m4s >>>> >>>> after your patch: >>>> >>>> liuqideMacBook-Pro:xxx liuqi$ ./ffmpeg -v quiet -i ~/Movies/Test/bbb_sunflower_1080p_30fps_normal.mp4 -c copy -f hls -hls_list_size 4 -hls_segment_type fmp4 -hls_time 3 -t 50 output_test.m3u8 >>>> liuqideMacBook-Pro:xxx liuqi$ cat output_test.m3u8 >>>> #EXTM3U >>>> #EXT-X-VERSION:7 >>>> #EXT-X-TARGETDURATION:3 >>>> #EXT-X-MEDIA-SEQUENCE:0 >>>> #EXT-X-MAP:URI="init.mp4" >>>> #EXTINF:3.866667, >>>> output_test0.m4s >>>> #EXTINF:7.300000, >>>> output_test1.m4s >>>> #EXTINF:8.333333, >>>> output_test2.m4s >>>> #EXTINF:3.966667, >>>> output_test3.m4s >>>> #EXTINF:8.333333, >>>> output_test4.m4s >>>> #EXTINF:4.033333, >>>> output_test5.m4s >>>> #EXTINF:8.333333, >>>> output_test6.m4s >>>> #EXTINF:4.633333, >>>> output_test7.m4s >>>> liuqideMacBook-Pro:xxx liuqi$ >>>> liuqideMacBook-Pro:xxx liuqi$ >>>> >>>> the m3u8 list is incorrect, because users want control the m3u8 list length, because their disk do not have enough space to save the fragments. >>>> >>> >>> Ok I will fix this. > > > I'm attaching a new patch that resolves all of these issues, while still resolving this bug for VOD playlists. > > Can you please review? > > > <0001-libavformat-hlsenc-Fix-HLS-Manifest-Generation-from-.patch> From bbc4870c0d685f5c07e82042c3f2ef153d83f3d1 Mon Sep 17 00:00:00 2001 From: "Ronak Patel (Audible)" Date: Thu, 2 Aug 2018 09:25:12 -0400 Subject: [PATCH] libavformat/hlsenc: Fix HLS Manifest Generation from an N^2 algorithm to N. 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 --- libavformat/dashenc.c | 2 +- libavformat/hlsenc.c | 54 +++++++++++++++++++++++++++++++++------------------ 2 files changed, 36 insertions(+), 20 deletions(-) if (replace_int_data_in_filename(&filename, oc->url, 's', 0) < 1) { @@ -1166,9 +1167,10 @@ static int hls_rename_temp_file(AVFormatContext *s, AVFormatContext *oc) if (!final_filename) return AVERROR(ENOMEM); + ——you add a empty line final_filename[len-4] = '\0'; + ——you add a empty line ret = ff_rename(oc->url, final_filename, s); - oc->url[len-4] = '\0’; ——Why do you give the len - 4 = 0? av_freep(&final_filename); return ret; } @@ -1373,9 +1375,7 @@ static int hls_window(AVFormatContext *s, int last, VariantStream *vs) int ret = 0; 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"); - static unsigned warned_non_file; + int use_temp_file = (s->flags & HLS_TEMP_FILE); ——What will have if use http put method? char *key_uri = NULL; char *iv_string = NULL; AVDictionary *options = NULL; @@ -1397,11 +1397,9 @@ static int hls_window(AVFormatContext *s, int last, VariantStream *vs) hls->version = 7; } - if (!use_rename && !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"); - ——I have see this message long time, i have not remove this message because this is used to http method. Why do you remove it? 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); + //av_log(s, AV_LOG_INFO, "We're going to write out to %s", temp_filename); ------this info message is unused? if ((ret = hlsenc_io_open(s, &hls->m3u8_out, temp_filename, &options)) < 0) goto fail; @@ -1472,8 +1470,9 @@ 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) @@ -2253,11 +2252,14 @@ static int hls_write_packet(AVFormatContext *s, AVPacket *pkt) hlsenc_io_close(s, &vs->vtt_avf->pb, vs->vtt_avf->url); } } + + // look to rename the asset name if ((hls->flags & HLS_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 (!(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); + } + } ——Just reindent? } if (vs->fmp4_init_mode) { @@ -2286,6 +2288,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 ((hls->flags & HLS_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,14 +2347,16 @@ static int hls_write_packet(AVFormatContext *s, AVPacket *pkt) return ret; } - if (!vs->fmp4_init_mode || byterange_mode) + // 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) { ------Whatever event VOD or Live Streaming, the EXT-X-TARGETDURATION need refresh when lrint(current fragment duration) is large than lrint(the before duration). if ((ret = hls_window(s, 0, vs)) < 0) { return ret; } + } } - vs->packets_written++; ret = ff_write_chained(oc, stream_index, pkt, s, 0); + vs->packets_written++; return ret; } @@ -2394,15 +2409,16 @@ 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 ((hls->flags & HLS_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); if (!old_filename) { return AVERROR(ENOMEM); } - } + } /* 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); diff --git a/libavformat/dashenc.c b/libavformat/dashenc.c -------you have modify dash index ae57fd5..ae22c08 100644 --- a/libavformat/dashenc.c +++ b/libavformat/dashenc.c @@ -483,7 +483,7 @@ static void output_segment_list(OutputStream *os, AVIOContext *out, AVFormatCont target_duration = lrint(duration); } - ff_hls_write_playlist_header(c->m3u8_out, 6, -1, target_duration, + ff_hls_write_playlist_header(c->m3u8_out, 7, -1, target_duration, start_number, PLAYLIST_TYPE_NONE); ff_hls_write_init_file(c->m3u8_out, os->initfile, c->single_file, diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c index b5644f0..0eb0801 100644 --- a/libavformat/hlsenc.c +++ b/libavformat/hlsenc.c @@ -942,6 +942,7 @@ static int sls_flag_use_localtime_filename(AVFormatContext *oc, HLSContext *c, V if (c->flags & (HLS_SECOND_LEVEL_SEGMENT_SIZE | HLS_SECOND_LEVEL_SEGMENT_DURATION)) { av_strlcpy(vs->current_segment_final_filename_fmt, oc->url, sizeof(vs->current_segment_final_filename_fmt)); + ——you add a empty line if (c->flags & HLS_SECOND_LEVEL_SEGMENT_SIZE) { char *filename = NULL;