dvb psi reorganize - create parsing library

This commit is contained in:
Jaroslav Kysela 2015-03-23 10:30:49 +01:00
parent 30f5c44d2c
commit 6547bbe2e0
6 changed files with 395 additions and 364 deletions

View file

@ -225,13 +225,15 @@ SRCS += src/muxer.c \
# Optional code
#
# MPEGTS core
# MPEGTS core, order by usage (psi lib, tsdemux)
SRCS-$(CONFIG_MPEGTS) += \
src/descrambler/descrambler.c \
src/descrambler/caclient.c \
src/input/mpegts.c \
src/input/mpegts/mpegts_pid.c \
src/input/mpegts/mpegts_input.c \
src/input/mpegts/tsdemux.c \
src/input/mpegts/dvb_psi_lib.c \
src/input/mpegts/mpegts_network.c \
src/input/mpegts/mpegts_mux.c \
src/input/mpegts/mpegts_service.c \
@ -240,9 +242,8 @@ SRCS-$(CONFIG_MPEGTS) += \
src/input/mpegts/dvb_charset.c \
src/input/mpegts/dvb_psi.c \
src/input/mpegts/fastscan.c \
src/input/mpegts/tsdemux.c \
src/input/mpegts/mpegts_mux_sched.c \
src/input/mpegts/mpegts_network_scan.c \
src/input/mpegts/mpegts_network_scan.c
# MPEGTS DVB
SRCS-${CONFIG_MPEGTS_DVB} += \

View file

