Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c8b181e9 authored by Zhijun He's avatar Zhijun He
Browse files

Camera2: add deferred output config support

Allow surfaces to be deferred during session creation. Once the surfaces are ready,
the application can finish the deferred output configuration to be able to submit
requests with these surface targets.

Bug: 28323863
Change-Id: Id6634c3ef2ecc84422a88f63de0a19a0cb496e96
parent 7d45e023
Loading
Loading
Loading
Loading
+48 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package android.hardware.camera2;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.hardware.camera2.params.OutputConfiguration;
import android.os.Handler;
import android.view.Surface;

@@ -219,6 +220,53 @@ public abstract class CameraCaptureSession implements AutoCloseable {
     */
    public abstract void tearDown(@NonNull Surface surface) throws CameraAccessException;

    /**
     * <p>
     * Finish the deferred output configurations where the output Surface was not configured before.
     * </p>
     * <p>
     * For camera use cases where a preview and other output configurations need to be configured,
     * it can take some time for the preview Surface to be ready (e.g., if the preview Surface is
     * obtained from {@link android.view.SurfaceView}, the SurfaceView is ready after the UI layout
     * is done, then it takes some time to get the preview Surface).
     * </p>
     * <p>
     * To speed up camera startup time, the application can configure the
     * {@link CameraCaptureSession} with the desired preview size, and defer the preview output
     * configuration until the Surface is ready. After the {@link CameraCaptureSession} is created
     * successfully with this deferred configuration and other normal configurations, the
     * application can submit requests that don't include deferred output Surfaces. Once the
     * deferred Surface is ready, the application can set the Surface to the same deferred output
     * configuration with the {@link OutputConfiguration#setDeferredSurface} method, and then finish
     * the deferred output configuration via this method, before it can submit requests with this
     * output target.
     * </p>
     * <p>
     * The output Surfaces included by this list of deferred {@link OutputConfiguration
     * OutputConfigurations} can be used as {@link CaptureRequest} targets as soon as this call
     * returns;
     * </p>
     * <p>
     * This method is not supported by Legacy devices.
     * </p>
     *
     * @param deferredOutputConfigs a list of {@link OutputConfiguration OutputConfigurations} that
     *            have had {@link OutputConfiguration#setDeferredSurface setDeferredSurface} invoked
     *            with a valid output Surface.
     * @throws CameraAccessException if the camera device is no longer connected or has encountered
     *             a fatal error.
     * @throws IllegalStateException if this session is no longer active, either because the session
     *             was explicitly closed, a new session has been created or the camera device has
     *             been closed. Or if this output configuration was already finished with the
     *             included surface before.
     * @throws IllegalArgumentException for invalid output configurations, including ones where the
     *             source of the Surface is no longer valid or the Surface is from a unsupported
     *             source.
     * @hide
     */
    public abstract void finishDeferredConfiguration(
            List<OutputConfiguration> deferredOutputConfigs) throws CameraAccessException;

    /**
     * <p>Submit a request for an image to be captured by the camera device.</p>
     *
+7 −0
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import android.hardware.camera2.dispatch.BroadcastDispatcher;
import android.hardware.camera2.dispatch.DuckTypingDispatcher;
import android.hardware.camera2.dispatch.HandlerDispatcher;
import android.hardware.camera2.dispatch.InvokeDispatcher;
import android.hardware.camera2.params.OutputConfiguration;
import android.hardware.camera2.utils.TaskDrainer;
import android.hardware.camera2.utils.TaskSingleDrainer;
import android.os.Handler;
@@ -155,6 +156,12 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession
        mDeviceImpl.tearDown(surface);
    }

    @Override
    public void finishDeferredConfiguration(
            List<OutputConfiguration> deferredOutputConfigs) throws CameraAccessException {
        mDeviceImpl.finishDeferredConfig(deferredOutputConfigs);
    }

    @Override
    public synchronized int capture(CaptureRequest request, CaptureCallback callback,
            Handler handler) throws CameraAccessException {
+13 −0
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraConstrainedHighSpeedCaptureSession;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.params.OutputConfiguration;
import android.hardware.camera2.params.StreamConfigurationMap;
import android.hardware.camera2.utils.SurfaceUtils;
import android.os.Handler;
@@ -256,6 +257,12 @@ public class CameraConstrainedHighSpeedCaptureSessionImpl
        return mSessionImpl.isAborting();
    }

    @Override
    public void finishDeferredConfiguration(List<OutputConfiguration> deferredOutputConfigs)
            throws CameraAccessException {
        mSessionImpl.finishDeferredConfiguration(deferredOutputConfigs);
    }

    private class WrapperCallback extends StateCallback {
        private final StateCallback mCallback;

@@ -263,26 +270,32 @@ public class CameraConstrainedHighSpeedCaptureSessionImpl
            mCallback = callback;
        }

        @Override
        public void onConfigured(CameraCaptureSession session) {
            mCallback.onConfigured(CameraConstrainedHighSpeedCaptureSessionImpl.this);
        }

        @Override
        public void onConfigureFailed(CameraCaptureSession session) {
            mCallback.onConfigureFailed(CameraConstrainedHighSpeedCaptureSessionImpl.this);
        }

        @Override
        public void onReady(CameraCaptureSession session) {
            mCallback.onReady(CameraConstrainedHighSpeedCaptureSessionImpl.this);
        }

        @Override
        public void onActive(CameraCaptureSession session) {
            mCallback.onActive(CameraConstrainedHighSpeedCaptureSessionImpl.this);
        }

        @Override
        public void onClosed(CameraCaptureSession session) {
            mCallback.onClosed(CameraConstrainedHighSpeedCaptureSessionImpl.this);
        }

        @Override
        public void onSurfacePrepared(CameraCaptureSession session, Surface surface) {
            mCallback.onSurfacePrepared(CameraConstrainedHighSpeedCaptureSessionImpl.this,
                    surface);
+36 −1
Original line number Diff line number Diff line
@@ -407,7 +407,10 @@ public class CameraDeviceImpl extends CameraDevice
                int streamId = mConfiguredOutputs.keyAt(i);
                OutputConfiguration outConfig = mConfiguredOutputs.valueAt(i);

                if (!outputs.contains(outConfig)) {
                if (!outputs.contains(outConfig) || outConfig.isDeferredConfiguration()) {
                    // Always delete the deferred output configuration when the session
                    // is created, as the deferred output configuration doesn't have unique surface
                    // related identifies.
                    deleteList.add(streamId);
                } else {
                    addSet.remove(outConfig);  // Don't create a stream previously created
@@ -744,6 +747,37 @@ public class CameraDeviceImpl extends CameraDevice
        }
    }

    public void finishDeferredConfig(List<OutputConfiguration> deferredConfigs)
            throws CameraAccessException {
        if (deferredConfigs == null || deferredConfigs.size() == 0) {
            throw new IllegalArgumentException("deferred config is null or empty");
        }

        synchronized(mInterfaceLock) {
            for (OutputConfiguration config : deferredConfigs) {
                int streamId = -1;
                for (int i = 0; i < mConfiguredOutputs.size(); i++) {
                    // Have to use equal here, as createCaptureSessionByOutputConfigurations() and
                    // createReprocessableCaptureSessionByConfigurations() do a copy of the configs.
                    if (config.equals(mConfiguredOutputs.valueAt(i))) {
                        streamId = mConfiguredOutputs.keyAt(i);
                        break;
                    }
                }
                if (streamId == -1) {
                    throw new IllegalArgumentException("Deferred config is not part of this "
                            + "session");
                }

                if (config.getSurface() == null) {
                    throw new IllegalArgumentException("The deferred config for stream " + streamId
                            + " must have a non-null surface");
                }
                mRemoteDevice.setDeferredConfiguration(streamId, config);
            }
        }
    }

    public int capture(CaptureRequest request, CaptureCallback callback, Handler handler)
            throws CameraAccessException {
        if (DEBUG) {
@@ -2037,6 +2071,7 @@ public class CameraDeviceImpl extends CameraDevice
     *
     * <p> Handle binder death for ICameraDeviceUser. Trigger onError.</p>
     */
    @Override
    public void binderDied() {
        Log.w(TAG, "CameraDevice " + mCameraId + " died unexpectedly");

+9 −0
Original line number Diff line number Diff line
@@ -215,5 +215,14 @@ public class ICameraDeviceUserWrapper {
        }
    }

    public void setDeferredConfiguration(int streamId, OutputConfiguration deferredConfig)
            throws CameraAccessException {
        try {
            mRemoteDevice.setDeferredConfiguration(streamId, deferredConfig);
        } catch (Throwable t) {
            CameraManager.throwAsPublicException(t);
            throw new UnsupportedOperationException("Unexpected exception", t);
        }
    }

}
Loading