Пиксельные форматы, CVPixelBufferRefs и glReadPixels
Я использую glReadPixels
читать данные в CVPixelBufferRef
, Я использую CVPixelBufferRef
как вход в AVAssetWriter
, К сожалению, форматы пикселей, кажется, не соответствуют друг другу.
Я думаю glReadPixels
возвращает данные пикселей в формате RGBA, в то время как AVAssetWriter
хочет данные пикселей в формате ARGB. Какой лучший способ конвертировать RGBA в ARGB?
Вот что я пробовал до сих пор:
- битовое манипулирование по типу argb = (rgba >> 8) | (RGBA << 24)
- используя
CGImageRef
в качестве промежуточного шага
Битовая манипуляция не сработала, потому что CVPixelBufferRef, похоже, не поддерживает подписки. CGImageRef
промежуточный шаг работает... но я бы предпочел не иметь 50 дополнительных строк кода, которые могли бы потенциально снизить производительность.
5 ответов
Лучше, чем использовать процессор для обмена компонентами, было бы написать простой фрагментный шейдер, чтобы эффективно делать это на GPU при рендеринге изображения.
И лучший лучший способ - полностью удалить этап копирования с помощью iOS5 CoreVideo CVOpenGLESTextureCache, который позволяет выполнять рендеринг прямо в CVPixelBufferRef, исключая вызов glReadPixels.
ps Я почти уверен, что AVAssetWriter хочет данные в формате BGRA (на самом деле он, вероятно, хочет это в yuv, но это другая история).
ОБНОВЛЕНИЕ: что касается ссылок, документ по-прежнему находится под NDA, но есть два свободно доступных примера кода:
Сами заголовочные файлы содержат хорошую документацию, и Mac-эквивалент очень похож (CVOpenGLTextureCache), поэтому у вас должно быть достаточно для начала работы.
Что касается битовых манипуляций, вы можете получить указатель на необработанные данные пиксельного буфера:
CVPixelBufferLockBaseAddress(buffer, 0);
size_t stride = CVPixelBufferGetBytesPerRow(buffer);
char *data = (char *)CVPixelBufferGetBaseAddress(buffer);
for (size_t y = 0; y < CVPixelBufferGetHeight(buffer); ++y) {
uint32_t *pixels = (uint32_t *)(data + stride * y);
for (size_t x = 0; x < CVPixelBufferGetWidth(buffer); ++x)
pixels[x] = (pixels[x] >> 8) | (pixels[x] << 24);
}
CVPixelBufferUnlockBaseAddress(buffer, 0);
Это своего рода выстрел в темноте, но вы пробовали GL_BGRA
за glReadPixels
с kCVPixelFormatType_32BGRA
за CVPixelBufferCreate
?
Я предлагаю это, потому что в Технических вопросах и ответах QA1501 не указан ни один из поддерживаемых форматов RGBA.
glReadPixels(0, 0, width, height, GL_BGRA, GL_UNSIGNED_BYTE, _buffer);
CVPixelBufferRef buffer = NULL;
CVReturn ret = CVPixelBufferCreateWithBytes(kCFAllocatorDefault,_size.width,_size.height,kCVPixelFormatType_32BGRA,glubyte,_size.width*4,NULL,NULL,NULL,&buffer);
glReadPixels(0, 0, w*s, h*s, GL_BGRA, GL_UNSIGNED_BYTE, буфер);
Используйте GL_BGRA в glReadPixels. Работает, только что попробовал сам.