diff options
author | phintuka <phintuka> | 2009-01-27 09:24:34 +0000 |
---|---|---|
committer | phintuka <phintuka> | 2009-01-27 09:24:34 +0000 |
commit | 907dfca143a4af28363fe614bc39c6b29d0d1040 (patch) | |
tree | 77cc288788cb05da54863be8a29a7f76d16b4bf1 | |
parent | 9acaea31f9360abe34a6e2d3393d427f4b6e79b4 (diff) | |
download | xineliboutput-907dfca143a4af28363fe614bc39c6b29d0d1040.tar.gz xineliboutput-907dfca143a4af28363fe614bc39c6b29d0d1040.tar.bz2 |
Initial import
-rw-r--r-- | tools/ts.c | 300 |
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; +} |