- Shell 100%
| libvax_duplicate_gop_fix.so | ||
| NtsVaxCreatorServer.ldpreload-wrapper | ||
| README.md | ||
视频预处理时长异常修复说明
1. 项目结论
本目录提供 NtsVaxCreatorServer 的生产应急修复补丁,用于解决部分业务 H.264/TS 视频生成 .nix 索引时只记录开头少量帧,进而表现为播放时长只有几秒或时长异常的问题。
问题本质不是视频整体损坏,而是特定 H.264 码流结构触发了原预处理程序的兼容性缺陷:异常视频的 GOP/关键帧附近通常先出现 SEI,随后才出现 SPS/PPS,同时存在 B 帧、DTS 和解码顺序下非单调的 PTS。原程序按 PTS 去重视频 payload 时,会把“后到达但 PTS 相同”的 GOP 标记一起丢弃,导致后续 GOP/帧索引无法完整写入 .nix。
最终方案通过 LD_PRELOAD 在运行时修正 CNsTsVaxWriter::AddVideoPayload 的重复 PTS 分支,把遗漏的 GOP 标记补到已经写入的帧记录中,并继续调用原有 GOP 索引逻辑。补丁:
- 不修改输入 TS;
- 不生成临时完整 TS;
- 不改变
.nix输出路径或格式; - 不改变后端调用路径,仍调用
/usr/local/sbin/NtsVaxCreatorServer; - 对正常样例不做额外修正,验证中
fixed=0。
现有材料记录表明,该补丁已通过 CentOS 7 兼容构建和异常/正常样例验证,并解决了本次报告的生产问题。它属于无源码条件下的运行时热修复,不等同于厂商源码级修复。
2. 最终交付物
当前目录中的生产部署文件如下:
| 文件 | 大小 | 用途 |
|---|---|---|
libvax_duplicate_gop_fix.so |
16,360 字节 | 运行时 GOP 标记修复库 |
NtsVaxCreatorServer.ldpreload-wrapper |
391 字节 | 保持原调用路径不变的 shell 启动包装器 |
README.md |
- | 本说明文档 |
SHA-256:
libvax_duplicate_gop_fix.so
B568C5CC1CBA862CCA69FF552C194912C485A5D7B60AF5B354BE03F320D3D646
NtsVaxCreatorServer.ldpreload-wrapper
568847587BB4028FBA5E13A201263288B314C358429F4ABC1E52919DA3C07659
3. 现象与根因
3.1 码流侧特征
异常样例和转码后的正常样例均为 1920×1080、25 fps、H.264 High Profile,但关键差异如下:
| 特征 | 异常样例 | 正常/转码样例 |
|---|---|---|
| H.264 level | 4.2 | 4.0 |
| B 帧 | has_b_frames=2 |
has_b_frames=0 |
| DTS | 存在 | 未报告 |
| PTS | 在 PES/解码顺序下非单调 | 单调 |
| 典型关键帧 NAL 顺序 | AUD → SEI → SEI → SEI → SPS → PPS → IDR |
AUD → SPS → PPS → SEI → … → IDR |
| FFmpeg 解码 | 可成功解码 | 可成功解码 |
NAL 类型对应关系:9=AUD、6=SEI、7=SPS、8=PPS、5=IDR。异常视频可见 FFmpeg 警告:
non-existing SPS 0 referenced in buffering period
这说明 SEI 中引用了尚未出现的 SPS,但播放器和 FFmpeg 通常仍能容错,因此不能简单认定原视频整体损坏。
3.2 原程序失效链路
- 正常视频 payload 先以某个 PTS 到达并写入环形缓冲区。
- 含 GOP 标记的后续 payload 使用相同 PTS 到达。
- 原
CNsTsVaxWriter::AddVideoPayload将其视为重复 PTS 并提前返回。 - GOP 标记随 payload 被丢弃,
AddGopIndex无法持续生成索引。 .nix仅保存开头少量帧/GOP,业务侧看到时长异常或播放提前停止。
3.3 决定性实验
对一组异常样例截取 10 秒,在不转码的前提下进行对照:
| 处理方式 | .nix 大小 |
帧数 | GOP 数 |
|---|---|---|---|
| 仅 remux,保留 SEI | 192 字节 | 27 | 2 |
| 仅移除 H.264 SEI | 480 字节 | 252 | 11 |
仅 remux 没有改善,移除 SEI 后索引恢复,证明触发点来自 H.264 SEI/SPS 排列及原写入器的后续处理,而不是 MPEG-TS 容器整体损坏。
4. 补丁工作方式
wrapper 在启动原程序前设置:
export LD_BIND_NOW=1
export LD_PRELOAD="/usr/local/lib/libvax_duplicate_gop_fix.so${LD_PRELOAD:+:$LD_PRELOAD}"
exec /usr/local/sbin/NtsVaxCreatorServer.real "$@"
LD_BIND_NOW=1 必须保留。补丁会修改目标库的 GOT 槽;立即绑定可避免延迟绑定稍后写回已恢复为只读的 GOT 页面而引发崩溃。
补丁库的核心逻辑为:
- 定位
libnstsvaxcreator.so及其动态符号表; - 将
CNsTsVaxWriter::AddVideoPayload的 GOT 槽指向补丁函数; - 非 GOP 标记或非重复 PTS 情况继续调用原函数;
- 命中“相同 PTS 的 GOP 标记 payload”时,找到上一条已写入记录并补写标记;
- 对首个标记也被丢弃的边界场景,为第一条缓冲帧合成初始标记;
- 更新标记计数并调用原
AddGopIndex,不走原来的重复数据丢弃路径。
为兼容 CentOS 7,最终实现不调用可能被链接为 dlsym@GLIBC_2.34 的 dlsym,而是通过 dl_iterate_phdr 解析 ELF 的 DT_SYMTAB、DT_STRTAB、DT_HASH/DT_GNU_HASH。交付 .so 只要求 GLIBC_2.2.5,可运行于 CentOS 7 的 glibc 2.17。
5. 适用条件与上线前检查
适用环境:
- Linux x86-64;
- 已验证目标为 CentOS 7;
- 后端调用形式为
/usr/local/sbin/NtsVaxCreatorServer <input.ts> <output.nix>; - 目标机上的原始
NtsVaxCreatorServer和libnstsvaxcreator.so与本次分析版本一致。
上线前先记录现网文件信息,至少保存哈希、文件类型和依赖版本:
sudo sha256sum /usr/local/sbin/NtsVaxCreatorServer \
/usr/local/lib/libnstsvaxcreator.so
file /usr/local/sbin/NtsVaxCreatorServer
ldd /usr/local/sbin/NtsVaxCreatorServer
readelf --version-info ./libvax_duplicate_gop_fix.so | grep GLIBC
最后一条应只看到兼容的低版本 GLIBC 需求,不应出现 GLIBC_2.34。如厂商已更新原程序或 libnstsvaxcreator.so,不要直接复用本补丁,应重新核对结构偏移、符号和全量样例。
建议先在单台预处理节点灰度,并准备一组异常、正常视频各至少一条进行回归。
6. 生产部署
以下命令假定当前目录中已有两个交付文件。先确认尚未存在同名备份;如果 .real 已存在,应先查明它是否是原始程序,避免覆盖有效备份。
test -x /usr/local/sbin/NtsVaxCreatorServer
test ! -e /usr/local/sbin/NtsVaxCreatorServer.real
备份原程序并安装补丁:
sudo install -m 0755 \
/usr/local/sbin/NtsVaxCreatorServer \
/usr/local/sbin/NtsVaxCreatorServer.real
sudo install -m 0755 \
./libvax_duplicate_gop_fix.so \
/usr/local/lib/libvax_duplicate_gop_fix.so
sudo install -m 0755 \
./NtsVaxCreatorServer.ldpreload-wrapper \
/usr/local/sbin/NtsVaxCreatorServer
部署后的目录应为:
/usr/local/sbin/NtsVaxCreatorServer # shell wrapper,后端继续调用此路径
/usr/local/sbin/NtsVaxCreatorServer.real # 原始二进制
/usr/local/lib/libvax_duplicate_gop_fix.so # 修复库
检查文件及权限:
file /usr/local/sbin/NtsVaxCreatorServer
file /usr/local/sbin/NtsVaxCreatorServer.real
ls -l /usr/local/sbin/NtsVaxCreatorServer \
/usr/local/sbin/NtsVaxCreatorServer.real \
/usr/local/lib/libvax_duplicate_gop_fix.so
/usr/local/sbin/NtsVaxCreatorServer 应显示为 POSIX shell script,三个文件均应具有 0755 权限。
7. 上线验证
用一条异常样例和一条正常样例分别生成 .nix,保持原业务调用参数不变:
/usr/local/sbin/NtsVaxCreatorServer abnormal.ts abnormal.nix
/usr/local/sbin/NtsVaxCreatorServer normal.ts normal.nix
短时开启补丁诊断:
VAX_GOP_FIX_DEBUG=1 \
/usr/local/sbin/NtsVaxCreatorServer abnormal.ts abnormal.debug.nix \
2>abnormal.debug.log
grep 'vax_gop_fix: calls=' abnormal.debug.log
典型摘要为:
vax_gop_fix: calls=... fixed=...
- 异常样例预期
fixed>0; - 正常样例预期
fixed=0; - 生产常态不需要设置
VAX_GOP_FIX_DEBUG。
原程序在本地测试中经常返回 rc=1,即使生成的 .nix 完全有效,因此不能只根据进程返回码判断成功。还应检查 .nix 是否存在、大小是否合理,以及头部的帧数和 GOP 数。该格式在现有分析脚本中按以下偏移读取:
0x28–0x2B:小端frame_count;0x2C–0x2F:小端gop_count。
最终应同时确认:异常视频播放时长恢复、正常视频无回归、后端仍能关联原输入和输出路径。
8. 已完成验证
8.1 四组 10 秒样例
以下数据来自归档的 .nix 头部及调试日志:
| 样例 | 原程序异常样例 帧/GOP | 补丁后异常样例 帧/GOP | 补丁后正常样例 帧/GOP | 异常样例 fixed |
|---|---|---|---|---|
| 样例 A | 0 / 0 | 251 / 11 | 250 / 5 | 10 |
| 样例 B | 2 / 1 | 252 / 11 | 250 / 5 | 10 |
| 样例 C | 27 / 2 | 252 / 11 | 250 / 5 | 9 |
| 样例 D | 2 / 1 | 252 / 11 | 250 / 5 | 10 |
4 组正常样例均为 fixed=0,说明补丁没有误命中正常流。
8.2 完整样例 D
| 样例 | .nix 大小 |
帧数 | GOP 数 | fixed |
|---|---|---|---|---|
| 异常原流 + 补丁 | 4,128 字节 | 3,108 | 125 | 124 |
| 正常转码流 + 补丁 | 2,144 字节 | 3,108 | 63 | 0 |
两者帧数完全一致。异常原流 GOP 数较多,是因为原流 GOP 间隔比转码后的正常流短,并非补丁重复生成帧。
9. 回滚
如灰度发现异常,立即恢复原程序并移除修复库:
sudo test -x /usr/local/sbin/NtsVaxCreatorServer.real
sudo install -m 0755 \
/usr/local/sbin/NtsVaxCreatorServer.real \
/usr/local/sbin/NtsVaxCreatorServer
sudo rm -f /usr/local/lib/libvax_duplicate_gop_fix.so
确认恢复后的 NtsVaxCreatorServer 已重新显示为 ELF 二进制,并用正常样例做一次回归。建议保留 .real 备份直到灰度和观察期结束;确认无需再次启用补丁后再人工清理。
10. 常见问题
wrapper 报缺少文件并返回 127
wrapper 会主动检查以下两个文件:
/usr/local/lib/libvax_duplicate_gop_fix.so
/usr/local/sbin/NtsVaxCreatorServer.real
检查文件是否存在、可读/可执行,以及权限是否为 0755。
报 GLIBC_2.34 not found
这通常表示误用了早期在 Ubuntu 24 上编译的 ELF launcher 或旧补丁。最终交付使用 shell wrapper,当前 .so 仅要求 GLIBC_2.2.5。替换为本目录中的两个最终文件,不要使用旧的 NtsVaxCreatorServer.ldpreload-launcher。
部署后没有出现修复效果
- 用
file确认原路径已经是 shell wrapper; - 用
VAX_GOP_FIX_DEBUG=1检查是否输出calls/fixed; - 确认
LD_BIND_NOW=1没有从 wrapper 中移除; - 检查 SELinux、systemd 或安全启动器是否清理/禁止
LD_PRELOAD; - 核对现网原程序和
libnstsvaxcreator.so是否已被厂商更新。
.nix 已生成但程序返回 1
这是原程序在现有样例上的已知行为。应以 .nix 头部帧数/GOP 数、文件大小和实际播放验证为主,不能仅看返回码。
11. 方案边界与风险
- 补丁依赖当前
NtsVaxCreatorServer/libnstsvaxcreator.so的符号和内存布局;厂商升级后二进制偏移可能变化。 - 补丁只修复“重复 PTS 导致 GOP 标记丢失”这一类问题,不能覆盖所有损坏 TS 或其他编码异常。
LD_PRELOAD可能被 SELinux、受限执行环境或安全包装器禁用。- 这是生产应急/灰度方案,长期方案仍应优先推动厂商在源码中修正写入器的重复 PTS 处理,并补充回归测试。
- 不建议把“移除 SEI 后生成完整临时 TS”作为生产主方案:它会增加预处理磁盘占用,并可能破坏后端/数据库对原文件与索引的关联。