/src/mpv/stream/stream_dvb.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | |
3 | | dvbstream |
4 | | (C) Dave Chapman <dave@dchapman.com> 2001, 2002. |
5 | | (C) Rozhuk Ivan <rozhuk.im@gmail.com> 2016 - 2017 |
6 | | |
7 | | Original authors: Nico, probably Arpi |
8 | | |
9 | | Some code based on dvbstream, 0.4.3-pre3 (CVS checkout), |
10 | | http://sourceforge.net/projects/dvbtools/ |
11 | | |
12 | | Modified for use with MPlayer, for details see the changelog at |
13 | | http://svn.mplayerhq.hu/mplayer/trunk/ |
14 | | $Id$ |
15 | | |
16 | | Copyright notice: |
17 | | |
18 | | This file is part of mpv. |
19 | | |
20 | | mpv is free software; you can redistribute it and/or modify |
21 | | it under the terms of the GNU General Public License as published by |
22 | | the Free Software Foundation; either version 2 of the License, or |
23 | | (at your option) any later version. |
24 | | |
25 | | mpv is distributed in the hope that it will be useful, |
26 | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
27 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
28 | | GNU General Public License for more details. |
29 | | |
30 | | You should have received a copy of the GNU General Public License along |
31 | | with mpv. If not, see <http://www.gnu.org/licenses/>. |
32 | | |
33 | | */ |
34 | | |
35 | | #include "config.h" |
36 | | #include <stdio.h> |
37 | | #include <stdlib.h> |
38 | | #include <string.h> |
39 | | #include <sys/ioctl.h> |
40 | | #include <sys/time.h> |
41 | | #include <poll.h> |
42 | | #include <unistd.h> |
43 | | #include <fcntl.h> |
44 | | #include <errno.h> |
45 | | |
46 | | #include "osdep/io.h" |
47 | | #include "misc/ctype.h" |
48 | | #include "osdep/timer.h" |
49 | | |
50 | | #include "stream.h" |
51 | | #include "common/tags.h" |
52 | | #include "options/m_config.h" |
53 | | #include "options/m_option.h" |
54 | | #include "options/options.h" |
55 | | #include "options/path.h" |
56 | | #include "osdep/poll_wrapper.h" |
57 | | #include "osdep/threads.h" |
58 | | |
59 | | #include "dvbin.h" |
60 | | #include "dvb_tune.h" |
61 | | |
62 | | #if !HAVE_GPL |
63 | | #error GPL only |
64 | | #endif |
65 | | |
66 | 0 | #define CHANNEL_LINE_LEN 256 |
67 | | |
68 | | #define OPT_BASE_STRUCT dvb_opts_t |
69 | | |
70 | | static dvb_state_t *global_dvb_state = NULL; |
71 | | static mp_static_mutex global_dvb_state_lock = MP_STATIC_MUTEX_INITIALIZER; |
72 | | |
73 | | const struct m_sub_options stream_dvb_conf = { |
74 | | .opts = (const m_option_t[]) { |
75 | | {"prog", OPT_STRING(cfg_prog), .flags = UPDATE_DVB_PROG}, |
76 | | {"card", OPT_INT(cfg_devno), M_RANGE(0, MAX_ADAPTERS-1)}, |
77 | | {"timeout", OPT_FLOAT(cfg_timeout), M_RANGE(0, FLT_MAX)}, |
78 | | {"file", OPT_STRING(cfg_file), .flags = M_OPT_FILE}, |
79 | | {"full-transponder", OPT_BOOL(cfg_full_transponder)}, |
80 | | {"channel-switch-offset", OPT_INT(cfg_channel_switch_offset), |
81 | | .flags = UPDATE_DVB_PROG}, |
82 | | {0} |
83 | | }, |
84 | | .size = sizeof(dvb_opts_t), |
85 | | .defaults = &(const dvb_opts_t){ |
86 | | .cfg_prog = NULL, |
87 | | .cfg_timeout = 30, |
88 | | }, |
89 | | }; |
90 | | |
91 | | void dvbin_close(stream_t *stream); |
92 | | |
93 | | static fe_code_rate_t parse_fec(const char *cr) |
94 | 0 | { |
95 | 0 | if (!strcmp(cr, "FEC_1_2")) { |
96 | 0 | return FEC_1_2; |
97 | 0 | } else if (!strcmp(cr, "FEC_2_3")) { |
98 | 0 | return FEC_2_3; |
99 | 0 | } else if (!strcmp(cr, "FEC_3_4")) { |
100 | 0 | return FEC_3_4; |
101 | 0 | } else if (!strcmp(cr, "FEC_4_5")) { |
102 | 0 | return FEC_4_5; |
103 | 0 | } else if (!strcmp(cr, "FEC_5_6")) { |
104 | 0 | return FEC_5_6; |
105 | 0 | } else if (!strcmp(cr, "FEC_6_7")) { |
106 | 0 | return FEC_6_7; |
107 | 0 | } else if (!strcmp(cr, "FEC_7_8")) { |
108 | 0 | return FEC_7_8; |
109 | 0 | } else if (!strcmp(cr, "FEC_8_9")) { |
110 | 0 | return FEC_8_9; |
111 | 0 | } else if (!strcmp(cr, "FEC_NONE")) { |
112 | 0 | return FEC_NONE; |
113 | 0 | } |
114 | 0 | return FEC_NONE; |
115 | 0 | } |
116 | | |
117 | | static fe_modulation_t parse_vdr_modulation(const char** modstring) |
118 | 0 | { |
119 | 0 | static const struct { const char *s; fe_modulation_t v; } table[] = { |
120 | 0 | { "16", QAM_16 }, |
121 | 0 | { "32", QAM_32 }, |
122 | 0 | { "64", QAM_64 }, |
123 | 0 | { "128", QAM_128 }, |
124 | 0 | { "256", QAM_256 }, |
125 | 0 | { "998", QAM_AUTO }, |
126 | 0 | { "2", QPSK }, |
127 | 0 | { "5", PSK_8 }, |
128 | 0 | { "6", APSK_16 }, |
129 | 0 | { "7", APSK_32 }, |
130 | 0 | { "10", VSB_8 }, |
131 | 0 | { "11", VSB_16 }, |
132 | 0 | { "12", DQPSK }, |
133 | 0 | }; |
134 | 0 | for (int i = 0; i < MP_ARRAY_SIZE(table); i++) { |
135 | 0 | if (!strncmp(*modstring, table[i].s, strlen(table[i].s))) { |
136 | 0 | *modstring += strlen(table[i].s); |
137 | 0 | return table[i].v; |
138 | 0 | } |
139 | 0 | } |
140 | 0 | return QAM_AUTO; |
141 | 0 | } |
142 | | |
143 | | static void parse_vdr_par_string(const char *vdr_par_str, dvb_channel_t *ptr) |
144 | 0 | { |
145 | | //FIXME: There is more information in this parameter string, especially related |
146 | | // to non-DVB-S reception. |
147 | 0 | if (!vdr_par_str[0]) |
148 | 0 | return; |
149 | 0 | const char *vdr_par = &vdr_par_str[0]; |
150 | 0 | while (vdr_par && *vdr_par) { |
151 | 0 | switch (mp_toupper(*vdr_par)) { |
152 | 0 | case 'H': |
153 | 0 | ptr->pol = 'H'; |
154 | 0 | vdr_par++; |
155 | 0 | break; |
156 | 0 | case 'V': |
157 | 0 | ptr->pol = 'V'; |
158 | 0 | vdr_par++; |
159 | 0 | break; |
160 | 0 | case 'S': |
161 | 0 | vdr_par++; |
162 | 0 | ptr->is_dvb_x2 = *vdr_par == '1'; |
163 | 0 | vdr_par++; |
164 | 0 | break; |
165 | 0 | case 'P': |
166 | 0 | vdr_par++; |
167 | 0 | char *endptr = NULL; |
168 | 0 | errno = 0; |
169 | 0 | int n = strtol(vdr_par, &endptr, 10); |
170 | 0 | if (!errno && endptr != vdr_par) { |
171 | 0 | ptr->stream_id = n; |
172 | 0 | vdr_par = endptr; |
173 | 0 | } |
174 | 0 | break; |
175 | 0 | case 'I': |
176 | 0 | vdr_par++; |
177 | 0 | ptr->inv = (*vdr_par == '1') ? INVERSION_ON : INVERSION_OFF; |
178 | 0 | vdr_par++; |
179 | 0 | break; |
180 | 0 | case 'M': |
181 | 0 | vdr_par++; |
182 | 0 | ptr->mod = parse_vdr_modulation(&vdr_par); |
183 | 0 | break; |
184 | 0 | default: |
185 | 0 | vdr_par++; |
186 | 0 | } |
187 | 0 | } |
188 | 0 | } |
189 | | |
190 | | static char *dvb_strtok_r(char *s, const char *sep, char **p) |
191 | 0 | { |
192 | 0 | if (!s && !(s = *p)) |
193 | 0 | return NULL; |
194 | | |
195 | | /* Skip leading separators. */ |
196 | 0 | s += strspn(s, sep); |
197 | | |
198 | | /* s points at first non-separator, or end of string. */ |
199 | 0 | if (!*s) |
200 | 0 | return *p = 0; |
201 | | |
202 | | /* Move *p to next separator. */ |
203 | 0 | *p = s + strcspn(s, sep); |
204 | 0 | if (**p) { |
205 | 0 | *(*p)++ = 0; |
206 | 0 | } else { |
207 | 0 | *p = 0; |
208 | 0 | } |
209 | 0 | return s; |
210 | 0 | } |
211 | | |
212 | | static bool parse_pid_string(struct mp_log *log, char *pid_string, |
213 | | dvb_channel_t *ptr) |
214 | 0 | { |
215 | 0 | if (!pid_string[0]) |
216 | 0 | return false; |
217 | 0 | int pcnt = 0; |
218 | | /* These tokens also catch vdr-style PID lists. |
219 | | * They can contain 123=deu@3,124=eng+jap@4;125 |
220 | | * 3 and 4 are codes for codec type, =langLeft+langRight is allowed, |
221 | | * and ; may separate a dolby channel. |
222 | | * With the numChars-test and the full token-list, all is handled |
223 | | * gracefully. |
224 | | */ |
225 | 0 | const char *tokens = "+,;"; |
226 | 0 | char *pidPart; |
227 | 0 | char *savePtr = NULL; |
228 | 0 | pidPart = dvb_strtok_r(pid_string, tokens, &savePtr); |
229 | 0 | while (pidPart != NULL) { |
230 | 0 | if (ptr->pids_cnt >= DMX_FILTER_SIZE - 1) { |
231 | 0 | mp_verbose(log, "Maximum number of PIDs for one channel " |
232 | 0 | "reached, ignoring further ones!\n"); |
233 | 0 | break; |
234 | 0 | } |
235 | 0 | int numChars = 0; |
236 | 0 | int pid = 0; |
237 | 0 | pcnt += sscanf(pidPart, "%d%n", &pid, &numChars); |
238 | 0 | if (numChars > 0) { |
239 | 0 | ptr->pids[ptr->pids_cnt] = pid; |
240 | 0 | ptr->pids_cnt++; |
241 | 0 | } |
242 | 0 | pidPart = dvb_strtok_r(NULL, tokens, &savePtr); |
243 | 0 | } |
244 | 0 | return pcnt > 0; |
245 | 0 | } |
246 | | |
247 | | static dvb_channels_list_t *dvb_get_channels(struct mp_log *log, |
248 | | dvb_channels_list_t *list_add, |
249 | | int cfg_full_transponder, |
250 | | char *filename, |
251 | | unsigned int frontend, |
252 | | int delsys, unsigned int delsys_mask) |
253 | 0 | { |
254 | 0 | dvb_channels_list_t *list = list_add; |
255 | |
|
256 | 0 | if (!filename) |
257 | 0 | return list; |
258 | | |
259 | 0 | const char *cbl_conf = |
260 | 0 | "%d:%255[^:]:%d:%255[^:]:%255[^:]:%255[^:]:%255[^:]\n"; |
261 | 0 | const char *sat_conf = "%d:%c:%d:%d:%255[^:]:%255[^:]\n"; |
262 | 0 | const char *ter_conf = |
263 | 0 | "%d:%255[^:]:%255[^:]:%255[^:]:%255[^:]:%255[^:]:%255[^:]:%255[^:]:%255[^:]:%255[^:]:%255[^:]\n"; |
264 | 0 | const char *atsc_conf = "%d:%255[^:]:%255[^:]:%255[^:]\n"; |
265 | 0 | const char *vdr_conf = |
266 | 0 | "%d:%255[^:]:%255[^:]:%d:%255[^:]:%255[^:]:%255[^:]:%*255[^:]:%d:%*d:%*d:%*d\n%n"; |
267 | |
|
268 | 0 | mp_verbose(log, "Reading config file %s for type %s\n", |
269 | 0 | filename, get_dvb_delsys(delsys)); |
270 | 0 | FILE *f = fopen(filename, "r"); |
271 | 0 | if (!f) { |
272 | 0 | mp_fatal(log, "Can't open file %s\n", filename); |
273 | 0 | return list; |
274 | 0 | } |
275 | | |
276 | 0 | if (!list) |
277 | 0 | list = talloc_zero(NULL, dvb_channels_list_t); |
278 | |
|
279 | 0 | while (!feof(f)) { |
280 | 0 | char line[CHANNEL_LINE_LEN]; |
281 | 0 | if (!fgets(line, CHANNEL_LINE_LEN, f)) |
282 | 0 | continue; |
283 | | |
284 | 0 | if (line[0] == '#' || strlen(line) == 0) |
285 | 0 | continue; |
286 | | |
287 | 0 | dvb_channel_t chn = {0}; |
288 | 0 | dvb_channel_t *ptr = &chn; |
289 | |
|
290 | 0 | char tmp_lcr[256], tmp_hier[256], inv[256], bw[256], cr[256], mod[256], |
291 | 0 | transm[256], gi[256], vpid_str[256], apid_str[256], tpid_str[256], |
292 | 0 | vdr_par_str[256], vdr_loc_str[256]; |
293 | |
|
294 | 0 | vpid_str[0] = apid_str[0] = tpid_str[0] = 0; |
295 | 0 | vdr_loc_str[0] = vdr_par_str[0] = 0; |
296 | |
|
297 | 0 | char *colon = strchr(line, ':'); |
298 | 0 | if (!colon) |
299 | 0 | continue; |
300 | 0 | int k = colon - line; |
301 | 0 | if (!k) |
302 | 0 | continue; |
303 | | // In some modern VDR-style configs, channel name also has bouquet after ;. |
304 | | // Parse that off, we ignore it. |
305 | 0 | char *bouquet_sep = strchr(line, ';'); |
306 | 0 | { |
307 | 0 | int namelen = k; |
308 | 0 | if (bouquet_sep && bouquet_sep < colon) |
309 | 0 | namelen = bouquet_sep - line; |
310 | 0 | ptr->name = talloc_strndup(list, line, namelen); |
311 | 0 | } |
312 | |
|
313 | 0 | k++; |
314 | |
|
315 | 0 | ptr->pids_cnt = 0; |
316 | 0 | ptr->freq = 0; |
317 | 0 | ptr->service_id = -1; |
318 | 0 | ptr->is_dvb_x2 = false; |
319 | 0 | ptr->frontend = frontend; |
320 | 0 | ptr->delsys = delsys; |
321 | 0 | ptr->diseqc = 0; |
322 | 0 | ptr->stream_id = NO_STREAM_ID_FILTER; |
323 | 0 | ptr->inv = INVERSION_AUTO; |
324 | 0 | ptr->bw = BANDWIDTH_AUTO; |
325 | 0 | ptr->cr = FEC_AUTO; |
326 | 0 | ptr->cr_lp = FEC_AUTO; |
327 | 0 | ptr->mod = QAM_AUTO; |
328 | 0 | ptr->hier = HIERARCHY_AUTO; |
329 | 0 | ptr->gi = GUARD_INTERVAL_AUTO; |
330 | 0 | ptr->trans = TRANSMISSION_MODE_AUTO; |
331 | | |
332 | | // Check if VDR-type channels.conf-line - then full line is consumed by the scan. |
333 | 0 | int fields, num_chars = 0; |
334 | 0 | fields = sscanf(&line[k], vdr_conf, |
335 | 0 | &ptr->freq, vdr_par_str, vdr_loc_str, &ptr->srate, |
336 | 0 | vpid_str, apid_str, tpid_str, &ptr->service_id, |
337 | 0 | &num_chars); |
338 | |
|
339 | 0 | bool is_vdr_conf = (num_chars == strlen(&line[k])); |
340 | | |
341 | | // Special case: DVB-T style ZAP config also has 13 columns. |
342 | | // Most columns should have non-numeric content, but some channel list generators insert 0 |
343 | | // if a value is not used. However, INVERSION_* should always set after frequency. |
344 | 0 | if (is_vdr_conf && !strncmp(vdr_par_str, "INVERSION_", 10)) { |
345 | 0 | is_vdr_conf = false; |
346 | 0 | } |
347 | |
|
348 | 0 | if (is_vdr_conf) { |
349 | | // Modulation parsed here, not via old xine-parsing path. |
350 | 0 | mod[0] = '\0'; |
351 | | // It's a VDR-style config line. |
352 | 0 | parse_vdr_par_string(vdr_par_str, ptr); |
353 | | // Frequency in VDR-style config files is in MHz for DVB-S, |
354 | | // and may be in MHz, kHz or Hz for DVB-C and DVB-T. |
355 | | // General rule to get useful units is to multiply by 1000 until value is larger than 1000000. |
356 | 0 | while (ptr->freq < 1000000U) { |
357 | 0 | ptr->freq *= 1000U; |
358 | 0 | } |
359 | | // Symbol rate in VDR-style config files is divided by 1000. |
360 | 0 | ptr->srate *= 1000U; |
361 | 0 | switch (delsys) { |
362 | 0 | case SYS_DVBT: |
363 | 0 | case SYS_DVBT2: |
364 | | /* Fix delsys value. */ |
365 | 0 | if (ptr->is_dvb_x2) { |
366 | 0 | ptr->delsys = delsys = SYS_DVBT2; |
367 | 0 | } else { |
368 | 0 | ptr->delsys = delsys = SYS_DVBT; |
369 | 0 | } |
370 | 0 | if (!DELSYS_IS_SET(delsys_mask, delsys)) |
371 | 0 | continue; /* Skip channel. */ |
372 | 0 | mp_verbose(log, "VDR, %s, NUM: %d, NUM_FIELDS: %d, NAME: %s, " |
373 | 0 | "FREQ: %d, SRATE: %d, T2: %s\n", |
374 | 0 | get_dvb_delsys(delsys), |
375 | 0 | list->NUM_CHANNELS, fields, |
376 | 0 | ptr->name, ptr->freq, ptr->srate, |
377 | 0 | (delsys == SYS_DVBT2) ? "yes" : "no"); |
378 | 0 | break; |
379 | 0 | case SYS_DVBC_ANNEX_A: |
380 | 0 | case SYS_DVBC_ANNEX_C: |
381 | 0 | case SYS_ATSC: |
382 | 0 | case SYS_DVBC_ANNEX_B: |
383 | 0 | case SYS_ISDBT: |
384 | 0 | mp_verbose(log, "VDR, %s, NUM: %d, NUM_FIELDS: %d, NAME: %s, " |
385 | 0 | "FREQ: %d, SRATE: %d\n", |
386 | 0 | get_dvb_delsys(delsys), |
387 | 0 | list->NUM_CHANNELS, fields, |
388 | 0 | ptr->name, ptr->freq, ptr->srate); |
389 | 0 | break; |
390 | 0 | case SYS_DVBS: |
391 | 0 | case SYS_DVBS2: |
392 | | /* Fix delsys value. */ |
393 | 0 | if (ptr->is_dvb_x2) { |
394 | 0 | ptr->delsys = delsys = SYS_DVBS2; |
395 | 0 | } else { |
396 | 0 | ptr->delsys = delsys = SYS_DVBS; |
397 | 0 | } |
398 | 0 | if (!DELSYS_IS_SET(delsys_mask, delsys)) |
399 | 0 | continue; /* Skip channel. */ |
400 | | |
401 | 0 | if (vdr_loc_str[0]) { |
402 | | // In older vdr config format, this field contained the DISEQc information. |
403 | | // If it is numeric, assume that's it. |
404 | 0 | int diseqc_info = 0; |
405 | 0 | int valid_digits = 0; |
406 | 0 | if (sscanf(vdr_loc_str, "%d%n", &diseqc_info, |
407 | 0 | &valid_digits) == 1) |
408 | 0 | { |
409 | 0 | if (valid_digits == strlen(vdr_loc_str)) { |
410 | 0 | ptr->diseqc = (unsigned int)diseqc_info; |
411 | 0 | if (ptr->diseqc > 4) |
412 | 0 | continue; |
413 | 0 | if (ptr->diseqc > 0) |
414 | 0 | ptr->diseqc--; |
415 | 0 | } |
416 | 0 | } |
417 | 0 | } |
418 | | |
419 | 0 | mp_verbose(log, "VDR, %s, NUM: %d, NUM_FIELDS: %d, NAME: %s, " |
420 | 0 | "FREQ: %d, SRATE: %d, POL: %c, DISEQC: %d, S2: %s, " |
421 | 0 | "StreamID: %d, SID: %d\n", |
422 | 0 | get_dvb_delsys(delsys), |
423 | 0 | list->NUM_CHANNELS, |
424 | 0 | fields, ptr->name, ptr->freq, ptr->srate, ptr->pol, |
425 | 0 | ptr->diseqc, (delsys == SYS_DVBS2) ? "yes" : "no", |
426 | 0 | ptr->stream_id, ptr->service_id); |
427 | 0 | break; |
428 | 0 | default: |
429 | 0 | break; |
430 | 0 | } |
431 | 0 | } else { |
432 | | // ZAP style channel config file. |
433 | 0 | switch (delsys) { |
434 | 0 | case SYS_DVBT: |
435 | 0 | case SYS_DVBT2: |
436 | 0 | case SYS_ISDBT: |
437 | 0 | fields = sscanf(&line[k], ter_conf, |
438 | 0 | &ptr->freq, inv, bw, cr, tmp_lcr, mod, |
439 | 0 | transm, gi, tmp_hier, vpid_str, apid_str); |
440 | 0 | mp_verbose(log, "%s, NUM: %d, NUM_FIELDS: %d, NAME: %s, FREQ: %d\n", |
441 | 0 | get_dvb_delsys(delsys), list->NUM_CHANNELS, |
442 | 0 | fields, ptr->name, ptr->freq); |
443 | 0 | break; |
444 | 0 | case SYS_DVBC_ANNEX_A: |
445 | 0 | case SYS_DVBC_ANNEX_C: |
446 | 0 | fields = sscanf(&line[k], cbl_conf, |
447 | 0 | &ptr->freq, inv, &ptr->srate, |
448 | 0 | cr, mod, vpid_str, apid_str); |
449 | 0 | mp_verbose(log, "%s, NUM: %d, NUM_FIELDS: %d, NAME: %s, FREQ: %d, " |
450 | 0 | "SRATE: %d\n", |
451 | 0 | get_dvb_delsys(delsys), |
452 | 0 | list->NUM_CHANNELS, fields, ptr->name, |
453 | 0 | ptr->freq, ptr->srate); |
454 | 0 | break; |
455 | 0 | case SYS_ATSC: |
456 | 0 | case SYS_DVBC_ANNEX_B: |
457 | 0 | fields = sscanf(&line[k], atsc_conf, |
458 | 0 | &ptr->freq, mod, vpid_str, apid_str); |
459 | 0 | mp_verbose(log, "%s, NUM: %d, NUM_FIELDS: %d, NAME: %s, FREQ: %d\n", |
460 | 0 | get_dvb_delsys(delsys), list->NUM_CHANNELS, |
461 | 0 | fields, ptr->name, ptr->freq); |
462 | 0 | break; |
463 | 0 | case SYS_DVBS: |
464 | 0 | case SYS_DVBS2: |
465 | 0 | fields = sscanf(&line[k], sat_conf, |
466 | 0 | &ptr->freq, &ptr->pol, &ptr->diseqc, &ptr->srate, |
467 | 0 | vpid_str, |
468 | 0 | apid_str); |
469 | 0 | ptr->pol = mp_toupper(ptr->pol); |
470 | 0 | ptr->freq *= 1000U; |
471 | 0 | ptr->srate *= 1000U; |
472 | 0 | if (ptr->diseqc > 4) |
473 | 0 | continue; |
474 | 0 | if (ptr->diseqc > 0) |
475 | 0 | ptr->diseqc--; |
476 | 0 | mp_verbose(log, "%s, NUM: %d, NUM_FIELDS: %d, NAME: %s, FREQ: %d, " |
477 | 0 | "SRATE: %d, POL: %c, DISEQC: %d\n", |
478 | 0 | get_dvb_delsys(delsys), |
479 | 0 | list->NUM_CHANNELS, fields, ptr->name, ptr->freq, |
480 | 0 | ptr->srate, ptr->pol, ptr->diseqc); |
481 | 0 | break; |
482 | 0 | default: |
483 | 0 | break; |
484 | 0 | } |
485 | 0 | } |
486 | | |
487 | 0 | if (parse_pid_string(log, vpid_str, ptr)) |
488 | 0 | fields++; |
489 | 0 | if (parse_pid_string(log, apid_str, ptr)) |
490 | 0 | fields++; |
491 | | /* If we do not know the service_id, PMT can not be extracted. |
492 | | Teletext decoding will fail without PMT. */ |
493 | 0 | if (ptr->service_id != -1) { |
494 | 0 | if (parse_pid_string(log, tpid_str, ptr)) |
495 | 0 | fields++; |
496 | 0 | } |
497 | | |
498 | |
|
499 | 0 | if (fields < 2 || ptr->pids_cnt == 0 || ptr->freq == 0 || |
500 | 0 | strlen(ptr->name) == 0) |
501 | 0 | continue; |
502 | | |
503 | | /* Add some PIDs which are mandatory in DVB, |
504 | | * and contain human-readable helpful data. */ |
505 | | |
506 | | /* This is the STD, the service description table. |
507 | | * It contains service names and such, ffmpeg decodes it. */ |
508 | 0 | ptr->pids[ptr->pids_cnt] = 0x0011; |
509 | 0 | ptr->pids_cnt++; |
510 | | |
511 | | /* This is the EIT, which contains EPG data. |
512 | | * ffmpeg can not decode it (yet), but e.g. VLC |
513 | | * shows what was recorded. */ |
514 | 0 | ptr->pids[ptr->pids_cnt] = 0x0012; |
515 | 0 | ptr->pids_cnt++; |
516 | |
|
517 | 0 | if (ptr->service_id != -1) { |
518 | | /* We have the PMT-PID in addition. |
519 | | This will be found later, when we tune to the channel. |
520 | | Push back here to create the additional demux. */ |
521 | 0 | ptr->pids[ptr->pids_cnt] = -1; // Placeholder. |
522 | 0 | ptr->pids_cnt++; |
523 | 0 | } |
524 | |
|
525 | 0 | bool has8192 = false, has0 = false; |
526 | 0 | for (int cnt = 0; cnt < ptr->pids_cnt; cnt++) { |
527 | 0 | if (ptr->pids[cnt] == 8192) |
528 | 0 | has8192 = true; |
529 | 0 | if (ptr->pids[cnt] == 0) |
530 | 0 | has0 = true; |
531 | 0 | } |
532 | | |
533 | | /* 8192 is the pseudo-PID for full TP dump, |
534 | | enforce that if requested. */ |
535 | 0 | if (!has8192 && cfg_full_transponder) |
536 | 0 | has8192 = 1; |
537 | 0 | if (has8192) { |
538 | 0 | ptr->pids[0] = 8192; |
539 | 0 | ptr->pids_cnt = 1; |
540 | 0 | } else if (!has0) { |
541 | 0 | ptr->pids[ptr->pids_cnt] = 0; //PID 0 is the PAT |
542 | 0 | ptr->pids_cnt++; |
543 | 0 | } |
544 | |
|
545 | 0 | mp_verbose(log, " PIDS: "); |
546 | 0 | for (int cnt = 0; cnt < ptr->pids_cnt; cnt++) |
547 | 0 | mp_verbose(log, " %d ", ptr->pids[cnt]); |
548 | 0 | mp_verbose(log, "\n"); |
549 | |
|
550 | 0 | switch (delsys) { |
551 | 0 | case SYS_DVBT: |
552 | 0 | case SYS_DVBT2: |
553 | 0 | case SYS_ISDBT: |
554 | 0 | case SYS_DVBC_ANNEX_A: |
555 | 0 | case SYS_DVBC_ANNEX_C: |
556 | 0 | if (!strcmp(inv, "INVERSION_ON")) { |
557 | 0 | ptr->inv = INVERSION_ON; |
558 | 0 | } else if (!strcmp(inv, "INVERSION_OFF")) { |
559 | 0 | ptr->inv = INVERSION_OFF; |
560 | 0 | } |
561 | |
|
562 | 0 | ptr->cr = parse_fec(cr); |
563 | 0 | } |
564 | |
|
565 | 0 | switch (delsys) { |
566 | 0 | case SYS_DVBT: |
567 | 0 | case SYS_DVBT2: |
568 | 0 | case SYS_ISDBT: |
569 | 0 | case SYS_DVBC_ANNEX_A: |
570 | 0 | case SYS_DVBC_ANNEX_C: |
571 | 0 | case SYS_ATSC: |
572 | 0 | case SYS_DVBC_ANNEX_B: |
573 | 0 | if (!strcmp(mod, "QAM_128")) { |
574 | 0 | ptr->mod = QAM_128; |
575 | 0 | } else if (!strcmp(mod, "QAM_256")) { |
576 | 0 | ptr->mod = QAM_256; |
577 | 0 | } else if (!strcmp(mod, "QAM_64")) { |
578 | 0 | ptr->mod = QAM_64; |
579 | 0 | } else if (!strcmp(mod, "QAM_32")) { |
580 | 0 | ptr->mod = QAM_32; |
581 | 0 | } else if (!strcmp(mod, "QAM_16")) { |
582 | 0 | ptr->mod = QAM_16; |
583 | 0 | } else if (!strcmp(mod, "VSB_8") || !strcmp(mod, "8VSB")) { |
584 | 0 | ptr->mod = VSB_8; |
585 | 0 | } else if (!strcmp(mod, "VSB_16") || !strcmp(mod, "16VSB")) { |
586 | 0 | ptr->mod = VSB_16; |
587 | 0 | } |
588 | 0 | } |
589 | | |
590 | | /* Modulation defines real delsys for ATSC: |
591 | | Terrestrial (VSB) is SYS_ATSC, Cable (QAM) is SYS_DVBC_ANNEX_B. */ |
592 | 0 | if (delsys == SYS_ATSC || delsys == SYS_DVBC_ANNEX_B) { |
593 | 0 | if (ptr->mod == VSB_8 || ptr->mod == VSB_16) { |
594 | 0 | delsys = SYS_ATSC; |
595 | 0 | } else { |
596 | 0 | delsys = SYS_DVBC_ANNEX_B; |
597 | 0 | } |
598 | 0 | if (!DELSYS_IS_SET(delsys_mask, delsys)) |
599 | 0 | continue; /* Skip channel. */ |
600 | 0 | mp_verbose(log, "Switched to delivery system for ATSC: %s (guessed from modulation)\n", |
601 | 0 | get_dvb_delsys(delsys)); |
602 | 0 | } |
603 | | |
604 | 0 | switch (delsys) { |
605 | 0 | case SYS_DVBT: |
606 | 0 | case SYS_DVBT2: |
607 | 0 | case SYS_ISDBT: |
608 | 0 | if (!strcmp(bw, "BANDWIDTH_5_MHZ")) { |
609 | 0 | ptr->bw = BANDWIDTH_5_MHZ; |
610 | 0 | } else if (!strcmp(bw, "BANDWIDTH_6_MHZ")) { |
611 | 0 | ptr->bw = BANDWIDTH_6_MHZ; |
612 | 0 | } else if (!strcmp(bw, "BANDWIDTH_7_MHZ")) { |
613 | 0 | ptr->bw = BANDWIDTH_7_MHZ; |
614 | 0 | } else if (!strcmp(bw, "BANDWIDTH_8_MHZ")) { |
615 | 0 | ptr->bw = BANDWIDTH_8_MHZ; |
616 | 0 | } else if (!strcmp(bw, "BANDWIDTH_10_MHZ")) { |
617 | 0 | ptr->bw = BANDWIDTH_10_MHZ; |
618 | 0 | } |
619 | | |
620 | |
|
621 | 0 | if (!strcmp(transm, "TRANSMISSION_MODE_2K")) { |
622 | 0 | ptr->trans = TRANSMISSION_MODE_2K; |
623 | 0 | } else if (!strcmp(transm, "TRANSMISSION_MODE_8K")) { |
624 | 0 | ptr->trans = TRANSMISSION_MODE_8K; |
625 | 0 | } else if (!strcmp(transm, "TRANSMISSION_MODE_AUTO")) { |
626 | 0 | ptr->trans = TRANSMISSION_MODE_AUTO; |
627 | 0 | } |
628 | |
|
629 | 0 | if (!strcmp(gi, "GUARD_INTERVAL_1_32")) { |
630 | 0 | ptr->gi = GUARD_INTERVAL_1_32; |
631 | 0 | } else if (!strcmp(gi, "GUARD_INTERVAL_1_16")) { |
632 | 0 | ptr->gi = GUARD_INTERVAL_1_16; |
633 | 0 | } else if (!strcmp(gi, "GUARD_INTERVAL_1_8")) { |
634 | 0 | ptr->gi = GUARD_INTERVAL_1_8; |
635 | 0 | } else if (!strcmp(gi, "GUARD_INTERVAL_1_4")) { |
636 | 0 | ptr->gi = GUARD_INTERVAL_1_4; |
637 | 0 | } |
638 | |
|
639 | 0 | ptr->cr_lp = parse_fec(tmp_lcr); |
640 | |
|
641 | 0 | if (!strcmp(tmp_hier, "HIERARCHY_1")) { |
642 | 0 | ptr->hier = HIERARCHY_1; |
643 | 0 | } else if (!strcmp(tmp_hier, "HIERARCHY_2")) { |
644 | 0 | ptr->hier = HIERARCHY_2; |
645 | 0 | } else if (!strcmp(tmp_hier, "HIERARCHY_4")) { |
646 | 0 | ptr->hier = HIERARCHY_4; |
647 | 0 | } else if (!strcmp(tmp_hier, "HIERARCHY_NONE")) { |
648 | 0 | ptr->hier = HIERARCHY_NONE; |
649 | 0 | } |
650 | 0 | } |
651 | |
|
652 | 0 | MP_TARRAY_APPEND(list, list->channels, list->NUM_CHANNELS, *ptr); |
653 | 0 | } |
654 | | |
655 | 0 | fclose(f); |
656 | 0 | if (list->NUM_CHANNELS == 0) |
657 | 0 | TA_FREEP(&list); |
658 | |
|
659 | 0 | return list; |
660 | 0 | } |
661 | | |
662 | | static int dvb_streaming_read(stream_t *stream, void *buffer, int size) |
663 | 0 | { |
664 | 0 | dvb_priv_t *priv = stream->priv; |
665 | 0 | dvb_state_t *state = priv->state; |
666 | 0 | int pos = 0; |
667 | 0 | int tries = state->retry; |
668 | 0 | const int fd = state->dvr_fd; |
669 | |
|
670 | 0 | MP_TRACE(stream, "dvb_streaming_read(%d)\n", size); |
671 | |
|
672 | 0 | struct pollfd pfds[1]; |
673 | 0 | pfds[0].fd = fd; |
674 | 0 | pfds[0].events = POLLIN | POLLPRI; |
675 | |
|
676 | 0 | while (pos < size) { |
677 | 0 | int rk = read(fd, (char *)buffer + pos, (size - pos)); |
678 | 0 | if (rk <= 0) { |
679 | 0 | if (pos || tries == 0) |
680 | 0 | break; |
681 | 0 | tries--; |
682 | 0 | if (mp_poll(pfds, 1, MP_TIME_S_TO_NS(2)) <= 0) { |
683 | 0 | MP_ERR(stream, "dvb_streaming_read: failed with " |
684 | 0 | "errno %d when reading %d bytes\n", errno, size - pos); |
685 | 0 | errno = 0; |
686 | 0 | break; |
687 | 0 | } |
688 | 0 | continue; |
689 | 0 | } |
690 | 0 | pos += rk; |
691 | 0 | MP_TRACE(stream, "got %d bytes\n", pos); |
692 | 0 | } |
693 | |
|
694 | 0 | if (!pos) |
695 | 0 | MP_ERR(stream, "dvb_streaming_read: returning 0 bytes\n"); |
696 | | |
697 | | // Check if config parameters have been updated. |
698 | 0 | dvb_update_config(stream); |
699 | |
|
700 | 0 | return pos; |
701 | 0 | } |
702 | | |
703 | | int dvb_set_channel(stream_t *stream, unsigned int adapter, unsigned int n) |
704 | 0 | { |
705 | 0 | dvb_priv_t *priv = stream->priv; |
706 | 0 | dvb_state_t *state = priv->state; |
707 | |
|
708 | 0 | mp_assert(adapter < state->adapters_count); |
709 | 0 | int devno = state->adapters[adapter].devno; |
710 | 0 | dvb_channels_list_t *new_list = state->adapters[adapter].list; |
711 | 0 | mp_assert(n < new_list->NUM_CHANNELS); |
712 | 0 | dvb_channel_t *channel = &(new_list->channels[n]); |
713 | |
|
714 | 0 | if (state->is_on) { //the fds are already open and we have to stop the demuxers |
715 | | /* Remove all demuxes. */ |
716 | 0 | dvb_fix_demuxes(priv, 0); |
717 | |
|
718 | 0 | state->retry = 0; |
719 | | // empty both the stream's and driver's buffer |
720 | 0 | char buf[4096]; |
721 | 0 | while (dvb_streaming_read(stream, buf, sizeof(buf)) > 0) {} |
722 | |
|
723 | 0 | if (state->cur_adapter != adapter || |
724 | 0 | state->cur_frontend != channel->frontend) { |
725 | 0 | dvbin_close(stream); |
726 | 0 | if (!dvb_open_devices(priv, devno, channel->frontend, channel->pids_cnt)) { |
727 | 0 | MP_ERR(stream, "dvb_set_channel: couldn't open devices of adapter " |
728 | 0 | "%d\n", devno); |
729 | 0 | return 0; |
730 | 0 | } |
731 | 0 | } else { |
732 | | // close all demux_fds with pos > pids required for the new channel |
733 | | // or open other demux_fds if we have too few |
734 | 0 | if (!dvb_fix_demuxes(priv, channel->pids_cnt)) |
735 | 0 | return 0; |
736 | 0 | } |
737 | 0 | } else { |
738 | 0 | if (!dvb_open_devices(priv, devno, channel->frontend, channel->pids_cnt)) { |
739 | 0 | MP_ERR(stream, "dvb_set_channel: couldn't open devices of adapter " |
740 | 0 | "%d\n", devno); |
741 | 0 | return 0; |
742 | 0 | } |
743 | 0 | } |
744 | | |
745 | 0 | state->retry = 5; |
746 | 0 | new_list->current = n; |
747 | 0 | MP_VERBOSE(stream, "dvb_set_channel: new channel name=\"%s\", adapter: %d, " |
748 | 0 | "channel: %d\n", channel->name, devno, n); |
749 | |
|
750 | 0 | if (channel->freq != state->last_freq) { |
751 | 0 | if (!dvb_tune(priv, channel->delsys, channel->freq, |
752 | 0 | channel->pol, channel->srate, channel->diseqc, |
753 | 0 | channel->stream_id, channel->inv, |
754 | 0 | channel->mod, channel->gi, |
755 | 0 | channel->trans, channel->bw, channel->cr, channel->cr_lp, |
756 | 0 | channel->hier, priv->opts->cfg_timeout)) |
757 | 0 | return 0; |
758 | 0 | } |
759 | | |
760 | 0 | state->is_on = true; |
761 | 0 | state->last_freq = channel->freq; |
762 | 0 | state->cur_adapter = adapter; |
763 | 0 | state->cur_frontend = channel->frontend; |
764 | |
|
765 | 0 | if (channel->service_id != -1) { |
766 | | /* We need the PMT-PID in addition. |
767 | | If it has not yet beem resolved, do it now. */ |
768 | 0 | for (int i = 0; i < channel->pids_cnt; i++) { |
769 | 0 | if (channel->pids[i] == -1) { |
770 | 0 | MP_VERBOSE(stream, "dvb_set_channel: PMT-PID for service %d " |
771 | 0 | "not resolved yet, parsing PAT...\n", |
772 | 0 | channel->service_id); |
773 | 0 | int pmt_pid = dvb_get_pmt_pid(priv, adapter, channel->service_id); |
774 | 0 | MP_VERBOSE(stream, "found PMT-PID: %d\n", pmt_pid); |
775 | 0 | channel->pids[i] = pmt_pid; |
776 | 0 | break; |
777 | 0 | } |
778 | 0 | } |
779 | 0 | } |
780 | | |
781 | | // sets demux filters and restart the stream |
782 | 0 | for (int i = 0; i < channel->pids_cnt; i++) { |
783 | 0 | if (channel->pids[i] == -1) { |
784 | | // In case PMT was not resolved, skip it here. |
785 | 0 | MP_ERR(stream, "dvb_set_channel: PMT-PID not found, " |
786 | 0 | "teletext decoding may fail.\n"); |
787 | 0 | continue; |
788 | 0 | } |
789 | 0 | if (!dvb_set_ts_filt(priv, state->demux_fds[i], channel->pids[i], |
790 | 0 | DMX_PES_OTHER)) |
791 | 0 | return 0; |
792 | 0 | } |
793 | | |
794 | 0 | return 1; |
795 | 0 | } |
796 | | |
797 | | static int dvbin_stream_control(struct stream *s, int cmd, void *arg) |
798 | 0 | { |
799 | 0 | dvb_priv_t *priv = s->priv; |
800 | 0 | dvb_state_t *state = priv->state; |
801 | |
|
802 | 0 | if (state->cur_adapter >= state->adapters_count) |
803 | 0 | return STREAM_ERROR; |
804 | 0 | dvb_channels_list_t *list = state->adapters[state->cur_adapter].list; |
805 | |
|
806 | 0 | switch (cmd) { |
807 | 0 | case STREAM_CTRL_GET_METADATA: { |
808 | 0 | struct mp_tags *metadata = talloc_zero(NULL, struct mp_tags); |
809 | 0 | char *progname = list->channels[list->current].name; |
810 | 0 | mp_tags_set_str(metadata, "title", progname); |
811 | 0 | *(struct mp_tags **)arg = metadata; |
812 | 0 | return STREAM_OK; |
813 | 0 | } |
814 | 0 | } |
815 | 0 | return STREAM_UNSUPPORTED; |
816 | 0 | } |
817 | | |
818 | | void dvbin_close(stream_t *stream) |
819 | 0 | { |
820 | 0 | dvb_priv_t *priv = stream->priv; |
821 | 0 | dvb_state_t *state = priv->state; |
822 | |
|
823 | 0 | if (state->switching_channel && state->is_on) { |
824 | | // Prevent state destruction, reset channel-switch. |
825 | 0 | state->switching_channel = false; |
826 | 0 | mp_mutex_lock(&global_dvb_state_lock); |
827 | 0 | global_dvb_state->stream_used = false; |
828 | 0 | mp_mutex_unlock(&global_dvb_state_lock); |
829 | 0 | return; |
830 | 0 | } |
831 | | |
832 | 0 | for (int i = state->demux_fds_cnt - 1; i >= 0; i--) { |
833 | 0 | state->demux_fds_cnt--; |
834 | 0 | close(state->demux_fds[i]); |
835 | 0 | } |
836 | 0 | close(state->dvr_fd); |
837 | 0 | close(state->fe_fd); |
838 | 0 | state->fe_fd = state->dvr_fd = -1; |
839 | |
|
840 | 0 | state->is_on = false; |
841 | 0 | state->cur_adapter = -1; |
842 | 0 | state->cur_frontend = -1; |
843 | |
|
844 | 0 | mp_mutex_lock(&global_dvb_state_lock); |
845 | 0 | TA_FREEP(&global_dvb_state); |
846 | 0 | mp_mutex_unlock(&global_dvb_state_lock); |
847 | 0 | } |
848 | | |
849 | | static int dvb_streaming_start(stream_t *stream, char *progname) |
850 | 0 | { |
851 | 0 | dvb_priv_t *priv = stream->priv; |
852 | 0 | dvb_state_t *state = priv->state; |
853 | |
|
854 | 0 | if (!progname) |
855 | 0 | return 0; |
856 | | |
857 | 0 | dvb_channels_list_t *list = state->adapters[state->cur_adapter].list; |
858 | 0 | dvb_channel_t *channel = NULL; |
859 | 0 | int i; |
860 | 0 | for (i = 0; i < list->NUM_CHANNELS; i ++) { |
861 | 0 | if (!strcmp(list->channels[i].name, progname)) { |
862 | 0 | channel = &(list->channels[i]); |
863 | 0 | break; |
864 | 0 | } |
865 | 0 | } |
866 | |
|
867 | 0 | if (!channel) { |
868 | 0 | MP_ERR(stream, "no such channel \"%s\"\n", progname); |
869 | 0 | return 0; |
870 | 0 | } |
871 | 0 | list->current = i; |
872 | | |
873 | | // When switching channels, cfg_channel_switch_offset |
874 | | // keeps the offset to the initially chosen channel. |
875 | 0 | list->current = (list->NUM_CHANNELS + list->current + |
876 | 0 | priv->opts->cfg_channel_switch_offset) % list->NUM_CHANNELS; |
877 | 0 | channel = &(list->channels[list->current]); |
878 | 0 | MP_INFO(stream, "Tuning to channel \"%s\"...\n", channel->name); |
879 | 0 | MP_VERBOSE(stream, "Program number %d: name=\"%s\", freq=%u\n", i, |
880 | 0 | channel->name, channel->freq); |
881 | |
|
882 | 0 | if (!dvb_set_channel(stream, state->cur_adapter, list->current)) { |
883 | 0 | dvbin_close(stream); |
884 | 0 | return 0; |
885 | 0 | } |
886 | | |
887 | 0 | return 1; |
888 | 0 | } |
889 | | |
890 | | void dvb_update_config(stream_t *stream) |
891 | 0 | { |
892 | 0 | dvb_priv_t *priv = stream->priv; |
893 | 0 | dvb_state_t *state = priv->state; |
894 | | |
895 | | // Throttle the check to at maximum once every 0.1 s. |
896 | 0 | int now = (int)(mp_time_sec()*10); |
897 | 0 | if (now == priv->opts_check_time) |
898 | 0 | return; |
899 | 0 | priv->opts_check_time = now; |
900 | |
|
901 | 0 | if (!m_config_cache_update(priv->opts_cache)) |
902 | 0 | return; |
903 | | |
904 | | // Re-parse stream path, if we have cfg parameters now, |
905 | | // these should be preferred. |
906 | 0 | if (!dvb_parse_path(stream)) { |
907 | 0 | MP_ERR(stream, "error parsing DVB config, not tuning."); |
908 | 0 | return; |
909 | 0 | } |
910 | | |
911 | 0 | int r = dvb_streaming_start(stream, priv->prog); |
912 | 0 | if (r) { |
913 | | // Stream will be pulled down after channel switch, |
914 | | // persist state. |
915 | 0 | state->switching_channel = true; |
916 | 0 | } |
917 | 0 | } |
918 | | |
919 | | static int dvb_open(stream_t *stream) |
920 | 686 | { |
921 | 686 | dvb_priv_t *priv = NULL; |
922 | | |
923 | 686 | mp_mutex_lock(&global_dvb_state_lock); |
924 | 686 | if (global_dvb_state && global_dvb_state->stream_used) { |
925 | 0 | MP_ERR(stream, "DVB stream already in use, only one DVB stream can exist at a time!\n"); |
926 | 0 | mp_mutex_unlock(&global_dvb_state_lock); |
927 | 0 | goto err_out; |
928 | 0 | } |
929 | | |
930 | | // Need to re-get config in any case, not part of global state. |
931 | 686 | stream->priv = talloc_zero(stream, dvb_priv_t); |
932 | 686 | priv = stream->priv; |
933 | 686 | priv->opts_cache = m_config_cache_alloc(stream, stream->global, &stream_dvb_conf); |
934 | 686 | priv->opts = priv->opts_cache->opts; |
935 | | |
936 | 686 | dvb_state_t *state = dvb_get_state(stream); |
937 | | |
938 | 686 | priv->state = state; |
939 | 686 | priv->log = stream->log; |
940 | 686 | if (!state) { |
941 | 686 | MP_ERR(stream, "DVB configuration is empty\n"); |
942 | 686 | mp_mutex_unlock(&global_dvb_state_lock); |
943 | 686 | goto err_out; |
944 | 686 | } |
945 | | |
946 | 0 | if (!dvb_parse_path(stream)) { |
947 | 0 | mp_mutex_unlock(&global_dvb_state_lock); |
948 | 0 | goto err_out; |
949 | 0 | } |
950 | | |
951 | 0 | state->stream_used = true; |
952 | 0 | mp_mutex_unlock(&global_dvb_state_lock); |
953 | |
|
954 | 0 | if (!state->is_on) { |
955 | | // State could be already initialized, for example, we just did a channel switch. |
956 | | // The following setup only has to be done once. |
957 | |
|
958 | 0 | state->cur_frontend = -1; |
959 | |
|
960 | 0 | if (!dvb_streaming_start(stream, priv->prog)) |
961 | 0 | goto err_out; |
962 | 0 | } |
963 | | |
964 | 0 | stream->fill_buffer = dvb_streaming_read; |
965 | 0 | stream->close = dvbin_close; |
966 | 0 | stream->control = dvbin_stream_control; |
967 | 0 | stream->streaming = true; |
968 | 0 | stream->demuxer = "lavf"; |
969 | 0 | stream->lavf_type = "mpegts"; |
970 | |
|
971 | 0 | return STREAM_OK; |
972 | | |
973 | 686 | err_out: |
974 | 686 | talloc_free(priv); |
975 | 686 | stream->priv = NULL; |
976 | 686 | return STREAM_ERROR; |
977 | 0 | } |
978 | | |
979 | | int dvb_parse_path(stream_t *stream) |
980 | 0 | { |
981 | 0 | dvb_priv_t *priv = stream->priv; |
982 | 0 | dvb_state_t *state = priv->state; |
983 | | |
984 | | // Parse stream path. Common rule: cfg wins over stream path, |
985 | | // since cfg may be changed at runtime. |
986 | 0 | bstr prog, devno; |
987 | 0 | if (!bstr_split_tok(bstr0(stream->path), "@", &devno, &prog)) { |
988 | 0 | prog = devno; |
989 | 0 | devno.len = 0; |
990 | 0 | } |
991 | |
|
992 | 0 | if (priv->opts->cfg_devno != 0) { |
993 | 0 | priv->devno = priv->opts->cfg_devno; |
994 | 0 | } else if (devno.len) { |
995 | 0 | bstr r; |
996 | 0 | priv->devno = bstrtoll(devno, &r, 0); |
997 | 0 | if (r.len || priv->devno < 0 || priv->devno >= MAX_ADAPTERS) { |
998 | 0 | MP_ERR(stream, "invalid devno: '%.*s'\n", BSTR_P(devno)); |
999 | 0 | return 0; |
1000 | 0 | } |
1001 | 0 | } else { |
1002 | | // Default to the default of cfg_devno. |
1003 | 0 | priv->devno = priv->opts->cfg_devno; |
1004 | 0 | } |
1005 | | |
1006 | | // Current adapter is derived from devno. |
1007 | 0 | state->cur_adapter = -1; |
1008 | 0 | for (int i = 0; i < state->adapters_count; i++) { |
1009 | 0 | if (state->adapters[i].devno == priv->devno) { |
1010 | 0 | state->cur_adapter = i; |
1011 | 0 | break; |
1012 | 0 | } |
1013 | 0 | } |
1014 | |
|
1015 | 0 | if (state->cur_adapter == -1) { |
1016 | 0 | MP_ERR(stream, "No configuration found for adapter %d!\n", |
1017 | 0 | priv->devno); |
1018 | 0 | return 0; |
1019 | 0 | } |
1020 | | |
1021 | 0 | char *new_prog = NULL; |
1022 | 0 | if (priv->opts->cfg_prog != NULL && strlen(priv->opts->cfg_prog) > 0) { |
1023 | 0 | new_prog = talloc_strdup(priv, priv->opts->cfg_prog); |
1024 | 0 | } else if (prog.len) { |
1025 | 0 | new_prog = bstrto0(priv, prog); |
1026 | 0 | } else { |
1027 | | // We use the first program from the channel list. |
1028 | 0 | dvb_channels_list_t *list = state->adapters[state->cur_adapter].list; |
1029 | 0 | if (!list) { |
1030 | 0 | MP_ERR(stream, "No channel list available for adapter %d!\n", priv->devno); |
1031 | 0 | return 0; |
1032 | 0 | } |
1033 | 0 | new_prog = talloc_strdup(priv, list->channels[0].name); |
1034 | 0 | } |
1035 | 0 | talloc_free(priv->prog); |
1036 | 0 | priv->prog = new_prog; |
1037 | |
|
1038 | 0 | MP_VERBOSE(stream, "dvb_config: prog=\"%s\", devno=%d\n", |
1039 | 0 | priv->prog, priv->devno); |
1040 | 0 | return 1; |
1041 | 0 | } |
1042 | | |
1043 | | dvb_state_t *dvb_get_state(stream_t *stream) |
1044 | 686 | { |
1045 | 686 | dvb_priv_t *priv = stream->priv; |
1046 | 686 | if (global_dvb_state) |
1047 | 0 | return global_dvb_state; |
1048 | | |
1049 | 686 | struct mp_log *log = stream->log; |
1050 | 686 | struct mpv_global *global = stream->global; |
1051 | | |
1052 | 686 | dvb_state_t *state = talloc_zero(NULL, dvb_state_t); |
1053 | 686 | state->switching_channel = false; |
1054 | 686 | state->is_on = false; |
1055 | 686 | state->stream_used = true; |
1056 | 686 | state->fe_fd = state->dvr_fd = -1; |
1057 | | |
1058 | 11.6k | for (unsigned int i = 0; i < MAX_ADAPTERS; i++) { |
1059 | 10.9k | dvb_channels_list_t *list = NULL; |
1060 | 10.9k | unsigned int delsys_mask[MAX_FRONTENDS]; |
1061 | 98.7k | for (unsigned int f = 0; f < MAX_FRONTENDS; f++) { |
1062 | 87.8k | char filename[100]; |
1063 | 87.8k | snprintf(filename, sizeof(filename), "/dev/dvb/adapter%u/frontend%u", i, f); |
1064 | 87.8k | int fd = open(filename, O_RDONLY | O_NONBLOCK | O_CLOEXEC); |
1065 | 87.8k | if (fd < 0) |
1066 | 87.8k | continue; |
1067 | | |
1068 | 0 | delsys_mask[f] = dvb_get_tuner_delsys_mask(fd, log); |
1069 | 0 | delsys_mask[f] &= DELSYS_SUPP_MASK; /* Filter unsupported delivery systems. */ |
1070 | 0 | close(fd); |
1071 | 0 | if (delsys_mask[f] == 0) { |
1072 | 0 | mp_verbose(log, "Frontend device %s has no supported delivery systems.\n", |
1073 | 0 | filename); |
1074 | 0 | continue; /* Skip tuner. */ |
1075 | 0 | } |
1076 | | |
1077 | | /* Create channel list for adapter. */ |
1078 | 0 | for (unsigned int delsys = 0; delsys < SYS_DVB__COUNT__; delsys++) { |
1079 | 0 | if (!DELSYS_IS_SET(delsys_mask[f], delsys)) |
1080 | 0 | continue; /* Skip unsupported. */ |
1081 | | |
1082 | 0 | mp_verbose(log, "Searching channel list for delivery system %s\n", get_dvb_delsys(delsys)); |
1083 | 0 | const char *conf_file_name; |
1084 | 0 | switch (delsys) { |
1085 | 0 | case SYS_DVBC_ANNEX_A: |
1086 | 0 | case SYS_DVBC_ANNEX_C: |
1087 | 0 | conf_file_name = "channels.conf.cbl"; |
1088 | 0 | break; |
1089 | 0 | case SYS_ATSC: |
1090 | 0 | conf_file_name = "channels.conf.atsc"; |
1091 | 0 | break; |
1092 | 0 | case SYS_DVBT: |
1093 | 0 | if (DELSYS_IS_SET(delsys_mask[f], SYS_DVBT2)) |
1094 | 0 | continue; /* Add all channels later with T2. */ |
1095 | 0 | conf_file_name = "channels.conf.ter"; |
1096 | 0 | break; |
1097 | 0 | case SYS_DVBT2: |
1098 | 0 | conf_file_name = "channels.conf.ter"; |
1099 | 0 | break; |
1100 | 0 | case SYS_ISDBT: |
1101 | 0 | conf_file_name = "channels.conf.isdbt"; |
1102 | 0 | break; |
1103 | 0 | case SYS_DVBS: |
1104 | 0 | if (DELSYS_IS_SET(delsys_mask[f], SYS_DVBS2)) |
1105 | 0 | continue; /* Add all channels later with S2. */ |
1106 | 0 | conf_file_name = "channels.conf.sat"; |
1107 | 0 | break; |
1108 | 0 | case SYS_DVBS2: |
1109 | 0 | conf_file_name = "channels.conf.sat"; |
1110 | 0 | break; |
1111 | 0 | default: |
1112 | 0 | continue; |
1113 | 0 | } |
1114 | | |
1115 | 0 | void *talloc_ctx = talloc_new(NULL); |
1116 | 0 | char *conf_file; |
1117 | 0 | if (priv->opts->cfg_file && priv->opts->cfg_file[0]) { |
1118 | 0 | conf_file = mp_get_user_path(talloc_ctx, global, priv->opts->cfg_file); |
1119 | 0 | } else { |
1120 | 0 | conf_file = mp_find_config_file(talloc_ctx, global, conf_file_name); |
1121 | 0 | if (conf_file) { |
1122 | 0 | mp_verbose(log, "Ignoring other channels.conf files.\n"); |
1123 | 0 | } else { |
1124 | 0 | conf_file = mp_find_config_file(talloc_ctx, global, |
1125 | 0 | "channels.conf"); |
1126 | 0 | } |
1127 | 0 | } |
1128 | |
|
1129 | 0 | list = dvb_get_channels(log, list, priv->opts->cfg_full_transponder, |
1130 | 0 | conf_file, f, delsys, delsys_mask[f]); |
1131 | 0 | talloc_free(talloc_ctx); |
1132 | 0 | } |
1133 | 0 | } |
1134 | | /* Add adapter with non zero channel list. */ |
1135 | 10.9k | if (!list) |
1136 | 10.9k | continue; |
1137 | | |
1138 | 0 | dvb_adapter_config_t tmp = { |
1139 | 0 | .devno = i, |
1140 | 0 | .list = talloc_steal(state, list), |
1141 | 0 | }; |
1142 | 0 | memcpy(&tmp.delsys_mask, delsys_mask, sizeof(delsys_mask)); |
1143 | |
|
1144 | 0 | MP_TARRAY_APPEND(state, state->adapters, state->adapters_count, tmp); |
1145 | |
|
1146 | 0 | mp_verbose(log, "Added adapter with channels to state list, now %d.\n", |
1147 | 0 | state->adapters_count); |
1148 | 0 | } |
1149 | | |
1150 | 686 | if (state->adapters_count == 0) |
1151 | 686 | TA_FREEP(&state); |
1152 | | |
1153 | 686 | global_dvb_state = state; |
1154 | 686 | return state; |
1155 | 686 | } |
1156 | | |
1157 | | const stream_info_t stream_info_dvb = { |
1158 | | .name = "dvbin", |
1159 | | .open = dvb_open, |
1160 | | .protocols = (const char *const[]){ "dvb", NULL }, |
1161 | | .stream_origin = STREAM_ORIGIN_UNSAFE, |
1162 | | }; |