[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