1 // .asf fileformat docs from http://divx.euro.ru
8 extern int verbose
; // defined in mplayer.c
20 #define ASF_LOAD_GUID_PREFIX(guid) (*(uint32_t *)(guid))
22 #define ASF_LOAD_GUID_PREFIX(guid) \
23 ((guid)[3] << 24 | (guid)[2] << 16 | (guid)[1] << 8 | (guid)[0])
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;
51 double asf_packetrate
=0;
52 int asf_movielength
=0;
56 // the variable string is modify in this function
57 void pack_asf_string(char* string
, int length
) {
59 if( string
==NULL
) return;
60 for( i
=0, j
=0; i
<length
&& string
[i
]!='\0'; i
+=2, j
++) {
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
) {
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
:
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";
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
]);
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
123 mp_msg(MSGT_HEADER
,MSGL_V
,"ASF_check: invalid subchunks_no %d\n",(int) asfh
.cno
);
124 return 0; // invalid header???
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
;
137 uint16_t stream_count
=0;
142 //printf("ASF file! (subchunks: %d)\n",asfh.cno);
143 while(!stream_eof(demuxer
->stream
)){
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
);
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
);
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);
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
;
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;
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);
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;
208 // stream-specific data:
209 // stream_read(demuxer->stream,(char*) buffer,streamh.stream_size);
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;
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
);
228 // case ASF_GUID_PREFIX_index_chunk: return "guid_index_chunk";
230 case ASF_GUID_PREFIX_content_desc
: // Content description
233 stream_read(demuxer
->stream
,(char*) &contenth
,sizeof(contenth
));
234 le2me_ASF_content_description_t(&contenth
);
235 mp_msg(MSGT_HEADER
,MSGL_V
,"\n");
237 if( contenth
.title_size
!=0 ) {
238 string
=(char*)malloc(contenth
.title_size
);
239 stream_read(demuxer
->stream
, string
, contenth
.title_size
);
241 print_asf_string(" Title: ", string
, contenth
.title_size
);
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
);
251 print_asf_string(" Author: ", string
, contenth
.author_size
);
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
);
261 print_asf_string(" Copyright: ", string
, contenth
.copyright_size
);
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
);
271 print_asf_string(" Comment: ", string
, contenth
.comment_size
);
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
);
281 print_asf_string(" Rating: ", string
, contenth
.rating_size
);
283 mp_msg(MSGT_HEADER
,MSGL_V
,"\n");
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
);
295 printf("Memory allocation failed\n");
298 stream_read( demuxer
->stream
, object
, objh
.size
);
299 // FIXME: We need some endian handling below...
301 stream_count
= le2me_16(*(uint16_t*)ptr
);
302 ptr
+= sizeof(uint16_t);
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");
323 if(ASF_LOAD_GUID_PREFIX(objh
.guid
)==ASF_GUID_PREFIX_data_chunk
) break; // movi chunk
325 if(!stream_seek(demuxer
->stream
,endpos
)) break;
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
;
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
) {
344 } else if(demuxer
->a_streams
[id
] && rate
> ar
) {
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
;
357 mp_msg(MSGT_HEADER
,MSGL_ERR
,"ASF: no audio or video headers found - broken file?\n");
360 demuxer
->video
->id
=-2; // audio-only
361 } else if (best_video
> 0 && demuxer
->video
->id
== -1) demuxer
->video
->id
= best_video
;
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
);