Преобразование RGBA в ARGB (glReadPixels -> AVAssetWriter) - PullRequest
3 голосов
/ 07 января 2012

Я хочу записать изображения, отрисованные с помощью OpenGL, в кинофайл с помощью AVAssetWriter. Возникает проблема, что единственный способ получить доступ к пикселям из кадрового буфера OpenGL - это использовать glReadPixels, который поддерживает только RGBA-пиксельный формат на iOS. Но AVAssetWriter не поддерживает этот формат. Здесь я могу использовать ARGB или BGRA. Поскольку альфа-значения можно игнорировать, я пришел к выводу, что самым быстрым способом преобразования RGBA в ARGB будет дать glReadPixels буфер, смещенный на один байт:

UInt8 *buffer = malloc(width*height*4+1);
glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer+1);

Проблема в том, что вызов glReadPixels приводит к сбою EXC_BAD_ACCESS. Если я не сдвигаю буфер на один байт, он работает отлично (но, очевидно, с неправильными цветами в видеофайле). В чем здесь проблема?

Ответы [ 5 ]

5 голосов
/ 07 января 2012

Я пришел к выводу, что самый быстрый способ конвертировать RGBA в ARGB - дать glReadPixels буфер, смещенный на один байт

Это, однако, сместит ваши альфа-значения на 1пиксель также.Вот еще одно предложение:

Рендеринг изображения в текстуру (используя FBO с этой текстурой в качестве цветовой привязки).Затем визуализируем эту текстуру в другой фрейм-буфер с помощью шейдера фрагментов:

#version ...
uniform sampler2D image;
uniform vec2 image_dim;
void main() 
{
    // we want to address texel centers by absolute fragment coordinates, this
    // requires a bit of work (OpenGL-ES SL doesn't provide texelFetch function).
    gl_FragColor.rgba = 
        texture2D(image, vec2( (2*gl_FragCoord.x + 1)/(2*image_dim.y), 
                               (2*gl_FragCoord.y + 1)/(2*image_dim.y) )
        ).argb; // this swizzles RGBA into ARGB order if read into a RGBA buffer
}
1 голос
/ 07 января 2012

Попробуйте позвонить

glPixelStorei(GL_PACK_ALIGNMENT,1) 

до glReadPixels.

Из документов :

GL_PACK_ALIGNMENT

Указываеттребования выравнивания для начала каждой строки пикселей в памяти.Допустимые значения: 1 (выравнивание по байтам), 2 (строки, выровненные по четным номерам байтов), 4 (выравнивание по словам) и 8 (строки начинаются с границ двойного слова).

По умолчанию установлено значение 4 (см. glGet ).Это часто упоминается как нарушитель спокойствия в различных типах * OpenGL * списков , хотя это, как правило, больше связано с эффектами заполнения строк, чем выравниванием по буферу.

В качестве альтернативного подхода, что произойдет, если вы выделите 4 дополнительных байта, сделайте glReadPixels как 4-байтовое выравнивание, начиная с буфера + 4, а затем передайте свой буфер AVAssetWriter + 3 (хотя я не знаю, является ли AVAssetWriter более терпимым к выравниваниювопросы)?

1 голос
/ 07 января 2012

Что произойдет, если вы добавите дополнительные 128 байт в конец буфера?Возможно, что OpenGL пытается заполнить 4/8/16 / etc байтов за раз для производительности и имеет ошибку, когда буфер не выровнен или что-то в этом роде.Это был бы не первый случай, когда оптимизация производительности в OpenGL имела проблемы в крайнем случае:)

0 голосов
/ 07 января 2012

Использование buffer+1 будет означать, что данные записываются не в начале вашей памяти malloc'd, а скорее в один байт, поэтому они будут записываться поверх конца вашей памяти malloc, вызывая сбой.

Если в glReadPixels для iOS будет приниматься только GL_RGBA, то, я думаю, вам придется пройтись и переставить их самостоятельно.

ОБНОВЛЕНИЕ, извините, я пропустил +1 в вашем malloc, StilesCrisis, вероятно, прав насчет причины сбоя.

0 голосов
/ 07 января 2012

Вам нужно будет сдвинуть байты, выполнив memcpy или другую операцию копирования.Изменение указателей оставит их без выравнивания, что может или не может быть в пределах возможностей любого базового оборудования (ширина шины DMA, гранулярность мозаики и т. Д.)

...