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