Визуализация кадра камеры iPhone 4 YpCbCr в текстуру OpenGL ES 2.0 в iOS 4.3 - PullRequest
7 голосов
/ 22 июня 2011

Я пытаюсь отобразить родное плоское изображение в текстуру OpenGL ES 2.0 в iOS 4.3 на iPhone 4. Тем не менее, текстура сглаживает все черное.Моя камера настроена так:

[videoOutput setVideoSettings:[NSDictionary dictionaryWithObject:[NSNumber numberWithInt:kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange] 
                                                          forKey:(id)kCVPixelBufferPixelFormatTypeKey]];

, и я передаю данные пикселей в мою текстуру следующим образом:

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, bufferWidth, bufferHeight, 0, GL_RGB_422_APPLE, GL_UNSIGNED_SHORT_8_8_REV_APPLE, CVPixelBufferGetBaseAddress(cameraFrame));

Мои шейдеры фреймов:

varying highp vec2 textureCoordinate;

uniform sampler2D videoFrame; 

void main() { 
    lowp vec4 color; 
    color = texture2D(videoFrame, textureCoordinate); 
    lowp vec3 convertedColor = vec3(-0.87075, 0.52975, -1.08175); 
    convertedColor += 1.164 * color.g; // Y
    convertedColor += vec3(0.0, -0.391, 2.018) * color.b; // U
    convertedColor += vec3(1.596, -0.813, 0.0) * color.r; // V
    gl_FragColor = vec4(convertedColor, 1.0); 
} 

и мой вершинный шейдер -

attribute vec4 position;
attribute vec4 inputTextureCoordinate;

varying vec2 textureCoordinate;

void main()
{
    gl_Position = position;
    textureCoordinate = inputTextureCoordinate.xy;
}

Это прекрасно работает, когда я работаю с изображением BGRA, а мой фрагментный шейдер только

gl_FragColor = texture2D(videoFrame, textureCoordinate);

Что если что-то не так?Я здесь скучаю?Спасибо!

Ответы [ 2 ]

10 голосов
/ 28 июня 2011

OK. У нас есть рабочий успех здесь. Ключ передавал Y и UV как две отдельные текстуры фрагментному шейдеру. Вот последний шейдер:

#ifdef GL_ES
precision mediump float;
#endif

varying vec2 textureCoordinate;

uniform sampler2D videoFrame; 
uniform sampler2D videoFrameUV;

const mat3 yuv2rgb = mat3(
                            1, 0, 1.2802,
                            1, -0.214821, -0.380589,
                            1, 2.127982, 0
                            );

void main() {    
    vec3 yuv = vec3(
                    1.1643 * (texture2D(videoFrame, textureCoordinate).r - 0.0625),
                    texture2D(videoFrameUV, textureCoordinate).r - 0.5,
                    texture2D(videoFrameUV, textureCoordinate).a - 0.5
                    );
    vec3 rgb = yuv * yuv2rgb;

    gl_FragColor = vec4(rgb, 1.0);
} 

Вам нужно будет создать свои текстуры так:

int bufferHeight = CVPixelBufferGetHeight(cameraFrame);
int bufferWidth = CVPixelBufferGetWidth(cameraFrame);
glBindTexture(GL_TEXTURE_2D, videoFrameTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, bufferWidth, bufferHeight, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, CVPixelBufferGetBaseAddressOfPlane(cameraFrame, 0));

glBindTexture(GL_TEXTURE_2D, videoFrameTextureUV);
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, bufferWidth/2, bufferHeight/2, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, CVPixelBufferGetBaseAddressOfPlane(cameraFrame, 1));

и затем передайте их так:

glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, videoFrameTexture);

glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, videoFrameTextureUV);

glActiveTexture(GL_TEXTURE0);
glUniform1i(videoFrameUniform, 0);
glUniform1i(videoFrameUniformUV, 1);

Мальчик, я с облегчением!

P.S. Значения для матрицы yuv2rgb отсюда http://en.wikipedia.org/wiki/YUV, и я скопировал код отсюда http://www.ogre3d.org/forums/viewtopic.php?f=5&t=25877, чтобы выяснить, как получить правильные значения YUV для начала.

2 голосов
/ 22 июня 2011

Ваш код пытается преобразовать 32-битный цвет в 444 с лишним байта в RGBA. Это не будет работать слишком хорошо. Я не знаю ничего, что выводит "ЮВА", например.

Кроме того, я думаю, возвращенный альфа-канал равен 0 для выхода камеры BGRA, а не 1, поэтому я не уверен, почему он работает (IIRC для преобразования его в CGImage необходимо использовать AlphaNoneSkipLast) .

Вывод 420 "bi planar" структурирован примерно так:

  1. Заголовок, сообщающий вам, где находятся самолеты (используется CVPixelBufferGetBaseAddressOfPlane() и его друзьями)
  2. Плоскость Y: высота и время; bytes_per_row_1 & times; 1 байт
  3. Плоскость Cb, Cr: высота / 2 & times; bytes_per_row_2 & times; 2 байта (2 байта на блок 2x2).

bytes_per_row_1 - приблизительно width, а bytes_per_row_2 - приблизительно width/2, но вы захотите использовать CVPixelBufferGetBytesPerRowOfPlane () для устойчивости (вы также можете проверить результаты ..GetHeightOfPlane и ... GetWidthOfPlane).

Возможно, вам повезет, если рассматривать ее как 1-компонентную текстуру width * height и 2-компонентную текстуру width / 2 * height / 2. Вы, вероятно, захотите проверить количество байтов на строку и обработать случай, когда это не просто ширина * количество компонентов (хотя это, вероятно, верно для большинства режимов видео). AIUI, вы также захотите очистить контекст GL перед вызовом CVPixelBufferUnlockBaseAddress ().

Кроме того, вы можете скопировать все это в память в ожидаемый формат (оптимизация этого цикла может быть немного сложнее). Преимущество копирования заключается в том, что вам не нужно беспокоиться о доступе к памяти после того, как вы разблокировали пиксельный буфер.

...