xcode 解码 H264 VideoToolkit API 失败,VTDecompressionSessionCreate 中出现错误 -8971

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/24039345/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-15 05:00:15  来源:igfitidea点击:

Decoding H264 VideoToolkit API fails with Error -8971 in VTDecompressionSessionCreate

iosxcodemacosh.264video-processing

提问by lowtraxx

I am trying to write a Video decoder using the Hardware supported Video Toolkit Decoder. But if I try to initialize the decoding session like in the example posted below, I get the error -8971 while calling VTDecompressionSessionCreate. Can anyone tell me what I am doing wrong here?

我正在尝试使用硬件支持的视频工具包解码器编写视频解码器。但是,如果我尝试像下面发布的示例一样初始化解码会话,则在调用 VTDecompressionSessionCreate 时会收到错误 -8971。谁能告诉我我在这里做错了什么?

Thank you and best regards,

感谢你并致以真诚的问候,

Oliver

奥利弗

OSStatus status;

int tmpWidth = sps.EncodedWidth();
int tmpHeight = sps.EncodedHeight();
NSLog(@"Got new Width and Height from SPS - %dx%d", tmpWidth, tmpHeight);

const VTDecompressionOutputCallbackRecord callback = { ReceivedDecompressedFrame, self };
status = CMVideoFormatDescriptionCreate(NULL,
                                       kCMVideoCodecType_H264,
                                       tmpWidth,
                                       tmpHeight,
                                       NULL,
                                       &decoderFormatDescription);

if (status == noErr)
{
    // Set the pixel attributes for the destination buffer
    CFMutableDictionaryRef destinationPixelBufferAttributes = CFDictionaryCreateMutable(
                                                                 NULL, // CFAllocatorRef allocator
                                                                 0,    // CFIndex capacity
                                                                 &kCFTypeDictionaryKeyCallBacks, 
                                                                 &kCFTypeDictionaryValueCallBacks);

    SInt32 destinationPixelType = kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange;
    CFDictionarySetValue(destinationPixelBufferAttributes,kCVPixelBufferPixelFormatTypeKey, CFNumberCreate(NULL, kCFNumberSInt32Type, &destinationPixelType));
    CFDictionarySetValue(destinationPixelBufferAttributes,kCVPixelBufferWidthKey, CFNumberCreate(NULL, kCFNumberSInt32Type, &tmpWidth));
    CFDictionarySetValue(destinationPixelBufferAttributes, kCVPixelBufferHeightKey, CFNumberCreate(NULL, kCFNumberSInt32Type, &tmpHeight));
    CFDictionarySetValue(destinationPixelBufferAttributes, kCVPixelBufferOpenGLCompatibilityKey, kCFBooleanTrue);

    // Set the Decoder Parameters
    CFMutableDictionaryRef decoderParameters = CFDictionaryCreateMutable(
                                                        NULL, // CFAllocatorRef allocator
                                                        0,    // CFIndex capacity
                                                        &kCFTypeDictionaryKeyCallBacks,
                                                        &kCFTypeDictionaryValueCallBacks);

    CFDictionarySetValue(decoderParameters,kVTDecompressionPropertyKey_RealTime, kCFBooleanTrue);

    // Create the decompression session
    // Throws Error -8971 (codecExtensionNotFoundErr)
    status = VTDecompressionSessionCreate(NULL, decoderFormatDescription, decoderParameters, destinationPixelBufferAttributes, &callback, &decoderDecompressionSession);

    // release the dictionaries
    CFRelease(destinationPixelBufferAttributes);
    CFRelease(decoderParameters);

    // Check the Status
    if(status != noErr)
    {
        NSLog(@"Error %d while creating Video Decompression Session.", (int)status);
        continue;
    }
}
else
{
    NSLog(@"Error %d while creating Video Format Descripttion.", (int)status);
    continue;
}

采纳答案by lowtraxx

You need to create the CMFormatDescriptionRef from your SPS and PPS like

您需要从 SPS 和 PPS 中创建 CMFormatDescriptionRef,例如

CMFormatDescriptionRef decoderFormatDescription;
const uint8_t* const parameterSetPointers[2] = { (const uint8_t*)[currentSps bytes], (const uint8_t*)[currentPps bytes] };
const size_t parameterSetSizes[2] = { [currentSps length], [currentPps length] };
status = CMVideoFormatDescriptionCreateFromH264ParameterSets(NULL,
                                                             2,
                                                             parameterSetPointers,
                                                             parameterSetSizes,
                                                             4,
                                                             &decoderFormatDescription);

Also if you are getting your Video Data in Annex-B format you need to remove the start code and replace it with the 4-Byte size information for the decoder to recognize it as avcc formated (Thats what the 5th parameter to CMVideoFormatDescriptionCreateFromH264ParameterSets is for).

此外,如果您以 Annex-B 格式获取视频数据,您需要删除起始代码并将其替换为 4 字节大小信息,以便解码器将其识别为 avcc 格式(这就是 CMVideoFormatDescriptionCreateFromH264ParameterSets 的第 5 个参数的用途) .

回答by focs

I also stumbled with kVTVideoDecoderBadDataErr. In my case I was changing the header 0x00000001with the size of the NAL package which included the 4 bytes of this header, that was the reason. I changed the size to not include these 4 bytes (frame_size = sizeof(NAL) - 4). This size should be encoded in big-endian.

我也偶然发现了kVTVideoDecoderBadDataErr. 就我而言,我正在0x00000001使用 NAL 包的大小更改标头,其中包括该标头的 4 个字节,这就是原因。我将大小更改为不包括这 4 个字节 ( frame_size = sizeof(NAL) - 4)。这个大小应该以大端编码。

回答by David Collins

@Joride

@乔里德

refer to http://www.szatmary.org/blog/25

参考http://www.szatmary.org/blog/25

It explains that the header (first) byte of each buffer within a NALU describes the buffer's type. You need to mask off these bits and compare them to the table provided. Note the comment about the bit fields. You need to mask the byte with 0x1f to the type value.

它解释了 NALU 中每个缓冲区的头(第一个)字节描述了缓冲区的类型。您需要屏蔽这些位并将它们与提供的表格进行比较。请注意有关位域的注释。您需要将带有 0x1f 的字节屏蔽为类型值。