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