static int hls_close(AVFormatContext *s) { HLSContext *c = s->priv_data; free_variant_list(c); return 0; }
static int applehttp_close(AVFormatContext *s) { AppleHTTPContext *c = s->priv_data; free_variant_list(c); return 0; }
static int hls_close(URLContext *h) { HLSContext *s = h->priv_data; free_segment_list(s); free_variant_list(s); ffurl_close(s->seg_hd); return 0; }
static int applehttp_close(URLContext *h) { AppleHTTPContext *s = h->priv_data; free_segment_list(s); free_variant_list(s); ffurl_close(s->seg_hd); av_free(s); return 0; }
static int hls_close(AVFormatContext *s) { HLSContext *c = s->priv_data; free_variant_list(c); av_dict_free(&c->avio_opts); return 0; }
static int hls_read_header(AVFormatContext *s) { HLSContext *c = s->priv_data; int ret = 0, i, j, stream_offset = 0; c->interrupt_callback = &s->interrupt_callback; if ((ret = parse_playlist(c, s->filename, NULL, s->pb)) < 0) goto fail; if (c->n_variants == 0) { av_log(NULL, AV_LOG_WARNING, "Empty playlist\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\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; } /* Open the demuxer for each variant */ for (i = 0; i < c->n_variants; i++) { struct variant *v = c->variants[i]; AVInputFormat *in_fmt = NULL; char bitrate_str[20]; AVProgram * program = NULL; 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; 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); 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. */ av_log(s, AV_LOG_ERROR, "Error when loading first segment '%s'\n", v->segments[0]->url); 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; v->stream_offset = stream_offset; v->ctx->ctx_flags &= ~AVFMTCTX_NOHEADER; ret = avformat_find_stream_info(v->ctx, NULL); if (ret < 0) goto fail; snprintf(bitrate_str, sizeof(bitrate_str), "%d", v->bandwidth); /* Create new AVprogram for variant i */ program = av_new_program(s, i); if ( !program ) goto fail; av_dict_set(&program->metadata, "variant_bitrate", bitrate_str, 0); program->bitrate = v->bandwidth; /* Create new AVStreams for each stream in this variant */ for (j = 0; j < v->ctx->nb_streams; j++) { AVStream *st = avformat_new_stream(s, NULL); if (!st) { ret = AVERROR(ENOMEM); goto fail; } ff_program_add_stream_index(s, i, st->index); 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); } stream_offset += v->ctx->nb_streams; } c->first_packet = 1; c->first_timestamp = AV_NOPTS_VALUE; c->seek_timestamp = AV_NOPTS_VALUE; return 0; fail: free_variant_list(c); return ret; }
static int m3u_format_parser(struct list_mgt *mgt,ByteIOContext *s) { unsigned char line[1024]; int ret; unsigned char *p; int getnum=0; struct list_item tmpitem; char prefix[1024]=""; char prefixex[1024]=""; int prefix_len=0,prefixex_len=0; double start_time=mgt->full_time; char *oprefix=mgt->location!=NULL?mgt->location:mgt->filename; if(NULL!=mgt->prefix) { av_free(mgt->prefix); mgt->prefix = NULL; } if(oprefix) { mgt->prefix = strdup(oprefix); char *tail,*tailex,*extoptions; extoptions=strchr(oprefix,'?');/*ext options is start with ? ,we don't need in nested*/ if(is_NET_URL(oprefix)) { tail=strchr(oprefix+10,'/');/*skip Http:// and shttp:,and to first '/'*/ if(!extoptions)// no ? tailex=strrchr(oprefix+10,'/');/*skip Http:// and shttp:,start to last '/'*/ else tailex=memrchr(oprefix+10,'/',extoptions-oprefix-10);/*skip Http:// and shttp:,start to last '/',between http-->? */ } else { tail=strchr(oprefix,'/'); /*first '/'*/ if(!extoptions)//no ? tailex=strrchr(oprefix,'/'); /*to last '/' */ else tailex=memrchr(oprefix+10,'/',extoptions-oprefix-10);/*skip Http:// and shttp:,start to last '/',between http-->? */ } if(tail!=NULL) { prefix_len=tail-oprefix+1;/*left '/'..*/ memcpy(prefix,oprefix,prefix_len); prefix[prefix_len]='\0'; } if(tailex!=NULL) { prefixex_len=tailex-oprefix+1;/*left '/'..*/ memcpy(prefixex,oprefix,prefixex_len); prefixex[prefixex_len]='\0'; } } memset(&tmpitem,0,sizeof(tmpitem)); tmpitem.seq=-1; av_log(NULL, AV_LOG_INFO, "m3u_format_parser get prefix=%s\n",prefix); av_log(NULL, AV_LOG_INFO, "m3u_format_parser get prefixex=%s\n",prefixex); #if 0 if(mgt->n_variants>0) { free_variant_list(mgt); } #endif while(m3u_format_get_line(s,line,1024)>=0) { if (url_interrupt_cb()) { return -1; } tmpitem.ktype = KEY_NONE; ret = m3u_parser_line(mgt,line,&tmpitem); if(ret>0) { struct list_item*item; int need_prefix=0; int size_file=tmpitem.file?(strlen(tmpitem.file)+32):4; tmpitem.start_time=start_time; if(tmpitem.file && (is_NET_URL(prefix)) && /*net protocal*/ !(is_NET_URL(tmpitem.file)))/*if item is not net protocal*/ { /*if m3u is http,item is not http,add prefix*/ need_prefix=1; size_file+=prefixex_len; } item=av_malloc(sizeof(struct list_item)+size_file); if(!item) return AVERROR(ENOMEM); memcpy(item,&tmpitem,sizeof(tmpitem)); item->file=NULL; if(tmpitem.file) { item->file=&item[1]; if(need_prefix) { if(tmpitem.file[0]=='/') { /*has '/',not need the dir */ strcpy(item->file,prefix); strcpy(item->file+prefix_len,tmpitem.file+1);/*don't copy two '/',we have left before*/ } else { /*no '/', some I save the full path frefix*/ if(!strncmp(prefixex,"shttps://",9)) { strcpy(item->file,"http"); strcpy(item->file+4,prefixex+6); strcpy(item->file+4+prefixex_len -6,tmpitem.file); } else { strcpy(item->file,prefixex); strcpy(item->file+prefixex_len,tmpitem.file); } } } else { strcpy(item->file,tmpitem.file); } } if(mgt->flags&KEY_FLAG&&NULL!= mgt->key_tmp&&mgt->key_tmp->is_have_key_file>0) { item->key_ctx = av_mallocz(sizeof(struct AES128KeyContext)); if(!item->key_ctx) { ret = AVERROR(ENOMEM); break; } memcpy(item->key_ctx->key,mgt->key_tmp->key,sizeof(item->key_ctx->key)); if(mgt->has_iv>0) { memcpy(item->key_ctx->iv,mgt->key_tmp->iv,sizeof(item->key_ctx->iv)); } else { //from applehttp.c av_log(NULL,AV_LOG_INFO,"Current item seq number:%d\n",item->seq); AV_WB32(item->key_ctx->iv + 12, item->seq); } item->ktype = mgt->key_tmp->key_type; } if(mgt->next_seq>=0 && item->seq<0) { item->seq=mgt->next_seq; mgt->next_seq++; } if(!(tmpitem.flags&INVALID_ITEM_FLAG)) { ret =list_test_and_add_item(mgt,item); if(ret==0) { getnum++; start_time+=item->duration; } else { av_free(item); mgt->next_seq--; } } if((item->flags &ENDLIST_FLAG) && (item->flags < (1<<12))) { mgt->have_list_end=1; break; } memset(&tmpitem,0,sizeof(tmpitem)); tmpitem.seq=-1; } else if(ret <0) { if(ret ==-(TRICK_LOGIC_BASE+0)&&(mgt->flags&KEY_FLAG)&&NULL!= mgt->key_tmp&&0==mgt->key_tmp->is_have_key_file) { //get key from server URLContext *uc; if (ffurl_open(&uc, mgt->key_tmp->key_from, AVIO_FLAG_READ) == 0) { if (ffurl_read_complete(uc, mgt->key_tmp->key, sizeof(mgt->key_tmp->key)) != sizeof(mgt->key_tmp->key)) { av_log(NULL, AV_LOG_ERROR, "Unable to read key file %s\n", mgt->key_tmp->key_from); } av_log(NULL,AV_LOG_INFO,"Just get aes key file from server\n"); mgt->key_tmp->is_have_key_file = 1; ffurl_close(uc); } else { av_log(NULL, AV_LOG_ERROR, "Unable to open key file %s\n", mgt->key_tmp->key_from); } memset(&tmpitem,0,sizeof(tmpitem)); continue; } if(ret ==-(TRICK_LOGIC_BASE+1)||ret ==-(TRICK_LOGIC_BASE+2)) { memset(&tmpitem,0,sizeof(tmpitem)); continue; } break; } else { if(tmpitem.flags&ALLOW_CACHE_FLAG) mgt->flags|=ALLOW_CACHE_FLAG; if(tmpitem.flags&INVALID_ITEM_FLAG) { av_log(NULL,AV_LOG_INFO,"just a trick,drop this item,seq number:%d\n",tmpitem.seq); continue; } } } if(mgt->key_tmp) { av_free(mgt->key_tmp); mgt->key_tmp = NULL; } mgt->file_size=AVERROR_STREAM_SIZE_NOTVALID; mgt->full_time=start_time; mgt->last_load_time = av_gettime(); av_log(NULL, AV_LOG_INFO, "m3u_format_parser end num =%d,fulltime=%.4lf\n",getnum,start_time); return getnum; }
static int m3u_parser_line(struct list_mgt *mgt,unsigned char *line,struct list_item*item) { unsigned char *p=line; int enditem=0; const char* ptr = NULL; int isLetvFlag = 0; while(*p==' ' && p!='\0' && p-line<1024) p++; if(*p!='#' && strlen(p)>0&&mgt->is_variant==0) { item->file=p; enditem=1; } else if(av_strstart(line,EXT_LETV_VER, &ptr)) { av_log(NULL,AV_LOG_INFO,"Get letv version: %s\n",ptr+1); mgt->flags|=IGNORE_SEQUENCE_FLAG; } else if(is_TAG(p,EXT_X_ENDLIST)) { item->flags|=ENDLIST_FLAG; enditem=1; } else if(is_TAG(p,EXTINF)) { double duration=0.00; parseDouble(p+8,&duration); av_log(NULL,AV_LOG_INFO,"Get item duration:%.4lf\n",duration); //sscanf(p+8,"%d",&duration);//skip strlen("#EXTINF:") if(duration>0) { item->flags|=DURATION_FLAG; item->duration=duration; } } else if (av_strstart(line, "#EXT-X-TARGETDURATION:", &ptr)) { mgt->target_duration = atoi(ptr); av_log(NULL, AV_LOG_INFO, "get target duration:%ld\n",mgt->target_duration); } else if(is_TAG(p,EXT_X_ALLOW_CACHE)) { item->flags|=ALLOW_CACHE_FLAG; } else if(is_TAG(p,EXT_X_MEDIA_SEQUENCE)&&!(mgt->flags&IGNORE_SEQUENCE_FLAG)) { int seq = -1; int ret=0; int slen = strlen("#EXT-X-MEDIA-SEQUENCE:"); ret=sscanf(p+slen,"%d",&seq); //skip strlen("#EXT-X-MEDIA-SEQUENCE:"); if(ret>0&&seq>=0&&seq>=mgt->next_seq) { if(mgt->start_seq<0) { mgt->start_seq=seq; if(seq>0) { mgt->flags |=REAL_STREAMING_FLAG; } } item->seq=seq; mgt->next_seq=seq+1; } else { item->seq = seq; item->flags|=INVALID_ITEM_FLAG; } } else if(av_strstart(p,"#EXT-X-STREAM-INF:",&ptr)) { struct variant_info info = {{0}}; ff_parse_key_value(p, (ff_parse_key_val_cb) handle_variant_args, &info); mgt->bandwidth = atoi(info.bandwidth); av_log(NULL, AV_LOG_INFO, "get a stream info,bandwidth:%d\n",mgt->bandwidth); mgt->is_variant = 1; return -(TRICK_LOGIC_BASE+1); } else if(av_strstart(p,"#EXT-X-KEY:",&ptr)) { struct key_info info = {{0}}; uint8_t iv[16] = ""; ff_parse_key_value(ptr, (ff_parse_key_val_cb) handle_key_args, &info); #if 0 av_log(NULL,AV_LOG_INFO,"==========start dump a aes key===========\n"); av_log(NULL,AV_LOG_INFO,"==========key location : %s\n",info.uri); av_log(NULL,AV_LOG_INFO,"==========key iv : %s\n",info.iv); av_log(NULL,AV_LOG_INFO,"==========key method : %s\n",info.method); av_log(NULL,AV_LOG_INFO,"==========end dump a aes key===========\n"); #endif struct encrypt_key_priv_t* key_priv_info = av_mallocz(sizeof(struct encrypt_key_priv_t)); if(NULL == key_priv_info) { av_log(NULL,AV_LOG_ERROR,"no memory for key_info\n"); return -1; } if(NULL!=mgt->key_tmp) { av_log(NULL,AV_LOG_INFO,"released old key info\n"); av_free(mgt->key_tmp); mgt->key_tmp = NULL; } enum KeyType key_type = KEY_NONE; if (!strcmp(info.method, "AES-128")) { key_type = KEY_AES_128; } if (!strncmp(info.iv, "0x", 2) || !strncmp(info.iv, "0X", 2)) { ff_hex_to_data(iv, info.iv + 2); mgt->has_iv = 1; } else { mgt->has_iv = 0; } if(key_type ==KEY_AES_128) { key_priv_info->key_type = key_type; if(mgt->has_iv>0) { memcpy(key_priv_info->iv,iv,sizeof(key_priv_info->iv)); } memcpy(key_priv_info->key_from, "s", 1); memcpy(key_priv_info->key_from+1, info.uri, MAX_URL_SIZE-1); av_log(NULL,AV_LOG_INFO,"aes key location,before:%s,after:%s\n",info.uri,key_priv_info->key_from); key_priv_info->is_have_key_file = 0; mgt->key_tmp = key_priv_info; mgt->flags |= KEY_FLAG; return -(TRICK_LOGIC_BASE+0); } else { av_log(NULL,AV_LOG_INFO,"just only support aes key\n"); av_free(key_priv_info); key_priv_info = NULL; } } else { if(mgt->is_variant>0) { if(av_strstart(p,"http",&ptr)) { if (!new_variant(mgt, mgt->bandwidth, p, NULL)) { free_variant_list(mgt); return -1; } } else { if (!new_variant(mgt, mgt->bandwidth, p, mgt->prefix)) { free_variant_list(mgt); return -1; } } mgt->is_variant = 0; mgt->bandwidth = 0; return -(TRICK_LOGIC_BASE+2); } return 0; } return enditem; }
static int applehttp_read_header(AVFormatContext *s, AVFormatParameters *ap) { AppleHTTPContext *c = s->priv_data; int ret = 0, i, j, stream_offset = 0; if ((ret = parse_playlist(c, s->filename, NULL, s->pb)) < 0) goto fail; if (c->n_variants == 0) { av_log(NULL, AV_LOG_WARNING, "Empty playlist\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\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; } /* Open the demuxer for each variant */ for (i = 0; i < c->n_variants; i++) { struct variant *v = c->variants[i]; AVInputFormat *in_fmt = NULL; char bitrate_str[20]; if (v->n_segments == 0) continue; 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; 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); v->pb.seekable = 0; ret = av_probe_input_buffer(&v->pb, &in_fmt, v->segments[0]->url, NULL, 0, 0); if (ret < 0) goto fail; ret = av_open_input_stream(&v->ctx, &v->pb, v->segments[0]->url, in_fmt, NULL); if (ret < 0) goto fail; 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, i); if (!st) { ret = AVERROR(ENOMEM); goto fail; } avcodec_copy_context(st->codec, v->ctx->streams[j]->codec); av_metadata_set2(&st->metadata, "variant_bitrate", bitrate_str, 0); } stream_offset += v->ctx->nb_streams; } c->first_packet = 1; return 0; fail: free_variant_list(c); return ret; }
static int m3u_parser_line(struct list_mgt *mgt,unsigned char *line,struct list_item*item) { unsigned char *p=line; int enditem=0; const char* ptr = NULL; while(*p==' ' && p!='\0' && p-line<1024) p++; if(*p!='#' && strlen(p)>0) { item->file=p; enditem=1; }else if(is_TAG(p,EXT_X_ENDLIST)){ item->flags=ENDLIST_FLAG; enditem=1; }else if(is_TAG(p,EXTINF)){ int duration=0; sscanf(p+8,"%d",&duration);//skip strlen("#EXTINF:") if(duration>0){ item->flags|=DURATION_FLAG; item->duration=duration; } }else if(is_TAG(p,EXT_X_ALLOW_CACHE)){ item->flags|=ALLOW_CACHE_FLAG; }else if(is_TAG(p,EXT_X_MEDIA_SEQUENCE)){ int seq = -1; int slen = strlen("#EXT-X-MEDIA-SEQUENCE:"); sscanf(p+slen,"%d",&seq); //skip strlen("#EXT-X-MEDIA-SEQUENCE:"); if(seq>0){ if(seq>mgt->seq){ mgt->seq = seq; mgt->flags |=REAL_STREAMING_FLAG; av_log(NULL, AV_LOG_INFO, "get new sequence number:%ld\n",seq); }else{ //av_log(NULL, AV_LOG_INFO, "drop this list,sequence number:%ld\n",seq); return 0; } }else{ mgt->seq = seq; av_log(NULL, AV_LOG_INFO, "get a invalid sequence number:%d\n",seq); } } else if(is_TAG(p,EXT_X_STREAM_INF)){ struct variant_info info = {{0}}; ff_parse_key_value(p, (ff_parse_key_val_cb) handle_variant_args, &info); mgt->bandwidth = atoi(info.bandwidth); av_log(NULL, AV_LOG_INFO, "get a stream info,bandwidth:%d\n",mgt->bandwidth); mgt->is_variant = 1; return -(TRICK_LOGIC_BASE+1); } else if(av_strstart(p,"#EXT-X-KEY:",&ptr)){ struct key_info info = {{0}}; uint8_t iv[16] = ""; ff_parse_key_value(ptr, (ff_parse_key_val_cb) handle_key_args, &info); av_log(NULL,AV_LOG_INFO,"==========start dump a aes key===========\n"); av_log(NULL,AV_LOG_INFO,"==========key location : %s\n",info.uri); av_log(NULL,AV_LOG_INFO,"==========key iv : %s\n",info.iv); av_log(NULL,AV_LOG_INFO,"==========key method : %s\n",info.method); av_log(NULL,AV_LOG_INFO,"==========end dump a aes key===========\n"); struct encrypt_key_priv_t* key_priv_info = av_mallocz(sizeof(struct encrypt_key_priv_t)); if(NULL == key_priv_info){ av_log(NULL,AV_LOG_ERROR,"no memory for key_info\n"); return -1; } if(NULL!=mgt->key_tmp){ av_log(NULL,AV_LOG_INFO,"released old key info\n"); av_free(mgt->key_tmp); mgt->key_tmp = NULL; } enum KeyType key_type = KEY_NONE; if (!strcmp(info.method, "AES-128")){ key_type = KEY_AES_128; } if (!strncmp(info.iv, "0x", 2) || !strncmp(info.iv, "0X", 2)) { ff_hex_to_data(iv, info.iv + 2); mgt->has_iv = 1; }else{ mgt->has_iv = 0; } if(key_type ==KEY_AES_128){ key_priv_info->key_type = key_type; if(mgt->has_iv>0){ memcpy(key_priv_info->iv,iv,sizeof(key_priv_info->iv)); } av_log(NULL,AV_LOG_INFO,"aes key location : %s\n",info.uri); av_strlcpy(key_priv_info->key_from, info.uri, sizeof(key_priv_info->key_from)); key_priv_info->is_have_key_file = 0; mgt->key_tmp = key_priv_info; mgt->flags |= KEY_FLAG; return -(TRICK_LOGIC_BASE+0); }else{ av_log(NULL,AV_LOG_INFO,"just only support aes key\n"); av_free(key_priv_info); key_priv_info = NULL; } } else{ if(mgt->is_variant>0){ if (!new_variant(mgt, mgt->bandwidth, p, mgt->prefix)) { free_variant_list(mgt); return -1; } mgt->is_variant = 0; mgt->bandwidth = 0; return -(TRICK_LOGIC_BASE+2); } return 0; } return enditem; }
static int applehttp_read_header(AVFormatContext *s, AVFormatParameters *ap) { AppleHTTPContext *c = s->priv_data; int ret = 0, i, j, stream_offset = 0; if ((ret = parse_playlist(c, s->filename, NULL, s->pb)) < 0) goto fail; if (c->n_variants == 0) { av_log(NULL, AV_LOG_WARNING, "Empty playlist\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\n"); ret = AVERROR_EOF; goto fail; } /* If this isn't a live stream, calculate the total duration of the * stream. */ if (c->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; } c->min_end_seq = INT_MAX; /* Open the demuxer for each variant */ for (i = 0; i < c->n_variants; i++) { struct variant *v = c->variants[i]; if (v->n_segments == 0) continue; c->max_start_seq = FFMAX(c->max_start_seq, v->start_seq_no); c->min_end_seq = FFMIN(c->min_end_seq, v->start_seq_no + v->n_segments); ret = av_open_input_file(&v->ctx, v->segments[0]->url, NULL, 0, NULL); if (ret < 0) goto fail; url_fclose(v->ctx->pb); v->ctx->pb = NULL; v->stream_offset = stream_offset; /* Create new AVStreams for each stream in this variant */ for (j = 0; j < v->ctx->nb_streams; j++) { AVStream *st = av_new_stream(s, i); if (!st) { ret = AVERROR(ENOMEM); goto fail; } avcodec_copy_context(st->codec, v->ctx->streams[j]->codec); } stream_offset += v->ctx->nb_streams; } c->last_packet_dts = AV_NOPTS_VALUE; c->cur_seq_no = c->max_start_seq; /* If this is a live stream with more than 3 segments, start at the * third last segment. */ if (!c->finished && c->min_end_seq - c->max_start_seq > 3) c->cur_seq_no = c->min_end_seq - 2; return 0; fail: free_variant_list(c); return ret; }
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 int hls_read_header(AVFormatContext *s) { URLContext *u = (s->flags & AVFMT_FLAG_CUSTOM_IO) ? NULL : s->pb->opaque; HLSContext *c = s->priv_data; int ret = 0, i, j, stream_offset = 0; c->interrupt_callback = &s->interrupt_callback; // if the URL context is good, read important options we must broker later if (u && u->prot->priv_data_class) { // get the previous user agent & set back to null if string size is zero av_freep(&c->user_agent); av_opt_get(u->priv_data, "user-agent", 0, (uint8_t**)&(c->user_agent)); if (c->user_agent && !strlen(c->user_agent)) av_freep(&c->user_agent); // get the previous cookies & set back to null if string size is zero av_freep(&c->cookies); av_opt_get(u->priv_data, "cookies", 0, (uint8_t**)&(c->cookies)); if (c->cookies && !strlen(c->cookies)) av_freep(&c->cookies); // get the previous headers & set back to null if string size is zero av_freep(&c->headers); av_opt_get(u->priv_data, "headers", 0, (uint8_t**)&(c->headers)); if (c->headers && !strlen(c->headers)) av_freep(&c->headers); } if ((ret = parse_playlist(c, s->filename, NULL, s->pb)) < 0) goto fail; 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; } /* 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->n_segments == 0) continue; if (!(pls->ctx = avformat_alloc_context())) { ret = AVERROR(ENOMEM); goto fail; } pls->index = i; pls->needed = 1; pls->parent = s; /* If this is a live stream with more than 3 segments, start at the * third last segment. */ pls->cur_seq_no = pls->start_seq_no; if (!pls->finished && pls->n_segments > 3) pls->cur_seq_no = pls->start_seq_no + pls->n_segments - 3; pls->read_buffer = av_malloc(INITIAL_BUFFER_SIZE); 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->stream_offset = stream_offset; ret = avformat_open_input(&pls->ctx, pls->segments[0]->url, in_fmt, NULL); if (ret < 0) goto fail; pls->ctx->ctx_flags &= ~AVFMTCTX_NOHEADER; ret = avformat_find_stream_info(pls->ctx, NULL); if (ret < 0) goto fail; /* Create new AVStreams for each stream in this playlist */ for (j = 0; j < pls->ctx->nb_streams; j++) { AVStream *st = avformat_new_stream(s, NULL); AVStream *ist = pls->ctx->streams[j]; if (!st) { ret = AVERROR(ENOMEM); goto fail; } st->id = i; avpriv_set_pts_info(st, ist->pts_wrap_bits, ist->time_base.num, ist->time_base.den); avcodec_copy_context(st->codec, pls->ctx->streams[j]->codec); } stream_offset += pls->ctx->nb_streams; } /* Create a program for each variant */ for (i = 0; i < c->n_variants; i++) { struct variant *v = c->variants[i]; char bitrate_str[20]; AVProgram *program; snprintf(bitrate_str, sizeof(bitrate_str), "%d", v->bandwidth); program = av_new_program(s, i); if (!program) goto fail; av_dict_set(&program->metadata, "variant_bitrate", bitrate_str, 0); for (j = 0; j < v->n_playlists; j++) { struct playlist *pls = v->playlists[j]; int is_shared = playlist_in_multiple_variants(c, pls); int k; for (k = 0; k < pls->ctx->nb_streams; k++) { struct AVStream *st = s->streams[pls->stream_offset + k]; ff_program_add_stream_index(s, i, pls->stream_offset + k); /* Set variant_bitrate for streams unique to this variant */ if (!is_shared && v->bandwidth) av_dict_set(&st->metadata, "variant_bitrate", bitrate_str, 0); } } } c->first_packet = 1; c->first_timestamp = AV_NOPTS_VALUE; c->seek_timestamp = AV_NOPTS_VALUE; return 0; fail: free_playlist_list(c); free_variant_list(c); return ret; }