diff --git a/modules/demux/asf/asf.c b/modules/demux/asf/asf.c index acd4410dfb1470ac12e9df104886fb91bae20bf3..905b5d7cc8decb61d6f9a8422c0b27b5f131268c 100644 --- a/modules/demux/asf/asf.c +++ b/modules/demux/asf/asf.c @@ -71,7 +71,7 @@ vlc_module_end () *****************************************************************************/ static int Demux ( demux_t * ); static int Control( demux_t *, int i_query, va_list args ); -static void FlushRemainingPackets( demux_t *p_demux ); +static void FlushQueues( demux_t *p_demux ); #define MAX_ASF_TRACKS (ASF_MAX_STREAMNUMBER + 1) #define ASF_PREROLL_FROM_CURRENT -1 @@ -79,10 +79,12 @@ static void FlushRemainingPackets( demux_t *p_demux ); /* callbacks for packet parser */ static void Packet_UpdateTime( asf_packet_sys_t *p_packetsys, uint8_t i_stream_number, mtime_t i_time ); +static void Packet_SetSendTime( asf_packet_sys_t *p_packetsys, mtime_t i_time); +static bool Block_Dequeue( demux_t *p_demux, mtime_t i_nexttime ); static asf_track_info_t * Packet_GetTrackInfo( asf_packet_sys_t *p_packetsys, uint8_t i_stream_number ); static bool Packet_DoSkip( asf_packet_sys_t *p_packetsys, uint8_t i_stream_number, bool b_packet_keyframe ); -static void Packet_Send(asf_packet_sys_t *p_packetsys, uint8_t i_stream_number, block_t **pp_frame); +static void Packet_Enqueue( asf_packet_sys_t *p_packetsys, uint8_t i_stream_number, block_t **pp_frame ); static void Packet_SetAR( asf_packet_sys_t *p_packetsys, uint8_t i_stream_number, uint8_t i_ratio_x, uint8_t i_ratio_y ); @@ -98,13 +100,22 @@ typedef struct asf_track_info_t info; + struct + { + block_t *p_first; + block_t **pp_last; + } queue; + } asf_track_t; struct demux_sys_t { mtime_t i_time; /* s */ + mtime_t i_sendtime; mtime_t i_length; /* length of file file */ uint64_t i_bitrate; /* global file bitrate */ + bool b_eos; /* end of current stream */ + bool b_eof; /* end of current media */ asf_object_root_t *p_root; asf_object_file_properties_t *p_fp; @@ -128,7 +139,6 @@ struct demux_sys_t vlc_meta_t *meta; }; -static mtime_t GetMoviePTS( demux_sys_t * ); static int DemuxInit( demux_t * ); static void DemuxEnd( demux_t * ); @@ -162,9 +172,10 @@ static int Open( vlc_object_t * p_this ) p_sys->packet_sys.p_demux = p_demux; p_sys->packet_sys.pf_doskip = Packet_DoSkip; - p_sys->packet_sys.pf_send = Packet_Send; + p_sys->packet_sys.pf_send = Packet_Enqueue; p_sys->packet_sys.pf_gettrackinfo = Packet_GetTrackInfo; p_sys->packet_sys.pf_updatetime = Packet_UpdateTime; + p_sys->packet_sys.pf_updatesendtime = Packet_SetSendTime; p_sys->packet_sys.pf_setaspectratio = Packet_SetAR; return VLC_SUCCESS; @@ -173,6 +184,7 @@ static int Open( vlc_object_t * p_this ) /***************************************************************************** * Demux: read packet and send them to decoders *****************************************************************************/ +#define CHUNK (CLOCK_FREQ / 10) static int Demux( demux_t *p_demux ) { demux_sys_t *p_sys = p_demux->p_sys; @@ -198,30 +210,48 @@ static int Demux( demux_t *p_demux ) tk->b_selected = false; } - for( ;; ) + while( !p_sys->b_eos && p_sys->i_sendtime - p_sys->i_time < (mtime_t)p_sys->p_fp->i_preroll * 1000 + CHUNK ) { - const uint8_t *p_peek; - mtime_t i_length; - mtime_t i_time_begin = GetMoviePTS( p_sys ); - int i_result; + /* Read and demux a packet */ + if( DemuxASFPacket( &p_sys->packet_sys, + p_sys->p_fp->i_min_data_packet_size, + p_sys->p_fp->i_max_data_packet_size ) <= 0 ) + { + p_sys->b_eos = true; + /* Check if we have concatenated files */ + const uint8_t *p_peek; + if( stream_Peek( p_demux->s, &p_peek, 16 ) == 16 ) + { + guid_t guid; -#if 0 - /* FIXME: returns EOF too early for some mms streams */ - if( p_sys->i_data_end >= 0 && - stream_Tell( p_demux->s ) >= p_sys->i_data_end ) - return 0; /* EOF */ -#endif + ASF_GetGUID( &guid, p_peek ); + p_sys->b_eof = !guidcmp( &guid, &asf_object_header_guid ); + if( !p_sys->b_eof ) + msg_Warn( p_demux, "found a new ASF header" ); + } + else + p_sys->b_eof = true; + } - /* Check if we have concatenated files */ - if( stream_Peek( p_demux->s, &p_peek, 16 ) == 16 ) - { - guid_t guid; + if ( p_sys->i_time == -1 ) + p_sys->i_time = p_sys->i_sendtime; + } - ASF_GetGUID( &guid, p_peek ); - if( guidcmp( &guid, &asf_object_header_guid ) ) + if( p_sys->b_eos || + (p_sys->i_sendtime >= p_sys->i_time + (mtime_t)p_sys->p_fp->i_preroll * 1000 + CHUNK) ) + { + bool b_data = Block_Dequeue( p_demux, p_sys->i_time + CHUNK ); + + p_sys->i_time += CHUNK; + es_out_Control( p_demux->out, ES_OUT_SET_PCR, VLC_TS_0 + p_sys->i_time ); +#ifdef ASF_DEBUG + msg_Dbg( p_demux, "Demux Loop Setting PCR to %"PRId64, VLC_TS_0 + p_sys->i_time ); +#endif + if ( !b_data && p_sys->b_eos ) + { + /* We end this stream */ + if( !p_sys->b_eof ) { - msg_Warn( p_demux, "found a new ASF header" ); - /* We end this stream */ DemuxEnd( p_demux ); /* And we prepare to read the next one */ @@ -229,42 +259,14 @@ static int Demux( demux_t *p_demux ) { msg_Err( p_demux, "failed to load the new header" ); dialog_Fatal( p_demux, _("Could not demux ASF stream"), "%s", - _("VLC failed to load the ASF header.") ); + _("VLC failed to load the ASF header.") ); return 0; } es_out_Control( p_demux->out, ES_OUT_RESET_PCR ); - continue; } + else + return VLC_DEMUXER_EOF; } - - /* Read and demux a packet */ - if( ( i_result = DemuxASFPacket( &p_sys->packet_sys, - p_sys->p_fp->i_min_data_packet_size, - p_sys->p_fp->i_max_data_packet_size ) ) <= 0 ) - { - FlushRemainingPackets( p_demux ); - return i_result; - } - if( i_time_begin == -1 ) - { - i_time_begin = GetMoviePTS( p_sys ); - } - else - { - i_length = GetMoviePTS( p_sys ) - i_time_begin; - if( i_length < 0 || i_length >= 40 * 1000 ) break; - } - } - - /* Set the PCR */ - /* WARN: Don't move it before the end of the whole chunk */ - p_sys->i_time = GetMoviePTS( p_sys ); - if( p_sys->i_time >= 0 ) - { -#ifdef ASF_DEBUG - msg_Dbg( p_demux, "Demux Loop Setting PCR to %"PRId64, VLC_TS_0 + p_sys->i_time ); -#endif - es_out_Control( p_demux->out, ES_OUT_SET_PCR, VLC_TS_0 + p_sys->i_time ); } return 1; @@ -382,18 +384,17 @@ static void SeekPrepare( demux_t *p_demux ) { demux_sys_t *p_sys = p_demux->p_sys; - p_sys->i_time = VLC_TS_INVALID; + p_sys->b_eof = false; + p_sys->b_eos = false; + p_sys->i_time = -1; + p_sys->i_sendtime = -1; p_sys->i_preroll_start = ASFPACKET_PREROLL_FROM_CURRENT; + FlushQueues( p_demux ); for( int i = 0; i < MAX_ASF_TRACKS ; i++ ) { asf_track_t *tk = p_sys->track[i]; - if( !tk ) - continue; - - tk->i_time = -1; - if( tk->info.p_frame ) - block_ChainRelease( tk->info.p_frame ); - tk->info.p_frame = NULL; + if( tk ) + tk->i_time = -1; } es_out_Control( p_demux->out, ES_OUT_RESET_PCR ); @@ -528,38 +529,6 @@ static int Control( demux_t *p_demux, int i_query, va_list args ) /***************************************************************************** * *****************************************************************************/ -static mtime_t GetMoviePTS( demux_sys_t *p_sys ) -{ - mtime_t i_time = -1; - int i; - /* As some tracks might have been deselected by access, the PCR might - * stop updating */ - for( i = 0; i < MAX_ASF_TRACKS ; i++ ) - { - const asf_track_t *tk = p_sys->track[i]; - - if( tk && tk->p_es && tk->b_selected ) - { - /* Skip discrete tracks */ - if ( tk->i_cat != VIDEO_ES && tk->i_cat != AUDIO_ES ) - continue; - - /* We need to have all ES seen once, as they might have lower DTS */ - if ( tk->i_time + (int64_t)p_sys->p_fp->i_preroll * 1000 < 0 ) - { - /* early fail */ - return -1; - } - else if ( tk->i_time > -1 && ( i_time == -1 || i_time > tk->i_time ) ) - { - i_time = tk->i_time; - } - } - } - - return i_time; -} - static void Packet_SetAR( asf_packet_sys_t *p_packetsys, uint8_t i_stream_number, uint8_t i_ratio_x, uint8_t i_ratio_y ) { @@ -583,6 +552,11 @@ static void Packet_SetAR( asf_packet_sys_t *p_packetsys, uint8_t i_stream_number tk->p_fmt->video.i_sar_den = i_ratio_y; } +static void Packet_SetSendTime( asf_packet_sys_t *p_packetsys, mtime_t i_time ) +{ + p_packetsys->p_demux->p_sys->i_sendtime = i_time; +} + static void Packet_UpdateTime( asf_packet_sys_t *p_packetsys, uint8_t i_stream_number, mtime_t i_time ) { @@ -635,30 +609,60 @@ static bool Packet_DoSkip( asf_packet_sys_t *p_packetsys, uint8_t i_stream_numbe return false; } -static void Packet_Send(asf_packet_sys_t *p_packetsys, uint8_t i_stream_number, block_t **pp_frame) +static void Packet_Enqueue( asf_packet_sys_t *p_packetsys, uint8_t i_stream_number, block_t **pp_frame ) { demux_t *p_demux = p_packetsys->p_demux; demux_sys_t *p_sys = p_demux->p_sys; - const asf_track_t *tk = p_sys->track[i_stream_number]; + asf_track_t *tk = p_sys->track[i_stream_number]; if ( !tk ) return; block_t *p_gather = block_ChainGather( *pp_frame ); - - if( p_sys->i_time < VLC_TS_0 && tk->i_time > VLC_TS_INVALID ) + if( p_gather ) { - p_sys->i_time = tk->i_time; - es_out_Control( p_demux->out, ES_OUT_SET_PCR, VLC_TS_0 + p_sys->i_time ); + block_ChainLastAppend( & tk->queue.pp_last, p_gather ); #ifdef ASF_DEBUG - msg_Dbg( p_demux, " setting PCR to %"PRId64, VLC_TS_0 + p_sys->i_time ); + msg_Dbg( p_demux, " enqueue packet dts %"PRId64" pts %"PRId64" pcr %"PRId64, p_gather->i_dts, p_gather->i_pts, p_sys->i_time ); #endif } + *pp_frame = NULL; +} + +static bool Block_Dequeue( demux_t *p_demux, mtime_t i_nexttime ) +{ + demux_sys_t *p_sys = p_demux->p_sys; + bool b_tracks_have_data = false; + for( int i = 0; i < MAX_ASF_TRACKS; i++ ) + { + asf_track_t *tk = p_sys->track[i]; + if (!tk) + continue; + b_tracks_have_data |= (tk->queue.p_first != NULL); + while( tk->queue.p_first && tk->queue.p_first->i_dts <= i_nexttime ) + { + block_t *p_block = tk->queue.p_first; + tk->queue.p_first = p_block->p_next; + if( tk->queue.p_first == NULL ) + tk->queue.pp_last = &tk->queue.p_first; + else + p_block->p_next = NULL; + + if( p_sys->i_time < VLC_TS_0 ) + { + es_out_Control( p_demux->out, ES_OUT_SET_PCR, VLC_TS_0 + p_sys->i_time ); #ifdef ASF_DEBUG - msg_Dbg( p_demux, " sending packet dts %"PRId64" pts %"PRId64" pcr %"PRId64, p_gather->i_dts, p_gather->i_pts, p_sys->i_time ); + msg_Dbg( p_demux, " dequeue setting PCR to %"PRId64, VLC_TS_0 + p_sys->i_time ); #endif - es_out_Send( p_demux->out, tk->p_es, p_gather ); - *pp_frame = NULL; + } + +#ifdef ASF_DEBUG + msg_Dbg( p_demux, " sending packet dts %"PRId64" pts %"PRId64" pcr %"PRId64, p_block->i_dts, p_block->i_pts, p_sys->i_time ); +#endif + es_out_Send( p_demux->out, tk->p_es, p_block ); + } + } + return b_tracks_have_data; } /***************************************************************************** @@ -743,7 +747,10 @@ static int DemuxInit( demux_t *p_demux ) /* init context */ p_sys->i_time = -1; + p_sys->i_sendtime = -1; p_sys->i_length = 0; + p_sys->b_eos = false; + p_sys->b_eof = false; p_sys->i_bitrate = 0; p_sys->p_root = NULL; p_sys->p_fp = NULL; @@ -837,6 +844,8 @@ static int DemuxInit( demux_t *p_demux ) tk->p_es = NULL; tk->info.p_esp = NULL; tk->info.p_frame = NULL; + tk->queue.p_first = NULL; + tk->queue.pp_last = &tk->queue.p_first; if ( strncmp( p_demux->psz_access, "mms", 3 ) ) { @@ -1228,17 +1237,28 @@ error: } /***************************************************************************** - * FlushRemainingPackets: flushes tail packets + * FlushQueues: flushes tail packets and send queues *****************************************************************************/ -static void FlushRemainingPackets( demux_t *p_demux ) +static void FlushQueues( demux_t *p_demux ) { demux_sys_t *p_sys = p_demux->p_sys; for ( unsigned int i = 0; i < MAX_ASF_TRACKS; i++ ) { asf_track_t *tk = p_sys->track[i]; - if( tk && tk->info.p_frame ) - Packet_Send( &p_sys->packet_sys, i, &tk->info.p_frame ); + if( !tk ) + continue; + if( tk->info.p_frame ) + { + block_ChainRelease( tk->info.p_frame ); + tk->info.p_frame = NULL; + } + if( tk->queue.p_first ) + { + block_ChainRelease( tk->queue.p_first ); + tk->queue.p_first = NULL; + tk->queue.pp_last = &tk->queue.p_first; + } } } @@ -1260,15 +1280,14 @@ static void DemuxEnd( demux_t *p_demux ) p_sys->meta = NULL; } + FlushQueues( p_demux ); + for( int i = 0; i < MAX_ASF_TRACKS; i++ ) { asf_track_t *tk = p_sys->track[i]; if( tk ) { - if( tk->info.p_frame ) - block_ChainRelease( tk->info.p_frame ); - if( tk->p_es ) { es_out_Del( p_demux->out, tk->p_es ); diff --git a/modules/demux/asf/asfpacket.c b/modules/demux/asf/asfpacket.c index b69c8a9b950bbc74f865c96ec5e330313fa1f5e7..526fd666f4c0e8381c4be5c2e85200aa1ab485ea 100644 --- a/modules/demux/asf/asfpacket.c +++ b/modules/demux/asf/asfpacket.c @@ -245,7 +245,6 @@ static int DemuxPayload(asf_packet_sys_t *p_packetsys, asf_packet_t *pkt, int i_ { /* optional DWORDS missing */ i_base_pts = (mtime_t)pkt->send_time; - i_base_pts -= *p_packetsys->pi_preroll; } /* Compressed payload */ else if( i_replicated_data_length == 1 ) @@ -298,25 +297,17 @@ static int DemuxPayload(asf_packet_sys_t *p_packetsys, asf_packet_t *pkt, int i_ p_packetsys->pf_doskip( p_packetsys, i_stream_number, b_packet_keyframe ) ) goto skip; - bool b_hugedelay = ( *p_packetsys->pi_preroll * 1000 > CLOCK_FREQ * 3 ); - - if ( b_preroll_done || b_hugedelay ) + if ( b_preroll_done ) { - mtime_t i_track_time; - if ( !b_hugedelay ) - { - i_track_time = INT64_C(1000) * pkt->send_time; - i_track_time -= *p_packetsys->pi_preroll * 1000; - if ( p_tkinfo->p_sp ) - i_track_time -= p_tkinfo->p_sp->i_time_offset * 10; - } - else - i_track_time = i_base_pts; + mtime_t i_track_time = i_base_pts; if ( p_packetsys->pf_updatetime ) p_packetsys->pf_updatetime( p_packetsys, i_stream_number, i_track_time ); } + if( p_packetsys->pf_updatesendtime ) + p_packetsys->pf_updatesendtime( p_packetsys, INT64_C(1000) * pkt->send_time ); + uint32_t i_subpayload_count = 0; while (i_payload_data_length) { @@ -333,14 +324,11 @@ static int DemuxPayload(asf_packet_sys_t *p_packetsys, asf_packet_t *pkt, int i_ if ( p_tkinfo->p_sp ) i_payload_pts -= p_tkinfo->p_sp->i_time_offset * 10; - mtime_t i_payload_dts = INT64_C(1000) * pkt->send_time; - i_payload_dts -= *p_packetsys->pi_preroll * 1000; + mtime_t i_payload_dts = i_base_pts; + if ( p_tkinfo->p_sp ) i_payload_dts -= p_tkinfo->p_sp->i_time_offset * 10; - if ( b_hugedelay ) - i_payload_dts = i_base_pts; - if ( i_sub_payload_data_length && DemuxSubPayload( p_packetsys, i_stream_number, &p_tkinfo->p_frame, i_sub_payload_data_length, i_payload_pts, i_payload_dts, diff --git a/modules/demux/asf/asfpacket.h b/modules/demux/asf/asfpacket.h index ee9de9c46de3786d7a2583f25dccd863e203847e..e8434c0d74ab5da4c1caaa7fe9a5a73cda1cf699 100644 --- a/modules/demux/asf/asfpacket.h +++ b/modules/demux/asf/asfpacket.h @@ -51,6 +51,7 @@ struct asf_packet_sys_s /* optional callbacks */ bool (*pf_doskip)(asf_packet_sys_t *, uint8_t, bool); + void (*pf_updatesendtime)(asf_packet_sys_t *, mtime_t); void (*pf_updatetime)(asf_packet_sys_t *, uint8_t, mtime_t); void (*pf_setaspectratio)(asf_packet_sys_t *, uint8_t, uint8_t, uint8_t); };