mpegts: optimize the data patch (join MPEG-TS packets for processing)
This commit is contained in:
parent
c4adde611f
commit
a698e088e8
11 changed files with 315 additions and 229 deletions
|
@ -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 );
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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 );
|
||||
|
||||
|
|
|
@ -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];
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -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
45
src/tvh_endian.h
Normal 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 */
|
|
@ -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); }
|
||||
|
||||
|
|
66
src/utils.c
66
src/utils.c
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue