static int parse_playlist(HLSContext *c, const char *url, struct variant *var, AVIOContext *in) { int ret = 0, duration = 0, is_segment = 0, is_variant = 0, bandwidth = 0; enum KeyType key_type = KEY_NONE; uint8_t iv[16] = ""; int has_iv = 0; char key[MAX_URL_SIZE] = ""; char line[1024]; const char *ptr; int close_in = 0; if (!in) { int is_redirected = 0; URLContext *h = NULL; AVDictionary *opts = NULL; close_in = 1; /* Some HLS servers dont like being sent the range header */ av_dict_set(&opts, "seekable", "0", 0); ret = avio_open2(&in, url, AVIO_FLAG_READ, c->interrupt_callback, &opts); av_dict_free(&opts); if (ret < 0) return ret; h = (URLContext *) in->opaque; ff_http_get_location_changed(h, &is_redirected); if ( is_redirected ) { ff_http_get_new_location(h, var->url); av_log(NULL, AV_LOG_WARNING, "the var url changed to %s \n", var->url); } } read_chomp_line(in, line, sizeof(line)); if (strcmp(line, "#EXTM3U")) { ret = AVERROR_INVALIDDATA; goto fail; } if (var) { free_segment_list(var); var->finished = 0; } while (!url_feof(in)) { read_chomp_line(in, line, sizeof(line)); if (av_strstart(line, "#EXT-X-STREAM-INF:", &ptr)) { struct variant_info info = {{0}}; is_variant = 1; ff_parse_key_value(ptr, (ff_parse_key_val_cb) handle_variant_args, &info); bandwidth = atoi(info.bandwidth); } else if (av_strstart(line, "#EXT-X-KEY:", &ptr)) { struct key_info info = {{0}}; ff_parse_key_value(ptr, (ff_parse_key_val_cb) handle_key_args, &info); key_type = KEY_NONE; has_iv = 0; 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); has_iv = 1; } av_strlcpy(key, info.uri, sizeof(key)); } else if (av_strstart(line, "#EXT-X-TARGETDURATION:", &ptr)) { if (!var) { var = new_variant(c, 0, url, NULL); if (!var) { ret = AVERROR(ENOMEM); goto fail; } } var->target_duration = atoi(ptr); } else if (av_strstart(line, "#EXT-X-MEDIA-SEQUENCE:", &ptr)) { if (!var) { var = new_variant(c, 0, url, NULL); if (!var) { ret = AVERROR(ENOMEM); goto fail; } } var->start_seq_no = atoi(ptr); } else if (av_strstart(line, "#EXT-X-ENDLIST", &ptr)) { if (var) var->finished = 1; } else if (av_strstart(line, "#EXTINF:", &ptr)) { is_segment = 1; duration = atoi(ptr); } else if (av_strstart(line, "#", NULL)) { continue; } else if (line[0]) { if (is_variant) { if (!new_variant(c, bandwidth, line, url)) { ret = AVERROR(ENOMEM); goto fail; } is_variant = 0; bandwidth = 0; } if (is_segment) { struct segment *seg; if (!var) { var = new_variant(c, 0, url, NULL); if (!var) { ret = AVERROR(ENOMEM); goto fail; } } seg = av_malloc(sizeof(struct segment)); if (!seg) { ret = AVERROR(ENOMEM); goto fail; } seg->duration = duration; seg->key_type = key_type; if (has_iv) { memcpy(seg->iv, iv, sizeof(iv)); } else { int seq = var->start_seq_no + var->n_segments; memset(seg->iv, 0, sizeof(seg->iv)); AV_WB32(seg->iv + 12, seq); } ff_make_absolute_url(seg->key, sizeof(seg->key), url, key); ff_make_absolute_url(seg->url, sizeof(seg->url), url, line); dynarray_add(&var->segments, &var->n_segments, seg); is_segment = 0; } } } if (var) var->last_load_time = av_gettime(); fail: if (close_in) avio_close(in); 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; 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 parse_playlist(HLSContext *c, const char *url, struct variant *var, AVIOContext *in) { int ret = 0, is_segment = 0, is_variant = 0, bandwidth = 0; int64_t duration = 0; enum KeyType key_type = KEY_NONE; uint8_t iv[16] = ""; int has_iv = 0; char key[MAX_URL_SIZE] = ""; char line[1024]; const char *ptr; int close_in = 0; uint8_t *new_url = NULL; if (!in) { ret = open_in(c, &in, url); if (ret < 0) return ret; close_in = 1; } if (av_opt_get(in, "location", AV_OPT_SEARCH_CHILDREN, &new_url) >= 0) url = new_url; read_chomp_line(in, line, sizeof(line)); if (strcmp(line, "#EXTM3U")) { ret = AVERROR_INVALIDDATA; goto fail; } if (var) { free_segment_list(var); var->finished = 0; } while (!in->eof_reached) { read_chomp_line(in, line, sizeof(line)); if (av_strstart(line, "#EXT-X-STREAM-INF:", &ptr)) { struct variant_info info = {{0}}; is_variant = 1; ff_parse_key_value(ptr, (ff_parse_key_val_cb) handle_variant_args, &info); bandwidth = atoi(info.bandwidth); } else if (av_strstart(line, "#EXT-X-KEY:", &ptr)) { struct key_info info = {{0}}; ff_parse_key_value(ptr, (ff_parse_key_val_cb) handle_key_args, &info); key_type = KEY_NONE; has_iv = 0; 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); has_iv = 1; } av_strlcpy(key, info.uri, sizeof(key)); } else if (av_strstart(line, "#EXT-X-TARGETDURATION:", &ptr)) { if (!var) { var = new_variant(c, 0, url, NULL); if (!var) { ret = AVERROR(ENOMEM); goto fail; } } var->target_duration = atoi(ptr) * AV_TIME_BASE; } else if (av_strstart(line, "#EXT-X-MEDIA-SEQUENCE:", &ptr)) { if (!var) { var = new_variant(c, 0, url, NULL); if (!var) { ret = AVERROR(ENOMEM); goto fail; } } var->start_seq_no = atoi(ptr); } else if (av_strstart(line, "#EXT-X-ENDLIST", &ptr)) { if (var) var->finished = 1; } else if (av_strstart(line, "#EXTINF:", &ptr)) { is_segment = 1; duration = atof(ptr) * AV_TIME_BASE; } else if (av_strstart(line, "#", NULL)) { continue; } else if (line[0]) { if (is_variant) { if (!new_variant(c, bandwidth, line, url)) { ret = AVERROR(ENOMEM); goto fail; } is_variant = 0; bandwidth = 0; } if (is_segment) { struct segment *seg; if (!var) { var = new_variant(c, 0, url, NULL); if (!var) { ret = AVERROR(ENOMEM); goto fail; } } seg = av_malloc(sizeof(struct segment)); if (!seg) { ret = AVERROR(ENOMEM); goto fail; } seg->duration = duration; seg->key_type = key_type; if (has_iv) { memcpy(seg->iv, iv, sizeof(iv)); } else { int seq = var->start_seq_no + var->n_segments; memset(seg->iv, 0, sizeof(seg->iv)); AV_WB32(seg->iv + 12, seq); } ff_make_absolute_url(seg->key, sizeof(seg->key), url, key); ff_make_absolute_url(seg->url, sizeof(seg->url), url, line); dynarray_add(&var->segments, &var->n_segments, seg); is_segment = 0; } } } if (var) var->last_load_time = av_gettime_relative(); fail: av_free(new_url); if (close_in) avio_close(in); 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 parse_playlist(AppleHTTPContext *c, const char *url, struct variant *var, ByteIOContext *in) { int ret = 0, duration = 0, is_segment = 0, is_variant = 0, bandwidth = 0; char line[1024]; const char *ptr; int close_in = 0; if (!in) { close_in = 1; if ((ret = url_fopen(&in, url, URL_RDONLY)) < 0) return ret; } read_chomp_line(in, line, sizeof(line)); if (strcmp(line, "#EXTM3U")) { ret = AVERROR_INVALIDDATA; goto fail; } if (var) free_segment_list(var); c->finished = 0; while (!url_feof(in)) { read_chomp_line(in, line, sizeof(line)); if (av_strstart(line, "#EXT-X-STREAM-INF:", &ptr)) { struct variant_info info = {{0}}; is_variant = 1; ff_parse_key_value(ptr, (ff_parse_key_val_cb) handle_variant_args, &info); bandwidth = atoi(info.bandwidth); } else if (av_strstart(line, "#EXT-X-TARGETDURATION:", &ptr)) { c->target_duration = atoi(ptr); } else if (av_strstart(line, "#EXT-X-MEDIA-SEQUENCE:", &ptr)) { if (!var) { var = new_variant(c, 0, url, NULL); if (!var) { ret = AVERROR(ENOMEM); goto fail; } } var->start_seq_no = atoi(ptr); } else if (av_strstart(line, "#EXT-X-ENDLIST", &ptr)) { c->finished = 1; } else if (av_strstart(line, "#EXTINF:", &ptr)) { is_segment = 1; duration = atoi(ptr); } else if (av_strstart(line, "#", NULL)) { continue; } else if (line[0]) { if (is_variant) { if (!new_variant(c, bandwidth, line, url)) { ret = AVERROR(ENOMEM); goto fail; } is_variant = 0; bandwidth = 0; } if (is_segment) { struct segment *seg; if (!var) { var = new_variant(c, 0, url, NULL); if (!var) { ret = AVERROR(ENOMEM); goto fail; } } seg = av_malloc(sizeof(struct segment)); if (!seg) { ret = AVERROR(ENOMEM); goto fail; } seg->duration = duration; make_absolute_url(seg->url, sizeof(seg->url), url, line); dynarray_add(&var->segments, &var->n_segments, seg); is_segment = 0; } } } c->last_load_time = av_gettime(); fail: if (close_in) url_fclose(in); return ret; }
static int parse_playlist(HLSContext *c, const char *url, struct variant *var, AVIOContext *in) { char* resolution; int ret = 0, is_segment = 0, is_variant = 0, bandwidth = 0; double duration = 0.0; enum KeyType key_type = KEY_NONE; uint8_t iv[16] = ""; int has_iv = 0; char key[MAX_URL_SIZE] = ""; char line[1024]; const char *ptr; int close_in = 0; if (!in) { close_in = 1; if ((ret = avio_open2(&in, url, AVIO_FLAG_READ, c->interrupt_callback, NULL)) < 0) return ret; } read_chomp_line(in, line, sizeof(line)); if (strcmp(line, "#EXTM3U")) { ret = AVERROR_INVALIDDATA; goto fail; } if (var) { free_segment_list(var); var->finished = 0; } while (!url_feof(in)) { static int a = 0; read_chomp_line(in, line, sizeof(line)); if (av_strstart(line, "#EXT-X-STREAM-INF:", &ptr)) { struct variant_info info = {{0}}; is_variant = 1; ff_parse_key_value(ptr, (ff_parse_key_val_cb) handle_variant_args, &info); bandwidth = atoi(info.bandwidth); resolution = info.resolution; for(uint32_t i=0; i<20; i++) { if(info.resolution[i] == 'x') { memcpy(info.width, info.resolution, i); memcpy(info.height, info.resolution+i+1, 20-i); c->ctx->width = atoi(info.width); c->ctx->height = atoi(info.height); break; } } LOGI("resolution = %s, width = %s, height = %s",info.resolution, info.width, info.height); } else if (av_strstart(line, "#EXT-X-KEY:", &ptr)) { struct key_info info = {{0}}; ff_parse_key_value(ptr, (ff_parse_key_val_cb) handle_key_args, &info); key_type = KEY_NONE; has_iv = 0; 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); has_iv = 1; } av_strlcpy(key, info.uri, sizeof(key)); } else if (av_strstart(line, "#EXT-X-TARGETDURATION:", &ptr)) { if (!var) { var = new_variant(c, 0, url, NULL); if (!var) { ret = AVERROR(ENOMEM); goto fail; } } var->target_duration = atof(ptr); } else if (av_strstart(line, "#EXT-X-MEDIA-SEQUENCE:", &ptr)) { if (!var) { var = new_variant(c, 0, url, NULL); if (!var) { ret = AVERROR(ENOMEM); goto fail; } } var->start_seq_no = atoi(ptr); // LOGV("EXT-X-MEDIA-SEQUENCE = %d", var->start_seq_no); } else if (av_strstart(line, "#EXT-X-ENDLIST", &ptr)) { if (var) var->finished = 1; // static int a = 0; // FILE *fp = fopen( "/mnt/sdcard/Die_Hls.txt", "wta+"); // fprintf(fp, "Line = %d, Times = %d, recive EXT-X-ENDLIST", __LINE__, a); // fclose(fp); // a++; } else if (av_strstart(line, "#EXTINF:", &ptr)) { is_segment = 1; duration = atof(ptr); } else if (av_strstart(line, "#", NULL)) { continue; } else if (line[0]) { if (is_variant) { if (!new_variant(c, bandwidth, line, url)) { ret = AVERROR(ENOMEM); goto fail; } is_variant = 0; bandwidth = 0; } if (is_segment) { struct segment *seg; if (!var) { var = new_variant(c, 0, url, NULL); if (!var) { ret = AVERROR(ENOMEM); goto fail; } } seg = av_malloc(sizeof(struct segment)); if (!seg) { ret = AVERROR(ENOMEM); goto fail; } seg->duration = duration; seg->key_type = key_type; if (has_iv) { memcpy(seg->iv, iv, sizeof(iv)); } else { int seq = var->start_seq_no + var->n_segments; memset(seg->iv, 0, sizeof(seg->iv)); AV_WB32(seg->iv + 12, seq); } ff_make_absolute_url(seg->key, sizeof(seg->key), url, key); ff_make_absolute_url(seg->url, sizeof(seg->url), url, line); dynarray_add(&var->segments, &var->n_segments, seg); is_segment = 0; } } } if (var) var->last_load_time = av_gettime(); fail: if (close_in) avio_close(in); return ret; }
static int parse_playlist(HLSContext *c, const char *url, struct variant *var, AVIOContext *in) { int ret = 0, duration = 0, is_segment = 0, is_variant = 0, bandwidth = 0; enum KeyType key_type = KEY_NONE; uint8_t iv[16] = ""; int has_iv = 0; char key[MAX_URL_SIZE] = ""; char line[1024]; const char *ptr; int close_in = 0; const char *locattion=NULL; int totaltime=0; int isdiscontinued=0; if (!in) { close_in = 1; #ifdef AVIO_OPEN2 if ((ret = avio_open2(&in, url, AVIO_FLAG_READ | URL_NO_LP_BUFFER,c->interrupt_callback, NULL)) < 0) return ret; #else if ((ret = avio_open(&in, url, AVIO_FLAG_READ | URL_NO_LP_BUFFER)) < 0){ av_log(NULL, AV_LOG_ERROR, "parse_playlist :open [%s]failed=%d\n",url,ret); return ret; } #endif } if(in->reallocation) locattion=in->reallocation; else locattion=url; read_chomp_line(in, line, sizeof(line)); if (strcmp(line, "#EXTM3U")) { av_log(NULL, AV_LOG_ERROR, "not a valid m3u file,first line is [%s]\n",line); ret = AVERROR_INVALIDDATA; goto fail; } if (var) { free_segment_list(var); var->finished = 0; } while (1) { int sret; line[0]=0; if(url_interrupt_cb()) break; sret=read_chomp_line(in, line, sizeof(line)); if(sret<0){ av_log(NULL, AV_LOG_ERROR, "read_chomp_line end,ret=%d,var=%x,c->n_variants=%x\n",sret,var,c->n_variants); ret=(var!=NULL ||c->n_variants>0)?0:sret; break; } av_log(NULL, AV_LOG_INFO+1, "parse_playlist :[%s]\n",line); if (av_strstart(line, "#EXT-X-STREAM-INF:", &ptr)) { struct variant_info info = {{0}}; is_variant = 1; ff_parse_key_value(ptr, (ff_parse_key_val_cb) handle_variant_args, &info); bandwidth = atoi(info.bandwidth); } else if (av_strstart(line, "#EXT-X-KEY:", &ptr)) { struct key_info info = {{0}}; ff_parse_key_value(ptr, (ff_parse_key_val_cb) handle_key_args, &info); key_type = KEY_NONE; has_iv = 0; 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); has_iv = 1; } av_strlcpy(key, info.uri, sizeof(key)); } else if (av_strstart(line, "#EXT-X-TARGETDURATION:", &ptr)) { if (!var) { var = new_variant(c, 0, url, NULL); if (!var) { ret = AVERROR(ENOMEM); goto fail; } } var->target_duration = atoi(ptr); } else if (av_strstart(line, "#EXT-X-MEDIA-SEQUENCE:", &ptr)) { if (!var) { var = new_variant(c, 0, url, NULL); if (!var) { ret = AVERROR(ENOMEM); goto fail; } } var->start_seq_no = atoi(ptr); } else if (av_strstart(line, "#EXT-X-ENDLIST", &ptr)) { if (var) var->finished = 1; } else if (av_strstart(line, "#EXTINF:", &ptr)) { is_segment = 1; duration = atoi(ptr); } else if (av_strstart(line, "#EXT-X-DISCONTINUITY", &ptr)) { isdiscontinued = 1; } else if (av_strstart(line, "#", NULL)) { continue; } else if (line[0]) { if (is_variant) { if (!new_variant(c, bandwidth, line, locattion)) { ret = AVERROR(ENOMEM); goto fail; } is_variant = 0; bandwidth = 0; } if (is_segment) { struct segment *seg; if (!var) { var = new_variant(c, 0, url, NULL); if (!var) { ret = AVERROR(ENOMEM); goto fail; } } seg = av_malloc(sizeof(struct segment)); if (!seg) { ret = AVERROR(ENOMEM); goto fail; } seg->duration = duration; seg->key_type = key_type; seg->seg_starttime=totaltime; seg->flags=DISCONTINUE_FLAG; totaltime+=duration; if (has_iv) { memcpy(seg->iv, iv, sizeof(iv)); } else { int seq = var->start_seq_no + var->n_segments; memset(seg->iv, 0, sizeof(seg->iv)); AV_WB32(seg->iv + 12, seq); } ff_make_absolute_url(seg->key, sizeof(seg->key), url, key); ff_make_absolute_url(seg->url, sizeof(seg->url), locattion, line); dynarray_add(&var->segments, &var->n_segments, seg); is_segment = 0; } } } if (var){ var->last_load_time = av_gettime(); var->total_time_s=totaltime; } fail: if (close_in) avio_close(in); return ret; }
static int parse_playlist(HLSContext *c, const char *url, struct playlist *pls, AVIOContext *in) { int ret = 0, is_segment = 0, is_variant = 0, bandwidth = 0; int64_t duration = 0; enum KeyType key_type = KEY_NONE; uint8_t iv[16] = ""; int has_iv = 0; char key[MAX_URL_SIZE] = ""; char line[MAX_URL_SIZE]; const char *ptr; int close_in = 0; uint8_t *new_url = NULL; if (!in) { AVDictionary *opts = NULL; close_in = 1; /* Some HLS servers don't like being sent the range header */ av_dict_set(&opts, "seekable", "0", 0); // broker prior HTTP options that should be consistent across requests av_dict_set(&opts, "user-agent", c->user_agent, 0); av_dict_set(&opts, "cookies", c->cookies, 0); av_dict_set(&opts, "headers", c->headers, 0); ret = avio_open2(&in, url, AVIO_FLAG_READ, c->interrupt_callback, &opts); av_dict_free(&opts); if (ret < 0) return ret; } if (av_opt_get(in, "location", AV_OPT_SEARCH_CHILDREN, &new_url) >= 0) url = new_url; read_chomp_line(in, line, sizeof(line)); if (strcmp(line, "#EXTM3U")) { ret = AVERROR_INVALIDDATA; goto fail; } if (pls) { free_segment_list(pls); pls->finished = 0; } while (!url_feof(in)) { read_chomp_line(in, line, sizeof(line)); if (av_strstart(line, "#EXT-X-STREAM-INF:", &ptr)) { struct variant_info info = {{0}}; is_variant = 1; ff_parse_key_value(ptr, (ff_parse_key_val_cb) handle_variant_args, &info); bandwidth = atoi(info.bandwidth); } else if (av_strstart(line, "#EXT-X-KEY:", &ptr)) { struct key_info info = {{0}}; ff_parse_key_value(ptr, (ff_parse_key_val_cb) handle_key_args, &info); key_type = KEY_NONE; has_iv = 0; 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); has_iv = 1; } av_strlcpy(key, info.uri, sizeof(key)); } else if (av_strstart(line, "#EXT-X-TARGETDURATION:", &ptr)) { if (!pls) { if (!new_variant(c, 0, url, NULL)) { ret = AVERROR(ENOMEM); goto fail; } pls = c->playlists[c->n_playlists - 1]; } pls->target_duration = atoi(ptr) * AV_TIME_BASE; } else if (av_strstart(line, "#EXT-X-MEDIA-SEQUENCE:", &ptr)) { if (!pls) { if (!new_variant(c, 0, url, NULL)) { ret = AVERROR(ENOMEM); goto fail; } pls = c->playlists[c->n_playlists - 1]; } pls->start_seq_no = atoi(ptr); } else if (av_strstart(line, "#EXT-X-ENDLIST", &ptr)) { if (pls) pls->finished = 1; } else if (av_strstart(line, "#EXTINF:", &ptr)) { is_segment = 1; duration = atof(ptr) * AV_TIME_BASE; } else if (av_strstart(line, "#", NULL)) { continue; } else if (line[0]) { if (is_variant) { if (!new_variant(c, bandwidth, line, url)) { ret = AVERROR(ENOMEM); goto fail; } is_variant = 0; bandwidth = 0; } if (is_segment) { struct segment *seg; if (!pls) { if (!new_variant(c, 0, url, NULL)) { ret = AVERROR(ENOMEM); goto fail; } pls = c->playlists[c->n_playlists - 1]; } seg = av_malloc(sizeof(struct segment)); if (!seg) { ret = AVERROR(ENOMEM); goto fail; } seg->duration = duration; seg->key_type = key_type; if (has_iv) { memcpy(seg->iv, iv, sizeof(iv)); } else { int seq = pls->start_seq_no + pls->n_segments; memset(seg->iv, 0, sizeof(seg->iv)); AV_WB32(seg->iv + 12, seq); } ff_make_absolute_url(seg->key, sizeof(seg->key), url, key); ff_make_absolute_url(seg->url, sizeof(seg->url), url, line); dynarray_add(&pls->segments, &pls->n_segments, seg); is_segment = 0; } } } if (pls) pls->last_load_time = av_gettime(); fail: av_free(new_url); if (close_in) avio_close(in); return ret; }