[MPlayer-dev-eng] [PATCH] make multi-stream mms-over-http work (-bandwidth option)
Reimar Döffinger
Reimar.Doeffinger at stud.uni-karlsruhe.de
Sat Dec 11 22:52:35 CET 2004
Hi,
currently MPlayer can only play the lowest-quality streams in many asf
files. This is caused because MPlayer scans only the "top level" of the
properties-tree in the asf header, thus only detecting the lowres
streams.
The attached patch fixes this by simply brute-force scanning the whole
header for the appropriate guids - this seems the simplest and most
sensible approach to me (why do people always want such complicated
structures/parsers when like in a video container it's completely useless?).
In addition I also modified the networking code so that it tries to make
a sensible decision which streams to select (based on -bandwidth
setting) and modified the request it sends to the server (some servers just send the default streams when e.g. you send it more that two things in the stream-switch-entry= ).
Now the most important thing is testing, so if you have any asf files or
know any internet streams, please test it on them.
I know this patch changes a lot of code, but I didn't see any way to
make it smaller :-(.
Tell me what you think of this patch, and especially when would be a
good time to apply it (before the release (btw. when is that going to
be? ;-) ) or after or whatever).
Greetings,
Reimar Döffinger
-------------- next part --------------
Index: libmpdemux/asf_streaming.c
===================================================================
RCS file: /cvsroot/mplayer/main/libmpdemux/asf_streaming.c,v
retrieving revision 1.49
diff -u -r1.49 asf_streaming.c
--- libmpdemux/asf_streaming.c 21 Jul 2004 10:18:29 -0000 1.49
+++ libmpdemux/asf_streaming.c 11 Dec 2004 21:37:04 -0000
@@ -141,18 +141,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 +238,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 +275,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 +286,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
+ rate = le2me_32(rate);
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;
+ 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);
+ if (ptr > &buffer[size]) goto len_err_out;
+ 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;
+ }
+ }
+ // 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 +615,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 +628,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);
Index: libmpdemux/asfheader.c
===================================================================
RCS file: /cvsroot/mplayer/main/libmpdemux/asfheader.c,v
retrieving revision 1.39
diff -u -r1.39 asfheader.c
--- libmpdemux/asfheader.c 17 Apr 2004 10:31:38 -0000 1.39
+++ libmpdemux/asfheader.c 11 Dec 2004 21:37:06 -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;
- 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;
+ }
-// case ASF_GUID_PREFIX_index_chunk: return "guid_index_chunk";
+ // 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;
+ }
- 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;
}
More information about the MPlayer-dev-eng
mailing list