我有一个标准的GLSurfaceView类:
public class TestSurfaceView extends GLSurfaceView {
public MainRenderer mRenderer;
public GStreamerSurfaceView(Context context) {
super(context);
setEGLContextClientVersion(2);
mRenderer = new MainRenderer(context);
setRenderer(mRenderer);
setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);
}
}
我有一个实现GLSurfaceView.Renderer的Renderer类:
public class MainRenderer implements GLSurfaceView.Renderer {
private int[] hTex;
private SurfaceTexture mSTexture;
private Context context;
MainRenderer(Context c) {
context = c;
}
public void onSurfaceCreated(GL10 unused, EGLConfig config) {
}
public void onDrawFrame(GL10 unused) {
}
public void onSurfaceChanged(GL10 unused, int width, int height) {
}
public void onSurfaceCreated(GL10 arg0, javax.microedition.khronos.egl.EGLConfig arg1) {
}
}
在一个单独的JNI线程中,我将一些视频数据(YUV格式)上传到OpenGLES纹理。我在Java中收到一个新纹理可用的通知,并且我有相应的纹理ID。
如何在Renderer类中显示此纹理的内容,而对性能影响最小?
答案 0 :(得分:2)
对于帧来自Camera或MediaCodec的情况,有一些非常有效的解决方案。听起来你在软件中生成或解码视频,这会对事物产生轻微的影响(尽管你的代码中已经声明了SurfaceTexture,这很奇怪)。诀窍是" OpenGL ES纹理"部分,因为纹理与EGL上下文相关联,并且EGL上下文一次只能在一个线程中激活。
因为您使用的是GLSurfaceView而不是普通的SurfaceView,所以您无法控制GLSurfaceView的渲染器线程中的EGL上下文。解决这个问题的最简单方法是跳过一些环节来创建第二个与第一个共享的EGL上下文。完成后,在单独的JNI线程中创建的纹理将可用于GLSurfaceView渲染器线程。
您可以在Grafika's" show + capture camera"中找到相关示例。活动。如果你看一下CameraCaptureActivity.java中的onDrawFrame()
方法,你可以看到它调用updateSharedContext()
,它将消息传递给运行TextureMovieEncoder的线程,使其运行handleUpdateSharedContext()
, )创建用于馈送视频编码器的表面。
如果您使用普通的SurfaceView,并进行自己的EGL和线程管理,代码将不那么曲折。您可以一次创建两个上下文,然后只将一个上传到生成图像的线程。您还可以创建单个上下文并使用eglMakeCurrent()
在线程之间进行转换,但在某些平台上这可能会很昂贵。
更新: Grafika" show + capture camera"实施有竞争条件;有关问题和解决方案的详细信息,请参阅this bug report。在一个线程中创建纹理并在另一个线程中使用它时,您必须执行一些额外的步骤。在一个线程上在一个上下文中完成所有操作通常会更好。 Grafika中的其他活动使用普通的SurfaceView并执行自己的EGL上下文和线程管理。