diff options
Diffstat (limited to 'libs/android-transcoder/src/main/java/net/ypresto/androidtranscoder/engine/InputSurface.java')
-rw-r--r-- | libs/android-transcoder/src/main/java/net/ypresto/androidtranscoder/engine/InputSurface.java | 175 |
1 files changed, 175 insertions, 0 deletions
diff --git a/libs/android-transcoder/src/main/java/net/ypresto/androidtranscoder/engine/InputSurface.java b/libs/android-transcoder/src/main/java/net/ypresto/androidtranscoder/engine/InputSurface.java new file mode 100644 index 000000000..9793c8911 --- /dev/null +++ b/libs/android-transcoder/src/main/java/net/ypresto/androidtranscoder/engine/InputSurface.java @@ -0,0 +1,175 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * 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. + */ +// from: https://android.googlesource.com/platform/cts/+/lollipop-release/tests/tests/media/src/android/media/cts/InputSurface.java +// blob: 157ed88d143229e4edb6889daf18fb73aa2fc5a5 +package net.ypresto.androidtranscoder.engine; +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.view.Surface; +/** + * Holds state associated with a Surface used for MediaCodec encoder input. + * <p> + * The constructor takes a Surface obtained from MediaCodec.createInputSurface(), and uses that + * to create an EGL window surface. Calls to eglSwapBuffers() cause a frame of data to be sent + * to the video encoder. + */ +class InputSurface { + private static final String TAG = "InputSurface"; + private static final int EGL_RECORDABLE_ANDROID = 0x3142; + private EGLDisplay mEGLDisplay = EGL14.EGL_NO_DISPLAY; + private EGLContext mEGLContext = EGL14.EGL_NO_CONTEXT; + private EGLSurface mEGLSurface = EGL14.EGL_NO_SURFACE; + private Surface mSurface; + /** + * Creates an InputSurface from a Surface. + */ + public InputSurface(Surface surface) { + if (surface == null) { + throw new NullPointerException(); + } + mSurface = surface; + eglSetup(); + } + /** + * Prepares EGL. We want a GLES 2.0 context and a surface that supports recording. + */ + private void eglSetup() { + 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"); + } + // Configure EGL for recordable and OpenGL ES 2.0. We want enough RGB bits + // to minimize artifacts from possible YUV conversion. + int[] attribList = { + EGL14.EGL_RED_SIZE, 8, + EGL14.EGL_GREEN_SIZE, 8, + EGL14.EGL_BLUE_SIZE, 8, + EGL14.EGL_RENDERABLE_TYPE, EGL14.EGL_OPENGL_ES2_BIT, + EGL_RECORDABLE_ANDROID, 1, + EGL14.EGL_NONE + }; + EGLConfig[] configs = new EGLConfig[1]; + int[] numConfigs = new int[1]; + if (!EGL14.eglChooseConfig(mEGLDisplay, attribList, 0, configs, 0, configs.length, + numConfigs, 0)) { + throw new RuntimeException("unable to find RGB888+recordable ES2 EGL config"); + } + // Configure context for OpenGL ES 2.0. + int[] attrib_list = { + EGL14.EGL_CONTEXT_CLIENT_VERSION, 2, + EGL14.EGL_NONE + }; + mEGLContext = EGL14.eglCreateContext(mEGLDisplay, configs[0], EGL14.EGL_NO_CONTEXT, + attrib_list, 0); + checkEglError("eglCreateContext"); + if (mEGLContext == null) { + throw new RuntimeException("null context"); + } + // Create a window surface, and attach it to the Surface we received. + int[] surfaceAttribs = { + EGL14.EGL_NONE + }; + mEGLSurface = EGL14.eglCreateWindowSurface(mEGLDisplay, configs[0], mSurface, + surfaceAttribs, 0); + checkEglError("eglCreateWindowSurface"); + if (mEGLSurface == null) { + throw new RuntimeException("surface was null"); + } + } + /** + * Discard all resources held by this class, notably the EGL context. Also releases the + * Surface that was passed to our constructor. + */ + public void release() { + if (mEGLDisplay != EGL14.EGL_NO_DISPLAY) { + EGL14.eglDestroySurface(mEGLDisplay, mEGLSurface); + EGL14.eglDestroyContext(mEGLDisplay, mEGLContext); + EGL14.eglReleaseThread(); + EGL14.eglTerminate(mEGLDisplay); + } + mSurface.release(); + mEGLDisplay = EGL14.EGL_NO_DISPLAY; + mEGLContext = EGL14.EGL_NO_CONTEXT; + mEGLSurface = EGL14.EGL_NO_SURFACE; + mSurface = null; + } + /** + * Makes our EGL context and surface current. + */ + public void makeCurrent() { + if (!EGL14.eglMakeCurrent(mEGLDisplay, mEGLSurface, mEGLSurface, mEGLContext)) { + throw new RuntimeException("eglMakeCurrent failed"); + } + } + public void makeUnCurrent() { + 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. + */ + public boolean swapBuffers() { + return EGL14.eglSwapBuffers(mEGLDisplay, mEGLSurface); + } + /** + * Returns the Surface that the MediaCodec receives buffers from. + */ + public Surface getSurface() { + return mSurface; + } + /** + * Queries the surface's width. + */ + public int getWidth() { + int[] value = new int[1]; + EGL14.eglQuerySurface(mEGLDisplay, mEGLSurface, EGL14.EGL_WIDTH, value, 0); + return value[0]; + } + /** + * Queries the surface's height. + */ + public int getHeight() { + int[] value = new int[1]; + EGL14.eglQuerySurface(mEGLDisplay, mEGLSurface, EGL14.EGL_HEIGHT, value, 0); + return value[0]; + } + /** + * Sends the presentation time stamp to EGL. Time is expressed in nanoseconds. + */ + public void setPresentationTime(long nsecs) { + EGLExt.eglPresentationTimeANDROID(mEGLDisplay, mEGLSurface, nsecs); + } + /** + * 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)); + } + } +} |