+
+/*
+ * PSI demultiplexing and decoding
+ */
+
+/*****************************************************************************
+ * DemuxPSI : makes up complete PSI data
+ *****************************************************************************/
+void input_DemuxPSI( input_thread_t * p_input, data_packet_t * p_data,
+ es_descriptor_t * p_es, boolean_t b_unit_start, boolean_t b_lost )
+{
+ es_ts_data_t * p_demux_data;
+
+ p_demux_data = (es_ts_data_t *)p_es->p_demux_data;
+
+#define p_psi (p_demux_data->p_psi_section)
+#define p (p_data->p_payload_start)
+
+ if( b_unit_start )
+ {
+ /* unit_start set to 1 -> presence of a pointer field
+ * (see ISO/IEC 13818 (2.4.4.2) which should be set to 0x00 */
+ if( (u8)p[0] != 0x00 )
+ {
+ /* intf_WarnMsg( 2, */
+ intf_ErrMsg( "Non zero pointer field found. Trying to continue" );
+ p+=(u8)p[0];
+ }
+ else
+ p++;
+
+ /* This is the begining of a new section */
+
+ if( ((u8)(p[1]) & 0xc0) != 0x80 )
+ {
+ intf_ErrMsg( "Invalid PSI packet" );
+ p_psi->b_trash = 1;
+ }
+ else
+ {
+ p_psi->i_section_length = U16_AT(p+1) & 0x0fff;
+ p_psi->b_section_complete = 0;
+ p_psi->i_read_in_section = 0;
+ p_psi->i_section_number = (u8)p[6];
+
+ if( p_psi->b_is_complete || p_psi->i_section_number == 0 )
+ {
+ /* This is a new PSI packet */
+ p_psi->b_is_complete = 0;
+ p_psi->b_trash = 0;
+ p_psi->i_version_number = ( p[5] >> 1 ) & 0x1f;
+ p_psi->i_last_section_number = (u8)p[7];
+
+ /* We'll write at the begining of the buffer */
+ p_psi->p_current = p_psi->buffer;
+ }
+ else
+ {
+ if( p_psi->b_section_complete )
+ {
+ /* New Section of an already started PSI */
+ p_psi->b_section_complete = 0;
+
+ if( p_psi->i_version_number != (( p[5] >> 1 ) & 0x1f) )
+ {
+ intf_WarnMsg( 2,"PSI version differs inside same PAT" );
+ p_psi->b_trash = 1;
+ }
+ if( p_psi->i_section_number + 1 != (u8)p[6] )
+ {
+ intf_WarnMsg( 2,
+ "PSI Section discontinuity. Packet lost ?");
+ p_psi->b_trash = 1;
+ }
+ else
+ p_psi->i_section_number++;
+ }
+ else
+ {
+ intf_WarnMsg( 2, "Received unexpected new PSI section" );
+ p_psi->b_trash = 1;
+ }
+ }
+ }
+ } /* b_unit_start */
+
+ if( !p_psi->b_trash )
+ {
+ /* read */
+ if( (p_data->p_payload_end - p) >=
+ ( p_psi->i_section_length - p_psi->i_read_in_section ) )
+ {
+ /* The end of the section is in this TS packet */
+ memcpy( p_psi->p_current, p,
+ (p_psi->i_section_length - p_psi->i_read_in_section) );
+
+ p_psi->b_section_complete = 1;
+ p_psi->p_current +=
+ (p_psi->i_section_length - p_psi->i_read_in_section);
+
+ if( p_psi->i_section_number == p_psi->i_last_section_number )
+ {
+ /* This was the last section of PSI */
+ p_psi->b_is_complete = 1;
+ }
+ }
+ else
+ {
+ memcpy( p_psi->buffer, p, p_data->p_payload_end - p );
+ p_psi->i_read_in_section+= p_data->p_payload_end - p;
+
+ p_psi->p_current += p_data->p_payload_end - p;
+ }
+ }
+
+ if ( p_psi->b_is_complete )
+ {
+ switch( p_demux_data->i_psi_type)
+ {
+ case PSI_IS_PAT:
+ input_DecodePAT( p_input, p_es );
+ break;
+ case PSI_IS_PMT:
+ input_DecodePMT( p_input, p_es );
+ break;
+ default:
+ intf_ErrMsg("Received unknown PSI in demuxPSI");
+ }
+ }
+#undef p_psi
+#undef p
+
+ return ;
+}
+
+/*****************************************************************************
+ * DecodePAT : Decodes Programm association table and deal with it
+ *****************************************************************************/
+static void input_DecodePAT( input_thread_t * p_input, es_descriptor_t * p_es )
+{
+
+ stream_ts_data_t * p_stream_data;
+ es_ts_data_t * p_demux_data;
+
+
+ p_demux_data = (es_ts_data_t *)p_es->p_demux_data;
+ p_stream_data = (stream_ts_data_t *)p_input->stream.p_demux_data;
+
+#define p_psi (p_demux_data->p_psi_section)
+
+ if( p_stream_data->i_pat_version != p_psi->i_version_number )
+ {
+ /* PAT has changed. We are going to delete all programms and
+ * create new ones. We chose not to only change what was needed
+ * as a PAT change may mean the stream is radically changing and
+ * this is a secure method to avoid krashed */
+ pgrm_descriptor_t * p_pgrm;
+ es_descriptor_t * p_current_es;
+ es_ts_data_t * p_es_demux;
+ pgrm_ts_data_t * p_pgrm_demux;
+ byte_t * p_current_data;
+
+ int i_section_length,i_program_id,i_pmt_pid;
+ int i_loop, i_current_section;
+
+ p_current_data = p_psi->buffer;
+
+
+ for( i_loop = 0; i_loop < p_input->stream.i_pgrm_number; i_loop++ )
+ {
+ input_DelProgram( p_input, p_input->stream.pp_programs[i_loop] );
+ }
+
+ do
+ {
+ i_section_length = U16_AT(p_current_data+1) & 0x0fff;
+ i_current_section = (u8)p_current_data[6];
+
+ for( i_loop = 0; i_loop < (i_section_length-9)/4 ; i_loop++ )
+ {
+ i_program_id = U16_AT(p_current_data + i_loop*4 + 8);
+ i_pmt_pid = U16_AT( p_current_data + i_loop*4 + 10) & 0x1fff;
+
+ /* If program = 0, we're having info about NIT not PMT */
+ if( i_program_id )
+ {
+ /* Add this program */
+ p_pgrm = input_AddProgram( p_input, i_program_id,
+ sizeof( pgrm_ts_data_t ) );
+
+ /* whatis the PID of the PMT of this program */
+ p_pgrm_demux = (pgrm_ts_data_t *)p_pgrm->p_demux_data;
+ p_pgrm_demux->i_pmt_version = PMT_UNINITIALIZED;
+
+ /* Add the PMT ES to this program */
+ p_current_es = input_AddES( p_input, p_pgrm,(u16)i_pmt_pid,
+ sizeof( es_ts_data_t) );
+ p_es_demux = (es_ts_data_t *)p_current_es->p_demux_data;
+ p_es_demux->b_psi = 1;
+ p_es_demux->i_psi_type = PSI_IS_PMT;
+
+ p_es_demux->p_psi_section =
+ malloc( sizeof( psi_section_t ) );
+ p_es_demux->p_psi_section->b_is_complete = 0;
+ }
+ }
+
+ p_current_data+=3+i_section_length;
+
+ } while( i_current_section < p_psi->i_last_section_number );
+
+ /* Go to the beginning of the next section*/
+ p_stream_data->i_pat_version = p_psi->i_version_number;
+
+ }
+#undef p_psi
+
+}
+
+/*****************************************************************************
+ * DecodePMT : decode a given Program Stream Map
+ * ***************************************************************************
+ * When the PMT changes, it may mean a deep change in the stream, and it is
+ * careful to deletes the ES and add them again. If the PMT doesn't change,
+ * there no need to do anything.
+ *****************************************************************************/
+static void input_DecodePMT( input_thread_t * p_input, es_descriptor_t * p_es )
+{
+
+ pgrm_ts_data_t * p_pgrm_data;
+ es_ts_data_t * p_demux_data;
+
+ p_demux_data = (es_ts_data_t *)p_es->p_demux_data;
+ p_pgrm_data = (pgrm_ts_data_t *)p_es->p_pgrm->p_demux_data;
+
+#define p_psi (p_demux_data->p_psi_section)
+
+ if( p_psi->i_version_number != p_pgrm_data->i_pmt_version )
+ {
+ es_descriptor_t * p_new_es;
+ es_ts_data_t * p_es_demux;
+ byte_t * p_current_data, * p_current_section;
+ int i_section_length,i_current_section;
+ int i_prog_info_length, i_loop;
+ int i_es_info_length, i_pid, i_stream_type;
+
+ p_current_section = p_psi->buffer;
+ p_current_data = p_psi->buffer;
+
+ p_pgrm_data->i_pcr_pid = U16_AT(p_current_section + 8) & 0x1fff;
+
+ /* Delete all ES in this program except the PSI */
+ for( i_loop=0; i_loop < p_es->p_pgrm->i_es_number; i_loop++ )
+ {
+ p_es_demux = (es_ts_data_t *)
+ p_es->p_pgrm->pp_es[i_loop]->p_demux_data;
+ if ( ! p_es_demux->b_psi )
+ input_DelES( p_input, p_es->p_pgrm->pp_es[i_loop] );
+ }
+
+ /* Then add what we received in this PMT */
+ do
+ {
+
+ i_section_length = U16_AT(p_current_data+1) & 0x0fff;
+ i_current_section = (u8)p_current_data[6];
+ i_prog_info_length = U16_AT(p_current_data+10) & 0x0fff;
+
+ /* For the moment we ignore program descriptors */
+ p_current_data += 12+i_prog_info_length;
+
+ /* The end of the section, before the CRC is at
+ * p_current_section + i_section_length -1 */
+ while( p_current_data < p_current_section + i_section_length -1 )
+ {
+ i_stream_type = (int)p_current_data[0];
+ i_pid = U16_AT( p_current_data + 1 ) & 0x1fff;
+ i_es_info_length = U16_AT( p_current_data + 3 ) & 0x0fff;
+
+ /* Add this ES to the program */
+ p_new_es = input_AddES( p_input, p_es->p_pgrm,
+ (u16)i_pid, sizeof( es_ts_data_t ) );
+ p_new_es->i_type = i_stream_type;
+
+ /* We want to decode */
+ input_SelectES( p_input, p_new_es );
+
+ p_current_data += 5 + i_es_info_length;
+ }
+
+ /* Go to the beginning of the next section*/
+ p_current_data += 3+i_section_length;
+
+ p_current_section+=1;
+
+ } while( i_current_section < p_psi->i_last_section_number );
+
+ p_pgrm_data->i_pmt_version = p_psi->i_version_number;
+
+ }
+
+#undef p_psi
+}