descrambler: use buffer to make streaming of scrambled streams faster

This commit is contained in:
Jaroslav Kysela 2014-06-09 15:26:55 +02:00
parent 476d8b77b8
commit 5eb3255186
6 changed files with 79 additions and 34 deletions

View file

@ -133,7 +133,8 @@ int descrambler_descramble ( struct service *t,
struct elementary_stream *st,
const uint8_t *tsb );
int descrambler_open_pid ( struct mpegts_mux *mux, void *opaque, int pid,
descrambler_section_callback_t callback );
descrambler_section_callback_t callback,
struct service *service );
int descrambler_close_pid ( struct mpegts_mux *mux, void *opaque, int pid );
void descrambler_flush_tables ( struct mpegts_mux *mux );
void descrambler_cat_data ( struct mpegts_mux *mux, const uint8_t *data, int len );

View file

@ -72,17 +72,6 @@ typedef struct dmx_filter {
uint8_t mode[DMX_FILTER_SIZE];
} dmx_filter_t;
typedef struct dmx_sct_filter_params {
uint16_t pid;
dmx_filter_t filter;
uint32_t timeout;
uint32_t flags;
#define DMX_CHECK_CRC 1
#define DMX_ONESHOT 2
#define DMX_IMMEDIATE_START 4
#define DMX_KERNEL_CLIENT 0x8000
} dmx_filter_params_t;
#define CA_SET_DESCR 0x40106f86
#define CA_SET_DESCR_X 0x866f1040
#define CA_SET_PID 0x40086f87
@ -203,10 +192,16 @@ typedef struct capmt_service {
/**
**
*/
typedef struct capmt_dmx {
dmx_filter_t filter;
uint16_t pid;
uint32_t flags;
} capmt_dmx_t;
typedef struct capmt_filters {
int max;
int adapter;
dmx_filter_params_t dmx[MAX_FILTER];
capmt_dmx_t dmx[MAX_FILTER];
} capmt_filters_t;
typedef struct capmt_demuxes {
@ -348,7 +343,7 @@ capmt_poll_rem(capmt_t *capmt, int fd)
}
static void
capmt_pid_add(capmt_t *capmt, int adapter, int pid)
capmt_pid_add(capmt_t *capmt, int adapter, int pid, mpegts_service_t *s)
{
capmt_adapter_t *ca = &capmt->capmt_adapters[adapter];
capmt_opaque_t *o = NULL, *t;
@ -367,7 +362,9 @@ capmt_pid_add(capmt_t *capmt, int adapter, int pid)
o->adapter = adapter;
o->pid = pid;
mmi = LIST_FIRST(&capmt->capmt_adapters[adapter].ca_tuner->mi_mux_active);
descrambler_open_pid(mmi->mmi_mux, o, pid, capmt_table_input);
descrambler_open_pid(mmi->mmi_mux, o,
s ? DESCRAMBLER_ECM_PID(pid) : pid,
capmt_table_input, (service_t *)s);
}
}
@ -766,8 +763,7 @@ capmt_set_filter(capmt_t *capmt, int adapter, sbuf_t *sb, int offset)
uint8_t demux_index = sbuf_peek_u8 (sb, offset + 4);
uint8_t filter_index = sbuf_peek_u8 (sb, offset + 5);
uint16_t pid = sbuf_peek_u16(sb, offset + 6);
dmx_filter_params_t *filter;
dmx_filter_params_t *params = (dmx_filter_params_t *)sbuf_peek(sb, offset + 6);
capmt_dmx_t *filter;
capmt_filters_t *cf;
capmt_service_t *ct;
mpegts_service_t *t;
@ -788,11 +784,10 @@ capmt_set_filter(capmt_t *capmt, int adapter, sbuf_t *sb, int offset)
cf->adapter = adapter;
filter = &cf->dmx[filter_index];
filter->pid = pid;
capmt_pid_add(capmt, adapter, pid);
memcpy(&filter->filter, &params->filter, sizeof(params->filter));
filter->timeout = 0;
memcpy(&filter->filter, sbuf_peek(sb, offset + 10), sizeof(filter->filter));
filter->flags = 0;
/* ECM messages have the higher priority */
t = NULL;
LIST_FOREACH(ct, &capmt->capmt_services, ct_link) {
t = (mpegts_service_t *)ct->td_service;
pthread_mutex_lock(&t->s_stream_mutex);
@ -808,6 +803,7 @@ capmt_set_filter(capmt_t *capmt, int adapter, sbuf_t *sb, int offset)
pthread_mutex_unlock(&t->s_stream_mutex);
if (st) break;
}
capmt_pid_add(capmt, adapter, pid, t);
/* Update the max values */
if (capmt->capmt_demuxes.max <= demux_index)
capmt->capmt_demuxes.max = demux_index + 1;
@ -827,7 +823,7 @@ capmt_stop_filter(capmt_t *capmt, int adapter, sbuf_t *sb, int offset)
uint8_t demux_index = sbuf_peek_u8 (sb, offset + 4);
uint8_t filter_index = sbuf_peek_u8 (sb, offset + 5);
int16_t pid = sbuf_peek_s16le(sb, offset + 6);
dmx_filter_params_t *filter;
capmt_dmx_t *filter;
capmt_filters_t *cf;
tvhtrace("capmt", "stopping filter: adapter=%d, demux=%d, filter=%d, pid=%d",
@ -950,7 +946,7 @@ capmt_msg_size(capmt_t *capmt, sbuf_t *sb, int offset)
else if (cmd == CA_SET_DESCR)
return 4 + 16;
else if (oscam_new && cmd == DMX_SET_FILTER)
return 4 + 2 + sizeof(dmx_filter_params_t);
return 4 + 2 + 60;
else if (oscam_new && cmd == DMX_STOP)
return 4 + 4;
else {
@ -1320,6 +1316,8 @@ capmt_thread(void *aux)
pthread_mutex_unlock(&global_lock);
if (!capmt->capmt_running) continue;
/* open connection to camd.socket */
capmt_connect(capmt, 0);
@ -1379,8 +1377,7 @@ capmt_thread(void *aux)
if (capmt->capmt_adapters[i].ca_sock >= 0)
close(capmt->capmt_adapters[i].ca_sock);
if (!capmt->capmt_running)
break;
if (!capmt->capmt_running) continue;
/* schedule reconnection */
if(subscriptions_active() && !fatal) {

View file

@ -1983,7 +1983,7 @@ cwc_service_start(service_t *t)
descrambler_open_pid(ct->cs_mux, ct,
DESCRAMBLER_ECM_PID(ct->cs_estream->es_pid),
cwc_table_input);
cwc_table_input, t);
tvhlog(LOG_DEBUG, "cwc", "%s using CWC %s:%d",
service_nicename(t), cwc->cwc_hostname, cwc->cwc_port);

View file

@ -132,12 +132,15 @@ descrambler_done ( void )
void
descrambler_service_start ( service_t *t )
{
t->s_descramble_key = 0;
#if ENABLE_CWC
cwc_service_start(t);
#endif
#if ENABLE_CAPMT
capmt_service_start(t);
#endif
t->s_descramble_buf = calloc(1, sizeof(sbuf_t));
sbuf_init(t->s_descramble_buf);
}
void
@ -147,6 +150,10 @@ descrambler_service_stop ( service_t *t )
while ((td = LIST_FIRST(&t->s_descramblers)) != NULL)
td->td_stop(td);
if (t->s_descramble_buf) {
sbuf_free(t->s_descramble_buf);
t->s_descramble_buf = NULL;
}
}
void
@ -189,8 +196,9 @@ descrambler_descramble ( service_t *t,
const uint8_t *tsb )
{
th_descrambler_t *td;
int count, failed;
int count, failed, off, size;
count = failed = 0;
LIST_FOREACH(td, &t->s_descramblers, td_service_link) {
count++;
if (td->td_keystate == DS_FORBIDDEN) {
@ -199,12 +207,37 @@ descrambler_descramble ( service_t *t,
}
if (td->td_keystate != DS_RESOLVED)
continue;
if (t->s_descramble_buf) {
for (off = 0, size = t->s_descramble_buf->sb_ptr; off < size; off += 188)
tvhcsa_descramble(td->td_csa,
(mpegts_service_t *)td->td_service,
st, t->s_descramble_buf->sb_data + off);
sbuf_free(t->s_descramble_buf);
free(t->s_descramble_buf);
t->s_descramble_buf = NULL;
}
tvhcsa_descramble(td->td_csa,
(struct mpegts_service *)td->td_service,
(mpegts_service_t *)td->td_service,
st, tsb);
return 1;
}
return count == failed ? -1 : 0;
if (t->s_descramble_key && count != failed) {
/*
* Fill a temporary buffer until the keys are known to make
* streaming faster.
*/
if (t->s_descramble_buf == NULL) {
t->s_descramble_buf = calloc(1, sizeof(sbuf_t));
if (t->s_descramble_buf)
sbuf_init(t->s_descramble_buf);
}
if (t->s_descramble_buf) {
if (t->s_descramble_buf->sb_ptr >= 3000 * 188)
sbuf_cut(t->s_descramble_buf, 300 * 188);
sbuf_append(t->s_descramble_buf, tsb, 188);
}
}
return count && count == failed ? -1 : count;
}
static int
@ -227,6 +260,12 @@ descrambler_table_callback
ds->last_data_len = 0;
}
ds->callback(ds->opaque, mt->mt_pid, ptr, len);
if ((mt->mt_flags & MT_FAST) != 0) { /* ECM */
if (mt->mt_service) {
/* The keys are requested from this moment */
mt->mt_service->s_descramble_key |= 1;
}
}
}
pthread_mutex_unlock(&mt->mt_mux->mm_descrambler_lock);
return 0;
@ -234,7 +273,8 @@ descrambler_table_callback
static int
descrambler_open_pid_( mpegts_mux_t *mux, void *opaque, int pid,
descrambler_section_callback_t callback )
descrambler_section_callback_t callback,
service_t *service )
{
descrambler_table_t *dt;
descrambler_section_t *ds;
@ -257,6 +297,8 @@ descrambler_open_pid_( mpegts_mux_t *mux, void *opaque, int pid,
TAILQ_INIT(&dt->sections);
dt->table = mpegts_table_add(mux, 0, 0, descrambler_table_callback,
dt, "descrambler", MT_FULL | flags, pid);
if (dt->table)
dt->table->mt_service = (mpegts_service_t *)service;
TAILQ_INSERT_TAIL(&mux->mm_descrambler_tables, dt, link);
}
ds = calloc(1, sizeof(*ds));
@ -269,12 +311,13 @@ descrambler_open_pid_( mpegts_mux_t *mux, void *opaque, int pid,
int
descrambler_open_pid( mpegts_mux_t *mux, void *opaque, int pid,
descrambler_section_callback_t callback )
descrambler_section_callback_t callback,
service_t *service )
{
int res;
pthread_mutex_lock(&mux->mm_descrambler_lock);
res = descrambler_open_pid_(mux, opaque, pid, callback);
res = descrambler_open_pid_(mux, opaque, pid, callback, service);
pthread_mutex_unlock(&mux->mm_descrambler_lock);
return res;
}
@ -391,7 +434,7 @@ descrambler_cat_data( mpegts_mux_t *mux, const uint8_t *data, int len )
}
}
if (emm)
descrambler_open_pid_(mux, opaque, pid, callback);
descrambler_open_pid_(mux, opaque, pid, callback, NULL);
pthread_mutex_unlock(&mux->mm_descrambler_lock);
next:
data += dlen;
@ -456,7 +499,7 @@ descrambler_open_emm( mpegts_mux_t *mux, void *opaque, int caid,
tvhtrace("descrambler",
"attach emm caid %04X (%i) pid %04X (%i) - direct",
caid, caid, pid, pid);
descrambler_open_pid_(mux, opaque, pid, callback);
descrambler_open_pid_(mux, opaque, pid, callback, NULL);
}
pthread_mutex_unlock(&mux->mm_descrambler_lock);
return 1;

View file

@ -194,6 +194,8 @@ struct mpegts_table
mpegts_psi_section_t mt_sect;
struct mpegts_table_mux_cb *mt_mux_cb;
mpegts_service_t *mt_service;
void (*mt_destroy) (mpegts_table_t *mt); // Allow customisable destroy hook
// useful for dynamic allocation of

View file

@ -400,7 +400,9 @@ typedef struct service {
*/
struct th_descrambler_list s_descramblers;
int s_scrambled_seen;
uint16_t s_scrambled_seen;
uint16_t s_descramble_key;
sbuf_t *s_descramble_buf;
/**
* List of all and filtered components.