- if( p_es_descriptor->b_psi )
- {
- /* The payload contains PSI tables */
- input_DemuxPSI( p_input, p_ts_packet, p_es_descriptor,
- b_unit_start, b_lost );
- }
- else
- {
- /* The payload carries a PES stream */
- input_DemuxPES( p_input, p_ts_packet, p_es_descriptor,
- b_unit_start, b_lost );
- }
- }
-
-#undef p
-}
-
-
-
-
-/*****************************************************************************
- * input_DemuxPES:
- *****************************************************************************
- * Gather a PES packet and analyzes its header.
- *****************************************************************************/
-static __inline__ void input_DemuxPES( input_thread_t *p_input,
- ts_packet_t *p_ts_packet,
- es_descriptor_t *p_es_descriptor,
- boolean_t b_unit_start,
- boolean_t b_packet_lost )
-{
- decoder_fifo_t * p_fifo;
- u8 i_pes_header_size;
- int i_dummy;
- pes_packet_t* p_last_pes;
- ts_packet_t * p_ts;
- int i_ts_payload_size;
-
-
-#define p_pes (p_es_descriptor->p_pes_packet)
-
- ASSERT(p_input);
- ASSERT(p_ts_packet);
- ASSERT(p_es_descriptor);
-
- //intf_DbgMsg("PES-demultiplexing %p (%p)\n", p_ts_packet, p_pes);
-
- /* If we lost data, discard the PES packet we are trying to reassemble
- if any and wait for the beginning of a new one in order to synchronise
- again */
- if( b_packet_lost && p_pes != NULL )
- {
- intf_DbgMsg("PES %p trashed because of packet lost\n", p_pes);
- input_NetlistFreePES( p_input, p_pes );
- p_pes = NULL;
- }
-
- /* If the TS packet contains the begining of a new PES packet, and if we
- were reassembling a PES packet, then the PES should be complete now,
- so parse its header and give it to the decoders */
- if( b_unit_start && p_pes != NULL )
- {
- //intf_DbgMsg("End of PES packet %p\n", p_pes);
-
- /* Parse the header. The header has a variable length, but in order
- to improve the algorithm, we will read the 14 bytes we may be
- interested in */
- p_ts = p_pes->p_first_ts;
- i_ts_payload_size = p_ts->i_payload_end - p_ts->i_payload_start;
- i_dummy = 0;
-
- if(i_ts_payload_size >= PES_HEADER_SIZE)
- {
- /* This part of the header entirely fits in the payload of
- the first TS packet */
- p_pes->p_pes_header = &(p_ts->buffer[p_ts->i_payload_start]);
- }
- else
- {
- /* This part of the header does not fit in the current TS packet:
- copy the part of the header we are interested in to the
- p_pes_header_save buffer. The buffer is dynamicly allocated if
- needed so it's time expensive but this situation almost never occur. */
- intf_DbgMsg("Code never tested encountered, WARNING ! (benny)\n");
- if( !p_pes->p_pes_header_save )
- {
- p_pes->p_pes_header_save = malloc(PES_HEADER_SIZE);
- }
-
- do
- {
- memcpy(p_pes->p_pes_header_save + i_dummy,
- &p_ts->buffer[p_ts->i_payload_start], i_ts_payload_size);
- i_dummy += i_ts_payload_size;
-
- p_ts = p_ts->p_next_ts;
- if(!p_ts)
- {
- /* The payload of the PES packet is shorter than the 14 bytes
- we would read. This means that high packet lost occured
- so the PES won't be usefull for any decoder. Moreover,
- this should never happen so we can trash the packet and
- exit roughly without regrets */
- intf_DbgMsg("PES packet too short: trashed\n");
- input_NetlistFreePES( p_input, p_pes );
- p_pes = NULL;
- /* Stats XXX?? */
- return;
- }
-
- i_ts_payload_size = p_ts->i_payload_end - p_ts->i_payload_start;
- }
- while(i_ts_payload_size + i_dummy < PES_HEADER_SIZE);
-
- /* This last TS packet is partly header, partly payload, so just
- copy the header part */
- memcpy(p_pes->p_pes_header_save + i_dummy,
- &p_ts->buffer[p_ts->i_payload_start],
- PES_HEADER_SIZE - i_dummy);
-
- /* The header must be read in the buffer not in any TS packet */
- p_pes->p_pes_header = p_pes->p_pes_header_save;
- }
-
- /* Now we have the part of the PES header we were interested in:
- parse it */
-
- /* First read the 6 header bytes common to all PES packets:
- use them to test the PES validity */
- if( (p_pes->p_pes_header[0] || p_pes->p_pes_header[1] ||
- (p_pes->p_pes_header[2] != 1)) ||
- /* packet_start_code_prefix != 0x000001 */
- ((i_dummy = U16_AT(p_pes->p_pes_header + 4)) &&
- (i_dummy + 6 != p_pes->i_pes_size)) )
- /* PES_packet_length is set and != total received payload */
- {
- /* Trash the packet and set p_pes to NULL to be sure the next PES
- packet will have its b_data_lost flag set */
- intf_DbgMsg("Corrupted PES packet received: trashed\n");
- input_NetlistFreePES( p_input, p_pes );
- p_pes = NULL;
- /* Stats XXX?? */
- }
- else
- {
- /* The PES packet is valid. Check its type to test if it may
- carry additional informations in a header extension */
- p_pes->i_stream_id = p_pes->p_pes_header[3];
-
- switch( p_pes->i_stream_id )
- {
- case 0xBE: /* Padding */
- case 0xBC: /* Program stream map */
- case 0xBF: /* Private stream 2 */
- case 0xB0: /* ECM */
- case 0xB1: /* EMM */
- case 0xFF: /* Program stream directory */
- case 0xF2: /* DSMCC stream */
- case 0xF8: /* ITU-T H.222.1 type E stream */
- /* The payload begins immediatly after the 6 bytes header, so
- we have finished with the parsing */
- i_pes_header_size = 6;
- break;
-
- default:
- /* 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] + 9;
-
- /* Now parse the optional header extensions (in the limit of
- the 14 bytes */
- if( p_pes->b_has_pts )
- {
- pcr_descriptor_t * p_pcr;
-
- p_pcr = p_input->p_pcr;
-
- p_pes->i_pts =
- ( ((mtime_t)(p_pes->p_pes_header[9] & 0x0E) << 29) |
- (((mtime_t)U16_AT(p_pes->p_pes_header + 10) << 14) - (1 << 14)) |
- ((mtime_t)U16_AT(p_pes->p_pes_header + 12) >> 1) ) * 300;
- p_pes->i_pts /= 27;
-
- if( p_pcr->i_synchro_state )
- {
- switch( p_pcr->i_synchro_state )
- {
- case SYNCHRO_NOT_STARTED:
- p_pes->b_has_pts = 0;
- break;
-
- case SYNCHRO_START:
- p_pes->i_pts += p_pcr->delta_pcr;
- 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 SYNCHRO_REINIT: /* We skip a PES */
- p_pes->b_has_pts = 0;
- p_pcr->i_synchro_state = SYNCHRO_START;
- break;
- }
- }
- else
- {
- p_pes->i_pts += p_pcr->delta_pcr + p_pcr->delta_absolute;
- }
- }
- break;
- }
-
- /* Now we've parsed the header, we just have to indicate in some
- specific TS packets where the PES payload begins (renumber
- i_payload_start), so that the decoders can find the beginning
- of their data right out of the box. */
- p_ts = p_pes->p_first_ts;
- i_ts_payload_size = p_ts->i_payload_end - p_ts->i_payload_start;
- while( i_pes_header_size > i_ts_payload_size )
- {
- /* These packets are entirely filled by the PES header. */
- i_pes_header_size -= i_ts_payload_size;
- p_ts->i_payload_start = p_ts->i_payload_end;
- /* Go to the next TS packet: here we won't have to test it is
- not NULL because we trash the PES packets when packet lost
- occurs */
- p_ts = p_ts->p_next_ts;
- i_ts_payload_size = p_ts->i_payload_end - p_ts->i_payload_start;
- }
- /* This last packet is partly header, partly payload. */
- p_ts->i_payload_start += i_pes_header_size;
-
-
- /* Now we can eventually put the PES packet in the decoder's
- PES fifo */
- switch( p_es_descriptor->i_type )
- {
- 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:
- case MPEG2_AUDIO_ES:
- p_fifo = &(((adec_thread_t*)(p_es_descriptor->p_dec))->fifo);
- break;
-
- case AC3_AUDIO_ES:
-#if 0
- /* we skip 4 bytes at the beginning of the AC3 payload */
- p_ts->i_payload_start += 4;
-#endif
- 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;
- 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",
- p_es_descriptor->i_id, p_es_descriptor->i_type);
- p_fifo = NULL;
- break;
- }
-
- if( p_fifo != NULL )
- {
- vlc_mutex_lock( &p_fifo->data_lock );
- if( DECODER_FIFO_ISFULL( *p_fifo ) )
- {
- /* The FIFO is full !!! This should not happen. */
-#ifdef STATS
- 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("PES trashed - fifo full ! (%d, %d)\n",
- p_es_descriptor->i_id, p_es_descriptor->i_type);
- }
- else
- {
- //intf_DbgMsg("Putting %p into fifo %p/%d\n",
- // p_pes, p_fifo, p_fifo->i_end);
- p_fifo->buffer[p_fifo->i_end] = p_pes;
- DECODER_FIFO_INCEND( *p_fifo );
-
- /* Warn the decoder that it's got work to do. */
- vlc_cond_signal( &p_fifo->data_wait );
- }
- vlc_mutex_unlock( &p_fifo->data_lock );
- }
- else
- {
- intf_DbgMsg("No fifo to receive PES %p: trash\n", p_pes);
-#ifdef STATS
- 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 );
- }
- }
- }
-
-
- /* If we are at the beginning of a new PES packet, we must fetch a new
- PES buffer to begin with the reassembly of this PES packet. This is
- also here that we can synchronise with the stream if we we lost
- packets or if the decoder has just started */
- if( b_unit_start )
- {
- p_last_pes = p_pes;
-
- /* Get a new one PES from the PES netlist. */
- if( (p_pes = input_NetlistGetPES( p_input )) == (NULL) )
- {
- /* PES netlist is empty ! */
- p_input->b_error = 1;
- }
- else
- {
- //intf_DbgMsg("New PES packet %p (first TS: %p)\n", p_pes, p_ts_packet);
-
- /* Init the PES fields so that the first TS packet could be correctly
- added to the PES packet (see below) */
- p_pes->p_first_ts = p_ts_packet;
- p_pes->p_last_ts = NULL;
-
- /* If the last pes packet was null, this means that the synchronisation
- was lost and so warn the decoder that he will have to find a way to
- recover */
- if( !p_last_pes )
- p_pes->b_data_loss = 1;
-
- /* Read the b_random_access flag status and then reinit it */
- p_pes->b_random_access = p_es_descriptor->b_random;
- p_es_descriptor->b_random = 0;
- }