]> git.sesse.net Git - vlc/blob - modules/demux/asf/asf.c
* all: better support for MBR mms stream (display only received streams).
[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         vlc_bool_t b_access_selected;
641
642         p_sp = ASF_FindObject( p_sys->p_root->p_hdr,
643                                &asf_object_stream_properties_guid,
644                                i_stream );
645
646         tk = p_sys->track[p_sp->i_stream_number] = malloc( sizeof( asf_track_t ) );
647         memset( tk, 0, sizeof( asf_track_t ) );
648
649         tk->i_time = -1;
650         tk->p_sp = p_sp;
651         tk->p_es = NULL;
652         tk->p_frame = NULL;
653
654         /* Check (in case of mms) if this track is selected (ie will receive data) */
655         if( !stream_Control( p_demux->s, STREAM_CONTROL_ACCESS, ACCESS_GET_PRIVATE_ID_STATE,
656                              p_sp->i_stream_number, &b_access_selected ) &&
657             !b_access_selected )
658         {
659             tk->i_cat = UNKNOWN_ES;
660             msg_Dbg( p_demux, "ignoring not selected stream(ID:%d) (by access)",
661                      p_sp->i_stream_number );
662             continue;
663         }
664
665         if( ASF_CmpGUID( &p_sp->i_stream_type, &asf_object_stream_type_audio ) &&
666             p_sp->i_type_specific_data_length >= sizeof( WAVEFORMATEX ) - 2 )
667         {
668             es_format_t fmt;
669             uint8_t *p_data = p_sp->p_type_specific_data;
670             int i_format;
671
672             es_format_Init( &fmt, AUDIO_ES, 0 );
673             i_format = GetWLE( &p_data[0] );
674             wf_tag_to_fourcc( i_format, &fmt.i_codec, NULL );
675             fmt.audio.i_channels        = GetWLE(  &p_data[2] );
676             fmt.audio.i_rate      = GetDWLE( &p_data[4] );
677             fmt.i_bitrate         = GetDWLE( &p_data[8] ) * 8;
678             fmt.audio.i_blockalign      = GetWLE(  &p_data[12] );
679             fmt.audio.i_bitspersample   = GetWLE(  &p_data[14] );
680
681             if( p_sp->i_type_specific_data_length > sizeof( WAVEFORMATEX ) &&
682                 i_format != WAVE_FORMAT_MPEGLAYER3 &&
683                 i_format != WAVE_FORMAT_MPEG )
684             {
685                 fmt.i_extra = __MIN( GetWLE( &p_data[16] ),
686                                      p_sp->i_type_specific_data_length -
687                                      sizeof( WAVEFORMATEX ) );
688                 fmt.p_extra = malloc( fmt.i_extra );
689                 memcpy( fmt.p_extra, &p_data[sizeof( WAVEFORMATEX )],
690                         fmt.i_extra );
691             }
692
693             tk->i_cat = AUDIO_ES;
694             tk->p_es = es_out_Add( p_demux->out, &fmt );
695             es_format_Clean( &fmt );
696
697             msg_Dbg( p_demux, "added new audio stream(codec:0x%x,ID:%d)",
698                     GetWLE( p_data ), p_sp->i_stream_number );
699         }
700         else if( ASF_CmpGUID( &p_sp->i_stream_type,
701                               &asf_object_stream_type_video ) &&
702                  p_sp->i_type_specific_data_length >= 11 +
703                  sizeof( BITMAPINFOHEADER ) )
704         {
705             es_format_t  fmt;
706             uint8_t      *p_data = &p_sp->p_type_specific_data[11];
707
708             es_format_Init( &fmt, VIDEO_ES,
709                             VLC_FOURCC( p_data[16], p_data[17],
710                                         p_data[18], p_data[19] ) );
711             fmt.video.i_width = GetDWLE( p_data + 4 );
712             fmt.video.i_height= GetDWLE( p_data + 8 );
713
714             if( p_sp->i_type_specific_data_length > 11 +
715                 sizeof( BITMAPINFOHEADER ) )
716             {
717                 fmt.i_extra = __MIN( GetDWLE( p_data ),
718                                      p_sp->i_type_specific_data_length - 11 -
719                                      sizeof( BITMAPINFOHEADER ) );
720                 fmt.p_extra = malloc( fmt.i_extra );
721                 memcpy( fmt.p_extra, &p_data[sizeof( BITMAPINFOHEADER )],
722                         fmt.i_extra );
723             }
724
725             /* Look for an aspect ratio */
726             if( p_sys->p_root->p_metadata )
727             {
728                 asf_object_metadata_t *p_meta = p_sys->p_root->p_metadata;
729                 int i, i_aspect_x = 0, i_aspect_y = 0;
730
731                 for( i = 0; i < p_meta->i_record_entries_count; i++ )
732                 {
733                     if( !strcmp( p_meta->record[i].psz_name, "AspectRatioX" ) )
734                     {
735                         if( (!i_aspect_x && !p_meta->record[i].i_stream) ||
736                             p_meta->record[i].i_stream ==
737                             p_sp->i_stream_number )
738                             i_aspect_x = p_meta->record[i].i_val;
739                     }
740                     if( !strcmp( p_meta->record[i].psz_name, "AspectRatioY" ) )
741                     {
742                         if( (!i_aspect_y && !p_meta->record[i].i_stream) ||
743                             p_meta->record[i].i_stream ==
744                             p_sp->i_stream_number )
745                             i_aspect_y = p_meta->record[i].i_val;
746                     }
747                 }
748
749                 if( i_aspect_x && i_aspect_y )
750                 {
751                     fmt.video.i_aspect = i_aspect_x *
752                         (int64_t)fmt.video.i_width * VOUT_ASPECT_FACTOR /
753                         fmt.video.i_height / i_aspect_y;
754                 }
755             }
756
757             tk->i_cat = VIDEO_ES;
758             tk->p_es = es_out_Add( p_demux->out, &fmt );
759             es_format_Clean( &fmt );
760
761             msg_Dbg( p_demux, "added new video stream(ID:%d)",
762                      p_sp->i_stream_number );
763         }
764         else
765         {
766             tk->i_cat = UNKNOWN_ES;
767             msg_Dbg( p_demux, "ignoring unknown stream(ID:%d)",
768                      p_sp->i_stream_number );
769         }
770     }
771
772     p_sys->i_data_begin = p_sys->p_root->p_data->i_object_pos + 50;
773     if( p_sys->p_root->p_data->i_object_size != 0 )
774     { /* local file */
775         p_sys->i_data_end = p_sys->p_root->p_data->i_object_pos +
776                                     p_sys->p_root->p_data->i_object_size;
777     }
778     else
779     { /* live/broacast */
780         p_sys->i_data_end = -1;
781     }
782
783
784     /* go to first packet */
785     stream_Seek( p_demux->s, p_sys->i_data_begin );
786
787     /* try to calculate movie time */
788     if( p_sys->p_fp->i_data_packets_count > 0 )
789     {
790         int64_t i_count;
791         int64_t i_size = stream_Size( p_demux->s );
792
793         if( p_sys->i_data_end > 0 && i_size > p_sys->i_data_end )
794         {
795             i_size = p_sys->i_data_end;
796         }
797
798         /* real number of packets */
799         i_count = ( i_size - p_sys->i_data_begin ) /
800                   p_sys->p_fp->i_min_data_packet_size;
801
802         /* calculate the time duration in micro-s */
803         p_sys->i_length = (mtime_t)p_sys->p_fp->i_play_duration / 10 *
804                    (mtime_t)i_count /
805                    (mtime_t)p_sys->p_fp->i_data_packets_count;
806
807         if( p_sys->i_length > 0 )
808         {
809             p_sys->i_bitrate = 8 * i_size * (int64_t)1000000 / p_sys->i_length;
810         }
811     }
812
813     /* Create meta information */
814     p_sys->meta = vlc_meta_New();
815
816     if( ( p_cd = ASF_FindObject( p_sys->p_root->p_hdr,
817                                  &asf_object_content_description_guid, 0 ) ) )
818     {
819         if( p_cd->psz_title && *p_cd->psz_title )
820         {
821             vlc_meta_Add( p_sys->meta, VLC_META_TITLE, p_cd->psz_title );
822         }
823         if( p_cd->psz_author && *p_cd->psz_author )
824         {
825              vlc_meta_Add( p_sys->meta, VLC_META_AUTHOR, p_cd->psz_author );
826         }
827         if( p_cd->psz_copyright && *p_cd->psz_copyright )
828         {
829             vlc_meta_Add( p_sys->meta, VLC_META_COPYRIGHT, p_cd->psz_copyright );
830         }
831         if( p_cd->psz_description && *p_cd->psz_description )
832         {
833             vlc_meta_Add( p_sys->meta, VLC_META_DESCRIPTION, p_cd->psz_description );
834         }
835         if( p_cd->psz_rating && *p_cd->psz_rating )
836         {
837             vlc_meta_Add( p_sys->meta, VLC_META_RATING, p_cd->psz_rating );
838         }
839     }
840     for( i_stream = 0, i = 0; i < 128; i++ )
841     {
842         asf_object_codec_list_t *p_cl = ASF_FindObject( p_sys->p_root->p_hdr,
843                                                         &asf_object_codec_list_guid, 0 );
844
845         if( p_sys->track[i] )
846         {
847             vlc_meta_t *tk = vlc_meta_New();
848             TAB_APPEND( p_sys->meta->i_track, p_sys->meta->track, tk );
849
850             if( p_cl && i_stream < p_cl->i_codec_entries_count )
851             {
852                 if( p_cl->codec[i_stream].psz_name &&
853                     *p_cl->codec[i_stream].psz_name )
854                 {
855                     vlc_meta_Add( tk, VLC_META_CODEC_NAME,
856                                   p_cl->codec[i_stream].psz_name );
857                 }
858                 if( p_cl->codec[i_stream].psz_description &&
859                     *p_cl->codec[i_stream].psz_description )
860                 {
861                     vlc_meta_Add( tk, VLC_META_CODEC_DESCRIPTION,
862                                   p_cl->codec[i_stream].psz_description );
863                 }
864             }
865             i_stream++;
866         }
867     }
868
869     es_out_Control( p_demux->out, ES_OUT_RESET_PCR );
870     return VLC_SUCCESS;
871
872 error:
873     ASF_FreeObjectRoot( p_demux->s, p_sys->p_root );
874     return VLC_EGENERIC;
875 }
876 /*****************************************************************************
877  *
878  *****************************************************************************/
879 static void DemuxEnd( demux_t *p_demux )
880 {
881     demux_sys_t *p_sys = p_demux->p_sys;
882     int         i;
883
884     if( p_sys->p_root )
885     {
886         ASF_FreeObjectRoot( p_demux->s, p_sys->p_root );
887         p_sys->p_root = NULL;
888     }
889     if( p_sys->meta )
890     {
891         vlc_meta_Delete( p_sys->meta );
892         p_sys->meta = NULL;
893     }
894
895     for( i = 0; i < 128; i++ )
896     {
897         asf_track_t *tk = p_sys->track[i];
898
899         if( tk )
900         {
901             if( tk->p_frame )
902             {
903                 block_ChainRelease( tk->p_frame );
904             }
905             if( tk->p_es )
906             {
907                 es_out_Del( p_demux->out, tk->p_es );
908             }
909             free( tk );
910         }
911         p_sys->track[i] = 0;
912     }
913 }
914