1 /*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU Lesser General Public License as published by
4 * the Free Software Foundation version 2.1 of the License.
5 *
6 * This program is distributed in the hope that it will be useful,
7 * but WITHOUT ANY WARRANTY; without even the implied warranty of
8 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 * GNU Lesser General Public License for more details.
10 *
11 * You should have received a copy of the GNU Lesser General Public License
12 * along with this program; if not, write to the Free Software
13 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
14 * Or, point your browser to http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
15 *
16 * These routines were written as part of the dvb-apps, as:
17 * util functions for various ?zap implementations
18 *
19 * Copyright (C) 2001 Johannes Stezenbach (js@convergence.de)
20 * for convergence integrated media
21 *
22 * Originally licensed as GPLv2 or upper
23 *
24 * All subsequent changes are under GPLv2 only and are:
25 * Copyright (c) 2011-2012 - Mauro Carvalho Chehab
26 *
27 */
28
29 #include <string.h>
30 #include <unistd.h>
31 #include <stdio.h>
32 #include <time.h>
33 #include <errno.h>
34
35 #include <sys/ioctl.h>
36 #include <sys/types.h>
37 #include <sys/stat.h>
38 #include <fcntl.h>
39 #include <stdlib.h> /* free */
40
41 #include <libdvbv5/dvb-demux.h>
42 #include <libdvbv5/dvb-dev.h>
43
44 #define MAX_TIME 10 /* 1.0 seconds */
45
46 #define xioctl(fh, request, arg...) ({ \
47 int __rc; \
48 struct timespec __start, __end; \
49 \
50 clock_gettime(CLOCK_MONOTONIC, &__start); \
51 do { \
52 __rc = ioctl(fh, request, ##arg); \
53 if (__rc != -1) \
54 break; \
55 if ((errno != EINTR) && (errno != EAGAIN)) \
56 break; \
57 clock_gettime(CLOCK_MONOTONIC, &__end); \
58 if (__end.tv_sec * 10 + __end.tv_nsec / 100000000 > \
59 __start.tv_sec * 10 + __start.tv_nsec / 100000000 + \
60 MAX_TIME) \
61 break; \
62 } while (1); \
63 \
64 __rc; \
65 })
66
dvb_dmx_open(int adapter,int demux)67 int dvb_dmx_open(int adapter, int demux)
68 {
69 int fd_demux;
70 struct dvb_device *dvb;
71 struct dvb_dev_list *dvb_dev;
72
73 dvb = dvb_dev_alloc();
74 dvb_dev_find(dvb, NULL, NULL);
75 dvb_dev = dvb_dev_seek_by_adapter(dvb, adapter, demux, DVB_DEVICE_DEMUX);
76 if (!dvb_dev) {
77 dvb_dev_free(dvb);
78 return -1;
79 }
80
81 fd_demux = open(dvb_dev->path, O_RDWR | O_NONBLOCK);
82 dvb_dev_free(dvb);
83 return fd_demux;
84 }
85
dvb_dmx_close(int dmx_fd)86 void dvb_dmx_close(int dmx_fd)
87 {
88 (void)xioctl(dmx_fd, DMX_STOP);
89 close(dmx_fd);
90 }
91
dvb_dmx_stop(int dmx_fd)92 void dvb_dmx_stop(int dmx_fd)
93 {
94 (void)xioctl(dmx_fd, DMX_STOP);
95 }
96
dvb_set_pesfilter(int dmxfd,int pid,dmx_pes_type_t type,dmx_output_t output,int buffersize)97 int dvb_set_pesfilter(int dmxfd, int pid, dmx_pes_type_t type,
98 dmx_output_t output, int buffersize)
99 {
100 struct dmx_pes_filter_params pesfilter;
101
102 if (buffersize) {
103 if (xioctl(dmxfd, DMX_SET_BUFFER_SIZE, buffersize) == -1)
104 perror("DMX_SET_BUFFER_SIZE failed");
105 }
106
107 memset(&pesfilter, 0, sizeof(pesfilter));
108
109 pesfilter.pid = pid;
110 pesfilter.input = DMX_IN_FRONTEND;
111 pesfilter.output = output;
112 pesfilter.pes_type = type;
113 pesfilter.flags = DMX_IMMEDIATE_START;
114
115 if (xioctl(dmxfd, DMX_SET_PES_FILTER, &pesfilter) == -1) {
116 fprintf(stderr, "DMX_SET_PES_FILTER failed "
117 "(PID = 0x%04x): %d %m\n", pid, errno);
118 return -1;
119 }
120
121 return 0;
122 }
123
dvb_set_section_filter(int dmxfd,int pid,unsigned filtsize,unsigned char * filter,unsigned char * mask,unsigned char * mode,unsigned int flags)124 int dvb_set_section_filter(int dmxfd, int pid, unsigned filtsize,
125 unsigned char *filter,
126 unsigned char *mask,
127 unsigned char *mode,
128 unsigned int flags)
129 {
130 struct dmx_sct_filter_params sctfilter;
131
132 if (filtsize > DMX_FILTER_SIZE)
133 filtsize = DMX_FILTER_SIZE;
134
135 memset(&sctfilter, 0, sizeof(sctfilter));
136
137 sctfilter.pid = pid;
138
139 if (filter)
140 memcpy(sctfilter.filter.filter, filter, filtsize);
141 if (mask)
142 memcpy(sctfilter.filter.mask, mask, filtsize);
143 if (mode)
144 memcpy(sctfilter.filter.mode, mode, filtsize);
145
146 sctfilter.flags = flags;
147
148 if (xioctl(dmxfd, DMX_SET_FILTER, &sctfilter) == -1) {
149 fprintf(stderr, "DMX_SET_FILTER failed (PID = 0x%04x): %d %m\n",
150 pid, errno);
151 return -1;
152 }
153
154 return 0;
155 }
156
dvb_get_pmt_pid(int patfd,int sid)157 int dvb_get_pmt_pid(int patfd, int sid)
158 {
159 int count;
160 int pmt_pid = 0;
161 int patread = 0;
162 int section_length;
163 unsigned char buft[4096];
164 unsigned char *buf = buft;
165 struct dmx_sct_filter_params f;
166
167 memset(&f, 0, sizeof(f));
168 f.pid = 0;
169 f.filter.filter[0] = 0x00;
170 f.filter.mask[0] = 0xff;
171 f.timeout = 0;
172 f.flags = DMX_IMMEDIATE_START | DMX_CHECK_CRC;
173
174 if (xioctl(patfd, DMX_SET_FILTER, &f) == -1) {
175 perror("ioctl DMX_SET_FILTER failed");
176 return -1;
177 }
178
179 while (!patread){
180 if (((count = read(patfd, buf, sizeof(buft))) < 0) && errno == EOVERFLOW)
181 count = read(patfd, buf, sizeof(buft));
182
183 if (count < 0) {
184 perror("read_sections: read error");
185 return -1;
186 }
187
188 section_length = ((buf[1] & 0x0f) << 8) | buf[2];
189 if (count != section_length + 3)
190 continue;
191
192 buf += 8;
193 section_length -= 8;
194
195 patread = 1; /* assumes one section contains the whole pat */
196 while (section_length > 0) {
197 int service_id = (buf[0] << 8) | buf[1];
198 if (service_id == sid) {
199 pmt_pid = ((buf[2] & 0x1f) << 8) | buf[3];
200 section_length = 0;
201 }
202 buf += 4;
203 section_length -= 4;
204 }
205 }
206
207 return pmt_pid;
208 }
209