ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

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

2019-10-24 19:24:54  阅读:235  来源: 互联网

标签:android-camera2 mediacodec android-camera android


我正在制作一个视频流应用程序,使视频比特率适应可用的上行链路带宽,并且我希望它可以动态地更改视频分辨率,以便在较低比特率上不会出现太多压缩失真.尽管通过释放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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有