- [症状] 在主线程测试一切正常,一旦放入后台截屏/编码线程,
CoCreateInstance 直接崩溃罢工。
- [根本原因] 硬件编码器和解码器都是纯正的 COM 组件。后台
TThread 启动时默认没有 COM 上下文。
- [破局方案] 必须在编码器和解码器的
Initialize 或线程 Execute 头部强行注入 CoInitialize(nil),并在销毁前调用 CoUninitialize。
2. 底层头文件翻译 Bug 与 absolute 内存欺骗
- [症状] 软硬解自适应时,调用
GetOutputStreamInfo 报 E2033(参数类型不一致)。
- [根本原因] 翻译接口时将 C++ 中的结构体指针错误翻译成了强类型的
out Pointer。传 Pointer 会导致堆栈溢出,传 Record 无法编译。
- [破局方案] 祭出 Delphi 黑魔法
absolute 关键字 (LStreamInfoHack: Pointer absolute LStreamInfo;),骗过编译器类型检查,实现内存级安全写入。
- [症状] 提取画面循环中,内存与显存呈线性爆炸式泄漏。
- [根本原因] 对包含 COM 接口指针(如
pSample)的记录体使用 FillChar 清零,绕过了 Delphi 的垃圾回收,导致旧接口的 _Release 永远不被触发。
- [破局方案] 彻底禁用
FillChar,改为逐项显式赋值 nil,让 Delphi 编译器自动插入减引用计数代码。
💣 二、 硬件编码端 (Encoder) 的生死劫
4. 异步 MFT 的“锁死”机制
- [症状] 成功实例化硬件编码器,但调用
ProcessInput 喂入画面时直接返回错误。
- [根本原因] Windows 8 引入的现代显卡硬件编码器属于异步 MFT。默认情况下它们是被锁死的,拒绝接收任何同步管线的调用。
- [破局方案] 必须通过
IMFAttributes 接口,向编码器写入 MF_TRANSFORM_ASYNC_UNLOCK = 1 的隐藏属性,强行唤醒其异步硬件加速特性。
5. 格式嗅探短路与 C0000005 越界崩溃
- [症状] 喂入 DXGI 截取到的 ARGB32 纹理时,显卡驱动层引发段错误崩溃。
- [根本原因] 编码器输入格式嗅探逻辑使用了
or。显卡驱动总是把 NV12 排在第 0 位,导致嗅探器提前跳出,编码器误以为进来的纹理是 NV12 并按此跨距读取 ARGB32,当场越界。
- [破局方案] 重构嗅探循环为绝对优先权:优先锁定
ARGB32,实现显存零拷贝直通;若无,则将 NV12 作为备胎。
6. 异步状态机死锁: $C00D36B5 与 E_UNEXPECTED
- [症状] 编码主循环卡死,或者
ProcessOutput 频繁报错。
- [根本原因] 硬件编码器是“吞吐极其不平衡”的黑盒。
- 当它吃饱了(返回
$C00D36B5 MF_E_NOTACCEPTING),如果你继续强塞输入,它会直接崩溃;必须立刻转去调用 ProcessOutput 榨干它。
- 当它被榨干了(返回
E_UNEXPECTED 或 MF_E_TRANSFORM_NEED_MORE_INPUT),如果你继续索要输出,它也会报错;此时必须 Break 退出,去抓取下一帧。
- [破局方案] 建立基于
$C00D36B5 (输入满) 和 E_UNEXPECTED (输出空) 的自适应双向榨取循环,精准踩着硬件的状态机节奏跳舞。
7. 幻影组件:被骗去寻找的 Video Processor
- [症状] 试图用
CoCreateInstance 唤醒 VideoProcessorMFT 来做 ARGB32 到 NV12 的前置转换,结果在部分机器上报类未注册。
- [根本原因] 官方 MFT 隐藏在内部注册表中需用
MFTEnumEx 唤醒。但更大的真相是:现代显卡硬件编码器完全支持原生吞入 ARGB32 纹理,我们根本不需要这个软件转换器!
- [破局方案] 卸载转换器累赘,把输入优先级严格锁定为 ARGB32,实现纯硬件直通压缩。
💣 三、 硬件解码端 (Decoder) 的自适应阵痛
8. DXVA 硬件代理的傲慢
- [症状] 使用硬件枚举标志寻找纯硬件 H.264 解码器失败。
- [根本原因] 许多显卡不会注册独立的解码 MFT。必须使用微软官方的“软件代理” (
CLSID_CMSH264DecoderMFT),并在初始化时强行喂给它 DXGIDeviceManager,它才会瞬间觉醒为 DXVA 硬件加速状态。
9. 流格式变更 (Stream Change) 引发的 100% CPU 空转
- [症状] 解码器遇到第一帧 SPS/PPS 时,不吐画面,线程 CPU 飙升至 100%。
- [根本原因] 解码器确认画面尺寸后,返回
$C00D36B3 请求重新握手。若不重新设置输出格式并直接 Continue,就会陷入每秒数千万次的死循环。
- [破局方案] 拦截
$C00D36B3,动态索要最新格式并 SetOutputType,解锁输出阀门。
10. 幽灵降级:DXVA 与 CPU 模式的内存争夺战
- [症状] 解码器偶尔抛出
$80070057 (E_INVALIDARG) 崩溃。
- [根本原因] 解码器可能悄悄从 DXVA 显存模式(自己分配内存)降级为软件模式(要求调用者分配内存)。如果依然传
pSample := nil,直接崩溃。
- [破局方案] 每次提取前调用
GetOutputStreamInfo 嗅探标志位 $00000100,实现硬解传 nil,软解分配 IMFMediaBuffer 的双模无缝切换。
💣 四、 色彩科学与内存对齐 (渲染端)
11. 符号位屠杀:shr 导致的霓虹色块溢出
- [症状] 画面出现刺眼的高亮红蓝杂块。
- [根本原因] YUV 色差(如 U-128)为负数时,Delphi 的
shr 8 执行逻辑右移,连带符号位一起移入数值区,导致颜色数值爆炸,最终被 Clamping 锁死在 255 极值。
- [破局方案] 全部替换为
div 256,交由编译器优化为安全的算术右移 (sar)。
12. 16 像素宏块陷阱 (顶部绿条与画面撕裂)
- [症状] 1080P 画面顶部出现纯绿条,软解模式下画面横向撕裂。
- [根本原因] H.264 底层强制 16 像素对齐(1080 -> 1088)。多出的 8 行 Padding 数据全为 0,UV 平面被全 0 污染,在色彩空间中表现为高亮纯绿。
- [破局方案] 渲染前计算真实的
LAlignedHeight := (FHeight + 15) and (not 15),跳过废弃的 Padding 区域精准采点。
13. 色域坍缩:BT.601 导致的画面发灰
- [症状] 画面缺乏对比度,黑色变深灰,文字边缘有微弱色差。
- [根本原因] H.264 管线输出 16-235 的 Studio 限制色域。强行用老旧的 BT.601 矩阵映射到 PC 显示器,导致色彩断层。
- [破局方案] 重写纯汇编级转换引擎,换装专为 1080P 设计的高清 BT.709 满血扩展矩阵。
💣 五、 流媒体状态管控与防漏
14. 幽灵码流:无限膨胀的 TMemoryStream
- [症状] 编码开启后,主程序 RAM 以每秒数 MB 速度飙升。
- [根本原因] 对象池复用的
TMemoryStream 携带上一帧残余数据,新一帧数据不断 Append,体积滚雪球。
- [破局方案] 在每次编码抓取前强制执行
LBin.Clear;喂给解码器前必须 LBin.Position := 0。
15. H.264 “双煞”:高延迟与开局重影
- [症状] 画面拖动滞后严重,且初次渲染时画面产生严重残影/撕裂。
- [根本原因] 解码器默认开启 B 帧缓冲池导致延迟;首帧如果没有收到完整的 I 帧(关键帧),P 帧差异数据只能糊在空画面上产生重影。
- [破局方案] 1. 编解码双端注入
MF_LOW_LATENCY 属性击穿缓冲池。
2. 首帧联调时,向编码器发送 RequestKeyFrame 指令,强制呼叫 I 帧洗地。
posted @
2026-04-02 16:41
Lonely-妖蛋
阅读(
2)
评论()
收藏
举报