public interface

SurfaceProcessor

 androidx.camera.core.SurfaceProcessor

Subclasses:

SurfaceProcessorImpl, SurfaceProcessorWithExecutor, DefaultSurfaceProcessor, SurfaceProcessorInternal, DualSurfaceProcessor

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

Interface to implement a GPU-based post-processing effect.

This interface is for implementing a GPU effect for the Preview UseCase. Both the input and the output of the implementation are s. It's recommended to use graphics API such as OpenGL or Vulkan to access the .

If the implementation fails to process frames, for example, fails to allocate the resources, it should throw a ProcessingException in either SurfaceProcessor.onInputSurface(SurfaceRequest) or SurfaceProcessor.onOutputSurface(SurfaceOutput) to notify CameraX. If the implementation encounters an error after the pipeline is running, it should invalidate the input by calling SurfaceRequest.invalidate(), then throwing a ProcessingException when SurfaceProcessor.onInputSurface(SurfaceRequest) is invoked again.

Once the implementation throws an exception, CameraX will treat it as an unrecoverable error and abort the pipeline. If the SurfaceOutput.getTargets() is CameraEffect.PREVIEW, CameraX will not propagate the error to the app. It's the implementation's responsibility to notify the app. For example:


 class SurfaceProcessorImpl implements SurfaceProcessor {

     Consumer mErrorListener;

     SurfaceProcessorImpl(@NonNull Consumer errorListener) {
         mErrorListener = errorListener;
     }

     void onInputSurface(@NonNull SurfaceRequest request) throws ProcessingException {
         try {
             // Setup the input stream.
         } catch (Exception e) {
             // Notify the app before throwing a ProcessingException.
             mErrorListener.accept(e)
             throw new ProcessingException(e);
         }
     }

     void onOutputSurface(@NonNull SurfaceRequest request) throws ProcessingException {
         try {
             // Setup the output streams.
         } catch (Exception e) {
             // Notify the app before throwing a ProcessingException.
             mErrorListener.accept(e)
             throw new ProcessingException(e);
         }
     }
 }
 

Summary

Methods
public voidonInputSurface(SurfaceRequest request)

Invoked when CameraX requires an input for reading original frames.

public voidonOutputSurface(SurfaceOutput surfaceOutput)

Invoked when CameraX provides output Surface(s) for drawing processed frames.

Methods

public void onInputSurface(SurfaceRequest request)

Invoked when CameraX requires an input for reading original frames.

CameraX requests s when the upstream pipeline is reconfigured. For example, when UseCases are bound to lifecycle.

With OpenGL, the implementation should create a backed by SurfaceTexture with the size of SurfaceRequest.getResolution(), then listen for the SurfaceTexture to get the incoming frames. The should not be released until the callback provided in SurfaceRequest.provideSurface(Surface, Executor, Consumer) is invoked. CameraX may request new input before releasing the existing one.

If the implementation encounters errors in creating the input , it should throw an ProcessingException to notify CameraX.

The implementation can replace a previously provided by invoking SurfaceRequest.invalidate(). Once invoked, CameraX will restart the camera pipeline and call SurfaceProcessor.onInputSurface(SurfaceRequest) again with another SurfaceRequest.

The value of the SurfaceTexture will need an additional transformation. CameraX calculates the additional transformation based on UseCase configurations such as ViewPort and target rotation, and provide the value via SurfaceOutput.updateTransformMatrix(float[], float[]). Code sample:


 // Create Surface based on the request.
 SurfaceTexture surfaceTexture = SurfaceTexture(textureName);
 surfaceTexture.setDefaultBufferSize(request.resolution.width, request.resolution.height);
 Surface surface = Surface(surfaceTexture);

 // Provide the Surface to CameraX, and cleanup when it's no longer used.
 surfaceRequest.provideSurface(surface, executor, result -> {
     surfaceTexture.setOnFrameAvailableListener(null)
     surfaceTexture.release()
     surface.release()
 });

 // Listen to the incoming frames.
 surfaceTexture.setOnFrameAvailableListener(surfaceTexture -> {
     // Process the incoming frames and draw to the output Surface from #onOutputSurface
 }, handler);
 

