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



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

我使用的是"渲染到纹理"方法,在这个答案中用代码描述(https://stackoverflow.com/a/9704392/707773)捕捉屏幕并为cocos2d游戏编写视频。我做的一个修改是,当我调用CVOpenGLESTextureCacheCreate时,我使用的是[EAGLContext currentContext]而不是[[GPUImageOpenGLESContext sharedImageProcessingOpenGLESContext] context]

它确实录制了视频,但有两个问题

  1. 当它开始录制时,屏幕上的新绘图就会停止。我希望这个应用程序也能继续在屏幕上绘图。由于我是OpenGL ES的新手,我对帧缓冲区对象等没有深入的了解,所以我很难弄清楚如何同时在屏幕上绘制和捕捉屏幕。我会很欣赏这方面的代码示例。

  2. 录制的视频被倒置。我怎样才能把它指向正确的方向?

以前我也考虑过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);
}

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

glBindTexture([videoWriter textureCacheTarget], [videoWriter textureCacheID]);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, [videoWriter textureCacheID], 0);

您似乎缺少一些关于这些东西如何工作的知识,并且不可能知道问题所在。让我为你分解一些事情,这样你就可以确定你的问题,希望你自己能解决它,但在其他方面,用代码中更具体的部分来问另一个问题,显示哪些有效,哪些无效。

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

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

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

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

GLint defaultFBO;
glGetIntegerv(GL_FRAMEBUFFER_BINDING_OES, &defaultFBO);

(在此处找到)但您需要确保在绑定主缓冲区时调用此函数,因此最好是在开始录制之前,这样您就知道它是正确的缓冲区。

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

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

还有其他方法,如

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

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

最新更新