File: dmx.c

package info (click to toggle)
getstream 20100616-3
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 492 kB
  • sloc: ansic: 5,057; makefile: 39; sh: 13
file content (160 lines) | stat: -rw-r--r-- 3,638 bytes parent folder | download | duplicates (6)
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;
}