]> git.sesse.net Git - vlc/blob - modules/demux/asf/asf.c
* modules/demux/asf/* use index for seeking if available and if there's a video track.
[vlc] / modules / demux / asf / asf.c
1 /*****************************************************************************
2  * asf.c : ASF demux module
3  *****************************************************************************
4  * Copyright (C) 2002-2003 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
8  *
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.
13  *
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.
18  *
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  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include <stdlib.h>                                      /* malloc(), free() */
28
29 #include <vlc/vlc.h>
30 #include <vlc_demux.h>
31 #include <vlc_interface.h>
32
33 #include <vlc_meta.h>
34 #include <vlc_access.h>                /* GET_PRIVATE_ID_STATE */
35 #include <vlc_codecs.h>                /* BITMAPINFOHEADER, WAVEFORMATEX */
36 #include "libasf.h"
37
38 /* TODO
39  *  - add support for the newly added object: language, bitrate,
40  *                                            extended stream properties.
41  */
42
43 /*****************************************************************************
44  * Module descriptor
45  *****************************************************************************/
46 static int  Open  ( vlc_object_t * );
47 static void Close ( vlc_object_t * );
48
49 vlc_module_begin();
50     set_category( CAT_INPUT );
51     set_subcategory( SUBCAT_INPUT_DEMUX );
52     set_description( _("ASF v1.0 demuxer") );
53     set_capability( "demux2", 200 );
54     set_callbacks( Open, Close );
55     add_shortcut( "asf" );
56 vlc_module_end();
57
58
59 /*****************************************************************************
60  * Local prototypes
61  *****************************************************************************/
62 static int Demux  ( demux_t * );
63 static int Control( demux_t *, int i_query, va_list args );
64
65 typedef struct
66 {
67     int i_cat;
68
69     es_out_id_t     *p_es;
70
71     asf_object_stream_properties_t *p_sp;
72
73     mtime_t i_time;
74
75     block_t         *p_frame; /* use to gather complete frame */
76
77 } asf_track_t;
78
79 struct demux_sys_t
80 {
81     mtime_t             i_time;     /* s */
82     mtime_t             i_length;   /* length of file file */
83     int64_t             i_bitrate;  /* global file bitrate */
84
85     asf_object_root_t            *p_root;
86     asf_object_file_properties_t *p_fp;
87
88     unsigned int        i_track;
89     asf_track_t         *track[128];
90
91     int64_t             i_data_begin;
92     int64_t             i_data_end;
93
94     vlc_bool_t          b_index;
95     vlc_meta_t          *meta;
96 };
97
98 static mtime_t  GetMoviePTS( demux_sys_t * );
99 static int      DemuxInit( demux_t * );
100 static void     DemuxEnd( demux_t * );
101 static int      DemuxPacket( demux_t * );
102
103 /*****************************************************************************
104  * Open: check file and initializes ASF structures
105  *****************************************************************************/
106 static int Open( vlc_object_t * p_this )
107 {
108     demux_t     *p_demux = (demux_t *)p_this;
109     demux_sys_t *p_sys;
110     guid_t      guid;
111     uint8_t     *p_peek;
112
113     /* A little test to see if it could be a asf stream */
114     if( stream_Peek( p_demux->s, &p_peek, 16 ) < 16 ) return VLC_EGENERIC;
115
116     ASF_GetGUID( &guid, p_peek );
117     if( !ASF_CmpGUID( &guid, &asf_object_header_guid ) ) return VLC_EGENERIC;
118
119     /* Set p_demux fields */
120     p_demux->pf_demux = Demux;
121     p_demux->pf_control = Control;
122     p_demux->p_sys = p_sys = malloc( sizeof( demux_sys_t ) );
123     memset( p_sys, 0, sizeof( demux_sys_t ) );
124
125     /* Load the headers */
126     if( DemuxInit( p_demux ) )
127     {
128         free( p_sys );
129         return VLC_EGENERIC;
130     }
131     return VLC_SUCCESS;
132 }
133
134
135 /*****************************************************************************
136  * Demux: read packet and send them to decoders
137  *****************************************************************************/
138 static int Demux( demux_t *p_demux )
139 {
140     demux_sys_t *p_sys = p_demux->p_sys;
141
142     for( ;; )
143     {
144         uint8_t *p_peek;
145         mtime_t i_length;
146         mtime_t i_time_begin = GetMoviePTS( p_sys );
147         int i_result;
148
149         if( p_demux->b_die ) break;
150
151         /* Check if we have concatenated files */
152         if( stream_Peek( p_demux->s, &p_peek, 16 ) == 16 )
153         {
154             guid_t guid;
155
156             ASF_GetGUID( &guid, p_peek );
157             if( ASF_CmpGUID( &guid, &asf_object_header_guid ) )
158             {
159                 msg_Warn( p_demux, "found a new ASF header" );
160                 /* We end this stream */
161                 DemuxEnd( p_demux );
162
163                 /* And we prepare to read the next one */
164                 if( DemuxInit( p_demux ) )
165                 {
166                     msg_Err( p_demux, "failed to load the new header" );
167                     intf_UserFatal( p_demux, VLC_FALSE, _("Could not demux ASF stream"), 
168                                     _("VLC failed to load the ASF header.") );
169                     return 0;
170                 }
171                 continue;
172             }
173         }
174
175         /* Read and demux a packet */
176         if( ( i_result = DemuxPacket( p_demux ) ) <= 0 )
177         {
178             return i_result;
179         }
180         if( i_time_begin == -1 )
181         {
182             i_time_begin = GetMoviePTS( p_sys );
183         }
184         else
185         {
186             i_length = GetMoviePTS( p_sys ) - i_time_begin;
187             if( i_length < 0 || i_length >= 40 * 1000 ) break;
188         }
189     }
190
191     /* Set the PCR */
192     p_sys->i_time = GetMoviePTS( p_sys );
193     if( p_sys->i_time >= 0 )
194     {
195         es_out_Control( p_demux->out, ES_OUT_SET_PCR, p_sys->i_time );
196     }
197
198     return 1;
199 }
200
201 /*****************************************************************************
202  * Close: frees unused data
203  *****************************************************************************/
204 static void Close( vlc_object_t * p_this )
205 {
206     demux_t     *p_demux = (demux_t *)p_this;
207
208     DemuxEnd( p_demux );
209
210     free( p_demux->p_sys );
211 }
212
213 /*****************************************************************************
214  * SeekIndex: goto to i_date or i_percent
215  *****************************************************************************/
216 static int SeekIndex( demux_t *p_demux, mtime_t i_date, float f_pos )
217 {
218     demux_sys_t *p_sys = p_demux->p_sys;
219     asf_object_index_t *p_index;
220     int64_t i_pos;
221
222     msg_Dbg( p_demux, "seek with index: %i seconds, position %f",
223              (int)(i_date/1000000), f_pos );
224
225     p_index = ASF_FindObject( p_sys->p_root, &asf_object_index_guid, 0 );
226
227     if( i_date < 0 ) i_date = p_sys->i_length * f_pos;
228
229     i_pos = i_date * 10 / p_index->i_index_entry_time_interval;
230     i_pos = p_index->index_entry[i_pos].i_packet_number *
231         p_sys->p_fp->i_min_data_packet_size;
232
233     return stream_Seek( p_demux->s, p_sys->i_data_begin + i_pos );
234 }
235
236 /*****************************************************************************
237  * Control:
238  *****************************************************************************/
239 static int Control( demux_t *p_demux, int i_query, va_list args )
240 {
241     demux_sys_t *p_sys = p_demux->p_sys;
242     vlc_meta_t  *p_meta;
243     int64_t     i64, *pi64;
244     double      f, *pf;
245     int         i;
246
247     switch( i_query )
248     {
249     case DEMUX_GET_LENGTH:
250         pi64 = (int64_t*)va_arg( args, int64_t * );
251         *pi64 = p_sys->i_length;
252         return VLC_SUCCESS;
253
254     case DEMUX_GET_TIME:
255         pi64 = (int64_t*)va_arg( args, int64_t * );
256         if( p_sys->i_time < 0 ) return VLC_EGENERIC;
257         *pi64 = p_sys->i_time;
258         return VLC_SUCCESS;
259
260     case DEMUX_SET_TIME:
261         p_sys->i_time = -1;
262         for( i = 0; i < 128 ; i++ )
263             if( p_sys->track[i] ) p_sys->track[i]->i_time = -1;
264
265         if( p_sys->b_index && p_sys->i_length > 0 )
266         {
267             i64 = (int64_t)va_arg( args, int64_t );
268             return SeekIndex( p_demux, i64, -1 );
269         }
270         else
271         {
272             return demux2_vaControlHelper( p_demux->s, p_sys->i_data_begin,
273                                            p_sys->i_data_end, p_sys->i_bitrate,
274                                            p_sys->p_fp->i_min_data_packet_size,
275                                            i_query, args );
276         }
277
278     case DEMUX_GET_POSITION:
279         if( p_sys->i_time < 0 ) return VLC_EGENERIC;
280         if( p_sys->i_length > 0 )
281         {
282             pf = (double*)va_arg( args, double * );
283             *pf = p_sys->i_time / (double)p_sys->i_length;
284             return VLC_SUCCESS;
285         }
286         return demux2_vaControlHelper( p_demux->s, p_sys->i_data_begin,
287                                        p_sys->i_data_end, p_sys->i_bitrate,
288                                        p_sys->p_fp->i_min_data_packet_size,
289                                        i_query, args );
290
291     case DEMUX_SET_POSITION:
292         p_sys->i_time = -1;
293         for( i = 0; i < 128 ; i++ )
294             if( p_sys->track[i] ) p_sys->track[i]->i_time = -1;
295
296         if( p_sys->b_index && p_sys->i_length > 0 )
297         {
298             f = (double)va_arg( args, double );
299             return SeekIndex( p_demux, -1, f );
300         }
301         else
302         {
303             return demux2_vaControlHelper( p_demux->s, p_sys->i_data_begin,
304                                            p_sys->i_data_end, p_sys->i_bitrate,
305                                            p_sys->p_fp->i_min_data_packet_size,
306                                            i_query, args );
307         }
308
309     case DEMUX_GET_META:
310         p_meta = (vlc_meta_t*)va_arg( args, vlc_meta_t* );
311         vlc_meta_Merge( p_meta, p_sys->meta );
312         return VLC_SUCCESS;
313
314     default:
315         return demux2_vaControlHelper( p_demux->s, p_sys->i_data_begin,
316                                        p_sys->i_data_end, p_sys->i_bitrate,
317                                        p_sys->p_fp->i_min_data_packet_size,
318                                        i_query, args );
319     }
320 }
321
322 /*****************************************************************************
323  *
324  *****************************************************************************/
325 static mtime_t GetMoviePTS( demux_sys_t *p_sys )
326 {
327     mtime_t i_time = -1;
328     int     i;
329
330     for( i = 0; i < 128 ; i++ )
331     {
332         asf_track_t *tk = p_sys->track[i];
333
334         if( tk && tk->p_es && tk->i_time > 0)
335         {
336             if( i_time < 0 ) i_time = tk->i_time;
337             else i_time = __MIN( i_time, tk->i_time );
338         }
339     }
340
341     return i_time;
342 }
343
344 #define GETVALUE2b( bits, var, def ) \
345     switch( (bits)&0x03 ) \
346     { \
347         case 1: var = p_peek[i_skip]; i_skip++; break; \
348         case 2: var = GetWLE( p_peek + i_skip );  i_skip+= 2; break; \
349         case 3: var = GetDWLE( p_peek + i_skip ); i_skip+= 4; break; \
350         case 0: \
351         default: var = def; break;\
352     }
353
354 static int DemuxPacket( demux_t *p_demux )
355 {
356     demux_sys_t *p_sys = p_demux->p_sys;
357     int         i_data_packet_min = p_sys->p_fp->i_min_data_packet_size;
358     uint8_t     *p_peek;
359     int         i_skip;
360
361     int         i_packet_size_left;
362     int         i_packet_flags;
363     int         i_packet_property;
364
365     int         b_packet_multiple_payload;
366     int         i_packet_length;
367     int         i_packet_sequence;
368     int         i_packet_padding_length;
369
370     uint32_t    i_packet_send_time;
371     uint16_t    i_packet_duration;
372     int         i_payload;
373     int         i_payload_count;
374     int         i_payload_length_type;
375
376
377     if( stream_Peek( p_demux->s, &p_peek,i_data_packet_min)<i_data_packet_min )
378     {
379         msg_Warn( p_demux, "cannot peek while getting new packet, EOF ?" );
380         return 0;
381     }
382     i_skip = 0;
383
384     /* *** parse error correction if present *** */
385     if( p_peek[0]&0x80 )
386     {
387         unsigned int i_error_correction_length_type;
388         unsigned int i_error_correction_data_length;
389         unsigned int i_opaque_data_present;
390
391         i_error_correction_data_length = p_peek[0] & 0x0f;  // 4bits
392         i_opaque_data_present = ( p_peek[0] >> 4 )& 0x01;    // 1bit
393         i_error_correction_length_type = ( p_peek[0] >> 5 ) & 0x03; // 2bits
394         i_skip += 1; // skip error correction flags
395
396         if( i_error_correction_length_type != 0x00 ||
397             i_opaque_data_present != 0 ||
398             i_error_correction_data_length != 0x02 )
399         {
400             goto loop_error_recovery;
401         }
402
403         i_skip += i_error_correction_data_length;
404     }
405     else
406     {
407         msg_Warn( p_demux, "p_peek[0]&0x80 != 0x80" );
408     }
409
410     /* sanity check */
411     if( i_skip + 2 >= i_data_packet_min )
412     {
413         goto loop_error_recovery;
414     }
415
416     i_packet_flags = p_peek[i_skip]; i_skip++;
417     i_packet_property = p_peek[i_skip]; i_skip++;
418
419     b_packet_multiple_payload = i_packet_flags&0x01;
420
421     /* read some value */
422     GETVALUE2b( i_packet_flags >> 5, i_packet_length, i_data_packet_min );
423     GETVALUE2b( i_packet_flags >> 1, i_packet_sequence, 0 );
424     GETVALUE2b( i_packet_flags >> 3, i_packet_padding_length, 0 );
425
426     i_packet_send_time = GetDWLE( p_peek + i_skip ); i_skip += 4;
427     i_packet_duration  = GetWLE( p_peek + i_skip ); i_skip += 2;
428
429 //        i_packet_size_left = i_packet_length;   // XXX data really read 
430     /* FIXME I have to do that for some file, I don't known why */
431     i_packet_size_left = i_data_packet_min;
432
433     if( b_packet_multiple_payload )
434     {
435         i_payload_count = p_peek[i_skip] & 0x3f;
436         i_payload_length_type = ( p_peek[i_skip] >> 6 )&0x03;
437         i_skip++;
438     }
439     else
440     {
441         i_payload_count = 1;
442         i_payload_length_type = 0x02; // unused
443     }
444
445     for( i_payload = 0; i_payload < i_payload_count ; i_payload++ )
446     {
447         asf_track_t   *tk;
448
449         int i_packet_keyframe;
450         int i_stream_number;
451         int i_media_object_number;
452         int i_media_object_offset;
453         int i_replicated_data_length;
454         int i_payload_data_length;
455         int i_payload_data_pos;
456         int i_sub_payload_data_length;
457         int i_tmp;
458
459         mtime_t i_pts;
460         mtime_t i_pts_delta;
461
462         if( i_skip >= i_packet_size_left )
463         {
464             /* prevent some segfault with invalid file */
465             break;
466         }
467
468         i_packet_keyframe = p_peek[i_skip] >> 7;
469         i_stream_number = p_peek[i_skip++] & 0x7f;
470
471         GETVALUE2b( i_packet_property >> 4, i_media_object_number, 0 );
472         GETVALUE2b( i_packet_property >> 2, i_tmp, 0 );
473         GETVALUE2b( i_packet_property, i_replicated_data_length, 0 );
474
475         if( i_replicated_data_length > 1 ) // should be at least 8 bytes
476         {
477             i_pts = (mtime_t)GetDWLE( p_peek + i_skip + 4 ) * 1000;
478             i_skip += i_replicated_data_length;
479             i_pts_delta = 0;
480
481             i_media_object_offset = i_tmp;
482
483             if( i_skip >= i_packet_size_left )
484             {
485                 break;
486             }
487         }
488         else if( i_replicated_data_length == 1 )
489         {
490             /* msg_Dbg( p_demux, "found compressed payload" ); */
491
492             i_pts = (mtime_t)i_tmp * 1000;
493             i_pts_delta = (mtime_t)p_peek[i_skip] * 1000; i_skip++;
494
495             i_media_object_offset = 0;
496         }
497         else
498         {
499             i_pts = (mtime_t)i_packet_send_time * 1000;
500             i_pts_delta = 0;
501
502             i_media_object_offset = i_tmp;
503         }
504
505         i_pts = __MAX( i_pts - p_sys->p_fp->i_preroll * 1000, 0 );
506         if( b_packet_multiple_payload )
507         {
508             GETVALUE2b( i_payload_length_type, i_payload_data_length, 0 );
509         }
510         else
511         {
512             i_payload_data_length = i_packet_length -
513                                         i_packet_padding_length - i_skip;
514         }
515
516         if( i_payload_data_length < 0 || i_skip + i_payload_data_length > i_packet_size_left )
517         {
518             break;
519         }
520 #if 0
521          msg_Dbg( p_demux,
522                   "payload(%d/%d) stream_number:%d media_object_number:%d media_object_offset:%d replicated_data_length:%d payload_data_length %d",
523                   i_payload + 1, i_payload_count, i_stream_number, i_media_object_number,
524                   i_media_object_offset, i_replicated_data_length, i_payload_data_length );
525 #endif
526
527         if( ( tk = p_sys->track[i_stream_number] ) == NULL )
528         {
529             msg_Warn( p_demux,
530                       "undeclared stream[Id 0x%x]", i_stream_number );
531             i_skip += i_payload_data_length;
532             continue;   // over payload
533         }
534
535         if( !tk->p_es )
536         {
537             i_skip += i_payload_data_length;
538             continue;
539         }
540
541
542         for( i_payload_data_pos = 0;
543              i_payload_data_pos < i_payload_data_length &&
544                     i_packet_size_left > 0;
545              i_payload_data_pos += i_sub_payload_data_length )
546         {
547             block_t *p_frag;
548             int i_read;
549
550             // read sub payload length
551             if( i_replicated_data_length == 1 )
552             {
553                 i_sub_payload_data_length = p_peek[i_skip]; i_skip++;
554                 i_payload_data_pos++;
555             }
556             else
557             {
558                 i_sub_payload_data_length = i_payload_data_length;
559             }
560
561             /* FIXME I don't use i_media_object_number, sould I ? */
562             if( tk->p_frame && i_media_object_offset == 0 )
563             {
564                 /* send complete packet to decoder */
565                 block_t *p_gather = block_ChainGather( tk->p_frame );
566
567                 es_out_Send( p_demux->out, tk->p_es, p_gather );
568
569                 tk->p_frame = NULL;
570             }
571
572             i_read = i_sub_payload_data_length + i_skip;
573             if( ( p_frag = stream_Block( p_demux->s, i_read ) ) == NULL )
574             {
575                 msg_Warn( p_demux, "cannot read data" );
576                 return 0;
577             }
578             i_packet_size_left -= i_read;
579
580             p_frag->p_buffer += i_skip;
581             p_frag->i_buffer -= i_skip;
582
583             if( tk->p_frame == NULL )
584             {
585                 tk->i_time =
586                     ( (mtime_t)i_pts + i_payload * (mtime_t)i_pts_delta );
587
588                 p_frag->i_pts = tk->i_time;
589
590                 if( tk->i_cat != VIDEO_ES )
591                     p_frag->i_dts = p_frag->i_pts;
592                 else
593                 {
594                     p_frag->i_dts = p_frag->i_pts;
595                     p_frag->i_pts = 0;
596                 }
597             }
598
599             block_ChainAppend( &tk->p_frame, p_frag );
600
601             i_skip = 0;
602             if( i_packet_size_left > 0 )
603             {
604                 if( stream_Peek( p_demux->s, &p_peek, i_packet_size_left )
605                                                          < i_packet_size_left )
606                 {
607                     msg_Warn( p_demux, "cannot peek, EOF ?" );
608                     return 0;
609                 }
610             }
611         }
612     }
613
614     if( i_packet_size_left > 0 )
615     {
616         if( stream_Read( p_demux->s, NULL, i_packet_size_left )
617                                                          < i_packet_size_left )
618         {
619             msg_Warn( p_demux, "cannot skip data, EOF ?" );
620             return 0;
621         }
622     }
623
624     return 1;
625
626 loop_error_recovery:
627     msg_Warn( p_demux, "unsupported packet header" );
628     if( p_sys->p_fp->i_min_data_packet_size != p_sys->p_fp->i_max_data_packet_size )
629     {
630         msg_Err( p_demux, "unsupported packet header, fatal error" );
631         return -1;
632     }
633     stream_Read( p_demux->s, NULL, i_data_packet_min );
634
635     return 1;
636 }
637
638 /*****************************************************************************
639  *
640  *****************************************************************************/
641 static int DemuxInit( demux_t *p_demux )
642 {
643     demux_sys_t *p_sys = p_demux->p_sys;
644     vlc_bool_t b_seekable;
645     unsigned int i_stream, i;
646     asf_object_content_description_t *p_cd;
647     asf_object_index_t *p_index;
648     vlc_bool_t b_index;
649
650     /* init context */
651     p_sys->i_time   = -1;
652     p_sys->i_length = 0;
653     p_sys->i_bitrate = 0;
654     p_sys->p_root   = NULL;
655     p_sys->p_fp     = NULL;
656     p_sys->b_index  = 0;
657     p_sys->i_track  = 0;
658     for( i = 0; i < 128; i++ )
659     {
660         p_sys->track[i] = NULL;
661     }
662     p_sys->i_data_begin = -1;
663     p_sys->i_data_end   = -1;
664     p_sys->meta         = NULL;
665
666     /* Now load all object ( except raw data ) */
667     stream_Control( p_demux->s, STREAM_CAN_FASTSEEK, &b_seekable );
668     if( !(p_sys->p_root = ASF_ReadObjectRoot(p_demux->s, b_seekable)) )
669     {
670         msg_Warn( p_demux, "ASF plugin discarded (not a valid file)" );
671         return VLC_EGENERIC;
672     }
673     p_sys->p_fp = p_sys->p_root->p_fp;
674
675     if( p_sys->p_fp->i_min_data_packet_size != p_sys->p_fp->i_max_data_packet_size )
676     {
677         msg_Warn( p_demux, "ASF plugin discarded (invalid file_properties object)" );
678         goto error;
679     }
680
681     p_sys->i_track = ASF_CountObject( p_sys->p_root->p_hdr,
682                                       &asf_object_stream_properties_guid );
683     if( p_sys->i_track <= 0 )
684     {
685         msg_Warn( p_demux, "ASF plugin discarded (cannot find any stream!)" );
686         goto error;
687     }
688
689     /* check if index is available */
690     p_index = ASF_FindObject( p_sys->p_root, &asf_object_index_guid, 0 );
691     b_index = p_index && p_index->i_index_entry_count;
692
693     msg_Dbg( p_demux, "found %d streams", p_sys->i_track );
694
695     for( i_stream = 0; i_stream < p_sys->i_track; i_stream ++ )
696     {
697         asf_track_t    *tk;
698         asf_object_stream_properties_t *p_sp;
699         vlc_bool_t b_access_selected;
700
701         p_sp = ASF_FindObject( p_sys->p_root->p_hdr,
702                                &asf_object_stream_properties_guid,
703                                i_stream );
704
705         tk = p_sys->track[p_sp->i_stream_number] = malloc( sizeof( asf_track_t ) );
706         memset( tk, 0, sizeof( asf_track_t ) );
707
708         tk->i_time = -1;
709         tk->p_sp = p_sp;
710         tk->p_es = NULL;
711         tk->p_frame = NULL;
712
713         /* Check (in case of mms) if this track is selected (ie will receive data) */
714         if( !stream_Control( p_demux->s, STREAM_CONTROL_ACCESS, ACCESS_GET_PRIVATE_ID_STATE,
715                              p_sp->i_stream_number, &b_access_selected ) &&
716             !b_access_selected )
717         {
718             tk->i_cat = UNKNOWN_ES;
719             msg_Dbg( p_demux, "ignoring not selected stream(ID:%d) (by access)",
720                      p_sp->i_stream_number );
721             continue;
722         }
723
724         if( ASF_CmpGUID( &p_sp->i_stream_type, &asf_object_stream_type_audio ) &&
725             p_sp->i_type_specific_data_length >= sizeof( WAVEFORMATEX ) - 2 )
726         {
727             es_format_t fmt;
728             uint8_t *p_data = p_sp->p_type_specific_data;
729             int i_format;
730
731             es_format_Init( &fmt, AUDIO_ES, 0 );
732             i_format = GetWLE( &p_data[0] );
733             wf_tag_to_fourcc( i_format, &fmt.i_codec, NULL );
734             fmt.audio.i_channels        = GetWLE(  &p_data[2] );
735             fmt.audio.i_rate      = GetDWLE( &p_data[4] );
736             fmt.i_bitrate         = GetDWLE( &p_data[8] ) * 8;
737             fmt.audio.i_blockalign      = GetWLE(  &p_data[12] );
738             fmt.audio.i_bitspersample   = GetWLE(  &p_data[14] );
739
740             if( p_sp->i_type_specific_data_length > sizeof( WAVEFORMATEX ) &&
741                 i_format != WAVE_FORMAT_MPEGLAYER3 &&
742                 i_format != WAVE_FORMAT_MPEG )
743             {
744                 fmt.i_extra = __MIN( GetWLE( &p_data[16] ),
745                                      p_sp->i_type_specific_data_length -
746                                      sizeof( WAVEFORMATEX ) );
747                 fmt.p_extra = malloc( fmt.i_extra );
748                 memcpy( fmt.p_extra, &p_data[sizeof( WAVEFORMATEX )],
749                         fmt.i_extra );
750             }
751
752             tk->i_cat = AUDIO_ES;
753             tk->p_es = es_out_Add( p_demux->out, &fmt );
754             es_format_Clean( &fmt );
755
756             msg_Dbg( p_demux, "added new audio stream(codec:0x%x,ID:%d)",
757                     GetWLE( p_data ), p_sp->i_stream_number );
758         }
759         else if( ASF_CmpGUID( &p_sp->i_stream_type,
760                               &asf_object_stream_type_video ) &&
761                  p_sp->i_type_specific_data_length >= 11 +
762                  sizeof( BITMAPINFOHEADER ) )
763         {
764             es_format_t  fmt;
765             uint8_t      *p_data = &p_sp->p_type_specific_data[11];
766
767             es_format_Init( &fmt, VIDEO_ES,
768                             VLC_FOURCC( p_data[16], p_data[17],
769                                         p_data[18], p_data[19] ) );
770             fmt.video.i_width = GetDWLE( p_data + 4 );
771             fmt.video.i_height= GetDWLE( p_data + 8 );
772
773
774             if( fmt.i_codec == VLC_FOURCC( 'D','V','R',' ') )
775             {
776                 /* DVR-MS special ASF */
777                 fmt.i_codec = VLC_FOURCC( 'm','p','g','2' ) ;
778                 fmt.b_packetized = VLC_FALSE;
779             }
780
781             if( p_sp->i_type_specific_data_length > 11 +
782                 sizeof( BITMAPINFOHEADER ) )
783             {
784                 fmt.i_extra = __MIN( GetDWLE( p_data ),
785                                      p_sp->i_type_specific_data_length - 11 -
786                                      sizeof( BITMAPINFOHEADER ) );
787                 fmt.p_extra = malloc( fmt.i_extra );
788                 memcpy( fmt.p_extra, &p_data[sizeof( BITMAPINFOHEADER )],
789                         fmt.i_extra );
790             }
791
792             /* Look for an aspect ratio */
793             if( p_sys->p_root->p_metadata )
794             {
795                 asf_object_metadata_t *p_meta = p_sys->p_root->p_metadata;
796                 int i_aspect_x = 0, i_aspect_y = 0;
797                 unsigned int i;
798
799                 for( i = 0; i < p_meta->i_record_entries_count; i++ )
800                 {
801                     if( !strcmp( p_meta->record[i].psz_name, "AspectRatioX" ) )
802                     {
803                         if( (!i_aspect_x && !p_meta->record[i].i_stream) ||
804                             p_meta->record[i].i_stream ==
805                             p_sp->i_stream_number )
806                             i_aspect_x = p_meta->record[i].i_val;
807                     }
808                     if( !strcmp( p_meta->record[i].psz_name, "AspectRatioY" ) )
809                     {
810                         if( (!i_aspect_y && !p_meta->record[i].i_stream) ||
811                             p_meta->record[i].i_stream ==
812                             p_sp->i_stream_number )
813                             i_aspect_y = p_meta->record[i].i_val;
814                     }
815                 }
816
817                 if( i_aspect_x && i_aspect_y )
818                 {
819                     fmt.video.i_aspect = i_aspect_x *
820                         (int64_t)fmt.video.i_width * VOUT_ASPECT_FACTOR /
821                         fmt.video.i_height / i_aspect_y;
822                 }
823             }
824
825             tk->i_cat = VIDEO_ES;
826             tk->p_es = es_out_Add( p_demux->out, &fmt );
827             es_format_Clean( &fmt );
828
829             /* If there is a video track then use the index for seeking */
830             p_sys->b_index = b_index;
831
832             msg_Dbg( p_demux, "added new video stream(ID:%d)",
833                      p_sp->i_stream_number );
834         }
835         else if( ASF_CmpGUID( &p_sp->i_stream_type, &asf_object_extended_stream_header ) &&
836             p_sp->i_type_specific_data_length >= 64 )
837         {
838             /* Now follows a 64 byte header of which we don't know much */
839             es_format_t fmt;
840             guid_t  *p_ref  = (guid_t *)p_sp->p_type_specific_data;
841             uint8_t *p_data = p_sp->p_type_specific_data + 64;
842             unsigned int i_data = p_sp->i_type_specific_data_length - 64;
843
844             msg_Dbg( p_demux, "Ext stream header detected. datasize = %d", p_sp->i_type_specific_data_length );
845             if( ASF_CmpGUID( p_ref, &asf_object_extended_stream_type_audio ) && 
846                 i_data >= sizeof( WAVEFORMATEX ) - 2)
847             {
848                 int      i_format;
849                 es_format_Init( &fmt, AUDIO_ES, 0 );
850                 i_format = GetWLE( &p_data[0] );
851                 if( i_format == 0 ) 
852                     fmt.i_codec = VLC_FOURCC( 'a','5','2',' ');
853                 else
854                     wf_tag_to_fourcc( i_format, &fmt.i_codec, NULL );
855                 fmt.audio.i_channels        = GetWLE(  &p_data[2] );
856                 fmt.audio.i_rate      = GetDWLE( &p_data[4] );
857                 fmt.i_bitrate         = GetDWLE( &p_data[8] ) * 8;
858                 fmt.audio.i_blockalign      = GetWLE(  &p_data[12] );
859                 fmt.audio.i_bitspersample   = GetWLE(  &p_data[14] );
860                 fmt.b_packetized = VLC_TRUE;
861
862                 if( p_sp->i_type_specific_data_length > sizeof( WAVEFORMATEX ) &&
863                     i_format != WAVE_FORMAT_MPEGLAYER3 &&
864                     i_format != WAVE_FORMAT_MPEG )
865                 {
866                     fmt.i_extra = __MIN( GetWLE( &p_data[16] ),
867                                          p_sp->i_type_specific_data_length -
868                                          sizeof( WAVEFORMATEX ) );
869                     fmt.p_extra = malloc( fmt.i_extra );
870                     memcpy( fmt.p_extra, &p_data[sizeof( WAVEFORMATEX )],
871                         fmt.i_extra );
872                 }
873
874                 tk->i_cat = AUDIO_ES;
875                 tk->p_es = es_out_Add( p_demux->out, &fmt );
876                 es_format_Clean( &fmt );
877
878                 msg_Dbg( p_demux, "added new audio stream (codec:0x%x,ID:%d)",
879                     i_format, p_sp->i_stream_number );
880             }
881         }
882         else
883         {
884             tk->i_cat = UNKNOWN_ES;
885             msg_Dbg( p_demux, "ignoring unknown stream(ID:%d)",
886                      p_sp->i_stream_number );
887         }
888     }
889
890     p_sys->i_data_begin = p_sys->p_root->p_data->i_object_pos + 50;
891     if( p_sys->p_root->p_data->i_object_size != 0 )
892     { /* local file */
893         p_sys->i_data_end = p_sys->p_root->p_data->i_object_pos +
894                                     p_sys->p_root->p_data->i_object_size;
895     }
896     else
897     { /* live/broacast */
898         p_sys->i_data_end = -1;
899     }
900
901     /* go to first packet */
902     stream_Seek( p_demux->s, p_sys->i_data_begin );
903
904     /* try to calculate movie time */
905     if( p_sys->p_fp->i_data_packets_count > 0 )
906     {
907         int64_t i_count;
908         int64_t i_size = stream_Size( p_demux->s );
909
910         if( p_sys->i_data_end > 0 && i_size > p_sys->i_data_end )
911         {
912             i_size = p_sys->i_data_end;
913         }
914
915         /* real number of packets */
916         i_count = ( i_size - p_sys->i_data_begin ) /
917                   p_sys->p_fp->i_min_data_packet_size;
918
919         /* calculate the time duration in micro-s */
920         p_sys->i_length = (mtime_t)p_sys->p_fp->i_play_duration / 10 *
921                    (mtime_t)i_count /
922                    (mtime_t)p_sys->p_fp->i_data_packets_count;
923
924         if( p_sys->i_length > 0 )
925         {
926             p_sys->i_bitrate = 8 * i_size * (int64_t)1000000 / p_sys->i_length;
927         }
928     }
929
930     /* Create meta information */
931     p_sys->meta = vlc_meta_New();
932
933     if( ( p_cd = ASF_FindObject( p_sys->p_root->p_hdr,
934                                  &asf_object_content_description_guid, 0 ) ) )
935     {
936         if( p_cd->psz_title && *p_cd->psz_title )
937         {
938             vlc_meta_SetTitle( p_sys->meta, p_cd->psz_title );
939         }
940         if( p_cd->psz_artist && *p_cd->psz_artist )
941         {
942              vlc_meta_SetArtist( p_sys->meta, p_cd->psz_artist );
943         }
944         if( p_cd->psz_copyright && *p_cd->psz_copyright )
945         {
946             vlc_meta_SetCopyright( p_sys->meta, p_cd->psz_copyright );
947         }
948         if( p_cd->psz_description && *p_cd->psz_description )
949         {
950             vlc_meta_SetDescription( p_sys->meta, p_cd->psz_description );
951         }
952         if( p_cd->psz_rating && *p_cd->psz_rating )
953         {
954             vlc_meta_SetRating( p_sys->meta, p_cd->psz_rating );
955         }
956     }
957     /// \tood Fix Child meta for ASF tracks
958 #if 0
959     for( i_stream = 0, i = 0; i < 128; i++ )
960     {
961         asf_object_codec_list_t *p_cl = ASF_FindObject( p_sys->p_root->p_hdr,
962                                                         &asf_object_codec_list_guid, 0 );
963
964         if( p_sys->track[i] )
965         {
966             vlc_meta_t *tk = vlc_meta_New();
967             TAB_APPEND( p_sys->meta->i_track, p_sys->meta->track, tk );
968
969             if( p_cl && i_stream < p_cl->i_codec_entries_count )
970             {
971                 if( p_cl->codec[i_stream].psz_name &&
972                     *p_cl->codec[i_stream].psz_name )
973                 {
974                     vlc_meta_Add( tk, VLC_META_CODEC_NAME,
975                                   p_cl->codec[i_stream].psz_name );
976                 }
977                 if( p_cl->codec[i_stream].psz_description &&
978                     *p_cl->codec[i_stream].psz_description )
979                 {
980                     vlc_meta_Add( tk, VLC_META_CODEC_DESCRIPTION,
981                                   p_cl->codec[i_stream].psz_description );
982                 }
983             }
984             i_stream++;
985         }
986     }
987 #endif
988
989     es_out_Control( p_demux->out, ES_OUT_RESET_PCR );
990     return VLC_SUCCESS;
991
992 error:
993     ASF_FreeObjectRoot( p_demux->s, p_sys->p_root );
994     return VLC_EGENERIC;
995 }
996 /*****************************************************************************
997  *
998  *****************************************************************************/
999 static void DemuxEnd( demux_t *p_demux )
1000 {
1001     demux_sys_t *p_sys = p_demux->p_sys;
1002     int         i;
1003
1004     if( p_sys->p_root )
1005     {
1006         ASF_FreeObjectRoot( p_demux->s, p_sys->p_root );
1007         p_sys->p_root = NULL;
1008     }
1009     if( p_sys->meta )
1010     {
1011         vlc_meta_Delete( p_sys->meta );
1012         p_sys->meta = NULL;
1013     }
1014
1015     for( i = 0; i < 128; i++ )
1016     {
1017         asf_track_t *tk = p_sys->track[i];
1018
1019         if( tk )
1020         {
1021             if( tk->p_frame )
1022             {
1023                 block_ChainRelease( tk->p_frame );
1024             }
1025             if( tk->p_es )
1026             {
1027                 es_out_Del( p_demux->out, tk->p_es );
1028             }
1029             free( tk );
1030         }
1031         p_sys->track[i] = 0;
1032     }
1033 }
1034