From 047ca4f8afd4dd48c2fe31bd7d48be89e8b146ce Mon Sep 17 00:00:00 2001 From: Christophe Massiot Date: Tue, 21 Dec 1999 18:12:29 +0000 Subject: [PATCH] =?UTF-8?q?D=EF=BF=BDbut=20du=20d=EF=BF=BDcodeur=20+=20d?= =?UTF-8?q?=EF=BF=BDbut=20du=20parseur.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit �videmment �a compile pas et on n'est pas sortis de l'auberge, m'enfin... --- include/undec_picture.h | 101 +++++++++++++ include/vdec_motion.h | 29 ++++ include/video_fifo.h | 69 +++++++++ include/video_parser.h | 42 +++++- src/video_decoder/vdec_motion.c | 147 +++++++++++++++++++ src/video_decoder/video_decoder.c | 215 +++++++++++++++------------- src/video_parser/video_fifo.c | 226 ++++++++++++++++++++++++++++++ src/video_parser/video_parser.c | 56 ++++++-- src/video_parser/vpar_headers.c | 140 ++++++++++++++++++ 9 files changed, 915 insertions(+), 110 deletions(-) create mode 100644 include/undec_picture.h create mode 100644 include/vdec_motion.h create mode 100644 include/video_fifo.h create mode 100644 src/video_decoder/vdec_motion.c create mode 100644 src/video_parser/video_fifo.c create mode 100644 src/video_parser/vpar_headers.c diff --git a/include/undec_picture.h b/include/undec_picture.h new file mode 100644 index 0000000000..10f2ca808b --- /dev/null +++ b/include/undec_picture.h @@ -0,0 +1,101 @@ +/******************************************************************************* + * undec_picture.h: undecoded pictures type + * (c)1999 VideoLAN + ******************************************************************************* + * This header is required by all modules which have to handle pictures. It + * includes all common video types and constants. + ******************************************************************************* + * Requires: + * "config.h" + * "common.h" + * "video.h" + *******************************************************************************/ + +/******************************************************************************* + * macroblock_info_t : information on a macroblock + *******************************************************************************/ +typedef struct +{ + int i_mb_type; + int i_motion_type; + int i_dct_type; + (void *) p_idct_function[12](coeff_t * p_block); + + int ppp_motion_vectors[2][2][2]; + int pi_field_select[2][2]; +} macroblock_info_t; + +/* Macroblock types */ +#define MB_INTRA 1 +#define MB_PATTERN 2 +#define MB_MOTION_BACKWARD 4 +#define MB_MOTION_FORWARD 8 +#define MB_QUANT 16 + +/* Motion types */ +#define MOTION_FIELD 1 +#define MOTION_FRAME 2 +#define MOTION_16X8 2 +#define MOTION_DMV 3 + +/******************************************************************************* + * undec_link_t : link to an undecoded picture + *******************************************************************************/ +typedef struct undec_link_s +{ + struct undec_picture_s * p_undec; + picture_t ** pp_frame; +} undec_link_t + +/******************************************************************************* + * undec_picture_t: undecoded picture + ******************************************************************************* + * Any picture destined to be decoded by a video decoder thread should be + * stored in this structure from it's creation to it's effective display. + *******************************************************************************/ +typedef struct undec_picture_s +{ + /* Picture data */ + picture_t * p_picture; + + int i_coding_type; + boolean_t b_mpeg2; + int i_mb_height, i_mb_width; + int i_structure; + + macroblock_info_t * p_mb_info; + + picture_t * p_backward_ref; + picture_t * p_forward_ref; + + undec_link_t pp_referencing_undec[MAX_REFERENCING_UNDEC]; +} undec_picture_t; + + +/* Pictures types */ +#define I_CODING_TYPE 1 +#define P_CODING_TYPE 2 +#define B_CODING_TYPE 3 +#define D_CODING_TYPE 4 /* MPEG-1 ONLY */ +/* other values are reserved */ + +/* Structures */ +#define TOP_FIRST 1 +#define BOTTOM_FIRST 2 +#define FRAME_STRUCTURE 3 + +/******************************************************************************* + * pel_lookup_table_t : lookup table for pixels + *******************************************************************************/ +typedef struct pel_lookup_table_s { +#ifdef BIG_PICTURES + u32 * pi_pel; +#else + u16 * pi_pel; +#endif + + /* When the size of the picture changes, this structure is freed, so we + * keep a reference count. */ + int i_refcount; + vlc_mutex_t lock; +} pel_lookup_table_t; diff --git a/include/vdec_motion.h b/include/vdec_motion.h new file mode 100644 index 0000000000..44302a072c --- /dev/null +++ b/include/vdec_motion.h @@ -0,0 +1,29 @@ +/***************************************************************************** + * vdec_motion.h : types for the motion compensation algorithm + * (c)1999 VideoLAN + ***************************************************************************** + ***************************************************************************** + * Requires: + * "config.h" + * "common.h" + * "vlc_thread.h" + * "video_parser.h" + * "undec_picture.h" + *****************************************************************************/ + +/***************************************************************************** + * Function pointers + *****************************************************************************/ +typedef void (*f_motion_mb_t)( coeff_t *, pel_lookup_table_t *, + int, coeff_t *, int, int, int, int, int ); +typedef void (*f_motion_t)( vdec_thread_t *, undec_picture_t *, int, + f_motion_mb_t ); + +/***************************************************************************** + * Prototypes + *****************************************************************************/ +void vdec_MotionMacroblock420( coeff_t * p_src, pel_lookup_table_t * p_lookup, + int i_width_line, + coeff_t * p_dest, int i_dest_x, i_dest_y, + int i_stride_line, + i_mv1_x, i_mv1_y, i_mv2_x, i_mv2_y ); diff --git a/include/video_fifo.h b/include/video_fifo.h new file mode 100644 index 0000000000..f115ddd80d --- /dev/null +++ b/include/video_fifo.h @@ -0,0 +1,69 @@ +/***************************************************************************** + * video_fifo.h : FIFO for the pool of video_decoders + * (c)1999 VideoLAN + ***************************************************************************** + ***************************************************************************** + * Requires: + * "config.h" + * "common.h" + * "vlc_thread.h" + * "video_parser.h" + * "undec_picture.h" + *****************************************************************************/ + +/***************************************************************************** + * Macros + *****************************************************************************/ + +/* ?? move to inline functions */ +#define VIDEO_FIFO_ISEMPTY( fifo ) ( (fifo).i_start == (fifo).i_end ) +#define VIDEO_FIFO_ISFULL( fifo ) ( ( ( (fifo).i_end + 1 - (fifo).i_start ) \ + & VFIFO_SIZE ) == 0 ) +#define VIDEO_FIFO_START( fifo ) ( (fifo).buffer[ (fifo).i_start ] ) +#define VIDEO_FIFO_INCSTART( fifo ) ( (fifo).i_start = ((fifo).i_start + 1) \ + & VFIFO_SIZE ) +#define VIDEO_FIFO_END( fifo ) ( (fifo).buffer[ (fifo).i_end ] ) +#define VIDEO_FIFO_INCEND( fifo ) ( (fifo).i_end = ((fifo).i_end + 1) \ + & VFIFO_SIZE ) + +/***************************************************************************** + * video_fifo_t + ***************************************************************************** + * This rotative FIFO contains undecoded pictures that are to be decoded + *****************************************************************************/ +typedef struct video_fifo_s +{ + vlc_mutex_t lock; /* fifo data lock */ + vlc_cond_t wait; /* fifo data conditional variable */ + + /* buffer is an array of undec_picture_t pointers */ + undec_picture_t * buffer[VFIFO_SIZE + 1]; + int i_start; + int i_end; + + struct video_parser_s * p_vpar; +} video_fifo_t; + +/***************************************************************************** + * video_buffer_t + ***************************************************************************** + * This structure enables the parser to maintain a list of free + * undec_picture_t structures + *****************************************************************************/ +typedef struct video_buffer_s +{ + vlc_mutex_t lock; /* buffer data lock */ + + undec_picture_t p_undec_p[VFIFO_SIZE + 1]; + undec_picture_t * pp_undec_free[VFIFO_SIZE+1]; /* this is a LIFO */ + int i_index; +} video_buffer_t; + +/***************************************************************************** + * Prototypes + *****************************************************************************/ +undec_picture_t * vpar_GetPicture( video_fifo_t * p_fifo ); +undec_picture_t * vpar_NewPicture( video_fifo_t * p_fifo ); +void vpar_DecodePicture( video_fifo_t * p_fifo, undec_picture_t * p_undec_p ); +void vpar_ReleasePicture( video_fifo_t * p_fifo, undec_picture_t * p_undec_p ); +void vpar_DestroyPicture( video_fifo_t * p_fifo, undec_picture_t * p_undec_p ); diff --git a/include/video_parser.h b/include/video_parser.h index 3005acb28b..56993cb749 100644 --- a/include/video_parser.h +++ b/include/video_parser.h @@ -11,9 +11,22 @@ * "input.h" * "video.h" * "video_output.h" - * "parser_fifo.h" + * "decoder_fifo.h" + * "video_fifo.h" *******************************************************************************/ +/******************************************************************************* + * sequence_t : sequence descriptor + ******************************************************************************* + * ?? + *******************************************************************************/ +typedef struct sequence_s +{ + u32 i_height, i_width; + unsigned int i_aspect_ratio; + double frame_rate; +} sequence_t; + /******************************************************************************* * vpar_thread_t: video parser thread descriptor ******************************************************************************* @@ -35,7 +48,7 @@ typedef struct vpar_thread_s /* Input properties */ - parser_fifo_t fifo; /* PES input fifo */ + decoder_fifo_t fifo; /* PES input fifo */ /* The bit stream structure handles the PES stream at the bit level */ bit_stream_t bit_stream; @@ -44,11 +57,19 @@ typedef struct vpar_thread_s vout_thread_t * p_vout; /* video output thread */ int i_stream; /* video stream id */ - + /* Decoder properties */ + struct vdec_thread_s * p_vdec[MAX_VDEC]; + video_fifo_t vfifo; + video_buffer_t vbuffer; + + /* Parser properties */ + sequence_t sequence; + #ifdef STATS /* Statistics */ count_t c_loops; /* number of loops */ count_t c_idle_loops; /* number of idle loops */ + count_t c_sequences; /* number of sequences */ count_t c_pictures; /* number of pictures read */ count_t c_i_pictures; /* number of I pictures read */ count_t c_p_pictures; /* number of P pictures read */ @@ -60,6 +81,19 @@ typedef struct vpar_thread_s #endif } vpar_thread_t; +/******************************************************************************* + * Standard start codes + *******************************************************************************/ +#define PICTURE_START_CODE 0x100 +#define SLICE_START_CODE_MIN 0x101 +#define SLICE_START_CODE_MAX 0x1AF +#define USER_DATA_START_CODE 0x1B2 +#define SEQUENCE_HEADER_CODE 0x1B3 +#define SEQUENCE_ERROR_CODE 0x1B4 +#define EXTENSION_START_CODE 0x1B5 +#define SEQUENCE_END_CODE 0x1B7 +#define GROUP_START_CODE 0x1B8 + /******************************************************************************* * Prototypes *******************************************************************************/ @@ -67,7 +101,7 @@ typedef struct vpar_thread_s /* Thread management functions */ vpar_thread_t * vpar_CreateThread ( /* video_cfg_t *p_cfg, */ input_thread_t *p_input /*, vout_thread_t *p_vout, int *pi_status */ ); -void vpar_DestroyThread ( vpar_thread_t *p_vpar /*, int *pi_status */ ); +void vpar_DestroyThread ( vpar_thread_t *p_vpar /*, int *pi_status */ ); /* Time management functions */ /* ?? */ diff --git a/src/video_decoder/vdec_motion.c b/src/video_decoder/vdec_motion.c new file mode 100644 index 0000000000..310d41b6d6 --- /dev/null +++ b/src/video_decoder/vdec_motion.c @@ -0,0 +1,147 @@ +/***************************************************************************** + * vdec_motion.c : motion compensation routines + * (c)1999 VideoLAN + *****************************************************************************/ + +/* ?? passer en terminate/destroy avec les signaux supplémentaires */ + +/***************************************************************************** + * Preamble + *****************************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" +#include "common.h" +#include "mtime.h" +#include "vlc_thread.h" + +#include "intf_msg.h" +#include "debug.h" /* ?? temporaire, requis par netlist.h */ + +#include "input.h" +#include "input_netlist.h" +#include "decoder_fifo.h" +#include "video.h" +#include "video_output.h" +#include "video_parser.h" + +#include "undec_picture.h" +#include "video_fifo.h" +#include "video_decoder.h" + +/* + * Local prototypes + */ + +/***************************************************************************** + * vdec_MotionCompensation : motion compensation + *****************************************************************************/ +void vdec_MotionFrame( vdec_thread_t * p_vdec, + undec_picture_t * p_undec_p, int i_mb, + f_motion_mb_t pf_mb_motion ) +{ + static int p_chroma_nb_blocks[4] = {1, 2, 4}; + static int p_chroma_nb_elems[4] = {0, 64, 128, 256}; + + int i_mb_x, i_mb_y; /* Position of our macroblock in the final picture */ + elem_t * p_y, p_u, p_v; /* Pointers to our picture's data */ + +#define P_mb_info p_undec_p->p_mb_info[i_mb] + + i_mb_x = (i_mb << 5) % p_undec_p->p_picture->i_width; + i_mb_y = (i_mb << 5) / p_undec_p->p_picture->i_width; + p_y = &p_undec_p->p_picture->p_y[256*i_mb]; + p_u = &p_undec_p->p_picture->p_u[p_chroma_nb_elems[p_undec_p->p_picture->i_chroma_type]*i_mb]; + p_v = &p_undec_p->p_picture->p_v[p_chroma_nb_elems[p_undec_p->p_picture->i_chroma_type]*i_mb]; + + if( (p_undec_p->i_coding_type == P_CODING_TYPE) || + (P_mb_info->i_mb_type & MB_MOTION_FORWARD) ) + { + if( (P_mb_info->i_motion_type == MOTION_FRAME) || + !(P_mb_info->i_mb_type & MB_INTRA) ) + { + MotionBlock( p_undec_p->p_forward->p_u, + p_undec_p->p_forward->p_lookup_lum, + p_undec_p->p_picture->i_width, + p_u, i_mb_x, i_mb_y, + p_undec_p->p_picture->i_width, + p_undec_p->ppp_motion_vectors[0][0][0], + p_undec_p->ppp_motion_vectors[0][0][1] ); + } + } +} + +/***************************************************************************** + * MotionMacroblock : motion compensation for a macroblock + *****************************************************************************/ +void vdec_MotionMacroblock420( coeff_t * p_src, pel_lookup_table_t * p_lookup, + int i_width_line, + coeff_t * p_dest, int i_dest_x, i_dest_y, + int i_stride_line, + i_mv1_x, i_mv1_y, i_mv2_x, i_mv2_y ) +{ + /* Luminance */ + MotionBlock( p_undec_p->p_forward->p_u, p_undec_p->p_forward->p_lookup_lum, + p_undec_p->p_picture->i_width, p_u, i_mb_x, i_mb_y, + p_undec_p->p_picture->i_width, + p_undec_p->ppp_motion_vectors[0][0][0], + p_undec_p->ppp_motion_vectors[0][0][1] ); + +} + +/***************************************************************************** + * MotionBlock : motion compensation for one 8x8 block + *****************************************************************************/ +void __inline__ MotionBlock( coeff_t * p_src, pel_lookup_table_t * p_lookup, + int i_width_line, + coeff_t * p_dest, int i_dest_x, i_dest_y, + int i_stride_line, + i_mv1_x, i_mv1_y, i_mv2_x, i_mv2_y ) +{ + static (void *) ComponentMode( coeff_t * p_src, + pel_lookup_table_t * p_lookup, + coeff_t * p_dest, int i_dest_x, i_dest_y, + int i_stride_line, i_mv_x, i_mv_y )[4] + = { ComponentNN, ComponentNH, ComponentHN, + ComponentHH }; + + int i_mode; + + i_mode = (i_mv_x & 1) | ((i_mv_y & 1) << 1); + + ComponentMode[i_mode]( p_src, p_lookup, i_width_line, + p_dest, i_dest_x, i_dest_y, + i_stride_line, i_mv_x >> 1, i_mv_y >> 1 ); +} + +/***************************************************************************** + * ComponentNN : motion compensation without half pel + *****************************************************************************/ +void ComponentNN( coeff_t * p_src, pel_lookup_table_t * p_lookup, + int i_width_line, + coeff_t * p_dest, int i_dest_x, i_dest_y, + int i_stride_line, i_mv1_x, i_mv1_y, i_mv2_x, i_mv2_y ) +{ + int i_vpos; + register int i_hpos, i_src_loc; + + i_src_loc = (i_dest_y + i_mv_y)*i_width_line + i_dest_x + i_mv_x; + + for( i_vpos = 0; i_vpos < 8; i_vpos++ ) + { + for( i_hpos = 0; i_hpos < 8; i_hpos++ ) + { + p_dest[i_hpos] += p_src[p_lookup->pi_pel[i_src_loc + i_hpos]]; + } + + p_dest += 8; + i_src_loc += i_stride_line; + } +} diff --git a/src/video_decoder/video_decoder.c b/src/video_decoder/video_decoder.c index 245129b780..00df1e880a 100644 --- a/src/video_decoder/video_decoder.c +++ b/src/video_decoder/video_decoder.c @@ -30,27 +30,31 @@ #include "decoder_fifo.h" #include "video.h" #include "video_output.h" +#include "video_parser.h" + +#include "undec_picture.h" +#include "video_fifo.h" #include "video_decoder.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 void DecodePicture ( vdec_thread_t *p_vdec, + undec_picture_t * p_undec_p ); /******************************************************************************* - * vdec_CreateThread: create a generic decoder thread + * vdec_CreateThread: create a video decoder thread ******************************************************************************* * This function creates a new video decoder thread, and returns a pointer * to its description. On error, it returns NULL. * Following configuration properties are used: * ?? *******************************************************************************/ -vdec_thread_t * vdec_CreateThread( /* video_cfg_t *p_cfg, */ input_thread_t *p_input /*, - vout_thread_t *p_vout, int *pi_status */ ) +vdec_thread_t * vdec_CreateThread( vpar_thread_t *p_vpar /*, int *pi_status */ ) { vdec_thread_t * p_vdec; @@ -59,7 +63,7 @@ vdec_thread_t * vdec_CreateThread( /* video_cfg_t *p_cfg, */ input_thread_t *p_i /* Allocate the memory needed to store the thread's structure */ if ( (p_vdec = (vdec_thread_t *)malloc( sizeof(vdec_thread_t) )) == NULL ) { - intf_ErrMsg("adec error: not enough memory for vdec_CreateThread() to create the new thread\n"); + intf_ErrMsg("vdec error: not enough memory for vdec_CreateThread() to create the new thread\n"); return( NULL ); } @@ -70,21 +74,13 @@ vdec_thread_t * vdec_CreateThread( /* video_cfg_t *p_cfg, */ input_thread_t *p_i p_vdec->b_error = 0; /* - * Initialize the input properties + * Initialize the parser 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 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_vdec->p_vpar = p_vpar; /* Spawn the video decoder thread */ - if ( vlc_thread_create(&p_vdec->thread_id, "video decoder", (vlc_thread_func)RunThread, (void *)p_vdec) ) + if ( vlc_thread_create(&p_vdec->thread_id, "video decoder", + (vlc_thread_func)RunThread, (void *)p_vdec) ) { intf_ErrMsg("vdec error: can't spawn video decoder thread\n"); free( p_vdec ); @@ -96,9 +92,9 @@ vdec_thread_t * vdec_CreateThread( /* video_cfg_t *p_cfg, */ input_thread_t *p_i } /******************************************************************************* - * vdec_DestroyThread: destroy a generic decoder thread + * vdec_DestroyThread: destroy a video decoder thread ******************************************************************************* - * Destroy a terminated thread. This function will return 0 if the thread could + * Destroy and terminate 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. *******************************************************************************/ @@ -108,10 +104,6 @@ void vdec_DestroyThread( vdec_thread_t *p_vdec /*, int *pi_status */ ) /* 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) ); /* Waiting for the decoder thread to exit */ /* Remove this as soon as the "status" flag is implemented */ @@ -121,22 +113,7 @@ void vdec_DestroyThread( vdec_thread_t *p_vdec /*, int *pi_status */ ) /* following functions are local */ /******************************************************************************* - * CheckConfiguration: check vdec_CreateThread() configuration - ******************************************************************************* - * Set default parameters where required. In DEBUG mode, check if configuration - * is valid. - *******************************************************************************/ -#if 0 -static int CheckConfiguration( video_cfg_t *p_cfg ) -{ - /* ?? */ - - return( 0 ); -} -#endif - -/******************************************************************************* - * InitThread: initialize vdec output thread + * InitThread: initialize video decoder 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 @@ -144,41 +121,12 @@ static int CheckConfiguration( video_cfg_t *p_cfg ) *******************************************************************************/ static int InitThread( vdec_thread_t *p_vdec ) { - intf_DbgMsg("vdec debug: initializing video decoder thread %p\n", p_vdec); - /* 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_cond_wait( &p_vdec->fifo.data_wait, &p_vdec->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 ); - -#if 0 - /* ?? */ - /* Create video stream */ - p_vdec->i_stream = vout_CreateStream( p_vdec->p_vout ); - if( p_vdec->i_stream < 0 ) /* error */ - { - return( 1 ); - } - - /* Initialize decoding 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; @@ -191,15 +139,15 @@ static int InitThread( vdec_thread_t *p_vdec ) } /******************************************************************************* - * RunThread: generic decoder thread + * RunThread: video decoder thread ******************************************************************************* - * Generic decoder thread. This function does only returns when the thread is + * Video decoder thread. This function does only return when the thread is * terminated. *******************************************************************************/ static void RunThread( vdec_thread_t *p_vdec ) { - - intf_DbgMsg("vdec debug: running video decoder thread (%p) (pid == %i)\n", p_vdec, getpid()); + intf_DbgMsg("vdec debug: running video decoder thread (%p) (pid == %i)\n", + p_vdec, getpid()); /* * Initialize thread and free configuration @@ -211,16 +159,18 @@ static void RunThread( vdec_thread_t *p_vdec ) } p_vdec->b_run = 1; -/* REMOVE ME !!!!! */ -p_vdec->b_error = 1; - /* * Main loop - it is not executed if an error occured during * initialization */ while( (!p_vdec->b_die) && (!p_vdec->b_error) ) { - /* ?? */ + undec_picture_t * p_undec_p; + + if( (p_undec_p = GetPicture( p_vdec->p_vpar->p_fifo )) != NULL ) + { + DecodePicture( p_vdec, p_undec_p ); + } } /* @@ -245,21 +195,14 @@ p_vdec->b_error = 1; *******************************************************************************/ static void ErrorThread( vdec_thread_t *p_vdec ) { + undec_picture_t * p_undec_p; + /* Wait until a `die' order */ while( !p_vdec->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 ); + p_undec_p = GetPicture( p_vdec->p_vpar.vfifo ); + DestroyPicture( p_vdec->p_vpar.vfifo, p_undec_p ); - /* ?? trash all trashable PES packets */ - while( !DECODER_FIFO_ISEMPTY(p_vdec->fifo) ) - { - input_NetlistFreePES( p_vdec->bit_stream.p_input, DECODER_FIFO_START(p_vdec->fifo) ); - DECODER_FIFO_INCSTART( p_vdec->fifo ); - } - - vlc_mutex_unlock( &p_vdec->fifo.data_lock ); /* Sleep a while */ msleep( VDEC_IDLE_SLEEP ); } @@ -273,16 +216,96 @@ static void ErrorThread( vdec_thread_t *p_vdec ) *******************************************************************************/ static void EndThread( vdec_thread_t *p_vdec ) { - intf_DbgMsg("vdec debug: destroying video decoder thread %p\n", p_vdec); + intf_DbgMsg("vdec debug: EndThread(%p)\n", p_vdec); +} -#ifdef DEBUG - /* Check for remaining PES packets */ - /* ?? */ -#endif +/******************************************************************************* + * DecodePicture : decode a picture + *******************************************************************************/ +static void DecodePicture( vdec_thread_t *p_vdec, undec_picture_t * p_undec_p ) +{ + static int pi_chroma_nb_blocks[4] = {0, 1, 2, 4}; + static int pi_chroma_nb_coeffs[4] = {0, 64, 128, 256}; + static f_motion_mb_t ppf_chroma_motion[4] = { NULL, + &vdec_MotionMacroBlock420, + &vdec_MotionMacroBlock422, + &vdec_MotionMacroBlock444 }; + static f_motion_t pppf_motion_forward[4][2] = { + {NULL, NULL} /* I picture */ + {&vdec_MotionForward, &vdec_MotionForward} /* P */ + {NULL, &vdec_MotionForward} /* B */ + {NULL, NULL} /* D */ }; + static f_motion_t pppf_motion_backward[4][2] = { + {NULL, NULL} /* I picture */ + {NULL, NULL} /* P */ + {NULL, &vdec_MotionBackward} /* B */ + {NULL, NULL} /* D */ }; + static f_motion_t ppf_motion[4] = { NULL, + &vdec_MotionTopFirst, + &vdec_MotionBottomFirst, + &vdec_MotionFrame }; + + int i_mb, i_b, i_totb; + coeff_t * p_y, p_u, p_v; + f_motion_mb_t pf_chroma_motion; + f_motion_t pf_motion_forward, pf_motion_backward; + int i_chroma_nb_blocks, i_chroma_nb_coeffs; + + p_y = (coeff_t *)p_undec_p->p_picture->p_y; + p_u = (coeff_t *)p_undec_p->p_picture->p_u; + p_v = (coeff_t *)p_undec_p->p_picture->p_v; - /* Destroy thread structures allocated by InitThread */ -// vout_DestroyStream( p_vdec->p_vout, p_vdec->i_stream ); - /* ?? */ +#define I_chroma_format p_undec_p->p_picture->i_chroma_format + pf_chroma_motion = ppf_chroma_motion[I_chroma_format]; + pf_motion_forward + pf_motion = ppf_motion[p_undec_p->i_structure]; - intf_DbgMsg("vdec debug: EndThread(%p)\n", p_vdec); + i_chroma_nb_blocks = pi_chroma_nb_blocks[I_chroma_format]; + i_chroma_nb_coeffs = pi_chroma_nb_coeffs[I_chroma_format]; +#undef I_chroma_format + + for( i_mb = 0; i_mb < p_undec_p->i_mb_height*p_undec_p->i_mb_width; i_mb++ ) + { +#define P_mb_info p_undec_p->p_mb_info[i_ref] + + /* + * Inverse DCT (ISO/IEC 13818-2 section Annex A) + */ + + /* Luminance : always 4 blocks */ + for( i_b = 0; i_b < 4; i_b++ ) + { + (*P_mb_info.p_idct_function[i_b])( p_y + i_b*64 ); + } + i_totb = 4; + + /* Chrominance Cr */ + for( i_b = 0; i_b < i_chroma_nb_blocks; i_b++ ) + { + (*P_mb_info.p_idct_function[i_totb + i_b])( p_u + i_b*64 ); + } + i_totb += i_chroma_nb_blocks; + + /* Chrominance Cb */ + for( i_b = 0; i_b < i_chroma_nb_blocks; i_b++ ) + { + (*P_mb_info.p_idct_function[i_totb + i_b])( p_v + i_b*64 ); + } + + /* + * Motion Compensation (ISO/IEC 13818-2 section 7.6) + */ + (*pf_motion)( p_vdec, p_undec_p, i_mb, pf_chroma_motion ); + + p_y += 256; + p_u += i_chroma_nb_coeffs; + p_v += i_chroma_nb_coeffs; +#undef P_mb_info + } + + /* + * Decoding is finished, mark the picture ready for displaying and free + * unneeded memory + */ + vpar_ReleasePicture( p_vdec->p_vpar->p_fifo, p_undec_p ); } diff --git a/src/video_parser/video_fifo.c b/src/video_parser/video_fifo.c new file mode 100644 index 0000000000..ef97dbd5a2 --- /dev/null +++ b/src/video_parser/video_fifo.c @@ -0,0 +1,226 @@ +/******************************************************************************* + * video_fifo.c : video FIFO management + * (c)1999 VideoLAN + *******************************************************************************/ + +/******************************************************************************* + * Preamble + *******************************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" +#include "common.h" +#include "mtime.h" +#include "vlc_thread.h" + +#include "intf_msg.h" +#include "debug.h" /* ?? temporaire, requis par netlist.h */ + +#include "input.h" +#include "input_netlist.h" +#include "decoder_fifo.h" +#include "video.h" +#include "video_output.h" +#include "video_parser.h" + +#include "undec_picture.h" +#include "video_fifo.h" +#include "video_decoder.h" + +/***************************************************************************** + * vpar_InitFIFO : initialize the video FIFO + *****************************************************************************/ +void vpar_InitFIFO( vpar_thread_t * p_vpar ) +{ + int i_dummy; + + /* Initialize mutex and cond */ + vlc_mutex_init( p_vpar->vfifo.lock ); + vlc_cond_init( p_vpar->vfifo.wait ); + vlc_mutex_init( p_vpar->vbuffer.lock ); + + /* Initialize FIFO properties */ + p_vpar->vfifo.i_start = p_vpar->vfifo.i_end = 0; + p_vpar->vfifo.p_vpar = p_vpar; + + /* Initialize buffer properties */ + i_index = VFIFO_SIZE; /* all structures are available */ + for( i_dummy = 0; i_dummy < VFIFO_SIZE + 1; i_dummy++ ) + { + p_vpar->vfifo.pp_undec_free[i_dummy] = p_vpar->vfifo.p_undec_p + i; + } +} + +/***************************************************************************** + * vpar_GetPicture : return a picture to be decoded + *****************************************************************************/ +undec_picture_t * vpar_GetPicture( video_fifo_t * p_fifo ) +{ + undec_picture_t * p_undec_p; + + vlc_mutex_lock( &p_fifo->lock ); + while( VIDEO_FIFO_ISEMPTY( *p_fifo ) ) + { + vlc_cond_wait( &p_fifo->wait, &p_fifo->lock ); + if( p_fifo->p_vpar->b_die ) + { + vlc_mutex_unlock( &p_fifo->lock ); + return( NULL ); + } + } + + p_undec_p = VIDEO_FIFO_START( *p_fifo ); + VIDEO_FIFO_INCSTART( *p_fifo ); + + vlc_mutex_unlock( &p_fifo->lock ); + + return( p_undec_p ); +} + +/***************************************************************************** + * vpar_NewPicture : return a buffer for the parser + *****************************************************************************/ +undec_picture_t * vpar_NewPicture( video_fifo_t * p_fifo ) +{ + undec_picture_t * p_undec_p; + +#define P_buffer p_fifo->p_vpar.vbuffer + vlc_mutex_lock( &P_buffer->lock ); + if( P_buffer.i_index == -1 ) + { + /* No more structures available. This should not happen ! */ + return NULL; + } + + p_undec_p = P_buffer->pp_undec_free[ P_buffer->i_index-- ]; +#undef P_buffer + + vlc_mutex_unlock( &P_buffer->lock ); + return( p_undec_p ); +} + +/***************************************************************************** + * vpar_DecodePicture : put a picture in the video fifo, if it is decodable + *****************************************************************************/ +void vpar_DecodePicture( video_fifo_t * p_fifo, undec_picture_t * p_undec_p ) +{ + boolean_t b_decodable; + + switch( p_undec_p ) + { + case B_CODING_TYPE: + b_decodable = ((p_undec_p->p_backward_p != NULL) && + (p_undec_p->p_forward_p != NULL)); + break; + case P_CODING_TYPE: + b_decodable = (p_undec_p->p_backward_p != NULL); + break; + case I_CODING_TYPE: + case D_CODING_TYPE: + b_decodable = TRUE; + break; + default: + /* That should not happen */ + } + + if( b_decodable ) + { + /* Place picture in the video FIFO */ + vlc_mutex_lock( &p_fifo->lock ); + + /* By construction, the video FIFO cannot be full */ + VIDEO_FIFO_END( *p_fifo ) = p_undec_p; + VIDEO_FIFO_INCEND( *p_fifo ); + + vlc_mutex_unlock( &p_fifo->lock ); + } +} + +/***************************************************************************** + * vpar_ReleasePicture : put a picture in the video_output fifo, and update + * links and buffers + *****************************************************************************/ +void vpar_ReleasePicture( video_fifo_t * p_fifo, undec_picture_t * p_undec_p ) +{ + int i_ref; + + /* Tell referencing pictures so that they can be decoded */ + for( i_ref = 0; p_undec_p->pp_referencing_undec[i_ref].p_undec != NULL + && i_ref < MAX_REFERENCING_UNDEC; i_ref++ ) + { + *p_undec_p->pp_referencing_undec[i_ref].pp_frame = p_undec_p->p_picture; + vout_LinkPicture( p_fifo->p_vpar.p_vout, p_picture ); + + /* Try to put the referencing picture in the video FIFO */ + vpar_DecodePicture( p_fifo, p_undec_p->pp_referencing_undec[i_ref].p_undec ); + } + + /* Unlink referenced pictures */ + if( p_undec_p->p_forward_ref != NULL ) + { + vout_UnlinkPicture( p_fifo->p_vpar.p_vout, p_undec_p->p_forward_ref ); + if( p_undec_p->p_backward_ref != NULL ) + { + vout_UnlinkPicture( p_fifo->p_vpar.p_vout, p_undec_p->p_backward_ref ); + } + } + + /* Mark the picture to be displayed */ + vout_DisplayPicture( p_fifo->p_vpar.p_vout, p_undec_p->p_picture ); + + /* Release the undec_picture_t structure */ +#define P_buffer p_fifo->p_vpar.vbuffer + vlc_mutex_lock( &P_buffer->lock ); + + P_buffer->pp_undec_free[ ++P_buffer->i_index ] = p_undec_p; + + vlc_mutex_unlock( &P_buffer->lock ); +#undef P_buffer + } +} + +/***************************************************************************** + * vpar_DestroyPicture : destroy a picture in case of error + *****************************************************************************/ +void vpar_DestroyPicture( video_fifo_t * p_fifo, undec_picture_t * p_undec_p ) +{ + int i_ref; + + /* Destroy referencing pictures */ + for( i_ref = 0; p_undec_p->pp_referencing_undec[i_ref].p_undec != NULL + && i_ref < MAX_REFERENCING_UNDEC; i_ref++ ) + { + /* Try to put the referencing picture in the video FIFO */ + vpar_DestroyPicture( p_fifo, p_undec_p->pp_referencing_undec[i_ref].p_undec ); + } + + /* Unlink referenced pictures */ + if( p_undec_p->p_forward_ref != NULL ) + { + vout_UnlinkPicture( p_fifo->p_vpar.p_vout, p_undec_p->p_forward_ref ); + if( p_undec_p->p_backward_ref != NULL ) + { + vout_UnlinkPicture( p_fifo->p_vpar.p_vout, p_undec_p->p_backward_ref ); + } + } + + /* Release the picture buffer */ + vout_DestroyPicture( p_fifo->p_vpar.p_vout, p_undec_p->p_picture ); + + /* Release the undec_picture_t structure */ +#define P_buffer p_fifo->p_vpar.vbuffer + vlc_mutex_lock( &P_buffer->lock ); + + P_buffer->pp_undec_free[ ++P_buffer->i_index ] = p_undec_p; + + vlc_mutex_unlock( &P_buffer->lock ); +#undef P_buffer + } +} diff --git a/src/video_parser/video_parser.c b/src/video_parser/video_parser.c index 367b8b0f9c..5dd26aac19 100644 --- a/src/video_parser/video_parser.c +++ b/src/video_parser/video_parser.c @@ -104,7 +104,7 @@ vpar_thread_t * vpar_CreateThread( /* video_cfg_t *p_cfg, */ input_thread_t *p_i * be destroyed, and non 0 else. The last case probably means that the thread * was still active, and another try may succeed. *******************************************************************************/ -void vpar g_DestroyThread( vpar_thread_t *p_vpar /*, int *pi_status */ ) +void vpar_DestroyThread( vpar_thread_t *p_vpar /*, int *pi_status */ ) { intf_DbgMsg("vpar debug: requesting termination of video parser thread %p\n", p_vpar); @@ -152,11 +152,11 @@ static int InitThread( vpar_thread_t *p_vpar ) /* Our first job is to initialize the bit stream structure with the * beginning of the input stream */ vlc_mutex_lock( &p_vpar->fifo.data_lock ); - while ( PARSER_FIFO_ISEMPTY(p_vpar->fifo) ) + while ( DECODER_FIFO_ISEMPTY(p_vpar->fifo) ) { vlc_cond_wait( &p_vpar->fifo.data_wait, &p_vpar->fifo.data_lock ); } - p_vpar->bit_stream.p_ts = PARSER_FIFO_START( p_vpar->fifo )->p_first_ts; + p_vpar->bit_stream.p_ts = DECODER_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 ); @@ -187,24 +187,37 @@ static int InitThread( vpar_thread_t *p_vpar ) p_vpar->c_decoded_b_pictures = 0; #endif + /* Initialize video FIFO */ + vpar_InitFIFO( p_vpar ); + + bzero( p_vpar->p_vdec, MAX_VDEC*sizeof(vdec_thread_t *) ); + + /* Spawn a video_decoder thread */ + /* ??? add the possibility to launch multiple vdec threads */ + if( (p_vpar->p_vdec[0] = vdec_CreateThread( p_vpar )) == NULL ) + { + return( 1 ); + } + /* Mark thread as running and return */ - intf_DbgMsg("vpar debug: InitThread(%p) succeeded\n", p_vpar); + intf_DbgMsg("vpar debug: InitThread(%p) succeeded\n", p_vpar); return( 0 ); } /******************************************************************************* * RunThread: generic parser thread ******************************************************************************* - * Generic parser thread. This function does only returns when the thread is + * Video parser thread. This function does only returns when the thread is * terminated. *******************************************************************************/ static void RunThread( vpar_thread_t *p_vpar ) { + int i_dummy; intf_DbgMsg("vpar debug: running video parser thread (%p) (pid == %i)\n", p_vpar, getpid()); /* - * Initialize thread and free configuration + * Initialize thread */ p_vpar->b_error = InitThread( p_vpar ); if( p_vpar->b_error ) @@ -213,16 +226,28 @@ static void RunThread( vpar_thread_t *p_vpar ) } p_vpar->b_run = 1; -/* REMOVE ME !!!!! */ -p_vpar->b_error = 1; - /* * Main loop - it is not executed if an error occured during * initialization */ while( (!p_vpar->b_die) && (!p_vpar->b_error) ) { - /* ?? */ + /* Find the next sequence header in the stream */ + p_vpar->b_error = vpar_NextSequenceHeader( p_vpar ); + +#ifdef STATS + p_vpar->c_sequences++; +#endif + + while( (!p_vpar->b_die) && (!p_vpar->b_error) ) + { + /* Parse the next sequence, group or picture header */ + if( vpar_ParseHeader( p_vpar ) ) + { + /* End of sequence */ + break; + }; + } } /* @@ -275,6 +300,8 @@ static void ErrorThread( vpar_thread_t *p_vpar ) *******************************************************************************/ static void EndThread( vpar_thread_t *p_vpar ) { + int i_dummy; + intf_DbgMsg("vpar debug: destroying video parser thread %p\n", p_vpar); #ifdef DEBUG @@ -286,5 +313,14 @@ static void EndThread( vpar_thread_t *p_vpar ) // vout_DestroyStream( p_vpar->p_vout, p_vpar->i_stream ); /* ?? */ + /* Destroy vdec threads */ + for( i_dummy = 0; i_dummy < MAX_VDEC; i_dummy++ ) + { + if( p_vpar->p_vdec[i_dummy] != NULL ) + vdec_DestroyThread( p_vpar->p_vdec[i_dummy] ); + else + break; + } + intf_DbgMsg("vpar debug: EndThread(%p)\n", p_vpar); } diff --git a/src/video_parser/vpar_headers.c b/src/video_parser/vpar_headers.c new file mode 100644 index 0000000000..31edbac04b --- /dev/null +++ b/src/video_parser/vpar_headers.c @@ -0,0 +1,140 @@ +/***************************************************************************** + * vpar_headers.c : headers parsing + * (c)1999 VideoLAN + *****************************************************************************/ + +/* ?? passer en terminate/destroy avec les signaux supplémentaires */ + +/***************************************************************************** + * Preamble + *****************************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" +#include "common.h" +#include "mtime.h" +#include "vlc_thread.h" + +#include "intf_msg.h" +#include "debug.h" /* ?? temporaire, requis par netlist.h */ + +#include "input.h" +#include "input_netlist.h" +#include "decoder_fifo.h" +#include "video.h" +#include "video_output.h" +#include "video_parser.h" + +#include "undec_picture.h" +#include "video_fifo.h" +#include "video_decoder.h" + +/* + * Local prototypes + */ + +/***************************************************************************** + * vpar_NextSequenceHeader : Find the next sequence header + *****************************************************************************/ +void vpar_NextSequenceHeader( vpar_thread_t * p_vpar ) +{ + while( !p_vpar->b_die ) + { + NextStartCode( p_vpar ); + if( ShowBits( &p_vpar->bit_stream, 32 ) == SEQUENCE_START_CODE ) + return; + } +} + +/***************************************************************************** + * vpar_ParseHeader : Parse the next header + *****************************************************************************/ +int vpar_ParseHeader( vpar_thread_t * p_vpar ) +{ + while( !p_vpar->b_die ) + { + NextStartCode( p_vpar ); + switch( GetBits32( &p_vpar->bit_stream ) ) + { + case SEQUENCE_HEADER_CODE: + SequenceHeader( p_vpar ); + return 0; + break; + + case GROUP_START_CODE: + GroupHeader( p_vpar ); + return 0; + break; + + case PICTURE_START_CODE: + PictureHeader( p_vpar ); + return 0; + break; + + case SEQUENCE_END_CODE: + return 1; + break; + + default: + } + } + + return 0; +} + +/* + * Following functions are local + */ + +/***************************************************************************** + * NextStartCode : Find the next start code + *****************************************************************************/ +static __inline__ void NextStartCode( vpar_thread_t * p_vpar ) +{ + /* Re-align the buffer to an 8-bit boundary */ + DumpBits( &p_vpar->bit_stream, p_vpar->bit_stream.fifo.i_available & 7 ); + + while( ShowBits( &p_vpar->bit_stream, 24 ) != 0x01L && !p_vpar->b_die ) + { + DumpBits( &p_vpar->bit_stream, 8 ); + } +} + +/***************************************************************************** + * SequenceHeader : Parse the next sequence header + *****************************************************************************/ +static void SequenceHeader( vpar_thread_t * p_vpar ) +{ + int i_frame_rate_code; + + p_vpar->sequence.i_height = ntohl( GetBits( p_vpar->bit_stream, 12 ) ); + p_vpar->sequence.i_width = ntohl( GetBits( p_vpar->bit_stream, 12 ) ); + p_vpar->sequence.i_ratio = GetBits( p_vpar->bit_stream, 4 ); + i_frame_rate_code = GetBits( p_vpar->bit_stream, 4 ); + + /* We don't need bit_rate_value, marker_bit, vbv_buffer_size, + * constrained_parameters_flag */ + DumpBits( p_vpar->bits_stream, 30 ); +} + +/***************************************************************************** + * GroupHeader : Parse the next group of pictures header + *****************************************************************************/ +static void GroupHeader( vpar_thread_t * p_vpar ) +{ + +} +/***************************************************************************** + * PictureHeader : Parse the next picture header + *****************************************************************************/ +static void PictureHeader( vpar_thread_t * p_vpar ) +{ + +}