@ -32,7 +32,6 @@
#define MPEGTS_ONID_NONE 0xFFFF
#define MPEGTS_TSID_NONE 0xFFFF
#define MPEGTS_PSI_SECTION_SIZE 5000
#define MPEGTS_FULLMUX_PID 0x2000
#define MPEGTS_TABLES_PID 0x2001
#define MPEGTS_PID_NONE 0xFFFF
@ -119,9 +118,6 @@ struct mpegts_packet
typedef int (*mpegts_table_callback_t)
( mpegts_table_t*, const uint8_t *buf, int len, int tableid );
typedef void (*mpegts_psi_section_callback_t)
( const uint8_t *tsb, size_t len, void *opaque );
struct mpegts_table_mux_cb
{
int tag;
@ -129,13 +125,6 @@ struct mpegts_table_mux_cb
const uint8_t dtag, const uint8_t *dptr, int dlen );
};
struct mpegts_psi_section
{
int ps_offset;
int ps_lock;
uint8_t ps_data[MPEGTS_PSI_SECTION_SIZE];
};
typedef struct mpegts_table_state
{
int tableid;
@ -267,13 +256,6 @@ struct mpegts_table_feed {
uint8_t mtf_tsb[0];
};
/*
* Assemble SI section
*/
void mpegts_psi_section_reassemble
( mpegts_psi_section_t *ps, const uint8_t *tsb, int crc, int ccerr,
mpegts_psi_section_callback_t cb, void *opaque );
/* **************************************************************************
* Logical network
* *************************************************************************/
@ -963,6 +945,33 @@ void mpegts_table_destroy ( mpegts_table_t *mt );
void mpegts_table_consistency_check( mpegts_mux_t *mm );
void dvb_bat_destroy
(struct mpegts_table *mt);
int dvb_pat_callback
(struct mpegts_table *mt, const uint8_t *ptr, int len, int tableid);
int dvb_cat_callback
(struct mpegts_table *mt, const uint8_t *ptr, int len, int tableid);
int dvb_pmt_callback
(struct mpegts_table *mt, const uint8_t *ptr, int len, int tabelid);
int dvb_nit_callback
(struct mpegts_table *mt, const uint8_t *ptr, int len, int tableid);
int dvb_bat_callback
(struct mpegts_table *mt, const uint8_t *ptr, int len, int tableid);
int dvb_fs_sdt_callback
(struct mpegts_table *mt, const uint8_t *ptr, int len, int tableid);
int dvb_sdt_callback
(struct mpegts_table *mt, const uint8_t *ptr, int len, int tableid);
int dvb_tdt_callback
(struct mpegts_table *mt, const uint8_t *ptr, int len, int tableid);
int atsc_vct_callback
(struct mpegts_table *mt, const uint8_t *ptr, int len, int tableid);
void psi_tables_default ( struct mpegts_mux *mm );
void psi_tables_dvb ( struct mpegts_mux *mm );
void psi_tables_atsc_t ( struct mpegts_mux *mm );
void psi_tables_atsc_c ( struct mpegts_mux *mm );
mpegts_service_t *mpegts_service_create0
( mpegts_service_t *ms, const idclass_t *class, const char *uuid,
mpegts_mux_t *mm, uint16_t sid, uint16_t pmt_pid, htsmsg_t *conf );

View file

@ -199,6 +199,29 @@ do {\
DVB_LOOP_INIT(ptr, len, off, lptr, llen);\
DVB_DESC_EACH(lptr, llen, dtag, dlen, dptr)\
/*
* SI typedefs
*/
#define MPEGTS_PSI_SECTION_SIZE 5000
typedef struct mpegts_psi_section
{
int ps_offset;
int ps_lock;
uint8_t ps_data[MPEGTS_PSI_SECTION_SIZE];
} mpegts_psi_section_t;
typedef void (*mpegts_psi_section_callback_t)
( const uint8_t *tsb, size_t len, void *opaque );
/*
* Assemble SI section
*/
void mpegts_psi_section_reassemble
( mpegts_psi_section_t *ps, const uint8_t *tsb, int crc, int ccerr,
mpegts_psi_section_callback_t cb, void *opaque );
/* PSI table callbacks */
int dvb_table_end
@ -209,32 +232,6 @@ int dvb_table_begin
struct mpegts_table_state **st, int *sect, int *last, int *ver);
void dvb_table_reset
(struct mpegts_table *mt);
void dvb_bat_destroy
(struct mpegts_table *mt);
int dvb_pat_callback
(struct mpegts_table *mt, const uint8_t *ptr, int len, int tableid);
int dvb_cat_callback
(struct mpegts_table *mt, const uint8_t *ptr, int len, int tableid);
int dvb_pmt_callback
(struct mpegts_table *mt, const uint8_t *ptr, int len, int tabelid);
int dvb_nit_callback
(struct mpegts_table *mt, const uint8_t *ptr, int len, int tableid);
int dvb_bat_callback
(struct mpegts_table *mt, const uint8_t *ptr, int len, int tableid);
int dvb_fs_sdt_callback
(struct mpegts_table *mt, const uint8_t *ptr, int len, int tableid);
int dvb_sdt_callback
(struct mpegts_table *mt, const uint8_t *ptr, int len, int tableid);
int dvb_tdt_callback
(struct mpegts_table *mt, const uint8_t *ptr, int len, int tableid);
int atsc_vct_callback
(struct mpegts_table *mt, const uint8_t *ptr, int len, int tableid);
void psi_tables_default ( struct mpegts_mux *mm );
void psi_tables_dvb ( struct mpegts_mux *mm );
void psi_tables_atsc_t ( struct mpegts_mux *mm );
void psi_tables_atsc_c ( struct mpegts_mux *mm );
extern htsmsg_t *satellites;

View file

@ -1,6 +1,6 @@
/*
* MPEG TS Program Specific Information code
* Copyright (C) 2007 - 2010 Andreas <EFBFBD>man
* Copyright (C) 2007 - 2010 Andreas Öman
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -81,44 +81,11 @@ typedef struct dvb_bat {
LIST_HEAD(,dvb_bat_id) bats;
} dvb_bat_t;
SKEL_DECLARE(mpegts_table_state_skel, struct mpegts_table_state);
int dvb_bouquets_parse = 1;
static int
psi_parse_pmt(mpegts_mux_t *mux, mpegts_service_t *t, const uint8_t *ptr, int len);
/* **************************************************************************
* Lookup tables
* *************************************************************************/
static const int dvb_servicetype_map[][2] = {
{ 0x01, ST_SDTV }, /* SDTV (MPEG2) */
{ 0x02, ST_RADIO },
{ 0x11, ST_HDTV }, /* HDTV (MPEG2) */
{ 0x16, ST_SDTV }, /* Advanced codec SDTV */
{ 0x19, ST_HDTV }, /* Advanced codec HDTV */
{ 0x80, ST_SDTV }, /* NET POA - Cabo SDTV */
{ 0x91, ST_HDTV }, /* Bell TV HDTV */
{ 0x96, ST_SDTV }, /* Bell TV SDTV */
{ 0xA0, ST_HDTV }, /* Bell TV tiered HDTV */
{ 0xA4, ST_HDTV }, /* DN HDTV */
{ 0xA6, ST_HDTV }, /* Bell TV tiered HDTV */
{ 0xA8, ST_SDTV }, /* DN advanced SDTV */
{ 0xD3, ST_SDTV }, /* SKY TV SDTV */
};
int
dvb_servicetype_lookup ( int t )
{
int i;
for (i = 0; i < ARRAY_SIZE(dvb_servicetype_map); i++) {
if (dvb_servicetype_map[i][0] == t)
return dvb_servicetype_map[i][1];
}
return -1;
}
static inline int
mpegts_mux_alive(mpegts_mux_t *mm)
{
@ -871,199 +838,6 @@ dvb_bskyb_local_channels
#endif /* ENABLE_MPEGTS_DVB */
/* **************************************************************************
* Tables
* *************************************************************************/
static int sect_cmp
( struct mpegts_table_state *a, struct mpegts_table_state *b )
{
if (a->tableid != b->tableid)
return a->tableid - b->tableid;
if (a->extraid < b->extraid)
return -1;
if (a->extraid > b->extraid)
return 1;
return 0;
}
static void
mpegts_table_state_reset
( mpegts_table_t *mt, mpegts_table_state_t *st, int last )
{
int i;
mt->mt_finished = 0;
st->complete = 0;
st->version = 0xff; /* invalid */
memset(st->sections, 0, sizeof(st->sections));
for (i = 0; i < last / 32; i++)
st->sections[i] = 0xFFFFFFFF;
st->sections[last / 32] = 0xFFFFFFFF << (31 - (last % 32));
}
static struct mpegts_table_state *
mpegts_table_state_find
( mpegts_table_t *mt, int tableid, uint64_t extraid, int last )
{
struct mpegts_table_state *st;
/* Find state */
SKEL_ALLOC(mpegts_table_state_skel);
mpegts_table_state_skel->tableid = tableid;
mpegts_table_state_skel->extraid = extraid;
st = RB_INSERT_SORTED(&mt->mt_state, mpegts_table_state_skel, link, sect_cmp);
if (!st) {
st = mpegts_table_state_skel;
SKEL_USED(mpegts_table_state_skel);
mt->mt_incomplete++;
mpegts_table_state_reset(mt, st, last);
}
return st;
}
/*
* End table
*/
static int
dvb_table_complete
(mpegts_table_t *mt)
{
if (mt->mt_incomplete || !mt->mt_complete) {
int total = 0;
mpegts_table_state_t *st;
RB_FOREACH(st, &mt->mt_state, link)
total++;
tvhtrace(mt->mt_name, "incomplete %d complete %d total %d",
mt->mt_incomplete, mt->mt_complete, total);
return 2;
}
if (!mt->mt_finished)
tvhdebug(mt->mt_name, "completed pid %d table %08X / %08x", mt->mt_pid, mt->mt_table, mt->mt_mask);
mt->mt_finished = 1;
return 0;
}
int
dvb_table_end
(mpegts_table_t *mt, mpegts_table_state_t *st, int sect)
{
int sa, sb;
uint32_t rem;
if (st && !st->complete) {
assert(sect >= 0 && sect <= 255);
sa = sect / 32;
sb = sect % 32;
st->sections[sa] &= ~(0x1 << (31 - sb));
if (!st->sections[sa]) {
rem = 0;
for (sa = 0; sa < 8; sa++)
rem |= st->sections[sa];
if (rem) return 1;
tvhtrace(mt->mt_name, " tableid %02X extraid %016" PRIx64 " completed",
st->tableid, st->extraid);
st->complete = 1;
mt->mt_incomplete--;
return dvb_table_complete(mt);
}
} else if (st)
return dvb_table_complete(mt);
return 2;
}
/*
* Begin table
*/
int
dvb_table_begin
(mpegts_table_t *mt, const uint8_t *ptr, int len,
int tableid, uint64_t extraid, int minlen,
mpegts_table_state_t **ret, int *sect, int *last, int *ver)
{
mpegts_table_state_t *st;
uint32_t sa, sb;
/* Not long enough */
if (len < minlen) {
tvhdebug(mt->mt_name, "invalid table length %d min %d", len, minlen);
return -1;
}
/* Ignore next */
if((ptr[2] & 1) == 0)
return -1;
tvhtrace(mt->mt_name, "pid %02X tableid %02X extraid %016" PRIx64 " len %d",
mt->mt_pid, tableid, extraid, len);
/* Section info */
if (sect && ret) {
*sect = ptr[3];
*last = ptr[4];
*ver = (ptr[2] >> 1) & 0x1F;
*ret = st = mpegts_table_state_find(mt, tableid, extraid, *last);
tvhtrace(mt->mt_name, " section %d last %d ver %d (ver %d st %d incomp %d comp %d)",
*sect, *last, *ver, st->version, st->complete, mt->mt_incomplete, mt->mt_complete);
/* Ignore previous version */
/* This check is for the broken PMT tables where:
* last 0 version 21 = PCR + Audio PID 0x0044
* last 0 version 22 = Audio PID 0x0044, PCR + Video PID 0x0045
*/
if (*last == 0 && st->version - 1 == *ver)
return -1;
/* New version */
if (st->version != *ver) {
if (st->complete == 2)
mt->mt_complete--;
if (st->complete)
mt->mt_incomplete++;
tvhtrace(mt->mt_name, " new version, restart");
mpegts_table_state_reset(mt, st, *last);
st->version = *ver;
}
/* Complete? */
if (st->complete) {
tvhtrace(mt->mt_name, " skip, already complete (%i)", st->complete);
if (st->complete == 1) {
st->complete = 2;
mt->mt_complete++;
return dvb_table_complete(mt);
} else if (st->complete == 2) {
return dvb_table_complete(mt);
}
assert(0);
}
/* Already seen? */
sa = *sect / 32;
sb = *sect % 32;
if (!(st->sections[sa] & (0x1 << (31 - sb)))) {
tvhtrace(mt->mt_name, " skip, already seen");
return -1;
}
}
tvhlog_hexdump(mt->mt_name, ptr, len);
return 1;
}
void
dvb_table_reset(mpegts_table_t *mt)
{
mpegts_table_state_t *st;
tvhtrace(mt->mt_name, "pid %02X complete reset", mt->mt_pid);
mt->mt_incomplete = 0;
mt->mt_complete = 0;
while ((st = RB_FIRST(&mt->mt_state)) != NULL) {
RB_REMOVE(&mt->mt_state, st, link);
free(st);
}
}
/*
* PAT processing
*/

View file

@ -0,0 +1,340 @@
/*
* MPEG TS Program Specific Information Library code
* Copyright (C) 2007 - 2010 Andreas Öman
* Copyright (C) 2015 Jaroslav Kysela
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "tvheadend.h"
#include "input.h"
#include "dvb.h"
SKEL_DECLARE(mpegts_table_state_skel, struct mpegts_table_state);
/* **************************************************************************
* Lookup tables
* *************************************************************************/
static const int dvb_servicetype_map[][2] = {
{ 0x01, ST_SDTV }, /* SDTV (MPEG2) */
{ 0x02, ST_RADIO },
{ 0x11, ST_HDTV }, /* HDTV (MPEG2) */
{ 0x16, ST_SDTV }, /* Advanced codec SDTV */
{ 0x19, ST_HDTV }, /* Advanced codec HDTV */
{ 0x80, ST_SDTV }, /* NET POA - Cabo SDTV */
{ 0x91, ST_HDTV }, /* Bell TV HDTV */
{ 0x96, ST_SDTV }, /* Bell TV SDTV */
{ 0xA0, ST_HDTV }, /* Bell TV tiered HDTV */
{ 0xA4, ST_HDTV }, /* DN HDTV */
{ 0xA6, ST_HDTV }, /* Bell TV tiered HDTV */
{ 0xA8, ST_SDTV }, /* DN advanced SDTV */
{ 0xD3, ST_SDTV }, /* SKY TV SDTV */
};
int
dvb_servicetype_lookup ( int t )
{
int i;
for (i = 0; i < ARRAY_SIZE(dvb_servicetype_map); i++) {
if (dvb_servicetype_map[i][0] == t)
return dvb_servicetype_map[i][1];
}
return -1;
}
/* **************************************************************************
* Tables
* *************************************************************************/
/*
* Section assembly
*/
static int
mpegts_psi_section_reassemble0
( mpegts_psi_section_t *ps, const uint8_t *data,
int len, int start, int crc,
mpegts_psi_section_callback_t cb, void *opaque)
{
int excess, tsize;
if(start) {
// Payload unit start indicator
ps->ps_offset = 0;
ps->ps_lock = 1;
}
if(!ps->ps_lock)
return -1;
memcpy(ps->ps_data + ps->ps_offset, data, len);
ps->ps_offset += len;
if(ps->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]);
if(ps->ps_offset < tsize)
return len; // Not there yet
excess = ps->ps_offset - tsize;
if(crc && tvh_crc32(ps->ps_data, tsize, 0xffffffff))
return -1;
ps->ps_offset = 0;
if (cb)
cb(ps->ps_data, tsize - (crc ? 4 : 0), opaque);
return len - excess;
}
/**
*
*/
void
mpegts_psi_section_reassemble
(mpegts_psi_section_t *ps, const uint8_t *tsb, int crc, int ccerr,
mpegts_psi_section_callback_t cb, void *opaque)
{
int off = tsb[3] & 0x20 ? tsb[4] + 5 : 4;
int pusi = tsb[1] & 0x40;
int r;
if (ccerr)
ps->ps_lock = 0;
if(off >= 188) {
ps->ps_lock = 0;
return;
}
if(pusi) {
int len = tsb[off++];
if(len > 0) {
if(len > 188 - off) {
ps->ps_lock = 0;
return;
}
mpegts_psi_section_reassemble0(ps, tsb + off, len, 0, crc, cb, opaque);
off += len;
}
}
while(off < 188) {
r = mpegts_psi_section_reassemble0(ps, tsb + off, 188 - off, pusi, crc,
cb, opaque);
if(r < 0) {
ps->ps_lock = 0;
break;
}
off += r;
pusi = 0;
}
}
/*
*
*/
static int sect_cmp
( struct mpegts_table_state *a, struct mpegts_table_state *b )
{
if (a->tableid != b->tableid)
return a->tableid - b->tableid;
if (a->extraid < b->extraid)
return -1;
if (a->extraid > b->extraid)
return 1;
return 0;
}
static void
mpegts_table_state_reset
( mpegts_table_t *mt, mpegts_table_state_t *st, int last )
{
int i;
mt->mt_finished = 0;
st->complete = 0;
st->version = 0xff; /* invalid */
memset(st->sections, 0, sizeof(st->sections));
for (i = 0; i < last / 32; i++)
st->sections[i] = 0xFFFFFFFF;
st->sections[last / 32] = 0xFFFFFFFF << (31 - (last % 32));
}
static struct mpegts_table_state *
mpegts_table_state_find
( mpegts_table_t *mt, int tableid, uint64_t extraid, int last )
{
struct mpegts_table_state *st;
/* Find state */
SKEL_ALLOC(mpegts_table_state_skel);
mpegts_table_state_skel->tableid = tableid;
mpegts_table_state_skel->extraid = extraid;
st = RB_INSERT_SORTED(&mt->mt_state, mpegts_table_state_skel, link, sect_cmp);
if (!st) {
st = mpegts_table_state_skel;
SKEL_USED(mpegts_table_state_skel);
mt->mt_incomplete++;
mpegts_table_state_reset(mt, st, last);
}
return st;
}
/*
* End table
*/
static int
dvb_table_complete
(mpegts_table_t *mt)
{
if (mt->mt_incomplete || !mt->mt_complete) {
int total = 0;
mpegts_table_state_t *st;
RB_FOREACH(st, &mt->mt_state, link)
total++;
tvhtrace(mt->mt_name, "incomplete %d complete %d total %d",
mt->mt_incomplete, mt->mt_complete, total);
return 2;
}
if (!mt->mt_finished)
tvhdebug(mt->mt_name, "completed pid %d table %08X / %08x", mt->mt_pid, mt->mt_table, mt->mt_mask);
mt->mt_finished = 1;
return 0;
}
int
dvb_table_end
(mpegts_table_t *mt, mpegts_table_state_t *st, int sect)
{
int sa, sb;
uint32_t rem;
if (st && !st->complete) {
assert(sect >= 0 && sect <= 255);
sa = sect / 32;
sb = sect % 32;
st->sections[sa] &= ~(0x1 << (31 - sb));
if (!st->sections[sa]) {
rem = 0;
for (sa = 0; sa < 8; sa++)
rem |= st->sections[sa];
if (rem) return 1;
tvhtrace(mt->mt_name, " tableid %02X extraid %016" PRIx64 " completed",
st->tableid, st->extraid);
st->complete = 1;
mt->mt_incomplete--;
return dvb_table_complete(mt);
}
} else if (st)
return dvb_table_complete(mt);
return 2;
}
/*
* Begin table
*/
int
dvb_table_begin
(mpegts_table_t *mt, const uint8_t *ptr, int len,
int tableid, uint64_t extraid, int minlen,
mpegts_table_state_t **ret, int *sect, int *last, int *ver)
{
mpegts_table_state_t *st;
uint32_t sa, sb;
/* Not long enough */
if (len < minlen) {
tvhdebug(mt->mt_name, "invalid table length %d min %d", len, minlen);
return -1;
}
/* Ignore next */
if((ptr[2] & 1) == 0)
return -1;
tvhtrace(mt->mt_name, "pid %02X tableid %02X extraid %016" PRIx64 " len %d",
mt->mt_pid, tableid, extraid, len);
/* Section info */
if (sect && ret) {
*sect = ptr[3];
*last = ptr[4];
*ver = (ptr[2] >> 1) & 0x1F;
*ret = st = mpegts_table_state_find(mt, tableid, extraid, *last);
tvhtrace(mt->mt_name, " section %d last %d ver %d (ver %d st %d incomp %d comp %d)",
*sect, *last, *ver, st->version, st->complete, mt->mt_incomplete, mt->mt_complete);
/* Ignore previous version */
/* This check is for the broken PMT tables where:
* last 0 version 21 = PCR + Audio PID 0x0044
* last 0 version 22 = Audio PID 0x0044, PCR + Video PID 0x0045
*/
if (*last == 0 && st->version - 1 == *ver)
return -1;
/* New version */
if (st->version != *ver) {
if (st->complete == 2)
mt->mt_complete--;
if (st->complete)
mt->mt_incomplete++;
tvhtrace(mt->mt_name, " new version, restart");
mpegts_table_state_reset(mt, st, *last);
st->version = *ver;
}
/* Complete? */
if (st->complete) {
tvhtrace(mt->mt_name, " skip, already complete (%i)", st->complete);
if (st->complete == 1) {
st->complete = 2;
mt->mt_complete++;
return dvb_table_complete(mt);
} else if (st->complete == 2) {
return dvb_table_complete(mt);
}
assert(0);
}
/* Already seen? */
sa = *sect / 32;
sb = *sect % 32;
if (!(st->sections[sa] & (0x1 << (31 - sb)))) {
tvhtrace(mt->mt_name, " skip, already seen");
return -1;
}
}
tvhlog_hexdump(mt->mt_name, ptr, len);
return 1;
}
void
dvb_table_reset(mpegts_table_t *mt)
{
mpegts_table_state_t *st;
tvhtrace(mt->mt_name, "pid %02X complete reset", mt->mt_pid);
mt->mt_incomplete = 0;
mt->mt_complete = 0;
while ((st = RB_FIRST(&mt->mt_state)) != NULL) {
RB_REMOVE(&mt->mt_state, st, link);
free(st);
}
}

View file

@ -295,96 +295,6 @@ mpegts_table_flush_all ( mpegts_mux_t *mm )
pthread_mutex_unlock(&mm->mm_tables_lock);
}
/*
* Section assembly
*/
static int
mpegts_psi_section_reassemble0
( mpegts_psi_section_t *ps, const uint8_t *data,
int len, int start, int crc,
mpegts_psi_section_callback_t cb, void *opaque)
{
int excess, tsize;
if(start) {
// Payload unit start indicator
ps->ps_offset = 0;
ps->ps_lock = 1;
}
if(!ps->ps_lock)
return -1;
memcpy(ps->ps_data + ps->ps_offset, data, len);
ps->ps_offset += len;
if(ps->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]);
if(ps->ps_offset < tsize)
return len; // Not there yet
excess = ps->ps_offset - tsize;
if(crc && tvh_crc32(ps->ps_data, tsize, 0xffffffff))
return -1;
ps->ps_offset = 0;
if (cb)
cb(ps->ps_data, tsize - (crc ? 4 : 0), opaque);
return len - excess;
}
/**
*
*/
void
mpegts_psi_section_reassemble
(mpegts_psi_section_t *ps, const uint8_t *tsb, int crc, int ccerr,
mpegts_psi_section_callback_t cb, void *opaque)
{
int off = tsb[3] & 0x20 ? tsb[4] + 5 : 4;
int pusi = tsb[1] & 0x40;
int r;
if (ccerr)
ps->ps_lock = 0;
if(off >= 188) {
ps->ps_lock = 0;
return;
}
if(pusi) {
int len = tsb[off++];
if(len > 0) {
if(len > 188 - off) {
ps->ps_lock = 0;
return;
}
mpegts_psi_section_reassemble0(ps, tsb + off, len, 0, crc, cb, opaque);
off += len;
}
}
while(off < 188) {
r = mpegts_psi_section_reassemble0(ps, tsb + off, 188 - off, pusi, crc,
cb, opaque);
if(r < 0) {
ps->ps_lock = 0;
break;
}
off += r;
pusi = 0;
}
}
/******************************************************************************
* Editor Configuration