/* * get file property. * return value packet size ... success * -1 ... error */ int asf_get_file_property(const uint8_t *header,int asf_header_size, struct asf_file_header_t *fileh) { int pos = 0; int packet_size = 0; /* examine file properties */ pos = find_asf_guid(header,0,asf_file_header_guid,asf_header_size); if(pos < 0) { goto failed; } if((pos + sizeof(struct asf_file_header_t )) > asf_header_size) {/* 2big */ goto failed; } memcpy((uint8_t *)fileh,header + pos,sizeof(struct asf_file_header_t)); /* little endian */ fileh->file_size = le2me_64(fileh->file_size); fileh->creation_time = le2me_64(fileh->creation_time); fileh->num_packets = le2me_64(fileh->num_packets); fileh->play_duration = le2me_64(fileh->play_duration); fileh->send_duration = le2me_64(fileh->send_duration); fileh->preroll = le2me_64(fileh->preroll); fileh->flags = le2me_32(fileh->flags); fileh->min_packet_size = le2me_32(fileh->min_packet_size); fileh->max_packet_size = le2me_32(fileh->max_packet_size); fileh->max_bitrate = le2me_32(fileh->max_bitrate); display(MSDL_VER,"file size = %lld\n",fileh->file_size); display(MSDL_VER,"play_duration = %d\n", fileh->play_duration/10000000); display(MSDL_VER,"send_duration = %d\n", fileh->send_duration/10000000); display(MSDL_VER,"# of packets = %d\n", fileh->num_packets); display(MSDL_VER,"flags = %x\n", fileh->flags); packet_size = fileh->max_packet_size; display(MSDL_VER,"packet_size = %d\n", fileh->max_packet_size); display(MSDL_VER,"min_packsize = %d\n", fileh->min_packet_size); return packet_size; failed: return -1; }
static int get_meta(char *buf, int buf_len, int this_stream_num, float* asp_ratio) { int pos = 0; uint16_t records_count; uint16_t x = 0, y = 0; if ((pos = find_asf_guid(buf, asf_metadata_header, pos, buf_len)) < 0) return 0; CHECKDEC(buf_len, pos); buf += pos; CHECKDEC(buf_len, 2); records_count = AV_RL16(buf); buf += 2; while (records_count--) { ASF_meta_record_t record_entry; char* name; if (!(buf = read_meta_record(&record_entry, buf, &buf_len))) return 0; /* reserved, must be zero */ if (record_entry.lang_list_index) continue; /* match stream number: 0 to match all */ if (record_entry.stream_num && record_entry.stream_num != this_stream_num) continue; if (!(name = get_ucs2str(record_entry.name, record_entry.name_length))) { mp_msg(MSGT_HEADER, MSGL_ERR, MSGTR_MemAllocFailed); continue; } if (strcmp(name, "AspectRatioX") == 0) x = AV_RL16(record_entry.data); else if (strcmp(name, "AspectRatioY") == 0) y = AV_RL16(record_entry.data); free(name); } if (x && y) { *asp_ratio = (float)x / (float)y; return 1; } return 0; }
static int is_drm(char* buf, int buf_len) { uint32_t data_len, type_len, key_len, url_len; int pos = find_asf_guid(buf, asf_content_encryption, 0, buf_len); if (pos < 0) return 0; CHECKDEC(buf_len, pos + 4); buf += pos; data_len = AV_RL32(buf); buf += 4; CHECKDEC(buf_len, data_len); buf += data_len; type_len = AV_RL32(buf); if (type_len < 4) return 0; CHECKDEC(buf_len, 4 + type_len + 4); buf += 4; if (buf[0] != 'D' || buf[1] != 'R' || buf[2] != 'M' || buf[3] != '\0') return 0; buf += type_len; key_len = AV_RL32(buf); CHECKDEC(buf_len, key_len + 4); buf += 4; buf[key_len - 1] = '\0'; mp_msg(MSGT_HEADER, MSGL_V, "DRM Key ID: %s\n", buf); buf += key_len; url_len = AV_RL32(buf); CHECKDEC(buf_len, url_len); buf += 4; buf[url_len - 1] = '\0'; mp_msg(MSGT_HEADER, MSGL_INFO, MSGTR_MPDEMUX_ASFHDR_DRMLicenseURL, buf); return 1; }
/* * choose best audio and video streams, below bw. * 'header' is an asf header, and 'asf_header_size' is its size. * the result will be in 'streams' * return value: 1 ... success * -1 ... failed */ int asf_choose_best_streams(const uint8_t *header, int asf_header_size, int bw, struct asf_streams_t *streams) { int i = 0,pos = 0,start = 0; int *v_rates = NULL, *a_rates = NULL; int v_rate = 0, a_rate = 0, v_idx = -1, a_idx = -1; /* header is entire ASF header, including very first asf_header_t. */ pos = sizeof(struct asf_header_t); start = pos; /* choose best (fastest) streams */ while((pos = find_asf_guid(header,pos,asf_stream_header_guid,asf_header_size)) >= 0) { struct asf_stream_header_t *streamh = (struct asf_stream_header_t *)(header + pos); pos += sizeof(struct asf_stream_header_t); if(pos > asf_header_size) /* error */ return -1; /* get ASF GUID PREFIX (first 4 byte of GUID) */ switch(get32_le(streamh->type)) { case ASF_AUDIO_STREAM: /* audio stream */ display(MSDL_VER,"audio stream detected!!!!\n"); if(streams->audio_streams == NULL) { /* no audio stream registerd yet */ streams->audio_streams = (int *)xmalloc(sizeof(int)); streams->n_audio = 1; } else { /* more audio streams.!! */ streams->n_audio++; streams->audio_streams = (int *)xrealloc(streams->audio_streams, streams->n_audio * sizeof(int)); } streams->audio_streams[streams->n_audio - 1] = le2me_16(streamh->stream_no); break; case ASF_VIDEO_STREAM: /* video streams */ display(MSDL_VER,"video stream detected!!!!\n"); if(streams->video_streams == NULL) { /* no video stream registerd yet */ streams->video_streams = (int *)xmalloc(sizeof(int)); streams->n_video = 1; } else { /* more video streams.!! */ streams->n_video++; streams->video_streams = (int *)xrealloc(streams->video_streams, streams->n_video * sizeof(int)); } streams->video_streams[streams->n_video - 1] = le2me_16(streamh->stream_no); break; case ASF_COMMAND_MEDIA_STREAM: /* Command media stream... whatever*/ display(MSDL_VER,"Command media stream detected, but ignore this.\n"); break; case ASF_FILE_TRANSFER_MEDIA_STREAM: /* File transfer media stream... I don't know what the heck this is.*/ display(MSDL_VER,"File transfer stream detected, but ignore this.\n"); break; } } a_rates = (int *)xmalloc(streams->n_audio * sizeof(int)); v_rates = (int *)xmalloc(streams->n_video * sizeof(int)); pos = find_asf_guid(header,start,asf_stream_group_guid,asf_header_size); if(pos >= 0) { /* stream bitrate proterties object */ int stream_count = 0; uint8_t *ptr = (uint8_t *)header + pos; display(MSDL_VER,"stream bitrate properties object\n"); stream_count = get16_le(ptr); /* little endian. */ ptr += sizeof(uint16_t); if(ptr > header + asf_header_size) goto failed; display(MSDL_VER,"stream count = [0x%x] [%u]\n",stream_count,stream_count); display(MSDL_VER,"audio streams: %d, video streams: %d\n", streams->n_audio,streams->n_video); for(i = 0; i < stream_count; i++) { uint32_t rate = 0; int id = 0; int j = 0; id = get16_le(ptr); ptr += sizeof(uint16_t); if(ptr > header + asf_header_size) goto failed; rate = get32_le(ptr); ptr += sizeof(uint32_t); if(ptr > header + asf_header_size) goto failed; display(MSDL_VER, "stream_id = [0x%x] [%u]\n" "max bitrate = [0x%x] [%u]\n", id,id,rate,rate); for(j = 0; j < streams->n_audio; j++) { if(id == streams->audio_streams[j]) { display(MSDL_VER,"is audio stream\n"); a_rates[j] = rate; break; } } for(j = 0; j < streams->n_video; j++) { if(id == streams->video_streams[j]) { display(MSDL_VER,"is video stream\n"); v_rates[j] = rate; break; } } } } /* just to make sure bw is not Zero! */ if(bw == 0) { bw = INT_MAX_BANDWIDTH; } if(streams->n_audio) { /* find lowest-bitrate audio stream */ a_rate = a_rates[0]; a_idx = 0; for(i = 0; i < streams->n_audio; i++) { if(a_rates[i] < a_rate) { a_rate = a_rates[i]; a_idx = i; } } if(max_idx(streams->n_video,v_rates,bw - a_rate) < 0) { /* both audio and video are not possible, try video only next */ a_idx = -1; a_rate = 0; } } /* find best video stream */ v_idx = max_idx(streams->n_video,v_rates,bw - a_rate); if(v_idx >= 0) { v_rate = v_rates[v_idx]; } /* find best auido stream */ a_idx = max_idx(streams->n_audio,a_rates,bw - v_rate); free(v_rates); v_rates = NULL; free(a_rates); a_rates = NULL; if(a_idx < 0 && v_idx < 0) { display(MSDL_ERR,"bandwidth too low ... cannot get streams."); return -1; } if(a_idx >= 0) { streams->audio_id = streams->audio_streams[a_idx]; } else if(streams->n_audio) { display(MSDL_ERR,"Bandwidth too too small so deselected audio....sad.\n"); } if(v_idx >= 0) { streams->video_id = streams->video_streams[v_idx]; } else if(streams->n_video) { display(MSDL_ERR,"Bandwidth too too small so deselected video....sad.\n"); } return 1; failed: free(v_rates); free(a_rates); return -1; }
int read_asf_header(demuxer_t *demuxer,struct asf_priv* asf){ int hdr_len = asf->header.objh.size - sizeof(asf->header); int hdr_skip = 0; char *hdr = NULL; char guid_buffer[16]; int pos, start = stream_tell(demuxer->stream); uint32_t* streams = NULL; int audio_streams=0; int video_streams=0; uint16_t stream_count=0; int best_video = -1; int best_audio = -1; uint64_t data_len; ASF_stream_header_t *streamh; uint8_t *buffer; int audio_pos=0; if(hdr_len < 0) { mp_msg(MSGT_HEADER, MSGL_FATAL, "Header size is too small.\n"); return 0; } if (hdr_len > 1024 * 1024) { mp_msg(MSGT_HEADER, MSGL_ERR, MSGTR_MPDEMUX_ASFHDR_HeaderSizeOver1MB, hdr_len); hdr_skip = hdr_len - 1024 * 1024; hdr_len = 1024 * 1024; } hdr = malloc(hdr_len); if (!hdr) { mp_msg(MSGT_HEADER, MSGL_FATAL, MSGTR_MPDEMUX_ASFHDR_HeaderMallocFailed, hdr_len); return 0; } stream_read(demuxer->stream, hdr, hdr_len); if (hdr_skip) stream_skip(demuxer->stream, hdr_skip); if (stream_eof(demuxer->stream)) { mp_msg(MSGT_HEADER, MSGL_FATAL, MSGTR_MPDEMUX_ASFHDR_EOFWhileReadingHeader); goto err_out; } if (is_drm(hdr, hdr_len)) mp_msg(MSGT_HEADER, MSGL_FATAL, MSGTR_MPDEMUX_ASFHDR_DRMProtected); if ((pos = find_asf_guid(hdr, asf_ext_stream_audio, 0, hdr_len)) >= 0) { // Special case: found GUID for dvr-ms audio. // Now skip back to associated stream header. int sh_pos=0; sh_pos = find_backwards_asf_guid(hdr, asf_stream_header_guid, pos); if (sh_pos > 0) { sh_audio_t *sh_audio; mp_msg(MSGT_HEADER, MSGL_V, "read_asf_header found dvr-ms audio stream header pos=%d\n", sh_pos); // found audio stream header - following code reads header and // initializes audio stream. audio_pos = pos - 16 - 8; streamh = (ASF_stream_header_t *)&hdr[sh_pos]; le2me_ASF_stream_header_t(streamh); audio_pos += 64; //16+16+4+4+4+16+4; buffer = &hdr[audio_pos]; sh_audio=new_sh_audio(demuxer,streamh->stream_no & 0x7F, NULL); sh_audio->needs_parsing = 1; mp_msg(MSGT_DEMUX, MSGL_INFO, MSGTR_AudioID, "asfheader", streamh->stream_no & 0x7F); ++audio_streams; if (!asf_init_audio_stream(demuxer, asf, sh_audio, streamh, &audio_pos, &buffer, hdr, hdr_len)) goto len_err_out; if (!get_ext_stream_properties(hdr, hdr_len, streamh->stream_no, asf, 0)) goto len_err_out; } } // find stream headers // only reset pos if we didnt find dvr_ms audio stream // if we did find it then we want to avoid reading its header twice if (audio_pos == 0) pos = 0; while ((pos = find_asf_guid(hdr, asf_stream_header_guid, pos, hdr_len)) >= 0) { streamh = (ASF_stream_header_t *)&hdr[pos]; pos += sizeof(ASF_stream_header_t); if (pos > hdr_len) goto len_err_out; le2me_ASF_stream_header_t(streamh); mp_msg(MSGT_HEADER, MSGL_V, "stream type: %s\n", asf_chunk_type(streamh->type)); mp_msg(MSGT_HEADER, MSGL_V, "stream concealment: %s\n", asf_chunk_type(streamh->concealment)); mp_msg(MSGT_HEADER, MSGL_V, "type: %d bytes, stream: %d bytes ID: %d\n", (int)streamh->type_size, (int)streamh->stream_size, (int)streamh->stream_no); mp_msg(MSGT_HEADER, MSGL_V, "unk1: %lX unk2: %X\n", (unsigned long)streamh->unk1, (unsigned int)streamh->unk2); mp_msg(MSGT_HEADER, MSGL_V, "FILEPOS=0x%X\n", pos + start); // type-specific data: buffer = &hdr[pos]; pos += streamh->type_size; if (pos > hdr_len) goto len_err_out; switch(ASF_LOAD_GUID_PREFIX(streamh->type)){ case ASF_GUID_PREFIX_audio_stream: { sh_audio_t* sh_audio=new_sh_audio(demuxer,streamh->stream_no & 0x7F, NULL); mp_msg(MSGT_DEMUX, MSGL_INFO, MSGTR_AudioID, "asfheader", streamh->stream_no & 0x7F); ++audio_streams; if (!asf_init_audio_stream(demuxer, asf, sh_audio, streamh, &pos, &buffer, hdr, hdr_len)) goto len_err_out; //if(demuxer->audio->id==-1) demuxer->audio->id=streamh.stream_no & 0x7F; break; } case ASF_GUID_PREFIX_video_stream: { unsigned int len; float asp_ratio; sh_video_t* sh_video=new_sh_video(demuxer,streamh->stream_no & 0x7F); mp_msg(MSGT_DEMUX, MSGL_INFO, MSGTR_VideoID, "asfheader", streamh->stream_no & 0x7F); len=streamh->type_size-(4+4+1+2); ++video_streams; // sh_video->bih=malloc(chunksize); memset(sh_video->bih,0,chunksize); sh_video->bih=calloc((len<sizeof(*sh_video->bih))?sizeof(*sh_video->bih):len,1); memcpy(sh_video->bih,&buffer[4+4+1+2],len); le2me_BITMAPINFOHEADER(sh_video->bih); if (sh_video->bih->biSize > len && sh_video->bih->biSize > sizeof(*sh_video->bih)) sh_video->bih->biSize = len; if (sh_video->bih->biCompression == mmioFOURCC('D', 'V', 'R', ' ')) { //mp_msg(MSGT_DEMUXER, MSGL_WARN, MSGTR_MPDEMUX_ASFHDR_DVRWantsLibavformat); //sh_video->fps=(float)sh_video->video.dwRate/(float)sh_video->video.dwScale; //sh_video->frametime=(float)sh_video->video.dwScale/(float)sh_video->video.dwRate; asf->asf_frame_state=-1; asf->asf_frame_start_found=0; asf->asf_is_dvr_ms=1; asf->dvr_last_vid_pts=0.0; } else asf->asf_is_dvr_ms=0; if (!get_ext_stream_properties(hdr, hdr_len, streamh->stream_no, asf, 1)) goto len_err_out; if (get_meta(hdr, hdr_len, streamh->stream_no, &asp_ratio)) { sh_video->aspect = asp_ratio * sh_video->bih->biWidth / sh_video->bih->biHeight; } sh_video->i_bps = asf->bps; if( mp_msg_test(MSGT_DEMUX,MSGL_V) ) print_video_header(sh_video->bih, MSGL_V); //asf_video_id=streamh.stream_no & 0x7F; //if(demuxer->video->id==-1) demuxer->video->id=streamh.stream_no & 0x7F; break; } } // stream-specific data: // stream_read(demuxer->stream,(char*) buffer,streamh.stream_size); } // find file header pos = find_asf_guid(hdr, asf_file_header_guid, 0, hdr_len); if (pos >= 0) { ASF_file_header_t *fileh = (ASF_file_header_t *)&hdr[pos]; pos += sizeof(ASF_file_header_t); if (pos > hdr_len) goto len_err_out; le2me_ASF_file_header_t(fileh); mp_msg(MSGT_HEADER, MSGL_V, "ASF: packets: %d flags: %d " "max_packet_size: %d min_packet_size: %d max_bitrate: %d " "preroll: %d\n", (int)fileh->num_packets, (int)fileh->flags, (int)fileh->min_packet_size, (int)fileh->max_packet_size, (int)fileh->max_bitrate, (int)fileh->preroll); asf->packetsize=fileh->max_packet_size; asf->packet=malloc(asf->packetsize); // !!! asf->packetrate=fileh->max_bitrate/8.0/(double)asf->packetsize; asf->movielength=(fileh->play_duration-10000*fileh->preroll)/10000000.0; } // find content header pos = find_asf_guid(hdr, asf_content_desc_guid, 0, hdr_len); if (pos >= 0) { ASF_content_description_t *contenth = (ASF_content_description_t *)&hdr[pos]; char *string=NULL; uint16_t* wstring = NULL; uint16_t len; pos += sizeof(ASF_content_description_t); if (pos > hdr_len) goto len_err_out; le2me_ASF_content_description_t(contenth); mp_msg(MSGT_HEADER,MSGL_V,"\n"); // extract the title if((len = contenth->title_size) != 0) { wstring = (uint16_t*)&hdr[pos]; pos += len; if (pos > hdr_len) goto len_err_out; if ((string = get_ucs2str(wstring, len))) { mp_msg(MSGT_HEADER,MSGL_V," Title: %s\n", string); demux_info_add(demuxer, "title", string); free(string); } } // extract the author if((len = contenth->author_size) != 0) { wstring = (uint16_t*)&hdr[pos]; pos += len; if (pos > hdr_len) goto len_err_out; if ((string = get_ucs2str(wstring, len))) { mp_msg(MSGT_HEADER,MSGL_V," Author: %s\n", string); demux_info_add(demuxer, "author", string); free(string); } } // extract the copyright if((len = contenth->copyright_size) != 0) { wstring = (uint16_t*)&hdr[pos]; pos += len; if (pos > hdr_len) goto len_err_out; if ((string = get_ucs2str(wstring, len))) { mp_msg(MSGT_HEADER,MSGL_V," Copyright: %s\n", string); demux_info_add(demuxer, "copyright", string); free(string); } } // extract the comment if((len = contenth->comment_size) != 0) { wstring = (uint16_t*)&hdr[pos]; pos += len; if (pos > hdr_len) goto len_err_out; if ((string = get_ucs2str(wstring, len))) { mp_msg(MSGT_HEADER,MSGL_V," Comment: %s\n", string); demux_info_add(demuxer, "comments", string); free(string); } } // extract the rating if((len = contenth->rating_size) != 0) { wstring = (uint16_t*)&hdr[pos]; pos += len; if (pos > hdr_len) goto len_err_out; if ((string = get_ucs2str(wstring, len))) { mp_msg(MSGT_HEADER,MSGL_V," Rating: %s\n", string); free(string); } } mp_msg(MSGT_HEADER,MSGL_V,"\n"); } // find content header pos = find_asf_guid(hdr, asf_stream_group_guid, 0, hdr_len); if (pos >= 0) { int max_streams = (hdr_len - pos - 2) / 6; uint16_t stream_id, i; uint32_t max_bitrate; char *ptr = &hdr[pos]; mp_msg(MSGT_HEADER,MSGL_V,"============ ASF Stream group == START ===\n"); if(max_streams <= 0) goto len_err_out; stream_count = AV_RL16(ptr); ptr += sizeof(uint16_t); if(stream_count > max_streams) stream_count = max_streams; if(stream_count > 0) streams = malloc(2*stream_count*sizeof(uint32_t)); mp_msg(MSGT_HEADER,MSGL_V," stream count=[0x%x][%u]\n", stream_count, stream_count ); for( i=0 ; i<stream_count ; i++ ) { stream_id = AV_RL16(ptr); ptr += sizeof(uint16_t); max_bitrate = AV_RL32(ptr); ptr += sizeof(uint32_t); mp_msg(MSGT_HEADER,MSGL_V," stream id=[0x%x][%u]\n", stream_id, stream_id ); mp_msg(MSGT_HEADER,MSGL_V," max bitrate=[0x%x][%u]\n", max_bitrate, max_bitrate ); streams[2*i] = stream_id; streams[2*i+1] = max_bitrate; } mp_msg(MSGT_HEADER,MSGL_V,"============ ASF Stream group == END ===\n"); } free(hdr); hdr = NULL; start = stream_tell(demuxer->stream); // start of first data chunk stream_read(demuxer->stream, guid_buffer, 16); if (memcmp(guid_buffer, asf_data_chunk_guid, 16) != 0) { mp_msg(MSGT_HEADER, MSGL_FATAL, MSGTR_MPDEMUX_ASFHDR_NoDataChunkAfterHeader); free(streams); streams = NULL; return 0; } // read length of chunk data_len = stream_read_qword_le(demuxer->stream); demuxer->movi_start = stream_tell(demuxer->stream) + 26; demuxer->movi_end = start + data_len; mp_msg(MSGT_HEADER, MSGL_V, "Found movie at 0x%X - 0x%X\n", (int)demuxer->movi_start, (int)demuxer->movi_end); if(streams) { // stream selection is done in the network code, it shouldn't be done here // as the servers often do not care about what we requested. #if 0 uint32_t vr = 0, ar = 0,i; #ifdef CONFIG_NETWORKING if( demuxer->stream->streaming_ctrl!=NULL ) { if( demuxer->stream->streaming_ctrl->bandwidth!=0 && demuxer->stream->streaming_ctrl->data!=NULL ) { best_audio = ((asf_http_streaming_ctrl_t*)demuxer->stream->streaming_ctrl->data)->audio_id; best_video = ((asf_http_streaming_ctrl_t*)demuxer->stream->streaming_ctrl->data)->video_id; } } else #endif for(i = 0; i < stream_count; i++) { uint32_t id = streams[2*i]; uint32_t rate = streams[2*i+1]; if(demuxer->v_streams[id] && rate > vr) { vr = rate; best_video = id; } else if(demuxer->a_streams[id] && rate > ar) { ar = rate; best_audio = id; } } #endif free(streams); streams = NULL; } mp_msg(MSGT_HEADER,MSGL_V,"ASF: %d audio and %d video streams found\n",audio_streams,video_streams); if(!audio_streams) demuxer->audio->id=-2; // nosound else if(best_audio > 0 && demuxer->audio->id == -1) demuxer->audio->id=best_audio; if(!video_streams){ if(!audio_streams){ mp_msg(MSGT_HEADER,MSGL_ERR,MSGTR_MPDEMUX_ASFHDR_AudioVideoHeaderNotFound); return 0; } demuxer->video->id=-2; // audio-only } else if (best_video > 0 && demuxer->video->id == -1) demuxer->video->id = best_video; #if 0 if( mp_msg_test(MSGT_HEADER,MSGL_V) ){ printf("ASF duration: %d\n",(int)fileh.duration); printf("ASF start pts: %d\n",(int)fileh.start_timestamp); printf("ASF end pts: %d\n",(int)fileh.end_timestamp); } #endif return 1; len_err_out: mp_msg(MSGT_HEADER, MSGL_FATAL, MSGTR_MPDEMUX_ASFHDR_InvalidLengthInASFHeader); err_out: if (hdr) free(hdr); if (streams) free(streams); return 0; }
static int get_ext_stream_properties(char *buf, int buf_len, int stream_num, struct asf_priv* asf, int is_video) { int pos=0; uint8_t *buffer = &buf[0]; uint64_t avg_ft; unsigned bitrate; while ((pos = find_asf_guid(buf, asf_ext_stream_header, pos, buf_len)) >= 0) { int this_stream_num, stnamect, payct, i; int buf_max_index=pos+50; if (buf_max_index > buf_len) return 0; buffer = &buf[pos]; // the following info is available // some of it may be useful but we're skipping it for now // starttime(8 bytes), endtime(8), // leak-datarate(4), bucket-datasize(4), init-bucket-fullness(4), // alt-leak-datarate(4), alt-bucket-datasize(4), alt-init-bucket-fullness(4), // max-object-size(4), // flags(4) (reliable,seekable,no_cleanpoints?,resend-live-cleanpoints, rest of bits reserved) buffer += 8+8; bitrate = AV_RL32(buffer); buffer += 8*4; this_stream_num=AV_RL16(buffer);buffer+=2; if (this_stream_num == stream_num) { buf_max_index+=14; if (buf_max_index > buf_len) return 0; buffer+=2; //skip stream-language-id-index avg_ft = AV_RL64(buffer); // provided in 100ns units buffer+=8; asf->bps = bitrate / 8; // after this are values for stream-name-count and // payload-extension-system-count // followed by associated info for each stnamect = AV_RL16(buffer);buffer+=2; payct = AV_RL16(buffer);buffer+=2; // need to read stream names if present in order // to get lengths - values are ignored for now for (i=0; i<stnamect; i++) { int stream_name_len; buf_max_index+=4; if (buf_max_index > buf_len) return 0; buffer+=2; //language_id_index stream_name_len = AV_RL16(buffer);buffer+=2; buffer+=stream_name_len; //stream_name buf_max_index+=stream_name_len; if (buf_max_index > buf_len) return 0; } if (is_video) { asf->vid_repdata_count = payct; asf->vid_repdata_sizes = malloc(payct*sizeof(int)); } else { asf->aud_repdata_count = payct; asf->aud_repdata_sizes = malloc(payct*sizeof(int)); } for (i=0; i<payct; i++) { int payload_len; buf_max_index+=22; if (buf_max_index > buf_len) return 0; // Each payload extension definition starts with a GUID. // In dvr-ms files one of these indicates the presence an // extension that contains pts values and this is always present // in the video and audio streams. // Another GUID indicates the presence of an extension // that contains useful video frame demuxing information. // Note that the extension data in each packet does not contain // these GUIDs and that this header section defines the order the data // will appear in. if (memcmp(buffer, asf_dvr_ms_timing_rep_data, 16) == 0) { if (is_video) asf->vid_ext_timing_index = i; else asf->aud_ext_timing_index = i; } else if (is_video && memcmp(buffer, asf_dvr_ms_vid_frame_rep_data, 16) == 0) asf->vid_ext_frame_index = i; buffer+=16; payload_len = AV_RL16(buffer);buffer+=2; if (is_video) asf->vid_repdata_sizes[i] = payload_len; else asf->aud_repdata_sizes[i] = payload_len; buffer+=4;//sys_len } return 1; } } return 1; }
static int asf_streaming_parse_header(int fd, streaming_ctrl_t* streaming_ctrl) { ASF_stream_chunck_t chunk; asf_http_streaming_ctrl_t* asf_ctrl = streaming_ctrl->data; char* buffer=NULL, *chunk_buffer=NULL; int i,r,size,pos = 0; int start; int buffer_size = 0; int chunk_size2read = 0; int bw = streaming_ctrl->bandwidth; int *v_rates = NULL, *a_rates = NULL; int v_rate = 0, a_rate = 0, a_idx = -1, v_idx = -1; if(asf_ctrl == NULL) return -1; // The ASF header can be in several network chunks. For example if the content description // is big, the ASF header will be split in 2 network chunk. // So we need to retrieve all the chunk before starting to parse the header. do { if (asf_read_wrapper(fd, &chunk, sizeof(ASF_stream_chunck_t), streaming_ctrl) <= 0) return -1; // Endian handling of the stream chunk le2me_ASF_stream_chunck_t(&chunk); size = asf_streaming( &chunk, &r) - sizeof(ASF_stream_chunck_t); if(r) mp_msg(MSGT_NETWORK,MSGL_WARN,MSGTR_MPDEMUX_ASF_WarnDropHeader); if(size < 0){ mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_ASF_ErrorParsingChunkHeader); return -1; } if (chunk.type != ASF_STREAMING_HEADER) { mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_ASF_NoHeaderAtFirstChunk); return -1; } // audit: do not overflow buffer_size if (size > SIZE_MAX - buffer_size) return -1; buffer = malloc(size+buffer_size); if(buffer == NULL) { mp_msg(MSGT_NETWORK,MSGL_FATAL,MSGTR_MPDEMUX_ASF_BufferMallocFailed,size+buffer_size); return -1; } if( chunk_buffer!=NULL ) { memcpy( buffer, chunk_buffer, buffer_size ); free( chunk_buffer ); } chunk_buffer = buffer; buffer += buffer_size; buffer_size += size; if (asf_read_wrapper(fd, buffer, size, streaming_ctrl) <= 0) return -1; if( chunk_size2read==0 ) { ASF_header_t *asfh = (ASF_header_t *)buffer; if(size < (int)sizeof(ASF_header_t)) { mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_ASF_ErrChunk2Small); return -1; } else mp_msg(MSGT_NETWORK,MSGL_DBG2,"Got chunk\n"); chunk_size2read = AV_RL64(&asfh->objh.size); mp_msg(MSGT_NETWORK,MSGL_DBG2,"Size 2 read=%d\n", chunk_size2read); } } while( buffer_size<chunk_size2read); buffer = chunk_buffer; size = buffer_size; start = sizeof(ASF_header_t); pos = find_asf_guid(buffer, asf_file_header_guid, start, size); if (pos >= 0) { ASF_file_header_t *fileh = (ASF_file_header_t *) &buffer[pos]; pos += sizeof(ASF_file_header_t); if (pos > size) goto len_err_out; /* if(fileh.packetsize != fileh.packetsize2) { printf("Error packetsize check don't match\n"); return -1; } */ asf_ctrl->packet_size = AV_RL32(&fileh->max_packet_size); // before playing. // preroll: time in ms to bufferize before playing streaming_ctrl->prebuffer_size = (unsigned int)(((double)fileh->preroll/1000.0)*((double)fileh->max_bitrate/8.0)); } pos = start; while ((pos = find_asf_guid(buffer, asf_stream_header_guid, pos, size)) >= 0) { ASF_stream_header_t *streamh = (ASF_stream_header_t *)&buffer[pos]; pos += sizeof(ASF_stream_header_t); if (pos > size) goto len_err_out; switch(ASF_LOAD_GUID_PREFIX(streamh->type)) { case 0xF8699E40 : // audio stream if(asf_ctrl->audio_streams == NULL){ asf_ctrl->audio_streams = malloc(sizeof(int)); asf_ctrl->n_audio = 1; } else { asf_ctrl->n_audio++; asf_ctrl->audio_streams = realloc(asf_ctrl->audio_streams, asf_ctrl->n_audio*sizeof(int)); } asf_ctrl->audio_streams[asf_ctrl->n_audio-1] = AV_RL16(&streamh->stream_no); break; case 0xBC19EFC0 : // video stream if(asf_ctrl->video_streams == NULL){ asf_ctrl->video_streams = malloc(sizeof(int)); asf_ctrl->n_video = 1; } else { asf_ctrl->n_video++; asf_ctrl->video_streams = realloc(asf_ctrl->video_streams, asf_ctrl->n_video*sizeof(int)); } asf_ctrl->video_streams[asf_ctrl->n_video-1] = AV_RL16(&streamh->stream_no); break; } } // always allocate to avoid lots of ifs later v_rates = calloc(asf_ctrl->n_video, sizeof(int)); a_rates = calloc(asf_ctrl->n_audio, sizeof(int)); pos = find_asf_guid(buffer, asf_stream_group_guid, start, size); if (pos >= 0) { // stream bitrate properties object int stream_count; char *ptr = &buffer[pos]; char *end = &buffer[size]; mp_msg(MSGT_NETWORK, MSGL_V, "Stream bitrate properties object\n"); if (ptr + 2 > end) goto len_err_out; stream_count = AV_RL16(ptr); ptr += 2; mp_msg(MSGT_NETWORK, MSGL_V, " stream count=[0x%x][%u]\n", stream_count, stream_count ); for( i=0 ; i<stream_count ; i++ ) { uint32_t rate; int id; int j; if (ptr + 6 > end) goto len_err_out; id = AV_RL16(ptr); ptr += 2; rate = AV_RL32(ptr); ptr += 4; mp_msg(MSGT_NETWORK, MSGL_V, " stream id=[0x%x][%u]\n", id, id); mp_msg(MSGT_NETWORK, MSGL_V, " max bitrate=[0x%x][%u]\n", rate, rate); for (j = 0; j < asf_ctrl->n_video; j++) { if (id == asf_ctrl->video_streams[j]) { mp_msg(MSGT_NETWORK, MSGL_V, " is video stream\n"); v_rates[j] = rate; break; } } for (j = 0; j < asf_ctrl->n_audio; j++) { if (id == asf_ctrl->audio_streams[j]) { mp_msg(MSGT_NETWORK, MSGL_V, " is audio stream\n"); a_rates[j] = rate; break; } } } } free(buffer); // automatic stream selection based on bandwidth if (bw == 0) bw = INT_MAX; mp_msg(MSGT_NETWORK, MSGL_V, "Max bandwidth set to %d\n", bw); if (asf_ctrl->n_audio) { // find lowest-bitrate audio stream a_rate = a_rates[0]; a_idx = 0; for (i = 0; i < asf_ctrl->n_audio; i++) { if (a_rates[i] < a_rate) { a_rate = a_rates[i]; a_idx = i; } } if (max_idx(asf_ctrl->n_video, v_rates, bw - a_rate) < 0) { // both audio and video are not possible, try video only next a_idx = -1; a_rate = 0; } } // find best video stream v_idx = max_idx(asf_ctrl->n_video, v_rates, bw - a_rate); if (v_idx >= 0) v_rate = v_rates[v_idx]; // find best audio stream a_idx = max_idx(asf_ctrl->n_audio, a_rates, bw - v_rate); free(v_rates); free(a_rates); if (a_idx < 0 && v_idx < 0) { mp_msg(MSGT_NETWORK, MSGL_FATAL, MSGTR_MPDEMUX_ASF_Bandwidth2SmallCannotPlay); return -1; } if (audio_id > 0) // a audio stream was forced asf_ctrl->audio_id = audio_id; else if (a_idx >= 0) asf_ctrl->audio_id = asf_ctrl->audio_streams[a_idx]; else if (asf_ctrl->n_audio) { mp_msg(MSGT_NETWORK, MSGL_WARN, MSGTR_MPDEMUX_ASF_Bandwidth2SmallDeselectedAudio); audio_id = -2; } if (video_id > 0) // a video stream was forced asf_ctrl->video_id = video_id; else if (v_idx >= 0) asf_ctrl->video_id = asf_ctrl->video_streams[v_idx]; else if (asf_ctrl->n_video) { mp_msg(MSGT_NETWORK, MSGL_WARN, MSGTR_MPDEMUX_ASF_Bandwidth2SmallDeselectedVideo); video_id = -2; } return 1; len_err_out: mp_msg(MSGT_NETWORK, MSGL_FATAL, MSGTR_MPDEMUX_ASF_InvalidLenInHeader); free(buffer); free(v_rates); free(a_rates); return -1; }