From: Jaroslav Kysela Date: Tue, 28 Apr 2015 12:43:14 +0000 (+0200) Subject: linuxdvb: rewrite PID subscription (limit used PID at once) X-Git-Tag: v4.1~97 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=5ba809b6bbd70ee3ae92616741ccaeb42e2e26ba;p=thirdparty%2Ftvheadend.git linuxdvb: rewrite PID subscription (limit used PID at once) --- diff --git a/src/input/mpegts.h b/src/input/mpegts.h index f81f0f777..1ea32a6e4 100644 --- a/src/input/mpegts.h +++ b/src/input/mpegts.h @@ -173,7 +173,6 @@ typedef struct mpegts_pid { int mp_pid; int mp_type; // mask for all subscribers - int mp_fd; // linuxdvb demux fd int8_t mp_cc; RB_HEAD(,mpegts_pid_sub) mp_subs; // subscribers to pid LIST_HEAD(,mpegts_pid_sub) mp_svc_subs; @@ -1035,15 +1034,6 @@ LIST_HEAD(,mpegts_listener) mpegts_listeners; if (ml->op) ml->op(t, ml->ml_opaque, arg1);\ } (void)0 -/* - * Misc - */ -#if ENABLE_LINUXDVB -void linuxdvb_filter_close ( int fd ); -#else -static inline void linuxdvb_filter_close ( int fd ) { assert(0); }; -#endif - #endif /* __TVH_MPEGTS_H__ */ /****************************************************************************** diff --git a/src/input/mpegts/linuxdvb/linuxdvb_frontend.c b/src/input/mpegts/linuxdvb/linuxdvb_frontend.c index baac4ef34..1bdcc76e5 100644 --- a/src/input/mpegts/linuxdvb/linuxdvb_frontend.c +++ b/src/input/mpegts/linuxdvb/linuxdvb_frontend.c @@ -86,6 +86,14 @@ const idclass_t linuxdvb_frontend_class = .opts = PO_RDONLY | PO_NOSAVE, .off = offsetof(linuxdvb_frontend_t, lfe_number), }, + { + .type = PT_INT, + .id = "pids_max", + .name = "Maximum PIDs ", + .off = offsetof(linuxdvb_frontend_t, lfe_pids_max), + .opts = PO_ADVANCED, + .def.i = 32 + }, { .type = PT_BOOL, .id = "powersave", @@ -333,6 +341,7 @@ linuxdvb_frontend_stop_mux lfe->lfe_in_setup = 0; lfe->lfe_freq = 0; + mpegts_pid_done(&lfe->lfe_pids); } static int @@ -353,79 +362,51 @@ linuxdvb_frontend_start_mux return res; } -void -linuxdvb_filter_close - ( int fd ) -{ - close(fd); -} - -static void -linuxdvb_frontend_open_pid0 - ( linuxdvb_frontend_t *lfe, mpegts_pid_t *mp ) +static mpegts_pid_t * +linuxdvb_frontend_open_pid + ( mpegts_input_t *mi, mpegts_mux_t *mm, int pid, int type, int weight, void *owner ) { - char name[256]; - struct dmx_pes_filter_params dmx_param; - int fd; - - /* Do not open internal PIDs */ - if (mp->mp_pid > MPEGTS_FULLMUX_PID) - return; - - /* Already opened */ - if (mp->mp_fd != -1) - return; - - /* Not locked */ - if (!lfe->lfe_locked) - return; - - lfe->mi_display_name((mpegts_input_t*)lfe, name, sizeof(name)); + mpegts_pid_t *mp; + linuxdvb_frontend_t *lfe = (linuxdvb_frontend_t*)mi; + int change = 0; - /* Open DMX */ - fd = tvh_open(lfe->lfe_dmx_path, O_RDWR, 0); - if(fd == -1) { - tvherror("linuxdvb", "%s - failed to open dmx for pid %d [e=%s]", - name, mp->mp_pid, strerror(errno)); - return; + if (pid < MPEGTS_FULLMUX_PID) + change = mpegts_pid_add(&lfe->lfe_pids, pid, weight) >= 0; + else if (pid == MPEGTS_FULLMUX_PID) { + change = lfe->lfe_pids.all == 0; + lfe->lfe_pids.all = 1; } - /* Install filter */ - tvhtrace("linuxdvb", "%s - open PID %04X (%d) fd %d", - name, mp->mp_pid, mp->mp_pid, fd); - memset(&dmx_param, 0, sizeof(dmx_param)); - dmx_param.pid = mp->mp_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, mp->mp_pid, strerror(errno)); - close(fd); - return; - } + if (!(mp = mpegts_input_open_pid(mi, mm, pid, type, weight, owner))) + return NULL; - /* Store */ - mp->mp_fd = fd; + if (change && lfe->lfe_dvr_pipe.wr > 0) + tvh_write(lfe->lfe_dvr_pipe.wr, "c", 1); - return; + return mp; } -static mpegts_pid_t * -linuxdvb_frontend_open_pid +static int +linuxdvb_frontend_close_pid ( mpegts_input_t *mi, mpegts_mux_t *mm, int pid, int type, int weight, void *owner ) { - mpegts_pid_t *mp; linuxdvb_frontend_t *lfe = (linuxdvb_frontend_t*)mi; + int change = 0, r; - if (!(mp = mpegts_input_open_pid(mi, mm, pid, type, weight, owner))) - return NULL; + if (pid < MPEGTS_FULLMUX_PID) + change = mpegts_pid_del(&lfe->lfe_pids, pid, weight) >= 0; + else if (pid == MPEGTS_FULLMUX_PID) { + change = lfe->lfe_pids.all != 0; + lfe->lfe_pids.all = 0; + } - linuxdvb_frontend_open_pid0(lfe, mp); + if ((r = mpegts_input_close_pid(mi, mm, pid, type, weight, owner)) <= 0) + return r; - return mp; + if (change) + tvh_write(lfe->lfe_dvr_pipe.wr, "c", 1); + + return r; } static idnode_set_t * @@ -497,7 +478,6 @@ 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; - mpegts_pid_t *mp; fe_status_t fe_status; signal_state_t status; signal_status_t sigstat; @@ -607,12 +587,6 @@ linuxdvb_frontend_monitor ( void *aux ) /* Table handlers */ linuxdvb_frontend_default_tables(lfe, (dvb_mux_t*)mm); - /* Locked - ensure everything is open */ - pthread_mutex_lock(&lfe->mi_output_lock); - RB_FOREACH(mp, &mm->mm_pids, mp_link) - linuxdvb_frontend_open_pid0(lfe, mp); - pthread_mutex_unlock(&lfe->mi_output_lock); - /* Re-arm (quick) */ } else { gtimer_arm_ms(&lfe->lfe_monitor_timer, linuxdvb_frontend_monitor, @@ -867,25 +841,138 @@ linuxdvb_frontend_monitor ( void *aux ) } } +typedef struct linuxdvb_pid { + int fd; + int pid; +} linuxdvb_pid_t; + +static void +linuxdvb_frontend_open_pid0 + ( linuxdvb_frontend_t *lfe, const char *name, + linuxdvb_pid_t *pids, int pids_size, int pid ) +{ + struct dmx_pes_filter_params dmx_param; + int fd; + + for ( ; pids_size > 0 && pids->fd >= 0; pids_size--, pids++); + if (pids_size == 0) { + tvherror("linuxdvb", "%s - maximum PID count reached, pid %d ignored", + name, pid); + return; + } + + /* Open DMX */ + fd = tvh_open(lfe->lfe_dmx_path, O_RDWR, 0); + if(fd == -1) { + tvherror("linuxdvb", "%s - failed to open dmx for pid %d [e=%s]", + name, pid, strerror(errno)); + return; + } + + /* Install filter */ + tvhtrace("linuxdvb", "%s - open PID %04X (%d) fd %d", name, pid, pid, fd); + 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; + } + + /* Store */ + pids->fd = fd; + pids->pid = pid; +} + +static void +linuxdvb_frontend_close_pid0 + ( linuxdvb_frontend_t *lfe, const char *name, + linuxdvb_pid_t *pids, int pids_size, int pid ) +{ + for ( ; pids_size > 0 && pids->pid != pid; + pids_size--, pids++); + if (pids_size == 0) + return; + close(pids->fd); + pids->fd = -1; + pids->pid = -1; +} + +static int +linuxdvb_pid_exists ( linuxdvb_pid_t *pids, int pids_size, int pid ) +{ + int i; + for (i = 0; i < pids_size; i++) + if (pids[i].fd >= 0 && pids[i].pid == pid) + return 1; + return 0; +} + +static void +linuxdvb_update_pids ( linuxdvb_frontend_t *lfe, const char *name, + mpegts_apids_t *tuned, linuxdvb_pid_t *pids, + int pids_size ) +{ + mpegts_apids_t wpid, padd, pdel; + int i, max = MAX(16, lfe->lfe_pids_max); + + pthread_mutex_lock(&lfe->lfe_dvr_lock); + + if (!lfe->lfe_pids.all) { + mpegts_pid_weighted(&wpid, &lfe->lfe_pids, max); + mpegts_pid_compare(&wpid, tuned, &padd, &pdel); + mpegts_pid_done(&wpid); + for (i = 0; i < pdel.count; i++) + linuxdvb_frontend_close_pid0(lfe, name, pids, pids_size, pdel.pids[i].pid); + for (i = 0; i < padd.count; i++) + linuxdvb_frontend_open_pid0(lfe, name, pids, pids_size, padd.pids[i].pid); + mpegts_pid_done(&padd); + mpegts_pid_done(&pdel); + } + + if (lfe->lfe_pids.all && !linuxdvb_pid_exists(pids, pids_size, MPEGTS_FULLMUX_PID)) + linuxdvb_frontend_open_pid0(lfe, name, pids, pids_size, MPEGTS_FULLMUX_PID); + else if (!lfe->lfe_pids.all && linuxdvb_pid_exists(pids, pids_size, MPEGTS_FULLMUX_PID)) + linuxdvb_frontend_close_pid0(lfe, name, pids, pids_size, MPEGTS_FULLMUX_PID); + + mpegts_pid_done(tuned); + mpegts_pid_weighted(tuned, &lfe->lfe_pids, max); + tuned->all = lfe->lfe_pids.all; + + pthread_mutex_unlock(&lfe->lfe_dvr_lock); +} + static void * linuxdvb_frontend_input_thread ( void *aux ) { linuxdvb_frontend_t *lfe = aux; mpegts_mux_instance_t *mmi; - int dvr = -1; - char buf[256]; - int nfds; + char name[256], b; tvhpoll_event_t ev[2]; tvhpoll_t *efd; ssize_t n; size_t skip = (MIN(lfe->lfe_skip_bytes, 1024*1024) / 188) * 188; size_t counter = 0; + linuxdvb_pid_t pids[128]; + mpegts_apids_t tuned; sbuf_t sb; - int nodata = 4; + int i, dvr = -1, nfds, nodata = 4; + + mpegts_pid_init(&tuned); + for (i = 0; i < ARRAY_SIZE(pids); i++) { + pids[i].fd = -1; + pids[i].pid = -1; + } /* Get MMI */ pthread_mutex_lock(&lfe->lfe_dvr_lock); - lfe->mi_display_name((mpegts_input_t*)lfe, buf, sizeof(buf)); + lfe->mi_display_name((mpegts_input_t*)lfe, name, sizeof(name)); mmi = LIST_FIRST(&lfe->mi_mux_active); pthread_cond_signal(&lfe->lfe_dvr_cond); pthread_mutex_unlock(&lfe->lfe_dvr_lock); @@ -894,7 +981,7 @@ linuxdvb_frontend_input_thread ( void *aux ) /* Open DVR */ dvr = tvh_open(lfe->lfe_dvr_path, O_RDONLY | O_NONBLOCK, 0); if (dvr < 0) { - tvherror("linuxdvb", "%s - failed to open %s", buf, lfe->lfe_dvr_path); + tvherror("linuxdvb", "%s - failed to open %s", name, lfe->lfe_dvr_path); return NULL; } @@ -910,12 +997,15 @@ linuxdvb_frontend_input_thread ( void *aux ) /* Allocate memory */ sbuf_init_fixed(&sb, MIN(MAX(18800, lfe->lfe_ibuf_size), 1880000)); + /* Subscribe PIDs */ + linuxdvb_update_pids(lfe, name, &tuned, pids, ARRAY_SIZE(pids)); + /* Read */ while (tvheadend_running) { nfds = tvhpoll_wait(efd, ev, 1, 150); if (nfds == 0) { /* timeout */ if (nodata == 0) { - tvhlog(LOG_WARNING, "linuxdvb", "%s - poll TIMEOUT", buf); + tvhlog(LOG_WARNING, "linuxdvb", "%s - poll TIMEOUT", name); nodata = 50; lfe->lfe_nodata = 1; } else { @@ -923,6 +1013,15 @@ linuxdvb_frontend_input_thread ( void *aux ) } } if (nfds < 1) continue; + if (ev[0].data.fd == lfe->lfe_dvr_pipe.rd) { + if (read(lfe->lfe_dvr_pipe.rd, &b, 1) > 0) { + if (b == 'c') + linuxdvb_update_pids(lfe, name, &tuned, pids, ARRAY_SIZE(pids)); + else + break; + } + continue; + } if (ev[0].data.fd != dvr) break; nodata = 50; @@ -933,11 +1032,11 @@ linuxdvb_frontend_input_thread ( void *aux ) if (ERRNO_AGAIN(errno)) continue; if (errno == EOVERFLOW) { - tvhlog(LOG_WARNING, "linuxdvb", "%s - read() EOVERFLOW", buf); + tvhlog(LOG_WARNING, "linuxdvb", "%s - read() EOVERFLOW", name); continue; } tvhlog(LOG_ERR, "linuxdvb", "%s - read() error %d (%s)", - buf, errno, strerror(errno)); + name, errno, strerror(errno)); break; } @@ -957,6 +1056,10 @@ linuxdvb_frontend_input_thread ( void *aux ) sbuf_free(&sb); tvhpoll_destroy(efd); + for (i = 0; i < ARRAY_SIZE(pids); i++) + if (pids[i].fd >= 0) + close(pids[i].fd); + mpegts_pid_done(&tuned); close(dvr); return NULL; } @@ -1477,6 +1580,7 @@ linuxdvb_frontend_create lfe->lfe_name[sizeof(lfe->lfe_name)-1] = '\0'; lfe->lfe_ibuf_size = 18800; lfe->lfe_status_period = 1000; + lfe->lfe_pids_max = 32; lfe = (linuxdvb_frontend_t*)mpegts_input_create0((mpegts_input_t*)lfe, idc, uuid, conf); if (!lfe) return NULL; @@ -1502,6 +1606,7 @@ linuxdvb_frontend_create lfe->mi_stop_mux = linuxdvb_frontend_stop_mux; lfe->mi_network_list = linuxdvb_frontend_network_list; lfe->mi_open_pid = linuxdvb_frontend_open_pid; + lfe->mi_close_pid = linuxdvb_frontend_close_pid; lfe->mi_enabled_updated = linuxdvb_frontend_enabled_updated; /* Adapter link */ @@ -1511,6 +1616,7 @@ linuxdvb_frontend_create /* DVR lock/cond */ pthread_mutex_init(&lfe->lfe_dvr_lock, NULL); pthread_cond_init(&lfe->lfe_dvr_cond, NULL); + mpegts_pid_init(&lfe->lfe_pids); /* Satconf */ if (conf) { diff --git a/src/input/mpegts/linuxdvb/linuxdvb_private.h b/src/input/mpegts/linuxdvb/linuxdvb_private.h index 559eaa03a..0522d15f5 100644 --- a/src/input/mpegts/linuxdvb/linuxdvb_private.h +++ b/src/input/mpegts/linuxdvb/linuxdvb_private.h @@ -120,6 +120,8 @@ struct linuxdvb_frontend th_pipe_t lfe_dvr_pipe; pthread_mutex_t lfe_dvr_lock; pthread_cond_t lfe_dvr_cond; + mpegts_apids_t lfe_pids; + int lfe_pids_max; /* * Tuning diff --git a/src/input/mpegts/mpegts_input.c b/src/input/mpegts/mpegts_input.c index 2baa3f1ce..e2e9ad6d3 100644 --- a/src/input/mpegts/mpegts_input.c +++ b/src/input/mpegts/mpegts_input.c @@ -517,8 +517,6 @@ mpegts_input_close_pid } if (!RB_FIRST(&mp->mp_subs)) { RB_REMOVE(&mm->mm_pids, mp, mp_link); - if (mp->mp_fd != -1) - linuxdvb_filter_close(mp->mp_fd); free(mp); return 1; } else { diff --git a/src/input/mpegts/mpegts_mux.c b/src/input/mpegts/mpegts_mux.c index b6bc532d4..b4fc44fe7 100644 --- a/src/input/mpegts/mpegts_mux.c +++ b/src/input/mpegts/mpegts_mux.c @@ -761,8 +761,6 @@ mpegts_mux_stop ( mpegts_mux_t *mm, int force, int reason ) } } RB_REMOVE(&mm->mm_pids, mp, mp_link); - if (mp->mp_fd != -1) - linuxdvb_filter_close(mp->mp_fd); free(mp); } pthread_mutex_unlock(&mi->mi_output_lock); @@ -1257,7 +1255,6 @@ mpegts_mux_find_pid_ ( mpegts_mux_t *mm, int pid, int create ) mp = calloc(1, sizeof(*mp)); mp->mp_pid = pid; if (!RB_INSERT_SORTED(&mm->mm_pids, mp, mp_link, mp_cmp)) { - mp->mp_fd = -1; mp->mp_cc = -1; } else { free(mp);