Как преобразовать в 16-битный формат пикселей для использования в OpenGL ES 2.0 при чтении кадров из видео (AV Foundation) - PullRequest
1 голос
/ 25 мая 2011

Я использую OpenGL , чтобы выполнить некоторую обработку изображения для каждого кадра видео 1280x720 QuickTime. Затем кадры считываются и из них создается новое видео. Проблема заключается в большом количестве данных, которые необходимо передать в OpenGL (с использованием glTexImage2D и glReadPixels ), что приводит к очень медленному процессу.

В настоящее время я использую kCVPixelFormatType_32BGRA в качестве формата пикселей для моего AVAssetReaderTrackOutput экземпляра. Чтобы уменьшить потребление времени, я бы хотел использовать 16-битный формат пикселей. К сожалению, переход на такой формат дает мне пустые кадры при вызове метода AVAssetReaderTrackOutput copyNextSampleBuffer . У кого-нибудь есть опыт использования 16-битного пиксельного формата в AV Foundation?

Если я не могу заставить AV Foundation изменить для меня формат, я полагаю, я мог бы конвертировать из 32-битного в 16-битный «вручную», возможно, используя инструкции NEON? Любая помощь приветствуется.

1 Ответ

1 голос
/ 25 мая 2011

Еще одна ревизия, и теперь это вики сообщества, потому что я сделал так много ошибок, отвечая на этот вопрос в одиночку, что это имеет смысл.

Хотя CoreGraphics prima facie сможет выполнять от 32 до 16 битДля преобразования, использующего что-то вроде следующего кода, вместо этого он сообщает, что «4 целых бита / компонент; 16 бит / пиксель; 3-компонентное цветовое пространство; kCGImageAlphaPremultipliedLast» - это неподдерживаемая комбинация параметров.Таким образом, кажется, что CoreGraphics не может внутренне постигать изображения 4 бит / канал

CGColorSpaceRef colourSpace = CGColorSpaceCreateDeviceRGB();
CGDataProviderRef dataProvider = CGDataProviderCreateWithData(NULL, buffer, width*height*4, NULL);
CGImageRef inputImage = CGImageCreate(  width, height,
                                        8, 32, width*4, 
                                        colourSpace, 
                                        kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big,
                                        dataProvider,
                                        NULL, NO,
                                        kCGRenderingIntentDefault);
CGDataProviderRelease(dataProvider);

unsigned char *outputImage = (unsigned char *)malloc(width*height*2);
CGContextRef targetContext = CGBitmapContextCreate( outputImage,
                                                    width, height,
                                                    4, width*2,
                                                    colourSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
CGContextDrawImage(targetContext, CGRectMake(0, 0, width, height), inputImage);

/* uplopad outputImage to OpenGL here! */

CGContextRelease(targetContext);
CGImageRelease(inputImage);
CGColorSpaceRelease(colourSpace);
free(outputImage);

Тем не менее, согласно документации:.

1007

Поддерживаемые форматы пиксельных kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange, kCVPixelFormatType_420YpCbCr8BiPlanarFullRange и kCVPixelFormatType_32BGRA,кроме iPhone 3G, где поддерживаются форматы пикселей kCVPixelFormatType_422YpCbCr8 и kCVPixelFormatType_32BGRA.

Так что для уменьшения размера получаемого изображения вы можете переключиться на цветовое пространство YCbCr.Поскольку буферы возвращаются бипланарно (т. Е. Все компоненты y для всего изображения, а затем все компоненты Cb и Cr в виде отдельного блока), вы можете загрузить их как две отдельные текстуры в OpenGL и рекомбинировать в шейдере, предполагая, что вы счастливыограничивая себя 3GS и выше, и можете позволить себе потратить 2 текстурных блока из 8, доступных на устройствах SGX iOS.

YCbCr - это цветовое пространство, которое представляет цвет как яркость (Y) и цвет (CbCr) отдельно.Опытным путем было показано, что цветовой канал может быть выбран с более низкой частотой, чем яркость, и никто не сможет сказать.Часть «420» в формате пикселей описывает, сколько компонентов Cb и Cr вы получаете для каждых 4 компонентов Y - по сути, это говорит о том, что вы получаете один образец Cb и один из Cr для каждых четырех образцов Y. Следовательно, у вас естьвсего шесть байтов для описания четырех пикселей, для 12 бит / пиксель, а не 24 бит / пиксель в RGB.Это экономит 50% вашего хранилища.

Для целей GL вы потенциально понесли дополнительные расходы, потому что это две загрузки, а не одна.Вам также понадобится использовать три варианта, если вы хотите избежать зависимого чтения текстур, и я думаю, что SGX ограничен восемью из них.

...