From patchwork Sun Dec 3 14:54:36 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rainer Hochecker X-Patchwork-Id: 6527 Delivered-To: ffmpegpatchwork@gmail.com Received: by 10.2.161.94 with SMTP id m30csp3398366jah; Sun, 3 Dec 2017 06:55:08 -0800 (PST) X-Google-Smtp-Source: AGs4zMa8vx3jemdFJdS/FkfNg05iAyef0mlMgJqlXZWF8g2hdymclb+Y85/aFk2kQKi6m/bNRyk8 X-Received: by 10.28.52.81 with SMTP id b78mr1050269wma.70.1512312908358; Sun, 03 Dec 2017 06:55:08 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1512312908; cv=none; d=google.com; s=arc-20160816; b=c3Q4J/IiWK+oVmCTklawRcscNLVcA6ad9U2fDCm1+8ex/g3FQeQYmAZ3u9GQ/B6SGL ZqA4Yd8xR8XFqsK00ZigKEfBbQ2Dpxhxe79O8Wno9dSzugu7s/Nd4zS+qespBIIExvEP g6lyNfrOmbWSsI/5ZeBY/psmRzhr9GEglFyrhw7iFxdR7jYv7mSeC0syII9+E7VSHWfF r8nRusvy2132CKY120lhVyXD9dSLClfeQzRadAKoWWn7MyZ0fffzDt12FtmSYNYmQSEj kIWxqQ32iWCUYtlvF21jNVA6AkF9jiCYkqNIPyUflIAAbBwLezAUyHrOQWXwOzBZZFxN c9tg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:mime-version:cc:reply-to :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:references:in-reply-to:message-id:date :to:from:delivered-to:arc-authentication-results; bh=o/h6WkewvhhAObcoo+VQdJE08rBA/yEc2vgEzR1PoFE=; b=lcEyfSYqBAAftL38lcfcpNbyuXZBZufOa/X9KTD/dn7Gd0bmzrNd2f+Bm1YgzwkHU1 qafNXb6JsvGcpMJPuLJawNFI+6/jbSFQ0Jqoi6CC7E45DR+PU8Y3Ls/xJx8Va48Sw5Wk BLp/IPw0iFYJKwmzEQO4hlDmpM0OWhSm0pBLqkAJZ6R56UMDb0PQNt4atwXaZoSseqHQ cJEBiziyBOl8ultZDHqrBUpAmhxJXOyV49qFVmmxJ917i8OkR7kz2q1S/sqXSRYCOFZG zS/0/RjbT3v10xRIRy80RXRHzL7xLfnZq8qW9GolFWhCCj1QRxXCG6rKhR5g0pAYNvdf VeEw== 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 i11si3582231wmb.138.2017.12.03.06.55.07; Sun, 03 Dec 2017 06:55:08 -0800 (PST) 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 EBA1868A561; Sun, 3 Dec 2017 16:54:49 +0200 (EET) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mout.kundenserver.de (mout.kundenserver.de [217.72.192.73]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id A152168A538 for ; Sun, 3 Dec 2017 16:54:43 +0200 (EET) Received: from localhost.localdomain ([89.247.207.216]) by mrelayeu.kundenserver.de (mreue105 [212.227.15.183]) with ESMTPSA (Nemesis) id 0LdEVV-1emM9k1xiL-00iRx7; Sun, 03 Dec 2017 15:54:45 +0100 From: Rainer Hochecker To: ffmpeg-devel@ffmpeg.org Date: Sun, 3 Dec 2017 15:54:36 +0100 Message-Id: <20171203145436.42095-3-fernetmenta@online.de> X-Mailer: git-send-email 2.14.1 In-Reply-To: <20171203145436.42095-1-fernetmenta@online.de> References: <0489f119587681fc5a2b15fdc8afdd2d@mail.onse.fi> <20171203145436.42095-1-fernetmenta@online.de> X-Provags-ID: V03:K0:H6zFsVK+puzNpIe0X/47H/aw+/J653mK+wUSoAKUh1MzPAld94I in3iu4p2SZWRqYaNPMNjzwoU6v6Jon94X5YUEs3iMuOU/FkRpTRc3qbbk/rVCSrvpVKCt67 BD0oCFyZIv9uu6++HAhMvP9neKBb4hrpWJ1wyM0hVUlUAOTTnrgkErJIFga903xSWk40yLu yD7oXvK541MnSGmwKi+Bw== X-UI-Out-Filterresults: notjunk:1; V01:K0:YM9eYONNjdE=:n/LcMwVtm9/ZaH20DMRNxy ypePhHQs7Ls2mrrlldKJY5KN2gZ3nQYNkEO3iaOYE9cOpjpUcF38XB80Z5bPzvChIZuhHFZwo VoHQO109eCYKicEnV4ZV8CDrtBEljYZrgs8znFz2uEnXCnmwcU0V7PScl6r+KMmAdEgdgOH/r jHr7uDZjJbUhl1owlNTz34TMEvsF1i+h6SA3kXQO0KhdbfFh/yN9N8rVxmqlDKgDfJkeWClrw Sz6h5iQ/Znn1mhaikIxr8nX7bx5V7mmUrNXedWcw3iJP7FPLs8D7Y9XjdiG64OA7gksHtnFVM k9b3+UlzxpKcPzqwPufnCc6vBpuE+NskEMkPrZn3GHNrhPYgfAZym2Z2tNKpGkajaJPGOnWI+ T4n83+Lklde72IhqpSfcdNQQ5ZK8EPw+ctk//vEnZlVGuEIxz36R9CyF/fiPczy0va4sqxl5O 5wYJXgwIPVVSxF4UWlccPbmuqFOhQacaRK+HP4782X20NqUS4uJCx8y49eh+YJ7aP2Qr0noZ9 El+YH4ft2QZUzpKXqc0l/eXhQiLeFi8ZzkDaBuK/A6++WshhuTDluPyKCrzBLoSRScIB72J1K TcvbBwVC0RiJTPPXwZL5uBFA+6jjtvHUwX9PNPzHaiHQfWvhHoe0lLkEDkhFN1eI9hAcrCIL/ 81HOWpPlZOgUJxQOjUNWU5+1XDEp7vVCwF8dWP2ocpfQKDXtc7XYekIcO43BCFH1FPODWLqdw +gLB2BqytBYPNHa2GwgQbj2qF9VuSYzvOY7c2w== Subject: [FFmpeg-devel] [PATCH v4 2/2] lavf/hls: add option to defer parsing of variants 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: Rainer Hochecker MIME-Version: 1.0 Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" --- doc/demuxers.texi | 6 ++++ libavformat/hls.c | 106 ++++++++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 98 insertions(+), 14 deletions(-) diff --git a/doc/demuxers.texi b/doc/demuxers.texi index 73dc0feec1..33643f966a 100644 --- a/doc/demuxers.texi +++ b/doc/demuxers.texi @@ -316,6 +316,12 @@ segment index to start live streams at (negative values are from the end). @item max_reload Maximum number of times a insufficient list is attempted to be reloaded. Default value is 1000. + +@item load_all_variants +If 0, only the first variant/playlist is loaded on open. All other variants +get disabled and can be enabled by setting discard option in program. +Default value is 1. + @end table @section image2 diff --git a/libavformat/hls.c b/libavformat/hls.c index 3c2c720abe..500e3c15de 100644 --- a/libavformat/hls.c +++ b/libavformat/hls.c @@ -112,6 +112,7 @@ struct playlist { int n_segments; struct segment **segments; int needed; + int parsed; int cur_seq_no; int64_t cur_seg_offset; int64_t last_load_time; @@ -206,6 +207,7 @@ typedef struct HLSContext { int strict_std_compliance; char *allowed_extensions; int max_reload; + int load_all_variants; } HLSContext; static int read_chomp_line(AVIOContext *s, char *buf, int maxlen) @@ -315,6 +317,7 @@ static struct playlist *new_playlist(HLSContext *c, const char *url, pls->id3_mpegts_timestamp = AV_NOPTS_VALUE; pls->index = c->n_playlists; + pls->parsed = 0; pls->needed = 0; dynarray_add(&c->playlists, &c->n_playlists, pls); return pls; @@ -867,6 +870,10 @@ fail: av_free(new_url); if (close_in) ff_format_io_close(c->ctx, &in); + + if (pls) + pls->parsed = 1; + return ret; } @@ -1260,17 +1267,30 @@ static int64_t default_reload_interval(struct playlist *pls) pls->target_duration; } -static int playlist_needed(struct playlist *pls) +static int playlist_needed(AVFormatContext *s, struct playlist *pls, int check_parsed) { - AVFormatContext *s = pls->parent; + HLSContext *c = s->priv_data; int i, j; int stream_needed = 0; int first_st; /* If there is no context or streams yet, the playlist is needed */ - if (!pls->ctx || !pls->n_main_streams) + if (check_parsed && (!pls->ctx || !pls->n_main_streams)) return 1; + /* If the playlist belongs to a non discarded variant and is not parsed, + * we need to parse and activate it later */ + for (i = 0; i < s->nb_programs; i++) { + AVProgram *program = s->programs[i]; + struct variant *var = c->variants[i]; + if (program->discard < AVDISCARD_ALL) { + for (j = 0; j < var->n_playlists; j++) { + if (var->playlists[j] == pls && !var->playlists[j]->parsed) + return 1; + } + } + } + /* check if any of the streams in the playlist are needed */ for (i = 0; i < pls->n_main_streams; i++) { if (pls->main_streams[i]->discard < AVDISCARD_ALL) { @@ -1324,7 +1344,7 @@ restart: /* Check that the playlist is still needed before opening a new * segment. */ - v->needed = playlist_needed(v); + v->needed = playlist_needed(v->parent, v, 1); if (!v->needed) { av_log(v->parent, AV_LOG_INFO, "No longer receiving playlist %d\n", @@ -1418,23 +1438,41 @@ reload: static void add_renditions_to_variant(HLSContext *c, struct variant *var, enum AVMediaType type, const char *group_id) { - int i; + int i, j; + int found; for (i = 0; i < c->n_renditions; i++) { struct rendition *rend = c->renditions[i]; if (rend->type == type && !strcmp(rend->group_id, group_id)) { - if (rend->playlist) + if (rend->playlist) { /* rendition is an external playlist * => add the playlist to the variant */ - dynarray_add(&var->playlists, &var->n_playlists, rend->playlist); - else + found = 0; + for (j = 0; j < var->n_playlists; j++) { + if (var->playlists[j] == rend->playlist) { + found = 1; + break; + } + } + if (!found) + dynarray_add(&var->playlists, &var->n_playlists, rend->playlist); + } else { /* rendition is part of the variant main Media Playlist * => add the rendition to the main Media Playlist */ - dynarray_add(&var->playlists[0]->renditions, - &var->playlists[0]->n_renditions, - rend); + found = 0; + for (j = 0; j < var->playlists[0]->n_renditions; j++) { + if (var->playlists[0]->renditions[j] == rend) { + found = 1; + break; + } + } + if (!found) + dynarray_add(&var->playlists[0]->renditions, + &var->playlists[0]->n_renditions, + rend); + } } } } @@ -1831,8 +1869,15 @@ static int hls_read_header(AVFormatContext *s) goto fail; } /* If the playlist only contained playlists (Master Playlist), - * parse each individual playlist. */ - if (c->n_playlists > 1 || c->playlists[0]->n_segments == 0) { + * parse all individual playlists. + If option load_all_variants is false, load only first variant */ + if (!c->load_all_variants && c->n_variants > 1) { + for (i = 0; i < c->variants[0]->n_playlists; i++) { + struct playlist *pls = c->variants[0]->playlists[i]; + if ((ret = parse_playlist(c, pls->url, pls, NULL)) < 0) + goto fail; + } + } else if (c->n_playlists > 1 || c->playlists[0]->n_segments == 0) { for (i = 0; i < c->n_playlists; i++) { struct playlist *pls = c->playlists[i]; if ((ret = parse_playlist(c, pls->url, pls, NULL)) < 0) @@ -1876,6 +1921,10 @@ static int hls_read_header(AVFormatContext *s) if (!program) goto fail; av_dict_set_int(&program->metadata, "variant_bitrate", v->bandwidth, 0); + + /* start with the first variant and disable all others */ + if (i > 0 && !c->load_all_variants) + program->discard = AVDISCARD_ALL; } /* Select the starting segments */ @@ -1893,6 +1942,9 @@ static int hls_read_header(AVFormatContext *s) for (i = 0; i < c->n_playlists; i++) { struct playlist *pls = c->playlists[i]; + if (!pls->parsed) + continue; + if ((ret = init_playlist(c, pls)) < 0) goto fail; @@ -1906,6 +1958,26 @@ fail: return ret; } +static void activate_playlist(AVFormatContext *s, struct playlist *pls) { + + HLSContext *c = s->priv_data; + + if (pls->index < c->n_variants) { + + struct variant *var = c->variants[pls->index]; + + if (parse_playlist(c, pls->url, pls, NULL) < 0) + return; + if (var->audio_group[0]) + add_renditions_to_variant(c, var, AVMEDIA_TYPE_AUDIO, var->audio_group); + if (var->video_group[0]) + add_renditions_to_variant(c, var, AVMEDIA_TYPE_VIDEO, var->video_group); + if (var->subtitles_group[0]) + add_renditions_to_variant(c, var, AVMEDIA_TYPE_SUBTITLE, var->subtitles_group); + init_playlist(c, pls); + } +} + static int recheck_discard_flags(AVFormatContext *s, int first) { HLSContext *c = s->priv_data; @@ -1916,9 +1988,11 @@ static int recheck_discard_flags(AVFormatContext *s, int first) for (i = 0; i < c->n_playlists; i++) { struct playlist *pls = c->playlists[i]; - cur_needed = playlist_needed(c->playlists[i]); + cur_needed = playlist_needed(s, c->playlists[i], 0); if (cur_needed && !pls->needed) { + if (!pls->parsed) + activate_playlist(s, pls); pls->needed = 1; changed = 1; pls->cur_seq_no = select_cur_seq_no(c, pls); @@ -2165,6 +2239,8 @@ static int hls_read_seek(AVFormatContext *s, int stream_index, for (i = 0; i < c->n_playlists; i++) { /* Reset reading */ struct playlist *pls = c->playlists[i]; + if (!pls->parsed) + continue; if (pls->input) ff_format_io_close(pls->parent, &pls->input); av_packet_unref(&pls->pkt); @@ -2221,6 +2297,8 @@ static const AVOption hls_options[] = { INT_MIN, INT_MAX, FLAGS}, {"max_reload", "Maximum number of times a insufficient list is attempted to be reloaded", OFFSET(max_reload), AV_OPT_TYPE_INT, {.i64 = 1000}, 0, INT_MAX, FLAGS}, + {"load_all_variants", "parse all playlists of all variants at startup", + OFFSET(load_all_variants), AV_OPT_TYPE_BOOL, {.i64 = 1}, 0, 1, FLAGS}, {NULL} };