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