summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--xine/ts2es.c262
-rw-r--r--xine/ts2es.h21
2 files changed, 283 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;
+}
+
diff --git a/xine/ts2es.h b/xine/ts2es.h
new file mode 100644
index 00000000..8a5ab724
--- /dev/null
+++ b/xine/ts2es.h
@@ -0,0 +1,21 @@
+/*
+ * ts2es.h: demux MPEG-TS -> ES
+ *
+ * See the main source file 'xineliboutput.c' for copyright information and
+ * how to reach the author.
+ *
+ * $Id: ts2es.h,v 1.1 2009-02-23 22:16:08 phintuka Exp $
+ *
+ */
+
+#ifndef _DEMUX_XVDR_TS2ES_H_
+#define _DEMUX_XVDR_TS2ES_H_
+
+typedef struct ts2es_s ts2es_t;
+
+ts2es_t *ts2es_init (fifo_buffer_t *dst_fifo, ts_stream_type stream_type, uint stream_index);
+buf_element_t *ts2es_put (ts2es_t *ts2es, uint8_t *ts_packet);
+void ts2es_flush (ts2es_t *ts2es);
+void ts2es_dispose (ts2es_t *ts2es);
+
+#endif /* _DEMUX_XVDR_TS2ES_H_ */