static int find_expected_header(AVCodecContext *c, int size, int key_frame, uint8_t out[64]) { int sample_rate = c->sample_rate; if (size > 4096) return 0; AV_WB24(out, 1); if (c->codec_id == AV_CODEC_ID_MPEG4) { if (key_frame) { return 3; } else { out[3] = 0xB6; return 4; } } else if (c->codec_id == AV_CODEC_ID_MPEG1VIDEO || c->codec_id == AV_CODEC_ID_MPEG2VIDEO) { return 3; } else if (c->codec_id == AV_CODEC_ID_H264) { return 3; } else if (c->codec_id == AV_CODEC_ID_MP3 || c->codec_id == AV_CODEC_ID_MP2) { int lsf, mpeg25, sample_rate_index, bitrate_index, frame_size; int layer = c->codec_id == AV_CODEC_ID_MP3 ? 3 : 2; unsigned int header = 0xFFF00000; lsf = sample_rate < (24000 + 32000) / 2; mpeg25 = sample_rate < (12000 + 16000) / 2; sample_rate <<= lsf + mpeg25; if (sample_rate < (32000 + 44100) / 2) sample_rate_index = 2; else if (sample_rate < (44100 + 48000) / 2) sample_rate_index = 0; else sample_rate_index = 1; sample_rate = avpriv_mpa_freq_tab[sample_rate_index] >> (lsf + mpeg25); for (bitrate_index = 2; bitrate_index < 30; bitrate_index++) { frame_size = avpriv_mpa_bitrate_tab[lsf][layer - 1][bitrate_index >> 1]; frame_size = (frame_size * 144000) / (sample_rate << lsf) + (bitrate_index & 1); if (frame_size == size) break; } header |= (!lsf) << 19; header |= (4 - layer) << 17; header |= 1 << 16; //no crc AV_WB32(out, header); if (size <= 0) return 2; //we guess there is no crc, if there is one the user clearly does not care about overhead if (bitrate_index == 30) return -1; //something is wrong ... header |= (bitrate_index >> 1) << 12; header |= sample_rate_index << 10; header |= (bitrate_index & 1) << 9; return 2; //FIXME actually put the needed ones in build_elision_headers() //return 3; //we guess that the private bit is not set //FIXME the above assumptions should be checked, if these turn out false too often something should be done }
/** Read magic cookie chunk */ static int read_kuki_chunk(AVFormatContext *s, int64_t size) { AVIOContext *pb = s->pb; AVStream *st = s->streams[0]; if (size < 0 || size > INT_MAX - AV_INPUT_BUFFER_PADDING_SIZE) return -1; if (st->codecpar->codec_id == AV_CODEC_ID_AAC) { /* The magic cookie format for AAC is an mp4 esds atom. The lavc AAC decoder requires the data from the codec specific description as extradata input. */ int strt, skip; strt = avio_tell(pb); ff_mov_read_esds(s, pb); skip = size - (avio_tell(pb) - strt); if (skip < 0 || !st->codecpar->extradata || st->codecpar->codec_id != AV_CODEC_ID_AAC) { av_log(s, AV_LOG_ERROR, "invalid AAC magic cookie\n"); return AVERROR_INVALIDDATA; } avio_skip(pb, skip); } else if (st->codecpar->codec_id == AV_CODEC_ID_ALAC) { #define ALAC_PREAMBLE 12 #define ALAC_HEADER 36 #define ALAC_NEW_KUKI 24 uint8_t preamble[12]; if (size < ALAC_NEW_KUKI) { av_log(s, AV_LOG_ERROR, "invalid ALAC magic cookie\n"); avio_skip(pb, size); return AVERROR_INVALIDDATA; } if (avio_read(pb, preamble, ALAC_PREAMBLE) != ALAC_PREAMBLE) { av_log(s, AV_LOG_ERROR, "failed to read preamble\n"); return AVERROR_INVALIDDATA; } av_freep(&st->codecpar->extradata); if (ff_alloc_extradata(st->codecpar, ALAC_HEADER)) return AVERROR(ENOMEM); /* For the old style cookie, we skip 12 bytes, then read 36 bytes. * The new style cookie only contains the last 24 bytes of what was * 36 bytes in the old style cookie, so we fabricate the first 12 bytes * in that case to maintain compatibility. */ if (!memcmp(&preamble[4], "frmaalac", 8)) { if (size < ALAC_PREAMBLE + ALAC_HEADER) { av_log(s, AV_LOG_ERROR, "invalid ALAC magic cookie\n"); av_freep(&st->codecpar->extradata); return AVERROR_INVALIDDATA; } if (avio_read(pb, st->codecpar->extradata, ALAC_HEADER) != ALAC_HEADER) { av_log(s, AV_LOG_ERROR, "failed to read kuki header\n"); av_freep(&st->codecpar->extradata); return AVERROR_INVALIDDATA; } avio_skip(pb, size - ALAC_PREAMBLE - ALAC_HEADER); } else { AV_WB32(st->codecpar->extradata, 36); memcpy(&st->codecpar->extradata[4], "alac", 4); AV_WB32(&st->codecpar->extradata[8], 0); memcpy(&st->codecpar->extradata[12], preamble, 12); if (avio_read(pb, &st->codecpar->extradata[24], ALAC_NEW_KUKI - 12) != ALAC_NEW_KUKI - 12) { av_log(s, AV_LOG_ERROR, "failed to read new kuki header\n"); av_freep(&st->codecpar->extradata); return AVERROR_INVALIDDATA; } avio_skip(pb, size - ALAC_NEW_KUKI); } } else { av_freep(&st->codecpar->extradata); if (ff_get_extradata(st->codecpar, pb, size) < 0) return AVERROR(ENOMEM); } return 0; }
HRESULT CStreamParser::ParseH264AnnexB(Packet *pPacket) { if (!m_pPacketBuffer) { m_pPacketBuffer = InitPacket(pPacket); } m_pPacketBuffer->Append(pPacket); BYTE *start = m_pPacketBuffer->GetData(); BYTE *end = start + m_pPacketBuffer->GetDataSize(); MOVE_TO_H264_START_CODE(start, end); while(start <= end-4) { BYTE *next = start + 1; MOVE_TO_H264_START_CODE(next, end); // End of buffer reached if(next >= end-4) { break; } size_t size = next - start; CH264Nalu Nalu; Nalu.SetBuffer(start, (int)size, 0); Packet *p2 = nullptr; while (Nalu.ReadNext()) { Packet *p3 = new Packet(); p3->SetDataSize(Nalu.GetDataLength() + 4); // Write size of the NALU (Big Endian) AV_WB32(p3->GetData(), (uint32_t)Nalu.GetDataLength()); memcpy(p3->GetData() + 4, Nalu.GetDataBuffer(), Nalu.GetDataLength()); if (!p2) { p2 = p3; } else { p2->Append(p3); SAFE_DELETE(p3); } } if (!p2) break; p2->StreamId = m_pPacketBuffer->StreamId; p2->bDiscontinuity = m_pPacketBuffer->bDiscontinuity; m_pPacketBuffer->bDiscontinuity = FALSE; p2->bSyncPoint = m_pPacketBuffer->bSyncPoint; m_pPacketBuffer->bSyncPoint = FALSE; p2->rtStart = m_pPacketBuffer->rtStart; m_pPacketBuffer->rtStart = Packet::INVALID_TIME; p2->rtStop = m_pPacketBuffer->rtStop; m_pPacketBuffer->rtStop = Packet::INVALID_TIME; p2->pmt = m_pPacketBuffer->pmt; m_pPacketBuffer->pmt = nullptr; m_queue.Queue(p2); if(pPacket->rtStart != Packet::INVALID_TIME) { m_pPacketBuffer->rtStart = pPacket->rtStart; m_pPacketBuffer->rtStop = pPacket->rtStop; pPacket->rtStart = Packet::INVALID_TIME; } if(pPacket->bDiscontinuity) { m_pPacketBuffer->bDiscontinuity = pPacket->bDiscontinuity; pPacket->bDiscontinuity = FALSE; } if(pPacket->bSyncPoint) { m_pPacketBuffer->bSyncPoint = pPacket->bSyncPoint; pPacket->bSyncPoint = FALSE; } if(m_pPacketBuffer->pmt) { DeleteMediaType(m_pPacketBuffer->pmt); } m_pPacketBuffer->pmt = pPacket->pmt; pPacket->pmt = nullptr; start = next; } if(start > m_pPacketBuffer->GetData()) { m_pPacketBuffer->RemoveHead(start - m_pPacketBuffer->GetData()); } SAFE_DELETE(pPacket); do { pPacket = nullptr; REFERENCE_TIME rtStart = Packet::INVALID_TIME, rtStop = rtStart = Packet::INVALID_TIME; std::deque<Packet *>::iterator it; for (it = m_queue.GetQueue()->begin(); it != m_queue.GetQueue()->end(); ++it) { // Skip the first if (it == m_queue.GetQueue()->begin()) { continue; } Packet *p = *it; BYTE* pData = p->GetData(); if((pData[4]&0x1f) == 0x09) { m_bHasAccessUnitDelimiters = true; } if ((pData[4]&0x1f) == 0x09 || (!m_bHasAccessUnitDelimiters && p->rtStart != Packet::INVALID_TIME)) { pPacket = p; if (p->rtStart == Packet::INVALID_TIME && rtStart != Packet::INVALID_TIME) { p->rtStart = rtStart; p->rtStop = rtStop; } break; } if (rtStart == Packet::INVALID_TIME) { rtStart = p->rtStart; rtStop = p->rtStop; } } if (pPacket) { Packet *p = m_queue.Get(); Packet *p2 = nullptr; while ((p2 = m_queue.Get()) != pPacket) { p->Append(p2); SAFE_DELETE(p2); } // Return m_queue.GetQueue()->push_front(pPacket); Queue(p); } } while (pPacket != nullptr); return S_OK; }
/** return 0 on packet, <0 on partial packet or error... */ static int svq3_parse_packet (AVFormatContext *s, PayloadContext *sv, AVStream *st, AVPacket *pkt, uint32_t *timestamp, const uint8_t *buf, int len, int flags) { int config_packet, start_packet, end_packet; if (len < 2) return AVERROR_INVALIDDATA; config_packet = buf[0] & 0x40; start_packet = buf[0] & 0x20; end_packet = buf[0] & 0x10; buf += 2; // ignore buf[1] len -= 2; if (config_packet) { av_freep(&st->codec->extradata); st->codec->extradata_size = 0; if (len < 2 || !(st->codec->extradata = av_malloc(len + 8 + FF_INPUT_BUFFER_PADDING_SIZE))) return AVERROR_INVALIDDATA; st->codec->extradata_size = len + 8; memcpy(st->codec->extradata, "SEQH", 4); AV_WB32(st->codec->extradata + 4, len); memcpy(st->codec->extradata + 8, buf, len); /* We set codec_id to CODEC_ID_NONE initially to * delay decoder initialization since extradata is * carried within the RTP stream, not SDP. Here, * by setting codec_id to CODEC_ID_SVQ3, we are signalling * to the decoder that it is OK to initialize. */ st->codec->codec_id = CODEC_ID_SVQ3; return AVERROR(EAGAIN); } if (start_packet) { int res; if (sv->pktbuf) { uint8_t *tmp; url_close_dyn_buf(sv->pktbuf, &tmp); av_free(tmp); } if ((res = url_open_dyn_buf(&sv->pktbuf)) < 0) return res; sv->timestamp = *timestamp; } if (!sv->pktbuf) return AVERROR_INVALIDDATA; put_buffer(sv->pktbuf, buf, len); if (end_packet) { av_init_packet(pkt); pkt->stream_index = st->index; *timestamp = sv->timestamp; pkt->size = url_close_dyn_buf(sv->pktbuf, &pkt->data); pkt->destruct = av_destruct_packet; sv->pktbuf = NULL; return 0; } return AVERROR(EAGAIN); }
static int redspark_read_header(AVFormatContext *s) { AVIOContext *pb = s->pb; RedSparkContext *redspark = s->priv_data; AVCodecParameters *par; GetByteContext gbc; int i, coef_off, ret = 0; uint32_t key, data; uint8_t header[HEADER_SIZE]; AVStream *st; st = avformat_new_stream(s, NULL); if (!st) return AVERROR(ENOMEM); par = st->codecpar; /* Decrypt header */ data = avio_rb32(pb); key = data ^ 0x52656453; data ^= key; AV_WB32(header, data); key = rol(key, 11); for (i = 4; i < HEADER_SIZE; i += 4) { key += rol(key, 3); data = avio_rb32(pb) ^ key; AV_WB32(header + i, data); } par->codec_id = AV_CODEC_ID_ADPCM_THP; par->codec_type = AVMEDIA_TYPE_AUDIO; bytestream2_init(&gbc, header, HEADER_SIZE); bytestream2_seek(&gbc, 0x3c, SEEK_SET); par->sample_rate = bytestream2_get_be32u(&gbc); if (par->sample_rate <= 0 || par->sample_rate > 96000) { av_log(s, AV_LOG_ERROR, "Invalid sample rate: %d\n", par->sample_rate); return AVERROR_INVALIDDATA; } st->duration = bytestream2_get_be32u(&gbc) * 14; redspark->samples_count = 0; bytestream2_skipu(&gbc, 10); par->channels = bytestream2_get_byteu(&gbc); if (!par->channels) { return AVERROR_INVALIDDATA; } coef_off = 0x54 + par->channels * 8; if (bytestream2_get_byteu(&gbc)) // Loop flag coef_off += 16; if (coef_off + par->channels * (32 + 14) > HEADER_SIZE) { return AVERROR_INVALIDDATA; } if (ff_alloc_extradata(par, 32 * par->channels)) { return AVERROR_INVALIDDATA; } /* Get the ADPCM table */ bytestream2_seek(&gbc, coef_off, SEEK_SET); for (i = 0; i < par->channels; i++) { if (bytestream2_get_bufferu(&gbc, par->extradata + i * 32, 32) != 32) { return AVERROR_INVALIDDATA; } bytestream2_skipu(&gbc, 14); } avpriv_set_pts_info(st, 64, 1, par->sample_rate); 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; int start_time=mgt->full_time; char *oprefix=mgt->location!=NULL?mgt->location:mgt->filename; if(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'; if(NULL!=mgt->prefix){ av_free(mgt->prefix); mgt->prefix = NULL; } mgt->prefix = strdup(prefixex); } } memset(&tmpitem,0,sizeof(tmpitem)); 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) { 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 int seq = mgt->seq+mgt->item_num; av_log(NULL,AV_LOG_INFO,"Current item seq number:%d\n",seq); AV_WB32(item->key_ctx->iv + 12, seq); } item->ktype = mgt->key_tmp->key_type; } if(mgt->flags&REAL_STREAMING_FLAG){ ret =list_test_and_add_item(mgt,item); if(ret==0){ start_time+=item->duration; } }else{ ret = list_add_item(mgt,item); start_time+=item->duration; } if(item->flags &ENDLIST_FLAG) { mgt->have_list_end=1; break; } else { memset(&tmpitem,0,sizeof(tmpitem)); if(ret == 0){ getnum++; } } } 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(mgt->flags&REAL_STREAMING_FLAG&&mgt->jump_item_num==INT_MAX){ mgt->jump_item_num = 0; av_log(NULL, AV_LOG_INFO, "drop this list,sequence number:%ld\n",mgt->seq); break; } } } if(mgt->key_tmp){ av_free(mgt->key_tmp); mgt->key_tmp = NULL; } if(mgt->n_variants>0){//just choose middle definition; float value; ret=am_getconfig_float("libplayer.hls.level",&value); if(ret==0&&value<1){ mgt->ctype =LOW_BANDWIDTH; }else if(ret==0&&value>0&&value<2){ mgt->ctype =MIDDLE_BANDWIDTH; }else if(ret==0&&value>1){ mgt->ctype =HIGH_BANDWIDTH; }else{ mgt->ctype =MIDDLE_BANDWIDTH; } } 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=%d\n",getnum,start_time); return getnum;
static int rmff_dump_prop(rmff_prop_t *prop, char *buffer, int bufsize) { if (!prop) return 0; if (bufsize < RMFF_PROPHEADER_SIZE) return -1; AV_WB32(buffer, prop->object_id); AV_WB32(buffer+4, prop->size); AV_WB16(buffer+8, prop->object_version); AV_WB32(buffer+10, prop->max_bit_rate); AV_WB32(buffer+14, prop->avg_bit_rate); AV_WB32(buffer+18, prop->max_packet_size); AV_WB32(buffer+22, prop->avg_packet_size); AV_WB32(buffer+26, prop->num_packets); AV_WB32(buffer+30, prop->duration); AV_WB32(buffer+34, prop->preroll); AV_WB32(buffer+38, prop->index_offset); AV_WB32(buffer+42, prop->data_offset); AV_WB16(buffer+46, prop->num_streams); AV_WB16(buffer+48, prop->flags); return RMFF_PROPHEADER_SIZE; }
static int parse_playlist(AppleHTTPContext *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) { close_in = 1; if ((ret = avio_open(&in, url, AVIO_FLAG_READ)) < 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 (!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); } 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 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; }
static void mux_frames(int n) { int end_frames = frames + n; while (1) { AVPacket pkt; uint8_t pktdata[8] = { 0 }; av_init_packet(&pkt); if (av_compare_ts(audio_dts, audio_st->time_base, video_dts, video_st->time_base) < 0) { pkt.dts = pkt.pts = audio_dts; pkt.stream_index = 1; pkt.duration = audio_duration; audio_dts += audio_duration; } else { if (frames == end_frames) break; pkt.dts = video_dts; pkt.stream_index = 0; pkt.duration = duration; if ((frames % gop_size) == 0) { pkt.flags |= AV_PKT_FLAG_KEY; last_picture = AV_PICTURE_TYPE_I; pkt.pts = pkt.dts + duration; video_dts = pkt.pts; } else { if (last_picture == AV_PICTURE_TYPE_P) { last_picture = AV_PICTURE_TYPE_B; pkt.pts = pkt.dts; video_dts = next_p_pts; } else { last_picture = AV_PICTURE_TYPE_P; if (((frames + 1) % gop_size) == 0) { pkt.pts = pkt.dts + duration; video_dts = pkt.pts; } else { next_p_pts = pkt.pts = pkt.dts + 2 * duration; video_dts += duration; } } } if (!bframes) pkt.pts = pkt.dts; if (fake_pkt_duration) pkt.duration = fake_pkt_duration; frames++; } if (clear_duration) pkt.duration = 0; AV_WB32(pktdata + 4, pkt.pts); pkt.data = pktdata; pkt.size = 8; if (skip_write) continue; if (skip_write_audio && pkt.stream_index == 1) continue; if (do_interleave) av_interleaved_write_frame(ctx, &pkt); else av_write_frame(ctx, &pkt); } }
static int apng_read_header(AVFormatContext *s) { APNGDemuxContext *ctx = s->priv_data; AVIOContext *pb = s->pb; uint32_t len, tag; AVStream *st; int acTL_found = 0; int64_t ret = AVERROR_INVALIDDATA; /* verify PNGSIG */ if (avio_rb64(pb) != PNGSIG) return ret; /* parse IHDR (must be first chunk) */ len = avio_rb32(pb); tag = avio_rl32(pb); if (len != 13 || tag != MKTAG('I', 'H', 'D', 'R')) return ret; st = avformat_new_stream(s, NULL); if (!st) return AVERROR(ENOMEM); /* set the timebase to something large enough (1/100,000 of second) * to hopefully cope with all sane frame durations */ avpriv_set_pts_info(st, 64, 1, 100000); st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO; st->codecpar->codec_id = AV_CODEC_ID_APNG; st->codecpar->width = avio_rb32(pb); st->codecpar->height = avio_rb32(pb); if ((ret = av_image_check_size(st->codecpar->width, st->codecpar->height, 0, s)) < 0) return ret; /* extradata will contain every chunk up to the first fcTL (excluded) */ ctx->extra_data = av_malloc(len + 12 + AV_INPUT_BUFFER_PADDING_SIZE); if (!ctx->extra_data) return AVERROR(ENOMEM); ctx->extra_data_size = len + 12; AV_WB32(ctx->extra_data, len); AV_WL32(ctx->extra_data+4, tag); AV_WB32(ctx->extra_data+8, st->codecpar->width); AV_WB32(ctx->extra_data+12, st->codecpar->height); if ((ret = avio_read(pb, ctx->extra_data+16, 9)) < 0) goto fail; while (!avio_feof(pb)) { if (acTL_found && ctx->num_play != 1) { int64_t size = avio_size(pb); int64_t offset = avio_tell(pb); if (size < 0) { ret = size; goto fail; } else if (offset < 0) { ret = offset; goto fail; } else if ((ret = ffio_ensure_seekback(pb, size - offset)) < 0) { av_log(s, AV_LOG_WARNING, "Could not ensure seekback, will not loop\n"); ctx->num_play = 1; } } if ((ctx->num_play == 1 || !acTL_found) && ((ret = ffio_ensure_seekback(pb, 4 /* len */ + 4 /* tag */)) < 0)) goto fail; len = avio_rb32(pb); if (len > 0x7fffffff) { ret = AVERROR_INVALIDDATA; goto fail; } tag = avio_rl32(pb); switch (tag) { case MKTAG('a', 'c', 'T', 'L'): if ((ret = avio_seek(pb, -8, SEEK_CUR)) < 0 || (ret = append_extradata(ctx, pb, len + 12)) < 0) goto fail; acTL_found = 1; ctx->num_frames = AV_RB32(ctx->extra_data + ret + 8); ctx->num_play = AV_RB32(ctx->extra_data + ret + 12); av_log(s, AV_LOG_DEBUG, "num_frames: %"PRIu32", num_play: %"PRIu32"\n", ctx->num_frames, ctx->num_play); break; case MKTAG('f', 'c', 'T', 'L'): if (!acTL_found) { ret = AVERROR_INVALIDDATA; goto fail; } if ((ret = avio_seek(pb, -8, SEEK_CUR)) < 0) goto fail; return 0; default: if ((ret = avio_seek(pb, -8, SEEK_CUR)) < 0 || (ret = append_extradata(ctx, pb, len + 12)) < 0) goto fail; } } fail: if (ctx->extra_data_size) { av_freep(&ctx->extra_data); ctx->extra_data_size = 0; } return ret; }