1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160
|
#include <sys/ioctl.h>
#include <time.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <errno.h>
#include <linux/dvb/dmx.h>
#include <linux/dvb/frontend.h>
#include <event.h>
#include "getstream.h"
#include "psi.h"
static inline char *dmxname(int adapter) {
static char dmxname[128];
sprintf(dmxname, "/dev/dvb/adapter%d/demux0", adapter);
return dmxname;
}
/*
* DMX_PES_VIDEO
* DMX_PES_AUDIO
* DMX_PES_TELETEXT
* DMX_PES_OTHER
*
*/
static int dmx_set_pes_filter(int fd, int pid, int pestype) {
struct dmx_pes_filter_params pesFilterParams;
memset(&pesFilterParams, 0, sizeof(struct dmx_pes_filter_params));
logwrite(LOG_INFO,"dmx: Setting filter for pid %d pestype %d", pid, pestype);
pesFilterParams.pid = pid;
pesFilterParams.input = DMX_IN_FRONTEND;
pesFilterParams.output = DMX_OUT_TS_TAP;
pesFilterParams.pes_type = pestype;
pesFilterParams.flags = DMX_IMMEDIATE_START;
if (ioctl(fd, DMX_SET_PES_FILTER, &pesFilterParams) < 0) {
logwrite(LOG_ERROR,"demux: ioctl DMX_SET_PES_FILTER failed for pid %u pestype %d ",pid, pestype);
return 0;
}
return 1;
}
void dmx_leave_pid(struct adapter_s *a, int pid) {
if (a->dmx.pidtable[pid].fd >= 0)
close(a->dmx.pidtable[pid].fd);
a->dmx.pidtable[pid].fd=-1;
return;
}
int dmx_join_pid(struct adapter_s *a, unsigned int pid, int type) {
int fd;
/* Budget mode does not need this */
if(a->budgetmode && a->dmx.pidtable[0x2000].fd >= 0)
return 1;
/* Already joined ? */
if (a->dmx.pidtable[pid].fd >= 0) {
logwrite(LOG_ERROR,"dmx: already joined pid %d", pid);
return 1;
}
fd=open(dmxname(a->no), O_RDWR);
if (fd < 0) {
logwrite(LOG_ERROR,"dmx: failed opening dmx device for joining pid %d", pid);
return 0;
}
if (!dmx_set_pes_filter(fd, pid, type)) {
close(fd);
return 0;
}
a->dmx.pidtable[pid].fd=fd;
a->dmx.pidtable[pid].type=type;
return 1;
}
/*
* Apply section filter to opened demux interface.
*
*/
int demux_set_sct_filter(int fd, int pid,
struct dmx_filter *df, int flags, int timeout) {
struct dmx_sct_filter_params sctFilterParams;
memset(&sctFilterParams, 0, sizeof(struct dmx_sct_filter_params));
sctFilterParams.pid=pid;
sctFilterParams.timeout=timeout;
sctFilterParams.flags=flags;
memcpy(&sctFilterParams.filter, df, sizeof(struct dmx_filter));
if (ioctl(fd, DMX_SET_FILTER, &sctFilterParams) < 0) {
logwrite(LOG_ERROR, "demux: ioctl DMX_SET_PES_FILTER failed for pid %u",pid);
exit(-1);
}
return 0;
}
/*
* It is known that the flexcop chipset aka SkyStar2/AirStar cards
* sometimes stop receiving interrupts. A workaround in the kernel
* trys to reset the card in case the number of joined/forwarded
* pids gets from 0 to 1 which means we need to drop all filters
* and reaquire them. This function is called from dvr.c in case
* we see no read avalability on the dvr0 device in 5 seconds.
*
* We are going up to PID_MAX+1 aka 0x2000 in case we are in budget
* mode and just have a single filter.
*
*/
void dmx_bounce_filter(struct adapter_s *adapter) {
int i;
for(i=0;i<=PID_MAX+1;i++) {
if (adapter->dmx.pidtable[i].fd < 0)
continue;
ioctl(adapter->dmx.pidtable[i].fd, DMX_STOP);
}
for(i=0;i<=PID_MAX+1;i++) {
if (adapter->dmx.pidtable[i].fd < 0)
continue;
ioctl(adapter->dmx.pidtable[i].fd, DMX_START);
}
}
int dmx_init(struct adapter_s *adapter) {
int i;
/* Reset dmxfd fds - Run until 0x2000 as thats the budget mode pid */
for(i=0;i<=PID_MAX+1;i++)
adapter->dmx.pidtable[i].fd=-1;
return 1;
}
|