static int hls_read_header(AVFormatContext *s) { HLSContext *c = s->priv_data; int ret = 0, i, j, stream_offset = 0; int only_parser_one_variants=1; int parser_start,parser_end; //c->interrupt_callback = &s->interrupt_callback; c->total_brate=500*1024; c->latest_3file_brate=c->total_brate; c->latest_1file_brate=c->total_brate; s->bit_rate=0; if ((ret = parse_playlist(c, s->filename, NULL, s->pb)) < 0){ av_log(NULL, AV_LOG_WARNING, "parse_playlist failed ret=%d\n",ret); goto fail; } if (c->n_variants == 0) { av_log(NULL, AV_LOG_WARNING, "Empty playlist 1\n"); ret = AVERROR_EOF; goto fail; } /* If the playlist only contained variants, parse each individual * variant playlist. */ if (c->n_variants > 1 || c->variants[0]->n_segments == 0) { for (i = 0; i < c->n_variants; i++) { struct variant *v = c->variants[i]; if ((ret = parse_playlist(c, v->url, v, NULL)) < 0) goto fail; } } if (c->variants[0]->n_segments == 0) { av_log(NULL, AV_LOG_WARNING, "Empty playlist 2\n"); ret = AVERROR_EOF; goto fail; } /* If this isn't a live stream, calculate the total duration of the * stream. */ if (c->variants[0]->finished) { int64_t duration = 0; for (i = 0; i < c->variants[0]->n_segments; i++) duration += c->variants[0]->segments[i]->duration; s->duration = duration * AV_TIME_BASE; } if(only_parser_one_variants){ parser_start=select_best_variant(c,c->total_brate); parser_end=parser_start+1; }else{ parser_start=0; parser_end=c->n_variants; } /* Open the demuxer for each variant */ for (i = parser_start; i < parser_end; i++) { struct variant *v = c->variants[i]; AVInputFormat *in_fmt = NULL; char bitrate_str[20]; if (v->n_segments == 0) continue; if (!(v->ctx = avformat_alloc_context())) { ret = AVERROR(ENOMEM); goto fail; } v->index = i; v->needed = 1; v->parent = s; /* If this is a live stream with more than 3 segments, start at the * third last segment. */ v->cur_seq_no = v->start_seq_no; if (!v->finished && v->n_segments > 3) v->cur_seq_no = v->start_seq_no + v->n_segments - 3; #ifdef USED_LP_BUF v->read_buffer = av_malloc(INITIAL_BUFFER_SIZE); memset(&v->urllpbuf,0,sizeof(&v->urllpbuf)); if(url_lpopen_ex(&v->urllpbuf,0,AVIO_FLAG_READ,read_data,read_data_exseek)==0){ ffio_init_context(&v->pb, v->read_buffer, INITIAL_BUFFER_SIZE, 0, &v->urllpbuf, url_lpread, NULL, NULL); }else{ ffio_init_context(&v->pb, v->read_buffer, INITIAL_BUFFER_SIZE, 0, &v->urllpbuf, read_data, NULL, NULL); } v->urllpbuf.is_streamed=1; v->urllpbuf.is_slowmedia=1; v->urllpbuf.priv_data=v; #else v->read_buffer = av_malloc(INITIAL_BUFFER_SIZE); ffio_init_context(&v->pb, v->read_buffer, INITIAL_BUFFER_SIZE, 0, v, read_data, NULL, NULL); #endif v->pb.seekable = 0; ret = av_probe_input_buffer(&v->pb, &in_fmt, v->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. */ avformat_free_context(v->ctx); v->ctx = NULL; goto fail; } v->ctx->pb = &v->pb; ret = avformat_open_input(&v->ctx, v->segments[0]->url, in_fmt, NULL); if (ret < 0) goto fail; if(v->bandwidth<=0 && v->segments[0]->seg_filesize>0 && v->segments[0]->duration>0){ v->bandwidth=v->segments[0]->seg_filesize/v->segments[0]->duration; } v->stream_offset = stream_offset; snprintf(bitrate_str, sizeof(bitrate_str), "%d", v->bandwidth); /* Create new AVStreams for each stream in this variant */ for (j = 0; j < v->ctx->nb_streams; j++) { AVStream *st = av_new_stream(s, 0); if (!st) { ret = AVERROR(ENOMEM); goto fail; } st->id = i; avcodec_copy_context(st->codec, v->ctx->streams[j]->codec); if (v->bandwidth) av_dict_set(&st->metadata, "variant_bitrate", bitrate_str, 0); if(st->codec->bit_rate<=0) st->codec->bit_rate=v->bandwidth/v->ctx->nb_streams; } v->ctx->bit_rate=v->bandwidth; stream_offset += v->ctx->nb_streams; s->bit_rate+=v->bandwidth; } c->first_packet = 1; c->first_timestamp = AV_NOPTS_VALUE; c->seek_timestamp = AV_NOPTS_VALUE; c->discontinue_pts_interval_ms=2000; s->flags|=AVFMT_FLAG_FILESIZE_NOT_VALID; if(s->pb){ /*reset read and free lp buf.*/ /*del lp buf,to free memory*/ ffio_fdopen_resetlpbuf(s->pb,0); s->pb->flags|=AVIO_FLAG_SIZE_NOTVALID; s->file_size=-1; } return 0; fail: free_variant_list(c); return ret; }
static struct list_item * switchto_next_item(struct list_mgt *mgt) { struct list_item *next = NULL; struct list_item *current = NULL; if (!mgt) { return NULL; } int isNeedFetch = 1; int64_t reload_interval = mgt->item_num > 0 && mgt->current_item != NULL ?\ mgt->current_item->duration:mgt->target_duration; if(reload_interval >0){ //to usec reload_interval *= 1000000; } if (mgt->n_variants > 0&&mgt->codec_buf_level>=0) { //vod,have mulit-bandwidth streams //av_log(NULL, AV_LOG_INFO, "current playing item index: %d,current playing seq:%d\n", mgt->playing_item_index, mgt->playing_item_seq); int is_switch = select_best_variant(mgt); if (is_switch>0) { //will remove this tricks. if (mgt->item_num > 0) { list_delall_item(mgt); } mgt->current_item = mgt->current_item->next = NULL; mgt->start_seq = -1; if(!mgt->have_list_end){ mgt->next_seq = mgt->playing_item_seq+1; }else{ mgt->next_seq = -1; } mgt->next_index = 0; mgt->item_num = 0; mgt->full_time = 0; if(mgt->cur_uio){ url_fclose(mgt->cur_uio); mgt->cur_uio = NULL; } if(mgt->debug_level==1){ hls_base_info_dump(mgt); } } if(mgt->debug_level>1){ hls_base_info_dump(mgt); } //av_log(NULL, AV_LOG_INFO, "select best variant,bandwidth: %d\n", mgt->playing_variant->bandwidth); } reload: if (mgt->current_item == NULL || mgt->current_item->next == NULL) { /*new refresh this mgtlist now*/ ByteIOContext *bio = mgt->cur_uio; int ret; char* url = NULL; if (mgt->n_variants > 0 && NULL != mgt->playing_variant) { url = mgt->playing_variant->url; //av_log(NULL, AV_LOG_INFO, "list open variant url:%s,bandwidth:%d\n", url, mgt->playing_variant->bandwidth); } else { url = mgt->filename; //av_log(NULL, AV_LOG_INFO, "list open url:%s\n", url); } if (!mgt->have_list_end && (av_gettime() - mgt->last_load_time < reload_interval)&&mgt->item_num>0) { //av_log(NULL, AV_LOG_INFO, "drop fetch playlist from server\n"); isNeedFetch = 0; } if (url_interrupt_cb()) { return NULL; } if (isNeedFetch == 0 || (ret = list_open_internet(&bio, mgt, url, mgt->flags | URL_MINI_BUFFER | URL_NO_LP_BUFFER)) != 0) { if(ret!=0&&mgt->n_variants>1){ switch_bw_level(mgt,-1); } goto switchnext; } mgt->cur_uio = bio; if (mgt->current_item && mgt->current_item->file) { /*current item,switch to next*/ current = mgt->current_item; next = mgt->current_item->next; for (; next != NULL; next = next->next) { if (next->file && strcmp(current->file, next->file) == 0) { /*found the same item,switch to the next*/ current = next; break; } } #if 0 while (current != mgt->item_list) { /*del the old item,lest current,and then play current->next*/ list_del_item(mgt, mgt->item_list); } #endif mgt->current_item = current; /*switch to new current;*/ if (!mgt->have_list_end && mgt->item_num > LIVE_LIST_MAX) { list_shrink_live_list(mgt); } } } switchnext: if (mgt->current_item) { next = mgt->current_item->next; } else { if (!mgt->have_list_end) { //live tv next = mgt->item_list; } else { next = list_find_next_item_by_index(mgt, mgt->playing_item_index); } } if (mgt->listclose){ return NULL; } if (next){ if(next->file!=NULL){ if(mgt->debug_level>1){ RLOG("Player switch to new item,url =%s,total item=%d,start=%.4lf,duration=%.4lf,index:%d,seq:%d\n", next->file, mgt->item_num, next->start_time, next->duration,next->index,next->seq); } } }else { if(mgt->debug_level>1){ RLOG("Player can't find new item,total=%d\n", mgt->item_num); } if (!mgt->have_list_end) { if (url_interrupt_cb()) { return NULL; } usleep(100 * 1000); reload_interval = mgt->target_duration * 500000; isNeedFetch = 1; goto reload; } } return next; }