]> git.sesse.net Git - vlc/blob - modules/demux/asf/asf.c
asf: Fix packet length handling to be correct
[vlc] / modules / demux / asf / asf.c
1 /*****************************************************************************
2  * asf.c : ASF demux module
3  *****************************************************************************
4  * Copyright (C) 2002-2003 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 #include <vlc_common.h>
33 #include <vlc_plugin.h>
34 #include <vlc_demux.h>
35 #include <vlc_dialog.h>
36
37 #include <vlc_meta.h>
38 #include <vlc_access.h>                /* GET_PRIVATE_ID_STATE */
39 #include <vlc_codecs.h>                /* BITMAPINFOHEADER, WAVEFORMATEX */
40 #include "libasf.h"
41
42 /* TODO
43  *  - add support for the newly added object: language, bitrate,
44  *                                            extended stream properties.
45  */
46
47 /*****************************************************************************
48  * Module descriptor
49  *****************************************************************************/
50 static int  Open  ( vlc_object_t * );
51 static void Close ( vlc_object_t * );
52
53 vlc_module_begin ()
54     set_category( CAT_INPUT )
55     set_subcategory( SUBCAT_INPUT_DEMUX )
56     set_description( N_("ASF v1.0 demuxer") )
57     set_capability( "demux", 200 )
58     set_callbacks( Open, Close )
59     add_shortcut( "asf" )
60 vlc_module_end ()
61
62
63 /*****************************************************************************
64  * Local prototypes
65  *****************************************************************************/
66 static int Demux  ( demux_t * );
67 static int Control( demux_t *, int i_query, va_list args );
68
69 typedef struct
70 {
71     int i_cat;
72
73     es_out_id_t     *p_es;
74
75     asf_object_stream_properties_t *p_sp;
76
77     mtime_t i_time;
78
79     block_t         *p_frame; /* use to gather complete frame */
80
81 } asf_track_t;
82
83 struct demux_sys_t
84 {
85     mtime_t             i_time;     /* s */
86     mtime_t             i_length;   /* length of file file */
87     int64_t             i_bitrate;  /* global file bitrate */
88
89     asf_object_root_t            *p_root;
90     asf_object_file_properties_t *p_fp;
91
92     unsigned int        i_track;
93     asf_track_t         *track[128]; /* track number is stored on 7 bits */
94
95     int64_t             i_data_begin;
96     int64_t             i_data_end;
97
98     bool          b_index;
99     vlc_meta_t          *meta;
100 };
101
102 static mtime_t  GetMoviePTS( demux_sys_t * );
103 static int      DemuxInit( demux_t * );
104 static void     DemuxEnd( demux_t * );
105 static int      DemuxPacket( demux_t * );
106
107 /*****************************************************************************
108  * Open: check file and initializes ASF structures
109  *****************************************************************************/
110 static int Open( vlc_object_t * p_this )
111 {
112     demux_t     *p_demux = (demux_t *)p_this;
113     demux_sys_t *p_sys;
114     guid_t      guid;
115     const uint8_t     *p_peek;
116
117     /* A little test to see if it could be a asf stream */
118     if( stream_Peek( p_demux->s, &p_peek, 16 ) < 16 ) return VLC_EGENERIC;
119
120     ASF_GetGUID( &guid, p_peek );
121     if( !ASF_CmpGUID( &guid, &asf_object_header_guid ) ) return VLC_EGENERIC;
122
123     /* Set p_demux fields */
124     p_demux->pf_demux = Demux;
125     p_demux->pf_control = Control;
126     p_demux->p_sys = p_sys = malloc( sizeof( demux_sys_t ) );
127     memset( p_sys, 0, sizeof( demux_sys_t ) );
128
129     /* Load the headers */
130     if( DemuxInit( p_demux ) )
131     {
132         free( p_sys );
133         return VLC_EGENERIC;
134     }
135     return VLC_SUCCESS;
136 }
137
138
139 /*****************************************************************************
140  * Demux: read packet and send them to decoders
141  *****************************************************************************/
142 static int Demux( demux_t *p_demux )
143 {
144     demux_sys_t *p_sys = p_demux->p_sys;
145
146     for( ;; )
147     {
148         const uint8_t *p_peek;
149         mtime_t i_length;
150         mtime_t i_time_begin = GetMoviePTS( p_sys );
151         int i_result;
152
153         if( !vlc_object_alive (p_demux) )
154             break;
155 #if 0
156         /* FIXME: returns EOF too early for some mms streams */
157         if( p_sys->i_data_end >= 0 &&
158                 stream_Tell( p_demux->s ) >= p_sys->i_data_end )
159             return 0; /* EOF */
160 #endif
161
162         /* Check if we have concatenated files */
163         if( stream_Peek( p_demux->s, &p_peek, 16 ) == 16 )
164         {
165             guid_t guid;
166
167             ASF_GetGUID( &guid, p_peek );
168             if( ASF_CmpGUID( &guid, &asf_object_header_guid ) )
169             {
170                 msg_Warn( p_demux, "found a new ASF header" );
171                 /* We end this stream */
172                 DemuxEnd( p_demux );
173
174                 /* And we prepare to read the next one */
175                 if( DemuxInit( p_demux ) )
176                 {
177                     msg_Err( p_demux, "failed to load the new header" );
178                     dialog_Fatal( p_demux, _("Could not demux ASF stream"), "%s",
179                                     _("VLC failed to load the ASF header.") );
180                     return 0;
181                 }
182                 es_out_Control( p_demux->out, ES_OUT_RESET_PCR );
183                 continue;
184             }
185         }
186
187         /* Read and demux a packet */
188         if( ( i_result = DemuxPacket( p_demux ) ) <= 0 )
189         {
190             return i_result;
191         }
192         if( i_time_begin == -1 )
193         {
194             i_time_begin = GetMoviePTS( p_sys );
195         }
196         else
197         {
198             i_length = GetMoviePTS( p_sys ) - i_time_begin;
199             if( i_length < 0 || i_length >= 40 * 1000 ) break;
200         }
201     }
202
203     /* Set the PCR */
204     p_sys->i_time = GetMoviePTS( p_sys );
205     if( p_sys->i_time >= 0 )
206     {
207         es_out_Control( p_demux->out, ES_OUT_SET_PCR, p_sys->i_time+1 );
208     }
209
210     return 1;
211 }
212
213 /*****************************************************************************
214  * Close: frees unused data
215  *****************************************************************************/
216 static void Close( vlc_object_t * p_this )
217 {
218     demux_t     *p_demux = (demux_t *)p_this;
219
220     DemuxEnd( p_demux );
221
222     free( p_demux->p_sys );
223 }
224
225 /*****************************************************************************
226  * SeekIndex: goto to i_date or i_percent
227  *****************************************************************************/
228 static int SeekPercent( demux_t *p_demux, int i_query, va_list args )
229 {
230     demux_sys_t *p_sys = p_demux->p_sys;
231     return demux_vaControlHelper( p_demux->s, p_sys->i_data_begin,
232                                    p_sys->i_data_end, p_sys->i_bitrate,
233                                    p_sys->p_fp->i_min_data_packet_size,
234                                    i_query, args );
235 }
236
237 static int SeekIndex( demux_t *p_demux, mtime_t i_date, float f_pos )
238 {
239     demux_sys_t *p_sys = p_demux->p_sys;
240     asf_object_index_t *p_index;
241
242     msg_Dbg( p_demux, "seek with index: %i seconds, position %f",
243              i_date >= 0 ? (int)(i_date/1000000) : -1, f_pos );
244
245     if( i_date < 0 )
246         i_date = p_sys->i_length * f_pos;
247
248     p_index = ASF_FindObject( p_sys->p_root, &asf_object_index_guid, 0 );
249
250     uint64_t i_entry = i_date * 10 / p_index->i_index_entry_time_interval;
251     if( i_entry >= p_index->i_index_entry_count )
252     {
253         msg_Warn( p_demux, "Incomplete index" );
254         return VLC_EGENERIC;
255     }
256
257     uint64_t i_offset = (uint64_t)p_index->index_entry[i_entry].i_packet_number *
258                         p_sys->p_fp->i_min_data_packet_size;
259     return stream_Seek( p_demux->s, p_sys->i_data_begin + i_offset );
260 }
261
262 static void SeekPrepare( demux_t *p_demux )
263 {
264     demux_sys_t *p_sys = p_demux->p_sys;
265
266     p_sys->i_time = -1;
267     for( int i = 0; i < 128 ; i++ )
268     {
269         asf_track_t *tk = p_sys->track[i];
270         if( !tk )
271             continue;
272
273         tk->i_time = 1;
274         if( tk->p_frame )
275             block_ChainRelease( tk->p_frame );
276         tk->p_frame = NULL;
277     }
278 }
279
280 /*****************************************************************************
281  * Control:
282  *****************************************************************************/
283 static int Control( demux_t *p_demux, int i_query, va_list args )
284 {
285     demux_sys_t *p_sys = p_demux->p_sys;
286     vlc_meta_t  *p_meta;
287     int64_t     i64, *pi64;
288     double      f, *pf;
289
290     switch( i_query )
291     {
292     case DEMUX_GET_LENGTH:
293         pi64 = (int64_t*)va_arg( args, int64_t * );
294         *pi64 = p_sys->i_length;
295         return VLC_SUCCESS;
296
297     case DEMUX_GET_TIME:
298         pi64 = (int64_t*)va_arg( args, int64_t * );
299         if( p_sys->i_time < 0 ) return VLC_EGENERIC;
300         *pi64 = p_sys->i_time;
301         return VLC_SUCCESS;
302
303     case DEMUX_SET_TIME:
304         SeekPrepare( p_demux );
305
306         if( p_sys->b_index && p_sys->i_length > 0 )
307         {
308             va_list acpy;
309             va_copy( acpy, args );
310             i64 = (int64_t)va_arg( acpy, int64_t );
311             va_end( acpy );
312
313             if( !SeekIndex( p_demux, i64, -1 ) )
314                 return VLC_SUCCESS;
315         }
316         return SeekPercent( p_demux, i_query, args );
317
318     case DEMUX_GET_POSITION:
319         if( p_sys->i_time < 0 ) return VLC_EGENERIC;
320         if( p_sys->i_length > 0 )
321         {
322             pf = (double*)va_arg( args, double * );
323             *pf = p_sys->i_time / (double)p_sys->i_length;
324             return VLC_SUCCESS;
325         }
326         return demux_vaControlHelper( p_demux->s, p_sys->i_data_begin,
327                                        p_sys->i_data_end, p_sys->i_bitrate,
328                                        p_sys->p_fp->i_min_data_packet_size,
329                                        i_query, args );
330
331     case DEMUX_SET_POSITION:
332         SeekPrepare( p_demux );
333
334         if( p_sys->b_index && p_sys->i_length > 0 )
335         {
336             va_list acpy;
337             va_copy( acpy, args );
338             f = (double)va_arg( acpy, double );
339             va_end( acpy );
340
341             if( !SeekIndex( p_demux, -1, f ) )
342                 return VLC_SUCCESS;
343         }
344         return SeekPercent( p_demux, i_query, args );
345
346     case DEMUX_GET_META:
347         p_meta = (vlc_meta_t*)va_arg( args, vlc_meta_t* );
348         vlc_meta_Merge( p_meta, p_sys->meta );
349         return VLC_SUCCESS;
350
351     default:
352         return demux_vaControlHelper( p_demux->s, p_sys->i_data_begin,
353                                        p_sys->i_data_end, p_sys->i_bitrate,
354                                        p_sys->p_fp->i_min_data_packet_size,
355                                        i_query, args );
356     }
357 }
358
359 /*****************************************************************************
360  *
361  *****************************************************************************/
362 static mtime_t GetMoviePTS( demux_sys_t *p_sys )
363 {
364     mtime_t i_time = -1;
365     int     i;
366
367     for( i = 0; i < 128 ; i++ )
368     {
369         asf_track_t *tk = p_sys->track[i];
370
371         if( tk && tk->p_es && tk->i_time > 0)
372         {
373             if( i_time < 0 ) i_time = tk->i_time;
374             else i_time = __MIN( i_time, tk->i_time );
375         }
376     }
377
378     return i_time;
379 }
380
381 #define GETVALUE2b( bits, var, def ) \
382     switch( (bits)&0x03 ) \
383     { \
384         case 1: var = p_peek[i_skip]; i_skip++; break; \
385         case 2: var = GetWLE( p_peek + i_skip );  i_skip+= 2; break; \
386         case 3: var = GetDWLE( p_peek + i_skip ); i_skip+= 4; break; \
387         case 0: \
388         default: var = def; break;\
389     }
390
391 static int DemuxPacket( demux_t *p_demux )
392 {
393     demux_sys_t *p_sys = p_demux->p_sys;
394     int         i_data_packet_min = p_sys->p_fp->i_min_data_packet_size;
395     const uint8_t *p_peek;
396     int         i_skip;
397
398     int         i_packet_size_left;
399     int         i_packet_flags;
400     int         i_packet_property;
401
402     int         b_packet_multiple_payload;
403     int         i_packet_length;
404     int         i_packet_sequence;
405     int         i_packet_padding_length;
406
407     uint32_t    i_packet_send_time;
408     uint16_t    i_packet_duration;
409     int         i_payload;
410     int         i_payload_count;
411     int         i_payload_length_type;
412
413
414     if( stream_Peek( p_demux->s, &p_peek,i_data_packet_min)<i_data_packet_min )
415     {
416         msg_Warn( p_demux, "cannot peek while getting new packet, EOF ?" );
417         return 0;
418     }
419     i_skip = 0;
420
421     /* *** parse error correction if present *** */
422     if( p_peek[0]&0x80 )
423     {
424         unsigned int i_error_correction_length_type;
425         unsigned int i_error_correction_data_length;
426         unsigned int i_opaque_data_present;
427
428         i_error_correction_data_length = p_peek[0] & 0x0f;  // 4bits
429         i_opaque_data_present = ( p_peek[0] >> 4 )& 0x01;    // 1bit
430         i_error_correction_length_type = ( p_peek[0] >> 5 ) & 0x03; // 2bits
431         i_skip += 1; // skip error correction flags
432
433         if( i_error_correction_length_type != 0x00 ||
434             i_opaque_data_present != 0 ||
435             i_error_correction_data_length != 0x02 )
436         {
437             goto loop_error_recovery;
438         }
439
440         i_skip += i_error_correction_data_length;
441     }
442     else
443     {
444         msg_Warn( p_demux, "p_peek[0]&0x80 != 0x80" );
445     }
446
447     /* sanity check */
448     if( i_skip + 2 >= i_data_packet_min )
449     {
450         goto loop_error_recovery;
451     }
452
453     i_packet_flags = p_peek[i_skip]; i_skip++;
454     i_packet_property = p_peek[i_skip]; i_skip++;
455
456     b_packet_multiple_payload = i_packet_flags&0x01;
457
458     /* read some value */
459     GETVALUE2b( i_packet_flags >> 5, i_packet_length, i_data_packet_min );
460     GETVALUE2b( i_packet_flags >> 1, i_packet_sequence, 0 );
461     GETVALUE2b( i_packet_flags >> 3, i_packet_padding_length, 0 );
462
463     if( i_packet_padding_length > i_packet_length )
464     {
465         msg_Warn( p_demux, "Too large padding: %d", i_packet_padding_length );
466         goto loop_error_recovery;
467     }
468
469     if( i_packet_length < i_data_packet_min )
470     {
471         /* if packet length too short, there is extra padding */
472         i_packet_padding_length += i_data_packet_min - i_packet_length;
473         i_packet_length = i_data_packet_min;
474     }
475
476     i_packet_send_time = GetDWLE( p_peek + i_skip ); i_skip += 4;
477     i_packet_duration  = GetWLE( p_peek + i_skip ); i_skip += 2;
478
479     i_packet_size_left = i_packet_length;
480
481     if( b_packet_multiple_payload )
482     {
483         i_payload_count = p_peek[i_skip] & 0x3f;
484         i_payload_length_type = ( p_peek[i_skip] >> 6 )&0x03;
485         i_skip++;
486     }
487     else
488     {
489         i_payload_count = 1;
490         i_payload_length_type = 0x02; // unused
491     }
492
493     for( i_payload = 0; i_payload < i_payload_count ; i_payload++ )
494     {
495         asf_track_t   *tk;
496
497         int i_packet_keyframe;
498         int i_stream_number;
499         int i_media_object_number;
500         int i_media_object_offset;
501         int i_replicated_data_length;
502         int i_payload_data_length;
503         int i_payload_data_pos;
504         int i_sub_payload_data_length;
505         int i_tmp;
506
507         mtime_t i_pts;
508         mtime_t i_pts_delta;
509
510         if( i_skip >= i_packet_size_left )
511         {
512             /* prevent some segfault with invalid file */
513             break;
514         }
515
516         i_packet_keyframe = p_peek[i_skip] >> 7;
517         i_stream_number = p_peek[i_skip++] & 0x7f;
518
519         GETVALUE2b( i_packet_property >> 4, i_media_object_number, 0 );
520         GETVALUE2b( i_packet_property >> 2, i_tmp, 0 );
521         GETVALUE2b( i_packet_property, i_replicated_data_length, 0 );
522
523         if( i_replicated_data_length > 1 ) // should be at least 8 bytes
524         {
525             i_pts = (mtime_t)GetDWLE( p_peek + i_skip + 4 ) * 1000;
526             i_skip += i_replicated_data_length;
527             i_pts_delta = 0;
528
529             i_media_object_offset = i_tmp;
530
531             if( i_skip >= i_packet_size_left )
532             {
533                 break;
534             }
535         }
536         else if( i_replicated_data_length == 1 )
537         {
538             /* msg_Dbg( p_demux, "found compressed payload" ); */
539
540             i_pts = (mtime_t)i_tmp * 1000;
541             i_pts_delta = (mtime_t)p_peek[i_skip] * 1000; i_skip++;
542
543             i_media_object_offset = 0;
544         }
545         else
546         {
547             i_pts = (mtime_t)i_packet_send_time * 1000;
548             i_pts_delta = 0;
549
550             i_media_object_offset = i_tmp;
551         }
552
553         i_pts = __MAX( i_pts - p_sys->p_fp->i_preroll * 1000, 0 );
554         if( b_packet_multiple_payload )
555         {
556             GETVALUE2b( i_payload_length_type, i_payload_data_length, 0 );
557         }
558         else
559         {
560             i_payload_data_length = i_packet_length -
561                                     i_packet_padding_length - i_skip;
562         }
563
564         if( i_payload_data_length < 0 || i_payload_data_length > i_packet_size_left )
565         {
566             break;
567         }
568 #if 0
569          msg_Dbg( p_demux,
570                   "payload(%d/%d) stream_number:%d media_object_number:%d media_object_offset:%d replicated_data_length:%d payload_data_length %d",
571                   i_payload + 1, i_payload_count, i_stream_number, i_media_object_number,
572                   i_media_object_offset, i_replicated_data_length, i_payload_data_length );
573 #endif
574
575         if( ( tk = p_sys->track[i_stream_number] ) == NULL )
576         {
577             msg_Warn( p_demux,
578                       "undeclared stream[Id 0x%x]", i_stream_number );
579             i_skip += i_payload_data_length;
580             continue;   // over payload
581         }
582
583         if( !tk->p_es )
584         {
585             i_skip += i_payload_data_length;
586             continue;
587         }
588
589
590         for( i_payload_data_pos = 0;
591              i_payload_data_pos < i_payload_data_length &&
592                     i_packet_size_left > 0;
593              i_payload_data_pos += i_sub_payload_data_length )
594         {
595             block_t *p_frag;
596             int i_read;
597
598             // read sub payload length
599             if( i_replicated_data_length == 1 )
600             {
601                 i_sub_payload_data_length = p_peek[i_skip]; i_skip++;
602                 i_payload_data_pos++;
603             }
604             else
605             {
606                 i_sub_payload_data_length = i_payload_data_length;
607             }
608
609             /* FIXME I don't use i_media_object_number, sould I ? */
610             if( tk->p_frame && i_media_object_offset == 0 )
611             {
612                 /* send complete packet to decoder */
613                 block_t *p_gather = block_ChainGather( tk->p_frame );
614
615                 if( p_gather->i_dts > VLC_TS_INVALID )
616                     tk->i_time = p_gather->i_dts - VLC_TS_0;
617
618                 if( p_sys->i_time < 0 )
619                     es_out_Control( p_demux->out, ES_OUT_SET_PCR, VLC_TS_0 + tk->i_time );
620
621                 es_out_Send( p_demux->out, tk->p_es, p_gather );
622
623                 tk->p_frame = NULL;
624             }
625
626             i_read = i_sub_payload_data_length + i_skip;
627             if( ( p_frag = stream_Block( p_demux->s, i_read ) ) == NULL )
628             {
629                 msg_Warn( p_demux, "cannot read data" );
630                 return 0;
631             }
632             i_packet_size_left -= i_read;
633
634             p_frag->p_buffer += i_skip;
635             p_frag->i_buffer -= i_skip;
636
637             if( tk->p_frame == NULL )
638             {
639                 p_frag->i_pts = VLC_TS_0 + i_pts + i_payload * (mtime_t)i_pts_delta;
640                 if( tk->i_cat != VIDEO_ES )
641                     p_frag->i_dts = VLC_TS_0 + p_frag->i_pts;
642                 else
643                 {
644                     p_frag->i_dts = VLC_TS_0 + p_frag->i_pts;
645                     p_frag->i_pts = VLC_TS_INVALID;
646                 }
647             }
648
649             block_ChainAppend( &tk->p_frame, p_frag );
650
651             i_skip = 0;
652             if( i_packet_size_left > 0 )
653             {
654                 if( stream_Peek( p_demux->s, &p_peek, i_packet_size_left )
655                                                          < i_packet_size_left )
656                 {
657                     msg_Warn( p_demux, "cannot peek, EOF ?" );
658                     return 0;
659                 }
660             }
661         }
662     }
663
664     if( i_packet_size_left > 0 )
665     {
666 #ifdef ASF_DEBUG
667         if( i_packet_size_left > i_packet_padding_length )
668             msg_Warn( p_demux, "Didn't read %d bytes in the packet",
669                             i_packet_size_left - i_packet_padding_length );
670         else if( i_packet_size_left < i_packet_padding_length )
671             msg_Warn( p_demux, "Read %d too much bytes in the packet",
672                             i_packet_padding_length - i_packet_size_left );
673 #endif
674         if( stream_Read( p_demux->s, NULL, i_packet_size_left )
675                                                          < i_packet_size_left )
676         {
677             msg_Err( p_demux, "cannot skip data, EOF ?" );
678             return 0;
679         }
680     }
681
682     return 1;
683
684 loop_error_recovery:
685     msg_Warn( p_demux, "unsupported packet header" );
686     if( p_sys->p_fp->i_min_data_packet_size != p_sys->p_fp->i_max_data_packet_size )
687     {
688         msg_Err( p_demux, "unsupported packet header, fatal error" );
689         return -1;
690     }
691     if( stream_Read( p_demux->s, NULL, i_data_packet_min ) != i_data_packet_min )
692     {
693         msg_Warn( p_demux, "cannot skip data, EOF ?" );
694         return 0;
695     }
696
697     return 1;
698 }
699
700 /*****************************************************************************
701  *
702  *****************************************************************************/
703 static int DemuxInit( demux_t *p_demux )
704 {
705     demux_sys_t *p_sys = p_demux->p_sys;
706
707     /* init context */
708     p_sys->i_time   = -1;
709     p_sys->i_length = 0;
710     p_sys->i_bitrate = 0;
711     p_sys->p_root   = NULL;
712     p_sys->p_fp     = NULL;
713     p_sys->b_index  = 0;
714     p_sys->i_track  = 0;
715     for( int i = 0; i < 128; i++ )
716     {
717         p_sys->track[i] = NULL;
718     }
719     p_sys->i_data_begin = -1;
720     p_sys->i_data_end   = -1;
721     p_sys->meta         = NULL;
722
723     /* Now load all object ( except raw data ) */
724     bool b_seekable;
725     stream_Control( p_demux->s, STREAM_CAN_FASTSEEK, &b_seekable );
726     if( !(p_sys->p_root = ASF_ReadObjectRoot(p_demux->s, b_seekable)) )
727     {
728         msg_Warn( p_demux, "ASF plugin discarded (not a valid file)" );
729         return VLC_EGENERIC;
730     }
731     p_sys->p_fp = p_sys->p_root->p_fp;
732
733     if( p_sys->p_fp->i_min_data_packet_size != p_sys->p_fp->i_max_data_packet_size )
734     {
735         msg_Warn( p_demux, "ASF plugin discarded (invalid file_properties object)" );
736         goto error;
737     }
738
739     p_sys->i_track = ASF_CountObject( p_sys->p_root->p_hdr,
740                                       &asf_object_stream_properties_guid );
741     if( p_sys->i_track <= 0 )
742     {
743         msg_Warn( p_demux, "ASF plugin discarded (cannot find any stream!)" );
744         goto error;
745     }
746     msg_Dbg( p_demux, "found %d streams", p_sys->i_track );
747
748     /* check if index is available */
749     asf_object_index_t *p_index = ASF_FindObject( p_sys->p_root,
750                                                   &asf_object_index_guid, 0 );
751     const bool b_index = p_index && p_index->i_index_entry_count;
752
753     /* Find the extended header if any */
754     asf_object_t *p_hdr_ext = ASF_FindObject( p_sys->p_root->p_hdr,
755                                               &asf_object_header_extension_guid, 0 );
756
757     asf_object_language_list_t *p_languages = NULL;
758     if( p_hdr_ext )
759         p_languages = ASF_FindObject( p_hdr_ext, &asf_object_language_list, 0 );
760
761     for( unsigned i_stream = 0; i_stream < p_sys->i_track; i_stream++ )
762     {
763         asf_track_t    *tk;
764         asf_object_stream_properties_t *p_sp;
765         asf_object_extended_stream_properties_t *p_esp;
766         bool b_access_selected;
767
768         p_sp = ASF_FindObject( p_sys->p_root->p_hdr,
769                                &asf_object_stream_properties_guid,
770                                i_stream );
771         p_esp = NULL;
772
773         tk = p_sys->track[p_sp->i_stream_number] = malloc( sizeof( asf_track_t ) );
774         memset( tk, 0, sizeof( asf_track_t ) );
775
776         tk->i_time = -1;
777         tk->p_sp = p_sp;
778         tk->p_es = NULL;
779         tk->p_frame = NULL;
780
781         /* Check (in case of mms) if this track is selected (ie will receive data) */
782         if( !stream_Control( p_demux->s, STREAM_CONTROL_ACCESS, ACCESS_GET_PRIVATE_ID_STATE,
783                              p_sp->i_stream_number, &b_access_selected ) &&
784             !b_access_selected )
785         {
786             tk->i_cat = UNKNOWN_ES;
787             msg_Dbg( p_demux, "ignoring not selected stream(ID:%d) (by access)",
788                      p_sp->i_stream_number );
789             continue;
790         }
791
792         /* Find the associated extended_stream_properties if any */
793         if( p_hdr_ext )
794         {
795             int i_ext_stream = ASF_CountObject( p_hdr_ext,
796                                                 &asf_object_extended_stream_properties );
797             for( int i = 0; i < i_ext_stream; i++ )
798             {
799                 asf_object_t *p_tmp =
800                     ASF_FindObject( p_hdr_ext,
801                                     &asf_object_extended_stream_properties, i );
802                 if( p_tmp->ext_stream.i_stream_number == p_sp->i_stream_number )
803                 {
804                     p_esp = &p_tmp->ext_stream;
805                     break;
806                 }
807             }
808         }
809
810         es_format_t fmt;
811
812         if( ASF_CmpGUID( &p_sp->i_stream_type, &asf_object_stream_type_audio ) &&
813             p_sp->i_type_specific_data_length >= sizeof( WAVEFORMATEX ) - 2 )
814         {
815             uint8_t *p_data = p_sp->p_type_specific_data;
816             int i_format;
817
818             es_format_Init( &fmt, AUDIO_ES, 0 );
819             i_format = GetWLE( &p_data[0] );
820             wf_tag_to_fourcc( i_format, &fmt.i_codec, NULL );
821             fmt.audio.i_channels        = GetWLE(  &p_data[2] );
822             fmt.audio.i_rate      = GetDWLE( &p_data[4] );
823             fmt.i_bitrate         = GetDWLE( &p_data[8] ) * 8;
824             fmt.audio.i_blockalign      = GetWLE(  &p_data[12] );
825             fmt.audio.i_bitspersample   = GetWLE(  &p_data[14] );
826
827             if( p_sp->i_type_specific_data_length > sizeof( WAVEFORMATEX ) &&
828                 i_format != WAVE_FORMAT_MPEGLAYER3 &&
829                 i_format != WAVE_FORMAT_MPEG )
830             {
831                 fmt.i_extra = __MIN( GetWLE( &p_data[16] ),
832                                      p_sp->i_type_specific_data_length -
833                                      sizeof( WAVEFORMATEX ) );
834                 fmt.p_extra = malloc( fmt.i_extra );
835                 memcpy( fmt.p_extra, &p_data[sizeof( WAVEFORMATEX )],
836                         fmt.i_extra );
837             }
838
839             msg_Dbg( p_demux, "added new audio stream(codec:0x%x,ID:%d)",
840                     GetWLE( p_data ), p_sp->i_stream_number );
841         }
842         else if( ASF_CmpGUID( &p_sp->i_stream_type,
843                               &asf_object_stream_type_video ) &&
844                  p_sp->i_type_specific_data_length >= 11 +
845                  sizeof( BITMAPINFOHEADER ) )
846         {
847             uint8_t      *p_data = &p_sp->p_type_specific_data[11];
848
849             es_format_Init( &fmt, VIDEO_ES,
850                             VLC_FOURCC( p_data[16], p_data[17],
851                                         p_data[18], p_data[19] ) );
852             fmt.video.i_width = GetDWLE( p_data + 4 );
853             fmt.video.i_height= GetDWLE( p_data + 8 );
854
855             if( p_esp && p_esp->i_average_time_per_frame > 0 )
856             {
857                 fmt.video.i_frame_rate = 10000000;
858                 fmt.video.i_frame_rate_base = p_esp->i_average_time_per_frame;
859             }
860
861             if( fmt.i_codec == VLC_FOURCC( 'D','V','R',' ') )
862             {
863                 /* DVR-MS special ASF */
864                 fmt.i_codec = VLC_FOURCC( 'm','p','g','2' ) ;
865                 fmt.b_packetized = false;
866             }
867
868             if( p_sp->i_type_specific_data_length > 11 +
869                 sizeof( BITMAPINFOHEADER ) )
870             {
871                 fmt.i_extra = __MIN( GetDWLE( p_data ),
872                                      p_sp->i_type_specific_data_length - 11 -
873                                      sizeof( BITMAPINFOHEADER ) );
874                 fmt.p_extra = malloc( fmt.i_extra );
875                 memcpy( fmt.p_extra, &p_data[sizeof( BITMAPINFOHEADER )],
876                         fmt.i_extra );
877             }
878
879             /* Look for an aspect ratio */
880             if( p_sys->p_root->p_metadata )
881             {
882                 asf_object_metadata_t *p_meta = p_sys->p_root->p_metadata;
883                 int i_aspect_x = 0, i_aspect_y = 0;
884                 unsigned int i;
885
886                 for( i = 0; i < p_meta->i_record_entries_count; i++ )
887                 {
888                     if( !strcmp( p_meta->record[i].psz_name, "AspectRatioX" ) )
889                     {
890                         if( (!i_aspect_x && !p_meta->record[i].i_stream) ||
891                             p_meta->record[i].i_stream ==
892                             p_sp->i_stream_number )
893                             i_aspect_x = p_meta->record[i].i_val;
894                     }
895                     if( !strcmp( p_meta->record[i].psz_name, "AspectRatioY" ) )
896                     {
897                         if( (!i_aspect_y && !p_meta->record[i].i_stream) ||
898                             p_meta->record[i].i_stream ==
899                             p_sp->i_stream_number )
900                             i_aspect_y = p_meta->record[i].i_val;
901                     }
902                 }
903
904                 if( i_aspect_x && i_aspect_y )
905                 {
906                     fmt.video.i_sar_num = i_aspect_x;
907                     fmt.video.i_sar_den = i_aspect_y;
908                 }
909             }
910
911             /* If there is a video track then use the index for seeking */
912             p_sys->b_index = b_index;
913
914             msg_Dbg( p_demux, "added new video stream(ID:%d)",
915                      p_sp->i_stream_number );
916         }
917         else if( ASF_CmpGUID( &p_sp->i_stream_type, &asf_object_extended_stream_header ) &&
918             p_sp->i_type_specific_data_length >= 64 )
919         {
920             /* Now follows a 64 byte header of which we don't know much */
921             guid_t  *p_ref  = (guid_t *)p_sp->p_type_specific_data;
922             uint8_t *p_data = p_sp->p_type_specific_data + 64;
923             unsigned int i_data = p_sp->i_type_specific_data_length - 64;
924
925             msg_Dbg( p_demux, "Ext stream header detected. datasize = %d", p_sp->i_type_specific_data_length );
926             if( ASF_CmpGUID( p_ref, &asf_object_extended_stream_type_audio ) &&
927                 i_data >= sizeof( WAVEFORMATEX ) - 2)
928             {
929                 int      i_format;
930                 es_format_Init( &fmt, AUDIO_ES, 0 );
931                 i_format = GetWLE( &p_data[0] );
932                 if( i_format == 0 )
933                     fmt.i_codec = VLC_CODEC_A52;
934                 else
935                     wf_tag_to_fourcc( i_format, &fmt.i_codec, NULL );
936                 fmt.audio.i_channels        = GetWLE(  &p_data[2] );
937                 fmt.audio.i_rate      = GetDWLE( &p_data[4] );
938                 fmt.i_bitrate         = GetDWLE( &p_data[8] ) * 8;
939                 fmt.audio.i_blockalign      = GetWLE(  &p_data[12] );
940                 fmt.audio.i_bitspersample   = GetWLE(  &p_data[14] );
941                 fmt.b_packetized = true;
942
943                 if( p_sp->i_type_specific_data_length > sizeof( WAVEFORMATEX ) &&
944                     i_format != WAVE_FORMAT_MPEGLAYER3 &&
945                     i_format != WAVE_FORMAT_MPEG )
946                 {
947                     fmt.i_extra = __MIN( GetWLE( &p_data[16] ),
948                                          p_sp->i_type_specific_data_length -
949                                          sizeof( WAVEFORMATEX ) );
950                     fmt.p_extra = malloc( fmt.i_extra );
951                     memcpy( fmt.p_extra, &p_data[sizeof( WAVEFORMATEX )],
952                         fmt.i_extra );
953                 }
954
955                 msg_Dbg( p_demux, "added new audio stream (codec:0x%x,ID:%d)",
956                     i_format, p_sp->i_stream_number );
957             }
958             else
959             {
960                 es_format_Init( &fmt, UNKNOWN_ES, 0 );
961             }
962         }
963         else
964         {
965             es_format_Init( &fmt, UNKNOWN_ES, 0 );
966         }
967
968         tk->i_cat = fmt.i_cat;
969         if( fmt.i_cat != UNKNOWN_ES )
970         {
971             if( p_esp && p_languages &&
972                 p_esp->i_language_index >= 0 &&
973                 p_esp->i_language_index < p_languages->i_language )
974             {
975                 fmt.psz_language = strdup( p_languages->ppsz_language[p_esp->i_language_index] );
976                 char *p;
977                 if( fmt.psz_language && (p = strchr( fmt.psz_language, '-' )) )
978                     *p = '\0';
979             }
980
981             tk->p_es = es_out_Add( p_demux->out, &fmt );
982         }
983         else
984         {
985             msg_Dbg( p_demux, "ignoring unknown stream(ID:%d)",
986                      p_sp->i_stream_number );
987         }
988         es_format_Clean( &fmt );
989     }
990
991     p_sys->i_data_begin = p_sys->p_root->p_data->i_object_pos + 50;
992     if( p_sys->p_root->p_data->i_object_size != 0 )
993     { /* local file */
994         p_sys->i_data_end = p_sys->p_root->p_data->i_object_pos +
995                                     p_sys->p_root->p_data->i_object_size;
996     }
997     else
998     { /* live/broacast */
999         p_sys->i_data_end = -1;
1000     }
1001
1002     /* go to first packet */
1003     stream_Seek( p_demux->s, p_sys->i_data_begin );
1004
1005     /* try to calculate movie time */
1006     if( p_sys->p_fp->i_data_packets_count > 0 )
1007     {
1008         int64_t i_count;
1009         int64_t i_size = stream_Size( p_demux->s );
1010
1011         if( p_sys->i_data_end > 0 && i_size > p_sys->i_data_end )
1012         {
1013             i_size = p_sys->i_data_end;
1014         }
1015
1016         /* real number of packets */
1017         i_count = ( i_size - p_sys->i_data_begin ) /
1018                   p_sys->p_fp->i_min_data_packet_size;
1019
1020         /* calculate the time duration in micro-s */
1021         p_sys->i_length = (mtime_t)p_sys->p_fp->i_play_duration / 10 *
1022                    (mtime_t)i_count /
1023                    (mtime_t)p_sys->p_fp->i_data_packets_count - p_sys->p_fp->i_preroll * 1000;
1024         if( p_sys->i_length < 0 )
1025             p_sys->i_length = 0;
1026
1027         if( p_sys->i_length > 0 )
1028         {
1029             p_sys->i_bitrate = 8 * i_size * (int64_t)1000000 / p_sys->i_length;
1030         }
1031     }
1032
1033     /* Create meta information */
1034     p_sys->meta = vlc_meta_New();
1035
1036     asf_object_content_description_t *p_cd;
1037     if( ( p_cd = ASF_FindObject( p_sys->p_root->p_hdr,
1038                                  &asf_object_content_description_guid, 0 ) ) )
1039     {
1040         if( p_cd->psz_title && *p_cd->psz_title )
1041         {
1042             vlc_meta_SetTitle( p_sys->meta, p_cd->psz_title );
1043         }
1044         if( p_cd->psz_artist && *p_cd->psz_artist )
1045         {
1046              vlc_meta_SetArtist( p_sys->meta, p_cd->psz_artist );
1047         }
1048         if( p_cd->psz_copyright && *p_cd->psz_copyright )
1049         {
1050             vlc_meta_SetCopyright( p_sys->meta, p_cd->psz_copyright );
1051         }
1052         if( p_cd->psz_description && *p_cd->psz_description )
1053         {
1054             vlc_meta_SetDescription( p_sys->meta, p_cd->psz_description );
1055         }
1056         if( p_cd->psz_rating && *p_cd->psz_rating )
1057         {
1058             vlc_meta_SetRating( p_sys->meta, p_cd->psz_rating );
1059         }
1060     }
1061     /// \tood Fix Child meta for ASF tracks
1062 #if 0
1063     for( i_stream = 0, i = 0; i < 128; i++ )
1064     {
1065         asf_object_codec_list_t *p_cl = ASF_FindObject( p_sys->p_root->p_hdr,
1066                                                         &asf_object_codec_list_guid, 0 );
1067
1068         if( p_sys->track[i] )
1069         {
1070             vlc_meta_t *tk = vlc_meta_New();
1071             TAB_APPEND( p_sys->meta->i_track, p_sys->meta->track, tk );
1072
1073             if( p_cl && i_stream < p_cl->i_codec_entries_count )
1074             {
1075                 if( p_cl->codec[i_stream].psz_name &&
1076                     *p_cl->codec[i_stream].psz_name )
1077                 {
1078                     vlc_meta_Add( tk, VLC_META_CODEC_NAME,
1079                                   p_cl->codec[i_stream].psz_name );
1080                 }
1081                 if( p_cl->codec[i_stream].psz_description &&
1082                     *p_cl->codec[i_stream].psz_description )
1083                 {
1084                     vlc_meta_Add( tk, VLC_META_CODEC_DESCRIPTION,
1085                                   p_cl->codec[i_stream].psz_description );
1086                 }
1087             }
1088             i_stream++;
1089         }
1090     }
1091 #endif
1092     return VLC_SUCCESS;
1093
1094 error:
1095     ASF_FreeObjectRoot( p_demux->s, p_sys->p_root );
1096     return VLC_EGENERIC;
1097 }
1098 /*****************************************************************************
1099  *
1100  *****************************************************************************/
1101 static void DemuxEnd( demux_t *p_demux )
1102 {
1103     demux_sys_t *p_sys = p_demux->p_sys;
1104     int         i;
1105
1106     if( p_sys->p_root )
1107     {
1108         ASF_FreeObjectRoot( p_demux->s, p_sys->p_root );
1109         p_sys->p_root = NULL;
1110     }
1111     if( p_sys->meta )
1112     {
1113         vlc_meta_Delete( p_sys->meta );
1114         p_sys->meta = NULL;
1115     }
1116
1117     for( i = 0; i < 128; i++ )
1118     {
1119         asf_track_t *tk = p_sys->track[i];
1120
1121         if( tk )
1122         {
1123             if( tk->p_frame )
1124             {
1125                 block_ChainRelease( tk->p_frame );
1126             }
1127             if( tk->p_es )
1128             {
1129                 es_out_Del( p_demux->out, tk->p_es );
1130             }
1131             free( tk );
1132         }
1133         p_sys->track[i] = 0;
1134     }
1135 }
1136