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