public abstract class

CameraEffect

extends java.lang.Object

 java.lang.Object

↳androidx.camera.core.CameraEffect

Subclasses:

OverlayEffect

Gradle dependencies

compile group: 'androidx.camera', name: 'camera-core', version: '1.5.0-alpha01'

  • groupId: androidx.camera
  • artifactId: camera-core
  • version: 1.5.0-alpha01

Artifact androidx.camera:camera-core:1.5.0-alpha01 it located at Google repository (https://maven.google.com/)

Overview

An effect for one or multiple camera outputs.

This API allows the implementer to inject code into CameraX pipeline and apply visual effects, such as a portrait effect. The CameraEffect class contains two types of information, the processor and the configuration.

  • The processor is an implementation of either SurfaceProcessor or ImageProcessor. It consumes original camera frames from CameraX, applies the effect, and returns the processed frames back to CameraX.
  • The configuration provides information on how the processor should be injected into the pipeline. For example, the target UseCases where the effect should be applied. It may also contain information about camera configuration. For example, the exposure level.

If CameraX fails to send frames to the CameraEffect, the error will be delivered to the app via error callbacks such as ImageCapture.OnImageCapturedCallback.onError(ImageCaptureException). If CameraEffect fails to process and return the frames, for example, unable to allocate the resources for image processing, it must throw java.lang.Throwable in the processor implementation. The java.lang.Throwable will be caught and forwarded to the app via error callbacks. Please see the Javadoc of the processor interfaces for details.

Extend this class to create specific effects. The java.util.concurrent.Executor provided in the constructors will be used by CameraX to call the processors.

Code sample for a portrait effect that targets the Preview UseCase:


 class PortraitPreviewEffect extends CameraEffect {
     PortraitPreviewEffect() {
         super(PREVIEW, getExecutor(), getSurfaceProcessor());
     }

     private static Executor getExecutor() {
         // Returns an executor for calling the SurfaceProcessor
     }

     private static SurfaceProcessor getSurfaceProcessor() {
         // Return a SurfaceProcessor implementation that applies a portrait effect.
     }
 }
 

Summary

Fields
public static final intIMAGE_CAPTURE

Bitmask option to indicate that CameraX should apply this effect to ImageCapture.

public static final intOUTPUT_OPTION_ONE_FOR_ALL_TARGETS

Use this option to receive one output Surface for all the output targets.

public static final intOUTPUT_OPTION_ONE_FOR_EACH_TARGET

Use this option to receive one output Surface for each corresponding output target.

public static final intPREVIEW

Bitmask option to indicate that CameraX should apply this effect to Preview.

public static final intTRANSFORMATION_ARBITRARY

Flag to indicate that the implementation will handle arbitrary transformation.

public static final intTRANSFORMATION_CAMERA_AND_SURFACE_ROTATION

Flag to indicate that the implementation will handle the camera and the Surface rotation.

public static final intTRANSFORMATION_PASSTHROUGH

Flag to indicate that the surface processor should be ignored, so no transformation is required.

public static final intVIDEO_CAPTURE

Bitmask option to indicate that CameraX should apply this effect to VideoCapture.

Constructors
protectedCameraEffect(int targets, java.util.concurrent.Executor executor, ImageProcessor imageProcessor, Consumer<java.lang.Throwable> errorListener)

protectedCameraEffect(int targets, java.util.concurrent.Executor executor, SurfaceProcessor surfaceProcessor, Consumer<java.lang.Throwable> errorListener)

protectedCameraEffect(int targets, int transformation, java.util.concurrent.Executor executor, SurfaceProcessor surfaceProcessor, Consumer<java.lang.Throwable> errorListener)

protectedCameraEffect(int targets, int outputOption, int transformation, java.util.concurrent.Executor executor, SurfaceProcessor surfaceProcessor, Consumer<java.lang.Throwable> errorListener)

Methods
public SurfaceProcessorInternalcreateSurfaceProcessorInternal()

Creates a SurfaceProcessorInternal instance.

public Consumer<java.lang.Throwable>getErrorListener()

Gets the Error listener associated with this effect.

public java.util.concurrent.ExecutorgetExecutor()

Gets the java.util.concurrent.Executor associated with this effect.

public ImageProcessorgetImageProcessor()

Gets the ImageProcessor associated with this effect.

public intgetOutputOption()

Gets the target option.

public SurfaceProcessorgetSurfaceProcessor()

Gets the SurfaceProcessor associated with this effect.

public intgetTargets()

Ges the target UseCases of this effect.

public intgetTransformation()

Gets the transformation that the SurfaceProcessor will handle.

from java.lang.Objectclone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait

Fields

public static final int PREVIEW

Bitmask option to indicate that CameraX should apply this effect to Preview.

public static final int VIDEO_CAPTURE

Bitmask option to indicate that CameraX should apply this effect to VideoCapture.

public static final int IMAGE_CAPTURE

Bitmask option to indicate that CameraX should apply this effect to ImageCapture.

public static final int TRANSFORMATION_ARBITRARY

Flag to indicate that the implementation will handle arbitrary transformation.

When this flag is used, CameraX may suggest arbitrary transformation via SurfaceOutput.updateTransformMatrix(float[], float[]) for the SurfaceProcessor to handle, including mirroring, rotating, cropping and/or scaling.

Use this flag if the CameraEffect implementation can handle arbitrary transformation.

public static final int TRANSFORMATION_CAMERA_AND_SURFACE_ROTATION

Flag to indicate that the implementation will handle the camera and the Surface rotation.

When this flag is used, the value of SurfaceOutput.updateTransformMatrix(float[], float[]) will be a combination of the camera sensor orientation and the Surface rotation. The camera rotation is the value written by camera framework, which can be retrieved via if the consumer is a . The Surface rotation is the value of the default Display.

Use this flag if the CameraEffect implementation handles the camera and the Surface rotation.

public static final int TRANSFORMATION_PASSTHROUGH

Flag to indicate that the surface processor should be ignored, so no transformation is required.

Use this flag if the CameraEffect only intends to specify the targets of buffer sharing.

public static final int OUTPUT_OPTION_ONE_FOR_ALL_TARGETS

Use this option to receive one output Surface for all the output targets.

When the effect targets multiple UseCases, e.g. Preview, VideoCapture, the effect will only receive one output Surface for all the outputs. CameraX is responsible for copying the processed frames to different output Surfaces.

Use this option if all UseCases receive the same content.

public static final int OUTPUT_OPTION_ONE_FOR_EACH_TARGET

Use this option to receive one output Surface for each corresponding output target.

When the effect targets multiple UseCases, e.g. Preview, VideoCapture, the effect will receive two output Surfaces, one for Preview and one for VideoCapture. The effect is responsible for drawing the processed frames to the corresponding output Surfaces.

Use this option if each UseCase receives different content.

Constructors

protected CameraEffect(int targets, java.util.concurrent.Executor executor, ImageProcessor imageProcessor, Consumer<java.lang.Throwable> errorListener)

Parameters:

targets: the target UseCase to which this effect should be applied. Currently, ImageProcessor can only target CameraEffect.IMAGE_CAPTURE. Targeting other UseCase will throw java.lang.IllegalArgumentException.
executor: the java.util.concurrent.Executor on which the imageProcessor and errorListener will be invoked.
imageProcessor: a ImageProcessor implementation. Once the effect is active, CameraX will send frames to the ImageProcessor on the executor, and deliver the processed frames to the app.
errorListener: invoked if the effect runs into unrecoverable errors. This is invoked on the provided executor.

protected CameraEffect(int targets, int transformation, java.util.concurrent.Executor executor, SurfaceProcessor surfaceProcessor, Consumer<java.lang.Throwable> errorListener)

protected CameraEffect(int targets, int outputOption, int transformation, java.util.concurrent.Executor executor, SurfaceProcessor surfaceProcessor, Consumer<java.lang.Throwable> errorListener)

Parameters:

targets: the target UseCase to which this effect should be applied. Currently SurfaceProcessor can target the following combinations:

Targeting other UseCase combinations will throw java.lang.IllegalArgumentException.
outputOption: the option to specify how many output Surface the effect will handle.
transformation: the transformation that the SurfaceProcessor will handle.
executor: the java.util.concurrent.Executor on which the imageProcessor and errorListener will be invoked.
surfaceProcessor: a SurfaceProcessor implementation. Once the effect is active, CameraX will send frames to the SurfaceProcessor on the executor, and deliver the processed frames to the app.
errorListener: invoked if the effect runs into unrecoverable errors. The java.lang.Throwable will be the error thrown by this CameraEffect. For example, ProcessingException. This is invoked on the provided executor.

protected CameraEffect(int targets, java.util.concurrent.Executor executor, SurfaceProcessor surfaceProcessor, Consumer<java.lang.Throwable> errorListener)

Parameters:

targets: the target UseCase to which this effect should be applied. Currently SurfaceProcessor can target the following combinations:

Targeting other UseCase combinations will throw java.lang.IllegalArgumentException.
executor: the java.util.concurrent.Executor on which the imageProcessor and errorListener will be invoked.
surfaceProcessor: a SurfaceProcessor implementation. Once the effect is active, CameraX will send frames to the SurfaceProcessor on the executor, and deliver the processed frames to the app.
errorListener: invoked if the effect runs into unrecoverable errors. The java.lang.Throwable will be the error thrown by this CameraEffect. For example, ProcessingException. This is invoked on the provided executor.

Methods

public int getTargets()

Ges the target UseCases of this effect.

public int getTransformation()

Gets the transformation that the SurfaceProcessor will handle.

public int getOutputOption()

Gets the target option.

public java.util.concurrent.Executor getExecutor()

Gets the java.util.concurrent.Executor associated with this effect.

This method returns the value set in the constructor.

public Consumer<java.lang.Throwable> getErrorListener()

Gets the Error listener associated with this effect.

This method returns the value set in the constructor. The java.lang.Throwable will be the error thrown by this CameraEffect. For example, ProcessingException.

public SurfaceProcessor getSurfaceProcessor()

Gets the SurfaceProcessor associated with this effect.

public ImageProcessor getImageProcessor()

Gets the ImageProcessor associated with this effect.

public SurfaceProcessorInternal createSurfaceProcessorInternal()

Creates a SurfaceProcessorInternal instance.

Throws java.lang.IllegalArgumentException if the effect does not contain a SurfaceProcessor.

Source

/*
 * Copyright 2022 The Android Open Source Project
 *
 * 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 androidx.camera.core;

import static androidx.camera.core.impl.ImageFormatConstants.INTERNAL_DEFINED_IMAGE_FORMAT_PRIVATE;
import static androidx.camera.core.processing.TargetUtils.checkSupportedTargets;
import static androidx.core.util.Preconditions.checkArgument;

import android.graphics.ImageFormat;
import android.view.Display;

import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RestrictTo;
import androidx.camera.core.processing.SurfaceProcessorInternal;
import androidx.camera.core.processing.SurfaceProcessorWithExecutor;
import androidx.core.util.Consumer;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.Executor;

/**
 * An effect for one or multiple camera outputs.
 *
 * <p>This API allows the implementer to inject code into CameraX pipeline and apply visual
 * effects, such as a portrait effect. The {@link CameraEffect} class contains two types of
 * information, the processor and the configuration.
 * <ul>
 * <li>The processor is an implementation of either {@link SurfaceProcessor} or
 * {@link ImageProcessor}. It consumes original camera frames from CameraX, applies the effect,
 * and returns the processed frames back to CameraX.
 * <li>The configuration provides information on how the processor should be injected into the
 * pipeline. For example, the target {@link UseCase}s where the effect should be applied. It may
 * also contain information about camera configuration. For example, the exposure level.
 * </ul>
 *
 * <p>If CameraX fails to send frames to the {@link CameraEffect}, the error will be
 * delivered to the app via error callbacks such as
 * {@link ImageCapture.OnImageCapturedCallback#onError}. If {@link CameraEffect} fails to
 * process and return the frames, for example, unable to allocate the resources for image
 * processing, it must throw {@link Throwable} in the processor implementation. The
 * {@link Throwable} will be caught and forwarded to the app via error callbacks. Please see the
 * Javadoc of the processor interfaces for details.
 *
 * <p>Extend this class to create specific effects. The {@link Executor} provided in the
 * constructors will be used by CameraX to call the processors.
 *
 * <p>Code sample for a portrait effect that targets the {@link Preview} {@link UseCase}:
 *
 * <pre><code>
 * class PortraitPreviewEffect extends CameraEffect {
 *     PortraitPreviewEffect() {
 *         super(PREVIEW, getExecutor(), getSurfaceProcessor());
 *     }
 *
 *     private static Executor getExecutor() {
 *         // Returns an executor for calling the SurfaceProcessor
 *     }
 *
 *     private static SurfaceProcessor getSurfaceProcessor() {
 *         // Return a SurfaceProcessor implementation that applies a portrait effect.
 *     }
 * }
 * </code></pre>
 */
public abstract class CameraEffect {

    /**
     * Options for the transformation handled by the effect.
     */
    @Retention(RetentionPolicy.SOURCE)
    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
    @IntDef(flag = true, value = {TRANSFORMATION_ARBITRARY,
            TRANSFORMATION_CAMERA_AND_SURFACE_ROTATION, TRANSFORMATION_PASSTHROUGH})
    public @interface Transformations {
    }

    /**
     * Bitmask options for the effect targets.
     */
    @Retention(RetentionPolicy.SOURCE)
    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
    @IntDef(flag = true, value = {PREVIEW, VIDEO_CAPTURE, IMAGE_CAPTURE})
    public @interface Targets {
    }

    /**
     * Options for how many outputs the effect handles.
     */
    @Retention(RetentionPolicy.SOURCE)
    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
    @IntDef(value = {OUTPUT_OPTION_ONE_FOR_ALL_TARGETS, OUTPUT_OPTION_ONE_FOR_EACH_TARGET})
    public @interface OutputOptions {
    }

    /**
     * Bitmask options for the effect buffer formats.
     */
    @Retention(RetentionPolicy.SOURCE)
    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
    @IntDef(flag = true, value = {INTERNAL_DEFINED_IMAGE_FORMAT_PRIVATE, ImageFormat.JPEG})
    public @interface Formats {
    }

    /**
     * Bitmask option to indicate that CameraX should apply this effect to {@link Preview}.
     */
    public static final int PREVIEW = 1;

    /**
     * Bitmask option to indicate that CameraX should apply this effect to {@code VideoCapture}.
     */
    public static final int VIDEO_CAPTURE = 1 << 1;

    /**
     * Bitmask option to indicate that CameraX should apply this effect to {@link ImageCapture}.
     */
    public static final int IMAGE_CAPTURE = 1 << 2;

    // Allowed targets for SurfaceProcessor
    private static final List<Integer> SURFACE_PROCESSOR_TARGETS = Arrays.asList(
            PREVIEW,
            VIDEO_CAPTURE,
            PREVIEW | VIDEO_CAPTURE,
            PREVIEW | VIDEO_CAPTURE | IMAGE_CAPTURE);

    /**
     * Flag to indicate that the implementation will handle arbitrary transformation.
     *
     * <p>When this flag is used, CameraX may suggest arbitrary transformation via
     * {@link SurfaceOutput#updateTransformMatrix} for the {@link SurfaceProcessor} to handle,
     * including mirroring, rotating, cropping and/or scaling.
     *
     * <p>Use this flag if the {@link CameraEffect} implementation can handle arbitrary
     * transformation.
     */
    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
    public static final int TRANSFORMATION_ARBITRARY = 0;

    /**
     * Flag to indicate that the implementation will handle the camera and the Surface rotation.
     *
     * <p>When this flag is used, the value of {@link SurfaceOutput#updateTransformMatrix} will
     * be a combination of the camera sensor orientation and the Surface rotation. The camera
     * rotation is the value written by camera framework, which can be retrieved via
     * {@link android.graphics.SurfaceTexture#getTransformMatrix(float[])} if the consumer is a
     * {@link android.graphics.SurfaceTexture}. The Surface rotation is the value of the default
     * {@link Display#getRotation()}.
     *
     * <p>Use this flag if the {@link CameraEffect} implementation handles the camera and the
     * Surface rotation.
     */
    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
    public static final int TRANSFORMATION_CAMERA_AND_SURFACE_ROTATION = 1;

    /**
     * Flag to indicate that the surface processor should be ignored, so no transformation is
     * required.
     *
     * <p>Use this flag if the {@link CameraEffect} only intends to specify the targets of buffer
     * sharing.
     */
    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
    public static final int TRANSFORMATION_PASSTHROUGH = 2;

    /**
     * Use this option to receive one output Surface for all the output targets.
     *
     * <p>When the effect targets multiple UseCases, e.g. Preview, VideoCapture, the effect will
     * only receive one output Surface for all the outputs. CameraX is responsible for copying the
     * processed frames to different output Surfaces.
     *
     * <p>Use this option if all UseCases receive the same content.
     */
    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
    public static final int OUTPUT_OPTION_ONE_FOR_ALL_TARGETS = 0;

    /**
     * Use this option to receive one output Surface for each corresponding output target.
     *
     * <p>When the effect targets multiple UseCases, e.g. Preview, VideoCapture, the effect will
     * receive two output Surfaces, one for Preview and one for VideoCapture. The effect is
     * responsible for drawing the processed frames to the corresponding output Surfaces.
     *
     * <p>Use this option if each UseCase receives different content.
     */
    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
    public static final int OUTPUT_OPTION_ONE_FOR_EACH_TARGET = 1;

    @Targets
    private final int mTargets;
    @OutputOptions
    private final int mOutputOption;
    @Transformations
    private final int mTransformation;
    @NonNull
    private final Executor mExecutor;
    @Nullable
    private final SurfaceProcessor mSurfaceProcessor;
    @Nullable
    private final ImageProcessor mImageProcessor;
    @NonNull
    private final Consumer<Throwable> mErrorListener;

    /**
     * @param targets        the target {@link UseCase} to which this effect should be applied.
     *                       Currently, {@link ImageProcessor} can only target
     *                       {@link #IMAGE_CAPTURE}. Targeting other {@link UseCase} will throw
     *                       {@link IllegalArgumentException}.
     * @param executor       the {@link Executor} on which the {@param imageProcessor} and
     *                       {@param errorListener} will be invoked.
     * @param imageProcessor a {@link ImageProcessor} implementation. Once the effect is active,
     *                       CameraX will send frames to the {@link ImageProcessor} on the
     *                       {@param executor}, and deliver the processed frames to the app.
     * @param errorListener  invoked if the effect runs into unrecoverable errors. This is
     *                       invoked on the provided {@param executor}.
     */
    protected CameraEffect(
            @Targets int targets,
            @NonNull Executor executor,
            @NonNull ImageProcessor imageProcessor,
            @NonNull Consumer<Throwable> errorListener) {
        checkArgument(targets == IMAGE_CAPTURE,
                "Currently ImageProcessor can only target IMAGE_CAPTURE.");
        mTargets = targets;
        mTransformation = TRANSFORMATION_ARBITRARY;
        mOutputOption = OUTPUT_OPTION_ONE_FOR_ALL_TARGETS;
        mExecutor = executor;
        mSurfaceProcessor = null;
        mImageProcessor = imageProcessor;
        mErrorListener = errorListener;
    }

    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
    protected CameraEffect(
            @Targets int targets,
            @Transformations int transformation,
            @NonNull Executor executor,
            @NonNull SurfaceProcessor surfaceProcessor,
            @NonNull Consumer<Throwable> errorListener) {
        this(targets, OUTPUT_OPTION_ONE_FOR_ALL_TARGETS, transformation, executor, surfaceProcessor,
                errorListener);
    }

    /**
     * @param targets          the target {@link UseCase} to which this effect should be applied.
     *                         Currently {@link SurfaceProcessor} can target the following
     *                         combinations:
     *                         <ul>
     *                         <li>{@link #PREVIEW}
     *                         <li>{@link #PREVIEW} | {@link #VIDEO_CAPTURE}
     *                         <li>{@link #PREVIEW} | {@link #VIDEO_CAPTURE} |
     *                         {@link #IMAGE_CAPTURE}
     *                         </ul>
     *                         Targeting other {@link UseCase} combinations will throw
     *                         {@link IllegalArgumentException}.
     * @param outputOption     the option to specify how many output Surface the effect will handle.
     * @param transformation   the transformation that the {@link SurfaceProcessor} will handle.
     * @param executor         the {@link Executor} on which the {@param imageProcessor} and
     *                         {@param errorListener} will be invoked.
     * @param surfaceProcessor a {@link SurfaceProcessor} implementation. Once the effect is
     *                         active, CameraX will send frames to the {@link SurfaceProcessor}
     *                         on the {@param executor}, and deliver the processed frames to the
     *                         app.
     * @param errorListener    invoked if the effect runs into unrecoverable errors. The
     *                         {@link Throwable} will be the error thrown by this
     *                         {@link CameraEffect}. For example, {@link ProcessingException}.
     *                         This is invoked on the provided {@param executor}.
     */
    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
    protected CameraEffect(
            @Targets int targets,
            @OutputOptions int outputOption,
            @Transformations int transformation,
            @NonNull Executor executor,
            @NonNull SurfaceProcessor surfaceProcessor,
            @NonNull Consumer<Throwable> errorListener) {
        checkSupportedTargets(SURFACE_PROCESSOR_TARGETS, targets);
        mTargets = targets;
        mOutputOption = outputOption;
        mTransformation = transformation;
        mExecutor = executor;
        mSurfaceProcessor = surfaceProcessor;
        mImageProcessor = null;
        mErrorListener = errorListener;
    }

    /**
     * @param targets          the target {@link UseCase} to which this effect should be applied.
     *                         Currently {@link SurfaceProcessor} can target the following
     *                         combinations:
     *                         <ul>
     *                         <li>{@link #PREVIEW}
     *                         <li>{@link #PREVIEW} | {@link #VIDEO_CAPTURE}
     *                         <li>{@link #PREVIEW} | {@link #VIDEO_CAPTURE} |
     *                         {@link #IMAGE_CAPTURE}
     *                         </ul>
     *                         Targeting other {@link UseCase} combinations will throw
     *                         {@link IllegalArgumentException}.
     * @param executor         the {@link Executor} on which the {@param imageProcessor} and
     *                         {@param errorListener} will be invoked.
     * @param surfaceProcessor a {@link SurfaceProcessor} implementation. Once the effect is
     *                         active, CameraX will send frames to the {@link SurfaceProcessor}
     *                         on the {@param executor}, and deliver the processed frames to the
     *                         app.
     * @param errorListener    invoked if the effect runs into unrecoverable errors. The
     *                         {@link Throwable} will be the error thrown by this
     *                         {@link CameraEffect}. For example, {@link ProcessingException}.
     *                         This is invoked on the provided {@param executor}.
     */
    protected CameraEffect(
            @Targets int targets,
            @NonNull Executor executor,
            @NonNull SurfaceProcessor surfaceProcessor,
            @NonNull Consumer<Throwable> errorListener) {
        this(targets, OUTPUT_OPTION_ONE_FOR_ALL_TARGETS, TRANSFORMATION_ARBITRARY, executor,
                surfaceProcessor, errorListener);
    }

    /**
     * Ges the target {@link UseCase}s of this effect.
     */
    @Targets
    public int getTargets() {
        return mTargets;
    }

    /**
     * Gets the transformation that the {@link SurfaceProcessor} will handle.
     */
    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
    @Transformations
    public int getTransformation() {
        return mTransformation;
    }

    /**
     * Gets the target option.
     */
    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
    @OutputOptions
    public int getOutputOption() {
        return mOutputOption;
    }

    /**
     * Gets the {@link Executor} associated with this effect.
     *
     * <p>This method returns the value set in the constructor.
     */
    @NonNull
    public Executor getExecutor() {
        return mExecutor;
    }

    /**
     * Gets the Error listener associated with this effect.
     *
     * <p>This method returns the value set in the constructor. The {@link Throwable} will be the
     * error thrown by this {@link CameraEffect}. For example, {@link ProcessingException}.
     */
    @NonNull
    public Consumer<Throwable> getErrorListener() {
        return mErrorListener;
    }

    /**
     * Gets the {@link SurfaceProcessor} associated with this effect.
     */
    @Nullable
    public SurfaceProcessor getSurfaceProcessor() {
        return mSurfaceProcessor;
    }

    /**
     * Gets the {@link ImageProcessor} associated with this effect.
     */
    @Nullable
    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
    public ImageProcessor getImageProcessor() {
        return mImageProcessor;
    }

    // --- Internal methods ---

    /**
     * Creates a {@link SurfaceProcessorInternal} instance.
     *
     * <p>Throws {@link IllegalArgumentException} if the effect does not contain a
     * {@link SurfaceProcessor}.
     */
    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
    @NonNull
    public SurfaceProcessorInternal createSurfaceProcessorInternal() {
        return new SurfaceProcessorWithExecutor(this);
    }
}