diff mbox series

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

Message ID 20200430131053.1208-1-yyyaroslav@gmail.com
State Accepted
Commit 7f0200d0d2639ed9cfd37934b29b43c3c3c4e674
Headers show
Series [FFmpeg-devel] libavformat/hlsenc: Allow usage of 'periodic-rekey' with multi-variant streams | expand

Checks

Context Check Description
andriy/default pending
andriy/make success Make finished
andriy/make_fate success Make fate finished

Commit Message

Yaroslav Pogrebnyak April 30, 2020, 1:10 p.m. UTC
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@gmail.com>

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

Comments

Liu Steven April 30, 2020, 2:44 p.m. UTC | #1
> 2020年4月30日 下午9:10,Yaroslav Pogrebnyak <yyyaroslav@gmail.com> 写道:
> 
> 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@gmail.com>
> 
> ---
> 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");
> -- 
> 2.17.1
> 
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
> 
> To unsubscribe, visit link above, or email
> ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

LGTM


Thanks

Steven Liu
diff mbox series

Patch

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");