linuxdvb: updated tuning/pid filtering code

All services/tables should now be opened using PES filters if the
tuner is not in full mux mode.
This commit is contained in:
Adam Sutton 2013-06-01 23:03:17 +01:00
parent ead0b1b5ff
commit f26ee05092
4 changed files with 268 additions and 66 deletions

View file

@ -77,6 +77,8 @@ const idclass_t linuxdvb_frontend_class =
PT_STR, linuxdvb_frontend_t, lfe_dmx_path, 1) },
{ PROPDEF2("number", "FE Number",
PT_INT, linuxdvb_frontend_t, lfe_number, 1) },
{ PROPDEF1("fullmux", "Full Mux Mode",
PT_BOOL, linuxdvb_frontend_t, lfe_fullmux) },
{}
}
};
@ -169,15 +171,24 @@ static void
linuxdvb_frontend_stop_mux
( mpegts_input_t *mi, mpegts_mux_instance_t *mmi )
{
char buf1[256], buf2[256];
linuxdvb_frontend_t *lfe = (linuxdvb_frontend_t*)mi;
mi->mi_display_name(mi, buf1, sizeof(buf1));
mmi->mmi_mux->mm_display_name(mmi->mmi_mux, buf2, sizeof(buf2));
tvhdebug("linuxdvb", "%s - stopping %s", buf1, buf2);
/* Stop thread */
if (lfe->lfe_dvr_pipe.wr > 0) {
tvh_write(lfe->lfe_dvr_pipe.wr, "", 1);
tvhtrace("linuxdvb", "%s - waiting for dvr thread", buf1);
pthread_join(lfe->lfe_dvr_thread, NULL);
tvh_pipe_close(&lfe->lfe_dvr_pipe);
tvhlog(LOG_DEBUG, "linuxdvb", "stopped dvr thread");
tvhdebug("linuxdvb", "%s - stopped dvr thread", buf1);
}
/* Not locked */
lfe->lfe_locked = 0;
}
static int
@ -185,9 +196,13 @@ linuxdvb_frontend_start_mux
( mpegts_input_t *mi, mpegts_mux_instance_t *mmi )
{
int r;
char buf1[256], buf2[256];
linuxdvb_frontend_t *lfe = (linuxdvb_frontend_t*)mi;
mpegts_mux_instance_t *cur = LIST_FIRST(&mi->mi_mux_active);
tvhtrace("mpegts", "linuxdvb_frontend_start_mux(%p, %p)", mi, mmi);
mi->mi_display_name(mi, buf1, sizeof(buf1));
mmi->mmi_mux->mm_display_name(mmi->mmi_mux, buf2, sizeof(buf2));
tvhdebug("linuxdvb", "%s - starting %s", buf1, buf2);
// Not sure if this is right place?
/* Currently active */
@ -204,6 +219,7 @@ linuxdvb_frontend_start_mux
/* Open FE */
if (lfe->lfe_fe_fd <= 0) {
tvhtrace("linuxdvb", "%s - opening FE %s", buf1, lfe->lfe_fe_path);
lfe->lfe_fe_fd = tvh_open(lfe->lfe_fe_path, O_RDWR | O_NONBLOCK, 0);
if (lfe->lfe_fe_fd <= 0) {
return SM_CODE_TUNING_FAILED;
@ -211,12 +227,12 @@ linuxdvb_frontend_start_mux
}
/* Tune */
tvhtrace("linuxdvb", "%s - tuning", buf1);
r = linuxdvb_frontend_tune(lfe, (linuxdvb_mux_t*)mmi->mmi_mux);
/* Failed */
if (r != 0) {
tvhlog(LOG_ERR, "linuxdvb", "'%s' failed to tune '%s' error %s",
lfe->lfe_fe_path, "TODO", strerror(errno));
tvherror("linuxdvb", "%s - failed to tune [e=%s]", buf1, strerror(errno));
if (errno == EINVAL)
mmi->mmi_tune_failed = 1;
return SM_CODE_TUNING_FAILED;
@ -227,27 +243,205 @@ linuxdvb_frontend_start_mux
lfe->lfe_monitor += 4;
gtimer_arm_ms(&lfe->lfe_monitor_timer, linuxdvb_frontend_monitor, lfe, 50);
/* Send alert */
// TODO: should this be moved elsewhere?
return r;
}
static int
linuxdvb_frontend_open_pid
( linuxdvb_frontend_t *lfe, int pid, const char *name )
{
char buf[256];
struct dmx_pes_filter_params dmx_param;
int fd = tvh_open(lfe->lfe_dmx_path, O_RDWR, 0);
if (!name) {
lfe->mi_display_name((mpegts_input_t*)lfe, buf, sizeof(buf));
name = buf;
}
if(fd == -1) {
tvherror("linuxdvb", "%s - failed to open dmx for pid %d [e=%s]",
name, pid, strerror(errno));
return -1;
}
memset(&dmx_param, 0, sizeof(dmx_param));
dmx_param.pid = pid;
dmx_param.input = DMX_IN_FRONTEND;
dmx_param.output = DMX_OUT_TS_TAP;
dmx_param.pes_type = DMX_PES_OTHER;
dmx_param.flags = DMX_IMMEDIATE_START;
if(ioctl(fd, DMX_SET_PES_FILTER, &dmx_param)) {
tvherror("linuxdvb", "%s - failed to config dmx for pid %d [e=%s]",
name, pid, strerror(errno));
close(fd);
return -1;
}
return fd;
}
static void
linuxdvb_frontend_open_service
( mpegts_input_t *mi, mpegts_service_t *ms )
( mpegts_input_t *mi, mpegts_service_t *s )
{
char buf[256];
elementary_stream_t *st;
linuxdvb_frontend_t *lfe = (linuxdvb_frontend_t*)mi;
/* Ignore in full rx mode OR if not yet locked */
if (lfe->lfe_fullmux || !lfe->lfe_locked)
return;
mi->mi_display_name(mi, buf, sizeof(buf));
/* Install PES filters */
TAILQ_FOREACH(st, &s->s_components, es_link) {
if(st->es_pid >= 0x2000)
continue;
if(st->es_demuxer_fd != -1)
continue;
st->es_cc_valid = 0;
st->es_demuxer_fd
= linuxdvb_frontend_open_pid((linuxdvb_frontend_t*)mi, st->es_pid, buf);
}
}
static void
linuxdvb_frontend_close_service
( mpegts_input_t *mi, mpegts_service_t *ms )
( mpegts_input_t *mi, mpegts_service_t *s )
{
linuxdvb_frontend_t *lfe = (linuxdvb_frontend_t*)mi;
/* Ignore in full rx mode OR if not yet locked */
if (lfe->lfe_fullmux || !lfe->lfe_locked)
return;
}
/* **************************************************************************
* Data processing
* *************************************************************************/
static void
linuxdvb_frontend_default_tables
( linuxdvb_frontend_t *lfe, linuxdvb_mux_t *lm )
{
mpegts_mux_t *mm = (mpegts_mux_t*)lfe;
/* Common */
mpegts_table_add(mm, DVB_PAT_BASE, DVB_PAT_MASK, dvb_pat_callback,
NULL, "pat", MT_QUICKREQ | MT_CRC, DVB_PAT_PID);
#if 0
mpegts_table_add(mm, DVB_CAT_BASE, DVB_CAT_MASK, dvb_cat_callback,
NULL, "cat", MT_CRC, DVB_CAT_PID);
#endif
/* ATSC */
if (lfe->lfe_info.type == FE_ATSC) {
#if 0
int tableid;
if (lc->lm_tuning.dmc_fe_params.u.vsb.modulation == VSB_8)
tableid = ATSC_VCT_TERR;
else
tableid = ATSC_VCT_CAB;
mpegts_table_add(mm, tableid, 0xff, atsc_vct_callback,
NULL, "vct", MT_QUICKREQ | MT_CRC, ATSC_VCT_PID);
#endif
/* DVB */
} else {
mpegts_table_add(mm, DVB_NIT_BASE, DVB_NIT_MASK, dvb_nit_callback,
NULL, "nit", MT_QUICKREQ | MT_CRC, DVB_NIT_PID);
mpegts_table_add(mm, DVB_SDT_BASE, DVB_SDT_MASK, dvb_sdt_callback,
NULL, "sdt", MT_QUICKREQ | MT_CRC, DVB_SDT_PID);
mpegts_table_add(mm, DVB_BAT_BASE, DVB_BAT_MASK, dvb_bat_callback,
NULL, "bat", MT_CRC, DVB_BAT_PID);
#if 0
mpegts_table_add(mm, DVB_TOT_BASE, DVB_TOT_MASK, dvb_tot_callback,
NULL, "tot", MT_CRC, DVB_TOT_PID);
#endif
}
}
static void
linuxdvb_frontend_open_services ( linuxdvb_frontend_t *lfe )
{
service_t *s;
LIST_FOREACH(s, &lfe->mi_transports, s_active_link)
linuxdvb_frontend_open_service((mpegts_input_t*)lfe,
(mpegts_service_t*)s);
}
static void
linuxdvb_frontend_monitor_stats ( linuxdvb_frontend_t *lfe )
{
}
static void
linuxdvb_frontend_monitor ( void *aux )
{
linuxdvb_frontend_t *lfe = aux;
mpegts_mux_instance_t *mmi = LIST_FIRST(&lfe->mi_mux_active);
mpegts_mux_t *mm;
fe_status_t fe_status;
signal_state_t status;
// TODO: check the frontend is accessible
if (!mmi) return;
mm = mmi->mmi_mux;
/* Get current status */
if (!ioctl(lfe->lfe_fe_fd, FE_READ_STATUS, &fe_status))
status = SIGNAL_UNKNOWN;
else if (fe_status & FE_HAS_LOCK)
status = SIGNAL_GOOD;
else if (fe_status & (FE_HAS_SYNC | FE_HAS_VITERBI | FE_HAS_CARRIER))
status = SIGNAL_BAD;
else if (fe_status & FE_HAS_SIGNAL)
status = SIGNAL_FAINT;
else
status = SIGNAL_NONE;
/* Set default period */
gtimer_arm(&lfe->lfe_monitor_timer, linuxdvb_frontend_monitor, lfe, 1);
/* Waiting for lock */
if (lfe->lfe_locked) {
/* Locked */
if (status == SIGNAL_GOOD) {
lfe->lfe_locked = 1;
/* Start input */
tvh_pipe(O_NONBLOCK, &lfe->lfe_dvr_pipe);
pthread_create(&lfe->lfe_dvr_thread, NULL,
linuxdvb_frontend_input_thread, lfe);
/* Table handlers */
linuxdvb_frontend_default_tables(lfe, (linuxdvb_mux_t*)mm);
/* Services */
linuxdvb_frontend_open_services(lfe);
/* Re-arm (quick) */
} else {
gtimer_arm_ms(&lfe->lfe_monitor_timer, linuxdvb_frontend_monitor,
lfe, 50);
/* Monitor 1 per sec */
if (dispatch_clock < lfe->lfe_monitor)
return;
lfe->lfe_monitor = dispatch_clock + 1;
}
}
/* Monitor stats */
linuxdvb_frontend_monitor_stats(lfe);
}
static void *
linuxdvb_frontend_input_thread ( void *aux )
{
@ -260,32 +454,35 @@ linuxdvb_frontend_input_thread ( void *aux )
ssize_t c;
struct epoll_event ev;
struct dmx_pes_filter_params dmx_param;
int fullmux;
/* Get MMI */
pthread_mutex_lock(&global_lock);
lfe->mi_display_name((mpegts_input_t*)lfe, buf, sizeof(buf));
mmi = LIST_FIRST(&lfe->mi_mux_active);
fullmux = lfe->lfe_fullmux;
pthread_mutex_unlock(&global_lock);
if (mmi == NULL) return NULL;
/* Open DMX */
dmx = tvh_open(lfe->lfe_dmx_path, O_RDWR, 0);
if (dmx < 0) {
tvherror("linuxdvb", "%s - failed to open %s", buf, lfe->lfe_dmx_path);
return NULL;
}
memset(&dmx_param, 0, sizeof(dmx_param));
dmx_param.pid = 0x2000;
dmx_param.input = DMX_IN_FRONTEND;
dmx_param.output = DMX_OUT_TS_TAP;
dmx_param.pes_type = DMX_PES_OTHER;
dmx_param.flags = DMX_IMMEDIATE_START;
if(ioctl(dmx, DMX_SET_PES_FILTER, &dmx_param) == -1) {
tvhlog(LOG_ERR, "dvb",
"Unable to configure demuxer \"%s\" for all PIDs -- %s",
lfe->lfe_dmx_path, strerror(errno));
close(dmx);
return NULL;
if (fullmux) {
dmx = tvh_open(lfe->lfe_dmx_path, O_RDWR, 0);
if (dmx < 0) {
tvherror("linuxdvb", "%s - failed to open %s", buf, lfe->lfe_dmx_path);
return NULL;
}
memset(&dmx_param, 0, sizeof(dmx_param));
dmx_param.pid = 0x2000;
dmx_param.input = DMX_IN_FRONTEND;
dmx_param.output = DMX_OUT_TS_TAP;
dmx_param.pes_type = DMX_PES_OTHER;
dmx_param.flags = DMX_IMMEDIATE_START;
if(ioctl(dmx, DMX_SET_PES_FILTER, &dmx_param) == -1) {
tvherror("linuxdvb", "%s - open raw filter failed [e=%s]",
buf, strerror(errno));
close(dmx);
return NULL;
}
}
/* Open DVR */
@ -331,48 +528,14 @@ linuxdvb_frontend_input_thread ( void *aux )
NULL, NULL, buf);
}
close(dmx);
if (dmx != -1) close(dmx);
close(dvr);
return NULL;
}
static void
linuxdvb_frontend_monitor ( void *aux )
{
linuxdvb_frontend_t *lfe = aux;
mpegts_mux_instance_t *mmi = LIST_FIRST(&lfe->mi_mux_active);
mpegts_mux_t *mm;
if (!mmi) return;
mm = mmi->mmi_mux;
fe_status_t fe_status;
if (!ioctl(lfe->lfe_fe_fd, FE_READ_STATUS, &fe_status))
tvhtrace("mpegts", "fe_status = %02X", fe_status);
else
tvhtrace("mpegts", "fe_status = unknown");
if (fe_status & FE_HAS_LOCK) {
// Note: the lock
// Open pending services
tvh_pipe(O_NONBLOCK, &lfe->lfe_dvr_pipe);
pthread_create(&lfe->lfe_dvr_thread, NULL, linuxdvb_frontend_input_thread, lfe);
// TODO: these tables need to vary based on type
mpegts_table_add(mm, DVB_PAT_BASE, DVB_PAT_MASK, dvb_pat_callback,
NULL, "pat", MT_QUICKREQ | MT_CRC, DVB_PAT_PID);
mpegts_table_add(mm, DVB_SDT_BASE, DVB_SDT_MASK, dvb_sdt_callback,
NULL, "sdt", MT_QUICKREQ | MT_CRC, DVB_SDT_PID);
mpegts_table_add(mm, DVB_NIT_BASE, DVB_NIT_MASK, dvb_nit_callback,
NULL, "nit", MT_QUICKREQ | MT_CRC, DVB_NIT_PID);
mpegts_table_add(mm, DVB_BAT_BASE, DVB_BAT_MASK, dvb_bat_callback,
NULL, "bat", MT_CRC, DVB_BAT_PID);
} else {
gtimer_arm_ms(&lfe->lfe_monitor_timer, linuxdvb_frontend_monitor, lfe, 1000);
}
}
/* **************************************************************************
* Tuning
* *************************************************************************/
static int
linuxdvb_frontend_tune
@ -504,6 +667,7 @@ linuxdvb_frontend_create0
lfe->mi_stop_mux = linuxdvb_frontend_stop_mux;
lfe->mi_open_service = linuxdvb_frontend_open_service;
lfe->mi_close_service = linuxdvb_frontend_close_service;
lfe->lfe_open_pid = linuxdvb_frontend_open_pid;
/* Adapter link */
lfe->lh_parent = (linuxdvb_hardware_t*)la;

View file

@ -133,17 +133,38 @@ linuxdvb_mux_create_instances ( mpegts_mux_t *mm )
}
}
#if 0
static void
linuxdvb_mux_open_table ( mpegts_mux_t *mm, mpegts_table_t *mt )
{
char buf[256];
linuxdvb_frontend_t *lfe;
if (mt->mt_pid >= 0x2000)
return;
mm->mm_display_name(mm, buf, sizeof(buf));
if (!mm->mm_table_filter[mt->mt_pid])
tvhtrace("mpegts", "%s - opened table %s pid %04X (%d)",
buf, mt->mt_name, mt->mt_pid, mt->mt_pid);
mm->mm_table_filter[mt->mt_pid] = 1;
/* Open DMX */
if (mm->mm_active) {
lfe = (linuxdvb_frontend_t*)mm->mm_active->mmi_input;
mt->mt_fd = lfe->lfe_open_pid(lfe, mt->mt_pid, NULL);
}
}
static void
linuxdvb_mux_close_table ( mpegts_mux_t *mm, mpegts_table_t *mt )
{
char buf[256];
if (mt->mt_pid >= 0x2000)
return;
mm->mm_display_name(mm, buf, sizeof(buf));
tvhtrace("mpegts", "%s - closed table %s pid %04X (%d)",
buf, mt->mt_name, mt->mt_pid, mt->mt_pid);
mm->mm_table_filter[mt->mt_pid] = 0;
close(mt->mt_fd);
}
#endif
/* **************************************************************************
* Creation/Config
@ -203,6 +224,8 @@ linuxdvb_mux_create0
lm->mm_display_name = linuxdvb_mux_display_name;
lm->mm_config_save = linuxdvb_mux_config_save;
lm->mm_create_instances = linuxdvb_mux_create_instances;
lm->mm_open_table = linuxdvb_mux_open_table;
lm->mm_close_table = linuxdvb_mux_close_table;
/* No config */
if (!conf) return lm;

View file

@ -135,15 +135,21 @@ struct linuxdvb_frontend
* Reception
*/
int lfe_fe_fd;
int lfe_dvr_fd;
pthread_t lfe_dvr_thread;
th_pipe_t lfe_dvr_pipe;
/*
* Tuning
*/
int lfe_locked;
time_t lfe_monitor;
gtimer_t lfe_monitor_timer;
int (*lfe_open_pid) (linuxdvb_frontend_t *lfe, int pid, const char *name);
/*
* Configuration
*/
int lfe_fullmux;
};
linuxdvb_frontend_t *

View file

@ -366,6 +366,15 @@ typedef enum {
#define SM_CODE_NO_ACCESS 401
#define SM_CODE_NO_INPUT 402
typedef enum
{
SIGNAL_UNKNOWN,
SIGNAL_GOOD,
SIGNAL_BAD,
SIGNAL_FAINT,
SIGNAL_NONE
} signal_state_t;
/**
* Streaming messages are sent from the pad to its receivers
*/