Пиксельные форматы, 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, но есть два свободно доступных примера кода:

GLCameraRipple и RosyWriter

Сами заголовочные файлы содержат хорошую документацию, и 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. Работает, только что попробовал сам.

Другие вопросы по тегам