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

Commit 1ac7646e authored by Ruben Brunk's avatar Ruben Brunk Committed by Android Git Automerger
Browse files

am 8acfdc7b: Merge "camera2: Hide JPEGs in RGBA gralloc buffers." into lmp-dev

* commit '8acfdc7bf6b8ee5250351723ab2eef28f2b71e51':
  camera2: Hide JPEGs in RGBA gralloc buffers.
parents d2f5f47f 81ba9861
Loading
Loading
Loading
Loading
+7 −4
Original line number Original line Diff line number Diff line
@@ -22,6 +22,7 @@ import android.util.Log;
import android.view.Surface;
import android.view.Surface;


import java.util.ArrayList;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.List;


/**
/**
@@ -38,14 +39,16 @@ public class BurstHolder {
     *
     *
     * @param requestId id of the burst request.
     * @param requestId id of the burst request.
     * @param repeating true if this burst is repeating.
     * @param repeating true if this burst is repeating.
     * @param requests a {@link java.util.List} of {@link CaptureRequest}s in this burst.
     * @param requests a {@link List} of {@link CaptureRequest}s in this burst.
     * @param jpegSurfaceIds a {@link Collection} of IDs for the surfaces that have jpeg outputs.
     */
     */
    public BurstHolder(int requestId, boolean repeating, List<CaptureRequest> requests) {
    public BurstHolder(int requestId, boolean repeating, List<CaptureRequest> requests,
        mRequestBuilders = new ArrayList<RequestHolder.Builder>();
                       Collection<Long> jpegSurfaceIds) {
        mRequestBuilders = new ArrayList<>();
        int i = 0;
        int i = 0;
        for (CaptureRequest r : requests) {
        for (CaptureRequest r : requests) {
            mRequestBuilders.add(new RequestHolder.Builder(requestId, /*subsequenceId*/i,
            mRequestBuilders.add(new RequestHolder.Builder(requestId, /*subsequenceId*/i,
                    /*request*/r, repeating));
                    /*request*/r, repeating, jpegSurfaceIds));
            ++i;
            ++i;
        }
        }
        mRepeating = repeating;
        mRepeating = repeating;
+1 −1
Original line number Original line Diff line number Diff line
@@ -522,7 +522,7 @@ public class LegacyCameraDevice implements AutoCloseable {
        return surfaceIds;
        return surfaceIds;
    }
    }


    static boolean containsSurfaceId(Surface s, List<Long> ids) {
    static boolean containsSurfaceId(Surface s, Collection<Long> ids) {
        long id = getSurfaceId(s);
        long id = getSurfaceId(s);
        return ids.contains(id);
        return ids.contains(id);
    }
    }
+66 −66
Original line number Original line Diff line number Diff line
@@ -42,16 +42,52 @@ public class RequestHolder {
    private final int mNumPreviewTargets;
    private final int mNumPreviewTargets;
    private volatile boolean mFailed = false;
    private volatile boolean mFailed = false;


    /**
     * A builder class for {@link RequestHolder} objects.
     *
     * <p>
     * This allows per-request queries to be cached for repeating {@link CaptureRequest} objects.
     * </p>
     */
    public final static class Builder {
        private final int mRequestId;
        private final int mSubsequenceId;
        private final CaptureRequest mRequest;
        private final boolean mRepeating;
        private final int mNumJpegTargets;
        private final int mNumPreviewTargets;
        private final Collection<Long> mJpegSurfaceIds;

        /**
         * Construct a new {@link Builder} to generate {@link RequestHolder} objects.
         *
         * @param requestId the ID to set in {@link RequestHolder} objects.
         * @param subsequenceId the sequence ID to set in {@link RequestHolder} objects.
         * @param request the original {@link CaptureRequest} to set in {@link RequestHolder}
         *                objects.
         * @param repeating {@code true} if the request is repeating.
         */
        public Builder(int requestId, int subsequenceId, CaptureRequest request,
                       boolean repeating, Collection<Long> jpegSurfaceIds) {
            checkNotNull(request, "request must not be null");
            mRequestId = requestId;
            mSubsequenceId = subsequenceId;
            mRequest = request;
            mRepeating = repeating;
            mJpegSurfaceIds = jpegSurfaceIds;
            mNumJpegTargets = numJpegTargets(mRequest);
            mNumPreviewTargets = numPreviewTargets(mRequest);
        }

        /**
        /**
         * Returns true if the given surface requires jpeg buffers.
         * Returns true if the given surface requires jpeg buffers.
         *
         *
         * @param s a {@link android.view.Surface} to check.
         * @param s a {@link android.view.Surface} to check.
         * @return true if the surface requires a jpeg buffer.
         * @return true if the surface requires a jpeg buffer.
         */
         */
    public static boolean jpegType(Surface s)
        private boolean jpegType(Surface s)
                throws LegacyExceptionUtils.BufferQueueAbandonedException {
                throws LegacyExceptionUtils.BufferQueueAbandonedException {
        return LegacyCameraDevice.detectSurfaceType(s) ==
            return LegacyCameraDevice.containsSurfaceId(s, mJpegSurfaceIds);
                CameraMetadataNative.NATIVE_JPEG_FORMAT;
        }
        }


        /**
        /**
@@ -67,16 +103,15 @@ public class RequestHolder {
         * @param s a {@link android.view.Surface} to check.
         * @param s a {@link android.view.Surface} to check.
         * @return true if the surface requires a non-jpeg buffer type.
         * @return true if the surface requires a non-jpeg buffer type.
         */
         */
    public static boolean previewType(Surface s)
        private boolean previewType(Surface s)
                throws LegacyExceptionUtils.BufferQueueAbandonedException {
                throws LegacyExceptionUtils.BufferQueueAbandonedException {
        return LegacyCameraDevice.detectSurfaceType(s) !=
            return !jpegType(s);
                CameraMetadataNative.NATIVE_JPEG_FORMAT;
        }
        }


        /**
        /**
         * Returns the number of surfaces targeted by the request that require jpeg buffers.
         * Returns the number of surfaces targeted by the request that require jpeg buffers.
         */
         */
    private static int numJpegTargets(CaptureRequest request) {
        private int numJpegTargets(CaptureRequest request) {
            int count = 0;
            int count = 0;
            for (Surface s : request.getTargets()) {
            for (Surface s : request.getTargets()) {
                try {
                try {
@@ -84,7 +119,7 @@ public class RequestHolder {
                        ++count;
                        ++count;
                    }
                    }
                } catch (LegacyExceptionUtils.BufferQueueAbandonedException e) {
                } catch (LegacyExceptionUtils.BufferQueueAbandonedException e) {
                Log.w(TAG, "Surface abandoned, skipping...", e);
                    Log.d(TAG, "Surface abandoned, skipping...", e);
                }
                }
            }
            }
            return count;
            return count;
@@ -93,7 +128,7 @@ public class RequestHolder {
        /**
        /**
         * Returns the number of surfaces targeted by the request that require non-jpeg buffers.
         * Returns the number of surfaces targeted by the request that require non-jpeg buffers.
         */
         */
    private static int numPreviewTargets(CaptureRequest request) {
        private int numPreviewTargets(CaptureRequest request) {
            int count = 0;
            int count = 0;
            for (Surface s : request.getTargets()) {
            for (Surface s : request.getTargets()) {
                try {
                try {
@@ -101,47 +136,12 @@ public class RequestHolder {
                        ++count;
                        ++count;
                    }
                    }
                } catch (LegacyExceptionUtils.BufferQueueAbandonedException e) {
                } catch (LegacyExceptionUtils.BufferQueueAbandonedException e) {
                Log.w(TAG, "Surface abandoned, skipping...", e);
                    Log.d(TAG, "Surface abandoned, skipping...", e);
                }
                }
            }
            }
            return count;
            return count;
        }
        }


    /**
     * A builder class for {@link RequestHolder} objects.
     *
     * <p>
     * This allows per-request queries to be cached for repeating {@link CaptureRequest} objects.
     * </p>
     */
    public final static class Builder {
        private final int mRequestId;
        private final int mSubsequenceId;
        private final CaptureRequest mRequest;
        private final boolean mRepeating;
        private final int mNumJpegTargets;
        private final int mNumPreviewTargets;

        /**
         * Construct a new {@link Builder} to generate {@link RequestHolder} objects.
         *
         * @param requestId the ID to set in {@link RequestHolder} objects.
         * @param subsequenceId the sequence ID to set in {@link RequestHolder} objects.
         * @param request the original {@link CaptureRequest} to set in {@link RequestHolder}
         *                objects.
         * @param repeating {@code true} if the request is repeating.
         */
        public Builder(int requestId, int subsequenceId, CaptureRequest request,
                       boolean repeating) {
            checkNotNull(request, "request must not be null");
            mRequestId = requestId;
            mSubsequenceId = subsequenceId;
            mRequest = request;
            mRepeating = repeating;
            mNumJpegTargets = numJpegTargets(mRequest);
            mNumPreviewTargets = numPreviewTargets(mRequest);
        }

        /**
        /**
         * Build a new {@link RequestHolder} using with parameters generated from this
         * Build a new {@link RequestHolder} using with parameters generated from this
         *      {@link Builder}.
         *      {@link Builder}.
+5 −2
Original line number Original line Diff line number Diff line
@@ -39,8 +39,11 @@ public class RequestQueue {
    private long mCurrentFrameNumber = 0;
    private long mCurrentFrameNumber = 0;
    private long mCurrentRepeatingFrameNumber = INVALID_FRAME;
    private long mCurrentRepeatingFrameNumber = INVALID_FRAME;
    private int mCurrentRequestId = 0;
    private int mCurrentRequestId = 0;
    private final List<Long> mJpegSurfaceIds;


    public RequestQueue() {}
    public RequestQueue(List<Long> jpegSurfaceIds) {
        mJpegSurfaceIds = jpegSurfaceIds;
    }


    /**
    /**
     * Return and remove the next burst on the queue.
     * Return and remove the next burst on the queue.
@@ -117,7 +120,7 @@ public class RequestQueue {
    public synchronized int submit(List<CaptureRequest> requests, boolean repeating,
    public synchronized int submit(List<CaptureRequest> requests, boolean repeating,
            /*out*/LongParcelable frameNumber) {
            /*out*/LongParcelable frameNumber) {
        int requestId = mCurrentRequestId++;
        int requestId = mCurrentRequestId++;
        BurstHolder burst = new BurstHolder(requestId, repeating, requests);
        BurstHolder burst = new BurstHolder(requestId, repeating, requests, mJpegSurfaceIds);
        long ret = INVALID_FRAME;
        long ret = INVALID_FRAME;
        if (burst.isRepeating()) {
        if (burst.isRepeating()) {
            Log.i(TAG, "Repeating capture request set.");
            Log.i(TAG, "Repeating capture request set.");
+35 −8
Original line number Original line Diff line number Diff line
@@ -91,9 +91,11 @@ public class RequestThreadManager {
    private SurfaceTexture mPreviewTexture;
    private SurfaceTexture mPreviewTexture;
    private Camera.Parameters mParams;
    private Camera.Parameters mParams;


    private final List<Long> mJpegSurfaceIds = new ArrayList<>();

    private Size mIntermediateBufferSize;
    private Size mIntermediateBufferSize;


    private final RequestQueue mRequestQueue = new RequestQueue();
    private final RequestQueue mRequestQueue = new RequestQueue(mJpegSurfaceIds);
    private LegacyRequest mLastRequest = null;
    private LegacyRequest mLastRequest = null;
    private SurfaceTexture mDummyTexture;
    private SurfaceTexture mDummyTexture;
    private Surface mDummySurface;
    private Surface mDummySurface;
@@ -102,6 +104,10 @@ public class RequestThreadManager {
    private final FpsCounter mPrevCounter = new FpsCounter("Incoming Preview");
    private final FpsCounter mPrevCounter = new FpsCounter("Incoming Preview");
    private final FpsCounter mRequestCounter = new FpsCounter("Incoming Requests");
    private final FpsCounter mRequestCounter = new FpsCounter("Incoming Requests");


    // Stuff JPEGs into HAL_PIXEL_FORMAT_RGBA_8888 gralloc buffers to get around SW write
    // limitations for (b/17379185).
    private static final boolean USE_BLOB_FORMAT_OVERRIDE = true;

    /**
    /**
     * Container object for Configure messages.
     * Container object for Configure messages.
     */
     */
@@ -197,10 +203,13 @@ public class RequestThreadManager {
            }
            }
            for (Surface s : holder.getHolderTargets()) {
            for (Surface s : holder.getHolderTargets()) {
                try {
                try {
                    if (RequestHolder.jpegType(s)) {
                    if (LegacyCameraDevice.containsSurfaceId(s, mJpegSurfaceIds)) {
                        Log.i(TAG, "Producing jpeg buffer...");
                        Log.i(TAG, "Producing jpeg buffer...");
                        LegacyCameraDevice.setSurfaceDimens(s, data.length +

                                LegacyCameraDevice.nativeGetJpegFooterSize(), /*height*/1);
                        int totalSize = data.length + LegacyCameraDevice.nativeGetJpegFooterSize();
                        totalSize += ((totalSize - 1) & ~0x3) + 4; // align to next octonibble

                        LegacyCameraDevice.setSurfaceDimens(s, totalSize, /*height*/1);
                        LegacyCameraDevice.setNextTimestamp(s, timestamp);
                        LegacyCameraDevice.setNextTimestamp(s, timestamp);
                        LegacyCameraDevice.produceFrame(s, data, data.length, /*height*/1,
                        LegacyCameraDevice.produceFrame(s, data, data.length, /*height*/1,
                                CameraMetadataNative.NATIVE_JPEG_FORMAT);
                                CameraMetadataNative.NATIVE_JPEG_FORMAT);
@@ -316,6 +325,7 @@ public class RequestThreadManager {
            mGLThreadManager.ignoreNewFrames();
            mGLThreadManager.ignoreNewFrames();
            mGLThreadManager.waitUntilIdle();
            mGLThreadManager.waitUntilIdle();
        }
        }
        resetJpegSurfaceFormats(mCallbackOutputs);
        mPreviewOutputs.clear();
        mPreviewOutputs.clear();
        mCallbackOutputs.clear();
        mCallbackOutputs.clear();
        mPreviewTexture = null;
        mPreviewTexture = null;
@@ -329,6 +339,12 @@ public class RequestThreadManager {
                    LegacyCameraDevice.setSurfaceOrientation(s, facing, orientation);
                    LegacyCameraDevice.setSurfaceOrientation(s, facing, orientation);
                    switch (format) {
                    switch (format) {
                        case CameraMetadataNative.NATIVE_JPEG_FORMAT:
                        case CameraMetadataNative.NATIVE_JPEG_FORMAT:
                            if (USE_BLOB_FORMAT_OVERRIDE) {
                                // Override to RGBA_8888 format.
                                LegacyCameraDevice.setSurfaceFormat(s,
                                        LegacyMetadataMapper.HAL_PIXEL_FORMAT_RGBA_8888);
                            }
                            mJpegSurfaceIds.add(LegacyCameraDevice.getSurfaceId(s));
                            mCallbackOutputs.add(s);
                            mCallbackOutputs.add(s);
                            break;
                            break;
                        default:
                        default:
@@ -426,8 +442,19 @@ public class RequestThreadManager {
        }
        }


        mCamera.setParameters(mParams);
        mCamera.setParameters(mParams);
        // TODO: configure the JPEG surface with some arbitrary size
    }
        // using LegacyCameraDevice.nativeConfigureSurface

    private void resetJpegSurfaceFormats(Collection<Surface> surfaces) {
        if (!USE_BLOB_FORMAT_OVERRIDE || surfaces == null) {
            return;
        }
        for(Surface s : surfaces) {
            try {
                LegacyCameraDevice.setSurfaceFormat(s, LegacyMetadataMapper.HAL_PIXEL_FORMAT_BLOB);
            } catch (LegacyExceptionUtils.BufferQueueAbandonedException e) {
                Log.w(TAG, "Surface abandoned, skipping...", e);
            }
        }
    }
    }


    /**
    /**
@@ -459,9 +486,8 @@ public class RequestThreadManager {
        List<Size> configuredJpegSizes = new ArrayList<Size>();
        List<Size> configuredJpegSizes = new ArrayList<Size>();
        for (Surface callbackSurface : callbackOutputs) {
        for (Surface callbackSurface : callbackOutputs) {
            try {
            try {
                int format = LegacyCameraDevice.detectSurfaceType(callbackSurface);


                if (format != CameraMetadataNative.NATIVE_JPEG_FORMAT) {
                if (!LegacyCameraDevice.containsSurfaceId(callbackSurface, mJpegSurfaceIds)) {
                    continue; // Ignore non-JPEG callback formats
                    continue; // Ignore non-JPEG callback formats
                }
                }


@@ -821,6 +847,7 @@ public class RequestThreadManager {
                    if (mCamera != null) {
                    if (mCamera != null) {
                        mCamera.release();
                        mCamera.release();
                    }
                    }
                    resetJpegSurfaceFormats(mCallbackOutputs);
                    break;
                    break;
                default:
                default:
                    throw new AssertionError("Unhandled message " + msg.what +
                    throw new AssertionError("Unhandled message " + msg.what +
Loading