1
|
/*
|
2
|
* TV Input - DVB - Support functions
|
3
|
* Copyright (C) 2007 Andreas ?man
|
4
|
*
|
5
|
* This program is free software: you can redistribute it and/or modify
|
6
|
* it under the terms of the GNU General Public License as published by
|
7
|
* the Free Software Foundation, either version 3 of the License, or
|
8
|
* (at your option) any later version.
|
9
|
*
|
10
|
* This program is distributed in the hope that it will be useful,
|
11
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
13
|
* GNU General Public License for more details.
|
14
|
*
|
15
|
* You should have received a copy of the GNU General Public License
|
16
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
17
|
*/
|
18
|
|
19
|
#include <pthread.h>
|
20
|
|
21
|
#include <sys/types.h>
|
22
|
#include <sys/stat.h>
|
23
|
#include <sys/ioctl.h>
|
24
|
#include <errno.h>
|
25
|
#include <iconv.h>
|
26
|
|
27
|
#include <stdio.h>
|
28
|
#include <unistd.h>
|
29
|
#include <stdlib.h>
|
30
|
#include <string.h>
|
31
|
|
32
|
#include <linux/dvb/frontend.h>
|
33
|
|
34
|
#include "tvheadend.h"
|
35
|
#include "dvb_support.h"
|
36
|
#include "dvb.h"
|
37
|
|
38
|
/**
|
39
|
*
|
40
|
*/
|
41
|
static iconv_t convert_iso_8859[16];
|
42
|
static iconv_t convert_utf8;
|
43
|
static iconv_t convert_latin1;
|
44
|
|
45
|
|
46
|
static iconv_t
|
47
|
dvb_iconv_open(const char *srcencoding)
|
48
|
{
|
49
|
iconv_t ic;
|
50
|
ic = iconv_open("UTF8", srcencoding);
|
51
|
return ic;
|
52
|
}
|
53
|
|
54
|
void
|
55
|
dvb_conversion_init(void)
|
56
|
{
|
57
|
char buf[50];
|
58
|
int i;
|
59
|
|
60
|
for(i = 1; i <= 15; i++) {
|
61
|
snprintf(buf, sizeof(buf), "ISO_8859-%d", i);
|
62
|
convert_iso_8859[i] = dvb_iconv_open(buf);
|
63
|
}
|
64
|
|
65
|
convert_utf8 = dvb_iconv_open("UTF8");
|
66
|
convert_latin1 = dvb_iconv_open("ISO6937");
|
67
|
}
|
68
|
|
69
|
|
70
|
|
71
|
/*
|
72
|
* DVB String conversion according to EN 300 468, Annex A
|
73
|
* Not all character sets are supported, but it should cover most of them
|
74
|
*/
|
75
|
|
76
|
int
|
77
|
dvb_get_string(char *dst, size_t dstlen, const uint8_t *src, size_t srclen, char *dvb_default_charset)
|
78
|
{
|
79
|
iconv_t ic;
|
80
|
int len;
|
81
|
char *in, *out;
|
82
|
size_t inlen, outlen;
|
83
|
int utf8 = 0;
|
84
|
int i;
|
85
|
unsigned char *tmp;
|
86
|
int r;
|
87
|
if(srclen < 1) {
|
88
|
*dst = 0;
|
89
|
return 0;
|
90
|
}
|
91
|
|
92
|
switch(src[0]) {
|
93
|
case 0:
|
94
|
return -1;
|
95
|
|
96
|
case 0x01 ... 0x0b:
|
97
|
ic = convert_iso_8859[src[0] + 4];
|
98
|
src++; srclen--;
|
99
|
break;
|
100
|
|
101
|
case 0x0c ... 0x0f:
|
102
|
return -1;
|
103
|
|
104
|
case 0x10: /* Table A.4 */
|
105
|
if(srclen < 3 || src[1] != 0 || src[2] == 0 || src[2] > 0x0f)
|
106
|
return -1;
|
107
|
|
108
|
ic = convert_iso_8859[src[2]];
|
109
|
src+=3; srclen-=3;
|
110
|
break;
|
111
|
|
112
|
case 0x11 ... 0x14:
|
113
|
return -1;
|
114
|
|
115
|
case 0x15:
|
116
|
ic = convert_utf8;
|
117
|
utf8 = 1;
|
118
|
break;
|
119
|
case 0x16 ... 0x1f:
|
120
|
return -1;
|
121
|
|
122
|
default:
|
123
|
if (dvb_default_charset != NULL && sscanf(dvb_default_charset, "ISO8859-%d", &i) > 0) {
|
124
|
if (i > 0 && i < 16) {
|
125
|
ic = convert_iso_8859[i];
|
126
|
} else {
|
127
|
ic = convert_latin1;
|
128
|
}
|
129
|
} else {
|
130
|
ic = convert_latin1;
|
131
|
}
|
132
|
break;
|
133
|
}
|
134
|
|
135
|
if(srclen < 1) {
|
136
|
*dst = 0;
|
137
|
return 0;
|
138
|
}
|
139
|
|
140
|
tmp = alloca(srclen + 1);
|
141
|
memcpy(tmp, src, srclen);
|
142
|
tmp[srclen] = 0;
|
143
|
|
144
|
|
145
|
/* Escape control codes */
|
146
|
|
147
|
if(!utf8) {
|
148
|
for(i = 0; i < srclen; i++) {
|
149
|
if(tmp[i] >= 0x80 && tmp[i] <= 0x9f)
|
150
|
tmp[i] = ' ';
|
151
|
}
|
152
|
}
|
153
|
|
154
|
if(ic == (iconv_t) -1)
|
155
|
return -1;
|
156
|
|
157
|
inlen = srclen;
|
158
|
outlen = dstlen - 1;
|
159
|
|
160
|
out = dst;
|
161
|
in = (char *)tmp;
|
162
|
if (dvb_default_charset != NULL ) {
|
163
|
if (sscanf(dvb_default_charset, "ISO8859-%d", &i) > 0 && i > 0 && i < 16) {
|
164
|
ic = convert_iso_8859[i];
|
165
|
} else {
|
166
|
ic = convert_latin1;
|
167
|
}
|
168
|
}
|
169
|
while(inlen > 0) {
|
170
|
r = iconv(ic, &in, &inlen, &out, &outlen);
|
171
|
if(r == (size_t) -1) {
|
172
|
if(errno == EILSEQ) {
|
173
|
in++;
|
174
|
inlen--;
|
175
|
continue;
|
176
|
} else {
|
177
|
return -1;
|
178
|
}
|
179
|
}
|
180
|
}
|
181
|
|
182
|
len = dstlen - outlen - 1;
|
183
|
dst[len] = 0;
|
184
|
return 0;
|
185
|
}
|
186
|
|
187
|
|
188
|
int
|
189
|
dvb_get_string_with_len(char *dst, size_t dstlen,
|
190
|
const uint8_t *buf, size_t buflen, char *dvb_default_charset)
|
191
|
{
|
192
|
int l = buf[0];
|
193
|
|
194
|
if(l + 1 > buflen)
|
195
|
return -1;
|
196
|
|
197
|
if(dvb_get_string(dst, dstlen, buf + 1, l, dvb_default_charset))
|
198
|
return -1;
|
199
|
|
200
|
return l + 1;
|
201
|
}
|
202
|
|
203
|
|
204
|
/**
|
205
|
*
|
206
|
*/
|
207
|
void
|
208
|
atsc_utf16_to_utf8(uint8_t *src, int len, char *buf, int buflen)
|
209
|
{
|
210
|
int i, c, r;
|
211
|
|
212
|
for(i = 0; i < len; i++) {
|
213
|
c = (src[i * 2 + 0] << 8) | src[i * 2 + 1];
|
214
|
|
215
|
if(buflen >= 7) {
|
216
|
r = put_utf8(buf, c);
|
217
|
buf += r;
|
218
|
buflen -= r;
|
219
|
}
|
220
|
}
|
221
|
*buf = 0;
|
222
|
}
|
223
|
|
224
|
|
225
|
|
226
|
|
227
|
|
228
|
/*
|
229
|
* DVB time and date functions
|
230
|
*/
|
231
|
|
232
|
time_t
|
233
|
dvb_convert_date(uint8_t *dvb_buf)
|
234
|
{
|
235
|
int i;
|
236
|
int year, month, day, hour, min, sec;
|
237
|
long int mjd;
|
238
|
struct tm dvb_time;
|
239
|
|
240
|
mjd = (dvb_buf[0] & 0xff) << 8;
|
241
|
mjd += (dvb_buf[1] & 0xff);
|
242
|
hour = bcdtoint(dvb_buf[2] & 0xff);
|
243
|
min = bcdtoint(dvb_buf[3] & 0xff);
|
244
|
sec = bcdtoint(dvb_buf[4] & 0xff);
|
245
|
/*
|
246
|
* Use the routine specified in ETSI EN 300 468 V1.4.1,
|
247
|
* "Specification for Service Information in Digital Video Broadcasting"
|
248
|
* to convert from Modified Julian Date to Year, Month, Day.
|
249
|
*/
|
250
|
year = (int) ((mjd - 15078.2) / 365.25);
|
251
|
month = (int) ((mjd - 14956.1 - (int) (year * 365.25)) / 30.6001);
|
252
|
day = mjd - 14956 - (int) (year * 365.25) - (int) (month * 30.6001);
|
253
|
if (month == 14 || month == 15)
|
254
|
i = 1;
|
255
|
else
|
256
|
i = 0;
|
257
|
year += i;
|
258
|
month = month - 1 - i * 12;
|
259
|
|
260
|
dvb_time.tm_sec = sec;
|
261
|
dvb_time.tm_min = min;
|
262
|
dvb_time.tm_hour = hour;
|
263
|
dvb_time.tm_mday = day;
|
264
|
dvb_time.tm_mon = month - 1;
|
265
|
dvb_time.tm_year = year;
|
266
|
dvb_time.tm_isdst = -1;
|
267
|
dvb_time.tm_wday = 0;
|
268
|
dvb_time.tm_yday = 0;
|
269
|
return (timegm(&dvb_time));
|
270
|
}
|
271
|
|
272
|
/**
|
273
|
*
|
274
|
*/
|
275
|
static struct strtab adaptertype[] = {
|
276
|
{ "DVB-S", FE_QPSK },
|
277
|
{ "DVB-C", FE_QAM },
|
278
|
{ "DVB-T", FE_OFDM },
|
279
|
{ "ATSC", FE_ATSC },
|
280
|
};
|
281
|
|
282
|
|
283
|
int
|
284
|
dvb_str_to_adaptertype(const char *str)
|
285
|
{
|
286
|
return str2val(str, adaptertype);
|
287
|
}
|
288
|
|
289
|
const char *
|
290
|
dvb_adaptertype_to_str(int type)
|
291
|
{
|
292
|
return val2str(type, adaptertype) ?: "invalid";
|
293
|
}
|
294
|
|
295
|
const char *
|
296
|
dvb_polarisation_to_str(int pol)
|
297
|
{
|
298
|
switch(pol) {
|
299
|
case POLARISATION_VERTICAL: return "V";
|
300
|
case POLARISATION_HORIZONTAL: return "H";
|
301
|
case POLARISATION_CIRCULAR_LEFT: return "L";
|
302
|
case POLARISATION_CIRCULAR_RIGHT: return "R";
|
303
|
default: return "X";
|
304
|
}
|
305
|
}
|
306
|
|
307
|
const char *
|
308
|
dvb_polarisation_to_str_long(int pol)
|
309
|
{
|
310
|
switch(pol) {
|
311
|
case POLARISATION_VERTICAL: return "Vertical";
|
312
|
case POLARISATION_HORIZONTAL: return "Horizontal";
|
313
|
case POLARISATION_CIRCULAR_LEFT: return "Left";
|
314
|
case POLARISATION_CIRCULAR_RIGHT: return "Right";
|
315
|
default: return "??";
|
316
|
}
|
317
|
}
|
318
|
|
319
|
|
320
|
th_dvb_adapter_t *
|
321
|
dvb_adapter_find_by_identifier(const char *identifier)
|
322
|
{
|
323
|
th_dvb_adapter_t *tda;
|
324
|
|
325
|
TAILQ_FOREACH(tda, &dvb_adapters, tda_global_link)
|
326
|
if(!strcmp(identifier, tda->tda_identifier))
|
327
|
return tda;
|
328
|
return NULL;
|
329
|
}
|
330
|
|
331
|
|
332
|
/**
|
333
|
*
|
334
|
*/
|
335
|
static const char *
|
336
|
nicenum(char *x, size_t siz, unsigned int v)
|
337
|
{
|
338
|
if(v < 1000)
|
339
|
snprintf(x, siz, "%d", v);
|
340
|
else if(v < 1000000)
|
341
|
snprintf(x, siz, "%d,%03d", v / 1000, v % 1000);
|
342
|
else if(v < 1000000000)
|
343
|
snprintf(x, siz, "%d,%03d,%03d",
|
344
|
v / 1000000, (v % 1000000) / 1000, v % 1000);
|
345
|
else
|
346
|
snprintf(x, siz, "%d,%03d,%03d,%03d",
|
347
|
v / 1000000000, (v % 1000000000) / 1000000,
|
348
|
(v % 1000000) / 1000, v % 1000);
|
349
|
return x;
|
350
|
}
|
351
|
|
352
|
|
353
|
/**
|
354
|
*
|
355
|
*/
|
356
|
void
|
357
|
dvb_mux_nicefreq(char *buf, size_t size, th_dvb_mux_instance_t *tdmi)
|
358
|
{
|
359
|
char freq[50];
|
360
|
|
361
|
if(tdmi->tdmi_adapter->tda_type == FE_QPSK) {
|
362
|
nicenum(freq, sizeof(freq), tdmi->tdmi_conf.dmc_fe_params.frequency);
|
363
|
snprintf(buf, size, "%s kHz", freq);
|
364
|
} else {
|
365
|
nicenum(freq, sizeof(freq),
|
366
|
tdmi->tdmi_conf.dmc_fe_params.frequency / 1000);
|
367
|
snprintf(buf, size, "%s kHz", freq);
|
368
|
}
|
369
|
}
|
370
|
|
371
|
|
372
|
/**
|
373
|
*
|
374
|
*/
|
375
|
void
|
376
|
dvb_mux_nicename(char *buf, size_t size, th_dvb_mux_instance_t *tdmi)
|
377
|
{
|
378
|
char freq[50];
|
379
|
const char *n = tdmi->tdmi_network;
|
380
|
|
381
|
if(tdmi->tdmi_adapter->tda_type == FE_QPSK) {
|
382
|
nicenum(freq, sizeof(freq), tdmi->tdmi_conf.dmc_fe_params.frequency);
|
383
|
snprintf(buf, size, "%s%s%s kHz %s (%s)",
|
384
|
n?:"", n ? ": ":"", freq,
|
385
|
dvb_polarisation_to_str_long(tdmi->tdmi_conf.dmc_polarisation),
|
386
|
tdmi->tdmi_conf.dmc_satconf ? tdmi->tdmi_conf.dmc_satconf->sc_name : "No satconf");
|
387
|
|
388
|
} else {
|
389
|
nicenum(freq, sizeof(freq), tdmi->tdmi_conf.dmc_fe_params.frequency / 1000);
|
390
|
snprintf(buf, size, "%s%s%s kHz", n?:"", n ? ": ":"", freq);
|
391
|
}
|
392
|
}
|
393
|
|