菜鸟教程小白 发表于 2022-12-12 17:56:00

ios - iOS App的OPENGL快速录屏


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

<p>我正在使用此答案 (<a href="https://stackoverflow.com/a/9704392/707773" rel="noreferrer noopener nofollow">https://stackoverflow.com/a/9704392/707773</a>) 中的代码描述的“渲染到纹理”方法来捕获屏幕并为 cocos2d 游戏编写视频。我所做的一项修改是,当我调用 <code>CVOpenGLESTextureCacheCreate</code> 时,我使用的是 <code></code> 而不是 <code>[ context]</code> </p>

<p>它确实录制了视频,但有两个问题</p>

<ol>
<li><p>当它开始录制时,屏幕上的新绘图就会停止。我也希望应用程序继续在屏幕上绘图。由于我是 OpenGL ES 的新手,我对帧缓冲区对象等没有深入的了解,所以我很难弄清楚如何同时在屏幕上绘制和捕获屏幕。我会欣赏这方面的代码示例。</p></li>
<li><p>录制的视频被上下翻转。我怎样才能让它朝着正确的方向前进?</p></li>
</ol>

<p>之前我也考虑过 <code>glReadPixels</code> 方法,但它有性能缺陷。</p>

<p>更新:我还想到了一些想法。根据我的一点了解,</p>

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

<p>更新:
主图</p>

<pre><code>// ----- Display the keyframe -----
Texture* t = augmentationTexture;
frameTextureID = ;
aspectRatio = (float) / (float);
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&#39;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.targetPositiveDimensions.data, &amp;modelViewMatrixVideo.data);
    SampleApplicationUtils :: scalePoseMatrix(videoData.targetPositiveDimensions.data, videoData.targetPositiveDimensions.data * aspectRatio, videoData.targetPositiveDimensions.data, &amp;modelViewMatrixVideo.data);

    SampleApplicationUtils::multiplyMatrix(projMatrix.data, &amp;modelViewMatrixVideo.data, &amp;modelViewProjectionVideo.data);

    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*) &amp;modelViewProjectionVideo.data);
    glUniform1i(texSampler2DHandle, 0 /*GL_TEXTURE0*/);
    glDrawElements(GL_TRIANGLES, kNumQuadIndices, GL_UNSIGNED_SHORT, quadIndices);

    glDisableVertexAttribArray(vertexHandle);
    glDisableVertexAttribArray(normalHandle);
    glDisableVertexAttribArray(textureCoordHandle);

    glUseProgram(0);
}
</code></pre>

<p>将视频纹理缓冲区添加到帧中</p>

<pre><code>glBindTexture(, );
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, , 0);
</code></pre></p>
                                    <br><hr><h1><strong>Best Answer-推荐答案</ strong></h1><br>
                                            <p><p>您似乎缺少一些关于这些事情如何工作的知识,并且不可能知道您的问题出在哪里。让我为您分解一些事情,以便您确定您的问题,希望自己解决它,但另外提出另一个问题,其中包含更具体的代码部分,显示哪些有效,哪些无效。</p>

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

<ul>
<li>生成新的帧缓冲区以获取 ID 并绑定(bind)它</li>
<li>生成渲染缓冲区或纹理以获取 ID 并绑定(bind)它</li>
<li>使用 <code>glRenderbufferStorage</code> 或 <code>glTexImage2D</code> 或在 iOS 中设置缓冲区的数据和格式,如果你想将其绑定(bind)到查看你有 <code>renderbufferStorage:fromDrawable :</code> 在 <code>EAGLContext</code> 对象上。 (最后一个可能由一些更高级别的对象完成,例如 <code>GLKView</code>)</li>
<li>使用 <code>glFramebufferRenderbuffer</code> 或 <code>glFramebufferTexture2D</code></li> 将渲染缓冲区附加到帧缓冲区
</ul>

<p>通过这种方式,您可以创建任意数量的帧缓冲区供您绘制。要选择要绘制的缓冲区,您只需绑定(bind)正确的帧缓冲区。</p>

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

<pre><code>GLint defaultFBO;
glGetIntegerv(GL_FRAMEBUFFER_BINDING_OES, &amp;defaultFBO);
</code></pre>

<p>(找到 <a href="https://stackoverflow.com/questions/9746602/getting-default-frame-buffer-id-from-glkview-glkit" rel="noreferrer noopener nofollow">here</a> )
但是您需要确保在绑定(bind)主缓冲区时调用它,因此最好在开始录制之前调用它,这样您就知道它是正确的缓冲区。</p>

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

<ul>
<li>绑定(bind)FBO</li>
<li>绘制场景</li>
<li>处理 FBO 以进行视频录制</li>
<li>绑定(bind)主缓冲区</li>
<li>绑定(bind) FBO 纹理</li>
<li>将绑定(bind)的纹理绘制到主缓冲区</li>
</ul>

<p>还有其他方法,比如</p>

<ul>
<li>从媒体(相机、视频...)获取数据</li>
<li>绑定(bind)FBO</li>
<li>将媒体数据绘制到 FBO</li>
<li>处理 FBO 以进行视频录制</li>
<li>绑定(bind)主缓冲区</li>
<li>将媒体数据绘制到主缓冲区</li>
</ul>

<p>这将绘制两次场景,而不是重复使用 FBO 中纹理中的同一场景。如果你在绘图上没有做任何繁重的操作,这些基本相同,但最好还是使用第一个。</p></p>
                                   
                                                <p style="font-size: 20px;">关于ios - iOS App的OPENGL快速录屏,我们在Stack Overflow上找到一个类似的问题:
                                                        <a href="https://stackoverflow.com/questions/34427881/" rel="noreferrer noopener nofollow" style="color: red;">
                                                                https://stackoverflow.com/questions/34427881/
                                                        </a>
                                                </p>
                                       
页: [1]
查看完整版本: ios - iOS App的OPENGL快速录屏