diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/CameraView.java b/cameraview/src/main/java/com/otaliastudios/cameraview/CameraView.java index b76543a6..8a3e546b 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/CameraView.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/CameraView.java @@ -68,6 +68,7 @@ import com.otaliastudios.cameraview.markers.MarkerLayout; import com.otaliastudios.cameraview.markers.MarkerParser; import com.otaliastudios.cameraview.overlay.OverlayLayout; import com.otaliastudios.cameraview.preview.CameraPreview; +import com.otaliastudios.cameraview.preview.FilterCameraPreview; import com.otaliastudios.cameraview.preview.GlCameraPreview; import com.otaliastudios.cameraview.preview.SurfaceCameraPreview; import com.otaliastudios.cameraview.preview.TextureCameraPreview; @@ -2132,17 +2133,27 @@ public class CameraView extends FrameLayout implements LifecycleObserver { //endregion - //region Effects - - public void setFilter(@NonNull Filters filter) { - setFilter(filter.newInstance()); - } + //region Filters + /** + * Applies a real-time filter to the camera preview, if it supports it. + * The only preview type that does so is currently {@link Preview#GL_SURFACE}. + * + * The filter will be applied to any picture snapshot taken with + * {@link #takePictureSnapshot()} and any video snapshot taken with + * {@link #takeVideoSnapshot(File)}. + * + * Use {@link com.otaliastudios.cameraview.filters.NoFilter} to clear the existing filter, + * and take a look at the {@link Filters} class for commonly used filters. + * + * @see Filters + * @param filter a new filter + */ public void setFilter(@NonNull Filter filter) { - if (mCameraPreview instanceof GlCameraPreview) { - ((GlCameraPreview) mCameraPreview).setShaderEffect(filter); + if (mCameraPreview instanceof FilterCameraPreview) { + ((FilterCameraPreview) mCameraPreview).setFilter(filter); } else { - LOG.w("setFilter", "setFilter is supported only for GLSurfaceView"); + LOG.w("setFilter() is supported only for GL_SURFACE. Preview:", mPreview); } } diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/filters/Filters.java b/cameraview/src/main/java/com/otaliastudios/cameraview/filters/Filters.java index 2747ddc9..620527c5 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/filters/Filters.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/filters/Filters.java @@ -2,6 +2,12 @@ package com.otaliastudios.cameraview.filters; import androidx.annotation.NonNull; +/** + * Contains commonly used {@link Filter}s. + * + * You can use {@link #newInstance()} to create a new instance and + * pass it to {@link com.otaliastudios.cameraview.CameraView#setFilter(Filter)}. + */ public enum Filters { NONE(NoFilter.class), AUTO_FIX(AutoFixFilter.class), @@ -32,6 +38,10 @@ public enum Filters { this.filterClass = filterClass; } + /** + * Returns a new instance of the given filter. + * @return a new instance + */ @NonNull public Filter newInstance() { try { diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/internal/egl/EglViewport.java b/cameraview/src/main/java/com/otaliastudios/cameraview/internal/egl/EglViewport.java index d1be7c14..0868ac1f 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/internal/egl/EglViewport.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/internal/egl/EglViewport.java @@ -63,11 +63,13 @@ public class EglViewport extends EglElement { private boolean mIsShaderChanged = false; public EglViewport() { + this(new NoFilter()); + } + + public EglViewport(@NonNull Filter filter) { mTextureTarget = GLES11Ext.GL_TEXTURE_EXTERNAL_OES; mTextureUnit = GLES20.GL_TEXTURE0; - - //init the default shader effect - mShaderEffect = new NoFilter(); + mShaderEffect = filter; initProgram(); } 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 9e88c955..0bf448ba 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/picture/SnapshotGlPictureRecorder.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/picture/SnapshotGlPictureRecorder.java @@ -97,9 +97,9 @@ public class SnapshotGlPictureRecorder extends PictureRecorder { @RendererThread @Override - public void onRendererFrame(@NonNull SurfaceTexture surfaceTexture, final float scaleX, final float scaleY, Filter shaderEffect) { + public void onRendererFrame(@NonNull SurfaceTexture surfaceTexture, final float scaleX, final float scaleY) { mPreview.removeRendererFrameCallback(this); - SnapshotGlPictureRecorder.this.onRendererFrame(surfaceTexture, scaleX, scaleY, shaderEffect); + SnapshotGlPictureRecorder.this.onRendererFrame(surfaceTexture, scaleX, scaleY); } @Override @@ -151,7 +151,7 @@ public class SnapshotGlPictureRecorder extends PictureRecorder { */ @RendererThread @TargetApi(Build.VERSION_CODES.KITKAT) - private void onRendererFrame(final @NonNull SurfaceTexture surfaceTexture, final float scaleX, final float scaleY, @NonNull Filter filter) { + private void onRendererFrame(final @NonNull SurfaceTexture surfaceTexture, final float scaleX, final float scaleY) { // Get egl context from the RendererThread, which is the one in which we have created // the textureId and the overlayTextureId, managed by the GlSurfaceView. // Next operations can then be performed on different threads using this handle. diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/preview/FilterCameraPreview.java b/cameraview/src/main/java/com/otaliastudios/cameraview/preview/FilterCameraPreview.java new file mode 100644 index 00000000..c36a9dd2 --- /dev/null +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/preview/FilterCameraPreview.java @@ -0,0 +1,26 @@ +package com.otaliastudios.cameraview.preview; + + +import android.content.Context; +import android.view.View; +import android.view.ViewGroup; + +import androidx.annotation.NonNull; + +import com.otaliastudios.cameraview.filters.Filter; + + +/** + * A preview that support GL filters defined through the {@link Filter} interface. + */ +public abstract class FilterCameraPreview extends CameraPreview { + + public FilterCameraPreview(@NonNull Context context, @NonNull ViewGroup parent) { + super(context, parent); + } + + public abstract void setFilter(@NonNull Filter filter); + + @NonNull + public abstract Filter getCurrentFilter(); +} diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/preview/GlCameraPreview.java b/cameraview/src/main/java/com/otaliastudios/cameraview/preview/GlCameraPreview.java index 28142c89..3aacbf10 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/preview/GlCameraPreview.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/preview/GlCameraPreview.java @@ -58,7 +58,7 @@ import javax.microedition.khronos.opengles.GL10; * Callbacks are guaranteed to be called on the renderer thread, which means that we can fetch * the GL context that was created and is managed by the {@link GLSurfaceView}. */ -public class GlCameraPreview extends CameraPreview { +public class GlCameraPreview extends FilterCameraPreview { private boolean mDispatched; private final float[] mTransformMatrix = new float[16]; @@ -69,8 +69,7 @@ public class GlCameraPreview extends CameraPreview