Home | History | Annotate | Download | only in cts
      1 /*
      2  * Copyright (C) 2013 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package android.media.cts;
     18 
     19 import android.opengl.EGL14;
     20 import android.opengl.EGLExt;
     21 import android.opengl.EGLConfig;
     22 import android.opengl.EGLContext;
     23 import android.opengl.EGLDisplay;
     24 import android.opengl.EGLSurface;
     25 import android.util.Log;
     26 import android.view.Surface;
     27 
     28 
     29 /**
     30  * Holds state associated with a Surface used for MediaCodec encoder input.
     31  * <p>
     32  * The constructor takes a Surface obtained from MediaCodec.createInputSurface(), and uses that
     33  * to create an EGL window surface.  Calls to eglSwapBuffers() cause a frame of data to be sent
     34  * to the video encoder.
     35  */
     36 class InputSurface {
     37     private static final String TAG = "InputSurface";
     38 
     39     private static final int EGL_RECORDABLE_ANDROID = 0x3142;
     40 
     41     private EGLDisplay mEGLDisplay = EGL14.EGL_NO_DISPLAY;
     42     private EGLContext mEGLContext = EGL14.EGL_NO_CONTEXT;
     43     private EGLSurface mEGLSurface = EGL14.EGL_NO_SURFACE;
     44     private EGLConfig[] mConfigs = new EGLConfig[1];
     45 
     46     private Surface mSurface;
     47     private int mWidth;
     48     private int mHeight;
     49 
     50     /**
     51      * Creates an InputSurface from a Surface.
     52      */
     53     public InputSurface(Surface surface) {
     54         if (surface == null) {
     55             throw new NullPointerException();
     56         }
     57         mSurface = surface;
     58 
     59         eglSetup();
     60     }
     61 
     62     /**
     63      * Prepares EGL.  We want a GLES 2.0 context and a surface that supports recording.
     64      */
     65     private void eglSetup() {
     66         mEGLDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY);
     67         if (mEGLDisplay == EGL14.EGL_NO_DISPLAY) {
     68             throw new RuntimeException("unable to get EGL14 display");
     69         }
     70         int[] version = new int[2];
     71         if (!EGL14.eglInitialize(mEGLDisplay, version, 0, version, 1)) {
     72             mEGLDisplay = null;
     73             throw new RuntimeException("unable to initialize EGL14");
     74         }
     75 
     76         // Configure EGL for recordable and OpenGL ES 2.0.  We want enough RGB bits
     77         // to minimize artifacts from possible YUV conversion.
     78         int[] attribList = {
     79                 EGL14.EGL_RED_SIZE, 8,
     80                 EGL14.EGL_GREEN_SIZE, 8,
     81                 EGL14.EGL_BLUE_SIZE, 8,
     82                 EGL14.EGL_RENDERABLE_TYPE, EGL14.EGL_OPENGL_ES2_BIT,
     83                 EGL_RECORDABLE_ANDROID, 1,
     84                 EGL14.EGL_NONE
     85         };
     86         int[] numConfigs = new int[1];
     87         if (!EGL14.eglChooseConfig(mEGLDisplay, attribList, 0, mConfigs, 0, mConfigs.length,
     88                 numConfigs, 0)) {
     89             throw new RuntimeException("unable to find RGB888+recordable ES2 EGL config");
     90         }
     91 
     92         // Configure context for OpenGL ES 2.0.
     93         int[] attrib_list = {
     94                 EGL14.EGL_CONTEXT_CLIENT_VERSION, 2,
     95                 EGL14.EGL_NONE
     96         };
     97         mEGLContext = EGL14.eglCreateContext(mEGLDisplay, mConfigs[0], EGL14.EGL_NO_CONTEXT,
     98                 attrib_list, 0);
     99         checkEglError("eglCreateContext");
    100         if (mEGLContext == null) {
    101             throw new RuntimeException("null context");
    102         }
    103 
    104         // Create a window surface, and attach it to the Surface we received.
    105         createEGLSurface();
    106 
    107         mWidth = getWidth();
    108         mHeight = getHeight();
    109     }
    110 
    111     public void updateSize(int width, int height) {
    112         if (width != mWidth || height != mHeight) {
    113             Log.d(TAG, "re-create EGLSurface");
    114             releaseEGLSurface();
    115             createEGLSurface();
    116             mWidth = getWidth();
    117             mHeight = getHeight();
    118         }
    119     }
    120 
    121     private void createEGLSurface() {
    122         //EGLConfig[] configs = new EGLConfig[1];
    123         int[] surfaceAttribs = {
    124                 EGL14.EGL_NONE
    125         };
    126         mEGLSurface = EGL14.eglCreateWindowSurface(mEGLDisplay, mConfigs[0], mSurface,
    127                 surfaceAttribs, 0);
    128         checkEglError("eglCreateWindowSurface");
    129         if (mEGLSurface == null) {
    130             throw new RuntimeException("surface was null");
    131         }
    132     }
    133     private void releaseEGLSurface() {
    134         if (mEGLDisplay != EGL14.EGL_NO_DISPLAY) {
    135             EGL14.eglDestroySurface(mEGLDisplay, mEGLSurface);
    136             mEGLSurface = EGL14.EGL_NO_SURFACE;
    137         }
    138     }
    139     /**
    140      * Discard all resources held by this class, notably the EGL context.  Also releases the
    141      * Surface that was passed to our constructor.
    142      */
    143     public void release() {
    144         if (mEGLDisplay != EGL14.EGL_NO_DISPLAY) {
    145             EGL14.eglDestroySurface(mEGLDisplay, mEGLSurface);
    146             EGL14.eglDestroyContext(mEGLDisplay, mEGLContext);
    147             EGL14.eglReleaseThread();
    148             EGL14.eglTerminate(mEGLDisplay);
    149         }
    150 
    151         mSurface.release();
    152 
    153         mEGLDisplay = EGL14.EGL_NO_DISPLAY;
    154         mEGLContext = EGL14.EGL_NO_CONTEXT;
    155         mEGLSurface = EGL14.EGL_NO_SURFACE;
    156 
    157         mSurface = null;
    158     }
    159 
    160     /**
    161      * Makes our EGL context and surface current.
    162      */
    163     public void makeCurrent() {
    164         if (!EGL14.eglMakeCurrent(mEGLDisplay, mEGLSurface, mEGLSurface, mEGLContext)) {
    165             throw new RuntimeException("eglMakeCurrent failed");
    166         }
    167     }
    168 
    169     public void makeUnCurrent() {
    170         if (!EGL14.eglMakeCurrent(mEGLDisplay, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_SURFACE,
    171                 EGL14.EGL_NO_CONTEXT)) {
    172             throw new RuntimeException("eglMakeCurrent failed");
    173         }
    174     }
    175 
    176     /**
    177      * Calls eglSwapBuffers.  Use this to "publish" the current frame.
    178      */
    179     public boolean swapBuffers() {
    180         return EGL14.eglSwapBuffers(mEGLDisplay, mEGLSurface);
    181     }
    182 
    183     /**
    184      * Returns the Surface that the MediaCodec receives buffers from.
    185      */
    186     public Surface getSurface() {
    187         return mSurface;
    188     }
    189 
    190     /**
    191      * Queries the surface's width.
    192      */
    193     public int getWidth() {
    194         int[] value = new int[1];
    195         EGL14.eglQuerySurface(mEGLDisplay, mEGLSurface, EGL14.EGL_WIDTH, value, 0);
    196         return value[0];
    197     }
    198 
    199     /**
    200      * Queries the surface's height.
    201      */
    202     public int getHeight() {
    203         int[] value = new int[1];
    204         EGL14.eglQuerySurface(mEGLDisplay, mEGLSurface, EGL14.EGL_HEIGHT, value, 0);
    205         return value[0];
    206     }
    207 
    208     /**
    209      * Sends the presentation time stamp to EGL.  Time is expressed in nanoseconds.
    210      */
    211     public void setPresentationTime(long nsecs) {
    212         EGLExt.eglPresentationTimeANDROID(mEGLDisplay, mEGLSurface, nsecs);
    213     }
    214 
    215     /**
    216      * Checks for EGL errors.
    217      */
    218     private void checkEglError(String msg) {
    219         int error;
    220         if ((error = EGL14.eglGetError()) != EGL14.EGL_SUCCESS) {
    221             throw new RuntimeException(msg + ": EGL error: 0x" + Integer.toHexString(error));
    222         }
    223     }
    224 }
    225