You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

iOS通过RTSP传输原始H.265时VTDecompressionSessionDecodeFrame报错误-12909求助

解决VTDecompressionSessionDecodeFrame错误-12909(HEVC实时流解码)

我之前在处理RTSP传输H.265流用VideoToolkit解码的场景里,踩过不少类似的坑。错误码-12909本质上是参数不合法或者解码会话配置出问题导致的,咱们结合你的三个操作步骤逐一排查:

1. 先盯紧CMVideoFormatDescriptionCreateFromHEVCParameterSets的参数

这个函数生成的格式描述是后续解码的基础,参数错了后面全白搭:

  • 参数集数据必须剥离起始码:RTSP流里的H.265 NALU通常带0x000001或0x00000001的起始码,但这个函数要求传入的是裸NALU数据(去掉起始码后的部分)。你要确保parameterSetPointers指向的是剥离起始码后的VPS/SPS/PPS,parameterSetSizes也要对应减去起始码的长度。
  • kNALUHeaderSize要匹配:HEVC的NALU头是1字节(包含nal_unit_type等信息),所以这里必须传1,而不是4(那是起始码的长度)。如果传了4,等于告诉系统“我的参数集前面还有4字节头”,但实际上你已经带了起始码,这就完全乱了。
  • 别跳过错误检查:一定要判断这个函数的返回值是不是noErr,如果格式描述创建失败,后面的会话创建和解码肯定会报错。

举个正确处理参数集的示例:

// 假设从RTSP拿到的VPS/SPS/PPS是带0x000001起始码的NSData
NSData *rawVPS = ...;
NSData *rawSPS = ...;
NSData *rawPPS = ...;

// 剥离起始码(前3字节是0x000001)
const uint8_t *paramSetPointers[] = {
    rawVPS.bytes + 3,
    rawSPS.bytes + 3,
    rawPPS.bytes + 3
};
size_t paramSetSizes[] = {
    rawVPS.length - 3,
    rawSPS.length - 3,
    rawPPS.length - 3
};

CMVideoFormatDescriptionRef formatDesc = NULL;
OSStatus status = CMVideoFormatDescriptionCreateFromHEVCParameterSets(
    kCFAllocatorDefault,
    3,
    paramSetPointers,
    paramSetSizes,
    1, // 这里必须是1,对应HEVC的1字节NALU头
    NULL,
    &formatDesc
);

if (status != noErr) {
    NSLog(@"格式描述创建失败: %d", (int)status);
    // 这里一定要处理错误,别继续往下走
    return;
}

2. 检查VTDecompressionSessionCreate的配置细节

创建解码会话时,几个容易忽略的点:

  • 添加实时流专属配置:你传了NULL作为configuration参数,对于RTSP实时流,最好加上几个关键属性,比如开启实时模式、禁止帧重排序(如果你的流没有B帧的话),否则解码会话可能无法适配实时场景:
NSDictionary *decompConfig = @{
    (__bridge NSString *)kVTDecompressionPropertyKey_RealTime: @YES,
    (__bridge NSString *)kVTDecompressionPropertyKey_AllowFrameReordering: @NO
};

OSStatus status = VTDecompressionSessionCreate(
    NULL,
    formatDesc,
    (__bridge CFDictionaryRef)decompConfig,
    NULL,
    &decompressionCallBack,
    &_decompressionSession
);
  • 回调函数要合规:decompressionCallBack的函数签名必须严格符合VTDecompressionOutputCallback的要求,返回值和参数不能错。如果回调有问题,会话可能创建成功,但解码时直接返回-12909。
  • 确认会话创建成功:同样要检查status是不是noErr,如果_decompressionSession是NULL,解码时必然报错。

3. 解码帧时的最后检查

到了VTDecompressionSessionDecodeFrame这一步,还要确认:

  • 帧数据同样要剥离起始码:和参数集一样,传入的CMSampleBuffer里的H.265帧数据必须是裸NALU,不能带起始码。
  • 解码标志位要合适:实时流一般传kVTDecompressionSessionDecodeFrame_EnableAsynchronousDecompression或者0,不要传那些适合离线解码的标志位。
  • 不要重复使用失效的会话:如果前面的会话因为参数错误创建失败,不要抱着侥幸心理继续调用解码。

快速排查清单

最后给你列个快速检查的清单,能帮你快速定位问题:

  • 每一步操作都打印OSStatus,确认从格式描述到会话创建全是noErr。
  • 用ffmpeg把RTSP流dump成本地文件,用工具查看参数集是否完整、正确(比如ffprobe -show_streams input.h265)。
  • 所有传入VideoToolkit的H.265数据(参数集+帧)都必须剥离起始码。

内容的提问来源于stack exchange,提问作者Mench

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 07:56:55