#include <sys/uio.h>
#include <string.h>
-#include <X11/Xlib.h>
-#include <X11/extensions/XShm.h>
-#include <sys/soundcard.h>
-
#include <stdlib.h>
#include <stdio.h>
#include <sys/ioctl.h>
/******************************************************************************
* Local prototypes
******************************************************************************/
-static void input_Thread( input_thread_t *p_input );
-static void ErrorThread( input_thread_t *p_input );
-static void EndThread( input_thread_t *p_input );
-static __inline__ int input_ReadPacket( input_thread_t *p_input );
-static __inline__ void input_SortPacket( input_thread_t *p_input,
- ts_packet_t *ts_packet );
-static __inline__ void input_DemuxTS( input_thread_t *p_input,
- ts_packet_t *ts_packet,
- es_descriptor_t *es_descriptor );
-static __inline__ void input_DemuxPES( input_thread_t *p_input,
+static void RunThread ( input_thread_t *p_input );
+static void ErrorThread ( input_thread_t *p_input );
+static void EndThread ( input_thread_t *p_input );
+
+static __inline__ int input_ReadPacket( input_thread_t *p_input );
+static __inline__ void input_SortPacket( input_thread_t *p_input,
+ ts_packet_t *ts_packet );
+static __inline__ void input_DemuxTS( input_thread_t *p_input,
ts_packet_t *ts_packet,
- es_descriptor_t *p_es_descriptor,
- boolean_t b_unit_start, boolean_t b_packet_lost );
-static __inline__ void input_DemuxPSI( input_thread_t *p_input,
- ts_packet_t *ts_packet,
- es_descriptor_t *p_es_descriptor,
- boolean_t b_unit_start, boolean_t b_packet_lost );
+ es_descriptor_t *es_descriptor );
+static __inline__ void input_DemuxPES( input_thread_t *p_input,
+ ts_packet_t *ts_packet,
+ es_descriptor_t *p_es_descriptor,
+ boolean_t b_unit_start, boolean_t b_packet_lost );
+static __inline__ void input_DemuxPSI( input_thread_t *p_input,
+ ts_packet_t *ts_packet,
+ es_descriptor_t *p_es_descriptor,
+ boolean_t b_unit_start, boolean_t b_packet_lost );
/*******************************************************************************
- * input_CreateThread: initialize and spawn an input thread
+ * input_CreateThread: creates a new input thread
*******************************************************************************
- * This function initializes and spawns an input thread. It returns NULL on
- * failure. If you want a better understanding of the input thread, don't start
- * by reading this function :-).
+ * This function creates a new input, and returns a pointer
+ * to its description. On error, it returns NULL.
+ * If pi_status is NULL, then the function will block until the thread is ready.
+ * If not, it will be updated using one of the THREAD_* constants.
*******************************************************************************/
-input_thread_t *input_CreateThread( input_cfg_t *p_cfg )
+input_thread_t *input_CreateThread ( int i_method, char *psz_source, int i_port, int i_vlan,
+ p_vout_thread_t p_vout, p_aout_thread_t p_aout, int *pi_status )
{
- input_thread_t * p_input;
- int i_index;
+ input_thread_t * p_input; /* thread descriptor */
+ int i_status; /* thread status */
+ int i_index; /* index for tables initialization */
- intf_DbgMsg("input debug 1-1: creating thread (cfg : %p)\n", p_cfg );
-
- /* Allocate input_thread_t structure. */
- if( !( p_input = (input_thread_t *)malloc(sizeof(input_thread_t)) ) )
+ /* Allocate descriptor */
+ intf_DbgMsg("\n");
+ p_input = (input_thread_t *)malloc( sizeof(input_thread_t) );
+ if( p_input == NULL )
{
- intf_ErrMsg("input error: can't allocate input thread structure (%s)\n",
- strerror(errno));
+ intf_ErrMsg("error: %s\n", strerror(ENOMEM));
return( NULL );
}
- /* Init it */
- bzero( p_input, sizeof(input_thread_t));
- for( i_index = 0; i_index < INPUT_MAX_ES; i_index++ )
+
+ /* Initialize thread properties */
+ p_input->b_die = 0;
+ p_input->b_error = 0;
+ p_input->pi_status = (pi_status != NULL) ? pi_status : &i_status;
+ *p_input->pi_status = THREAD_CREATE;
+
+ /* Initialize input method description */
+ p_input->i_method = i_method;
+ p_input->psz_source = psz_source;
+ p_input->i_port = i_port;
+ p_input->i_vlan = i_vlan;
+ switch( i_method )
{
- p_input->p_es[i_index].i_id = EMPTY_PID;
+ case INPUT_METHOD_TS_FILE: /* file methods */
+ p_input->p_Open = input_FileOpen;
+ p_input->p_Read = input_FileRead;
+ p_input->p_Close = input_FileClose;
+ break;
+ case INPUT_METHOD_TS_VLAN_BCAST: /* vlan network method */
+ if( !p_main->b_vlans )
+ {
+ intf_ErrMsg("error: vlans are not activated\n");
+ free( p_input );
+ return( NULL );
+ }
+ /* ... pass through */
+ case INPUT_METHOD_TS_UCAST: /* network methods */
+ case INPUT_METHOD_TS_MCAST:
+ case INPUT_METHOD_TS_BCAST:
+ p_input->p_Open = input_NetworkOpen;
+ p_input->p_Read = input_NetworkRead;
+ p_input->p_Close = input_NetworkClose;
+ break;
+ default:
+ intf_ErrMsg("error: unknow input method\n");
+ free( p_input );
+ return( NULL );
+ break;
}
- /* Find out which method we are gonna use and retrieve pointers. */
- if( !((p_cfg->i_properties) & INPUT_CFG_METHOD) )
+ /* Initialize stream description */
+ for( i_index = 0; i_index < INPUT_MAX_ES; i_index++ )
{
- /* i_method is not set. */
- intf_DbgMsg("input debug: using default method (%d)\n",
- INPUT_DEFAULT_METHOD);
- p_cfg->i_method = INPUT_DEFAULT_METHOD;
- p_cfg->i_properties |= INPUT_CFG_METHOD;
+ p_input->p_es[i_index].i_id = EMPTY_PID;
}
- p_input->i_method = p_cfg->i_method;
- switch( p_cfg->i_method )
- {
- /* File methods */
- case INPUT_METHOD_TS_FILE:
- p_input->p_open = &input_FileCreateMethod;
- p_input->p_read = &input_FileRead;
- p_input->p_clean = &input_FileDestroyMethod;
- break;
-
- /* Network methods */
- case INPUT_METHOD_TS_UCAST:
- case INPUT_METHOD_TS_MCAST:
- case INPUT_METHOD_TS_BCAST:
- case INPUT_METHOD_TS_VLAN_BCAST:
- p_input->p_open = &input_NetworkCreateMethod;
- p_input->p_read = &input_NetworkRead;
- p_input->p_clean = &input_NetworkDestroyMethod;
- break;
+
+ /* Initialize default settings for spawned decoders */
+ p_input->p_aout = p_aout;
+ p_input->p_vout = p_vout;
- case INPUT_METHOD_NONE:
- default:
-#ifdef DEBUG
- /* Internal error, which should never happen */
- intf_DbgMsg("input debug: unknow method type %d\n",
- p_cfg->i_method);
- return( NULL );
+#ifdef STATS
+ /* Initialize statistics */
+ p_input->c_loops = 0;
+ p_input->c_bytes = 0;
+ p_input->c_payload_bytes = 0;
+ p_input->c_packets_read = 0;
+ p_input->c_packets_trashed = 0;
#endif
- break;
- }
- /* Initialize PSI decoder. */
- intf_DbgMsg("Initializing PSI decoder\n");
- if( input_PsiInit( p_input ) == -1 )
+ /* Initialize PSI and PCR decoders */
+ if( input_PsiInit( p_input ) )
{
free( p_input );
return( NULL );
}
- /* Initialize PCR decoder. */
- intf_DbgMsg("Initializing PCR decoder\n");
- if( input_PcrInit( p_input ) == -1 )
+ if( input_PcrInit( p_input ) )
{
- input_PsiClean( p_input );
+ input_PsiEnd( p_input );
free( p_input );
return( NULL );
}
- /* Initialize netlists. */
- if( input_NetlistOpen( p_input ) )
+ /* Initialize netlists */
+ if( input_NetlistInit( p_input ) )
{
- input_PsiClean( p_input );
- input_PcrClean( p_input );
+ input_PsiEnd( p_input );
+ input_PcrEnd( p_input );
free( p_input );
return( NULL );
}
-#ifdef STATS
- /* Initialize counters. */
- p_input->c_bytes = 0;
- p_input->c_payload_bytes = 0;
- p_input->c_ts_packets_read = 0;
- p_input->c_ts_packets_trashed = 0;
-#ifdef DEBUG
- p_input->c_loops = 0;
-#endif
-#endif
+ intf_DbgMsg("configuration: method=%d, source=%s, port=%d, vlan=%d\n",
+ i_method, psz_source, i_port, i_vlan );
/* Let the appropriate method open the socket. */
- if( (*(p_input->p_open))( p_input, p_cfg ) == -1 )
+ if( p_input->p_Open( p_input ) )
{
- input_NetlistClean( p_input );
- input_PsiClean( p_input );
- input_PcrClean( p_input );
+ input_NetlistEnd( p_input );
+ input_PsiEnd( p_input );
+ input_PcrEnd( p_input );
free( p_input );
return( NULL );
}
- intf_DbgMsg("input debug: method %d properly initialized the socket\n",
- p_input->i_method);
-
/* Create thread and set locks. */
- p_input->b_die = 0;
vlc_mutex_init( &p_input->netlist.lock );
vlc_mutex_init( &p_input->programs_lock );
vlc_mutex_init( &p_input->es_lock );
-#ifdef NO_THREAD
- input_Thread( p_input );
-#else
- if( vlc_thread_create(&p_input->thread_id, "input", (vlc_thread_func_t)input_Thread,
- (void *) p_input) )
+ if( vlc_thread_create(&p_input->thread_id, "input", (void *) RunThread, (void *) p_input) )
{
- intf_ErrMsg("input error: can't spawn input thread (%s)\n",
- strerror(errno) );
- (*p_input->p_clean)( p_input );
- input_NetlistClean( p_input );;
- input_PsiClean( p_input );
- input_PcrClean( p_input );
+ intf_ErrMsg("error: %s\n", strerror(errno) );
+ p_input->p_Close( p_input );
+ input_NetlistEnd( p_input );;
+ input_PsiEnd( p_input );
+ input_PcrEnd( p_input );
free( p_input );
return( NULL );
}
-#endif
-
- /* Default setting for new decoders */
- p_input->p_aout = p_cfg->p_aout;
-
+
+ intf_Msg("Input initialized\n");
+
+ /* If status is NULL, wait until the thread is created */
+ if( pi_status == NULL )
+ {
+ do
+ {
+ msleep( THREAD_SLEEP );
+ }while( (i_status != THREAD_READY) && (i_status != THREAD_ERROR)
+ && (i_status != THREAD_FATAL) );
+ if( i_status != THREAD_READY )
+ {
+ return( NULL );
+ }
+ }
return( p_input );
}
******************************************************************************
* This function should not return until the thread is effectively cancelled.
******************************************************************************/
-void input_DestroyThread( input_thread_t *p_input )
+void input_DestroyThread( input_thread_t *p_input, int *pi_status )
{
- intf_DbgMsg("input debug: requesting termination of input thread\n");
- p_input->b_die = 1; /* ask thread to kill itself */
+ int i_status; /* thread status */
- /* Remove this as soon as the "status" flag is implemented */
- vlc_thread_join( p_input->thread_id ); /* wait until it's done */
+ /* Set status */
+ p_input->pi_status = (pi_status != NULL) ? pi_status : &i_status;
+ *p_input->pi_status = THREAD_DESTROY;
+
+ /* Request thread destruction */
+ p_input->b_die = 1;
+
+ /* If status is NULL, wait until thread has been destroyed */
+ if( pi_status == NULL )
+ {
+ do
+ {
+ msleep( THREAD_SLEEP );
+ }while( (i_status != THREAD_OVER) && (i_status != THREAD_ERROR)
+ && (i_status != THREAD_FATAL) );
+ }
}
#if 0
/* following functions are local */
/*******************************************************************************
- * input_Thread: input thread
+ * InitThread: initialize input 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( input_thread_t *p_input )
+{
+ /* Mark thread as running and return */
+ intf_DbgMsg("\n");
+ *p_input->pi_status = THREAD_READY;
+ intf_DbgMsg("thread ready\n");
+ return( 0 );
+}
+
+/*******************************************************************************
+ * RunThread: main thread loop
*******************************************************************************
* Thread in charge of processing the network packets and demultiplexing.
*******************************************************************************/
-static void input_Thread( input_thread_t *p_input )
+static void RunThread( input_thread_t *p_input )
{
- intf_DbgMsg("input debug 11-1: thread %p is active\n", p_input);
+ /*
+ * Initialize thread and free configuration
+ */
+ p_input->b_error = InitThread( p_input );
+ if( p_input->b_error )
+ {
+ free( p_input ); /* destroy descriptor */
+ return;
+ }
+
+ /*
+ * Main loop
+ */
+ intf_DbgMsg("\n");
while( !p_input->b_die && !p_input->b_error )
{
/* Scatter read the UDP packet from the network or the file. */
#endif
}
+ /*
+ * Error loop
+ */
if( p_input->b_error )
{
ErrorThread( p_input );
}
- /* Ohoh, we have to die as soon as possible. */
+ /* End of thread */
EndThread( p_input );
-
- intf_DbgMsg("input debug: thread %p destroyed\n", p_input);
- vlc_thread_exit();
+ intf_DbgMsg("thread end\n");
}
/******************************************************************************
* ErrorThread: RunThread() error loop
+ *******************************************************************************
+ * This function is called when an error occured during thread main's loop.
******************************************************************************/
static void ErrorThread( input_thread_t *p_input )
{
+ /* Wait until a `die' order */
+ intf_DbgMsg("\n");
while( !p_input->b_die )
{
- msleep( INPUT_IDLE_SLEEP );
+ /* Sleep a while */
+ msleep( VOUT_IDLE_SLEEP );
}
}
*******************************************************************************/
static void EndThread( input_thread_t * p_input )
{
- int i_es_loop;
+ int * pi_status; /* threas status */
+ int i_es_loop; /* es index */
- (*p_input->p_clean)( p_input ); /* close input method */
+ /* Store status */
+ intf_DbgMsg("\n");
+ pi_status = p_input->pi_status;
+ *pi_status = THREAD_END;
- /* Destroy all decoder threads. */
- for( i_es_loop = 0; i_es_loop < INPUT_MAX_ES; i_es_loop++ )
- {
- if( p_input->pp_selected_es[i_es_loop] )
- {
- switch( p_input->pp_selected_es[i_es_loop]->i_type )
- {
- case MPEG1_VIDEO_ES:
- case MPEG2_VIDEO_ES:
- vdec_DestroyThread( (vdec_thread_t*)(p_input->pp_selected_es[i_es_loop]->p_dec) /*, NULL */ );
- break;
-
- case MPEG1_AUDIO_ES:
- case MPEG2_AUDIO_ES:
- adec_DestroyThread( (adec_thread_t*)(p_input->pp_selected_es[i_es_loop]->p_dec) );
- break;
+ /* Close input method */
+ p_input->p_Close( p_input );
- case AC3_AUDIO_ES:
- ac3dec_DestroyThread( (ac3dec_thread_t *)(p_input->pp_selected_es[i_es_loop]->p_dec) );
- break;
-
- default:
- break;
- }
- }
- else
+ /* Destroy all decoder threads */
+ for( i_es_loop = 0;
+ (i_es_loop < INPUT_MAX_ES) && (p_input->pp_selected_es[i_es_loop] != NULL) ;
+ i_es_loop++ )
+ {
+ switch( p_input->pp_selected_es[i_es_loop]->i_type )
{
- /* pp_selected_es should not contain any hole. */
+ case MPEG1_VIDEO_ES:
+ case MPEG2_VIDEO_ES:
+#ifdef OLD_DECODER
+ vdec_DestroyThread( (vdec_thread_t*)(p_input->pp_selected_es[i_es_loop]->p_dec) /*, NULL */ );
+#else
+ vpar_DestroyThread( (vpar_thread_t*)(p_input->pp_selected_es[i_es_loop]->p_dec) /*, NULL */ );
+#endif
+ break;
+ case MPEG1_AUDIO_ES:
+ case MPEG2_AUDIO_ES:
+ adec_DestroyThread( (adec_thread_t*)(p_input->pp_selected_es[i_es_loop]->p_dec) );
break;
+ case AC3_AUDIO_ES:
+ ac3dec_DestroyThread( (ac3dec_thread_t *)(p_input->pp_selected_es[i_es_loop]->p_dec) );
+ break;
+ case DVD_SPU_ES:
+ fprintf(stderr, "input.h : destroying spudec\n");
+ spudec_DestroyThread( (spudec_thread_t *)(p_input->pp_selected_es[i_es_loop]->p_dec) );
+ break;
+ case 0:
+ /* Special streams for the PSI decoder, PID 0 and 1 */
+ break;
+#ifdef DEBUG
+ default:
+ intf_DbgMsg("error: unknown decoder type %d\n", p_input->pp_selected_es[i_es_loop]->i_type );
+ break;
+#endif
}
}
- input_NetlistClean( p_input ); /* clean netlist */
- input_PsiClean( p_input ); /* clean PSI information */
- input_PcrClean( p_input ); /* clean PCR information */
- free( p_input ); /* free input_thread structure */
+ input_NetlistEnd( p_input ); /* clean netlist */
+ input_PsiEnd( p_input ); /* clean PSI information */
+ input_PcrEnd( p_input ); /* clean PCR information */
+ free( p_input ); /* free input_thread structure */
- intf_DbgMsg("input debug: EndThread(%p)\n", p_input);
+ /* Update status */
+ *pi_status = THREAD_OVER;
}
/*******************************************************************************
#endif /* FIFO netlist */
/* Scatter read the buffer. */
- i_packet_size = (*p_input->p_read)( p_input,
+ i_packet_size = (*p_input->p_Read)( p_input,
&p_input->netlist.p_ts_free[i_base_index],
INPUT_TS_READ_ONCE );
if( i_packet_size == (-1) )
#endif
#ifdef STATS
- p_input->c_ts_packets_read += i_current_index - i_base_index;
+ p_input->c_packets_read += i_current_index - i_base_index;
p_input->c_bytes += (i_current_index - i_base_index) * TS_PACKET_SIZE;
#endif
- return( 0 );
+ return( 0 );
}
/*******************************************************************************
// U16_AT(&p_ts_packet->buffer[1]) & 0x1fff);
input_NetlistFreeTS( p_input, p_ts_packet );
#ifdef STATS
- p_input->c_ts_packets_trashed++;
+ p_input->c_packets_trashed++;
#endif
}
{
input_NetlistFreeTS( p_input, p_ts_packet );
#ifdef STATS
- p_input->c_ts_packets_trashed++;
+ p_input->c_packets_trashed++;
#endif
}
else
/* The PES header contains at least 3 more bytes: parse them */
p_pes->b_data_alignment = p_pes->p_pes_header[6] & 0x04;
p_pes->b_has_pts = p_pes->p_pes_header[7] & 0x80;
- i_pes_header_size = p_pes->p_pes_header[8]
- + (p_es_descriptor->i_type == AC3_AUDIO_ES) ? 13 : 9;
+ i_pes_header_size = p_pes->p_pes_header[8] + 9;
/* Now parse the optional header extensions (in the limit of
the 14 bytes */
case SYNCHRO_START:
p_pes->i_pts += p_pcr->delta_pcr;
- p_pcr->delta_absolute = mdate() - p_pes->i_pts + 500000;
+ p_pcr->delta_absolute = mdate() - p_pes->i_pts + INPUT_PTS_DELAY;
p_pes->i_pts += p_pcr->delta_absolute;
p_pcr->i_synchro_state = 0;
break;
{
case MPEG1_VIDEO_ES:
case MPEG2_VIDEO_ES:
+#ifdef OLD_DECODER
p_fifo = &(((vdec_thread_t*)(p_es_descriptor->p_dec))->fifo);
+#else
+ p_fifo = &(((vpar_thread_t*)(p_es_descriptor->p_dec))->fifo);
+#endif
break;
case MPEG1_AUDIO_ES:
break;
case AC3_AUDIO_ES:
+ /* we skip 4 bytes at the beginning of the AC3 payload */
+ p_ts->i_payload_start += 4;
p_fifo = &(((ac3dec_thread_t *)(p_es_descriptor->p_dec))->fifo);
break;
+ case DVD_SPU_ES:
+ /* we skip 4 bytes at the beginning of the subpicture payload */
+ p_ts->i_payload_start += 4;
+ fprintf(stderr, "input.h : launching spudec\n");
+ p_fifo = &(((spudec_thread_t *)(p_es_descriptor->p_dec))->fifo);
+ break;
+
default:
/* This should never happen */
intf_DbgMsg("Unknown stream type (%d, %d): PES trashed\n",
{
/* The FIFO is full !!! This should not happen. */
#ifdef STATS
- p_input->c_ts_packets_trashed += p_pes->i_ts_packets;
+ p_input->c_packets_trashed += p_pes->i_ts_packets;
p_es_descriptor->c_invalid_packets += p_pes->i_ts_packets;
#endif
input_NetlistFreePES( p_input, p_pes );
{
intf_DbgMsg("No fifo to receive PES %p: trash\n", p_pes);
#ifdef STATS
- p_input->c_ts_packets_trashed += p_pes->i_ts_packets;
+ p_input->c_packets_trashed += p_pes->i_ts_packets;
p_es_descriptor->c_invalid_packets += p_pes->i_ts_packets;
#endif
input_NetlistFreePES( p_input, p_pes );