
OBS Studio 中 libcaption 闭字幕库解析从 EIA-608 字符集到 H.264 SEI 字幕封装【免费下载链接】obs-studioOBS Studio - Free and open source software for live streaming and screen recording项目地址: https://gitcode.com/GitHub_Trending/ob/obs-studiolibcaption 是 OBS Studio 内置于 deps/libcaption 的纯 C 字幕库用于创建和解析闭字幕Closed Caption数据。它帮助 OBS 这类社区开发的广播工具实现字幕的编码与解码并在编码流程中将字幕载荷封装为 H.264 SEI NALU 注入视频码流。读完本文你将理解 libcaption 的 EIA-608/CEA-708 支持边界、字符集映射机制、帧缓冲模型以及它在 libobs/obs-output.c 中如何被调用把字幕真正写进推流视频流。一、libcaption 的定位与支持范围根据 READMEv0.8作者 Matthew Szatmarylibcaption 的核心目标是以 C 语言实现闭字幕数据的创建与解析采用 MIT 许可证见 LICENSE.txt开放给社区广播工具并跨平台实现 EIA-608 / CEA-708 中与 Apple iOS 平台兼容的一个子集以保证各平台行为一致。其能力边界在 README 中被明确限定这些限定与源码结构完全对应能力项支持范围源码佐证EIA-608 编码/解码仅控制码control、前导码preamble以及 BNA / SNA / 扩展西欧字符集src/eia608.c、src/eia608_charmap.cCEA-708 编码仅将 608 数据封装进 NTSC field 1 user data 结构src/cea708.c、caption/cea708.hH.264 工具函数将 708 载荷包装为 SEI NALU及其逆向操作src/mpeg.c、caption/mpeg.hREADME 对 H.264 封装的描述相当具体将 708 载荷前置 3 个字节nal_unit_type 6、payloadType 4、PayloadSize可变再追加一个编码为完整字节、值为 127 的 stop bit若载荷中出现 emulated start code0,0,1 序列则插入一个 emulation prevention byte值为 3。逆向解封装函数也一并提供。这一点可以从 caption/mpeg.h 的 SEI 类型枚举得到印证——sei_type_user_data_registered_itu_t_t35 4正是 payloadType 4ITU-T T.35 用户数据 SEI。二、字符集支持6 个字符集映射表README 中最具实操价值的内容是字符映射表。608 数据按高位掩码区分字符集libcaption 支持的完整字符集如下完整表格见 README缩写字符集覆盖内容示例BNABasic North American英文字母、数字、标点以及 á、é、í、ó、ú、ç、Ñ 等常见重音字符行末为 █ 占位块SNASpecial North American®、°、½、¿、™、¢、£、♪ 等符号与少量法文重音字符WESExtended Western EuropeanSpanish/MiscellaneousÁ、É、Ó、Ú、Ü、ü、¡、©、•、“、” 等WEFExtended Western EuropeanFrenchÀ、Â、Ç、È、Ê、Ë、ë、Î、Ï 等WEPExtended Western EuropeanPortugueseÃ、ã、Í、Ò、Õ、{}、~ 等WEGExtended Western EuropeanGerman/DanishÄ、ä、Ö、ö、ß、¥、Å、Ø、┌┐└┘ 等这些判定逻辑并非文档空谈而是以位运算内联函数直接落在 caption/eia608.h 中。例如static inline int eia608_is_basicna(uint16_t cc_data) { return 0x0000 ! (0x6000 cc_data); } static inline int eia608_is_specialna(uint16_t cc_data) { return 0x1130 (0x7770 cc_data); } static inline int eia608_is_westeu(uint16_t cc_data) { return 0x1220 (0x7660 cc_data); } static inline int eia608_is_control(uint16_t cc_data) { return 0x1420 (0x7670 cc_data) || 0x1720 (0x7770 cc_data); } static inline int eia608_is_preamble(uint16_t cc_data) { return 0x1040 (0x7040 cc_data); }同文件还实现了 EIA-608 的奇偶校验parity机制每个字节最高位由低 7 位异或得出eia608_parity_varify用于校验、eia608_parity_strip用于剥离。这解释了为什么解码入口 src/caption.c 的caption_frame_decode第一步就调用eia608_parity_varify——校验失败直接置LIBCAPTION_ERROR而0x8080padding则按LIBCAPTION_OK跳过。UTF-8 到 EIA-608 的双向转换由 src/utf8.c 与 src/eia608_from_utf8.c 完成后者由 src/eia608_from_utf8.re2c 用 re2c 生成这也正是构建说明中 re2c 为可选依赖的原因。三、帧缓冲模型双缓冲的 15×32 屏幕libcaption 的解码状态载体是caption_frame_t定义在 caption/caption.h屏幕固定为SCREEN_ROWS 15行 ×SCREEN_COLS 32列每个单元格caption_frame_cell_t携带 1 位下划线uln、3 位样式sty对应eia608_style_white/green/blue/cyan/red/yellow/...等 EIA-608 颜色以及最多 4 字节 UTF-8 字符front/back两块帧缓冲分别对应 EIA-608 的显示内存Paint On 写入与非显示内存Pop On 写入write指针指示当前写入目标内联谓词caption_frame_popon/caption_frame_painton/caption_frame_rollup判断当前处于哪种字幕模式roll-up 行数由_caption_frame_rollup[] { 0, 2, 3, 4 }依state.rup查表得出。解码主循环caption_frame_decodesrc/caption.c的分支结构精确对应 README 所说的控制码、前导码、字符集三类数据处理奇偶校验→ 失败即 ERRORpadding0x8080→ 直接 OKXDS 时间戳数据eia608_is_xds→ 交给 src/xds.c 的xds_decode控制码→caption_frame_decode_control处理 Paint Onresume_direct_captioning切到 front 缓冲、Roll-up 2/3/4 行、Carriage Return滚动行、Backspace、Delete to End of Row、Pop Onresume_caption_loading切到 back 缓冲、End of Caption把 back 拷贝到 front 并置LIBCAPTION_READY、Tab 偏移等BNA / SNA / WestEU 文本→caption_frame_decode_text经eia608_to_utf8转 UTF-8 后逐格写入。注意西欧扩展字符走替换前一字符的向后兼容策略会先调用caption_frame_backspace前导码 / 行中样式变更→ 更新行列位置、颜色与下划线状态。一个值得注意的实现细节解码时会跳过与控制码/SNA 码重复的cc_data与 iOS/VLC 行为对齐且未知模式下frame-write为空收到文本会被忽略返回LIBCAPTION_OK而非报错。反向的纯文本 → 字幕帧入口是caption_frame_from_textsrc/caption.c它初始化帧、按SCREEN_COLS用utf8_wrap_length折行、跳过行首空白最后caption_frame_end提交。caption_frame_to_text则反向把 front 缓冲导出为 CRLF 分隔的 UTF-8 文本导出缓冲区上限由宏CAPTION_FRAME_TEXT_BYTES定义。四、CEA-708 封装NTSC field 1 用户数据结构708 侧的实现集中在 src/cea708.c对外接口由 caption/cea708.h 给出cea708_t结构包含 ITU-T T.35 头国家码country_united_states 181、厂商码t35_provider_direct_tv 47/t35_provider_atsc 49、user identifier、user data type code与最多 32 条cc_data_t每条含cc_valid、2 位cc_type和 16 位cc_datacc_type枚举区分cc_type_ntsc_cc_field_1、cc_type_ntsc_cc_field_2、cc_type_dtvcc_packet_data、cc_type_dtvcc_packet_start——这就是 README 所说708 支持限于把 608 数据编码进 NTSC field 1 user data 结构的具体含义核心 API 为cea708_init按 HLS 兼容默认值配置、cea708_add_cc_data追加一条 608 字对、cea708_render序列化出 T.35 载荷、cea708_parse_h264/cea708_parse_h262从码流中解析还原、cea708_to_caption_frame转回 608 帧缓冲、cea708_dump调试打印。五、H.264 SEI NALU 工具函数README 描述的3 字节头 stop bit 127 emulation prevention封装逻辑对应 caption/mpeg.h 中的 SEI 消息体系sei_message_t链表 sei_t带时间戳构成消息容器sei_message_new/sei_message_append/sei_render/sei_parse完成构造、拼接、序列化与反序列化高层转换函数sei_from_caption_frame帧 → SEI、sei_to_caption_frameSEI → 帧、sei_from_sccSCC 字幕文件 → SEI、sei_from_caption_clear清屏 SEI码流级解析通过mpeg_bitstream_tsrc/mpeg.c完成mpeg_bitstream_parse接收一帧 NALU支持STREAM_TYPE_H262 0x02/STREAM_TYPE_H264 0x1B/STREAM_TYPE_H265 0x24内部用cea708[MAX_REFRENCE_FRAMES]64 个的延迟队列处理 B 帧乱序mpeg_bitstream_flush负责排空未决帧。这正对应 README Limitations 一节的表述当前 B 帧字幕支持是最小化的——libcaption 只保证回放时字幕不需要重排即按显示顺序而非编码顺序挂载字幕而非完整还原 B 帧重排下的精确 PTS 映射。此外仓库中还提供了 SCC / SRT / VTT 等字幕文本格式的互转src/scc.c、src/srt.c、src/vtt.c、src/dvtcc.cREADME 未展开但它们同属该库的字幕编解码生态。六、libcaption 在 OBS 中的集成方式在 OBS 构建系统中libcaption 是一个静态库且默认不随主构建编译deps/libcaption/CMakeLists.txt 中声明add_library(caption STATIC EXCLUDE_FROM_ALL)并暴露OBS::caption别名源文件列表即上面提到的全部src/*.clibobs/CMakeLists.txt 按需引入if(NOT TARGET OBS::caption)时add_subdirectory随后将OBS::caption链入 libobs 目标。运行时集成点在 libobs/obs-output.c字幕入口obs_output_captionlibobs/obs-output.c接收 CEA-708 打包数据每包 3 字节obs_output_output_caption_text1/text2则接受纯文本默认显示 2 秒挂载到视频包add_caption[libobs/obs-output.c](https://link.gitcode.com/i/9c623c84c797dec12fd16f52868d8d31#L1499 附近)是两条路径的汇合点——若队列里是 608 字对数据则cea708_init建立 popon 帧、逐条做eia608_parity_varify校验后cea708_add_cc_data追加、最终cea708_render生成 SEI 载荷写入 encoder packet若是纯文本则caption_frame_from_textsei_from_caption_frame走文本路径帧级调度输出回调中按caption_timestamp frame_timestamp判断该帧是否携带字幕保证字幕与帧时间戳对齐。从源码结构看这条链路完整覆盖了 README 描述的三个能力面608 解码/校验eia608_*、708 封装cea708_*、H.264 SEI 包装sei_*。七、构建方法README 给出的构建步骤如下当前仓库 deps/libcaption/CMakeLists.txt 要求 CMake 3.28macOS / Linux先安装 git、cmake、编译器可选安装 re2c 和 ffmpeg# 常规构建 cmake . make # 若希望不依赖 re2c跳过 re2c 生成 eia608_from_utf8 代码的路径 cmake -DENABLE_RE2COFF . make # 安装 sudo make installWindowsREADME 明确说明作者未在 Windows 上测试过 libcaption但它是纯 C 实现且无外部依赖从源码结构看没有理由不能编译——当前 OBS 仓库本身已在 CMake 中无条件支持将其编译为静态库。八、适用边界小结结合 README 与源码使用 libcaption 时应记住以下前提与限制能力是子集608 仅覆盖控制码、前导码与六种字符集708 仅是 NTSC field 1 user data 结构下的 608 透传封装而非完整 CEA-708 服务层窗口、样式、多服务实现B 帧策略保守字幕以回放顺序对齐不提供 B 帧重排下的精确时间戳重映射状态机严格解码依赖LIBCAPTION_ERROR / OK / READY三态libcaption_status_update保证 ERROR 与 READY 的优先级奇偶校验失败会污染整帧状态平台一致性优先行为基准是 Apple iOS 的字幕支持范围包括跳过重复 SNA/控制码等细节跨平台一致性比覆盖更多特性更受重视。对想在 OBS 推流中携带闭字幕、或开发类似广播工具的开发者而言libcaption 提供了从 UTF-8 文本到 EIA-608 字对、再到 CEA-708 T.35 / H.264 SEI NALU 的完整工具链入口是 caption/caption.h 的caption_frame_tAPI封装出口是 caption/mpeg.h 的sei_render系列函数而 OBS 的实际调用方式可直接对照 libobs/obs-output.c 的add_caption实现。【免费下载链接】obs-studioOBS Studio - Free and open source software for live streaming and screen recording项目地址: https://gitcode.com/GitHub_Trending/ob/obs-studio创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考