diff options
Diffstat (limited to 'tools/ts.c')
-rw-r--r-- | tools/ts.c | 682 |
1 files changed, 0 insertions, 682 deletions
diff --git a/tools/ts.c b/tools/ts.c deleted file mode 100644 index 0f6e2576..00000000 --- a/tools/ts.c +++ /dev/null @@ -1,682 +0,0 @@ -/* - * 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.14 2009-09-09 11:58:40 phintuka Exp $ - * - */ - -/*#define LOG_PCR*/ -/*#define LOG_PMT*/ - -#include <inttypes.h> -#include <stdlib.h> -#include <string.h> - -#ifndef LOG_MODULENAME -# define LOG_MODULENAME "[mpeg-ts ] " -# define SysLogLevel iSysLogLevel -# include "../logdefs.h" -#endif - -#include "mpeg.h" -#include "ts.h" -#include "pes.h" - -#ifdef LOG_PMT -# define LOGPMT LOGMSG -#else -# define LOGPMT(x...) -#endif - -#ifdef LOG_PCR -# define LOGPCR LOGMSG -#else -# define LOGPCR(x...) -#endif - - -/* - * ts_compute_crc32() - * - * taken from xine-lib demux_ts.c - */ -static uint32_t ts_compute_crc32(const 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, const uint8_t *pkt) -{ - const 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 - (int)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 - */ - - const 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; - - LOGPMT("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_get_reg_desc() - * - * Find the registration code (tag=5) and return it as a uint32_t - * This should return "AC-3" or 0x41432d33 for AC3/A52 audio tracks. - * - * taken from xine-lib demux_ts.c - */ -static void ts_get_reg_desc(uint32_t *dest, const uint8_t *data, int length) -{ - const unsigned char *d = data; - - while (d < (data + length)) { - if (d[0] == 5 && d[1] >= 4) { - *dest = (d[2] << 24) | (d[3] << 16) | (d[4] << 8) | d[5]; - LOGPMT("parse_pmt: found registration format identifier 0x%.4x", *dest); - return; - } - d += 2 + d[1]; - } - LOGPMT("pare_pmt: found no format id"); - *dest = 0; -} - -static int find_audio_track(pmt_data_t *pmt, uint pid) -{ - int i; - for (i = 0; i < pmt->audio_tracks_count; i++) { - if (pmt->audio_tracks[i].pid == pid) - return i; - } - return -1; -} - -/* - * ts_parse_pmt() - * - * modified from xine-lib demux_ts.c - */ -int ts_parse_pmt (pmt_data_t *pmt, uint program_no, const uint8_t *pkt) -{ - const uint8_t *originalPkt = pkt; - const uint8_t *ptr = NULL; - uint pusi = ts_PAYLOAD_START(pkt); - - uint32_t section_syntax_indicator; - uint32_t section_length = 0; /* to calm down gcc */ - uint32_t program_number; - uint32_t version_number; - uint32_t current_next_indicator; - uint32_t section_number; - uint32_t last_section_number; - uint32_t program_info_length; - uint32_t crc32; - uint32_t calc_crc32; - uint32_t coded_length; - uint pid; - uint8_t *stream; - uint i; - int count; - uint8_t len; - uint offset = 0; - - /* - * A new section should start with the payload unit start - * indicator set. We allocate some mem (max. allowed for a PM section) - * to copy the complete section into one chunk. - */ - if (pusi) { - pkt += pkt[4]; /* pointer */ - offset = 1; - - if (pmt->pmt != NULL) - free(pmt->pmt); - pmt->pmt = (uint8_t *) calloc(4096, sizeof(uint8_t)); - pmt->pmt_write_ptr = pmt->pmt; - - section_syntax_indicator = (pkt[6] >> 7) & 0x01; - section_length = ((pkt[6] << 8) | pkt[7]) & 0x03ff; - program_number = (pkt[8] << 8) | pkt[9]; - version_number = (pkt[10] >> 1) & 0x1f; - current_next_indicator = pkt[10] & 0x01; - section_number = pkt[11]; - last_section_number = pkt[12]; - - LOGPMT("PMT: section_syntax: %d", section_syntax_indicator); - LOGPMT(" section_length: %d", section_length); - LOGPMT(" program_number: %#.4x", program_number); - LOGPMT(" version_number: %d", version_number); - LOGPMT(" c/n indicator: %d", current_next_indicator); - LOGPMT(" section_number: %d", section_number); - LOGPMT(" last_section_number: %d", last_section_number); - - if ((section_syntax_indicator != 1) || !current_next_indicator) { - LOGMSG("parse_pmt: ssi error"); - return 0; - } - - if (program_number != program_no) { - /* several programs can share the same PMT pid */ - LOGMSG("parse_pmt: program number %i, looking for %i", program_number, program_no); - return 0; - } - - if ((section_number != 0) || (last_section_number != 0)) { - LOGMSG("parse_pmt: unsupported PMT (%d sections)", last_section_number); - return 0; - } - } - - if (!pusi) { - section_length = (pmt->pmt[1] << 8 | pmt->pmt[2]) & 0x03ff; - version_number = (pkt[10] >> 1) & 0x1f; - } - - count = ts_PAYLOAD_SIZE(originalPkt); - - ptr = originalPkt + offset + (TS_SIZE - count); - len = count - offset; - memcpy(pmt->pmt_write_ptr, ptr, len); - pmt->pmt_write_ptr += len; - - if (pmt->pmt_write_ptr < pmt->pmt + section_length) { - LOGPMT("parse_pmt: didn't get all PMT TS packets yet..."); - return 0; - } - - if (!section_length) { - free(pmt->pmt); - pmt->pmt = NULL; - LOGMSG("parse_pmt: zero-length section"); - return 0; - } - - LOGPMT("parse_pmt: have all TS packets for the PMT section"); - - crc32 = (uint32_t) pmt->pmt[section_length+3-4] << 24; - crc32 |= (uint32_t) pmt->pmt[section_length+3-3] << 16; - crc32 |= (uint32_t) pmt->pmt[section_length+3-2] << 8; - crc32 |= (uint32_t) pmt->pmt[section_length+3-1] ; - - /* Check CRC. */ - calc_crc32 = ts_compute_crc32 (pmt->pmt, section_length + 3 - 4, 0xffffffff); - if (crc32 != calc_crc32) { - LOGMSG("parse_pmt: invalid CRC32"); - return 0; - } - - if (crc32 == pmt->crc32 && version_number == pmt->version_number) { - LOGPMT("parse_pmt: PMT with CRC32=%d already parsed. Skipping.", crc32); - return 0; - } - - LOGPMT("parse_pmt: new PMT, parsing..."); - pmt->crc32 = crc32; - pmt->version_number = version_number; - - /* reset PIDs */ - pmt->audio_tracks_count = 0; - pmt->spu_tracks_count = 0; - pmt->video_pid = INVALID_PID; - - /* ES definitions start here */ - program_info_length = ((pmt->pmt[10] << 8) | pmt->pmt[11]) & 0x0fff; - - stream = &pmt->pmt[12] + program_info_length; - coded_length = 13 + program_info_length; - if (coded_length > section_length) { - LOGMSG("parse_pmt: PMT with inconsistent progInfo length"); - return 0; - } - section_length -= coded_length; - - - /* - * Extract the elementary streams. - */ - while (section_length > 0) { - unsigned int stream_info_length; - - pid = ((stream[1] << 8) | stream[2]) & 0x1fff; - stream_info_length = ((stream[3] << 8) | stream[4]) & 0x0fff; - coded_length = 5 + stream_info_length; - if (coded_length > section_length) { - LOGMSG("parse_pmt: PMT with inconsistent streamInfo length"); - return 0; - } - - switch (stream[0]) { - case ISO_11172_VIDEO: - case ISO_13818_VIDEO: - case ISO_14496_PART2_VIDEO: - case ISO_14496_PART10_VIDEO: - LOGPMT("parse_pmt: video pid 0x%.4x type %2.2x", pid, stream[0]); - if (pmt->video_pid == INVALID_PID) { - pmt->video_pid = pid; - pmt->video_type = (ts_stream_type)stream[0]; - } - break; - - case ISO_11172_AUDIO: - case ISO_13818_AUDIO: - case ISO_13818_PART7_AUDIO: - case ISO_14496_PART3_AUDIO: - if (pmt->audio_tracks_count < TS_MAX_AUDIO_TRACKS) { - if (find_audio_track(pmt, pid) < 0) { - LOGPMT("parse_pmt: audio pid 0x%.4x type %2.2x", pid, stream[0]); - pmt->audio_tracks[pmt->audio_tracks_count].pid = pid; - pmt->audio_tracks[pmt->audio_tracks_count].type = (ts_stream_type)stream[0]; - /* ts_get_lang_desc(pmt->audio_tracks[pmt->audio_tracks_count].lang, */ - /* stream + 5, stream_info_length); */ - pmt->audio_tracks_count++; - } - } - break; - - case ISO_13818_PRIVATE: - case ISO_13818_TYPE_C: - break; - case ISO_13818_PES_PRIVATE: - for (i = 5; i < coded_length; i += stream[i+1] + 2) { - if ((stream[i] == STREAM_DESCR_AC3) && (pmt->audio_tracks_count < TS_MAX_AUDIO_TRACKS)) { - if (find_audio_track(pmt, pid) < 0) { - LOGPMT("parse_pmt: AC3 audio pid 0x%.4x type %2.2x", pid, stream[0]); - pmt->audio_tracks[pmt->audio_tracks_count].pid = pid; - pmt->audio_tracks[pmt->audio_tracks_count].type = STREAM_AUDIO_AC3; - /* demux_ts_get_lang_desc(pmt->audio_tracks[pmt->audio_tracks_count].lang, */ - /* stream + 5, stream_info_length); */ - pmt->audio_tracks_count++; - break; - } - } - /* DVBSUB */ - else if (stream[i] == STREAM_DESCR_DVBSUB) { - uint pos; - for (pos = i + 2; - pos + 8 <= i + 2 + stream[i + 1] - && pmt->spu_tracks_count < TS_MAX_SPU_TRACKS; - pos += 8) { - int no = pmt->spu_tracks_count; - - pmt->spu_tracks_count++; - - memcpy(pmt->spu_tracks[no].lang, &stream[pos], 3); - pmt->spu_tracks[no].lang[3] = 0; - pmt->spu_tracks[no].comp_page_id = (stream[pos + 4] << 8) | stream[pos + 5]; - pmt->spu_tracks[no].aux_page_id = (stream[pos + 6] << 8) | stream[pos + 7]; - pmt->spu_tracks[no].pid = pid; - - LOGPMT("parse_pmt: DVBSUB pid 0x%.4x: %s page %d %d type %2.2x", pid, - pmt->spu_tracks[no].lang, pmt->spu_tracks[no].comp_page_id, - pmt->spu_tracks[no].aux_page_id, stream[0]); - } - } - } - break; - - default: - - /* This following section handles all the cases where the audio track info is stored - * in PMT user info with stream id >= 0x80 - * We first check that the stream id >= 0x80, because all values below that are - * invalid if not handled above, then we check the registration format identifier - * to see if it holds "AC-3" (0x41432d33) and if is does, we tag this as an audio stream. - */ - if ((pmt->audio_tracks_count < TS_MAX_AUDIO_TRACKS) && (stream[0] >= 0x80) ) { - if (find_audio_track(pmt, pid) < 0) { - uint32_t format_identifier = 0; - ts_get_reg_desc(&format_identifier, stream + 5, stream_info_length); - /* If no format identifier, assume A52 */ - if ((format_identifier == 0x41432d33) || (format_identifier == 0)) { - pmt->audio_tracks[pmt->audio_tracks_count].pid = pid; - pmt->audio_tracks[pmt->audio_tracks_count].type = (ts_stream_type)stream[0]; - /* ts_get_lang_desc(pmt->audio_tracks[pmt->audio_tracks_count].lang, */ - /* stream + 5, stream_info_length); */ - pmt->audio_tracks_count++; - break; - } - } - } else { - LOGPMT("parse_pmt: unknown stream_type: 0x%.2x pid: 0x%.4x", stream[0], pid); - } - break; - } - stream += coded_length; - section_length -= coded_length; - } - - - /* - * Get the current PCR PID. - */ - pid = ((pmt->pmt[8] << 8) | pmt->pmt[9]) & 0x1fff; - if (pmt->pcr_pid != pid) { - - if (pmt->pcr_pid == INVALID_PID) - LOGPMT("parse_pmt: pcr pid 0x%.4x", pid); - else - LOGPMT("parse_pmt: pcr pid changed 0x%.4x", pid); - - pmt->pcr_pid = pid; - } - - return 1; -} - -/* - * ts_get_pcr() - */ -static int ts_get_pcr_1(const uint8_t *pkt, int64_t *ppcr) -{ - if (!ts_ADAPT_FIELD_EXISTS(pkt)) { - return 0; - } - - if (ts_HAS_ERROR(pkt)) { - LOGMSG("ts_get_pcr: transport error"); - return 0; - } - - /* pcr flag ? */ - if (! (pkt[5] & 0x10)) - return 0; - - int64_t pcr; - uint epcr; - - pcr = ((int64_t) pkt[6]) << 25; - pcr += (int64_t) (pkt[7] << 17); - pcr += (int64_t) (pkt[8] << 9); - pcr += (int64_t) (pkt[9] << 1); - pcr += (int64_t) ((pkt[10] & 0x80) >> 7); - - epcr = ((pkt[10] & 0x1) << 8) | pkt[11]; - - LOGPCR("ts_get_pcr: PCR: %"PRId64", EPCR: %u", pcr, epcr); - *ppcr = pcr; - return 1; -} - -int64_t ts_get_pcr(const uint8_t *pkt) -{ - int64_t pcr = NO_PTS; - ts_get_pcr_1(pkt, &pcr); - return pcr; -} - -int ts_get_pcr_n(const uint8_t *pkt, int npkt, int64_t *pcr) -{ - pkt += TS_SIZE * npkt; - while (npkt > 0) { - npkt--; - pkt -= TS_SIZE; - if (ts_get_pcr_1(pkt, pcr)) - return 1; - } - return 0; -} - - -/* - * ts_state_t - */ - -struct ts_state_s { - - uint8_t pusi_seen; - - uint8_t inside_pes; /* Scanning ES (PES start code seen and skipped) */ - - 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 = NO_PTS; - 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; -} |