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