[bTSstream-devel] [Git][videolan/bitstream][master] 3 commits: dvb/si: add AIT

Christophe Massiot (@cmassiot) gitlab at videolan.org
Wed Mar 5 10:47:32 UTC 2025



Christophe Massiot pushed to branch master at VideoLAN / bitstream


Commits:
915db7d1 by Arnaud de Turckheim at 2025-03-03T18:04:24+01:00
dvb/si: add AIT

- - - - -
b3774681 by Arnaud de Turckheim at 2025-03-05T11:47:10+01:00
dvb/si/desc_6f: fix typo

- - - - -
ebc8106c by Christophe Massiot at 2025-03-05T11:47:18+01:00
Merge branch 'quarium-ait'

- - - - -


5 changed files:

- dvb/si.h
- + dvb/si/ait.h
- + dvb/si/ait_print.h
- dvb/si_print.h
- examples/dvb_print_si.c


Changes:

=====================================
dvb/si.h
=====================================
@@ -51,5 +51,6 @@
 #include <bitstream/dvb/si/st.h>
 #include <bitstream/dvb/si/dit.h>
 #include <bitstream/dvb/si/sit.h>
+#include <bitstream/dvb/si/ait.h>
 
 #endif


=====================================
dvb/si/ait.h
=====================================
@@ -0,0 +1,413 @@
+/*****************************************************************************
+ * ait.h: ETSI TS 102 809 Application Information Table (AIT)
+ *****************************************************************************
+ * Copyright (C) 2024 EasyTools
+ *
+ * Authors: Arnaud de Turckheim <adeturckheim at easytools.tv>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject
+ * to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *****************************************************************************/
+
+/*
+ * Normative references:
+ *  - ETSI TS 102 809 V1.1.1 (2010-01) (Signalling and carriage of interactive
+ *  applications and services)
+ */
+
+#ifndef __BITSTREAM_DVB_AIT_H__
+#define __BITSTREAM_DVB_AIT_H__
+
+#include <bitstream/common.h>
+#include <bitstream/mpeg/psi/psi.h>
+#include <bitstream/mpeg/psi/descriptors.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*****************************************************************************
+ * Application Information Table descriptors
+ *****************************************************************************/
+#define AIT_DESC_APP                0x00
+
+#define AIT_DESC_APP_SIZE           3
+#define AIT_DESC_APP_PROFILE_SIZE   5
+
+static inline uint8_t ait_desc_app_get_profilelength(const uint8_t *p_desc)
+{
+    return p_desc[2];
+}
+
+static inline uint8_t *ait_desc_app_next_profile(const uint8_t *p_desc,
+                                                 uint8_t *p_profile)
+{
+    uint8_t profilelength = ait_desc_app_get_profilelength(p_desc);
+
+    if (!p_profile)
+        p_profile = (uint8_t *)p_desc + 3;
+    else
+        p_profile += AIT_DESC_APP_PROFILE_SIZE;
+    return p_profile - p_desc - 3 + AIT_DESC_APP_PROFILE_SIZE > profilelength ?
+        NULL : p_profile;
+}
+
+#define ait_desc_app_each_profile(DESC, PROFILE) \
+    for (uint8_t *PROFILE = ait_desc_app_next_profile(DESC, NULL); \
+         PROFILE != NULL; \
+         PROFILE = ait_desc_app_next_profile(DESC, PROFILE))
+
+static inline uint16_t ait_desc_app_profile_get_type(const uint8_t *p_profile)
+{
+    return p_profile[0] << 8 | p_profile[1];
+}
+
+static inline uint8_t ait_desc_app_profile_get_major(const uint8_t *p_profile)
+{
+    return p_profile[2];
+}
+
+static inline uint8_t ait_desc_app_profile_get_minor(const uint8_t *p_profile)
+{
+    return p_profile[3];
+}
+
+static inline uint8_t ait_desc_app_profile_get_micro(const uint8_t *p_profile)
+{
+    return p_profile[4];
+}
+
+static inline uint8_t ait_desc_app_get_service_bound(const uint8_t *p_desc)
+{
+    uint8_t profilelength = ait_desc_app_get_profilelength(p_desc);
+    return (p_desc[3 + profilelength] >> 7) & 0x1;
+}
+
+static inline uint8_t ait_desc_app_get_visibily(const uint8_t *p_desc)
+{
+    uint8_t profilelength = ait_desc_app_get_profilelength(p_desc);
+    return (p_desc[3 + profilelength] >> 5) & 0x3;
+}
+
+static inline uint8_t ait_desc_app_get_priority(const uint8_t *p_desc)
+{
+    uint8_t profilelength = ait_desc_app_get_profilelength(p_desc);
+    return p_desc[3 + profilelength + 1];
+}
+
+static inline uint8_t *ait_desc_app_next_transport_proto(const uint8_t *p_desc,
+                                                         uint8_t *p_proto)
+{
+    const uint8_t *p_end = p_desc + DESC_HEADER_SIZE + desc_get_length(p_desc);
+    uint8_t profilelength = ait_desc_app_get_profilelength(p_desc);
+    if (!p_proto)
+        p_proto = (uint8_t *)p_desc + 5 + profilelength;
+    else
+        p_proto++;
+    return p_proto >= p_end ? NULL : p_proto;
+}
+
+#define ait_desc_app_each_transport_proto(DESC, PROTO) \
+    for (uint8_t *PROTO = ait_desc_app_next_transport_proto(DESC, NULL); \
+         PROTO != NULL; \
+         PROTO = ait_desc_app_next_transport_proto(DESC, PROTO))
+
+static inline bool ait_desc_app_validate(const uint8_t *p_desc)
+{
+    uint8_t tag = desc_get_tag(p_desc);
+    uint8_t length = desc_get_length(p_desc);
+
+    if (tag != AIT_DESC_APP || length < AIT_DESC_APP_SIZE)
+        return false;
+
+    uint8_t profilelength = ait_desc_app_get_profilelength(p_desc);
+    if (length < AIT_DESC_APP + profilelength)
+        return false;
+    return true;
+}
+
+#define AIT_DESC_APP_NAME           0x01
+
+static inline uint8_t *ait_desc_app_name_get_code(const uint8_t *p_name)
+{
+    return (uint8_t *)p_name;
+}
+
+static inline uint8_t ait_desc_app_name_get_textlength(const uint8_t *p_name)
+{
+    return p_name[3];
+}
+
+static inline uint8_t *ait_desc_app_name_get_text(const uint8_t *p_name,
+                                                  uint8_t *text_len)
+{
+    if (text_len)
+        *text_len = p_name[3];
+    return (uint8_t *)p_name + 4;
+}
+
+static inline uint8_t *ait_desc_app_name_next_name(const uint8_t *p_desc,
+                                                   uint8_t *p_name)
+{
+    const uint8_t *p_end = p_desc + DESC_HEADER_SIZE + desc_get_length(p_desc);
+    if (!p_name)
+        p_name = (uint8_t *)p_desc + DESC_HEADER_SIZE;
+    else
+        p_name += 3 + ait_desc_app_name_get_textlength(p_name);
+    return p_name + 3 > p_end ? NULL : p_name;
+}
+
+#define ait_desc_app_name_each_name(DESC, NAME) \
+    for (uint8_t *NAME = ait_desc_app_name_next_name(DESC, NULL); \
+         NAME != NULL; \
+         NAME = ait_desc_app_name_next_name(DESC, NAME))
+
+static inline bool ait_desc_app_name_validate(const uint8_t *p_desc)
+{
+    return desc_get_tag(p_desc) == AIT_DESC_APP_NAME;
+}
+
+#define AIT_DESC_TRANSPORT_PROTO    0x02
+
+#define AIT_DESC_TRANSPORT_PROTO_SIZE   3
+
+static inline uint16_t ait_desc_transport_proto_get_id(const uint8_t *p_desc)
+{
+    return p_desc[2] << 8 | p_desc[3];
+}
+
+static inline uint8_t ait_desc_transport_proto_get_label(const uint8_t *p_desc)
+{
+    return p_desc[4];
+}
+
+static inline bool ait_desc_transport_proto_validate(const uint8_t *p_desc)
+{
+    uint8_t tag = desc_get_tag(p_desc);
+    uint8_t length = desc_get_length(p_desc);
+
+    return tag == AIT_DESC_TRANSPORT_PROTO &&
+        length >= AIT_DESC_TRANSPORT_PROTO_SIZE;
+}
+
+
+#define AIT_DESC_EXTERNAL_APP_AUTH  0x05
+#define AIT_DESC_APP_RECORD         0x06
+#define AIT_DESC_APP_ICON           0x0B
+#define AIT_DESC_APP_STORAGE        0x10
+#define AIT_DESC_GRAPH_CONSTRAINS   0x14
+#define AIT_DESC_APP_LOCATION       0x15
+
+static inline uint8_t *
+ait_desc_app_location_get_initial_path(const uint8_t *p_desc, uint8_t *length)
+{
+    if (length)
+        *length = p_desc[1];
+    return (uint8_t *)p_desc + 2;
+}
+
+static inline bool ait_desc_app_location_validate(const uint8_t *p_desc)
+{
+    return desc_get_tag(p_desc) == AIT_DESC_APP_LOCATION;
+}
+
+#define AIT_DESC_APP_USAGE          0x16
+#define AIT_DESC_APP_BOUND          0x17
+#define AIT_DESC_PRIVATE_DATA       0x5F
+
+
+/*****************************************************************************
+ * Application Information Table
+ *****************************************************************************/
+#define AIT_TABLE_ID            0x74
+#define AIT_HEADER_SIZE         (PSI_HEADER_SIZE_SYNTAX1 + 4)
+#define AIT_APP_IDENTIFIER_SIZE 6
+#define AIT_APP_SIZE            (AIT_APP_IDENTIFIER_SIZE + 3)
+
+static inline void ait_init(uint8_t *p_ait)
+{
+    psi_init(p_ait, true);
+    psi_set_tableid(p_ait, AIT_TABLE_ID);
+    p_ait[8] = 0xf0;
+}
+
+static inline void ait_set_length(uint8_t *p_ait, uint16_t i_ait_length)
+{
+    psi_set_length(p_ait, AIT_HEADER_SIZE + PSI_CRC_SIZE - PSI_HEADER_SIZE
+                    + i_ait_length);
+}
+
+static inline void ait_set_desclength(uint8_t *p_ait, uint16_t i_length)
+{
+    p_ait[8] &= ~0xf;
+    p_ait[8] |= i_length >> 8;
+    p_ait[9] = i_length & 0xff;
+}
+
+static inline uint16_t ait_get_desclength(const uint8_t *p_ait)
+{
+    return ((p_ait[8] & 0xf) << 8) | p_ait[9];
+}
+
+static inline uint8_t *ait_get_descs(uint8_t *p_ait)
+{
+    return &p_ait[8];
+}
+
+static inline uint32_t aitn_get_organisation_id(const uint8_t *p_aitn)
+{
+    return p_aitn[0] << 24 | p_aitn[1] << 16 | p_aitn[2] << 8 | p_aitn[3];
+}
+
+static inline uint16_t aitn_get_application_id(const uint8_t *p_aitn)
+{
+    return p_aitn[4] << 8 | p_aitn[5];
+}
+
+#define AITN_CONTROL_CODE_AUTOSTART             0x01
+#define AITN_CONTROL_CODE_PRESENT               0x02
+#define AITN_CONTROL_CODE_DESTROY               0x03
+#define AITN_CONTROL_CODE_KILL                  0x04
+#define AITN_CONTROL_CODE_PREFETCH              0x05
+#define AITN_CONTROL_CODE_REMOTE                0x06
+#define AITN_CONTROL_CODE_DISABLED              0x07
+#define AITN_CONTROL_CODE_PLAYBACK_AUTOSTART    0x08
+
+static inline const char *aitn_control_code_txt(uint8_t i_control_code)
+{
+    switch (i_control_code) {
+        case AITN_CONTROL_CODE_AUTOSTART: return "autostart";
+        case AITN_CONTROL_CODE_PRESENT: return "present";
+        case AITN_CONTROL_CODE_DESTROY: return "destroy";
+        case AITN_CONTROL_CODE_KILL: return "kill";
+        case AITN_CONTROL_CODE_PREFETCH: return "prefetch";
+        case AITN_CONTROL_CODE_REMOTE: return "remote";
+        case AITN_CONTROL_CODE_DISABLED: return "disabled";
+        case AITN_CONTROL_CODE_PLAYBACK_AUTOSTART: return "playback autostart";
+        default:
+            return "Reserved";
+    }
+}
+
+static inline uint8_t aitn_get_control_code(const uint8_t *p_aitn)
+{
+    return p_aitn[6];
+}
+
+static inline void aitn_set_desclength(uint8_t *p_aitn, uint16_t i_length)
+{
+    p_aitn[7] &= ~0xf;
+    p_aitn[7] |= i_length >> 8;
+    p_aitn[8] = i_length & 0xff;
+}
+
+static inline uint16_t aitn_get_desclength(const uint8_t *p_aitn)
+{
+    return ((p_aitn[7] & 0xf) << 8) | p_aitn[8];
+}
+
+static inline uint8_t *aitn_get_descs(uint8_t *p_aitn)
+{
+    return &p_aitn[7];
+}
+
+#define aitn_each_desc(AITN, DESC)  descs_each_desc(aitn_get_descs(AITN), DESC)
+
+static inline uint8_t *ait_next_app(const uint8_t *p_ait, uint8_t *p_ait_n)
+{
+    uint16_t i_section_size =
+        psi_get_length(p_ait) + PSI_HEADER_SIZE - PSI_CRC_SIZE;
+    if (!p_ait_n)
+        p_ait_n = (uint8_t *)p_ait + AIT_HEADER_SIZE +
+            ait_get_desclength(p_ait);
+    else {
+        if (p_ait_n + AIT_APP_SIZE - p_ait > i_section_size) return NULL;
+        p_ait_n += AIT_APP_SIZE + aitn_get_desclength(p_ait_n);
+    }
+    return (p_ait_n - p_ait < i_section_size) ? p_ait_n : NULL;
+}
+
+#define ait_each_app(AIT, APP) \
+    for (uint8_t *APP = ait_next_app(AIT, NULL); \
+         APP; \
+         APP = ait_next_app(AIT, APP))
+
+static inline uint8_t *ait_get_apps(uint8_t *p_ait)
+{
+    uint16_t desclength = ait_get_desclength(p_ait);
+    return ait_get_descs(p_ait) + 2 + desclength;
+}
+
+static inline void ait_set_applength(uint8_t *p_ait, uint16_t i_length)
+{
+    uint8_t *p_apps = ait_get_apps(p_ait);
+    p_apps[0] &= ~0xf;
+    p_apps[0] |= i_length >> 8;
+    p_apps[1] = i_length & 0xff;
+}
+
+static inline uint16_t ait_get_appslength(const uint8_t *p_ait)
+{
+    const uint8_t *p_apps = ait_get_apps((uint8_t *)p_ait);
+    return ((p_apps[0] & 0xf) << 8) | p_apps[1];
+}
+
+static inline bool ait_validate(const uint8_t *p_ait)
+{
+    uint16_t i_section_size =
+        psi_get_length(p_ait) + PSI_HEADER_SIZE - PSI_CRC_SIZE;
+
+    if (!psi_get_syntax(p_ait) || psi_get_tableid(p_ait) != AIT_TABLE_ID)
+        return false;
+
+    if (i_section_size < AIT_HEADER_SIZE
+         || i_section_size < AIT_HEADER_SIZE + ait_get_desclength(p_ait))
+        return false;
+
+    if (!descs_validate(p_ait + 8))
+        return false;
+
+    ait_each_app(p_ait, p_app) {
+        if (!descs_validate(p_app + 7))
+            return false;
+    }
+    return true;
+}
+
+static inline bool ait_table_validate(uint8_t **pp_sections)
+{
+    uint8_t i_last_section = psi_table_get_lastsection(pp_sections);
+    uint8_t i;
+
+    for (i = 0; i <= i_last_section; i++) {
+        uint8_t *p_section = psi_table_get_section(pp_sections, i);
+
+        if (!psi_check_crc(p_section))
+            return false;
+    }
+
+    return true;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif


=====================================
dvb/si/ait_print.h
=====================================
@@ -0,0 +1,278 @@
+/*****************************************************************************
+ * ait_print.h: ETSI TS 102 809 Application Information Table (AIT) (printing)
+ *****************************************************************************
+ * Copyright (C) 2024 EasyTools
+ *
+ * Authors: Arnaud de Turckheim <adeturckheim at easytools.tv>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject
+ * to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *****************************************************************************/
+
+#ifndef __BITSTREAM_DVB_AIT_PRINT_H__
+#define __BITSTREAM_DVB_AIT_PRINT_H__
+
+#include <bitstream/common.h>
+#include <bitstream/mpeg/psi/psi.h>
+#include <bitstream/mpeg/psi/descs_print.h>
+#include <bitstream/dvb/si/ait.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*****************************************************************************
+ * Application Information Table descriptors
+ *****************************************************************************/
+static inline void ait_desc_app_print(const uint8_t *p_desc,
+                                      f_print pf_print, void *print_opaque,
+                                      f_iconv pf_iconv, void *iconv_opaque,
+                                      print_type_t i_print_type)
+{
+    switch (i_print_type) {
+        case PRINT_XML:
+            pf_print(print_opaque, "<APP service_bound=\"%s\" "
+                     "visibilty=\"%u\" priority=\"%u\">",
+                     ait_desc_app_get_service_bound(p_desc) ? "true" : "false",
+                     ait_desc_app_get_visibily(p_desc),
+                     ait_desc_app_get_priority(p_desc));
+            break;
+        default:
+            pf_print(print_opaque, "    - app service_bound=%s visibilty=%u "
+                     "priority=%u",
+                     ait_desc_app_get_service_bound(p_desc) ? "true" : "false",
+                     ait_desc_app_get_visibily(p_desc),
+                     ait_desc_app_get_priority(p_desc));
+    }
+
+    ait_desc_app_each_profile(p_desc, p_profile) {
+        switch (i_print_type) {
+            case PRINT_XML:
+                pf_print(print_opaque, "<PROFILE type=\"%u\" "
+                         "major=\"%u\" minor=\"%u\" micro=\"%u\" />",
+                         ait_desc_app_profile_get_type(p_profile),
+                         ait_desc_app_profile_get_major(p_profile),
+                         ait_desc_app_profile_get_minor(p_profile),
+                         ait_desc_app_profile_get_micro(p_profile));
+                break;
+
+            default:
+                pf_print(print_opaque, "      - profile type=%u "
+                         "version=%u.%u.%u",
+                         ait_desc_app_profile_get_type(p_profile),
+                         ait_desc_app_profile_get_major(p_profile),
+                         ait_desc_app_profile_get_minor(p_profile),
+                         ait_desc_app_profile_get_micro(p_profile));
+
+        }
+    }
+
+    ait_desc_app_each_transport_proto(p_desc, p_proto) {
+        switch (i_print_type) {
+            case PRINT_XML:
+                pf_print(print_opaque, "<TRANSPORT_PROTOCOL value=\"%u\"/>",
+                         *p_proto);
+                break;
+
+            default:
+                pf_print(print_opaque, "      - transport_protocol %u",
+                         *p_proto);
+        }
+    }
+}
+
+static inline void ait_desc_app_name_print(const uint8_t *p_desc,
+                                           f_print pf_print, void *print_opaque,
+                                           f_iconv pf_iconv, void *iconv_opaque,
+                                           print_type_t i_print_type)
+{
+    switch (i_print_type) {
+        case PRINT_XML:
+            pf_print(print_opaque, "<APP_NAME>");
+            break;
+        default:
+            pf_print(print_opaque, "    - app_name");
+    }
+
+    ait_desc_app_name_each_name(p_desc, p_name) {
+        uint8_t *code = ait_desc_app_name_get_code(p_name);
+        uint8_t text_len;
+        const uint8_t *text = ait_desc_app_name_get_text(p_name, &text_len);
+        char *psz_text = dvb_string_get(text, text_len, pf_iconv, iconv_opaque);
+
+        switch (i_print_type) {
+            case PRINT_XML:
+                pf_print(print_opaque, "<NAME language=\"%3.3s\" test=\"%s\"/>",
+                         (char *)code, psz_text);
+                break;
+
+            default:
+                pf_print(print_opaque, "      - language=%3.3s test=\"%s\"",
+                         (char *)code, psz_text);
+        }
+
+        free(psz_text);
+    }
+}
+
+static inline void ait_desc_transport_proto_print(const uint8_t *p_desc,
+                                                  f_print pf_print,
+                                                  void *print_opaque,
+                                                  f_iconv pf_iconv,
+                                                  void *iconv_opaque,
+                                                  print_type_t i_print_type)
+{
+    switch (i_print_type) {
+        case PRINT_XML:
+            pf_print(print_opaque, "<TRANSPORT_PROTOCOL id=\"%u\" label=\"%u\""
+                     ">",
+                     ait_desc_transport_proto_get_id(p_desc),
+                     ait_desc_transport_proto_get_label(p_desc));
+            break;
+        default:
+            pf_print(print_opaque, "    - transport_protocol id=%u label=%u",
+                     ait_desc_transport_proto_get_id(p_desc),
+                     ait_desc_transport_proto_get_label(p_desc));
+    }
+}
+
+static inline void ait_desc_app_location_print(const uint8_t *p_desc,
+                                               f_print pf_print,
+                                               void *print_opaque,
+                                               f_iconv pf_iconv,
+                                               void *iconv_opaque,
+                                               print_type_t i_print_type)
+{
+    uint8_t initial_path_len;
+    uint8_t *initial_path =
+        ait_desc_app_location_get_initial_path(p_desc, &initial_path_len);
+    switch (i_print_type) {
+        case PRINT_XML:
+            pf_print(print_opaque, "<TRANSPORT_PROTOCOL id=\"%u\" label=\"%u\""
+                     "initial_path=\"%.*s\"/>",
+                     ait_desc_transport_proto_get_id(p_desc),
+                     ait_desc_transport_proto_get_label(p_desc),
+                     (int)initial_path_len, (char *)initial_path);
+            break;
+        default:
+            pf_print(print_opaque, "    - transport_protocol id=%u label=%u "
+                     "initial_path=\"%.*s\"",
+                     ait_desc_transport_proto_get_id(p_desc),
+                     ait_desc_transport_proto_get_label(p_desc),
+                     (int)initial_path_len, (char *)initial_path);
+    }
+}
+
+/*****************************************************************************
+ * Application Information Table
+ *****************************************************************************/
+static inline void ait_table_print(uint8_t **pp_sections,
+                                   f_print pf_print, void *print_opaque,
+                                   f_iconv pf_iconv, void *iconv_opaque,
+                                   print_type_t i_print_type)
+{
+    uint8_t i_last_section = psi_table_get_lastsection(pp_sections);
+    uint8_t i;
+
+    uint16_t idext = psi_table_get_tableidext(pp_sections);
+    uint8_t test = idext & 0x8000 ? 1 : 0;
+    uint16_t type = idext & 0x7fff;
+
+    switch (i_print_type) {
+    case PRINT_XML:
+        pf_print(print_opaque, "<AIT test=\"%s\" type=\"%hu\" version=\"%hhu\" "
+                 "current_next=\"%d\">",
+                 test ? "true" : "false",
+                 type,
+                 psi_table_get_version(pp_sections),
+                 !psi_table_get_current(pp_sections) ? 0 : 1);
+        break;
+    default:
+        pf_print(print_opaque, "new AIT %stype=%hu version=%hhu%s",
+                 test ? "test " : "",
+                 type,
+                 psi_table_get_version(pp_sections),
+                 !psi_table_get_current(pp_sections) ? " (next)" : "");
+    }
+
+    descs_print(ait_get_descs(psi_table_get_section(pp_sections, 0)),
+                pf_print, print_opaque, pf_iconv, iconv_opaque, i_print_type);
+
+    for (i = 0; i <= i_last_section; i++) {
+        uint8_t *p_section = psi_table_get_section(pp_sections, i);
+
+        ait_each_app(p_section, p_app) {
+            switch (i_print_type) {
+                case PRINT_XML:
+                    break;
+                default:
+                    pf_print(print_opaque, "  * app organisation=%u id=%hu "
+                             "control_code=%s",
+                             aitn_get_organisation_id(p_app),
+                             aitn_get_application_id(p_app),
+                             aitn_control_code_txt(aitn_get_control_code(p_app))
+                             );
+                    break;
+            }
+
+            aitn_each_desc(p_app, p_desc) {
+                uint8_t tag = desc_get_tag(p_desc);
+
+                switch (tag) {
+#define CASE_DESC(Value, Name) \
+                case AIT_DESC_##Value: \
+                    if (ait_desc_##Name##_validate(p_desc)) \
+                        ait_desc_##Name##_print(p_desc, \
+                                                pf_print, print_opaque, \
+                                                pf_iconv, iconv_opaque, \
+                                                i_print_type); \
+                    else \
+                        desc_print_error(p_desc, pf_print, print_opaque, \
+                                         i_print_type); \
+                    break;
+
+                CASE_DESC(APP, app)
+                CASE_DESC(APP_NAME, app_name)
+                CASE_DESC(TRANSPORT_PROTO, transport_proto)
+                CASE_DESC(APP_LOCATION, app_location)
+#undef CASE_DESC
+
+                default:
+                    desc_print(p_desc, pf_print, print_opaque, i_print_type);
+                    break;
+                }
+            }
+        }
+    }
+
+    switch (i_print_type) {
+    case PRINT_XML:
+        pf_print(print_opaque, "</AIT>");
+        break;
+    default:
+        pf_print(print_opaque, "end AIT");
+    }
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif


=====================================
dvb/si_print.h
=====================================
@@ -38,5 +38,6 @@
 #include <bitstream/dvb/si/rst_print.h>
 #include <bitstream/dvb/si/dit_print.h>
 #include <bitstream/dvb/si/sit_print.h>
+#include <bitstream/dvb/si/ait_print.h>
 
 #endif


=====================================
examples/dvb_print_si.c
=====================================
@@ -89,6 +89,8 @@ static PSI_TABLE_DECLARE(pp_current_nit_sections);
 static PSI_TABLE_DECLARE(pp_next_nit_sections);
 static PSI_TABLE_DECLARE(pp_current_sdt_sections);
 static PSI_TABLE_DECLARE(pp_next_sdt_sections);
+static PSI_TABLE_DECLARE(pp_current_ait_sections);
+static PSI_TABLE_DECLARE(pp_next_ait_sections);
 
 static const char *psz_native_encoding = "UTF-8";
 static const char *psz_current_encoding = "";
@@ -111,11 +113,12 @@ enum tables_t {
     TABLE_SIT,
     TABLE_PMT,
     TABLE_SCTE35,
+    TABLE_AIT,
     TABLE_END
 };
 static const char * const ppsz_all_tables[TABLE_END] = {
     "pat", "cat", "tsdt", "nit", "bat", "sdt", "eit", "tot", "tdt", "rst",
-    "dit", "sit", "pmt", "scte35"
+    "dit", "sit", "pmt", "scte35", "ait"
 };
 static bool pb_print_table[TABLE_END];
 
@@ -461,14 +464,27 @@ static void handle_tsdt_section(uint16_t i_pid, uint8_t *p_section)
  *****************************************************************************/
 static void handle_pmt_es(uint8_t *p_pmt, bool b_select)
 {
-    int j = 0;
-    uint8_t *p_es;
-    while ((p_es = pmt_get_es(p_pmt, j)) != NULL) {
+    pmt_each_es(p_pmt, p_es) {
         uint16_t i_pid = pmtn_get_pid(p_es);
         uint8_t i_type = pmtn_get_streamtype(p_es);
-        j++;
 
         switch (i_type) {
+            case PMT_STREAMTYPE_PRIVATE_PSI:
+                pmtn_each_desc(p_es, p_desc) {
+                    uint8_t tag = desc_get_tag(p_desc);
+
+                    switch (tag) {
+                        case 0x6f:
+                            if (b_select)
+                                p_pids[i_pid].i_psi_refcount++;
+                            else
+                                p_pids[i_pid].i_psi_refcount--;
+                            break;
+                        default:
+                            break;
+                    }
+                }
+                break;
             case PMT_STREAMTYPE_SCTE_35:
                 if (b_select)
                     p_pids[i_pid].i_psi_refcount++;
@@ -961,6 +977,63 @@ static void handle_scte35_section(uint16_t i_pid, uint8_t *p_scte35)
     free(p_scte35);
 }
 
+/*****************************************************************************
+ * handle_ait
+ *****************************************************************************/
+static void handle_ait(void)
+{
+    if (psi_table_validate(pp_current_ait_sections) &&
+        psi_table_compare(pp_current_ait_sections, pp_next_ait_sections)) {
+        /* Same version AIT. Shortcut. */
+        psi_table_free(pp_next_ait_sections);
+        psi_table_init(pp_next_ait_sections);
+        return;
+    }
+
+    if (!ait_table_validate(pp_next_ait_sections)) {
+        switch (i_print_type) {
+        case PRINT_XML:
+            printf("<ERROR type=\"invalid_ait\"/>\n");
+            break;
+        default:
+            printf("invalid AIT received\n");
+        }
+        psi_table_free(pp_next_ait_sections);
+        psi_table_init(pp_next_ait_sections);
+        return;
+    }
+
+    /* Switch tables. */
+    psi_table_free(pp_current_ait_sections);
+    psi_table_copy(pp_current_ait_sections, pp_next_ait_sections);
+    psi_table_init(pp_next_ait_sections);
+
+    if (pb_print_table[TABLE_AIT])
+        ait_table_print(pp_current_ait_sections, print_wrapper, NULL,
+                        iconv_wrapper, NULL, i_print_type);
+}
+
+static void handle_ait_section(uint16_t i_pid, uint8_t *p_section)
+{
+    if (!ait_validate(p_section)) {
+        switch (i_print_type) {
+        case PRINT_XML:
+            printf("<ERROR type=\"invalid_ait_section\" pid=\"%hu\"/>\n",
+                   i_pid);
+            break;
+        default:
+            printf("invalid AIT section received on PID %hu\n", i_pid);
+        }
+        free(p_section);
+        return;
+    }
+
+    if (!psi_table_section(pp_next_ait_sections, p_section))
+        return;
+
+    handle_ait();
+}
+
 /*****************************************************************************
  * handle_section
  *****************************************************************************/
@@ -1037,6 +1110,10 @@ static void handle_section(uint16_t i_pid, uint8_t *p_section)
         handle_scte35_section(i_pid, p_section);
         break;
 
+    case AIT_TABLE_ID:
+        handle_ait_section(i_pid, p_section);
+        break;
+
     default:
         free( p_section );
         break;



View it on GitLab: https://code.videolan.org/videolan/bitstream/-/compare/612b01604e2920f2941b52431997afca1abd64c0...ebc8106ce8279b8be7861ab9e83e9ac42bb528f8

-- 
View it on GitLab: https://code.videolan.org/videolan/bitstream/-/compare/612b01604e2920f2941b52431997afca1abd64c0...ebc8106ce8279b8be7861ab9e83e9ac42bb528f8
You're receiving this email because of your account on code.videolan.org.


VideoLAN code repository instance


More information about the biTStream-devel mailing list