我无法让 vImage(Accelerate Framework)将 420Yp8_Cb8_Cr8(平面)转换为 ARGB8888
I can't get vImage (Accelerate Framework) to convert 420Yp8_Cb8_Cr8 (planar) to ARGB8888
我正在尝试将平面 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,
&convertInfo, 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, 0},
kvImagePrintDiagnosticsToConsole,
&error );
vImage_Buffer dest;
error = vImageBuffer_Init( &dest, image_height, image_width, 8, kvImagePrintDiagnosticsToConsole);
error = vImageConvert_AnyToAny( icref, thumbnail_buffers, &dest, (void*)0, kvImagePrintDiagnosticsToConsole); //kvImageGetTempBufferSize
我遇到了同样的错误,但这次我在控制台上打印了以下消息。
<Error>: kvImagePrintDiagnosticsToConsole: vImageConvert_AnyToAny: srcs[1].height must be >= dests[0].height
但这对我来说没有任何意义。当我有 4:2:0 数据时,我的 Cb 高度怎么可能不是我的 Yp 高度的一半(与我的目标 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
的宽度和高度是错误的。例如,我将输出缓冲区指定为 4 * image_width
,每像素 8 位,而它本应简单地设置为 image_width
和每像素 32 位——相同数量的内存,但发送了错误的消息API。我猜那行上的文字“8”让我忘记了那个插槽是什么。我一定学过很多次的教训——说出你的神奇数字。
无论如何,现在是错误部分。使输入和输出缓冲区在宽度、高度、像素深度方面正确固定所有对 low-level vImageConvert_420Yp8_Cb8_Cr8ToARGB8888
和朋友的调用。例如,在平面 YCC 情况下,您的 Cb 和 Cr 缓冲区自然会具有 Yp 平面的一半宽度和一半高度。然而,在 vImageConvert_AnyToAny
的情况下,这些缓冲区导致调用失败并退出——说一些愚蠢的事情,比如我需要我的 Cb 平面与我的 Yp 平面具有相同的尺寸,即使对于 4:2:0。这似乎是 Apple 在调用完成工作的 lower-level 代码之前所做的一些预检中的错误。
我解决了 vImageConvert_AnyToAny
错误,方法是简单地使输入缓冲区太大,并且只填充 top-left 象限中的 Cb 和 Cr 数据。在转换期间在那里找到数据就好了。我用 vImageBuffer_Init()
创建了这些 too-big 缓冲区,其中 Apple 分配了 too-big malloc,这会被浪费掉。我没有尝试手工制作 vImage_Buffer
——只是在大小上撒谎并只分配我需要的内存。这可能会奏效,或者 Apple 可能会相信宽度和高度,然后爬进杂草中。如果你亲手制作了一个,你最好说出关于 rowBytes
的真相。
在将此答案标记为正确之前,我将暂时保留此答案,希望 Apple 的某个人看到此问题并修复该错误,并可能得到启发,为我们这些遇到困难的人改进文档。
我正在尝试将平面 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,
&convertInfo, 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, 0},
kvImagePrintDiagnosticsToConsole,
&error );
vImage_Buffer dest;
error = vImageBuffer_Init( &dest, image_height, image_width, 8, kvImagePrintDiagnosticsToConsole);
error = vImageConvert_AnyToAny( icref, thumbnail_buffers, &dest, (void*)0, kvImagePrintDiagnosticsToConsole); //kvImageGetTempBufferSize
我遇到了同样的错误,但这次我在控制台上打印了以下消息。
<Error>: kvImagePrintDiagnosticsToConsole: vImageConvert_AnyToAny: srcs[1].height must be >= dests[0].height
但这对我来说没有任何意义。当我有 4:2:0 数据时,我的 Cb 高度怎么可能不是我的 Yp 高度的一半(与我的目标 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
的宽度和高度是错误的。例如,我将输出缓冲区指定为 4 * image_width
,每像素 8 位,而它本应简单地设置为 image_width
和每像素 32 位——相同数量的内存,但发送了错误的消息API。我猜那行上的文字“8”让我忘记了那个插槽是什么。我一定学过很多次的教训——说出你的神奇数字。
无论如何,现在是错误部分。使输入和输出缓冲区在宽度、高度、像素深度方面正确固定所有对 low-level vImageConvert_420Yp8_Cb8_Cr8ToARGB8888
和朋友的调用。例如,在平面 YCC 情况下,您的 Cb 和 Cr 缓冲区自然会具有 Yp 平面的一半宽度和一半高度。然而,在 vImageConvert_AnyToAny
的情况下,这些缓冲区导致调用失败并退出——说一些愚蠢的事情,比如我需要我的 Cb 平面与我的 Yp 平面具有相同的尺寸,即使对于 4:2:0。这似乎是 Apple 在调用完成工作的 lower-level 代码之前所做的一些预检中的错误。
我解决了 vImageConvert_AnyToAny
错误,方法是简单地使输入缓冲区太大,并且只填充 top-left 象限中的 Cb 和 Cr 数据。在转换期间在那里找到数据就好了。我用 vImageBuffer_Init()
创建了这些 too-big 缓冲区,其中 Apple 分配了 too-big malloc,这会被浪费掉。我没有尝试手工制作 vImage_Buffer
——只是在大小上撒谎并只分配我需要的内存。这可能会奏效,或者 Apple 可能会相信宽度和高度,然后爬进杂草中。如果你亲手制作了一个,你最好说出关于 rowBytes
的真相。
在将此答案标记为正确之前,我将暂时保留此答案,希望 Apple 的某个人看到此问题并修复该错误,并可能得到启发,为我们这些遇到困难的人改进文档。