1 /*****************************************************************************
2 * asf.c : ASF demux module
3 *****************************************************************************
4 * Copyright (C) 2002-2003 the VideoLAN team
7 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
32 #include <vlc_common.h>
33 #include <vlc_plugin.h>
34 #include <vlc_demux.h>
35 #include <vlc_dialog.h>
38 #include <vlc_access.h> /* GET_PRIVATE_ID_STATE */
39 #include <vlc_codecs.h> /* BITMAPINFOHEADER, WAVEFORMATEX */
43 * - add support for the newly added object: language, bitrate,
44 * extended stream properties.
47 /*****************************************************************************
49 *****************************************************************************/
50 static int Open ( vlc_object_t
* );
51 static void Close ( vlc_object_t
* );
54 set_category( CAT_INPUT
)
55 set_subcategory( SUBCAT_INPUT_DEMUX
)
56 set_description( N_("ASF v1.0 demuxer") )
57 set_capability( "demux", 200 )
58 set_callbacks( Open
, Close
)
63 /*****************************************************************************
65 *****************************************************************************/
66 static int Demux ( demux_t
* );
67 static int Control( demux_t
*, int i_query
, va_list args
);
75 asf_object_stream_properties_t
*p_sp
;
79 block_t
*p_frame
; /* use to gather complete frame */
85 mtime_t i_time
; /* s */
86 mtime_t i_length
; /* length of file file */
87 int64_t i_bitrate
; /* global file bitrate */
89 asf_object_root_t
*p_root
;
90 asf_object_file_properties_t
*p_fp
;
93 asf_track_t
*track
[128]; /* track number is stored on 7 bits */
99 unsigned int i_seek_track
;
100 unsigned int i_wait_keyframe
;
105 static mtime_t
GetMoviePTS( demux_sys_t
* );
106 static int DemuxInit( demux_t
* );
107 static void DemuxEnd( demux_t
* );
108 static int DemuxPacket( demux_t
* );
110 /*****************************************************************************
111 * Open: check file and initializes ASF structures
112 *****************************************************************************/
113 static int Open( vlc_object_t
* p_this
)
115 demux_t
*p_demux
= (demux_t
*)p_this
;
118 const uint8_t *p_peek
;
120 /* A little test to see if it could be a asf stream */
121 if( stream_Peek( p_demux
->s
, &p_peek
, 16 ) < 16 ) return VLC_EGENERIC
;
123 ASF_GetGUID( &guid
, p_peek
);
124 if( !ASF_CmpGUID( &guid
, &asf_object_header_guid
) ) return VLC_EGENERIC
;
126 /* Set p_demux fields */
127 p_demux
->pf_demux
= Demux
;
128 p_demux
->pf_control
= Control
;
129 p_demux
->p_sys
= p_sys
= malloc( sizeof( demux_sys_t
) );
130 memset( p_sys
, 0, sizeof( demux_sys_t
) );
132 /* Load the headers */
133 if( DemuxInit( p_demux
) )
142 /*****************************************************************************
143 * Demux: read packet and send them to decoders
144 *****************************************************************************/
145 static int Demux( demux_t
*p_demux
)
147 demux_sys_t
*p_sys
= p_demux
->p_sys
;
151 const uint8_t *p_peek
;
153 mtime_t i_time_begin
= GetMoviePTS( p_sys
);
156 if( !vlc_object_alive (p_demux
) )
159 /* FIXME: returns EOF too early for some mms streams */
160 if( p_sys
->i_data_end
>= 0 &&
161 stream_Tell( p_demux
->s
) >= p_sys
->i_data_end
)
165 /* Check if we have concatenated files */
166 if( stream_Peek( p_demux
->s
, &p_peek
, 16 ) == 16 )
170 ASF_GetGUID( &guid
, p_peek
);
171 if( ASF_CmpGUID( &guid
, &asf_object_header_guid
) )
173 msg_Warn( p_demux
, "found a new ASF header" );
174 /* We end this stream */
177 /* And we prepare to read the next one */
178 if( DemuxInit( p_demux
) )
180 msg_Err( p_demux
, "failed to load the new header" );
181 dialog_Fatal( p_demux
, _("Could not demux ASF stream"), "%s",
182 _("VLC failed to load the ASF header.") );
185 es_out_Control( p_demux
->out
, ES_OUT_RESET_PCR
);
190 /* Read and demux a packet */
191 if( ( i_result
= DemuxPacket( p_demux
) ) <= 0 )
195 if( i_time_begin
== -1 )
197 i_time_begin
= GetMoviePTS( p_sys
);
201 i_length
= GetMoviePTS( p_sys
) - i_time_begin
;
202 if( i_length
< 0 || i_length
>= 40 * 1000 ) break;
207 p_sys
->i_time
= GetMoviePTS( p_sys
);
208 if( p_sys
->i_time
>= 0 )
210 es_out_Control( p_demux
->out
, ES_OUT_SET_PCR
, p_sys
->i_time
+1 );
216 /*****************************************************************************
217 * Close: frees unused data
218 *****************************************************************************/
219 static void Close( vlc_object_t
* p_this
)
221 demux_t
*p_demux
= (demux_t
*)p_this
;
225 free( p_demux
->p_sys
);
228 /*****************************************************************************
229 * SeekIndex: goto to i_date or i_percent
230 *****************************************************************************/
231 static int SeekPercent( demux_t
*p_demux
, int i_query
, va_list args
)
233 demux_sys_t
*p_sys
= p_demux
->p_sys
;
234 p_sys
->i_wait_keyframe
= p_sys
->i_seek_track
? 50 : 0;
235 return demux_vaControlHelper( p_demux
->s
, p_sys
->i_data_begin
,
236 p_sys
->i_data_end
, p_sys
->i_bitrate
,
237 p_sys
->p_fp
->i_min_data_packet_size
,
241 static int SeekIndex( demux_t
*p_demux
, mtime_t i_date
, float f_pos
)
243 demux_sys_t
*p_sys
= p_demux
->p_sys
;
244 asf_object_index_t
*p_index
;
246 msg_Dbg( p_demux
, "seek with index: %i seconds, position %f",
247 i_date
>= 0 ? (int)(i_date
/1000000) : -1, f_pos
);
250 i_date
= p_sys
->i_length
* f_pos
;
252 p_index
= ASF_FindObject( p_sys
->p_root
, &asf_object_index_guid
, 0 );
254 uint64_t i_entry
= i_date
* 10 / p_index
->i_index_entry_time_interval
;
255 if( i_entry
>= p_index
->i_index_entry_count
)
257 msg_Warn( p_demux
, "Incomplete index" );
261 p_sys
->i_wait_keyframe
= p_sys
->i_seek_track
? 50 : 0;
263 uint64_t i_offset
= (uint64_t)p_index
->index_entry
[i_entry
].i_packet_number
*
264 p_sys
->p_fp
->i_min_data_packet_size
;
265 return stream_Seek( p_demux
->s
, p_sys
->i_data_begin
+ i_offset
);
268 static void SeekPrepare( demux_t
*p_demux
)
270 demux_sys_t
*p_sys
= p_demux
->p_sys
;
273 for( int i
= 0; i
< 128 ; i
++ )
275 asf_track_t
*tk
= p_sys
->track
[i
];
281 block_ChainRelease( tk
->p_frame
);
286 /*****************************************************************************
288 *****************************************************************************/
289 static int Control( demux_t
*p_demux
, int i_query
, va_list args
)
291 demux_sys_t
*p_sys
= p_demux
->p_sys
;
298 case DEMUX_GET_LENGTH
:
299 pi64
= (int64_t*)va_arg( args
, int64_t * );
300 *pi64
= p_sys
->i_length
;
304 pi64
= (int64_t*)va_arg( args
, int64_t * );
305 if( p_sys
->i_time
< 0 ) return VLC_EGENERIC
;
306 *pi64
= p_sys
->i_time
;
310 SeekPrepare( p_demux
);
312 if( p_sys
->b_index
&& p_sys
->i_length
> 0 )
315 va_copy( acpy
, args
);
316 i64
= (int64_t)va_arg( acpy
, int64_t );
319 if( !SeekIndex( p_demux
, i64
, -1 ) )
322 return SeekPercent( p_demux
, i_query
, args
);
324 case DEMUX_GET_POSITION
:
325 if( p_sys
->i_time
< 0 ) return VLC_EGENERIC
;
326 if( p_sys
->i_length
> 0 )
328 pf
= (double*)va_arg( args
, double * );
329 *pf
= p_sys
->i_time
/ (double)p_sys
->i_length
;
332 return demux_vaControlHelper( p_demux
->s
, p_sys
->i_data_begin
,
333 p_sys
->i_data_end
, p_sys
->i_bitrate
,
334 p_sys
->p_fp
->i_min_data_packet_size
,
337 case DEMUX_SET_POSITION
:
338 SeekPrepare( p_demux
);
340 if( p_sys
->b_index
&& p_sys
->i_length
> 0 )
343 va_copy( acpy
, args
);
344 f
= (double)va_arg( acpy
, double );
347 if( !SeekIndex( p_demux
, -1, f
) )
350 return SeekPercent( p_demux
, i_query
, args
);
353 p_meta
= (vlc_meta_t
*)va_arg( args
, vlc_meta_t
* );
354 vlc_meta_Merge( p_meta
, p_sys
->meta
);
358 return demux_vaControlHelper( p_demux
->s
, p_sys
->i_data_begin
,
359 p_sys
->i_data_end
, p_sys
->i_bitrate
,
360 p_sys
->p_fp
->i_min_data_packet_size
,
365 /*****************************************************************************
367 *****************************************************************************/
368 static mtime_t
GetMoviePTS( demux_sys_t
*p_sys
)
373 for( i
= 0; i
< 128 ; i
++ )
375 asf_track_t
*tk
= p_sys
->track
[i
];
377 if( tk
&& tk
->p_es
&& tk
->i_time
> 0)
379 if( i_time
< 0 ) i_time
= tk
->i_time
;
380 else i_time
= __MIN( i_time
, tk
->i_time
);
387 #define GETVALUE2b( bits, var, def ) \
388 switch( (bits)&0x03 ) \
390 case 1: var = p_peek[i_skip]; i_skip++; break; \
391 case 2: var = GetWLE( p_peek + i_skip ); i_skip+= 2; break; \
392 case 3: var = GetDWLE( p_peek + i_skip ); i_skip+= 4; break; \
394 default: var = def; break;\
397 static int DemuxPacket( demux_t
*p_demux
)
399 demux_sys_t
*p_sys
= p_demux
->p_sys
;
400 int i_data_packet_min
= p_sys
->p_fp
->i_min_data_packet_size
;
401 const uint8_t *p_peek
;
404 int i_packet_size_left
;
406 int i_packet_property
;
408 int b_packet_multiple_payload
;
410 int i_packet_sequence
;
411 int i_packet_padding_length
;
413 uint32_t i_packet_send_time
;
414 uint16_t i_packet_duration
;
417 int i_payload_length_type
;
420 if( stream_Peek( p_demux
->s
, &p_peek
,i_data_packet_min
)<i_data_packet_min
)
422 msg_Warn( p_demux
, "cannot peek while getting new packet, EOF ?" );
427 /* *** parse error correction if present *** */
430 unsigned int i_error_correction_length_type
;
431 unsigned int i_error_correction_data_length
;
432 unsigned int i_opaque_data_present
;
434 i_error_correction_data_length
= p_peek
[0] & 0x0f; // 4bits
435 i_opaque_data_present
= ( p_peek
[0] >> 4 )& 0x01; // 1bit
436 i_error_correction_length_type
= ( p_peek
[0] >> 5 ) & 0x03; // 2bits
437 i_skip
+= 1; // skip error correction flags
439 if( i_error_correction_length_type
!= 0x00 ||
440 i_opaque_data_present
!= 0 ||
441 i_error_correction_data_length
!= 0x02 )
443 goto loop_error_recovery
;
446 i_skip
+= i_error_correction_data_length
;
450 msg_Warn( p_demux
, "p_peek[0]&0x80 != 0x80" );
454 if( i_skip
+ 2 >= i_data_packet_min
)
456 goto loop_error_recovery
;
459 i_packet_flags
= p_peek
[i_skip
]; i_skip
++;
460 i_packet_property
= p_peek
[i_skip
]; i_skip
++;
462 b_packet_multiple_payload
= i_packet_flags
&0x01;
464 /* read some value */
465 GETVALUE2b( i_packet_flags
>> 5, i_packet_length
, i_data_packet_min
);
466 GETVALUE2b( i_packet_flags
>> 1, i_packet_sequence
, 0 );
467 GETVALUE2b( i_packet_flags
>> 3, i_packet_padding_length
, 0 );
469 if( i_packet_padding_length
> i_packet_length
)
471 msg_Warn( p_demux
, "Too large padding: %d", i_packet_padding_length
);
472 goto loop_error_recovery
;
475 if( i_packet_length
< i_data_packet_min
)
477 /* if packet length too short, there is extra padding */
478 i_packet_padding_length
+= i_data_packet_min
- i_packet_length
;
479 i_packet_length
= i_data_packet_min
;
482 i_packet_send_time
= GetDWLE( p_peek
+ i_skip
); i_skip
+= 4;
483 i_packet_duration
= GetWLE( p_peek
+ i_skip
); i_skip
+= 2;
485 i_packet_size_left
= i_packet_length
;
487 if( b_packet_multiple_payload
)
489 i_payload_count
= p_peek
[i_skip
] & 0x3f;
490 i_payload_length_type
= ( p_peek
[i_skip
] >> 6 )&0x03;
496 i_payload_length_type
= 0x02; // unused
499 for( i_payload
= 0; i_payload
< i_payload_count
; i_payload
++ )
503 int i_packet_keyframe
;
504 unsigned int i_stream_number
;
505 int i_media_object_number
;
506 int i_media_object_offset
;
507 int i_replicated_data_length
;
508 int i_payload_data_length
;
509 int i_payload_data_pos
;
510 int i_sub_payload_data_length
;
516 if( i_skip
>= i_packet_size_left
)
518 /* prevent some segfault with invalid file */
522 i_packet_keyframe
= p_peek
[i_skip
] >> 7;
523 i_stream_number
= p_peek
[i_skip
++] & 0x7f;
525 GETVALUE2b( i_packet_property
>> 4, i_media_object_number
, 0 );
526 GETVALUE2b( i_packet_property
>> 2, i_tmp
, 0 );
527 GETVALUE2b( i_packet_property
, i_replicated_data_length
, 0 );
529 if( i_replicated_data_length
> 1 ) // should be at least 8 bytes
531 i_pts
= (mtime_t
)GetDWLE( p_peek
+ i_skip
+ 4 ) * 1000;
532 i_skip
+= i_replicated_data_length
;
535 i_media_object_offset
= i_tmp
;
537 if( i_skip
>= i_packet_size_left
)
542 else if( i_replicated_data_length
== 1 )
544 /* msg_Dbg( p_demux, "found compressed payload" ); */
546 i_pts
= (mtime_t
)i_tmp
* 1000;
547 i_pts_delta
= (mtime_t
)p_peek
[i_skip
] * 1000; i_skip
++;
549 i_media_object_offset
= 0;
553 i_pts
= (mtime_t
)i_packet_send_time
* 1000;
556 i_media_object_offset
= i_tmp
;
559 i_pts
= __MAX( i_pts
- p_sys
->p_fp
->i_preroll
* 1000, 0 );
560 if( b_packet_multiple_payload
)
562 GETVALUE2b( i_payload_length_type
, i_payload_data_length
, 0 );
566 i_payload_data_length
= i_packet_length
-
567 i_packet_padding_length
- i_skip
;
570 if( i_payload_data_length
< 0 || i_payload_data_length
> i_packet_size_left
)
576 "payload(%d/%d) stream_number:%d media_object_number:%d media_object_offset:%d replicated_data_length:%d payload_data_length %d",
577 i_payload
+ 1, i_payload_count
, i_stream_number
, i_media_object_number
,
578 i_media_object_offset
, i_replicated_data_length
, i_payload_data_length
);
581 if( ( tk
= p_sys
->track
[i_stream_number
] ) == NULL
)
584 "undeclared stream[Id 0x%x]", i_stream_number
);
585 i_skip
+= i_payload_data_length
;
586 continue; // over payload
589 if( p_sys
->i_wait_keyframe
&&
590 !(i_stream_number
== p_sys
->i_seek_track
&& i_packet_keyframe
&&
591 !i_media_object_offset
) )
593 i_skip
+= i_payload_data_length
;
594 p_sys
->i_wait_keyframe
--;
595 continue; // over payload
597 p_sys
->i_wait_keyframe
= 0;
601 i_skip
+= i_payload_data_length
;
606 for( i_payload_data_pos
= 0;
607 i_payload_data_pos
< i_payload_data_length
&&
608 i_packet_size_left
> 0;
609 i_payload_data_pos
+= i_sub_payload_data_length
)
614 // read sub payload length
615 if( i_replicated_data_length
== 1 )
617 i_sub_payload_data_length
= p_peek
[i_skip
]; i_skip
++;
618 i_payload_data_pos
++;
622 i_sub_payload_data_length
= i_payload_data_length
;
625 /* FIXME I don't use i_media_object_number, sould I ? */
626 if( tk
->p_frame
&& i_media_object_offset
== 0 )
628 /* send complete packet to decoder */
629 block_t
*p_gather
= block_ChainGather( tk
->p_frame
);
631 if( p_gather
->i_dts
> VLC_TS_INVALID
)
632 tk
->i_time
= p_gather
->i_dts
- VLC_TS_0
;
634 if( p_sys
->i_time
< 0 )
635 es_out_Control( p_demux
->out
, ES_OUT_SET_PCR
, VLC_TS_0
+ tk
->i_time
);
637 es_out_Send( p_demux
->out
, tk
->p_es
, p_gather
);
642 i_read
= i_sub_payload_data_length
+ i_skip
;
643 if( ( p_frag
= stream_Block( p_demux
->s
, i_read
) ) == NULL
)
645 msg_Warn( p_demux
, "cannot read data" );
648 i_packet_size_left
-= i_read
;
650 p_frag
->p_buffer
+= i_skip
;
651 p_frag
->i_buffer
-= i_skip
;
653 if( tk
->p_frame
== NULL
)
655 p_frag
->i_pts
= VLC_TS_0
+ i_pts
+ i_payload
* (mtime_t
)i_pts_delta
;
656 if( tk
->i_cat
!= VIDEO_ES
)
657 p_frag
->i_dts
= VLC_TS_0
+ p_frag
->i_pts
;
660 p_frag
->i_dts
= VLC_TS_0
+ p_frag
->i_pts
;
661 p_frag
->i_pts
= VLC_TS_INVALID
;
665 block_ChainAppend( &tk
->p_frame
, p_frag
);
668 if( i_packet_size_left
> 0 )
670 if( stream_Peek( p_demux
->s
, &p_peek
, i_packet_size_left
)
671 < i_packet_size_left
)
673 msg_Warn( p_demux
, "cannot peek, EOF ?" );
680 if( i_packet_size_left
> 0 )
683 if( i_packet_size_left
> i_packet_padding_length
)
684 msg_Warn( p_demux
, "Didn't read %d bytes in the packet",
685 i_packet_size_left
- i_packet_padding_length
);
686 else if( i_packet_size_left
< i_packet_padding_length
)
687 msg_Warn( p_demux
, "Read %d too much bytes in the packet",
688 i_packet_padding_length
- i_packet_size_left
);
690 if( stream_Read( p_demux
->s
, NULL
, i_packet_size_left
)
691 < i_packet_size_left
)
693 msg_Err( p_demux
, "cannot skip data, EOF ?" );
701 msg_Warn( p_demux
, "unsupported packet header" );
702 if( p_sys
->p_fp
->i_min_data_packet_size
!= p_sys
->p_fp
->i_max_data_packet_size
)
704 msg_Err( p_demux
, "unsupported packet header, fatal error" );
707 if( stream_Read( p_demux
->s
, NULL
, i_data_packet_min
) != i_data_packet_min
)
709 msg_Warn( p_demux
, "cannot skip data, EOF ?" );
716 /*****************************************************************************
718 *****************************************************************************/
719 static int DemuxInit( demux_t
*p_demux
)
721 demux_sys_t
*p_sys
= p_demux
->p_sys
;
726 p_sys
->i_bitrate
= 0;
727 p_sys
->p_root
= NULL
;
731 p_sys
->i_seek_track
= 0;
732 p_sys
->i_wait_keyframe
= 0;
733 for( int i
= 0; i
< 128; i
++ )
735 p_sys
->track
[i
] = NULL
;
737 p_sys
->i_data_begin
= -1;
738 p_sys
->i_data_end
= -1;
741 /* Now load all object ( except raw data ) */
743 stream_Control( p_demux
->s
, STREAM_CAN_FASTSEEK
, &b_seekable
);
744 if( !(p_sys
->p_root
= ASF_ReadObjectRoot(p_demux
->s
, b_seekable
)) )
746 msg_Warn( p_demux
, "ASF plugin discarded (not a valid file)" );
749 p_sys
->p_fp
= p_sys
->p_root
->p_fp
;
751 if( p_sys
->p_fp
->i_min_data_packet_size
!= p_sys
->p_fp
->i_max_data_packet_size
)
753 msg_Warn( p_demux
, "ASF plugin discarded (invalid file_properties object)" );
757 p_sys
->i_track
= ASF_CountObject( p_sys
->p_root
->p_hdr
,
758 &asf_object_stream_properties_guid
);
759 if( p_sys
->i_track
<= 0 )
761 msg_Warn( p_demux
, "ASF plugin discarded (cannot find any stream!)" );
764 msg_Dbg( p_demux
, "found %d streams", p_sys
->i_track
);
766 /* check if index is available */
767 asf_object_index_t
*p_index
= ASF_FindObject( p_sys
->p_root
,
768 &asf_object_index_guid
, 0 );
769 const bool b_index
= p_index
&& p_index
->i_index_entry_count
;
771 /* Find the extended header if any */
772 asf_object_t
*p_hdr_ext
= ASF_FindObject( p_sys
->p_root
->p_hdr
,
773 &asf_object_header_extension_guid
, 0 );
775 asf_object_language_list_t
*p_languages
= NULL
;
777 p_languages
= ASF_FindObject( p_hdr_ext
, &asf_object_language_list
, 0 );
779 for( unsigned i_stream
= 0; i_stream
< p_sys
->i_track
; i_stream
++ )
782 asf_object_stream_properties_t
*p_sp
;
783 asf_object_extended_stream_properties_t
*p_esp
;
784 bool b_access_selected
;
786 p_sp
= ASF_FindObject( p_sys
->p_root
->p_hdr
,
787 &asf_object_stream_properties_guid
,
791 tk
= p_sys
->track
[p_sp
->i_stream_number
] = malloc( sizeof( asf_track_t
) );
792 memset( tk
, 0, sizeof( asf_track_t
) );
799 /* Check (in case of mms) if this track is selected (ie will receive data) */
800 if( !stream_Control( p_demux
->s
, STREAM_CONTROL_ACCESS
, ACCESS_GET_PRIVATE_ID_STATE
,
801 p_sp
->i_stream_number
, &b_access_selected
) &&
804 tk
->i_cat
= UNKNOWN_ES
;
805 msg_Dbg( p_demux
, "ignoring not selected stream(ID:%d) (by access)",
806 p_sp
->i_stream_number
);
810 /* Find the associated extended_stream_properties if any */
813 int i_ext_stream
= ASF_CountObject( p_hdr_ext
,
814 &asf_object_extended_stream_properties
);
815 for( int i
= 0; i
< i_ext_stream
; i
++ )
817 asf_object_t
*p_tmp
=
818 ASF_FindObject( p_hdr_ext
,
819 &asf_object_extended_stream_properties
, i
);
820 if( p_tmp
->ext_stream
.i_stream_number
== p_sp
->i_stream_number
)
822 p_esp
= &p_tmp
->ext_stream
;
830 if( ASF_CmpGUID( &p_sp
->i_stream_type
, &asf_object_stream_type_audio
) &&
831 p_sp
->i_type_specific_data_length
>= sizeof( WAVEFORMATEX
) - 2 )
833 uint8_t *p_data
= p_sp
->p_type_specific_data
;
836 es_format_Init( &fmt
, AUDIO_ES
, 0 );
837 i_format
= GetWLE( &p_data
[0] );
838 wf_tag_to_fourcc( i_format
, &fmt
.i_codec
, NULL
);
839 fmt
.audio
.i_channels
= GetWLE( &p_data
[2] );
840 fmt
.audio
.i_rate
= GetDWLE( &p_data
[4] );
841 fmt
.i_bitrate
= GetDWLE( &p_data
[8] ) * 8;
842 fmt
.audio
.i_blockalign
= GetWLE( &p_data
[12] );
843 fmt
.audio
.i_bitspersample
= GetWLE( &p_data
[14] );
845 if( p_sp
->i_type_specific_data_length
> sizeof( WAVEFORMATEX
) &&
846 i_format
!= WAVE_FORMAT_MPEGLAYER3
&&
847 i_format
!= WAVE_FORMAT_MPEG
)
849 fmt
.i_extra
= __MIN( GetWLE( &p_data
[16] ),
850 p_sp
->i_type_specific_data_length
-
851 sizeof( WAVEFORMATEX
) );
852 fmt
.p_extra
= malloc( fmt
.i_extra
);
853 memcpy( fmt
.p_extra
, &p_data
[sizeof( WAVEFORMATEX
)],
857 msg_Dbg( p_demux
, "added new audio stream(codec:0x%x,ID:%d)",
858 GetWLE( p_data
), p_sp
->i_stream_number
);
860 else if( ASF_CmpGUID( &p_sp
->i_stream_type
,
861 &asf_object_stream_type_video
) &&
862 p_sp
->i_type_specific_data_length
>= 11 +
863 sizeof( BITMAPINFOHEADER
) )
865 uint8_t *p_data
= &p_sp
->p_type_specific_data
[11];
867 es_format_Init( &fmt
, VIDEO_ES
,
868 VLC_FOURCC( p_data
[16], p_data
[17],
869 p_data
[18], p_data
[19] ) );
870 fmt
.video
.i_width
= GetDWLE( p_data
+ 4 );
871 fmt
.video
.i_height
= GetDWLE( p_data
+ 8 );
873 if( p_esp
&& p_esp
->i_average_time_per_frame
> 0 )
875 fmt
.video
.i_frame_rate
= 10000000;
876 fmt
.video
.i_frame_rate_base
= p_esp
->i_average_time_per_frame
;
879 if( fmt
.i_codec
== VLC_FOURCC( 'D','V','R',' ') )
881 /* DVR-MS special ASF */
882 fmt
.i_codec
= VLC_FOURCC( 'm','p','g','2' ) ;
883 fmt
.b_packetized
= false;
886 if( p_sp
->i_type_specific_data_length
> 11 +
887 sizeof( BITMAPINFOHEADER
) )
889 fmt
.i_extra
= __MIN( GetDWLE( p_data
),
890 p_sp
->i_type_specific_data_length
- 11 -
891 sizeof( BITMAPINFOHEADER
) );
892 fmt
.p_extra
= malloc( fmt
.i_extra
);
893 memcpy( fmt
.p_extra
, &p_data
[sizeof( BITMAPINFOHEADER
)],
897 /* Look for an aspect ratio */
898 if( p_sys
->p_root
->p_metadata
)
900 asf_object_metadata_t
*p_meta
= p_sys
->p_root
->p_metadata
;
901 int i_aspect_x
= 0, i_aspect_y
= 0;
904 for( i
= 0; i
< p_meta
->i_record_entries_count
; i
++ )
906 if( !strcmp( p_meta
->record
[i
].psz_name
, "AspectRatioX" ) )
908 if( (!i_aspect_x
&& !p_meta
->record
[i
].i_stream
) ||
909 p_meta
->record
[i
].i_stream
==
910 p_sp
->i_stream_number
)
911 i_aspect_x
= p_meta
->record
[i
].i_val
;
913 if( !strcmp( p_meta
->record
[i
].psz_name
, "AspectRatioY" ) )
915 if( (!i_aspect_y
&& !p_meta
->record
[i
].i_stream
) ||
916 p_meta
->record
[i
].i_stream
==
917 p_sp
->i_stream_number
)
918 i_aspect_y
= p_meta
->record
[i
].i_val
;
922 if( i_aspect_x
&& i_aspect_y
)
924 fmt
.video
.i_sar_num
= i_aspect_x
;
925 fmt
.video
.i_sar_den
= i_aspect_y
;
929 /* If there is a video track then use the index for seeking */
930 p_sys
->b_index
= b_index
;
932 msg_Dbg( p_demux
, "added new video stream(ID:%d)",
933 p_sp
->i_stream_number
);
935 else if( ASF_CmpGUID( &p_sp
->i_stream_type
, &asf_object_extended_stream_header
) &&
936 p_sp
->i_type_specific_data_length
>= 64 )
938 /* Now follows a 64 byte header of which we don't know much */
939 guid_t
*p_ref
= (guid_t
*)p_sp
->p_type_specific_data
;
940 uint8_t *p_data
= p_sp
->p_type_specific_data
+ 64;
941 unsigned int i_data
= p_sp
->i_type_specific_data_length
- 64;
943 msg_Dbg( p_demux
, "Ext stream header detected. datasize = %d", p_sp
->i_type_specific_data_length
);
944 if( ASF_CmpGUID( p_ref
, &asf_object_extended_stream_type_audio
) &&
945 i_data
>= sizeof( WAVEFORMATEX
) - 2)
948 es_format_Init( &fmt
, AUDIO_ES
, 0 );
949 i_format
= GetWLE( &p_data
[0] );
951 fmt
.i_codec
= VLC_CODEC_A52
;
953 wf_tag_to_fourcc( i_format
, &fmt
.i_codec
, NULL
);
954 fmt
.audio
.i_channels
= GetWLE( &p_data
[2] );
955 fmt
.audio
.i_rate
= GetDWLE( &p_data
[4] );
956 fmt
.i_bitrate
= GetDWLE( &p_data
[8] ) * 8;
957 fmt
.audio
.i_blockalign
= GetWLE( &p_data
[12] );
958 fmt
.audio
.i_bitspersample
= GetWLE( &p_data
[14] );
959 fmt
.b_packetized
= true;
961 if( p_sp
->i_type_specific_data_length
> sizeof( WAVEFORMATEX
) &&
962 i_format
!= WAVE_FORMAT_MPEGLAYER3
&&
963 i_format
!= WAVE_FORMAT_MPEG
)
965 fmt
.i_extra
= __MIN( GetWLE( &p_data
[16] ),
966 p_sp
->i_type_specific_data_length
-
967 sizeof( WAVEFORMATEX
) );
968 fmt
.p_extra
= malloc( fmt
.i_extra
);
969 memcpy( fmt
.p_extra
, &p_data
[sizeof( WAVEFORMATEX
)],
973 msg_Dbg( p_demux
, "added new audio stream (codec:0x%x,ID:%d)",
974 i_format
, p_sp
->i_stream_number
);
978 es_format_Init( &fmt
, UNKNOWN_ES
, 0 );
983 es_format_Init( &fmt
, UNKNOWN_ES
, 0 );
986 tk
->i_cat
= fmt
.i_cat
;
987 if( fmt
.i_cat
!= UNKNOWN_ES
)
989 if( p_esp
&& p_languages
&&
990 p_esp
->i_language_index
>= 0 &&
991 p_esp
->i_language_index
< p_languages
->i_language
)
993 fmt
.psz_language
= strdup( p_languages
->ppsz_language
[p_esp
->i_language_index
] );
995 if( fmt
.psz_language
&& (p
= strchr( fmt
.psz_language
, '-' )) )
999 /* Set the track on which we'll do our seeking to the first video track */
1000 if(!p_sys
->i_seek_track
&& fmt
.i_cat
== VIDEO_ES
)
1001 p_sys
->i_seek_track
= p_sp
->i_stream_number
;
1003 tk
->p_es
= es_out_Add( p_demux
->out
, &fmt
);
1007 msg_Dbg( p_demux
, "ignoring unknown stream(ID:%d)",
1008 p_sp
->i_stream_number
);
1010 es_format_Clean( &fmt
);
1013 p_sys
->i_data_begin
= p_sys
->p_root
->p_data
->i_object_pos
+ 50;
1014 if( p_sys
->p_root
->p_data
->i_object_size
!= 0 )
1016 p_sys
->i_data_end
= p_sys
->p_root
->p_data
->i_object_pos
+
1017 p_sys
->p_root
->p_data
->i_object_size
;
1020 { /* live/broacast */
1021 p_sys
->i_data_end
= -1;
1024 /* go to first packet */
1025 stream_Seek( p_demux
->s
, p_sys
->i_data_begin
);
1027 /* try to calculate movie time */
1028 if( p_sys
->p_fp
->i_data_packets_count
> 0 )
1031 int64_t i_size
= stream_Size( p_demux
->s
);
1033 if( p_sys
->i_data_end
> 0 && i_size
> p_sys
->i_data_end
)
1035 i_size
= p_sys
->i_data_end
;
1038 /* real number of packets */
1039 i_count
= ( i_size
- p_sys
->i_data_begin
) /
1040 p_sys
->p_fp
->i_min_data_packet_size
;
1042 /* calculate the time duration in micro-s */
1043 p_sys
->i_length
= (mtime_t
)p_sys
->p_fp
->i_play_duration
/ 10 *
1045 (mtime_t
)p_sys
->p_fp
->i_data_packets_count
- p_sys
->p_fp
->i_preroll
* 1000;
1046 if( p_sys
->i_length
< 0 )
1047 p_sys
->i_length
= 0;
1049 if( p_sys
->i_length
> 0 )
1051 p_sys
->i_bitrate
= 8 * i_size
* (int64_t)1000000 / p_sys
->i_length
;
1055 /* Create meta information */
1056 p_sys
->meta
= vlc_meta_New();
1058 asf_object_content_description_t
*p_cd
;
1059 if( ( p_cd
= ASF_FindObject( p_sys
->p_root
->p_hdr
,
1060 &asf_object_content_description_guid
, 0 ) ) )
1062 if( p_cd
->psz_title
&& *p_cd
->psz_title
)
1064 vlc_meta_SetTitle( p_sys
->meta
, p_cd
->psz_title
);
1066 if( p_cd
->psz_artist
&& *p_cd
->psz_artist
)
1068 vlc_meta_SetArtist( p_sys
->meta
, p_cd
->psz_artist
);
1070 if( p_cd
->psz_copyright
&& *p_cd
->psz_copyright
)
1072 vlc_meta_SetCopyright( p_sys
->meta
, p_cd
->psz_copyright
);
1074 if( p_cd
->psz_description
&& *p_cd
->psz_description
)
1076 vlc_meta_SetDescription( p_sys
->meta
, p_cd
->psz_description
);
1078 if( p_cd
->psz_rating
&& *p_cd
->psz_rating
)
1080 vlc_meta_SetRating( p_sys
->meta
, p_cd
->psz_rating
);
1083 /// \tood Fix Child meta for ASF tracks
1085 for( i_stream
= 0, i
= 0; i
< 128; i
++ )
1087 asf_object_codec_list_t
*p_cl
= ASF_FindObject( p_sys
->p_root
->p_hdr
,
1088 &asf_object_codec_list_guid
, 0 );
1090 if( p_sys
->track
[i
] )
1092 vlc_meta_t
*tk
= vlc_meta_New();
1093 TAB_APPEND( p_sys
->meta
->i_track
, p_sys
->meta
->track
, tk
);
1095 if( p_cl
&& i_stream
< p_cl
->i_codec_entries_count
)
1097 if( p_cl
->codec
[i_stream
].psz_name
&&
1098 *p_cl
->codec
[i_stream
].psz_name
)
1100 vlc_meta_Add( tk
, VLC_META_CODEC_NAME
,
1101 p_cl
->codec
[i_stream
].psz_name
);
1103 if( p_cl
->codec
[i_stream
].psz_description
&&
1104 *p_cl
->codec
[i_stream
].psz_description
)
1106 vlc_meta_Add( tk
, VLC_META_CODEC_DESCRIPTION
,
1107 p_cl
->codec
[i_stream
].psz_description
);
1117 ASF_FreeObjectRoot( p_demux
->s
, p_sys
->p_root
);
1118 return VLC_EGENERIC
;
1120 /*****************************************************************************
1122 *****************************************************************************/
1123 static void DemuxEnd( demux_t
*p_demux
)
1125 demux_sys_t
*p_sys
= p_demux
->p_sys
;
1130 ASF_FreeObjectRoot( p_demux
->s
, p_sys
->p_root
);
1131 p_sys
->p_root
= NULL
;
1135 vlc_meta_Delete( p_sys
->meta
);
1139 for( i
= 0; i
< 128; i
++ )
1141 asf_track_t
*tk
= p_sys
->track
[i
];
1147 block_ChainRelease( tk
->p_frame
);
1151 es_out_Del( p_demux
->out
, tk
->p_es
);
1155 p_sys
->track
[i
] = 0;