summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--tools/ts.c300
1 files changed, 300 insertions, 0 deletions
diff --git a/tools/ts.c b/tools/ts.c
new file mode 100644
index 00000000..19d525eb
--- /dev/null
+++ b/tools/ts.c
@@ -0,0 +1,300 @@
+/*
+ * ts.c: MPEG-TS
+ *
+ * See the main source file 'xineliboutput.c' for copyright information and
+ * how to reach the author.
+ *
+ * $Id: ts.c,v 1.1 2009-01-27 09:24:34 phintuka Exp $
+ *
+ */
+
+#ifndef LOGDBG
+# include "../logdefs.h"
+#endif
+
+#include "ts.h"
+#include "pes.h"
+
+/*
+ * ts_compute_crc32()
+ *
+ * taken from xine-lib demux_ts.c
+ */
+static uint32_t ts_compute_crc32(uint8_t *data, uint32_t length, uint32_t crc32)
+{
+ static uint32_t crc32_table[256];
+ static uint init_done = 0;
+
+ if (!init_done) {
+ uint32_t i, j, k;
+ init_done = 1;
+ for (i = 0 ; i < 256 ; i++) {
+ k = 0;
+ for (j = (i << 24) | 0x800000 ; j != 0x80000000 ; j <<= 1)
+ k = (k << 1) ^ (((k ^ j) & 0x80000000) ? 0x04c11db7 : 0);
+ crc32_table[i] = k;
+ }
+ }
+
+ uint32_t i;
+ for(i = 0; i < length; i++)
+ crc32 = (crc32 << 8) ^ crc32_table[(crc32 >> 24) ^ data[i]];
+
+ return crc32;
+}
+
+/*
+ * parse_pat()
+ *
+ * - parse PAT for PMT pid and program number
+ *
+ * modified from xine-lib demux_ts.c
+ */
+int ts_parse_pat(pat_data_t *pat, uint8_t *pkt)
+{
+ uint8_t *original_pkt = pkt;
+
+ if (! ts_PAYLOAD_START(pkt)) {
+ LOGMSG ("parse_pat: PAT without payload unit start indicator");
+ return 0;
+ }
+
+ /* jump to payload */
+ pkt += pkt[4]; /* pointer */
+ if (pkt - original_pkt > TS_SIZE) {
+ LOGMSG("parse_pat: PAT with invalid pointer");
+ return 0;
+ }
+
+ uint section_syntax_indicator = ((pkt[6] >> 7) & 0x01) ;
+ uint section_length = ((pkt[6] & 0x03) << 8) | pkt[7];
+/*uint transport_stream_id = (pkt[8] << 8) | pkt[9];*/
+/*uint version_number = (pkt[10] >> 1) & 0x1f;*/
+ uint current_next_indicator = pkt[10] & 0x01;
+ uint section_number = pkt[11];
+ uint last_section_number = pkt[12];
+ uint32_t crc32, calc_crc32;
+
+ crc32 = pkt[section_length + 4] << 24;
+ crc32 |= pkt[section_length + 5] << 16;
+ crc32 |= pkt[section_length + 6] << 8;
+ crc32 |= pkt[section_length + 7] ;
+
+ if ((section_syntax_indicator != 1) || !(current_next_indicator)) {
+ LOGMSG("parse_pat: ssi error");
+ return 0;
+ }
+
+ if (pkt - original_pkt > TS_SIZE-4 - 1 - 3 - section_length) {
+ LOGMSG("parse_pat: unsupported PAT does not fit to single TS packet");
+ return 0;
+ }
+
+ if ((section_number != 0) || (last_section_number != 0)) {
+ LOGMSG("parse_pat: unsoupported PAT consists of multiple (%d) sections", last_section_number);
+ return 0;
+ }
+
+ /* Check CRC */
+ calc_crc32 = ts_compute_crc32 (pkt + 5, section_length + 3 - 4, 0xffffffff);
+ if (crc32 != calc_crc32) {
+ LOGMSG("parse_pat: invalid CRC");
+ return 0;
+ }
+
+ /*
+ * Process all programs in the program loop
+ */
+
+ uint8_t *program;
+ uint program_count;
+
+ program_count = 0;
+ for (program = pkt + 13;
+ program < pkt + 13 + section_length - 9;
+ program += 4) {
+ uint program_number = (program[0] << 8) | program[1];
+ uint pmt_pid = ((program[2] & 0x1f) << 8) | program[3];
+
+ /* skip NIT pids */
+ if (program_number == 0x0000)
+ continue;
+
+ pat->program_number[program_count] = program_number;
+ pat->pmt_pid[program_count] = pmt_pid;
+
+ LOGDBG("PAT acquired count=%d programNumber=0x%04x pmtPid=0x%04x",
+ program_count,
+ pat->program_number[program_count],
+ pat->pmt_pid[program_count]);
+
+ program_count++;
+ }
+
+ pat->program_number[program_count] = 0;
+
+ return program_count;
+}
+
+
+/*
+ * ts_state_t
+ */
+
+struct ts_state_s {
+
+ uint8_t pusi_seen;
+
+ uint8_t inside_pes; /* Scanning ES (PES start code seen and skippped) */
+
+ uint32_t buf_len; /* bytes queued */
+ uint32_t buf_size; /* buffer size */
+ uint8_t buf[0]; /* payload: partial PES / video stream header etc. */
+};
+
+ts_state_t *ts_state_init(int buffer_size)
+{
+ if (buffer_size < 8 * TS_SIZE)
+ buffer_size = 8 * TS_SIZE;
+
+ ts_state_t *ts = (ts_state_t*)calloc(1, sizeof(ts_state_t) + buffer_size);
+ ts->buf_size = buffer_size;
+ return ts;
+}
+
+void ts_state_reset(ts_state_t *ts)
+{
+ int buf_size = ts->buf_size;
+ memset(ts, 0, sizeof(ts_state_t));
+ ts->buf_size = buf_size;
+}
+
+void ts_state_dispose(ts_state_t *ts)
+{
+ free(ts);
+}
+
+/*
+ * ts_add_payload()
+ *
+ * Add TS packet payload to buffer.
+ * - PUSI resets the buffer
+ * - all data before first PUSI is discarded
+ */
+static int ts_add_payload(ts_state_t *ts, const uint8_t *data)
+{
+ /* start from PUSI */
+ if (!ts->pusi_seen) {
+ if (!ts_PAYLOAD_START(data))
+ return 0;
+ ts->pusi_seen = 1;
+ ts->buf_len = 0;
+ }
+
+ if (ts->buf_len >= ts->buf_size - TS_SIZE) {
+ LOGMSG("ts_add_payload: buffer full");
+ ts->buf_len -= TS_SIZE;
+ memcpy(ts->buf, ts->buf+TS_SIZE, ts->buf_len);
+ }
+
+ int len = ts_PAYLOAD_SIZE(data);
+ if (len > 0) {
+ memcpy(ts->buf + ts->buf_len, ts_GET_PAYLOAD(data), len);
+ ts->buf_len += len;
+ }
+
+ return ts->buf_len;
+}
+
+/*
+ * ts_skip_payload()
+ */
+static void ts_skip_payload(ts_state_t *ts, unsigned int n)
+{
+ if (n < ts->buf_len) {
+ ts->buf_len -= n;
+ memcpy(ts->buf, ts->buf + n, ts->buf_len);
+ } else {
+ ts->buf_len = 0;
+ }
+}
+
+/*
+ * ts_scan_startcode()
+ *
+ * - discard all data until startcode (00 00 01) is found
+ * - returns number of bytes left
+ */
+static int ts_scan_startcode(ts_state_t *ts)
+{
+ if (ts->buf_len > 2) {
+ /* scan for PES or MPEG 00 00 01 */
+ unsigned int i = 0, n = ts->buf_len - 2;
+ while (i < n) {
+ if (ts->buf[i+2] != 1)
+ i += 3;
+ else if(ts->buf[i+1])
+ i += 2;
+ else if(ts->buf[i])
+ i++;
+ else
+ break;
+ }
+
+ /* skip data until start code */
+ ts_skip_payload(ts, i);
+ }
+
+ return ts->buf_len;
+}
+
+/*
+ * ts_get_pes()
+ *
+ * - scan for PES start
+ * - return (PES) bytes queued
+ */
+static int ts_get_pes(ts_state_t *ts, const uint8_t *data)
+{
+ if (ts_add_payload(ts, data) > 0)
+ return ts_scan_startcode(ts);
+ return 0;
+}
+
+/*
+ * ts_get_pts()
+ */
+
+int64_t ts_get_pts(ts_state_t *ts, const uint8_t *data)
+{
+ int64_t pts = INT64_C(-1);
+ int cnt = ts_get_pes(ts, data);
+
+ if (cnt > 14) {
+ pts = pes_get_pts(ts->buf, ts->buf_len);
+
+ if (pts < 0 && cnt > 2*TS_SIZE)
+ ts_state_reset(ts);
+ }
+
+ return pts;
+}
+
+/*
+ * ts_get_picture_type()
+ */
+
+int ts_get_picture_type(ts_state_t *ts, const uint8_t *data, int h264)
+{
+ int pic = NO_PICTURE;
+ return pic;
+}
+
+/*
+ * ts_get_video_size()
+ */
+
+int ts_get_video_size(ts_state_t *ts, const uint8_t *data, video_size_t *size, int h264)
+{
+ return 0;
+}