/*****************************************************************************
* input_ext-dec.c: services to the decoders
*****************************************************************************
- * Copyright (C) 1998, 1999, 2000 VideoLAN
- * $Id: input_ext-dec.c,v 1.16 2001/05/08 00:43:57 sam Exp $
+ * Copyright (C) 1998-2001 VideoLAN
+ * $Id: input_ext-dec.c,v 1.36 2002/10/23 23:17:44 gbazin Exp $
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
*
/*****************************************************************************
* Preamble
*****************************************************************************/
-#include "defs.h"
-
#include <string.h> /* memcpy(), memset() */
#include <sys/types.h> /* off_t */
-#include "config.h"
-#include "common.h"
-#include "threads.h"
-#include "mtime.h"
-
-#include "intf_msg.h"
+#include <vlc/vlc.h>
#include "stream_control.h"
#include "input_ext-dec.h"
#include "input_ext-intf.h"
-
-#include "input.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 )
+ void (* pf_bitstream_callback)( bit_stream_t *, vlc_bool_t ),
+ void * p_callback_arg )
{
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;
/* Get the first data packet. */
vlc_mutex_lock( &p_fifo->data_lock );
- while ( DECODER_FIFO_ISEMPTY( *p_fifo ) )
+ while ( p_fifo->p_first == NULL )
{
if ( p_fifo->b_die )
{
}
vlc_cond_wait( &p_fifo->data_wait, &p_fifo->data_lock );
}
- p_bit_stream->p_data = DECODER_FIFO_START( *p_fifo )->p_first;
+ p_bit_stream->p_data = p_fifo->p_first->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;
+ p_bit_stream->i_pts = p_fifo->p_first->i_pts;
+ p_bit_stream->i_dts = p_fifo->p_first->i_dts;
+ p_bit_stream->p_pts_validity = p_bit_stream->p_byte;
vlc_mutex_unlock( &p_fifo->data_lock );
/* Call back the decoder. */
}
/*****************************************************************************
- * NextDataPacket: go to the next data packet
+ * DecoderError : an error occured, use this function to empty the fifo
*****************************************************************************/
-void NextDataPacket( bit_stream_t * p_bit_stream )
+void DecoderError( decoder_fifo_t * p_fifo )
{
- decoder_fifo_t * p_fifo = p_bit_stream->p_decoder_fifo;
- boolean_t b_new_pes;
+ /* We take the lock, because we are going to read/write the start/end
+ * indexes of the decoder fifo */
+ vlc_mutex_lock (&p_fifo->data_lock);
+
+ /* Wait until a `die' order is sent */
+ while (!p_fifo->b_die)
+ {
+ /* Trash all received PES packets */
+ input_DeletePES( p_fifo->p_packets_mgt, p_fifo->p_first );
+ p_fifo->p_first = NULL;
+ p_fifo->pp_last = &p_fifo->p_first;
+
+ /* If the input is waiting for us, tell him to stop */
+ vlc_cond_signal( &p_fifo->data_wait );
+
+ /* Waiting for the input thread to put new PES packets in the fifo */
+ vlc_cond_wait (&p_fifo->data_wait, &p_fifo->data_lock);
+ }
+
+ /* We can release the lock before leaving */
+ vlc_mutex_unlock (&p_fifo->data_lock);
+}
+
+/*****************************************************************************
+ * GetPES: return the first PES from the fifo
+ *****************************************************************************/
+static inline pes_packet_t *_GetPES( decoder_fifo_t * p_fifo )
+{
+ pes_packet_t * p_pes;
+
+ vlc_mutex_lock( &p_fifo->data_lock );
+
+ if( p_fifo->p_first == NULL )
+ {
+ /* No PES in the FIFO. p_last is no longer valid. */
+ p_fifo->pp_last = &p_fifo->p_first;
+
+ if( p_fifo->b_die )
+ {
+ vlc_mutex_unlock( &p_fifo->data_lock );
+ return NULL;
+ }
+
+ /* 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 receive a packet. */
+ vlc_cond_wait( &p_fifo->data_wait, &p_fifo->data_lock );
+ }
+
+ p_pes = p_fifo->p_first;
+
+ vlc_mutex_unlock( &p_fifo->data_lock );
+
+ return p_pes;
+}
+
+pes_packet_t * GetPES( decoder_fifo_t * p_fifo )
+{
+ return( _GetPES( p_fifo ) );
+}
+
+/*****************************************************************************
+ * NextPES: free the current PES and return the next one
+ *****************************************************************************/
+static inline pes_packet_t * _NextPES( decoder_fifo_t * p_fifo )
+{
+ pes_packet_t * p_next;
+
+ vlc_mutex_lock( &p_fifo->data_lock );
+
+ /* Free the previous PES packet. */
+ p_next = p_fifo->p_first->p_next;
+ p_fifo->p_first->p_next = NULL;
+ input_DeletePES( p_fifo->p_packets_mgt, p_fifo->p_first );
+ p_fifo->p_first = p_next;
+ p_fifo->i_depth--;
+
+ vlc_mutex_unlock( &p_fifo->data_lock );
+
+ return _GetPES( p_fifo );
+}
+
+pes_packet_t * NextPES( decoder_fifo_t * p_fifo )
+{
+ return( _NextPES( p_fifo ) );
+}
+
+/*****************************************************************************
+ * NextDataPacket: go to the data packet after *pp_data, return 1 if we
+ * changed PES
+ *****************************************************************************/
+static inline vlc_bool_t _NextDataPacket( decoder_fifo_t * p_fifo,
+ data_packet_t ** pp_data )
+{
+ vlc_bool_t b_new_pes;
/* We are looking for the next data packet that contains real data,
* and not just a PES header */
{
/* 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 )
+ if( (*pp_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 ) )
- {
- /* 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 );
+ /* The next packet could be found in the next PES packet */
+ *pp_data = (_NextPES( p_fifo ))->p_first;
b_new_pes = 1;
}
{
/* Perhaps the next data packet of the current PES packet contains
* real data (ie its payload's size is greater than 0). */
- p_bit_stream->p_data = p_bit_stream->p_data->p_next;
+ *pp_data = (*pp_data)->p_next;
b_new_pes = 0;
}
- } while ( p_bit_stream->p_data->p_payload_start
- == p_bit_stream->p_data->p_payload_end );
+ } while ( (*pp_data)->p_payload_start == (*pp_data)->p_payload_end );
+
+ return( b_new_pes );
+}
+
+vlc_bool_t NextDataPacket( decoder_fifo_t * p_fifo, data_packet_t ** pp_data )
+{
+ return( _NextDataPacket( p_fifo, pp_data ) );
+}
+
+/*****************************************************************************
+ * BitstreamNextDataPacket: go to the next data packet, and update bitstream
+ * context
+ *****************************************************************************/
+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->p_data );
/* We've found a data packet which contains interesting data... */
p_bit_stream->p_byte = p_bit_stream->p_data->p_payload_start;
{
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_fifo->p_first->i_pts )
+ {
+ p_bit_stream->i_pts = p_fifo->p_first->i_pts;
+ p_bit_stream->i_dts = p_fifo->p_first->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 : return i_bits bits from the bit stream, even when
+ * UnalignedShowBits : places i_bits bits into the bit buffer, even when
* not aligned on a word boundary
*****************************************************************************/
u32 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( (ptrdiff_t)p_bit_stream->p_byte & (sizeof(WORD_TYPE) - 1) )
{
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 );
}
((byte_t *)&p_bit_stream->i_showbits_buffer)[i] =
* p_bit_stream->p_byte;
}
}
- return( ShowBits( p_bit_stream, i_bits ) );
+ /* We have 32 bits ready for reading, it will be enough. */
+ break;
}
}
- return( p_bit_stream->fifo.buffer >> (8 * sizeof(WORD_TYPE) - i_bits) );
+
+ /* It shouldn't loop :-)) */
+ return( ShowBits( p_bit_stream, i_bits ) );
}
/*****************************************************************************
}
else
{
- p_bit_stream->pf_next_data_packet( p_bit_stream );
+ _BitstreamNextDataPacket( p_bit_stream );
i_result |= *(p_bit_stream->p_byte++) << (i_bits - 8);
i_bits -= 8;
}
}
else
{
- p_bit_stream->pf_next_data_packet( p_bit_stream );
+ _BitstreamNextDataPacket( p_bit_stream );
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 );
{
/* Get aligned on a word boundary. Otherwise it is safer
* to do it the next time.
- * NB : we _will_ get aligned, because we have at most
+ * NB : we _will_ get aligned, because we have at most
* sizeof(WORD_TYPE) - 1 bytes to store, and at least
* sizeof(WORD_TYPE) - 1 empty bytes in the bit buffer. */
AlignWord( p_bit_stream );
}
else
{
- p_bit_stream->pf_next_data_packet( p_bit_stream );
+ _BitstreamNextDataPacket( p_bit_stream );
p_bit_stream->p_byte++;
p_bit_stream->fifo.i_available += 8;
}
}
else
{
- p_bit_stream->pf_next_data_packet( p_bit_stream );
+ _BitstreamNextDataPacket( p_bit_stream );
p_bit_stream->fifo.buffer = *(p_bit_stream->p_byte++)
<< ( sizeof(WORD_TYPE) * 8 - 8
- p_bit_stream->fifo.i_available );
}
}
+/*****************************************************************************
+ * 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;
+ }
+}
+
+/****************************************************************************
+ * input_NextPES : extract a PES from the fifo. If pp_pes is NULL then this
+ * PES is deleted, else pp_pes will be set to this PES
+ ****************************************************************************/
+int input_NextPES( decoder_fifo_t *p_fifo, pes_packet_t **pp_pes )
+{
+ pes_packet_t *p_pes, *p_next;
+
+ vlc_mutex_lock( &p_fifo->data_lock );
+
+ /* if fifo is emty wait */
+ while( !p_fifo->p_first )
+ {
+ if( p_fifo->b_die )
+ {
+ vlc_mutex_unlock( &p_fifo->data_lock );
+ if( pp_pes )
+ {
+ *pp_pes = NULL;
+ }
+ return( -1 );
+ }
+ vlc_cond_signal( &p_fifo->data_wait );
+ vlc_cond_wait( &p_fifo->data_wait, &p_fifo->data_lock );
+ }
+ p_pes = p_fifo->p_first;
+
+ p_next = p_pes->p_next;
+ p_pes->p_next = NULL;
+
+
+ p_fifo->p_first = p_next;
+ p_fifo->i_depth--;
+
+ if( !p_fifo->p_first )
+ {
+ /* No PES in the fifo */
+ /* pp_last 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 );
+ }
+ return( 0 );
+}
+