First stab at moving mux initial config system to using dvb-apps mux config files directly.

This commit is contained in:
Adam Sutton 2012-08-01 15:08:59 +01:00
parent 0b38ca1287
commit 629a07009f
10 changed files with 516 additions and 14835 deletions

View file

@ -75,6 +75,7 @@ SRCS = src/main.c \
src/avc.c \
src/huffman.c \
src/filebundle.c \
src/muxes.c \
SRCS += src/epggrab/module.c\
src/epggrab/channel.c\

View file

@ -314,6 +314,13 @@ const char* dvb_mux_delsys2str(int delsys);
const char* dvb_mux_qam2str(int qam);
const char* dvb_mux_rolloff2str(int rolloff);
int dvb_mux_str2bw(const char *str);
int dvb_mux_str2qam(const char *str);
int dvb_mux_str2fec(const char *str);
int dvb_mux_str2mode(const char *str);
int dvb_mux_str2guard(const char *str);
int dvb_mux_str2hier(const char *str);
void dvb_mux_save(th_dvb_mux_instance_t *tdmi);
void dvb_mux_load(th_dvb_adapter_t *tda);

View file

@ -505,6 +505,39 @@ const char* dvb_mux_rolloff2str(int rolloff) {
}
#endif
/**
* for external use
*/
int dvb_mux_str2bw(const char *str)
{
return str2val(str, bwtab);
}
int dvb_mux_str2qam(const char *str)
{
return str2val(str, qamtab);
}
int dvb_mux_str2fec(const char *str)
{
return str2val(str, fectab);
}
int dvb_mux_str2mode(const char *str)
{
return str2val(str, modetab);
}
int dvb_mux_str2guard(const char *str)
{
return str2val(str, guardtab);
}
int dvb_mux_str2hier(const char *str)
{
return str2val(str, hiertab);
}
/**
*
*/

View file

@ -29,23 +29,19 @@
#include "tvheadend.h"
#include "dvb.h"
#include "dvb_preconf.h"
/**
* A big list of all known DVB networks (from linuxtv.org)
*/
#include "linuxtv_muxes.h"
#include "muxes.h"
/**
*
*/
static void
dvb_mux_preconf_add(th_dvb_adapter_t *tda, const struct mux *m, int num,
dvb_mux_preconf_add(th_dvb_adapter_t *tda, const network_t *net,
const char *source, const char *satconf)
{
const mux_t *m;
struct dvb_mux_conf dmc;
int i;
for(i = 0; i < num; i++) {
LIST_FOREACH(m, &net->muxes, link) {
memset(&dmc, 0, sizeof(dmc));
@ -103,7 +99,6 @@ dvb_mux_preconf_add(th_dvb_adapter_t *tda, const struct mux *m, int num,
dmc.dmc_satconf = dvb_satconf_entry_find(tda, satconf, 0);
dvb_mux_create(tda, &dmc, 0xffff, NULL, source, 1, 1, NULL, NULL);
m++;
}
}
@ -115,42 +110,35 @@ int
dvb_mux_preconf_add_network(th_dvb_adapter_t *tda, const char *id,
const char *satconf)
{
const struct region *r;
const struct network *n;
int nr, nn, i, j;
region_list_t *list;
const region_t *r;
const network_t *n;
char source[100];
snprintf(source, sizeof(source), "built-in configuration from \"%s\"", id);
switch(tda->tda_type) {
case FE_QAM:
r = regions_DVBC;
nr = sizeof(regions_DVBC) / sizeof(regions_DVBC[0]);
break;
case FE_QPSK:
r = regions_DVBS;
nr = sizeof(regions_DVBS) / sizeof(regions_DVBS[0]);
break;
case FE_OFDM:
r = regions_DVBT;
nr = sizeof(regions_DVBT) / sizeof(regions_DVBT[0]);
break;
case FE_ATSC:
r = regions_ATSC;
nr = sizeof(regions_ATSC) / sizeof(regions_ATSC[0]);
break;
default:
return -1;
case FE_QAM:
list = &regions_DVBC;
break;
case FE_QPSK:
list = &regions_DVBS;
break;
case FE_OFDM:
list = &regions_DVBT;
break;
case FE_ATSC:
list = &regions_ATSC;
break;
default:
return -1;
}
for(i = 0; i < nr; i++) {
n = r[i].networks;
nn = r[i].nnetworks;
for(j = 0; j < nn; j++) {
if(!strcmp(n[j].name, id)) {
dvb_mux_preconf_add(tda, n[j].muxes, n[j].nmuxes, source, satconf);
break;
LIST_FOREACH(r, list, link) {
LIST_FOREACH(n, &r->networks, link) {
if(!strcmp(n->id, id)) {
dvb_mux_preconf_add(tda, n, source, satconf);
break;
}
}
}
@ -163,61 +151,52 @@ dvb_mux_preconf_add_network(th_dvb_adapter_t *tda, const char *id,
htsmsg_t *
dvb_mux_preconf_get_node(int fetype, const char *node)
{
const struct region *r;
const struct network *n;
int nr, nn, i;
region_list_t *list = NULL;
const region_t *r;
const network_t *n;
htsmsg_t *out, *e;
switch(fetype) {
case FE_QAM:
r = regions_DVBC;
nr = sizeof(regions_DVBC) / sizeof(regions_DVBC[0]);
break;
case FE_QPSK:
r = regions_DVBS;
nr = sizeof(regions_DVBS) / sizeof(regions_DVBS[0]);
break;
case FE_OFDM:
r = regions_DVBT;
nr = sizeof(regions_DVBT) / sizeof(regions_DVBT[0]);
break;
case FE_ATSC:
r = regions_ATSC;
nr = sizeof(regions_ATSC) / sizeof(regions_ATSC[0]);
break;
default:
tvhlog(LOG_ERR, "DVB", "No built-in config for fetype %d", fetype);
return NULL;
case FE_QAM:
list = &regions_DVBC;
break;
case FE_QPSK:
list = &regions_DVBS;
break;
case FE_OFDM:
list = &regions_DVBT;
break;
case FE_ATSC:
list = &regions_ATSC;
break;
default:
tvhlog(LOG_ERR, "DVB", "No built-in config for fetype %d", fetype);
return NULL;
}
out = htsmsg_create_list();
if(!strcmp(node, "root")) {
for(i = 0; i < nr; i++) {
LIST_FOREACH(r, list, link) {
e = htsmsg_create_map();
htsmsg_add_u32(e, "leaf", 0);
htsmsg_add_str(e, "text", r[i].name);
htsmsg_add_str(e, "id", r[i].name);
htsmsg_add_str(e, "text", r->name);
htsmsg_add_str(e, "id", r->id);
htsmsg_add_msg(out, NULL, e);
}
return out;
}
for(i = 0; i < nr; i++)
if(!strcmp(node, r[i].name))
LIST_FOREACH(r, list, link)
if (!strcmp(node, r->id))
break;
if (!r) return out;
if(i == nr)
return out;
n = r[i].networks;
nn = r[i].nnetworks;
for(i = 0; i < nn; i++) {
LIST_FOREACH(n, &r->networks, link) {
e = htsmsg_create_map();
htsmsg_add_u32(e, "leaf", 1);
htsmsg_add_str(e, "text", n[i].name);
htsmsg_add_str(e, "id", n[i].name);
htsmsg_add_str(e, "text", n->name);
htsmsg_add_str(e, "id", n->id);
htsmsg_add_msg(out, NULL, e);
}

File diff suppressed because it is too large Load diff

View file

@ -57,6 +57,7 @@
#include "trap.h"
#include "settings.h"
#include "ffdecsa/FFdecsa.h"
#include "muxes.h"
int running;
time_t dispatch_clock;
@ -168,6 +169,7 @@ usage(const char *argv0)
printf(" -a <adapters> Use only DVB adapters specified (csv)\n");
printf(" -c <directory> Alternate configuration path.\n"
" Defaults to [$HOME/.hts/tvheadend]\n");
printf(" -m <directory> Alternate mux configuration directory\n");
printf(" -f Fork and daemonize\n");
printf(" -p <pidfile> Write pid to <pidfile> instead of /var/run/tvheadend.pid,\n"
" only works with -f\n");
@ -257,11 +259,12 @@ main(int argc, char **argv)
char *p, *endp;
uint32_t adapter_mask = 0xffffffff;
int crash = 0;
const char *muxpath = NULL;
// make sure the timezone is set
tzset();
while((c = getopt(argc, argv, "Aa:fp:u:g:c:Chdr:j:s")) != -1) {
while((c = getopt(argc, argv, "Aa:fp:u:g:c:m:Chdr:j:s")) != -1) {
switch(c) {
case 'a':
adapter_mask = 0x0;
@ -301,6 +304,9 @@ main(int argc, char **argv)
case 'c':
confpath = optarg;
break;
case 'm':
muxpath = optarg;
break;
case 'd':
log_debug_to_console = 1;
break;
@ -380,6 +386,8 @@ main(int argc, char **argv)
* Initialize subsystems
*/
muxes_init(muxpath);
service_init();
channels_init();

View file

@ -1,39 +0,0 @@
#!/bin/sh
gcc -O2 -Wall main.c -o muxbuilder
cat <<EOF
struct mux {
unsigned int freq;
unsigned int symrate;
char fec;
char constellation;
char bw;
char fechp;
char feclp;
char tmode;
char guard;
char hierarchy;
char polarisation;
};
struct network {
const char *name;
const struct mux *muxes;
const int nmuxes;
};
struct region {
const char *name;
const struct network *networks;
const int nnetworks;
};
EOF
find $1/dvb-s -type f | sort | xargs ./muxbuilder DVBS
find $1/dvb-t -type f | sort | xargs ./muxbuilder DVBT
find $1/dvb-c -type f | sort | xargs ./muxbuilder DVBC
find $1/atsc -type f | sort | xargs ./muxbuilder ATSC

View file

@ -1,548 +0,0 @@
#include <stdlib.h>
#include <libgen.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <strings.h>
#include <ctype.h>
char *type;
struct strtab {
const char *v1;
const char *v2;
};
static struct strtab fectab[] = {
{ "NONE", "0" },
{ "1/2", "1" },
{ "2/3", "2" },
{ "3/4", "3" },
{ "4/5", "4" },
{ "5/6", "5" },
{ "6/7", "6" },
{ "7/8", "7" },
{ "8/9", "8" },
{ "AUTO", "9" },
{ "1/1", "9" },
{ "3/5", "10" },
{ "9/10", "11" },
};
static struct strtab qamtab[] = {
{ "QPSK", "0" },
{ "QAM16", "1" },
{ "QAM32", "2" },
{ "QAM64", "3" },
{ "QAM128", "4" },
{ "QAM256", "5" },
{ "AUTO", "6" },
{ "8VSB", "7" },
{ "16VSB", "8" },
{ "8PSK", "9" }
};
static struct strtab bwtab[] = {
{ "8MHz", "0" },
{ "7MHz", "1" },
{ "6MHz", "2" },
{ "AUTO", "3" }
};
static struct strtab modetab[] = {
{ "2k", "0" },
{ "8k", "1" },
{ "AUTO", "2" }
};
static struct strtab guardtab[] = {
{ "1/32", "0" },
{ "1/16", "1" },
{ "1/8", "2" },
{ "1/4", "3" },
{ "AUTO", "4" },
};
static struct strtab hiertab[] = {
{ "NONE", "0" },
{ "1", "1" },
{ "2", "2" },
{ "4", "3" },
{ "AUTO", "4" }
};
static const char *
str2str0(const char *str, struct strtab tab[], int l, const char *what)
{
int i;
for(i = 0; i < l; i++)
if(!strcasecmp(str, tab[i].v1))
return tab[i].v2;
fprintf(stderr, "Warning, cannot translate %s (%s)\n", str, what);
return "#error";
}
#define str2str(str, tab,what) str2str0(str, tab, sizeof(tab) / sizeof(tab[0]),what)
static void
dvb_t_config(const char *l)
{
unsigned long freq;
char bw[20], fec[20], fec2[20], qam[20], mode[20], guard[20], hier[20];
int r;
r = sscanf(l, "%lu %10s %10s %10s %10s %10s %10s %10s",
&freq, bw, fec, fec2, qam, mode, guard, hier);
if(r != 8)
return;
printf("\t{.freq = %lu, "
".bw = %s, "
".constellation = %s, "
".fechp = %s, "
".feclp = %s, "
".tmode = %s, "
".guard = %s, "
".hierarchy = %s},\n "
,
freq,
str2str(bw, bwtab, "bandwidth"),
str2str(qam, qamtab, "constellation"),
str2str(fec, fectab, "fec"),
str2str(fec2, fectab, "fec2"),
str2str(mode, modetab, "mode"),
str2str(guard, guardtab, "guard"),
str2str(hier, hiertab, "hierarchy"));
}
static void
dvb_s_config(const char *l)
{
unsigned long freq, symrate;
char fec[20], polarisation;
int r;
r = sscanf(l, "%lu %c %lu %s",
&freq, &polarisation, &symrate, fec);
if(r != 4)
return;
printf("\t{"
".freq = %lu, "
".symrate = %lu, "
".fec = %s, "
".polarisation = '%c'"
"},\n",
freq,
symrate,
str2str(fec, fectab, "fec"),
polarisation);
}
static void
dvb_s2_config(const char *l)
{
}
static void
dvb_c_config(const char *l)
{
unsigned long freq, symrate;
char fec[20], qam[20];
int r;
r = sscanf(l, "%lu %lu %s %s",
&freq, &symrate, fec, qam);
if(r != 4)
return;
printf("\t{ "
".freq = %lu, .symrate = %lu, .fec = %s, .constellation = %s},\n",
freq, symrate, str2str(fec, fectab, "fec"), str2str(qam, qamtab, "constellations"));
}
static void
atsc_config(const char *l)
{
unsigned long freq;
char modulation[20];
int r;
r = sscanf(l, "%lu %s",
&freq, modulation);
if(r != 2)
return;
printf("\t{ "
".freq = %lu, .constellation = %s},\n",
freq, str2str(modulation, qamtab, "constellations"));
}
/**
*
*/
typedef struct network {
char *structname;
char *displayname;
char *comment;
struct network *next;
} network_t;
typedef struct region {
char *shortname;
char *longname;
struct network *networks;
struct region *next;
} region_t;
region_t *regions;
static region_t *
find_region(const char *name, const char *longname)
{
region_t *c, *n, **p;
for(c = regions; c != NULL; c = c->next)
if(!strcmp(name, c->shortname))
return c;
n = malloc(sizeof(region_t));
n->shortname = strdup(name);
n->longname = strdup(longname);
n->networks = NULL;
if(regions == NULL)
regions = n;
else {
p = &regions;
while((c = *p) != NULL) {
if(strcmp(c->longname, longname) > 0)
break;
p = &c->next;
}
n->next = *p;
*p = n;
}
return n;
}
static network_t *
add_network(region_t *x, const char *name)
{
network_t *m, *n, **p;
n = calloc(1, sizeof(network_t));
n->structname = strdup(name);
if(x->networks == NULL)
x->networks = n;
else {
p = &x->networks;
while((m = *p) != NULL) {
if(strcmp(m->structname, name) > 0)
break;
p = &m->next;
}
n->next = *p;
*p = n;
}
return n;
}
static const struct {
const char *code;
const char *name;
} tldlist[] = {
{"auto", "--Generic--"},
{"ad", "Andorra"},
{"at", "Austria"},
{"au", "Australia"},
{"ax", "Aland Islands"},
{"be", "Belgium"},
{"br", "Brazil"},
{"ca", "Canada"},
{"ch", "Switzerland"},
{"cz", "Czech Republic"},
{"de", "Germany"},
{"dk", "Denmark"},
{"es", "Spain"},
{"fi", "Finland"},
{"fr", "France"},
{"gr", "Greece"},
{"hk", "Hong Kong"},
{"hr", "Croatia"},
{"hu", "Hungary"},
{"il", "Israel"},
{"ir", "Iran"},
{"is", "Iceland"},
{"it", "Italy"},
{"lt", "Lithuania"},
{"lu", "Luxembourg"},
{"lv", "Latvia"},
{"nl", "Netherlands"},
{"no", "Norway"},
{"nz", "New Zealand"},
{"pl", "Poland"},
{"ro", "Romania"},
{"se", "Sweden"},
{"si", "Slovenia"},
{"sk", "Slovakia"},
{"tw", "Taiwan"},
{"uk", "United Kingdom"},
{"us", "United States"},
{"vn", "Vietnam"},
};
static const char *
tldcode2longname(const char *tld)
{
int i;
for(i = 0; i < sizeof(tldlist) / sizeof(tldlist[0]); i++)
if(!strcmp(tld, tldlist[i].code))
return tldlist[i].name;
fprintf(stderr, "Unable to translate tld %s\n", tld);
fprintf(stderr, "Exiting. Output is incomplete\n");
exit(1);
}
static void
scan_file(char *fname)
{
FILE *fp;
char line[200];
int l;
char c, *s;
char smartname[200];
char *bn;
int gotcomment = 0;
region_t *co;
network_t *ne;
char *name, *displayname;
char buf[100];
fp = fopen(fname, "r");
if(fp == NULL) {
fprintf(stderr, "Unable to open file %s -- %s", fname, strerror(errno));
return;
}
l = 0;
bn = basename(fname);
while(*bn) {
c = *bn++;
smartname[l++] = isalnum(c) ? c : '_';
}
smartname[l] = 0;
name = basename(fname);
if(!strcmp(type, "DVBS")) {
displayname = name;
co = find_region("geo", "Geosynchronous Orbit");
} else {
l = 0;
c = 0;
while(*name && c != '-') {
c = *name++;
if (c != '-') {
buf[l++] = c;
}
}
buf[l] = 0;
displayname = name;
co = find_region(buf, tldcode2longname(buf));
}
snprintf(buf, sizeof(buf), "%s_%s", type, smartname);
printf("static const struct mux muxes_%s[] = {\n", buf);
ne = add_network(co, buf);
bn = ne->displayname = strdup(displayname);
while(*bn) {
if(*bn == '_') *bn = ' ';
bn++;
}
// ne->muxlistname = strdup(buf);
#if 0
if(pass == 2) {
printf("{\n");
printf("\t.type = %s,\n", type);
printf("\t.name = \"%s\",\n", basename(fname));
printf("\t.muxes = muxlist_%s_%s,\n", type, smartname);
printf("\t.nmuxes = sizeof(muxlist_%s_%s) / sizeof(struct mux),\n",
type, smartname);
printf("\t.comment = ");
}
#endif
while(!feof(fp)) {
memset(line, 0, sizeof(line));
if(fgets(line, sizeof(line) - 1, fp) == NULL)
break;
l = strlen(line);
while(l > 0 && line[l - 1] < 32)
line[--l] = 0;
switch(line[0]) {
case '#':
if(gotcomment)
break;
s = line + 2;
if(strstr(s, " freq "))
break;
// ne->comment = strdup(s);
gotcomment = 1;
break;
case 'A':
atsc_config(line + 1);
break;
case 'C':
dvb_c_config(line + 1);
break;
case 'T':
dvb_t_config(line + 1);
break;
case 'S':
if(line[1] == '2')
dvb_s2_config(line + 2);
else
dvb_s_config(line + 1);
break;
default:
break;
}
}
printf("};\n\n");
fclose(fp);
}
static void
dump_networks(region_t *c)
{
network_t *n;
printf("static const struct network networks_%s_%s[] = {\n",
type, c->shortname);
for(n = c->networks; n != NULL; n = n->next) {
printf("\t{\n");
printf("\t\t.name = \"%s\",\n", n->displayname);
printf("\t\t.muxes = muxes_%s,\n", n->structname);
printf("\t\t.nmuxes = sizeof(muxes_%s) / sizeof(struct mux),\n",
n->structname);
if(n->comment)
printf("\t\t.comment = \"%s\",\n", n->comment);
printf("\t},\n");
}
printf("};\n\n");
}
static void
dump_regions(void)
{
region_t *r;
printf("static const struct region regions_%s[] = {\n", type);
for(r = regions; r != NULL; r = r->next) {
printf("\t{\n");
printf("\t\t.name = \"%s\",\n", r->longname);
printf("\t\t.networks = networks_%s_%s,\n", type, r->shortname);
printf("\t\t.nnetworks = sizeof(networks_%s_%s) / sizeof(struct network),\n",
type, r->shortname);
printf("\t},\n");
}
printf("};\n\n");
}
int
main(int argc, char **argv)
{
int i;
region_t *c;
if(argc < 2)
return 1;
type = argv[1];
#if 0
printf("struct mux {\n"
"unsigned int freq;\n"
"unsigned int symrate;\n"
"char fec;\n"
"char constellation;\n"
"char bw;\n"
"char fechp;\n"
"char feclp;\n"
"char tmode;\n"
"char guard;\n"
"char hierarchy;\n"
"char polarisation;\n"
"}\n");
#endif
for(i = 2; i < argc; i++)
scan_file(argv[i]);
for(c = regions; c != NULL; c = c->next) {
dump_networks(c);
}
dump_regions();
return 0;
}

354
src/muxes.c Normal file
View file

@ -0,0 +1,354 @@
/*
* tvheadend, intial mux list
* Copyright (C) 2012 Adam Sutton
*
* 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, either version 3 of the License, or
* (at your option) any later version.
*
* 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, see <http://www.gnu.org/licenses/>.
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>
#include <stdlib.h>
#include <libgen.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <strings.h>
#include <ctype.h>
#include "tvheadend.h"
#include "dvb/dvb.h"
#include "muxes.h"
region_list_t regions_DVBC;
region_list_t regions_DVBT;
region_list_t regions_DVBS;
region_list_t regions_ATSC;
/* **************************************************************************
* Country codes
* *************************************************************************/
static const struct {
const char *code;
const char *name;
} tldlist[] = {
{"auto", "--Generic--"},
{"ad", "Andorra"},
{"at", "Austria"},
{"au", "Australia"},
{"ax", "Aland Islands"},
{"be", "Belgium"},
{"br", "Brazil"},
{"ca", "Canada"},
{"ch", "Switzerland"},
{"cz", "Czech Republic"},
{"de", "Germany"},
{"dk", "Denmark"},
{"es", "Spain"},
{"fi", "Finland"},
{"fr", "France"},
{"gr", "Greece"},
{"hk", "Hong Kong"},
{"hr", "Croatia"},
{"hu", "Hungary"},
{"il", "Israel"},
{"ir", "Iran"},
{"is", "Iceland"},
{"it", "Italy"},
{"lt", "Lithuania"},
{"lu", "Luxembourg"},
{"lv", "Latvia"},
{"nl", "Netherlands"},
{"no", "Norway"},
{"nz", "New Zealand"},
{"pl", "Poland"},
{"ro", "Romania"},
{"se", "Sweden"},
{"si", "Slovenia"},
{"sk", "Slovakia"},
{"tw", "Taiwan"},
{"uk", "United Kingdom"},
{"us", "United States"},
{"vn", "Vietnam"},
};
static const char *
tldcode2longname(const char *tld)
{
int i;
for(i = 0; i < sizeof(tldlist) / sizeof(tldlist[0]); i++)
if(!strcmp(tld, tldlist[i].code))
return tldlist[i].name;
return NULL;
}
/* **************************************************************************
* Type specific parsers
* *************************************************************************/
static int _muxes_load_atsc ( mux_t *mux, const char *line )
{
char qam[20];
int r;
r = sscanf(line, "%u %s", &mux->freq, qam);
if (r != 2) return 1;
if ((mux->constellation = dvb_mux_str2qam(qam)) == -1) return 1;
return 0;
}
static int _muxes_load_dvbt ( mux_t *mux, const char *line )
{
char bw[20], fec[20], fec2[20], qam[20], mode[20], guard[20], hier[20];
int r;
r = sscanf(line, "%u %10s %10s %10s %10s %10s %10s %10s",
&mux->freq, bw, fec, fec2, qam, mode, guard, hier);
if(r != 8) return 1;
if ((mux->bw = dvb_mux_str2bw(bw)) == -1) return 1;
if ((mux->constellation = dvb_mux_str2qam(qam)) == -1) return 1;
if ((mux->fechp = dvb_mux_str2fec(fec)) == -1) return 1;
if ((mux->feclp = dvb_mux_str2fec(fec2)) == -1) return 1;
if ((mux->tmode = dvb_mux_str2mode(mode)) == -1) return 1;
if ((mux->guard = dvb_mux_str2guard(guard)) == -1) return 1;
if ((mux->hierarchy = dvb_mux_str2hier(hier)) == -1) return 1;
return 0;
}
static int _muxes_load_dvbs ( mux_t *mux, const char *line )
{
char fec[20], qam[20], hier[20];
int r, v2 = 0;
if (*line == '2') {
v2 = 2;
line++;
}
r = sscanf(line, "%u %c %u %s %s %s",
&mux->freq, &mux->polarisation, &mux->symrate,
fec, hier, qam);
if (r != (4+v2)) return 1;
if ((mux->fec = dvb_mux_str2fec(fec)) == -1) return 1;
if (v2) {
if ((mux->hierarchy = dvb_mux_str2hier(hier)) == -1) return 1;
if ((mux->constellation = dvb_mux_str2qam(qam)) == -1) return 1;
}
return 0;
}
static int _muxes_load_dvbc ( mux_t *mux, const char *line )
{
char fec[20], qam[20];
int r;
r = sscanf(line, "%u %u %s %s",
&mux->freq, &mux->symrate, fec, qam);
if(r != 4) return 1;
if ((mux->fec = dvb_mux_str2fec(fec)) == -1) return 1;
if ((mux->constellation = dvb_mux_str2qam(qam)) == -1) return 1;
return 0;
}
/* **************************************************************************
* File processing
* *************************************************************************/
/*
* Sorting
*/
static int _net_cmp ( void *a, void *b )
{
return strcmp(((network_t*)a)->name, ((network_t*)b)->name);
}
static int _reg_cmp ( void *a, void *b )
{
return strcmp(((region_t*)a)->name, ((region_t*)b)->name);
}
/*
* Create/Find region entry
*/
static region_t *_muxes_region_create
( const char *type, const char *id, const char *desc )
{
region_t *reg;
region_list_t *list = NULL;
if (!strcmp(type, "dvb-s")) list = &regions_DVBS;
else if (!strcmp(type, "dvb-t")) list = &regions_DVBT;
else if (!strcmp(type, "dvb-c")) list = &regions_DVBC;
else if (!strcmp(type, "atsc")) list = &regions_ATSC;
if (!list) return NULL;
LIST_FOREACH(reg, list, link) {
if (!strcmp(reg->id, id)) break;
}
if (!reg) {
reg = calloc(1, sizeof(region_t));
reg->id = strdup(id);
reg->name = strdup(desc);
LIST_INSERT_SORTED(list, reg, link, _reg_cmp);
}
return reg;
}
/*
* Process mux entry
*/
static void _muxes_load_one ( network_t *net, const char *line )
{
int r = 1;
mux_t *mux = calloc(1, sizeof(mux_t));
switch (line[0]) {
case 'A':
r = _muxes_load_atsc(mux, line+1);
break;
case 'T':
r = _muxes_load_dvbt(mux, line+1);
break;
case 'S':
r = _muxes_load_dvbs(mux, line+1);
break;
case 'C':
r = _muxes_load_dvbc(mux, line+1);
break;
}
if (r) {
free(mux);
} else {
LIST_INSERT_HEAD(&net->muxes, mux, link);
}
}
/*
* Process a file
*/
static void _muxes_load_file ( const char *type, const char *path )
{
FILE *fp;
int i;
region_t *reg;
network_t *net;
char *name, *co;
char buf[256], buf2[256];
fp = fopen(path, "r");
if (!fp) return;
/* Region */
strcpy(buf, path);
if (!(name = basename(buf))) return;
if (!strcmp(type, "dvb-s")) {
reg = _muxes_region_create(type, "geo", "Geo-synchronous Orbit");
} else {
if (!(co = strtok(name, "-"))) return;
reg = _muxes_region_create(type, co, tldcode2longname(co));
}
if (!reg) return;
/* Network */
i = 0;
name = basename((char*)path);
while (*name) {
buf[i++] = isalnum(*name) ? *name : '_';
name++;
}
buf[i] = '\0';
snprintf(buf2, sizeof(buf2), "%s_%s", type, buf);
net = calloc(1, sizeof(network_t));
net->id = strdup(buf2);
net->name = strdup(buf);
LIST_INSERT_SORTED(&reg->networks, net, link, _net_cmp);
/* Process file */
while (!feof(fp)) {
/* Get line */
memset(buf, 0, sizeof(buf));
if (!fgets(buf, sizeof(buf) - 1, fp)) break;
i = 0;
while (buf[i]) {
if (buf[i] == '#')
buf[i] = '\0';
else
i++;
}
while (i > 0 && buf[i-1] < 32) buf[--i] = 0;
/* Process mux */
switch (*buf) {
case 'A':
case 'C':
case 'T':
case 'S':
_muxes_load_one(net, buf);
default:
break;
}
}
}
/*
* Process directory
*
* Note: should we follow symlinks?
*/
static void _muxes_load_dir ( const char *path, const char *type )
{
DIR *dir;
struct dirent *dent;
struct stat st;
if (!(dir = opendir(path))) return;
while ((dent = readdir(dir))) {
if (*dent->d_name == '.') continue;
char p[256];
sprintf(p, "%s/%s", path, dent->d_name);
if (stat(p, &st)) continue;
if (S_ISDIR(st.st_mode))
_muxes_load_dir(p, dent->d_name);
else
_muxes_load_file(type, p);
}
closedir(dir);
}
/*
* Initialise the mux list
*/
void muxes_init ( const char *path )
{
/* TODO: Default */
if (!path) return;
/* Process */
_muxes_load_dir(path, NULL);
}

59
src/muxes.h Normal file
View file

@ -0,0 +1,59 @@
/*
* tvheadend, intial mux list
* Copyright (C) 2012 Adam Sutton
*
* 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, either version 3 of the License, or
* (at your option) any later version.
*
* 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, see <http://www.gnu.org/licenses/>.
*/
#ifndef __TVH_MUXES_H__
#define __TVH_MUXES_H__
typedef struct mux {
LIST_ENTRY(mux) link;
unsigned int freq;
unsigned int symrate;
char fec;
char constellation;
char bw;
char fechp;
char feclp;
char tmode;
char guard;
char hierarchy;
char polarisation;
} mux_t;
typedef struct network {
const char *id;
const char *name;
LIST_ENTRY(network) link;
LIST_HEAD(,mux) muxes;
} network_t;
typedef struct region {
const char *id;
const char *name;
LIST_ENTRY(region) link;
LIST_HEAD(,network) networks;
} region_t;
typedef LIST_HEAD(,region) region_list_t;
extern region_list_t regions_DVBC;
extern region_list_t regions_DVBT;
extern region_list_t regions_DVBS;
extern region_list_t regions_ATSC;
void muxes_init ( const char *path );
#endif /* __TVH_MUXES_H__ */