[FFmpeg-devel] [PATCH 10/18] avformat/hls: add support for byte-ranged segments

Michael Niedermayer michaelni at gmx.at
Tue Dec 31 04:05:46 CET 2013


On Mon, Dec 30, 2013 at 01:14:24PM +0200, Anssi Hannula wrote:
> Add support for EXT-X-BYTERANGE added in HLS protocol v4.
> 
> Signed-off-by: Anssi Hannula <anssi.hannula at iki.fi>
> ---
>  libavformat/hls.c | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++++--
>  1 file changed, 61 insertions(+), 2 deletions(-)
> 
> diff --git a/libavformat/hls.c b/libavformat/hls.c
> index 2a337fb..4c23d51 100644
> --- a/libavformat/hls.c
> +++ b/libavformat/hls.c
> @@ -61,6 +61,8 @@ enum KeyType {
>  
>  struct segment {
>      int64_t duration;
> +    int64_t url_offset;
> +    int64_t size;
>      char url[MAX_URL_SIZE];
>      char key[MAX_URL_SIZE];
>      enum KeyType key_type;
> @@ -92,6 +94,7 @@ struct playlist {
>      struct segment **segments;
>      int needed, cur_needed;
>      int cur_seq_no;
> +    int64_t cur_seq_offset;
>      int64_t last_load_time;
>  
>      char key_url[MAX_URL_SIZE];
> @@ -443,6 +446,8 @@ static int parse_playlist(HLSContext *c, const char *url,
>      char line[MAX_URL_SIZE];
>      const char *ptr;
>      int close_in = 0;
> +    int64_t seg_offset = 0;
> +    int64_t seg_size = -1;
>      uint8_t *new_url = NULL;
>      struct variant_info variant_info;
>  
> @@ -526,6 +531,11 @@ static int parse_playlist(HLSContext *c, const char *url,
>          } else if (av_strstart(line, "#EXTINF:", &ptr)) {
>              is_segment = 1;
>              duration   = atof(ptr) * AV_TIME_BASE;
> +        } else if (av_strstart(line, "#EXT-X-BYTERANGE:", &ptr)) {
> +            seg_size = atoi(ptr);
> +            ptr = strchr(ptr, '@');
> +            if (ptr)
> +                seg_offset = atoi(ptr+1);
>          } else if (av_strstart(line, "#", NULL)) {
>              continue;
>          } else if (line[0]) {
> @@ -563,6 +573,16 @@ static int parse_playlist(HLSContext *c, const char *url,
>                  ff_make_absolute_url(seg->url, sizeof(seg->url), url, line);
>                  dynarray_add(&pls->segments, &pls->n_segments, seg);
>                  is_segment = 0;
> +
> +                seg->size = seg_size;
> +                if (seg_size >= 0) {
> +                    seg->url_offset = seg_offset;
> +                    seg_offset += seg_size;
> +                    seg_size = -1;
> +                } else {
> +                    seg->url_offset = 0;
> +                    seg_offset = 0;
> +                }
>              }
>          }
>      }
> @@ -579,9 +599,23 @@ fail:
>  static int open_input(HLSContext *c, struct playlist *pls)
>  {
>      AVDictionary *opts = NULL;
> +    AVDictionary *offset_opts = NULL;
>      int ret;
>      struct segment *seg = pls->segments[pls->cur_seq_no - pls->start_seq_no];
>  
> +    if (seg->size >= 0) {
> +        /* try to restrict the HTTP request to the part we want
> +         * (if this is in fact a HTTP request) */
> +        char offset[24] = { 0 };
> +        char end_offset[24] = { 0 };
> +        snprintf(offset, sizeof(offset) - 1, "%"PRId64,
> +                 seg->url_offset);
> +        snprintf(end_offset, sizeof(end_offset) - 1, "%"PRId64,
> +                 seg->url_offset + seg->size);
> +        av_dict_set(&offset_opts, "offset", offset, 0);
> +        av_dict_set(&offset_opts, "end_offset", end_offset, 0);
> +    }
> +
>      // broker prior HTTP options that should be consistent across requests
>      av_dict_set(&opts, "user-agent", c->user_agent, 0);
>      av_dict_set(&opts, "cookies", c->cookies, 0);
> @@ -589,9 +623,10 @@ static int open_input(HLSContext *c, struct playlist *pls)
>      av_dict_set(&opts, "seekable", "0", 0);
>  
>      if (seg->key_type == KEY_NONE) {
> +        av_dict_copy(&opts, offset_opts, 0);
>          ret = ffurl_open(&pls->input, seg->url, AVIO_FLAG_READ,
>                            &pls->parent->interrupt_callback, &opts);

> -        goto cleanup;
> +


>      } else if (seg->key_type == KEY_AES_128) {
>          char iv[33], key[33], url[MAX_URL_SIZE];
>          if (strcmp(seg->key, pls->key_url)) {
> @@ -625,6 +660,7 @@ static int open_input(HLSContext *c, struct playlist *pls)
>          /* Need to repopulate options */
>          av_dict_free(&opts);
>          av_dict_set(&opts, "seekable", "0", 0);
> +        av_dict_copy(&opts, offset_opts, 0);
>          if ((ret = ffurl_connect(pls->input, &opts)) < 0) {
>              ffurl_close(pls->input);
>              pls->input = NULL;
> @@ -635,8 +671,22 @@ static int open_input(HLSContext *c, struct playlist *pls)
>      else
>        ret = AVERROR(ENOSYS);
>  
> +    /* Seek to the requested position. If this was a HTTP request,
> +     * the offset should already be there. */
> +    if (ret == 0) {
> +        int seekret = ffurl_seek(pls->input, seg->url_offset, SEEK_SET);
> +        if (seekret < 0) {
> +            av_log(pls->parent, AV_LOG_ERROR, "Unable to seek to offset %"PRId64" of HLS segment '%s'\n", seg->url_offset, seg->url);
> +            ret = seekret;
> +            ffurl_close(pls->input);
> +            pls->input = NULL;
> +        }
> +    }

maybe i misunderstand something but why do you need to seek if the
offset was already provided to the protocol ?


[...]

-- 
Michael     GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB

Opposition brings concord. Out of discord comes the fairest harmony.
-- Heraclitus
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: Digital signature
URL: <http://ffmpeg.org/pipermail/ffmpeg-devel/attachments/20131231/0a71554c/attachment.asc>


More information about the ffmpeg-devel mailing list