diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/internal/egl/EglBaseSurface.java b/cameraview/src/main/java/com/otaliastudios/cameraview/internal/egl/EglBaseSurface.java deleted file mode 100644 index be07f0b1..00000000 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/internal/egl/EglBaseSurface.java +++ /dev/null @@ -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. - *
- * 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. - *
- * @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. - *
- * 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. - *
- * 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. - *
- * 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(); - } -} diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/internal/egl/EglCore.java b/cameraview/src/main/java/com/otaliastudios/cameraview/internal/egl/EglCore.java deleted file mode 100644 index 3d9c6b65..00000000 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/internal/egl/EglCore.java +++ /dev/null @@ -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). - *
- * 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. - *
- * Equivalent to EglCore(null, 0). - */ - public EglCore() { - this(null, 0); - } - - /** - * Prepares EGL display and context. - *
- * @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. - *
- * 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. - *
- * 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)); - } - } -} diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/internal/egl/EglWindowSurface.java b/cameraview/src/main/java/com/otaliastudios/cameraview/internal/egl/EglWindowSurface.java deleted file mode 100644 index 0cb49776..00000000 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/internal/egl/EglWindowSurface.java +++ /dev/null @@ -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. - *
- * 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. - *
- * 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). - *
- * Does not require that the surface's EGL context be current. - */ - public void release() { - releaseEglSurface(); - if (mSurface != null) { - if (mReleaseSurface) { - mSurface.release(); - } - mSurface = null; - } - } -} diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/picture/SnapshotGlPictureRecorder.java b/cameraview/src/main/java/com/otaliastudios/cameraview/picture/SnapshotGlPictureRecorder.java index 121a63bf..7b2dca41 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/picture/SnapshotGlPictureRecorder.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/picture/SnapshotGlPictureRecorder.java @@ -11,7 +11,6 @@ import android.os.Build; import com.otaliastudios.cameraview.PictureResult; import com.otaliastudios.cameraview.internal.GlTextureDrawer; -import com.otaliastudios.cameraview.internal.egl.EglBaseSurface; import com.otaliastudios.cameraview.overlay.Overlay; import com.otaliastudios.cameraview.controls.Facing; import com.otaliastudios.cameraview.engine.CameraEngine; @@ -46,7 +45,7 @@ import android.view.Surface; * - We move to another thread, and create a new EGL surface for that EGL context. * - We make this new surface current, and re-draw the textureId on it * - [Optional: fill the overlayTextureId and draw it on the same surface] - * - We use glReadPixels (through {@link EglBaseSurface#saveFrameTo(Bitmap.CompressFormat)}) + * - We use glReadPixels (through {@link EglSurface#toByteArray(Bitmap.CompressFormat)}) * and save to file. * * We create a new EGL surface and redraw the frame because: