From gitlab at videolan.org Thu Aug 27 10:56:20 2026 From: gitlab at videolan.org (Christophe Massiot (@cmassiot)) Date: Thu, 27 Aug 2026 12:56:20 +0200 Subject: [bTSstream-devel] [Git][videolan/bitstream][master] dvb/si: add the TTML subtitling descriptor Message-ID: <6a9017d4f907_16e10e8a7da5c119504a@gitlab.mail> Christophe Massiot pushed to branch master at VideoLAN / bitstream Commits: d4dd59d3 by Kieran Kunhya at 2026-08-27T10:21:52+00:00 dvb/si: add the TTML subtitling descriptor Extension descriptor 0x20 of ETSI EN 303 560, which signals a DVB TTML subtitle stream in the PMT: language, subtitle purpose, text-to-speech suitability, the TTML processor profiles the stream conforms to, and the optional presentation qualifier. Only the profile list sits at a fixed offset; the qualifier, the essential font list and the service description text each move with a count read out of the descriptor, so validate() walks them rather than checking a single length. Co-Authored-By: Claude Opus 5 (1M context) - - - - - 3 changed files: - + dvb/si/desc_7f20.h - dvb/si/descs_list.h - mpeg/psi/descs_print.h Changes: ===================================== dvb/si/desc_7f20.h ===================================== @@ -0,0 +1,237 @@ +/***************************************************************************** + * desc_7f20.h: ETSI EN 303 560 Extension descriptor 0x20: TTML subtitling + * descriptor + ***************************************************************************** + * Copyright (C) 2026 Open Broadcast Systems Ltd + * + * Authors: Kieran Kunhya + * + * 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 EN 303 560 V1.1.1 (2018-05) (TTML subtitling systems) + */ + +#ifndef __BITSTREAM_DVB_DESC_7F20_H__ +#define __BITSTREAM_DVB_DESC_7F20_H__ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + +/***************************************************************************** + * Extension descriptor 0x20: TTML subtitling descriptor + *****************************************************************************/ +#define DESC7F20_HEADER_SIZE (DESC7F_HEADER_SIZE + 5) +#define DESC7F20_PROFILE_SIZE 1 +#define DESC7F20_QUALIFIER_SIZE 4 +#define DESC7F20_FONT_COUNT_SIZE 1 +#define DESC7F20_FONT_SIZE 1 +#define DESC7F20_TEXT_LENGTH_SIZE 1 + +/* subtitle_purpose, EN 303 560 table 2 */ +#define DESC7F20_PURPOSE_SAME_LANG_DIALOGUE 0x00 +#define DESC7F20_PURPOSE_OTHER_LANG_DIALOGUE 0x01 +#define DESC7F20_PURPOSE_ALL_DIALOGUE 0x02 +#define DESC7F20_PURPOSE_HARD_OF_HEARING 0x10 +#define DESC7F20_PURPOSE_OTHER_LANG_DIALOGUE_HOH 0x11 +#define DESC7F20_PURPOSE_ALL_DIALOGUE_HOH 0x12 +#define DESC7F20_PURPOSE_AUDIO_DESCRIPTION 0x30 +#define DESC7F20_PURPOSE_CONTENT_RELATED_COMMENTARY 0x31 + +/* TTS_suitability, EN 303 560 table 3 */ +#define DESC7F20_TTS_UNKNOWN 0x0 +#define DESC7F20_TTS_SUITABLE 0x1 +#define DESC7F20_TTS_NOT_SUITABLE 0x2 + +/* dvb_ttml_profile, EN 303 560 table 5 */ +#define DESC7F20_PROFILE_DEFAULT 0x00 +#define DESC7F20_PROFILE_IMSC1_TEXT 0x01 +#define DESC7F20_PROFILE_EBUTTD 0x02 + +static inline void desc7f20_init(uint8_t *p_desc) +{ + desc7f_init(p_desc); + desc_set_length(p_desc, (DESC7F20_HEADER_SIZE - DESC_HEADER_SIZE)); + desc7f_set_tag_extension(p_desc, DESC7F_TAG_TTML_SUBTITLING); + p_desc[7] = 0x30; /* reserved_zero_future_use */ +} + +static inline const uint8_t *desc7f20_get_code(const uint8_t *p_desc) +{ + return p_desc + DESC7F_HEADER_SIZE; +} + +static inline void desc7f20_set_code(uint8_t *p_desc, const uint8_t p_code[3]) +{ + memcpy(p_desc + DESC7F_HEADER_SIZE, p_code, 3); +} + +BITSTREAM_GET_SET(desc7f20, subtitle_purpose, uint8, 48, 6); +BITSTREAM_GET_SET(desc7f20, tts_suitability, uint8, 54, 2); +BITSTREAM_GET_SET(desc7f20, essential_font_usage_flag, uint8, 56, 1); +BITSTREAM_GET_SET(desc7f20, qualifier_present_flag, uint8, 57, 1); +BITSTREAM_GET_SET(desc7f20, profile_count, uint8, 60, 4); + +/* Only the profile list is at a fixed offset; every field after it moves with + * counts read out of the descriptor itself. */ +static inline uint8_t *desc7f20_get_profile(const uint8_t *p_desc, uint8_t n) +{ + if (n >= desc7f20_get_profile_count(p_desc)) + return NULL; + return (uint8_t *)p_desc + DESC7F20_HEADER_SIZE + n * DESC7F20_PROFILE_SIZE; +} + +static inline uint8_t *desc7f20_get_qualifier(const uint8_t *p_desc) +{ + if (!desc7f20_get_qualifier_present_flag(p_desc)) + return NULL; + return (uint8_t *)p_desc + DESC7F20_HEADER_SIZE + + desc7f20_get_profile_count(p_desc) * DESC7F20_PROFILE_SIZE; +} + +BITSTREAM_GET_SET(desc7f20_qualifier, size, uint8, 0, 4); +BITSTREAM_GET_SET(desc7f20_qualifier, cadence, uint8, 4, 4); +BITSTREAM_GET_SET(desc7f20_qualifier, monochrome_flag, uint8, 8, 1); +BITSTREAM_GET_SET(desc7f20_qualifier, enhanced_accessibility_contrast_flag, + uint8, 9, 1); +BITSTREAM_GET_SET(desc7f20_qualifier, position, uint8, 10, 4); + +static inline uint8_t *desc7f20_get_font_count(const uint8_t *p_desc) +{ + if (!desc7f20_get_essential_font_usage_flag(p_desc)) + return NULL; + return (uint8_t *)p_desc + DESC7F20_HEADER_SIZE + + desc7f20_get_profile_count(p_desc) * DESC7F20_PROFILE_SIZE + + (desc7f20_get_qualifier_present_flag(p_desc) ? + DESC7F20_QUALIFIER_SIZE : 0); +} + +static inline uint8_t *desc7f20_get_font(const uint8_t *p_desc, uint8_t n) +{ + uint8_t *p_font_count = desc7f20_get_font_count(p_desc); + if (!p_font_count || n >= *p_font_count) + return NULL; + return p_font_count + DESC7F20_FONT_COUNT_SIZE + n * DESC7F20_FONT_SIZE; +} + +BITSTREAM_GET_SET(desc7f20_font, font_id, uint8, 1, 7); + +static inline uint8_t *desc7f20_get_text_length(const uint8_t *p_desc) +{ + uint8_t *p_font_count = desc7f20_get_font_count(p_desc); + if (p_font_count) + return p_font_count + DESC7F20_FONT_COUNT_SIZE + + *p_font_count * DESC7F20_FONT_SIZE; + return (uint8_t *)p_desc + DESC7F20_HEADER_SIZE + + desc7f20_get_profile_count(p_desc) * DESC7F20_PROFILE_SIZE + + (desc7f20_get_qualifier_present_flag(p_desc) ? + DESC7F20_QUALIFIER_SIZE : 0); +} + +static inline uint8_t *desc7f20_get_text(const uint8_t *p_desc, + uint8_t *pi_length) +{ + uint8_t *p_text_length = desc7f20_get_text_length(p_desc); + *pi_length = *p_text_length; + return p_text_length + DESC7F20_TEXT_LENGTH_SIZE; +} + +static inline bool desc7f20_validate(const uint8_t *p_desc) +{ + uint16_t i_desc_length = desc_get_length(p_desc); + if (i_desc_length + DESC_HEADER_SIZE < DESC7F20_HEADER_SIZE) + return false; + /* dvb_ttml_profile_count shall not be set to zero */ + if (!desc7f20_get_profile_count(p_desc)) + return false; + + uint16_t i_size = DESC7F20_HEADER_SIZE - DESC_HEADER_SIZE + + desc7f20_get_profile_count(p_desc) * DESC7F20_PROFILE_SIZE + + (desc7f20_get_qualifier_present_flag(p_desc) ? + DESC7F20_QUALIFIER_SIZE : 0); + if (desc7f20_get_essential_font_usage_flag(p_desc)) { + if (i_size + DESC7F20_FONT_COUNT_SIZE > i_desc_length) + return false; + i_size += DESC7F20_FONT_COUNT_SIZE + + *desc7f20_get_font_count(p_desc) * DESC7F20_FONT_SIZE; + } + if (i_size + DESC7F20_TEXT_LENGTH_SIZE > i_desc_length) + return false; + i_size += DESC7F20_TEXT_LENGTH_SIZE + *desc7f20_get_text_length(p_desc); + /* trailing reserved_zero_future_use bytes are allowed */ + return i_size <= i_desc_length; +} + +static inline void desc7f20_print(const uint8_t *p_desc, f_print pf_print, + void *opaque, print_type_t i_print_type) +{ + char psz_code[4]; + memcpy(psz_code, desc7f20_get_code(p_desc), 3); + psz_code[3] = '\0'; + + uint8_t i_profile_count = desc7f20_get_profile_count(p_desc); + char psz_profiles[i_profile_count * 3 + 1]; + psz_profiles[0] = '\0'; + for (uint8_t i = 0; i < i_profile_count; i++) + sprintf(psz_profiles + i * 3, i + 1 < i_profile_count ? "%02x " : "%02x", + *desc7f20_get_profile(p_desc, i)); + + uint8_t i_text_length; + const uint8_t *p_text = desc7f20_get_text(p_desc, &i_text_length); + char psz_text[i_text_length + 1]; + memcpy(psz_text, p_text, i_text_length); + psz_text[i_text_length] = '\0'; + + switch (i_print_type) { + case PRINT_XML: + pf_print(opaque, + "", + psz_code, + desc7f20_get_subtitle_purpose(p_desc), + desc7f20_get_tts_suitability(p_desc), + psz_profiles, psz_text); + break; + default: + pf_print(opaque, + " - desc 7f20 ttml_subtitling language=%s" + " subtitle_purpose=%u tts_suitability=%u" + " profiles=\"%s\" text=\"%s\"", + psz_code, + desc7f20_get_subtitle_purpose(p_desc), + desc7f20_get_tts_suitability(p_desc), + psz_profiles, psz_text); + } +} + +#ifdef __cplusplus +} +#endif + +#endif ===================================== dvb/si/descs_list.h ===================================== @@ -90,6 +90,7 @@ #include #include #include +#include #include #include ===================================== mpeg/psi/descs_print.h ===================================== @@ -209,6 +209,7 @@ static inline void descl_print(uint8_t *p_descl, uint16_t i_length, CASE_DESC(7f06) CASE_DESC(7f15) CASE_DESC(7f19) + CASE_DESC(7f20) default: desc7f_print(p_desc, pf_print, print_opaque, i_print_type); View it on GitLab: https://code.videolan.org/videolan/bitstream/-/commit/d4dd59d374a082e789c7db0c0716dc7c5a1d4cb8 -- View it on GitLab: https://code.videolan.org/videolan/bitstream/-/commit/d4dd59d374a082e789c7db0c0716dc7c5a1d4cb8 You're receiving this email because of your account on code.videolan.org. Manage all notifications: https://code.videolan.org/-/profile/notifications | Help: https://code.videolan.org/help From gitlab at videolan.org Thu Aug 27 10:56:44 2026 From: gitlab at videolan.org (Christophe Massiot (@cmassiot)) Date: Thu, 27 Aug 2026 12:56:44 +0200 Subject: [bTSstream-devel] [Git][videolan/bitstream][master] haivision/srt: add timeout and crypto handshake rejection codes Message-ID: <6a9017ec22b83_16e10e9556f641195559@gitlab.mail> Christophe Massiot pushed to branch master at VideoLAN / bitstream Commits: a3be36c2 by Kieran Kunhya at 2026-08-27T10:56:36+00:00 haivision/srt: add timeout and crypto handshake rejection codes SRT_REJ_TIMEOUT and SRT_REJ_CRYPTO, the latter being sent when the two peers have conflicting crypto modes (AES-CTR vs AES-GCM). Co-Authored-By: Claude Opus 5 (1M context) - - - - - 1 changed file: - haivision/srt.h Changes: ===================================== haivision/srt.h ===================================== @@ -325,6 +325,8 @@ static inline const uint8_t *srt_get_control_packet_cif(const uint8_t *buf) #define SRT_HANDSHAKE_TYPE_REJ_CONGESTION 1013 #define SRT_HANDSHAKE_TYPE_REJ_FILTER 1014 #define SRT_HANDSHAKE_TYPE_REJ_GROUP 1015 +#define SRT_HANDSHAKE_TYPE_REJ_TIMEOUT 1016 +#define SRT_HANDSHAKE_TYPE_REJ_CRYPTO 1017 static inline void srt_set_handshake_version(uint8_t *cif, uint32_t version) { View it on GitLab: https://code.videolan.org/videolan/bitstream/-/commit/a3be36c2e916f94120a63621461f55e44a6d8eb9 -- View it on GitLab: https://code.videolan.org/videolan/bitstream/-/commit/a3be36c2e916f94120a63621461f55e44a6d8eb9 You're receiving this email because of your account on code.videolan.org. Manage all notifications: https://code.videolan.org/-/profile/notifications | Help: https://code.videolan.org/help