From patchwork Thu Apr 30 13:10:53 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yaroslav Pogrebnyak X-Patchwork-Id: 19401 Return-Path: X-Original-To: patchwork@ffaux-bg.ffmpeg.org Delivered-To: patchwork@ffaux-bg.ffmpeg.org Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org [79.124.17.100]) by ffaux.localdomain (Postfix) with ESMTP id 6136544A695 for ; Thu, 30 Apr 2020 16:38:12 +0300 (EEST) Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 41F9568C73E; Thu, 30 Apr 2020 16:38:12 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-oi1-f195.google.com (mail-oi1-f195.google.com [209.85.167.195]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id E208E68C72D for ; Thu, 30 Apr 2020 16:38:05 +0300 (EEST) Received: by mail-oi1-f195.google.com with SMTP id a2so5197217oia.11 for ; Thu, 30 Apr 2020 06:38:05 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id; bh=7mF53QOWBsNRH2xlX2j0MT03UYhiVN1TZ189ruTmjy0=; b=OAH5x746hNxaacxRAM5Hrm8WUdB+/rVxaPcWOYnjZ+0C5DrRPoLuE9O4eqEyd8UTit /jEnpsbPGcxjI3p10M+R0Tn22ChG62mMNnr8CTyXT94pu3VJyli5xnTTXn600gP10TPM HC2A89ZxoBoNlmna7ImNRbVcSiZ3He8NEvDWsGHyJ+h4ernNrDVloh7Hu7ofW2Ryass6 bXn9r5aKWS+JP2/bPDKeYFVyXR9nL3gz6P6FwRQ9G74aO9PDxpUXfTwHWugCyN3zJEUW cqqhT4e+DACW7HsatpfWQZRpKMiwjRNq+lXigxSQcUshSrj3ClBzJkdEtMfhChSo6elH pVpg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id; bh=7mF53QOWBsNRH2xlX2j0MT03UYhiVN1TZ189ruTmjy0=; b=UixEQBJkuyYw3YX8fAKL4/jZZ34Yar7Cm1QAjxNNNKcpkouLWmnKAd/XJLxEaHN0Dv bMtF7Tn59KbLwAum6LaoJeA97HwpyIdn2R3DoQSQf1WDWleK90AZ45IWzk+WgwLmYhA6 yHR+UubhV3H+2AKYp/i3EN4BDQbC3J2cgZulW9I7+bMHTDJNcSj2tfbj/jygwbfvrWI7 hGlaVsQVDUfLb0FfmyZHcBjdCc9Zn+woU0DIV8WcZKfwF1JbqOv6fj1Myfeb6AAyZgIV bxg8/bFiPo8HzZi/hPQK8ADgXrsylaTEVRvVyo40nTn8IJXrHlCmkzmrogJ+J26zP5ba A/JQ== X-Gm-Message-State: AGi0PuZFW3ojcCzS8k9/O8FynxNB8eoEztLuc8dC8ex1oUPUDjrx7a+B 3Qk8bbjwnlsgcRNb6mfhQvXYkCIjvH0AWg== X-Google-Smtp-Source: APiQypJvrx656Z5kxHvlI4xzsTxJwm+X5BmWzrCOJclXLB7Sef5O+sjGUfhbc8so1tadhiLdR6nZuw== X-Received: by 2002:a17:90a:ba84:: with SMTP id t4mr2891071pjr.81.1588252289958; Thu, 30 Apr 2020 06:11:29 -0700 (PDT) Received: from localhost.localdomain ([180.249.118.59]) by smtp.gmail.com with ESMTPSA id x12sm3418626pfo.62.2020.04.30.06.11.27 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 30 Apr 2020 06:11:29 -0700 (PDT) From: Yaroslav Pogrebnyak To: ffmpeg-devel@ffmpeg.org Date: Thu, 30 Apr 2020 21:10:53 +0800 Message-Id: <20200430131053.1208-1-yyyaroslav@gmail.com> X-Mailer: git-send-email 2.17.1 Subject: [FFmpeg-devel] [PATCH] libavformat/hlsenc: Allow usage of 'periodic-rekey' with multi-variant streams 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: Yaroslav Pogrebnyak MIME-Version: 1.0 Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" This patch adds possibility to use 'periodic-rekey' option with multi-variant streams to hlsenc muxer. All streams variants use parameters from the same key_info_file. There are 2 sets of encryption options that kind of overlaps and add complexity, so I tried to do the thing without changing too much code. There is a little duplication of the key_file, key_uri, iv_string, etc in the VariantStream since we copy it from hls to each variant stream, but generally all the code remains the same to minimise appearing of unexpected bugs. Refactoring could be done as a separate patch then as needed. Signed-off-by: Yaroslav Pogrebnyak --- libavformat/hlsenc.c | 81 ++++++++++++++++++++++++-------------------- 1 file changed, 44 insertions(+), 37 deletions(-) diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c index d75684741f..1522eb5218 100644 --- a/libavformat/hlsenc.c +++ b/libavformat/hlsenc.c @@ -157,6 +157,13 @@ typedef struct VariantStream { char *fmp4_init_filename; char *base_output_dirname; + int encrypt_started; + + char key_file[LINE_BUFFER_SIZE + 1]; + char key_uri[LINE_BUFFER_SIZE + 1]; + char key_string[KEYSIZE*2 + 1]; + char iv_string[KEYSIZE*2 + 1]; + AVStream **streams; char codec_attr[128]; CodecAttributeStatus attr_status; @@ -705,7 +712,7 @@ static int do_encrypt(AVFormatContext *s, VariantStream *vs) } -static int hls_encryption_start(AVFormatContext *s) +static int hls_encryption_start(AVFormatContext *s, VariantStream *vs) { HLSContext *hls = s->priv_data; int ret; @@ -722,44 +729,44 @@ static int hls_encryption_start(AVFormatContext *s) return ret; } - ff_get_line(pb, hls->key_uri, sizeof(hls->key_uri)); - hls->key_uri[strcspn(hls->key_uri, "\r\n")] = '\0'; + ff_get_line(pb, vs->key_uri, sizeof(vs->key_uri)); + vs->key_uri[strcspn(vs->key_uri, "\r\n")] = '\0'; - ff_get_line(pb, hls->key_file, sizeof(hls->key_file)); - hls->key_file[strcspn(hls->key_file, "\r\n")] = '\0'; + ff_get_line(pb, vs->key_file, sizeof(vs->key_file)); + vs->key_file[strcspn(vs->key_file, "\r\n")] = '\0'; - ff_get_line(pb, hls->iv_string, sizeof(hls->iv_string)); - hls->iv_string[strcspn(hls->iv_string, "\r\n")] = '\0'; + ff_get_line(pb, vs->iv_string, sizeof(vs->iv_string)); + vs->iv_string[strcspn(vs->iv_string, "\r\n")] = '\0'; ff_format_io_close(s, &pb); - if (!*hls->key_uri) { + if (!*vs->key_uri) { av_log(hls, AV_LOG_ERROR, "no key URI specified in key info file\n"); return AVERROR(EINVAL); } - if (!*hls->key_file) { + if (!*vs->key_file) { av_log(hls, AV_LOG_ERROR, "no key file specified in key info file\n"); return AVERROR(EINVAL); } set_http_options(s, &options, hls); - ret = s->io_open(s, &pb, hls->key_file, AVIO_FLAG_READ, &options); + ret = s->io_open(s, &pb, vs->key_file, AVIO_FLAG_READ, &options); av_dict_free(&options); if (ret < 0) { - av_log(hls, AV_LOG_ERROR, "error opening key file %s\n", hls->key_file); + av_log(hls, AV_LOG_ERROR, "error opening key file %s\n", vs->key_file); return ret; } ret = avio_read(pb, key, sizeof(key)); ff_format_io_close(s, &pb); if (ret != sizeof(key)) { - av_log(hls, AV_LOG_ERROR, "error reading key file %s\n", hls->key_file); + av_log(hls, AV_LOG_ERROR, "error reading key file %s\n", vs->key_file); if (ret >= 0 || ret == AVERROR_EOF) ret = AVERROR(EINVAL); return ret; } - ff_data_to_hex(hls->key_string, key, sizeof(key), 0); + ff_data_to_hex(vs->key_string, key, sizeof(key), 0); return 0; } @@ -1081,8 +1088,8 @@ static int hls_append_segment(struct AVFormatContext *s, HLSContext *hls, } if (hls->key_info_file || hls->encrypt) { - av_strlcpy(en->key_uri, hls->key_uri, sizeof(en->key_uri)); - av_strlcpy(en->iv_string, hls->iv_string, sizeof(en->iv_string)); + av_strlcpy(en->key_uri, vs->key_uri, sizeof(en->key_uri)); + av_strlcpy(en->iv_string, vs->iv_string, sizeof(en->iv_string)); } if (!vs->segments) @@ -1170,9 +1177,9 @@ static int parse_playlist(AVFormatContext *s, const char *url, VariantStream *vs ptr += strlen("URI=\""); end = av_stristr(ptr, ","); if (end) { - av_strlcpy(hls->key_uri, ptr, end - ptr); + av_strlcpy(vs->key_uri, ptr, end - ptr); } else { - av_strlcpy(hls->key_uri, ptr, sizeof(hls->key_uri)); + av_strlcpy(vs->key_uri, ptr, sizeof(vs->key_uri)); } } @@ -1181,9 +1188,9 @@ static int parse_playlist(AVFormatContext *s, const char *url, VariantStream *vs ptr += strlen("IV=0x"); end = av_stristr(ptr, ","); if (end) { - av_strlcpy(hls->iv_string, ptr, end - ptr); + av_strlcpy(vs->iv_string, ptr, end - ptr); } else { - av_strlcpy(hls->iv_string, ptr, sizeof(hls->iv_string)); + av_strlcpy(vs->iv_string, ptr, sizeof(vs->iv_string)); } } @@ -1692,21 +1699,27 @@ static int hls_start(AVFormatContext *s, VariantStream *vs) " ignoring -hls_enc\n"); } - if (!c->encrypt_started || (c->flags & HLS_PERIODIC_REKEY)) { + if (!vs->encrypt_started || (c->flags & HLS_PERIODIC_REKEY)) { if (c->key_info_file) { - if ((err = hls_encryption_start(s)) < 0) + if ((err = hls_encryption_start(s, vs)) < 0) goto fail; } else { - if ((err = do_encrypt(s, vs)) < 0) - goto fail; + if (!c->encrypt_started) { + if ((err = do_encrypt(s, vs)) < 0) + goto fail; + c->encrypt_started = 1; + } + av_strlcpy(vs->key_uri, c->key_uri, sizeof(vs->key_uri)); + av_strlcpy(vs->key_string, c->key_string, sizeof(vs->key_string)); + av_strlcpy(vs->iv_string, c->iv_string, sizeof(vs->iv_string)); } - c->encrypt_started = 1; + vs->encrypt_started = 1; } - err = av_strlcpy(iv_string, c->iv_string, sizeof(iv_string)); + err = av_strlcpy(iv_string, vs->iv_string, sizeof(iv_string)); if (!err) { snprintf(iv_string, sizeof(iv_string), "%032"PRIx64, vs->sequence); - memset(c->iv_string, 0, sizeof(c->iv_string)); - memcpy(c->iv_string, iv_string, sizeof(iv_string)); + memset(vs->iv_string, 0, sizeof(vs->iv_string)); + memcpy(vs->iv_string, iv_string, sizeof(iv_string)); } } if (c->segment_type != SEGMENT_TYPE_FMP4) { @@ -2403,8 +2416,8 @@ static int hls_write_packet(AVFormatContext *s, AVPacket *pkt) AVDictionary *options = NULL; char *filename = NULL; if (hls->key_info_file || hls->encrypt) { - av_dict_set(&options, "encryption_key", hls->key_string, 0); - av_dict_set(&options, "encryption_iv", hls->iv_string, 0); + av_dict_set(&options, "encryption_key", vs->key_string, 0); + av_dict_set(&options, "encryption_iv", vs->iv_string, 0); filename = av_asprintf("crypto:%s", oc->url); } else { filename = av_asprintf("%s", oc->url); @@ -2595,8 +2608,8 @@ static int hls_write_trailer(struct AVFormatContext *s) return AVERROR(ENOMEM); } if (hls->key_info_file || hls->encrypt) { - av_dict_set(&options, "encryption_key", hls->key_string, 0); - av_dict_set(&options, "encryption_iv", hls->iv_string, 0); + av_dict_set(&options, "encryption_key", vs->key_string, 0); + av_dict_set(&options, "encryption_iv", vs->iv_string, 0); filename = av_asprintf("crypto:%s", oc->url); } else { filename = av_asprintf("%s", oc->url); @@ -2742,12 +2755,6 @@ static int hls_init(AVFormatContext *s) ret); goto fail; } - //TODO: Updates needed to encryption functionality with periodic re-key when more than one variant streams are present - if (hls->nb_varstreams > 1 && hls->flags & HLS_PERIODIC_REKEY) { - ret = AVERROR(EINVAL); - av_log(s, AV_LOG_ERROR, "Periodic re-key not supported when more than one variant streams are present\n"); - goto fail; - } if (!hls->method && http_base_proto) { av_log(hls, AV_LOG_WARNING, "No HTTP method set, hls muxer defaulting to method PUT.\n");