10l fix by Jindrich Makovicka
[mplayer/greg.git] / libmpdemux / asfheader.c
blob8c816865facf7a6d966df2e17002f9d30d94035c
1 // .asf fileformat docs from http://divx.euro.ru
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <unistd.h>
8 extern int verbose; // defined in mplayer.c
10 #include "config.h"
11 #include "mp_msg.h"
13 #include "stream.h"
14 #include "demuxer.h"
15 #include "stheader.h"
17 #include "asf.h"
19 #ifdef ARCH_X86
20 #define ASF_LOAD_GUID_PREFIX(guid) (*(uint32_t *)(guid))
21 #else
22 #define ASF_LOAD_GUID_PREFIX(guid) \
23 ((guid)[3] << 24 | (guid)[2] << 16 | (guid)[1] << 8 | (guid)[0])
24 #endif
26 #define ASF_GUID_PREFIX_audio_stream 0xF8699E40
27 #define ASF_GUID_PREFIX_video_stream 0xBC19EFC0
28 #define ASF_GUID_PREFIX_audio_conceal_none 0x49f1a440
29 #define ASF_GUID_PREFIX_audio_conceal_interleave 0xbfc3cd50
30 #define ASF_GUID_PREFIX_header 0x75B22630
31 #define ASF_GUID_PREFIX_data_chunk 0x75b22636
32 #define ASF_GUID_PREFIX_index_chunk 0x33000890
33 #define ASF_GUID_PREFIX_stream_header 0xB7DC0791
34 #define ASF_GUID_PREFIX_header_2_0 0xD6E229D1
35 #define ASF_GUID_PREFIX_file_header 0x8CABDCA1
36 #define ASF_GUID_PREFIX_content_desc 0x75b22633
37 #define ASF_GUID_PREFIX_stream_group 0x7bf875ce
40 static ASF_header_t asfh;
41 static ASF_obj_header_t objh;
42 static ASF_file_header_t fileh;
43 static ASF_stream_header_t streamh;
44 static ASF_content_description_t contenth;
46 unsigned char* asf_packet=NULL;
47 int asf_scrambling_h=1;
48 int asf_scrambling_w=1;
49 int asf_scrambling_b=1;
50 int asf_packetsize=0;
51 double asf_packetrate=0;
52 int asf_movielength=0;
54 //int i;
56 // the variable string is modify in this function
57 void pack_asf_string(char* string, int length) {
58 int i,j;
59 if( string==NULL ) return;
60 for( i=0, j=0; i<length && string[i]!='\0'; i+=2, j++) {
61 string[j]=string[i];
63 string[j]='\0';
66 // the variable string is modify in this function
67 void print_asf_string(const char* name, char* string, int length) {
68 pack_asf_string(string, length);
69 mp_msg(MSGT_HEADER,MSGL_V,"%s%s\n", name, string);
72 static char* asf_chunk_type(unsigned char* guid) {
73 static char tmp[60];
74 char *p;
75 int i;
77 switch(ASF_LOAD_GUID_PREFIX(guid)){
78 case ASF_GUID_PREFIX_audio_stream:
79 return "guid_audio_stream";
80 case ASF_GUID_PREFIX_video_stream:
81 return "guid_video_stream";
82 case ASF_GUID_PREFIX_audio_conceal_none:
83 return "guid_audio_conceal_none";
84 case ASF_GUID_PREFIX_audio_conceal_interleave:
85 return "guid_audio_conceal_interleave";
86 case ASF_GUID_PREFIX_header:
87 return "guid_header";
88 case ASF_GUID_PREFIX_data_chunk:
89 return "guid_data_chunk";
90 case ASF_GUID_PREFIX_index_chunk:
91 return "guid_index_chunk";
92 case ASF_GUID_PREFIX_stream_header:
93 return "guid_stream_header";
94 case ASF_GUID_PREFIX_header_2_0:
95 return "guid_header_2_0";
96 case ASF_GUID_PREFIX_file_header:
97 return "guid_file_header";
98 case ASF_GUID_PREFIX_content_desc:
99 return "guid_content_desc";
100 default:
101 strcpy(tmp, "unknown guid ");
102 p = tmp + strlen(tmp);
103 for (i = 0; i < 16; i++) {
104 if ((1 << i) & ((1<<4) | (1<<6) | (1<<8))) *p++ = '-';
105 sprintf(p, "%02x", guid[i]);
106 p += 2;
108 return tmp;
112 int asf_check_header(demuxer_t *demuxer){
113 unsigned char asfhdrguid[16]={0x30,0x26,0xB2,0x75,0x8E,0x66,0xCF,0x11,0xA6,0xD9,0x00,0xAA,0x00,0x62,0xCE,0x6C};
114 stream_read(demuxer->stream,(char*) &asfh,sizeof(asfh)); // header obj
115 le2me_ASF_header_t(&asfh); // swap to machine endian
116 // for(i=0;i<16;i++) printf(" %02X",temp[i]);printf("\n");
117 // for(i=0;i<16;i++) printf(" %02X",asfhdrguid[i]);printf("\n");
118 if(memcmp(asfhdrguid,asfh.objh.guid,16)){
119 mp_msg(MSGT_HEADER,MSGL_V,"ASF_check: not ASF guid!\n");
120 return 0; // not ASF guid
122 if(asfh.cno>256){
123 mp_msg(MSGT_HEADER,MSGL_V,"ASF_check: invalid subchunks_no %d\n",(int) asfh.cno);
124 return 0; // invalid header???
126 return 1;
129 extern void print_wave_header(WAVEFORMATEX *h);
130 extern void print_video_header(BITMAPINFOHEADER *h);
132 int read_asf_header(demuxer_t *demuxer){
133 static unsigned char buffer[2048];
134 uint32_t* streams = NULL;
135 int audio_streams=0;
136 int video_streams=0;
137 uint16_t stream_count=0;
138 int best_video = -1;
139 int best_audio = -1;
141 #if 1
142 //printf("ASF file! (subchunks: %d)\n",asfh.cno);
143 while(!stream_eof(demuxer->stream)){
144 int pos,endpos;
145 pos=stream_tell(demuxer->stream);
146 stream_read(demuxer->stream,(char*) &objh,sizeof(objh));
147 le2me_ASF_obj_header_t(&objh);
148 if(stream_eof(demuxer->stream)) break; // EOF
149 endpos=pos+objh.size;
150 // for(i=0;i<16;i++) printf("%02X ",objh.guid[i]);
151 //printf("0x%08X [%s] %d\n",pos, asf_chunk_type(objh.guid),(int) objh.size);
152 switch(ASF_LOAD_GUID_PREFIX(objh.guid)){
153 case ASF_GUID_PREFIX_stream_header:
154 stream_read(demuxer->stream,(char*) &streamh,sizeof(streamh));
155 le2me_ASF_stream_header_t(&streamh);
156 if(verbose>0){
157 mp_msg(MSGT_HEADER,MSGL_V,"stream type: %s\n",asf_chunk_type(streamh.type));
158 mp_msg(MSGT_HEADER,MSGL_V,"stream concealment: %s\n",asf_chunk_type(streamh.concealment));
159 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);
160 mp_msg(MSGT_HEADER,MSGL_V,"unk1: %lX unk2: %X\n",(unsigned long)streamh.unk1,(unsigned int)streamh.unk2);
161 mp_msg(MSGT_HEADER,MSGL_V,"FILEPOS=0x%X\n",stream_tell(demuxer->stream));
163 if(streamh.type_size>2048 || streamh.stream_size>2048){
164 mp_msg(MSGT_HEADER,MSGL_FATAL,"FATAL: header size bigger than 2048 bytes (%d,%d)!\n"
165 "Please contact mplayer authors, and upload/send this file.\n",
166 (int)streamh.type_size,(int)streamh.stream_size);
167 return 0;
169 // type-specific data:
170 stream_read(demuxer->stream,(char*) buffer,streamh.type_size);
171 switch(ASF_LOAD_GUID_PREFIX(streamh.type)){
172 case ASF_GUID_PREFIX_audio_stream: {
173 sh_audio_t* sh_audio=new_sh_audio(demuxer,streamh.stream_no & 0x7F);
174 ++audio_streams;
175 sh_audio->wf=calloc((streamh.type_size<sizeof(WAVEFORMATEX))?sizeof(WAVEFORMATEX):streamh.type_size,1);
176 memcpy(sh_audio->wf,buffer,streamh.type_size);
177 le2me_WAVEFORMATEX(sh_audio->wf);
178 if(verbose>=1) print_wave_header(sh_audio->wf);
179 if(ASF_LOAD_GUID_PREFIX(streamh.concealment)==ASF_GUID_PREFIX_audio_conceal_interleave){
180 stream_read(demuxer->stream,(char*) buffer,streamh.stream_size);
181 asf_scrambling_h=buffer[0];
182 asf_scrambling_w=(buffer[2]<<8)|buffer[1];
183 asf_scrambling_b=(buffer[4]<<8)|buffer[3];
184 asf_scrambling_w/=asf_scrambling_b;
185 } else {
186 asf_scrambling_b=asf_scrambling_h=asf_scrambling_w=1;
188 mp_msg(MSGT_HEADER,MSGL_V,"ASF: audio scrambling: %d x %d x %d\n",asf_scrambling_h,asf_scrambling_w,asf_scrambling_b);
189 //if(demuxer->audio->id==-1) demuxer->audio->id=streamh.stream_no & 0x7F;
190 break;
192 case ASF_GUID_PREFIX_video_stream: {
193 sh_video_t* sh_video=new_sh_video(demuxer,streamh.stream_no & 0x7F);
194 unsigned int len=streamh.type_size-(4+4+1+2);
195 ++video_streams;
196 // sh_video->bih=malloc(chunksize); memset(sh_video->bih,0,chunksize);
197 sh_video->bih=calloc((len<sizeof(BITMAPINFOHEADER))?sizeof(BITMAPINFOHEADER):len,1);
198 memcpy(sh_video->bih,&buffer[4+4+1+2],len);
199 le2me_BITMAPINFOHEADER(sh_video->bih);
200 //sh_video->fps=(float)sh_video->video.dwRate/(float)sh_video->video.dwScale;
201 //sh_video->frametime=(float)sh_video->video.dwScale/(float)sh_video->video.dwRate;
202 if(verbose>=1) print_video_header(sh_video->bih);
203 //asf_video_id=streamh.stream_no & 0x7F;
204 //if(demuxer->video->id==-1) demuxer->video->id=streamh.stream_no & 0x7F;
205 break;
208 // stream-specific data:
209 // stream_read(demuxer->stream,(char*) buffer,streamh.stream_size);
210 break;
211 // case ASF_GUID_PREFIX_header_2_0: return "guid_header_2_0";
212 case ASF_GUID_PREFIX_file_header: // guid_file_header
213 stream_read(demuxer->stream,(char*) &fileh,sizeof(fileh));
214 le2me_ASF_file_header_t(&fileh);
215 //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);
216 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);
217 asf_packetsize=fileh.max_packet_size;
218 asf_packet=malloc(asf_packetsize); // !!!
219 asf_packetrate=fileh.max_bitrate/8.0/(double)asf_packetsize;
220 asf_movielength=fileh.send_duration/10000000LL;
221 break;
222 case ASF_GUID_PREFIX_data_chunk: // guid_data_chunk
223 demuxer->movi_start=stream_tell(demuxer->stream)+26;
224 demuxer->movi_end=endpos;
225 mp_msg(MSGT_HEADER,MSGL_V,"Found movie at 0x%X - 0x%X\n",(int)demuxer->movi_start,(int)demuxer->movi_end);
226 break;
228 // case ASF_GUID_PREFIX_index_chunk: return "guid_index_chunk";
230 case ASF_GUID_PREFIX_content_desc: // Content description
232 char *string=NULL;
233 stream_read(demuxer->stream,(char*) &contenth,sizeof(contenth));
234 le2me_ASF_content_description_t(&contenth);
235 mp_msg(MSGT_HEADER,MSGL_V,"\n");
236 // extract the title
237 if( contenth.title_size!=0 ) {
238 string=(char*)malloc(contenth.title_size);
239 stream_read(demuxer->stream, string, contenth.title_size);
240 if(verbose>0)
241 print_asf_string(" Title: ", string, contenth.title_size);
242 else
243 pack_asf_string(string, contenth.title_size);
244 demux_info_add(demuxer, "name", string);
246 // extract the author
247 if( contenth.author_size!=0 ) {
248 string=(char*)realloc((void*)string, contenth.author_size);
249 stream_read(demuxer->stream, string, contenth.author_size);
250 if(verbose>0)
251 print_asf_string(" Author: ", string, contenth.author_size);
252 else
253 pack_asf_string(string, contenth.author_size);
254 demux_info_add(demuxer, "author", string);
256 // extract the copyright
257 if( contenth.copyright_size!=0 ) {
258 string=(char*)realloc((void*)string, contenth.copyright_size);
259 stream_read(demuxer->stream, string, contenth.copyright_size);
260 if(verbose>0)
261 print_asf_string(" Copyright: ", string, contenth.copyright_size);
262 else
263 pack_asf_string(string, contenth.copyright_size);
264 demux_info_add(demuxer, "copyright", string);
266 // extract the comment
267 if( contenth.comment_size!=0 ) {
268 string=(char*)realloc((void*)string, contenth.comment_size);
269 stream_read(demuxer->stream, string, contenth.comment_size);
270 if(verbose>0)
271 print_asf_string(" Comment: ", string, contenth.comment_size);
272 else
273 pack_asf_string(string, contenth.comment_size);
274 demux_info_add(demuxer, "comments", string);
276 // extract the rating
277 if( contenth.rating_size!=0 ) {
278 string=(char*)realloc((void*)string, contenth.rating_size);
279 stream_read(demuxer->stream, string, contenth.rating_size);
280 if(verbose>0)
281 print_asf_string(" Rating: ", string, contenth.rating_size);
283 mp_msg(MSGT_HEADER,MSGL_V,"\n");
284 free(string);
285 break;
287 case ASF_GUID_PREFIX_stream_group: {
288 uint16_t stream_id, i;
289 uint32_t max_bitrate;
290 char *object=NULL, *ptr=NULL;
291 printf("============ ASF Stream group == START ===\n");
292 printf(" object size = %d\n", (int)objh.size);
293 object = (char*)malloc(objh.size);
294 if( object==NULL ) {
295 printf("Memory allocation failed\n");
296 return 0;
298 stream_read( demuxer->stream, object, objh.size );
299 // FIXME: We need some endian handling below...
300 ptr = object;
301 stream_count = le2me_16(*(uint16_t*)ptr);
302 ptr += sizeof(uint16_t);
303 if(stream_count > 0)
304 streams = (uint32_t*)malloc(2*stream_count*sizeof(uint32_t));
305 printf(" stream count=[0x%x][%u]\n", stream_count, stream_count );
306 for( i=0 ; i<stream_count && ptr<((char*)object+objh.size) ; i++ ) {
307 stream_id = le2me_16(*(uint16_t*)ptr);
308 ptr += sizeof(uint16_t);
309 memcpy(&max_bitrate, ptr, sizeof(uint32_t));// workaround unaligment bug on sparc
310 max_bitrate = le2me_32(max_bitrate);
311 ptr += sizeof(uint32_t);
312 printf(" stream id=[0x%x][%u]\n", stream_id, stream_id );
313 printf(" max bitrate=[0x%x][%u]\n", max_bitrate, max_bitrate );
314 streams[2*i] = stream_id;
315 streams[2*i+1] = max_bitrate;
317 printf("============ ASF Stream group == END ===\n");
318 free( object );
319 break;
321 } // switch GUID
323 if(ASF_LOAD_GUID_PREFIX(objh.guid)==ASF_GUID_PREFIX_data_chunk) break; // movi chunk
325 if(!stream_seek(demuxer->stream,endpos)) break;
326 } // while EOF
328 if(streams) {
329 uint32_t vr = 0, ar = 0,i;
330 #ifdef MPLAYER_NETWORK
331 if( demuxer->stream->streaming_ctrl!=NULL ) {
332 if( demuxer->stream->streaming_ctrl->bandwidth!=0 && demuxer->stream->streaming_ctrl->data!=NULL ) {
333 best_audio = ((asf_http_streaming_ctrl_t*)demuxer->stream->streaming_ctrl->data)->audio_id;
334 best_video = ((asf_http_streaming_ctrl_t*)demuxer->stream->streaming_ctrl->data)->video_id;
336 } else
337 #endif
338 for(i = 0; i < stream_count; i++) {
339 uint32_t id = streams[2*i];
340 uint32_t rate = streams[2*i+1];
341 if(demuxer->v_streams[id] && rate > vr) {
342 vr = rate;
343 best_video = id;
344 } else if(demuxer->a_streams[id] && rate > ar) {
345 ar = rate;
346 best_audio = id;
349 free(streams);
352 mp_msg(MSGT_HEADER,MSGL_V,"ASF: %d audio and %d video streams found\n",audio_streams,video_streams);
353 if(!audio_streams) demuxer->audio->id=-2; // nosound
354 else if(best_audio > 0 && demuxer->audio->id == -1) demuxer->audio->id=best_audio;
355 if(!video_streams){
356 if(!audio_streams){
357 mp_msg(MSGT_HEADER,MSGL_ERR,"ASF: no audio or video headers found - broken file?\n");
358 return 0;
360 demuxer->video->id=-2; // audio-only
361 } else if (best_video > 0 && demuxer->video->id == -1) demuxer->video->id = best_video;
363 #if 0
364 if(verbose){
365 printf("ASF duration: %d\n",(int)fileh.duration);
366 printf("ASF start pts: %d\n",(int)fileh.start_timestamp);
367 printf("ASF end pts: %d\n",(int)fileh.end_timestamp);
369 #endif
371 #endif
372 return 1;