- /* Check the continuity of the stream. */
- i_dummy = ((p[3] & 0x0f) - p_es_descriptor->i_continuity_counter) & 0x0f;
- if( i_dummy == 1 )
- {
- /* Everything is ok, just increase our counter */
- p_es_descriptor->i_continuity_counter++;
- }
- else
- {
- if( !b_payload && i_dummy == 0 )
- {
- /* This is a packet without payload, this is allowed by the draft
- As there is nothing interessant in this packet (except PCR that
- have already been handled), we can trash the packet. */
- intf_DbgMsg("Packet without payload received by TS demux\n");
- b_trash = 1;
- }
- else if( i_dummy <= 0 )
- {
- /* Duplicate packet: mark it as being to be trashed. */
- intf_DbgMsg("Duplicate packet received by TS demux\n");
- b_trash = 1;
- }
- else
- {
- /* This can indicate that we missed a packet or that the
- continuity_counter wrapped and we received a dup packet: as we
- don't know, do as if we missed a packet to be sure to recover
- from this situation */
- intf_DbgMsg("Packet lost by TS demux: current %d, packet %d\n",
- p_es_descriptor->i_continuity_counter & 0x0f,
- p[3] & 0x0f);
- b_lost = 1;
- p_es_descriptor->i_continuity_counter = p[3] & 0x0f;
- }
- }
-
- /* Trash the packet if it has no payload or if it is bad */
- if( b_trash )
- {
- input_NetlistFreeTS( p_input, p_ts_packet );
-#ifdef STATS
- p_input->c_ts_packets_trashed++;
-#endif
- }
- else
- {
- 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 ?? */
- 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 ?? */
- }
- 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 = 9 + p_pes->p_pes_header[8];
-
- /* 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;
- pthread_mutex_lock( &p_pcr->lock );
- if( p_pcr->delta_clock == 0 )
- {
- p_pes->b_has_pts = 0;
- }
- else
- {
- 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) );
- p_pes->i_pts *= 300;
- p_pes->i_pts /= 27;
- p_pes->i_pts += p_pcr->delta_clock;
- if( p_pcr->c_pts == 0 )
- {
- p_pcr->delta_decode = mdate() - p_pes->i_pts + 500000;
- }
- p_pes->i_pts += p_pcr->delta_decode;
- p_pcr->c_pts += 1;
- }
- pthread_mutex_unlock( &p_pcr->lock );
- }
- 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:
- p_fifo = &(((vdec_thread_t*)(p_es_descriptor->p_dec))->fifo);
- break;
- case MPEG1_AUDIO_ES:
- case MPEG2_AUDIO_ES:
- p_fifo = &(((adec_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 )
- {
- pthread_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_ts_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. */
- pthread_cond_signal( &p_fifo->data_wait );
- }
- pthread_mutex_unlock( &p_fifo->data_lock );
- }
- else
- {
- 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_es_descriptor->c_invalid_packets += p_pes->i_ts_packets;
-#endif
- input_NetlistFreePES( p_input, p_pes );
- }
- }
- }
-
-