static int hls_read_header(AVFormatContext *s)

{

    void *u = (s->flags & AVFMT_FLAG_CUSTOM_IO) ? NULL : s->pb;

    HLSContext *c = s->priv_data;

    int ret = 0, i;

    int highest_cur_seq_no = 0;



    c->ctx                = s;

    c->interrupt_callback = &s->interrupt_callback;

    c->strict_std_compliance = s->strict_std_compliance;



    c->first_packet = 1;

    c->first_timestamp = AV_NOPTS_VALUE;

    c->cur_timestamp = AV_NOPTS_VALUE;



    if (u) {

        // get the previous user agent & set back to null if string size is zero

        update_options(&c->user_agent, "user-agent", u);



        // get the previous cookies & set back to null if string size is zero

        update_options(&c->cookies, "cookies", u);



        // get the previous headers & set back to null if string size is zero

        update_options(&c->headers, "headers", u);



        // get the previous http proxt & set back to null if string size is zero

        update_options(&c->http_proxy, "http_proxy", u);

    }



    if ((ret = parse_playlist(c, s->filename, NULL, s->pb)) < 0)

        goto fail;



    if ((ret = save_avio_options(s)) < 0)

        goto fail;



    /* Some HLS servers don't like being sent the range header */

    av_dict_set(&c->avio_opts, "seekable", "0", 0);



    if (c->n_variants == 0) {

        av_log(NULL, AV_LOG_WARNING, "Empty playlist\n");

        ret = AVERROR_EOF;

        goto fail;

    }

    /* If the playlist only contained playlists (Master Playlist),

     * parse each individual playlist. */

    if (c->n_playlists > 1 || c->playlists[0]->n_segments == 0) {

        for (i = 0; i < c->n_playlists; i++) {

            struct playlist *pls = c->playlists[i];

            if ((ret = parse_playlist(c, pls->url, pls, NULL)) < 0)

                goto fail;

        }

    }



    if (c->variants[0]->playlists[0]->n_segments == 0) {

        av_log(NULL, AV_LOG_WARNING, "Empty playlist\n");

        ret = AVERROR_EOF;

        goto fail;

    }



    /* If this isn't a live stream, calculate the total duration of the

     * stream. */

    if (c->variants[0]->playlists[0]->finished) {

        int64_t duration = 0;

        for (i = 0; i < c->variants[0]->playlists[0]->n_segments; i++)

            duration += c->variants[0]->playlists[0]->segments[i]->duration;

        s->duration = duration;

    }



    /* Associate renditions with variants */

    for (i = 0; i < c->n_variants; i++) {

        struct variant *var = c->variants[i];



        if (var->audio_group[0])

            add_renditions_to_variant(c, var, AVMEDIA_TYPE_AUDIO, var->audio_group);

        if (var->video_group[0])

            add_renditions_to_variant(c, var, AVMEDIA_TYPE_VIDEO, var->video_group);

        if (var->subtitles_group[0])

            add_renditions_to_variant(c, var, AVMEDIA_TYPE_SUBTITLE, var->subtitles_group);

    }



    /* Create a program for each variant */

    for (i = 0; i < c->n_variants; i++) {

        struct variant *v = c->variants[i];

        AVProgram *program;



        program = av_new_program(s, i);

        if (!program)

            goto fail;

        av_dict_set_int(&program->metadata, "variant_bitrate", v->bandwidth, 0);

    }



    /* Select the starting segments */

    for (i = 0; i < c->n_playlists; i++) {

        struct playlist *pls = c->playlists[i];



        if (pls->n_segments == 0)

            continue;



        pls->cur_seq_no = select_cur_seq_no(c, pls);

        highest_cur_seq_no = FFMAX(highest_cur_seq_no, pls->cur_seq_no);

    }



    /* Open the demuxer for each playlist */

    for (i = 0; i < c->n_playlists; i++) {

        struct playlist *pls = c->playlists[i];

        AVInputFormat *in_fmt = NULL;



        if (!(pls->ctx = avformat_alloc_context())) {

            ret = AVERROR(ENOMEM);

            goto fail;

        }



        if (pls->n_segments == 0)

            continue;



        pls->index  = i;

        pls->needed = 1;

        pls->parent = s;



        /*

         * If this is a live stream and this playlist looks like it is one segment

         * behind, try to sync it up so that every substream starts at the same

         * time position (so e.g. avformat_find_stream_info() will see packets from

         * all active streams within the first few seconds). This is not very generic,

         * though, as the sequence numbers are technically independent.

         */

        if (!pls->finished && pls->cur_seq_no == highest_cur_seq_no - 1 &&

            highest_cur_seq_no < pls->start_seq_no + pls->n_segments) {

            pls->cur_seq_no = highest_cur_seq_no;

        }



        pls->read_buffer = av_malloc(INITIAL_BUFFER_SIZE);

        if (!pls->read_buffer){

            ret = AVERROR(ENOMEM);

            avformat_free_context(pls->ctx);

            pls->ctx = NULL;

            goto fail;

        }

        ffio_init_context(&pls->pb, pls->read_buffer, INITIAL_BUFFER_SIZE, 0, pls,

                          read_data, NULL, NULL);

        pls->pb.seekable = 0;

        ret = av_probe_input_buffer(&pls->pb, &in_fmt, pls->segments[0]->url,

                                    NULL, 0, 0);

        if (ret < 0) {

            /* Free the ctx - it isn't initialized properly at this point,

             * so avformat_close_input shouldn't be called. If

             * avformat_open_input fails below, it frees and zeros the

             * context, so it doesn't need any special treatment like this. */

            av_log(s, AV_LOG_ERROR, "Error when loading first segment '%s'\n", pls->segments[0]->url);

            avformat_free_context(pls->ctx);

            pls->ctx = NULL;

            goto fail;

        }

        pls->ctx->pb       = &pls->pb;

        pls->ctx->io_open  = nested_io_open;



        if ((ret = ff_copy_whiteblacklists(pls->ctx, s)) < 0)

            goto fail;



        ret = avformat_open_input(&pls->ctx, pls->segments[0]->url, in_fmt, NULL);

        if (ret < 0)

            goto fail;



        if (pls->id3_deferred_extra && pls->ctx->nb_streams == 1) {

            ff_id3v2_parse_apic(pls->ctx, &pls->id3_deferred_extra);

            avformat_queue_attached_pictures(pls->ctx);

            ff_id3v2_free_extra_meta(&pls->id3_deferred_extra);

            pls->id3_deferred_extra = NULL;

        }



        pls->ctx->ctx_flags &= ~AVFMTCTX_NOHEADER;

        ret = avformat_find_stream_info(pls->ctx, NULL);

        if (ret < 0)

            goto fail;



        if (pls->is_id3_timestamped == -1)

            av_log(s, AV_LOG_WARNING, "No expected HTTP requests have been made\n");



        /* Create new AVStreams for each stream in this playlist */

        ret = update_streams_from_subdemuxer(s, pls);

        if (ret < 0)

            goto fail;



        add_metadata_from_renditions(s, pls, AVMEDIA_TYPE_AUDIO);

        add_metadata_from_renditions(s, pls, AVMEDIA_TYPE_VIDEO);

        add_metadata_from_renditions(s, pls, AVMEDIA_TYPE_SUBTITLE);

    }



    return 0;

fail:

    free_playlist_list(c);

    free_variant_list(c);

    free_rendition_list(c);

    return ret;

}
