mpegts: optimize the data patch (join MPEG-TS packets for processing)

This commit is contained in:
Jaroslav Kysela 2015-03-16 21:46:11 +01:00
parent c4adde611f
commit a698e088e8
11 changed files with 315 additions and 229 deletions

View file

@ -167,7 +167,7 @@ void descrambler_keys ( th_descrambler_t *t, int type,
const uint8_t *even, const uint8_t *odd );
int descrambler_descramble ( struct service *t,
struct elementary_stream *st,
const uint8_t *tsb );
const uint8_t *tsb, int len );
int descrambler_open_pid ( struct mpegts_mux *mux, void *opaque, int pid,
descrambler_section_callback_t callback,
struct service *service );

View file

@ -367,18 +367,20 @@ ecm_reset( service_t *t, th_descrambler_runtime_t *dr )
int
descrambler_descramble ( service_t *t,
elementary_stream_t *st,
const uint8_t *tsb )
const uint8_t *tsb,
int len )
{
th_descrambler_t *td;
th_descrambler_runtime_t *dr = t->s_descramble;
int count, failed, resolved, off, size, flush_data = 0;
uint8_t *tsb2, ki;
int count, failed, resolved, off, len2, len3, flush_data = 0;
const uint8_t *tsb2;
uint8_t ki;
lock_assert(&t->s_stream_mutex);
if (dr == NULL) {
if ((tsb[3] & 0x80) == 0) {
ts_recv_packet2((mpegts_service_t *)t, tsb);
ts_recv_packet2((mpegts_service_t *)t, tsb, len);
return 1;
}
return -1;
@ -386,7 +388,7 @@ descrambler_descramble ( service_t *t,
if (dr->dr_csa.csa_type == DESCRAMBLER_NONE && dr->dr_buf.sb_ptr == 0)
if ((tsb[3] & 0x80) == 0) {
ts_recv_packet2((mpegts_service_t *)t, tsb);
ts_recv_packet2((mpegts_service_t *)t, tsb, len);
return 1;
}
@ -414,12 +416,11 @@ descrambler_descramble ( service_t *t,
/* process the queued TS packets */
if (dr->dr_buf.sb_ptr > 0) {
for (off = 0, size = dr->dr_buf.sb_ptr; off < size; off += 188) {
tsb2 = dr->dr_buf.sb_data + off;
for (tsb2 = tsb, len2 = dr->dr_buf.sb_ptr; len2 > 0; tsb2 += len3, len2 -= len3) {
ki = tsb2[3];
if ((ki & 0x80) != 0x00) {
if (key_valid(dr, ki) == 0) {
sbuf_cut(&dr->dr_buf, off);
sbuf_cut(&dr->dr_buf, tsb2 - tsb);
flush_data = 1;
goto next;
}
@ -429,8 +430,8 @@ descrambler_descramble ( service_t *t,
(ki & 0x40) ? "odd" : "even",
((mpegts_service_t *)t)->s_dvb_svcname);
if (key_late(dr, ki)) {
sbuf_cut(&dr->dr_buf, off);
if (ecm_reset(t, dr)) {
sbuf_cut(&dr->dr_buf, tsb2 - tsb);
flush_data = 1;
goto next;
}
@ -438,9 +439,10 @@ descrambler_descramble ( service_t *t,
key_update(dr, ki);
}
}
dr->dr_csa.csa_descramble(&dr->dr_csa, (mpegts_service_t *)t, tsb2);
len3 = mpegts_word_count(tsb2, len2, 0xFF0000C0);
dr->dr_csa.csa_descramble(&dr->dr_csa, (mpegts_service_t *)t, tsb2, len3);
}
if (off > 0)
if (len2 == 0)
service_reset_streaming_status_flags(t, TSS_NO_ACCESS);
sbuf_free(&dr->dr_buf);
}
@ -473,7 +475,7 @@ descrambler_descramble ( service_t *t,
key_update(dr, ki);
}
}
dr->dr_csa.csa_descramble(&dr->dr_csa, (mpegts_service_t *)t, tsb);
dr->dr_csa.csa_descramble(&dr->dr_csa, (mpegts_service_t *)t, tsb, len);
service_reset_streaming_status_flags(t, TSS_NO_ACCESS);
return 1;
}
@ -520,7 +522,7 @@ next:
((mpegts_service_t *)t)->s_dvb_svcname);
}
}
sbuf_append(&dr->dr_buf, tsb, 188);
sbuf_append(&dr->dr_buf, tsb, len);
service_set_streaming_status_flags(t, TSS_NO_ACCESS);
}
} else {

View file

@ -33,10 +33,13 @@ tvhcsa_aes_flush
static void
tvhcsa_aes_descramble
( tvhcsa_t *csa, struct mpegts_service *s, const uint8_t *tsb )
( tvhcsa_t *csa, struct mpegts_service *s, const uint8_t *tsb, int len )
{
aes_decrypt_packet(csa->csa_aes_keys, (unsigned char *)tsb);
ts_recv_packet2(s, tsb);
const uint8_t *tsb2, *end2;
for (tsb2 = tsb, end2 = tsb + len; tsb2 < end2; tsb2 += 188)
aes_decrypt_packet(csa->csa_aes_keys, (unsigned char *)tsb2);
ts_recv_packet2(s, tsb, len);
}
static void
@ -45,9 +48,6 @@ tvhcsa_des_flush
{
#if ENABLE_DVBCSA
int i;
const uint8_t *t0;
if(csa->csa_fill_even) {
csa->csa_tsbbatch_even[csa->csa_fill_even].data = NULL;
dvbcsa_bs_decrypt(csa->csa_key_even, csa->csa_tsbbatch_even, 184);
@ -59,45 +59,31 @@ tvhcsa_des_flush
csa->csa_fill_odd = 0;
}
t0 = csa->csa_tsbcluster;
ts_recv_packet2(s, csa->csa_tsbcluster, csa->csa_fill * 188);
for(i = 0; i < csa->csa_fill; i++) {
ts_recv_packet2(s, t0);
t0 += 188;
}
csa->csa_fill = 0;
#else
int r;
int r, l;
unsigned char *vec[3];
while(1) {
vec[0] = csa->csa_tsbcluster;
vec[1] = csa->csa_tsbcluster + csa->csa_fill * 188;
vec[2] = NULL;
vec[0] = csa->csa_tsbcluster;
vec[1] = csa->csa_tsbcluster + csa->csa_fill * 188;
vec[2] = NULL;
r = decrypt_packets(csa->csa_keys, vec);
if(r > 0) {
ts_recv_packet2(s, csa->csa_tsbcluster, r * 188);
r = decrypt_packets(csa->csa_keys, vec);
if(r > 0) {
int i;
const uint8_t *t0 = csa->csa_tsbcluster;
l = csa->csa_fill - r;
assert(l >= 0);
for(i = 0; i < r; i++) {
ts_recv_packet2(s, t0);
t0 += 188;
}
r = csa->csa_fill - r;
assert(r >= 0);
if(r > 0)
memmove(csa->csa_tsbcluster, t0, r * 188);
csa->csa_fill = r;
} else {
csa->csa_fill = 0;
}
break;
if(l > 0)
memmove(csa->csa_tsbcluster, csa->csa_tsbcluster + r * 188, l * 188);
csa->csa_fill = l;
} else {
csa->csa_fill = 0;
}
#endif
@ -105,8 +91,10 @@ tvhcsa_des_flush
static void
tvhcsa_des_descramble
( tvhcsa_t *csa, struct mpegts_service *s, const uint8_t *tsb )
( tvhcsa_t *csa, struct mpegts_service *s, const uint8_t *tsb, int tsb_len )
{
const uint8_t *tsb_end = tsb + tsb_len;
assert(csa->csa_fill >= 0 && csa->csa_fill < csa->csa_cluster_size);
#if ENABLE_DVBCSA
@ -117,61 +105,65 @@ tvhcsa_des_descramble
int offset;
int n;
pkt = csa->csa_tsbcluster + csa->csa_fill * 188;
memcpy(pkt, tsb, 188);
csa->csa_fill++;
for ( ; tsb < tsb_end; tsb += 188) {
do { // handle this packet
xc0 = pkt[3] & 0xc0;
if(xc0 == 0x00) { // clear
break;
}
if(xc0 == 0x40) { // reserved
break;
}
if(xc0 == 0x80 || xc0 == 0xc0) { // encrypted
ev_od = (xc0 & 0x40) >> 6; // 0 even, 1 odd
pkt[3] &= 0x3f; // consider it decrypted now
if(pkt[3] & 0x20) { // incomplete packet
offset = 4 + pkt[4] + 1;
len = 188 - offset;
n = len >> 3;
// FIXME: //residue = len - (n << 3);
if(n == 0) { // decrypted==encrypted!
break; // this doesn't need more processing
}
} else {
len = 184;
offset = 4;
// FIXME: //n = 23;
// FIXME: //residue = 0;
}
if(ev_od == 0) {
csa->csa_tsbbatch_even[csa->csa_fill_even].data = pkt + offset;
csa->csa_tsbbatch_even[csa->csa_fill_even].len = len;
csa->csa_fill_even++;
} else {
csa->csa_tsbbatch_odd[csa->csa_fill_odd].data = pkt + offset;
csa->csa_tsbbatch_odd[csa->csa_fill_odd].len = len;
csa->csa_fill_odd++;
}
}
} while(0);
pkt = csa->csa_tsbcluster + csa->csa_fill * 188;
memcpy(pkt, tsb, 188);
csa->csa_fill++;
if(csa->csa_fill != csa->csa_cluster_size)
return;
do { // handle this packet
xc0 = pkt[3] & 0xc0;
if(xc0 == 0x00) { // clear
break;
}
if(xc0 == 0x40) { // reserved
break;
}
if(xc0 == 0x80 || xc0 == 0xc0) { // encrypted
ev_od = (xc0 & 0x40) >> 6; // 0 even, 1 odd
pkt[3] &= 0x3f; // consider it decrypted now
if(pkt[3] & 0x20) { // incomplete packet
offset = 4 + pkt[4] + 1;
len = 188 - offset;
n = len >> 3;
// FIXME: //residue = len - (n << 3);
if(n == 0) { // decrypted==encrypted!
break; // this doesn't need more processing
}
} else {
len = 184;
offset = 4;
// FIXME: //n = 23;
// FIXME: //residue = 0;
}
if(ev_od == 0) {
csa->csa_tsbbatch_even[csa->csa_fill_even].data = pkt + offset;
csa->csa_tsbbatch_even[csa->csa_fill_even].len = len;
csa->csa_fill_even++;
} else {
csa->csa_tsbbatch_odd[csa->csa_fill_odd].data = pkt + offset;
csa->csa_tsbbatch_odd[csa->csa_fill_odd].len = len;
csa->csa_fill_odd++;
}
}
} while(0);
tvhcsa_des_flush(csa, s);
if(csa->csa_fill == csa->csa_cluster_size)
tvhcsa_des_flush(csa, s);
}
#else
memcpy(csa->csa_tsbcluster + csa->csa_fill * 188, tsb, 188);
csa->csa_fill++;
for ( ; tsb < tsb_end; tsb += 188 ) {
if(csa->csa_fill != csa->csa_cluster_size)
return;
memcpy(csa->csa_tsbcluster + csa->csa_fill * 188, tsb, 188);
csa->csa_fill++;
tvhcsa_des_flush(csa, s);
if(csa->csa_fill == csa->csa_cluster_size)
tvhcsa_des_flush(csa, s);
}
#endif
}

View file

@ -41,7 +41,8 @@ typedef struct tvhcsa
int csa_type; /*< see DESCRAMBLER_* defines */
int csa_keylen;
void (*csa_descramble)
( struct tvhcsa *csa, struct mpegts_service *s, const uint8_t *tsb );
( struct tvhcsa *csa, struct mpegts_service *s,
const uint8_t *tsb, int len );
void (*csa_flush)
( struct tvhcsa *csa, struct mpegts_service *s );

View file

@ -262,8 +262,9 @@ struct mpegts_table
struct mpegts_table_feed {
TAILQ_ENTRY(mpegts_table_feed) mtf_link;
uint8_t mtf_tsb[188];
int mtf_len;
mpegts_mux_t *mtf_mux;
uint8_t mtf_tsb[0];
};
/*

View file

@ -875,7 +875,7 @@ mpegts_input_recv_packets
for (tmp = tsb, end = tsb + p * 188; tmp < end; tmp += 188) {
uint16_t pid = ((tmp[1] & 0x1f) << 8) | tmp[2];
if (*pcr_pid == MPEGTS_PID_NONE || *pcr_pid == pid) {
ts_recv_packet1(NULL, tmp, pcr, 0);
ts_recv_packet1(NULL, tmp, 188, pcr, 0);
if (*pcr != PTS_UNSET) *pcr_pid = pid;
}
}
@ -911,20 +911,20 @@ mpegts_input_recv_packets
}
static void
mpegts_input_table_dispatch ( mpegts_mux_t *mm, const uint8_t *tsb )
mpegts_input_table_dispatch ( mpegts_mux_t *mm, const uint8_t *tsb, int tsb_len )
{
int i, len = 0, c = 0;
const uint8_t *tsb2, *tsb2_end;
uint16_t pid = ((tsb[1] & 0x1f) << 8) | tsb[2];
uint8_t cc = (tsb[3] & 0x0f);
mpegts_table_t *mt, **vec;
/* Collate - tables may be removed during callbacks */
pthread_mutex_lock(&mm->mm_tables_lock);
i = mm->mm_num_tables;
vec = alloca(i * sizeof(mpegts_table_t *));
pthread_mutex_lock(&mm->mm_tables_lock);
LIST_FOREACH(mt, &mm->mm_tables, mt_link) {
c++;
if (mt->mt_destroyed || !mt->mt_subscribed)
if (mt->mt_destroyed || !mt->mt_subscribed || mt->mt_pid != pid)
continue;
mpegts_table_grab(mt);
if (len < i)
@ -939,20 +939,22 @@ mpegts_input_table_dispatch ( mpegts_mux_t *mm, const uint8_t *tsb )
/* Process */
for (i = 0; i < len; i++) {
mt = vec[i];
if (!mt->mt_destroyed && mt->mt_pid == pid) {
if (tsb[3] & 0x10) {
int ccerr = 0;
if (mt->mt_cc != -1 && mt->mt_cc != cc) {
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, tsb, 0, ccerr,
mpegts_table_dispatch, mt);
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);
}
}
}
mpegts_table_release(mt);
}
}
@ -998,32 +1000,34 @@ mpegts_input_table_waiting ( mpegts_input_t *mi, mpegts_mux_t *mm )
#if ENABLE_TSDEBUG
static void
tsdebug_check_tspkt( mpegts_mux_t *mm, uint8_t *pkt )
tsdebug_check_tspkt( mpegts_mux_t *mm, uint8_t *pkt, int len )
{
void tsdebugcw_new_keys(service_t *t, int type, uint8_t *odd, uint8_t *even);
uint32_t pos, type, keylen, sid, crc;
mpegts_service_t *t;
if (memcmp(pkt + 4, "TVHeadendDescramblerKeys", 24))
return;
pos = 4 + 24;
type = pkt[pos + 0];
keylen = pkt[pos + 1];
sid = (pkt[pos + 2] << 8) | pkt[pos + 3];
pos += 4 + 2 * keylen;
if (pos > 184)
return;
crc = (pkt[pos + 0] << 24) | (pkt[pos + 1] << 16) |
(pkt[pos + 2] << 8) | pkt[pos + 3];
if (crc != tvh_crc32(pkt, pos, 0x859aa5ba))
return;
LIST_FOREACH(t, &mm->mm_services, s_dvb_mux_link)
if (t->s_dvb_service_id == sid) break;
if (!t)
return;
pos = 4 + 24 + 4;
tvhdebug("descrambler", "Keys from MPEG-TS source (PID 0x1FFF)!");
tsdebugcw_new_keys((service_t *)t, type, pkt + pos, pkt + pos + keylen);
for ( ; len > 0; pkt += 188, len -= 188) {
if (memcmp(pkt + 4, "TVHeadendDescramblerKeys", 24))
continue;
pos = 4 + 24;
type = pkt[pos + 0];
keylen = pkt[pos + 1];
sid = (pkt[pos + 2] << 8) | pkt[pos + 3];
pos += 4 + 2 * keylen;
if (pos > 184)
return;
crc = (pkt[pos + 0] << 24) | (pkt[pos + 1] << 16) |
(pkt[pos + 2] << 8) | pkt[pos + 3];
if (crc != tvh_crc32(pkt, pos, 0x859aa5ba))
return;
LIST_FOREACH(t, &mm->mm_services, s_dvb_mux_link)
if (t->s_dvb_service_id == sid) break;
if (!t)
return;
pos = 4 + 24 + 4;
tvhdebug("descrambler", "Keys from MPEG-TS source (PID 0x1FFF)!");
tsdebugcw_new_keys((service_t *)t, type, pkt + pos, pkt + pos + keylen);
}
}
#endif
@ -1034,14 +1038,13 @@ mpegts_input_process
uint16_t pid;
uint8_t cc;
uint8_t *tsb = mpkt->mp_data;
int len = mpkt->mp_len;
int len = mpkt->mp_len, llen;
int type = 0, f;
mpegts_pid_t *mp;
mpegts_pid_sub_t *mps;
service_t *s;
int table_wakeup = 0;
uint8_t *end = mpkt->mp_data + len;
mpegts_mux_t *mm = mpkt->mp_mux;
mpegts_mux_t *mm = mpkt->mp_mux;
mpegts_mux_instance_t *mmi;
#if ENABLE_TSDEBUG
off_t tsdebug_pos;
@ -1058,7 +1061,19 @@ mpegts_input_process
/* Process */
assert((len % 188) == 0);
while (tsb < end) {
while (len > 0) {
/*
* mask
* 0 - 0xFF - sync word 0x47
* 1 - 0x80 - transport error
* 1 - 0x1F - pid high
* 2 - 0xFF - pid low
* 3 - 0xC0 - scrambled
* 3 - 0x10 - CC check
*/
llen = mpegts_word_count(tsb, len, 0xFF9FFFD0);
pid = (tsb[1] << 8) | tsb[2];
cc = tsb[3];
@ -1073,7 +1088,7 @@ mpegts_input_process
/* Ignore NUL packets */
if (pid == 0x1FFF) {
#if ENABLE_TSDEBUG
tsdebug_check_tspkt(mm, tsb);
tsdebug_check_tspkt(mm, tsb, llen);
#endif
goto done;
}
@ -1096,12 +1111,12 @@ mpegts_input_process
/* Stream all PIDs */
LIST_FOREACH(mps, &mm->mm_all_subs, mps_svcraw_link)
if ((mps->mps_type & MPS_ALL) || (type & (MPS_TABLE|MPS_FTABLE)))
ts_recv_raw((mpegts_service_t *)mps->mps_owner, tsb);
ts_recv_raw((mpegts_service_t *)mps->mps_owner, tsb, llen);
/* Stream raw PIDs */
if (type & MPS_RAW) {
LIST_FOREACH(mps, &mp->mp_svc_subs, mps_svcraw_link)
ts_recv_raw((mpegts_service_t *)mps->mps_owner, tsb);
ts_recv_raw((mpegts_service_t *)mps->mps_owner, tsb, llen);
}
/* Stream service data */
@ -1110,7 +1125,7 @@ mpegts_input_process
s = mps->mps_owner;
f = (type & (MPS_TABLE|MPS_FTABLE)) ||
(pid == s->s_pmt_pid) || (pid == s->s_pcr_pid);
ts_recv_packet1((mpegts_service_t*)s, tsb, NULL, f);
ts_recv_packet1((mpegts_service_t*)s, tsb, llen, NULL, f);
}
} else
/* Stream table data */
@ -1119,7 +1134,7 @@ mpegts_input_process
if (s->s_type != STYPE_STD) continue;
f = (type & (MPS_TABLE|MPS_FTABLE)) ||
(pid == s->s_pmt_pid) || (pid == s->s_pcr_pid);
ts_recv_packet1((mpegts_service_t*)s, tsb, NULL, f);
ts_recv_packet1((mpegts_service_t*)s, tsb, llen, NULL, f);
}
}
@ -1127,14 +1142,12 @@ mpegts_input_process
if (type & (MPS_TABLE | MPS_FTABLE)) {
if (!(tsb[1] & 0x80)) {
if (type & MPS_FTABLE)
mpegts_input_table_dispatch(mm, tsb);
mpegts_input_table_dispatch(mm, tsb, llen);
if (type & MPS_TABLE) {
// TODO: might be able to optimise this a bit by having slightly
// larger buffering and trying to aggregate data (if we get
// same PID multiple times in the loop)
mpegts_table_feed_t *mtf = malloc(sizeof(mpegts_table_feed_t));
memcpy(mtf->mtf_tsb, tsb, 188);
mtf->mtf_mux = mm;
mpegts_table_feed_t *mtf = malloc(sizeof(mpegts_table_feed_t)+llen);
mtf->mtf_len = llen;
memcpy(mtf->mtf_tsb, tsb, llen);
mtf->mtf_mux = mm;
TAILQ_INSERT_TAIL(&mi->mi_table_queue, mtf, mtf_link);
table_wakeup = 1;
}
@ -1147,14 +1160,15 @@ mpegts_input_process
/* Stream to all fullmux subscribers */
LIST_FOREACH(mps, &mm->mm_all_subs, mps_svcraw_link)
ts_recv_raw((mpegts_service_t *)mps->mps_owner, tsb);
ts_recv_raw((mpegts_service_t *)mps->mps_owner, tsb, llen);
}
done:
tsb += 188;
tsb += llen;
len -= llen;
#if ENABLE_TSDEBUG
mm->mm_tsdebug_pos += 188;
mm->mm_tsdebug_pos += llen;
#endif
}
@ -1266,7 +1280,7 @@ mpegts_input_table_thread ( void *aux )
/* Process */
pthread_mutex_lock(&global_lock);
if (mtf->mtf_mux && mtf->mtf_mux->mm_active)
mpegts_input_table_dispatch(mtf->mtf_mux, mtf->mtf_tsb);
mpegts_input_table_dispatch(mtf->mtf_mux, mtf->mtf_tsb, mtf->mtf_len);
pthread_mutex_unlock(&global_lock);
/* Cleanup */

