diff --git a/include/parser_fifo.h b/include/parser_fifo.h new file mode 100644 index 0000000000..4439264a57 --- /dev/null +++ b/include/parser_fifo.h @@ -0,0 +1,196 @@ +/****************************************************************************** + * parser_fifo.h: interface for parsers PES fifo + * (c)1999 VideoLAN + ****************************************************************************** + * Required headers: + * - "config.h" + * - "common.h" + * - "vlc_thread.h" + * - "input.h" + ******************************************************************************/ + +/****************************************************************************** + * Macros + ******************************************************************************/ + +/* ?? move to inline functions */ +#define PARSER_FIFO_ISEMPTY( fifo ) ( (fifo).i_start == (fifo).i_end ) +#define PARSER_FIFO_ISFULL( fifo ) ( ( ( (fifo).i_end + 1 - (fifo).i_start ) \ + & FIFO_SIZE ) == 0 ) +#define PARSER_FIFO_START( fifo ) ( (fifo).buffer[ (fifo).i_start ] ) +#define PARSER_FIFO_INCSTART( fifo ) ( (fifo).i_start = ((fifo).i_start + 1) \ + & FIFO_SIZE ) +#define PARSER_FIFO_END( fifo ) ( (fifo).buffer[ (fifo).i_end ] ) +#define PARSER_FIFO_INCEND( fifo ) ( (fifo).i_end = ((fifo).i_end + 1) \ + & FIFO_SIZE ) + +/****************************************************************************** + * parser_fifo_t + ****************************************************************************** + * This rotative FIFO contains PES packets that are to be decoded... + ******************************************************************************/ +typedef struct +{ + vlc_mutex_t data_lock; /* fifo data lock */ + vlc_cond_t data_wait; /* fifo data conditional variable */ + + /* buffer is an array of PES packets pointers */ + pes_packet_t * buffer[FIFO_SIZE + 1]; + int i_start; + int i_end; + +} parser_fifo_t; + +/****************************************************************************** + * bit_fifo_t : bit fifo descriptor + ****************************************************************************** + * This type describes a bit fifo used to store bits while working with the + * input stream at the bit level. + ******************************************************************************/ +typedef struct bit_fifo_s +{ + /* This unsigned integer allows us to work at the bit level. This buffer + * can contain 32 bits, and the used space can be found on the MSb's side + * and the available space on the LSb's side. */ + u32 buffer; + + /* Number of bits available in the bit buffer */ + int i_available; + +} bit_fifo_t; + +/****************************************************************************** + * bit_stream_t : bit stream descriptor + ****************************************************************************** + * This type, based on a PES stream, includes all the structures needed to + * handle the input stream like a bit stream. + ******************************************************************************/ +typedef struct bit_stream_s +{ + /* + * Input structures + */ + /* The input thread feeds the stream with fresh PES packets */ + input_thread_t * p_input; + /* The parser fifo contains the data of the PES stream */ + parser_fifo_t * p_parser_fifo; + + /* + * Byte structures + */ + /* Current TS packet (in the current PES packet of the PES stream) */ + ts_packet_t * p_ts; + /* Index of the next byte that is to be read (in the current TS packet) */ + unsigned int i_byte; + + /* + * Bit structures + */ + bit_fifo_t fifo; + +} bit_stream_t; + + +/***************************************************************************** + * GetByte : reads the next byte in the input stream + *****************************************************************************/ +static __inline__ byte_t GetByte( bit_stream_t * p_bit_stream ) +{ + /* Is the input thread dying ? */ + if ( p_bit_stream->p_input->b_die ) + { + return( 0 ); + } + + /* Are there some bytes left in the current TS packet ? */ + if ( p_bit_stream->i_byte < p_bit_stream->p_ts->i_payload_end ) + { + return( p_bit_stream->p_ts->buffer[ p_bit_stream->i_byte++ ] ); + } + else + { + /* We are looking for the next TS packet that contains real data, + * and not just a PES header */ + do + { + /* We were reading the last TS packet of this PES packet... It's + * time to jump to the next PES packet */ + if ( p_bit_stream->p_ts->p_next_ts == NULL ) + { + /* We are going to read/write the start and end indexes of the + * parser fifo and to use the fifo's conditional variable, + * that's why we need to take the lock before */ + vlc_mutex_lock( &p_bit_stream->p_parser_fifo->data_lock ); + /* We should increase the start index of the parser fifo, but + * if we do this now, the input thread could overwrite the + * pointer to the current PES packet, and we weren't able to + * give it back to the netlist. That's why we free the PES + * packet first. */ + input_NetlistFreePES( p_bit_stream->p_input, PARSER_FIFO_START(*p_bit_stream->p_parser_fifo) ); + PARSER_FIFO_INCSTART( *p_bit_stream->p_parser_fifo ); + + while ( PARSER_FIFO_ISEMPTY(*p_bit_stream->p_parser_fifo) ) + { + vlc_cond_wait( &p_bit_stream->p_parser_fifo->data_wait, + &p_bit_stream->p_parser_fifo->data_lock ); + if ( p_bit_stream->p_input->b_die ) + { + vlc_mutex_unlock( &(p_bit_stream->p_parser_fifo->data_lock) ); + return( 0 ); + } + } + + /* The next byte could be found in the next PES packet */ + p_bit_stream->p_ts = PARSER_FIFO_START( *p_bit_stream->p_parser_fifo )->p_first_ts; + + /* We can release the fifo's data lock */ + vlc_mutex_unlock( &p_bit_stream->p_parser_fifo->data_lock ); + } + /* Perhaps the next TS packet of the current PES packet contains + * real data (ie its payload's size is greater than 0) */ + else + { + p_bit_stream->p_ts = p_bit_stream->p_ts->p_next_ts; + } + } while ( p_bit_stream->p_ts->i_payload_start == p_bit_stream->p_ts->i_payload_end ); + + /* We've found a TS packet which contains interesting data... As we + * return the payload's first byte, we set i_byte to the following + * one */ + p_bit_stream->i_byte = p_bit_stream->p_ts->i_payload_start; + return( p_bit_stream->p_ts->buffer[ p_bit_stream->i_byte++ ] ); + } +} + +/****************************************************************************** + * NeedBits : reads i_bits new bits in the bit stream and stores them in the + * bit buffer + ****************************************************************************** + * - i_bits must be less or equal 32 ! + * - There is something important to notice with that function : if the number + * of bits available in the bit buffer when calling NeedBits() is greater than + * 24 (i_available > 24) but less than the number of needed bits + * (i_available < i_bits), the byte returned by GetByte() will be shifted with + * a negative value and the number of bits available in the bit buffer will be + * set to more than 32 ! + ******************************************************************************/ +static __inline__ void NeedBits( bit_stream_t * p_bit_stream, int i_bits ) +{ + while ( p_bit_stream->fifo.i_available < i_bits ) + { + p_bit_stream->fifo.buffer |= ((u32)GetByte( p_bit_stream )) << (24 - p_bit_stream->fifo.i_available); + p_bit_stream->fifo.i_available += 8; + } +} + +/****************************************************************************** + * DumpBits : removes i_bits bits from the bit buffer + ****************************************************************************** + * - i_bits <= i_available + * - i_bits < 32 (because (u32 << 32) <=> (u32 = u32)) + ******************************************************************************/ +static __inline__ void DumpBits( bit_stream_t * p_bit_stream, int i_bits ) +{ + p_bit_stream->fifo.buffer <<= i_bits; + p_bit_stream->fifo.i_available -= i_bits; +} diff --git a/include/video_parser.h b/include/video_parser.h index 0a199e715e..3005acb28b 100644 --- a/include/video_parser.h +++ b/include/video_parser.h @@ -1,5 +1,5 @@ /******************************************************************************* - * video_decoder.h : video decoder thread + * video_parser.h : video parser thread * (c)1999 VideoLAN ******************************************************************************* ******************************************************************************* @@ -11,15 +11,15 @@ * "input.h" * "video.h" * "video_output.h" - * "decoder_fifo.h" + * "parser_fifo.h" *******************************************************************************/ /******************************************************************************* - * vdec_thread_t: video decoder thread descriptor + * vpar_thread_t: video parser thread descriptor ******************************************************************************* * ?? *******************************************************************************/ -typedef struct vdec_thread_s +typedef struct vpar_thread_s { /* Thread properties and locks */ boolean_t b_die; /* `die' flag */ @@ -35,7 +35,7 @@ typedef struct vdec_thread_s /* Input properties */ - decoder_fifo_t fifo; /* PES input fifo */ + parser_fifo_t fifo; /* PES input fifo */ /* The bit stream structure handles the PES stream at the bit level */ bit_stream_t bit_stream; @@ -58,16 +58,16 @@ typedef struct vdec_thread_s count_t c_decoded_p_pictures; /* number of P pictures decoded */ count_t c_decoded_b_pictures; /* number of B pictures decoded */ #endif -} vdec_thread_t; +} vpar_thread_t; /******************************************************************************* * Prototypes *******************************************************************************/ /* Thread management functions */ -vdec_thread_t * vdec_CreateThread ( /* video_cfg_t *p_cfg, */ input_thread_t *p_input /*, +vpar_thread_t * vpar_CreateThread ( /* video_cfg_t *p_cfg, */ input_thread_t *p_input /*, vout_thread_t *p_vout, int *pi_status */ ); -void vdec_DestroyThread ( vdec_thread_t *p_vdec /*, int *pi_status */ ); +void vpar_DestroyThread ( vpar_thread_t *p_vpar /*, int *pi_status */ ); /* Time management functions */ /* ?? */ diff --git a/src/video_parser/video_parser.c b/src/video_parser/video_parser.c index 08ccd14669..367b8b0f9c 100644 --- a/src/video_parser/video_parser.c +++ b/src/video_parser/video_parser.c @@ -1,5 +1,5 @@ /******************************************************************************* - * video_decoder.c : video decoder thread + * video_parser.c : video parser thread * (c)1999 VideoLAN *******************************************************************************/ @@ -23,7 +23,7 @@ #include "vlc_thread.h" #include "intf_msg.h" -#include "debug.h" /* ?? temporaire, requis par netlist.h */ +#include "debug.h" /* ?? temporaire, requis par netlist.h */ #include "input.h" #include "input_netlist.h" @@ -31,97 +31,99 @@ #include "video.h" #include "video_output.h" #include "video_decoder.h" +#include "video_parser.h" +#include "parser_fifo.h" /* * Local prototypes */ //static int CheckConfiguration ( video_cfg_t *p_cfg ); -static int InitThread ( vdec_thread_t *p_vdec ); -static void RunThread ( vdec_thread_t *p_vdec ); -static void ErrorThread ( vdec_thread_t *p_vdec ); -static void EndThread ( vdec_thread_t *p_vdec ); +static int InitThread ( vpar_thread_t *p_vpar ); +static void RunThread ( vpar_thread_t *p_vpar ); +static void ErrorThread ( vpar_thread_t *p_vpar ); +static void EndThread ( vpar_thread_t *p_vpar ); /******************************************************************************* - * vdec_CreateThread: create a generic decoder thread + * vpar_CreateThread: create a generic parser thread ******************************************************************************* - * This function creates a new video decoder thread, and returns a pointer + * This function creates a new video parser thread, and returns a pointer * to its description. On error, it returns NULL. * Following configuration properties are used: * ?? *******************************************************************************/ -vdec_thread_t * vpar_CreateThread( /* video_cfg_t *p_cfg, */ input_thread_t *p_input /*, +vpar_thread_t * vpar_CreateThread( /* video_cfg_t *p_cfg, */ input_thread_t *p_input /*, vout_thread_t *p_vout, int *pi_status */ ) { - vdec_thread_t * p_vdec; + vpar_thread_t * p_vpar; - intf_DbgMsg("vdec debug: creating video decoder thread\n"); + intf_DbgMsg("vpar debug: creating video parser thread\n"); /* Allocate the memory needed to store the thread's structure */ - if ( (p_vdec = (vdec_thread_t *)malloc( sizeof(vdec_thread_t) )) == NULL ) + if ( (p_vpar = (vpar_thread_t *)malloc( sizeof(vpar_thread_t) )) == NULL ) { - intf_ErrMsg("adec error: not enough memory for vdec_CreateThread() to create the new thread\n"); + intf_ErrMsg("vpar error: not enough memory for vpar_CreateThread() to create the new thread\n"); return( NULL ); } /* * Initialize the thread properties */ - p_vdec->b_die = 0; - p_vdec->b_error = 0; + p_vpar->b_die = 0; + p_vpar->b_error = 0; /* * Initialize the input properties */ - /* Initialize the decoder fifo's data lock and conditional variable and set * its buffer as empty */ - vlc_mutex_init( &p_vdec->fifo.data_lock ); - vlc_cond_init( &p_vdec->fifo.data_wait ); - p_vdec->fifo.i_start = 0; - p_vdec->fifo.i_end = 0; + /* Initialize the parser fifo's data lock and conditional variable and set * its buffer as empty */ + vlc_mutex_init( &p_vpar->fifo.data_lock ); + vlc_cond_init( &p_vpar->fifo.data_wait ); + p_vpar->fifo.i_start = 0; + p_vpar->fifo.i_end = 0; /* Initialize the bit stream structure */ - p_vdec->bit_stream.p_input = p_input; - p_vdec->bit_stream.p_decoder_fifo = &p_vdec->fifo; - p_vdec->bit_stream.fifo.buffer = 0; - p_vdec->bit_stream.fifo.i_available = 0; + p_vpar->bit_stream.p_input = p_input; + p_vpar->bit_stream.p_parser_fifo = &p_vpar->fifo; + p_vpar->bit_stream.fifo.buffer = 0; + p_vpar->bit_stream.fifo.i_available = 0; - /* Spawn the video decoder thread */ - if ( vlc_thread_create(&p_vdec->thread_id, "video decoder", (vlc_thread_func)RunThread, (void *)p_vdec) ) + /* Spawn the video parser thread */ + if ( vlc_thread_create(&p_vpar->thread_id, "video parser", (vlc_thread_func)RunThread, (void *)p_vpar) ) { - intf_ErrMsg("vdec error: can't spawn video decoder thread\n"); - free( p_vdec ); + intf_ErrMsg("vpar error: can't spawn video parser thread\n"); + free( p_vpar ); return( NULL ); } - intf_DbgMsg("vdec debug: video decoder thread (%p) created\n", p_vdec); - return( p_vdec ); + intf_DbgMsg("vpar debug: video parser thread (%p) created\n", p_vpar); + return( p_vpar ); } /******************************************************************************* - * vdec_DestroyThread: destroy a generic decoder thread + * vpar_DestroyThread: destroy a generic parser thread ******************************************************************************* * Destroy a terminated thread. This function will return 0 if the thread could * be destroyed, and non 0 else. The last case probably means that the thread * was still active, and another try may succeed. *******************************************************************************/ -void vdec_DestroyThread( vdec_thread_t *p_vdec /*, int *pi_status */ ) +void vpar g_DestroyThread( vpar_thread_t *p_vpar /*, int *pi_status */ ) { - intf_DbgMsg("vdec debug: requesting termination of video decoder thread %p\n", p_vdec); + intf_DbgMsg("vpar debug: requesting termination of video parser thread %p\n", p_vpar); /* Ask thread to kill itself */ - p_vdec->b_die = 1; - /* Make sure the decoder thread leaves the GetByte() function */ - vlc_mutex_lock( &(p_vdec->fifo.data_lock) ); - vlc_cond_signal( &(p_vdec->fifo.data_wait) ); - vlc_mutex_unlock( &(p_vdec->fifo.data_lock) ); + p_vpar->b_die = 1; + /* Make sure the parser thread leaves the GetByte() function */ + vlc_mutex_lock( &(p_vpar->fifo.data_lock) ); + vlc_cond_signal( &(p_vpar->fifo.data_wait) ); + vlc_mutex_unlock( &(p_vpar->fifo.data_lock) ); - /* Waiting for the decoder thread to exit */ + /* Waiting for the parser thread to exit */ /* Remove this as soon as the "status" flag is implemented */ - vlc_thread_join( p_vdec->thread_id ); + vlc_thread_join( p_vpar->thread_id ); } /* following functions are local */ /******************************************************************************* - * CheckConfiguration: check vdec_CreateThread() configuration + * CheckConfiguration: check vpar_CreateThread() configuration ******************************************************************************* * Set default parameters where required. In DEBUG mode, check if configuration * is valid. @@ -136,89 +138,89 @@ static int CheckConfiguration( video_cfg_t *p_cfg ) #endif /******************************************************************************* - * InitThread: initialize vdec output thread + * InitThread: initialize vpar output thread ******************************************************************************* * This function is called from RunThread and performs the second step of the * initialization. It returns 0 on success. Note that the thread's flag are not * modified inside this function. *******************************************************************************/ -static int InitThread( vdec_thread_t *p_vdec ) +static int InitThread( vpar_thread_t *p_vpar ) { - intf_DbgMsg("vdec debug: initializing video decoder thread %p\n", p_vdec); + intf_DbgMsg("vpar debug: initializing video parser thread %p\n", p_vpar); /* Our first job is to initialize the bit stream structure with the * beginning of the input stream */ - vlc_mutex_lock( &p_vdec->fifo.data_lock ); - while ( DECODER_FIFO_ISEMPTY(p_vdec->fifo) ) + vlc_mutex_lock( &p_vpar->fifo.data_lock ); + while ( PARSER_FIFO_ISEMPTY(p_vpar->fifo) ) { - vlc_cond_wait( &p_vdec->fifo.data_wait, &p_vdec->fifo.data_lock ); + vlc_cond_wait( &p_vpar->fifo.data_wait, &p_vpar->fifo.data_lock ); } - p_vdec->bit_stream.p_ts = DECODER_FIFO_START( p_vdec->fifo )->p_first_ts; - p_vdec->bit_stream.i_byte = p_vdec->bit_stream.p_ts->i_payload_start; - vlc_mutex_unlock( &p_vdec->fifo.data_lock ); + p_vpar->bit_stream.p_ts = PARSER_FIFO_START( p_vpar->fifo )->p_first_ts; + p_vpar->bit_stream.i_byte = p_vpar->bit_stream.p_ts->i_payload_start; + vlc_mutex_unlock( &p_vpar->fifo.data_lock ); #if 0 /* ?? */ /* Create video stream */ - p_vdec->i_stream = vout_CreateStream( p_vdec->p_vout ); - if( p_vdec->i_stream < 0 ) /* error */ + p_vpar->i_stream = vout_CreateStream( p_vpar->p_vout ); + if( p_vpar->i_stream < 0 ) /* error */ { return( 1 ); } - /* Initialize decoding data */ + /* Initialize parsing data */ /* ?? */ #endif /* Initialize other properties */ #ifdef STATS - p_vdec->c_loops = 0; - p_vdec->c_idle_loops = 0; - p_vdec->c_pictures = 0; - p_vdec->c_i_pictures = 0; - p_vdec->c_p_pictures = 0; - p_vdec->c_b_pictures = 0; - p_vdec->c_decoded_pictures = 0; - p_vdec->c_decoded_i_pictures = 0; - p_vdec->c_decoded_p_pictures = 0; - p_vdec->c_decoded_b_pictures = 0; + p_vpar->c_loops = 0; + p_vpar->c_idle_loops = 0; + p_vpar->c_pictures = 0; + p_vpar->c_i_pictures = 0; + p_vpar->c_p_pictures = 0; + p_vpar->c_b_pictures = 0; + p_vpar->c_decoded_pictures = 0; + p_vpar->c_decoded_i_pictures = 0; + p_vpar->c_decoded_p_pictures = 0; + p_vpar->c_decoded_b_pictures = 0; #endif /* Mark thread as running and return */ - intf_DbgMsg("vdec debug: InitThread(%p) succeeded\n", p_vdec); + intf_DbgMsg("vpar debug: InitThread(%p) succeeded\n", p_vpar); return( 0 ); } /******************************************************************************* - * RunThread: generic decoder thread + * RunThread: generic parser thread ******************************************************************************* - * Generic decoder thread. This function does only returns when the thread is + * Generic parser thread. This function does only returns when the thread is * terminated. *******************************************************************************/ -static void RunThread( vdec_thread_t *p_vdec ) +static void RunThread( vpar_thread_t *p_vpar ) { - intf_DbgMsg("vdec debug: running video decoder thread (%p) (pid == %i)\n", p_vdec, getpid()); + intf_DbgMsg("vpar debug: running video parser thread (%p) (pid == %i)\n", p_vpar, getpid()); /* * Initialize thread and free configuration */ - p_vdec->b_error = InitThread( p_vdec ); - if( p_vdec->b_error ) + p_vpar->b_error = InitThread( p_vpar ); + if( p_vpar->b_error ) { return; } - p_vdec->b_run = 1; + p_vpar->b_run = 1; /* REMOVE ME !!!!! */ -p_vdec->b_error = 1; +p_vpar->b_error = 1; /* * Main loop - it is not executed if an error occured during * initialization */ - while( (!p_vdec->b_die) && (!p_vdec->b_error) ) + while( (!p_vpar->b_die) && (!p_vpar->b_error) ) { /* ?? */ } @@ -226,14 +228,14 @@ p_vdec->b_error = 1; /* * Error loop */ - if( p_vdec->b_error ) + if( p_vpar->b_error ) { - ErrorThread( p_vdec ); + ErrorThread( p_vpar ); } /* End of thread */ - EndThread( p_vdec ); - p_vdec->b_run = 0; + EndThread( p_vpar ); + p_vpar->b_run = 0; } /******************************************************************************* @@ -243,25 +245,25 @@ p_vdec->b_error = 1; * thread can still receive feed, but must be ready to terminate as soon as * possible. *******************************************************************************/ -static void ErrorThread( vdec_thread_t *p_vdec ) +static void ErrorThread( vpar_thread_t *p_vpar ) { /* Wait until a `die' order */ - while( !p_vdec->b_die ) + while( !p_vpar->b_die ) { /* We take the lock, because we are going to read/write the start/end - * indexes of the decoder fifo */ - vlc_mutex_lock( &p_vdec->fifo.data_lock ); + * indexes of the parser fifo */ + vlc_mutex_lock( &p_vpar->fifo.data_lock ); /* ?? trash all trashable PES packets */ - while( !DECODER_FIFO_ISEMPTY(p_vdec->fifo) ) + while( !PARSER_FIFO_ISEMPTY(p_vpar->fifo) ) { - input_NetlistFreePES( p_vdec->bit_stream.p_input, DECODER_FIFO_START(p_vdec->fifo) ); - DECODER_FIFO_INCSTART( p_vdec->fifo ); + input_NetlistFreePES( p_vpar->bit_stream.p_input, PARSER_FIFO_START(p_vpar->fifo) ); + PARSER_FIFO_INCSTART( p_vpar->fifo ); } - vlc_mutex_unlock( &p_vdec->fifo.data_lock ); + vlc_mutex_unlock( &p_vpar->fifo.data_lock ); /* Sleep a while */ - msleep( VDEC_IDLE_SLEEP ); + msleep( VPAR_IDLE_SLEEP ); } } @@ -271,9 +273,9 @@ static void ErrorThread( vdec_thread_t *p_vdec ) * This function is called when the thread ends after a sucessfull * initialization. *******************************************************************************/ -static void EndThread( vdec_thread_t *p_vdec ) +static void EndThread( vpar_thread_t *p_vpar ) { - intf_DbgMsg("vdec debug: destroying video decoder thread %p\n", p_vdec); + intf_DbgMsg("vpar debug: destroying video parser thread %p\n", p_vpar); #ifdef DEBUG /* Check for remaining PES packets */ @@ -281,8 +283,8 @@ static void EndThread( vdec_thread_t *p_vdec ) #endif /* Destroy thread structures allocated by InitThread */ -// vout_DestroyStream( p_vdec->p_vout, p_vdec->i_stream ); +// vout_DestroyStream( p_vpar->p_vout, p_vpar->i_stream ); /* ?? */ - intf_DbgMsg("vdec debug: EndThread(%p)\n", p_vdec); + intf_DbgMsg("vpar debug: EndThread(%p)\n", p_vpar); }