OPENGL iOS应用程序的快速屏幕录制

时间:2015-12-23 02:51:04

标签: ios iphone opengl-es

我是OpenGL ES的新手。我正在尝试为iOS应用程序的屏幕录制编写代码,尤其是游戏。

我使用'渲染纹理'使用此答案中的代码(https://stackoverflow.com/a/9704392/707773)描述的方法捕获屏幕并为cocos2d游戏编写视频。我做的一项修改是,当我致电int page = 1; int size = 10 var customers = tx.Customers .Where(x => x.....) .Skip((page - 1) * 10).Take(size) .ToList(); 时,我使用CVOpenGLESTextureCacheCreate代替[EAGLContext currentContext]

它会录制视频,但有两个问题

  1. 开始录制时,屏幕上的新绘图停止。我希望应用程序继续在屏幕上绘图。由于我是OpenGL ES的新手,我对帧缓冲对象等没有深刻理解,因此我很难弄清楚如何同时在屏幕上绘图并捕获屏幕。我会很感激这方面的代码示例。

  2. 录制的视频翻转过来。我怎样才能正确指明它?

  3. 之前我也考虑过[[GPUImageOpenGLESContext sharedImageProcessingOpenGLESContext] context]方法,但这有性能上的缺点。

    更新:还想到了一些想法。根据我的理解,

    我可以简单地将纹理绘制回屏幕,但不知道如何。

    更新: 主要吸引力

    glReadPixels

    将视频纹理缓冲区添加到帧

    // ----- Display the keyframe -----
    Texture* t = augmentationTexture[OBJECT_KEYFRAME_1 + playerIndex];
    frameTextureID = [t textureID];
    aspectRatio = (float)[t height] / (float)[t width];
    texCoords = quadTexCoords;
    
    // Get the current projection matrix
    QCAR::Matrix44F projMatrix = vapp.projectionMatrix;
    
    // If the current status is valid (not NOT_READY or ERROR), render the
    // video quad with the texture we've just selected
    if (NOT_READY != currentStatus) {
        // Convert trackable pose to matrix for use with OpenGL
        QCAR::Matrix44F modelViewMatrixVideo = QCAR::Tool::convertPose2GLMatrix(trackablePose);
        QCAR::Matrix44F modelViewProjectionVideo;
    
        // SampleApplicationUtils::translatePoseMatrix(0.0f, 0.0f, videoData[playerIndex].targetPositiveDimensions.data[0], &modelViewMatrixVideo.data[0]);
        SampleApplicationUtils :: scalePoseMatrix(videoData[playerIndex].targetPositiveDimensions.data[0], videoData[playerIndex].targetPositiveDimensions.data[0] * aspectRatio, videoData[playerIndex].targetPositiveDimensions.data[0], &modelViewMatrixVideo.data[0]);
    
        SampleApplicationUtils::multiplyMatrix(projMatrix.data, &modelViewMatrixVideo.data[0], &modelViewProjectionVideo.data[0]);
    
        glUseProgram(shaderProgramID);
    
        glVertexAttribPointer(vertexHandle, 3, GL_FLOAT, GL_FALSE, 0, quadVertices);
        glVertexAttribPointer(normalHandle, 3, GL_FLOAT, GL_FALSE, 0, quadNormals);
        glVertexAttribPointer(textureCoordHandle, 2, GL_FLOAT, GL_FALSE, 0, texCoords);
    
        glEnableVertexAttribArray(vertexHandle);
        glEnableVertexAttribArray(normalHandle);
        glEnableVertexAttribArray(textureCoordHandle);
    
        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_2D, frameTextureID);
        glUniformMatrix4fv(mvpMatrixHandle, 1, GL_FALSE, (GLfloat*) &modelViewProjectionVideo.data[0]);
        glUniform1i(texSampler2DHandle, 0 /*GL_TEXTURE0*/);
        glDrawElements(GL_TRIANGLES, kNumQuadIndices, GL_UNSIGNED_SHORT, quadIndices);
    
        glDisableVertexAttribArray(vertexHandle);
        glDisableVertexAttribArray(normalHandle);
        glDisableVertexAttribArray(textureCoordHandle);
    
        glUseProgram(0);
    }
    

1 个答案:

答案 0 :(得分:2)

您似乎缺少一些关于这些事情如何运作的知识,并且无法知道您的问题所在。让我为你分解一些事情,以便你可以找出你的问题,希望自己修复它,但另外问一些代码更具体的代码,显示什么是有效的,什么不是。

因此,从帧缓冲区开始,此对象是其他缓冲区的容器,在您的情况下可能是纹理和渲染缓冲区。通过绑定特定的帧缓冲区,您将告诉GPU绘制到连接到此帧缓冲区的缓冲区。最常见的附件是颜色,深度和模板缓冲区。最常见的是,创建新帧缓冲区的过程如下所示:

  • 生成新的帧缓冲区以获取ID并将其绑定
  • 生成渲染缓冲区或纹理以获取ID并将其绑定
  • 使用glRenderbufferStorageglTexImage2D或在iOS中设置缓冲区的数据和格式,如果要将其绑定到renderbufferStorage:fromDrawable:上的EAGLContext宾语。 (最后一个可能由某些更高级别的对象完成,例如GLKView
  • 使用glFramebufferRenderbufferglFramebufferTexture2D
  • 将渲染缓冲区附加到帧缓冲区

这样您可以创建任意数量的帧缓冲区。要选择要绘制到哪个缓冲区,只需要绑定正确的帧缓冲区。

通常我们将帧缓冲区分为主帧缓冲区和帧缓冲区对象(FBO)。主框架缓冲区是代表您的屏幕并且ID为0的框架缓冲区,因此在大多数平台中,您可以简单地绑定0索引缓冲区以继续绘制到主屏幕/视图。但是在iOS上,这是非常重要的,从您的角度来看,没有主框架缓冲区这样的东西。您需要保存通过renderbufferStorage:fromDrawable:生成的渲染缓冲区的ID,如果这不在您的代码中(您使用的是更高级别的工具),则需要通过调用<向GPU询问缓冲区ID / p>

GLint defaultFBO;
glGetIntegerv(GL_FRAMEBUFFER_BINDING_OES, &defaultFBO);

(找到here) 但是你需要确保在绑定主缓冲区时调用它,所以最好在开始录制之前,因此你知道它是正确的缓冲区。

然后FBO是任何其他不是主要的帧缓冲区。它也被称为屏幕外帧缓冲区。这些通常用于后处理或预处理。在您的情况下,您可以使用一个将像素绘制到纹理数据中,CPU可以使用您提供的链接中描述的纹理缓存轻松访问这些数据。所以现在你有至少2个缓冲区,主缓冲区和屏幕外缓冲区。屏幕外缓冲区将具有纹理,然后可以将其重新绘制到主缓冲区。现在你的绘制基本管道应该是这样的:

  • 绑定FBO
  • 绘制场景
  • 处理视频录制的FBO
  • 绑定主缓冲区
  • 绑定FBO纹理
  • 将绑定纹理绘制到主缓冲区

还有其他方法,例如

  • 从媒体获取数据(相机,视频......)
  • 绑定FBO
  • 将媒体数据绘制到FBO
  • 处理视频录制的FBO
  • 绑定主缓冲区
  • 将媒体数据绘制到主缓冲区

这将绘制场景两次,而不是重复使用FBO中纹理的相同场景。如果你没有在绘图上做任何繁重的操作,这些操作基本相同,但最好还是使用第一个。