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 */
45 * - add support for the newly added object: language, bitrate,
46 * extended stream properties.
49 /*****************************************************************************
51 *****************************************************************************/
52 static int Open ( vlc_object_t * );
53 static void Close ( vlc_object_t * );
56 set_category( CAT_INPUT )
57 set_subcategory( SUBCAT_INPUT_DEMUX )
58 set_description( N_("ASF/WMV demuxer") )
59 set_capability( "demux", 200 )
60 set_callbacks( Open, Close )
61 add_shortcut( "asf", "wmv" )
65 /*****************************************************************************
67 *****************************************************************************/
68 static int Demux ( demux_t * );
69 static int Control( demux_t *, int i_query, va_list args );
70 static void FlushRemainingPackets( demux_t *p_demux );
72 #define MAX_ASF_TRACKS 128
80 asf_object_stream_properties_t *p_sp;
81 asf_object_extended_stream_properties_t *p_esp;
85 block_t *p_frame; /* use to gather complete frame */
90 mtime_t i_time; /* s */
91 mtime_t i_length; /* length of file file */
92 uint64_t i_bitrate; /* global file bitrate */
94 asf_object_root_t *p_root;
95 asf_object_file_properties_t *p_fp;
98 asf_track_t *track[MAX_ASF_TRACKS]; /* track number is stored on 7 bits */
100 uint64_t i_data_begin;
105 uint8_t i_seek_track;
106 unsigned int i_wait_keyframe;
111 static mtime_t GetMoviePTS( demux_sys_t * );
112 static int DemuxInit( demux_t * );
113 static void DemuxEnd( demux_t * );
114 static int DemuxPacket( demux_t * );
116 /*****************************************************************************
117 * Open: check file and initializes ASF structures
118 *****************************************************************************/
119 static int Open( vlc_object_t * p_this )
121 demux_t *p_demux = (demux_t *)p_this;
124 const uint8_t *p_peek;
126 /* A little test to see if it could be a asf stream */
127 if( stream_Peek( p_demux->s, &p_peek, 16 ) < 16 ) return VLC_EGENERIC;
129 ASF_GetGUID( &guid, p_peek );
130 if( !guidcmp( &guid, &asf_object_header_guid ) ) return VLC_EGENERIC;
132 /* Set p_demux fields */
133 p_demux->pf_demux = Demux;
134 p_demux->pf_control = Control;
135 p_demux->p_sys = p_sys = calloc( 1, sizeof( demux_sys_t ) );
137 /* Load the headers */
138 if( DemuxInit( p_demux ) )
146 /*****************************************************************************
147 * Demux: read packet and send them to decoders
148 *****************************************************************************/
149 static int Demux( demux_t *p_demux )
151 demux_sys_t *p_sys = p_demux->p_sys;
155 const uint8_t *p_peek;
157 mtime_t i_time_begin = GetMoviePTS( p_sys );
160 if( !vlc_object_alive (p_demux) )
163 /* FIXME: returns EOF too early for some mms streams */
164 if( p_sys->i_data_end >= 0 &&
165 stream_Tell( p_demux->s ) >= p_sys->i_data_end )
169 /* Check if we have concatenated files */
170 if( stream_Peek( p_demux->s, &p_peek, 16 ) == 16 )
174 ASF_GetGUID( &guid, p_peek );
175 if( guidcmp( &guid, &asf_object_header_guid ) )
177 msg_Warn( p_demux, "found a new ASF header" );
178 /* We end this stream */
181 /* And we prepare to read the next one */
182 if( DemuxInit( p_demux ) )
184 msg_Err( p_demux, "failed to load the new header" );
185 dialog_Fatal( p_demux, _("Could not demux ASF stream"), "%s",
186 _("VLC failed to load the ASF header.") );
189 es_out_Control( p_demux->out, ES_OUT_RESET_PCR );
194 /* Read and demux a packet */
195 if( ( i_result = DemuxPacket( p_demux ) ) <= 0 )
197 FlushRemainingPackets( p_demux );
200 if( i_time_begin == -1 )
202 i_time_begin = GetMoviePTS( p_sys );
206 i_length = GetMoviePTS( p_sys ) - i_time_begin;
207 if( i_length < 0 || i_length >= 40 * 1000 ) break;
212 p_sys->i_time = GetMoviePTS( p_sys );
213 if( p_sys->i_time >= 0 )
216 msg_Dbg( p_demux, "Setting PCR to %"PRId64, p_sys->i_time );
218 es_out_Control( p_demux->out, ES_OUT_SET_PCR, p_sys->i_time+1 );
224 /*****************************************************************************
225 * Close: frees unused data
226 *****************************************************************************/
227 static void Close( vlc_object_t * p_this )
229 demux_t *p_demux = (demux_t *)p_this;
233 free( p_demux->p_sys );
236 /*****************************************************************************
237 * WaitKeyframe: computes the number of frames to wait for a keyframe
238 *****************************************************************************/
239 static void WaitKeyframe( demux_t *p_demux )
241 demux_sys_t *p_sys = p_demux->p_sys;
242 if ( ! p_sys->i_seek_track )
244 for ( int i=0; i<MAX_ASF_TRACKS; i++ )
246 asf_track_t *tk = p_sys->track[i];
247 if ( tk && tk->p_sp && tk->i_cat == VIDEO_ES )
249 bool b_selected = false;
250 es_out_Control( p_demux->out, ES_OUT_GET_ES_STATE,
251 tk->p_es, &b_selected );
254 p_sys->i_seek_track = tk->p_sp->i_stream_number;
261 if ( p_sys->i_seek_track )
263 /* Skip forward at least 1 min */
264 asf_track_t *tk = p_sys->track[p_sys->i_seek_track];
265 if ( tk->p_esp && tk->p_esp->i_average_time_per_frame )
267 /* 1 min if fastseek, otherwise 5 sec */
268 /* That's a guess for bandwidth */
269 uint64_t i_maxwaittime = ( p_sys->b_canfastseek ) ? 600000000 : 50000000;
270 i_maxwaittime /= tk->p_esp->i_average_time_per_frame;
271 p_sys->i_wait_keyframe = __MIN( i_maxwaittime, UINT_MAX );
275 p_sys->i_wait_keyframe = ( p_sys->b_canfastseek ) ? 25 * 30 : 25 * 5;
280 p_sys->i_wait_keyframe = 0;
285 /*****************************************************************************
286 * SeekIndex: goto to i_date or i_percent
287 *****************************************************************************/
288 static int SeekPercent( demux_t *p_demux, int i_query, va_list args )
290 demux_sys_t *p_sys = p_demux->p_sys;
292 WaitKeyframe( p_demux );
294 msg_Dbg( p_demux, "seek with percent: waiting %i frames", p_sys->i_wait_keyframe );
295 return demux_vaControlHelper( p_demux->s, __MIN( INT64_MAX, p_sys->i_data_begin ),
296 __MIN( INT64_MAX, p_sys->i_data_end ),
297 __MIN( INT64_MAX, p_sys->i_bitrate ),
298 __MIN( INT16_MAX, p_sys->p_fp->i_min_data_packet_size ),
302 static int SeekIndex( demux_t *p_demux, mtime_t i_date, float f_pos )
304 demux_sys_t *p_sys = p_demux->p_sys;
305 asf_object_index_t *p_index;
307 msg_Dbg( p_demux, "seek with index: %i seconds, position %f",
308 i_date >= 0 ? (int)(i_date/1000000) : -1, f_pos );
311 i_date = p_sys->i_length * f_pos;
313 p_index = ASF_FindObject( p_sys->p_root, &asf_object_simple_index_guid, 0 );
315 uint64_t i_entry = i_date * 10 / p_index->i_index_entry_time_interval;
316 if( i_entry >= p_index->i_index_entry_count )
318 msg_Warn( p_demux, "Incomplete index" );
322 WaitKeyframe( p_demux );
324 uint64_t i_offset = (uint64_t)p_index->index_entry[i_entry].i_packet_number *
325 p_sys->p_fp->i_min_data_packet_size;
327 if ( stream_Seek( p_demux->s, i_offset + p_sys->i_data_begin ) == VLC_SUCCESS )
329 es_out_Control( p_demux->out, ES_OUT_SET_NEXT_DISPLAY_TIME, VLC_TS_0 + i_date );
332 else return VLC_EGENERIC;
335 static void SeekPrepare( demux_t *p_demux )
337 demux_sys_t *p_sys = p_demux->p_sys;
339 p_sys->i_time = VLC_TS_INVALID;
340 for( int i = 0; i < MAX_ASF_TRACKS ; i++ )
342 asf_track_t *tk = p_sys->track[i];
346 tk->i_time = VLC_TS_INVALID;
348 block_ChainRelease( tk->p_frame );
352 es_out_Control( p_demux->out, ES_OUT_RESET_PCR, VLC_TS_INVALID );
355 /*****************************************************************************
357 *****************************************************************************/
358 static int Control( demux_t *p_demux, int i_query, va_list args )
360 demux_sys_t *p_sys = p_demux->p_sys;
367 case DEMUX_GET_LENGTH:
368 pi64 = (int64_t*)va_arg( args, int64_t * );
369 *pi64 = p_sys->i_length;
373 pi64 = (int64_t*)va_arg( args, int64_t * );
374 if( p_sys->i_time < 0 ) return VLC_EGENERIC;
375 *pi64 = p_sys->i_time;
380 ! ( p_sys->p_fp->i_flags & ASF_FILE_PROPERTIES_SEEKABLE ) )
383 SeekPrepare( p_demux );
385 if( p_sys->b_index && p_sys->i_length > 0 )
388 va_copy( acpy, args );
389 i64 = (int64_t)va_arg( acpy, int64_t );
392 if( !SeekIndex( p_demux, i64, -1 ) )
395 return SeekPercent( p_demux, i_query, args );
397 case DEMUX_GET_POSITION:
398 if( p_sys->i_time < 0 ) return VLC_EGENERIC;
399 if( p_sys->i_length > 0 )
401 pf = (double*)va_arg( args, double * );
402 *pf = p_sys->i_time / (double)p_sys->i_length;
405 return demux_vaControlHelper( p_demux->s,
406 __MIN( INT64_MAX, p_sys->i_data_begin ),
407 __MIN( INT64_MAX, p_sys->i_data_end ),
408 __MIN( INT64_MAX, p_sys->i_bitrate ),
409 __MIN( INT16_MAX, p_sys->p_fp->i_min_data_packet_size ),
412 case DEMUX_SET_POSITION:
414 ! ( p_sys->p_fp->i_flags & ASF_FILE_PROPERTIES_SEEKABLE ) )
417 SeekPrepare( p_demux );
419 if( p_sys->b_index && p_sys->i_length > 0 )
422 va_copy( acpy, args );
423 f = (double)va_arg( acpy, double );
426 if( !SeekIndex( p_demux, -1, f ) )
429 return SeekPercent( p_demux, i_query, args );
432 p_meta = (vlc_meta_t*)va_arg( args, vlc_meta_t* );
433 vlc_meta_Merge( p_meta, p_sys->meta );
438 ! ( p_sys->p_fp->i_flags & ASF_FILE_PROPERTIES_SEEKABLE ) )
440 bool *pb_bool = (bool*)va_arg( args, bool * );
447 return demux_vaControlHelper( p_demux->s,
448 __MIN( INT64_MAX, p_sys->i_data_begin ),
449 __MIN( INT64_MAX, p_sys->i_data_end),
450 __MIN( INT64_MAX, p_sys->i_bitrate ),
451 ( p_sys->p_fp ) ? __MIN( INT_MAX, p_sys->p_fp->i_min_data_packet_size ) : 1,
456 /*****************************************************************************
458 *****************************************************************************/
459 static mtime_t GetMoviePTS( demux_sys_t *p_sys )
464 for( i = 0; i < MAX_ASF_TRACKS ; i++ )
466 asf_track_t *tk = p_sys->track[i];
468 if( tk && tk->p_es && tk->i_time > 0)
470 if( i_time < 0 ) i_time = tk->i_time;
471 else i_time = __MIN( i_time, tk->i_time );
478 static inline int GetValue2b(uint32_t *var, const uint8_t *p, unsigned int *skip, int left, int bits)
485 *var = p[*skip]; *skip += 1;
490 *var = GetWLE(&p[*skip]); *skip += 2;
495 *var = GetDWLE(&p[*skip]); *skip += 4;
507 uint32_t padding_length;
512 /* buffer handling for this ASF packet */
514 const uint8_t *p_peek;
518 static void SendPacket(demux_t *p_demux, asf_track_t *tk)
520 demux_sys_t *p_sys = p_demux->p_sys;
522 block_t *p_gather = block_ChainGather( tk->p_frame );
524 if( p_sys->i_time < VLC_TS_0 && tk->i_time > VLC_TS_INVALID )
526 p_sys->i_time = tk->i_time;
527 es_out_Control( p_demux->out, ES_OUT_SET_PCR, p_sys->i_time );
529 msg_Dbg( p_demux, " setting PCR to %"PRId64, p_sys->i_time );
534 msg_Dbg( p_demux, " sending packet dts %"PRId64" pts %"PRId64" pcr %"PRId64, p_gather->i_dts, p_gather->i_pts, p_sys->i_time );
537 es_out_Send( p_demux->out, tk->p_es, p_gather );
541 static int DemuxSubPayload(demux_t *p_demux, asf_track_t *tk,
542 uint32_t i_sub_payload_data_length, mtime_t i_pts, mtime_t i_dts,
543 uint32_t i_media_object_offset, bool b_keyframe )
545 /* FIXME I don't use i_media_object_number, sould I ? */
546 if( tk->p_frame && i_media_object_offset == 0 )
547 SendPacket(p_demux, tk);
549 block_t *p_frag = stream_Block( p_demux->s, i_sub_payload_data_length );
550 if( p_frag == NULL ) {
551 msg_Warn( p_demux, "cannot read data" );
555 p_frag->i_pts = VLC_TS_0 + i_pts;
556 p_frag->i_dts = VLC_TS_0 + i_dts;
558 p_frag->i_flags |= BLOCK_FLAG_TYPE_I;
560 block_ChainAppend( &tk->p_frame, p_frag );
565 static uint32_t SkipBytes( stream_t *s, uint32_t i_bytes )
568 int i_to_read = __MIN(i_bytes, INT_MAX);
569 uint32_t i_bytes_read = 0;
573 i_read = stream_Read( s, NULL, i_to_read );
575 i_bytes_read += i_read;
576 if ( i_read < i_to_read || i_bytes == 0 )
581 i_to_read = __MIN(i_bytes, INT_MAX);
587 static void ParsePayloadExtensions(demux_t *p_demux, asf_track_t *tk,
588 const struct asf_packet_t *pkt,
589 uint32_t i_length, bool *b_keyframe )
591 if ( !tk || !tk->p_esp || !tk->p_esp->p_ext ) return;
592 const uint8_t *p_data = pkt->p_peek + pkt->i_skip + 8;
594 uint16_t i_payload_extensions_size;
595 asf_payload_extension_system_t *p_ext = NULL;
597 /* Extensions always come in the declared order */
598 for ( int i=0; i< tk->p_esp->i_payload_extension_system_count; i++ )
600 p_ext = &tk->p_esp->p_ext[i];
601 if ( p_ext->i_data_size == 0xFFFF ) /* Variable length extension data */
603 if ( i_length < 2 ) return;
604 i_payload_extensions_size = GetWLE( p_data );
607 i_payload_extensions_size = 0;
611 i_payload_extensions_size = p_ext->i_data_size;
614 if ( i_length < i_payload_extensions_size ) return;
616 if ( guidcmp( &p_ext->i_extension_id, &mfasf_sampleextension_outputcleanpoint_guid ) )
618 if ( i_payload_extensions_size != sizeof(uint8_t) ) goto sizeerror;
619 *b_keyframe |= *p_data;
621 else if ( guidcmp( &p_ext->i_extension_id, &asf_dvr_sampleextension_videoframe_guid ) )
623 if ( i_payload_extensions_size != sizeof(uint32_t) ) goto sizeerror;
625 uint32_t i_val = GetDWLE( p_data );
626 /* Valid keyframe must be a split frame start fragment */
627 *b_keyframe = i_val & ASF_EXTENSION_VIDEOFRAME_NEWFRAME;
630 /* And flagged as IFRAME */
631 *b_keyframe |= ( ( i_val & ASF_EXTENSION_VIDEOFRAME_TYPE_MASK )
632 == ASF_EXTENSION_VIDEOFRAME_IFRAME );
636 i_length -= i_payload_extensions_size;
637 p_data += i_payload_extensions_size;
643 msg_Warn( p_demux, "Unknown extension " GUID_FMT " data size of %u",
644 GUID_PRINT( p_ext->i_extension_id ), i_payload_extensions_size );
647 static int DemuxPayload(demux_t *p_demux, struct asf_packet_t *pkt, int i_payload)
650 VLC_UNUSED( i_payload );
652 demux_sys_t *p_sys = p_demux->p_sys;
654 if( ! pkt->left || pkt->i_skip >= pkt->left )
657 bool b_packet_keyframe = pkt->p_peek[pkt->i_skip] >> 7;
658 uint8_t i_stream_number = pkt->p_peek[pkt->i_skip++] & 0x7f;
660 uint32_t i_media_object_number = 0;
661 if (GetValue2b(&i_media_object_number, pkt->p_peek, &pkt->i_skip, pkt->left - pkt->i_skip, pkt->property >> 4) < 0)
663 uint32_t i_media_object_offset = 0;
664 if (GetValue2b(&i_media_object_offset, pkt->p_peek, &pkt->i_skip, pkt->left - pkt->i_skip, pkt->property >> 2) < 0)
666 uint32_t i_replicated_data_length = 0;
667 if (GetValue2b(&i_replicated_data_length, pkt->p_peek, &pkt->i_skip, pkt->left - pkt->i_skip, pkt->property) < 0)
671 uint8_t i_pts_delta = 0;
672 uint32_t i_payload_data_length = 0;
673 uint32_t i_temp_payload_length = 0;
674 bool b_preroll_done = false;
675 p_sys->p_fp->i_preroll = __MIN( p_sys->p_fp->i_preroll, INT64_MAX );
678 if( i_replicated_data_length > 7 ) // should be at least 8 bytes
680 /* Followed by 2 optional DWORDS, offset in media and presentation time */
681 i_base_pts = (mtime_t)GetDWLE( pkt->p_peek + pkt->i_skip + 4 );
683 /* Parsing extensions, See 7.3.1 */
684 ParsePayloadExtensions( p_demux, p_sys->track[i_stream_number], pkt,
685 i_replicated_data_length, &b_packet_keyframe );
687 b_preroll_done = ( i_base_pts > (int64_t)p_sys->p_fp->i_preroll );
688 i_base_pts -= p_sys->p_fp->i_preroll;
689 pkt->i_skip += i_replicated_data_length;
691 if( ! pkt->left || pkt->i_skip >= pkt->left )
694 else if ( i_replicated_data_length == 0 )
696 /* optional DWORDS missing */
697 i_base_pts = (mtime_t)pkt->send_time;
698 b_preroll_done = ( i_base_pts > (int64_t)p_sys->p_fp->i_preroll );
700 /* Compressed payload */
701 else if( i_replicated_data_length == 1 )
703 /* i_media_object_offset is presentation time */
704 /* Next byte is Presentation Time Delta */
705 i_pts_delta = pkt->p_peek[pkt->i_skip];
706 i_base_pts = (mtime_t)i_media_object_offset;
707 b_preroll_done = ( i_base_pts > (int64_t)p_sys->p_fp->i_preroll );
708 i_base_pts -= p_sys->p_fp->i_preroll;
710 i_media_object_offset = 0;
714 /* >1 && <8 Invalid replicated length ! */
715 msg_Warn( p_demux, "Invalid replicated data length detected." );
716 i_payload_data_length = pkt->length - pkt->padding_length - pkt->i_skip;
720 if (i_base_pts < 0) i_base_pts = 0; // FIXME?
723 if( pkt->multiple ) {
724 if (GetValue2b(&i_temp_payload_length, pkt->p_peek, &pkt->i_skip, pkt->left - pkt->i_skip, pkt->length_type) < 0)
727 i_temp_payload_length = pkt->length - pkt->padding_length - pkt->i_skip;
729 i_payload_data_length = i_temp_payload_length;
733 "payload(%d) stream_number:%"PRIu8" media_object_number:%d media_object_offset:%"PRIu32" replicated_data_length:%"PRIu32" payload_data_length %"PRIu32,
734 i_payload + 1, i_stream_number, i_media_object_number,
735 i_media_object_offset, i_replicated_data_length, i_payload_data_length );
737 " pts=%"PRId64" st=%"PRIu32, i_base_pts, pkt->send_time );
740 if( ! i_payload_data_length || i_payload_data_length > pkt->left )
742 msg_Dbg( p_demux, " payload length problem %d %"PRIu32" %"PRIu32, pkt->multiple, i_payload_data_length, pkt->left );
746 asf_track_t *tk = p_sys->track[i_stream_number];
749 msg_Warn( p_demux, "undeclared stream[Id 0x%x]", i_stream_number );
753 if( p_sys->i_wait_keyframe )
755 if ( i_stream_number == p_sys->i_seek_track )
757 if ( !b_packet_keyframe )
759 p_sys->i_wait_keyframe--;
763 p_sys->i_wait_keyframe = 0;
772 if ( b_preroll_done )
774 tk->i_time = INT64_C(1000) * pkt->send_time;
775 tk->i_time -= p_sys->p_fp->i_preroll * 1000;
776 tk->i_time -= tk->p_sp->i_time_offset * 10;
779 uint32_t i_subpayload_count = 0;
780 while (i_payload_data_length)
782 uint32_t i_sub_payload_data_length = i_payload_data_length;
783 if( i_replicated_data_length == 1 )
785 i_sub_payload_data_length = pkt->p_peek[pkt->i_skip++];
786 i_payload_data_length--;
789 SkipBytes( p_demux->s, pkt->i_skip );
791 mtime_t i_payload_pts = i_base_pts + (mtime_t)i_pts_delta * i_subpayload_count * 1000;
792 i_payload_pts -= tk->p_sp->i_time_offset * 10;
793 mtime_t i_payload_dts = INT64_C(1000) * pkt->send_time;
794 i_payload_dts -= tk->p_sp->i_time_offset * 10;
796 if ( i_sub_payload_data_length &&
797 DemuxSubPayload(p_demux, tk, i_sub_payload_data_length,
798 i_payload_pts, i_payload_dts, i_media_object_offset,
799 b_packet_keyframe ) < 0)
802 if ( pkt->left > pkt->i_skip + i_sub_payload_data_length )
803 pkt->left -= pkt->i_skip + i_sub_payload_data_length;
809 int i_return = stream_Peek( p_demux->s, &pkt->p_peek, __MIN(pkt->left, INT_MAX) );
810 if ( i_return <= 0 || (unsigned int) i_return < __MIN(pkt->left, INT_MAX) )
812 msg_Warn( p_demux, "cannot peek, EOF ?" );
817 if ( i_sub_payload_data_length <= i_payload_data_length )
818 i_payload_data_length -= i_sub_payload_data_length;
820 i_payload_data_length = 0;
822 i_subpayload_count++;
828 pkt->i_skip += i_payload_data_length;
832 static int DemuxPacket( demux_t *p_demux )
834 demux_sys_t *p_sys = p_demux->p_sys;
836 uint32_t i_data_packet_min = p_sys->p_fp->i_min_data_packet_size;
838 const uint8_t *p_peek;
839 int i_return = stream_Peek( p_demux->s, &p_peek,i_data_packet_min );
840 if( i_return <= 0 || ((unsigned int) i_return) < i_data_packet_min )
842 msg_Warn( p_demux, "cannot peek while getting new packet, EOF ?" );
845 unsigned int i_skip = 0;
847 /* *** parse error correction if present *** */
850 unsigned int i_error_correction_data_length = p_peek[0] & 0x0f;
851 unsigned int i_opaque_data_present = ( p_peek[0] >> 4 )& 0x01;
852 unsigned int i_error_correction_length_type = ( p_peek[0] >> 5 ) & 0x03;
853 i_skip += 1; // skip error correction flags
855 if( i_error_correction_length_type != 0x00 ||
856 i_opaque_data_present != 0 ||
857 i_error_correction_data_length != 0x02 )
859 goto loop_error_recovery;
862 i_skip += i_error_correction_data_length;
865 msg_Warn( p_demux, "no error correction" );
868 if( i_skip + 2 >= i_data_packet_min )
869 goto loop_error_recovery;
871 struct asf_packet_t pkt;
872 int i_packet_flags = p_peek[i_skip]; i_skip++;
873 pkt.property = p_peek[i_skip]; i_skip++;
874 pkt.multiple = !!(i_packet_flags&0x01);
876 pkt.length = i_data_packet_min;
877 pkt.padding_length = 0;
879 if (GetValue2b(&pkt.length, p_peek, &i_skip, i_data_packet_min - i_skip, i_packet_flags >> 5) < 0)
880 goto loop_error_recovery;
881 uint32_t i_packet_sequence;
882 if (GetValue2b(&i_packet_sequence, p_peek, &i_skip, i_data_packet_min - i_skip, i_packet_flags >> 1) < 0)
883 goto loop_error_recovery;
884 if (GetValue2b(&pkt.padding_length, p_peek, &i_skip, i_data_packet_min - i_skip, i_packet_flags >> 3) < 0)
885 goto loop_error_recovery;
887 if( pkt.padding_length > pkt.length )
889 msg_Warn( p_demux, "Too large padding: %"PRIu32, pkt.padding_length );
890 goto loop_error_recovery;
893 if( pkt.length < i_data_packet_min )
895 /* if packet length too short, there is extra padding */
896 pkt.padding_length += i_data_packet_min - pkt.length;
897 pkt.length = i_data_packet_min;
900 pkt.send_time = GetDWLE( p_peek + i_skip ); i_skip += 4;
901 /* uint16_t i_packet_duration = GetWLE( p_peek + i_skip ); */ i_skip += 2;
903 i_return = stream_Peek( p_demux->s, &p_peek, pkt.length );
904 if( i_return <= 0 || pkt.length == 0 || (unsigned int)i_return < pkt.length )
906 msg_Warn( p_demux, "cannot peek, EOF ?" );
910 int i_payload_count = 1;
911 pkt.length_type = 0x02; //unused
914 i_payload_count = p_peek[i_skip] & 0x3f;
915 pkt.length_type = ( p_peek[i_skip] >> 6 )&0x03;
920 msg_Dbg(p_demux, "%d payloads", i_payload_count);
925 pkt.left = pkt.length;
927 for( int i_payload = 0; i_payload < i_payload_count ; i_payload++ )
928 if (DemuxPayload(p_demux, &pkt, i_payload) < 0)
930 msg_Warn( p_demux, "payload err %d / %d", i_payload + 1, i_payload_count );
937 if( pkt.left > pkt.padding_length )
938 msg_Warn( p_demux, "Didn't read %"PRIu32" bytes in the packet",
939 pkt.left - pkt.padding_length );
940 else if( pkt.left < pkt.padding_length )
941 msg_Warn( p_demux, "Read %"PRIu32" too much bytes in the packet",
942 pkt.padding_length - pkt.left );
944 int i_return = stream_Read( p_demux->s, NULL, pkt.left );
945 if( i_return < 0 || (unsigned int) i_return < pkt.left )
947 msg_Err( p_demux, "cannot skip data, EOF ?" );
955 msg_Warn( p_demux, "unsupported packet header" );
956 if( p_sys->p_fp->i_min_data_packet_size != p_sys->p_fp->i_max_data_packet_size )
958 msg_Err( p_demux, "unsupported packet header, fatal error" );
961 i_return = stream_Read( p_demux->s, NULL, i_data_packet_min );
962 if( i_return <= 0 || (unsigned int) i_return != i_data_packet_min )
964 msg_Warn( p_demux, "cannot skip data, EOF ?" );
971 /*****************************************************************************
973 *****************************************************************************/
974 typedef struct asf_es_priorities_t
976 uint16_t *pi_stream_numbers;
978 } asf_es_priorities_t;
980 /* Fills up our exclusion list */
981 static void ASF_fillup_es_priorities_ex( demux_sys_t *p_sys, void *p_hdr,
982 asf_es_priorities_t *p_prios )
984 /* Find stream exclusions */
985 asf_object_advanced_mutual_exclusion_t *p_mutex =
986 ASF_FindObject( p_hdr, &asf_object_advanced_mutual_exclusion, 0 );
987 if (! p_mutex ) return;
989 #if ( UINT_MAX > SIZE_MAX / 2 )
990 if ( p_sys->i_track > (size_t)SIZE_MAX / sizeof(uint16_t) )
993 p_prios->pi_stream_numbers = malloc( (size_t)p_sys->i_track * sizeof(uint16_t) );
994 if ( !p_prios->pi_stream_numbers ) return;
996 if ( p_mutex->i_stream_number_count )
998 /* Just set highest prio on highest in the group */
999 for ( uint16_t i = 1; i < p_mutex->i_stream_number_count; i++ )
1001 if ( p_prios->i_count > p_sys->i_track ) break;
1002 p_prios->pi_stream_numbers[ p_prios->i_count++ ] = p_mutex->pi_stream_number[ i ];
1007 /* Fills up our bitrate exclusion list */
1008 static void ASF_fillup_es_bitrate_priorities_ex( demux_sys_t *p_sys, void *p_hdr,
1009 asf_es_priorities_t *p_prios )
1011 /* Find bitrate exclusions */
1012 asf_object_bitrate_mutual_exclusion_t *p_bitrate_mutex =
1013 ASF_FindObject( p_hdr, &asf_object_bitrate_mutual_exclusion_guid, 0 );
1014 if (! p_bitrate_mutex ) return;
1016 #if ( UINT_MAX > SIZE_MAX / 2 )
1017 if ( p_sys->i_track > (size_t)SIZE_MAX / sizeof(uint16_t) )
1020 p_prios->pi_stream_numbers = malloc( (size_t)p_sys->i_track * sizeof( uint16_t ) );
1021 if ( !p_prios->pi_stream_numbers ) return;
1023 if ( p_bitrate_mutex->i_stream_number_count )
1025 /* Just remove < highest */
1026 for ( uint16_t i = 1; i < p_bitrate_mutex->i_stream_number_count; i++ )
1028 if ( p_prios->i_count > p_sys->i_track ) break;
1029 p_prios->pi_stream_numbers[ p_prios->i_count++ ] = p_bitrate_mutex->pi_stream_numbers[ i ];
1035 #define GET_CHECKED( target, getter, maxtarget, temp ) \
1037 temp i_temp = getter;\
1038 if ( i_temp > maxtarget ) {\
1039 msg_Warn( p_demux, "rejecting stream %u : " #target " overflow", i_stream );\
1040 es_format_Clean( &fmt );\
1047 static int DemuxInit( demux_t *p_demux )
1049 demux_sys_t *p_sys = p_demux->p_sys;
1053 p_sys->i_length = 0;
1054 p_sys->i_bitrate = 0;
1055 p_sys->p_root = NULL;
1059 p_sys->i_seek_track = 0;
1060 p_sys->i_wait_keyframe = 0;
1061 for( int i = 0; i < MAX_ASF_TRACKS; i++ )
1063 p_sys->track[i] = NULL;
1065 p_sys->i_data_begin = 0;
1066 p_sys->i_data_end = 0;
1069 /* Now load all object ( except raw data ) */
1070 stream_Control( p_demux->s, STREAM_CAN_FASTSEEK, &p_sys->b_canfastseek );
1071 if( !(p_sys->p_root = ASF_ReadObjectRoot(p_demux->s, p_sys->b_canfastseek)) )
1073 msg_Warn( p_demux, "ASF plugin discarded (not a valid file)" );
1074 return VLC_EGENERIC;
1076 p_sys->p_fp = p_sys->p_root->p_fp;
1078 if( p_sys->p_fp->i_min_data_packet_size != p_sys->p_fp->i_max_data_packet_size )
1080 msg_Warn( p_demux, "ASF plugin discarded (invalid file_properties object)" );
1084 if ( ASF_FindObject( p_sys->p_root->p_hdr,
1085 &asf_object_content_encryption_guid, 0 ) != NULL
1086 || ASF_FindObject( p_sys->p_root->p_hdr,
1087 &asf_object_extended_content_encryption_guid, 0 ) != NULL
1088 || ASF_FindObject( p_sys->p_root->p_hdr,
1089 &asf_object_advanced_content_encryption_guid, 0 ) != NULL )
1091 msg_Warn( p_demux, "ASF plugin discarded (DRM encumbered content)" );
1095 p_sys->i_track = ASF_CountObject( p_sys->p_root->p_hdr,
1096 &asf_object_stream_properties_guid );
1097 if( p_sys->i_track == 0 )
1099 msg_Warn( p_demux, "ASF plugin discarded (cannot find any stream!)" );
1102 msg_Dbg( p_demux, "found %u streams", p_sys->i_track );
1104 /* check if index is available */
1105 asf_object_index_t *p_index = ASF_FindObject( p_sys->p_root,
1106 &asf_object_simple_index_guid, 0 );
1107 const bool b_index = p_index && p_index->i_index_entry_count;
1109 /* Find the extended header if any */
1110 asf_object_t *p_hdr_ext = ASF_FindObject( p_sys->p_root->p_hdr,
1111 &asf_object_header_extension_guid, 0 );
1113 asf_object_language_list_t *p_languages = NULL;
1114 asf_es_priorities_t fmt_priorities_ex = { NULL, 0 };
1115 asf_es_priorities_t fmt_priorities_bitrate_ex = { NULL, 0 };
1119 p_languages = ASF_FindObject( p_hdr_ext, &asf_object_language_list, 0 );
1121 ASF_fillup_es_priorities_ex( p_sys, p_hdr_ext, &fmt_priorities_ex );
1122 ASF_fillup_es_bitrate_priorities_ex( p_sys, p_hdr_ext, &fmt_priorities_bitrate_ex );
1125 for( unsigned i_stream = 0; i_stream < p_sys->i_track; i_stream++ )
1128 asf_object_stream_properties_t *p_sp;
1129 asf_object_extended_stream_properties_t *p_esp;
1130 bool b_access_selected;
1132 p_sp = ASF_FindObject( p_sys->p_root->p_hdr,
1133 &asf_object_stream_properties_guid,
1137 tk = p_sys->track[p_sp->i_stream_number] = malloc( sizeof( asf_track_t ) );
1138 memset( tk, 0, sizeof( asf_track_t ) );
1146 /* Check (in case of mms) if this track is selected (ie will receive data) */
1147 if( !stream_Control( p_demux->s, STREAM_GET_PRIVATE_ID_STATE,
1148 (int) p_sp->i_stream_number, &b_access_selected ) &&
1149 !b_access_selected )
1151 tk->i_cat = UNKNOWN_ES;
1152 msg_Dbg( p_demux, "ignoring not selected stream(ID:%u) (by access)",
1153 p_sp->i_stream_number );
1157 /* Find the associated extended_stream_properties if any */
1160 int i_ext_stream = ASF_CountObject( p_hdr_ext,
1161 &asf_object_extended_stream_properties_guid );
1162 for( int i = 0; i < i_ext_stream; i++ )
1164 asf_object_t *p_tmp =
1165 ASF_FindObject( p_hdr_ext,
1166 &asf_object_extended_stream_properties_guid, i );
1167 if( p_tmp->ext_stream.i_stream_number == p_sp->i_stream_number )
1169 p_esp = &p_tmp->ext_stream;
1178 if( guidcmp( &p_sp->i_stream_type, &asf_object_stream_type_audio ) &&
1179 p_sp->i_type_specific_data_length >= sizeof( WAVEFORMATEX ) - 2 )
1181 uint8_t *p_data = p_sp->p_type_specific_data;
1184 es_format_Init( &fmt, AUDIO_ES, 0 );
1185 i_format = GetWLE( &p_data[0] );
1186 wf_tag_to_fourcc( i_format, &fmt.i_codec, NULL );
1188 GET_CHECKED( fmt.audio.i_channels, GetWLE( &p_data[2] ),
1190 GET_CHECKED( fmt.audio.i_rate, GetDWLE( &p_data[4] ),
1191 UINT_MAX, uint32_t );
1192 GET_CHECKED( fmt.i_bitrate, GetDWLE( &p_data[8] ) * 8,
1193 UINT_MAX, uint32_t );
1194 fmt.audio.i_blockalign = GetWLE( &p_data[12] );
1195 fmt.audio.i_bitspersample = GetWLE( &p_data[14] );
1197 if( p_sp->i_type_specific_data_length > sizeof( WAVEFORMATEX ) &&
1198 i_format != WAVE_FORMAT_MPEGLAYER3 &&
1199 i_format != WAVE_FORMAT_MPEG )
1201 GET_CHECKED( fmt.i_extra, __MIN( GetWLE( &p_data[16] ),
1202 p_sp->i_type_specific_data_length -
1203 sizeof( WAVEFORMATEX ) ),
1204 INT_MAX, uint32_t );
1205 fmt.p_extra = malloc( fmt.i_extra );
1206 memcpy( fmt.p_extra, &p_data[sizeof( WAVEFORMATEX )],
1210 msg_Dbg( p_demux, "added new audio stream(codec:0x%x,ID:%d)",
1211 GetWLE( p_data ), p_sp->i_stream_number );
1213 else if( guidcmp( &p_sp->i_stream_type,
1214 &asf_object_stream_type_video ) &&
1215 p_sp->i_type_specific_data_length >= 11 +
1216 sizeof( VLC_BITMAPINFOHEADER ) )
1218 uint8_t *p_data = &p_sp->p_type_specific_data[11];
1220 es_format_Init( &fmt, VIDEO_ES,
1221 VLC_FOURCC( p_data[16], p_data[17],
1222 p_data[18], p_data[19] ) );
1224 GET_CHECKED( fmt.video.i_width, GetDWLE( p_data + 4 ),
1225 UINT_MAX, uint32_t );
1226 GET_CHECKED( fmt.video.i_height, GetDWLE( p_data + 8 ),
1227 UINT_MAX, uint32_t );
1229 if( p_esp && p_esp->i_average_time_per_frame > 0 )
1231 fmt.video.i_frame_rate = 10000000;
1232 GET_CHECKED( fmt.video.i_frame_rate_base,
1233 p_esp->i_average_time_per_frame,
1234 UINT_MAX, uint64_t );
1237 if( fmt.i_codec == VLC_FOURCC( 'D','V','R',' ') )
1239 /* DVR-MS special ASF */
1240 fmt.i_codec = VLC_FOURCC( 'm','p','g','2' ) ;
1241 fmt.b_packetized = false;
1244 if( p_sp->i_type_specific_data_length > 11 +
1245 sizeof( VLC_BITMAPINFOHEADER ) )
1247 GET_CHECKED( fmt.i_extra, __MIN( GetDWLE( p_data ),
1248 p_sp->i_type_specific_data_length - 11 -
1249 sizeof( VLC_BITMAPINFOHEADER ) ),
1250 UINT_MAX, uint32_t );
1251 fmt.p_extra = malloc( fmt.i_extra );
1252 memcpy( fmt.p_extra, &p_data[sizeof( VLC_BITMAPINFOHEADER )],
1256 /* Look for an aspect ratio */
1257 if( p_sys->p_root->p_metadata )
1259 asf_object_metadata_t *p_meta = p_sys->p_root->p_metadata;
1260 unsigned int i_aspect_x = 0, i_aspect_y = 0;
1262 for( i = 0; i < p_meta->i_record_entries_count; i++ )
1264 if( !strcmp( p_meta->record[i].psz_name, "AspectRatioX" ) )
1266 if( (!i_aspect_x && !p_meta->record[i].i_stream) ||
1267 p_meta->record[i].i_stream ==
1268 p_sp->i_stream_number )
1269 GET_CHECKED( i_aspect_x, p_meta->record[i].i_val,
1270 UINT_MAX, uint64_t );
1272 if( !strcmp( p_meta->record[i].psz_name, "AspectRatioY" ) )
1274 if( (!i_aspect_y && !p_meta->record[i].i_stream) ||
1275 p_meta->record[i].i_stream ==
1276 p_sp->i_stream_number )
1277 GET_CHECKED( i_aspect_y, p_meta->record[i].i_val,
1278 UINT_MAX, uint64_t );
1282 if( i_aspect_x && i_aspect_y )
1284 fmt.video.i_sar_num = i_aspect_x;
1285 fmt.video.i_sar_den = i_aspect_y;
1289 /* If there is a video track then use the index for seeking */
1290 p_sys->b_index = b_index;
1292 msg_Dbg( p_demux, "added new video stream(ID:%d)",
1293 p_sp->i_stream_number );
1295 else if( guidcmp( &p_sp->i_stream_type, &asf_object_extended_stream_header ) &&
1296 p_sp->i_type_specific_data_length >= 64 )
1298 /* Now follows a 64 byte header of which we don't know much */
1299 guid_t *p_ref = (guid_t *)p_sp->p_type_specific_data;
1300 uint8_t *p_data = p_sp->p_type_specific_data + 64;
1301 unsigned int i_data = p_sp->i_type_specific_data_length - 64;
1303 msg_Dbg( p_demux, "Ext stream header detected. datasize = %d", p_sp->i_type_specific_data_length );
1304 if( guidcmp( p_ref, &asf_object_extended_stream_type_audio ) &&
1305 i_data >= sizeof( WAVEFORMATEX ) - 2)
1308 es_format_Init( &fmt, AUDIO_ES, 0 );
1309 i_format = GetWLE( &p_data[0] );
1311 fmt.i_codec = VLC_CODEC_A52;
1313 wf_tag_to_fourcc( i_format, &fmt.i_codec, NULL );
1314 GET_CHECKED( fmt.audio.i_channels, GetWLE( &p_data[2] ),
1316 GET_CHECKED( fmt.audio.i_rate, GetDWLE( &p_data[4] ),
1317 UINT_MAX, uint32_t );
1318 GET_CHECKED( fmt.i_bitrate, GetDWLE( &p_data[8] ) * 8,
1319 UINT_MAX, uint32_t );
1320 fmt.audio.i_blockalign = GetWLE( &p_data[12] );
1321 fmt.audio.i_bitspersample = GetWLE( &p_data[14] );
1322 fmt.b_packetized = true;
1324 if( p_sp->i_type_specific_data_length > sizeof( WAVEFORMATEX ) &&
1325 i_format != WAVE_FORMAT_MPEGLAYER3 &&
1326 i_format != WAVE_FORMAT_MPEG )
1328 GET_CHECKED( fmt.i_extra, __MIN( GetWLE( &p_data[16] ),
1329 p_sp->i_type_specific_data_length -
1330 sizeof( WAVEFORMATEX ) ),
1331 INT_MAX, uint32_t );
1332 fmt.p_extra = malloc( fmt.i_extra );
1333 memcpy( fmt.p_extra, &p_data[sizeof( WAVEFORMATEX )],
1337 msg_Dbg( p_demux, "added new audio stream (codec:0x%x,ID:%d)",
1338 i_format, p_sp->i_stream_number );
1342 es_format_Init( &fmt, UNKNOWN_ES, 0 );
1347 es_format_Init( &fmt, UNKNOWN_ES, 0 );
1350 tk->i_cat = fmt.i_cat;
1351 if( fmt.i_cat != UNKNOWN_ES )
1353 if( p_esp && p_languages &&
1354 p_esp->i_language_index < p_languages->i_language )
1356 fmt.psz_language = strdup( p_languages->ppsz_language[p_esp->i_language_index] );
1358 if( fmt.psz_language && (p = strchr( fmt.psz_language, '-' )) )
1362 /* Set our priority so we won't get multiple videos */
1363 int i_priority = ES_PRIORITY_SELECTABLE_MIN;
1364 for( uint16_t i = 0; i < fmt_priorities_ex.i_count; i++ )
1366 if ( fmt_priorities_ex.pi_stream_numbers[i] == p_sp->i_stream_number )
1368 i_priority = ES_PRIORITY_NOT_DEFAULTABLE;
1372 for( uint16_t i = 0; i < fmt_priorities_bitrate_ex.i_count; i++ )
1374 if ( fmt_priorities_bitrate_ex.pi_stream_numbers[i] == p_sp->i_stream_number )
1376 i_priority = ES_PRIORITY_NOT_DEFAULTABLE;
1380 fmt.i_priority = i_priority;
1382 tk->p_es = es_out_Add( p_demux->out, &fmt );
1386 msg_Dbg( p_demux, "ignoring unknown stream(ID:%d)",
1387 p_sp->i_stream_number );
1390 es_format_Clean( &fmt );
1393 free( fmt_priorities_ex.pi_stream_numbers );
1394 free( fmt_priorities_bitrate_ex.pi_stream_numbers );
1396 p_sys->i_data_begin = p_sys->p_root->p_data->i_object_pos + 50;
1397 if( p_sys->p_root->p_data->i_object_size != 0 )
1399 p_sys->i_data_end = p_sys->p_root->p_data->i_object_pos +
1400 p_sys->p_root->p_data->i_object_size;
1401 p_sys->i_data_end = __MIN( (uint64_t)stream_Size( p_demux->s ), p_sys->i_data_end );
1404 { /* live/broacast */
1405 p_sys->i_data_end = 0;
1408 /* go to first packet */
1409 stream_Seek( p_demux->s, p_sys->i_data_begin );
1411 /* try to calculate movie time */
1412 if( p_sys->p_fp->i_data_packets_count > 0 )
1415 uint64_t i_size = stream_Size( p_demux->s );
1417 if( p_sys->i_data_end > 0 && i_size > p_sys->i_data_end )
1419 i_size = p_sys->i_data_end;
1422 /* real number of packets */
1423 i_count = ( i_size - p_sys->i_data_begin ) /
1424 p_sys->p_fp->i_min_data_packet_size;
1426 /* calculate the time duration in micro-s */
1427 p_sys->i_length = (mtime_t)p_sys->p_fp->i_play_duration / 10 *
1429 (mtime_t)p_sys->p_fp->i_data_packets_count - p_sys->p_fp->i_preroll * 1000;
1430 if( p_sys->i_length < 0 )
1431 p_sys->i_length = 0;
1433 if( p_sys->i_length > 0 )
1435 p_sys->i_bitrate = 8 * i_size * 1000000 / p_sys->i_length;
1439 /* Create meta information */
1440 p_sys->meta = vlc_meta_New();
1442 asf_object_content_description_t *p_cd;
1443 if( ( p_cd = ASF_FindObject( p_sys->p_root->p_hdr,
1444 &asf_object_content_description_guid, 0 ) ) )
1446 if( p_cd->psz_title && *p_cd->psz_title )
1448 vlc_meta_SetTitle( p_sys->meta, p_cd->psz_title );
1450 if( p_cd->psz_artist && *p_cd->psz_artist )
1452 vlc_meta_SetArtist( p_sys->meta, p_cd->psz_artist );
1454 if( p_cd->psz_copyright && *p_cd->psz_copyright )
1456 vlc_meta_SetCopyright( p_sys->meta, p_cd->psz_copyright );
1458 if( p_cd->psz_description && *p_cd->psz_description )
1460 vlc_meta_SetDescription( p_sys->meta, p_cd->psz_description );
1462 if( p_cd->psz_rating && *p_cd->psz_rating )
1464 vlc_meta_SetRating( p_sys->meta, p_cd->psz_rating );
1467 /// \tood Fix Child meta for ASF tracks
1469 for( i_stream = 0, i = 0; i < MAX_ASF_TRACKS; i++ )
1471 asf_object_codec_list_t *p_cl = ASF_FindObject( p_sys->p_root->p_hdr,
1472 &asf_object_codec_list_guid, 0 );
1474 if( p_sys->track[i] )
1476 vlc_meta_t *tk = vlc_meta_New();
1477 TAB_APPEND( p_sys->meta->i_track, p_sys->meta->track, tk );
1479 if( p_cl && i_stream < p_cl->i_codec_entries_count )
1481 if( p_cl->codec[i_stream].psz_name &&
1482 *p_cl->codec[i_stream].psz_name )
1484 vlc_meta_Add( tk, VLC_META_CODEC_NAME,
1485 p_cl->codec[i_stream].psz_name );
1487 if( p_cl->codec[i_stream].psz_description &&
1488 *p_cl->codec[i_stream].psz_description )
1490 vlc_meta_Add( tk, VLC_META_CODEC_DESCRIPTION,
1491 p_cl->codec[i_stream].psz_description );
1501 ASF_FreeObjectRoot( p_demux->s, p_sys->p_root );
1502 return VLC_EGENERIC;
1505 /*****************************************************************************
1506 * FlushRemainingPackets: flushes tail packets
1507 *****************************************************************************/
1509 static void FlushRemainingPackets( demux_t *p_demux )
1511 demux_sys_t *p_sys = p_demux->p_sys;
1512 for ( unsigned int i = 0; i < MAX_ASF_TRACKS; i++ )
1514 asf_track_t *tk = p_sys->track[i];
1515 if( tk && tk->p_frame )
1516 SendPacket( p_demux, tk );
1520 /*****************************************************************************
1522 *****************************************************************************/
1523 static void DemuxEnd( demux_t *p_demux )
1525 demux_sys_t *p_sys = p_demux->p_sys;
1529 ASF_FreeObjectRoot( p_demux->s, p_sys->p_root );
1530 p_sys->p_root = NULL;
1534 vlc_meta_Delete( p_sys->meta );
1538 for( int i = 0; i < MAX_ASF_TRACKS; i++ )
1540 asf_track_t *tk = p_sys->track[i];
1546 msg_Warn( p_demux, "Still one frame for track %u, something is wrong", i );
1547 block_ChainRelease( tk->p_frame );
1551 es_out_Del( p_demux->out, tk->p_es );
1555 p_sys->track[i] = 0;