Я не могу заставить vImage (Accelerate Framework) преобразовать 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,
&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
Но для меня это не имеет никакого смысла. Как моя высота Cb может быть любой, кроме половины моей высоты Yp (которая совпадает с моей высотой целевого RGB), когда у меня есть данные 4:2:0? (То же для ширины?) Что, черт возьми, я делаю не так? Я собираюсь сделать и другие преобразования (4:4:4, 4:2:2 и т. Д.), Поэтому любые разъяснения по этим API будут очень благодарны. Кроме того, каково мое расположение для этих преобразований? Выше я использую kCVImageBufferChromaLocation_Center. Это правильно?
Немного новой информации: с момента публикации я увидел вопиющую ошибку, но ее исправление не помогло. Обратите внимание, что в приведенном выше случае vImageConvert_AnyToAny я инициализировал целевой буфер только шириной изображения вместо ширины 4*, чтобы освободить место для 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.
1 ответ
Хорошо, я понял - отчасти ошибка пользователя, отчасти ошибка Apple. Я неправильно думал о ширине и высоте vImage_Buffer. Например, выходной буфер, который я указал как 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 перед вызовом кода нижнего уровня, который выполняет эту работу.
Я работал над ошибкой vImageConvert_AnyToAny, просто создавая слишком большие входные буферы и заполняя только данные Cb и Cr в верхнем левом квадранте. Данные были найдены там во время конвертации просто отлично. Я сделал эти слишком большие буферы с помощью vImageBuffer_Init(), где Apple выделила слишком большой malloc, который тратится зря. Я не пробовал делать vImage_Buffer вручную - лгал о размере и выделял только ту память, которая мне нужна. Это может сработать, или, возможно, Apple уползет в сорняки, доверяя ширине и высоте. Однако если вы сделаете его вручную, вам лучше рассказать правду о rowBytes.
Я собираюсь оставить этот ответ ненадолго, прежде чем отмечать его правильным, надеясь, что кто-то в Apple увидит это, исправит ошибку и, возможно, вдохновится на улучшение документации для тех из нас, кто спотыкается.