/* * Copyright (c) 2011-2012 - Mauro Carvalho Chehab * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation version 2 * of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * Or, point your browser to http://www.gnu.org/licenses/old-licenses/gpl-2.0.html */ #include #include #include #include #include #include #ifdef ENABLE_NLS # include "gettext.h" # include # define _(string) dgettext(LIBDVBV5_DOMAIN, string) #else # define _(string) string #endif # define N_(string) string #define PTABLE(a) .table = a, .size=ARRAY_SIZE(a) /* * Standard channel.conf format for DVB-T, DVB-C, DVB-S, DVB-S2 and ATSC */ static const char *vdr_parse_bandwidth[] = { [BANDWIDTH_1_712_MHZ] = "B1712", [BANDWIDTH_5_MHZ] = "B5", [BANDWIDTH_6_MHZ] = "B6", [BANDWIDTH_7_MHZ] = "B7", [BANDWIDTH_8_MHZ] = "B8", [BANDWIDTH_10_MHZ] = "B10", [BANDWIDTH_AUTO] = "B999", }; static const char *vdr_parse_code_rate_hp[12] = { [FEC_NONE] = "C0", [FEC_1_2] = "C12", [FEC_2_3] = "C23", [FEC_3_4] = "C34", [FEC_3_5] = "C35", [FEC_4_5] = "C45", [FEC_5_6] = "C56", [FEC_6_7] = "C67", [FEC_7_8] = "C78", [FEC_8_9] = "C89", [FEC_9_10] = "C910", [FEC_AUTO] = "C999", }; static const char *vdr_parse_code_rate_lp[12] = { [FEC_NONE] = "D0", [FEC_1_2] = "D12", [FEC_2_3] = "D23", [FEC_3_4] = "D34", [FEC_3_5] = "D35", [FEC_4_5] = "D45", [FEC_5_6] = "D56", [FEC_6_7] = "D67", [FEC_7_8] = "D78", [FEC_8_9] = "D89", [FEC_9_10] = "D910", [FEC_AUTO] = "D999", }; static const char *vdr_parse_guard_interval[] = { [GUARD_INTERVAL_1_4] = "G4", [GUARD_INTERVAL_1_8] = "G8", [GUARD_INTERVAL_1_16] = "G16", [GUARD_INTERVAL_1_32] = "G32", [GUARD_INTERVAL_1_128] = "G128", [GUARD_INTERVAL_19_128] = "G19128", [GUARD_INTERVAL_19_256] = "G19256", [GUARD_INTERVAL_AUTO] = "G999", }; static const char *vdr_parse_polarization[] = { [POLARIZATION_OFF] = "", [POLARIZATION_H] = "H", [POLARIZATION_V] = "V", [POLARIZATION_L] = "L", [POLARIZATION_R] = "R", }; static const char *vdr_parse_inversion[] = { [INVERSION_OFF] = "I0", [INVERSION_ON] = "I1", [INVERSION_AUTO] = "I999", }; static const char *vdr_parse_modulation[] = { [QAM_16] = "M16", [QAM_32] = "M32", [QAM_64] = "M64", [QAM_128] = "M128", [QAM_256] = "M256", [QPSK] = "M2", [PSK_8] = "M5", [APSK_16] = "M6", [APSK_32] = "M7", [VSB_8] = "M10", [VSB_16] = "M11", [DQPSK] = "M12", [QAM_AUTO] = "M999", }; static const char *vdr_parse_pilot[] = { [PILOT_OFF] = "N0", [PILOT_ON] = "N1", [PILOT_AUTO] = "N999", }; static const char *vdr_parse_rolloff[] = { [ROLLOFF_AUTO] = "O0", [ROLLOFF_20] = "O20", [ROLLOFF_25] = "O25", [ROLLOFF_35] = "O35", }; static const char *vdr_parse_trans_mode[] = { [TRANSMISSION_MODE_1K] = "T1", [TRANSMISSION_MODE_2K] = "T2", [TRANSMISSION_MODE_4K] = "T4", [TRANSMISSION_MODE_8K] = "T8", [TRANSMISSION_MODE_16K] = "T16", [TRANSMISSION_MODE_32K] = "T32", [TRANSMISSION_MODE_AUTO] = "T999", }; static const char *vdr_parse_hierarchy[] = { [HIERARCHY_1] = "Y1", [HIERARCHY_2] = "Y2", [HIERARCHY_4] = "Y4", [HIERARCHY_AUTO] = "Y999", [HIERARCHY_NONE] = "Y0", }; static const char *vdr_parse_delivery_system[] = { [SYS_DVBS] = "S0", [SYS_DVBS2] = "S1", [SYS_DVBT] = "S0", [SYS_DVBT2] = "S1", }; /* * The tables below deal only with the "Parameters" part of the VDR * format. */ static const struct dvb_parse_table sys_atsc_table[] = { { DTV_MODULATION, PTABLE(vdr_parse_modulation) }, { DTV_INVERSION, PTABLE(vdr_parse_inversion) }, }; static const struct dvb_parse_table sys_dvbc_table[] = { { DTV_SYMBOL_RATE, NULL, 0 }, { DTV_INNER_FEC, PTABLE(vdr_parse_code_rate_hp) }, { DTV_MODULATION, PTABLE(vdr_parse_modulation) }, { DTV_INVERSION, PTABLE(vdr_parse_inversion) }, }; static const struct dvb_parse_table sys_dvbs_table[] = { { DTV_DELIVERY_SYSTEM, PTABLE(vdr_parse_delivery_system) }, { DTV_POLARIZATION, PTABLE(vdr_parse_polarization) }, { DTV_SYMBOL_RATE, NULL, 0 }, { DTV_INNER_FEC, PTABLE(vdr_parse_code_rate_hp) }, { DTV_INVERSION, PTABLE(vdr_parse_inversion) }, }; static const struct dvb_parse_table sys_dvbs2_table[] = { { DTV_DELIVERY_SYSTEM, PTABLE(vdr_parse_delivery_system) }, { DTV_POLARIZATION, PTABLE(vdr_parse_polarization) }, { DTV_SYMBOL_RATE, NULL, 0 }, { DTV_INNER_FEC, PTABLE(vdr_parse_code_rate_hp) }, { DTV_INVERSION, PTABLE(vdr_parse_inversion) }, /* DVB-S2 specifics */ { DTV_MODULATION, PTABLE(vdr_parse_modulation) }, { DTV_PILOT, PTABLE(vdr_parse_pilot) }, { DTV_ROLLOFF, PTABLE(vdr_parse_rolloff) }, { DTV_STREAM_ID, NULL, }, }; static const struct dvb_parse_table sys_dvbt_table[] = { { DTV_DELIVERY_SYSTEM, PTABLE(vdr_parse_delivery_system) }, { DTV_BANDWIDTH_HZ, PTABLE(vdr_parse_bandwidth) }, { DTV_CODE_RATE_HP, PTABLE(vdr_parse_code_rate_hp) }, { DTV_CODE_RATE_LP, PTABLE(vdr_parse_code_rate_lp) }, { DTV_INVERSION, PTABLE(vdr_parse_inversion) }, { DTV_MODULATION, PTABLE(vdr_parse_modulation) }, { DTV_TRANSMISSION_MODE, PTABLE(vdr_parse_trans_mode) }, { DTV_GUARD_INTERVAL, PTABLE(vdr_parse_guard_interval) }, { DTV_HIERARCHY, PTABLE(vdr_parse_hierarchy) }, }; static const struct dvb_parse_table sys_dvbt2_table[] = { { DTV_DELIVERY_SYSTEM, PTABLE(vdr_parse_delivery_system) }, { DTV_BANDWIDTH_HZ, PTABLE(vdr_parse_bandwidth) }, { DTV_CODE_RATE_HP, PTABLE(vdr_parse_code_rate_hp) }, { DTV_CODE_RATE_LP, PTABLE(vdr_parse_code_rate_lp) }, { DTV_INVERSION, PTABLE(vdr_parse_inversion) }, { DTV_MODULATION, PTABLE(vdr_parse_modulation) }, { DTV_TRANSMISSION_MODE, PTABLE(vdr_parse_trans_mode) }, { DTV_GUARD_INTERVAL, PTABLE(vdr_parse_guard_interval) }, { DTV_HIERARCHY, PTABLE(vdr_parse_hierarchy) }, /* DVB-T2 specifics */ { DTV_STREAM_ID, NULL, }, }; static const struct dvb_parse_file vdr_file_format = { .formats = { { .id = "A", .delsys = SYS_ATSC, PTABLE(sys_atsc_table), }, { .id = "C", .delsys = SYS_DVBC_ANNEX_A, PTABLE(sys_dvbc_table), }, { .id = "S", .delsys = SYS_DVBS, PTABLE(sys_dvbs_table), }, { .id = "S", .delsys = SYS_DVBS2, PTABLE(sys_dvbs2_table), }, { .id = "T", .delsys = SYS_DVBT, PTABLE(sys_dvbt_table), }, { .id = "T", .delsys = SYS_DVBT2, PTABLE(sys_dvbt2_table), }, { NULL, 0, NULL, 0, } } }; int dvb_write_format_vdr(const char *fname, struct dvb_file *dvb_file) { const struct dvb_parse_file *parse_file = &vdr_file_format; const struct dvb_parse_struct *formats = parse_file->formats; int i, j, line = 0; FILE *fp; const struct dvb_parse_struct *fmt; struct dvb_entry *entry; const struct dvb_parse_table *table; const char *id; uint32_t delsys, freq, data, srate; char err_msg[80]; fp = fopen(fname, "w"); if (!fp) { perror(fname); return -errno; } for (entry = dvb_file->first_entry; entry != NULL; entry = entry->next) { if (dvb_retrieve_entry_prop(entry, DTV_DELIVERY_SYSTEM, &delsys) < 0) continue; for (i = 0; formats[i].delsys != 0; i++) { if (formats[i].delsys == delsys) break; } if (formats[i].delsys == 0) { fprintf(stderr, _("WARNING: entry %d: delivery system %d not supported on this format. skipping entry\n"), line, delsys); continue; } id = formats[i].id; if (!entry->channel) { fprintf(stderr, _("WARNING: entry %d: channel name not found. skipping entry\n"), line); continue; } if (dvb_retrieve_entry_prop(entry, DTV_FREQUENCY, &freq) < 0) { fprintf(stderr, _("WARNING: entry %d: frequency not found. skipping entry\n"), line); continue; } /* Output channel name */ fprintf(fp, "%s", entry->channel); if (entry->vchannel) fprintf(fp, ",%s", entry->vchannel); /* * Output frequency: * in kHz for terrestrial/cable * in MHz for satellite */ fprintf(fp, ":%i:", freq / 1000); /* Output modulation parameters */ fmt = &formats[i]; for (i = 0; i < fmt->size; i++) { table = &fmt->table[i]; for (j = 0; j < entry->n_props; j++) if (entry->props[j].cmd == table->prop) break; if (!table->size || j >= entry->n_props) continue; data = entry->props[j].u.data; if (table->prop == DTV_BANDWIDTH_HZ) { for (j = 0; j < ARRAY_SIZE(fe_bandwidth_name); j++) { if (fe_bandwidth_name[j] == data) { data = j; break; } } if (j == ARRAY_SIZE(fe_bandwidth_name)) data = BANDWIDTH_AUTO; } if (data >= table->size) { sprintf(err_msg, _("value not supported")); goto error; } fprintf(fp, "%s", table->table[data]); } /* Output format type */ fprintf(fp, ":%s:", id); /* * Output satellite location * FIXME: probably require some adjustments to match the * format expected by VDR. */ switch(delsys) { case SYS_DVBS: case SYS_DVBS2: fprintf(fp, "%s:", entry->location); } /* Output symbol rate */ srate = 27500000; switch(delsys) { case SYS_DVBS: case SYS_DVBS2: case SYS_DVBC_ANNEX_A: if (dvb_retrieve_entry_prop(entry, DTV_SYMBOL_RATE, &srate) < 0) { sprintf(err_msg, _("symbol rate not found")); goto error; } } fprintf(fp, "%d:", srate / 1000); /* Output video PID(s) */ for (i = 0; i < entry->video_pid_len; i++) { if (i) fprintf(fp,","); fprintf(fp, "%d", entry->video_pid[i]); } if (!i) fprintf(fp, "0"); fprintf(fp, ":"); /* Output audio PID(s) */ for (i = 0; i < entry->audio_pid_len; i++) { if (i) fprintf(fp,","); fprintf(fp, "%d", entry->audio_pid[i]); } if (!i) fprintf(fp, "0"); fprintf(fp, ":"); /* FIXME: Output teletex PID(s) */ fprintf(fp, "0:"); /* Output Conditional Access - let VDR discover it */ fprintf(fp, "0:"); /* Output Service ID */ fprintf(fp, "%d:", entry->service_id); /* Output SID, NID, TID and RID */ fprintf(fp, "0:0:0:"); fprintf(fp, "\n"); line++; }; fclose (fp); return 0; error: fprintf(stderr, _("ERROR: %s while parsing entry %d of %s\n"), err_msg, line, fname); fclose(fp); return -1; }