From patchwork Sun Dec 3 14:34:47 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rainer Hochecker X-Patchwork-Id: 6525 Delivered-To: ffmpegpatchwork@gmail.com Received: by 10.2.161.94 with SMTP id m30csp3384970jah; Sun, 3 Dec 2017 06:35:56 -0800 (PST) X-Google-Smtp-Source: AGs4zMYgPEaUQDMvWBrU+czAcBridDjOCANrqUnRGP6kX2kyffN0d64vkKC13/BWW0pYd87Un9yu X-Received: by 10.223.169.183 with SMTP id b52mr11331745wrd.63.1512311756234; Sun, 03 Dec 2017 06:35:56 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1512311756; cv=none; d=google.com; s=arc-20160816; b=XPsEaZa5OSgjH21cnyBDIu3qX4upH6dfxKiK+bcMnYigLxqtTIrdM1N42UXEGQ5I77 Xjpl4SS/Ca2bLu9aipBSV1do+a4A6a/iXuF/eenuA/feu98LKCSays94VxS6RSOWToVO gmXhtYa1MduHhWxtPv2iO7iIyvhu5JNygVZuOIkiRp7gI8YQCC8+lpdPAq4hHKilD8FZ woAoBPNjz3Dd4+mokGTlMqpyTABMdEJ9N0elhcyo4sSJypsTLjQk/L+oOPeinDcEnl0c 093FtP1m5XzY27wBpClt7Q9SxqwUNl08w1ZpnDoYcKqX3cH3jIV+nRpfd1nUOIB3k03A Lj0A== 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=7y+NF7xt2ahoFYkWkvMrggh64PO+D95ks07QuAzb/uc=; b=vV2J22y67RBEFPJgI0CT0zkmlFBhZ3YkfBBmuDSKzkUhsSNzSQyVr+4L3ZixxgUFJn KnDbxpcDz2gQOwWYRhNbs3HOtSHVBuk/TUKVloaxCsZ69eGq6gJDoWR0sK5PsIOYeX6Q pzl02Nqgd4QGsq009wZk+22IAcAu4mH+Tc/eD/Z4i67LkpPqEHmevSR2S0D9iC0N0+FR QVAuuLzlXQuxD5UVXUkgMGiPdZujTn/axkNeMs1EQ8T3m54ZZZGdGs/z8tNsa+AnFthx IghDv/7MadJIjvuZed0wwQhZPpsiEdcjL9lC22cSDzM0hdzkkC3q8g1nPAOL3jtuzcXQ o6ew== 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 v7si8769398wrf.198.2017.12.03.06.35.55; Sun, 03 Dec 2017 06:35:56 -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 5DF4B68A069; Sun, 3 Dec 2017 16:35:45 +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.75]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 4B75A68A539 for ; Sun, 3 Dec 2017 16:35:38 +0200 (EET) Received: from localhost.localdomain ([89.247.207.216]) by mrelayeu.kundenserver.de (mreue101 [212.227.15.183]) with ESMTPSA (Nemesis) id 0LoYQs-1f1zme1WsE-00gawm; Sun, 03 Dec 2017 15:35:42 +0100 From: Rainer Hochecker To: ffmpeg-devel@ffmpeg.org Date: Sun, 3 Dec 2017 15:34:47 +0100 Message-Id: <20171203143447.41590-4-fernetmenta@online.de> X-Mailer: git-send-email 2.14.1 In-Reply-To: <20171203143447.41590-1-fernetmenta@online.de> References: <0489f119587681fc5a2b15fdc8afdd2d@mail.onse.fi> <20171203143447.41590-1-fernetmenta@online.de> X-Provags-ID: V03:K0:R4tISHBn2j8A5PV+hkjJWMnkrZwGvcUPtGgdmmVdOZoU8PdDgGt VaBFIoILnKJMRXhiJfADkWjg1MG//wk1T2xzgrTTO8XZqE/+ROVctUw4PtX7JdegQ9VW8q4 Avu5qiaYKlblE9lGZmSJ9aFhrOD/kI3Hg8hFgsLWdEuwmrgF2/x0m0S5gjyqiNsjBEz7+Tz stgkLXE4Jv1A2B0hQLNMA== X-UI-Out-Filterresults: notjunk:1; V01:K0:LeRFUZeA6aQ=:Qk9UrpjePg6vYBptgHWcCT lb6+PWL6c3Bd3lFoZuls6OBTnEBraOquPbtkZnM+d2BySjeho232kl0vO0zbwJ2rFsrROJhSn yjhLGGFiPSiXbUB5h87+dRt3lnZWan/9kLS/V7enRNwp0XnAUjN0n2/cY4UtpRRWlHzhNfaq7 NcLHhe/Wms3nsm22v4kguPiRP+PSUTCSRVluCH36qigGWqjxlWxrK48FlnmQfQf1tLE+nege1 ONn3JdRyIY30zD9RMO6GirsVGQb2QAc1FbKe2TZdcNlw6/d1AbDUpWhjZD1CsOhS+wl0NP9gx fCwiyddl6j3qkuatRrk87etSs0Dbi/Id62mBc0ZM4LBnafKcAluR/pMknnOYz7gLgiXw4pqec uvytDydIYv69HntmUaIE0yDSM7hQh9wvI/JZMb65YinNcsWPSi3QcTHk0Ia+35FpAumqk4EAx iCbINuvW2QW54IfnCdj9A9Q9sBw4T+POnTyYkLSfnqrASmrbVKrYdgBdYuv9ol7S/qJ08W7m9 Nj+zACJdDcjFXQcO0aNz1MQTD9gdSWqu8+xNJN7Rw3LNHPxLOB6n+Tu+I5BZwqozrgAWwLMii 2ZthVqnccr5h1yOUhQkw27eyIDVsgqWNXmf3I3PHj1Qs8x54PwUVyjo/sKsuMjFZFaw9q4jij 5f31csCzqu2nI1ulpHO72I7hS8itB3VNkQ71g1/yqecQAIpHpx354RU4cyUwrjSzioyzX6oyQ 23WMPxm2qM7koOhFiHxD9d7Bo8k13Ui6hk+QRw== Subject: [FFmpeg-devel] [PATCH v3 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 3f83707c1f..731e8a569c 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); + } } } } @@ -1832,8 +1870,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) @@ -1877,6 +1922,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 */ @@ -1894,6 +1943,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; @@ -1907,6 +1959,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; @@ -1917,9 +1989,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); @@ -2166,6 +2240,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); @@ -2222,6 +2298,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} };