多路直播 + AI 实时翻译:一套「会翻译的直播墙」的工程复盘

这里写自定义目录标题

  • [多路直播 + AI 实时翻译:一套「会翻译的直播墙」的工程复盘](#多路直播 + AI 实时翻译:一套「会翻译的直播墙」的工程复盘)
    • 目录
    • [0. 先给结论(TL;DR)](#0. 先给结论(TL;DR))
    • [1. 我们到底要做一个什么系统](#1. 我们到底要做一个什么系统)
    • [2. 整体架构:一张图看懂](#2. 整体架构:一张图看懂)
    • [3. 播放层选型:为什么是 hls.js](#3. 播放层选型:为什么是 hls.js)
      • [3.1 结论](#3.1 结论)
      • [3.2 为什么](#3.2 为什么)
      • [3.3 同类方案横向对比](#3.3 同类方案横向对比)
    • [4. 接入层选型:为什么是 MediaMTX](#4. 接入层选型:为什么是 MediaMTX)
      • [4.1 结论与职责](#4.1 结论与职责)
      • [4.2 同类方案横向对比](#4.2 同类方案横向对比)
    • [5. 关键设计:一套「两档播放」模型](#5. 关键设计:一套「两档播放」模型)
    • [6. 转录层选型:ASR 与翻译怎么选](#6. 转录层选型:ASR 与翻译怎么选)
      • [6.1 两条转录车道](#6.1 两条转录车道)
      • [6.2 ASR 选型对比](#6.2 ASR 选型对比)
      • [6.3 翻译选型对比](#6.3 翻译选型对比)
      • [6.4 端到端开源方案参考](#6.4 端到端开源方案参考)
      • [6.5 存储归档](#6.5 存储归档)
    • [7. 最难的部分:让字幕跟着画面走](#7. 最难的部分:让字幕跟着画面走)
      • [7.1 时钟从哪来](#7.1 时钟从哪来)
      • [7.2 一个真实的坑:原生 HLS 没有时钟](#7.2 一个真实的坑:原生 HLS 没有时钟)
      • [7.3 诚实的边界](#7.3 诚实的边界)
    • [8. AI 研判:让转录文本真正「有用」](#8. AI 研判:让转录文本真正「有用」)
    • [9. 踩坑实录:9 个真实花时间的问题](#9. 踩坑实录:9 个真实花时间的问题)
      • [坑 1 · nginx 写不了代理临时文件 → 播放器疯狂重下](#坑 1 · nginx 写不了代理临时文件 → 播放器疯狂重下)
      • [坑 2 · 纯 HTTP 页面没有 `crypto.randomUUID` → 功能静默死亡](#坑 2 · 纯 HTTP 页面没有 crypto.randomUUID → 功能静默死亡)
      • [坑 3 · `IntersectionObserver` 挂在被销毁的 `<video>` 上](#坑 3 · IntersectionObserver 挂在被销毁的 <video> 上)
      • [坑 4 · `sample.mp4` 不支持 Range 请求](#坑 4 · sample.mp4 不支持 Range 请求)
      • [坑 5 · 聚焦会话:页面刷新被 409 拒绝](#坑 5 · 聚焦会话:页面刷新被 409 拒绝)
      • [坑 6 · 聚焦会话:每 50 秒重连一次](#坑 6 · 聚焦会话:每 50 秒重连一次)
      • [坑 7 · 一个 ffmpeg 参数让采样全停](#坑 7 · 一个 ffmpeg 参数让采样全停)
      • [坑 8 · 浏览器解码器是有预算的](#坑 8 · 浏览器解码器是有预算的)
      • [坑 9 · 一个没解决的坑:上游信源本身损坏(如实记录)](#坑 9 · 一个没解决的坑:上游信源本身损坏(如实记录))
    • [10. 经验总结:做「视频 + AI」系统的 8 条实践](#10. 经验总结:做「视频 + AI」系统的 8 条实践)
    • [11. 结语](#11. 结语)
    • 参考

多路直播 + AI 实时翻译:一套「会翻译的直播墙」的工程复盘

项目 :一个多信源电视/电台直播监控 + AI 转录翻译系统(下文简称「本系统」)

主题 :浏览器端 HLS 播放、多路直播接入、AI 实时转录与翻译、以及音画字幕同步

适合读者 :正在做「视频 + AI」方向、或准备自建直播/转录管线的工程师

阅读时长 :约 15 分钟。建议顺序阅读,第 2 章的架构图是全篇的地基。

核心亮点:一套「两档播放」模型 + 播放/转录共用同一时钟,让几十路直播墙稳定运行、字幕跟着画面走。


目录

  1. 先给结论(TL;DR)
  2. 我们到底要做一个什么系统
  3. 整体架构:一张图看懂
  4. [播放层选型:为什么是 hls.js](#播放层选型:为什么是 hls.js)
  5. [接入层选型:为什么是 MediaMTX](#接入层选型:为什么是 MediaMTX)
  6. 关键设计:一套「两档播放」模型
  7. [转录层选型:ASR 与翻译怎么选](#转录层选型:ASR 与翻译怎么选)
  8. 最难的部分:让字幕跟着画面走
  9. [AI 研判:让转录文本真正「有用」](#AI 研判:让转录文本真正「有用」)
  10. [踩坑实录:9 个真实花时间的问题](#踩坑实录:9 个真实花时间的问题)
  11. [经验总结:做「视频 + AI」系统的 8 条实践](#经验总结:做「视频 + AI」系统的 8 条实践)
  12. 结语
  13. 参考

0. 先给结论(TL;DR)

如果你只想知道结论,这一节足够;想理解「为什么」,请从第 1 章往下读。本文所有结论均来自真实项目的踩坑与复盘。

  • 浏览器播放 :用 hls.js(MSE 播放 HLS),原生 HLS 仅作兜底。
  • 流媒体服务器 :用 MediaMTX,负责 RTSP 收流 + 低延迟 HLS(LL-HLS)分发。
  • 媒体处理 :用 ffmpeg 拉流、转码、采样、抽音频。
  • 实时转录 :用实时 ASR (本项目取 Qwen-Audio Realtime),翻译用大模型。
  • 同类可选项 :播放器(Video.js / Shaka / dash.js)、服务器(SRS / ZLMediaKit /
    OvenMediaEngine)、ASR(Whisper / FunASR)、翻译(NLLB / OPUS-MT)。

全篇有两个反复出现的核心观点,先划重点:

  1. 播放和转录必须共用同一条时序 ------选中的频道,画面、声音、字幕走同一条链路、
    同一个时钟,才谈得上「同步」。
  2. HTTP 200 不等于真的在播------验收必须看到解码帧增长 / 音频推进,而不是接口成功。

1. 我们到底要做一个什么系统

这是一个「直播监控指挥台」:把国内外多路电视与电台直播源接入进来,在一面大屏墙上同时监控,对每一路做实时语音转录翻译成中文 ,并把结果归档成可检索、可下载的字幕库,还能对转录文本发起 AI 研判

一句话概括:让每一路直播都「听得懂、看得见、可检索」。

它同时踩在三个技术领域上,也决定了本文的三条主线:

复制代码
① 浏览器端视频播放    → 一个页面稳定解码多路 HLS 直播
② 流媒体接入与转发    → 把五花八门的公网源(HLS/RTSP)收进来,统一转成浏览器能播的格式
③ AI 转录 + 翻译      → 把直播音频实时转成原文并翻译,还要和画面对齐

把它拆成一个「输入 → 处理 → 输出」的流水线,理解起来最自然:

复制代码
多路公网直播源  →  统一接入与转发  →  浏览器播放  →  AI 转录/翻译  →  归档与研判
   (HLS/RTSP)        (ffmpeg+MediaMTX)     (hls.js)      (ASR+LLM)      (PostgreSQL+Agent)

后面每一章,都对应这条流水线上的一段。


2. 整体架构:一张图看懂

先看全貌。这张图是后面所有章节的地基:

复制代码
                       ┌────────────────────────── 公网直播源 ──────────────────────────┐
                       │   HLS(m3u8) / RTSP / 电台音频流 ......                          │
                       └───────────────────────────┬─────────────────────────────────┘
                                                   │  ffmpeg 拉流(worker 进程)
                                                   ▼
   ┌──────────────────────────►  MediaMTX  ◄──────────────────────────┐
   │                        RTSP 收流 + LL-HLS 分发                    │
   │                                  │                                │
   │   RTSP(给后端 ASR)              │  LL-HLS(给浏览器)             │
   ▼                                  ▼                                │
  后端连续 ASR                      nginx(同源代理)                     │
   (WebSocket 长连接)                   │                              │
   │                                   ▼                              │
   ▼                          浏览器 hls.js 播放器                      │
  原文 + 译文 ───────────────────────► 字幕栏 / 管理页                   │

再记住两条贯穿全项目的架构门禁(这是设计底线,不是可选项):

  1. 浏览器永远拿不到上游地址 。前端只能访问平台 API、SSE、快照和 HLS,
    永远不接触上游 URL / Header / Cookie / 密钥。所有源信息都收在服务端。
  2. AI 分析可以缺席,主链路不能停 。分析服务停掉或缺席时,配置、媒体接入、
    播放这条主链路仍然正常工作------转录是「增强」,不是「依赖」。

💡 读到这里,你应该已经理解 :系统是分层的,播放和转录是两条并行消费

同一条媒体流的链路。这个「一源两消费」的结构,是后面所有设计取舍的根源。


3. 播放层选型:为什么是 hls.js

3.1 结论

浏览器播放器用 hls.js 1.5.17。核心代码非常典型:

ts 复制代码
// 播放器模块:创建并挂载 hls.js
const hls = new Hls({
  lowLatencyMode: true,          // 开启低延迟 HLS(LL-HLS)
  liveMaxLatencyDuration: 12,    // 直播最大允许延迟
});
hls.loadSource("/hls/<channel>/focus/index.m3u8");
hls.attachMedia(video);

3.2 为什么

浏览器的 <video> 原生只对 HLS 有部分支持(Safari 好一些,Chromium 基本不支持)。

hls.js 是社区事实标准 :它把 HLS 的 m3u8 清单和 ts/fmp4 分片,用 MSE

(Media Source Extensions)喂给 <video>,让 Chrome / Edge / Firefox 都能播 HLS。

它有两个对本项目不可替代的能力:

  • lowLatencyMode :支持 LL-HLS(分片级别 200ms ~ 1s),这是「单击一个频道
    能立刻看到实时画面」的前提;
  • playingDate(PROGRAM-DATE-TIME) :能从 HLS 清单里拿到每一段的墙钟时间,
    这是字幕能和画面对齐的关键------没有它,字幕只能靠「猜时间」(见第 7 章)。

3.3 同类方案横向对比

项目 协议 特点 适合谁
hls.js(本项目) HLS 轻量、LL-HLS 支持好、事实标准 Web 端播 HLS 的默认答案
Video.js HLS/DASH 生态最全、插件多、皮肤丰富 需要成熟商业级 UI
Shaka Player(Google) DASH/HLS DRM 强、规范严谨 需要 Widevine/PlayReady
dash.js DASH DASH 参考实现 MPEG-DASH
Plyr / Vidstack 皮肤层 好看的控件层,常与 hls.js 组合 只想要控件
Clappr 插件化 可扩展播放器框架 需要自定义插件
ExoPlayer / Media3 多协议 移动端标准 Android App
AVPlayer HLS 原生 iOS/Safari 原生 苹果生态

选型结论 :Web 端播 HLS,hls.js 是默认答案 ;要花哨控件就套 Plyr/Vidstack,

要完整商业生态就 Video.js,要 DRM 就 Shaka。


4. 接入层选型:为什么是 MediaMTX

4.1 结论与职责

流媒体服务器用 MediaMTX 1.20(原名 rtsp-simple-server,Go 编写,单文件即可运行):

  • 收流:worker 用 ffmpeg 把公网源(m3u8 / rtsp)拉下来,以 RTSP 推到 MediaMTX;
  • 分发 :MediaMTX 同时对外提供 RTSPLL-HLS 。前端播放器走 LL-HLS,
    后端 ASR 走 RTSP,两路消费者互不干扰。

它比传统的 nginx-rtmp 更现代,开箱即用支持 LL-HLS,配置极简。一个实际调优细节:

yaml 复制代码
# mediamtx.yml(流媒体服务器配置)
readTimeout: 30s    # 默认 10s 太短:直播源偶发卡顿会让 MediaMTX 直接拆流
writeTimeout: 30s   # 放宽到 30s,让上游扛过瞬断,避免频道闪断

4.2 同类方案横向对比

项目 语言 特点
MediaMTX(本项目) Go 单文件、RTSP/LL-HLS/WebRTC、配置极简
SRS C++ 国产老牌、RTMP/HLS/WebRTC 全能
ZLMediaKit C++ 国产高性能、协议极全
OvenMediaEngine C++ 主打亚秒级 LLHLS / WebRTC
LiveKit Go WebRTC 实时音视频、房间模型
go2rtc Go 智能家居 RTSP 转 WebRTC/HLS
nginx-rtmp C 经典但已停止维护
Ant Media Server Java 企业级、社区版开源

选型结论 :只要「收流 + 分发」,MediaMTX / go2rtc 最省心;要高并发多协议,

SRS / ZLMediaKit 更成熟;要做实时互动/连麦,选 LiveKit / OvenMediaEngine。


5. 关键设计:一套「两档播放」模型

这是本项目最值得分享的设计,直接决定了系统的稳定性。核心思路:把「展示」和「采集」解耦。

问题 :一个页面同屏几十路直播,浏览器扛不住------每个 HLS 流都要独立解码器

和网络连接,Chromium 对同时解码的 MediaSource 数量有硬上限。

解法:把「看得见的墙」和「真正在拉的流」解耦,做两档播放:

复制代码
┌──────────────────────── 浏览器墙(N 路平铺)────────────────────────┐
│  ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐              │
│  │ 缩略图 1 │ │ 缩略图 2 │ │ 缩略图 3 │ │  ......      │  非聚焦:     │
│  │ 20s循环MP4│ │ 20s循环MP4│ │ 20s循环MP4│ │          │  服务端采样   │
│  └──────────┘ └──────────┘ └──────────┘ └──────────┘              │
│                                                                    │
│  ┌────────────────────────────────────────────────┐               │
│  │           聚焦(主屏)= 真·LL-HLS 直播          │  单击→申请    │
│  └────────────────────────────────────────────────┘  focus 会话     │
└────────────────────────────────────────────────────────────────────┘
  • 非聚焦的缩略图不播直播流 ,而是播一段 20 秒循环的采样 MP4(服务端每
    5 分钟重新采一次)。N 路缩略图只占极少解码和带宽,画面却一直是「动」的。
  • 聚焦(主屏)的那一路 :单击切到主屏时才申请一个 focus 会话 ,服务端
    单独拉一路低延迟 RTSP → LL-HLS,浏览器切到 /hls/<channel>/focus/
  • 同一时刻只有一路真正在拉公网直播源,其余全部走采样循环。
ts 复制代码
// 非聚焦格子:走服务端生成的 20 秒 MP4 循环
video.src = `/api/v1/channels/${id}/sample.mp4`;
// 聚焦格子:申请 focus 会话后切到 LL-HLS
video.src = `/hls/${id}/focus/index.m3u8`;

这个设计把「几十路并发解码」的浏览器压力,降到了「一路高清 + 若干路低码率 MP4」。

💡 读到这里,你应该已经理解 :稳定性的关键不是「拼命并行拉流」,而是

把「展示」和「采集」解耦。这几乎是所有多路直播墙的通用思路。


6. 转录层选型:ASR 与翻译怎么选

6.1 两条转录车道

接入之后就是转录。本项目把转录分成两条车道,兼顾「实时」与「覆盖」:

  1. 聚焦快车道(连续 ASR) :某频道被聚焦时,服务端用一个 ffmpeg 持续读取该
    频道的 focus 路径,按 200ms 一包 PCM 连续上传到 ASR 的单个 WebSocket
    长连接
    ;每约 4 秒提交一个识别窗口,结果按 item_id 归档。这样被选中的
    这一路,画面、声音、字幕共用同一个时钟

  2. 后台慢车道(全目录) :其余频道仍由调度器以短片轮询方式转录,保证
    「全信源都有覆盖」,但不宣称逐秒无遗漏(这是诚实的边界,见第 7 章)。

    聚焦频道 ─► ffmpeg 连续读流 ─► 单 WebSocket ─► 4s 窗口提交 ─► 原文+译文
    其他频道 ─► 短片轮询 ────────► 覆盖但不保证逐秒

6.2 ASR 选型对比

方案 类型 特点 代价
Qwen-Audio Realtime(本项目) 云服务 中文强、实时好、接入快 按量计费、受并发配额
Whisper / faster-whisper 开源 多语言、离线、社区标准 自扛 GPU、延迟与并发
whisper.cpp 开源 无 GPU 也能跑、边缘友好 精度/速度折中
FunASR(达摩院) 开源 中文场景强,含 VAD/标点 需自建服务
Vosk 开源 轻量、流式、小语种 精度一般
wav2vec 2.0 开源 可针对特定语言微调 需训练

取舍 :自建(Whisper/FunASR)无按量成本、数据不出内网,但要自己扛 GPU 和并发;

云服务(Qwen-Audio Realtime)国内合规、接入快、实时性好,代价是按量计费和配额。

6.3 翻译选型对比

方案 特点
大模型(qwen3.8-max)(本项目) 整段翻译,兼顾语境和术语,中文自然
NLLB-200(Meta) 200 语言,开源旗舰
OPUS-MT / Marian 按语言对分发的轻量模型,易自托管
Argos Translate 离线、纯 Python,安装即用

6.4 端到端开源方案参考

  • WhisperLive / whisper-stream:把 Whisper 做成实时流式服务;
  • RealtimeSTT + RealtimeTTS:实时识别 + 合成组合件;
  • faster-whisper-server:OpenAI 兼容的转录 HTTP 服务。

它们大多只解决「音频 → 文字」。本项目的差异化在于多路直播 + 字幕与画面按时钟
对齐 + 归档检索
------这正是最花功夫的部分,也是下一章的主题。

6.5 存储归档

转录结果写入 PostgreSQL 16 (Docker 容器,仅监听本机回环端口,不暴露公网),

按「频道 + 北京日期」融合成频道日报,支持按电视台/电台、频道、来源筛选,并可导出

UTF-8 BOM 的 TXT(兼容 Windows 记事本)。未配置数据库时,本地开发回退到

SQLite。


7. 最难的部分:让字幕跟着画面走

「能转录」不难,「让字幕和画面对上」才是真难点。 本章是全篇的技术核心。

7.1 时钟从哪来

对齐的核心是时间锚点

  • 播放侧 :从 hls.js 的 playingDate(HLS 清单的 PROGRAM-DATE-TIME)拿到
    当前播放的墙钟时间;
  • 转录侧 :每条字幕记录 audio_session_idaudio_sequence、媒体起止时间;
  • 渲染时 :只显示「当前 HLS 播放时间落入的那一个字幕窗口」的原文和译文,
    过期或未来的记录一律不显示。
ts 复制代码
// 电台/电视共用:按 HLS 播放时刻选择当前字幕窗口
const playingDate = hls.playingDate;              // 墙钟时间
showOnly(recordsInWindow(playingDate, 4 /* 秒 */)); // 4 秒窗口内的那一条

7.2 一个真实的坑:原生 HLS 没有时钟

刚开始电台用原生 HLS 播放,能播但 playingDate 永远是空,字幕栏一直空白。

修复电台也优先用 hls.js 来拿 PROGRAM-DATE-TIME;只有真的不能用 hls.js

时才回退原生,且此时宁可字幕空白,也不猜时间

7.3 诚实的边界

当前锚点仍是「接收端估算」:源 PTS/RTCP 与 HLS 播放时刻的绝对误差尚未独立标定

所以做到的是片段级(约 4 秒窗口)对齐 ,不是毫秒级------这一点必须在文档里如实写明,

不能靠「窗口连续」就宣称「绝对同步」。


8. AI 研判:让转录文本真正「有用」

转录只是「原料」,本项目的目标是让 AI 在文本上做用户触发的研判 (不是视频格子上

一直跑的实时分析按钮):

  • 值班员对已存储的转录文本发起研判,由大模型给出结论;
  • 界面右下角接入外部 Agent 平台videos_analysis_agent),支持流式回答、
    按频道隔离会话、一键生成「今日简报 / 关键要闻 / 重点关注」。

一个工程上的关键处理:模型会在答案里混入「思维链」和内部标记。桥接层直接丢弃
思维链增量
,并在前端渲染前剔除 <!-- ... --> 类注释,所以用户只看到干净答案,

同时保留逐字流式体验。

复制代码
Upstream SSE ─► 桥接层归一化(status/delta/final) ─► 丢弃思维链 ─► 前端流式渲染

9. 踩坑实录:9 个真实花时间的问题

这一章是本文最值钱的部分。 所有问题都在真实 Chromium(CDP 远程调试)驱动公开

页面时复现并修复的,而不是靠看日志猜。按「现象 → 根因 → 修复 → 教训」组织。

坑 1 · nginx 写不了代理临时文件 → 播放器疯狂重下

  • 现象 :每个墙格每秒钟重下一整段 sample.mp4,两分钟内一个浏览器发出约
    3560 次请求,客户端报 ERR_CONTENT_LENGTH_MISMATCH<video>MEDIA_ERR_NETWORK
  • 根因 :nginx 以部署用户运行,/var/lib/nginx/proxy/ 没有写权限 ,所有超出
    内存缓冲的响应体都失败(日志里 2 万多条 Permission denied)。
  • 修复 :把 client_body_temp_pathproxy_temp_path 等全部改到 $DATA_DIR/web/ 下。
  • 教训:播放问题不一定是播放器的锅,反向代理的一个权限就能制造「雪崩式重下」。

坑 2 · 纯 HTTP 页面没有 crypto.randomUUID → 功能静默死亡

  • 现象 :实时按钮从来没用过、配置发布失败、事件发不出去------全都没报错,只是悄悄不工作
  • 根因crypto.randomUUID 只在 Secure Context(HTTPS 或 localhost) 下存在。
    公开端点走 HTTP,调用直接抛 TypeError,把所有需要 id 的逻辑一起带崩。
  • 修复 :自己封装 randomId()(有 randomUUID 就用,否则用 getRandomValues)。
  • 教训:HTTP 下的浏览器 API 会用「安全上下文」给你挖坑,光看后端日志永远找不到。

坑 3 · IntersectionObserver 挂在被销毁的 <video>

  • 现象:墙重绘后所有格子变回静态快照。
  • 根因 :重绘替换了 <video> 元素,但旧观察者还盯着已从 DOM 移除的旧节点
    报告「不可见」并顺手把新格子 stop() 了。
  • 修复 :每次 ensure() 都先 disconnect() 再重新观察。
  • 教训:任何「观察者/订阅者」模式,都要在元素重建时重新绑定。

坑 4 · sample.mp4 不支持 Range 请求

  • 现象:Chromium 无法在片段内 seek,每循环一次就重下整个文件。
  • 修复 :接口支持 206 Partial Content + Content-Range,并支持 If-None-Match
    返回 304
  • 教训:媒体文件接口必须支持 Range,否则浏览器会退化成「每次重下」。

坑 5 · 聚焦会话:页面刷新被 409 拒绝

  • 现象sessionStorage 里的旧会话让 FocusManager.acquire 判定冲突,墙卡在
    采样循环且不报错
  • 修复 :同一用户 + 同一频道复用会话并刷新 TTL,换频道才移交槽位。

坑 6 · 聚焦会话:每 50 秒重连一次

  • 现象:续期逻辑是「先释放再申请」,导致周期性重新缓冲。
  • 修复 :同会话走「纯 TTL 刷新」,不再重启 LL-HLS。

坑 7 · 一个 ffmpeg 参数让采样全停

  • 现象:采样画面冻结 6 分钟,worker 日志却一片安静。
  • 根因-rw_timeout 在服务器上的 ffmpeg 4.4 对 RTSP 无效 ,直接把每次采样
    搞崩,而且失败不报错
  • 修复 :去掉该参数,改用 asyncio.wait_for(duration + 30s) 加超时,并在失败时打日志。
  • 教训:参数「看起来有效」不代表「真的生效」,静默失败最可怕。

坑 8 · 浏览器解码器是有预算的

  • 现象 :一次性初始化太多 HLS 实例,连主屏也卡在 HAVE_METADATA
  • 根因:Chromium 能同时解码的 MediaSource 数量有限。
  • 修复 :只有进入视口的非聚焦预览 才分配解码器,最多 3 个;移出视口就释放,
    为「主屏 + 缓存接续」预留容量。

坑 9 · 一个没解决的坑:上游信源本身损坏(如实记录)

  • 现象 :某路电视直播源,浏览器截图严重马赛克/灰屏。服务端直接捕获 focus 输出也
    损坏,用独立 ffmpeg 解同一上游同样报错(一次统计 77 条 H.264 error while decoding MB),priority=90 的备用源也有 64 条错误。
  • 结论 :问题定位在上游输入的解码阶段 ,尚未区分是源内容损坏、传输损坏,还是
    与现有 ffmpeg 的兼容性。
  • 我们的坚持不靠调高分辨率、不靠循环旧缓存、不靠忽略错误来假装修好
    没有干净可用的替代源之前,如实说明这是上游问题。
  • 教训 :不是所有 bug 都能修。能定位、能如实上报边界,本身就是工程能力。

10. 经验总结:做「视频 + AI」系统的 8 条实践

  1. 播放和转录共用一条时序 。选中的频道,画面、声音、字幕走同一条链路、同一个
    时钟,才能谈「同步」;多条链路各转各的,字幕永远只能「大概齐」。
  2. 区分「能拉到流」和「真的在播」 。HTTP 200 ≠ 有画面。验收要看 readyState
    解码帧是否增长、音频是否推进。
  3. 把「展示」和「采集」解耦 。多路墙别硬并行拉流;用低码率采样回放 + 单路
    高清聚焦,稳定性会高一个数量级。
  4. 给浏览器解码器做预算 。多路视频页面一定要有「只在视口内分配解码器」的策略,
    否则主屏会被拖死。
  5. 低延迟 HLS 别贪短 。保留片段数过少会加剧驱逐失败;靠 lowLatencyMode +
    合理的 liveMaxLatencyDuration,而不是拼命缩短窗口。
  6. 字幕容忍「迟到」,但拒绝「错位」 。慢翻译可以归档、可以显示等待,但绝不能
    迟到后覆盖下一段音频的字幕。
  7. 用真实浏览器做验收 。Chromium + CDP(--remote-debugging-port)驱动真实点击、
    Network 事件、读 getVideoPlaybackQuality(),比看服务端日志有效一个数量级。
  8. 诚实标注边界 。片段级对齐就写片段级,不宣称毫秒级;上游损坏就写上游损坏,
    不用「循环旧视频」掩盖断流。

11. 结语

一个「多路流媒体 + AI 转录翻译」系统,真正的难点从来不在「能不能播」,而在

稳定性、同步性和诚实度

  • 播放层 :用 hls.js + MediaMTX + ffmpeg 这套开源组合,能把多路直播收进来、
    以极低成本在浏览器里动起来;
  • 转录层 :用实时 ASR(如 Qwen-Audio Realtime)+ 大模型翻译 ,能快速拿到
    高质量中文输出;
  • 而真正的工程价值 ,在于把两者粘起来、让字幕跟着画面走,并且如实告诉用户
    哪里还没解决

如果你正在做「视频 + AI」方向,希望这份复盘能帮你少踩几个坑。


参考

播放与流媒体

语音识别与翻译

相关推荐
Niuguangshuo1 小时前
文本-音频时间戳对齐:5 个开源工具实测
算法·开源·音视频
刘广睿1 小时前
视频抽帧做图文笔记:帧选择策略与自动化封面挑选
图像处理·音视频·短视频·效率工具·python3.11
世岩清上2 小时前
一次性完工的数字展厅,如何预留后期内容更新空间?
大数据·网络·人工智能·音视频·展厅改造
揽秀亭长2 小时前
如何提取视频中的脚本内容?常见方法与工具对比
人工智能·音视频
AI直播技术杂谈2 小时前
多路数字人直播的算力调度方案对比:单卡、多卡与分布式
ai·音视频
m0_6145235510 小时前
普通视频怎么做多场景一镜到底:路线设计、逐段衔接与整体验收
人工智能·音视频
Pocker_Spades_A15 小时前
视频不用再一张张截图:ClipSketch AI 把关键画面转成漫画,还能顺手生成文案
人工智能·音视频
星辰徐哥15 小时前
本地视频预览别只自己看:把Remotion动效项目发给客户远程验收
docker·ai·node.js·html·音视频·react·remotion
镜像视界(浙江)科技有限公司15 小时前
《视频孪生之上:二维展示终结,三维空间计算重构城市逻辑》——跨摄像连续表达 × 三角测量厘米级定位 × 动态轨迹建模,构建新一代城市空间
大数据·人工智能·算法·矩阵·音视频·空间计算