]> git.sesse.net Git - vlc/blob - modules/demux/asf/asf.c
Include vlc_plugin.h as needed
[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/vlc.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( _("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( p_demux->b_die )
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         if( i_packet_size_left > i_packet_padding_length )
633             msg_Warn( p_demux, "Didn't read %d bytes in the packet",
634                             i_packet_size_left - i_packet_padding_length );
635         else if( i_packet_size_left < i_packet_padding_length )
636             msg_Warn( p_demux, "Read %d too much bytes in the packet",
637                             i_packet_padding_length - i_packet_size_left );
638
639         if( stream_Read( p_demux->s, NULL, i_packet_size_left )
640                                                          < i_packet_size_left )
641         {
642             msg_Err( p_demux, "cannot skip data, EOF ?" );
643             return 0;
644         }
645     }
646
647     return 1;
648
649 loop_error_recovery:
650     msg_Warn( p_demux, "unsupported packet header" );
651     if( p_sys->p_fp->i_min_data_packet_size != p_sys->p_fp->i_max_data_packet_size )
652     {
653         msg_Err( p_demux, "unsupported packet header, fatal error" );
654         return -1;
655     }
656     stream_Read( p_demux->s, NULL, i_data_packet_min );
657
658     return 1;
659 }
660
661 /*****************************************************************************
662  *
663  *****************************************************************************/
664 static int DemuxInit( demux_t *p_demux )
665 {
666     demux_sys_t *p_sys = p_demux->p_sys;
667     bool b_seekable;
668     unsigned int i_stream, i;
669     asf_object_content_description_t *p_cd;
670     asf_object_index_t *p_index;
671     bool b_index;
672
673     /* init context */
674     p_sys->i_time   = -1;
675     p_sys->i_length = 0;
676     p_sys->i_bitrate = 0;
677     p_sys->p_root   = NULL;
678     p_sys->p_fp     = NULL;
679     p_sys->b_index  = 0;
680     p_sys->i_track  = 0;
681     for( i = 0; i < 128; i++ )
682     {
683         p_sys->track[i] = NULL;
684     }
685     p_sys->i_data_begin = -1;
686     p_sys->i_data_end   = -1;
687     p_sys->meta         = NULL;
688
689     /* Now load all object ( except raw data ) */
690     stream_Control( p_demux->s, STREAM_CAN_FASTSEEK, &b_seekable );
691     if( !(p_sys->p_root = ASF_ReadObjectRoot(p_demux->s, b_seekable)) )
692     {
693         msg_Warn( p_demux, "ASF plugin discarded (not a valid file)" );
694         return VLC_EGENERIC;
695     }
696     p_sys->p_fp = p_sys->p_root->p_fp;
697
698     if( p_sys->p_fp->i_min_data_packet_size != p_sys->p_fp->i_max_data_packet_size )
699     {
700         msg_Warn( p_demux, "ASF plugin discarded (invalid file_properties object)" );
701         goto error;
702     }
703
704     p_sys->i_track = ASF_CountObject( p_sys->p_root->p_hdr,
705                                       &asf_object_stream_properties_guid );
706     if( p_sys->i_track <= 0 )
707     {
708         msg_Warn( p_demux, "ASF plugin discarded (cannot find any stream!)" );
709         goto error;
710     }
711
712     /* check if index is available */
713     p_index = ASF_FindObject( p_sys->p_root, &asf_object_index_guid, 0 );
714     b_index = p_index && p_index->i_index_entry_count;
715
716     msg_Dbg( p_demux, "found %d streams", p_sys->i_track );
717
718     for( i_stream = 0; i_stream < p_sys->i_track; i_stream ++ )
719     {
720         asf_track_t    *tk;
721         asf_object_stream_properties_t *p_sp;
722         bool b_access_selected;
723
724         p_sp = ASF_FindObject( p_sys->p_root->p_hdr,
725                                &asf_object_stream_properties_guid,
726                                i_stream );
727
728         tk = p_sys->track[p_sp->i_stream_number] = malloc( sizeof( asf_track_t ) );
729         memset( tk, 0, sizeof( asf_track_t ) );
730
731         tk->i_time = -1;
732         tk->p_sp = p_sp;
733         tk->p_es = NULL;
734         tk->p_frame = NULL;
735
736         /* Check (in case of mms) if this track is selected (ie will receive data) */
737         if( !stream_Control( p_demux->s, STREAM_CONTROL_ACCESS, ACCESS_GET_PRIVATE_ID_STATE,
738                              p_sp->i_stream_number, &b_access_selected ) &&
739             !b_access_selected )
740         {
741             tk->i_cat = UNKNOWN_ES;
742             msg_Dbg( p_demux, "ignoring not selected stream(ID:%d) (by access)",
743                      p_sp->i_stream_number );
744             continue;
745         }
746
747         if( ASF_CmpGUID( &p_sp->i_stream_type, &asf_object_stream_type_audio ) &&
748             p_sp->i_type_specific_data_length >= sizeof( WAVEFORMATEX ) - 2 )
749         {
750             es_format_t fmt;
751             uint8_t *p_data = p_sp->p_type_specific_data;
752             int i_format;
753
754             es_format_Init( &fmt, AUDIO_ES, 0 );
755             i_format = GetWLE( &p_data[0] );
756             wf_tag_to_fourcc( i_format, &fmt.i_codec, NULL );
757             fmt.audio.i_channels        = GetWLE(  &p_data[2] );
758             fmt.audio.i_rate      = GetDWLE( &p_data[4] );
759             fmt.i_bitrate         = GetDWLE( &p_data[8] ) * 8;
760             fmt.audio.i_blockalign      = GetWLE(  &p_data[12] );
761             fmt.audio.i_bitspersample   = GetWLE(  &p_data[14] );
762
763             if( p_sp->i_type_specific_data_length > sizeof( WAVEFORMATEX ) &&
764                 i_format != WAVE_FORMAT_MPEGLAYER3 &&
765                 i_format != WAVE_FORMAT_MPEG )
766             {
767                 fmt.i_extra = __MIN( GetWLE( &p_data[16] ),
768                                      p_sp->i_type_specific_data_length -
769                                      sizeof( WAVEFORMATEX ) );
770                 fmt.p_extra = malloc( fmt.i_extra );
771                 memcpy( fmt.p_extra, &p_data[sizeof( WAVEFORMATEX )],
772                         fmt.i_extra );
773             }
774
775             tk->i_cat = AUDIO_ES;
776             tk->p_es = es_out_Add( p_demux->out, &fmt );
777             es_format_Clean( &fmt );
778
779             msg_Dbg( p_demux, "added new audio stream(codec:0x%x,ID:%d)",
780                     GetWLE( p_data ), p_sp->i_stream_number );
781         }
782         else if( ASF_CmpGUID( &p_sp->i_stream_type,
783                               &asf_object_stream_type_video ) &&
784                  p_sp->i_type_specific_data_length >= 11 +
785                  sizeof( BITMAPINFOHEADER ) )
786         {
787             es_format_t  fmt;
788             uint8_t      *p_data = &p_sp->p_type_specific_data[11];
789
790             es_format_Init( &fmt, VIDEO_ES,
791                             VLC_FOURCC( p_data[16], p_data[17],
792                                         p_data[18], p_data[19] ) );
793             fmt.video.i_width = GetDWLE( p_data + 4 );
794             fmt.video.i_height= GetDWLE( p_data + 8 );
795
796
797             if( fmt.i_codec == VLC_FOURCC( 'D','V','R',' ') )
798             {
799                 /* DVR-MS special ASF */
800                 fmt.i_codec = VLC_FOURCC( 'm','p','g','2' ) ;
801                 fmt.b_packetized = false;
802             }
803
804             if( p_sp->i_type_specific_data_length > 11 +
805                 sizeof( BITMAPINFOHEADER ) )
806             {
807                 fmt.i_extra = __MIN( GetDWLE( p_data ),
808                                      p_sp->i_type_specific_data_length - 11 -
809                                      sizeof( BITMAPINFOHEADER ) );
810                 fmt.p_extra = malloc( fmt.i_extra );
811                 memcpy( fmt.p_extra, &p_data[sizeof( BITMAPINFOHEADER )],
812                         fmt.i_extra );
813             }
814
815             /* Look for an aspect ratio */
816             if( p_sys->p_root->p_metadata )
817             {
818                 asf_object_metadata_t *p_meta = p_sys->p_root->p_metadata;
819                 int i_aspect_x = 0, i_aspect_y = 0;
820                 unsigned int i;
821
822                 for( i = 0; i < p_meta->i_record_entries_count; i++ )
823                 {
824                     if( !strcmp( p_meta->record[i].psz_name, "AspectRatioX" ) )
825                     {
826                         if( (!i_aspect_x && !p_meta->record[i].i_stream) ||
827                             p_meta->record[i].i_stream ==
828                             p_sp->i_stream_number )
829                             i_aspect_x = p_meta->record[i].i_val;
830                     }
831                     if( !strcmp( p_meta->record[i].psz_name, "AspectRatioY" ) )
832                     {
833                         if( (!i_aspect_y && !p_meta->record[i].i_stream) ||
834                             p_meta->record[i].i_stream ==
835                             p_sp->i_stream_number )
836                             i_aspect_y = p_meta->record[i].i_val;
837                     }
838                 }
839
840                 if( i_aspect_x && i_aspect_y )
841                 {
842                     fmt.video.i_aspect = i_aspect_x *
843                         (int64_t)fmt.video.i_width * VOUT_ASPECT_FACTOR /
844                         fmt.video.i_height / i_aspect_y;
845                 }
846         }
847
848             tk->i_cat = VIDEO_ES;
849             tk->p_es = es_out_Add( p_demux->out, &fmt );
850             es_format_Clean( &fmt );
851
852             /* If there is a video track then use the index for seeking */
853             p_sys->b_index = b_index;
854
855             msg_Dbg( p_demux, "added new video stream(ID:%d)",
856                      p_sp->i_stream_number );
857         }
858         else if( ASF_CmpGUID( &p_sp->i_stream_type, &asf_object_extended_stream_header ) &&
859             p_sp->i_type_specific_data_length >= 64 )
860         {
861             /* Now follows a 64 byte header of which we don't know much */
862             es_format_t fmt;
863             guid_t  *p_ref  = (guid_t *)p_sp->p_type_specific_data;
864             uint8_t *p_data = p_sp->p_type_specific_data + 64;
865             unsigned int i_data = p_sp->i_type_specific_data_length - 64;
866
867             msg_Dbg( p_demux, "Ext stream header detected. datasize = %d", p_sp->i_type_specific_data_length );
868             if( ASF_CmpGUID( p_ref, &asf_object_extended_stream_type_audio ) &&
869                 i_data >= sizeof( WAVEFORMATEX ) - 2)
870             {
871                 int      i_format;
872                 es_format_Init( &fmt, AUDIO_ES, 0 );
873                 i_format = GetWLE( &p_data[0] );
874                 if( i_format == 0 )
875                     fmt.i_codec = VLC_FOURCC( 'a','5','2',' ');
876                 else
877                     wf_tag_to_fourcc( i_format, &fmt.i_codec, NULL );
878                 fmt.audio.i_channels        = GetWLE(  &p_data[2] );
879                 fmt.audio.i_rate      = GetDWLE( &p_data[4] );
880                 fmt.i_bitrate         = GetDWLE( &p_data[8] ) * 8;
881                 fmt.audio.i_blockalign      = GetWLE(  &p_data[12] );
882                 fmt.audio.i_bitspersample   = GetWLE(  &p_data[14] );
883                 fmt.b_packetized = true;
884
885                 if( p_sp->i_type_specific_data_length > sizeof( WAVEFORMATEX ) &&
886                     i_format != WAVE_FORMAT_MPEGLAYER3 &&
887                     i_format != WAVE_FORMAT_MPEG )
888                 {
889                     fmt.i_extra = __MIN( GetWLE( &p_data[16] ),
890                                          p_sp->i_type_specific_data_length -
891                                          sizeof( WAVEFORMATEX ) );
892                     fmt.p_extra = malloc( fmt.i_extra );
893                     memcpy( fmt.p_extra, &p_data[sizeof( WAVEFORMATEX )],
894                         fmt.i_extra );
895                 }
896
897                 tk->i_cat = AUDIO_ES;
898                 tk->p_es = es_out_Add( p_demux->out, &fmt );
899                 es_format_Clean( &fmt );
900
901                 msg_Dbg( p_demux, "added new audio stream (codec:0x%x,ID:%d)",
902                     i_format, p_sp->i_stream_number );
903             }
904         }
905         else
906         {
907             tk->i_cat = UNKNOWN_ES;
908             msg_Dbg( p_demux, "ignoring unknown stream(ID:%d)",
909                      p_sp->i_stream_number );
910         }
911     }
912
913     p_sys->i_data_begin = p_sys->p_root->p_data->i_object_pos + 50;
914     if( p_sys->p_root->p_data->i_object_size != 0 )
915     { /* local file */
916         p_sys->i_data_end = p_sys->p_root->p_data->i_object_pos +
917                                     p_sys->p_root->p_data->i_object_size;
918     }
919     else
920     { /* live/broacast */
921         p_sys->i_data_end = -1;
922     }
923
924     /* go to first packet */
925     stream_Seek( p_demux->s, p_sys->i_data_begin );
926
927     /* try to calculate movie time */
928     if( p_sys->p_fp->i_data_packets_count > 0 )
929     {
930         int64_t i_count;
931         int64_t i_size = stream_Size( p_demux->s );
932
933         if( p_sys->i_data_end > 0 && i_size > p_sys->i_data_end )
934         {
935             i_size = p_sys->i_data_end;
936         }
937
938         /* real number of packets */
939         i_count = ( i_size - p_sys->i_data_begin ) /
940                   p_sys->p_fp->i_min_data_packet_size;
941
942         /* calculate the time duration in micro-s */
943         p_sys->i_length = (mtime_t)p_sys->p_fp->i_play_duration / 10 *
944                    (mtime_t)i_count /
945                    (mtime_t)p_sys->p_fp->i_data_packets_count;
946
947         if( p_sys->i_length > 0 )
948         {
949             p_sys->i_bitrate = 8 * i_size * (int64_t)1000000 / p_sys->i_length;
950         }
951     }
952
953     /* Create meta information */
954     p_sys->meta = vlc_meta_New();
955
956     if( ( p_cd = ASF_FindObject( p_sys->p_root->p_hdr,
957                                  &asf_object_content_description_guid, 0 ) ) )
958     {
959         if( p_cd->psz_title && *p_cd->psz_title )
960         {
961             vlc_meta_SetTitle( p_sys->meta, p_cd->psz_title );
962         }
963         if( p_cd->psz_artist && *p_cd->psz_artist )
964         {
965              vlc_meta_SetArtist( p_sys->meta, p_cd->psz_artist );
966         }
967         if( p_cd->psz_copyright && *p_cd->psz_copyright )
968         {
969             vlc_meta_SetCopyright( p_sys->meta, p_cd->psz_copyright );
970         }
971         if( p_cd->psz_description && *p_cd->psz_description )
972         {
973             vlc_meta_SetDescription( p_sys->meta, p_cd->psz_description );
974         }
975         if( p_cd->psz_rating && *p_cd->psz_rating )
976         {
977             vlc_meta_SetRating( p_sys->meta, p_cd->psz_rating );
978         }
979     }
980     /// \tood Fix Child meta for ASF tracks
981 #if 0
982     for( i_stream = 0, i = 0; i < 128; i++ )
983     {
984         asf_object_codec_list_t *p_cl = ASF_FindObject( p_sys->p_root->p_hdr,
985                                                         &asf_object_codec_list_guid, 0 );
986
987         if( p_sys->track[i] )
988         {
989             vlc_meta_t *tk = vlc_meta_New();
990             TAB_APPEND( p_sys->meta->i_track, p_sys->meta->track, tk );
991
992             if( p_cl && i_stream < p_cl->i_codec_entries_count )
993             {
994                 if( p_cl->codec[i_stream].psz_name &&
995                     *p_cl->codec[i_stream].psz_name )
996                 {
997                     vlc_meta_Add( tk, VLC_META_CODEC_NAME,
998                                   p_cl->codec[i_stream].psz_name );
999                 }
1000                 if( p_cl->codec[i_stream].psz_description &&
1001                     *p_cl->codec[i_stream].psz_description )
1002                 {
1003                     vlc_meta_Add( tk, VLC_META_CODEC_DESCRIPTION,
1004                                   p_cl->codec[i_stream].psz_description );
1005                 }
1006             }
1007             i_stream++;
1008         }
1009     }
1010 #endif
1011
1012     es_out_Control( p_demux->out, ES_OUT_RESET_PCR );
1013     return VLC_SUCCESS;
1014
1015 error:
1016     ASF_FreeObjectRoot( p_demux->s, p_sys->p_root );
1017     return VLC_EGENERIC;
1018 }
1019 /*****************************************************************************
1020  *
1021  *****************************************************************************/
1022 static void DemuxEnd( demux_t *p_demux )
1023 {
1024     demux_sys_t *p_sys = p_demux->p_sys;
1025     int         i;
1026
1027     if( p_sys->p_root )
1028     {
1029         ASF_FreeObjectRoot( p_demux->s, p_sys->p_root );
1030         p_sys->p_root = NULL;
1031     }
1032     if( p_sys->meta )
1033     {
1034         vlc_meta_Delete( p_sys->meta );
1035         p_sys->meta = NULL;
1036     }
1037
1038     for( i = 0; i < 128; i++ )
1039     {
1040         asf_track_t *tk = p_sys->track[i];
1041
1042         if( tk )
1043         {
1044             if( tk->p_frame )
1045             {
1046                 block_ChainRelease( tk->p_frame );
1047             }
1048             if( tk->p_es )
1049             {
1050                 es_out_Del( p_demux->out, tk->p_es );
1051             }
1052             free( tk );
1053         }
1054         p_sys->track[i] = 0;
1055     }
1056 }
1057