diff --git a/src/descrambler.h b/src/descrambler.h index 8ce3e98e..10552023 100644 --- a/src/descrambler.h +++ b/src/descrambler.h @@ -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 ); diff --git a/src/descrambler/descrambler.c b/src/descrambler/descrambler.c index 8918fd6b..737a6882 100644 --- a/src/descrambler/descrambler.c +++ b/src/descrambler/descrambler.c @@ -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 { diff --git a/src/descrambler/tvhcsa.c b/src/descrambler/tvhcsa.c index a10480f7..99ff46a0 100644 --- a/src/descrambler/tvhcsa.c +++ b/src/descrambler/tvhcsa.c @@ -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 } diff --git a/src/descrambler/tvhcsa.h b/src/descrambler/tvhcsa.h index 4a2b6146..46950ddc 100644 --- a/src/descrambler/tvhcsa.h +++ b/src/descrambler/tvhcsa.h @@ -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 ); diff --git a/src/input/mpegts.h b/src/input/mpegts.h index 8246d435..850d652b 100644 --- a/src/input/mpegts.h +++ b/src/input/mpegts.h @@ -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]; }; /* diff --git a/src/input/mpegts/mpegts_input.c b/src/input/mpegts/mpegts_input.c index 5b63864b..85a57fa4 100644 --- a/src/input/mpegts/mpegts_input.c +++ b/src/input/mpegts/mpegts_input.c @@ -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 */ diff --git a/src/input/mpegts/tsdemux.c b/src/input/mpegts/tsdemux.c index 2db7720f..a5c04610 100644 --- a/src/input/mpegts/tsdemux.c +++ b/src/input/mpegts/tsdemux.c @@ -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); } /* diff --git a/src/input/mpegts/tsdemux.h b/src/input/mpegts/tsdemux.h index 74d19eca..22296800 100644 --- a/src/input/mpegts/tsdemux.h +++ b/src/input/mpegts/tsdemux.h @@ -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 */ diff --git a/src/tvh_endian.h b/src/tvh_endian.h new file mode 100644 index 00000000..588bd8a8 --- /dev/null +++ b/src/tvh_endian.h @@ -0,0 +1,45 @@ +/* + * 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 . + */ + +#ifndef __TVH_ENDIAN_H +#define __TVH_ENDIAN_H + +#include +#if defined(PLATFORM_DARWIN) +#include +#elif defined(PLATFORM_FREEBSD) +#include +#else +#include +#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 */ diff --git a/src/tvheadend.h b/src/tvheadend.h index a4b04f4e..2a281fd9 100644 --- a/src/tvheadend.h +++ b/src/tvheadend.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); } diff --git a/src/utils.c b/src/utils.c index 92d309fc..845bfa4d 100644 --- a/src/utils.c +++ b/src/utils.c @@ -27,29 +27,7 @@ #include #include #include "tvheadend.h" - -#if defined(PLATFORM_DARWIN) -#include -#elif defined(PLATFORM_FREEBSD) -#include -#else -#include -#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; +}