package io.agora.api.example.examples.advanced.videoRender;
import android.content.Context;
import android.graphics.SurfaceTexture;
import android.opengl.EGL14;
import android.opengl.EGLExt;
import android.opengl.GLDebugHelper;
import android.opengl.GLSurfaceView;
import android.util.AttributeSet;
import android.util.Log;
import android.view.TextureView;
import android.view.View;
import java.io.Writer;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import javax.microedition.khronos.egl.EGL10;
import javax.microedition.khronos.egl.EGL11;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.egl.EGLContext;
import javax.microedition.khronos.egl.EGLDisplay;
import javax.microedition.khronos.egl.EGLSurface;
import javax.microedition.khronos.opengles.GL;
import javax.microedition.khronos.opengles.GL10;
import static android.opengl.EGL14.EGL_BAD_ACCESS;
import static android.opengl.EGL14.EGL_BAD_ALLOC;
import static android.opengl.EGL14.EGL_BAD_ATTRIBUTE;
import static android.opengl.EGL14.EGL_BAD_CONFIG;
import static android.opengl.EGL14.EGL_BAD_CONTEXT;
import static android.opengl.EGL14.EGL_BAD_CURRENT_SURFACE;
import static android.opengl.EGL14.EGL_BAD_DISPLAY;
import static android.opengl.EGL14.EGL_BAD_MATCH;
import static android.opengl.EGL14.EGL_BAD_NATIVE_PIXMAP;
import static android.opengl.EGL14.EGL_BAD_NATIVE_WINDOW;
import static android.opengl.EGL14.EGL_BAD_PARAMETER;
import static android.opengl.EGL14.EGL_BAD_SURFACE;
import static android.opengl.EGL14.EGL_NOT_INITIALIZED;
import static android.opengl.EGL14.EGL_SUCCESS;
/**
* 参考 {@link GLSurfaceView} 实现
*
* @author fkwl5
*/
public class GLTextureView extends TextureView implements TextureView.SurfaceTextureListener, View.OnLayoutChangeListener {
private final static String TAG = "GLTextureView";
private final static boolean LOG_ATTACH_DETACH = true;
private final static boolean LOG_THREADS = false;
private final static boolean LOG_PAUSE_RESUME = true;
private final static boolean LOG_SURFACE = true;
private final static boolean LOG_RENDERER = true;
private final static boolean LOG_RENDERER_DRAW_FRAME = false;
private final static boolean LOG_EGL = true;
/**
* The renderer only renders
* when the surface is created, or when {@link #requestRender} is called.
*
* @see #getRenderMode()
* @see #setRenderMode(int)
* @see #requestRender()
*/
public final static int RENDERMODE_WHEN_DIRTY = 0;
/**
* The renderer is called
* continuously to re-render the scene.
*
* @see #getRenderMode()
* @see #setRenderMode(int)
*/
public final static int RENDERMODE_CONTINUOUSLY = 1;
/**
* Check glError() after every GL call and throw an exception if glError indicates
* that an error has occurred. This can be used to help track down which OpenGL ES call
* is causing an error.
*
* @see #getDebugFlags
* @see #setDebugFlags
*/
public final static int DEBUG_CHECK_GL_ERROR = 1;
/**
* Log GL calls to the system log at "verbose" level with tag "GLTextureView".
*
* @see #getDebugFlags
* @see #setDebugFlags
*/
public final static int DEBUG_LOG_GL_CALLS = 2;
/**
* 构造方法,必须调用 {@link #setRenderer} 才能进行渲染
*/
public GLTextureView(Context context) {
super(context);
init();
}
public GLTextureView(Context context, AttributeSet attributeSet) {
super(context, attributeSet);
init();
}
@Override
protected void finalize() throws Throwable {
try {
if (mGLThread != null) {
// GLThread may still be running if this view was never
// attached to a window.
mGLThread.requestExitAndWait();
}
} finally {
super.finalize();
}
}
private void init() {
setSurfaceTextureListener(this);
}
/**
* Set the glWrapper. If the glWrapper is not null, its
* {@link GLWrapper#wrap(GL)} method is called
* whenever a surface is created. A GLWrapper can be used to wrap
* the GL object that's passed to the renderer. Wrapping a GL
* object enables examining and modifying the behavior of the
* GL calls made by the renderer.
* <p>
* Wrapping is typically used for debugging purposes.
* <p>
* The default value is null.
*
* @param glWrapper the new GLWrapper
*/
public void setGLWrapper(GLWrapper glWrapper) {
mGLWrapper = glWrapper;
}
/**
* Set the debug flags to a new value. The value is
* constructed by OR-together zero or more
* of the DEBUG_CHECK_* constants. The debug flags take effect
* whenever a surface is created. The default value is zero.
*
* @param debugFlags the new debug flags
* @see #DEBUG_CHECK_GL_ERROR
* @see #DEBUG_LOG_GL_CALLS
*/
public void setDebugFlags(int debugFlags) {
mDebugFlags = debugFlags;
}
/**
* Get the current value of the debug flags.
*
* @return the current value of the debug flags.
*/
public int getDebugFlags() {
return mDebugFlags;
}
/**
* Control whether the EGL context is preserved when the GLTextureView is paused and
* resumed.
* <p>
* If set to true, then the EGL context may be preserved when the GLTextureView is paused.
* <p>
* Prior to API level 11, whether the EGL context is actually preserved or not
* depends upon whether the Android device can support an arbitrary number of
* EGL contexts or not. Devices that can only support a limited number of EGL
* contexts must release the EGL context in order to allow multiple applications
* to share the GPU.
* <p>
* If set to false, the EGL context will be released when the GLTextureView is paused,
* and recreated when the GLTextureView is resumed.
* <p>
* <p>
* The default is false.
*
* @param preserveOnPause preserve the EGL context when paused
*/
public void setPreserveEGLContextOnPause(boolean preserveOnPause) {
mPreserveEGLContextOnPause = preserveOnPause;
}
/**
* @return true if the EGL context will be preserved when paused
*/
public boolean getPreserveEGLContextOnPause() {
return mPreserveEGLContextOnPause;
}
/**
* Set the renderer associated with this view. Also starts the thread that
* will call the renderer, which in turn causes the rendering to start.
* <p>This method should be called once and only once in the life-cycle of
* a GLTextureView.
* <p>The following GLTextureView methods can only be called <em>before</em>
* setRenderer is called:
* <ul>
* <li>{@link #setEGLConfigChooser(boolean)}
* <li>{@link #setEGLConfigChooser(EGLConfigChooser)}
* <li>{@link #setEGLConfigChooser(int, int, int, int, int, int)}
* </ul>
* <p>
* The following GLTextureView methods can only be called <em>after</em>
* setRenderer is called:
* <ul>
* <li>{@link #getRenderMode()}
* <li>{@link #onPause()}
* <li>{@link #onResume()}
* <li>{@link #queueEvent(Runnable)}
* <li>{@link #requestRender()}
* <li>{@link #setRenderMode(int)}
* </ul>
*
* @param renderer the renderer to use to perform OpenGL drawing.
*/
public void setRenderer(Renderer renderer) {
checkRenderThreadState();
if (mEGLConfigChooser == null) {
mEGLConfigChooser = new SimpleEGLConfigChooser(true);
}
if (mEGLContextFactory == null) {