[FFmpeg-cvslog] libavformat/hlsenc: Allow usage of 'periodic-rekey' with multi-variant streams

Yaroslav Pogrebnyak git at videolan.org
Wed May 6 06:54:46 EEST 2020


ffmpeg | branch: master | Yaroslav Pogrebnyak <yyyaroslav at gmail.com> | Thu Apr 30 21:10:53 2020 +0800| [7f0200d0d2639ed9cfd37934b29b43c3c3c4e674] | committer: Steven Liu

libavformat/hlsenc: Allow usage of 'periodic-rekey' with multi-variant streams

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 <yyyaroslav at gmail.com>

> http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=7f0200d0d2639ed9cfd37934b29b43c3c3c4e674
---

 libavformat/hlsenc.c | 81 ++++++++++++++++++++++++++++------------------------
 1 file changed, 44 insertions(+), 37 deletions(-)

diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c
index 10984dddb8..f91108e892 100644
--- a/libavformat/hlsenc.c
+++ b/libavformat/hlsenc.c
@@ -160,6 +160,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;
@@ -708,7 +715,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;
@@ -725,44 +732,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;
 }
@@ -1084,8 +1091,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)
@@ -1173,9 +1180,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));
                 }
             }
 
@@ -1184,9 +1191,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));
                 }
             }
 
@@ -1695,21 +1702,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) {
@@ -2406,8 +2419,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);
@@ -2599,8 +2612,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);
@@ -2746,12 +2759,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");



More information about the ffmpeg-cvslog mailing list