asf: remove redundant casts
[vlc.git] / modules / demux / asf / asf.c
1 /*****************************************************************************
2  * asf.c : ASF demux module
3  *****************************************************************************
4  * Copyright © 2002-2004, 2006-2008, 2010 VLC authors and VideoLAN
5  *
6  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
7  *
8  * This program is free software; you can redistribute it and/or modify it
9  * under the terms of the GNU Lesser General Public License as published by
10  * the Free Software Foundation; either version 2.1 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public License
19  * along with this program; if not, write to the Free Software Foundation,
20  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21  *****************************************************************************/
22
23 /*****************************************************************************
24  * Preamble
25  *****************************************************************************/
26
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
31 #include <vlc_common.h>
32 #include <vlc_plugin.h>
33 #include <vlc_demux.h>
34 #include <vlc_dialog.h>
35
36 #include <vlc_meta.h>                  /* vlc_meta_Set*, vlc_meta_New */
37 #include <vlc_access.h>                /* GET_PRIVATE_ID_STATE */
38 #include <vlc_codecs.h>                /* VLC_BITMAPINFOHEADER, WAVEFORMATEX */
39 #include <vlc_input.h>
40 #include <vlc_vout.h>
41
42 #include <limits.h>
43
44 #include "asfpacket.h"
45 #include "libasf.h"
46 #include "assert.h"
47
48 /* TODO
49  *  - add support for the newly added object: language, bitrate,
50  *                                            extended stream properties.
51  */
52
53 /*****************************************************************************
54  * Module descriptor
55  *****************************************************************************/
56 static int  Open  ( vlc_object_t * );
57 static void Close ( vlc_object_t * );
58
59 vlc_module_begin ()
60     set_category( CAT_INPUT )
61     set_subcategory( SUBCAT_INPUT_DEMUX )
62     set_description( N_("ASF/WMV demuxer") )
63     set_capability( "demux", 200 )
64     set_callbacks( Open, Close )
65     add_shortcut( "asf", "wmv" )
66 vlc_module_end ()
67
68
69 /*****************************************************************************
70  * Local prototypes
71  *****************************************************************************/
72 static int Demux  ( demux_t * );
73 static int Control( demux_t *, int i_query, va_list args );
74
75 #define MAX_ASF_TRACKS (ASF_MAX_STREAMNUMBER + 1)
76 #define ASF_PREROLL_FROM_CURRENT -1
77
78 /* callbacks for packet parser */
79 static void Packet_UpdateTime( asf_packet_sys_t *p_packetsys, uint8_t i_stream_number,
80                                mtime_t i_time );
81 static void Packet_SetSendTime( asf_packet_sys_t *p_packetsys, mtime_t i_time);
82 static bool Block_Dequeue( demux_t *p_demux, mtime_t i_nexttime );
83 static asf_track_info_t * Packet_GetTrackInfo( asf_packet_sys_t *p_packetsys,
84                                                uint8_t i_stream_number );
85 static bool Packet_DoSkip( asf_packet_sys_t *p_packetsys, uint8_t i_stream_number, bool b_packet_keyframe );
86 static void Packet_Enqueue( asf_packet_sys_t *p_packetsys, uint8_t i_stream_number, block_t **pp_frame );
87 static void Packet_SetAR( asf_packet_sys_t *p_packetsys, uint8_t i_stream_number,
88                           uint8_t i_ratio_x, uint8_t i_ratio_y );
89
90 typedef struct
91 {
92     int i_cat;
93
94     es_out_id_t     *p_es;
95     es_format_t     *p_fmt; /* format backup for video changes */
96     bool             b_selected;
97
98     mtime_t          i_time; /* track time*/
99
100     asf_track_info_t info;
101
102     struct
103     {
104         block_t     *p_first;
105         block_t    **pp_last;
106     } queue;
107
108 } asf_track_t;
109
110 struct demux_sys_t
111 {
112     mtime_t             i_time;     /* s */
113     mtime_t             i_sendtime;
114     mtime_t             i_length;   /* length of file file */
115     uint64_t            i_bitrate;  /* global file bitrate */
116     bool                b_eos;      /* end of current stream */
117     bool                b_eof;      /* end of current media */
118
119     asf_object_root_t            *p_root;
120     asf_object_file_properties_t *p_fp;
121
122     unsigned int        i_track;
123     asf_track_t         *track[MAX_ASF_TRACKS]; /* track number is stored on 7 bits */
124
125     uint64_t            i_data_begin;
126     uint64_t            i_data_end;
127
128     bool                b_index;
129     bool                b_canfastseek;
130     uint8_t             i_seek_track;
131     uint8_t             i_access_selected_track[ES_CATEGORY_COUNT]; /* mms, depends on access algorithm */
132     unsigned int        i_wait_keyframe;
133
134     mtime_t             i_preroll_start;
135
136     asf_packet_sys_t    packet_sys;
137
138     vlc_meta_t          *meta;
139 };
140
141 static int      DemuxInit( demux_t * );
142 static void     DemuxEnd( demux_t * );
143
144 static void     FlushQueue( asf_track_t * );
145 static void     FlushQueues( demux_t *p_demux );
146
147 /*****************************************************************************
148  * Open: check file and initializes ASF structures
149  *****************************************************************************/
150 static int Open( vlc_object_t * p_this )
151 {
152     demux_t     *p_demux = (demux_t *)p_this;
153     demux_sys_t *p_sys;
154     guid_t      guid;
155     const uint8_t     *p_peek;
156
157     /* A little test to see if it could be a asf stream */
158     if( vlc_stream_Peek( p_demux->s, &p_peek, 16 ) < 16 ) return VLC_EGENERIC;
159
160     ASF_GetGUID( &guid, p_peek );
161     if( !guidcmp( &guid, &asf_object_header_guid ) ) return VLC_EGENERIC;
162
163     /* Set p_demux fields */
164     p_demux->pf_demux = Demux;
165     p_demux->pf_control = Control;
166     p_demux->p_sys = p_sys = calloc( 1, sizeof( demux_sys_t ) );
167
168     /* Load the headers */
169     if( DemuxInit( p_demux ) )
170     {
171         free( p_sys );
172         return VLC_EGENERIC;
173     }
174
175     p_sys->packet_sys.p_demux = p_demux;
176     p_sys->packet_sys.pf_doskip = Packet_DoSkip;
177     p_sys->packet_sys.pf_send = Packet_Enqueue;
178     p_sys->packet_sys.pf_gettrackinfo = Packet_GetTrackInfo;
179     p_sys->packet_sys.pf_updatetime = Packet_UpdateTime;
180     p_sys->packet_sys.pf_updatesendtime = Packet_SetSendTime;
181     p_sys->packet_sys.pf_setaspectratio = Packet_SetAR;
182
183     return VLC_SUCCESS;
184 }
185
186 /*****************************************************************************
187  * Demux: read packet and send them to decoders
188  *****************************************************************************/
189 #define CHUNK (CLOCK_FREQ / 10)
190 static int Demux( demux_t *p_demux )
191 {
192     demux_sys_t *p_sys = p_demux->p_sys;
193
194     for( int i=0; i<ES_CATEGORY_COUNT; i++ )
195     {
196         if ( p_sys->i_access_selected_track[i] > 0 )
197         {
198             es_out_Control( p_demux->out, ES_OUT_SET_ES_STATE,
199                             p_sys->track[p_sys->i_access_selected_track[i]]->p_es, true );
200             p_sys->i_access_selected_track[i] = 0;
201         }
202     }
203
204     /* Get selected tracks, especially for computing PCR */
205     for( int i=0; i<MAX_ASF_TRACKS; i++ )
206     {
207         asf_track_t *tk = p_sys->track[i];
208         if ( !tk ) continue;
209         if ( tk->p_es )
210             es_out_Control( p_demux->out, ES_OUT_GET_ES_STATE, tk->p_es, & tk->b_selected );
211         else
212             tk->b_selected = false;
213     }
214
215     while( !p_sys->b_eos && ( p_sys->i_sendtime - p_sys->i_time - CHUNK < 0 ||
216                             ( p_sys->i_sendtime - p_sys->i_time - CHUNK ) /
217                               UINT64_C( 1000 ) < p_sys->p_fp->i_preroll ) )
218     {
219         /* Read and demux a packet */
220         if( DemuxASFPacket( &p_sys->packet_sys,
221                              p_sys->p_fp->i_min_data_packet_size,
222                              p_sys->p_fp->i_max_data_packet_size ) <= 0 )
223         {
224             p_sys->b_eos = true;
225             /* Check if we have concatenated files */
226             const uint8_t *p_peek;
227             if( vlc_stream_Peek( p_demux->s, &p_peek, 16 ) == 16 )
228             {
229                 guid_t guid;
230
231                 ASF_GetGUID( &guid, p_peek );
232                 p_sys->b_eof = !guidcmp( &guid, &asf_object_header_guid );
233                 if( !p_sys->b_eof )
234                     msg_Warn( p_demux, "found a new ASF header" );
235             }
236             else
237                 p_sys->b_eof = true;
238         }
239
240         if ( p_sys->i_time == -1 )
241             p_sys->i_time = p_sys->i_sendtime;
242     }
243
244     if( p_sys->b_eos || ( p_sys->i_sendtime - p_sys->i_time - CHUNK >= 0 &&
245                         ( p_sys->i_sendtime - p_sys->i_time - CHUNK ) /
246                           UINT64_C( 1000 ) >= p_sys->p_fp->i_preroll ) )
247     {
248         bool b_data = Block_Dequeue( p_demux, p_sys->i_time + CHUNK );
249
250         p_sys->i_time += CHUNK;
251         es_out_Control( p_demux->out, ES_OUT_SET_PCR, VLC_TS_0 + p_sys->i_time );
252 #ifdef ASF_DEBUG
253         msg_Dbg( p_demux, "Demux Loop Setting PCR to %"PRId64, VLC_TS_0 + p_sys->i_time );
254 #endif
255         if ( !b_data && p_sys->b_eos )
256         {
257             /* We end this stream */
258             if( !p_sys->b_eof )
259             {
260                 DemuxEnd( p_demux );
261
262                 /* And we prepare to read the next one */
263                 if( DemuxInit( p_demux ) )
264                 {
265                     msg_Err( p_demux, "failed to load the new header" );
266                     vlc_dialog_display_error( p_demux,
267                         _("Could not demux ASF stream"), "%s",
268                         _("VLC failed to load the ASF header.") );
269                     return VLC_DEMUXER_EOF;
270                 }
271                 es_out_Control( p_demux->out, ES_OUT_RESET_PCR );
272             }
273             else
274                 return VLC_DEMUXER_EOF;
275         }
276     }
277
278     return 1;
279 }
280
281 /*****************************************************************************
282  * Close: frees unused data
283  *****************************************************************************/
284 static void Close( vlc_object_t * p_this )
285 {
286     demux_t     *p_demux = (demux_t *)p_this;
287
288     DemuxEnd( p_demux );
289
290     free( p_demux->p_sys );
291 }
292
293 /*****************************************************************************
294  * WaitKeyframe: computes the number of frames to wait for a keyframe
295  *****************************************************************************/
296 static void WaitKeyframe( demux_t *p_demux )
297 {
298     demux_sys_t *p_sys = p_demux->p_sys;
299     if ( ! p_sys->i_seek_track )
300     {
301         for ( int i=0; i<MAX_ASF_TRACKS; i++ )
302         {
303             asf_track_t *tk = p_sys->track[i];
304             if ( tk && tk->info.p_sp && tk->i_cat == VIDEO_ES && tk->b_selected )
305             {
306                 p_sys->i_seek_track = tk->info.p_sp->i_stream_number;
307                 break;
308             }
309         }
310     }
311
312     if ( p_sys->i_seek_track )
313     {
314         /* Skip forward at least 1 min */
315         asf_track_t *tk = p_sys->track[p_sys->i_seek_track];
316         if ( tk->info.p_esp && tk->info.p_esp->i_average_time_per_frame )
317         {
318             /* 1 min if fastseek, otherwise 5 sec */
319             /* That's a guess for bandwidth */
320             uint64_t i_maxwaittime = ( p_sys->b_canfastseek ) ? 600000000 : 50000000;
321             i_maxwaittime /= tk->info.p_esp->i_average_time_per_frame;
322             p_sys->i_wait_keyframe = __MIN( i_maxwaittime, UINT_MAX );
323         }
324         else
325         {
326             p_sys->i_wait_keyframe = ( p_sys->b_canfastseek ) ? 25 * 30 : 25 * 5;
327         }
328     }
329     else
330     {
331         p_sys->i_wait_keyframe = 0;
332     }
333
334 }
335
336 /*****************************************************************************
337  * SeekIndex: goto to i_date or i_percent
338  *****************************************************************************/
339 static int SeekPercent( demux_t *p_demux, int i_query, va_list args )
340 {
341     demux_sys_t *p_sys = p_demux->p_sys;
342
343     WaitKeyframe( p_demux );
344
345     msg_Dbg( p_demux, "seek with percent: waiting %i frames", p_sys->i_wait_keyframe );
346     return demux_vaControlHelper( p_demux->s, __MIN( INT64_MAX, p_sys->i_data_begin ),
347                                    __MIN( INT64_MAX, p_sys->i_data_end ),
348                                    __MIN( INT64_MAX, p_sys->i_bitrate ),
349                                    __MIN( INT16_MAX, p_sys->p_fp->i_min_data_packet_size ),
350                                    i_query, args );
351 }
352
353 static int SeekIndex( demux_t *p_demux, mtime_t i_date, float f_pos )
354 {
355     demux_sys_t *p_sys = p_demux->p_sys;
356     asf_object_index_t *p_index;
357
358     msg_Dbg( p_demux, "seek with index: %i seconds, position %f",
359              i_date >= 0 ? (int)(i_date/1000000) : -1, f_pos );
360
361     if( i_date < 0 )
362         i_date = p_sys->i_length * f_pos;
363
364     p_sys->i_preroll_start = i_date - (int64_t) p_sys->p_fp->i_preroll;
365     if ( p_sys->i_preroll_start < 0 ) p_sys->i_preroll_start = 0;
366
367     p_index = ASF_FindObject( p_sys->p_root, &asf_object_simple_index_guid, 0 );
368
369     uint64_t i_entry = p_sys->i_preroll_start * 10 / p_index->i_index_entry_time_interval;
370     if( i_entry >= p_index->i_index_entry_count )
371     {
372         msg_Warn( p_demux, "Incomplete index" );
373         return VLC_EGENERIC;
374     }
375
376     WaitKeyframe( p_demux );
377
378     uint64_t i_offset = (uint64_t)p_index->index_entry[i_entry].i_packet_number *
379                         p_sys->p_fp->i_min_data_packet_size;
380
381     if ( vlc_stream_Seek( p_demux->s, i_offset + p_sys->i_data_begin ) == VLC_SUCCESS )
382     {
383         es_out_Control( p_demux->out, ES_OUT_SET_NEXT_DISPLAY_TIME, VLC_TS_0 + i_date );
384         return VLC_SUCCESS;
385     }
386     else return VLC_EGENERIC;
387 }
388
389 static void SeekPrepare( demux_t *p_demux )
390 {
391     demux_sys_t *p_sys = p_demux->p_sys;
392
393     p_sys->b_eof = false;
394     p_sys->b_eos = false;
395     p_sys->i_time = -1;
396     p_sys->i_sendtime = -1;
397     p_sys->i_preroll_start = ASFPACKET_PREROLL_FROM_CURRENT;
398
399     for( int i = 0; i < MAX_ASF_TRACKS ; i++ )
400     {
401         asf_track_t *tk = p_sys->track[i];
402         if( tk )
403         {
404             FlushQueue( tk );
405             tk->i_time = -1;
406         }
407     }
408
409     es_out_Control( p_demux->out, ES_OUT_RESET_PCR );
410 }
411
412 /*****************************************************************************
413  * Control:
414  *****************************************************************************/
415 static int Control( demux_t *p_demux, int i_query, va_list args )
416 {
417     demux_sys_t *p_sys = p_demux->p_sys;
418     vlc_meta_t  *p_meta;
419     int64_t     i64, *pi64;
420     int         i;
421     double      f, *pf;
422
423     switch( i_query )
424     {
425     case DEMUX_GET_LENGTH:
426         pi64 = va_arg( args, int64_t * );
427         *pi64 = p_sys->i_length;
428         return VLC_SUCCESS;
429
430     case DEMUX_GET_TIME:
431         pi64 = va_arg( args, int64_t * );
432         if( p_sys->i_time < 0 ) return VLC_EGENERIC;
433         *pi64 = p_sys->i_time;
434         return VLC_SUCCESS;
435
436     case DEMUX_SET_TIME:
437         if ( p_sys->p_fp &&
438              ! ( p_sys->p_fp->i_flags & ASF_FILE_PROPERTIES_SEEKABLE ) )
439             return VLC_EGENERIC;
440
441         SeekPrepare( p_demux );
442
443         if( p_sys->b_index && p_sys->i_length > 0 )
444         {
445             va_list acpy;
446             va_copy( acpy, args );
447             i64 = va_arg( acpy, int64_t );
448             va_end( acpy );
449
450             if( !SeekIndex( p_demux, i64, -1 ) )
451                 return VLC_SUCCESS;
452         }
453         return SeekPercent( p_demux, i_query, args );
454
455     case DEMUX_SET_ES:
456     {
457         i = va_arg( args, int );
458         int i_ret;
459         if ( i >= 0 )
460         {
461             msg_Dbg( p_demux, "Requesting access to enable stream %d", i );
462             i_ret = vlc_stream_Control( p_demux->s,
463                                         STREAM_SET_PRIVATE_ID_STATE, i, true );
464         }
465         else
466         {  /* i contains -1 * es_category */
467             msg_Dbg( p_demux, "Requesting access to disable stream %d", i );
468             i_ret = vlc_stream_Control( p_demux->s,
469                                         STREAM_SET_PRIVATE_ID_STATE, i,
470                                         false );
471         }
472
473         if ( i_ret == VLC_SUCCESS )
474         {
475             asf_track_t *tk;
476             if( i >= 0 )
477             {
478                 tk = p_sys->track[i];
479             }
480             else
481             {
482                 for( int j = 0; j < MAX_ASF_TRACKS ; j++ )
483                 {
484                     tk = p_sys->track[j];
485                     if( !tk->p_fmt || tk->p_fmt->i_cat != -1 * i )
486                         continue;
487                     if( tk )
488                     {
489                         FlushQueue( tk );
490                         tk->i_time = -1;
491                     }
492                 }
493             }
494
495             p_sys->i_seek_track = 0;
496             if ( ( tk && tk->i_cat == VIDEO_ES ) || i == -1 * VIDEO_ES )
497                 WaitKeyframe( p_demux );
498         }
499         return i_ret;
500     }
501
502     case DEMUX_GET_POSITION:
503         if( p_sys->i_time < 0 ) return VLC_EGENERIC;
504         if( p_sys->i_length > 0 )
505         {
506             pf = va_arg( args, double * );
507             *pf = p_sys->i_time / (double)p_sys->i_length;
508             return VLC_SUCCESS;
509         }
510         return demux_vaControlHelper( p_demux->s,
511                                        __MIN( INT64_MAX, p_sys->i_data_begin ),
512                                        __MIN( INT64_MAX, p_sys->i_data_end ),
513                                        __MIN( INT64_MAX, p_sys->i_bitrate ),
514                                        __MIN( INT16_MAX, p_sys->p_fp->i_min_data_packet_size ),
515                                        i_query, args );
516
517     case DEMUX_SET_POSITION:
518         if ( p_sys->p_fp &&
519              ! ( p_sys->p_fp->i_flags & ASF_FILE_PROPERTIES_SEEKABLE ) )
520             return VLC_EGENERIC;
521
522         SeekPrepare( p_demux );
523
524         if( p_sys->b_index && p_sys->i_length > 0 )
525         {
526             va_list acpy;
527             va_copy( acpy, args );
528             f = va_arg( acpy, double );
529             va_end( acpy );
530
531             if( !SeekIndex( p_demux, -1, f ) )
532                 return VLC_SUCCESS;
533         }
534         return SeekPercent( p_demux, i_query, args );
535
536     case DEMUX_GET_META:
537         p_meta = va_arg( args, vlc_meta_t * );
538         vlc_meta_Merge( p_meta, p_sys->meta );
539         return VLC_SUCCESS;
540
541     case DEMUX_CAN_SEEK:
542         if ( p_sys->p_fp &&
543              ! ( p_sys->p_fp->i_flags & ASF_FILE_PROPERTIES_SEEKABLE ) )
544         {
545             bool *pb_bool = va_arg( args, bool * );
546             *pb_bool = false;
547             return VLC_SUCCESS;
548         }
549         // ft
550
551     default:
552         return demux_vaControlHelper( p_demux->s,
553                                       __MIN( INT64_MAX, p_sys->i_data_begin ),
554                                       __MIN( INT64_MAX, p_sys->i_data_end),
555                                       __MIN( INT64_MAX, p_sys->i_bitrate ),
556                     ( p_sys->p_fp ) ? __MIN( INT_MAX, p_sys->p_fp->i_min_data_packet_size ) : 1,
557                     i_query, args );
558     }
559 }
560
561 /*****************************************************************************
562  *
563  *****************************************************************************/
564 static void Packet_SetAR( asf_packet_sys_t *p_packetsys, uint8_t i_stream_number,
565                           uint8_t i_ratio_x, uint8_t i_ratio_y )
566 {
567     demux_t *p_demux = p_packetsys->p_demux;
568     asf_track_t *tk = p_demux->p_sys->track[i_stream_number];
569     if ( tk->p_fmt->video.i_sar_num == i_ratio_x && tk->p_fmt->video.i_sar_den == i_ratio_y )
570         return;
571
572     /* Only apply if origin pixel size >= 1x1, due to broken yacast */
573     if ( tk->p_fmt->video.i_height * i_ratio_x > tk->p_fmt->video.i_width * i_ratio_y )
574     {
575         vout_thread_t *p_vout = input_GetVout( p_demux->p_input );
576         if ( p_vout )
577         {
578             msg_Info( p_demux, "Changing aspect ratio to %i/%i", i_ratio_x, i_ratio_y );
579             vout_ChangeAspectRatio( p_vout, i_ratio_x, i_ratio_y );
580             vlc_object_release( p_vout );
581         }
582     }
583     tk->p_fmt->video.i_sar_num = i_ratio_x;
584     tk->p_fmt->video.i_sar_den = i_ratio_y;
585 }
586
587 static void Packet_SetSendTime( asf_packet_sys_t *p_packetsys, mtime_t i_time )
588 {
589     p_packetsys->p_demux->p_sys->i_sendtime = i_time;
590 }
591
592 static void Packet_UpdateTime( asf_packet_sys_t *p_packetsys, uint8_t i_stream_number,
593                                mtime_t i_time )
594 {
595     asf_track_t *tk = p_packetsys->p_demux->p_sys->track[i_stream_number];
596     if ( tk )
597         tk->i_time = i_time;
598 }
599
600 static asf_track_info_t * Packet_GetTrackInfo( asf_packet_sys_t *p_packetsys,
601                                                uint8_t i_stream_number )
602 {
603     asf_track_t *tk = p_packetsys->p_demux->p_sys->track[i_stream_number];
604     if (!tk)
605         return NULL;
606     else
607         return & tk->info;
608 }
609
610 static bool Packet_DoSkip( asf_packet_sys_t *p_packetsys, uint8_t i_stream_number, bool b_packet_keyframe )
611 {
612     demux_t *p_demux = p_packetsys->p_demux;
613     demux_sys_t *p_sys = p_demux->p_sys;
614     const asf_track_t *tk = p_sys->track[i_stream_number];
615
616     if( tk == NULL )
617     {
618         msg_Warn( p_demux, "undeclared stream[Id 0x%x]", i_stream_number );
619         return true;
620     }
621
622     if( p_sys->i_wait_keyframe )
623     {
624         if ( i_stream_number == p_sys->i_seek_track )
625         {
626             if ( !b_packet_keyframe )
627             {
628                 p_sys->i_wait_keyframe--;
629                 return true;
630             }
631             else
632                 p_sys->i_wait_keyframe = 0;
633         }
634         else
635             return true;
636     }
637
638     if( !tk->p_es )
639         return true;
640
641     return false;
642 }
643
644 static void Packet_Enqueue( asf_packet_sys_t *p_packetsys, uint8_t i_stream_number, block_t **pp_frame )
645 {
646     demux_t *p_demux = p_packetsys->p_demux;
647     demux_sys_t *p_sys = p_demux->p_sys;
648     asf_track_t *tk = p_sys->track[i_stream_number];
649     if ( !tk )
650         return;
651
652     block_t *p_gather = block_ChainGather( *pp_frame );
653     if( p_gather )
654     {
655         block_ChainLastAppend( & tk->queue.pp_last, p_gather );
656 #ifdef ASF_DEBUG
657         msg_Dbg( p_demux, "    enqueue packet dts %"PRId64" pts %"PRId64" pcr %"PRId64, p_gather->i_dts, p_gather->i_pts, p_sys->i_time );
658 #endif
659     }
660
661     *pp_frame = NULL;
662 }
663
664 static bool Block_Dequeue( demux_t *p_demux, mtime_t i_nexttime )
665 {
666     demux_sys_t *p_sys = p_demux->p_sys;
667     bool b_tracks_have_data = false;
668     for( int i = 0; i < MAX_ASF_TRACKS; i++ )
669     {
670         asf_track_t *tk = p_sys->track[i];
671         if (!tk)
672             continue;
673         b_tracks_have_data |= (tk->queue.p_first != NULL);
674         while( tk->queue.p_first && tk->queue.p_first->i_dts <= i_nexttime )
675         {
676             block_t *p_block = tk->queue.p_first;
677             tk->queue.p_first = p_block->p_next;
678             if( tk->queue.p_first == NULL )
679                 tk->queue.pp_last = &tk->queue.p_first;
680             else
681                 p_block->p_next = NULL;
682
683             if( p_sys->i_time < VLC_TS_0 )
684             {
685                 es_out_Control( p_demux->out, ES_OUT_SET_PCR, VLC_TS_0 + p_sys->i_time );
686 #ifdef ASF_DEBUG
687                 msg_Dbg( p_demux, "    dequeue setting PCR to %"PRId64, VLC_TS_0 + p_sys->i_time );
688 #endif
689             }
690
691 #ifdef ASF_DEBUG
692             msg_Dbg( p_demux, "    sending packet dts %"PRId64" pts %"PRId64" pcr %"PRId64, p_block->i_dts, p_block->i_pts, p_sys->i_time );
693 #endif
694             es_out_Send( p_demux->out, tk->p_es, p_block );
695         }
696     }
697     return b_tracks_have_data;
698 }
699
700 /*****************************************************************************
701  *
702  *****************************************************************************/
703 typedef struct asf_es_priorities_t
704 {
705     uint16_t *pi_stream_numbers;
706     uint16_t i_count;
707 } asf_es_priorities_t;
708
709 /* Fills up our exclusion list */
710 static void ASF_fillup_es_priorities_ex( demux_sys_t *p_sys, void *p_hdr,
711                                          asf_es_priorities_t *p_prios )
712 {
713     /* Find stream exclusions */
714     asf_object_advanced_mutual_exclusion_t *p_mutex =
715             ASF_FindObject( p_hdr, &asf_object_advanced_mutual_exclusion, 0 );
716     if (! p_mutex ) return;
717
718 #if ( UINT_MAX > SIZE_MAX / 2 )
719     if ( p_sys->i_track > (size_t)SIZE_MAX / sizeof(uint16_t) )
720         return;
721 #endif
722     p_prios->pi_stream_numbers = malloc( (size_t)p_sys->i_track * sizeof(uint16_t) );
723     if ( !p_prios->pi_stream_numbers ) return;
724
725     if ( p_mutex->i_stream_number_count )
726     {
727         /* Just set highest prio on highest in the group */
728         for ( uint16_t i = 1; i < p_mutex->i_stream_number_count; i++ )
729         {
730             if ( p_prios->i_count > p_sys->i_track || i > p_sys->i_track ) break;
731             p_prios->pi_stream_numbers[ p_prios->i_count++ ] = p_mutex->pi_stream_number[ i ];
732         }
733     }
734 }
735
736 /* Fills up our bitrate exclusion list */
737 static void ASF_fillup_es_bitrate_priorities_ex( demux_sys_t *p_sys, void *p_hdr,
738                                                  asf_es_priorities_t *p_prios )
739 {
740     /* Find bitrate exclusions */
741     asf_object_bitrate_mutual_exclusion_t *p_bitrate_mutex =
742             ASF_FindObject( p_hdr, &asf_object_bitrate_mutual_exclusion_guid, 0 );
743     if (! p_bitrate_mutex ) return;
744
745 #if ( UINT_MAX > SIZE_MAX / 2 )
746     if ( p_sys->i_track > (size_t)SIZE_MAX / sizeof(uint16_t) )
747         return;
748 #endif
749     p_prios->pi_stream_numbers = malloc( (size_t)p_sys->i_track * sizeof( uint16_t ) );
750     if ( !p_prios->pi_stream_numbers ) return;
751
752     if ( p_bitrate_mutex->i_stream_number_count )
753     {
754         /* Just remove < highest */
755         for ( uint16_t i = 1; i < p_bitrate_mutex->i_stream_number_count; i++ )
756         {
757             if ( p_prios->i_count > p_sys->i_track || i > p_sys->i_track ) break;
758             p_prios->pi_stream_numbers[ p_prios->i_count++ ] = p_bitrate_mutex->pi_stream_numbers[ i ];
759         }
760     }
761
762 }
763
764 #define GET_CHECKED( target, getter, maxtarget, temp ) \
765 {\
766     temp i_temp = getter;\
767     if ( i_temp > maxtarget ) {\
768         msg_Warn( p_demux, "rejecting stream %u : " #target " overflow", i_stream );\
769         es_format_Clean( &fmt );\
770         goto error;\
771     } else {\
772         target = i_temp;\
773     }\
774 }
775
776 static int DemuxInit( demux_t *p_demux )
777 {
778     demux_sys_t *p_sys = p_demux->p_sys;
779
780     /* init context */
781     p_sys->i_time   = -1;
782     p_sys->i_sendtime    = -1;
783     p_sys->i_length = 0;
784     p_sys->b_eos = false;
785     p_sys->b_eof = false;
786     p_sys->i_bitrate = 0;
787     p_sys->p_root   = NULL;
788     p_sys->p_fp     = NULL;
789     p_sys->b_index  = 0;
790     p_sys->i_track  = 0;
791     p_sys->i_seek_track = 0;
792     p_sys->i_wait_keyframe = 0;
793     for( int i = 0; i < MAX_ASF_TRACKS; i++ )
794     {
795         p_sys->track[i] = NULL;
796     }
797     p_sys->i_data_begin = 0;
798     p_sys->i_data_end   = 0;
799     p_sys->i_preroll_start = 0;
800     p_sys->meta         = NULL;
801
802     /* Now load all object ( except raw data ) */
803     vlc_stream_Control( p_demux->s, STREAM_CAN_FASTSEEK,
804                         &p_sys->b_canfastseek );
805     if( !(p_sys->p_root = ASF_ReadObjectRoot(p_demux->s, p_sys->b_canfastseek)) )
806     {
807         msg_Warn( p_demux, "ASF plugin discarded (not a valid file)" );
808         return VLC_EGENERIC;
809     }
810     p_sys->p_fp = p_sys->p_root->p_fp;
811
812     if( p_sys->p_fp->i_min_data_packet_size != p_sys->p_fp->i_max_data_packet_size )
813     {
814         msg_Warn( p_demux, "ASF plugin discarded (invalid file_properties object)" );
815         goto error;
816     }
817
818     if ( ASF_FindObject( p_sys->p_root->p_hdr,
819                          &asf_object_content_encryption_guid, 0 ) != NULL
820          || ASF_FindObject( p_sys->p_root->p_hdr,
821                             &asf_object_extended_content_encryption_guid, 0 ) != NULL
822          || ASF_FindObject( p_sys->p_root->p_hdr,
823                          &asf_object_advanced_content_encryption_guid, 0 ) != NULL )
824     {
825         vlc_dialog_display_error( p_demux, _("Could not demux ASF stream"), "%s",
826             ("DRM protected streams are not supported.") );
827         goto error;
828     }
829
830     p_sys->i_track = ASF_CountObject( p_sys->p_root->p_hdr,
831                                       &asf_object_stream_properties_guid );
832     if( p_sys->i_track == 0 )
833     {
834         msg_Warn( p_demux, "ASF plugin discarded (cannot find any stream!)" );
835         goto error;
836     }
837     msg_Dbg( p_demux, "found %u streams", p_sys->i_track );
838
839     /* check if index is available */
840     asf_object_index_t *p_index = ASF_FindObject( p_sys->p_root,
841                                                   &asf_object_simple_index_guid, 0 );
842     const bool b_index = p_index && p_index->i_index_entry_count;
843
844     /* Find the extended header if any */
845     asf_object_t *p_hdr_ext = ASF_FindObject( p_sys->p_root->p_hdr,
846                                               &asf_object_header_extension_guid, 0 );
847
848     asf_object_language_list_t *p_languages = NULL;
849     asf_es_priorities_t fmt_priorities_ex = { NULL, 0 };
850     asf_es_priorities_t fmt_priorities_bitrate_ex = { NULL, 0 };
851
852     if( p_hdr_ext )
853     {
854         p_languages = ASF_FindObject( p_hdr_ext, &asf_object_language_list, 0 );
855
856         ASF_fillup_es_priorities_ex( p_sys, p_hdr_ext, &fmt_priorities_ex );
857         ASF_fillup_es_bitrate_priorities_ex( p_sys, p_hdr_ext, &fmt_priorities_bitrate_ex );
858     }
859
860     const bool b_mms = !strncmp( p_demux->psz_access, "mms", 3 );
861     bool b_dvrms = false;
862
863     if( b_mms )
864     {
865         es_out_Control( p_demux->out, ES_OUT_SET_ES_CAT_POLICY,
866                         VIDEO_ES, ES_OUT_ES_POLICY_EXCLUSIVE );
867     }
868
869     for( unsigned i_stream = 0; i_stream < p_sys->i_track; i_stream++ )
870     {
871         asf_track_t    *tk;
872         asf_object_stream_properties_t *p_sp;
873         asf_object_extended_stream_properties_t *p_esp;
874         bool b_access_selected;
875
876         p_sp = ASF_FindObject( p_sys->p_root->p_hdr,
877                                &asf_object_stream_properties_guid,
878                                i_stream );
879         p_esp = NULL;
880
881         tk = p_sys->track[p_sp->i_stream_number] = malloc( sizeof( asf_track_t ) );
882         memset( tk, 0, sizeof( asf_track_t ) );
883
884         tk->i_time = -1;
885         tk->info.p_sp = p_sp;
886         tk->p_es = NULL;
887         tk->info.p_esp = NULL;
888         tk->info.p_frame = NULL;
889         tk->info.i_cat = UNKNOWN_ES;
890         tk->queue.p_first = NULL;
891         tk->queue.pp_last = &tk->queue.p_first;
892
893         if ( !b_mms )
894         {
895             /* Check (not mms) if this track is selected (ie will receive data) */
896             if( !vlc_stream_Control( p_demux->s, STREAM_GET_PRIVATE_ID_STATE,
897                                      (int) p_sp->i_stream_number,
898                                      &b_access_selected ) &&
899                 !b_access_selected )
900             {
901                 tk->i_cat = UNKNOWN_ES;
902                 msg_Dbg( p_demux, "ignoring not selected stream(ID:%u) (by access)",
903                          p_sp->i_stream_number );
904                 continue;
905             }
906         }
907
908         /* Find the associated extended_stream_properties if any */
909         if( p_hdr_ext )
910         {
911             int i_ext_stream = ASF_CountObject( p_hdr_ext,
912                                                 &asf_object_extended_stream_properties_guid );
913             for( int i = 0; i < i_ext_stream; i++ )
914             {
915                 asf_object_t *p_tmp =
916                     ASF_FindObject( p_hdr_ext,
917                                     &asf_object_extended_stream_properties_guid, i );
918                 if( p_tmp->ext_stream.i_stream_number == p_sp->i_stream_number )
919                 {
920                     p_esp = &p_tmp->ext_stream;
921                     tk->info.p_esp = p_esp;
922                     break;
923                 }
924             }
925         }
926
927         /* Check for DVR-MS */
928         if( p_esp )
929             for( uint16_t i=0; i<p_esp->i_payload_extension_system_count && !b_dvrms; i++ )
930                 b_dvrms = guidcmp( &p_esp->p_ext[i].i_extension_id, &asf_dvr_sampleextension_timing_rep_data_guid );
931
932         es_format_t fmt;
933
934         if( guidcmp( &p_sp->i_stream_type, &asf_object_stream_type_audio ) &&
935             p_sp->i_type_specific_data_length >= sizeof( WAVEFORMATEX ) - 2 )
936         {
937             uint8_t *p_data = p_sp->p_type_specific_data;
938             int i_format;
939
940             es_format_Init( &fmt, AUDIO_ES, 0 );
941             i_format = GetWLE( &p_data[0] );
942             wf_tag_to_fourcc( i_format, &fmt.i_codec, NULL );
943
944             GET_CHECKED( fmt.audio.i_channels,      GetWLE( &p_data[2] ),
945                                                         255, uint16_t );
946             GET_CHECKED( fmt.audio.i_rate,          GetDWLE( &p_data[4] ),
947                                                         UINT_MAX, uint32_t );
948             GET_CHECKED( fmt.i_bitrate,             GetDWLE( &p_data[8] ) * 8,
949                                                         UINT_MAX, uint32_t );
950             fmt.audio.i_blockalign      = GetWLE(  &p_data[12] );
951             fmt.audio.i_bitspersample   = GetWLE(  &p_data[14] );
952
953             if( p_sp->i_type_specific_data_length > sizeof( WAVEFORMATEX ) &&
954                 i_format != WAVE_FORMAT_MPEGLAYER3 &&
955                 i_format != WAVE_FORMAT_MPEG )
956             {
957                 GET_CHECKED( fmt.i_extra, __MIN( GetWLE( &p_data[16] ),
958                                      p_sp->i_type_specific_data_length -
959                                      sizeof( WAVEFORMATEX ) ),
960                              INT_MAX, uint32_t );
961                 fmt.p_extra = malloc( fmt.i_extra );
962                 memcpy( fmt.p_extra, &p_data[sizeof( WAVEFORMATEX )],
963                         fmt.i_extra );
964             }
965             msg_Dbg( p_demux, "added new audio stream (codec:%4.4s(0x%x),ID:%d)",
966                 (char*)&fmt.i_codec, GetWLE( p_data ), p_sp->i_stream_number );
967         }
968         else if( guidcmp( &p_sp->i_stream_type,
969                               &asf_object_stream_type_video ) &&
970                  p_sp->i_type_specific_data_length >= 11 +
971                  sizeof( VLC_BITMAPINFOHEADER ) )
972         {
973             uint8_t      *p_data = &p_sp->p_type_specific_data[11];
974
975             es_format_Init( &fmt, VIDEO_ES,
976                             VLC_FOURCC( p_data[16], p_data[17],
977                                         p_data[18], p_data[19] ) );
978
979             GET_CHECKED( fmt.video.i_width,      GetDWLE( p_data + 4 ),
980                                                      UINT_MAX, uint32_t );
981             GET_CHECKED( fmt.video.i_height,     GetDWLE( p_data + 8 ),
982                                                      UINT_MAX, uint32_t );
983             fmt.video.i_visible_width = fmt.video.i_width;
984             fmt.video.i_visible_height = fmt.video.i_height;
985
986             if( p_esp && p_esp->i_average_time_per_frame > 0 )
987             {
988                 fmt.video.i_frame_rate = 10000000;
989                 GET_CHECKED( fmt.video.i_frame_rate_base,
990                              p_esp->i_average_time_per_frame,
991                              UINT_MAX, uint64_t );
992             }
993
994             if( fmt.i_codec == VLC_FOURCC( 'D','V','R',' ') )
995             {
996                 /* DVR-MS special ASF */
997                 fmt.i_codec = VLC_CODEC_MPGV;
998             }
999
1000             if( p_sp->i_type_specific_data_length > 11 +
1001                 sizeof( VLC_BITMAPINFOHEADER ) )
1002             {
1003                 GET_CHECKED( fmt.i_extra, __MIN( GetDWLE( p_data ),
1004                                      p_sp->i_type_specific_data_length - 11 -
1005                                      sizeof( VLC_BITMAPINFOHEADER ) ),
1006                              UINT_MAX, uint32_t );
1007                 fmt.p_extra = malloc( fmt.i_extra );
1008                 memcpy( fmt.p_extra, &p_data[sizeof( VLC_BITMAPINFOHEADER )],
1009                         fmt.i_extra );
1010             }
1011
1012             /* Look for an aspect ratio */
1013             if( p_sys->p_root->p_metadata )
1014             {
1015                 asf_object_metadata_t *p_meta = p_sys->p_root->p_metadata;
1016                 unsigned int i_aspect_x = 0, i_aspect_y = 0;
1017                 uint32_t i;
1018                 for( i = 0; i < p_meta->i_record_entries_count; i++ )
1019                 {
1020                     if( !p_meta->record[i].psz_name )
1021                         continue;
1022                     if( !strcmp( p_meta->record[i].psz_name, "AspectRatioX" ) )
1023                     {
1024                         if( (!i_aspect_x && !p_meta->record[i].i_stream) ||
1025                             p_meta->record[i].i_stream ==
1026                             p_sp->i_stream_number )
1027                             GET_CHECKED( i_aspect_x, p_meta->record[i].i_val,
1028                                          UINT_MAX, uint64_t );
1029                     }
1030                     if( !strcmp( p_meta->record[i].psz_name, "AspectRatioY" ) )
1031                     {
1032                         if( (!i_aspect_y && !p_meta->record[i].i_stream) ||
1033                             p_meta->record[i].i_stream ==
1034                             p_sp->i_stream_number )
1035                             GET_CHECKED( i_aspect_y, p_meta->record[i].i_val,
1036                                          UINT_MAX, uint64_t );
1037                     }
1038                 }
1039
1040                 if( i_aspect_x && i_aspect_y )
1041                 {
1042                     fmt.video.i_sar_num = i_aspect_x;
1043                     fmt.video.i_sar_den = i_aspect_y;
1044                 }
1045             }
1046
1047             /* If there is a video track then use the index for seeking */
1048             p_sys->b_index = b_index;
1049
1050             msg_Dbg( p_demux, "added new video stream(codec:%4.4s,ID:%d)",
1051                      (char*)&fmt.i_codec, p_sp->i_stream_number );
1052         }
1053         else if( guidcmp( &p_sp->i_stream_type, &asf_object_stream_type_binary ) &&
1054             p_sp->i_type_specific_data_length >= 64 )
1055         {
1056             guid_t i_major_media_type;
1057             ASF_GetGUID( &i_major_media_type, p_sp->p_type_specific_data );
1058             msg_Dbg( p_demux, "stream(ID:%d) major type " GUID_FMT, p_sp->i_stream_number,
1059                      GUID_PRINT(i_major_media_type) );
1060
1061             guid_t i_media_subtype;
1062             ASF_GetGUID( &i_media_subtype, &p_sp->p_type_specific_data[16] );
1063             msg_Dbg( p_demux, "stream(ID:%d) subtype " GUID_FMT, p_sp->i_stream_number,
1064                      GUID_PRINT(i_media_subtype) );
1065
1066             //uint32_t i_fixed_size_samples = GetDWBE( &p_sp->p_type_specific_data[32] );
1067             //uint32_t i_temporal_compression = GetDWBE( &p_sp->p_type_specific_data[36] );
1068             //uint32_t i_sample_size = GetDWBE( &p_sp->p_type_specific_data[40] );
1069
1070             guid_t i_format_type;
1071             ASF_GetGUID( &i_format_type, &p_sp->p_type_specific_data[44] );
1072             msg_Dbg( p_demux, "stream(ID:%d) format type " GUID_FMT, p_sp->i_stream_number,
1073                      GUID_PRINT(i_format_type) );
1074
1075             //uint32_t i_format_data_size = GetDWBE( &p_sp->p_type_specific_data[60] );
1076             uint8_t *p_data = p_sp->p_type_specific_data + 64;
1077             unsigned int i_data = p_sp->i_type_specific_data_length - 64;
1078
1079             msg_Dbg( p_demux, "Ext stream header detected. datasize = %d", p_sp->i_type_specific_data_length );
1080             if( guidcmp( &i_major_media_type, &asf_object_extended_stream_type_audio ) &&
1081                 i_data >= sizeof( WAVEFORMATEX ) - 2)
1082             {
1083                 uint16_t i_format;
1084                 es_format_Init( &fmt, AUDIO_ES, 0 );
1085
1086                 i_format = GetWLE( &p_data[0] );
1087                 if( i_format == 0 )
1088                     fmt.i_codec = VLC_CODEC_A52;
1089                 else
1090                     wf_tag_to_fourcc( i_format, &fmt.i_codec, NULL );
1091
1092                 GET_CHECKED( fmt.audio.i_channels,      GetWLE( &p_data[2] ),
1093                                                             255, uint16_t );
1094                 GET_CHECKED( fmt.audio.i_rate,          GetDWLE( &p_data[4] ),
1095                                                             UINT_MAX, uint32_t );
1096                 GET_CHECKED( fmt.i_bitrate,             GetDWLE( &p_data[8] ) * 8,
1097                                                             UINT_MAX, uint32_t );
1098                 fmt.audio.i_blockalign      = GetWLE(  &p_data[12] );
1099                 fmt.audio.i_bitspersample   = GetWLE(  &p_data[14] );
1100
1101                 if( p_sp->i_type_specific_data_length > sizeof( WAVEFORMATEX ) &&
1102                     i_format != WAVE_FORMAT_MPEGLAYER3 &&
1103                     i_format != WAVE_FORMAT_MPEG && i_data >= 19 )
1104                 {
1105                     GET_CHECKED( fmt.i_extra, __MIN( GetWLE( &p_data[16] ),
1106                                          p_sp->i_type_specific_data_length -
1107                                          sizeof( WAVEFORMATEX ) ),
1108                                  INT_MAX, uint32_t );
1109                     fmt.p_extra = malloc( fmt.i_extra );
1110                     if ( fmt.p_extra )
1111                         memcpy( fmt.p_extra, &p_data[sizeof( WAVEFORMATEX )], fmt.i_extra );
1112                     else
1113                         fmt.i_extra = 0;
1114                 }
1115
1116                 msg_Dbg( p_demux, "added new audio stream (codec:%4.4s(0x%x),ID:%d)",
1117                     (char*)&fmt.i_codec, i_format, p_sp->i_stream_number );
1118             }
1119             else
1120             {
1121                 es_format_Init( &fmt, UNKNOWN_ES, 0 );
1122             }
1123         }
1124         else
1125         {
1126             es_format_Init( &fmt, UNKNOWN_ES, 0 );
1127         }
1128
1129         if( b_dvrms )
1130         {
1131             fmt.i_original_fourcc = VLC_FOURCC( 'D','V','R',' ');
1132             fmt.b_packetized = false;
1133         }
1134
1135         if( fmt.i_codec == VLC_CODEC_MP4A )
1136             fmt.b_packetized = false;
1137
1138         tk->i_cat = tk->info.i_cat = fmt.i_cat;
1139         if( fmt.i_cat != UNKNOWN_ES )
1140         {
1141             if( p_esp && p_languages &&
1142                 p_esp->i_language_index < p_languages->i_language &&
1143                 p_languages->ppsz_language[p_esp->i_language_index] )
1144             {
1145                 fmt.psz_language = strdup( p_languages->ppsz_language[p_esp->i_language_index] );
1146                 char *p;
1147                 if( fmt.psz_language && (p = strchr( fmt.psz_language, '-' )) )
1148                     *p = '\0';
1149             }
1150
1151             /* Set our priority so we won't get multiple videos */
1152             int i_priority = ES_PRIORITY_SELECTABLE_MIN;
1153             for( uint16_t i = 0; i < fmt_priorities_ex.i_count; i++ )
1154             {
1155                 if ( fmt_priorities_ex.pi_stream_numbers[i] == p_sp->i_stream_number )
1156                 {
1157                     i_priority = ES_PRIORITY_NOT_DEFAULTABLE;
1158                     break;
1159                 }
1160             }
1161             for( uint16_t i = 0; i < fmt_priorities_bitrate_ex.i_count; i++ )
1162             {
1163                 if ( fmt_priorities_bitrate_ex.pi_stream_numbers[i] == p_sp->i_stream_number )
1164                 {
1165                     i_priority = ES_PRIORITY_NOT_DEFAULTABLE;
1166                     break;
1167                 }
1168             }
1169             fmt.i_priority = i_priority;
1170
1171             if ( i_stream <= INT_MAX )
1172                 fmt.i_id = i_stream;
1173             else
1174                 msg_Warn( p_demux, "Can't set fmt.i_id to match stream id %u", i_stream );
1175
1176             if ( fmt.i_cat == VIDEO_ES )
1177             {
1178                 /* Backup our video format */
1179                 tk->p_fmt = malloc( sizeof( es_format_t ) );
1180                 if ( tk->p_fmt )
1181                     es_format_Copy( tk->p_fmt, &fmt );
1182             }
1183
1184             fmt.i_id = tk->info.p_sp->i_stream_number;
1185
1186             tk->p_es = es_out_Add( p_demux->out, &fmt );
1187
1188             if( !vlc_stream_Control( p_demux->s, STREAM_GET_PRIVATE_ID_STATE,
1189                                      (int) p_sp->i_stream_number,
1190                                      &b_access_selected ) &&
1191                 b_access_selected )
1192             {
1193                 p_sys->i_access_selected_track[fmt.i_cat] = p_sp->i_stream_number;
1194             }
1195
1196         }
1197         else
1198         {
1199             msg_Dbg( p_demux, "ignoring unknown stream(ID:%d)",
1200                      p_sp->i_stream_number );
1201         }
1202
1203         es_format_Clean( &fmt );
1204     }
1205
1206     free( fmt_priorities_ex.pi_stream_numbers );
1207     free( fmt_priorities_bitrate_ex.pi_stream_numbers );
1208
1209     p_sys->i_data_begin = p_sys->p_root->p_data->i_object_pos + 50;
1210     if( p_sys->p_root->p_data->i_object_size != 0 )
1211     { /* local file */
1212         p_sys->i_data_end = p_sys->p_root->p_data->i_object_pos +
1213                                     p_sys->p_root->p_data->i_object_size;
1214         p_sys->i_data_end = __MIN( (uint64_t)stream_Size( p_demux->s ), p_sys->i_data_end );
1215     }
1216     else
1217     { /* live/broacast */
1218         p_sys->i_data_end = 0;
1219     }
1220
1221     /* go to first packet */
1222     if( vlc_stream_Seek( p_demux->s, p_sys->i_data_begin ) != VLC_SUCCESS )
1223         goto error;
1224
1225     /* try to calculate movie time */
1226     if( p_sys->p_fp->i_data_packets_count > 0 )
1227     {
1228         uint64_t i_count;
1229         uint64_t i_size = stream_Size( p_demux->s );
1230
1231         if( p_sys->i_data_end > 0 && i_size > p_sys->i_data_end )
1232         {
1233             i_size = p_sys->i_data_end;
1234         }
1235
1236         /* real number of packets */
1237         i_count = ( i_size - p_sys->i_data_begin ) /
1238                   p_sys->p_fp->i_min_data_packet_size;
1239
1240         /* calculate the time duration in micro-s */
1241         p_sys->i_length = (mtime_t)p_sys->p_fp->i_play_duration / 10 *
1242                    (mtime_t)i_count /
1243                    (mtime_t)p_sys->p_fp->i_data_packets_count - p_sys->p_fp->i_preroll * 1000;
1244         if( p_sys->i_length < 0 )
1245             p_sys->i_length = 0;
1246
1247         if( p_sys->i_length > 0 )
1248         {
1249             p_sys->i_bitrate = 8 * i_size * 1000000 / p_sys->i_length;
1250         }
1251     }
1252
1253     /* Create meta information */
1254     p_sys->meta = vlc_meta_New();
1255
1256     asf_object_content_description_t *p_cd;
1257     if( ( p_cd = ASF_FindObject( p_sys->p_root->p_hdr,
1258                                  &asf_object_content_description_guid, 0 ) ) )
1259     {
1260         if( p_cd->psz_title && *p_cd->psz_title )
1261         {
1262             vlc_meta_SetTitle( p_sys->meta, p_cd->psz_title );
1263         }
1264         if( p_cd->psz_artist && *p_cd->psz_artist )
1265         {
1266              vlc_meta_SetArtist( p_sys->meta, p_cd->psz_artist );
1267         }
1268         if( p_cd->psz_copyright && *p_cd->psz_copyright )
1269         {
1270             vlc_meta_SetCopyright( p_sys->meta, p_cd->psz_copyright );
1271         }
1272         if( p_cd->psz_description && *p_cd->psz_description )
1273         {
1274             vlc_meta_SetDescription( p_sys->meta, p_cd->psz_description );
1275         }
1276         if( p_cd->psz_rating && *p_cd->psz_rating )
1277         {
1278             vlc_meta_SetRating( p_sys->meta, p_cd->psz_rating );
1279         }
1280     }
1281     asf_object_extended_content_description_t *p_ecd;
1282     if( ( p_ecd = ASF_FindObject( p_sys->p_root->p_hdr,
1283                                  &asf_object_extended_content_description, 0 ) ) )
1284     {
1285         for( int i = 0; i < p_ecd->i_count; i++ )
1286         {
1287
1288 #define set_meta( name, vlc_type ) \
1289             if( p_ecd->ppsz_name[i] && !strncmp( p_ecd->ppsz_name[i], name, strlen(name) ) ) \
1290                 vlc_meta_Set( p_sys->meta, vlc_type, p_ecd->ppsz_value[i] );
1291
1292             set_meta( "WM/AlbumTitle",   vlc_meta_Album )
1293             else set_meta( "WM/TrackNumber",  vlc_meta_TrackNumber )
1294             else set_meta( "WM/Year",         vlc_meta_Date )
1295             else set_meta( "WM/Genre",        vlc_meta_Genre )
1296             else set_meta( "WM/Genre",        vlc_meta_Genre )
1297             else set_meta( "WM/AlbumArtist",  vlc_meta_Artist )
1298             else set_meta( "WM/Publisher",    vlc_meta_Publisher )
1299             else set_meta( "WM/PartOfSet",    vlc_meta_DiscNumber )
1300             else if( p_ecd->ppsz_value[i] != NULL && p_ecd->ppsz_name[i] &&
1301                     *p_ecd->ppsz_value[i] != '\0' && /* no empty value */
1302                     *p_ecd->ppsz_value[i] != '{'  && /* no guid value */
1303                     *p_ecd->ppsz_name[i] != '{' )    /* no guid name */
1304                     vlc_meta_AddExtra( p_sys->meta, p_ecd->ppsz_name[i], p_ecd->ppsz_value[i] );
1305             /* TODO map WM/Composer, WM/Provider, WM/PartOfSet, PeakValue, AverageLevel  */
1306 #undef set_meta
1307         }
1308     }
1309
1310     /// \tood Fix Child meta for ASF tracks
1311 #if 0
1312     for( i_stream = 0, i = 0; i < MAX_ASF_TRACKS; i++ )
1313     {
1314         asf_object_codec_list_t *p_cl = ASF_FindObject( p_sys->p_root->p_hdr,
1315                                                         &asf_object_codec_list_guid, 0 );
1316
1317         if( p_sys->track[i] )
1318         {
1319             vlc_meta_t *tk = vlc_meta_New();
1320             TAB_APPEND( p_sys->meta->i_track, p_sys->meta->track, tk );
1321
1322             if( p_cl && i_stream < p_cl->i_codec_entries_count )
1323             {
1324                 if( p_cl->codec[i_stream].psz_name &&
1325                     *p_cl->codec[i_stream].psz_name )
1326                 {
1327                     vlc_meta_Add( tk, VLC_META_CODEC_NAME,
1328                                   p_cl->codec[i_stream].psz_name );
1329                 }
1330                 if( p_cl->codec[i_stream].psz_description &&
1331                     *p_cl->codec[i_stream].psz_description )
1332                 {
1333                     vlc_meta_Add( tk, VLC_META_CODEC_DESCRIPTION,
1334                                   p_cl->codec[i_stream].psz_description );
1335                 }
1336             }
1337             i_stream++;
1338         }
1339     }
1340 #endif
1341
1342     p_sys->packet_sys.pi_preroll = &p_sys->p_fp->i_preroll;
1343     p_sys->packet_sys.pi_preroll_start = &p_sys->i_preroll_start;
1344
1345     return VLC_SUCCESS;
1346
1347 error:
1348     DemuxEnd( p_demux );
1349     return VLC_EGENERIC;
1350 }
1351
1352 /*****************************************************************************
1353  * FlushQueues: flushes tail packets and send queues
1354  *****************************************************************************/
1355 static void FlushQueue( asf_track_t *tk )
1356 {
1357     if( tk->info.p_frame )
1358     {
1359         block_ChainRelease( tk->info.p_frame );
1360         tk->info.p_frame = NULL;
1361     }
1362     if( tk->queue.p_first )
1363     {
1364         block_ChainRelease( tk->queue.p_first );
1365         tk->queue.p_first = NULL;
1366         tk->queue.pp_last = &tk->queue.p_first;
1367     }
1368 }
1369
1370 static void FlushQueues( demux_t *p_demux )
1371 {
1372     demux_sys_t *p_sys = p_demux->p_sys;
1373     for ( unsigned int i = 0; i < MAX_ASF_TRACKS; i++ )
1374     {
1375         asf_track_t *tk = p_sys->track[i];
1376         if( !tk )
1377             continue;
1378         FlushQueue( tk );
1379     }
1380 }
1381
1382 /*****************************************************************************
1383  *
1384  *****************************************************************************/
1385 static void DemuxEnd( demux_t *p_demux )
1386 {
1387     demux_sys_t *p_sys = p_demux->p_sys;
1388
1389     if( p_sys->p_root )
1390     {
1391         ASF_FreeObjectRoot( p_demux->s, p_sys->p_root );
1392         p_sys->p_root = NULL;
1393     }
1394     if( p_sys->meta )
1395     {
1396         vlc_meta_Delete( p_sys->meta );
1397         p_sys->meta = NULL;
1398     }
1399
1400     FlushQueues( p_demux );
1401
1402     for( int i = 0; i < MAX_ASF_TRACKS; i++ )
1403     {
1404         asf_track_t *tk = p_sys->track[i];
1405
1406         if( tk )
1407         {
1408             if( tk->p_es )
1409             {
1410                 es_out_Del( p_demux->out, tk->p_es );
1411             }
1412             if ( tk->p_fmt )
1413             {
1414                 es_format_Clean( tk->p_fmt );
1415                 free( tk->p_fmt );
1416             }
1417             free( tk );
1418         }
1419         p_sys->track[i] = 0;
1420     }
1421 }
1422