View file

@ -42,14 +42,14 @@
#define TS_REMUX_BUFSIZE (188 * 100)
static void ts_remux(mpegts_service_t *t, const uint8_t *tsb, int error);
static void ts_remux(mpegts_service_t *t, const uint8_t *tsb, int len, int error);
/**
* Continue processing of transport stream packets
*/
static void
ts_recv_packet0
(mpegts_service_t *t, elementary_stream_t *st, const uint8_t *tsb)
(mpegts_service_t *t, elementary_stream_t *st, const uint8_t *tsb, int len)
{
mpegts_service_t *m;
int off, pusi, cc, error;
@ -58,53 +58,58 @@ ts_recv_packet0
if (!st) {
if(streaming_pad_probe_type(&t->s_streaming_pad, SMT_MPEGTS))
ts_remux(t, tsb, 0);
ts_remux(t, tsb, len, 0);
return;
}
error = !!(tsb[1] & 0x80);
pusi = !!(tsb[1] & 0x40);
/* Check CC */
if(tsb[3] & 0x10) {
cc = tsb[3] & 0xf;
if(st->es_cc != -1 && cc != st->es_cc) {
/* Let the hardware to stabilize and don't flood the log */
if (t->s_start_time + 1 < dispatch_clock &&
tvhlog_limit(&st->es_cc_log, 10))
tvhwarn("TS", "%s Continuity counter error (total %zi)",
service_component_nicename(st), st->es_cc_log.count);
avgstat_add(&t->s_cc_errors, 1, dispatch_clock);
avgstat_add(&st->es_cc_errors, 1, dispatch_clock);
error |= 2;
}
st->es_cc = (cc + 1) & 0xf;
}
if(streaming_pad_probe_type(&t->s_streaming_pad, SMT_MPEGTS))
ts_remux(t, tsb, error);
ts_remux(t, tsb, len, error);
LIST_FOREACH(m, &t->s_masters, s_masters_link) {
pthread_mutex_lock(&m->s_stream_mutex);
if(streaming_pad_probe_type(&m->s_streaming_pad, SMT_MPEGTS))
ts_remux(m, tsb, error);
ts_remux(m, tsb, len, error);
pthread_mutex_unlock(&m->s_stream_mutex);
}
off = tsb[3] & 0x20 ? tsb[4] + 5 : 4;
for ( ; len > 0; tsb += 188, len -= 188) {
if (st->es_type == SCT_CA)
return;
pusi = !!(tsb[1] & 0x40);
if(!streaming_pad_probe_type(&t->s_streaming_pad, SMT_PACKET))
return;
/* Check CC */
if(st->es_type == SCT_TELETEXT)
teletext_input(t, st, tsb);
if(tsb[3] & 0x10) {
cc = tsb[3] & 0xf;
if(st->es_cc != -1 && cc != st->es_cc) {
/* Let the hardware to stabilize and don't flood the log */
if (t->s_start_time + 1 < dispatch_clock &&
tvhlog_limit(&st->es_cc_log, 10))
tvhwarn("TS", "%s Continuity counter error (total %zi)",
service_component_nicename(st), st->es_cc_log.count);
avgstat_add(&t->s_cc_errors, 1, dispatch_clock);
avgstat_add(&st->es_cc_errors, 1, dispatch_clock);
error |= 2;
}
st->es_cc = (cc + 1) & 0xf;
}
if(off <= 188 && t->s_status == SERVICE_RUNNING)
parse_mpeg_ts((service_t*)t, st, tsb + off, 188 - off, pusi, error);
off = tsb[3] & 0x20 ? tsb[4] + 5 : 4;
if (st->es_type == SCT_CA)
continue;
if(!streaming_pad_probe_type(&t->s_streaming_pad, SMT_PACKET))
continue;
if(st->es_type == SCT_TELETEXT)
teletext_input(t, st, tsb);
if(off <= 188 && t->s_status == SERVICE_RUNNING)
parse_mpeg_ts((service_t*)t, st, tsb + off, 188 - off, pusi, error);
}
}
/**
@ -112,7 +117,7 @@ ts_recv_packet0
*/
int
ts_recv_packet1
(mpegts_service_t *t, const uint8_t *tsb, int64_t *pcrp, int table)
(mpegts_service_t *t, const uint8_t *tsb, int len, int64_t *pcrp, int table)
{
elementary_stream_t *st;
int pid, r;
@ -168,7 +173,7 @@ ts_recv_packet1
if(!error)
service_set_streaming_status_flags((service_t*)t, TSS_INPUT_SERVICE);
avgstat_add(&t->s_rate, 188, dispatch_clock);
avgstat_add(&t->s_rate, len, dispatch_clock);
if((tsb[3] & 0xc0) ||
(t->s_scrambled_seen && st && st->es_type != SCT_CA)) {
@ -180,7 +185,7 @@ ts_recv_packet1
t->s_scrambled_seen |= service_is_encrypted((service_t*)t);
/* scrambled stream */
r = descrambler_descramble((service_t *)t, st, tsb);
r = descrambler_descramble((service_t *)t, st, tsb, len);
if(r > 0) {
pthread_mutex_unlock(&t->s_stream_mutex);
return 1;
@ -195,7 +200,7 @@ ts_recv_packet1
}
} else {
ts_recv_packet0(t, st, tsb);
ts_recv_packet0(t, st, tsb, len);
}
pthread_mutex_unlock(&t->s_stream_mutex);
return 1;
@ -206,20 +211,24 @@ ts_recv_packet1
* Process transport stream packets, simple version
*/
void
ts_recv_packet2(mpegts_service_t *t, const uint8_t *tsb)
ts_recv_packet2(mpegts_service_t *t, const uint8_t *tsb, int len)
{
elementary_stream_t *st;
int pid = (tsb[1] & 0x1f) << 8 | tsb[2];
int pid, len2;
if((st = service_stream_find((service_t*)t, pid)) != NULL)
ts_recv_packet0(t, st, tsb);
for ( ; len > 0; tsb += len2, len -= len2 ) {
len2 = mpegts_word_count(tsb, len, 0xFF9FFFD0);
pid = (tsb[1] & 0x1f) << 8 | tsb[2];
if((st = service_stream_find((service_t*)t, pid)) != NULL)
ts_recv_packet0(t, st, tsb, len2);
}
}
/*
*
*/
void
ts_recv_raw(mpegts_service_t *t, const uint8_t *tsb)
ts_recv_raw(mpegts_service_t *t, const uint8_t *tsb, int len)
{
int pid, parent = 0;
@ -236,7 +245,7 @@ ts_recv_raw(mpegts_service_t *t, const uint8_t *tsb)
}
if(!parent) {
if (streaming_pad_probe_type(&t->s_streaming_pad, SMT_MPEGTS))
ts_remux(t, tsb, 0);
ts_remux(t, tsb, len, 0);
else {
/* No subscriber - set OK markers */
service_set_streaming_status_flags((service_t*)t, TSS_PACKETS);
@ -250,7 +259,7 @@ ts_recv_raw(mpegts_service_t *t, const uint8_t *tsb)
*
*/
static void
ts_remux(mpegts_service_t *t, const uint8_t *src, int error)
ts_remux(mpegts_service_t *t, const uint8_t *src, int len, int error)
{
streaming_message_t sm;
pktbuf_t *pb;
@ -259,7 +268,7 @@ ts_remux(mpegts_service_t *t, const uint8_t *src, int error)
if (sb->sb_data == NULL)
sbuf_init_fixed(sb, TS_REMUX_BUFSIZE);
sbuf_append(sb, src, 188);
sbuf_append(sb, src, len);
if (error)
sb->sb_err++;
@ -279,7 +288,7 @@ ts_remux(mpegts_service_t *t, const uint8_t *src, int error)
service_set_streaming_status_flags((service_t*)t, TSS_PACKETS);
t->s_streaming_live |= TSS_LIVE;
sbuf_reset(sb, TS_REMUX_BUFSIZE);
sbuf_reset(sb, 2*TS_REMUX_BUFSIZE);
}
/*

View file

@ -22,10 +22,10 @@
int ts_resync ( const uint8_t *tsb, int *len, int *idx );
int ts_recv_packet1
(struct mpegts_service *t, const uint8_t *tsb, int64_t *pcrp, int table);
(struct mpegts_service *t, const uint8_t *tsb, int len, int64_t *pcrp, int table);
void ts_recv_packet2(struct mpegts_service *t, const uint8_t *tsb);
void ts_recv_packet2(struct mpegts_service *t, const uint8_t *tsb, int len);
void ts_recv_raw(struct mpegts_service *t, const uint8_t *tsb);
void ts_recv_raw(struct mpegts_service *t, const uint8_t *tsb, int len);
#endif /* TSDEMUX_H */

45
src/tvh_endian.h Normal file
View file

@ -0,0 +1,45 @@
/*
* Copyright (c) 2015 Jaroslav Kysela <perex@perex.cz>
*
* 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/>.
*/
#ifndef __TVH_ENDIAN_H
#define __TVH_ENDIAN_H
#include <byteswap.h>
#if defined(PLATFORM_DARWIN)
#include <machine/endian.h>
#elif defined(PLATFORM_FREEBSD)
#include <sys/endian.h>
#else
#include <endian.h>
#endif
#ifndef BYTE_ORDER
#define BYTE_ORDER __BYTE_ORDER
#endif
#ifndef LITTLE_ENDIAN
#define LITTLE_ENDIAN __LITTLE_ENDIAN
#endif
#ifndef BIG_ENDIAN
#define BIG_ENDIAN __BIG_ENDIAN
#endif
#if BYTE_ORDER == LITTLE_ENDIAN
#define ENDIAN_SWAP_COND(x) (!(x))
#else
#define ENDIAN_SWAP_COND(x) (x)
#endif
#endif /* __TVH_ENDIAN_H */

View file

@ -716,6 +716,8 @@ char *regexp_escape ( const char *str );
char to_hex(char code);
char *url_encode(char *str);
int mpegts_word_count(const uint8_t *tsb, int len, uint32_t mask);
static inline int32_t deltaI32(int32_t a, int32_t b) { return (a > b) ? (a - b) : (b - a); }
static inline uint32_t deltaU32(uint32_t a, uint32_t b) { return (a > b) ? (a - b) : (b - a); }

View file

@ -27,29 +27,7 @@
#include <unistd.h>
#include <ctype.h>
#include "tvheadend.h"
#if defined(PLATFORM_DARWIN)
#include <machine/endian.h>
#elif defined(PLATFORM_FREEBSD)
#include <sys/endian.h>
#else
#include <endian.h>
#endif
#ifndef BYTE_ORDER
#define BYTE_ORDER __BYTE_ORDER
#endif
#ifndef LITTLE_ENDIAN
#define LITTLE_ENDIAN __LITTLE_ENDIAN
#endif
#ifndef BIG_ENDIAN
#define BIG_ENDIAN __BIG_ENDIAN
#endif
#if BYTE_ORDER == LITTLE_ENDIAN
#define ENDIAN_SWAP_COND(x) (!(x))
#else
#define ENDIAN_SWAP_COND(x) (x)
#endif
#include "tvh_endian.h"
/**
* CRC32
@ -615,3 +593,45 @@ char *url_encode(char *str) {
return buf;
}
/*
*
*/
static inline uint32_t mpegts_word32( const uint8_t *tsb )
{
//assert(((intptr_t)tsb & 3) == 0);
return *(uint32_t *)tsb;
}
int
mpegts_word_count ( const uint8_t *tsb, int len, uint32_t mask )
{
uint32_t val;
int r = 0;
#if BYTE_ORDER == LITTLE_ENDIAN
mask = bswap_32(mask);
#endif
val = mpegts_word32(tsb) & mask;
while (len >= 188) {
if (len >= 4*188 &&
(mpegts_word32(tsb+0*188) & mask) == val &&
(mpegts_word32(tsb+1*188) & mask) == val &&
(mpegts_word32(tsb+2*188) & mask) == val &&
(mpegts_word32(tsb+3*188) & mask) == val) {
r += 4*188;
len -= 4*188;
tsb += 4*188;
} else if ((mpegts_word32(tsb) & mask) == val) {
r += 188;
len -= 188;
tsb += 188;
} else {
break;
}
}
return r;
}