17cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang/*
27cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang * Copyright (C) 2018 The Android Open Source Project
37cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang *
47cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang * Licensed under the Apache License, Version 2.0 (the "License");
57cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang * you may not use this file except in compliance with the License.
67cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang * You may obtain a copy of the License at
77cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang *
87cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang *      http://www.apache.org/licenses/LICENSE-2.0
97cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang *
107cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang * Unless required by applicable law or agreed to in writing, software
117cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang * distributed under the License is distributed on an "AS IS" BASIS,
127cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
137cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang * See the License for the specific language governing permissions and
147cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang * limitations under the License.
157cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang */
167cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang
17db1945bea4e3816a04afe0ad41681cec1d0c074dAlan Viverettepackage androidx.heifwriter;
187cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang
197cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhangimport android.opengl.EGL14;
207cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhangimport android.opengl.EGLConfig;
217cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhangimport android.opengl.EGLContext;
227cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhangimport android.opengl.EGLDisplay;
237cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhangimport android.opengl.EGLExt;
247cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhangimport android.opengl.EGLSurface;
257cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhangimport android.util.Log;
267cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhangimport android.view.Surface;
277cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang
28b1433f75d87710262b14824c98854a4865f98836Aurimas Liutikasimport java.util.Objects;
29b1433f75d87710262b14824c98854a4865f98836Aurimas Liutikas
307cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang/**
317cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang * Holds state associated with a Surface used for MediaCodec encoder input.
327cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang * <p>
337cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang * The constructor takes a Surface obtained from MediaCodec.createInputSurface(), and uses that
347cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang * to create an EGL window surface. Calls to eglSwapBuffers() cause a frame of data to be sent
357cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang * to the video encoder.
367cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang *
377cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang * @hide
387cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang */
397cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhangpublic class EglWindowSurface {
407cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang    private static final String TAG = "EglWindowSurface";
417cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang
427cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang    private EGLDisplay mEGLDisplay = EGL14.EGL_NO_DISPLAY;
437cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang    private EGLContext mEGLContext = EGL14.EGL_NO_CONTEXT;
447cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang    private EGLSurface mEGLSurface = EGL14.EGL_NO_SURFACE;
457cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang    private EGLConfig[] mConfigs = new EGLConfig[1];
467cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang
477cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang    private Surface mSurface;
487cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang    private int mWidth;
497cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang    private int mHeight;
507cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang
517cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang    /**
527cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang     * Creates an EglWindowSurface from a Surface.
537cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang     */
547cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang    public EglWindowSurface(Surface surface) {
557cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang        if (surface == null) {
567cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang            throw new NullPointerException();
577cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang        }
587cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang        mSurface = surface;
597cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang
607cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang        eglSetup();
617cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang    }
627cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang
637cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang    /**
647cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang     * Prepares EGL. We want a GLES 2.0 context and a surface that supports recording.
657cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang     */
667cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang    private void eglSetup() {
677cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang        mEGLDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY);
68b1433f75d87710262b14824c98854a4865f98836Aurimas Liutikas        if (Objects.equals(mEGLDisplay, EGL14.EGL_NO_DISPLAY)) {
697cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang            throw new RuntimeException("unable to get EGL14 display");
707cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang        }
717cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang        int[] version = new int[2];
727cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang        if (!EGL14.eglInitialize(mEGLDisplay, version, 0, version, 1)) {
737cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang            mEGLDisplay = null;
747cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang            throw new RuntimeException("unable to initialize EGL14");
757cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang        }
767cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang
777cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang        // Configure EGL for recordable and OpenGL ES 2.0.  We want enough RGB bits
787cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang        // to minimize artifacts from possible YUV conversion.
797cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang        int[] attribList = {
807cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang                EGL14.EGL_RED_SIZE, 8,
817cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang                EGL14.EGL_GREEN_SIZE, 8,
827cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang                EGL14.EGL_BLUE_SIZE, 8,
837cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang                EGL14.EGL_RENDERABLE_TYPE, EGL14.EGL_OPENGL_ES2_BIT,
847cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang                EGLExt.EGL_RECORDABLE_ANDROID, 1,
857cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang                EGL14.EGL_NONE
867cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang        };
877cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang        int[] numConfigs = new int[1];
887cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang        if (!EGL14.eglChooseConfig(mEGLDisplay, attribList, 0, mConfigs, 0, mConfigs.length,
897cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang                numConfigs, 0)) {
907cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang            throw new RuntimeException("unable to find RGB888+recordable ES2 EGL config");
917cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang        }
927cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang
937cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang        // Configure context for OpenGL ES 2.0.
947cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang        int[] attrib_list = {
957cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang                EGL14.EGL_CONTEXT_CLIENT_VERSION, 2,
967cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang                EGL14.EGL_NONE
977cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang        };
987cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang        mEGLContext = EGL14.eglCreateContext(mEGLDisplay, mConfigs[0], EGL14.EGL_NO_CONTEXT,
997cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang                attrib_list, 0);
1007cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang        checkEglError("eglCreateContext");
1017cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang        if (mEGLContext == null) {
1027cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang            throw new RuntimeException("null context");
1037cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang        }
1047cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang
1057cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang        // Create a window surface, and attach it to the Surface we received.
1067cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang        createEGLSurface();
1077cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang
1087cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang        mWidth = getWidth();
1097cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang        mHeight = getHeight();
1107cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang    }
1117cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang
1127cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang    public void updateSize(int width, int height) {
1137cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang        if (width != mWidth || height != mHeight) {
1147cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang            Log.d(TAG, "re-create EGLSurface");
1157cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang            releaseEGLSurface();
1167cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang            createEGLSurface();
1177cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang            mWidth = getWidth();
1187cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang            mHeight = getHeight();
1197cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang        }
1207cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang    }
1217cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang
1227cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang    private void createEGLSurface() {
1237cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang        int[] surfaceAttribs = {
1247cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang                EGL14.EGL_NONE
1257cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang        };
1267cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang        mEGLSurface = EGL14.eglCreateWindowSurface(mEGLDisplay, mConfigs[0], mSurface,
1277cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang                surfaceAttribs, 0);
1287cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang        checkEglError("eglCreateWindowSurface");
1297cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang        if (mEGLSurface == null) {
1307cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang            throw new RuntimeException("surface was null");
1317cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang        }
1327cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang    }
1337cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang
1347cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang    private void releaseEGLSurface() {
135b1433f75d87710262b14824c98854a4865f98836Aurimas Liutikas        if (!Objects.equals(mEGLDisplay, EGL14.EGL_NO_DISPLAY)) {
1367cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang            EGL14.eglDestroySurface(mEGLDisplay, mEGLSurface);
1377cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang            mEGLSurface = EGL14.EGL_NO_SURFACE;
1387cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang        }
1397cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang    }
1407cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang
1417cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang    /**
1427cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang     * Discard all resources held by this class, notably the EGL context. Also releases the
1437cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang     * Surface that was passed to our constructor.
1447cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang     */
1457cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang    public void release() {
146b1433f75d87710262b14824c98854a4865f98836Aurimas Liutikas        if (!Objects.equals(mEGLDisplay, EGL14.EGL_NO_DISPLAY)) {
1477cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang            EGL14.eglDestroySurface(mEGLDisplay, mEGLSurface);
1487cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang            EGL14.eglDestroyContext(mEGLDisplay, mEGLContext);
1497cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang            EGL14.eglReleaseThread();
1507cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang            EGL14.eglTerminate(mEGLDisplay);
1517cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang        }
1527cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang
1537cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang        mSurface.release();
1547cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang
1557cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang        mEGLDisplay = EGL14.EGL_NO_DISPLAY;
1567cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang        mEGLContext = EGL14.EGL_NO_CONTEXT;
1577cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang        mEGLSurface = EGL14.EGL_NO_SURFACE;
1587cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang
1597cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang        mSurface = null;
1607cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang    }
1617cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang
1627cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang    /**
1637cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang     * Makes our EGL context and surface current.
1647cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang     */
1657cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang    public void makeCurrent() {
1667cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang        if (!EGL14.eglMakeCurrent(mEGLDisplay, mEGLSurface, mEGLSurface, mEGLContext)) {
1677cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang            throw new RuntimeException("eglMakeCurrent failed");
1687cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang        }
1697cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang    }
1707cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang
1717cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang    /**
1727cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang     * Makes our EGL context and surface not current.
1737cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang     */
1747cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang    public void makeUnCurrent() {
1757cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang        if (!EGL14.eglMakeCurrent(mEGLDisplay, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_SURFACE,
1767cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang                EGL14.EGL_NO_CONTEXT)) {
1777cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang            throw new RuntimeException("eglMakeCurrent failed");
1787cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang        }
1797cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang    }
1807cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang
1817cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang    /**
1827cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang     * Calls eglSwapBuffers. Use this to "publish" the current frame.
1837cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang     */
1847cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang    public boolean swapBuffers() {
1857cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang        return EGL14.eglSwapBuffers(mEGLDisplay, mEGLSurface);
1867cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang    }
1877cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang
1887cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang    /**
1897cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang     * Returns the Surface that the MediaCodec receives buffers from.
1907cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang     */
1917cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang    public Surface getSurface() {
1927cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang        return mSurface;
1937cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang    }
1947cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang
1957cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang    /**
1967cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang     * Queries the surface's width.
1977cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang     */
1987cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang    public int getWidth() {
1997cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang        int[] value = new int[1];
2007cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang        EGL14.eglQuerySurface(mEGLDisplay, mEGLSurface, EGL14.EGL_WIDTH, value, 0);
2017cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang        return value[0];
2027cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang    }
2037cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang
2047cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang    /**
2057cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang     * Queries the surface's height.
2067cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang     */
2077cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang    public int getHeight() {
2087cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang        int[] value = new int[1];
2097cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang        EGL14.eglQuerySurface(mEGLDisplay, mEGLSurface, EGL14.EGL_HEIGHT, value, 0);
2107cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang        return value[0];
2117cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang    }
2127cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang
2137cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang    /**
2147cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang     * Sends the presentation time stamp to EGL. Time is expressed in nanoseconds.
2157cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang     */
2167cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang    public void setPresentationTime(long nsecs) {
2177cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang        EGLExt.eglPresentationTimeANDROID(mEGLDisplay, mEGLSurface, nsecs);
2187cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang    }
2197cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang
2207cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang    /**
2217cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang     * Checks for EGL errors.
2227cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang     */
2237cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang    private void checkEglError(String msg) {
2247cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang        int error;
2257cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang        if ((error = EGL14.eglGetError()) != EGL14.EGL_SUCCESS) {
2267cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang            throw new RuntimeException(msg + ": EGL error: 0x" + Integer.toHexString(error));
2277cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang        }
2287cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang    }
2297cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang}
230