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;
}
Exemple #2
0
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;
}