X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;ds=sidebyside;f=src%2Fvideo_parser%2Fvideo_parser.c;h=5b1dfe49640a9ea374d0d8c2aa55e4a65a6828dc;hb=b0ab70c9bfc80da45733bc4fecbb0ccbedf30fc0;hp=6b7293d01b2e504bc357baf3cb0ff431268a50ec;hpb=dc804fe5e107ee240b89daa3b5c85da8ca029380;p=vlc diff --git a/src/video_parser/video_parser.c b/src/video_parser/video_parser.c index 6b7293d01b..5b1dfe4964 100644 --- a/src/video_parser/video_parser.c +++ b/src/video_parser/video_parser.c @@ -2,6 +2,7 @@ * video_parser.c : video parser thread ***************************************************************************** * Copyright (C) 1999, 2000 VideoLAN + * $Id: video_parser.c,v 1.75 2001/02/18 03:32:02 polux Exp $ * * Authors: Christophe Massiot * Samuel Hocevar @@ -21,8 +22,6 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. *****************************************************************************/ -/* FIXME: passer en terminate/destroy avec les signaux supplémentaires ?? */ - /***************************************************************************** * Preamble *****************************************************************************/ @@ -30,19 +29,20 @@ #include /* malloc(), free() */ #include /* getpid() */ -#include /* on BSD, uio.h needs types.h */ -#include /* "input.h" */ #include #include +#ifdef STATS +# include +#endif + #include "config.h" #include "common.h" #include "threads.h" #include "mtime.h" -#include "plugins.h" +#include "modules.h" #include "intf_msg.h" -#include "debug.h" /* XXX?? temporaire, requis par netlist.h */ #include "stream_control.h" #include "input_ext-dec.h" @@ -50,15 +50,17 @@ #include "video.h" #include "video_output.h" -#include "vdec_idct.h" #include "video_decoder.h" #include "vdec_motion.h" +#include "../video_decoder/vdec_idct.h" #include "vpar_blocks.h" -#include "vpar_headers.h" -#include "vpar_synchro.h" -#include "video_parser.h" -#include "video_fifo.h" +#include "../video_decoder/vpar_headers.h" +#include "../video_decoder/vpar_synchro.h" +#include "../video_decoder/video_parser.h" +#include "../video_decoder/video_fifo.h" + +#include "main.h" /* * Local prototypes @@ -67,49 +69,136 @@ static int InitThread ( vpar_thread_t *p_vpar ); static void RunThread ( vpar_thread_t *p_vpar ); static void ErrorThread ( vpar_thread_t *p_vpar ); static void EndThread ( vpar_thread_t *p_vpar ); +static void BitstreamCallback ( bit_stream_t *p_bit_stream, + boolean_t b_new_pes ); /***************************************************************************** * vpar_CreateThread: create a generic parser thread ***************************************************************************** * This function creates a new video parser thread, and returns a pointer * to its description. On error, it returns NULL. - * Following configuration properties are used: - * XXX?? *****************************************************************************/ vlc_thread_t vpar_CreateThread( vdec_config_t * p_config ) { vpar_thread_t * p_vpar; - intf_DbgMsg( "vpar debug: creating video parser thread\n" ); + intf_DbgMsg( "vpar debug: creating video parser thread" ); /* Allocate the memory needed to store the thread's structure */ if ( (p_vpar = (vpar_thread_t *)malloc( sizeof(vpar_thread_t) )) == NULL ) { intf_ErrMsg( "vpar error: not enough memory " - "for vpar_CreateThread() to create the new thread\n"); + "for vpar_CreateThread() to create the new thread"); return( 0 ); } /* * Initialize the thread properties */ - p_vpar->b_die = 0; - p_vpar->b_error = 0; p_vpar->p_fifo = p_config->decoder_config.p_decoder_fifo; p_vpar->p_config = p_config; p_vpar->p_vout = p_config->p_vout; + /* + * Choose the best motion compensation module + */ + p_vpar->p_motion_module = module_Need( p_main->p_bank, + MODULE_CAPABILITY_MOTION, NULL ); + + if( p_vpar->p_motion_module == NULL ) + { + intf_ErrMsg( "vpar error: no suitable motion compensation module" ); + free( p_vpar ); + return( 0 ); + } + +#define m ( p_vpar->pppf_motion ) +#define s ( p_vpar->ppf_motion_skipped ) +#define f ( p_vpar->p_motion_module->p_functions->motion.functions.motion ) + m[0][0][0] = m[0][0][1] = m[0][0][2] = m[0][0][3] = NULL; + m[0][1][0] = m[0][1][1] = m[0][1][2] = m[0][1][3] = NULL; + m[1][0][0] = NULL; + m[1][1][0] = NULL; + m[2][0][0] = NULL; + m[2][1][0] = NULL; + m[3][0][0] = NULL; + m[3][1][0] = NULL; + + m[1][0][1] = f.pf_field_field_420; + m[1][1][1] = f.pf_frame_field_420; + m[2][0][1] = f.pf_field_field_422; + m[2][1][1] = f.pf_frame_field_422; + m[3][0][1] = f.pf_field_field_444; + m[3][1][1] = f.pf_frame_field_444; + + m[1][0][2] = f.pf_field_16x8_420; + m[1][1][2] = f.pf_frame_frame_420; + m[2][0][2] = f.pf_field_16x8_422; + m[2][1][2] = f.pf_frame_frame_422; + m[3][0][2] = f.pf_field_16x8_444; + m[3][1][2] = f.pf_frame_frame_444; + + m[1][0][3] = f.pf_field_dmv_420; + m[1][1][3] = f.pf_frame_dmv_420; + m[2][0][3] = f.pf_field_dmv_422; + m[2][1][3] = f.pf_frame_dmv_422; + m[3][0][3] = f.pf_field_dmv_444; + m[3][1][3] = f.pf_frame_dmv_444; + + s[0][0] = s[0][1] = s[0][2] = s[0][3] = NULL; + s[1][0] = NULL; + s[2][0] = NULL; + s[3][0] = NULL; + + s[1][1] = f.pf_field_field_420; + s[2][1] = f.pf_field_field_422; + s[3][1] = f.pf_field_field_444; + + s[1][2] = f.pf_field_field_420; + s[2][2] = f.pf_field_field_422; + s[3][2] = f.pf_field_field_444; + + s[1][3] = f.pf_frame_frame_420; + s[2][3] = f.pf_frame_frame_422; + s[3][3] = f.pf_frame_frame_444; +#undef f +#undef s +#undef m + + /* + * Choose the best IDCT module + */ + p_vpar->p_idct_module = module_Need( p_main->p_bank, + MODULE_CAPABILITY_IDCT, NULL ); + + if( p_vpar->p_idct_module == NULL ) + { + intf_ErrMsg( "vpar error: no suitable IDCT module" ); + module_Unneed( p_main->p_bank, p_vpar->p_motion_module ); + free( p_vpar ); + return( 0 ); + } + +#define f p_vpar->p_idct_module->p_functions->idct.functions.idct + p_vpar->pf_init = f.pf_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; +#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\n"); + intf_ErrMsg("vpar error: can't spawn video parser thread"); + module_Unneed( p_main->p_bank, p_vpar->p_idct_module ); + module_Unneed( p_main->p_bank, p_vpar->p_motion_module ); free( p_vpar ); return( 0 ); } - intf_DbgMsg("vpar debug: video parser thread (%p) created\n", p_vpar); + intf_DbgMsg("vpar debug: video parser thread (%p) created", p_vpar); return( p_vpar->thread_id ); } @@ -128,10 +217,19 @@ static int InitThread( vpar_thread_t *p_vpar ) int i_dummy; #endif - intf_DbgMsg("vpar debug: initializing video parser thread %p\n", p_vpar); + intf_DbgMsg("vpar debug: initializing video parser thread %p", p_vpar); p_vpar->p_config->decoder_config.pf_init_bit_stream( &p_vpar->bit_stream, p_vpar->p_config->decoder_config.p_decoder_fifo ); + p_vpar->bit_stream.pf_bitstream_callback = BitstreamCallback; + p_vpar->bit_stream.p_callback_arg = (void *)p_vpar; + + /* InitBitstream has normally begun to read a PES packet, get its + * PTS/DTS */ + if( !p_vpar->p_fifo->b_die ) + { + BitstreamCallback( &p_vpar->bit_stream, 1 ); + } /* Initialize parsing data */ p_vpar->sequence.p_forward = NULL; @@ -140,6 +238,9 @@ static int InitThread( vpar_thread_t *p_vpar ) p_vpar->sequence.nonintra_quant.b_allocated = 0; p_vpar->sequence.chroma_intra_quant.b_allocated = 0; p_vpar->sequence.chroma_nonintra_quant.b_allocated = 0; + p_vpar->sequence.i_matrix_coefficients = 1; + p_vpar->sequence.next_pts = p_vpar->sequence.next_dts = 0; + p_vpar->sequence.b_expect_discontinuity = 0; /* Initialize copyright information */ p_vpar->sequence.b_copyright_flag = 0; @@ -186,12 +287,16 @@ static int InitThread( vpar_thread_t *p_vpar ) p_vpar->pp_vdec[0]->b_error = 0; p_vpar->pp_vdec[0]->p_vpar = p_vpar; +# ifndef SYS_BEOS +# if VDEC_NICE /* Re-nice ourself */ if( nice(VDEC_NICE) == -1 ) { - intf_WarnMsg( 2, "vpar warning : couldn't nice() (%s)\n", + intf_WarnMsg( 2, "vpar warning : couldn't nice() (%s)", strerror(errno) ); } +# endif +# endif #endif /* Initialize lookup tables */ @@ -203,6 +308,7 @@ static int InitThread( vpar_thread_t *p_vpar ) vpar_InitPMBType( p_vpar ); vpar_InitBMBType( p_vpar ); vpar_InitDCTTables( p_vpar ); + vpar_InitScanTable( p_vpar ); /* * Initialize the synchro properties @@ -210,7 +316,7 @@ static int InitThread( vpar_thread_t *p_vpar ) vpar_SynchroInit( p_vpar ); /* Mark thread as running and return */ - intf_DbgMsg("vpar debug: InitThread(%p) succeeded\n", p_vpar); + intf_DbgMsg("vpar debug: InitThread(%p) succeeded", p_vpar); return( 0 ); } @@ -222,25 +328,23 @@ static int InitThread( vpar_thread_t *p_vpar ) *****************************************************************************/ static void RunThread( vpar_thread_t *p_vpar ) { - intf_DbgMsg("vpar debug: running video parser thread (%p) (pid == %i)\n", p_vpar, getpid()); + intf_DbgMsg("vpar debug: running video parser thread (%p) (pid == %i)", p_vpar, getpid()); /* * Initialize thread */ - p_vpar->b_error = InitThread( p_vpar ); - - p_vpar->b_run = 1; + p_vpar->p_fifo->b_error = InitThread( p_vpar ); /* * Main loop - it is not executed if an error occured during * initialization */ - while( (!p_vpar->p_fifo->b_die) && (!p_vpar->b_error) ) + while( (!p_vpar->p_fifo->b_die) && (!p_vpar->p_fifo->b_error) ) { /* Find the next sequence header in the stream */ - p_vpar->b_error = vpar_NextSequenceHeader( p_vpar ); + p_vpar->p_fifo->b_error = vpar_NextSequenceHeader( p_vpar ); - while( (!p_vpar->p_fifo->b_die) && (!p_vpar->b_error) ) + while( (!p_vpar->p_fifo->b_die) && (!p_vpar->p_fifo->b_error) ) { #ifdef STATS p_vpar->c_loops++; @@ -257,13 +361,11 @@ static void RunThread( vpar_thread_t *p_vpar ) /* * Error loop */ - if( p_vpar->b_error ) + if( p_vpar->p_fifo->b_error ) { ErrorThread( p_vpar ); } - p_vpar->b_run = 0; - /* End of thread */ EndThread( p_vpar ); } @@ -312,31 +414,47 @@ static void EndThread( vpar_thread_t *p_vpar ) int i_dummy; #endif - intf_DbgMsg("vpar debug: destroying video parser thread %p\n", p_vpar); + intf_DbgMsg("vpar debug: destroying video parser thread %p", p_vpar); -#ifdef DEBUG - /* Check for remaining PES packets */ - /* XXX?? */ -#endif + /* Release used video buffers. */ + if( p_vpar->sequence.p_forward != NULL ) + { + vout_UnlinkPicture( p_vpar->p_vout, p_vpar->sequence.p_forward ); + } + if( p_vpar->sequence.p_backward != NULL ) + { + vout_DatePicture( p_vpar->p_vout, p_vpar->sequence.p_backward, + vpar_SynchroDate( p_vpar ) ); + vout_UnlinkPicture( p_vpar->p_vout, p_vpar->sequence.p_backward ); + } #ifdef STATS - intf_Msg("vpar stats: %d loops among %d sequence(s)\n", + intf_Msg("vpar stats: %d loops among %d sequence(s)", p_vpar->c_loops, p_vpar->c_sequences); - intf_Msg("vpar stats: Read %d frames/fields (I %d/P %d/B %d)\n", + + { + struct tms cpu_usage; + times( &cpu_usage ); + + intf_Msg("vpar stats: cpu usage (user: %d, system: %d)", + cpu_usage.tms_utime, cpu_usage.tms_stime); + } + + intf_Msg("vpar stats: Read %d frames/fields (I %d/P %d/B %d)", p_vpar->pc_pictures[I_CODING_TYPE] + p_vpar->pc_pictures[P_CODING_TYPE] + p_vpar->pc_pictures[B_CODING_TYPE], p_vpar->pc_pictures[I_CODING_TYPE], p_vpar->pc_pictures[P_CODING_TYPE], p_vpar->pc_pictures[B_CODING_TYPE]); - intf_Msg("vpar stats: Decoded %d frames/fields (I %d/P %d/B %d)\n", + intf_Msg("vpar stats: Decoded %d frames/fields (I %d/P %d/B %d)", p_vpar->pc_decoded_pictures[I_CODING_TYPE] + p_vpar->pc_decoded_pictures[P_CODING_TYPE] + p_vpar->pc_decoded_pictures[B_CODING_TYPE], p_vpar->pc_decoded_pictures[I_CODING_TYPE], p_vpar->pc_decoded_pictures[P_CODING_TYPE], p_vpar->pc_decoded_pictures[B_CODING_TYPE]); - intf_Msg("vpar stats: Read %d malformed frames/fields (I %d/P %d/B %d)\n", + intf_Msg("vpar stats: Read %d malformed frames/fields (I %d/P %d/B %d)", p_vpar->pc_malformed_pictures[I_CODING_TYPE] + p_vpar->pc_malformed_pictures[P_CODING_TYPE] + p_vpar->pc_malformed_pictures[B_CODING_TYPE], @@ -344,19 +462,15 @@ static void EndThread( vpar_thread_t *p_vpar ) p_vpar->pc_malformed_pictures[P_CODING_TYPE], p_vpar->pc_malformed_pictures[B_CODING_TYPE]); #define S p_vpar->sequence - intf_Msg("vpar info: %s stream (%dx%d), %d/1001 pi/s\n", + intf_Msg("vpar info: %s stream (%dx%d), %d.%d pi/s", S.b_mpeg2 ? "MPEG-2" : "MPEG-1", - S.i_width, S.i_height, S.i_frame_rate); - intf_Msg("vpar info: %s, %s, matrix_coeff: %d\n", + S.i_width, S.i_height, S.i_frame_rate/1001, S.i_frame_rate % 1001); + intf_Msg("vpar info: %s, %s, matrix_coeff: %d", S.b_progressive ? "Progressive" : "Non-progressive", S.i_scalable_mode ? "scalable" : "non-scalable", S.i_matrix_coefficients); #endif - /* Destroy thread structures allocated by InitThread */ -// vout_DestroyStream( p_vpar->p_vout, p_vpar->i_stream ); - /* XXX?? */ - /* Dispose of matrices if they have been allocated. */ if( p_vpar->sequence.intra_quant.b_allocated ) { @@ -388,7 +502,55 @@ static void EndThread( vpar_thread_t *p_vpar ) free( p_vpar->pp_vdec[0] ); #endif + 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_main->p_bank, p_vpar->p_idct_module ); + module_Unneed( p_main->p_bank, p_vpar->p_motion_module ); + free( p_vpar ); - intf_DbgMsg("vpar debug: EndThread(%p)\n", p_vpar); + intf_DbgMsg("vpar debug: EndThread(%p)", p_vpar); +} + +/***************************************************************************** + * BitstreamCallback: Import parameters from the new data/PES packet + ***************************************************************************** + * This function is called by input's NextDataPacket. + *****************************************************************************/ +static void BitstreamCallback ( bit_stream_t * p_bit_stream, + boolean_t b_new_pes ) +{ + vpar_thread_t * p_vpar = (vpar_thread_t *)p_bit_stream->p_callback_arg; + + if( b_new_pes ) + { + p_vpar->sequence.next_pts = + DECODER_FIFO_START( *p_bit_stream->p_decoder_fifo )->i_pts; + p_vpar->sequence.next_dts = + DECODER_FIFO_START( *p_bit_stream->p_decoder_fifo )->i_dts; + p_vpar->sequence.i_current_rate = + DECODER_FIFO_START( *p_bit_stream->p_decoder_fifo )->i_rate; + + if( DECODER_FIFO_START( *p_bit_stream->p_decoder_fifo )->b_discontinuity ) + { + /* Escape the current picture and reset the picture predictors. */ + p_vpar->sequence.b_expect_discontinuity = 1; + p_vpar->picture.b_error = 1; + } + } + + if( p_bit_stream->p_data->b_discard_payload ) + { + /* 1 packet messed up, trash the slice. */ + p_vpar->picture.b_error = 1; + } }