簡體   English   中英

在iOS 4.3中將YpCbCr iPhone 4相機框架渲染為OpenGL ES 2.0紋理

[英]Render YpCbCr iPhone 4 Camera Frame to an OpenGL ES 2.0 Texture in iOS 4.3

我正試圖在iPhone 4上的iOS 4.3中將原生平面圖像渲染為OpenGL ES 2.0紋理。然而,紋理全部變黑。 我的相機配置如下:

[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));

我的fragement着色器是:

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);

如果我在這里遺失了什么? 謝謝!

好。 我們在這里取得了成功。 關鍵是將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);

男孩,我松了一口氣!

PS yuv2rgb矩陣的值來自http://en.wikipedia.org/wiki/YUV ,我從這里復制代碼http://www.ogre3d.org/forums/viewtopic.php?f=5&t=25877找出如何獲得正確的YUV值。

您的代碼似乎嘗試將444-plus-unused-byte中的32位顏色轉換為RGBA。 這不會太好用。 我不知道任何輸出“YUVA”的東西。

此外,我認為返回的alpha通道對於BGRA相機輸出為0,而不是1,所以我不確定它為什么會起作用(IIRC將其轉換為CGImage,您需要使用AlphaNoneSkipLast)。

420“雙平面”輸出結構如下:

  1. 一個標題告訴你飛機的位置(由CVPixelBufferGetBaseAddressOfPlane()和朋友使用)
  2. Y平面:高度×bytes_per_row_1×1字節
  3. Cb,Cr平面:高度/ 2×bytes_per_row_2×2字節(每2x2塊2個字節)。

bytes_per_row_1大約是widthbytes_per_row_2大約是width/2 ,但是你需要使用CVPixelBufferGetBytesPerRowOfPlane()來獲得健壯性(你也可以查看..GetHeightOfPlane和... GetWidthOfPlane的結果)。

您可以將它視為單組分寬*高紋理和雙組分寬度/ 2 *高/ 2紋理。 您可能希望檢查每行字節數並處理不僅僅是寬度*組件數的情況(盡管對於大多數視頻模式可能都是如此)。 AIUI,您還需要在調用CVPixelBufferUnlockBaseAddress()之前刷新GL上下文。

或者,您可以將其全部復制到內存中以達到預期的格式(優化此循環可能有點棘手)。 復制的優點是,在解鎖像素緩沖區后,您無需擔心訪問內存的問題。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM