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

Commit 7a313104 authored by Eino-Ville Talvala's avatar Eino-Ville Talvala
Browse files

Camera2: Add support for partial result metadata quirk

- Add new CaptureListener.onCapturePartial() callback for receiving
  partial result metadata sooner than the full result metadata will be sent
  in onCaptureComplete().
- Add hidden keys for the partial result quirk
- Dispatch results to onCapturePartial based on the partial result quirk

All additions are hidden for now.

Bug: 11115603
Change-Id: Ie9a3be640f147257ae22e5b5edf0974bddc1cb85
parent e45d8b2d
Loading
Loading
Loading
Loading
+21 −0
Original line number Diff line number Diff line
@@ -332,6 +332,27 @@ public final class CameraCharacteristics extends CameraMetadata {
    public static final Key<Integer> LENS_FACING =
            new Key<Integer>("android.lens.facing", int.class);

    /**
     * <p>
     * If set to 1, the HAL will always split result
     * metadata for a single capture into multiple buffers,
     * returned using multiple process_capture_result calls.
     * </p>
     * <p>
     * Does not need to be listed in static
     * metadata. Support for partial results will be reworked in
     * future versions of camera service. This quirk will stop
     * working at that point; DO NOT USE without careful
     * consideration of future support.
     * </p>
     *
     * <b>Optional</b> - This value may be null on some devices.
     *
     * @hide
     */
    public static final Key<Byte> QUIRKS_USE_PARTIAL_RESULT =
            new Key<Byte>("android.quirks.usePartialResult", byte.class);

    /**
     * <p>
     * How many output streams can be allocated at
+30 −0
Original line number Diff line number Diff line
@@ -630,6 +630,36 @@ public interface CameraDevice extends AutoCloseable {
            // default empty implementation
        }

        /**
         * This method is called when some results from an image capture are
         * available.
         *
         * <p>The result provided here will contain some subset of the fields of
         * a full result. Multiple onCapturePartial calls may happen per
         * capture; a given result field will only be present in one partial
         * capture at most. The final onCaptureCompleted call will always
         * contain all the fields, whether onCapturePartial was called or
         * not.</p>
         *
         * <p>The default implementation of this method does nothing.</p>
         *
         * @param camera The CameraDevice sending the callback.
         * @param request The request that was given to the CameraDevice
         * @param result The partial output metadata from the capture, which
         * includes a subset of the CaptureResult fields.
         *
         * @see #capture
         * @see #captureBurst
         * @see #setRepeatingRequest
         * @see #setRepeatingBurst
         *
         * @hide
         */
        public void onCapturePartial(CameraDevice camera,
                CaptureRequest request, CaptureResult result) {
            // default empty implementation
        }

        /**
         * This method is called when an image capture has completed and the
         * result metadata is available.
+26 −0
Original line number Diff line number Diff line
@@ -589,6 +589,32 @@ public final class CaptureResult extends CameraMetadata {
    public static final Key<Integer> NOISE_REDUCTION_MODE =
            new Key<Integer>("android.noiseReduction.mode", int.class);

    /**
     * <p>
     * Whether a result given to the framework is the
     * final one for the capture, or only a partial that contains a
     * subset of the full set of dynamic metadata
     * values.
     * </p>
     * <p>
     * The entries in the result metadata buffers for a
     * single capture may not overlap, except for this entry. The
     * FINAL buffers must retain FIFO ordering relative to the
     * requests that generate them, so the FINAL buffer for frame 3 must
     * always be sent to the framework after the FINAL buffer for frame 2, and
     * before the FINAL buffer for frame 4. PARTIAL buffers may be returned
     * in any order relative to other frames, but all PARTIAL buffers for a given
     * capture must arrive before the FINAL buffer for that capture. This entry may
     * only be used by the HAL if quirks.usePartialResult is set to 1.
     * </p>
     *
     * <b>Optional</b> - This value may be null on some devices.
     *
     * @hide
     */
    public static final Key<Boolean> QUIRKS_PARTIAL_RESULT =
            new Key<Boolean>("android.quirks.partialResult", boolean.class);

    /**
     * <p>
     * A frame counter set by the framework. This value monotonically
+28 −5
Original line number Diff line number Diff line
@@ -577,6 +577,9 @@ public class CameraDevice implements android.hardware.camera2.CameraDevice {
            }
            final CaptureListenerHolder holder;

            Boolean quirkPartial = result.get(CaptureResult.QUIRKS_PARTIAL_RESULT);
            boolean quirkIsPartialResult = (quirkPartial != null && quirkPartial);

            synchronized (mLock) {
                // TODO: move this whole map into this class to make it more testable,
                //        exposing the methods necessary like subscribeToRequest, unsubscribe..
@@ -585,7 +588,7 @@ public class CameraDevice implements android.hardware.camera2.CameraDevice {
                holder = CameraDevice.this.mCaptureListenerMap.get(requestId);

                // Clean up listener once we no longer expect to see it.
                if (holder != null && !holder.isRepeating()) {
                if (holder != null && !holder.isRepeating() && !quirkIsPartialResult) {
                    CameraDevice.this.mCaptureListenerMap.remove(requestId);
                }

@@ -595,7 +598,7 @@ public class CameraDevice implements android.hardware.camera2.CameraDevice {
                // If we received a result for a repeating request and have
                // prior repeating requests queued for deletion, remove those
                // requests from mCaptureListenerMap.
                if (holder != null && holder.isRepeating()
                if (holder != null && holder.isRepeating() && !quirkIsPartialResult
                        && mRepeatingRequestIdDeletedList.size() > 0) {
                    Iterator<Integer> iter = mRepeatingRequestIdDeletedList.iterator();
                    while (iter.hasNext()) {
@@ -619,8 +622,25 @@ public class CameraDevice implements android.hardware.camera2.CameraDevice {
            final CaptureRequest request = holder.getRequest();
            final CaptureResult resultAsCapture = new CaptureResult(result, request, requestId);

            holder.getHandler().post(
                new Runnable() {
            Runnable resultDispatch = null;

            // Either send a partial result or the final capture completed result
            if (quirkIsPartialResult) {
                // Partial result
                resultDispatch = new Runnable() {
                    @Override
                    public void run() {
                        if (!CameraDevice.this.isClosed()){
                            holder.getListener().onCapturePartial(
                                CameraDevice.this,
                                request,
                                resultAsCapture);
                        }
                    }
                };
            } else {
                // Final capture result
                resultDispatch = new Runnable() {
                    @Override
                    public void run() {
                        if (!CameraDevice.this.isClosed()){
@@ -630,7 +650,10 @@ public class CameraDevice implements android.hardware.camera2.CameraDevice {
                                resultAsCapture);
                        }
                    }
                });
                };
            }

            holder.getHandler().post(resultDispatch);
        }

    }