Back to project page kickflip-android-sdk.
The source code is released under:
Apache License
If you think the Android project kickflip-android-sdk listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.
/* * Copyright 2013 Google Inc. All rights reserved. *//from w w w. ja v a 2 s. c om * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package io.kickflip.sdk.av; import android.graphics.SurfaceTexture; import android.opengl.EGL14; import android.opengl.EGLConfig; import android.opengl.EGLContext; import android.opengl.EGLDisplay; import android.opengl.EGLExt; import android.opengl.EGLSurface; import android.util.Log; import android.view.Surface; /** * Core EGL state (display, context, config). * @hide */ public final class EglCore { private static final String TAG = "EglCore"; /** * Constructor flag: surface must be recordable. This discourages EGL from using a * pixel format that cannot be converted efficiently to something usable by the video * encoder. */ public static final int FLAG_RECORDABLE = 0x01; /** * Constructor flag: ask for GLES3, fall back to GLES2 if not available. Without this * flag, GLES2 is used. */ public static final int FLAG_TRY_GLES3 = 0x02; // Android-specific extension. private static final int EGL_RECORDABLE_ANDROID = 0x3142; private EGLDisplay mEGLDisplay = EGL14.EGL_NO_DISPLAY; private EGLContext mEGLContext = EGL14.EGL_NO_CONTEXT; private EGLConfig mEGLConfig = null; private int mGlVersion = -1; /** * Prepares EGL display and context. * <p> * Equivalent to EglCore(null, 0). */ public EglCore() { this(null, 0); } /** * Prepares EGL display and context. * <p> * @param sharedContext The context to share, or null if sharing is not desired. * @param flags Configuration bit flags, e.g. FLAG_RECORDABLE. */ public EglCore(EGLContext sharedContext, int flags) { if (mEGLDisplay != EGL14.EGL_NO_DISPLAY) { throw new RuntimeException("EGL already set up"); } if (sharedContext == null) { sharedContext = EGL14.EGL_NO_CONTEXT; } mEGLDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY); if (mEGLDisplay == EGL14.EGL_NO_DISPLAY) { throw new RuntimeException("unable to get EGL14 display"); } int[] version = new int[2]; if (!EGL14.eglInitialize(mEGLDisplay, version, 0, version, 1)) { mEGLDisplay = null; throw new RuntimeException("unable to initialize EGL14"); } // Try to get a GLES3 context, if requested. if ((flags & FLAG_TRY_GLES3) != 0) { //Log.d(TAG, "Trying GLES 3"); EGLConfig config = getConfig(flags, 3); if (config != null) { int[] attrib3_list = { EGL14.EGL_CONTEXT_CLIENT_VERSION, 3, EGL14.EGL_NONE }; EGLContext context = EGL14.eglCreateContext(mEGLDisplay, config, sharedContext, attrib3_list, 0); if (EGL14.eglGetError() == EGL14.EGL_SUCCESS) { //Log.d(TAG, "Got GLES 3 config"); mEGLConfig = config; mEGLContext = context; mGlVersion = 3; } } } if (mEGLContext == EGL14.EGL_NO_CONTEXT) { // GLES 2 only, or GLES 3 attempt failed //Log.d(TAG, "Trying GLES 2"); EGLConfig config = getConfig(flags, 2); if (config == null) { throw new RuntimeException("Unable to find a suitable EGLConfig"); } int[] attrib2_list = { EGL14.EGL_CONTEXT_CLIENT_VERSION, 2, EGL14.EGL_NONE }; EGLContext context = EGL14.eglCreateContext(mEGLDisplay, config, sharedContext, attrib2_list, 0); checkEglError("eglCreateContext"); mEGLConfig = config; mEGLContext = context; mGlVersion = 2; } // Confirm with query. int[] values = new int[1]; EGL14.eglQueryContext(mEGLDisplay, mEGLContext, EGL14.EGL_CONTEXT_CLIENT_VERSION, values, 0); Log.d(TAG, "EGLContext created, client version " + values[0]); } /** * Finds a suitable EGLConfig. * * @param flags Bit flags from constructor. * @param version Must be 2 or 3. */ private EGLConfig getConfig(int flags, int version) { int renderableType = EGL14.EGL_OPENGL_ES2_BIT; if (version >= 3) { renderableType |= EGLExt.EGL_OPENGL_ES3_BIT_KHR; } // The actual surface is generally RGBA or RGBX, so situationally omitting alpha // doesn't really help. It can also lead to a huge performance hit on glReadPixels() // when reading into a GL_RGBA buffer. int[] attribList = { EGL14.EGL_RED_SIZE, 8, EGL14.EGL_GREEN_SIZE, 8, EGL14.EGL_BLUE_SIZE, 8, EGL14.EGL_ALPHA_SIZE, 8, //EGL14.EGL_DEPTH_SIZE, 16, //EGL14.EGL_STENCIL_SIZE, 8, EGL14.EGL_RENDERABLE_TYPE, renderableType, EGL14.EGL_NONE, 0, // placeholder for recordable [@-3] EGL14.EGL_NONE }; if ((flags & FLAG_RECORDABLE) != 0) { attribList[attribList.length - 3] = EGL_RECORDABLE_ANDROID; attribList[attribList.length - 2] = 1; } EGLConfig[] configs = new EGLConfig[1]; int[] numConfigs = new int[1]; if (!EGL14.eglChooseConfig(mEGLDisplay, attribList, 0, configs, 0, configs.length, numConfigs, 0)) { Log.w(TAG, "unable to find RGB8888 / " + version + " EGLConfig"); return null; } return configs[0]; } /** * Discard all resources held by this class, notably the EGL context. */ public void release() { if (mEGLDisplay != EGL14.EGL_NO_DISPLAY) { // Android is unusual in that it uses a reference-counted EGLDisplay. So for // every eglInitialize() we need an eglTerminate(). EGL14.eglMakeCurrent(mEGLDisplay, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_CONTEXT); EGL14.eglDestroyContext(mEGLDisplay, mEGLContext); EGL14.eglReleaseThread(); EGL14.eglTerminate(mEGLDisplay); } mEGLDisplay = EGL14.EGL_NO_DISPLAY; mEGLContext = EGL14.EGL_NO_CONTEXT; mEGLConfig = null; } @Override protected void finalize() throws Throwable { try { if (mEGLDisplay != EGL14.EGL_NO_DISPLAY) { // We're limited here -- finalizers don't run on the thread that holds // the EGL state, so if a surface or context is still current on another // thread we can't fully release it here. Exceptions thrown from here // are quietly discarded. Complain in the log file. Log.w(TAG, "WARNING: EglCore was not explicitly released -- state may be leaked"); release(); } } finally { super.finalize(); } } /** * Destroys the specified surface. Note the EGLSurface won't actually be destroyed if it's * still current in a context. */ public void releaseSurface(EGLSurface eglSurface) { EGL14.eglDestroySurface(mEGLDisplay, eglSurface); } /** * Creates an EGL surface associated with a Surface. * <p> * If this is destined for MediaCodec, the EGLConfig should have the "recordable" attribute. */ public EGLSurface createWindowSurface(Object surface) { if (!(surface instanceof Surface) && !(surface instanceof SurfaceTexture)) { throw new RuntimeException("invalid surface: " + surface); } // Create a window surface, and attach it to the Surface we received. int[] surfaceAttribs = { EGL14.EGL_NONE }; EGLSurface eglSurface = EGL14.eglCreateWindowSurface(mEGLDisplay, mEGLConfig, surface, surfaceAttribs, 0); checkEglError("eglCreateWindowSurface"); if (eglSurface == null) { throw new RuntimeException("surface was null"); } return eglSurface; } /** * Creates an EGL surface associated with an offscreen buffer. */ public EGLSurface createOffscreenSurface(int width, int height) { int[] surfaceAttribs = { EGL14.EGL_WIDTH, width, EGL14.EGL_HEIGHT, height, EGL14.EGL_NONE }; EGLSurface eglSurface = EGL14.eglCreatePbufferSurface(mEGLDisplay, mEGLConfig, surfaceAttribs, 0); checkEglError("eglCreatePbufferSurface"); if (eglSurface == null) { throw new RuntimeException("surface was null"); } return eglSurface; } /** * Makes our EGL context current, using the supplied surface for both "draw" and "read". */ public void makeCurrent(EGLSurface eglSurface) { if (mEGLDisplay == EGL14.EGL_NO_DISPLAY) { // called makeCurrent() before create? Log.d(TAG, "NOTE: makeCurrent w/o display"); } if (!EGL14.eglMakeCurrent(mEGLDisplay, eglSurface, eglSurface, mEGLContext)) { throw new RuntimeException("eglMakeCurrent failed"); } } /** * Makes our EGL context current, using the supplied "draw" and "read" surfaces. */ public void makeCurrent(EGLSurface drawSurface, EGLSurface readSurface) { if (mEGLDisplay == EGL14.EGL_NO_DISPLAY) { // called makeCurrent() before create? Log.d(TAG, "NOTE: makeCurrent w/o display"); } if (!EGL14.eglMakeCurrent(mEGLDisplay, drawSurface, readSurface, mEGLContext)) { throw new RuntimeException("eglMakeCurrent(draw,read) failed"); } } /** * Makes no context current. */ public void makeNothingCurrent() { if (!EGL14.eglMakeCurrent(mEGLDisplay, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_CONTEXT)) { throw new RuntimeException("eglMakeCurrent failed"); } } /** * Calls eglSwapBuffers. Use this to "publish" the current frame. * * @return false on failure */ public boolean swapBuffers(EGLSurface eglSurface) { return EGL14.eglSwapBuffers(mEGLDisplay, eglSurface); } /** * Sends the presentation time stamp to EGL. Time is expressed in nanoseconds. */ public void setPresentationTime(EGLSurface eglSurface, long nsecs) { EGLExt.eglPresentationTimeANDROID(mEGLDisplay, eglSurface, nsecs); } /** * Returns true if our context and the specified surface are current. */ public boolean isCurrent(EGLSurface eglSurface) { return mEGLContext.equals(EGL14.eglGetCurrentContext()) && eglSurface.equals(EGL14.eglGetCurrentSurface(EGL14.EGL_DRAW)); } /** * Performs a simple surface query. */ public int querySurface(EGLSurface eglSurface, int what) { int[] value = new int[1]; EGL14.eglQuerySurface(mEGLDisplay, eglSurface, what, value, 0); return value[0]; } /** * Returns the GLES version this context is configured for (2 or 3). */ public int getGlVersion() { return mGlVersion; } /** * Writes the current display, context, and surface to the log. */ public static void logCurrent(String msg) { EGLDisplay display; EGLContext context; EGLSurface surface; display = EGL14.eglGetCurrentDisplay(); context = EGL14.eglGetCurrentContext(); surface = EGL14.eglGetCurrentSurface(EGL14.EGL_DRAW); Log.i(TAG, "Current EGL (" + msg + "): display=" + display + ", context=" + context + ", surface=" + surface); } /** * Checks for EGL errors. */ private void checkEglError(String msg) { int error; if ((error = EGL14.eglGetError()) != EGL14.EGL_SUCCESS) { throw new RuntimeException(msg + ": EGL error: 0x" + Integer.toHexString(error)); } } }