diff options
Diffstat (limited to 'xine/ts2es.c')
-rw-r--r-- | xine/ts2es.c | 262 |
1 files changed, 262 insertions, 0 deletions
diff --git a/xine/ts2es.c b/xine/ts2es.c new file mode 100644 index 00000000..bf0ec7fb --- /dev/null +++ b/xine/ts2es.c @@ -0,0 +1,262 @@ +/* + * ts2es.c: demux MPEG-TS -> ES + * + * See the main source file 'xineliboutput.c' for copyright information and + * how to reach the author. + * + * $Id: ts2es.c,v 1.1 2009-02-23 22:16:08 phintuka Exp $ + * + */ + +#include <stdlib.h> + +#include <xine/buffer.h> + +#include "../tools/ts.h" +#include "../tools/pes.h" + +#include "ts2es.h" + +#define LOG_MODULENAME "[demux_vdr] " +#define SysLogLevel iSysLogLevel +#include "../logdefs.h" + + +struct ts2es_s { + fifo_buffer_t *fifo; + uint32_t stream_type; + uint32_t xine_buf_type; + + buf_element_t *buf; + int pes_start; + int64_t pts; +}; + + +static void ts2es_parse_pes(ts2es_t *this) +{ + if (!DATA_IS_PES(this->buf->content)) { + LOGMSG("ts2es: payload not PES ?"); + return; + } + + /* parse PES header */ + uint hdr_len = PES_HEADER_LEN(this->buf->content); + uint8_t pes_pid = this->buf->content[3]; + uint pes_len = (this->buf->content[4] << 8) | this->buf->content[5]; + + /* parse PTS */ + this->buf->pts = pes_get_pts(this->buf->content, this->buf->size); + if(this->buf->pts >= 0) + this->pts = this->buf->pts; + else + this->pts = 0; + + /* strip PES header */ + this->buf->content += hdr_len; + this->buf->size -= hdr_len; + + /* parse substream header */ + + if (pes_pid != PRIVATE_STREAM1) + return; + + /* RAW AC3 audio ? -> do nothing */ + if (this->stream_type == STREAM_AUDIO_AC3) { + this->xine_buf_type |= BUF_AUDIO_A52; + this->buf->type = this->xine_buf_type; + return; + } + + /* AC3 syncword in beginning of PS1 payload ? */ + if (this->buf->content[0] == 0x0B && + this->buf->content[1] == 0x77) { + /* --> RAW AC3 audio - do nothing */ + this->xine_buf_type |= BUF_AUDIO_A52; + this->buf->type = this->xine_buf_type; + return; + } + + /* audio in PS1 */ + if (this->stream_type == ISO_13818_PES_PRIVATE) { + + if ((this->buf->content[0] & 0xf0) == 0x80) { + /* AC3, strip substream header */ + this->buf->content += 4; + this->buf->size -= 4; + this->xine_buf_type |= BUF_AUDIO_A52; + this->buf->type = this->xine_buf_type; + return; + } + + if ((this->buf->content[0] & 0xf0) == 0xa0) { + /* PCM, strip substream header */ + int pcm_offset; + for (pcm_offset=0; ++pcm_offset < this->buf->size-1 ; ) { + if (this->buf->content[pcm_offset] == 0x01 && + this->buf->content[pcm_offset+1] == 0x80 ) { /* START */ + pcm_offset += 2; + break; + } + } + this->buf->content += pcm_offset; + this->buf->size -= pcm_offset; + + this->xine_buf_type |= BUF_AUDIO_LPCM_BE; + this->buf->type = this->xine_buf_type; + return; + } + + LOGMSG("ts2es: unhandled PS1 substream 0x%x", this->buf->content[0]); + return; + } + + /* DVB SPU */ + if (this->stream_type == STREAM_DVBSUB) { + if (this->buf->content[0] != 0x20 || + this->buf->content[1] != 0x00) + LOGMSG("ts2es: DVB SPU, invalid PES substream header"); + this->buf->decoder_info[2] = pes_len - hdr_len - 3 + 9; + return; + } +} + +buf_element_t *ts2es_put(ts2es_t *this, uint8_t *data) +{ + int bytes = ts_PAYLOAD_SIZE(data); + int pusi = ts_PAYLOAD_START(data); + buf_element_t *result = NULL; + + if (ts_HAS_ERROR(data)) { + LOGDBG("ts2es: transport error"); + return NULL; + } + if (!ts_HAS_PAYLOAD(data)) { + LOGDBG("ts2es: no payload, size %d", bytes); + return NULL; + } + + /* handle new payload unit */ + if (pusi) { + this->pes_start = 1; + if (this->buf) { + + this->buf->decoder_flags |= BUF_FLAG_FRAME_END; + this->buf->pts = this->pts; + + result = this->buf; + this->buf = NULL; + } + } + + /* need new buffer ? */ + if (!this->buf) { + this->buf = this->fifo->buffer_pool_alloc(this->fifo); + this->buf->type = this->xine_buf_type; + this->buf->decoder_info[0] = 1; + } + + /* strip ts header */ + data += TS_SIZE - bytes; + + /* copy payload */ + memcpy(this->buf->content + this->buf->size, data, bytes); + this->buf->size += bytes; + + /* parse PES header */ + if (this->pes_start) { + this->pes_start = 0; + + ts2es_parse_pes(this); + } + + /* split large packets */ + if (this->buf->size > 2048) { + this->buf->pts = this->pts; + + result = this->buf; + this->buf = NULL; + } + + return result; +} + +void ts2es_flush(ts2es_t *this) +{ + if (this->buf) { + + this->buf->decoder_flags |= BUF_FLAG_FRAME_END; + this->buf->pts = this->pts; + + this->fifo->put (this->fifo, this->buf); + this->buf = NULL; + } +} + +void ts2es_dispose(ts2es_t *data) +{ + if (data) { + if (data->buf) + data->buf->free_buffer(data->buf); + free(data); + } +} + +ts2es_t *ts2es_init(fifo_buffer_t *dst_fifo, ts_stream_type stream_type, uint stream_index) +{ + ts2es_t *data = calloc(1, sizeof(ts2es_t)); + data->fifo = dst_fifo; + + data->stream_type = stream_type; + + switch(stream_type) { + /* VIDEO (PES streams 0xe0...0xef) */ + case ISO_11172_VIDEO: + case ISO_13818_VIDEO: + case STREAM_VIDEO_MPEG: + data->xine_buf_type = BUF_VIDEO_MPEG; + break; + case ISO_14496_PART2_VIDEO: + data->xine_buf_type = BUF_VIDEO_MPEG4; + break; + case ISO_14496_PART10_VIDEO: + data->xine_buf_type = BUF_VIDEO_H264; + break; + + /* AUDIO (PES streams 0xc0...0xdf) */ + case ISO_11172_AUDIO: + case ISO_13818_AUDIO: + data->xine_buf_type = BUF_AUDIO_MPEG; + break; + case ISO_13818_PART7_AUDIO: + case ISO_14496_PART3_AUDIO: + data->xine_buf_type = BUF_AUDIO_AAC; + break; + + /* AUDIO (PES stream 0xbd) */ + case ISO_13818_PES_PRIVATE: + data->xine_buf_type = 0; + /* detect from PES substream header */ + break; + + /* DVB SPU (PES stream 0xbd) */ + case STREAM_DVBSUB: + data->xine_buf_type = BUF_SPU_DVB; + break; + + /* RAW AC3 */ + case STREAM_AUDIO_AC3: + data->xine_buf_type = BUF_AUDIO_A52; + break; + + default: + LOGMSG("ts2es: unknown stream type 0x%x", stream_type); + break; + } + + /* substream ID (audio/SPU) */ + data->xine_buf_type |= stream_index; + + return data; +} + |