
- the skel variable is shared in multiple thread - also remove mpegts_pid_sub_skel, it's not used frequently
917 lines
22 KiB
C
917 lines
22 KiB
C
/*
|
|
* TV Input - DVB - Support/Conversion functions
|
|
* Copyright (C) 2007 Andreas Öman
|
|
*
|
|
* 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 <sys/ioctl.h>
|
|
#include <errno.h>
|
|
|
|
#include <stdio.h>
|
|
#include <unistd.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "tvheadend.h"
|
|
#include "dvb.h"
|
|
#include "dvb_charset_tables.h"
|
|
#include "input.h"
|
|
#include "intlconv.h"
|
|
|
|
static int convert_iso_8859[16] = {
|
|
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, -1, 11, 12, 13
|
|
};
|
|
#define convert_utf8 14
|
|
#define convert_iso6937 15
|
|
#define convert_ucs2 16
|
|
#define convert_gb 17
|
|
|
|
static inline size_t conv_gb(const uint8_t *src, size_t srclen,
|
|
char *dst, size_t *dstlen)
|
|
{
|
|
ssize_t len;
|
|
len = intlconv_to_utf8(dst, *dstlen, "gb2312", (char *)src, srclen);
|
|
if (len < 0 || len > *dstlen)
|
|
return -1;
|
|
*dstlen -= len;
|
|
return 0;
|
|
}
|
|
|
|
static inline int encode_utf8(unsigned int c, char *outb, int outleft)
|
|
{
|
|
if (c <= 0x7F && outleft >= 1) {
|
|
*outb = c;
|
|
return 1;
|
|
} else if (c <= 0x7FF && outleft >=2) {
|
|
*outb++ = ((c >> 6) & 0x1F) | 0xC0;
|
|
*outb++ = ( c & 0x3F) | 0x80;
|
|
return 2;
|
|
} else if (c <= 0xFFFF && outleft >= 3) {
|
|
*outb++ = ((c >> 12) & 0x0F) | 0xE0;
|
|
*outb++ = ((c >> 6) & 0x3F) | 0x80;
|
|
*outb++ = ( c & 0x3F) | 0x80;
|
|
return 3;
|
|
} else if (c <= 0x10FFFF && outleft >= 4) {
|
|
*outb++ = ((c >> 18) & 0x07) | 0xF0;
|
|
*outb++ = ((c >> 12) & 0x3F) | 0x80;
|
|
*outb++ = ((c >> 6) & 0x3F) | 0x80;
|
|
*outb++ = ( c & 0x3F) | 0x80;
|
|
return 4;
|
|
} else {
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
static inline size_t conv_UCS2(const uint8_t *src, size_t srclen,char *dst, size_t *dstlen)
|
|
{
|
|
while (srclen>0 && (*dstlen)>0){
|
|
uint16_t uc = *src<<8|*(src+1);
|
|
int len = encode_utf8(uc, dst, *dstlen);
|
|
if (len == -1) {
|
|
errno = E2BIG;
|
|
return -1;
|
|
} else {
|
|
(*dstlen) -= len;
|
|
dst += len;
|
|
}
|
|
srclen-=2;
|
|
src+=2;
|
|
}
|
|
if (srclen>0) {
|
|
errno = E2BIG;
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static inline size_t conv_utf8(const uint8_t *src, size_t srclen,
|
|
char *dst, size_t *dstlen)
|
|
{
|
|
while (srclen>0 && (*dstlen)>0) {
|
|
*dst = (char) *src;
|
|
srclen--; (*dstlen)--;
|
|
src++; dst++;
|
|
}
|
|
if (srclen>0) {
|
|
errno = E2BIG;
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static inline size_t conv_8859(int conv,
|
|
const uint8_t *src, size_t srclen,
|
|
char *dst, size_t *dstlen)
|
|
{
|
|
uint16_t *table = conv_8859_table[conv];
|
|
|
|
while (srclen>0 && (*dstlen)>0) {
|
|
uint8_t c = *src;
|
|
if (c <= 0x7f) {
|
|
// lower half of iso-8859-* is identical to utf-8
|
|
*dst = (char) *src;
|
|
(*dstlen)--;
|
|
dst++;
|
|
} else if (c <= 0x9f) {
|
|
// codes 0x80 - 0x9f (control codes) are ignored
|
|
} else {
|
|
// map according to character table, skipping
|
|
// unmapped chars (value 0 in the table)
|
|
uint16_t uc = table[c-0xa0];
|
|
if (uc != 0) {
|
|
int len = encode_utf8(uc, dst, *dstlen);
|
|
if (len == -1) {
|
|
errno = E2BIG;
|
|
return -1;
|
|
} else {
|
|
(*dstlen) -= len;
|
|
dst += len;
|
|
}
|
|
}
|
|
}
|
|
srclen--;
|
|
src++;
|
|
}
|
|
if (srclen>0) {
|
|
errno = E2BIG;
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static inline size_t conv_6937(const uint8_t *src, size_t srclen,
|
|
char *dst, size_t *dstlen)
|
|
{
|
|
while (srclen>0 && (*dstlen)>0) {
|
|
uint8_t c = *src;
|
|
if (c <= 0x7f) {
|
|
// lower half of iso6937 is identical to utf-8
|
|
*dst = (char) *src;
|
|
(*dstlen)--;
|
|
dst++;
|
|
} else if (c <= 0x9f) {
|
|
// codes 0x80 - 0x9f (control codes) are ignored
|
|
} else {
|
|
uint16_t uc;
|
|
if (c >= 0xc0 && c <= 0xcf) {
|
|
// map two-byte sequence, skipping illegal combinations.
|
|
if (srclen<2) {
|
|
errno = EINVAL;
|
|
return -1;
|
|
}
|
|
srclen--;
|
|
src++;
|
|
uint8_t c2 = *src;
|
|
if (c2 == 0x20) {
|
|
uc = iso6937_lone_accents[c-0xc0];
|
|
} else if (c2 >= 0x41 && c2 <= 0x5a) {
|
|
uc = iso6937_multi_byte[c-0xc0][c2-0x41];
|
|
} else if (c2 >= 0x61 && c2 <= 0x7a) {
|
|
uc = iso6937_multi_byte[c-0xc0][c2-0x61+26];
|
|
} else {
|
|
uc = 0;
|
|
}
|
|
} else {
|
|
// map according to single character table, skipping
|
|
// unmapped chars (value 0 in the table)
|
|
uc = iso6937_single_byte[c-0xa0];
|
|
}
|
|
if (uc != 0) {
|
|
int len = encode_utf8(uc, dst, *dstlen);
|
|
if (len == -1) {
|
|
errno = E2BIG;
|
|
return -1;
|
|
} else {
|
|
(*dstlen) -= len;
|
|
dst += len;
|
|
}
|
|
}
|
|
}
|
|
srclen--;
|
|
src++;
|
|
}
|
|
if (srclen>0) {
|
|
errno = E2BIG;
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static inline size_t dvb_convert(int conv,
|
|
const uint8_t *src, size_t srclen,
|
|
char *dst, size_t *dstlen)
|
|
{
|
|
switch (conv) {
|
|
case convert_utf8: return conv_utf8(src, srclen, dst, dstlen);
|
|
case convert_iso6937: return conv_6937(src, srclen, dst, dstlen);
|
|
case convert_gb: return conv_gb(src,srclen,dst,dstlen);
|
|
case convert_ucs2:return conv_UCS2(src,srclen,dst,dstlen);
|
|
default: return conv_8859(conv, src, srclen, dst, dstlen);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* DVB String conversion according to EN 300 468, Annex A
|
|
* Not all character sets are supported, but it should cover most of them
|
|
*/
|
|
|
|
int
|
|
dvb_get_string
|
|
(char *dst, size_t dstlen, const uint8_t *src, size_t srclen,
|
|
const char *dvb_charset, dvb_string_conv_t *conv)
|
|
{
|
|
int ic = -1;
|
|
size_t len, outlen;
|
|
int i, auto_pl_charset = 0;
|
|
|
|
if(srclen < 1) {
|
|
*dst = 0;
|
|
return 0;
|
|
}
|
|
|
|
/* Check custom conversion */
|
|
while (conv && conv->func) {
|
|
if (conv->type == src[0])
|
|
return conv->func(dst, &dstlen, src, srclen);
|
|
conv++;
|
|
}
|
|
|
|
// check for automatic polish charset detection
|
|
if (dvb_charset && strcmp("AUTO_POLISH", dvb_charset) == 0) {
|
|
auto_pl_charset = 1;
|
|
dvb_charset = NULL;
|
|
}
|
|
|
|
// automatic charset detection
|
|
switch(src[0]) {
|
|
case 0:
|
|
return -1;
|
|
|
|
case 0x01 ... 0x0b:
|
|
if (auto_pl_charset && (src[0] + 4) == 5)
|
|
ic = convert_iso6937;
|
|
else
|
|
ic = convert_iso_8859[src[0] + 4];
|
|
src++; srclen--;
|
|
break;
|
|
|
|
case 0x0c ... 0x0f:
|
|
src++; srclen--;
|
|
break;
|
|
|
|
case 0x10: /* Table A.4 */
|
|
if(srclen < 3 || src[1] != 0 || src[2] == 0 || src[2] > 0x0f)
|
|
return -1;
|
|
|
|
ic = convert_iso_8859[src[2]];
|
|
src+=3; srclen-=3;
|
|
break;
|
|
|
|
case 0x11:
|
|
ic = convert_ucs2;
|
|
src++; srclen--;
|
|
break;
|
|
|
|
case 0x13:
|
|
ic = convert_gb;
|
|
src++; srclen--;
|
|
break;
|
|
|
|
case 0x12:
|
|
src++; srclen--;
|
|
break;
|
|
|
|
case 0x14:
|
|
ic = convert_ucs2;
|
|
src++; srclen--;
|
|
break;
|
|
|
|
case 0x15:
|
|
ic = convert_utf8;
|
|
src++; srclen--;
|
|
break;
|
|
|
|
case 0x16 ... 0x1f:
|
|
src++; srclen--;
|
|
break;
|
|
|
|
default:
|
|
if (auto_pl_charset)
|
|
ic = convert_iso_8859[2];
|
|
else
|
|
ic = convert_iso6937;
|
|
break;
|
|
}
|
|
|
|
// manual charset override
|
|
if (dvb_charset != NULL && dvb_charset[0] != 0) {
|
|
if (!strcmp(dvb_charset, "AUTO")) {
|
|
// ignore
|
|
} else if (sscanf(dvb_charset, "ISO-8859-%d", &i) > 0 && i > 0 && i < 16) {
|
|
ic = convert_iso_8859[i];
|
|
} else if (!strcmp(dvb_charset, "ISO-6937")) {
|
|
ic = convert_iso6937;
|
|
} else if (!strcmp(dvb_charset, "UTF-8")) {
|
|
ic = convert_utf8;
|
|
} else if (!strcmp(dvb_charset, "GB2312")) {
|
|
ic = convert_gb;
|
|
} else if (!strcmp(dvb_charset, "UCS2")) {
|
|
ic = convert_ucs2;
|
|
}
|
|
}
|
|
|
|
if(srclen < 1) {
|
|
*dst = 0;
|
|
return 0;
|
|
}
|
|
|
|
if(ic == -1)
|
|
return -1;
|
|
|
|
outlen = dstlen - 1;
|
|
|
|
if (dvb_convert(ic, src, srclen, dst, &outlen) == -1) {
|
|
return -1;
|
|
}
|
|
|
|
len = dstlen - outlen - 1;
|
|
dst[len] = 0;
|
|
return 0;
|
|
}
|
|
|
|
|
|
int
|
|
dvb_get_string_with_len(char *dst, size_t dstlen,
|
|
const uint8_t *buf, size_t buflen, const char *dvb_charset,
|
|
dvb_string_conv_t *conv)
|
|
{
|
|
int l = buf[0];
|
|
|
|
if(l + 1 > buflen)
|
|
return -1;
|
|
|
|
if(dvb_get_string(dst, dstlen, buf + 1, l, dvb_charset, conv))
|
|
return -1;
|
|
|
|
return l + 1;
|
|
}
|
|
|
|
|
|
/**
|
|
*
|
|
*/
|
|
void
|
|
atsc_utf16_to_utf8(const uint8_t *src, int len, char *buf, int buflen)
|
|
{
|
|
int i, c, r;
|
|
|
|
for(i = 0; i < len; i++) {
|
|
c = (src[i * 2 + 0] << 8) | src[i * 2 + 1];
|
|
|
|
if(buflen >= 7) {
|
|
r = put_utf8(buf, c);
|
|
buf += r;
|
|
buflen -= r;
|
|
}
|
|
}
|
|
*buf = 0;
|
|
}
|
|
|
|
/*
|
|
* DVB time and date functions
|
|
*/
|
|
|
|
time_t
|
|
dvb_convert_date(const uint8_t *dvb_buf)
|
|
{
|
|
int i;
|
|
int year, month, day, hour, min, sec;
|
|
long int mjd;
|
|
struct tm dvb_time;
|
|
|
|
mjd = (dvb_buf[0] & 0xff) << 8;
|
|
mjd += (dvb_buf[1] & 0xff);
|
|
hour = bcdtoint(dvb_buf[2] & 0xff);
|
|
min = bcdtoint(dvb_buf[3] & 0xff);
|
|
sec = bcdtoint(dvb_buf[4] & 0xff);
|
|
/*
|
|
* Use the routine specified in ETSI EN 300 468 V1.4.1,
|
|
* "Specification for Service Information in Digital Video Broadcasting"
|
|
* to convert from Modified Julian Date to Year, Month, Day.
|
|
*/
|
|
year = (int) ((mjd - 15078.2) / 365.25);
|
|
month = (int) ((mjd - 14956.1 - (int) (year * 365.25)) / 30.6001);
|
|
day = mjd - 14956 - (int) (year * 365.25) - (int) (month * 30.6001);
|
|
if (month == 14 || month == 15)
|
|
i = 1;
|
|
else
|
|
i = 0;
|
|
year += i;
|
|
month = month - 1 - i * 12;
|
|
|
|
dvb_time.tm_sec = sec;
|
|
dvb_time.tm_min = min;
|
|
dvb_time.tm_hour = hour;
|
|
dvb_time.tm_mday = day;
|
|
dvb_time.tm_mon = month - 1;
|
|
dvb_time.tm_year = year;
|
|
dvb_time.tm_isdst = -1;
|
|
dvb_time.tm_wday = 0;
|
|
dvb_time.tm_yday = 0;
|
|
return (timegm(&dvb_time));
|
|
}
|
|
|
|
/*
|
|
* DVB API helpers
|
|
*/
|
|
#if ENABLE_MPEGTS_DVB
|
|
|
|
|
|
#define dvb_str2val(p)\
|
|
const char *dvb_##p##2str (int p) { return val2str(p, p##tab); }\
|
|
int dvb_str2##p (const char *p) { return str2val(p, p##tab); }
|
|
|
|
#define DVB_EOD -10 /* end-of-data */
|
|
|
|
static const char *dvb_common2str(int p)
|
|
{
|
|
if (p == 0)
|
|
return "NONE";
|
|
if (p == 1)
|
|
return "AUTO";
|
|
return NULL;
|
|
}
|
|
|
|
static int dvb_str2common(const char *p)
|
|
{
|
|
if (strcmp(p, "NONE") == 0)
|
|
return 0;
|
|
if (strcmp(p, "AUTO") == 0)
|
|
return 1;
|
|
return DVB_EOD;
|
|
}
|
|
|
|
static int dvb_verify(int val, int *table)
|
|
{
|
|
while (*table != DVB_EOD) {
|
|
if (val == *table)
|
|
return val;
|
|
table++;
|
|
}
|
|
return 0; /* NONE */
|
|
}
|
|
|
|
const char *dvb_rolloff2str(int p)
|
|
{
|
|
static char __thread buf[16];
|
|
const char *res = dvb_common2str(p);
|
|
if (res)
|
|
return res;
|
|
sprintf(buf, "%02i", p / 10);
|
|
return buf;
|
|
}
|
|
|
|
int dvb_str2rolloff(const char *p)
|
|
{
|
|
static int rolloff_table[] = {
|
|
DVB_ROLLOFF_20,
|
|
DVB_ROLLOFF_25,
|
|
DVB_ROLLOFF_35,
|
|
DVB_EOD,
|
|
};
|
|
int res = dvb_str2common(p);
|
|
if (res != DVB_EOD)
|
|
return res;
|
|
return dvb_verify(atoi(p) * 10, rolloff_table);
|
|
}
|
|
|
|
const static struct strtab delsystab[] = {
|
|
{ "NONE", DVB_SYS_NONE },
|
|
{ "DVBC/ANNEX_A", DVB_SYS_DVBC_ANNEX_A },
|
|
{ "DVBC_ANNEX_A", DVB_SYS_DVBC_ANNEX_A },
|
|
{ "DVBC/ANNEX_B", DVB_SYS_DVBC_ANNEX_B },
|
|
{ "DVBC_ANNEX_B", DVB_SYS_DVBC_ANNEX_B },
|
|
{ "DVBC/ANNEX_C", DVB_SYS_DVBC_ANNEX_C },
|
|
{ "DVBC_ANNEX_C", DVB_SYS_DVBC_ANNEX_C },
|
|
{ "DVBC_ANNEX_AC",DVB_SYS_DVBC_ANNEX_A }, /* for compatibility */
|
|
{ "DVBT", DVB_SYS_DVBT },
|
|
{ "DVBT2", DVB_SYS_DVBT2 },
|
|
{ "DVBS", DVB_SYS_DVBS },
|
|
{ "DVBS2", DVB_SYS_DVBS2 },
|
|
{ "DVBH", DVB_SYS_DVBH },
|
|
{ "ISDBT", DVB_SYS_ISDBT },
|
|
{ "ISDBS", DVB_SYS_ISDBS },
|
|
{ "ISDBC", DVB_SYS_ISDBC },
|
|
{ "ATSC", DVB_SYS_ATSC },
|
|
{ "ATSCMH", DVB_SYS_ATSCMH },
|
|
{ "DTMB", DVB_SYS_DTMB },
|
|
{ "DMBTH", DVB_SYS_DTMB }, /* for compatibility */
|
|
{ "CMMB", DVB_SYS_CMMB },
|
|
{ "DAB", DVB_SYS_DAB },
|
|
{ "DSS", DVB_SYS_DSS },
|
|
{ "TURBO", DVB_SYS_TURBO }
|
|
};
|
|
dvb_str2val(delsys);
|
|
|
|
int
|
|
dvb_delsys2type ( dvb_fe_delivery_system_t delsys )
|
|
{
|
|
switch (delsys) {
|
|
case DVB_SYS_DVBC_ANNEX_A:
|
|
case DVB_SYS_DVBC_ANNEX_B:
|
|
case DVB_SYS_DVBC_ANNEX_C:
|
|
case DVB_SYS_ISDBC:
|
|
return DVB_TYPE_C;
|
|
case DVB_SYS_DVBT:
|
|
case DVB_SYS_DVBT2:
|
|
case DVB_SYS_TURBO:
|
|
case DVB_SYS_ISDBT:
|
|
return DVB_TYPE_T;
|
|
case DVB_SYS_DVBS:
|
|
case DVB_SYS_DVBS2:
|
|
case DVB_SYS_ISDBS:
|
|
return DVB_TYPE_S;
|
|
case DVB_SYS_ATSC:
|
|
case DVB_SYS_ATSCMH:
|
|
return DVB_TYPE_ATSC;
|
|
default:
|
|
return DVB_TYPE_NONE;
|
|
}
|
|
}
|
|
|
|
const char *dvb_fec2str(int p)
|
|
{
|
|
static char __thread buf[16];
|
|
const char *res = dvb_common2str(p);
|
|
if (res)
|
|
return res;
|
|
sprintf(buf, "%i/%i", p / 100, p % 100);
|
|
return buf;
|
|
}
|
|
|
|
int dvb_str2fec(const char *p)
|
|
{
|
|
static int fec_table[] = {
|
|
DVB_FEC_1_2,
|
|
DVB_FEC_1_3,
|
|
DVB_FEC_1_5,
|
|
DVB_FEC_2_3,
|
|
DVB_FEC_2_5,
|
|
DVB_FEC_2_9,
|
|
DVB_FEC_3_4,
|
|
DVB_FEC_3_5,
|
|
DVB_FEC_4_5,
|
|
DVB_FEC_4_15,
|
|
DVB_FEC_5_6,
|
|
DVB_FEC_5_9,
|
|
DVB_FEC_6_7,
|
|
DVB_FEC_7_8,
|
|
DVB_FEC_7_9,
|
|
DVB_FEC_7_15,
|
|
DVB_FEC_8_9,
|
|
DVB_FEC_8_15,
|
|
DVB_FEC_9_10,
|
|
DVB_FEC_9_20,
|
|
DVB_FEC_11_15,
|
|
DVB_FEC_11_20,
|
|
DVB_FEC_11_45,
|
|
DVB_FEC_13_18,
|
|
DVB_FEC_13_45,
|
|
DVB_FEC_14_45,
|
|
DVB_FEC_23_36,
|
|
DVB_FEC_25_36,
|
|
DVB_FEC_26_45,
|
|
DVB_FEC_28_45,
|
|
DVB_FEC_29_45,
|
|
DVB_FEC_31_45,
|
|
DVB_FEC_32_45,
|
|
DVB_FEC_77_90,
|
|
DVB_EOD,
|
|
};
|
|
int res = dvb_str2common(p);
|
|
int hi, lo;
|
|
if (res != DVB_EOD)
|
|
return res;
|
|
hi = lo = 0;
|
|
sscanf(p, "%i/%i", &hi, &lo);
|
|
return dvb_verify(hi * 100 + lo, fec_table);
|
|
}
|
|
|
|
const static struct strtab qamtab[] = {
|
|
{ "NONE", DVB_MOD_NONE },
|
|
{ "AUTO", DVB_MOD_AUTO },
|
|
{ "QPSK", DVB_MOD_QPSK },
|
|
{ "QAM4NR", DVB_MOD_QAM_4_NR },
|
|
{ "QAM/AUTO", DVB_MOD_QAM_AUTO },
|
|
{ "QAM-AUTO", DVB_MOD_QAM_AUTO },
|
|
{ "QAM/16", DVB_MOD_QAM_16 },
|
|
{ "QAM16", DVB_MOD_QAM_16 },
|
|
{ "QAM/32", DVB_MOD_QAM_32 },
|
|
{ "QAM32", DVB_MOD_QAM_32 },
|
|
{ "QAM/64", DVB_MOD_QAM_64 },
|
|
{ "QAM64", DVB_MOD_QAM_64 },
|
|
{ "QAM/128", DVB_MOD_QAM_128 },
|
|
{ "QAM128", DVB_MOD_QAM_128 },
|
|
{ "QAM/256", DVB_MOD_QAM_256 },
|
|
{ "QAM256", DVB_MOD_QAM_256 },
|
|
{ "VSB/8", DVB_MOD_VSB_8 },
|
|
{ "8VSB", DVB_MOD_VSB_8 },
|
|
{ "VSB/16", DVB_MOD_VSB_16 },
|
|
{ "16VSB", DVB_MOD_VSB_16 },
|
|
{ "PSK/8", DVB_MOD_PSK_8 },
|
|
{ "8PSK", DVB_MOD_PSK_8 },
|
|
{ "DQPSK", DVB_MOD_DQPSK },
|
|
{ "BPSK", DVB_MOD_BPSK },
|
|
{ "BPSK-S", DVB_MOD_BPSK_S },
|
|
{ "16APSK", DVB_MOD_APSK_16 },
|
|
{ "32APSK", DVB_MOD_APSK_32 },
|
|
{ "64APSK", DVB_MOD_APSK_64 },
|
|
{ "128APSK", DVB_MOD_APSK_128 },
|
|
{ "256APSK", DVB_MOD_APSK_256 },
|
|
{ "8APSK-L", DVB_MOD_APSK_8_L },
|
|
{ "16APSK-L", DVB_MOD_APSK_16_L },
|
|
{ "32APSK-L", DVB_MOD_APSK_32_L },
|
|
{ "64APSK-L", DVB_MOD_APSK_64_L },
|
|
{ "128APSK-L", DVB_MOD_APSK_128_L },
|
|
{ "256APSK-L", DVB_MOD_APSK_256_L },
|
|
};
|
|
dvb_str2val(qam);
|
|
|
|
const char *dvb_bw2str(int p)
|
|
{
|
|
static char __thread buf[16];
|
|
const char *res = dvb_common2str(p);
|
|
if (res)
|
|
return res;
|
|
if (p % 1000)
|
|
sprintf(buf, "%i.%iMHz", p / 1000, p % 1000);
|
|
else
|
|
sprintf(buf, "%iMHz", p / 1000);
|
|
return buf;
|
|
}
|
|
|
|
int dvb_str2bw(const char *p)
|
|
{
|
|
static int bw_table[] = {
|
|
DVB_BANDWIDTH_1_712_MHZ,
|
|
DVB_BANDWIDTH_5_MHZ,
|
|
DVB_BANDWIDTH_6_MHZ,
|
|
DVB_BANDWIDTH_7_MHZ,
|
|
DVB_BANDWIDTH_8_MHZ,
|
|
DVB_BANDWIDTH_10_MHZ,
|
|
DVB_EOD,
|
|
};
|
|
int len, res = dvb_str2common(p);
|
|
int hi, lo;
|
|
if (res != DVB_EOD)
|
|
return res;
|
|
len = strlen(p);
|
|
hi = lo = 0;
|
|
sscanf(p, "%i.%i", &hi, &lo);
|
|
if (len > 3 && strcmp(&p[len-3], "MHz") == 0)
|
|
hi = hi * 1000 + lo;
|
|
return dvb_verify(hi, bw_table);
|
|
}
|
|
|
|
const static struct strtab invertab[] = {
|
|
{ "NONE", DVB_INVERSION_UNDEFINED },
|
|
{ "AUTO", DVB_INVERSION_AUTO },
|
|
{ "ON", DVB_INVERSION_ON },
|
|
{ "OFF", DVB_INVERSION_OFF },
|
|
};
|
|
dvb_str2val(inver);
|
|
|
|
const static struct strtab modetab[] = {
|
|
{ "NONE", DVB_TRANSMISSION_MODE_NONE },
|
|
{ "AUTO", DVB_TRANSMISSION_MODE_AUTO },
|
|
{ "1k", DVB_TRANSMISSION_MODE_1K },
|
|
{ "2k", DVB_TRANSMISSION_MODE_2K },
|
|
{ "8k", DVB_TRANSMISSION_MODE_8K },
|
|
{ "4k", DVB_TRANSMISSION_MODE_4K },
|
|
{ "16k", DVB_TRANSMISSION_MODE_16K },
|
|
{ "32k", DVB_TRANSMISSION_MODE_32K },
|
|
{ "C1", DVB_TRANSMISSION_MODE_C1 },
|
|
{ "C3780", DVB_TRANSMISSION_MODE_C3780 },
|
|
};
|
|
dvb_str2val(mode);
|
|
|
|
const static struct strtab guardtab[] = {
|
|
{ "NONE", DVB_GUARD_INTERVAL_NONE },
|
|
{ "AUTO", DVB_GUARD_INTERVAL_AUTO },
|
|
{ "1/4", DVB_GUARD_INTERVAL_1_4 },
|
|
{ "1/8", DVB_GUARD_INTERVAL_1_8 },
|
|
{ "1/32", DVB_GUARD_INTERVAL_1_32 },
|
|
{ "1/16", DVB_GUARD_INTERVAL_1_16 },
|
|
{ "1/128", DVB_GUARD_INTERVAL_1_128 },
|
|
{ "19/128", DVB_GUARD_INTERVAL_19_128 },
|
|
{ "19/256", DVB_GUARD_INTERVAL_19_256 },
|
|
{ "PN420", DVB_GUARD_INTERVAL_PN420 },
|
|
{ "PN595", DVB_GUARD_INTERVAL_PN595 },
|
|
{ "PN945", DVB_GUARD_INTERVAL_PN945 },
|
|
};
|
|
dvb_str2val(guard);
|
|
|
|
const static struct strtab hiertab[] = {
|
|
{ "NONE", DVB_HIERARCHY_NONE },
|
|
{ "AUTO", DVB_HIERARCHY_AUTO },
|
|
{ "1", DVB_HIERARCHY_1 },
|
|
{ "2", DVB_HIERARCHY_2 },
|
|
{ "4", DVB_HIERARCHY_4 },
|
|
};
|
|
dvb_str2val(hier);
|
|
|
|
const static struct strtab poltab[] = {
|
|
{ "V", DVB_POLARISATION_VERTICAL },
|
|
{ "H", DVB_POLARISATION_HORIZONTAL },
|
|
{ "L", DVB_POLARISATION_CIRCULAR_LEFT },
|
|
{ "R", DVB_POLARISATION_CIRCULAR_RIGHT },
|
|
{ "O", DVB_POLARISATION_OFF },
|
|
};
|
|
dvb_str2val(pol);
|
|
|
|
const static struct strtab typetab[] = {
|
|
{"DVB-T", DVB_TYPE_T},
|
|
{"DVB-C", DVB_TYPE_C},
|
|
{"DVB-S", DVB_TYPE_S},
|
|
{"ATSC", DVB_TYPE_ATSC},
|
|
};
|
|
dvb_str2val(type);
|
|
|
|
const static struct strtab pilottab[] = {
|
|
{"NONE", DVB_PILOT_NONE},
|
|
{"AUTO", DVB_PILOT_AUTO},
|
|
{"ON", DVB_PILOT_ON},
|
|
{"OFF", DVB_PILOT_OFF}
|
|
};
|
|
dvb_str2val(pilot);
|
|
#undef dvb_str2val
|
|
|
|
static int
|
|
dvb_mux_conf_str_dvbt ( dvb_mux_conf_t *dmc, char *buf, size_t bufsize )
|
|
{
|
|
return
|
|
snprintf(buf, bufsize,
|
|
"%s freq %d bw %s cons %s hier %s code_rate %s:%s guard %s trans %s",
|
|
dvb_delsys2str(dmc->dmc_fe_delsys),
|
|
dmc->dmc_fe_freq,
|
|
dvb_bw2str(dmc->u.dmc_fe_ofdm.bandwidth),
|
|
dvb_qam2str(dmc->dmc_fe_modulation),
|
|
dvb_hier2str(dmc->u.dmc_fe_ofdm.hierarchy_information),
|
|
dvb_fec2str(dmc->u.dmc_fe_ofdm.code_rate_HP),
|
|
dvb_fec2str(dmc->u.dmc_fe_ofdm.code_rate_LP),
|
|
dvb_guard2str(dmc->u.dmc_fe_ofdm.guard_interval),
|
|
dvb_mode2str(dmc->u.dmc_fe_ofdm.transmission_mode));
|
|
}
|
|
|
|
static int
|
|
dvb_mux_conf_str_dvbc ( dvb_mux_conf_t *dmc, char *buf, size_t bufsize )
|
|
{
|
|
return
|
|
snprintf(buf, bufsize,
|
|
"%s freq %d sym %d mod %s fec %s",
|
|
dvb_delsys2str(dmc->dmc_fe_delsys),
|
|
dmc->dmc_fe_freq,
|
|
dmc->u.dmc_fe_qam.symbol_rate,
|
|
dvb_qam2str(dmc->dmc_fe_modulation),
|
|
dvb_fec2str(dmc->u.dmc_fe_qam.fec_inner));
|
|
}
|
|
|
|
static int
|
|
dvb_mux_conf_str_dvbs ( dvb_mux_conf_t *dmc, char *buf, size_t bufsize )
|
|
{
|
|
const char *pol = dvb_pol2str(dmc->u.dmc_fe_qpsk.polarisation);
|
|
const char dir = dmc->u.dmc_fe_qpsk.orbital_dir;
|
|
return
|
|
snprintf(buf, bufsize,
|
|
"%s pos %d.%d%c freq %d %c sym %d fec %s mod %s roff %s",
|
|
dvb_delsys2str(dmc->dmc_fe_delsys),
|
|
dmc->u.dmc_fe_qpsk.orbital_pos / 10,
|
|
dmc->u.dmc_fe_qpsk.orbital_pos % 10,
|
|
dir >= ' ' && dir <= 'z' ? dir : '?',
|
|
dmc->dmc_fe_freq,
|
|
pol ? pol[0] : 'X',
|
|
dmc->u.dmc_fe_qpsk.symbol_rate,
|
|
dvb_fec2str(dmc->u.dmc_fe_qpsk.fec_inner),
|
|
dvb_qam2str(dmc->dmc_fe_modulation),
|
|
dvb_rolloff2str(dmc->dmc_fe_rolloff));
|
|
}
|
|
|
|
static int
|
|
dvb_mux_conf_str_atsc ( dvb_mux_conf_t *dmc, char *buf, size_t bufsize )
|
|
{
|
|
return
|
|
snprintf(buf, bufsize,
|
|
"%s freq %d mod %s",
|
|
dvb_delsys2str(dmc->dmc_fe_delsys),
|
|
dmc->dmc_fe_freq,
|
|
dvb_qam2str(dmc->dmc_fe_modulation));
|
|
}
|
|
|
|
int
|
|
dvb_mux_conf_str ( dvb_mux_conf_t *dmc, char *buf, size_t bufsize )
|
|
{
|
|
switch (dmc->dmc_fe_type) {
|
|
case DVB_TYPE_NONE:
|
|
return
|
|
snprintf(buf, bufsize, "NONE %s", dvb_delsys2str(dmc->dmc_fe_delsys));
|
|
case DVB_TYPE_T:
|
|
return dvb_mux_conf_str_dvbt(dmc, buf, bufsize);
|
|
case DVB_TYPE_C:
|
|
return dvb_mux_conf_str_dvbc(dmc, buf, bufsize);
|
|
case DVB_TYPE_S:
|
|
return dvb_mux_conf_str_dvbs(dmc, buf, bufsize);
|
|
case DVB_TYPE_ATSC:
|
|
return dvb_mux_conf_str_atsc(dmc, buf, bufsize);
|
|
default:
|
|
return
|
|
snprintf(buf, bufsize, "UNKNOWN MUX CONFIG");
|
|
}
|
|
}
|
|
|
|
int
|
|
dvb_sat_position(const dvb_mux_conf_t *mc)
|
|
{
|
|
int pos = mc->u.dmc_fe_qpsk.orbital_pos;
|
|
assert(mc->dmc_fe_type == DVB_TYPE_S);
|
|
if (!mc->u.dmc_fe_qpsk.orbital_dir)
|
|
return INT_MAX;
|
|
if (mc->u.dmc_fe_qpsk.orbital_dir == 'W')
|
|
return -pos;
|
|
return pos;
|
|
}
|
|
|
|
const char *
|
|
dvb_sat_position_to_str(int position, char *buf, size_t buflen)
|
|
{
|
|
const int dec = position % 10;
|
|
|
|
if (!buf || !buflen)
|
|
return "";
|
|
snprintf(buf, buflen, "%d", abs(position / 10));
|
|
if (dec)
|
|
snprintf(buf + strlen(buf), buflen - strlen(buf), ".%d", abs(dec));
|
|
snprintf(buf + strlen(buf), buflen - strlen(buf), "%c", position < 0 ? 'W' : 'E');
|
|
return buf;
|
|
}
|
|
|
|
const int
|
|
dvb_sat_position_from_str( const char *buf )
|
|
{
|
|
const char *s = buf;
|
|
int min, maj;
|
|
char c;
|
|
|
|
if (!buf)
|
|
return INT_MAX;
|
|
maj = atoi(s);
|
|
while (*s && *s != '.')
|
|
s++;
|
|
min = *s == '.' ? atoi(s + 1) : 0;
|
|
if (*s != '.') s = buf;
|
|
do {
|
|
c = *s++;
|
|
} while (c && c != 'W' && c != 'E');
|
|
if (!c)
|
|
return INT_MAX;
|
|
if (maj > 180 || maj < 0)
|
|
return INT_MAX;
|
|
if (min > 9 || min < 0)
|
|
return INT_MAX;
|
|
return (maj * 10 + min) * (c == 'W' ? -1 : 1);
|
|
}
|
|
|
|
#endif /* ENABLE_MPEGTS_DVB */
|
|
|
|
/**
|
|
*
|
|
*/
|
|
extern pthread_mutex_t mpegts_pid_skel_mutex;
|
|
|
|
void dvb_init( void )
|
|
{
|
|
pthread_mutex_init(&mpegts_pid_skel_mutex, NULL);
|
|
}
|
|
|
|
void dvb_done( void )
|
|
{
|
|
extern SKEL_DECLARE(mpegts_table_state_skel, struct mpegts_table_state);
|
|
extern SKEL_DECLARE(mpegts_pid_skel, mpegts_pid_t);
|
|
|
|
SKEL_FREE(mpegts_table_state_skel);
|
|
SKEL_FREE(mpegts_pid_skel);
|
|
pthread_mutex_destroy(&mpegts_pid_skel_mutex);
|
|
}
|