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