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
相关产品推荐
相关产品推荐

