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

Steven Liu lq at chinaffmpeg.org
Thu Apr 30 17:44:56 EEST 2020



> 2020年4月30日 下午9:10,Yaroslav Pogrebnyak <yyyaroslav at 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 at 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 at ffmpeg.org
> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
> 
> To unsubscribe, visit link above, or email
> ffmpeg-devel-request at ffmpeg.org with subject "unsubscribe".

LGTM


Thanks

Steven Liu





More information about the ffmpeg-devel mailing list