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

Commit 5b3d7a7c authored by Emilian Peev's avatar Emilian Peev
Browse files

Camera: Add support for client requests&results when using extension sessions

Allow camera clients to query for any orthogonal camera parameters that
can be applied during extension capture sessions.
Enable capture result callbacks in the same scenario.

Bug: 198447410
Test: Camera CTS

Change-Id: Ifb472cd051121d83d230bcc152c6942b8fb82a2d
parent c5198640
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -17434,6 +17434,8 @@ package android.hardware.camera2 {
  }
  public final class CameraExtensionCharacteristics {
    method @NonNull public java.util.Set<android.hardware.camera2.CaptureRequest.Key> getAvailableCaptureRequestKeys(int);
    method @NonNull public java.util.Set<android.hardware.camera2.CaptureResult.Key> getAvailableCaptureResultKeys(int);
    method @Nullable public android.util.Range<java.lang.Long> getEstimatedCaptureLatencyRangeMillis(int, @NonNull android.util.Size, int);
    method @NonNull public <T> java.util.List<android.util.Size> getExtensionSupportedSizes(int, @NonNull Class<T>);
    method @NonNull public java.util.List<android.util.Size> getExtensionSupportedSizes(int, int);
@@ -17458,6 +17460,7 @@ package android.hardware.camera2 {
    ctor public CameraExtensionSession.ExtensionCaptureCallback();
    method public void onCaptureFailed(@NonNull android.hardware.camera2.CameraExtensionSession, @NonNull android.hardware.camera2.CaptureRequest);
    method public void onCaptureProcessStarted(@NonNull android.hardware.camera2.CameraExtensionSession, @NonNull android.hardware.camera2.CaptureRequest);
    method public void onCaptureResultAvailable(@NonNull android.hardware.camera2.CameraExtensionSession, @NonNull android.hardware.camera2.CaptureRequest, @NonNull android.hardware.camera2.TotalCaptureResult);
    method public void onCaptureSequenceAborted(@NonNull android.hardware.camera2.CameraExtensionSession, int);
    method public void onCaptureSequenceCompleted(@NonNull android.hardware.camera2.CameraExtensionSession, int);
    method public void onCaptureStarted(@NonNull android.hardware.camera2.CameraExtensionSession, @NonNull android.hardware.camera2.CaptureRequest, long);
+1 −1
Original line number Diff line number Diff line
@@ -657,7 +657,7 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
     *
     * @throws IllegalArgumentException if metadataClass is not a subclass of CameraMetadata
     */
    private <TKey> List<TKey>
    <TKey> List<TKey>
    getAvailableKeyList(Class<?> metadataClass, Class<TKey> keyClass, int[] filterTags,
            boolean includeSynthetic) {

+142 −2
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ import android.hardware.camera2.extension.IInitializeSessionCallback;
import android.hardware.camera2.extension.IPreviewExtenderImpl;
import android.hardware.camera2.extension.LatencyRange;
import android.hardware.camera2.extension.SizeList;
import android.hardware.camera2.impl.CameraMetadataNative;
import android.hardware.camera2.params.ExtensionSessionConfiguration;
import android.hardware.camera2.params.StreamConfigurationMap;
import android.os.ConditionVariable;
@@ -49,6 +50,7 @@ import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
@@ -795,4 +797,142 @@ public final class CameraExtensionCharacteristics {

        return null;
    }

    /**
     * Returns the set of keys supported by a {@link CaptureRequest} submitted in a
     * {@link CameraExtensionSession} with a given extension type.
     *
     * <p>The set returned is not modifiable, so any attempts to modify it will throw
     * a {@code UnsupportedOperationException}.</p>
     *
     * @param extension the extension type
     *
     * @return non-modifiable set of capture keys supported by camera extension session initialized
     *         with the given extension type.
     * @throws IllegalArgumentException in case of unsupported extension.
     */
    @NonNull
    public Set<CaptureRequest.Key> getAvailableCaptureRequestKeys(@Extension int extension) {
        long clientId = registerClient(mContext);
        if (clientId < 0) {
            throw new IllegalArgumentException("Unsupported extensions");
        }

        HashSet<CaptureRequest.Key> ret = new HashSet<>();

        try {
            if (!isExtensionSupported(mCameraId, extension, mChars)) {
                throw new IllegalArgumentException("Unsupported extension");
            }
            Pair<IPreviewExtenderImpl, IImageCaptureExtenderImpl> extenders =
                    initializeExtension(extension);
            extenders.second.onInit(mCameraId, mChars.getNativeMetadata());
            extenders.second.init(mCameraId, mChars.getNativeMetadata());
            CameraMetadataNative captureRequestMeta =
                    extenders.second.getAvailableCaptureRequestKeys();

            if (captureRequestMeta != null) {
                int[] requestKeys = captureRequestMeta.get(
                        CameraCharacteristics.REQUEST_AVAILABLE_REQUEST_KEYS);
                if (requestKeys == null) {
                    throw new AssertionError("android.request.availableRequestKeys must be non-null"
                            + " in the characteristics");
                }
                CameraCharacteristics requestChars = new CameraCharacteristics(captureRequestMeta);

                Object crKey = CaptureRequest.Key.class;
                Class<CaptureRequest.Key<?>> crKeyTyped = (Class<CaptureRequest.Key<?>>)crKey;

                ret.addAll(requestChars.getAvailableKeyList(CaptureRequest.class, crKeyTyped,
                        requestKeys, /*includeSynthetic*/ false));
            }

            // Jpeg quality and orientation must always be supported
            if (!ret.contains(CaptureRequest.JPEG_QUALITY)) {
                ret.add(CaptureRequest.JPEG_QUALITY);
            }
            if (!ret.contains(CaptureRequest.JPEG_ORIENTATION)) {
                ret.add(CaptureRequest.JPEG_ORIENTATION);
            }
            extenders.second.onDeInit();
        } catch (RemoteException e) {
            throw new IllegalStateException("Failed to query the available capture request keys!");
        } finally {
            unregisterClient(clientId);
        }

        return Collections.unmodifiableSet(ret);
    }

    /**
     * Returns the set of keys supported by a {@link CaptureResult} passed as an argument to
     * {@link CameraExtensionSession.ExtensionCaptureCallback#onCaptureResultAvailable}.
     *
     * <p>The set returned is not modifiable, so any attempts to modify it will throw
     * a {@code UnsupportedOperationException}.</p>
     *
     * <p>In case the set is empty, then the extension is not able to support any capture results
     * and the {@link CameraExtensionSession.ExtensionCaptureCallback#onCaptureResultAvailable}
     * callback will not be fired.</p>
     *
     * @param extension the extension type
     *
     * @return non-modifiable set of capture result keys supported by camera extension session
     *         initialized with the given extension type.
     * @throws IllegalArgumentException in case of unsupported extension.
     */
    @NonNull
    public Set<CaptureResult.Key> getAvailableCaptureResultKeys(@Extension int extension) {
        long clientId = registerClient(mContext);
        if (clientId < 0) {
            throw new IllegalArgumentException("Unsupported extensions");
        }

        HashSet<CaptureResult.Key> ret = new HashSet<>();
        try {
            if (!isExtensionSupported(mCameraId, extension, mChars)) {
                throw new IllegalArgumentException("Unsupported extension");
            }

            Pair<IPreviewExtenderImpl, IImageCaptureExtenderImpl> extenders =
                    initializeExtension(extension);
            extenders.second.onInit(mCameraId, mChars.getNativeMetadata());
            extenders.second.init(mCameraId, mChars.getNativeMetadata());
            CameraMetadataNative captureResultMeta =
                    extenders.second.getAvailableCaptureResultKeys();

            if (captureResultMeta != null) {
                int[] resultKeys = captureResultMeta.get(
                        CameraCharacteristics.REQUEST_AVAILABLE_RESULT_KEYS);
                if (resultKeys == null) {
                    throw new AssertionError("android.request.availableResultKeys must be non-null "
                            + "in the characteristics");
                }
                CameraCharacteristics resultChars = new CameraCharacteristics(captureResultMeta);
                Object crKey = CaptureResult.Key.class;
                Class<CaptureResult.Key<?>> crKeyTyped = (Class<CaptureResult.Key<?>>)crKey;

                ret.addAll(resultChars.getAvailableKeyList(CaptureResult.class, crKeyTyped,
                        resultKeys, /*includeSynthetic*/ false));

                // Jpeg quality, orientation and sensor timestamp must always be supported
                if (!ret.contains(CaptureResult.JPEG_QUALITY)) {
                    ret.add(CaptureResult.JPEG_QUALITY);
                }
                if (!ret.contains(CaptureResult.JPEG_ORIENTATION)) {
                    ret.add(CaptureResult.JPEG_ORIENTATION);
                }
                if (!ret.contains(CaptureResult.SENSOR_TIMESTAMP)) {
                    ret.add(CaptureResult.SENSOR_TIMESTAMP);
                }
            }
            extenders.second.onDeInit();
        } catch (RemoteException e) {
            throw new IllegalStateException("Failed to query the available capture result keys!");
        } finally {
            unregisterClient(clientId);
        }

        return Collections.unmodifiableSet(ret);
    }
}
+26 −0
Original line number Diff line number Diff line
@@ -172,6 +172,32 @@ public abstract class CameraExtensionSession implements AutoCloseable {
                int sequenceId) {
            // default empty implementation
        }

        /**
         * This method is called when an image capture has fully completed and all the
         * result metadata is available.
         *
         * <p>This callback will only be called in case
         * {@link CameraExtensionCharacteristics#getAvailableCaptureResultKeys} returns a valid
         * non-empty list.</p>
         *
         * <p>The default implementation of this method does nothing.</p>
         *
         * @param session The session received during
         *                {@link StateCallback#onConfigured(CameraExtensionSession)}
         * @param request The request that was given to the CameraDevice
         * @param result The total output metadata from the capture, which only includes the
         * capture result keys advertised as supported in
         * {@link CameraExtensionCharacteristics#getAvailableCaptureResultKeys}.
         *
         * @see #capture
         * @see #setRepeatingRequest
         * @see CameraExtensionCharacteristics#getAvailableCaptureResultKeys
         */
        public void onCaptureResultAvailable(@NonNull CameraExtensionSession session,
                @NonNull CaptureRequest request, @NonNull TotalCaptureResult result) {
            // default empty implementation
        }
    }

    /**
+2 −1
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@ package android.hardware.camera2.extension;

import android.view.Surface;
import android.hardware.camera2.extension.CaptureBundle;
import android.hardware.camera2.extension.IProcessResultImpl;
import android.hardware.camera2.extension.Size;

/** @hide */
@@ -25,5 +26,5 @@ interface ICaptureProcessorImpl
    void onOutputSurface(in Surface surface, int imageFormat);
    void onResolutionUpdate(in Size size);
    void onImageFormatUpdate(int imageFormat);
    void process(in List<CaptureBundle> capturelist);
    void process(in List<CaptureBundle> capturelist, in IProcessResultImpl resultCallback);
}
Loading