X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Finput%2Finput_ext-dec.c;h=0e15f6a7d6a712f34e12157fd40c2383eda31cb1;hb=baa735b3ee1d0136c5776e4bcf0f339641b626f5;hp=d4a04eef88d72c2baa7904a450f9e98627004fc4;hpb=b0ef1133453903177488e4347d66e5712a3dd52d;p=vlc diff --git a/src/input/input_ext-dec.c b/src/input/input_ext-dec.c index d4a04eef88..0e15f6a7d6 100644 --- a/src/input/input_ext-dec.c +++ b/src/input/input_ext-dec.c @@ -1,8 +1,8 @@ /***************************************************************************** * input_ext-dec.c: services to the decoders ***************************************************************************** - * Copyright (C) 1998, 1999, 2000 VideoLAN - * $Id: input_ext-dec.c,v 1.19 2001/09/24 11:17:49 massiot Exp $ + * Copyright (C) 1998-2001 VideoLAN + * $Id: input_ext-dec.c,v 1.45 2003/03/04 13:21:19 massiot Exp $ * * Authors: Christophe Massiot * @@ -24,53 +24,89 @@ /***************************************************************************** * Preamble *****************************************************************************/ -#include "defs.h" - #include /* memcpy(), memset() */ -#include /* off_t */ - -#include "config.h" -#include "common.h" -#include "threads.h" -#include "mtime.h" -#include "intf_msg.h" +#include #include "stream_control.h" #include "input_ext-dec.h" #include "input_ext-intf.h" #include "input_ext-plugins.h" -/***************************************************************************** - * InitBitstream: initialize a bit_stream_t structure - *****************************************************************************/ -void InitBitstream( bit_stream_t * p_bit_stream, decoder_fifo_t * p_fifo, - void (* pf_bitstream_callback)( struct bit_stream_s *, - boolean_t ), - void * p_callback_arg ) +/**************************************************************************** + * input_ExtractPES + ***************************************************************************** + * Extract a PES from the fifo. If pp_pes is NULL then the PES is just + * deleted, otherwise *pp_pes will point to this PES. + ****************************************************************************/ +void input_ExtractPES( decoder_fifo_t *p_fifo, pes_packet_t **pp_pes ) { - p_bit_stream->p_decoder_fifo = p_fifo; - p_bit_stream->pf_next_data_packet = NextDataPacket; - p_bit_stream->pf_bitstream_callback = pf_bitstream_callback; - p_bit_stream->p_callback_arg = p_callback_arg; + pes_packet_t *p_pes; - /* Get the first data packet. */ vlc_mutex_lock( &p_fifo->data_lock ); - while ( DECODER_FIFO_ISEMPTY( *p_fifo ) ) + + if( p_fifo->p_first == NULL ) { - if ( p_fifo->b_die ) + if( p_fifo->b_die ) { vlc_mutex_unlock( &p_fifo->data_lock ); + if( pp_pes ) *pp_pes = NULL; return; } + + /* Signal the input thread we're waiting. This is only + * needed in case of slave clock (ES plug-in) but it won't + * harm. */ + vlc_cond_signal( &p_fifo->data_wait ); + + /* Wait for the input to tell us when we received a packet. */ vlc_cond_wait( &p_fifo->data_wait, &p_fifo->data_lock ); } - p_bit_stream->p_data = DECODER_FIFO_START( *p_fifo )->p_first; + + p_pes = p_fifo->p_first; + p_fifo->p_first = p_pes->p_next; + p_pes->p_next = NULL; + p_fifo->i_depth--; + + if( !p_fifo->p_first ) + { + /* No PES in the FIFO. p_last is no longer valid. */ + p_fifo->pp_last = &p_fifo->p_first; + } + + vlc_mutex_unlock( &p_fifo->data_lock ); + + if( pp_pes ) + *pp_pes = p_pes; + else + input_DeletePES( p_fifo->p_packets_mgt, p_pes ); +} + +/***************************************************************************** + * InitBitstream: initialize a bit_stream_t structure and returns VLC_SUCCESS + * on success. + *****************************************************************************/ +int InitBitstream( bit_stream_t * p_bit_stream, decoder_fifo_t * p_fifo, + void (* pf_bitstream_callback)( bit_stream_t *, vlc_bool_t ), + void * p_callback_arg ) +{ + /* Get the first pes packet */ + input_ExtractPES( p_fifo, &p_bit_stream->p_pes ); + if( !p_bit_stream->p_pes ) + return VLC_EGENERIC; + + p_bit_stream->p_decoder_fifo = p_fifo; + p_bit_stream->pf_bitstream_callback = pf_bitstream_callback; + p_bit_stream->p_callback_arg = p_callback_arg; + + p_bit_stream->p_data = p_bit_stream->p_pes->p_first; p_bit_stream->p_byte = p_bit_stream->p_data->p_payload_start; p_bit_stream->p_end = p_bit_stream->p_data->p_payload_end; p_bit_stream->fifo.buffer = 0; p_bit_stream->fifo.i_available = 0; - vlc_mutex_unlock( &p_fifo->data_lock ); + p_bit_stream->i_pts = p_bit_stream->p_pes->i_pts; + p_bit_stream->i_dts = p_bit_stream->p_pes->i_dts; + p_bit_stream->p_pts_validity = p_bit_stream->p_byte; /* Call back the decoder. */ if( p_bit_stream->pf_bitstream_callback != NULL ) @@ -86,45 +122,69 @@ void InitBitstream( bit_stream_t * p_bit_stream, decoder_fifo_t * p_fifo, * sizeof(WORD_TYPE) - 1 empty bytes in the bit buffer. */ AlignWord( p_bit_stream ); } + + return VLC_SUCCESS; } /***************************************************************************** - * NextDataPacket: go to the next data packet + * CloseBitstream: free the bitstream structure. *****************************************************************************/ -void NextDataPacket( bit_stream_t * p_bit_stream ) +void CloseBitstream( bit_stream_t * p_bit_stream ) { - decoder_fifo_t * p_fifo = p_bit_stream->p_decoder_fifo; - boolean_t b_new_pes; + if( p_bit_stream->p_pes ) + input_DeletePES( p_bit_stream->p_decoder_fifo->p_packets_mgt, + p_bit_stream->p_pes ); +} + +/***************************************************************************** + * DecoderError : an error occured, use this function to empty the fifo + *****************************************************************************/ +void DecoderError( decoder_fifo_t * p_fifo ) +{ + /* No need to take the lock, because input_ExtractPES already takes it + * and also check for p_fifo->b_die */ + + /* Wait until a `die' order is sent */ + while( !p_fifo->b_die ) + { + /* Trash all received PES packets */ + input_ExtractPES( p_fifo, NULL ); + } +} + +/***************************************************************************** + * NextDataPacket: go to the data packet after *pp_data, return 1 if we + * changed PES. This function can fail in case of end of stream, you can + * check p_bit_stream->p_data or p_bit_stream->p_pes to know wether we did get + * the next data packet. + *****************************************************************************/ +static inline vlc_bool_t _NextDataPacket( decoder_fifo_t * p_fifo, + bit_stream_t * p_bit_stream ) +{ + vlc_bool_t b_new_pes; /* We are looking for the next data packet that contains real data, * and not just a PES header */ do { + /* Sanity check. Yes, this can happen if the caller doesn't check + * for p_fifo->b_die beforehand. */ + if( p_bit_stream->p_pes == NULL ) return 0; + /* We were reading the last data packet of this PES packet... It's * time to jump to the next PES packet */ if( p_bit_stream->p_data->p_next == NULL ) { - /* We are going to read/write the start and end indexes of the - * decoder fifo and to use the fifo's conditional variable, - * that's why we need to take the lock before. */ - vlc_mutex_lock( &p_fifo->data_lock ); - - /* Free the previous PES packet. */ - p_fifo->pf_delete_pes( p_fifo->p_packets_mgt, - DECODER_FIFO_START( *p_fifo ) ); - DECODER_FIFO_INCSTART( *p_fifo ); - - if( DECODER_FIFO_ISEMPTY( *p_fifo ) ) + /* The next packet could be found in the next PES packet */ + input_DeletePES( p_fifo->p_packets_mgt, p_bit_stream->p_pes ); + input_ExtractPES( p_fifo, &p_bit_stream->p_pes ); + if( !p_bit_stream->p_pes ) { - /* Wait for the input to tell us when we receive a packet. */ - vlc_cond_wait( &p_fifo->data_wait, &p_fifo->data_lock ); - } - - /* The next byte could be found in the next PES packet */ - p_bit_stream->p_data = DECODER_FIFO_START( *p_fifo )->p_first; - - vlc_mutex_unlock( &p_fifo->data_lock ); - + /* Couldn't get the next PES, might be an eos */ + p_bit_stream->p_data = NULL; + return 0; + } + p_bit_stream->p_data = p_bit_stream->p_pes->p_first; b_new_pes = 1; } else @@ -135,8 +195,29 @@ void NextDataPacket( bit_stream_t * p_bit_stream ) b_new_pes = 0; } - } while ( p_bit_stream->p_data->p_payload_start - == p_bit_stream->p_data->p_payload_end ); + } while ( p_bit_stream->p_data->p_payload_start == + p_bit_stream->p_data->p_payload_end ); + + return( b_new_pes ); +} + +vlc_bool_t NextDataPacket( decoder_fifo_t * p_fifo, + bit_stream_t * p_bit_stream ) +{ + return( _NextDataPacket( p_fifo, p_bit_stream ) ); +} + +/***************************************************************************** + * BitstreamNextDataPacket: go to the next data packet, and update bitstream + * context. This function can fail in case of eos! + *****************************************************************************/ +static inline void _BitstreamNextDataPacket( bit_stream_t * p_bit_stream ) +{ + decoder_fifo_t * p_fifo = p_bit_stream->p_decoder_fifo; + vlc_bool_t b_new_pes; + + b_new_pes = _NextDataPacket( p_fifo, p_bit_stream ); + if( !p_bit_stream->p_pes ) return; /* We've found a data packet which contains interesting data... */ p_bit_stream->p_byte = p_bit_stream->p_data->p_payload_start; @@ -147,16 +228,35 @@ void NextDataPacket( bit_stream_t * p_bit_stream ) { p_bit_stream->pf_bitstream_callback( p_bit_stream, b_new_pes ); } + + /* Discontinuity management. */ + if( p_bit_stream->p_data->b_discard_payload ) + { + p_bit_stream->i_pts = p_bit_stream->i_dts = 0; + } + + /* Retrieve the PTS. */ + if( b_new_pes && p_bit_stream->p_pes->i_pts ) + { + p_bit_stream->i_pts = p_bit_stream->p_pes->i_pts; + p_bit_stream->i_dts = p_bit_stream->p_pes->i_dts; + p_bit_stream->p_pts_validity = p_bit_stream->p_byte; + } +} + +void BitstreamNextDataPacket( bit_stream_t * p_bit_stream ) +{ + _BitstreamNextDataPacket( p_bit_stream ); } /***************************************************************************** * UnalignedShowBits : places i_bits bits into the bit buffer, even when * not aligned on a word boundary *****************************************************************************/ -void UnalignedShowBits( bit_stream_t * p_bit_stream, unsigned int i_bits ) +u32 UnalignedShowBits( bit_stream_t * p_bit_stream, unsigned int i_bits ) { /* We just fill in the bit buffer. */ - while( p_bit_stream->fifo.i_available < i_bits ) + while( (unsigned int)p_bit_stream->fifo.i_available < i_bits ) { if( p_bit_stream->p_byte < p_bit_stream->p_end ) { @@ -167,14 +267,15 @@ void UnalignedShowBits( bit_stream_t * p_bit_stream, unsigned int i_bits ) } else { - p_bit_stream->pf_next_data_packet( p_bit_stream ); + _BitstreamNextDataPacket( p_bit_stream ); + if( p_bit_stream->p_decoder_fifo->b_die ) return 0; if( (ptrdiff_t)p_bit_stream->p_byte & (sizeof(WORD_TYPE) - 1) ) { /* We are not aligned anymore. */ if( ((ptrdiff_t)p_bit_stream->p_byte & (sizeof(WORD_TYPE) - 1)) * 8 - < p_bit_stream->fifo.i_available ) + < (unsigned int)p_bit_stream->fifo.i_available ) { /* We are not aligned, and won't be. Copy the first word * of the packet in a temporary buffer, and we'll see @@ -187,12 +288,13 @@ void UnalignedShowBits( bit_stream_t * p_bit_stream, unsigned int i_bits ) p_bit_stream->i_showbits_buffer = 0; - for( j = i = 0 ; i < sizeof(WORD_TYPE) ; i++ ) + for( j = i = 0 ; i < (int)sizeof(WORD_TYPE) ; i++ ) { if( p_bit_stream->p_byte >= p_bit_stream->p_end ) { j = i; - p_bit_stream->pf_next_data_packet( p_bit_stream ); + _BitstreamNextDataPacket( p_bit_stream ); + if( p_bit_stream->p_decoder_fifo->b_die ) return 0; } ((byte_t *)&p_bit_stream->i_showbits_buffer)[i] = * p_bit_stream->p_byte; @@ -221,6 +323,9 @@ void UnalignedShowBits( bit_stream_t * p_bit_stream, unsigned int i_bits ) break; } } + + /* It shouldn't loop :-)) */ + return( ShowBits( p_bit_stream, i_bits ) ); } /***************************************************************************** @@ -246,7 +351,8 @@ u32 UnalignedGetBits( bit_stream_t * p_bit_stream, unsigned int i_bits ) } else { - p_bit_stream->pf_next_data_packet( p_bit_stream ); + _BitstreamNextDataPacket( p_bit_stream ); + if( p_bit_stream->p_decoder_fifo->b_die ) return 0; i_result |= *(p_bit_stream->p_byte++) << (i_bits - 8); i_bits -= 8; } @@ -266,7 +372,8 @@ u32 UnalignedGetBits( bit_stream_t * p_bit_stream, unsigned int i_bits ) } else { - p_bit_stream->pf_next_data_packet( p_bit_stream ); + _BitstreamNextDataPacket( p_bit_stream ); + if( p_bit_stream->p_decoder_fifo->b_die ) return 0; i_result |= *p_bit_stream->p_byte >> i_tmp; p_bit_stream->fifo.buffer = *(p_bit_stream->p_byte++) << ( sizeof(WORD_TYPE) * 8 - i_tmp ); @@ -308,7 +415,8 @@ void UnalignedRemoveBits( bit_stream_t * p_bit_stream ) } else { - p_bit_stream->pf_next_data_packet( p_bit_stream ); + _BitstreamNextDataPacket( p_bit_stream ); + if( p_bit_stream->p_decoder_fifo->b_die ) return; p_bit_stream->p_byte++; p_bit_stream->fifo.i_available += 8; } @@ -326,7 +434,8 @@ void UnalignedRemoveBits( bit_stream_t * p_bit_stream ) } else { - p_bit_stream->pf_next_data_packet( p_bit_stream ); + _BitstreamNextDataPacket( p_bit_stream ); + if( p_bit_stream->p_decoder_fifo->b_die ) return; p_bit_stream->fifo.buffer = *(p_bit_stream->p_byte++) << ( sizeof(WORD_TYPE) * 8 - 8 - p_bit_stream->fifo.i_available ); @@ -349,3 +458,52 @@ void UnalignedRemoveBits( bit_stream_t * p_bit_stream ) } } +/***************************************************************************** + * CurrentPTS: returns the current PTS and DTS + *****************************************************************************/ +void CurrentPTS( bit_stream_t * p_bit_stream, mtime_t * pi_pts, + mtime_t * pi_dts ) +{ + /* Check if the current PTS is already valid (ie. if the first byte + * of the packet has already been used in the decoder). */ + ptrdiff_t p_diff = p_bit_stream->p_pts_validity - p_bit_stream->p_byte; + if( p_diff < 0 || p_diff > 4 /* We are far away so it is valid */ + || (p_diff * 8) >= p_bit_stream->fifo.i_available + /* We have buffered less bytes than actually read */ ) + { + *pi_pts = p_bit_stream->i_pts; + if( pi_dts != NULL ) *pi_dts = p_bit_stream->i_dts; + p_bit_stream->i_pts = 0; + p_bit_stream->i_dts = 0; + } + else + { + *pi_pts = 0; + if( pi_dts != NULL) *pi_dts = 0; + } +} + +/***************************************************************************** + * NextPTS: returns the PTS and DTS for the next starting byte + *****************************************************************************/ +void NextPTS( bit_stream_t * p_bit_stream, mtime_t * pi_pts, + mtime_t * pi_dts ) +{ + /* Check if the current PTS is already valid (ie. if the first byte + * of the packet has already been used in the decoder). */ + ptrdiff_t p_diff = p_bit_stream->p_pts_validity - p_bit_stream->p_byte - 1; + if( p_diff < 0 || p_diff > 4 /* We are far away so it is valid */ + || (p_diff * 8) >= p_bit_stream->fifo.i_available + /* We have buffered less bytes than actually read */ ) + { + *pi_pts = p_bit_stream->i_pts; + if( pi_dts != NULL ) *pi_dts = p_bit_stream->i_dts; + p_bit_stream->i_pts = 0; + p_bit_stream->i_dts = 0; + } + else + { + *pi_pts = 0; + if( pi_dts != NULL) *pi_dts = 0; + } +}