From 0dbbdd009092da77757d8ee2480dd4b4e1b0a793 Mon Sep 17 00:00:00 2001 From: Mattia Iavarone Date: Mon, 5 Aug 2019 20:34:16 +0200 Subject: [PATCH] Add more docs and Filter.copy() --- .../cameraview/filters/BaseFilter.java | 66 ++++++++++++----- .../cameraview/filters/Filter.java | 72 +++++++++++++++++-- .../picture/SnapshotGlPictureRecorder.java | 2 +- .../video/SnapshotVideoRecorder.java | 4 +- 4 files changed, 117 insertions(+), 27 deletions(-) diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/filters/BaseFilter.java b/cameraview/src/main/java/com/otaliastudios/cameraview/filters/BaseFilter.java index 35890eca..db930822 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/filters/BaseFilter.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/filters/BaseFilter.java @@ -6,26 +6,34 @@ import androidx.annotation.NonNull; import com.otaliastudios.cameraview.CameraLogger; import com.otaliastudios.cameraview.internal.GlUtils; +import com.otaliastudios.cameraview.size.Size; import java.nio.FloatBuffer; /** - * A Base abstract class that every effect must extend so that there is a common getShader method. - *

- * This class has a default Vertex Shader implementation which in most cases not required to touch. - * In Effects like sepia, B/W any many, only pixel color changes which can be managed by only fragment shader. - * If there is some other effect which requires vertex shader also change, you can override it. - *

- * If your provide your own vertex and fragment shader, - * please set the {@link #mPositionVariableName}, {@link #mTextureCoordinateVariableName}, - * {@link #mMVPMatrixVariableName}, {@link #mTextureMatrixVariableName} - * according to your shader code. - *

- * Please note that these shader applies on live preview as well as pictureSnapshot and videoSnapshot, - * we only support GLES11Ext.GL_TEXTURE_EXTERNAL_OES - * check EglViewport() - *

- * The default implementation of this class is NoEffect. + * A base implementation of {@link Filter} that just leaves the fragment shader to subclasses. + * See {@link NoFilter} for a full implementation. + * + * This class offers a default vertex shader implementation which in most cases is not required + * to be changed. Most effects can be rendered by simply changing the fragment shader, thus + * by overriding {@link #getFragmentShader()}. + * + * This class expects variable to have a certain name: + * - {@link #vertexPositionName} + * - {@link #vertexTransformMatrixName} + * - {@link #vertexModelViewProjectionMatrixName} + * - {@link #vertexTextureCoordinateName} + * - {@link #fragmentTextureCoordinateName} + * + * You can either change these variables, for example in your constructor, or change your + * vertex and fragment shader code to use them. + * + * NOTE - All {@link BaseFilter}s should have a no-op public constructor. + * + * NOTE - the {@link android.graphics.SurfaceTexture} restrictions apply: + * We only support the {@link android.opengl.GLES11Ext#GL_TEXTURE_EXTERNAL_OES} texture target + * and it must be specified in the fragment shader as a samplerExternalOES texture. + * You also have to explicitly require the extension: see {@link #createDefaultFragmentShader(String)}. */ public abstract class BaseFilter implements Filter { @@ -65,6 +73,7 @@ public abstract class BaseFilter implements Filter { + " gl_FragColor = texture2D(sTexture, "+fragmentTextureCoordinateName+");\n" + "}\n"; } + // When the model/view/projection matrix is identity, this will exactly cover the viewport. private FloatBuffer vertexPosition = GlUtils.floatBuffer(new float[]{ -1.0f, -1.0f, // 0 bottom left @@ -84,6 +93,7 @@ public abstract class BaseFilter implements Filter { private int vertexTranformMatrixLocation = -1; private int vertexPositionLocation = -1; private int vertexTextureCoordinateLocation = -1; + private Size outputSize; @SuppressWarnings("WeakerAccess") protected String vertexPositionName = DEFAULT_VERTEX_POSITION_NAME; @@ -126,7 +136,10 @@ public abstract class BaseFilter implements Filter { @Override public void onDestroy(int programHandle) { - // Do nothing. + vertexPositionLocation = -1; + vertexTextureCoordinateLocation = -1; + vertexModelViewProjectionMatrixLocation = -1; + vertexTranformMatrixLocation = -1; } @NonNull @@ -137,7 +150,7 @@ public abstract class BaseFilter implements Filter { @Override public void setOutputSize(int width, int height) { - + outputSize = new Size(width, height); } @Override @@ -184,4 +197,21 @@ public abstract class BaseFilter implements Filter { GLES20.glDisableVertexAttribArray(vertexTextureCoordinateLocation); } + @Override + public BaseFilter copy() { + BaseFilter copy = onCopy(); + copy.setOutputSize(outputSize.getWidth(), outputSize.getHeight()); + return copy; + } + + @SuppressWarnings("WeakerAccess") + protected BaseFilter onCopy() { + try { + return getClass().newInstance(); + } catch (IllegalAccessException e) { + throw new RuntimeException("Filters should have a public no-op constructor.", e); + } catch (InstantiationException e) { + throw new RuntimeException("Filters should have a public no-op constructor.", e); + } + } } diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/filters/Filter.java b/cameraview/src/main/java/com/otaliastudios/cameraview/filters/Filter.java index ebdcb580..9fc22caf 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/filters/Filter.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/filters/Filter.java @@ -1,22 +1,82 @@ package com.otaliastudios.cameraview.filters; +import com.otaliastudios.cameraview.CameraView; + import androidx.annotation.NonNull; +import java.io.File; + +/** + * A Filter is a real time filter that operates onto the camera preview, plus any + * snapshot media taken with {@link CameraView#takePictureSnapshot()} and + * {@link CameraView#takeVideoSnapshot(File)}. + * + * You can apply filters to the camera engine using {@link CameraView#setFilter(Filter)}. + * The default filter is called {@link NoFilter} and can be used to restore the normal preview. + * A lof of other filters are collected in the {@link Filters} class. + * + * Advanced users can create custom filters using GLES. + * It is recommended to extend {@link BaseFilter} instead of this class. + */ public interface Filter { + /** + * Returns a String containing the vertex shader. + * Together with {@link #getFragmentShader()}, this will be used to + * create the OpenGL program. + * + * @return vertex shader + */ + @NonNull + String getVertexShader(); + + /** + * Returns a String containing the fragment shader. + * Together with {@link #getVertexShader()}, this will be used to + * create the OpenGL program. + * + * @return fragment shader + */ + @NonNull + String getFragmentShader(); + + /** + * The filter program was just created. We pass in a handle to the OpenGL + * program that was created, so you can fetch pointers. + * + * @param programHandle handle + */ void onCreate(int programHandle); + /** + * The filter program is about to be destroyed. + * + * @param programHandle handle + */ void onDestroy(int programHandle); + /** + * Called to render the actual texture. The given transformation matrix + * should be applied. + * + * @param transformMatrix matrix + */ void draw(float[] transformMatrix); + /** + * Called anytime the output size changes. + * @param width width + * @param height height + */ void setOutputSize(int width, int height); - @NonNull - String getVertexShader(); - - @NonNull - String getFragmentShader(); - + /** + * Clones this filter creating a new instance of it. + * If it has any important parameters, these should be passed + * to the new instance. + * + * @return a clone + */ + Filter copy(); } 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 e3394120..2ac45463 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/picture/SnapshotGlPictureRecorder.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/picture/SnapshotGlPictureRecorder.java @@ -104,7 +104,7 @@ public class SnapshotGlPictureRecorder extends PictureRecorder { @Override public void onFilterChanged(@NonNull Filter filter) { - mViewport.setFilter(filter); + mViewport.setFilter(filter.copy()); } }); } diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/video/SnapshotVideoRecorder.java b/cameraview/src/main/java/com/otaliastudios/cameraview/video/SnapshotVideoRecorder.java index 8b4184ea..3ff517ba 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/video/SnapshotVideoRecorder.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/video/SnapshotVideoRecorder.java @@ -104,9 +104,9 @@ public class SnapshotVideoRecorder extends VideoRecorder implements RendererFram @Override public void onFilterChanged(@NonNull Filter filter) { - mCurrentFilter = filter; + mCurrentFilter = filter.copy(); if (mEncoderEngine != null) { - mEncoderEngine.notify(TextureMediaEncoder.FILTER_EVENT, filter); + mEncoderEngine.notify(TextureMediaEncoder.FILTER_EVENT, mCurrentFilter); } }