From d5c5f67bfea13201f9aad5a0c29ddf5df79c1c8d Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Tue, 24 Mar 2015 18:23:51 +0100 Subject: [PATCH] psi parser: more code reorganization, add parser/remux helpers for other layers --- src/epggrab/module/eit.c | 2 +- src/input/mpegts.h | 7 -- src/input/mpegts/dvb.h | 32 ++++++- src/input/mpegts/dvb_psi_lib.c | 162 +++++++++++++++++++++++++++----- src/input/mpegts/mpegts_input.c | 19 +--- src/input/mpegts/mpegts_table.c | 52 ++-------- 6 files changed, 184 insertions(+), 90 deletions(-) diff --git a/src/epggrab/module/eit.c b/src/epggrab/module/eit.c index 85e53142..ecf9c213 100644 --- a/src/epggrab/module/eit.c +++ b/src/epggrab/module/eit.c @@ -696,7 +696,7 @@ static int _eit_start /* Standard (0x12) */ } else { - pid = 0x12; + pid = DVB_EIT_PID; opts = MT_RECORD; } mpegts_table_add(dm, 0, 0, _eit_callback, map, m->id, MT_CRC | opts, pid); diff --git a/src/input/mpegts.h b/src/input/mpegts.h index 21726c85..18d8936e 100644 --- a/src/input/mpegts.h +++ b/src/input/mpegts.h @@ -188,7 +188,6 @@ struct mpegts_table TAILQ_ENTRY(mpegts_table) mt_defer_link; mpegts_mux_t *mt_mux; - void *mt_opaque; void *mt_bat; mpegts_table_callback_t mt_callback; @@ -207,12 +206,6 @@ struct mpegts_table int mt_destroyed; // Refcounting int mt_arefcount; - int8_t mt_cc; - - tvhlog_limit_t mt_err_log; - - mpegts_psi_section_t mt_sect; - struct mpegts_table_mux_cb *mt_mux_cb; mpegts_service_t *mt_service; diff --git a/src/input/mpegts/dvb.h b/src/input/mpegts/dvb.h index a30c76c4..69633a2f 100644 --- a/src/input/mpegts/dvb.h +++ b/src/input/mpegts/dvb.h @@ -37,6 +37,7 @@ struct mpegts_mux; #define DVB_NIT_PID 0x10 #define DVB_SDT_PID 0x11 #define DVB_BAT_PID 0x11 +#define DVB_EIT_PID 0x12 #define DVB_VCT_PID 0x1FFB /* Tables */ @@ -207,6 +208,8 @@ do {\ typedef struct mpegts_psi_section { + int8_t ps_cc; + int8_t ps_cco; int ps_offset; int ps_lock; uint8_t ps_data[MPEGTS_PSI_SECTION_SIZE]; @@ -232,6 +235,7 @@ typedef struct mpegts_psi_table RB_HEAD(,mpegts_psi_table_state) mt_state; char *mt_name; + void *mt_opaque; uint8_t mt_table; // SI table id (base) uint8_t mt_mask; // mask @@ -241,16 +245,21 @@ typedef struct mpegts_psi_table int mt_complete; int mt_incomplete; uint8_t mt_finished; + + mpegts_psi_section_t mt_sect; + + tvhlog_limit_t mt_err_log; + } mpegts_psi_table_t; /* * Assemble SI section */ void mpegts_psi_section_reassemble - ( mpegts_psi_section_t *ps, const uint8_t *tsb, int crc, int ccerr, + ( mpegts_psi_table_t *mt, const uint8_t *tsb, int crc, mpegts_psi_section_callback_t cb, void *opaque ); -/* PSI table callbacks */ +/* PSI table parser helpers */ int dvb_table_end (mpegts_psi_table_t *mt, mpegts_psi_table_state_t *st, int sect ); @@ -261,6 +270,25 @@ int dvb_table_begin void dvb_table_reset (mpegts_psi_table_t *mt); void dvb_table_release (mpegts_psi_table_t *mt); +/* all-in-one parser */ + +typedef void (*mpegts_psi_parse_callback_t) + ( mpegts_psi_table_t *, const uint8_t *buf, int len ); + +void dvb_table_parse_init + ( mpegts_psi_table_t *mt, const char *name, int pid, void *opaque ); + +void dvb_table_parse_done ( mpegts_psi_table_t *mt); + +void dvb_table_parse + (mpegts_psi_table_t *mt, const uint8_t *tsb, int len, + int crc, int full, mpegts_psi_parse_callback_t cb); + +int dvb_table_append_crc32(uint8_t *dst, int off, int maxlen); + +int dvb_table_remux + (mpegts_psi_table_t *mt, const uint8_t *buf, int len, uint8_t **out); + extern htsmsg_t *satellites; /* diff --git a/src/input/mpegts/dvb_psi_lib.c b/src/input/mpegts/dvb_psi_lib.c index b65232c0..fafcbe6c 100644 --- a/src/input/mpegts/dvb_psi_lib.c +++ b/src/input/mpegts/dvb_psi_lib.c @@ -63,42 +63,54 @@ dvb_servicetype_lookup ( int t ) */ static int mpegts_psi_section_reassemble0 - ( mpegts_psi_section_t *ps, const uint8_t *data, + ( mpegts_psi_table_t *mt, const uint8_t *data, int len, int start, int crc, mpegts_psi_section_callback_t cb, void *opaque) { + uint8_t *p = mt->mt_sect.ps_data; int excess, tsize; if(start) { // Payload unit start indicator - ps->ps_offset = 0; - ps->ps_lock = 1; + mt->mt_sect.ps_offset = 0; + mt->mt_sect.ps_lock = 1; } - if(!ps->ps_lock) + if(!mt->mt_sect.ps_lock) return -1; - memcpy(ps->ps_data + ps->ps_offset, data, len); - ps->ps_offset += len; + memcpy(p + mt->mt_sect.ps_offset, data, len); + mt->mt_sect.ps_offset += len; - if(ps->ps_offset < 3) { + if(mt->mt_sect.ps_offset < 3) { /* We don't know the total length yet */ return len; } - tsize = 3 + (((ps->ps_data[1] & 0xf) << 8) | ps->ps_data[2]); + tsize = 3 + (((p[1] & 0xf) << 8) | p[2]); - if(ps->ps_offset < tsize) + if(mt->mt_sect.ps_offset < tsize) return len; // Not there yet - excess = ps->ps_offset - tsize; + if(p[0] == 0x72) { /* stuffing section */ + dvb_table_reset(mt); + cb = NULL; + crc = 0; + } - if(crc && tvh_crc32(ps->ps_data, tsize, 0xffffffff)) + if(crc && tvh_crc32(p, tsize, 0xffffffff)) { + if (tvhlog_limit(&mt->mt_err_log, 10)) + tvhwarn(mt->mt_name, "invalid checksum (len %i, errors %zi)", + tsize, mt->mt_err_log.count); return -1; + } + + excess = mt->mt_sect.ps_offset - tsize; + mt->mt_sect.ps_offset = 0; - ps->ps_offset = 0; if (cb) - cb(ps->ps_data, tsize - (crc ? 4 : 0), opaque); + cb(p, tsize - (crc ? 4 : 0), opaque); + return len - excess; } @@ -107,18 +119,25 @@ mpegts_psi_section_reassemble0 */ void mpegts_psi_section_reassemble - (mpegts_psi_section_t *ps, const uint8_t *tsb, int crc, int ccerr, + (mpegts_psi_table_t *mt, const uint8_t *tsb, int crc, mpegts_psi_section_callback_t cb, void *opaque) { - int off = tsb[3] & 0x20 ? tsb[4] + 5 : 4; - int pusi = tsb[1] & 0x40; + int pusi = tsb[1] & 0x40; + uint8_t cc = tsb[3]; + int off = cc & 0x20 ? tsb[4] + 5 : 4; int r; - if (ccerr) - ps->ps_lock = 0; + if (cc & 0x10) { + if (mt->mt_sect.ps_cc != -1 && mt->mt_sect.ps_cc != (cc & 0x0f)) { + uint16_t pid = ((tsb[1] & 0x1f) << 8) | tsb[2]; + tvhdebug(mt->mt_name, "PID %04X CC error %d != %d", pid, cc & 0x0f, mt->mt_sect.ps_cc); + mt->mt_sect.ps_lock = 0; + } + mt->mt_sect.ps_cc = (cc + 1) & 0x0f; + } if(off >= 188) { - ps->ps_lock = 0; + mt->mt_sect.ps_lock = 0; return; } @@ -126,19 +145,19 @@ mpegts_psi_section_reassemble int len = tsb[off++]; if(len > 0) { if(len > 188 - off) { - ps->ps_lock = 0; + mt->mt_sect.ps_lock = 0; return; } - mpegts_psi_section_reassemble0(ps, tsb + off, len, 0, crc, cb, opaque); + mpegts_psi_section_reassemble0(mt, tsb + off, len, 0, crc, cb, opaque); off += len; } } while(off < 188) { - r = mpegts_psi_section_reassemble0(ps, tsb + off, 188 - off, pusi, crc, + r = mpegts_psi_section_reassemble0(mt, tsb + off, 188 - off, pusi, crc, cb, opaque); if(r < 0) { - ps->ps_lock = 0; + mt->mt_sect.ps_lock = 0; break; } off += r; @@ -349,3 +368,100 @@ dvb_table_release(mpegts_psi_table_t *mt) free(st); } } + +/* + * + */ + +void dvb_table_parse_init + ( mpegts_psi_table_t *mt, const char *name, int pid, void *opaque ) +{ + memset(mt, 0, sizeof(*mt)); + mt->mt_name = strdup(name); + mt->mt_opaque = opaque; + mt->mt_pid = pid; + mt->mt_sect.ps_cc = -1; +} + +void dvb_table_parse_done( mpegts_psi_table_t *mt ) +{ + free(mt->mt_name); +} + +struct psi_parse { + mpegts_psi_table_t *mt; + mpegts_psi_parse_callback_t cb; + int full; +}; + +static void +dvb_table_parse_cb( const uint8_t *sec, size_t len, void *opaque ) +{ + struct psi_parse *parse = opaque; + + parse->cb(parse->mt, sec + parse->full, len - parse->full); +} + +void dvb_table_parse + (mpegts_psi_table_t *mt, const uint8_t *tsb, int len, + int crc, int full, mpegts_psi_parse_callback_t cb) +{ + const uint8_t *end; + struct psi_parse parse; + + parse.mt = mt; + parse.cb = cb; + parse.full = full ? 3 : 0; + + for (end = tsb + len; tsb < end; tsb += 188) + mpegts_psi_section_reassemble(mt, tsb, crc, + dvb_table_parse_cb, &parse); +} + +int dvb_table_append_crc32(uint8_t *dst, int off, int maxlen) +{ + if (off + 4 > maxlen) + return -1; + + uint32_t crc = tvh_crc32(dst, off, 0xffffffff); + dst[off++] = crc >> 24; + dst[off++] = crc >> 16; + dst[off++] = crc >> 8; + dst[off++] = crc; + return off; +} + +int dvb_table_remux + (mpegts_psi_table_t *mt, const uint8_t *buf, int len, uint8_t **out) +{ + uint8_t *obuf, pusi; + int ol = 0, l, m; + + /* try to guess the output size here */ + obuf = malloc(((len + 183 + 1 /* pusi */) / 184) * 188); + + pusi = 0x40; + while (len > 0) { + obuf[ol++] = 0x47; + obuf[ol++] = pusi | ((mt->mt_pid >> 8) & 0x1f); + obuf[ol++] = mt->mt_pid & 0xff; + obuf[ol++] = 0x10 | ((mt->mt_sect.ps_cco++) & 0x0f); + if (pusi) { + obuf[ol++] = 0; + m = 183; + pusi = 0; + } else { + m = 184; + } + l = MIN(m, len); + memcpy(obuf + ol, buf, l); + if (l < m) + memset(obuf + ol + l, 0xff, m - l); + ol += m; + len -= l; + buf += l; + } + + *out = obuf; + return ol; +} diff --git a/src/input/mpegts/mpegts_input.c b/src/input/mpegts/mpegts_input.c index dcd781a3..a3b0ad06 100644 --- a/src/input/mpegts/mpegts_input.c +++ b/src/input/mpegts/mpegts_input.c @@ -951,21 +951,10 @@ mpegts_input_table_dispatch ( mpegts_mux_t *mm, const uint8_t *tsb, int tsb_len for (i = 0; i < len; i++) { mt = vec[i]; if (!mt->mt_destroyed && mt->mt_pid == pid) - for (tsb2 = tsb, tsb2_end = tsb + tsb_len; tsb2 < tsb2_end; tsb2 += 188) { - uint8_t cc = tsb2[3]; - if (cc & 0x10) { - int ccerr = 0; - if (mt->mt_cc != -1 && mt->mt_cc != (cc & 0xF)) { - ccerr = 1; - /* Ignore dupes (shouldn't have payload set, but some seem to) */ - //if (((mt->mt_cc + 15) & 0xf) != cc) - tvhdebug("psi", "PID %04X CC error %d != %d", pid, cc, mt->mt_cc); - } - mt->mt_cc = (cc + 1) & 0xF; - mpegts_psi_section_reassemble(&mt->mt_sect, tsb2, 0, ccerr, - mpegts_table_dispatch, mt); - } - } + for (tsb2 = tsb, tsb2_end = tsb + tsb_len; tsb2 < tsb2_end; tsb2 += 188) + mpegts_psi_section_reassemble((mpegts_psi_table_t *)mt, tsb2, + mt->mt_flags & MT_CRC, + mpegts_table_dispatch, mt); mpegts_table_release(mt); } } diff --git a/src/input/mpegts/mpegts_table.c b/src/input/mpegts/mpegts_table.c index 29715650..ed0e7f7d 100644 --- a/src/input/mpegts/mpegts_table.c +++ b/src/input/mpegts/mpegts_table.c @@ -72,49 +72,17 @@ mpegts_table_dispatch { int tid, len, ret; mpegts_table_t *mt = aux; - int chkcrc = mt->mt_flags & MT_CRC; if(mt->mt_destroyed) return; - /* Table info */ tid = sec[0]; len = ((sec[1] & 0x0f) << 8) | sec[2]; - if (tid == 0x72) { /* stuffing section */ - if (len != r - 3) { - if (tvhlog_limit(&mt->mt_err_log, 10)) - tvhwarn(mt->mt_name, "stuffing found with trailing data " - "(len %i, total %zi, errors %zi)", - len, r, mt->mt_err_log.count); - } - dvb_table_reset((mpegts_psi_table_t *)mt); - return; - } - - /* It seems some hardware (or is it the dvb API?) does not - honour the DMX_CHECK_CRC flag, so we check it again */ - if(chkcrc && tvh_crc32(sec, r, 0xffffffff)) { - if (tvhlog_limit(&mt->mt_err_log, 10)) - tvhwarn(mt->mt_name, "invalid checksum (len %zi, errors %zi)", - r, mt->mt_err_log.count); - return; - } - - /* Not enough data */ - if(len < r - 3) { - tvhtrace(mt->mt_name, "not enough data, %d < %d", (int)r, len); - return; - } - /* Check table mask */ if((tid & mt->mt_mask) != mt->mt_table) return; - /* Strip trailing CRC */ - if(chkcrc) - len -= 4; - /* Pass with tableid / len in data */ if (mt->mt_flags & MT_FULL) ret = mt->mt_callback(mt, sec, len+3, tid); @@ -236,16 +204,16 @@ mpegts_table_add /* Create */ mt = calloc(1, sizeof(mpegts_table_t)); - mt->mt_arefcount = 1; - mt->mt_name = strdup(name); - mt->mt_callback = callback; - mt->mt_opaque = opaque; - mt->mt_pid = pid; - mt->mt_flags = flags & ~(MT_SKIPSUBS|MT_SCANSUBS); - mt->mt_table = tableid; - mt->mt_mask = mask; - mt->mt_mux = mm; - mt->mt_cc = -1; + mt->mt_arefcount = 1; + mt->mt_name = strdup(name); + mt->mt_callback = callback; + mt->mt_opaque = opaque; + mt->mt_pid = pid; + mt->mt_flags = flags & ~(MT_SKIPSUBS|MT_SCANSUBS); + mt->mt_table = tableid; + mt->mt_mask = mask; + mt->mt_mux = mm; + mt->mt_sect.ps_cc = -1; /* Open table */ if (pid < 0) {