From patchwork Mon Sep 12 07:01:24 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Steven Liu X-Patchwork-Id: 551 Delivered-To: ffmpegpatchwork@gmail.com Received: by 10.103.140.134 with SMTP id o128csp1465670vsd; Mon, 12 Sep 2016 00:01:40 -0700 (PDT) X-Received: by 10.28.207.14 with SMTP id f14mr8567052wmg.40.1473663700111; Mon, 12 Sep 2016 00:01:40 -0700 (PDT) Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id 73si13990586wmu.116.2016.09.12.00.01.35; Mon, 12 Sep 2016 00:01:40 -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; dkim=neutral (body hash did not verify) header.i=@gmail.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; dmarc=fail (p=NONE dis=NONE) header.from=gmail.com Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id BA65B689ED5; Mon, 12 Sep 2016 10:01:21 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-qk0-f178.google.com (mail-qk0-f178.google.com [209.85.220.178]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 66283689CBB for ; Mon, 12 Sep 2016 10:01:14 +0300 (EEST) Received: by mail-qk0-f178.google.com with SMTP id z190so122891887qkc.3 for ; Mon, 12 Sep 2016 00:01:26 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:from:date:message-id:subject:to; bh=0n2W/ucPi+ejYMQiA0shKqJ6CzPDqRXlyBFBbCDJyW0=; b=Q8JGG3JazQkf/UBYIunGona81LpOqImBQ5aElhWvzjv18ur7ogmxa7kyYKHxVuQR3s KCPLpnzD/nD6iIgELgYSN2zjnmHIMo78SLEKdOJm9MkctsJO1iCl2VMOHjRB1Q/PO3Sg 6BQiHwJ8hst9F34D877pmkVuMp+zklRdZ1LFaJGXQZdLL0N0ZfI150O4+f8rge+/ouco Zde1h8ZISerQAv76uPApjPNMEzNHIuSOkzwqp/yPmPRjzPce6SCGFkuW73opy5ZeXHQe UnFwNhfTcIQmI9puLhrg/pxQ+gpYo42l4eK+I4oKMn9TnhmxhFZ/Dxi2JIlO7VmI1F/0 TehQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:mime-version:from:date:message-id:subject:to; bh=0n2W/ucPi+ejYMQiA0shKqJ6CzPDqRXlyBFBbCDJyW0=; b=bOtrQp7lIIpMNgp/qpE5GhnZbwzGrDCJ0zeKGpz+afEcEhBUI/8p/6vkMJfB7epO57 b6twQKO06I4T5yMwzMcfePBuX2F5UUuKnoWRutrxVnzxgIaV6O5clCIIgXqZVBCKBssE HHSibSkINjdx2QW+mBiR8ywSTQ7TE56N4dvI0KN6d+vPWfnheDcRbd8Ql0N7SfRz/w/g 2rTnsaPY9Gg+RJzLXh9uosUDSdhzC8eKkLdisxOT5VqyhZHO3FG0m9MVzWV/dK/Qa7lx ou5mlrXywhEBRY4LZpPR8WoizIC5s2o0+fuj5XPlTytFpPCa43R4+w5C2UkoFe/fXpYp 9fdw== X-Gm-Message-State: AE9vXwM9klGRJHTFNkMaoX+3F/ntdNRU8rX/OyYqlCMmiFhGangpE/s9+MHHpEldLjlPbmSC98UI4Ac+AHGVJw== X-Received: by 10.55.82.66 with SMTP id g63mr17012285qkb.227.1473663684683; Mon, 12 Sep 2016 00:01:24 -0700 (PDT) MIME-Version: 1.0 Received: by 10.237.56.42 with HTTP; Mon, 12 Sep 2016 00:01:24 -0700 (PDT) From: Steven Liu Date: Mon, 12 Sep 2016 15:01:24 +0800 Message-ID: To: FFmpeg development discussions and patches X-Content-Filtered-By: Mailman/MimeDel 2.1.20 Subject: [FFmpeg-devel] [PATCH] avformat/hlsenc: refine EXT-X-BYTERANGE support for segments 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 Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" refine EXT-X-BYTERANGE tag, the spec link: https://tools.ietf.org/html/draft-pantos-http-live-streaming-19#section-4.3.2.2 the apple doc: https://developer.apple.com/library/ios/technotes/tn2288/_index.html#//apple_ref/doc/uid/DTS40012238-CH1-BYTE_RANGE_SUPPORT_FOR_SEGMENTS command line: ./ffmpeg -i ~/Movies/objectC/a.mp4 -c copy -f hls -hls_time 7 -hls_list_size 100 -hls_segment_size 2500000 -t 40 output-test.m3u8 output: localhost:ffmpeg liuqi$ ll *.ts ;cat output-test.m3u8 -rw-r--r-- 1 liuqi staff 2792176 9 12 14:44 output-test0.ts -rw-r--r-- 1 liuqi staff 3112528 9 12 14:44 output-test3.ts -rw-r--r-- 1 liuqi staff 3377420 9 12 14:44 output-test6.ts -rw-r--r-- 1 liuqi staff 1228016 9 12 14:44 output-test7.ts #EXTM3U #EXT-X-VERSION:4 #EXT-X-TARGETDURATION:10 #EXT-X-MEDIA-SEQUENCE:0 #EXTINF:9.021000, #EXT-X-BYTERANGE:1334988@0 output-test0.ts #EXTINF:3.000000, #EXT-X-BYTERANGE:721356@1334988 output-test0.ts #EXTINF:3.000000, #EXT-X-BYTERANGE:735832@2056344 output-test0.ts #EXTINF:6.000000, #EXT-X-BYTERANGE:1645940@0 output-test3.ts #EXTINF:3.000000, #EXT-X-BYTERANGE:715152@1645940 output-test3.ts #EXTINF:3.000000, #EXT-X-BYTERANGE:751436@2361092 output-test3.ts #EXTINF:9.000000, #EXT-X-BYTERANGE:3377420@0 output-test6.ts #EXTINF:3.960000, #EXT-X-BYTERANGE:1228016@0 output-test7.ts #EXT-X-ENDLIST localhost:ffmpeg liuqi$ ticket-id: #5839 Signed-off-by: Steven Liu --- libavformat/hlsenc.c | 38 +++++++++++++++++++++++++++++++++----- 1 file changed, 33 insertions(+), 5 deletions(-) @@ -476,7 +477,7 @@ static int hls_window(AVFormatContext *s, int last) AVIOContext *sub_out = NULL; char temp_filename[1024]; int64_t sequence = FFMAX(hls->start_sequence, hls->sequence - hls->nb_entries); - int version = hls->flags & HLS_SINGLE_FILE ? 4 : 3; + int version = 0; const char *proto = avio_find_protocol_name(s->filename); int use_rename = proto && !strcmp(proto, "file"); static unsigned warned_non_file; @@ -485,6 +486,12 @@ static int hls_window(AVFormatContext *s, int last) AVDictionary *options = NULL; double prog_date_time = hls->initial_prog_date_time; + if (hls->flags & (HLS_SINGLE_FILE) || hls->max_seg_size > 0) { + version = 4; + } else { + version = 3; + } + 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 temporarly partial files\n"); @@ -533,7 +540,8 @@ static int hls_window(AVFormatContext *s, int last) avio_printf(out, "#EXTINF:%ld,\n", lrint(en->duration)); else avio_printf(out, "#EXTINF:%f,\n", en->duration); - if (hls->flags & HLS_SINGLE_FILE) + if (hls->flags & HLS_SINGLE_FILE || + hls->max_seg_size > 0) avio_printf(out, "#EXT-X-BYTERANGE:%"PRIi64"@%"PRIi64"\n", en->size, en->pos); if (hls->flags & HLS_PROGRAM_DATE_TIME) { @@ -573,7 +581,8 @@ static int hls_window(AVFormatContext *s, int last) for (en = hls->segments; en; en = en->next) { avio_printf(sub_out, "#EXTINF:%f,\n", en->duration); - if (hls->flags & HLS_SINGLE_FILE) + if (hls->flags & HLS_SINGLE_FILE || + hls->max_seg_size > 0) avio_printf(sub_out, "#EXT-X-BYTERANGE:%"PRIi64"@%"PRIi64"\n", en->size, en->pos); if (hls->baseurl) @@ -610,7 +619,14 @@ static int hls_start(AVFormatContext *s) if (c->vtt_basename) av_strlcpy(vtt_oc->filename, c->vtt_basename, sizeof(vtt_oc->filename)); - } else { + } else if (c->max_seg_size > 0) { + if (av_get_frame_filename2(oc->filename, sizeof(oc->filename), + c->basename, c->wrap ? c->sequence % c->wrap : c->sequence, + AV_FRAME_FILENAME_FLAGS_MULTIPLE) < 0) { + av_log(oc, AV_LOG_ERROR, "Invalid segment filename template '%s' you can try use -use_localtime 1 with it\n", c->basename); + return AVERROR(EINVAL); + } + } else { if (c->use_localtime) { time_t now0; struct tm *tm, tmpbuf; @@ -943,7 +959,18 @@ static int hls_write_packet(AVFormatContext *s, AVPacket *pkt) if (hls->avf->oformat->priv_class && hls->avf->priv_data) av_opt_set(hls->avf->priv_data, "mpegts_flags", "resend_headers", 0); hls->number++; - } else { + } else if (hls->max_seg_size > 0) { + if (hls->avf->oformat->priv_class && hls->avf->priv_data) + av_opt_set(hls->avf->priv_data, "mpegts_flags", "resend_headers", 0); + if (hls->start_pos >= hls->max_seg_size ) { + ff_format_io_close(s, &oc->pb); + if (hls->vtt_avf) + ff_format_io_close(s, &hls->vtt_avf->pb); + ret = hls_start(s); + hls->start_pos = 0; + hls->number++; + } + } else { ff_format_io_close(s, &oc->pb); if (hls->vtt_avf) ff_format_io_close(s, &hls->vtt_avf->pb); @@ -1020,6 +1047,7 @@ static const AVOption options[] = { {"hls_key_info_file", "file with key URI and key file path", OFFSET(key_info_file), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E}, {"hls_subtitle_path", "set path of hls subtitles", OFFSET(subtitle_filename), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E}, {"hls_flags", "set flags affecting HLS playlist and media file generation", OFFSET(flags), AV_OPT_TYPE_FLAGS, {.i64 = 0 }, 0, UINT_MAX, E, "flags"}, + {"hls_segment_size", "set maximum size per segment file, (Byte)", OFFSET(max_seg_size), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, E}, {"single_file", "generate a single media file indexed with byte ranges", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_SINGLE_FILE }, 0, UINT_MAX, E, "flags"}, {"delete_segments", "delete segment files that are no longer part of the playlist", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_DELETE_SEGMENTS }, 0, UINT_MAX, E, "flags"}, {"round_durations", "round durations in m3u8 to whole numbers", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_ROUND_DURATIONS }, 0, UINT_MAX, E, "flags"}, -- 2.7.4 (Apple Git-66) diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c index a376312..08995f6 100644 --- a/libavformat/hlsenc.c +++ b/libavformat/hlsenc.c @@ -104,6 +104,7 @@ typedef struct HLSContext { double duration; // last segment duration computed so far, in seconds int64_t start_pos; // last segment starting position int64_t size; // last segment size + int64_t max_seg_size; // every segment file max size int nb_entries; int discontinuity_set;