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; }