我无法通过vImage加速框架将420Yp8_Cb8_Cr8平面转换为ARGB8888

问题描述

我正在尝试将Planar YpCbCr转换为RGBA,并且由于错误kvImageRoiLargerThanInputBuffer而失败。 我尝试了两种不同的方法。这是一些代码片段。 注意'thumbnail_buffers + 1'和'thumbnail_buffers + 2'的宽度和高度是'thumbnail_buffers + 0'的一半 因为我正在处理4:2:0,并且具有(1/2)*(1/2)个色度采样,每个色度采样与亮度采样一样多。这无声地失败了 (即使我要求解释(kvImagePrintDiagnosticsToConsole)。

error = vImageConvert_YpCbCrToARGB_GenerateConversion( 
        kvImage_YpCbCrToARGBMatrix_ITU_R_709_2,&fullrange_8bit_clamped_to_fullrange,&convertInfo,kvImage420Yp8_Cb8_Cr8,kvImageARGB8888,kvImagePrintDiagnosticsToConsole);



uint8_t BGRA8888_permuteMap[4] = {3,2,1,0};
uint8_t alpha = 255;

vImage_Buffer dest;
error = vImageConvert_420Yp8_Cb8_Cr8ToARGB8888( 
        thumbnail_buffers + 0,thumbnail_buffers + 1,thumbnail_buffers + 2,&dest,BGRA8888_permuteMap,alpha,kvImagePrintDiagnosticsToConsole //I don't think this flag works here
        );

所以我再次尝试使用vImageConvert_AnyToAny:

vImage_CGImageFormat cg_BGRA8888_format = {
    .bitsPerComponent = 8,.bitsPerPixel = 32,.colorSpace = baseColorspace,.bitmapInfo = 
        kCGImageAlphaNoneskipFirst | kCGBitmapByteOrder32Little,.version = 0,.decode = (CGFloat*)0,.renderingIntent = kCGRenderingIntentDefault
};


vImageCVImageFormatRef vformat = vImageCVImageFormat_Create(
    kCVPixelFormatType_420YpCbCr8Planar,kvImage_ARGBToYpCbCrMatrix_ITU_R_709_2,kCVImageBufferChromaLocation_Center,baseColorspace,0);


vImageConverterRef icref = vImageConverter_CreateForCVTocgImageFormat( 
    vformat,&cg_BGRA8888_format,(CGFloat[]){0,0},kvImagePrintDiagnosticsToConsole,&error );


vImage_Buffer dest;
error = vImageBuffer_Init( &dest,image_height,image_width,8,kvImagePrintDiagnosticsToConsole);
error = vImageConvert_AnyToAny( icref,thumbnail_buffers,(void*)0,kvImagePrintDiagnosticsToConsole); //kvImageGetTempBufferSize

我遇到相同的错误,但是这次我将以下消息打印到控制台。

<Error>: kvImagePrintDiagnosticsToConsole: vImageConvert_AnyToAny: srcs[1].height must be >= dests[0].height

但这对我来说没有任何意义。当我有4:2:0数据时,我的Cb高度除了Yp高度的一半(这与我的dest RGB高度相同)之外,怎么可能呢? (宽度也一样?) 我到底在做什么错?我还将进行其他转换(4:4:4、4:2:2等),因此请进行澄清 在这些API上将不胜感激。此外,这些转换对我的定位是什么?以上我用 kCVImageBufferChromaLocation_Center。正确吗?

一些新信息: 自发布以来,我看到了一个明显的错误,但是修复它并没有帮助。请注意,在上述vImageConvert_AnyToAny情况下,我仅使用图像宽度而不是4 * width初始化目标缓冲区,以便为RGBA腾出空间。那一定是问题所在,对吧?不。

进一步请注意,在vImageConvert_ *情况下,我根本没有初始化目标缓冲区。也修复了该问题,但无济于事。

到目前为止,我已经尝试了六种不同的转换方法,分别从(vImageConvert_ * | vImageConvert_AnyToAny)中选择一种,然后从(kvImage420Yp8_Cb8_Cr8 | kvImage420Yp8_CbCr8 | kvImage444CrYpCb8)中选择一种,每次都输入适当数量的输入缓冲区-仔细检查缓冲区考虑到每个平面每个像素的样本数量。每当我得到:

<Error>: kvImagePrintDiagnosticsToConsole: vImageConvert_AnyToAny: srcs[0].width must be >= dests[0].width

这对我来说毫无意义。如果我的亮度平面是100宽,那么我的RGBA缓冲区应该是400宽。从YCC到RGBA的任何指导或工作代码,将不胜感激。

解决方法

好吧,我知道了-部分用户错误,部分Apple错误。我在想vImage_Buffer的宽度和高度错误。例如,我将输出缓冲区I指定为4 * image_width,每个像素8位,而本来应该只是image_width和每个像素32位-相同的内存量,但向API发送了错误的消息。我猜那行上的文字“ 8”使我无法记住那个插槽是什么。我一定已经学过很多课了-给你的魔术数字命名。

无论如何,现在是错误部分。使输入和输出缓冲区在宽度,高度,像素深度方面正确无误,将所有调用固定为低级vImageConvert_420Yp8_Cb8_Cr8ToARGB8888和朋友。例如,在平面YCC情况下,您的Cb和Cr缓冲区自然会具有Yp平面的一半宽度和一半高度。但是,在vImageConvert_AnyToAny情况下,这些缓冲区导致调用失败并保释-说一些愚蠢的事情,例如,我需要Cb平面具有与Yp平面相同的尺寸,即使是4:2:0。这似乎是Apple在调用完成该工作的较低级代码之前进行的一些预检中的错误。

我通过简单地制作太大的输入缓冲区并仅在左上象限填充Cb和Cr数据来解决vImageConvert_AnyToAny错误。在转换期间在那里找到数据就好了。我使用vImageBuffer_Init()制作了这些太大的缓冲区,其中Apple分配了太大的malloc浪费了。我没有尝试手工制作vImage_Buffer -只是大小和分配我需要的内存。这可能行得通,或者也许苹果会相信宽度和高度而爬入杂草。如果您手工制作一个,则最好说出关于rowBytes的真相。

在将其标记为正确之前,我将稍等一下,希望苹果公司的人能够看到并解决该错误,并可能会得到启发,以改善我们those绊绊的文档。