microprocesseur.
#define VPAR_IDLE_SLEEP 100000
+/* Time to sleep when waiting for a buffer (from vout or the video fifo). */
#define VPAR_OUTMEM_SLEEP 50000
-
+
+/* The following directives only apply if you define VDEC_SMP below. */
+
/* Number of macroblock buffers available. It should be always greater than
* twice the number of macroblocks in a picture. VFIFO_SIZE + 1 should also
* be a power of two. */
* Video decoder configuration
*******************************************************************************/
+//#define VDEC_SMP
+
#define VDEC_IDLE_SLEEP 100000
/* Number of video_decoder threads to launch on startup of the video_parser.
* It should always be less than half the number of macroblocks of a
- * picture. */
+ * picture. Only available if you defined VDEC_SMP above. */
#define NB_VDEC 1
-/* Maximum range of values out of the IDCT + motion compensation. Only
- * used if you define MPEG2_COMPLIANT above. */
+/* Maximum range of values out of the IDCT + motion compensation. */
#define VDEC_CROPRANGE 2048
/*******************************************************************************
*****************************************************************************/
#ifndef OLD_DECODER
struct vpar_thread_s;
+struct macroblock_s;
#endif
/* Thread management functions */
vout_thread_t *p_vout, int *pi_status */ );
void vdec_DestroyThread ( vdec_thread_t *p_vdec /*, int *pi_status */ );
#else
+#ifndef VDEC_SMP
+int vdec_InitThread ( struct vdec_thread_s *p_vdec );
+void vdec_DecodeMacroblock ( struct vdec_thread_s *p_vdec, struct macroblock_s *p_mb );
+#endif
vdec_thread_t * vdec_CreateThread ( struct vpar_thread_s *p_vpar /*, int *pi_status */ );
void vdec_DestroyThread ( vdec_thread_t *p_vdec /*, int *pi_status */ );
#endif
* Macros
*****************************************************************************/
+#ifdef VDEC_SMP
/* ?? 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 ) \
#define VIDEO_FIFO_END( fifo ) ( (fifo).buffer[ (fifo).i_end ] )
#define VIDEO_FIFO_INCEND( fifo ) ( (fifo).i_end = ((fifo).i_end + 1) \
& VFIFO_SIZE )
+#endif
/*****************************************************************************
* vpar_GetMacroblock : return a macroblock to be decoded
*****************************************************************************/
static __inline__ macroblock_t * vpar_GetMacroblock( video_fifo_t * p_fifo )
{
+#ifdef VDEC_SMP
macroblock_t * p_mb;
vlc_mutex_lock( &p_fifo->lock );
vlc_mutex_unlock( &p_fifo->lock );
return( p_mb );
+#else
+ /* Shouldn't normally be used without SMP. */
+ return NULL;
+#endif
}
/*****************************************************************************
*****************************************************************************/
static __inline__ macroblock_t * vpar_NewMacroblock( video_fifo_t * p_fifo )
{
+#ifdef VDEC_SMP
macroblock_t * p_mb;
#define P_buffer p_fifo->p_vpar->vbuffer
vlc_mutex_unlock( &P_buffer.lock );
#undef P_buffer
return( p_mb );
+#else
+ return( &p_fifo->buffer );
+#endif
}
/*****************************************************************************
static __inline__ void vpar_DecodeMacroblock( video_fifo_t * p_fifo,
macroblock_t * p_mb )
{
+#ifdef VDEC_SMP
/* Place picture in the video FIFO */
vlc_mutex_lock( &p_fifo->lock );
VIDEO_FIFO_INCEND( *p_fifo );
vlc_mutex_unlock( &p_fifo->lock );
+#endif
+ /* Shouldn't normally be used without SMP. */
}
/*****************************************************************************
static __inline__ void vpar_ReleaseMacroblock( video_fifo_t * p_fifo,
macroblock_t * p_mb )
{
+#ifdef VDEC_SMP
boolean_t b_finished;
/* Unlink picture buffer */
P_buffer.pp_mb_free[ ++P_buffer.i_index ] = p_mb;
vlc_mutex_unlock( &P_buffer.lock );
#undef P_buffer
+
+#else
+ p_mb->p_picture->i_deccount--;
+ if( p_mb->p_picture->i_deccount == 1 )
+ {
+ /* Mark the picture to be displayed */
+ vout_DisplayPicture( p_fifo->p_vpar->p_vout, p_mb->p_picture );
+
+ /* Warn Synchro for its records. */
+ vpar_SynchroEnd( p_fifo->p_vpar );
+ }
+#endif
}
/*****************************************************************************
static __inline__ void vpar_DestroyMacroblock( video_fifo_t * p_fifo,
macroblock_t * p_mb )
{
+#ifdef VDEC_SMP
boolean_t b_finished;
/* Unlink picture buffer */
vlc_mutex_lock( &p_mb->p_picture->lock_deccount );
p_mb->p_picture->i_deccount--;
- b_finished = (p_mb->p_picture->i_deccount == 0);
+ b_finished = (p_mb->p_picture->i_deccount == 1);
vlc_mutex_unlock( &p_mb->p_picture->lock_deccount );
/* Test if it was the last block of the picture */
if( b_finished )
{
fprintf(stderr, "Image trashee\n");
- /* Mark the picture to be displayed */
+ /* Mark the picture to be trashed */
vout_DestroyPicture( p_fifo->p_vpar->p_vout, p_mb->p_picture );
/* Warn Synchro for its records. */
P_buffer.pp_mb_free[ ++P_buffer.i_index ] = p_mb;
vlc_mutex_unlock( &P_buffer.lock );
#undef P_buffer
+
+#else
+ p_mb->p_picture->i_deccount--;
+ if( p_mb->p_picture->i_deccount == 1 )
+ {
+ /* Mark the picture to be trashed */
+ vout_DestroyPicture( p_fifo->p_vpar->p_vout, p_mb->p_picture );
+
+ /* Warn Synchro for its records. */
+ vpar_SynchroEnd( p_fifo->p_vpar );
+ }
+#endif
}
/*****************************************************************************
typedef struct video_fifo_s
{
+#ifdef VDEC_SMP
vlc_mutex_t lock; /* fifo data lock */
vlc_cond_t wait; /* fifo data conditional variable */
/* buffer is an array of undec_picture_t pointers */
- macroblock_t * buffer[VFIFO_SIZE + 1];
- int i_start;
- int i_end;
+ macroblock_t * buffer[VFIFO_SIZE + 1];
+ int i_start;
+ int i_end;
+#else
+ macroblock_t buffer;
+#endif
struct vpar_thread_s * p_vpar;
} video_fifo_t;
* This structure enables the parser to maintain a list of free
* macroblock_t structures
*****************************************************************************/
+#ifdef VDEC_SMP
typedef struct video_buffer_s
{
vlc_mutex_t lock; /* buffer data lock */
macroblock_t * pp_mb_free[VFIFO_SIZE+1]; /* this is a LIFO */
int i_index;
} video_buffer_t;
+#endif
/*****************************************************************************
* vpar_thread_t: video parser thread descriptor
/* Output properties */
vout_thread_t * p_vout; /* video output thread */
- int i_stream; /* video stream id */
/* Decoder properties */
- struct vdec_thread_s * p_vdec[NB_VDEC];
+ struct vdec_thread_s * pp_vdec[NB_VDEC];
video_fifo_t vfifo;
+#ifdef VDEC_SMP
video_buffer_t vbuffer;
+#endif
/* Parser properties */
sequence_t sequence;
int i_current_structure;
picture_t * p_picture;
+#ifdef VDEC_SMP
macroblock_t * pp_mb[MAX_MB];
+#endif
/* Relative to the current field */
int i_coding_type, i_structure;
/*
* Local prototypes
*/
-static int InitThread ( vdec_thread_t *p_vdec );
+#ifdef VDEC_SMP
+static int vdec_InitThread ( vdec_thread_t *p_vdec );
+static void vdec_DecodeMacroblock( vdec_thread_t *p_vdec,
+ macroblock_t * p_mb );
+#endif
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 DecodeMacroblock ( vdec_thread_t *p_vdec,
- macroblock_t * p_mb );
/*******************************************************************************
* vdec_CreateThread: create a video decoder thread
/* Ask thread to kill itself */
p_vdec->b_die = 1;
- /* Make sure the parser thread leaves the GetByte() function */
+
+#ifdef VDEC_SMP
+ /* Make sure the decoder thread leaves the vpar_GetMacroblock() function */
vlc_mutex_lock( &(p_vdec->p_vpar->vfifo.lock) );
vlc_cond_signal( &(p_vdec->p_vpar->vfifo.wait) );
vlc_mutex_unlock( &(p_vdec->p_vpar->vfifo.lock) );
-
+#endif
/* Waiting for the decoder thread to exit */
/* Remove this as soon as the "status" flag is implemented */
/* following functions are local */
/*******************************************************************************
- * InitThread: initialize video decoder thread
+ * vdec_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
* modified inside this function.
*******************************************************************************/
-static int InitThread( vdec_thread_t *p_vdec )
+#ifdef VDEC_SMP
+static int vdec_InitThread( vdec_thread_t *p_vdec )
+#else
+int vdec_InitThread( vdec_thread_t *p_vdec )
+#endif
{
int i_dummy;
}
/*******************************************************************************
- * DecodeMacroblock : decode a macroblock of a picture
+ * vdec_DecodeMacroblock : decode a macroblock of a picture
*******************************************************************************/
#define DECODEBLOCKS( OPBLOCK ) \
{ \
} \
}
-static __inline__ void DecodeMacroblock( vdec_thread_t *p_vdec, macroblock_t * p_mb )
+#ifdef VDEC_SMP
+static __inline__ void vdec_DecodeMacroblock( vdec_thread_t *p_vdec, macroblock_t * p_mb )
+#else
+void vdec_DecodeMacroblock( vdec_thread_t *p_vdec, macroblock_t * p_mb )
+#endif
{
if( !(p_mb->i_mb_type & MB_INTRA) )
{
/*
* Initialize thread and free configuration
*/
- p_vdec->b_error = InitThread( p_vdec );
+ p_vdec->b_error = vdec_InitThread( p_vdec );
if( p_vdec->b_error )
{
return;
if( (p_mb = vpar_GetMacroblock( &p_vdec->p_vpar->vfifo )) != NULL )
{
- DecodeMacroblock( p_vdec, p_mb );
+ vdec_DecodeMacroblock( p_vdec, p_mb );
}
}
*****************************************************************************/
void vpar_InitFIFO( vpar_thread_t * p_vpar )
{
+#ifdef VDEC_SMP
int i_dummy;
-
+#endif
+
+ p_vpar->vfifo.p_vpar = p_vpar;
+
+#ifdef VDEC_SMP
/* Initialize mutex and cond */
vlc_mutex_init( &p_vpar->vfifo.lock );
vlc_cond_init( &p_vpar->vfifo.wait );
/* Initialize FIFO properties */
p_vpar->vfifo.i_start = p_vpar->vfifo.i_end = 0;
- p_vpar->vfifo.p_vpar = p_vpar;
/* Initialize buffer properties */
p_vpar->vbuffer.i_index = VFIFO_SIZE; /* all structures are available */
p_vpar->vbuffer.pp_mb_free[i_dummy] = p_vpar->vbuffer.p_macroblocks
+ i_dummy;
}
+#endif
}
/* Initialize video FIFO */
vpar_InitFIFO( p_vpar );
-
- bzero( p_vpar->p_vdec, NB_VDEC*sizeof(vdec_thread_t *) );
-
+
+ memset( p_vpar->pp_vdec, 0, NB_VDEC*sizeof(vdec_thread_t *) );
+
+#ifdef VDEC_SMP
/* Spawn video_decoder threads */
/* ??? modify the number of vdecs at runtime ? */
for( i_dummy = 0; i_dummy < NB_VDEC; i_dummy++ )
{
- if( (p_vpar->p_vdec[i_dummy] = vdec_CreateThread( p_vpar )) == NULL )
+ if( (p_vpar->pp_vdec[i_dummy] = vdec_CreateThread( p_vpar )) == NULL )
{
return( 1 );
}
}
+#else
+ /* Fake a video_decoder thread */
+ if( (p_vpar->pp_vdec[0] = (vdec_thread_t *)malloc(sizeof( vdec_thread_t ))) == NULL
+ || vdec_InitThread( p_vpar->pp_vdec[0] ) )
+ {
+ return( 1 );
+ }
+ p_vpar->pp_vdec[0]->b_die = 0;
+ p_vpar->pp_vdec[0]->b_error = 0;
+ p_vpar->pp_vdec[0]->p_vpar = p_vpar;
+#endif
/* Initialize lookup tables */
#if defined(MPEG2_COMPLIANT) && !defined(VDEC_DFT)
*******************************************************************************/
static void EndThread( vpar_thread_t *p_vpar )
{
+#ifdef VDEC_SMP
int i_dummy;
+#endif
intf_DbgMsg("vpar debug: destroying video parser thread %p\n", p_vpar);
free( p_vpar->sequence.chroma_nonintra_quant.pi_matrix );
}
+#ifdef VDEC_SMP
/* Destroy vdec threads */
for( i_dummy = 0; i_dummy < NB_VDEC; i_dummy++ )
{
- if( p_vpar->p_vdec[i_dummy] != NULL )
- vdec_DestroyThread( p_vpar->p_vdec[i_dummy] );
+ if( p_vpar->pp_vdec[i_dummy] != NULL )
+ vdec_DestroyThread( p_vpar->pp_vdec[i_dummy] );
else
break;
}
+#else
+ free( p_vpar->pp_vdec[0] );
+#endif
intf_DbgMsg("vpar debug: EndThread(%p)\n", p_vpar);
}
#include "video_parser.h"
#include "video_fifo.h"
-
/*
* Local prototypes
*/
memset( p_vpar->slice.pppi_pmv, 0, 8*sizeof(int) );
}
- if( (p_mb = p_vpar->picture.pp_mb[i_mb_base + i_mb] =
- vpar_NewMacroblock( &p_vpar->vfifo )) == NULL )
+ if( (p_mb = vpar_NewMacroblock( &p_vpar->vfifo )) == NULL )
{
p_vpar->picture.b_error = 1;
intf_ErrMsg("vpar error: macroblock list is empty !\n");
return;
}
+#ifdef VDEC_SMP
+ p_vpar->picture.pp_mb[i_mb_base + i_mb] = p_mb;
+#endif
InitMacroblock( p_vpar, p_mb );
/* Set the field we use for motion compensation */
p_mb->ppi_field_select[0][0] = p_mb->ppi_field_select[0][1]
= ( p_vpar->picture.i_current_structure == BOTTOM_FIELD );
+
+#ifndef VDEC_SMP
+ /* Decode the macroblock NOW ! */
+ vdec_DecodeMacroblock( p_vpar->pp_vdec[0], p_mb );
+#endif
}
/* Get a macroblock structure. */
- if( (p_mb = p_vpar->picture.pp_mb[i_mb_base + *pi_mb_address] =
- vpar_NewMacroblock( &p_vpar->vfifo )) == NULL )
+ if( (p_mb = vpar_NewMacroblock( &p_vpar->vfifo )) == NULL )
{
p_vpar->picture.b_error = 1;
intf_ErrMsg("vpar error: macroblock list is empty !\n");
return;
}
+#ifdef VDEC_SMP
+ p_vpar->picture.pp_mb[i_mb_base + *pi_mb_address] = p_mb;
+#endif
InitMacroblock( p_vpar, p_mb );
{
p_mb->i_mb_type |= MB_MOTION_FORWARD;
}
+
+#ifndef VDEC_SMP
+ /* Decode the macroblock NOW ! */
+ vdec_DecodeMacroblock( p_vpar->pp_vdec[0], p_mb );
+#endif
+
/*
if( p_vpar->picture.i_coding_type != I_CODING_TYPE )//!(p_mb->b_P_coding_type & MB_INTRA) )
{
p_mb->ppi_blocks[i_b][i_pos] = b_sign ? -i_level : i_level;
}
fprintf( stderr, "Non intra MPEG2 end (%d)\n", i_b );
-//p_vpar->picture.b_error = 1;
+p_vpar->picture.b_error = 1;
}
/*****************************************************************************
}
fprintf( stderr, "MPEG2 end (%d)\n", i_b );
-//p_vpar->b_error = 1;
+p_vpar->picture.b_error = 1;
}
vpar_BMBType, vpar_DMBType};
int i_structure;
- int i_mb_address, i_mb_base, i_mb;
+ int i_mb_address, i_mb_base;
boolean_t b_parsable;
u32 i_dummy;
+#ifdef VDEC_SMP
+ int i_mb;
+#endif
RemoveBits( &p_vpar->bit_stream, 10 ); /* temporal_reference */
p_vpar->picture.i_coding_type = GetBits( &p_vpar->bit_stream, 3 );
p_vpar->picture.i_coding_type,
NULL );
+#ifdef VDEC_SMP
for( i_mb = 0; p_vpar->picture.pp_mb[i_mb] != NULL; i_mb++ )
{
vpar_DestroyMacroblock( &p_vpar->vfifo,
p_vpar->picture.pp_mb[i_mb] );
}
+#endif
vout_DestroyPicture( p_vpar->p_vout, p_vpar->picture.p_picture );
}
P_picture->i_deccount = p_vpar->sequence.i_mb_size;
vlc_mutex_init( &p_vpar->picture.p_picture->lock_deccount );
- memset( p_vpar->picture.pp_mb, 0, MAX_MB );
+#ifdef VDEC_SMP
+ memset( p_vpar->picture.pp_mb, 0, MAX_MB*sizeof(macroblock_t *) );
+#endif
/* FIXME ! remove asap */
//memset( P_picture->p_data, 0, (p_vpar->sequence.i_mb_size*384));
/* Update the reference pointers. */
ReferenceUpdate( p_vpar, p_vpar->picture.i_coding_type, P_picture );
+
+#ifdef VDEC_SMP
+ /* Link referenced pictures for the decoder
+ * They are unlinked in vpar_ReleaseMacroblock() & vpar_DestroyMacroblock() */
+ if( p_vpar->picture.i_coding_type == P_CODING_TYPE ||
+ p_vpar->picture.i_coding_type == B_CODING_TYPE )
+ {
+ vout_LinkPicture( p_vpar->p_vout, p_vpar->sequence.p_forward );
+ }
+ if( p_vpar->picture.i_coding_type == B_CODING_TYPE )
+ {
+ vout_LinkPicture( p_vpar->p_vout, p_vpar->sequence.p_backward );
+ }
+#endif
}
p_vpar->picture.i_current_structure |= i_structure;
p_vpar->picture.i_structure = i_structure;
/* Initialize picture data for decoding. */
- if( p_vpar->picture.b_motion_field = (i_structure == BOTTOM_FIELD) )
+ if( (p_vpar->picture.b_motion_field = (i_structure == BOTTOM_FIELD)) )
{
i_mb_base = p_vpar->sequence.i_mb_size >> 1;
p_vpar->mb.i_l_y = 1;
{
/* Trash picture. */
//fprintf(stderr, "Image trashee\n");
- for( i_mb = 1; p_vpar->picture.pp_mb[i_mb]; i_mb++ )
+#ifdef VDEC_SMP
+ for( i_mb = 1; p_vpar->picture.pp_mb[i_mb] != NULL; i_mb++ )
{
vpar_DestroyMacroblock( &p_vpar->vfifo, p_vpar->picture.pp_mb[i_mb] );
}
- vout_DestroyPicture( p_vpar->p_vout, p_vpar->picture.p_picture );
+#endif
+
+ if( P_picture->i_deccount != 1 )
+ {
+ vout_DestroyPicture( p_vpar->p_vout, P_picture );
+ }
ReferenceReplace( p_vpar, p_vpar->picture.i_coding_type, NULL );
{
//fprintf(stderr, "Image parsee (%d)\n", p_vpar->picture.i_coding_type);
/* Frame completely parsed. */
+#ifdef VDEC_SMP
for( i_mb = 1; p_vpar->picture.pp_mb[i_mb] != NULL; i_mb++ )
{
vpar_DecodeMacroblock( &p_vpar->vfifo, p_vpar->picture.pp_mb[i_mb] );
}
- /* Link referenced pictures for the decoder
- * They are unlinked in vpar_ReleaseMacroblock() & vpar_DestroyMacroblock() */
- if( p_vpar->picture.i_coding_type == P_CODING_TYPE ||
- p_vpar->picture.i_coding_type == B_CODING_TYPE )
- {
- vout_LinkPicture( p_vpar->p_vout, p_vpar->sequence.p_forward );
- }
- if( p_vpar->picture.i_coding_type == B_CODING_TYPE )
- {
- vout_LinkPicture( p_vpar->p_vout, p_vpar->sequence.p_backward );
- }
-
/* Send signal to the video_decoder. */
vlc_mutex_lock( &p_vpar->vfifo.lock );
vlc_cond_signal( &p_vpar->vfifo.wait );
vlc_mutex_unlock( &p_vpar->vfifo.lock );
-
+#endif
+
/* Prepare context for the next picture. */
P_picture = NULL;
p_vpar->picture.i_current_structure = 0;