diff --git a/dvb/si.h b/dvb/si.h
index 237729a..331c2a2 100644
--- a/dvb/si.h
+++ b/dvb/si.h
@@ -358,6 +358,58 @@ static inline void desc40_print(const uint8_t *p_desc,
free(psz_network_name);
}
+/*****************************************************************************
+ * Descriptor 0x41: Service list descriptor
+ *****************************************************************************/
+#define DESC41_HEADER_SIZE DESC_HEADER_SIZE
+#define DESC41_SERVICE_SIZE 3
+
+static inline uint8_t *desc41_get_service(uint8_t *p_desc, uint8_t n)
+{
+ uint8_t *p_desc_n = p_desc + DESC41_HEADER_SIZE + n * DESC41_SERVICE_SIZE;
+ if (p_desc_n + DESC41_SERVICE_SIZE - p_desc
+ > desc_get_length(p_desc) + DESC41_HEADER_SIZE)
+ return NULL;
+ return p_desc_n;
+}
+
+static inline uint16_t desc41n_get_sid(const uint8_t *p_desc_n)
+{
+ return (p_desc_n[0] << 8) | p_desc_n[1];
+}
+
+static inline uint8_t desc41n_get_type(const uint8_t *p_desc_n)
+{
+ return p_desc_n[2];
+}
+
+static inline bool desc41_validate(const uint8_t *p_desc)
+{
+ return !(desc_get_length(p_desc) % DESC41_SERVICE_SIZE);
+}
+
+static inline void desc41_print(uint8_t *p_desc, f_print pf_print,
+ void *opaque, print_type_t i_print_type)
+{
+ uint8_t j = 0;
+ uint8_t *p_desc_n;
+
+ while ((p_desc_n = desc41_get_service(p_desc, j)) != NULL) {
+ j++;
+ switch (i_print_type) {
+ case PRINT_XML:
+ pf_print(opaque,
+ "",
+ desc41n_get_sid(p_desc_n), desc41n_get_type(p_desc_n));
+ break;
+ default:
+ pf_print(opaque,
+ " - desc 41 service_list sid=%hu type=%hhu",
+ desc41n_get_sid(p_desc_n), desc41n_get_type(p_desc_n));
+ }
+ }
+}
+
/*****************************************************************************
* Descriptor 0x43: Satellite delivery system descriptor
*****************************************************************************/
@@ -736,6 +788,54 @@ static inline void desc48_print(const uint8_t *p_desc,
free(psz_service);
}
+/*****************************************************************************
+ * Descriptor 0x4a: Linkage descriptor (partially implemented)
+ *****************************************************************************/
+#define DESC4A_HEADER_SIZE (DESC_HEADER_SIZE + 7)
+
+static inline uint16_t desc4a_get_tsid(const uint8_t *p_desc)
+{
+ return (p_desc[2] << 8) | p_desc[3];
+}
+
+static inline uint16_t desc4a_get_onid(const uint8_t *p_desc)
+{
+ return (p_desc[4] << 8) | p_desc[5];
+}
+
+static inline uint16_t desc4a_get_sid(const uint8_t *p_desc)
+{
+ return (p_desc[6] << 8) | p_desc[7];
+}
+
+static inline uint8_t desc4a_get_linkage(const uint8_t *p_desc)
+{
+ return p_desc[8];
+}
+
+static inline bool desc4a_validate(const uint8_t *p_desc)
+{
+ return desc_get_length(p_desc) >= DESC4A_HEADER_SIZE - DESC_HEADER_SIZE;
+}
+
+static inline void desc4a_print(const uint8_t *p_desc, f_print pf_print,
+ void *opaque, print_type_t i_print_type)
+{
+ switch (i_print_type) {
+ case PRINT_XML:
+ pf_print(opaque,
+ "",
+ desc4a_get_tsid(p_desc), desc4a_get_onid(p_desc),
+ desc4a_get_sid(p_desc), desc4a_get_linkage(p_desc));
+ break;
+ default:
+ pf_print(opaque,
+ " - desc 4a linkage tsid=%hu onid=%hu sid=%hu linkage=%hhu",
+ desc4a_get_tsid(p_desc), desc4a_get_onid(p_desc),
+ desc4a_get_sid(p_desc), desc4a_get_linkage(p_desc));
+ }
+}
+
/*****************************************************************************
* Descriptor 0x56: Teletext descriptor
*****************************************************************************/
@@ -1003,10 +1103,45 @@ static inline void desc5a_print(const uint8_t *p_desc, f_print pf_print,
}
}
+/*****************************************************************************
+ * Descriptor 0x5f: Private data specifier descriptor
+ *****************************************************************************/
+#define DESC5F_HEADER_SIZE (DESC_HEADER_SIZE + 4)
+
+static inline void desc5f_init(uint8_t *p_desc)
+{
+ desc_set_tag(p_desc, 0x5f);
+}
+
+static inline uint32_t desc5f_get_specifier(const uint8_t *p_desc)
+{
+ return (p_desc[2] << 24) | (p_desc[3] << 16) |
+ (p_desc[4] << 8) | p_desc[5];
+}
+
+static inline bool desc5f_validate(const uint8_t *p_desc)
+{
+ return desc_get_length(p_desc) >= DESC5F_HEADER_SIZE - DESC_HEADER_SIZE;
+}
+
+static inline void desc5f_print(const uint8_t *p_desc, f_print pf_print,
+ void *opaque, print_type_t i_print_type)
+{
+ switch (i_print_type) {
+ case PRINT_XML:
+ pf_print(opaque, "",
+ desc5f_get_specifier(p_desc));
+ break;
+ default:
+ pf_print(opaque, " - desc 5f private data specifier=%u",
+ desc5f_get_specifier(p_desc));
+ }
+}
+
/*****************************************************************************
* Descriptor 0x6a: AC-3 descriptor
*****************************************************************************/
-#define DESC6A_HEADER_SIZE 3
+#define DESC6A_HEADER_SIZE (DESC_HEADER_SIZE + 1)
static inline void desc6a_init(uint8_t *p_desc)
{
@@ -1035,6 +1170,94 @@ static inline void desc6a_print(const uint8_t *p_desc, f_print pf_print,
}
}
+/*****************************************************************************
+ * Descriptor 0x83: Logical channel descriptor (IEC/CENELEC 62 216)
+ * Only valid if a private data specifier descriptor 28 is present before.
+ *****************************************************************************/
+#define DESC83P28_HEADER_SIZE DESC_HEADER_SIZE
+#define DESC83P28_SERVICE_SIZE 4
+
+static inline void desc83p28_init(uint8_t *p_desc)
+{
+ desc_set_tag(p_desc, 0x83);
+}
+
+static inline uint8_t *desc83p28_get_service(uint8_t *p_desc, uint8_t n)
+{
+ uint8_t *p_desc_n = p_desc + DESC83P28_HEADER_SIZE
+ + n * DESC83P28_SERVICE_SIZE;
+ if (p_desc_n + DESC83P28_SERVICE_SIZE - p_desc
+ > desc_get_length(p_desc) + DESC83P28_HEADER_SIZE)
+ return NULL;
+ return p_desc_n;
+}
+
+static inline uint16_t desc83p28n_get_sid(const uint8_t *p_desc_n)
+{
+ return (p_desc_n[0] << 8) | p_desc_n[1];
+}
+
+static inline bool desc83p28n_get_visible(const uint8_t *p_desc_n)
+{
+ return !!(p_desc_n[2] & 0x80);
+}
+
+static inline uint16_t desc83p28n_get_lcn(const uint8_t *p_desc_n)
+{
+ return ((p_desc_n[2] & 0x3) << 8) | p_desc_n[3];
+}
+
+static inline bool desc83p28_validate(const uint8_t *p_desc)
+{
+ return !(desc_get_length(p_desc) % DESC83P28_SERVICE_SIZE);
+}
+
+static inline void desc83p28_print(uint8_t *p_desc, f_print pf_print,
+ void *opaque, print_type_t i_print_type)
+{
+ uint8_t j = 0;
+ uint8_t *p_desc_n;
+
+ while ((p_desc_n = desc83p28_get_service(p_desc, j)) != NULL) {
+ j++;
+ switch (i_print_type) {
+ case PRINT_XML:
+ pf_print(opaque,
+ "<%s sid=\"%hu\" visible=\"%d\" lcn=\"%hu\" />",
+ desc_get_tag(p_desc) == 0x88 ? "HD_SIMULCAST_LCN_DESC" : "LCN_DESC",
+ desc83p28n_get_sid(p_desc_n),
+ desc83p28n_get_visible(p_desc_n) ? 1 : 0,
+ desc83p28n_get_lcn(p_desc_n));
+ break;
+ default:
+ pf_print(opaque,
+ " - desc %hhu lcn sid=%hu%s lcn=%hu", desc_get_tag(p_desc),
+ desc83p28n_get_sid(p_desc_n),
+ desc83p28n_get_visible(p_desc_n) ? " visible" : "",
+ desc83p28n_get_lcn(p_desc_n));
+ }
+ }
+}
+
+/*****************************************************************************
+ * Descriptor 0x88: HD simulcast logical channel descriptor (IEC/CENELEC 62 216)
+ * Only valid if a private data specifier descriptor 28 is present before.
+ *****************************************************************************/
+#define DESC88P28_HEADER_SIZE DESC83P28_HEADER_SIZE
+#define DESC88P28_SERVICE_SIZE DESC83P28_SERVICE_SIZE
+
+static inline void desc88p28_init(uint8_t *p_desc)
+{
+ desc_set_tag(p_desc, 0x88);
+}
+
+#define desc88p28_get_service desc83p28_get_service
+#define desc88p28_get_sid desc83p28_get_sid
+#define desc88p28_get_visible desc83p28_get_visible
+#define desc88p28_get_lcn desc83p28_get_lcn
+#define desc88p28_validate desc83p28_validate
+#define desc88p28_print desc83p28_print
+
/*****************************************************************************
* Network Information Table
*****************************************************************************/
diff --git a/dvb/si_print.h b/dvb/si_print.h
index 66161d4..f0b02d9 100644
--- a/dvb/si_print.h
+++ b/dvb/si_print.h
@@ -39,6 +39,7 @@ static inline void descs_print(uint8_t *p_descs,
{
uint16_t j = 0;
uint8_t *p_desc;
+ uint32_t i_private_data_specifier = 0;
while ((p_desc = descs_get_desc(p_descs, j)) != NULL) {
uint8_t i_tag = desc_get_tag(p_desc);
@@ -46,6 +47,29 @@ static inline void descs_print(uint8_t *p_descs,
desc_print_begin(p_desc, pf_print, print_opaque, i_print_type);
+ if (i_private_data_specifier == 0x28) {
+ /* EICTA */
+ switch (i_tag) {
+#define CASE_DESC(id) \
+ case 0x##id: \
+ if (desc##id##p28_validate(p_desc)) \
+ desc##id##p28_print(p_desc, pf_print, print_opaque, \
+ i_print_type); \
+ else \
+ desc_print_error(p_desc, pf_print, print_opaque, \
+ i_print_type); \
+ goto print_end;
+
+ CASE_DESC(83)
+ CASE_DESC(88)
+
+#undef CASE_DESC
+
+ default:
+ break;
+ }
+ }
+
switch (i_tag) {
#define CASE_DESC(id) \
case 0x##id: \
@@ -71,20 +95,34 @@ static inline void descs_print(uint8_t *p_descs,
CASE_DESC(09)
CASE_DESC(0a)
CASE_DESC_ICONV(40)
+ CASE_DESC(41)
CASE_DESC(43)
CASE_DESC(44)
CASE_DESC(46)
CASE_DESC_ICONV(48)
+ CASE_DESC(4a)
CASE_DESC(56)
CASE_DESC(59)
CASE_DESC(5a)
CASE_DESC(6a)
+#undef CASE_DESC
+#undef CASE_DESC_ICONV
+
+ case 0x5f:
+ if (desc5f_validate(p_desc)) {
+ desc5f_print(p_desc, pf_print, print_opaque, i_print_type);
+ i_private_data_specifier = desc5f_get_specifier(p_desc);
+ } else
+ desc_print_error(p_desc, pf_print, print_opaque, i_print_type);
+ break;
+
default:
desc_print(p_desc, pf_print, print_opaque, i_print_type);
break;
}
+print_end:
desc_print_end(p_desc, pf_print, print_opaque, i_print_type);
}
}