/* * * * * * * Copyright (C) 2016 ChillingVan * * * * * * 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.chillingvan.canvasgl.glview.texture; import android.content.Context; import android.graphics.SurfaceTexture; import android.opengl.GLES11Ext; import android.opengl.GLES20; import android.os.Build; import android.util.AttributeSet; import android.util.Log; import com.chillingvan.canvasgl.ICanvasGL; import com.chillingvan.canvasgl.glview.texture.gles.EglContextWrapper; import com.chillingvan.canvasgl.glview.texture.gles.GLThread; import com.chillingvan.canvasgl.util.Loggers; import java.util.ArrayList; import java.util.List; /** * Used to generate multiple textures or consume textures from others. * This will not create {@link GLThread} automatically. You need to call {@link #setSharedEglContext(EglContextWrapper)} to trigger it. * Support providing multiple textures to Camera or Media. <br> * This can also consume textures from other GL zone( Should be in same GL context) <br> * And since this inherits {@link GLMultiTexConsumerView}, the {@link #setSharedEglContext} must be called */ public abstract class GLMultiTexProducerView extends GLMultiTexConsumerView { private static final String TAG = "GLMultiTexProducerView"; private int producedTextureTarget = GLES11Ext.GL_TEXTURE_EXTERNAL_OES; private List<GLTexture> producedTextureList = new ArrayList<>(); private SurfaceTextureCreatedListener surfaceTextureCreatedListener; public GLMultiTexProducerView(Context context) { super(context); } public GLMultiTexProducerView(Context context, AttributeSet attrs) { super(context, attrs); } public GLMultiTexProducerView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override protected final void onGLDraw(ICanvasGL canvas, List<GLTexture> consumedTextures) { onGLDraw(canvas, producedTextureList, consumedTextures); } @Override protected int getRenderMode() { return GLThread.RENDERMODE_WHEN_DIRTY; } /** * * @return The initial produced texture count */ protected int getInitialTexCount() { return 1; } /** * If it is used, it must be called before {@link GLThread#start()} called. * @param producedTextureTarget GLES20.GL_TEXTURE_2D or GLES11Ext.GL_TEXTURE_EXTERNAL_OES */ public void setProducedTextureTarget(int producedTextureTarget) { this.producedTextureTarget = producedTextureTarget; } @Override public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) { super.onSurfaceTextureAvailable(surface, width, height); } /** * Create a new produced texture and upload it to the canvas. */ public GLTexture addProducedGLTexture(int width, int height, boolean opaque, int target) { GLTexture glTexture = GLTexture.createRaw(width, height, opaque, target, mCanvas); producedTextureList.add(glTexture); return glTexture; } @Override public void onSurfaceChanged(int width, int height) { super.onSurfaceChanged(width, height); Loggers.d(TAG, "onSurfaceChanged: " + width + ", " + height); if (producedTextureList.isEmpty()) { for (int i = 0; i < getInitialTexCount(); i++) { // This must be in this thread because it relies on the GLContext of this thread producedTextureList.add(GLTexture.createRaw(width, height, false, producedTextureTarget, mCanvas)); } post(new Runnable() { @Override public void run() { if (!producedTextureList.isEmpty() && surfaceTextureCreatedListener != null) { surfaceTextureCreatedListener.onCreated(producedTextureList); } } }); } else { for (GLTexture glTexture : producedTextureList) { glTexture.getRawTexture().setSize(width, height); } } } @Override public void onDrawFrame() { if (producedTextureTarget != GLES20.GL_TEXTURE_2D) { for (GLTexture glTexture : producedTextureList) { glTexture.getSurfaceTexture().updateTexImage(); glTexture.getRawTexture().setNeedInvalidate(true); } } super.onDrawFrame(); } @Override public void onPause() { super.onPause(); Loggers.d(TAG, "onPause"); recycleProduceTexture(); if (mGLThread == null) { Log.w(TAG, "!!!!!! You may not call setShareEglContext !!!"); } } @Override protected void surfaceDestroyed() { super.surfaceDestroyed(); recycleProduceTexture(); } private void recycleProduceTexture() { for (GLTexture glTexture : producedTextureList) { if (!glTexture.getRawTexture().isRecycled()) { glTexture.getRawTexture().recycle(); } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { if (!glTexture.getSurfaceTexture().isReleased()) { glTexture.getSurfaceTexture().release(); } } else { glTexture.getSurfaceTexture().release(); } } producedTextureList.clear(); } /** * Set the listener to listen the texture creation. * @param surfaceTextureCreatedListener The texture listener */ public void setSurfaceTextureCreatedListener(SurfaceTextureCreatedListener surfaceTextureCreatedListener) { this.surfaceTextureCreatedListener = surfaceTextureCreatedListener; } /** * Listen when the produced textures created. */ public interface SurfaceTextureCreatedListener { /** * You can get the created Textures from this method. * The number of textures is decided by {@link GLMultiTexProducerView#getInitialTexCount} * @param producedTextureList The created Textures */ void onCreated(List<GLTexture> producedTextureList); } /** * If {@link #setSharedEglContext(EglContextWrapper)} is not called, this will not be triggered. * The consumedTextures are obtained from {@link GLMultiTexConsumerView#addConsumeGLTexture} * @param canvas the canvas to draw things * @param producedTextures The textures created by itself. * @param consumedTextures May be null. This only available when it gets from other GLMultiTexProducerView */ protected abstract void onGLDraw(ICanvasGL canvas, List<GLTexture> producedTextures, List<GLTexture> consumedTextures); }