【问题标题】:Rendering camera into multiple surfaces - on and off screen将相机渲染到多个表面 - 屏幕上和屏幕外
【发布时间】:2016-06-25 15:17:37
【问题描述】:

我想将相机输出渲染到一个视图中,并偶尔将相机输出帧保存到一个文件中,约束是 - 保存的帧应该与相机相同的分辨率已配置,而视图小于相机输出(保持纵横比)。

基于ContinuousCaptureActivity example in grafika,我认为最好的方法是将相机发送到SurfaceTexture,通常渲染输出并将其缩小为SurfaceView,并在需要时将全帧渲染为不同的Surface 没有视图,以便与常规SurfaceView 渲染并行地从中检索字节缓冲区。

该示例与我的情况非常相似 - 预览呈现为较小尺寸的视图,并且可以通过VideoEncoder 以全分辨率记录和保存。

我用我自己的逻辑替换了VideoEncoder 逻辑,但在尝试提供Surface 时遇到了困难,就像编码器一样,用于全分辨率渲染。如何创建这样的Surface?我的处理方法正确吗?


基于示例的一些代码思路:


surfaceCreated(SurfaceHolder holder) 方法内部(第 350 行):

@Override   // SurfaceHolder.Callback
public void surfaceCreated(SurfaceHolder holder) {
    Log.d(TAG, "surfaceCreated holder=" + holder);

    mEglCore = new EglCore(null, EglCore.FLAG_RECORDABLE);
    mDisplaySurface = new WindowSurface(mEglCore, holder.getSurface(), false);
    mDisplaySurface.makeCurrent();

    mFullFrameBlit = new FullFrameRect(
            new Texture2dProgram(Texture2dProgram.ProgramType.TEXTURE_EXT));
    mTextureId = mFullFrameBlit.createTextureObject();
    mCameraTexture = new SurfaceTexture(mTextureId);
    mCameraTexture.setOnFrameAvailableListener(this);

    Log.d(TAG, "starting camera preview");
    try {
        mCamera.setPreviewTexture(mCameraTexture);
    } catch (IOException ioe) {
        throw new RuntimeException(ioe);
    }
    mCamera.startPreview();


    // *** MY EDIT START ***

    // Encoder creation no longer needed
    //  try {
    //    mCircEncoder = new CircularEncoder(VIDEO_WIDTH, VIDEO_HEIGHT, 6000000,
    //            mCameraPreviewThousandFps / 1000, 7, mHandler);
    //  } catch (IOException ioe) {
    //      throw new RuntimeException(ioe);
    //  }

    mEncoderSurface = new WindowSurface(mEglCore, mCameraTexture); // <-- Crashes with EGL error 0x3003

    // *** MY EDIT END ***

    updateControls();
}

drawFrame() 方法(第 420 行):

private void drawFrame() {
    //Log.d(TAG, "drawFrame");
    if (mEglCore == null) {
        Log.d(TAG, "Skipping drawFrame after shutdown");
        return;
    }

    // Latch the next frame from the camera.
    mDisplaySurface.makeCurrent();
    mCameraTexture.updateTexImage();
    mCameraTexture.getTransformMatrix(mTmpMatrix);

    // Fill the SurfaceView with it.
    SurfaceView sv = (SurfaceView) findViewById(R.id.continuousCapture_surfaceView);
    int viewWidth = sv.getWidth();
    int viewHeight = sv.getHeight();
    GLES20.glViewport(0, 0, viewWidth, viewHeight);
    mFullFrameBlit.drawFrame(mTextureId, mTmpMatrix);
    mDisplaySurface.swapBuffers();

    // *** MY EDIT START ***

    // Send it to the video encoder.
    if (someCondition) {
        mEncoderSurface.makeCurrent();
        GLES20.glViewport(0, 0, VIDEO_WIDTH, VIDEO_HEIGHT);
        mFullFrameBlit.drawFrame(mTextureId, mTmpMatrix);
        mEncoderSurface.swapBuffers();
        try {
            mEncoderSurface.saveFrame(new File(getExternalFilesDir(null), String.valueOf(System.currentTimeMillis()) + ".png"));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    // *** MY EDIT END ***

}

【问题讨论】:

    标签: android android-camera surfaceview glsurfaceview


    【解决方案1】:

    你在正确的轨道上。 SurfaceTexture 只是对来自相机的原始 YUV 帧进行了快速环绕,因此“外部”纹理是原始图像,没有任何变化。您无法直接从外部纹理中读取像素,因此您必须先将其渲染到某个地方。

    最简单的方法是创建一个离屏 pbuffer 表面。 Grafika 的 gles/OffscreenSurface 类正是这样做的(调用eglCreatePbufferSurface())。将该 EGLSurface 设为当前,将纹理渲染到 FullFrameRect 上,然后使用 glReadPixels() 读取帧缓冲区(有关代码,请参阅 EglSurfaceBase#saveFrame())。不要打电话给eglSwapBuffers()

    请注意,您不是为输出创建一个 Android Surface,而只是一个 EGLSurface。 (They're different.)

    【讨论】:

    • 谢谢,它有效。我一直在阅读有关 pbuffers 的文章,据我所知,它们效率不高,与 FBO 或 PBO 一起工作要好得多。在这方面是真的吗?
    • 如果您使用的是常规 2D 纹理,您可以将纹理设置为 FBO 的颜色缓冲区,并直接从中读取像素。但是,不能以这种方式使用“外部”纹理(请记住,相机输出是 YUV,而 GLES 使用 RGB),因此您必须先在某处渲染纹理,然后才能使用 glReadPixels() 读取它。我在 Android 上的经验是,95% 以上的时间都花在压缩和保存图像上,其余大部分时间都花在了 glReadPixels() 上,并且效率低下。 pbuffer 将在噪音中。
    猜你喜欢
    • 1970-01-01
    • 2011-04-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-26
    • 1970-01-01
    • 2012-12-11
    • 1970-01-01
    相关资源
    最近更新 更多