static int read_data(void *opaque, uint8_t *buf, int buf_size)

{

    struct playlist *v = opaque;

    HLSContext *c = v->parent->priv_data;

    int ret, i;

    int just_opened = 0;




restart:

    if (!v->needed)

        return AVERROR_EOF;



    if (!v->input) {

        int64_t reload_interval;

        struct segment *seg;



        /* Check that the playlist is still needed before opening a new

         * segment. */

        if (v->ctx && v->ctx->nb_streams) {

            v->needed = 0;

            for (i = 0; i < v->n_main_streams; i++) {

                if (v->main_streams[i]->discard < AVDISCARD_ALL) {

                    v->needed = 1;

                    break;

                }

            }

        }

        if (!v->needed) {

            av_log(v->parent, AV_LOG_INFO, "No longer receiving playlist %d\n",

                v->index);

            return AVERROR_EOF;

        }



        /* If this is a live stream and the reload interval has elapsed since

         * the last playlist reload, reload the playlists now. */

        reload_interval = default_reload_interval(v);



reload:

        reload_count++;

        if (reload_count > c->max_reload)

            return AVERROR_EOF;

        if (!v->finished &&

            av_gettime_relative() - v->last_load_time >= reload_interval) {

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

                av_log(v->parent, AV_LOG_WARNING, "Failed to reload playlist %d\n",

                       v->index);

                return ret;

            }

            /* If we need to reload the playlist again below (if

             * there's still no more segments), switch to a reload

             * interval of half the target duration. */

            reload_interval = v->target_duration / 2;

        }

        if (v->cur_seq_no < v->start_seq_no) {

            av_log(NULL, AV_LOG_WARNING,

                   "skipping %d segments ahead, expired from playlists\n",

                   v->start_seq_no - v->cur_seq_no);

            v->cur_seq_no = v->start_seq_no;

        }

        if (v->cur_seq_no >= v->start_seq_no + v->n_segments) {

            if (v->finished)

                return AVERROR_EOF;

            while (av_gettime_relative() - v->last_load_time < reload_interval) {

                if (ff_check_interrupt(c->interrupt_callback))

                    return AVERROR_EXIT;

                av_usleep(100*1000);

            }

            /* Enough time has elapsed since the last reload */

            goto reload;

        }



        seg = current_segment(v);



        /* load/update Media Initialization Section, if any */

        ret = update_init_section(v, seg);

        if (ret)

            return ret;



        ret = open_input(c, v, seg);

        if (ret < 0) {

            if (ff_check_interrupt(c->interrupt_callback))

                return AVERROR_EXIT;

            av_log(v->parent, AV_LOG_WARNING, "Failed to open segment of playlist %d\n",

                   v->index);

            v->cur_seq_no += 1;

            goto reload;

        }

        just_opened = 1;

    }



    if (v->init_sec_buf_read_offset < v->init_sec_data_len) {

        /* Push init section out first before first actual segment */

        int copy_size = FFMIN(v->init_sec_data_len - v->init_sec_buf_read_offset, buf_size);

        memcpy(buf, v->init_sec_buf, copy_size);

        v->init_sec_buf_read_offset += copy_size;

        return copy_size;

    }



    ret = read_from_url(v, current_segment(v), buf, buf_size, READ_NORMAL);

    if (ret > 0) {

        if (just_opened && v->is_id3_timestamped != 0) {

            /* Intercept ID3 tags here, elementary audio streams are required

             * to convey timestamps using them in the beginning of each segment. */

            intercept_id3(v, buf, buf_size, &ret);

        }



        return ret;

    }

    ff_format_io_close(v->parent, &v->input);

    v->cur_seq_no++;



    c->cur_seq_no = v->cur_seq_no;



    goto restart;

}