parent
							
								
									3fddd80d5b
								
							
						
					
					
						commit
						4f7e1366aa
					
				| @ -1,243 +0,0 @@ | ||||
| /* | ||||
|  * Copyright 2013 Google Inc. All rights reserved. | ||||
|  * | ||||
|  * 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 com.otaliastudios.cameraview.internal.egl; | ||||
| 
 | ||||
| import android.graphics.Bitmap; | ||||
| import android.opengl.EGL14; | ||||
| import android.opengl.EGLSurface; | ||||
| import android.opengl.GLES20; | ||||
| import android.os.Build; | ||||
| import androidx.annotation.RequiresApi; | ||||
| import android.util.Log; | ||||
| 
 | ||||
| import com.otaliastudios.cameraview.CameraLogger; | ||||
| 
 | ||||
| import java.io.BufferedOutputStream; | ||||
| import java.io.ByteArrayOutputStream; | ||||
| import java.io.File; | ||||
| import java.io.FileOutputStream; | ||||
| import java.io.IOException; | ||||
| import java.nio.ByteBuffer; | ||||
| import java.nio.ByteOrder; | ||||
| 
 | ||||
| /** | ||||
|  * Common base class for EGL surfaces. | ||||
|  * <p> | ||||
|  * There can be multiple surfaces associated with a single context. | ||||
|  */ | ||||
| @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2) | ||||
| public class EglBaseSurface { | ||||
|     protected static final String TAG = EglBaseSurface.class.getSimpleName(); | ||||
|     private final static CameraLogger LOG = CameraLogger.create(TAG); | ||||
| 
 | ||||
|     // EglCore object we're associated with.  It may be associated with multiple surfaces.
 | ||||
|     protected EglCore mEglCore; | ||||
| 
 | ||||
|     private EGLSurface mEGLSurface = EGL14.EGL_NO_SURFACE; | ||||
|     private int mWidth = -1; | ||||
|     private int mHeight = -1; | ||||
| 
 | ||||
|     public EglBaseSurface(EglCore eglCore) { | ||||
|         mEglCore = eglCore; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Creates a window surface. | ||||
|      * <p> | ||||
|      * @param surface May be a Surface or SurfaceTexture. | ||||
|      */ | ||||
|     public void createWindowSurface(Object surface) { | ||||
|         if (mEGLSurface != EGL14.EGL_NO_SURFACE) { | ||||
|             throw new IllegalStateException("surface already created"); | ||||
|         } | ||||
|         mEGLSurface = mEglCore.createWindowSurface(surface); | ||||
| 
 | ||||
|         // Don't cache width/height here, because the size of the underlying surface can change
 | ||||
|         // out from under us (see e.g. HardwareScalerActivity).
 | ||||
|         //mWidth = mEglCore.querySurface(mEGLSurface, EGL14.EGL_WIDTH);
 | ||||
|         //mHeight = mEglCore.querySurface(mEGLSurface, EGL14.EGL_HEIGHT);
 | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Creates an off-screen surface. | ||||
|      */ | ||||
|     public void createOffscreenSurface(int width, int height) { | ||||
|         if (mEGLSurface != EGL14.EGL_NO_SURFACE) { | ||||
|             throw new IllegalStateException("surface already created"); | ||||
|         } | ||||
|         mEGLSurface = mEglCore.createOffscreenSurface(width, height); | ||||
|         mWidth = width; | ||||
|         mHeight = height; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Returns the surface's width, in pixels. | ||||
|      * <p> | ||||
|      * If this is called on a window surface, and the underlying surface is in the process | ||||
|      * of changing size, we may not see the new size right away (e.g. in the "surfaceChanged" | ||||
|      * callback).  The size should match after the next buffer swap. | ||||
|      */ | ||||
|     public int getWidth() { | ||||
|         if (mWidth < 0) { | ||||
|             return mEglCore.querySurface(mEGLSurface, EGL14.EGL_WIDTH); | ||||
|         } else { | ||||
|             return mWidth; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Returns the surface's height, in pixels. | ||||
|      */ | ||||
|     public int getHeight() { | ||||
|         if (mHeight < 0) { | ||||
|             return mEglCore.querySurface(mEGLSurface, EGL14.EGL_HEIGHT); | ||||
|         } else { | ||||
|             return mHeight; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Release the EGL surface. | ||||
|      */ | ||||
|     public void releaseEglSurface() { | ||||
|         mEglCore.releaseSurface(mEGLSurface); | ||||
|         mEGLSurface = EGL14.EGL_NO_SURFACE; | ||||
|         mWidth = mHeight = -1; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Makes our EGL context and surface current. | ||||
|      */ | ||||
|     public void makeCurrent() { | ||||
|         mEglCore.makeCurrent(mEGLSurface); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Makes our EGL context and surface current for drawing, using the supplied surface | ||||
|      * for reading. | ||||
|      */ | ||||
|     public void makeCurrentReadFrom(EglBaseSurface readSurface) { | ||||
|         mEglCore.makeCurrent(mEGLSurface, readSurface.mEGLSurface); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Calls eglSwapBuffers.  Use this to "publish" the current frame. | ||||
|      * | ||||
|      * @return false on failure | ||||
|      */ | ||||
|     public boolean swapBuffers() { | ||||
|         boolean result = mEglCore.swapBuffers(mEGLSurface); | ||||
|         if (!result) { | ||||
|             Log.d(TAG, "WARNING: swapBuffers() failed"); | ||||
|         } | ||||
|         return result; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Sends the presentation time stamp to EGL. | ||||
|      * https://www.khronos.org/registry/EGL/extensions/ANDROID/EGL_ANDROID_presentation_time.txt
 | ||||
|      * | ||||
|      * @param nsecs Timestamp, in nanoseconds. | ||||
|      */ | ||||
|     public void setPresentationTime(long nsecs) { | ||||
|         mEglCore.setPresentationTime(mEGLSurface, nsecs); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Saves the EGL surface to a file. | ||||
|      * <p> | ||||
|      * Expects that this object's EGL surface is current. | ||||
|      */ | ||||
|     public void saveFrameToFile(File file) throws IOException { | ||||
|         if (!mEglCore.isCurrent(mEGLSurface)) { | ||||
|             throw new RuntimeException("Expected EGL context/surface is not current"); | ||||
|         } | ||||
| 
 | ||||
|         // glReadPixels fills in a "direct" ByteBuffer with what is essentially big-endian RGBA
 | ||||
|         // data (i.e. a byte of red, followed by a byte of green...).  While the Bitmap
 | ||||
|         // constructor that takes an int[] wants little-endian ARGB (blue/red swapped), the
 | ||||
|         // Bitmap "copy pixels" method wants the same format GL provides.
 | ||||
|         //
 | ||||
|         // Ideally we'd have some way to re-use the ByteBuffer, especially if we're calling
 | ||||
|         // here often.
 | ||||
|         //
 | ||||
|         // Making this even more interesting is the upside-down nature of GL, which means
 | ||||
|         // our output will look upside down relative to what appears on screen if the
 | ||||
|         // typical GL conventions are used.
 | ||||
| 
 | ||||
|         String filename = file.toString(); | ||||
| 
 | ||||
|         int width = getWidth(); | ||||
|         int height = getHeight(); | ||||
|         ByteBuffer buf = ByteBuffer.allocateDirect(width * height * 4); | ||||
|         buf.order(ByteOrder.LITTLE_ENDIAN); | ||||
|         GLES20.glReadPixels(0, 0, width, height, | ||||
|                 GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, buf); | ||||
|         Egloo.checkGlError("glReadPixels"); | ||||
|         buf.rewind(); | ||||
| 
 | ||||
|         BufferedOutputStream bos = null; | ||||
|         try { | ||||
|             bos = new BufferedOutputStream(new FileOutputStream(filename)); | ||||
|             Bitmap bmp = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); | ||||
|             bmp.copyPixelsFromBuffer(buf); | ||||
|             bmp.compress(Bitmap.CompressFormat.PNG, 90, bos); | ||||
|             bmp.recycle(); | ||||
|         } finally { | ||||
|             if (bos != null) bos.close(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Saves the EGL surface to given format. | ||||
|      * <p> | ||||
|      * Expects that this object's EGL surface is current. | ||||
|      */ | ||||
|     public byte[] saveFrameTo(Bitmap.CompressFormat compressFormat) { | ||||
|         if (!mEglCore.isCurrent(mEGLSurface)) { | ||||
|             throw new RuntimeException("Expected EGL context/surface is not current"); | ||||
|         } | ||||
| 
 | ||||
|         // glReadPixels fills in a "direct" ByteBuffer with what is essentially big-endian RGBA
 | ||||
|         // data (i.e. a byte of red, followed by a byte of green...).  While the Bitmap
 | ||||
|         // constructor that takes an int[] wants little-endian ARGB (blue/red swapped), the
 | ||||
|         // Bitmap "copy pixels" method wants the same format GL provides.
 | ||||
|         //
 | ||||
|         // Ideally we'd have some way to re-use the ByteBuffer, especially if we're calling
 | ||||
|         // here often.
 | ||||
|         //
 | ||||
|         // Making this even more interesting is the upside-down nature of GL, which means
 | ||||
|         // our output will look upside down relative to what appears on screen if the
 | ||||
|         // typical GL conventions are used.
 | ||||
| 
 | ||||
|         int width = getWidth(); | ||||
|         int height = getHeight(); | ||||
|         ByteBuffer buf = ByteBuffer.allocateDirect(width * height * 4); | ||||
|         buf.order(ByteOrder.LITTLE_ENDIAN); | ||||
|         GLES20.glReadPixels(0, 0, width, height, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, | ||||
|                 buf); | ||||
|         Egloo.checkGlError("glReadPixels"); | ||||
|         buf.rewind(); | ||||
| 
 | ||||
|         ByteArrayOutputStream bos = new ByteArrayOutputStream(buf.array().length); | ||||
|         Bitmap bmp = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); | ||||
|         bmp.copyPixelsFromBuffer(buf); | ||||
|         bmp.compress(compressFormat, 90, bos); | ||||
|         bmp.recycle(); | ||||
|         return bos.toByteArray(); | ||||
|     } | ||||
| } | ||||
| @ -1,364 +0,0 @@ | ||||
| /* | ||||
|  * Copyright 2013 Google Inc. All rights reserved. | ||||
|  * | ||||
|  * 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 com.otaliastudios.cameraview.internal.egl; | ||||
| 
 | ||||
| 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.os.Build; | ||||
| import androidx.annotation.RequiresApi; | ||||
| import android.util.Log; | ||||
| import android.view.Surface; | ||||
| 
 | ||||
| /** | ||||
|  * -- from grafika -- | ||||
|  * | ||||
|  * Core EGL state (display, context, config). | ||||
|  * <p> | ||||
|  * The EGLContext must only be attached to one thread at a time.  This class is not thread-safe. | ||||
|  */ | ||||
| @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2) | ||||
| public final class EglCore { | ||||
|     private static final String TAG = EglCore.class.getSimpleName(); | ||||
| 
 | ||||
|     /** | ||||
|      * 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]; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Discards all resources held by this class, notably the EGL context.  This must be | ||||
|      * called from the thread where the context was created. | ||||
|      * <p> | ||||
|      * On completion, no context will be current. | ||||
|      */ | ||||
|     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. | ||||
|      * https://www.khronos.org/registry/EGL/extensions/ANDROID/EGL_ANDROID_presentation_time.txt
 | ||||
|      */ | ||||
|     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]; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Queries a string value. | ||||
|      */ | ||||
|     public String queryString(int what) { | ||||
|         return EGL14.eglQueryString(mEGLDisplay, what); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Returns the GLES version this context is configured for (currently 2 or 3). | ||||
|      */ | ||||
|     public int getGlVersion() { | ||||
|         return mGlVersion; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Checks for EGL errors.  Throws an exception if an error has been raised. | ||||
|      */ | ||||
|     private void checkEglError(String msg) { | ||||
|         int error; | ||||
|         if ((error = EGL14.eglGetError()) != EGL14.EGL_SUCCESS) { | ||||
|             throw new RuntimeException(msg + ": EGL error: 0x" + Integer.toHexString(error)); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -1,80 +0,0 @@ | ||||
| /* | ||||
|  * Copyright 2013 Google Inc. All rights reserved. | ||||
|  * | ||||
|  * 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 com.otaliastudios.cameraview.internal.egl; | ||||
| 
 | ||||
| import android.graphics.SurfaceTexture; | ||||
| import android.os.Build; | ||||
| import androidx.annotation.RequiresApi; | ||||
| import android.view.Surface; | ||||
| 
 | ||||
| /** | ||||
|  * Recordable EGL window surface. | ||||
|  * <p> | ||||
|  * It's good practice to explicitly release() the surface, preferably from a "finally" block. | ||||
|  */ | ||||
| @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2) | ||||
| public class EglWindowSurface extends EglBaseSurface { | ||||
|     private Surface mSurface; | ||||
|     private boolean mReleaseSurface; | ||||
| 
 | ||||
|     /** | ||||
|      * Associates an EGL surface with the native window surface. | ||||
|      * <p> | ||||
|      * Set releaseSurface to true if you want the Surface to be released when release() is | ||||
|      * called.  This is convenient, but can interfere with framework classes that expect to | ||||
|      * manage the Surface themselves (e.g. if you release a SurfaceView's Surface, the | ||||
|      * surfaceDestroyed() callback won't fire). | ||||
|      */ | ||||
|     public EglWindowSurface(EglCore eglCore, Surface surface, boolean releaseSurface) { | ||||
|         super(eglCore); | ||||
|         createWindowSurface(surface); | ||||
|         mSurface = surface; | ||||
|         mReleaseSurface = releaseSurface; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Associates an EGL surface with the SurfaceTexture. | ||||
|      */ | ||||
|     public EglWindowSurface(EglCore eglCore, SurfaceTexture surfaceTexture) { | ||||
|         super(eglCore); | ||||
|         createWindowSurface(surfaceTexture); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Associates an EGL surface with the Surface. | ||||
|      */ | ||||
|     public EglWindowSurface(EglCore eglCore, Surface surface) { | ||||
|         super(eglCore); | ||||
|         createWindowSurface(surface); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Releases any resources associated with the EGL surface (and, if configured to do so, | ||||
|      * with the Surface as well). | ||||
|      * <p> | ||||
|      * Does not require that the surface's EGL context be current. | ||||
|      */ | ||||
|     public void release() { | ||||
|         releaseEglSurface(); | ||||
|         if (mSurface != null) { | ||||
|             if (mReleaseSurface) { | ||||
|                 mSurface.release(); | ||||
|             } | ||||
|             mSurface = null; | ||||
|         } | ||||
|     } | ||||
| } | ||||
					Loading…
					
					
				
		Reference in new issue