3D 视频怎么解码和显示
3D 播放不是 decoder “解出立体感”。Decoder 只负责还原左右眼内容;立体感来自 renderer 的分眼和显示设备的光路隔离。
先说职责边界
| 阶段 | 负责什么 | 不负责什么 |
|---|---|---|
| demuxer | 读取 packet、track、时间戳、stereo metadata | 不负责立体融合 |
| decoder | 还原压缩码流,输出单帧、双帧或多视图帧 | 不负责最终分眼光路 |
| renderer | 按 layout 切分/采样,处理视口、颜色、同步 | 不负责码流预测语法 |
| display device | 把左右眼画面隔离给两只眼 | 不负责生成左右眼内容 |
| brain | 融合左右眼画面 | 不负责纠正工程错误 |
这张边界表非常重要。很多 3D 播放 bug 的根因是把显示问题误认为解码问题,或者把 metadata 问题误认为片源问题。
1. SBS / TB 单流怎么解码
SBS / TB 对 decoder 来说通常就是普通 2D 视频。它解出一张“大帧”,里面包含左右眼。
| 排布 | decoder 输出 | renderer 动作 |
|---|---|---|
| full-SBS | 一张宽度翻倍的大帧 | 左眼采左半,右眼采右半 |
| half-SBS | 一张普通宽度帧,左右半宽压缩 | 采半区后拉伸回单眼比例 |
| full-TB | 一张高度翻倍的大帧 | 左眼采上半,右眼采下半 |
| half-TB | 一张普通高度帧,上下半高压缩 | 采半区后拉伸回单眼比例 |
这里最关键的是 renderer 的纹理坐标,而不是 decoder。decoder 不知道“这半边属于左眼”,它只知道自己输出了一帧。
2. 多视图编码怎么解码
MVC / MV-HEVC 会在编码层描述视图关系。decoder 需要理解多个 view 之间的依赖。
| 概念 | 含义 | 解码影响 |
|---|---|---|
| base view | 主视图,通常可独立解码 | 兼容 2D 播放更容易 |
| dependent view | 依赖主视图的另一视图 | 必须先有参考视图 |
| inter-view prediction | 跨视图预测 | 节省码率,增加依赖 |
| view id | 视图编号 | 输出时要映射到左/右眼 |
| layer / operating point | 多层级选择 | 能力协商和降级播放 |
这种情况下,decoder 不再只是“吐一张大图”,它可能输出两个 image、两个 layer,或者由系统框架包装成平台特定结构。
3. 重排序和同步比 2D 更敏感
3D 播放必须保证左右眼同一时刻显示。只要一只眼晚一帧,用户就会明显不舒服。
| 队列 | 作用 | 3D 风险 |
|---|---|---|
| demux queue | 缓冲 packet | 左右轨供给不均会失步 |
| decoder input queue | 按 DTS 投喂 | 多视图依赖顺序更复杂 |
| DPB | 保存参考帧 | B 帧和多视图参考增加延迟 |
| output reorder queue | 按 PTS 输出 | 左右眼必须对齐同一 PTS |
| render queue | 等待显示 | 单眼丢帧不能简单继续 |
普通 2D 播放偶尔丢一帧,用户可能只觉得卡一下;3D 如果只丢一只眼,体验会明显崩。
4. Renderer 怎么把一帧变成两眼
从 OpenGL 或通用 GPU 渲染角度看,分眼通常有几种做法。
| 做法 | 说明 | 适用场景 |
|---|---|---|
| two viewport | 同一 framebuffer 左右分区 | 头显、左右并排输出 |
| two render target | 左右眼各一个 texture / surface | XR runtime、复杂后处理 |
| shader crop | fragment shader 采样不同纹理区域 | SBS / TB 最直接 |
| layer output | texture array 或 multiview | 现代 XR 渲染优化 |
| system stereo output | 交给系统或显示设备处理 | 3D TV / 平台播放器 |
SBS/TB 的核心代码思路是:同一张解码纹理,左眼和右眼使用不同 UV 范围。多轨或多视图则可能是左右眼各绑定一张纹理。
5. 分眼显示不只是输出两张图
显示设备必须保证左图只进左眼,右图只进右眼。
| 设备 | 分眼机制 | 工程注意点 |
|---|---|---|
| 红蓝眼镜 | 颜色过滤 | 色彩损失大,左右串扰依赖滤镜 |
| 偏振眼镜 | 偏振方向过滤 | 屏幕/投影和眼镜要匹配 |
| 快门眼镜 | 时间交替 | 刷新率、同步信号、亮度损失 |
| 裸眼 3D | 角度分光 | 观看位置、视点数、分辨率损失 |
| VR 头显 | 物理隔离 | 左右眼矩阵、畸变、IPD 配置 |
如果显示设备串扰严重,renderer 再正确也会重影。
6. 字幕和 UI 也是 3D 问题
3D 内容里字幕不是随便叠在屏幕上。字幕深度如果和画面冲突,会让眼睛很累。
| 元素 | 处理原则 |
|---|---|
| 字幕 | 通常放在零视差或舒适深度区域 |
| UI | 避免强负视差,保持左右一致 |
| 水印 | 两眼位置必须一致或明确设定深度 |
| 画中画 | 需要决定它属于屏幕平面还是空间物体 |
| 交互焦点 | VR/头显里要匹配 gaze 或 controller 深度 |
3D 播放器如果只处理视频,不处理字幕/UI 深度,发布级体验会差一截。
7. 播放异常怎么排查
| 现象 | 优先怀疑 | 检查方向 |
|---|---|---|
| 看到并排两张图 | stereo layout 未识别 | 文件 metadata、用户模式、renderer path |
| 深度反了 | eye order 错 | left/right mapping、metadata、设备模式 |
| 重影 | 分眼失败或串扰 | 显示设备、眼镜同步、偏振方向 |
| 运动发虚 | 左右眼不同步 | PTS 对齐、丢帧策略、双轨队列 |
| 头晕 | 视差过大或垂直错位 | 内容制作、rectification、矩阵 |
| 单眼花屏 | 多视图依赖或单轨损坏 | decoder view output、packet 边界 |
| seek 后左右错位 | keyframe 不对齐 | GOP、sync sample、flush 策略 |
一句话总结
3D 解码负责恢复左右视图,3D 显示负责正确分眼;真正的播放器稳定性来自时间戳、视图顺序、纹理采样、设备分光和字幕 UI 深度的一致处理。