1 /*****************************************************************************
2 * asf.c : ASF demux module
3 *****************************************************************************
4 * Copyright © 2002-2004, 2006-2008, 2010 VLC authors and VideoLAN
6 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
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.
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.
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 *****************************************************************************/
23 /*****************************************************************************
25 *****************************************************************************/
31 #include <vlc_common.h>
32 #include <vlc_plugin.h>
33 #include <vlc_demux.h>
34 #include <vlc_dialog.h>
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 */
43 #include "asfpacket.h"
48 * - add support for the newly added object: language, bitrate,
49 * extended stream properties.
52 /*****************************************************************************
54 *****************************************************************************/
55 static int Open ( vlc_object_t * );
56 static void Close ( vlc_object_t * );
59 set_category( CAT_INPUT )
60 set_subcategory( SUBCAT_INPUT_DEMUX )
61 set_description( N_("ASF/WMV demuxer") )
62 set_capability( "demux", 200 )
63 set_callbacks( Open, Close )
64 add_shortcut( "asf", "wmv" )
65 add_file_extension("asf")
66 add_file_extension("wma")
67 add_file_extension("wmv")
71 /*****************************************************************************
73 *****************************************************************************/
74 static int Demux ( demux_t * );
75 static int Control( demux_t *, int i_query, va_list args );
77 #define MAX_ASF_TRACKS (ASF_MAX_STREAMNUMBER + 1)
78 #define ASF_PREROLL_FROM_CURRENT -1
80 /* callbacks for packet parser */
81 static void Packet_UpdateTime( asf_packet_sys_t *p_packetsys, uint8_t i_stream_number,
83 static void Packet_SetSendTime( asf_packet_sys_t *p_packetsys, vlc_tick_t i_time);
84 static bool Block_Dequeue( demux_t *p_demux, vlc_tick_t i_nexttime );
85 static asf_track_info_t * Packet_GetTrackInfo( asf_packet_sys_t *p_packetsys,
86 uint8_t i_stream_number );
87 static bool Packet_DoSkip( asf_packet_sys_t *p_packetsys, uint8_t i_stream_number, bool b_packet_keyframe );
88 static void Packet_Enqueue( asf_packet_sys_t *p_packetsys, uint8_t i_stream_number, block_t **pp_frame );
89 static void Packet_SetAR( asf_packet_sys_t *p_packetsys, uint8_t i_stream_number,
90 uint8_t i_ratio_x, uint8_t i_ratio_y );
97 es_format_t *p_fmt; /* format backup for video changes */
100 vlc_tick_t i_time; /* track time*/
102 asf_track_info_t info;
114 vlc_tick_t i_time; /* s */
115 vlc_tick_t i_sendtime;
116 vlc_tick_t i_length; /* length of file */
117 uint64_t i_bitrate; /* global file bitrate */
118 bool b_eos; /* end of current stream */
119 bool b_eof; /* end of current media */
121 asf_object_root_t *p_root;
122 asf_object_file_properties_t *p_fp;
124 unsigned int i_track;
125 asf_track_t *track[MAX_ASF_TRACKS]; /* track number is stored on 7 bits */
127 uint64_t i_data_begin;
133 uint8_t i_seek_track;
134 uint8_t i_access_selected_track[ES_CATEGORY_COUNT]; /* mms, depends on access algorithm */
135 unsigned int i_wait_keyframe;
137 vlc_tick_t i_preroll_start;
139 asf_packet_sys_t packet_sys;
144 static int DemuxInit( demux_t * );
145 static void DemuxEnd( demux_t * );
147 static void FlushQueue( asf_track_t * );
148 static void FlushQueues( demux_t *p_demux );
150 /*****************************************************************************
151 * Open: check file and initializes ASF structures
152 *****************************************************************************/
153 static int Open( vlc_object_t * p_this )
155 demux_t *p_demux = (demux_t *)p_this;
158 const uint8_t *p_peek;
160 /* A little test to see if it could be a asf stream */
161 if( vlc_stream_Peek( p_demux->s, &p_peek, 16 ) < 16 ) return VLC_EGENERIC;
163 ASF_GetGUID( &guid, p_peek );
164 if( !guidcmp( &guid, &asf_object_header_guid ) ) return VLC_EGENERIC;
166 /* Set p_demux fields */
167 p_demux->pf_demux = Demux;
168 p_demux->pf_control = Control;
169 p_demux->p_sys = p_sys = calloc( 1, sizeof( demux_sys_t ) );
171 /* Load the headers */
172 if( DemuxInit( p_demux ) )
178 p_sys->packet_sys.priv = p_demux;
179 p_sys->packet_sys.s = p_demux->s;
180 p_sys->packet_sys.logger = p_demux->obj.logger;
181 p_sys->packet_sys.b_deduplicate = false;
182 p_sys->packet_sys.b_can_hold_multiple_packets = false;
183 p_sys->packet_sys.pf_doskip = Packet_DoSkip;
184 p_sys->packet_sys.pf_send = Packet_Enqueue;
185 p_sys->packet_sys.pf_gettrackinfo = Packet_GetTrackInfo;
186 p_sys->packet_sys.pf_updatetime = Packet_UpdateTime;
187 p_sys->packet_sys.pf_updatesendtime = Packet_SetSendTime;
188 p_sys->packet_sys.pf_setaspectratio = Packet_SetAR;
193 /*****************************************************************************
194 * Demux: read packet and send them to decoders
195 *****************************************************************************/
196 #define CHUNK VLC_TICK_FROM_MS(100)
197 static int Demux( demux_t *p_demux )
199 demux_sys_t *p_sys = p_demux->p_sys;
201 for( int i=0; i<ES_CATEGORY_COUNT; i++ )
203 if ( p_sys->i_access_selected_track[i] > 0 )
205 es_out_Control( p_demux->out, ES_OUT_SET_ES_STATE,
206 p_sys->track[p_sys->i_access_selected_track[i]]->p_es, true );
207 p_sys->i_access_selected_track[i] = 0;
211 /* Get selected tracks, especially for computing PCR */
212 for( int i=0; i<MAX_ASF_TRACKS; i++ )
214 asf_track_t *tk = p_sys->track[i];
217 es_out_Control( p_demux->out, ES_OUT_GET_ES_STATE, tk->p_es, & tk->b_selected );
219 tk->b_selected = false;
222 while( !p_sys->b_eos && ( p_sys->i_sendtime - p_sys->i_time - CHUNK < 0 ||
223 ( p_sys->i_sendtime - p_sys->i_time - CHUNK ) <
224 p_sys->p_fp->i_preroll ) )
226 /* Read and demux a packet */
227 if( DemuxASFPacket( &p_sys->packet_sys,
228 p_sys->p_fp->i_min_data_packet_size,
229 p_sys->p_fp->i_max_data_packet_size,
230 p_sys->i_data_begin, p_sys->i_data_end ) <= 0 )
233 /* Check if we have concatenated files */
234 const uint8_t *p_peek;
235 if( vlc_stream_Peek( p_demux->s, &p_peek, 16 ) == 16 )
239 ASF_GetGUID( &guid, p_peek );
240 p_sys->b_eof = !guidcmp( &guid, &asf_object_header_guid );
242 msg_Warn( p_demux, "found a new ASF header" );
248 if ( p_sys->i_time == VLC_TICK_INVALID )
249 p_sys->i_time = p_sys->i_sendtime;
252 if( p_sys->b_eos || ( p_sys->i_sendtime - p_sys->i_time - CHUNK >= 0 &&
253 ( p_sys->i_sendtime - p_sys->i_time - CHUNK ) >=
254 p_sys->p_fp->i_preroll ) )
256 bool b_data = Block_Dequeue( p_demux, p_sys->i_time + CHUNK );
258 if( p_sys->i_time != VLC_TICK_INVALID )
260 p_sys->i_time += CHUNK;
261 p_sys->b_pcr_sent = true;
262 es_out_SetPCR( p_demux->out, p_sys->i_time );
264 msg_Dbg( p_demux, "Demux Loop Setting PCR to %"PRId64, p_sys->i_time );
268 if ( !b_data && p_sys->b_eos )
270 if( p_sys->i_time != VLC_TICK_INVALID )
271 es_out_SetPCR( p_demux->out, p_sys->i_time );
273 /* We end this stream */
278 /* And we prepare to read the next one */
279 if( DemuxInit( p_demux ) )
281 msg_Err( p_demux, "failed to load the new header" );
282 return VLC_DEMUXER_EOF;
284 es_out_Control( p_demux->out, ES_OUT_RESET_PCR );
287 return VLC_DEMUXER_EOF;
294 /*****************************************************************************
295 * Close: frees unused data
296 *****************************************************************************/
297 static void Close( vlc_object_t * p_this )
299 demux_t *p_demux = (demux_t *)p_this;
303 free( p_demux->p_sys );
306 /*****************************************************************************
307 * WaitKeyframe: computes the number of frames to wait for a keyframe
308 *****************************************************************************/
309 static void WaitKeyframe( demux_t *p_demux )
311 demux_sys_t *p_sys = p_demux->p_sys;
312 if ( ! p_sys->i_seek_track )
314 for ( int i=0; i<MAX_ASF_TRACKS; i++ )
316 asf_track_t *tk = p_sys->track[i];
317 if ( tk && tk->info.p_sp && tk->i_cat == VIDEO_ES && tk->b_selected )
319 p_sys->i_seek_track = tk->info.p_sp->i_stream_number;
325 if ( p_sys->i_seek_track )
327 /* Skip forward at least 1 min */
328 asf_track_t *tk = p_sys->track[p_sys->i_seek_track];
329 if ( tk->info.p_esp && tk->info.p_esp->i_average_time_per_frame )
331 /* 1 min if fastseek, otherwise 5 sec */
332 /* That's a guess for bandwidth */
333 msftime_t i_maxwaittime = MSFTIME_FROM_SEC( p_sys->b_canfastseek ? 60 : 5);
334 uint64_t frames = i_maxwaittime / tk->info.p_esp->i_average_time_per_frame;
335 p_sys->i_wait_keyframe = __MIN( frames, UINT_MAX );
339 p_sys->i_wait_keyframe = ( p_sys->b_canfastseek ) ? 25 * 30 : 25 * 5;
344 p_sys->i_wait_keyframe = 0;
349 /*****************************************************************************
350 * SeekIndex: goto to i_date or i_percent
351 *****************************************************************************/
352 static int SeekPercent( demux_t *p_demux, int i_query, va_list args )
354 demux_sys_t *p_sys = p_demux->p_sys;
356 WaitKeyframe( p_demux );
358 msg_Dbg( p_demux, "seek with percent: waiting %i frames", p_sys->i_wait_keyframe );
359 return demux_vaControlHelper( p_demux->s, __MIN( INT64_MAX, p_sys->i_data_begin ),
360 __MIN( INT64_MAX, p_sys->i_data_end ),
361 __MIN( INT64_MAX, p_sys->i_bitrate ),
362 __MIN( INT16_MAX, p_sys->p_fp->i_min_data_packet_size ),
366 static int SeekIndex( demux_t *p_demux, vlc_tick_t i_date, float f_pos )
368 demux_sys_t *p_sys = p_demux->p_sys;
369 asf_object_index_t *p_index;
371 msg_Dbg( p_demux, "seek with index: %i seconds, position %f",
372 i_date >= 0 ? (int)SEC_FROM_VLC_TICK(i_date) : -1, f_pos );
375 i_date = p_sys->i_length * f_pos;
377 p_sys->i_preroll_start = i_date - p_sys->p_fp->i_preroll;
378 if ( p_sys->i_preroll_start < 0 ) p_sys->i_preroll_start = 0;
380 p_index = ASF_FindObject( p_sys->p_root, &asf_object_simple_index_guid, 0 );
382 uint64_t i_entry = MSFTIME_FROM_VLC_TICK(p_sys->i_preroll_start) / p_index->i_index_entry_time_interval;
383 if( i_entry >= p_index->i_index_entry_count )
385 msg_Warn( p_demux, "Incomplete index" );
389 WaitKeyframe( p_demux );
391 uint64_t i_offset = (uint64_t)p_index->index_entry[i_entry].i_packet_number *
392 p_sys->p_fp->i_min_data_packet_size;
394 if ( vlc_stream_Seek( p_demux->s, i_offset + p_sys->i_data_begin ) == VLC_SUCCESS )
396 es_out_Control( p_demux->out, ES_OUT_SET_NEXT_DISPLAY_TIME, VLC_TICK_0 + i_date );
399 else return VLC_EGENERIC;
402 static void SeekPrepare( demux_t *p_demux )
404 demux_sys_t *p_sys = p_demux->p_sys;
406 p_sys->b_eof = false;
407 p_sys->b_eos = false;
408 p_sys->b_pcr_sent = false;
409 p_sys->i_time = VLC_TICK_INVALID;
410 p_sys->i_sendtime = VLC_TICK_INVALID;
411 p_sys->i_preroll_start = ASFPACKET_PREROLL_FROM_CURRENT;
413 for( int i = 0; i < MAX_ASF_TRACKS ; i++ )
415 asf_track_t *tk = p_sys->track[i];
419 tk->i_time = VLC_TICK_INVALID;
423 es_out_Control( p_demux->out, ES_OUT_RESET_PCR );
426 /*****************************************************************************
428 *****************************************************************************/
429 static int Control( demux_t *p_demux, int i_query, va_list args )
431 demux_sys_t *p_sys = p_demux->p_sys;
439 case DEMUX_GET_LENGTH:
440 *va_arg( args, vlc_tick_t * ) = p_sys->i_length;
444 if( p_sys->i_time == VLC_TICK_INVALID ) return VLC_EGENERIC;
445 *va_arg( args, vlc_tick_t * ) = p_sys->i_time;
450 ! ( p_sys->p_fp->i_flags & ASF_FILE_PROPERTIES_SEEKABLE ) )
453 SeekPrepare( p_demux );
455 if( p_sys->b_index && p_sys->i_length != 0 )
458 va_copy( acpy, args );
459 i64 = va_arg( acpy, vlc_tick_t );
462 if( !SeekIndex( p_demux, i64, -1 ) )
465 return SeekPercent( p_demux, i_query, args );
469 i = va_arg( args, int );
473 msg_Dbg( p_demux, "Requesting access to enable stream %d", i );
474 i_ret = vlc_stream_Control( p_demux->s,
475 STREAM_SET_PRIVATE_ID_STATE, i, true );
478 { /* i contains -1 * es_category */
479 msg_Dbg( p_demux, "Requesting access to disable stream %d", i );
480 i_ret = vlc_stream_Control( p_demux->s,
481 STREAM_SET_PRIVATE_ID_STATE, i,
485 if ( i_ret == VLC_SUCCESS )
490 tk = p_sys->track[i];
494 for( int j = 0; j < MAX_ASF_TRACKS ; j++ )
496 tk = p_sys->track[j];
497 if( !tk || !tk->p_fmt || tk->i_cat != -1 * i )
500 tk->i_time = VLC_TICK_INVALID;
504 p_sys->i_seek_track = 0;
505 if ( ( tk && tk->i_cat == VIDEO_ES ) || i == -1 * VIDEO_ES )
506 WaitKeyframe( p_demux );
511 case DEMUX_SET_ES_LIST:
512 return VLC_EGENERIC; /* TODO */
514 case DEMUX_GET_POSITION:
515 if( p_sys->i_time == VLC_TICK_INVALID ) return VLC_EGENERIC;
516 if( p_sys->i_length != 0 )
518 pf = va_arg( args, double * );
519 *pf = p_sys->i_time / (double)p_sys->i_length;
522 return demux_vaControlHelper( p_demux->s,
523 __MIN( INT64_MAX, p_sys->i_data_begin ),
524 __MIN( INT64_MAX, p_sys->i_data_end ),
525 __MIN( INT64_MAX, p_sys->i_bitrate ),
526 __MIN( INT16_MAX, p_sys->p_fp->i_min_data_packet_size ),
529 case DEMUX_SET_POSITION:
531 ( !( p_sys->p_fp->i_flags & ASF_FILE_PROPERTIES_SEEKABLE ) && !p_sys->b_index ) )
534 SeekPrepare( p_demux );
536 if( p_sys->b_index && p_sys->i_length != 0 )
539 va_copy( acpy, args );
540 f = va_arg( acpy, double );
543 if( !SeekIndex( p_demux, -1, f ) )
546 return SeekPercent( p_demux, i_query, args );
549 p_meta = va_arg( args, vlc_meta_t * );
550 vlc_meta_Merge( p_meta, p_sys->meta );
555 ( !( p_sys->p_fp->i_flags & ASF_FILE_PROPERTIES_SEEKABLE ) && !p_sys->b_index ) )
557 bool *pb_bool = va_arg( args, bool * );
563 return demux_vaControlHelper( p_demux->s,
564 __MIN( INT64_MAX, p_sys->i_data_begin ),
565 __MIN( INT64_MAX, p_sys->i_data_end),
566 __MIN( INT64_MAX, p_sys->i_bitrate ),
567 ( p_sys->p_fp ) ? __MIN( INT_MAX, p_sys->p_fp->i_min_data_packet_size ) : 1,
572 /*****************************************************************************
574 *****************************************************************************/
575 static void Packet_SetAR( asf_packet_sys_t *p_packetsys, uint8_t i_stream_number,
576 uint8_t i_ratio_x, uint8_t i_ratio_y )
578 demux_t *p_demux = p_packetsys->priv;
579 demux_sys_t *p_sys = p_demux->p_sys;
580 asf_track_t *tk = p_sys->track[i_stream_number];
582 if ( !tk->p_fmt || (tk->p_fmt->video.i_sar_num == i_ratio_x && tk->p_fmt->video.i_sar_den == i_ratio_y ) )
585 tk->p_fmt->video.i_sar_num = i_ratio_x;
586 tk->p_fmt->video.i_sar_den = i_ratio_y;
588 es_out_Control( p_demux->out, ES_OUT_SET_ES_FMT, tk->p_es, tk->p_fmt );
591 static void Packet_SetSendTime( asf_packet_sys_t *p_packetsys, vlc_tick_t i_time )
593 demux_t *p_demux = p_packetsys->priv;
594 demux_sys_t *p_sys = p_demux->p_sys;
596 p_sys->i_sendtime = VLC_TICK_0 + i_time;
599 static void Packet_UpdateTime( asf_packet_sys_t *p_packetsys, uint8_t i_stream_number,
602 demux_t *p_demux = p_packetsys->priv;
603 demux_sys_t *p_sys = p_demux->p_sys;
604 asf_track_t *tk = p_sys->track[i_stream_number];
607 tk->i_time = VLC_TICK_0 + i_time;
610 static asf_track_info_t * Packet_GetTrackInfo( asf_packet_sys_t *p_packetsys,
611 uint8_t i_stream_number )
613 demux_t *p_demux = p_packetsys->priv;
614 demux_sys_t *p_sys = p_demux->p_sys;
615 asf_track_t *tk = p_sys->track[i_stream_number];
623 static bool Packet_DoSkip( asf_packet_sys_t *p_packetsys, uint8_t i_stream_number, bool b_packet_keyframe )
625 demux_t *p_demux = p_packetsys->priv;
626 demux_sys_t *p_sys = p_demux->p_sys;
627 const asf_track_t *tk = p_sys->track[i_stream_number];
631 msg_Warn( p_demux, "undeclared stream[Id 0x%x]", i_stream_number );
635 if( p_sys->i_wait_keyframe )
637 if ( i_stream_number == p_sys->i_seek_track )
639 if ( !b_packet_keyframe )
641 p_sys->i_wait_keyframe--;
645 p_sys->i_wait_keyframe = 0;
657 static void Packet_Enqueue( asf_packet_sys_t *p_packetsys, uint8_t i_stream_number, block_t **pp_frame )
659 demux_t *p_demux = p_packetsys->priv;
660 demux_sys_t *p_sys = p_demux->p_sys;
661 asf_track_t *tk = p_sys->track[i_stream_number];
665 block_t *p_gather = block_ChainGather( *pp_frame );
668 block_ChainLastAppend( & tk->queue.pp_last, p_gather );
670 msg_Dbg( p_demux, " enqueue packet dts %"PRId64" pts %"PRId64" pcr %"PRId64, p_gather->i_dts, p_gather->i_pts, p_sys->i_time );
677 static bool Block_Dequeue( demux_t *p_demux, vlc_tick_t i_nexttime )
679 demux_sys_t *p_sys = p_demux->p_sys;
680 bool b_tracks_have_data = false;
681 for( int i = 0; i < MAX_ASF_TRACKS; i++ )
683 asf_track_t *tk = p_sys->track[i];
686 b_tracks_have_data |= (tk->queue.p_first != NULL);
687 while( tk->queue.p_first && tk->queue.p_first->i_dts <= i_nexttime )
689 block_t *p_block = tk->queue.p_first;
690 tk->queue.p_first = p_block->p_next;
691 if( tk->queue.p_first == NULL )
692 tk->queue.pp_last = &tk->queue.p_first;
694 p_block->p_next = NULL;
696 if( !p_sys->b_pcr_sent && p_sys->i_time != VLC_TICK_INVALID )
698 p_sys->b_pcr_sent = true;
699 es_out_SetPCR( p_demux->out, p_sys->i_time );
701 msg_Dbg( p_demux, " dequeue setting PCR to %"PRId64, p_sys->i_time );
706 msg_Dbg( p_demux, " sending packet dts %"PRId64" pts %"PRId64" pcr %"PRId64, p_block->i_dts, p_block->i_pts, p_sys->i_time );
708 es_out_Send( p_demux->out, tk->p_es, p_block );
711 return b_tracks_have_data;
714 /*****************************************************************************
716 *****************************************************************************/
717 typedef struct asf_es_priorities_t
719 uint16_t *pi_stream_numbers;
721 } asf_es_priorities_t;
723 /* Fills up our exclusion list */
724 static void ASF_fillup_es_priorities_ex( demux_sys_t *p_sys, void *p_hdr,
725 asf_es_priorities_t *p_prios )
727 /* Find stream exclusions */
728 asf_object_advanced_mutual_exclusion_t *p_mutex =
729 ASF_FindObject( p_hdr, &asf_object_advanced_mutual_exclusion, 0 );
730 if (! p_mutex ) return;
732 #if ( UINT_MAX > SIZE_MAX / 2 )
733 if ( p_sys->i_track > (size_t)SIZE_MAX / sizeof(uint16_t) )
736 p_prios->pi_stream_numbers = vlc_alloc( p_sys->i_track, sizeof(uint16_t) );
737 if ( !p_prios->pi_stream_numbers ) return;
739 if ( p_mutex->i_stream_number_count )
741 /* Just set highest prio on highest in the group */
742 for ( uint16_t i = 1; i < p_mutex->i_stream_number_count; i++ )
744 if ( p_prios->i_count > p_sys->i_track || i > p_sys->i_track ) break;
745 p_prios->pi_stream_numbers[ p_prios->i_count++ ] = p_mutex->pi_stream_number[ i ];
750 /* Fills up our bitrate exclusion list */
751 static void ASF_fillup_es_bitrate_priorities_ex( demux_sys_t *p_sys, void *p_hdr,
752 asf_es_priorities_t *p_prios )
754 /* Find bitrate exclusions */
755 asf_object_bitrate_mutual_exclusion_t *p_bitrate_mutex =
756 ASF_FindObject( p_hdr, &asf_object_bitrate_mutual_exclusion_guid, 0 );
757 if (! p_bitrate_mutex ) return;
759 #if ( UINT_MAX > SIZE_MAX / 2 )
760 if ( p_sys->i_track > (size_t)SIZE_MAX / sizeof(uint16_t) )
763 p_prios->pi_stream_numbers = vlc_alloc( p_sys->i_track, sizeof( uint16_t ) );
764 if ( !p_prios->pi_stream_numbers ) return;
766 if ( p_bitrate_mutex->i_stream_number_count )
768 /* Just remove < highest */
769 for ( uint16_t i = 1; i < p_bitrate_mutex->i_stream_number_count; i++ )
771 if ( p_prios->i_count > p_sys->i_track || i > p_sys->i_track ) break;
772 p_prios->pi_stream_numbers[ p_prios->i_count++ ] = p_bitrate_mutex->pi_stream_numbers[ i ];
778 #define GET_CHECKED( target, getter, maxtarget, temp ) \
780 temp i_temp = getter;\
781 if ( i_temp > maxtarget ) {\
782 msg_Warn( p_demux, "rejecting stream %u : " #target " overflow", i_stream );\
783 es_format_Clean( &fmt );\
790 static int DemuxInit( demux_t *p_demux )
792 demux_sys_t *p_sys = p_demux->p_sys;
795 p_sys->i_time = VLC_TICK_INVALID;
796 p_sys->i_sendtime = VLC_TICK_INVALID;
798 p_sys->b_eos = false;
799 p_sys->b_eof = false;
800 p_sys->i_bitrate = 0;
801 p_sys->p_root = NULL;
805 p_sys->i_seek_track = 0;
806 p_sys->b_pcr_sent = false;
807 p_sys->i_wait_keyframe = 0;
808 for( int i = 0; i < MAX_ASF_TRACKS; i++ )
810 p_sys->track[i] = NULL;
812 p_sys->i_data_begin = 0;
813 p_sys->i_data_end = 0;
814 p_sys->i_preroll_start = 0;
817 /* Now load all object ( except raw data ) */
818 vlc_stream_Control( p_demux->s, STREAM_CAN_FASTSEEK,
819 &p_sys->b_canfastseek );
820 if( !(p_sys->p_root = ASF_ReadObjectRoot(p_demux->s, p_sys->b_canfastseek)) )
822 msg_Warn( p_demux, "ASF plugin discarded (not a valid file)" );
825 p_sys->p_fp = p_sys->p_root->p_fp;
827 if( p_sys->p_fp->i_min_data_packet_size != p_sys->p_fp->i_max_data_packet_size )
829 msg_Warn( p_demux, "ASF plugin discarded (invalid file_properties object)" );
833 if ( ASF_FindObject( p_sys->p_root->p_hdr,
834 &asf_object_content_encryption_guid, 0 ) != NULL
835 || ASF_FindObject( p_sys->p_root->p_hdr,
836 &asf_object_extended_content_encryption_guid, 0 ) != NULL
837 || ASF_FindObject( p_sys->p_root->p_hdr,
838 &asf_object_advanced_content_encryption_guid, 0 ) != NULL )
840 vlc_dialog_display_error( p_demux, _("Could not demux ASF stream"), "%s",
841 ("DRM protected streams are not supported.") );
845 p_sys->i_track = ASF_CountObject( p_sys->p_root->p_hdr,
846 &asf_object_stream_properties_guid );
847 if( p_sys->i_track == 0 )
849 msg_Warn( p_demux, "ASF plugin discarded (cannot find any stream!)" );
852 msg_Dbg( p_demux, "found %u streams", p_sys->i_track );
854 /* check if index is available */
855 asf_object_index_t *p_index = ASF_FindObject( p_sys->p_root,
856 &asf_object_simple_index_guid, 0 );
857 const bool b_index = p_index && p_index->i_index_entry_count;
859 /* Find the extended header if any */
860 asf_object_t *p_hdr_ext = ASF_FindObject( p_sys->p_root->p_hdr,
861 &asf_object_header_extension_guid, 0 );
863 asf_object_language_list_t *p_languages = NULL;
864 asf_es_priorities_t fmt_priorities_ex = { NULL, 0 };
865 asf_es_priorities_t fmt_priorities_bitrate_ex = { NULL, 0 };
869 p_languages = ASF_FindObject( p_hdr_ext, &asf_object_language_list, 0 );
871 ASF_fillup_es_priorities_ex( p_sys, p_hdr_ext, &fmt_priorities_ex );
872 ASF_fillup_es_bitrate_priorities_ex( p_sys, p_hdr_ext, &fmt_priorities_bitrate_ex );
875 const bool b_mms = !strncasecmp( p_demux->psz_url, "mms:", 4 );
876 bool b_dvrms = false;
880 es_out_Control( p_demux->out, ES_OUT_SET_ES_CAT_POLICY,
881 VIDEO_ES, ES_OUT_ES_POLICY_EXCLUSIVE );
884 for( unsigned i_stream = 0; i_stream < p_sys->i_track; i_stream++ )
887 asf_object_stream_properties_t *p_sp;
888 asf_object_extended_stream_properties_t *p_esp;
889 bool b_access_selected;
891 p_sp = ASF_FindObject( p_sys->p_root->p_hdr,
892 &asf_object_stream_properties_guid,
896 /* Ignore duplicated streams numbers */
897 if (p_sys->track[p_sp->i_stream_number])
900 tk = p_sys->track[p_sp->i_stream_number] = malloc( sizeof( asf_track_t ) );
903 memset( tk, 0, sizeof( asf_track_t ) );
905 ASFPacketTrackInit( &tk->info );
906 tk->i_time = VLC_TICK_INVALID;
907 tk->info.p_sp = p_sp;
909 tk->queue.p_first = NULL;
910 tk->queue.pp_last = &tk->queue.p_first;
912 tk->info.i_pktcount = 0;
916 /* Check (not mms) if this track is selected (ie will receive data) */
917 if( !vlc_stream_Control( p_demux->s, STREAM_GET_PRIVATE_ID_STATE,
918 (int) p_sp->i_stream_number,
919 &b_access_selected ) &&
922 tk->i_cat = UNKNOWN_ES;
923 msg_Dbg( p_demux, "ignoring not selected stream(ID:%u) (by access)",
924 p_sp->i_stream_number );
929 /* Find the associated extended_stream_properties if any */
932 int i_ext_stream = ASF_CountObject( p_hdr_ext,
933 &asf_object_extended_stream_properties_guid );
934 for( int i = 0; i < i_ext_stream; i++ )
936 asf_object_t *p_tmp =
937 ASF_FindObject( p_hdr_ext,
938 &asf_object_extended_stream_properties_guid, i );
939 if( p_tmp->ext_stream.i_stream_number == p_sp->i_stream_number )
941 p_esp = &p_tmp->ext_stream;
942 tk->info.p_esp = p_esp;
948 /* Check for DVR-MS */
950 for( uint16_t i=0; i<p_esp->i_payload_extension_system_count && !b_dvrms; i++ )
951 b_dvrms = guidcmp( &p_esp->p_ext[i].i_extension_id, &asf_dvr_sampleextension_timing_rep_data_guid );
955 if( guidcmp( &p_sp->i_stream_type, &asf_object_stream_type_audio ) &&
956 p_sp->i_type_specific_data_length >= sizeof( WAVEFORMATEX ) - 2 )
958 uint8_t *p_data = p_sp->p_type_specific_data;
961 es_format_Init( &fmt, AUDIO_ES, 0 );
962 i_format = GetWLE( &p_data[0] );
963 wf_tag_to_fourcc( i_format, &fmt.i_codec, NULL );
965 GET_CHECKED( fmt.audio.i_channels, GetWLE( &p_data[2] ),
967 GET_CHECKED( fmt.audio.i_rate, GetDWLE( &p_data[4] ),
968 UINT_MAX, uint32_t );
969 GET_CHECKED( fmt.i_bitrate, GetDWLE( &p_data[8] ) * 8,
970 UINT_MAX, uint32_t );
971 fmt.audio.i_blockalign = GetWLE( &p_data[12] );
972 fmt.audio.i_bitspersample = GetWLE( &p_data[14] );
974 if( p_sp->i_type_specific_data_length > sizeof( WAVEFORMATEX ) &&
975 i_format != WAVE_FORMAT_MPEGLAYER3 &&
976 i_format != WAVE_FORMAT_MPEG )
978 GET_CHECKED( fmt.i_extra, __MIN( GetWLE( &p_data[16] ),
979 p_sp->i_type_specific_data_length -
980 sizeof( WAVEFORMATEX ) ),
982 fmt.p_extra = malloc( fmt.i_extra );
983 memcpy( fmt.p_extra, &p_data[sizeof( WAVEFORMATEX )],
986 msg_Dbg( p_demux, "added new audio stream (codec:%4.4s(0x%x),ID:%d)",
987 (char*)&fmt.i_codec, GetWLE( p_data ), p_sp->i_stream_number );
989 else if( guidcmp( &p_sp->i_stream_type,
990 &asf_object_stream_type_video ) &&
991 p_sp->i_type_specific_data_length >= 11 +
992 sizeof( VLC_BITMAPINFOHEADER ) )
994 uint8_t *p_data = &p_sp->p_type_specific_data[11];
996 es_format_Init( &fmt, VIDEO_ES,
997 VLC_FOURCC( p_data[16], p_data[17],
998 p_data[18], p_data[19] ) );
1000 GET_CHECKED( fmt.video.i_width, GetDWLE( p_data + 4 ),
1001 UINT_MAX, uint32_t );
1002 GET_CHECKED( fmt.video.i_height, GetDWLE( p_data + 8 ),
1003 UINT_MAX, uint32_t );
1004 fmt.video.i_visible_width = fmt.video.i_width;
1005 fmt.video.i_visible_height = fmt.video.i_height;
1007 if( p_esp && p_esp->i_average_time_per_frame > 0 )
1009 fmt.video.i_frame_rate = 10000000;
1010 GET_CHECKED( fmt.video.i_frame_rate_base,
1011 p_esp->i_average_time_per_frame,
1012 UINT_MAX, uint64_t );
1015 if( fmt.i_codec == VLC_FOURCC( 'D','V','R',' ') )
1017 /* DVR-MS special ASF */
1018 fmt.i_codec = VLC_CODEC_MPGV;
1021 if( p_sp->i_type_specific_data_length > 11 +
1022 sizeof( VLC_BITMAPINFOHEADER ) )
1024 GET_CHECKED( fmt.i_extra, __MIN( GetDWLE( p_data ),
1025 p_sp->i_type_specific_data_length - 11 -
1026 sizeof( VLC_BITMAPINFOHEADER ) ),
1027 UINT_MAX, uint32_t );
1028 fmt.p_extra = malloc( fmt.i_extra );
1029 memcpy( fmt.p_extra, &p_data[sizeof( VLC_BITMAPINFOHEADER )],
1033 /* Look for an aspect ratio */
1034 if( p_sys->p_root->p_metadata )
1036 asf_object_metadata_t *p_meta = p_sys->p_root->p_metadata;
1037 unsigned int i_aspect_x = 0, i_aspect_y = 0;
1039 for( i = 0; i < p_meta->i_record_entries_count; i++ )
1041 if( !p_meta->record[i].psz_name )
1043 if( !strcmp( p_meta->record[i].psz_name, "AspectRatioX" ) )
1045 if( (!i_aspect_x && !p_meta->record[i].i_stream) ||
1046 p_meta->record[i].i_stream ==
1047 p_sp->i_stream_number )
1048 GET_CHECKED( i_aspect_x, p_meta->record[i].i_val,
1049 UINT_MAX, uint64_t );
1051 if( !strcmp( p_meta->record[i].psz_name, "AspectRatioY" ) )
1053 if( (!i_aspect_y && !p_meta->record[i].i_stream) ||
1054 p_meta->record[i].i_stream ==
1055 p_sp->i_stream_number )
1056 GET_CHECKED( i_aspect_y, p_meta->record[i].i_val,
1057 UINT_MAX, uint64_t );
1061 if( i_aspect_x && i_aspect_y )
1063 fmt.video.i_sar_num = i_aspect_x;
1064 fmt.video.i_sar_den = i_aspect_y;
1068 /* If there is a video track then use the index for seeking */
1069 p_sys->b_index = b_index;
1071 msg_Dbg( p_demux, "added new video stream(codec:%4.4s,ID:%d)",
1072 (char*)&fmt.i_codec, p_sp->i_stream_number );
1074 else if( guidcmp( &p_sp->i_stream_type, &asf_object_stream_type_binary ) &&
1075 p_sp->i_type_specific_data_length >= 64 )
1077 vlc_guid_t i_major_media_type;
1078 ASF_GetGUID( &i_major_media_type, p_sp->p_type_specific_data );
1079 msg_Dbg( p_demux, "stream(ID:%d) major type " GUID_FMT, p_sp->i_stream_number,
1080 GUID_PRINT(i_major_media_type) );
1082 vlc_guid_t i_media_subtype;
1083 ASF_GetGUID( &i_media_subtype, &p_sp->p_type_specific_data[16] );
1084 msg_Dbg( p_demux, "stream(ID:%d) subtype " GUID_FMT, p_sp->i_stream_number,
1085 GUID_PRINT(i_media_subtype) );
1087 //uint32_t i_fixed_size_samples = GetDWBE( &p_sp->p_type_specific_data[32] );
1088 //uint32_t i_temporal_compression = GetDWBE( &p_sp->p_type_specific_data[36] );
1089 //uint32_t i_sample_size = GetDWBE( &p_sp->p_type_specific_data[40] );
1091 vlc_guid_t i_format_type;
1092 ASF_GetGUID( &i_format_type, &p_sp->p_type_specific_data[44] );
1093 msg_Dbg( p_demux, "stream(ID:%d) format type " GUID_FMT, p_sp->i_stream_number,
1094 GUID_PRINT(i_format_type) );
1096 //uint32_t i_format_data_size = GetDWBE( &p_sp->p_type_specific_data[60] );
1097 uint8_t *p_data = p_sp->p_type_specific_data + 64;
1098 unsigned int i_data = p_sp->i_type_specific_data_length - 64;
1100 msg_Dbg( p_demux, "Ext stream header detected. datasize = %d", p_sp->i_type_specific_data_length );
1101 if( guidcmp( &i_major_media_type, &asf_object_extended_stream_type_audio ) &&
1102 i_data >= sizeof( WAVEFORMATEX ) - 2)
1105 es_format_Init( &fmt, AUDIO_ES, 0 );
1107 i_format = GetWLE( &p_data[0] );
1109 fmt.i_codec = VLC_CODEC_A52;
1111 wf_tag_to_fourcc( i_format, &fmt.i_codec, NULL );
1113 GET_CHECKED( fmt.audio.i_channels, GetWLE( &p_data[2] ),
1115 GET_CHECKED( fmt.audio.i_rate, GetDWLE( &p_data[4] ),
1116 UINT_MAX, uint32_t );
1117 GET_CHECKED( fmt.i_bitrate, GetDWLE( &p_data[8] ) * 8,
1118 UINT_MAX, uint32_t );
1119 fmt.audio.i_blockalign = GetWLE( &p_data[12] );
1120 fmt.audio.i_bitspersample = GetWLE( &p_data[14] );
1122 if( p_sp->i_type_specific_data_length > sizeof( WAVEFORMATEX ) &&
1123 i_format != WAVE_FORMAT_MPEGLAYER3 &&
1124 i_format != WAVE_FORMAT_MPEG && i_data >= 19 )
1126 GET_CHECKED( fmt.i_extra, __MIN( GetWLE( &p_data[16] ),
1127 p_sp->i_type_specific_data_length -
1128 sizeof( WAVEFORMATEX ) - 64),
1129 INT_MAX, uint32_t );
1130 fmt.p_extra = malloc( fmt.i_extra );
1132 memcpy( fmt.p_extra, &p_data[sizeof( WAVEFORMATEX )], fmt.i_extra );
1137 msg_Dbg( p_demux, "added new audio stream (codec:%4.4s(0x%x),ID:%d)",
1138 (char*)&fmt.i_codec, i_format, p_sp->i_stream_number );
1142 es_format_Init( &fmt, UNKNOWN_ES, 0 );
1147 es_format_Init( &fmt, UNKNOWN_ES, 0 );
1152 fmt.i_original_fourcc = VLC_FOURCC( 'D','V','R',' ');
1153 fmt.b_packetized = false;
1156 if( fmt.i_codec == VLC_CODEC_MP4A )
1157 fmt.b_packetized = false;
1159 tk->i_cat = tk->info.i_cat = fmt.i_cat;
1160 if( fmt.i_cat != UNKNOWN_ES )
1162 if( p_esp && p_languages &&
1163 p_esp->i_language_index < p_languages->i_language &&
1164 p_languages->ppsz_language[p_esp->i_language_index] )
1166 fmt.psz_language = strdup( p_languages->ppsz_language[p_esp->i_language_index] );
1168 if( fmt.psz_language && (p = strchr( fmt.psz_language, '-' )) )
1172 /* Set our priority so we won't get multiple videos */
1173 int i_priority = ES_PRIORITY_SELECTABLE_MIN;
1174 for( uint16_t i = 0; i < fmt_priorities_ex.i_count; i++ )
1176 if ( fmt_priorities_ex.pi_stream_numbers[i] == p_sp->i_stream_number )
1178 i_priority = ES_PRIORITY_NOT_DEFAULTABLE;
1182 for( uint16_t i = 0; i < fmt_priorities_bitrate_ex.i_count; i++ )
1184 if ( fmt_priorities_bitrate_ex.pi_stream_numbers[i] == p_sp->i_stream_number )
1186 i_priority = ES_PRIORITY_NOT_DEFAULTABLE;
1190 fmt.i_priority = i_priority;
1192 if ( i_stream <= INT_MAX )
1193 fmt.i_id = i_stream;
1195 msg_Warn( p_demux, "Can't set fmt.i_id to match stream id %u", i_stream );
1197 if ( fmt.i_cat == VIDEO_ES )
1199 /* Backup our video format */
1200 tk->p_fmt = malloc( sizeof( es_format_t ) );
1202 es_format_Copy( tk->p_fmt, &fmt );
1205 fmt.i_id = tk->info.p_sp->i_stream_number;
1207 tk->p_es = es_out_Add( p_demux->out, &fmt );
1209 if( !vlc_stream_Control( p_demux->s, STREAM_GET_PRIVATE_ID_STATE,
1210 (int) p_sp->i_stream_number,
1211 &b_access_selected ) &&
1214 p_sys->i_access_selected_track[fmt.i_cat] = p_sp->i_stream_number;
1220 msg_Dbg( p_demux, "ignoring unknown stream(ID:%d)",
1221 p_sp->i_stream_number );
1224 es_format_Clean( &fmt );
1227 free( fmt_priorities_ex.pi_stream_numbers );
1228 free( fmt_priorities_bitrate_ex.pi_stream_numbers );
1230 p_sys->i_data_begin = p_sys->p_root->p_data->i_object_pos + 50;
1231 if( p_sys->p_root->p_data->i_object_size != 0 )
1233 p_sys->i_data_end = p_sys->p_root->p_data->i_object_pos +
1234 p_sys->p_root->p_data->i_object_size;
1235 p_sys->i_data_end = __MIN( (uint64_t)stream_Size( p_demux->s ), p_sys->i_data_end );
1238 { /* live/broacast */
1239 p_sys->i_data_end = 0;
1242 /* go to first packet */
1243 if( vlc_stream_Seek( p_demux->s, p_sys->i_data_begin ) != VLC_SUCCESS )
1246 /* try to calculate movie time */
1247 if( p_sys->p_fp->i_data_packets_count > 0 )
1250 uint64_t i_size = stream_Size( p_demux->s );
1252 if( p_sys->i_data_end > 0 && i_size > p_sys->i_data_end )
1254 i_size = p_sys->i_data_end;
1257 /* real number of packets */
1258 i_count = ( i_size - p_sys->i_data_begin ) /
1259 p_sys->p_fp->i_min_data_packet_size;
1261 /* calculate the time duration in micro-s */
1262 p_sys->i_length = VLC_TICK_FROM_MSFTIME(p_sys->p_fp->i_play_duration) *
1263 (vlc_tick_t)i_count /
1264 (vlc_tick_t)p_sys->p_fp->i_data_packets_count;
1265 if( p_sys->i_length <= p_sys->p_fp->i_preroll )
1266 p_sys->i_length = 0;
1269 p_sys->i_length -= p_sys->p_fp->i_preroll;
1270 p_sys->i_bitrate = 8 * i_size * CLOCK_FREQ / p_sys->i_length;
1274 /* Create meta information */
1275 p_sys->meta = vlc_meta_New();
1277 asf_object_content_description_t *p_cd;
1278 if( ( p_cd = ASF_FindObject( p_sys->p_root->p_hdr,
1279 &asf_object_content_description_guid, 0 ) ) )
1281 if( p_cd->psz_title && *p_cd->psz_title )
1283 vlc_meta_SetTitle( p_sys->meta, p_cd->psz_title );
1285 if( p_cd->psz_artist && *p_cd->psz_artist )
1287 vlc_meta_SetArtist( p_sys->meta, p_cd->psz_artist );
1289 if( p_cd->psz_copyright && *p_cd->psz_copyright )
1291 vlc_meta_SetCopyright( p_sys->meta, p_cd->psz_copyright );
1293 if( p_cd->psz_description && *p_cd->psz_description )
1295 vlc_meta_SetDescription( p_sys->meta, p_cd->psz_description );
1297 if( p_cd->psz_rating && *p_cd->psz_rating )
1299 vlc_meta_SetRating( p_sys->meta, p_cd->psz_rating );
1302 asf_object_extended_content_description_t *p_ecd;
1303 if( ( p_ecd = ASF_FindObject( p_sys->p_root->p_hdr,
1304 &asf_object_extended_content_description, 0 ) ) )
1306 for( int i = 0; i < p_ecd->i_count; i++ )
1309 #define set_meta( name, vlc_type ) \
1310 if( p_ecd->ppsz_name[i] && !strncmp( p_ecd->ppsz_name[i], name, strlen(name) ) ) \
1311 vlc_meta_Set( p_sys->meta, vlc_type, p_ecd->ppsz_value[i] );
1313 set_meta( "WM/AlbumTitle", vlc_meta_Album )
1314 else set_meta( "WM/TrackNumber", vlc_meta_TrackNumber )
1315 else set_meta( "WM/Year", vlc_meta_Date )
1316 else set_meta( "WM/Genre", vlc_meta_Genre )
1317 else set_meta( "WM/Genre", vlc_meta_Genre )
1318 else set_meta( "WM/AlbumArtist", vlc_meta_AlbumArtist )
1319 else set_meta( "WM/Publisher", vlc_meta_Publisher )
1320 else set_meta( "WM/PartOfSet", vlc_meta_DiscNumber )
1321 else if( p_ecd->ppsz_value[i] != NULL && p_ecd->ppsz_name[i] &&
1322 *p_ecd->ppsz_value[i] != '\0' && /* no empty value */
1323 *p_ecd->ppsz_value[i] != '{' && /* no guid value */
1324 *p_ecd->ppsz_name[i] != '{' ) /* no guid name */
1325 vlc_meta_AddExtra( p_sys->meta, p_ecd->ppsz_name[i], p_ecd->ppsz_value[i] );
1326 /* TODO map WM/Composer, WM/Provider, WM/PartOfSet, PeakValue, AverageLevel */
1331 /// \tood Fix Child meta for ASF tracks
1333 for( i_stream = 0, i = 0; i < MAX_ASF_TRACKS; i++ )
1335 asf_object_codec_list_t *p_cl = ASF_FindObject( p_sys->p_root->p_hdr,
1336 &asf_object_codec_list_guid, 0 );
1338 if( p_sys->track[i] )
1340 vlc_meta_t *tk = vlc_meta_New();
1341 TAB_APPEND( p_sys->meta->i_track, p_sys->meta->track, tk );
1343 if( p_cl && i_stream < p_cl->i_codec_entries_count )
1345 if( p_cl->codec[i_stream].psz_name &&
1346 *p_cl->codec[i_stream].psz_name )
1348 vlc_meta_Add( tk, VLC_META_CODEC_NAME,
1349 p_cl->codec[i_stream].psz_name );
1351 if( p_cl->codec[i_stream].psz_description &&
1352 *p_cl->codec[i_stream].psz_description )
1354 vlc_meta_Add( tk, VLC_META_CODEC_DESCRIPTION,
1355 p_cl->codec[i_stream].psz_description );
1363 p_sys->packet_sys.pi_preroll = &p_sys->p_fp->i_preroll;
1364 p_sys->packet_sys.pi_preroll_start = &p_sys->i_preroll_start;
1365 p_sys->packet_sys.b_can_hold_multiple_packets = false;
1370 DemuxEnd( p_demux );
1371 return VLC_EGENERIC;
1374 /*****************************************************************************
1375 * FlushQueues: flushes tail packets and send queues
1376 *****************************************************************************/
1377 static void FlushQueue( asf_track_t *tk )
1379 ASFPacketTrackReset( &tk->info );
1380 if( tk->queue.p_first )
1382 block_ChainRelease( tk->queue.p_first );
1383 tk->queue.p_first = NULL;
1384 tk->queue.pp_last = &tk->queue.p_first;
1388 static void FlushQueues( demux_t *p_demux )
1390 demux_sys_t *p_sys = p_demux->p_sys;
1391 for ( unsigned int i = 0; i < MAX_ASF_TRACKS; i++ )
1393 asf_track_t *tk = p_sys->track[i];
1400 /*****************************************************************************
1402 *****************************************************************************/
1403 static void DemuxEnd( demux_t *p_demux )
1405 demux_sys_t *p_sys = p_demux->p_sys;
1409 ASF_FreeObjectRoot( p_demux->s, p_sys->p_root );
1410 p_sys->p_root = NULL;
1415 vlc_meta_Delete( p_sys->meta );
1419 FlushQueues( p_demux );
1421 for( int i = 0; i < MAX_ASF_TRACKS; i++ )
1423 asf_track_t *tk = p_sys->track[i];
1429 es_out_Del( p_demux->out, tk->p_es );
1433 es_format_Clean( tk->p_fmt );
1438 p_sys->track[i] = 0;