Parameters:

request: a request to provide for input.

See also: SurfaceRequest

public void onOutputSurface(SurfaceOutput surfaceOutput)

Invoked when CameraX provides output Surface(s) for drawing processed frames.

CameraX provides the output s when the downstream pipeline is reconfigured, for example, when UseCases are bound or the preview viewfinder is reset.

The provided s are for drawing processed frames. The implementation must get the via SurfaceOutput.getSurface(Executor, Consumer) and provide a listening to the end-of-life event of the . Then, the implementation should call SurfaceOutput.close() after it stops drawing to the . CameraX may provide new output before requesting to close the existing one.

If the implementation encounters an error and cannot consume the , it should throw an ProcessingException to notify CameraX.

When drawing to the , the implementation should apply an additional transformation to the input by calling SurfaceOutput.updateTransformMatrix(float[], float[]) with the value of SurfaceTexture} from the input .

Parameters:

surfaceOutput: contains a for drawing processed frames.

See also: SurfaceOutput

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 android.graphics.SurfaceTexture;
import android.view.Surface;

import androidx.annotation.NonNull;
import androidx.core.util.Consumer;

/**
 * Interface to implement a GPU-based post-processing effect.
 *
 * <p>This interface is for implementing a GPU effect for the {@link Preview} {@link UseCase}.
 * Both the input and the output of the implementation are {@link Surface}s. It's recommended to
 * use graphics API such as OpenGL or Vulkan to access the {@link Surface}.
 *
 * <p>If the implementation fails to process frames, for example, fails to allocate
 * the resources, it should throw a {@link ProcessingException} in either {@link #onInputSurface} or
 * {@link #onOutputSurface} to notify CameraX. If the implementation encounters an error after the
 * pipeline is running, it should invalidate the input {@link Surface} by calling
 * {@link SurfaceRequest#invalidate()}, then throwing a {@link ProcessingException} when
 * {@link SurfaceProcessor#onInputSurface} is invoked again.
 *
 * <p>Once the implementation throws an exception, CameraX will treat it as an unrecoverable error
 * and abort the pipeline. If the {@link SurfaceOutput#getTargets()} is
 * {@link CameraEffect#PREVIEW}, CameraX will not propagate the error to the app. It's the
 * implementation's responsibility to notify the app. For example:
 *
 * <pre><code>
 * class SurfaceProcessorImpl implements SurfaceProcessor {
 *
 *     Consumer<Exception> mErrorListener;
 *
 *     SurfaceProcessorImpl(@NonNull Consumer<Exception> errorListener) {
 *         mErrorListener = errorListener;
 *     }
 *
 *     void onInputSurface(@NonNull SurfaceRequest request) throws ProcessingException {
 *         try {
 *             // Setup the input stream.
 *         } catch (Exception e) {
 *             // Notify the app before throwing a ProcessingException.
 *             mErrorListener.accept(e)
 *             throw new ProcessingException(e);
 *         }
 *     }
 *
 *     void onOutputSurface(@NonNull SurfaceRequest request) throws ProcessingException {
 *         try {
 *             // Setup the output streams.
 *         } catch (Exception e) {
 *             // Notify the app before throwing a ProcessingException.
 *             mErrorListener.accept(e)
 *             throw new ProcessingException(e);
 *         }
 *     }
 * }
 * </code></pre>
 */
public interface SurfaceProcessor {

