• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2011-2012 - Mauro Carvalho Chehab
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU Lesser General Public License as published by
6  * the Free Software Foundation version 2.1 of the License.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * GNU Lesser General Public License for more details.
12  *
13  * You should have received a copy of the GNU Lesser General Public License
14  * along with this program; if not, write to the Free Software
15  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16  * Or, point your browser to http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
17  */
18 
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 
23 #include <libdvbv5/dvb-file.h>
24 #include <libdvbv5/dvb-v5-std.h>
25 
26 #ifdef ENABLE_NLS
27 # include "gettext.h"
28 # include <libintl.h>
29 # define _(string) dgettext(LIBDVBV5_DOMAIN, string)
30 
31 #else
32 # define _(string) string
33 #endif
34 
35 # define N_(string) string
36 
37 
38 #define PTABLE(a) .table = a, .size=ARRAY_SIZE(a)
39 
40 /*
41  * Standard channel.conf format for DVB-T, DVB-C, DVB-S, DVB-S2 and ATSC
42  */
43 static const char *vdr_parse_bandwidth[] = {
44 	[BANDWIDTH_1_712_MHZ] = "B1712",
45 	[BANDWIDTH_5_MHZ] =     "B5",
46 	[BANDWIDTH_6_MHZ] =     "B6",
47 	[BANDWIDTH_7_MHZ] =     "B7",
48 	[BANDWIDTH_8_MHZ] =     "B8",
49 	[BANDWIDTH_10_MHZ] =    "B10",
50 	[BANDWIDTH_AUTO] =      "B999",
51 };
52 
53 static const char *vdr_parse_code_rate_hp[12] = {
54 	[FEC_NONE] = "C0",
55 	[FEC_1_2] =  "C12",
56 	[FEC_2_3] =  "C23",
57 	[FEC_3_4] =  "C34",
58 	[FEC_3_5] =  "C35",
59 	[FEC_4_5] =  "C45",
60 	[FEC_5_6] =  "C56",
61 	[FEC_6_7] =  "C67",
62 	[FEC_7_8] =  "C78",
63 	[FEC_8_9] =  "C89",
64 	[FEC_9_10] = "C910",
65 	[FEC_AUTO] = "C999",
66 };
67 
68 static const char *vdr_parse_code_rate_lp[12] = {
69 	[FEC_NONE] = "D0",
70 	[FEC_1_2] =  "D12",
71 	[FEC_2_3] =  "D23",
72 	[FEC_3_4] =  "D34",
73 	[FEC_3_5] =  "D35",
74 	[FEC_4_5] =  "D45",
75 	[FEC_5_6] =  "D56",
76 	[FEC_6_7] =  "D67",
77 	[FEC_7_8] =  "D78",
78 	[FEC_8_9] =  "D89",
79 	[FEC_9_10] = "D910",
80 	[FEC_AUTO] = "D999",
81 };
82 static const char *vdr_parse_guard_interval[] = {
83 	[GUARD_INTERVAL_1_4] =    "G4",
84 	[GUARD_INTERVAL_1_8] =    "G8",
85 	[GUARD_INTERVAL_1_16] =   "G16",
86 	[GUARD_INTERVAL_1_32] =   "G32",
87 	[GUARD_INTERVAL_1_128] =  "G128",
88 	[GUARD_INTERVAL_19_128] = "G19128",
89 	[GUARD_INTERVAL_19_256] = "G19256",
90 	[GUARD_INTERVAL_AUTO] =   "G999",
91 };
92 
93 static const char *vdr_parse_polarization[] = {
94 	[POLARIZATION_OFF] = "",
95 	[POLARIZATION_H] =   "H",
96 	[POLARIZATION_V] =   "V",
97 	[POLARIZATION_L] =   "L",
98 	[POLARIZATION_R] =   "R",
99 };
100 
101 static const char *vdr_parse_inversion[] = {
102 	[INVERSION_OFF]  = "I0",
103 	[INVERSION_ON]   = "I1",
104 	[INVERSION_AUTO] = "I999",
105 };
106 
107 static const char *vdr_parse_modulation[] = {
108 	[QAM_16] =   "M16",
109 	[QAM_32] =   "M32",
110 	[QAM_64] =   "M64",
111 	[QAM_128] =  "M128",
112 	[QAM_256] =  "M256",
113 	[QPSK] =     "M2",
114 	[PSK_8] =    "M5",
115 	[APSK_16] =  "M6",
116 	[APSK_32] =  "M7",
117 	[VSB_8] =    "M10",
118 	[VSB_16] =   "M11",
119 	[DQPSK] =    "M12",
120 	[QAM_AUTO] = "M999",
121 };
122 
123 static const char *vdr_parse_pilot[] = {
124 	[PILOT_OFF] =  "N0",
125 	[PILOT_ON] =   "N1",
126 	[PILOT_AUTO] = "N999",
127 };
128 
129 static const char *vdr_parse_rolloff[] = {
130 	[ROLLOFF_AUTO] = "O0",
131 	[ROLLOFF_20]   = "O20",
132 	[ROLLOFF_25]   = "O25",
133 	[ROLLOFF_35]   = "O35",
134 };
135 
136 static const char *vdr_parse_trans_mode[] = {
137 	[TRANSMISSION_MODE_1K] =   "T1",
138 	[TRANSMISSION_MODE_2K] =   "T2",
139 	[TRANSMISSION_MODE_4K] =   "T4",
140 	[TRANSMISSION_MODE_8K] =   "T8",
141 	[TRANSMISSION_MODE_16K] =  "T16",
142 	[TRANSMISSION_MODE_32K] =  "T32",
143 	[TRANSMISSION_MODE_AUTO] = "T999",
144 };
145 
146 static const char *vdr_parse_hierarchy[] = {
147 	[HIERARCHY_1] =    "Y1",
148 	[HIERARCHY_2] =    "Y2",
149 	[HIERARCHY_4] =    "Y4",
150 	[HIERARCHY_AUTO] = "Y999",
151 	[HIERARCHY_NONE] = "Y0",
152 };
153 
154 static const char *vdr_parse_delivery_system[] = {
155 	[SYS_DVBS]  = "S0",
156 	[SYS_DVBS2] = "S1",
157 	[SYS_DVBT]  = "S0",
158 	[SYS_DVBT2] = "S1",
159 };
160 
161 /*
162  * The tables below deal only with the "Parameters" part of the VDR
163  * format.
164  */
165 static const struct dvb_parse_table sys_atsc_table[] = {
166 	{ DTV_MODULATION, PTABLE(vdr_parse_modulation) },
167 	{ DTV_INVERSION, PTABLE(vdr_parse_inversion) },
168 };
169 
170 static const struct dvb_parse_table sys_dvbc_table[] = {
171 	{ DTV_SYMBOL_RATE, NULL, 0 },
172 	{ DTV_INNER_FEC, PTABLE(vdr_parse_code_rate_hp) },
173 	{ DTV_MODULATION, PTABLE(vdr_parse_modulation) },
174 	{ DTV_INVERSION, PTABLE(vdr_parse_inversion) },
175 };
176 
177 static const struct dvb_parse_table sys_dvbs_table[] = {
178 	{ DTV_DELIVERY_SYSTEM, PTABLE(vdr_parse_delivery_system) },
179 	{ DTV_POLARIZATION, PTABLE(vdr_parse_polarization) },
180 	{ DTV_SYMBOL_RATE, NULL, 0 },
181 	{ DTV_INNER_FEC, PTABLE(vdr_parse_code_rate_hp) },
182 	{ DTV_INVERSION, PTABLE(vdr_parse_inversion) },
183 };
184 
185 static const struct dvb_parse_table sys_dvbs2_table[] = {
186 	{ DTV_DELIVERY_SYSTEM, PTABLE(vdr_parse_delivery_system) },
187 	{ DTV_POLARIZATION, PTABLE(vdr_parse_polarization) },
188 	{ DTV_SYMBOL_RATE, NULL, 0 },
189 	{ DTV_INNER_FEC, PTABLE(vdr_parse_code_rate_hp) },
190 	{ DTV_INVERSION, PTABLE(vdr_parse_inversion) },
191 	/* DVB-S2 specifics */
192 	{ DTV_MODULATION, PTABLE(vdr_parse_modulation) },
193 	{ DTV_PILOT, PTABLE(vdr_parse_pilot) },
194 	{ DTV_ROLLOFF, PTABLE(vdr_parse_rolloff) },
195 	{ DTV_STREAM_ID, NULL, },
196 };
197 
198 static const struct dvb_parse_table sys_dvbt_table[] = {
199 	{ DTV_BANDWIDTH_HZ, PTABLE(vdr_parse_bandwidth) },
200 	{ DTV_CODE_RATE_HP, PTABLE(vdr_parse_code_rate_hp) },
201 	{ DTV_CODE_RATE_LP, PTABLE(vdr_parse_code_rate_lp) },
202 	{ DTV_GUARD_INTERVAL, PTABLE(vdr_parse_guard_interval) },
203 	{ DTV_INVERSION, PTABLE(vdr_parse_inversion) },
204 	{ DTV_MODULATION, PTABLE(vdr_parse_modulation) },
205 	{ DTV_DELIVERY_SYSTEM, PTABLE(vdr_parse_delivery_system) },
206 	{ DTV_TRANSMISSION_MODE, PTABLE(vdr_parse_trans_mode) },
207 	{ DTV_HIERARCHY, PTABLE(vdr_parse_hierarchy) },
208 };
209 
210 static const struct dvb_parse_table sys_dvbt2_table[] = {
211 	{ DTV_BANDWIDTH_HZ, PTABLE(vdr_parse_bandwidth) },
212 	{ DTV_CODE_RATE_HP, PTABLE(vdr_parse_code_rate_hp) },
213 	{ DTV_CODE_RATE_LP, PTABLE(vdr_parse_code_rate_lp) },
214 	{ DTV_GUARD_INTERVAL, PTABLE(vdr_parse_guard_interval) },
215 	{ DTV_INVERSION, PTABLE(vdr_parse_inversion) },
216 	{ DTV_MODULATION, PTABLE(vdr_parse_modulation) },
217 	{ DTV_DELIVERY_SYSTEM, PTABLE(vdr_parse_delivery_system) },
218 	{ DTV_TRANSMISSION_MODE, PTABLE(vdr_parse_trans_mode) },
219 	{ DTV_HIERARCHY, PTABLE(vdr_parse_hierarchy) },
220 	/* DVB-T2 specifics */
221 	{ DTV_STREAM_ID, NULL, },
222 };
223 
224 static const struct dvb_parse_file vdr_file_format = {
225 	.formats = {
226 		{
227 			.id		= "A",
228 			.delsys		= SYS_ATSC,
229 			PTABLE(sys_atsc_table),
230 		}, {
231 			.id		= "C",
232 			.delsys		= SYS_DVBC_ANNEX_A,
233 			PTABLE(sys_dvbc_table),
234 		}, {
235 			.id		= "S",
236 			.delsys		= SYS_DVBS,
237 			PTABLE(sys_dvbs_table),
238 		}, {
239 			.id		= "S",
240 			.delsys		= SYS_DVBS2,
241 			PTABLE(sys_dvbs2_table),
242 		}, {
243 			.id		= "T",
244 			.delsys		= SYS_DVBT,
245 			PTABLE(sys_dvbt_table),
246 		}, {
247 			.id		= "T",
248 			.delsys		= SYS_DVBT2,
249 			PTABLE(sys_dvbt2_table),
250 		}, {
251 			NULL, 0, NULL, 0,
252 		}
253 	}
254 };
255 
dvb_write_format_vdr(const char * fname,struct dvb_file * dvb_file)256 int dvb_write_format_vdr(const char *fname,
257 			 struct dvb_file *dvb_file)
258 {
259 	const struct dvb_parse_file *parse_file = &vdr_file_format;
260 	const struct dvb_parse_struct *formats = parse_file->formats;
261 	int i, j, line = 0;
262 	FILE *fp;
263 	const struct dvb_parse_struct *fmt;
264 	struct dvb_entry *entry;
265 	const struct dvb_parse_table *table;
266 	const char *id;
267 	uint32_t delsys, freq, data, srate;
268 	char err_msg[80];
269 
270 	fp = fopen(fname, "w");
271 	if (!fp) {
272 		perror(fname);
273 		return -errno;
274 	}
275 
276 	for (entry = dvb_file->first_entry; entry != NULL; entry = entry->next) {
277 		if (dvb_retrieve_entry_prop(entry, DTV_DELIVERY_SYSTEM, &delsys) < 0)
278 			continue;
279 
280 		for (i = 0; formats[i].delsys != 0; i++) {
281 			if (formats[i].delsys == delsys)
282 				break;
283 		}
284 		if (formats[i].delsys == 0) {
285 			fprintf(stderr,
286 				_("WARNING: entry %d: delivery system %d not supported on this format. skipping entry\n"),
287 				 line, delsys);
288 			continue;
289 		}
290 		id = formats[i].id;
291 
292 		if (!entry->channel) {
293 			fprintf(stderr,
294 				_("WARNING: entry %d: channel name not found. skipping entry\n"),
295 				 line);
296 			continue;
297 		}
298 
299 		if (dvb_retrieve_entry_prop(entry, DTV_FREQUENCY, &freq) < 0) {
300 			fprintf(stderr,
301 				_("WARNING: entry %d: frequency not found. skipping entry\n"),
302 				 line);
303 			continue;
304 		}
305 
306 		/* Output channel name */
307 		fprintf(fp, "%s", entry->channel);
308 		if (entry->vchannel)
309 			fprintf(fp, ",%s", entry->vchannel);
310 		fprintf(fp, ":");
311 
312 		/*
313 		 * Output frequency:
314 		 *	in kHz for terrestrial/cable
315 		 *	in MHz for satellite
316 		 */
317 		fprintf(fp, "%i:", freq / 1000);
318 
319 		/* Output modulation parameters */
320 		fmt = &formats[i];
321 		for (i = 0; i < fmt->size; i++) {
322 			table = &fmt->table[i];
323 
324 			for (j = 0; j < entry->n_props; j++)
325 				if (entry->props[j].cmd == table->prop)
326 					break;
327 
328 			if (!table->size || j >= entry->n_props)
329 				continue;
330 
331 			data = entry->props[j].u.data;
332 
333 			if (table->prop == DTV_BANDWIDTH_HZ) {
334 				for (j = 0; j < ARRAY_SIZE(fe_bandwidth_name); j++) {
335 					if (fe_bandwidth_name[j] == data) {
336 						data = j;
337 						break;
338 					}
339 				}
340 				if (j == ARRAY_SIZE(fe_bandwidth_name))
341 					data = BANDWIDTH_AUTO;
342 			}
343 			if (data >= table->size) {
344 				sprintf(err_msg,
345 						_("value not supported"));
346 				goto error;
347 			}
348 
349 			fprintf(fp, "%s", table->table[data]);
350 		}
351 		fprintf(fp, ":");
352 
353 		/*
354 		 * Output sources configuration for VDR
355 		 *
356 		 *   S (satellite) xy.z (orbital position in degrees) E or W (east or west)
357 		 *
358 		 *   FIXME: in case of ATSC we use "A", this is what w_scan does
359 		 */
360 
361 		if (entry->location) {
362 			switch(delsys) {
363 			case SYS_DVBS:
364 			case SYS_DVBS2:
365 				fprintf(fp, "%s", entry->location);
366 				break;
367 			default:
368 				fprintf(fp, "%s", id);
369 				break;
370 			}
371 		} else {
372 			fprintf(fp, "%s", id);
373 		}
374 		fprintf(fp, ":");
375 
376 		/* Output symbol rate */
377 		srate = 27500000;
378 		switch(delsys) {
379 		case SYS_DVBT:
380 			srate = 0;
381 			break;
382 		case SYS_DVBS:
383 		case SYS_DVBS2:
384 		case SYS_DVBC_ANNEX_A:
385 			if (dvb_retrieve_entry_prop(entry, DTV_SYMBOL_RATE, &srate) < 0) {
386 				sprintf(err_msg,
387 						_("symbol rate not found"));
388 				goto error;
389 			}
390 		}
391 		fprintf(fp, "%d:", srate / 1000);
392 
393 		/* Output video PID(s) */
394 		for (i = 0; i < entry->video_pid_len; i++) {
395 			if (i)
396 				fprintf(fp,",");
397 			fprintf(fp, "%d", entry->video_pid[i]);
398 		}
399 		if (!i)
400 			fprintf(fp, "0");
401 		fprintf(fp, ":");
402 
403 		/* Output audio PID(s) */
404 		for (i = 0; i < entry->audio_pid_len; i++) {
405 			if (i)
406 				fprintf(fp,",");
407 			fprintf(fp, "%d", entry->audio_pid[i]);
408 		}
409 		if (!i)
410 			fprintf(fp, "0");
411 		fprintf(fp, ":");
412 
413 		/* FIXME: Output teletex PID(s) */
414 		fprintf(fp, "0:");
415 
416 		/* Output Conditional Access - let VDR discover it */
417 		fprintf(fp, "0:");
418 
419 		/* Output Service ID */
420 		fprintf(fp, "%d:", entry->service_id);
421 
422 		/* Output Network ID */
423 		fprintf(fp, "%d:", entry->network_id);
424 
425 		/* Output Transport Stream ID */
426 		fprintf(fp, "%d:", entry->transport_id);
427 
428 		/* Output Radio ID
429 		 * this is the last entry, tagged bei a new line (not a colon!)
430 		 */
431 		fprintf(fp, "0\n");
432 		line++;
433 	};
434 	fclose (fp);
435 	return 0;
436 
437 error:
438 	fprintf(stderr, _("ERROR: %s while parsing entry %d of %s\n"),
439 		 err_msg, line, fname);
440 	fclose(fp);
441 	return -1;
442 }
443