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 );
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;
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;
}
/* 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;
}
(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;
}
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);
}
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;
}
((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 {
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
{
#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);
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
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
int offset;
int n;
- pkt = csa->csa_tsbcluster + csa->csa_fill * 188;
- memcpy(pkt, tsb, 188);
- csa->csa_fill++;
-
- 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);
-
- if(csa->csa_fill != csa->csa_cluster_size)
- return;
-
- tvhcsa_des_flush(csa, s);
+ for ( ; tsb < tsb_end; tsb += 188) {
+
+ pkt = csa->csa_tsbcluster + csa->csa_fill * 188;
+ memcpy(pkt, tsb, 188);
+ csa->csa_fill++;
+
+ 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);
+
+ 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
}
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 );
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];
};
/*
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;
}
}
}
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)
/* 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);
}
}
#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
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;
/* 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];
/* Ignore NUL packets */
if (pid == 0x1FFF) {
#if ENABLE_TSDEBUG
- tsdebug_check_tspkt(mm, tsb);
+ tsdebug_check_tspkt(mm, tsb, llen);
#endif
goto done;
}
/* 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 */
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 */
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);
}
}
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;
}
/* 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
}
/* 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 */
#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;
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(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(st->es_type == SCT_TELETEXT)
- teletext_input(t, st, tsb);
+ off = tsb[3] & 0x20 ? tsb[4] + 5 : 4;
- if(off <= 188 && t->s_status == SERVICE_RUNNING)
- parse_mpeg_ts((service_t*)t, st, tsb + off, 188 - off, pusi, error);
+ 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);
+
+ }
}
/**
*/
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;
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)) {
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;
}
} else {
- ts_recv_packet0(t, st, tsb);
+ ts_recv_packet0(t, st, tsb, len);
}
pthread_mutex_unlock(&t->s_stream_mutex);
return 1;
* 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;
}
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);
*
*/
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;
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++;
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);
}
/*
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 */
--- /dev/null
+/*
+ * 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 */
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); }
#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
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;
+}