Mercurial > mplayer.hg
changeset 14236:2dc4595c3998
fix stream selection and -bandwidth for mms-over-http.
Modifies header parsing to do a brute-force scan for known guids, to avoid
having to analyze and parse the whole property-tree structure.
author | reimar |
---|---|
date | Sat, 25 Dec 2004 11:31:32 +0000 |
parents | eb4e9a8ffc2b |
children | cb14ee6b0944 |
files | libmpdemux/asf_streaming.c libmpdemux/asfheader.c |
diffstat | 2 files changed, 336 insertions(+), 186 deletions(-) [+] |
line wrap: on
line diff
--- a/libmpdemux/asf_streaming.c Fri Dec 24 14:55:54 2004 +0000 +++ b/libmpdemux/asf_streaming.c Sat Dec 25 11:31:32 2004 +0000 @@ -3,6 +3,7 @@ #include <string.h> #include <unistd.h> #include <errno.h> +#include <limits.h> #include "config.h" @@ -141,18 +142,37 @@ return stream_chunck->size+4; } +extern int find_asf_guid(char *buf, const char *guid, int cur_pos, int buf_len); +extern const char asf_file_header_guid[]; +extern const char asf_stream_header_guid[]; +extern const char asf_stream_group_guid[]; +extern int audio_id; +extern int video_id; + +static int max_idx(int s_count, int *s_rates, int bound) { + int i, best = -1, rate = 0; + for (i = 0; i < s_count; i++) { + if (s_rates[i] > rate && s_rates[i] <= bound) { + rate = s_rates[i]; + best = i; + } + } + return best; +} + static int asf_streaming_parse_header(int fd, streaming_ctrl_t* streaming_ctrl) { ASF_header_t asfh; - ASF_obj_header_t objh; - ASF_file_header_t fileh; - ASF_stream_header_t streamh; ASF_stream_chunck_t chunk; asf_http_streaming_ctrl_t* asf_ctrl = (asf_http_streaming_ctrl_t*) 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; @@ -219,35 +239,34 @@ return -1; } - pos += sizeof(asfh); + start = sizeof(asfh); - while(size - pos >= (int)sizeof(objh)) { - memcpy(&objh,buffer+pos,sizeof(objh)); - le2me_ASF_obj_header_t(&objh); - - switch(ASF_LOAD_GUID_PREFIX(objh.guid)) { - case 0x8CABDCA1 : // File header - pos += sizeof(objh); - memcpy(&fileh,buffer + pos,sizeof(fileh)); - le2me_ASF_file_header_t(&fileh); + 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; + le2me_ASF_file_header_t(fileh); /* if(fileh.packetsize != fileh.packetsize2) { printf("Error packetsize check don't match\n"); return -1; } */ - asf_ctrl->packet_size = fileh.max_packet_size; + asf_ctrl->packet_size = fileh->max_packet_size; // before playing. // preroll: time in ms to bufferize before playing - streaming_ctrl->prebuffer_size = (unsigned int)((double)((double)fileh.preroll/1000)*((double)fileh.max_bitrate/8)); - pos += sizeof(fileh); - break; - case 0xB7DC0791 : // stream header - pos += sizeof(objh); - memcpy(&streamh,buffer + pos,sizeof(streamh)); - le2me_ASF_stream_header_t(&streamh); - pos += sizeof(streamh) + streamh.type_size; - switch(ASF_LOAD_GUID_PREFIX(streamh.type)) { + 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; + le2me_ASF_stream_header_t(streamh); + switch(ASF_LOAD_GUID_PREFIX(streamh->type)) { case 0xF8699E40 : // audio stream if(asf_ctrl->audio_streams == NULL){ asf_ctrl->audio_streams = (int*)malloc(sizeof(int)); @@ -257,11 +276,7 @@ asf_ctrl->audio_streams = (int*)realloc(asf_ctrl->audio_streams, asf_ctrl->n_audio*sizeof(int)); } - asf_ctrl->audio_streams[asf_ctrl->n_audio-1] = streamh.stream_no; - pos += streamh.stream_size; - if( streaming_ctrl->bandwidth==0 ) { - asf_ctrl->audio_id = streamh.stream_no; - } + asf_ctrl->audio_streams[asf_ctrl->n_audio-1] = streamh->stream_no; break; case 0xBC19EFC0 : // video stream if(asf_ctrl->video_streams == NULL){ @@ -272,57 +287,127 @@ asf_ctrl->video_streams = (int*)realloc(asf_ctrl->video_streams, asf_ctrl->n_video*sizeof(int)); } - asf_ctrl->video_streams[asf_ctrl->n_video-1] = streamh.stream_no; - if( streaming_ctrl->bandwidth==0 ) { - asf_ctrl->video_id = streamh.stream_no; - } + asf_ctrl->video_streams[asf_ctrl->n_video-1] = streamh->stream_no; break; } - break; - case 0x7bf875ce : // stream bitrate properties object -printf("Stream bitrate properties object\n"); -printf("Max bandwidth set to %d\n", streaming_ctrl->bandwidth); - asf_ctrl->audio_id = 0; - asf_ctrl->video_id = 0; - if( streaming_ctrl->bandwidth!=0 ) { - int stream_count, stream_id, max_bitrate; - char *ptr = buffer+pos; - unsigned int total_bitrate=0, p_id=0, p_br=0; - int i; - ptr += sizeof(objh); + } + + // 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 + mp_msg(MSGT_NETWORK, MSGL_V, "Stream bitrate properties object\n"); + int stream_count; + char *ptr = &buffer[pos]; + stream_count = le2me_16(*(uint16_t*)ptr); ptr += sizeof(uint16_t); -printf(" stream count=[0x%x][%u]\n", stream_count, stream_count ); - for( i=0 ; i<stream_count && ptr<((char*)buffer+pos+objh.size) ; i++ ) { - stream_id = le2me_16(*(uint16_t*)ptr); + if (ptr > &buffer[size]) goto len_err_out; + 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; + id = le2me_16(*(uint16_t*)ptr); ptr += sizeof(uint16_t); - memcpy(&max_bitrate, ptr, sizeof(uint32_t));// workaround unaligment bug on sparc - max_bitrate = le2me_32(max_bitrate); - if( stream_id==1 ) total_bitrate = max_bitrate; - else if( total_bitrate+max_bitrate>streaming_ctrl->bandwidth ) { - total_bitrate += p_br; -printf("total_bitrate=%d\n", total_bitrate); -printf("id=%d\n", p_id); - break; - } + if (ptr > &buffer[size]) goto len_err_out; + memcpy(&rate, ptr, sizeof(uint32_t));// workaround unaligment bug on sparc ptr += sizeof(uint32_t); -printf(" stream id=[0x%x][%u]\n", stream_id, stream_id ); -printf(" max bitrate=[0x%x][%u]\n", max_bitrate, max_bitrate ); - p_id = stream_id; - p_br = max_bitrate; + if (ptr > &buffer[size]) goto len_err_out; + rate = le2me_32(rate); + 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; + } + } } - asf_ctrl->audio_id = 1; - asf_ctrl->video_id = p_id; - } - pos += objh.size; - break; - default : - pos += objh.size; - 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; } } - free(buffer); + // 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, "bandwidth too small, " + "file cannot be played!\n"); + 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, "bandwidth too small, " + "deselected audio stream\n"); + 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, "bandwidth too small, " + "deselected video stream\n"); + video_id = -2; + } + return 1; + +len_err_out: + mp_msg(MSGT_NETWORK, MSGL_FATAL, "Invalid length in ASF header!\n"); + if (buffer) free(buffer); + if (v_rates) free(v_rates); + if (a_rates) free(a_rates); + return -1; } int @@ -531,10 +616,11 @@ if(asf_http_ctrl->n_audio > 0) { for( i=0; i<asf_http_ctrl->n_audio ; i++ ) { stream_id = asf_http_ctrl->audio_streams[i]; - if(stream_id == asf_http_ctrl->audio_id || !asf_http_ctrl->audio_id) { + if(stream_id == asf_http_ctrl->audio_id) { enable = 0; } else { enable = 2; + continue; } asf_nb_stream++; ptr += sprintf(ptr, "ffff:%d:%d ", stream_id, enable); @@ -543,10 +629,11 @@ if(asf_http_ctrl->n_video > 0) { for( i=0; i<asf_http_ctrl->n_video ; i++ ) { stream_id = asf_http_ctrl->video_streams[i]; - if(stream_id == asf_http_ctrl->video_id || !asf_http_ctrl->video_id) { + if(stream_id == asf_http_ctrl->video_id) { enable = 0; } else { enable = 2; + continue; } asf_nb_stream++; ptr += sprintf(ptr, "ffff:%d:%d ", stream_id, enable);
--- a/libmpdemux/asfheader.c Fri Dec 24 14:55:54 2004 +0000 +++ b/libmpdemux/asfheader.c Sat Dec 25 11:31:32 2004 +0000 @@ -36,12 +36,24 @@ #define ASF_GUID_PREFIX_content_desc 0x75b22633 #define ASF_GUID_PREFIX_stream_group 0x7bf875ce +/* +const char asf_audio_stream_guid[16] = {0x40, 0x9e, 0x69, 0xf8, + 0x4d, 0x5b, 0xcf, 0x11, 0xa8, 0xfd, 0x00, 0x80, 0x5f, 0x5c, 0x44, 0x2b}; +const char asf_video_stream_guid[16] = {0xc0, 0xef, 0x19, 0xbc, + 0x4d, 0x5b, 0xcf, 0x11, 0xa8, 0xfd, 0x00, 0x80, 0x5f, 0x5c, 0x44, 0x2b}; +*/ +const char asf_stream_header_guid[16] = {0x91, 0x07, 0xdc, 0xb7, + 0xb7, 0xa9, 0xcf, 0x11, 0x8e, 0xe6, 0x00, 0xc0, 0x0c, 0x20, 0x53, 0x65}; +const char asf_file_header_guid[16] = {0xa1, 0xdc, 0xab, 0x8c, + 0x47, 0xa9, 0xcf, 0x11, 0x8e, 0xe4, 0x00, 0xc0, 0x0c, 0x20, 0x53, 0x65}; +const char asf_content_desc_guid[16] = {0x33, 0x26, 0xb2, 0x75, + 0x8e, 0x66, 0xcf, 0x11, 0xa6, 0xd9, 0x00, 0xaa, 0x00, 0x62, 0xce, 0x6c}; +const char asf_stream_group_guid[16] = {0xce, 0x75, 0xf8, 0x7b, + 0x8d, 0x46, 0xd1, 0x11, 0x8d, 0x82, 0x00, 0x60, 0x97, 0xc9, 0xa2, 0xb2}; +const char asf_data_chunk_guid[16] = {0x36, 0x26, 0xb2, 0x75, + 0x8e, 0x66, 0xcf, 0x11, 0xa6, 0xd9, 0x00, 0xaa, 0x00, 0x62, 0xce, 0x6c}; static ASF_header_t asfh; -static ASF_obj_header_t objh; -static ASF_file_header_t fileh; -static ASF_stream_header_t streamh; -static ASF_content_description_t contenth; unsigned char* asf_packet=NULL; int asf_scrambling_h=1; @@ -129,55 +141,84 @@ extern void print_wave_header(WAVEFORMATEX *h); extern void print_video_header(BITMAPINFOHEADER *h); +int find_asf_guid(char *buf, const char *guid, int cur_pos, int buf_len) +{ + int i; + for (i = cur_pos; i < buf_len - 19; i++) { + if (memcmp(&buf[i], guid, 16) == 0) + return i + 16 + 8; // point after guid + length + } + return -1; +} + int read_asf_header(demuxer_t *demuxer){ - static unsigned char buffer[2048]; + unsigned int hdr_len = asfh.objh.size - sizeof(asfh); + 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; -#if 1 - //printf("ASF file! (subchunks: %d)\n",asfh.cno); -while(!stream_eof(demuxer->stream)){ - int pos,endpos; - pos=stream_tell(demuxer->stream); - stream_read(demuxer->stream,(char*) &objh,sizeof(objh)); - le2me_ASF_obj_header_t(&objh); - if(stream_eof(demuxer->stream)) break; // EOF - endpos=pos+objh.size; -// for(i=0;i<16;i++) printf("%02X ",objh.guid[i]); - //printf("0x%08X [%s] %d\n",pos, asf_chunk_type(objh.guid),(int) objh.size); - switch(ASF_LOAD_GUID_PREFIX(objh.guid)){ - case ASF_GUID_PREFIX_stream_header: - stream_read(demuxer->stream,(char*) &streamh,sizeof(streamh)); - le2me_ASF_stream_header_t(&streamh); - if(verbose>0){ - 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",stream_tell(demuxer->stream)); - } - if(streamh.type_size>2048 || streamh.stream_size>2048){ - mp_msg(MSGT_HEADER,MSGL_FATAL,"FATAL: header size bigger than 2048 bytes (%d,%d)!\n" - "Please contact mplayer authors, and upload/send this file.\n", - (int)streamh.type_size,(int)streamh.stream_size); - return 0; - } - // type-specific data: - stream_read(demuxer->stream,(char*) buffer,streamh.type_size); - switch(ASF_LOAD_GUID_PREFIX(streamh.type)){ + if (hdr_len > 64 * 1024) { + mp_msg(MSGT_HEADER, MSGL_FATAL, + "FATAL: header size bigger than 64 kB (%d)!\n" + "Please contact MPlayer authors, and upload/send this file.\n", + hdr_len); + return 0; + } + hdr = malloc(hdr_len); + if (!hdr) { + mp_msg(MSGT_HEADER, MSGL_FATAL, "Could not allocate %d bytes for header\n", + hdr_len); + return 0; + } + stream_read(demuxer->stream, hdr, hdr_len); + if (stream_eof(demuxer->stream)) { + mp_msg(MSGT_HEADER, MSGL_FATAL, + "EOF while reading asf header, broken/incomplete file?\n"); + goto err_out; + } + + // find stream headers + pos = 0; + while ((pos = find_asf_guid(hdr, asf_stream_header_guid, pos, hdr_len)) >= 0) + { + ASF_stream_header_t *streamh = (ASF_stream_header_t *)&hdr[pos]; + char *buffer; + 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); - ++audio_streams; - sh_audio->wf=calloc((streamh.type_size<sizeof(WAVEFORMATEX))?sizeof(WAVEFORMATEX):streamh.type_size,1); - memcpy(sh_audio->wf,buffer,streamh.type_size); + sh_audio_t* sh_audio=new_sh_audio(demuxer,streamh->stream_no & 0x7F); + ++audio_streams; + sh_audio->wf=calloc((streamh->type_size<sizeof(WAVEFORMATEX))?sizeof(WAVEFORMATEX):streamh->type_size,1); + memcpy(sh_audio->wf,buffer,streamh->type_size); le2me_WAVEFORMATEX(sh_audio->wf); if(verbose>=1) print_wave_header(sh_audio->wf); - if(ASF_LOAD_GUID_PREFIX(streamh.concealment)==ASF_GUID_PREFIX_audio_conceal_interleave){ - stream_read(demuxer->stream,(char*) buffer,streamh.stream_size); + if(ASF_LOAD_GUID_PREFIX(streamh->concealment)==ASF_GUID_PREFIX_audio_conceal_interleave){ + buffer = &hdr[pos]; + pos += streamh->stream_size; + if (pos > hdr_len) goto len_err_out; asf_scrambling_h=buffer[0]; asf_scrambling_w=(buffer[2]<<8)|buffer[1]; asf_scrambling_b=(buffer[4]<<8)|buffer[3]; @@ -190,8 +231,8 @@ break; } case ASF_GUID_PREFIX_video_stream: { - sh_video_t* sh_video=new_sh_video(demuxer,streamh.stream_no & 0x7F); - unsigned int len=streamh.type_size-(4+4+1+2); + sh_video_t* sh_video=new_sh_video(demuxer,streamh->stream_no & 0x7F); + unsigned int 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(BITMAPINFOHEADER))?sizeof(BITMAPINFOHEADER):len,1); @@ -207,125 +248,139 @@ } // stream-specific data: // stream_read(demuxer->stream,(char*) buffer,streamh.stream_size); - break; -// case ASF_GUID_PREFIX_header_2_0: return "guid_header_2_0"; - case ASF_GUID_PREFIX_file_header: // guid_file_header - stream_read(demuxer->stream,(char*) &fileh,sizeof(fileh)); - le2me_ASF_file_header_t(&fileh); - //mp_msg(MSGT_HEADER,MSGL_V,"ASF: packets: %d flags: %d pack_size: %d frame_size: %d\n",(int)fileh.packets,(int)fileh.flags,(int)fileh.packetsize,(int)fileh.frame_size); - 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; + } + + // 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.send_duration/10000000LL; - break; - case ASF_GUID_PREFIX_data_chunk: // guid_data_chunk - demuxer->movi_start=stream_tell(demuxer->stream)+26; - demuxer->movi_end=endpos; - mp_msg(MSGT_HEADER,MSGL_V,"Found movie at 0x%X - 0x%X\n",(int)demuxer->movi_start,(int)demuxer->movi_end); - break; + asf_packetrate=fileh->max_bitrate/8.0/(double)asf_packetsize; + asf_movielength=fileh->send_duration/10000000LL; + } -// case ASF_GUID_PREFIX_index_chunk: return "guid_index_chunk"; - - case ASF_GUID_PREFIX_content_desc: // Content description - { + // 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; - stream_read(demuxer->stream,(char*) &contenth,sizeof(contenth)); - le2me_ASF_content_description_t(&contenth); + 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( contenth.title_size!=0 ) { - string=(char*)malloc(contenth.title_size); - stream_read(demuxer->stream, string, contenth.title_size); + if( contenth->title_size!=0 ) { + string = &hdr[pos]; + pos += contenth->title_size; + if (pos > hdr_len) goto len_err_out; if(verbose>0) - print_asf_string(" Title: ", string, contenth.title_size); + print_asf_string(" Title: ", string, contenth->title_size); else - pack_asf_string(string, contenth.title_size); + pack_asf_string(string, contenth->title_size); demux_info_add(demuxer, "name", string); } // extract the author - if( contenth.author_size!=0 ) { - string=(char*)realloc((void*)string, contenth.author_size); - stream_read(demuxer->stream, string, contenth.author_size); + if( contenth->author_size!=0 ) { + string = &hdr[pos]; + pos += contenth->author_size; + if (pos > hdr_len) goto len_err_out; if(verbose>0) - print_asf_string(" Author: ", string, contenth.author_size); + print_asf_string(" Author: ", string, contenth->author_size); else - pack_asf_string(string, contenth.author_size); + pack_asf_string(string, contenth->author_size); demux_info_add(demuxer, "author", string); } // extract the copyright - if( contenth.copyright_size!=0 ) { - string=(char*)realloc((void*)string, contenth.copyright_size); - stream_read(demuxer->stream, string, contenth.copyright_size); + if( contenth->copyright_size!=0 ) { + string = &hdr[pos]; + pos += contenth->copyright_size; + if (pos > hdr_len) goto len_err_out; if(verbose>0) - print_asf_string(" Copyright: ", string, contenth.copyright_size); + print_asf_string(" Copyright: ", string, contenth->copyright_size); else - pack_asf_string(string, contenth.copyright_size); + pack_asf_string(string, contenth->copyright_size); demux_info_add(demuxer, "copyright", string); } // extract the comment - if( contenth.comment_size!=0 ) { - string=(char*)realloc((void*)string, contenth.comment_size); - stream_read(demuxer->stream, string, contenth.comment_size); + if( contenth->comment_size!=0 ) { + string = &hdr[pos]; + pos += contenth->comment_size; + if (pos > hdr_len) goto len_err_out; if(verbose>0) - print_asf_string(" Comment: ", string, contenth.comment_size); + print_asf_string(" Comment: ", string, contenth->comment_size); else - pack_asf_string(string, contenth.comment_size); + pack_asf_string(string, contenth->comment_size); demux_info_add(demuxer, "comments", string); } // extract the rating - if( contenth.rating_size!=0 ) { - string=(char*)realloc((void*)string, contenth.rating_size); - stream_read(demuxer->stream, string, contenth.rating_size); + if( contenth->rating_size!=0 ) { + string = &hdr[pos]; + pos += contenth->rating_size; + if (pos > hdr_len) goto len_err_out; if(verbose>0) - print_asf_string(" Rating: ", string, contenth.rating_size); + print_asf_string(" Rating: ", string, contenth->rating_size); } mp_msg(MSGT_HEADER,MSGL_V,"\n"); - free(string); - break; - } - case ASF_GUID_PREFIX_stream_group: { + } + + // find content header + pos = find_asf_guid(hdr, asf_stream_group_guid, 0, hdr_len); + if (pos >= 0) { uint16_t stream_id, i; uint32_t max_bitrate; - char *object=NULL, *ptr=NULL; + char *ptr = &hdr[pos]; mp_msg(MSGT_HEADER,MSGL_V,"============ ASF Stream group == START ===\n"); - mp_msg(MSGT_HEADER,MSGL_V," object size = %d\n", (int)objh.size); - object = (char*)malloc(objh.size); - if( object==NULL ) { - mp_msg(MSGT_HEADER,MSGL_V,"Memory allocation failed\n"); - return 0; - } - stream_read( demuxer->stream, object, objh.size ); - // FIXME: We need some endian handling below... - ptr = object; stream_count = le2me_16(*(uint16_t*)ptr); ptr += sizeof(uint16_t); + if (ptr > &hdr[hdr_len]) goto len_err_out; if(stream_count > 0) streams = (uint32_t*)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 && ptr<((char*)object+objh.size) ; i++ ) { + for( i=0 ; i<stream_count ; i++ ) { stream_id = le2me_16(*(uint16_t*)ptr); ptr += sizeof(uint16_t); + if (ptr > &hdr[hdr_len]) goto len_err_out; memcpy(&max_bitrate, ptr, sizeof(uint32_t));// workaround unaligment bug on sparc max_bitrate = le2me_32(max_bitrate); ptr += sizeof(uint32_t); + if (ptr > &hdr[hdr_len]) goto len_err_out; 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( object ); - break; - } - } // switch GUID - - if(ASF_LOAD_GUID_PREFIX(objh.guid)==ASF_GUID_PREFIX_data_chunk) break; // movi chunk - - if(!stream_seek(demuxer->stream,endpos)) break; -} // while EOF + } + 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, "No data chunk following header!\n"); + return 0; + } + // read length of chunk + stream_read(demuxer->stream, (char *)&data_len, sizeof(data_len)); + le2me_64(data_len); + 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 MPLAYER_NETWORK if( demuxer->stream->streaming_ctrl!=NULL ) { @@ -346,7 +401,9 @@ 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); @@ -368,6 +425,12 @@ } #endif -#endif return 1; + +len_err_out: + mp_msg(MSGT_HEADER, MSGL_FATAL, "Invalid length in ASF header!\n"); +err_out: + if (hdr) free(hdr); + if (streams) free(streams); + return 0; }