其他分享
首页 > 其他分享> > Android Camera2:即时更改输出表面设置的最佳,最快方法

Android Camera2:即时更改输出表面设置的最佳,最快方法

作者:互联网

我正在制作一个视频流应用程序,使视频比特率适应可用的上行链路带宽,并且我希望它可以动态地更改视频分辨率,以便在较低比特率上不会出现太多压缩失真.尽管通过释放MediaCodec并在CameraCaptureSession上调用abortCaptures()和stopRepeating()然后为新分辨率配置所有内容来完成此工作,但这会在流中造成非常明显的中断-在我的测试中至少需要半秒钟.

当相机本身不支持所需的分辨率时,我使用OpenGL缩放图像,类似于this.我使用两个表面初始化捕获会话-一个用于向用户预览(使用TextureView),一个用于编码器,即直接使用MediaCodec的输入表面或使用我的OpenGL纹理表面.

这可以通过使用MediaCodec.createPersistentInputSurface()来解决,因为我将能够在分辨率变化中重用此缩放器实例,并且无需执行任何捕获操作,因为就相机而言,没有表面变化担心,但仅自API 23起可用,我也需要此实现来支持API 21.

然后还有曲面失效和重新创建的问题.例如,当用户按下“后退”按钮时,活动及其包含的TextureView被破坏,从而使预览图面无效.然后,当用户再次导航到该活动时,将创建一个新的TextureView,我需要开始在其中显示预览,而不会给缩放器/编码器看到的流引入任何滞后.

因此,我的问题通常是:如何在CameraCaptureSession中更改输出表面的集合,或重新创建CameraCaptureSession,同时将尽可能少的延迟引入视频流?

解决方法:

事实证明,实际上包含纹理(包括相机提供帧的纹理)的OpenGL上下文与任何特定的输出目标都不相关.因此,我可以使视频缩放器在初始化后更改其输出表面,如下所示:

...
}else if(inputMessage.what==MSG_CHANGE_SURFACE){
    // Detach the current thread from the context, as a precaution
    EGL14.eglMakeCurrent(mEGLDisplay, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_CONTEXT);
    checkEglError("eglMakeCurrent 1");

    // Destroy the old EGL surface and release its Android counterpart
    // the old surface belongs to the previous, now released, MediaCodec instance
    EGL14.eglDestroySurface(mEGLDisplay, mEGLSurface);
    checkEglError("eglDestroySurface");
    surface.release(); // surface is a field that holds the current MediaCodec encoder input surface

    surface=(Surface) inputMessage.obj;
    dstW=inputMessage.arg1; // these are used in glViewport and the fragment shader
    dstH=inputMessage.arg2;

    // Create a new EGL surface for the new MediaCodec instance
    int[] surfaceAttribs={
        EGL14.EGL_NONE
    };
    mEGLSurface=EGL14.eglCreateWindowSurface(mEGLDisplay, configs[0], surface, surfaceAttribs, 0);
    checkEglError("eglCreateWindowSurface");

    // Make it current for the current thread
    EGL14.eglMakeCurrent(mEGLDisplay, mEGLSurface, mEGLSurface, mEGLContext);
    checkEglError("eglMakeCurrent 2");

    // That's it, any subsequent draw calls will render to the new surface
}

使用这种方法,无需重新初始化CameraCaptureSession,因为相机输出到的表面集没有变化.

标签:android-camera2,mediacodec,android-camera,android
来源: https://codeday.me/bug/20191024/1923006.html