    /**
     * Invoked when CameraX requires an input {@link Surface} for reading original frames.
     *
     * <p>CameraX requests {@link Surface}s when the upstream pipeline is reconfigured. For
     * example, when {@link UseCase}s are bound to lifecycle.
     *
     * <p>With OpenGL, the implementation should create a {@link Surface} backed by
     * {@link SurfaceTexture} with the size of {@link SurfaceRequest#getResolution()}, then
     * listen for the {@link SurfaceTexture#setOnFrameAvailableListener} to get the incoming
     * frames. The {@link Surface} should not be released until the callback provided in
     * {@link SurfaceRequest#provideSurface} is invoked. CameraX may request new input
     * {@link Surface} before releasing the existing one.
     *
     * <p>If the implementation encounters errors in creating the input {@link Surface}, it
     * should throw an {@link ProcessingException} to notify CameraX.
     *
     * <p>The implementation can replace a previously provided {@link Surface} by invoking
     * {@link SurfaceRequest#invalidate()}. Once invoked, CameraX will restart the camera
     * pipeline and call {@link #onInputSurface} again with another {@link SurfaceRequest}.
     *
     * <p>The value of the {@link SurfaceTexture#getTransformMatrix} will need an additional
     * transformation. CameraX calculates the additional transformation based on {@link UseCase}
     * configurations such as {@link ViewPort} and target rotation, and provide the value via
     * {@link SurfaceOutput#updateTransformMatrix(float[], float[])}.
     *
     * Code sample:
     * <pre><code>
     * // Create Surface based on the request.
     * SurfaceTexture surfaceTexture = SurfaceTexture(textureName);
     * surfaceTexture.setDefaultBufferSize(request.resolution.width, request.resolution.height);
     * Surface surface = Surface(surfaceTexture);
     *
     * // Provide the Surface to CameraX, and cleanup when it's no longer used.
     * surfaceRequest.provideSurface(surface, executor, result -> {
     *     surfaceTexture.setOnFrameAvailableListener(null)
     *     surfaceTexture.release()
     *     surface.release()
     * });
     *
     * // Listen to the incoming frames.
     * surfaceTexture.setOnFrameAvailableListener(surfaceTexture -> {
     *     // Process the incoming frames and draw to the output Surface from #onOutputSurface
     * }, handler);
     * </code></pre>
     *
     * @param request a request to provide {@link Surface} for input.
     * @throws ProcessingException if the implementation fails to fulfill the
     *                             {@link SurfaceRequest}.
     * @see SurfaceRequest
     */
    void onInputSurface(@NonNull SurfaceRequest request) throws ProcessingException;

    /**
     * Invoked when CameraX provides output Surface(s) for drawing processed frames.
     *
     * <p>CameraX provides the output {@link Surface}s when the downstream pipeline is
     * reconfigured, for example, when {@link UseCase}s are bound or the preview viewfinder is
     * reset.
     *
     * <p>The provided {@link Surface}s are for drawing processed frames. The implementation must
     * get the {@link Surface} via {@link SurfaceOutput#getSurface} and provide a
     * {@link Consumer<SurfaceOutput.Event>} listening to the end-of-life event of the
     * {@link Surface}. Then, the implementation should call {@link SurfaceOutput#close()} after it
     * stops drawing to the {@link Surface}. CameraX may provide new output {@link Surface}
     * before requesting to close the existing one.
     *
     * <p>If the implementation encounters an error and cannot consume the {@link Surface},
     * it should throw an {@link ProcessingException} to notify CameraX.
     *
     * <p>When drawing to the {@link Surface}, the implementation should apply an additional
     * transformation to the input {@link Surface} by calling
     * {@link SurfaceOutput#updateTransformMatrix(float[], float[])} with the value of
     * {@link SurfaceTexture#getTransformMatrix(float[])}} from the input {@link Surface}.
     *
     * @param surfaceOutput contains a {@link Surface} for drawing processed frames.
     * @throws ProcessingException if the implementation fails to consume the {@link SurfaceOutput}.
     * @see SurfaceOutput
     */
    void onOutputSurface(@NonNull SurfaceOutput surfaceOutput) throws ProcessingException;
}