1 // .asf fileformat docs from http://divx.euro.ru
9 #include "libavutil/common.h"
10 #include "libavutil/intreadwrite.h"
14 #include "stream/stream.h"
21 #define ASF_LOAD_GUID_PREFIX(guid) (*(uint32_t *)(guid))
23 #define ASF_LOAD_GUID_PREFIX(guid) AV_RL32(guid)
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
38 #define ASF_GUID_PREFIX_ext_audio_stream 0x31178C9D
39 #define ASF_GUID_PREFIX_ext_stream_embed_stream_header 0x3AFB65E2
40 #define ASF_GUID_PREFIX_dvr_ms_timing_rep_data 0xFD3CC02A
41 #define ASF_GUID_PREFIX_dvr_ms_vid_frame_rep_data 0xDD6432CC
44 const char asf_audio_stream_guid[16] = {0x40, 0x9e, 0x69, 0xf8,
45 0x4d, 0x5b, 0xcf, 0x11, 0xa8, 0xfd, 0x00, 0x80, 0x5f, 0x5c, 0x44, 0x2b};
46 const char asf_video_stream_guid[16] = {0xc0, 0xef, 0x19, 0xbc,
47 0x4d, 0x5b, 0xcf, 0x11, 0xa8, 0xfd, 0x00, 0x80, 0x5f, 0x5c, 0x44, 0x2b};
49 const char asf_stream_header_guid
[16] = {0x91, 0x07, 0xdc, 0xb7,
50 0xb7, 0xa9, 0xcf, 0x11, 0x8e, 0xe6, 0x00, 0xc0, 0x0c, 0x20, 0x53, 0x65};
51 const char asf_file_header_guid
[16] = {0xa1, 0xdc, 0xab, 0x8c,
52 0x47, 0xa9, 0xcf, 0x11, 0x8e, 0xe4, 0x00, 0xc0, 0x0c, 0x20, 0x53, 0x65};
53 const char asf_content_desc_guid
[16] = {0x33, 0x26, 0xb2, 0x75,
54 0x8e, 0x66, 0xcf, 0x11, 0xa6, 0xd9, 0x00, 0xaa, 0x00, 0x62, 0xce, 0x6c};
55 const char asf_stream_group_guid
[16] = {0xce, 0x75, 0xf8, 0x7b,
56 0x8d, 0x46, 0xd1, 0x11, 0x8d, 0x82, 0x00, 0x60, 0x97, 0xc9, 0xa2, 0xb2};
57 const char asf_data_chunk_guid
[16] = {0x36, 0x26, 0xb2, 0x75,
58 0x8e, 0x66, 0xcf, 0x11, 0xa6, 0xd9, 0x00, 0xaa, 0x00, 0x62, 0xce, 0x6c};
59 const char asf_ext_stream_embed_stream_header
[16] = {0xe2, 0x65, 0xfb, 0x3a,
60 0xef, 0x47, 0xf2, 0x40, 0xac, 0x2c, 0x70, 0xa9, 0x0d, 0x71, 0xd3, 0x43};
61 const char asf_ext_stream_audio
[16] = {0x9d, 0x8c, 0x17, 0x31,
62 0xe1, 0x03, 0x28, 0x45, 0xb5, 0x82, 0x3d, 0xf9, 0xdb, 0x22, 0xf5, 0x03};
63 const char asf_ext_stream_header
[16] = {0xCB, 0xA5, 0xE6, 0x14,
64 0x72, 0xC6, 0x32, 0x43, 0x83, 0x99, 0xA9, 0x69, 0x52, 0x06, 0x5B, 0x5A};
65 const char asf_metadata_header
[16] = {0xea, 0xcb, 0xf8, 0xc5,
66 0xaf, 0x5b, 0x77, 0x48, 0x84, 0x67, 0xaa, 0x8c, 0x44, 0xfa, 0x4c, 0xca};
67 const char asf_content_encryption
[16] = {0xfb, 0xb3, 0x11, 0x22,
68 0x23, 0xbd, 0xd2, 0x11, 0xb4, 0xb7, 0x00, 0xa0, 0xc9, 0x55, 0xfc, 0x6e};
69 const char asf_dvr_ms_timing_rep_data
[16] = {0x2a, 0xc0, 0x3c,0xfd,
70 0xdb, 0x06, 0xfa, 0x4c, 0x80, 0x1c, 0x72, 0x12, 0xd3, 0x87, 0x45, 0xe4};
71 const char asf_dvr_ms_vid_frame_rep_data
[16] = {0xcc, 0x32, 0x64, 0xdd,
72 0x29, 0xe2, 0xdb, 0x40, 0x80, 0xf6, 0xd2, 0x63, 0x28, 0xd2, 0x76, 0x1f};
75 // must be 0 for metadata record, might be non-zero for metadata lib record
76 uint16_t lang_list_index
;
85 static char* get_ucs2str(const uint16_t* inbuf
, uint16_t inlen
)
87 char* outbuf
= calloc(inlen
, 2);
92 mp_msg(MSGT_HEADER
, MSGL_ERR
, MSGTR_MemAllocFailed
);
96 for (i
= 0; i
< inlen
/ 2; i
++) {
98 PUT_UTF8(AV_RL16(&inbuf
[i
]), tmp
, *q
++ = tmp
;)
103 static const char* asf_chunk_type(unsigned char* guid
) {
108 switch(ASF_LOAD_GUID_PREFIX(guid
)){
109 case ASF_GUID_PREFIX_audio_stream
:
110 return "guid_audio_stream";
111 case ASF_GUID_PREFIX_ext_audio_stream
:
112 return "guid_ext_audio_stream";
113 case ASF_GUID_PREFIX_ext_stream_embed_stream_header
:
114 return "guid_ext_stream_embed_stream_header";
115 case ASF_GUID_PREFIX_video_stream
:
116 return "guid_video_stream";
117 case ASF_GUID_PREFIX_audio_conceal_none
:
118 return "guid_audio_conceal_none";
119 case ASF_GUID_PREFIX_audio_conceal_interleave
:
120 return "guid_audio_conceal_interleave";
121 case ASF_GUID_PREFIX_header
:
122 return "guid_header";
123 case ASF_GUID_PREFIX_data_chunk
:
124 return "guid_data_chunk";
125 case ASF_GUID_PREFIX_index_chunk
:
126 return "guid_index_chunk";
127 case ASF_GUID_PREFIX_stream_header
:
128 return "guid_stream_header";
129 case ASF_GUID_PREFIX_header_2_0
:
130 return "guid_header_2_0";
131 case ASF_GUID_PREFIX_file_header
:
132 return "guid_file_header";
133 case ASF_GUID_PREFIX_content_desc
:
134 return "guid_content_desc";
135 case ASF_GUID_PREFIX_dvr_ms_timing_rep_data
:
136 return "guid_dvr_ms_timing_rep_data";
137 case ASF_GUID_PREFIX_dvr_ms_vid_frame_rep_data
:
138 return "guid_dvr_ms_vid_frame_rep_data";
140 strcpy(tmp
, "unknown guid ");
141 p
= tmp
+ strlen(tmp
);
142 for (i
= 0; i
< 16; i
++) {
143 if ((1 << i
) & ((1<<4) | (1<<6) | (1<<8))) *p
++ = '-';
144 sprintf(p
, "%02x", guid
[i
]);
151 int asf_check_header(demuxer_t
*demuxer
){
152 unsigned char asfhdrguid
[16]={0x30,0x26,0xB2,0x75,0x8E,0x66,0xCF,0x11,0xA6,0xD9,0x00,0xAA,0x00,0x62,0xCE,0x6C};
153 struct asf_priv
* asf
= calloc(1,sizeof(*asf
));
154 asf
->scrambling_h
=asf
->scrambling_w
=asf
->scrambling_b
=1;
155 stream_read(demuxer
->stream
,(char*) &asf
->header
,sizeof(asf
->header
)); // header obj
156 le2me_ASF_header_t(&asf
->header
); // swap to machine endian
157 // for(i=0;i<16;i++) printf(" %02X",temp[i]);printf("\n");
158 // for(i=0;i<16;i++) printf(" %02X",asfhdrguid[i]);printf("\n");
159 if(memcmp(asfhdrguid
,asf
->header
.objh
.guid
,16)){
160 mp_msg(MSGT_HEADER
,MSGL_V
,"ASF_check: not ASF guid!\n");
162 return 0; // not ASF guid
164 if(asf
->header
.cno
>256){
165 mp_msg(MSGT_HEADER
,MSGL_V
,"ASF_check: invalid subchunks_no %d\n",(int) asf
->header
.cno
);
167 return 0; // invalid header???
170 return DEMUXER_TYPE_ASF
;
173 void print_wave_header(WAVEFORMATEX
*h
, int verbose_level
);
174 void print_video_header(BITMAPINFOHEADER
*h
, int verbose_level
);
176 int find_asf_guid(char *buf
, const char *guid
, int cur_pos
, int buf_len
)
179 for (i
= cur_pos
; i
< buf_len
- 19; i
++) {
180 if (memcmp(&buf
[i
], guid
, 16) == 0)
181 return i
+ 16 + 8; // point after guid + length
186 static int find_backwards_asf_guid(char *buf
, const char *guid
, int cur_pos
)
189 for (i
=cur_pos
-16; i
>0; i
--) {
190 if (memcmp(&buf
[i
], guid
, 16) == 0)
191 return i
+ 16 + 8; // point after guid + length
196 static int get_ext_stream_properties(char *buf
, int buf_len
, int stream_num
, struct asf_priv
* asf
, int is_video
)
199 uint8_t *buffer
= &buf
[0];
203 while ((pos
= find_asf_guid(buf
, asf_ext_stream_header
, pos
, buf_len
)) >= 0) {
204 int this_stream_num
, stnamect
, payct
, i
;
205 int buf_max_index
=pos
+50;
206 if (buf_max_index
> buf_len
) return 0;
209 // the following info is available
210 // some of it may be useful but we're skipping it for now
211 // starttime(8 bytes), endtime(8),
212 // leak-datarate(4), bucket-datasize(4), init-bucket-fullness(4),
213 // alt-leak-datarate(4), alt-bucket-datasize(4), alt-init-bucket-fullness(4),
214 // max-object-size(4),
215 // flags(4) (reliable,seekable,no_cleanpoints?,resend-live-cleanpoints, rest of bits reserved)
218 bitrate
= AV_RL32(buffer
);
220 this_stream_num
=AV_RL16(buffer
);buffer
+=2;
222 if (this_stream_num
== stream_num
) {
224 if (buf_max_index
> buf_len
) return 0;
225 buffer
+=2; //skip stream-language-id-index
226 avg_ft
= AV_RL64(buffer
); // provided in 100ns units
228 asf
->bps
= bitrate
/ 8;
230 // after this are values for stream-name-count and
231 // payload-extension-system-count
232 // followed by associated info for each
233 stnamect
= AV_RL16(buffer
);buffer
+=2;
234 payct
= AV_RL16(buffer
);buffer
+=2;
236 // need to read stream names if present in order
237 // to get lengths - values are ignored for now
238 for (i
=0; i
<stnamect
; i
++) {
241 if (buf_max_index
> buf_len
) return 0;
242 buffer
+=2; //language_id_index
243 stream_name_len
= AV_RL16(buffer
);buffer
+=2;
244 buffer
+=stream_name_len
; //stream_name
245 buf_max_index
+=stream_name_len
;
246 if (buf_max_index
> buf_len
) return 0;
250 asf
->vid_repdata_count
= payct
;
251 asf
->vid_repdata_sizes
= malloc(payct
*sizeof(int));
253 asf
->aud_repdata_count
= payct
;
254 asf
->aud_repdata_sizes
= malloc(payct
*sizeof(int));
257 for (i
=0; i
<payct
; i
++) {
260 if (buf_max_index
> buf_len
) return 0;
261 // Each payload extension definition starts with a GUID.
262 // In dvr-ms files one of these indicates the presence an
263 // extension that contains pts values and this is always present
264 // in the video and audio streams.
265 // Another GUID indicates the presence of an extension
266 // that contains useful video frame demuxing information.
267 // Note that the extension data in each packet does not contain
268 // these GUIDs and that this header section defines the order the data
270 if (memcmp(buffer
, asf_dvr_ms_timing_rep_data
, 16) == 0) {
272 asf
->vid_ext_timing_index
= i
;
274 asf
->aud_ext_timing_index
= i
;
275 } else if (is_video
&& memcmp(buffer
, asf_dvr_ms_vid_frame_rep_data
, 16) == 0)
276 asf
->vid_ext_frame_index
= i
;
279 payload_len
= AV_RL16(buffer
);buffer
+=2;
282 asf
->vid_repdata_sizes
[i
] = payload_len
;
284 asf
->aud_repdata_sizes
[i
] = payload_len
;
294 #define CHECKDEC(l, n) if (((l) -= (n)) < 0) return 0
295 static char* read_meta_record(ASF_meta_record_t
* dest
, char* buf
,
298 CHECKDEC(*buf_len
, 2 + 2 + 2 + 2 + 4);
299 dest
->lang_list_index
= AV_RL16(buf
);
300 dest
->stream_num
= AV_RL16(&buf
[2]);
301 dest
->name_length
= AV_RL16(&buf
[4]);
302 dest
->data_type
= AV_RL16(&buf
[6]);
303 dest
->data_length
= AV_RL32(&buf
[8]);
304 buf
+= 2 + 2 + 2 + 2 + 4;
305 CHECKDEC(*buf_len
, dest
->name_length
);
306 dest
->name
= (uint16_t*)buf
;
307 buf
+= dest
->name_length
;
308 CHECKDEC(*buf_len
, dest
->data_length
);
310 buf
+= dest
->data_length
;
314 static int get_meta(char *buf
, int buf_len
, int this_stream_num
,
318 uint16_t records_count
;
319 uint16_t x
= 0, y
= 0;
321 if ((pos
= find_asf_guid(buf
, asf_metadata_header
, pos
, buf_len
)) < 0)
324 CHECKDEC(buf_len
, pos
);
326 CHECKDEC(buf_len
, 2);
327 records_count
= AV_RL16(buf
);
330 while (records_count
--) {
331 ASF_meta_record_t record_entry
;
334 if (!(buf
= read_meta_record(&record_entry
, buf
, &buf_len
)))
336 /* reserved, must be zero */
337 if (record_entry
.lang_list_index
)
339 /* match stream number: 0 to match all */
340 if (record_entry
.stream_num
&& record_entry
.stream_num
!= this_stream_num
)
342 if (!(name
= get_ucs2str(record_entry
.name
, record_entry
.name_length
))) {
343 mp_msg(MSGT_HEADER
, MSGL_ERR
, MSGTR_MemAllocFailed
);
346 if (strcmp(name
, "AspectRatioX") == 0)
347 x
= AV_RL16(record_entry
.data
);
348 else if (strcmp(name
, "AspectRatioY") == 0)
349 y
= AV_RL16(record_entry
.data
);
353 *asp_ratio
= (float)x
/ (float)y
;
359 static int is_drm(char* buf
, int buf_len
)
361 uint32_t data_len
, type_len
, key_len
, url_len
;
362 int pos
= find_asf_guid(buf
, asf_content_encryption
, 0, buf_len
);
367 CHECKDEC(buf_len
, pos
+ 4);
369 data_len
= AV_RL32(buf
);
371 CHECKDEC(buf_len
, data_len
);
373 type_len
= AV_RL32(buf
);
376 CHECKDEC(buf_len
, 4 + type_len
+ 4);
379 if (buf
[0] != 'D' || buf
[1] != 'R' || buf
[2] != 'M' || buf
[3] != '\0')
383 key_len
= AV_RL32(buf
);
384 CHECKDEC(buf_len
, key_len
+ 4);
387 buf
[key_len
- 1] = '\0';
388 mp_msg(MSGT_HEADER
, MSGL_V
, "DRM Key ID: %s\n", buf
);
391 url_len
= AV_RL32(buf
);
392 CHECKDEC(buf_len
, url_len
);
395 buf
[url_len
- 1] = '\0';
396 mp_msg(MSGT_HEADER
, MSGL_INFO
, MSGTR_MPDEMUX_ASFHDR_DRMLicenseURL
, buf
);
400 static int asf_init_audio_stream(demuxer_t
*demuxer
,struct asf_priv
* asf
, sh_audio_t
* sh_audio
, ASF_stream_header_t
*streamh
, int *ppos
, uint8_t** buf
, char *hdr
, unsigned int hdr_len
)
402 uint8_t *buffer
= *buf
;
405 sh_audio
->wf
=calloc((streamh
->type_size
<sizeof(WAVEFORMATEX
))?sizeof(WAVEFORMATEX
):streamh
->type_size
,1);
406 memcpy(sh_audio
->wf
,buffer
,streamh
->type_size
);
407 le2me_WAVEFORMATEX(sh_audio
->wf
);
408 if( mp_msg_test(MSGT_HEADER
,MSGL_V
) ) print_wave_header(sh_audio
->wf
,MSGL_V
);
409 if(ASF_LOAD_GUID_PREFIX(streamh
->concealment
)==ASF_GUID_PREFIX_audio_conceal_interleave
){
411 pos
+= streamh
->stream_size
;
412 if (pos
> hdr_len
) return 0;
413 asf
->scrambling_h
=buffer
[0];
414 asf
->scrambling_w
=(buffer
[2]<<8)|buffer
[1];
415 asf
->scrambling_b
=(buffer
[4]<<8)|buffer
[3];
416 if(asf
->scrambling_b
>0){
417 asf
->scrambling_w
/=asf
->scrambling_b
;
420 asf
->scrambling_b
=asf
->scrambling_h
=asf
->scrambling_w
=1;
422 mp_msg(MSGT_HEADER
,MSGL_V
,"ASF: audio scrambling: %d x %d x %d\n",asf
->scrambling_h
,asf
->scrambling_w
,asf
->scrambling_b
);
426 int read_asf_header(demuxer_t
*demuxer
,struct asf_priv
* asf
){
427 int hdr_len
= asf
->header
.objh
.size
- sizeof(asf
->header
);
430 char guid_buffer
[16];
431 int pos
, start
= stream_tell(demuxer
->stream
);
432 uint32_t* streams
= NULL
;
435 uint16_t stream_count
=0;
439 ASF_stream_header_t
*streamh
;
444 mp_msg(MSGT_HEADER
, MSGL_FATAL
, "Header size is too small.\n");
448 if (hdr_len
> 1024 * 1024) {
449 mp_msg(MSGT_HEADER
, MSGL_ERR
, MSGTR_MPDEMUX_ASFHDR_HeaderSizeOver1MB
,
451 hdr_skip
= hdr_len
- 1024 * 1024;
452 hdr_len
= 1024 * 1024;
454 hdr
= malloc(hdr_len
);
456 mp_msg(MSGT_HEADER
, MSGL_FATAL
, MSGTR_MPDEMUX_ASFHDR_HeaderMallocFailed
,
460 stream_read(demuxer
->stream
, hdr
, hdr_len
);
462 stream_skip(demuxer
->stream
, hdr_skip
);
463 if (stream_eof(demuxer
->stream
)) {
464 mp_msg(MSGT_HEADER
, MSGL_FATAL
, MSGTR_MPDEMUX_ASFHDR_EOFWhileReadingHeader
);
468 if (is_drm(hdr
, hdr_len
))
469 mp_msg(MSGT_HEADER
, MSGL_FATAL
, MSGTR_MPDEMUX_ASFHDR_DRMProtected
);
471 if ((pos
= find_asf_guid(hdr
, asf_ext_stream_audio
, 0, hdr_len
)) >= 0)
473 // Special case: found GUID for dvr-ms audio.
474 // Now skip back to associated stream header.
477 sh_pos
= find_backwards_asf_guid(hdr
, asf_stream_header_guid
, pos
);
480 sh_audio_t
*sh_audio
;
482 mp_msg(MSGT_HEADER
, MSGL_V
, "read_asf_header found dvr-ms audio stream header pos=%d\n", sh_pos
);
483 // found audio stream header - following code reads header and
484 // initializes audio stream.
485 audio_pos
= pos
- 16 - 8;
486 streamh
= (ASF_stream_header_t
*)&hdr
[sh_pos
];
487 le2me_ASF_stream_header_t(streamh
);
488 audio_pos
+= 64; //16+16+4+4+4+16+4;
489 buffer
= &hdr
[audio_pos
];
490 sh_audio
=new_sh_audio(demuxer
,streamh
->stream_no
& 0x7F);
491 mp_msg(MSGT_DEMUX
, MSGL_INFO
, MSGTR_AudioID
, "asfheader", streamh
->stream_no
& 0x7F);
493 if (!asf_init_audio_stream(demuxer
, asf
, sh_audio
, streamh
, &audio_pos
, &buffer
, hdr
, hdr_len
))
495 if (!get_ext_stream_properties(hdr
, hdr_len
, streamh
->stream_no
, asf
, 0))
499 // find stream headers
500 // only reset pos if we didnt find dvr_ms audio stream
501 // if we did find it then we want to avoid reading its header twice
505 while ((pos
= find_asf_guid(hdr
, asf_stream_header_guid
, pos
, hdr_len
)) >= 0)
507 streamh
= (ASF_stream_header_t
*)&hdr
[pos
];
508 pos
+= sizeof(ASF_stream_header_t
);
509 if (pos
> hdr_len
) goto len_err_out
;
510 le2me_ASF_stream_header_t(streamh
);
511 mp_msg(MSGT_HEADER
, MSGL_V
, "stream type: %s\n",
512 asf_chunk_type(streamh
->type
));
513 mp_msg(MSGT_HEADER
, MSGL_V
, "stream concealment: %s\n",
514 asf_chunk_type(streamh
->concealment
));
515 mp_msg(MSGT_HEADER
, MSGL_V
, "type: %d bytes, stream: %d bytes ID: %d\n",
516 (int)streamh
->type_size
, (int)streamh
->stream_size
,
517 (int)streamh
->stream_no
);
518 mp_msg(MSGT_HEADER
, MSGL_V
, "unk1: %lX unk2: %X\n",
519 (unsigned long)streamh
->unk1
, (unsigned int)streamh
->unk2
);
520 mp_msg(MSGT_HEADER
, MSGL_V
, "FILEPOS=0x%X\n", pos
+ start
);
521 // type-specific data:
523 pos
+= streamh
->type_size
;
524 if (pos
> hdr_len
) goto len_err_out
;
525 switch(ASF_LOAD_GUID_PREFIX(streamh
->type
)){
526 case ASF_GUID_PREFIX_audio_stream
: {
527 sh_audio_t
* sh_audio
=new_sh_audio(demuxer
,streamh
->stream_no
& 0x7F);
528 mp_msg(MSGT_DEMUX
, MSGL_INFO
, MSGTR_AudioID
, "asfheader", streamh
->stream_no
& 0x7F);
530 if (!asf_init_audio_stream(demuxer
, asf
, sh_audio
, streamh
, &pos
, &buffer
, hdr
, hdr_len
))
532 //if(demuxer->audio->id==-1) demuxer->audio->id=streamh.stream_no & 0x7F;
535 case ASF_GUID_PREFIX_video_stream
: {
538 sh_video_t
* sh_video
=new_sh_video(demuxer
,streamh
->stream_no
& 0x7F);
539 mp_msg(MSGT_DEMUX
, MSGL_INFO
, MSGTR_VideoID
, "asfheader", streamh
->stream_no
& 0x7F);
540 len
=streamh
->type_size
-(4+4+1+2);
542 // sh_video->bih=malloc(chunksize); memset(sh_video->bih,0,chunksize);
543 sh_video
->bih
=calloc((len
<sizeof(BITMAPINFOHEADER
))?sizeof(BITMAPINFOHEADER
):len
,1);
544 memcpy(sh_video
->bih
,&buffer
[4+4+1+2],len
);
545 le2me_BITMAPINFOHEADER(sh_video
->bih
);
546 if (sh_video
->bih
->biSize
> len
&& sh_video
->bih
->biSize
> sizeof(BITMAPINFOHEADER
))
547 sh_video
->bih
->biSize
= len
;
548 if (sh_video
->bih
->biCompression
== mmioFOURCC('D', 'V', 'R', ' ')) {
549 //mp_msg(MSGT_DEMUXER, MSGL_WARN, MSGTR_MPDEMUX_ASFHDR_DVRWantsLibavformat);
550 //sh_video->fps=(float)sh_video->video.dwRate/(float)sh_video->video.dwScale;
551 //sh_video->frametime=(float)sh_video->video.dwScale/(float)sh_video->video.dwRate;
552 asf
->asf_frame_state
=-1;
553 asf
->asf_frame_start_found
=0;
554 asf
->asf_is_dvr_ms
=1;
555 asf
->dvr_last_vid_pts
=0.0;
556 } else asf
->asf_is_dvr_ms
=0;
557 if (!get_ext_stream_properties(hdr
, hdr_len
, streamh
->stream_no
, asf
, 1))
559 if (get_meta(hdr
, hdr_len
, streamh
->stream_no
, &asp_ratio
)) {
560 sh_video
->aspect
= asp_ratio
* sh_video
->bih
->biWidth
/
561 sh_video
->bih
->biHeight
;
563 sh_video
->i_bps
= asf
->bps
;
565 if( mp_msg_test(MSGT_DEMUX
,MSGL_V
) ) print_video_header(sh_video
->bih
, MSGL_V
);
566 //asf_video_id=streamh.stream_no & 0x7F;
567 //if(demuxer->video->id==-1) demuxer->video->id=streamh.stream_no & 0x7F;
571 // stream-specific data:
572 // stream_read(demuxer->stream,(char*) buffer,streamh.stream_size);
576 pos
= find_asf_guid(hdr
, asf_file_header_guid
, 0, hdr_len
);
578 ASF_file_header_t
*fileh
= (ASF_file_header_t
*)&hdr
[pos
];
579 pos
+= sizeof(ASF_file_header_t
);
580 if (pos
> hdr_len
) goto len_err_out
;
581 le2me_ASF_file_header_t(fileh
);
582 mp_msg(MSGT_HEADER
, MSGL_V
, "ASF: packets: %d flags: %d "
583 "max_packet_size: %d min_packet_size: %d max_bitrate: %d "
585 (int)fileh
->num_packets
, (int)fileh
->flags
,
586 (int)fileh
->min_packet_size
, (int)fileh
->max_packet_size
,
587 (int)fileh
->max_bitrate
, (int)fileh
->preroll
);
588 asf
->packetsize
=fileh
->max_packet_size
;
589 asf
->packet
=malloc(asf
->packetsize
); // !!!
590 asf
->packetrate
=fileh
->max_bitrate
/8.0/(double)asf
->packetsize
;
591 asf
->movielength
=(fileh
->play_duration
-fileh
->preroll
)/10000000LL;
594 // find content header
595 pos
= find_asf_guid(hdr
, asf_content_desc_guid
, 0, hdr_len
);
597 ASF_content_description_t
*contenth
= (ASF_content_description_t
*)&hdr
[pos
];
599 uint16_t* wstring
= NULL
;
601 pos
+= sizeof(ASF_content_description_t
);
602 if (pos
> hdr_len
) goto len_err_out
;
603 le2me_ASF_content_description_t(contenth
);
604 mp_msg(MSGT_HEADER
,MSGL_V
,"\n");
606 if((len
= contenth
->title_size
) != 0) {
607 wstring
= (uint16_t*)&hdr
[pos
];
609 if (pos
> hdr_len
) goto len_err_out
;
610 if ((string
= get_ucs2str(wstring
, len
))) {
611 mp_msg(MSGT_HEADER
,MSGL_V
," Title: %s\n", string
);
612 demux_info_add(demuxer
, "name", string
);
616 // extract the author
617 if((len
= contenth
->author_size
) != 0) {
618 wstring
= (uint16_t*)&hdr
[pos
];
620 if (pos
> hdr_len
) goto len_err_out
;
621 if ((string
= get_ucs2str(wstring
, len
))) {
622 mp_msg(MSGT_HEADER
,MSGL_V
," Author: %s\n", string
);
623 demux_info_add(demuxer
, "author", string
);
627 // extract the copyright
628 if((len
= contenth
->copyright_size
) != 0) {
629 wstring
= (uint16_t*)&hdr
[pos
];
631 if (pos
> hdr_len
) goto len_err_out
;
632 if ((string
= get_ucs2str(wstring
, len
))) {
633 mp_msg(MSGT_HEADER
,MSGL_V
," Copyright: %s\n", string
);
634 demux_info_add(demuxer
, "copyright", string
);
638 // extract the comment
639 if((len
= contenth
->comment_size
) != 0) {
640 wstring
= (uint16_t*)&hdr
[pos
];
642 if (pos
> hdr_len
) goto len_err_out
;
643 if ((string
= get_ucs2str(wstring
, len
))) {
644 mp_msg(MSGT_HEADER
,MSGL_V
," Comment: %s\n", string
);
645 demux_info_add(demuxer
, "comments", string
);
649 // extract the rating
650 if((len
= contenth
->rating_size
) != 0) {
651 wstring
= (uint16_t*)&hdr
[pos
];
653 if (pos
> hdr_len
) goto len_err_out
;
654 if ((string
= get_ucs2str(wstring
, len
))) {
655 mp_msg(MSGT_HEADER
,MSGL_V
," Rating: %s\n", string
);
659 mp_msg(MSGT_HEADER
,MSGL_V
,"\n");
662 // find content header
663 pos
= find_asf_guid(hdr
, asf_stream_group_guid
, 0, hdr_len
);
665 uint16_t stream_id
, i
;
666 uint32_t max_bitrate
;
667 char *ptr
= &hdr
[pos
];
668 mp_msg(MSGT_HEADER
,MSGL_V
,"============ ASF Stream group == START ===\n");
669 stream_count
= AV_RL16(ptr
);
670 ptr
+= sizeof(uint16_t);
671 if (ptr
> &hdr
[hdr_len
]) goto len_err_out
;
673 streams
= malloc(2*stream_count
*sizeof(uint32_t));
674 mp_msg(MSGT_HEADER
,MSGL_V
," stream count=[0x%x][%u]\n", stream_count
, stream_count
);
675 for( i
=0 ; i
<stream_count
; i
++ ) {
676 stream_id
= AV_RL16(ptr
);
677 ptr
+= sizeof(uint16_t);
678 if (ptr
> &hdr
[hdr_len
]) goto len_err_out
;
679 memcpy(&max_bitrate
, ptr
, sizeof(uint32_t));// workaround unaligment bug on sparc
680 max_bitrate
= le2me_32(max_bitrate
);
681 ptr
+= sizeof(uint32_t);
682 if (ptr
> &hdr
[hdr_len
]) goto len_err_out
;
683 mp_msg(MSGT_HEADER
,MSGL_V
," stream id=[0x%x][%u]\n", stream_id
, stream_id
);
684 mp_msg(MSGT_HEADER
,MSGL_V
," max bitrate=[0x%x][%u]\n", max_bitrate
, max_bitrate
);
685 streams
[2*i
] = stream_id
;
686 streams
[2*i
+1] = max_bitrate
;
688 mp_msg(MSGT_HEADER
,MSGL_V
,"============ ASF Stream group == END ===\n");
692 start
= stream_tell(demuxer
->stream
); // start of first data chunk
693 stream_read(demuxer
->stream
, guid_buffer
, 16);
694 if (memcmp(guid_buffer
, asf_data_chunk_guid
, 16) != 0) {
695 mp_msg(MSGT_HEADER
, MSGL_FATAL
, MSGTR_MPDEMUX_ASFHDR_NoDataChunkAfterHeader
);
700 // read length of chunk
701 stream_read(demuxer
->stream
, (char *)&data_len
, sizeof(data_len
));
702 data_len
= le2me_64(data_len
);
703 demuxer
->movi_start
= stream_tell(demuxer
->stream
) + 26;
704 demuxer
->movi_end
= start
+ data_len
;
705 mp_msg(MSGT_HEADER
, MSGL_V
, "Found movie at 0x%X - 0x%X\n",
706 (int)demuxer
->movi_start
, (int)demuxer
->movi_end
);
709 // stream selection is done in the network code, it shouldn't be done here
710 // as the servers often do not care about what we requested.
712 uint32_t vr
= 0, ar
= 0,i
;
713 #ifdef MPLAYER_NETWORK
714 if( demuxer
->stream
->streaming_ctrl
!=NULL
) {
715 if( demuxer
->stream
->streaming_ctrl
->bandwidth
!=0 && demuxer
->stream
->streaming_ctrl
->data
!=NULL
) {
716 best_audio
= ((asf_http_streaming_ctrl_t
*)demuxer
->stream
->streaming_ctrl
->data
)->audio_id
;
717 best_video
= ((asf_http_streaming_ctrl_t
*)demuxer
->stream
->streaming_ctrl
->data
)->video_id
;
721 for(i
= 0; i
< stream_count
; i
++) {
722 uint32_t id
= streams
[2*i
];
723 uint32_t rate
= streams
[2*i
+1];
724 if(demuxer
->v_streams
[id
] && rate
> vr
) {
727 } else if(demuxer
->a_streams
[id
] && rate
> ar
) {
737 mp_msg(MSGT_HEADER
,MSGL_V
,"ASF: %d audio and %d video streams found\n",audio_streams
,video_streams
);
738 if(!audio_streams
) demuxer
->audio
->id
=-2; // nosound
739 else if(best_audio
> 0 && demuxer
->audio
->id
== -1) demuxer
->audio
->id
=best_audio
;
742 mp_msg(MSGT_HEADER
,MSGL_ERR
,MSGTR_MPDEMUX_ASFHDR_AudioVideoHeaderNotFound
);
745 demuxer
->video
->id
=-2; // audio-only
746 } else if (best_video
> 0 && demuxer
->video
->id
== -1) demuxer
->video
->id
= best_video
;
749 if( mp_msg_test(MSGT_HEADER
,MSGL_V
) ){
750 printf("ASF duration: %d\n",(int)fileh
.duration
);
751 printf("ASF start pts: %d\n",(int)fileh
.start_timestamp
);
752 printf("ASF end pts: %d\n",(int)fileh
.end_timestamp
);
759 mp_msg(MSGT_HEADER
, MSGL_FATAL
, MSGTR_MPDEMUX_ASFHDR_InvalidLengthInASFHeader
);
762 if (streams
) free(streams
);