Commit d0c9b479 authored by Christophe Massiot's avatar Christophe Massiot

* Rewrote the video decoder to take advantage of several processors (SMP mode) ;

* Fixed a bug in the video decoder initialization :-p ;
* Added --smp option and several hooks in src/input/input_ext-intf.c ;
* Grayscale mode now turns off chroma IDCT.
parent 18f5cd99
......@@ -30,7 +30,7 @@ AC3_SPDIF := ac3_spdif ac3_iec958
LPCM_DECODER := lpcm_decoder_thread
AUDIO_DECODER := audio_decoder adec_generic adec_layer1 adec_layer2 adec_math
SPU_DECODER := spu_decoder
VIDEO_DECODER := video_parser vpar_headers vpar_blocks vpar_synchro video_fifo video_decoder
VIDEO_DECODER := video_parser vpar_headers vpar_blocks vpar_synchro vpar_pool video_decoder
MISC := mtime tests modules netutils
C_OBJ := $(INTERFACE:%=src/interface/%.o) \
......
......@@ -439,13 +439,6 @@
* that raising this level dramatically lengthens the compilation time. */
#define VPAR_OPTIM_LEVEL 2
/* 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. */
#define VFIFO_SIZE 8191
/* Maximum number of macroblocks in a picture. */
#define MAX_MB 2048
......@@ -456,26 +449,16 @@
* Video decoder configuration
*****************************************************************************/
//#define VDEC_SMP
#define VDEC_IDLE_SLEEP ((int)(0.100*CLOCK_FREQ))
/* 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. Only available if you defined VDEC_SMP above. */
#define NB_VDEC 1
/* Maximum range of values out of the IDCT + motion compensation. */
#define VDEC_CROPRANGE 2048
/* Nice increments for decoders -- necessary for x11 scheduling */
#define VDEC_NICE 3
/*****************************************************************************
* Generic decoder configuration
*****************************************************************************/
/* Environment variable containing the SMP value. */
#define VDEC_SMP_VAR "vlc_smp"
#define GDEC_IDLE_SLEEP ((int)(0.100*CLOCK_FREQ))
/* No SMP by default, since it slows down things on non-smp machines. */
#define VDEC_SMP_DEFAULT 0
/*****************************************************************************
* Messages and console interfaces configuration
......
......@@ -4,7 +4,7 @@
* control the pace of reading.
*****************************************************************************
* Copyright (C) 1999, 2000 VideoLAN
* $Id: input_ext-intf.h,v 1.40 2001/06/27 09:53:56 massiot Exp $
* $Id: input_ext-intf.h,v 1.41 2001/07/18 14:21:00 massiot Exp $
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
*
......@@ -205,6 +205,7 @@ typedef struct stream_descriptor_s
/* New status and rate requested by the interface */
int i_new_status, i_new_rate;
int b_new_mute; /* int because it can be -1 */
vlc_cond_t stream_wait; /* interface -> input in case of a
* status change request */
......@@ -229,6 +230,8 @@ typedef struct stream_descriptor_s
stream_ctrl_t control;
} stream_descriptor_t;
#define MUTE_NO_CHANGE -1
/*****************************************************************************
* i_p_config_t
*****************************************************************************
......@@ -360,7 +363,6 @@ struct input_thread_s * input_CreateThread ( struct playlist_item_s *,
void input_DestroyThread( struct input_thread_s *, int *pi_status );
void input_SetStatus( struct input_thread_s *, int );
void input_SetRate ( struct input_thread_s *, int );
void input_Seek ( struct input_thread_s *, off_t );
void input_DumpStream( struct input_thread_s * );
char * input_OffsetToTime( struct input_thread_s *, char * psz_buffer, off_t );
......@@ -368,5 +370,8 @@ int input_ChangeES ( struct input_thread_s *, struct es_descriptor_s *, u8 );
int input_ToggleES ( struct input_thread_s *,
struct es_descriptor_s *,
boolean_t );
int input_ChangeArea( input_thread_t *, input_area_t * );
int input_ChangeArea( struct input_thread_s *, struct input_area_s * );
int input_ToggleGrayscale( struct input_thread_s * );
int input_ToggleMute( struct input_thread_s * );
int input_SetSMP( struct input_thread_s *, int );
......@@ -3,7 +3,7 @@
* but exported to plug-ins
*****************************************************************************
* Copyright (C) 1999, 2000, 2001 VideoLAN
* $Id: input_ext-plugins.h,v 1.1 2001/07/17 09:48:07 massiot Exp $
* $Id: input_ext-plugins.h,v 1.2 2001/07/18 14:21:00 massiot Exp $
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
*
......@@ -74,8 +74,7 @@ void input_EndDecoder( struct input_thread_s *, struct es_descriptor_s * );
void input_DecodePES ( struct decoder_fifo_s *, struct pes_packet_s * );
void input_EscapeDiscontinuity( struct input_thread_s *,
struct pgrm_descriptor_s * );
void input_EscapeAudioDiscontinuity( struct input_thread_s *,
struct pgrm_descriptor_s * );
void input_EscapeAudioDiscontinuity( struct input_thread_s * );
/*****************************************************************************
* Prototypes from input_clock.c
......
......@@ -62,7 +62,6 @@ typedef struct module_symbols_s
int ( * network_ChannelJoin ) ( int );
void ( * input_SetStatus ) ( struct input_thread_s *, int );
void ( * input_SetRate ) ( struct input_thread_s *, int );
void ( * input_Seek ) ( struct input_thread_s *, off_t );
void ( * input_DumpStream ) ( struct input_thread_s * );
char * ( * input_OffsetToTime ) ( struct input_thread_s *, char *, off_t );
......@@ -152,7 +151,6 @@ typedef struct module_symbols_s
(p_symbols)->network_ChannelCreate = network_ChannelCreate; \
(p_symbols)->network_ChannelJoin = network_ChannelJoin; \
(p_symbols)->input_SetStatus = input_SetStatus; \
(p_symbols)->input_SetRate = input_SetRate; \
(p_symbols)->input_Seek = input_Seek; \
(p_symbols)->input_DumpStream = input_DumpStream; \
(p_symbols)->input_OffsetToTime = input_OffsetToTime; \
......@@ -238,7 +236,6 @@ extern module_symbols_t* p_symbols;
# define network_ChannelJoin(a) p_symbols->network_ChannelJoin(a)
# define input_SetStatus(a,b) p_symbols->input_SetStatus(a,b)
# define input_SetRate(a,b) p_symbols->input_SetRate(a,b)
# define input_Seek(a,b) p_symbols->input_Seek(a,b)
# define input_DumpStream(a) p_symbols->input_DumpStream(a)
# define input_OffsetToTime(a,b,c) p_symbols->input_OffsetToTime(a,b,c)
......
......@@ -4,7 +4,7 @@
* of the reading.
*****************************************************************************
* Copyright (C) 1999, 2000 VideoLAN
* $Id: stream_control.h,v 1.5 2001/02/08 13:52:34 massiot Exp $
* $Id: stream_control.h,v 1.6 2001/07/18 14:21:00 massiot Exp $
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
*
......@@ -39,7 +39,9 @@ typedef struct stream_ctrl_s
int i_rate;
boolean_t b_mute;
boolean_t b_bw; /* black & white */
boolean_t b_grayscale; /* use color or grayscale */
int i_smp; /* number of symmetrical threads to launch
* to decode the video | 0 == disabled */
} stream_ctrl_t;
/* Possible status : */
......
......@@ -3,7 +3,7 @@
* This header provides a portable threads implementation.
*****************************************************************************
* Copyright (C) 1999, 2000 VideoLAN
* $Id: threads.h,v 1.19 2001/06/14 20:21:04 sam Exp $
* $Id: threads.h,v 1.20 2001/07/18 14:21:00 massiot Exp $
*
* Authors: Jean-Marc Dressler <polux@via.ecp.fr>
* Samuel Hocevar <sam@via.ecp.fr>
......@@ -491,6 +491,74 @@ static __inline__ int vlc_cond_signal( vlc_cond_t *p_condvar )
#endif
}
/*****************************************************************************
* vlc_cond_broadcast: start all threads waiting on condition completion
*****************************************************************************/
/*
* FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME
* Only works with pthreads, you need to adapt it for others
* FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME
*/
static __inline__ int vlc_cond_broadcast( vlc_cond_t *p_condvar )
{
#if defined( PTH_INIT_IN_PTH_H )
return pth_cond_notify( p_condvar, FALSE );
#elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
return pthread_cond_broadcast( p_condvar );
#elif defined( HAVE_CTHREADS_H )
/* condition_signal() */
if ( p_condvar->queue.head || p_condvar->implications )
{
cond_signal( (condition_t)p_condvar );
}
return 0;
#elif defined( HAVE_KERNEL_SCHEDULER_H )
if( !p_condvar )
{
return B_BAD_VALUE;
}
if( p_condvar->init < 2000 )
{
return B_NO_INIT;
}
while( p_condvar->thread != -1 )
{
thread_info info;
if( get_thread_info(p_condvar->thread, &info) == B_BAD_VALUE )
{
return 0;
}
if( info.state != B_THREAD_SUSPENDED )
{
/* The waiting thread is not suspended so it could
* have been interrupted beetwen the unlock and the
* suspend_thread line. That is why we sleep a little
* before retesting p_condver->thread. */
snooze( 10000 );
}
else
{
/* Ok, we have to wake up that thread */
resume_thread( p_condvar->thread );
return 0;
}
}
return 0;
#elif defined( WIN32 )
/* Try to release one waiting thread. */
PulseEvent ( *p_condvar );
return 0;
#endif
}
/*****************************************************************************
* vlc_cond_wait: wait until condition completion
*****************************************************************************/
......
......@@ -2,7 +2,7 @@
* vdec_common.h : structures from the video decoder exported to plug-ins
*****************************************************************************
* Copyright (C) 1999, 2000 VideoLAN
* $Id: vdec_ext-plugins.h,v 1.1 2001/07/17 09:48:07 massiot Exp $
* $Id: vdec_ext-plugins.h,v 1.2 2001/07/18 14:21:00 massiot Exp $
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
*
......@@ -98,24 +98,13 @@ typedef struct macroblock_s
*****************************************************************************/
typedef struct vdec_thread_s
{
/* Thread properties and locks */
boolean_t b_die; /* `die' flag */
boolean_t b_run; /* `run' flag */
boolean_t b_error; /* `error' flag */
boolean_t b_active; /* `active' flag */
vlc_thread_t thread_id; /* id for thread functions */
boolean_t b_die;
/* IDCT iformations */
void * p_idct_data;
dctelem_t p_pre_idct[64*64];
/* Macroblock copy functions */
void ( * pf_decode_init ) ( struct vdec_thread_s * );
void ( * pf_decode_mb_c ) ( struct vdec_thread_s *, struct macroblock_s * );
void ( * pf_decode_mb_bw )( struct vdec_thread_s *, struct macroblock_s * );
/* Input properties */
struct vpar_thread_s * p_vpar; /* video_parser thread */
struct vdec_pool_s * p_pool;
} vdec_thread_t;
......@@ -4,7 +4,7 @@
* includes all common video types and constants.
*****************************************************************************
* Copyright (C) 1999, 2000 VideoLAN
* $Id: video.h,v 1.30 2001/05/07 04:42:42 sam Exp $
* $Id: video.h,v 1.31 2001/07/18 14:21:00 massiot Exp $
*
* Authors: Vincent Seguin <seguin@via.ecp.fr>
*
......@@ -71,11 +71,6 @@ typedef struct picture_s
int i_display_height; /* useful picture height */
int i_aspect_ratio; /* aspect ratio */
/* Macroblock counter - the decoder use it to verify if it has
* decoded all the macroblocks of the picture */
int i_deccount;
vlc_mutex_t lock_deccount;
/* Picture data - data can always be freely modified. p_data itself
* (the pointer) should NEVER be modified. In YUV format, the p_y, p_u and
* p_v data pointers refers to different areas of p_data, and should not
......
......@@ -4,7 +4,7 @@
* decoders.
*****************************************************************************
* Copyright (C) 1998, 1999, 2000 VideoLAN
* $Id: input.c,v 1.126 2001/07/17 09:48:08 massiot Exp $
* $Id: input.c,v 1.127 2001/07/18 14:21:00 massiot Exp $
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
*
......@@ -138,6 +138,7 @@ input_thread_t *input_CreateThread ( playlist_item_t *p_item, int *pi_status )
p_input->stream.i_selected_es_number = 0;
p_input->stream.i_pgrm_number = 0;
p_input->stream.i_new_status = p_input->stream.i_new_rate = 0;
p_input->stream.b_new_mute = MUTE_NO_CHANGE;
p_input->stream.i_mux_rate = 0;
/* no stream, no area */
......@@ -154,7 +155,10 @@ input_thread_t *input_CreateThread ( playlist_item_t *p_item, int *pi_status )
p_input->stream.control.i_status = PLAYING_S;
p_input->stream.control.i_rate = DEFAULT_RATE;
p_input->stream.control.b_mute = 0;
p_input->stream.control.b_bw = 0;
p_input->stream.control.b_grayscale = main_GetIntVariable(
VOUT_GRAYSCALE_VAR, VOUT_GRAYSCALE_DEFAULT );
p_input->stream.control.i_smp = main_GetIntVariable(
VDEC_SMP_VAR, VDEC_SMP_DEFAULT );
/* Setup callbacks */
p_input->pf_file_open = FileOpen;
......@@ -322,6 +326,20 @@ static void RunThread( input_thread_t *p_input )
p_input->stream.p_newly_selected_es = NULL;
}
if( p_input->stream.b_new_mute != MUTE_NO_CHANGE )
{
if( p_input->stream.b_new_mute )
{
input_EscapeAudioDiscontinuity( p_input );
}
vlc_mutex_lock( &p_input->stream.control.control_lock );
p_input->stream.control.b_mute = p_input->stream.b_new_mute;
vlc_mutex_unlock( &p_input->stream.control.control_lock );
p_input->stream.b_new_mute = MUTE_NO_CHANGE;
}
vlc_mutex_unlock( &p_input->stream.stream_lock );
i_error = p_input->pf_read( p_input, pp_packets );
......
......@@ -2,7 +2,7 @@
* input_clock.c: Clock/System date convertions, stream management
*****************************************************************************
* Copyright (C) 1999, 2000 VideoLAN
* $Id: input_clock.c,v 1.19 2001/07/17 09:48:08 massiot Exp $
* $Id: input_clock.c,v 1.20 2001/07/18 14:21:00 massiot Exp $
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
*
......@@ -197,7 +197,7 @@ int input_ClockManageControl( input_thread_t * p_input,
/* Feed the audio decoders with a NULL packet to avoid
* discontinuities. */
input_EscapeAudioDiscontinuity( p_input, p_pgrm );
input_EscapeAudioDiscontinuity( p_input );
}
p_input->stream.i_new_status = UNDEF_S;
......
......@@ -2,7 +2,7 @@
* input_dec.c: Functions for the management of decoders
*****************************************************************************
* Copyright (C) 1999, 2000 VideoLAN
* $Id: input_dec.c,v 1.12 2001/07/17 09:48:08 massiot Exp $
* $Id: input_dec.c,v 1.13 2001/07/18 14:21:00 massiot Exp $
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
*
......@@ -147,10 +147,13 @@ void input_EscapeDiscontinuity( input_thread_t * p_input,
/*****************************************************************************
* input_EscapeAudioDiscontinuity: send a NULL packet to the audio decoders
*****************************************************************************/
void input_EscapeAudioDiscontinuity( input_thread_t * p_input,
pgrm_descriptor_t * p_pgrm )
void input_EscapeAudioDiscontinuity( input_thread_t * p_input )
{
int i_es, i;
int i_pgrm, i_es, i;
for( i_pgrm = 0; i_pgrm < p_input->stream.i_pgrm_number; i_pgrm++ )
{
pgrm_descriptor_t * p_pgrm = p_input->stream.pp_programs[i_pgrm];
for( i_es = 0; i_es < p_pgrm->i_es_number; i_es++ )
{
......@@ -164,5 +167,6 @@ void input_EscapeAudioDiscontinuity( input_thread_t * p_input,
}
}
}
}
}
......@@ -2,7 +2,7 @@
* input_ext-intf.c: services to the interface
*****************************************************************************
* Copyright (C) 1998, 1999, 2000 VideoLAN
* $Id: input_ext-intf.c,v 1.26 2001/07/17 09:48:08 massiot Exp $
* $Id: input_ext-intf.c,v 1.27 2001/07/18 14:21:00 massiot Exp $
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
*
......@@ -128,14 +128,6 @@ void input_SetStatus( input_thread_t * p_input, int i_mode )
vlc_mutex_unlock( &p_input->stream.stream_lock );
}
/*****************************************************************************
* input_SetRate: change the reading rate
*****************************************************************************/
void input_SetRate( input_thread_t * p_input, int i_mode )
{
; /* FIXME: stub */
}
/*****************************************************************************
* input_Seek: changes the stream postion
*****************************************************************************/
......@@ -339,3 +331,55 @@ int input_ChangeArea( input_thread_t * p_input, input_area_t * p_area )
return 0;
}
/****************************************************************************
* input_ToggleGrayscale: change to grayscale or color output
****************************************************************************/
int input_ToggleGrayscale( input_thread_t * p_input )
{
/* No need to warn the input thread since only the decoders and outputs
* worry about it. */
vlc_mutex_lock( &p_input->stream.control.control_lock );
p_input->stream.control.b_grayscale =
!p_input->stream.control.b_grayscale;
intf_WarnMsg( 3, "input warning: changing to %s output",
p_input->stream.control.b_grayscale ? "grayscale" : "color" );
vlc_mutex_unlock( &p_input->stream.control.control_lock );
return 0;
}
/****************************************************************************
* input_ToggleMute: activate/deactivate mute mode
****************************************************************************/
int input_ToggleMute( input_thread_t * p_input )
{
/* We need to feed the decoders with 0, and only input can do that, so
* pass the message to the input thread. */
vlc_mutex_lock( &p_input->stream.stream_lock );
p_input->stream.b_new_mute = !p_input->stream.control.b_mute;
intf_WarnMsg( 3, "input warning: %s mute mode",
p_input->stream.control.b_mute ? "activating" : "deactivating" );
vlc_mutex_unlock( &p_input->stream.stream_lock );
return 0;
}
/****************************************************************************
* input_SetSMP: change the number of video decoder threads
****************************************************************************/
int input_SetSMP( input_thread_t * p_input, int i_smp )
{
/* No need to warn the input thread since only the decoders
* worry about it. */
vlc_mutex_lock( &p_input->stream.control.control_lock );
p_input->stream.control.i_smp = i_smp;
vlc_mutex_unlock( &p_input->stream.control.control_lock );
return 0;
}
......@@ -4,7 +4,7 @@
* interface, such as command line.
*****************************************************************************
* Copyright (C) 1998, 1999, 2000 VideoLAN
* $Id: interface.c,v 1.79 2001/05/15 14:49:48 stef Exp $
* $Id: interface.c,v 1.80 2001/07/18 14:21:00 massiot Exp $
*
* Authors: Vincent Seguin <seguin@via.ecp.fr>
*
......@@ -394,6 +394,13 @@ int intf_ProcessKey( intf_thread_t *p_intf, int g_key )
break;
case INTF_KEY_TOGGLE_VOLUME: /* toggle mute */
/* Start/stop feeding audio data. */
if( p_intf->p_input != NULL )
{
input_ToggleMute( p_intf->p_input );
}
/* Start/stop playing sound. */
vlc_mutex_lock( &p_aout_bank->lock );
for( i_index = 0 ; i_index < p_aout_bank->i_count ; i_index++ )
{
......
......@@ -4,7 +4,7 @@
* and spawn threads.
*****************************************************************************
* Copyright (C) 1998, 1999, 2000 VideoLAN
* $Id: main.c,v 1.107 2001/07/16 22:00:45 gbazin Exp $
* $Id: main.c,v 1.108 2001/07/18 14:21:00 massiot Exp $
*
* Authors: Vincent Seguin <seguin@via.ecp.fr>
* Samuel Hocevar <sam@zoy.org>
......@@ -113,6 +113,7 @@
#define OPT_COLOR 164
#define OPT_FULLSCREEN 165
#define OPT_OVERLAY 166
#define OPT_SMP 167
#define OPT_CHANNELS 170
#define OPT_SERVER 171
......@@ -183,6 +184,7 @@ static const struct option longopts[] =
{ "yuv", 1, 0, OPT_YUV },
{ "fullscreen", 0, 0, OPT_FULLSCREEN },
{ "overlay", 0, 0, OPT_OVERLAY },
{ "smp", 1, 0, OPT_SMP },
/* DVD options */
{ "dvdtitle", 1, 0, 't' },
......@@ -693,6 +695,9 @@ static int GetConfiguration( int *pi_argc, char *ppsz_argv[], char *ppsz_env[] )
case OPT_YUV: /* --yuv */
main_PutPszVariable( YUV_METHOD_VAR, optarg );
break;
case OPT_SMP: /* --smp */
main_PutIntVariable( VDEC_SMP_VAR, atoi(optarg) );
break;
/* DVD options */
case 't':
......@@ -836,6 +841,7 @@ static void Usage( int i_fashion )
"\n --idct <module> \tIDCT method"
"\n --yuv <module> \tYUV method"
"\n --synchro <type> \tforce synchro algorithm"
"\n --smp <number of threads> \tuse several processors"
"\n"
"\n -t, --dvdtitle <num> \tchoose DVD title"
"\n -T, --dvdchapter <num> \tchoose DVD chapter"
......@@ -887,7 +893,8 @@ static void Usage( int i_fashion )
"\n " MOTION_METHOD_VAR "=<method name> \tmotion compensation method"
"\n " IDCT_METHOD_VAR "=<method name> \tIDCT method"
"\n " YUV_METHOD_VAR "=<method name> \tYUV method"
"\n " VPAR_SYNCHRO_VAR "={I|I+|IP|IP+|IPB} \tsynchro algorithm" );
"\n " VPAR_SYNCHRO_VAR "={I|I+|IP|IP+|IPB} \tsynchro algorithm"
"\n " VDEC_SMP_VAR "=<number of threads> \tuse several processors" );
/* DVD parameters */
intf_MsgImm( "\nDVD parameters:"
......
......@@ -2,7 +2,7 @@
* video_decoder.c : video decoder thread
*****************************************************************************
* Copyright (C) 1999, 2000 VideoLAN
* $Id: video_decoder.c,v 1.53 2001/07/17 09:48:08 massiot Exp $
* $Id: video_decoder.c,v 1.54 2001/07/18 14:21:00 massiot Exp $
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
* Gal Hendryckx <jimmy@via.ecp.fr>
......@@ -50,32 +50,20 @@
#include "vdec_ext-plugins.h"
#include "video_decoder.h"
#include "vpar_blocks.h"
#include "vpar_headers.h"
#include "vpar_synchro.h"
#include "video_parser.h"
#include "video_fifo.h"
#include "vpar_pool.h"
/*
* Local prototypes
*/
#ifdef VDEC_SMP
static int vdec_InitThread ( vdec_thread_t *p_vdec );
#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 );
/*****************************************************************************
* 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:
* XXX??
*****************************************************************************/
vdec_thread_t * vdec_CreateThread( vpar_thread_t *p_vpar /*, int *pi_status */ )
vdec_thread_t * vdec_CreateThread( vdec_pool_t * p_pool )
{
vdec_thread_t * p_vdec;
......@@ -92,12 +80,11 @@ vdec_thread_t * vdec_CreateThread( vpar_thread_t *p_vpar /*, int *pi_status */ )
* Initialize the thread properties
*/
p_vdec->b_die = 0;
p_vdec->b_error = 0;
/*
* Initialize the parser properties
*/
p_vdec->p_vpar = p_vpar;
p_vdec->p_pool = p_pool;
/* Spawn the video decoder thread */
if ( vlc_thread_create(&p_vdec->thread_id, "video decoder",
......@@ -114,27 +101,20 @@ vdec_thread_t * vdec_CreateThread( vpar_thread_t *p_vpar /*, int *pi_status */ )
/*****************************************************************************
* vdec_DestroyThread: destroy a video decoder thread
*****************************************************************************
* 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.
*****************************************************************************/
void vdec_DestroyThread( vdec_thread_t *p_vdec /*, int *pi_status */ )
void vdec_DestroyThread( vdec_thread_t *p_vdec )
{
intf_DbgMsg("vdec debug: requesting termination of video decoder thread %p", p_vdec);
/* Ask thread to kill itself */
p_vdec->b_die = 1;
#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
vlc_mutex_lock( &p_vdec->p_pool->lock );
vlc_cond_broadcast( &p_vdec->p_pool->wait_undecoded );
vlc_mutex_unlock( &p_vdec->p_pool->lock );
/* Waiting for the decoder thread to exit */
/* Remove this as soon as the "status" flag is implemented */
vlc_thread_join( p_vdec->thread_id );
}
......@@ -144,65 +124,28 @@ void vdec_DestroyThread( vdec_thread_t *p_vdec /*, int *pi_status */ )
* 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.
* initialization.
*****************************************************************************/
#ifdef VDEC_SMP
static int vdec_InitThread( vdec_thread_t *p_vdec )
#else
int vdec_InitThread( vdec_thread_t *p_vdec )
#endif
void vdec_InitThread( vdec_thread_t *p_vdec )
{
intf_DbgMsg("vdec debug: initializing video decoder thread %p", p_vdec);
p_vdec->p_idct_data = NULL;
p_vdec->pf_decode_init = p_vdec->p_vpar->pf_decode_init;
p_vdec->pf_decode_mb_c = p_vdec->p_vpar->pf_decode_mb_c;
p_vdec->pf_decode_mb_bw = p_vdec->p_vpar->pf_decode_mb_bw;
p_vdec->pf_decode_init( p_vdec );
#ifdef VDEC_SMP
/* Re-nice ourself */
if( nice(VDEC_NICE) == -1 )
{
intf_WarnMsg( 2, "vdec warning : couldn't nice() (%s)",
strerror(errno) );
}
#endif
p_vdec->p_pool->pf_decode_init( p_vdec );
p_vdec->p_pool->pf_idct_init( p_vdec );
/* Mark thread as running and return */
intf_DbgMsg("vdec debug: InitThread(%p) succeeded", p_vdec);
return( 0 );
}
/*****************************************************************************
* ErrorThread: RunThread() error loop
*****************************************************************************
* This function is called when an error occured during thread main's loop. The
* thread can still receive feed, but must be ready to terminate as soon as
* possible.
*****************************************************************************/
static void ErrorThread( vdec_thread_t *p_vdec )
{
macroblock_t * p_mb;
/* Wait until a `die' order */
while( !p_vdec->b_die )
{
p_mb = vpar_GetMacroblock( &p_vdec->p_vpar->vfifo );
vpar_DestroyMacroblock( &p_vdec->p_vpar->vfifo, p_mb );
}
}
/*****************************************************************************
* EndThread: thread destruction
* vdec_EndThread: thread destruction
*****************************************************************************
* This function is called when the thread ends after a sucessful
* initialization.
*****************************************************************************/
static void EndThread( vdec_thread_t *p_vdec )
void vdec_EndThread( vdec_thread_t *p_vdec )
{
intf_DbgMsg("vdec debug: EndThread(%p)", p_vdec);
......@@ -210,6 +153,8 @@ static void EndThread( vdec_thread_t *p_vdec )
{
free( p_vdec->p_idct_data );
}
free( p_vdec );
}
/*****************************************************************************
......@@ -223,44 +168,26 @@ static void RunThread( vdec_thread_t *p_vdec )
intf_DbgMsg("vdec debug: running video decoder thread (%p) (pid == %i)",
p_vdec, getpid());
/*
* Initialize thread and free configuration
*/
p_vdec->b_error = vdec_InitThread( p_vdec );
if( p_vdec->b_error )
{
return;
}
p_vdec->b_run = 1;
vdec_InitThread( p_vdec );
/*
* Main loop - it is not executed if an error occured during
* initialization
* Main loop
*/
while( (!p_vdec->b_die) && (!p_vdec->b_error) )
while( !p_vdec->b_die )
{
macroblock_t * p_mb;
if( (p_mb = vpar_GetMacroblock( &p_vdec->p_vpar->vfifo )) != NULL )
if( (p_mb = vpar_GetMacroblock( p_vdec->p_pool, &p_vdec->b_die )) != NULL )
{
p_vdec->pf_decode_mb_c( p_vdec, p_mb );
p_vdec->p_pool->pf_vdec_decode( p_vdec, p_mb );
/* Decoding is finished, release the macroblock and free
* unneeded memory. */
vpar_ReleaseMacroblock( &p_vdec->p_vpar->vfifo, p_mb );
}
p_vdec->p_pool->pf_free_mb( p_vdec->p_pool, p_mb );
}
/*
* Error loop
*/
if( p_vdec->b_error )
{
ErrorThread( p_vdec );
}
/* End of thread */
EndThread( p_vdec );
p_vdec->b_run = 0;
vdec_EndThread( p_vdec );
}
......@@ -2,7 +2,7 @@
* video_decoder.h : video decoder thread
*****************************************************************************
* Copyright (C) 1999, 2000 VideoLAN
* $Id: video_decoder.h,v 1.3 2001/07/17 09:48:08 massiot Exp $
* $Id: video_decoder.h,v 1.4 2001/07/18 14:21:00 massiot Exp $
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
*
......@@ -21,18 +21,6 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
*****************************************************************************/
/*****************************************************************************
* Requires:
* "config.h"
* "common.h"
* "mtime.h"
* "threads.h"
* "input.h"
* "video.h"
* "video_output.h"
* "decoder_fifo.h"
*****************************************************************************/
/*****************************************************************************
* Prototypes
*****************************************************************************/
......@@ -40,15 +28,14 @@ struct vpar_thread_s;
struct macroblock_s;
/* Thread management functions */
#ifndef VDEC_SMP
int vdec_InitThread ( struct vdec_thread_s *p_vdec );
#endif
void vdec_InitThread ( struct vdec_thread_s *p_vdec );
void vdec_EndThread ( struct vdec_thread_s *p_vdec );
void vdec_DecodeMacroblock ( struct vdec_thread_s *p_vdec,
struct macroblock_s *p_mb );
void vdec_DecodeMacroblockC ( struct vdec_thread_s *p_vdec,
struct macroblock_s *p_mb );
void vdec_DecodeMacroblockBW ( struct vdec_thread_s *p_vdec,
struct macroblock_s *p_mb );
struct vdec_thread_s * vdec_CreateThread( struct vpar_thread_s *p_vpar );
struct vdec_thread_s * vdec_CreateThread( struct vdec_pool_s * );
void vdec_DestroyThread ( struct vdec_thread_s *p_vdec );
/*****************************************************************************
* video_fifo.c : video FIFO management
*****************************************************************************
* Copyright (C) 1999, 2000 VideoLAN
* $Id: video_fifo.c,v 1.2 2001/07/17 09:48:08 massiot Exp $
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
*****************************************************************************/
/*****************************************************************************
* Preamble
*****************************************************************************/
#include "defs.h"
#include <string.h> /* memcpy(), memset() */
#include "config.h"
#include "common.h"
#include "threads.h"
#include "mtime.h"
#include "intf_msg.h"
#include "stream_control.h"
#include "input_ext-dec.h"
#include "video.h"
#include "video_output.h"
#include "vdec_ext-plugins.h"
#include "video_decoder.h"
#include "vpar_blocks.h"
#include "vpar_headers.h"
#include "vpar_synchro.h"
#include "video_parser.h"
#include "video_fifo.h"
/*****************************************************************************
* vpar_InitFIFO : initialize the video FIFO
*****************************************************************************/
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 );
vlc_mutex_init( &p_vpar->vbuffer.lock );
/* Initialize FIFO properties */
p_vpar->vfifo.i_start = p_vpar->vfifo.i_end = 0;
/* Initialize buffer properties */
p_vpar->vbuffer.i_index = VFIFO_SIZE; /* all structures are available */
for( i_dummy = 0; i_dummy < VFIFO_SIZE + 1; i_dummy++ )
{
p_vpar->vbuffer.pp_mb_free[i_dummy] = p_vpar->vbuffer.p_macroblocks
+ i_dummy;
}
#endif
}
/*****************************************************************************
* video_fifo.h : FIFO for the pool of video_decoders
*****************************************************************************
* Copyright (C) 1999, 2000 VideoLAN
* $Id: video_fifo.h,v 1.6 2001/07/17 09:48:08 massiot Exp $
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
*****************************************************************************/
/*****************************************************************************
* Requires:
* "config.h"
* "common.h"
* "threads.h"
* "video_parser.h"
* "undec_picture.h"
*****************************************************************************/
/*****************************************************************************
* Macros
*****************************************************************************/
#ifdef VDEC_SMP
/* FIXME: 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 )
#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 );
while( VIDEO_FIFO_ISEMPTY( *p_fifo ) )
{
vlc_cond_wait( &p_fifo->wait, &p_fifo->lock );
if( p_fifo->p_vpar->p_fifo->b_die )
{
vlc_mutex_unlock( &p_fifo->lock );
return( NULL );
}
}
p_mb = VIDEO_FIFO_START( *p_fifo );
VIDEO_FIFO_INCSTART( *p_fifo );
vlc_mutex_unlock( &p_fifo->lock );
return( p_mb );
#else
/* Shouldn't normally be used without SMP. */
return NULL;
#endif
}
/*****************************************************************************
* vpar_NewMacroblock : return a buffer for the parser
*****************************************************************************/
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_lock( &P_buffer.lock );
while( P_buffer.i_index == -1 )
{
/* No more structures available. This should not happen ! */
intf_DbgMsg("vpar debug: macroblock list is empty, delaying");
vlc_mutex_unlock( &P_buffer.lock );
if( p_fifo->p_vpar->p_fifo->b_die )
{
return( NULL );
}
msleep(VPAR_OUTMEM_SLEEP);
vlc_mutex_lock( &P_buffer.lock );
}
p_mb = P_buffer.pp_mb_free[ P_buffer.i_index-- ];
vlc_mutex_unlock( &P_buffer.lock );
#undef P_buffer
return( p_mb );
#else
return( &p_fifo->buffer );
#endif
}
/*****************************************************************************
* vpar_ReleaseMacroblock : release a macroblock and put the picture in the
* video output heap, if it is finished
*****************************************************************************/
static __inline__ void vpar_ReleaseMacroblock( 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 == 1);
vlc_mutex_unlock( &p_mb->p_picture->lock_deccount );
//intf_DbgMsg( "%d ", p_mb->p_picture->i_deccount );
/* Test if it was the last block of the picture */
if( b_finished )
{
//intf_DbgMsg( "Image decodee" );
/* 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, 0 );
/* Unlink referenced pictures */
if( p_mb->p_forward != NULL )
{
vout_UnlinkPicture( p_fifo->p_vpar->p_vout, p_mb->p_forward );
}
if( p_mb->p_backward != NULL )
{
vout_UnlinkPicture( p_fifo->p_vpar->p_vout, p_mb->p_backward );
}
}
/* Release the macroblock_t structure */
#define P_buffer p_fifo->p_vpar->vbuffer
vlc_mutex_lock( &P_buffer.lock );
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, 0 );
}
#endif
}
/*****************************************************************************
* vpar_DecodeMacroblock : put a macroblock in the video fifo
*****************************************************************************/
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 );
/* By construction, the video FIFO cannot be full */
VIDEO_FIFO_END( *p_fifo ) = p_mb;
VIDEO_FIFO_INCEND( *p_fifo );
vlc_mutex_unlock( &p_fifo->lock );
#else
p_fifo->p_vpar->pf_decode_mb_c( p_fifo->p_vpar->pp_vdec[0], p_mb );
vpar_ReleaseMacroblock( &p_fifo->p_vpar->vfifo, p_mb );
#endif
}
/*****************************************************************************
* vpar_DestroyMacroblock : destroy a macroblock in case of error
*****************************************************************************/
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 == 1);
vlc_mutex_unlock( &p_mb->p_picture->lock_deccount );
/* Test if it was the last block of the picture */
if( b_finished )
{
intf_DbgMsg( "Image trashee" );
/* 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, 1 );
/* Unlink referenced pictures */
if( p_mb->p_forward != NULL )
{
vout_UnlinkPicture( p_fifo->p_vpar->p_vout, p_mb->p_forward );
}
if( p_mb->p_backward != NULL )
{
vout_UnlinkPicture( p_fifo->p_vpar->p_vout, p_mb->p_backward );
}
}
/* Release the macroblock_t structure */
#define P_buffer p_fifo->p_vpar->vbuffer
vlc_mutex_lock( &P_buffer.lock );
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, 1 );
}
#endif
}
/*****************************************************************************
* vpar_FreeMacroblock : destroy a macroblock in case of error, without
* updating the macroblock counters
*****************************************************************************/
static __inline__ void vpar_FreeMacroblock( video_fifo_t * p_fifo,
macroblock_t * p_mb )
{
#ifdef VDEC_SMP
/* Release the macroblock_t structure */
#define P_buffer p_fifo->p_vpar->vbuffer
vlc_mutex_lock( &P_buffer.lock );
P_buffer.pp_mb_free[ ++P_buffer.i_index ] = p_mb;
vlc_mutex_unlock( &P_buffer.lock );
#undef P_buffer
#else
;
#endif
}
/*****************************************************************************
* Prototypes
*****************************************************************************/
void vpar_InitFIFO( struct vpar_thread_s * p_vpar );
......@@ -2,7 +2,7 @@
* video_parser.c : video parser thread
*****************************************************************************
* Copyright (C) 1999, 2000 VideoLAN
* $Id: video_parser.c,v 1.2 2001/07/17 09:48:08 massiot Exp $
* $Id: video_parser.c,v 1.3 2001/07/18 14:21:00 massiot Exp $
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
* Samuel Hocevar <sam@via.ecp.fr>
......@@ -55,13 +55,8 @@
#include "video_output.h"
#include "vdec_ext-plugins.h"
#include "video_decoder.h"
#include "vpar_blocks.h"
#include "vpar_headers.h"
#include "vpar_synchro.h"
#include "vpar_pool.h"
#include "video_parser.h"
#include "video_fifo.h"
/*
* Local prototypes
......@@ -99,6 +94,34 @@ vlc_thread_t vpar_CreateThread( vdec_config_t * p_config )
p_vpar->p_config = p_config;
p_vpar->p_vout = NULL;
/* Spawn the video parser thread */
if ( vlc_thread_create( &p_vpar->thread_id, "video parser",
(vlc_thread_func_t)RunThread, (void *)p_vpar ) )
{
intf_ErrMsg("vpar error: can't spawn video parser thread");
module_Unneed( p_vpar->p_idct_module );
module_Unneed( p_vpar->p_motion_module );
free( p_vpar );
return( 0 );
}
intf_DbgMsg("vpar debug: video parser thread (%p) created", p_vpar);
return( p_vpar->thread_id );
}
/* following functions are local */
/*****************************************************************************
* 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( vpar_thread_t *p_vpar )
{
intf_DbgMsg("vpar debug: initializing video parser thread %p", p_vpar);
/*
* Choose the best motion compensation module
*/
......@@ -178,47 +201,16 @@ vlc_thread_t vpar_CreateThread( vdec_config_t * p_config )
}
#define f p_vpar->p_idct_module->p_functions->idct.functions.idct
p_vpar->pf_idct_init = f.pf_idct_init;
p_vpar->pool.pf_idct_init = f.pf_idct_init;
p_vpar->pf_sparse_idct = f.pf_sparse_idct;
p_vpar->pf_idct = f.pf_idct;
p_vpar->pf_norm_scan = f.pf_norm_scan;
p_vpar->pf_decode_init = f.pf_decode_init;
p_vpar->pool.pf_decode_init = f.pf_decode_init;
p_vpar->pf_decode_mb_c = f.pf_decode_mb_c;
p_vpar->pf_decode_mb_bw = f.pf_decode_mb_bw;
#undef f
/* Spawn the video parser thread */
if ( vlc_thread_create( &p_vpar->thread_id, "video parser",
(vlc_thread_func_t)RunThread, (void *)p_vpar ) )
{
intf_ErrMsg("vpar error: can't spawn video parser thread");
module_Unneed( p_vpar->p_idct_module );
module_Unneed( p_vpar->p_motion_module );
free( p_vpar );
return( 0 );
}
intf_DbgMsg("vpar debug: video parser thread (%p) created", p_vpar);
return( p_vpar->thread_id );
}
/* following functions are local */
/*****************************************************************************
* 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( vpar_thread_t *p_vpar )
{
#ifdef VDEC_SMP
int i_dummy;
#endif
intf_DbgMsg("vpar debug: initializing video parser thread %p", p_vpar);
/* Initialize input bitstream */
p_vpar->p_config->decoder_config.pf_init_bit_stream( &p_vpar->bit_stream,
p_vpar->p_config->decoder_config.p_decoder_fifo, BitstreamCallback,
(void *)p_vpar );
......@@ -253,51 +245,6 @@ static int InitThread( vpar_thread_t *p_vpar )
sizeof(p_vpar->pc_malformed_pictures));
#endif
/* Initialize video FIFO */
vpar_InitFIFO( p_vpar );
memset( p_vpar->pp_vdec, 0, NB_VDEC*sizeof(vdec_thread_t *) );
#ifdef VDEC_SMP
/* Spawn video_decoder threads */
/* FIXME: modify the number of vdecs at runtime ?? */
for( i_dummy = 0; i_dummy < NB_VDEC; i_dummy++ )
{
if( (p_vpar->pp_vdec[i_dummy] = vdec_CreateThread( p_vpar )) == NULL )
{
return( 1 );
}
}
#else
/* Fake a video_decoder thread */
p_vpar->pp_vdec[0] = (vdec_thread_t *)malloc(sizeof( vdec_thread_t ));
if( p_vpar->pp_vdec[0] == NULL )
{
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;
if( vdec_InitThread( p_vpar->pp_vdec[0] ) )
{
return( 1 );
}
# if !defined(SYS_BEOS) && !defined(WIN32)
# if VDEC_NICE
/* Re-nice ourself */
if( nice(VDEC_NICE) == -1 )
{
intf_WarnMsg( 2, "vpar warning : couldn't nice() (%s)",
strerror(errno) );
}
# endif
# endif
#endif
/* Initialize lookup tables */
vpar_InitMbAddrInc( p_vpar );
vpar_InitDCTTables( p_vpar );
......@@ -311,6 +258,9 @@ static int InitThread( vpar_thread_t *p_vpar )
*/
vpar_SynchroInit( p_vpar );
/* Spawn optional video decoder threads */
vpar_InitPool( p_vpar );
/* Mark thread as running and return */
intf_DbgMsg("vpar debug: InitThread(%p) succeeded", p_vpar);
return( 0 );
......@@ -350,7 +300,7 @@ static void RunThread( vpar_thread_t *p_vpar )
{
/* End of sequence */
break;
};
}
}
}
......@@ -406,10 +356,6 @@ static void ErrorThread( vpar_thread_t *p_vpar )
*****************************************************************************/
static void EndThread( vpar_thread_t *p_vpar )
{
#ifdef VDEC_SMP
int i_dummy;
#endif
intf_DbgMsg("vpar debug: destroying video parser thread %p", p_vpar);
/* Release used video buffers. */
......@@ -489,30 +435,10 @@ static void EndThread( vpar_thread_t *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->pp_vdec[i_dummy] != NULL )
vdec_DestroyThread( p_vpar->pp_vdec[i_dummy] );
else
break;
}
#else
free( p_vpar->pp_vdec[0] );
#endif
vpar_EndPool( p_vpar );
free( p_vpar->p_config );
#ifdef VDEC_SMP
/* Destroy lock and cond */
vlc_mutex_destroy( &(p_vpar->vbuffer.lock) );
vlc_cond_destroy( &(p_vpar->vfifo.wait) );
vlc_mutex_destroy( &(p_vpar->vfifo.lock) );
#endif
vlc_mutex_destroy( &(p_vpar->synchro.fifo_lock) );
module_Unneed( p_vpar->p_idct_module );
module_Unneed( p_vpar->p_motion_module );
......
......@@ -2,9 +2,11 @@
* video_parser.h : video parser thread
*****************************************************************************
* Copyright (C) 1999, 2000 VideoLAN
* $Id: video_parser.h,v 1.10 2001/07/17 09:48:08 massiot Exp $
* $Id: video_parser.h,v 1.11 2001/07/18 14:21:00 massiot Exp $
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
* Jean-Marc Dressler <polux@via.ecp.fr>
* Stphane Borel <stef@via.ecp.fr>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
......@@ -21,65 +23,332 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
*****************************************************************************/
/*
* Block parsing structures
*/
/*****************************************************************************
* Requires:
* "config.h"
* "common.h"
* "mtime.h"
* "threads.h"
* "input.h"
* "video.h"
* "video_output.h"
* "decoder_fifo.h"
* "video_fifo.h"
* "vpar_headers.h"
* macroblock_parsing_t : macroblock context & predictors
*****************************************************************************/
typedef struct
{
unsigned char i_quantizer_scale; /* scale of the quantization
* matrices */
int pi_dc_dct_pred[3]; /* ISO/IEC 13818-2 7.2.1 */
int pppi_pmv[2][2][2]; /* Motion vect predictors, 7.6.3 */
int i_motion_dir;/* Used for the next skipped macroblock */
/* Context used to optimize block parsing */
int i_motion_type, i_mv_count, i_mv_format;
boolean_t b_dmv, b_dct_type;
/* Coordinates of the upper-left pixel of the macroblock, in lum and
* chroma */
int i_l_x, i_l_y, i_c_x, i_c_y;
} macroblock_parsing_t;
/*****************************************************************************
* video_fifo_t
*****************************************************************************
* This rotative FIFO contains undecoded macroblocks that are to be decoded
* lookup_t : entry type for lookup tables *
*****************************************************************************/
struct vpar_thread_s;
typedef struct lookup_s
{
int i_value;
int i_length;
} lookup_t;
typedef struct video_fifo_s
/*****************************************************************************
* ac_lookup_t : special entry type for lookup tables about ac coefficients
*****************************************************************************/
typedef struct dct_lookup_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;
#else
macroblock_t buffer;
char i_run;
char i_level;
char i_length;
} dct_lookup_t;
/*****************************************************************************
* Standard codes
*****************************************************************************/
/* Macroblock Address Increment types */
#define MB_ADDRINC_ESCAPE 8
#define MB_ADDRINC_STUFFING 15
/* Error constant for lookup tables */
#define MB_ERROR (-1)
/* Scan */
#define SCAN_ZIGZAG 0
#define SCAN_ALT 1
/* Constant for block decoding */
#define DCT_EOB 64
#define DCT_ESCAPE 65
/*****************************************************************************
* Constants
*****************************************************************************/
extern u8 pi_default_intra_quant[64];
extern u8 pi_default_nonintra_quant[64];
extern u8 pi_scan[2][64];
/*****************************************************************************
* Prototypes
*****************************************************************************/
void vpar_InitCrop( struct vpar_thread_s* p_vpar );
void vpar_InitMbAddrInc( struct vpar_thread_s * p_vpar );
void vpar_InitPMBType( struct vpar_thread_s * p_vpar );
void vpar_InitBMBType( struct vpar_thread_s * p_vpar );
void vpar_InitCodedPattern( struct vpar_thread_s * p_vpar );
void vpar_InitDCTTables( struct vpar_thread_s * p_vpar );
void vpar_InitScanTable( struct vpar_thread_s * p_vpar );
typedef void (*f_picture_data_t)( struct vpar_thread_s * p_vpar,
int i_mb_base );
#define PROTO_PICD( FUNCNAME ) \
void FUNCNAME( struct vpar_thread_s * p_vpar, int i_mb_base );
PROTO_PICD( vpar_PictureDataGENERIC )
#if (VPAR_OPTIM_LEVEL > 0)
PROTO_PICD( vpar_PictureData1I )
PROTO_PICD( vpar_PictureData1P )
PROTO_PICD( vpar_PictureData1B )
PROTO_PICD( vpar_PictureData1D )
PROTO_PICD( vpar_PictureData2IF )
PROTO_PICD( vpar_PictureData2PF )
PROTO_PICD( vpar_PictureData2BF )
#endif
#if (VPAR_OPTIM_LEVEL > 1)
PROTO_PICD( vpar_PictureData2IT )
PROTO_PICD( vpar_PictureData2PT )
PROTO_PICD( vpar_PictureData2BT )
PROTO_PICD( vpar_PictureData2IB )
PROTO_PICD( vpar_PictureData2PB )
PROTO_PICD( vpar_PictureData2BB )
#endif
struct vpar_thread_s * p_vpar;
} video_fifo_t;
/*
* Headers parsing structures
*/
/*****************************************************************************
* quant_matrix_t : Quantization Matrix
*****************************************************************************/
typedef struct quant_matrix_s
{
u8 * pi_matrix;
boolean_t b_allocated;
/* Has the matrix been allocated by vpar_headers ? */
} quant_matrix_t;
/*****************************************************************************
* video_buffer_t
* sequence_t : sequence descriptor
*****************************************************************************
* This structure enables the parser to maintain a list of free
* macroblock_t structures
* This structure should only be changed when reading the sequence header,
* or exceptionnally some extension structures (like quant_matrix).
*****************************************************************************/
#ifdef VDEC_SMP
typedef struct video_buffer_s
typedef struct sequence_s
{
vlc_mutex_t lock; /* buffer data lock */
u32 i_height, i_width; /* height and width of the lum
* comp of the picture */
u32 i_size; /* total number of pel of the lum comp */
u32 i_mb_height, i_mb_width, i_mb_size;
/* the same, in macroblock units */
unsigned int i_aspect_ratio; /* height/width display ratio */
unsigned int i_matrix_coefficients;/* coeffs of the YUV transform */
int i_frame_rate; /* theoritical frame rate in fps*1001 */
boolean_t b_mpeg2; /* guess */
boolean_t b_progressive; /* progressive (ie.
* non-interlaced) frame */
unsigned int i_scalable_mode; /* scalability ; unsupported, but
* modifies the syntax of the binary
* stream. */
quant_matrix_t intra_quant, nonintra_quant;
quant_matrix_t chroma_intra_quant, chroma_nonintra_quant;
/* current quantization matrices */
/* Chromatic information */
unsigned int i_chroma_format; /* see CHROMA_* below */
int i_chroma_nb_blocks; /* number of chroma blocks */
u32 i_chroma_width;/* width of a line of the chroma comp */
u32 i_chroma_mb_width, i_chroma_mb_height;
/* size of a macroblock in the chroma buffer
* (eg. 8x8 or 8x16 or 16x16) */
/* Parser context */
picture_t * p_forward; /* current forward reference frame */
picture_t * p_backward; /* current backward reference frame */
mtime_t next_pts, next_dts;
int i_current_rate;
boolean_t b_expect_discontinuity; /* reset the frame predictors
* after the current frame */
/* Copyright extension */
boolean_t b_copyright_flag; /* Whether the following
information is significant
or not. */
u8 i_copyright_id;
boolean_t b_original;
u64 i_copyright_nb;
} sequence_t;
macroblock_t p_macroblocks[VFIFO_SIZE + 1];
macroblock_t * pp_mb_free[VFIFO_SIZE+1]; /* this is a LIFO */
int i_index;
} video_buffer_t;
/*****************************************************************************
* picture_parsing_t : parser context descriptor
*****************************************************************************
* This structure should only be changed when reading the picture header.
*****************************************************************************/
typedef struct picture_parsing_s
{
/* ISO/CEI 11172-2 backward compatibility */
boolean_t pb_full_pel_vector[2];
int i_forward_f_code, i_backward_f_code;
/* Values from the picture_coding_extension. Please refer to ISO/IEC
* 13818-2. */
int ppi_f_code[2][2];
int i_intra_dc_precision;
boolean_t b_frame_pred_frame_dct, b_q_scale_type;
boolean_t b_intra_vlc_format;
boolean_t b_alternate_scan, b_progressive;
boolean_t b_top_field_first, b_concealment_mv;
boolean_t b_repeat_first_field;
/* Relative to the current field */
int i_coding_type, i_structure;
boolean_t b_frame_structure; /* i_structure == FRAME_STRUCTURE */
picture_t * p_picture; /* picture buffer from vout */
int i_current_structure; /* current parsed structure of
* p_picture (second field ?) */
boolean_t b_error; /* parsing error, try to recover */
int i_l_stride, i_c_stride;
/* number of coeffs to jump when changing
* lines (different with field pictures) */
} picture_parsing_t;
/*****************************************************************************
* Standard codes
*****************************************************************************/
#define PICTURE_START_CODE 0x100L
#define SLICE_START_CODE_MIN 0x101L
#define SLICE_START_CODE_MAX 0x1AFL
#define USER_DATA_START_CODE 0x1B2L
#define SEQUENCE_HEADER_CODE 0x1B3L
#define SEQUENCE_ERROR_CODE 0x1B4L
#define EXTENSION_START_CODE 0x1B5L
#define SEQUENCE_END_CODE 0x1B7L
#define GROUP_START_CODE 0x1B8L
/* extension start code IDs */
#define SEQUENCE_EXTENSION_ID 1
#define SEQUENCE_DISPLAY_EXTENSION_ID 2
#define QUANT_MATRIX_EXTENSION_ID 3
#define COPYRIGHT_EXTENSION_ID 4
#define SEQUENCE_SCALABLE_EXTENSION_ID 5
#define PICTURE_DISPLAY_EXTENSION_ID 7
#define PICTURE_CODING_EXTENSION_ID 8
#define PICTURE_SPATIAL_SCALABLE_EXTENSION_ID 9
#define PICTURE_TEMPORAL_SCALABLE_EXTENSION_ID 10
/* scalable modes */
#define SC_NONE 0
#define SC_DP 1
#define SC_SPAT 2
#define SC_SNR 3
#define SC_TEMP 4
/* Chroma types */
#define CHROMA_420 1
#define CHROMA_422 2
#define CHROMA_444 3
/* 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 */
/*****************************************************************************
* Prototypes
*****************************************************************************/
int vpar_NextSequenceHeader( struct vpar_thread_s * p_vpar );
int vpar_ParseHeader( struct vpar_thread_s * p_vpar );
/*
* Synchronization management
*/
/*****************************************************************************
* video_synchro_t : timers for the video synchro
*****************************************************************************/
#define MAX_PIC_AVERAGE 8
/* Read the discussion on top of vpar_synchro.c for more information. */
typedef struct video_synchro_s
{
/* synchro algorithm */
int i_type;
/* date of the beginning of the decoding of the current picture */
mtime_t decoding_start;
/* stream properties */
unsigned int i_n_p, i_n_b;
/* decoding values */
mtime_t p_tau[4]; /* average decoding durations */
unsigned int pi_meaningful[4]; /* number of durations read */
/* and p_vout->render_time (read with p_vout->change_lock) */
/* stream context */
unsigned int i_eta_p, i_eta_b;
boolean_t b_dropped_last; /* for special synchros below */
mtime_t backward_pts, current_pts;
int i_current_period; /* period to add to the next picture */
int i_backward_period; /* period to add after the next
* reference picture
* (backward_period * period / 2) */
#ifdef STATS
unsigned int i_trashed_pic, i_not_chosen_pic, i_pic;
#endif
} video_synchro_t;
/* Synchro algorithms */
#define VPAR_SYNCHRO_DEFAULT 0
#define VPAR_SYNCHRO_I 1
#define VPAR_SYNCHRO_Iplus 2
#define VPAR_SYNCHRO_IP 3
#define VPAR_SYNCHRO_IPplus 4
#define VPAR_SYNCHRO_IPB 5
/*****************************************************************************
* Prototypes
*****************************************************************************/
void vpar_SynchroInit ( struct vpar_thread_s * p_vpar );
boolean_t vpar_SynchroChoose ( struct vpar_thread_s * p_vpar,
int i_coding_type, int i_structure );
void vpar_SynchroTrash ( struct vpar_thread_s * p_vpar,
int i_coding_type, int i_structure );
void vpar_SynchroDecode ( struct vpar_thread_s * p_vpar,
int i_coding_type, int i_structure );
void vpar_SynchroEnd ( struct vpar_thread_s * p_vpar,
int i_coding_type, int i_structure,
int i_garbage );
mtime_t vpar_SynchroDate ( struct vpar_thread_s * p_vpar );
void vpar_SynchroNewPicture( struct vpar_thread_s * p_vpar, int i_coding_type,
int i_repeat_field );
/*
* Video parser structures
*/
/*****************************************************************************
* vpar_thread_t: video parser thread descriptor
*****************************************************************************
* XXX??
*****************************************************************************/
typedef struct vpar_thread_s
{
......@@ -96,11 +365,7 @@ typedef struct vpar_thread_s
vout_thread_t * p_vout; /* video output thread */
/* Decoder properties */
struct vdec_thread_s * pp_vdec[NB_VDEC];
video_fifo_t vfifo;
#ifdef VDEC_SMP
video_buffer_t vbuffer;
#endif
vdec_pool_t pool;
/* Parser properties */
sequence_t sequence;
......@@ -108,9 +373,11 @@ typedef struct vpar_thread_s
macroblock_parsing_t mb;
video_synchro_t synchro;
/* Lookup tables */
lookup_t pl_mb_addr_inc[2048]; /* for macroblock
address increment */
/*
* Lookup tables
*/
/* table for macroblock address increment */
lookup_t pl_mb_addr_inc[2048];
/* tables for macroblock types 0=P 1=B */
lookup_t ppl_mb_type[2][64];
/* table for coded_block_pattern */
......@@ -125,18 +392,16 @@ typedef struct vpar_thread_s
u8 pi_default_intra_quant[64];
u8 pi_default_nonintra_quant[64];
/* Motion compensation plugin used and shortcuts */
/* Motion compensation plug-in used and shortcuts */
struct module_s * p_motion_module;
void ( * pppf_motion[4][2][4] ) ( struct macroblock_s * );
void ( * ppf_motion_skipped[4][4] ) ( struct macroblock_s * );
/* IDCT plugin used and shortcuts to access its capabilities */
/* IDCT plugin used and shortcuts */
struct module_s * p_idct_module;
void ( * pf_idct_init ) ( struct vdec_thread_s * );
void ( * pf_sparse_idct ) ( void *, dctelem_t*, int );
void ( * pf_idct ) ( void *, dctelem_t*, int );
void ( * pf_norm_scan ) ( u8 ppi_scan[2][64] );
void ( * pf_decode_init ) ( struct vdec_thread_s * );
void ( * pf_decode_mb_c ) ( struct vdec_thread_s *, struct macroblock_s * );
void ( * pf_decode_mb_bw )( struct vdec_thread_s *, struct macroblock_s * );
......@@ -156,7 +421,7 @@ typedef struct vpar_thread_s
* Prototypes
*****************************************************************************/
/* Thread management functions */
/* Thread management functions - temporary ! */
vlc_thread_t vpar_CreateThread ( vdec_config_t * );
/*****************************************************************************
......
......@@ -2,7 +2,7 @@
* vpar_blocks.c : blocks parsing
*****************************************************************************
* Copyright (C) 1999, 2000 VideoLAN
* $Id: vpar_blocks.c,v 1.2 2001/07/17 09:48:08 massiot Exp $
* $Id: vpar_blocks.c,v 1.3 2001/07/18 14:21:00 massiot Exp $
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
* Jean-Marc Dressler <polux@via.ecp.fr>
......@@ -44,13 +44,8 @@
#include "video_output.h"
#include "vdec_ext-plugins.h"
#include "video_decoder.h"
#include "vpar_blocks.h"
#include "vpar_headers.h"
#include "vpar_synchro.h"
#include "vpar_pool.h"
#include "video_parser.h"
#include "video_fifo.h"
/*
* Welcome to vpar_blocks.c ! Here's where the heavy processor-critical parsing
......@@ -1644,14 +1639,7 @@ static __inline__ void SkippedMacroblock( vpar_thread_t * p_vpar, int i_mb,
return;
}
if( (p_mb = vpar_NewMacroblock( &p_vpar->vfifo )) == NULL )
{
/* b_die == 1 */
return;
}
#ifdef VDEC_SMP
p_vpar->picture.pp_mb[i_mb_base + i_mb] = p_mb;
#endif
p_mb = p_vpar->pool.pf_new_mb( &p_vpar->pool );
InitMacroblock( p_vpar, p_mb, i_coding_type, i_structure );
......@@ -1679,10 +1667,8 @@ static __inline__ void SkippedMacroblock( vpar_thread_t * p_vpar, int i_mb,
UpdateContext( p_vpar, i_structure );
#ifndef VDEC_SMP
/* Decode the macroblock NOW ! */
vpar_DecodeMacroblock ( &p_vpar->vfifo, p_mb );
#endif
p_vpar->pool.pf_decode_mb( &p_vpar->pool, p_mb );
}
/*****************************************************************************
......@@ -1776,7 +1762,7 @@ static __inline__ void MacroblockModes( vpar_thread_t * p_vpar,
if( p_vpar->picture.b_error ) \
{ \
/* Go to the next slice. */ \
vpar_FreeMacroblock( &p_vpar->vfifo, p_mb ); \
p_vpar->pool.pf_free_mb( &p_vpar->pool, p_mb ); \
return; \
}
......@@ -1830,14 +1816,7 @@ static __inline__ void ParseMacroblock(
}
/* Get a macroblock structure. */
if( (p_mb = vpar_NewMacroblock( &p_vpar->vfifo )) == NULL )
{
/* b_die == 1 */
return;
}
#ifdef VDEC_SMP
p_vpar->picture.pp_mb[i_mb_base + *pi_mb_address] = p_mb;
#endif
p_mb = p_vpar->pool.pf_new_mb( &p_vpar->pool );
InitMacroblock( p_vpar, p_mb, i_coding_type, i_structure );
......@@ -1960,24 +1939,27 @@ static __inline__ void ParseMacroblock(
* Effectively decode blocks.
*/
if( b_mpeg2 )
{
DecodeMPEG2IntraMB( p_vpar, p_mb );
}
else
{
DecodeMPEG1IntraMB( p_vpar, p_mb );
}
PARSEERROR
}
if( !p_vpar->picture.b_error )
{
UpdateContext( p_vpar, i_structure );
#ifndef VDEC_SMP
/* Decode the macroblock NOW ! */
vpar_DecodeMacroblock ( &p_vpar->vfifo, p_mb );
#endif
p_vpar->pool.pf_decode_mb( &p_vpar->pool, p_mb );
}
else
{
/* Go to the next slice. */
vpar_FreeMacroblock( &p_vpar->vfifo, p_mb );
p_vpar->pool.pf_free_mb( &p_vpar->pool, p_mb );
}
}
......@@ -2090,7 +2072,7 @@ static __inline__ void vpar_PictureData( vpar_thread_t * p_vpar,
}
#if 0
/* Buggy */
/* BUGGY */
/* Try to recover from error. If we missed less than half the
* number of macroblocks of the picture, mark the missed ones
* as skipped. */
......
......@@ -2,7 +2,7 @@
* vpar_headers.c : headers parsing
*****************************************************************************
* Copyright (C) 1999, 2000 VideoLAN
* $Id: vpar_headers.c,v 1.2 2001/07/17 09:48:08 massiot Exp $
* $Id: vpar_headers.c,v 1.3 2001/07/18 14:21:00 massiot Exp $
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
* Stphane Borel <stef@via.ecp.fr>
......@@ -44,13 +44,8 @@
#include "video_output.h"
#include "vdec_ext-plugins.h"
#include "video_decoder.h"
#include "vpar_blocks.h"
#include "vpar_headers.h"
#include "vpar_synchro.h"
#include "vpar_pool.h"
#include "video_parser.h"
#include "video_fifo.h"
/*
* Local prototypes
......@@ -450,7 +445,7 @@ static void SequenceHeader( vpar_thread_t * p_vpar )
/* XXX: The vout request and fifo opening will eventually be here */
/* Spawn an audio output if there is none */
/* Spawn a video output if there is none */
vlc_mutex_lock( &p_vout_bank->lock );
if( p_vout_bank->i_count == 0 )
......@@ -510,15 +505,6 @@ static void PictureHeader( vpar_thread_t * p_vpar )
ReferenceUpdate( p_vpar, I_CODING_TYPE, NULL );
if( p_vpar->picture.p_picture != NULL )
{
#ifdef VDEC_SMP
int i_mb;
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_vpar->sequence.b_expect_discontinuity = 0;
......@@ -613,14 +599,6 @@ static void PictureHeader( vpar_thread_t * p_vpar )
ReferenceReplace( p_vpar,
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 );
}
......@@ -747,30 +725,11 @@ static void PictureHeader( vpar_thread_t * p_vpar )
p_vpar->picture.i_c_stride = ( p_vpar->sequence.i_chroma_width
<< ( 1 - p_vpar->picture.b_frame_structure ));
P_picture->i_deccount = p_vpar->sequence.i_mb_size;
#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;
......@@ -855,6 +814,12 @@ static void PictureHeader( vpar_thread_t * p_vpar )
#endif
}
/* Wait for all the macroblocks to be decoded. */
p_vpar->pool.pf_wait_pool( &p_vpar->pool );
/* Re-spawn decoder threads if the user changed settings. */
vpar_SpawnPool( p_vpar );
if( p_vpar->p_fifo->b_die || p_vpar->p_fifo->b_error )
{
return;
......@@ -863,22 +828,13 @@ static void PictureHeader( vpar_thread_t * p_vpar )
if( p_vpar->picture.b_error )
{
/* Trash picture. */
#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] );
}
#endif
#ifdef STATS
p_vpar->pc_malformed_pictures[p_vpar->picture.i_coding_type]++;
#endif
if( P_picture->i_deccount != 1 )
{
vpar_SynchroEnd( p_vpar, 1 );
vpar_SynchroEnd( p_vpar, p_vpar->picture.i_coding_type,
p_vpar->picture.i_structure, 1 );
vout_DestroyPicture( p_vpar->p_vout, P_picture );
}
ReferenceReplace( p_vpar, p_vpar->picture.i_coding_type, NULL );
......@@ -890,17 +846,9 @@ static void PictureHeader( vpar_thread_t * p_vpar )
else if( p_vpar->picture.i_current_structure == FRAME_STRUCTURE )
{
/* 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] );
}
/* 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
vpar_SynchroEnd( p_vpar, p_vpar->picture.i_coding_type,
p_vpar->picture.i_structure, 0 );
vout_DisplayPicture( p_vpar->p_vout, P_picture );
/* Prepare context for the next picture. */
P_picture = NULL;
......
/*****************************************************************************
* vpar_headers.h : video parser : headers parsing
*****************************************************************************
* Copyright (C) 1999, 2000 VideoLAN
* $Id: vpar_headers.h,v 1.8 2001/07/17 09:48:08 massiot Exp $
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
* Stphane Borel <stef@via.ecp.fr>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
*****************************************************************************/
/*****************************************************************************
* Requires:
* "config.h"
* "common.h"
* "mtime.h"
* "threads.h"
* "input.h"
* "video.h"
* "video_output.h"
* "decoder_fifo.h"
* "video_fifo.h"
*****************************************************************************/
/*****************************************************************************
* quant_matrix_t : Quantization Matrix
*****************************************************************************/
typedef struct quant_matrix_s
{
u8 * pi_matrix;
boolean_t b_allocated;
/* Has the matrix been allocated by vpar_headers ? */
} quant_matrix_t;
/*****************************************************************************
* sequence_t : sequence descriptor
*****************************************************************************
* This structure should only be changed when reading the sequence header,
* or exceptionnally some extension structures (like quant_matrix).
*****************************************************************************/
typedef struct sequence_s
{
u32 i_height, i_width; /* height and width of the lum
* comp of the picture */
u32 i_size; /* total number of pel of the lum comp */
u32 i_mb_height, i_mb_width, i_mb_size;
/* the same, in macroblock units */
unsigned int i_aspect_ratio; /* height/width display ratio */
unsigned int i_matrix_coefficients;/* coeffs of the YUV transform */
int i_frame_rate; /* theoritical frame rate in fps*1001 */
boolean_t b_mpeg2; /* guess */
boolean_t b_progressive; /* progressive (ie.
* non-interlaced) frame */
unsigned int i_scalable_mode; /* scalability ; unsupported, but
* modifies the syntax of the binary
* stream. */
quant_matrix_t intra_quant, nonintra_quant;
quant_matrix_t chroma_intra_quant, chroma_nonintra_quant;
/* current quantization matrices */
/* Chromatic information */
unsigned int i_chroma_format; /* see CHROMA_* below */
int i_chroma_nb_blocks; /* number of chroma blocks */
u32 i_chroma_width;/* width of a line of the chroma comp */
u32 i_chroma_mb_width, i_chroma_mb_height;
/* size of a macroblock in the chroma buffer
* (eg. 8x8 or 8x16 or 16x16) */
/* Parser context */
picture_t * p_forward; /* current forward reference frame */
picture_t * p_backward; /* current backward reference frame */
mtime_t next_pts, next_dts;
int i_current_rate;
boolean_t b_expect_discontinuity; /* reset the frame predictors
* after the current frame */
/* Copyright extension */
boolean_t b_copyright_flag; /* Whether the following
information is significant
or not. */
u8 i_copyright_id;
boolean_t b_original;
u64 i_copyright_nb;
} sequence_t;
/*****************************************************************************
* picture_parsing_t : parser context descriptor
*****************************************************************************
* This structure should only be changed when reading the picture header.
*****************************************************************************/
typedef struct picture_parsing_s
{
/* ISO/CEI 11172-2 backward compatibility */
boolean_t pb_full_pel_vector[2];
int i_forward_f_code, i_backward_f_code;
/* Values from the picture_coding_extension. Please refer to ISO/IEC
* 13818-2. */
int ppi_f_code[2][2];
int i_intra_dc_precision;
boolean_t b_frame_pred_frame_dct, b_q_scale_type;
boolean_t b_intra_vlc_format;
boolean_t b_alternate_scan, b_progressive;
boolean_t b_top_field_first, b_concealment_mv;
boolean_t b_repeat_first_field;
/* Relative to the current field */
int i_coding_type, i_structure;
boolean_t b_frame_structure; /* i_structure == FRAME_STRUCTURE */
picture_t * p_picture; /* picture buffer from vout */
int i_current_structure; /* current parsed structure of
* p_picture (second field ?) */
#ifdef VDEC_SMP
macroblock_t * pp_mb[MAX_MB]; /* macroblock buffer to
* send to the vdec thread(s) */
#endif
boolean_t b_error; /* parsing error, try to recover */
int i_l_stride, i_c_stride;
/* number of coeffs to jump when changing
* lines (different with field pictures) */
} picture_parsing_t;
/*****************************************************************************
* Standard codes
*****************************************************************************/
#define PICTURE_START_CODE 0x100L
#define SLICE_START_CODE_MIN 0x101L
#define SLICE_START_CODE_MAX 0x1AFL
#define USER_DATA_START_CODE 0x1B2L
#define SEQUENCE_HEADER_CODE 0x1B3L
#define SEQUENCE_ERROR_CODE 0x1B4L
#define EXTENSION_START_CODE 0x1B5L
#define SEQUENCE_END_CODE 0x1B7L
#define GROUP_START_CODE 0x1B8L
/* extension start code IDs */
#define SEQUENCE_EXTENSION_ID 1
#define SEQUENCE_DISPLAY_EXTENSION_ID 2
#define QUANT_MATRIX_EXTENSION_ID 3
#define COPYRIGHT_EXTENSION_ID 4
#define SEQUENCE_SCALABLE_EXTENSION_ID 5
#define PICTURE_DISPLAY_EXTENSION_ID 7
#define PICTURE_CODING_EXTENSION_ID 8
#define PICTURE_SPATIAL_SCALABLE_EXTENSION_ID 9
#define PICTURE_TEMPORAL_SCALABLE_EXTENSION_ID 10
/* scalable modes */
#define SC_NONE 0
#define SC_DP 1
#define SC_SPAT 2
#define SC_SNR 3
#define SC_TEMP 4
/* Chroma types */
#define CHROMA_420 1
#define CHROMA_422 2
#define CHROMA_444 3
/* 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 */
/*****************************************************************************
* Prototypes
*****************************************************************************/
int vpar_NextSequenceHeader( struct vpar_thread_s * p_vpar );
int vpar_ParseHeader( struct vpar_thread_s * p_vpar );
/*****************************************************************************
* vpar_pool.c : management of the pool of decoder threads
*****************************************************************************
* Copyright (C) 1999, 2000, 2001 VideoLAN
* $Id: vpar_pool.c,v 1.1 2001/07/18 14:21:00 massiot Exp $
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
*****************************************************************************/
/*****************************************************************************
* Preamble
*****************************************************************************/
#include "defs.h"
#include <string.h> /* memcpy(), memset() */
#include <stdlib.h> /* realloc() */
#include "config.h"
#include "common.h"
#include "threads.h"
#include "mtime.h"
#include "intf_msg.h"
#include "stream_control.h"
#include "input_ext-dec.h"
#include "video.h"
#include "video_output.h"
#include "vdec_ext-plugins.h"
#include "vpar_pool.h"
#include "video_parser.h"
#include "video_decoder.h"
/*
* Local prototypes
*/
static void WaitDummy( vdec_pool_t * p_pool );
static void WaitPool( vdec_pool_t * p_pool );
static void FreeMacroblockDummy( vdec_pool_t * p_pool, macroblock_t * p_mb );
static void FreeMacroblockPool( vdec_pool_t * p_pool, macroblock_t * p_mb );
static macroblock_t * NewMacroblockDummy( vdec_pool_t * p_pool );
static macroblock_t * NewMacroblockPool( vdec_pool_t * p_pool );
static void DecodeMacroblockDummy( vdec_pool_t * p_pool, macroblock_t * p_mb );
static void DecodeMacroblockPool( vdec_pool_t * p_pool, macroblock_t * p_mb );
/*****************************************************************************
* vpar_InitPool: Initializes the pool structure
*****************************************************************************/
void vpar_InitPool( vpar_thread_t * p_vpar )
{
/* Initialize mutex and cond. */
vlc_mutex_init( &p_vpar->pool.lock );
vlc_cond_init( &p_vpar->pool.wait_empty );
vlc_cond_init( &p_vpar->pool.wait_undecoded );
/* Spawn optional video decoder threads. */
p_vpar->pool.i_smp = 0;
p_vpar->pool.pp_vdec = NULL;
p_vpar->pool.p_macroblocks = NULL;
p_vpar->pool.pp_empty_macroblocks = NULL;
p_vpar->pool.pp_new_macroblocks = NULL;
vpar_SpawnPool( p_vpar );
/* Initialize fake video decoder structure (used when
* decoder == parser). */
if ( (p_vpar->pool.p_vdec =
(vdec_thread_t *)malloc( sizeof(vdec_thread_t) )) == NULL )
{
intf_ErrMsg("vdec error: not enough memory for vdec_CreateThread() to create the new thread");
p_vpar->p_fifo->b_error = 1;
return;
}
p_vpar->pool.p_vdec->b_die = 0;
p_vpar->pool.p_vdec->p_pool = &p_vpar->pool;
vdec_InitThread( p_vpar->pool.p_vdec );
}
/*****************************************************************************
* vpar_SpawnPool: Create and cancel video decoder threads at any time
*****************************************************************************
* This function is called on startup, and everytime the user changes the
* number of threads to launch. Please note that *all* decoder threads must
* be idle during this operation, which only happens at the end of
* PictureHeader().
*****************************************************************************/
void vpar_SpawnPool( vpar_thread_t * p_vpar )
{
int i_new_smp;
boolean_t b_grayscale;
stream_ctrl_t * p_control;
p_control = p_vpar->p_config->decoder_config.p_stream_ctrl;
vlc_mutex_lock( &p_control->control_lock );
i_new_smp = p_control->i_smp;
b_grayscale = p_control->b_grayscale;
vlc_mutex_unlock( &p_control->control_lock );
/* FIXME: No error check because I'm tired. Come back later... */
/* No need to lock p_vpar->pool, since decoders MUST be idle here. */
if( p_vpar->pool.i_smp != i_new_smp )
{
int i;
if( p_vpar->pool.i_smp > i_new_smp )
{
/* The user reduces the number of threads. */
for( i = p_vpar->pool.i_smp - 1; i >= i_new_smp; i-- )
{
vdec_DestroyThread( p_vpar->pool.pp_vdec[i] );
}
p_vpar->pool.pp_vdec = realloc( p_vpar->pool.pp_vdec,
i_new_smp * sizeof(vdec_thread_t *) );
p_vpar->pool.p_macroblocks = realloc( p_vpar->pool.p_macroblocks,
i_new_smp * sizeof(macroblock_t) );
p_vpar->pool.pp_empty_macroblocks = realloc( p_vpar->pool.pp_empty_macroblocks,
i_new_smp * sizeof(macroblock_t *) );
p_vpar->pool.i_index_empty = i_new_smp;
p_vpar->pool.pp_new_macroblocks = realloc( p_vpar->pool.pp_new_macroblocks,
i_new_smp * sizeof(macroblock_t *) );
p_vpar->pool.i_index_new = 0;
}
else
{
/* The user raises the number of threads. */
p_vpar->pool.pp_vdec = realloc( p_vpar->pool.pp_vdec,
i_new_smp * sizeof(vdec_thread_t *) );
p_vpar->pool.p_macroblocks = realloc( p_vpar->pool.p_macroblocks,
i_new_smp * sizeof(macroblock_t) );
p_vpar->pool.pp_empty_macroblocks = realloc( p_vpar->pool.pp_empty_macroblocks,
i_new_smp * sizeof(macroblock_t *) );
p_vpar->pool.i_index_empty = i_new_smp;
p_vpar->pool.pp_new_macroblocks = realloc( p_vpar->pool.pp_new_macroblocks,
i_new_smp * sizeof(macroblock_t *) );
p_vpar->pool.i_index_new = 0;
for( i = p_vpar->pool.i_smp; i < i_new_smp ; i++ )
{
p_vpar->pool.pp_vdec[i] = vdec_CreateThread( &p_vpar->pool );
}
}
for( i = 0; i < i_new_smp; i++ )
{
p_vpar->pool.pp_empty_macroblocks[i] =
&p_vpar->pool.p_macroblocks[i];
}
p_vpar->pool.i_smp = i_new_smp;
}
if( i_new_smp )
{
/* We have at least one decoder thread. */
p_vpar->pool.pf_wait_pool = WaitPool;
p_vpar->pool.pf_new_mb = NewMacroblockPool;
p_vpar->pool.pf_free_mb = FreeMacroblockPool;
p_vpar->pool.pf_decode_mb = DecodeMacroblockPool;
}
else
{
/* No decoder pool. */
p_vpar->pool.pf_wait_pool = WaitDummy;
p_vpar->pool.pf_new_mb = NewMacroblockDummy;
p_vpar->pool.pf_free_mb = FreeMacroblockDummy;
p_vpar->pool.pf_decode_mb = DecodeMacroblockDummy;
}
if( !b_grayscale )
{
p_vpar->pool.pf_vdec_decode = p_vpar->pf_decode_mb_c;
}
else
{
p_vpar->pool.pf_vdec_decode = p_vpar->pf_decode_mb_bw;
}
}
/*****************************************************************************
* vpar_EndPool: Releases the pool structure
*****************************************************************************/
void vpar_EndPool( vpar_thread_t * p_vpar )
{
int i;
for( i = 0; i < p_vpar->pool.i_smp; i++ )
{
vdec_DestroyThread( p_vpar->pool.pp_vdec[i] );
}
if( p_vpar->pool.i_smp )
{
free( p_vpar->pool.pp_vdec );
free( p_vpar->pool.p_macroblocks );
free( p_vpar->pool.pp_new_macroblocks );
}
/* Free fake video decoder (used when parser == decoder). */
vdec_EndThread( p_vpar->pool.p_vdec );
/* Destroy lock and cond. */
vlc_mutex_destroy( &p_vpar->pool.lock );
vlc_cond_destroy( &p_vpar->pool.wait_empty );
vlc_cond_destroy( &p_vpar->pool.wait_undecoded );
}
/*****************************************************************************
* WaitPool: Wait until all decoders are idle
*****************************************************************************/
static void WaitPool( vdec_pool_t * p_pool )
{
vlc_mutex_lock( &p_pool->lock );
while( p_pool->i_index_empty != p_pool->i_smp )
{
vlc_cond_wait( &p_pool->wait_empty, &p_pool->lock );
}
vlc_mutex_unlock( &p_pool->lock );
}
/*****************************************************************************
* WaitDummy: Placeholder used when parser == decoder
*****************************************************************************/
static void WaitDummy( vdec_pool_t * p_pool )
{
}
/*****************************************************************************
* NewMacroblockPool: Get an empty macroblock from the decoder pool
*****************************************************************************/
static macroblock_t * NewMacroblockPool( vdec_pool_t * p_pool )
{
macroblock_t * p_mb;
vlc_mutex_lock( &p_pool->lock );
while( p_pool->i_index_empty == 0 )
{
vlc_cond_wait( &p_pool->wait_empty, &p_pool->lock );
}
p_mb = p_pool->pp_empty_macroblocks[ --p_pool->i_index_empty ];
vlc_mutex_unlock( &p_pool->lock );
return( p_mb );
}
/*****************************************************************************
* NewMacroblockDummy: Placeholder used when parser == decoder
*****************************************************************************/
static macroblock_t * NewMacroblockDummy( vdec_pool_t * p_pool )
{
return( &p_pool->mb );
}
/*****************************************************************************
* FreeMacroblockPool: Free a macroblock
*****************************************************************************/
static void FreeMacroblockPool( vdec_pool_t * p_pool, macroblock_t * p_mb )
{
vlc_mutex_lock( &p_pool->lock );
p_pool->pp_empty_macroblocks[ p_pool->i_index_empty++ ] = p_mb;
vlc_cond_signal( &p_pool->wait_empty );
vlc_mutex_unlock( &p_pool->lock );
}
/*****************************************************************************
* FreeMacroblockDummy: Placeholder used when parser == decoder
*****************************************************************************/
static void FreeMacroblockDummy( vdec_pool_t * p_pool, macroblock_t * p_mb )
{
}
/*****************************************************************************
* DecodeMacroblockPool: Send a macroblock to a vdec thread
*****************************************************************************/
static void DecodeMacroblockPool( vdec_pool_t * p_pool, macroblock_t * p_mb )
{
vlc_mutex_lock( &p_pool->lock );
/* The undecoded macroblock LIFO cannot be full, because
* #macroblocks == size of the LIFO */
p_pool->pp_new_macroblocks[ p_pool->i_index_new++ ] = p_mb;
vlc_cond_signal( &p_pool->wait_undecoded );
vlc_mutex_unlock( &p_pool->lock );
}
/*****************************************************************************
* DecodeMacroblockDummy: Placeholder used when parser == decoder
*****************************************************************************/
static void DecodeMacroblockDummy( vdec_pool_t * p_pool, macroblock_t * p_mb )
{
p_pool->pf_vdec_decode( p_pool->p_vdec, p_mb );
}
/*****************************************************************************
* vpar_blocks.h : video parser blocks management
* vpar_pool.h : video parser/video decoders communication
*****************************************************************************
* Copyright (C) 1999, 2000 VideoLAN
* $Id: vpar_blocks.h,v 1.4 2001/07/17 09:48:08 massiot Exp $
* $Id: vpar_pool.h,v 1.1 2001/07/18 14:21:00 massiot Exp $
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
* Jean-Marc Dressler <polux@via.ecp.fr>
* Stphane Borel <stef@via.ecp.fr>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
......@@ -24,115 +22,90 @@
*****************************************************************************/
/*****************************************************************************
* Requires:
* "config.h"
* "common.h"
* "mtime.h"
* "threads.h"
* "input.h"
* "video.h"
* "video_output.h"
* "decoder_fifo.h"
* "video_fifo.h"
*****************************************************************************/
/*****************************************************************************
* macroblock_parsing_t : macroblock context & predictors
* vdec_pool_t
*****************************************************************************
* This structure is used for the communication between the parser and the
* decoders.
*****************************************************************************/
typedef struct
typedef struct vdec_pool_s
{
unsigned char i_quantizer_scale; /* scale of the quantization
* matrices */
int pi_dc_dct_pred[3]; /* ISO/IEC 13818-2 7.2.1 */
int pppi_pmv[2][2][2]; /* Motion vect predictors, 7.6.3 */
int i_motion_dir;/* Used for the next skipped macroblock */
/* Context used to optimize block parsing */
int i_motion_type, i_mv_count, i_mv_format;
boolean_t b_dmv, b_dct_type;
/* Coordinates of the upper-left pixel of the macroblock, in lum and
* chroma */
int i_l_x, i_l_y, i_c_x, i_c_y;
} macroblock_parsing_t;
/* Locks */
vlc_mutex_t lock; /* Structure data lock */
vlc_cond_t wait_empty; /* The parser blocks there when all
* decoder threads are busy */
vlc_cond_t wait_undecoded; /* The decoders block there when no
* macroblock has been given by the
* parser */
/* Video decoder threads */
struct vdec_thread_s ** pp_vdec; /* Array of video decoder threads */
int i_smp; /* Number of symmetrical decoder threads,
* hence size of the pp_vdec, p_macroblocks
* and pp_new_macroblocks array */
/* Macroblocks */
macroblock_t * p_macroblocks;
/* Empty macroblocks */
macroblock_t ** pp_empty_macroblocks; /* Empty macroblocks */
int i_index_empty; /* Last empty macroblock */
/* Undecoded macroblocks, read by the decoders */
macroblock_t ** pp_new_macroblocks; /* Undecoded macroblocks */
int i_index_new; /* Last undecoded macroblock */
/* Undecoded macroblock, used when the parser and the decoder share the
* same thread */
macroblock_t mb;
struct vdec_thread_s * p_vdec; /* Fake video decoder */
/* Pointers to usual pool functions */
void (* pf_wait_pool) ( struct vdec_pool_s * );
macroblock_t * (* pf_new_mb) ( struct vdec_pool_s * );
void (* pf_free_mb) ( struct vdec_pool_s *,
struct macroblock_s * );
void (* pf_decode_mb) ( struct vdec_pool_s *,
struct macroblock_s * );
/* Pointer to the decoding function - used for B&W switching */
void (* pf_vdec_decode) ( struct vdec_thread_s *,
struct macroblock_s * );
boolean_t b_bw; /* Current value for B&W */
/* Access to the plug-ins needed by the video decoder thread */
void ( * pf_decode_init ) ( struct vdec_thread_s * );
void ( * pf_idct_init ) ( struct vdec_thread_s * );
} vdec_pool_t;
/*****************************************************************************
* lookup_t : entry type for lookup tables *
* Prototypes
*****************************************************************************/
typedef struct lookup_s
{
int i_value;
int i_length;
} lookup_t;
void vpar_InitPool( struct vpar_thread_s * );
void vpar_SpawnPool( struct vpar_thread_s * );
void vpar_EndPool( struct vpar_thread_s * );
/*****************************************************************************
* ac_lookup_t : special entry type for lookup tables about ac coefficients
* vpar_GetMacroblock: In a vdec thread, get the next available macroblock
*****************************************************************************/
typedef struct dct_lookup_s
static __inline__ macroblock_t * vpar_GetMacroblock( vdec_pool_t * p_pool,
boolean_t * pb_die )
{
char i_run;
char i_level;
char i_length;
} dct_lookup_t;
/*****************************************************************************
* Standard codes
*****************************************************************************/
/* Macroblock Address Increment types */
#define MB_ADDRINC_ESCAPE 8
#define MB_ADDRINC_STUFFING 15
/* Error constant for lookup tables */
#define MB_ERROR (-1)
/* Scan */
#define SCAN_ZIGZAG 0
#define SCAN_ALT 1
/* Constant for block decoding */
#define DCT_EOB 64
#define DCT_ESCAPE 65
/*****************************************************************************
* Constants
*****************************************************************************/
extern u8 pi_default_intra_quant[64];
extern u8 pi_default_nonintra_quant[64];
extern u8 pi_scan[2][64];
/*****************************************************************************
* Prototypes
*****************************************************************************/
void vpar_InitCrop( struct vpar_thread_s* p_vpar );
void vpar_InitMbAddrInc( struct vpar_thread_s * p_vpar );
void vpar_InitPMBType( struct vpar_thread_s * p_vpar );
void vpar_InitBMBType( struct vpar_thread_s * p_vpar );
void vpar_InitCodedPattern( struct vpar_thread_s * p_vpar );
void vpar_InitDCTTables( struct vpar_thread_s * p_vpar );
void vpar_InitScanTable( struct vpar_thread_s * p_vpar );
typedef void (*f_picture_data_t)( struct vpar_thread_s * p_vpar,
int i_mb_base );
#define PROTO_PICD( FUNCNAME ) \
void FUNCNAME( struct vpar_thread_s * p_vpar, int i_mb_base );
PROTO_PICD( vpar_PictureDataGENERIC )
#if (VPAR_OPTIM_LEVEL > 0)
PROTO_PICD( vpar_PictureData1I )
PROTO_PICD( vpar_PictureData1P )
PROTO_PICD( vpar_PictureData1B )
PROTO_PICD( vpar_PictureData1D )
PROTO_PICD( vpar_PictureData2IF )
PROTO_PICD( vpar_PictureData2PF )
PROTO_PICD( vpar_PictureData2BF )
#endif
#if (VPAR_OPTIM_LEVEL > 1)
PROTO_PICD( vpar_PictureData2IT )
PROTO_PICD( vpar_PictureData2PT )
PROTO_PICD( vpar_PictureData2BT )
PROTO_PICD( vpar_PictureData2IB )
PROTO_PICD( vpar_PictureData2PB )
PROTO_PICD( vpar_PictureData2BB )
#endif
macroblock_t * p_mb;
vlc_mutex_lock( &p_pool->lock );
while( p_pool->i_index_new == 0 && !*pb_die )
{
vlc_cond_wait( &p_pool->wait_undecoded, &p_pool->lock );
}
if( *pb_die )
{
vlc_mutex_unlock( &p_pool->lock );
return( NULL );
}
p_mb = p_pool->pp_new_macroblocks[ --p_pool->i_index_new ];
vlc_mutex_unlock( &p_pool->lock );
return( p_mb );
}
......@@ -2,7 +2,7 @@
* vpar_synchro.c : frame dropping routines
*****************************************************************************
* Copyright (C) 1999, 2000 VideoLAN
* $Id: vpar_synchro.c,v 1.2 2001/07/17 09:48:08 massiot Exp $
* $Id: vpar_synchro.c,v 1.3 2001/07/18 14:21:00 massiot Exp $
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
* Samuel Hocevar <sam@via.ecp.fr>
......@@ -112,11 +112,7 @@
#include "video_output.h"
#include "vdec_ext-plugins.h"
#include "video_decoder.h"
#include "vpar_blocks.h"
#include "vpar_headers.h"
#include "vpar_synchro.h"
#include "vpar_pool.h"
#include "video_parser.h"
#include "main.h"
......@@ -138,8 +134,6 @@ static int SynchroType( void );
void vpar_SynchroInit( vpar_thread_t * p_vpar )
{
p_vpar->synchro.i_type = SynchroType();
p_vpar->synchro.i_start = p_vpar->synchro.i_end = 0;
vlc_mutex_init( &p_vpar->synchro.fifo_lock );
/* We use a fake stream pattern, which is often right. */
p_vpar->synchro.i_n_p = p_vpar->synchro.i_eta_p = DEFAULT_NB_P;
......@@ -234,9 +228,6 @@ boolean_t vpar_SynchroChoose( vpar_thread_t * p_vpar, int i_coding_type,
vlc_mutex_lock( &p_vpar->p_vout->change_lock );
tau_yuv = p_vpar->p_vout->render_time;
vlc_mutex_unlock( &p_vpar->p_vout->change_lock );
#ifdef VDEC_SMP
vlc_mutex_lock( &p_vpar->synchro.fifo_lock );
#endif
switch( i_coding_type )
{
......@@ -317,9 +308,6 @@ boolean_t vpar_SynchroChoose( vpar_thread_t * p_vpar, int i_coding_type,
}
}
#ifdef VDEC_SMP
vlc_mutex_unlock( &p_vpar->synchro.fifo_lock );
#endif
#ifdef TRACE_VPAR
intf_DbgMsg("vpar synchro debug: %s picture scheduled for %s, %s (%lld)",
i_coding_type == B_CODING_TYPE ? "B" :
......@@ -356,46 +344,20 @@ void vpar_SynchroTrash( vpar_thread_t * p_vpar, int i_coding_type,
void vpar_SynchroDecode( vpar_thread_t * p_vpar, int i_coding_type,
int i_structure )
{
#ifdef VDEC_SMP
vlc_mutex_lock( &p_vpar->synchro.fifo_lock );
#endif
if( ((p_vpar->synchro.i_end + 1 - p_vpar->synchro.i_start)
% MAX_DECODING_PIC) )
{
p_vpar->synchro.p_date_fifo[p_vpar->synchro.i_end] = mdate();
p_vpar->synchro.pi_coding_types[p_vpar->synchro.i_end] = i_coding_type;
FIFO_INCREMENT( i_end );
}
else
{
/* FIFO full, panic() */
intf_ErrMsg("vpar error: synchro fifo full, estimations will be biased (%d:%d)",
p_vpar->synchro.i_start, p_vpar->synchro.i_end);
}
#ifdef VDEC_SMP
vlc_mutex_unlock( &p_vpar->synchro.fifo_lock );
#endif
p_vpar->synchro.decoding_start = mdate();
}
/*****************************************************************************
* vpar_SynchroEnd : Called when the image is totally decoded
*****************************************************************************/
void vpar_SynchroEnd( vpar_thread_t * p_vpar, int i_garbage )
void vpar_SynchroEnd( vpar_thread_t * p_vpar, int i_coding_type,
int i_structure, int i_garbage )
{
mtime_t tau;
int i_coding_type;
#ifdef VDEC_SMP
vlc_mutex_lock( &p_vpar->synchro.fifo_lock );
#endif
i_coding_type = p_vpar->synchro.pi_coding_types[p_vpar->synchro.i_start];
if( !i_garbage )
{
tau = mdate() - p_vpar->synchro.p_date_fifo[p_vpar->synchro.i_start];
tau = mdate() - p_vpar->synchro.decoding_start;
/* If duration too high, something happened (pause ?), so don't
* take it into account. */
......@@ -425,12 +387,6 @@ void vpar_SynchroEnd( vpar_thread_t * p_vpar, int i_garbage )
i_coding_type == B_CODING_TYPE ? "B" :
(i_coding_type == P_CODING_TYPE ? "P" : "I"));
}
FIFO_INCREMENT( i_start );
#ifdef VDEC_SMP
vlc_mutex_unlock( &p_vpar->synchro.fifo_lock );
#endif
}
/*****************************************************************************
......
/*****************************************************************************
* vpar_synchro.h : video parser blocks management
*****************************************************************************
* Copyright (C) 1999, 2000 VideoLAN
* $Id: vpar_synchro.h,v 1.10 2001/07/17 09:48:08 massiot Exp $
*
* Author: Christophe Massiot <massiot@via.ecp.fr>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
*****************************************************************************/
/*****************************************************************************
* Requires:
* "config.h"
* "common.h"
* "mtime.h"
* "threads.h"
* "input.h"
* "video.h"
* "video_output.h"
* "decoder_fifo.h"
* "video_fifo.h"
*****************************************************************************/
/*****************************************************************************
* video_synchro_t and video_synchro_tab_s : timers for the video synchro
*****************************************************************************/
#define MAX_DECODING_PIC 16
#define MAX_PIC_AVERAGE 8
/* Read the discussion on top of vpar_synchro.c for more information. */
typedef struct video_synchro_s
{
/* synchro algorithm */
int i_type;
/* fifo containing decoding dates */
mtime_t p_date_fifo[MAX_DECODING_PIC];
int pi_coding_types[MAX_DECODING_PIC];
unsigned int i_start, i_end;
vlc_mutex_t fifo_lock;
/* stream properties */
unsigned int i_n_p, i_n_b;
/* decoding values */
mtime_t p_tau[4]; /* average decoding durations */
unsigned int pi_meaningful[4]; /* number of durations read */
/* and p_vout->render_time (read with p_vout->change_lock) */
/* stream context */
unsigned int i_eta_p, i_eta_b;
boolean_t b_dropped_last; /* for special synchros below */
mtime_t backward_pts, current_pts;
int i_current_period; /* period to add to the next picture */
int i_backward_period; /* period to add after the next
* reference picture
* (backward_period * period / 2) */
#ifdef STATS
unsigned int i_trashed_pic, i_not_chosen_pic, i_pic;
#endif
} video_synchro_t;
#define FIFO_INCREMENT( i_counter ) \
p_vpar->synchro.i_counter = \
(p_vpar->synchro.i_counter + 1) % MAX_DECODING_PIC;
/* Synchro algorithms */
#define VPAR_SYNCHRO_DEFAULT 0
#define VPAR_SYNCHRO_I 1
#define VPAR_SYNCHRO_Iplus 2
#define VPAR_SYNCHRO_IP 3
#define VPAR_SYNCHRO_IPplus 4
#define VPAR_SYNCHRO_IPB 5
/*****************************************************************************
* Prototypes
*****************************************************************************/
void vpar_SynchroInit ( struct vpar_thread_s * p_vpar );
boolean_t vpar_SynchroChoose ( struct vpar_thread_s * p_vpar,
int i_coding_type, int i_structure );
void vpar_SynchroTrash ( struct vpar_thread_s * p_vpar,
int i_coding_type, int i_structure );
void vpar_SynchroDecode ( struct vpar_thread_s * p_vpar,
int i_coding_type, int i_structure );
void vpar_SynchroEnd ( struct vpar_thread_s * p_vpar, int i_garbage );
mtime_t vpar_SynchroDate ( struct vpar_thread_s * p_vpar );
void vpar_SynchroNewPicture( struct vpar_thread_s * p_vpar, int i_coding_type,
int i_repeat_field );
......@@ -5,7 +5,7 @@
* thread, and destroy a previously oppened video output thread.
*****************************************************************************
* Copyright (C) 2000 VideoLAN
* $Id: video_output.c,v 1.134 2001/07/11 02:01:05 sam Exp $
* $Id: video_output.c,v 1.135 2001/07/18 14:21:00 massiot Exp $
*
* Authors: Vincent Seguin <seguin@via.ecp.fr>
*
......@@ -685,9 +685,6 @@ picture_t *vout_CreatePicture( vout_thread_t *p_vout, int i_type,
#endif
vlc_mutex_unlock( &p_vout->picture_lock );
/* Initialize mutex */
vlc_mutex_init( &(p_free_picture->lock_deccount) );
return( p_free_picture );
}
......@@ -725,9 +722,6 @@ void vout_DestroyPicture( vout_thread_t *p_vout, picture_t *p_pic )
intf_DbgMsg("picture %p", p_pic);
#endif
/* destroy the lock that had been initialized in CreatePicture */
vlc_mutex_destroy( &(p_pic->lock_deccount) );
vlc_mutex_unlock( &p_vout->picture_lock );
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment