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

Commit a4d23ccc authored by Ravneet Dhanjal's avatar Ravneet Dhanjal
Browse files

Camera: Enable flexibility for postview format

- Allow postview and capture formats to differ which could be
useful for captures requesting formats such as JPEG_R, where allowing
a lighter weight postview format can decrease its latency
- Fix how postview sizes are generated in getPostviewSupportedSizes.
Postview sizes should not be subject to the API contract mandating
support of advertised sizes for JPEG, YUV, and PRIVATE since they are
relative to the capture size

Test: Camera CTS Test for basic and advanced extensions
Bug: 317393750
Change-Id: Idd347d38493e3bfb7d7ae8a20f5103b1f7a97118
parent 879dae1c
Loading
Loading
Loading
Loading
+12 −12
Original line number Diff line number Diff line
@@ -917,8 +917,11 @@ public final class CameraExtensionCharacteristics {
     * image. For example, it can be used as a temporary placeholder for the requested capture
     * while the final image is being processed. The supported sizes for a still capture's postview
     * can be retrieved using
     * {@link CameraExtensionCharacteristics#getPostviewSupportedSizes(int, Size, int)}.
     * The formats of the still capture and postview should be equivalent upon capture request.</p>
     * {@link CameraExtensionCharacteristics#getPostviewSupportedSizes(int, Size, int)}.</p>
     *
     * <p>Starting with Android {@link android.os.Build.VERSION_CODES#VANILLA_ICE_CREAM},
     * the formats of the still capture and postview are not required to be equivalent upon capture
     * request.</p>
     *
     * @param extension the extension type
     * @return {@code true} in case postview is supported, {@code false} otherwise
@@ -976,8 +979,7 @@ public final class CameraExtensionCharacteristics {
     *
     * @param extension the extension type
     * @param captureSize size of the still capture for which the postview is requested
     * @param format device-specific extension output format of the still capture and
     * postview
     * @param format device-specific extension output format of the postview
     * @return non-modifiable list of available sizes or an empty list if the format and
     * size is not supported.
     * @throws IllegalArgumentException in case of unsupported extension or if postview
@@ -1018,8 +1020,8 @@ public final class CameraExtensionCharacteristics {
                }
                IAdvancedExtenderImpl extender = initializeAdvancedExtension(extension);
                extender.init(mCameraId, mCharacteristicsMapNative);
                return generateSupportedSizes(extender.getSupportedPostviewResolutions(
                    sz), format, streamMap);
                return getSupportedSizes(extender.getSupportedPostviewResolutions(sz),
                        format);
            } else {
                Pair<IPreviewExtenderImpl, IImageCaptureExtenderImpl> extenders =
                        initializeExtension(extension);
@@ -1034,15 +1036,13 @@ public final class CameraExtensionCharacteristics {
                }

                if (format == ImageFormat.YUV_420_888) {
                    return generateSupportedSizes(
                            extenders.second.getSupportedPostviewResolutions(sz),
                            format, streamMap);
                    return getSupportedSizes(
                            extenders.second.getSupportedPostviewResolutions(sz), format);
                } else if (format == ImageFormat.JPEG) {
                    // The framework will perform the additional encoding pass on the
                    // processed YUV_420 buffers.
                    return generateJpegSupportedSizes(
                            extenders.second.getSupportedPostviewResolutions(sz),
                                    streamMap);
                    return getSupportedSizes(
                            extenders.second.getSupportedPostviewResolutions(sz), format);
                }  else if (format == ImageFormat.JPEG_R || format == ImageFormat.YCBCR_P010) {
                    // Jpeg_R/UltraHDR + YCBCR_P010 is currently not supported in the basic
                    // extension case
+41 −22
Original line number Diff line number Diff line
@@ -36,6 +36,8 @@ import android.os.RemoteException;
import android.util.Log;
import android.view.Surface;

import com.android.internal.camera.flags.Flags;

import java.nio.ByteBuffer;
import java.util.HashSet;
import java.util.Iterator;
@@ -57,6 +59,8 @@ public class CameraExtensionJpegProcessor implements ICaptureProcessorImpl {
    private android.hardware.camera2.extension.Size mResolution = null;
    private android.hardware.camera2.extension.Size mPostviewResolution = null;
    private int mFormat = -1;
    private int mPostviewFormat = -1;
    private int mCaptureFormat = -1;
    private Surface mOutputSurface = null;
    private ImageWriter mOutputWriter = null;
    private Surface mPostviewOutputSurface = null;
@@ -204,10 +208,12 @@ public class CameraExtensionJpegProcessor implements ICaptureProcessorImpl {
    }

    public void onOutputSurface(Surface surface, int format) throws RemoteException {
        if (format != ImageFormat.JPEG) {
        if (!Flags.extension10Bit() && format != ImageFormat.JPEG) {
            Log.e(TAG, "Unsupported output format: " + format);
            return;
        }
        CameraExtensionUtils.SurfaceInfo surfaceInfo = CameraExtensionUtils.querySurface(surface);
        mCaptureFormat = surfaceInfo.mFormat;
        mOutputSurface = surface;
        initializePipeline();
    }
@@ -215,10 +221,11 @@ public class CameraExtensionJpegProcessor implements ICaptureProcessorImpl {
    public void onPostviewOutputSurface(Surface surface) throws RemoteException {
        CameraExtensionUtils.SurfaceInfo postviewSurfaceInfo =
                CameraExtensionUtils.querySurface(surface);
        if (postviewSurfaceInfo.mFormat != ImageFormat.JPEG) {
        if (!Flags.extension10Bit() && postviewSurfaceInfo.mFormat != ImageFormat.JPEG) {
            Log.e(TAG, "Unsupported output format: " + postviewSurfaceInfo.mFormat);
            return;
        }
        mPostviewFormat = postviewSurfaceInfo.mFormat;
        mPostviewOutputSurface = surface;
        initializePostviewPipeline();
    }
@@ -233,7 +240,7 @@ public class CameraExtensionJpegProcessor implements ICaptureProcessorImpl {
    }

    public void onImageFormatUpdate(int format) throws RemoteException {
        if (format != ImageFormat.YUV_420_888) {
        if (!Flags.extension10Bit() && format != ImageFormat.YUV_420_888) {
            Log.e(TAG, "Unsupported input format: " + format);
            return;
        }
@@ -244,33 +251,45 @@ public class CameraExtensionJpegProcessor implements ICaptureProcessorImpl {
    private void initializePipeline() throws RemoteException {
        if ((mFormat != -1) && (mOutputSurface != null) && (mResolution != null) &&
                (mYuvReader == null)) {
            if (Flags.extension10Bit() && mCaptureFormat == ImageFormat.YUV_420_888) {
                // For the case when postview is JPEG and capture is YUV
                mProcessor.onOutputSurface(mOutputSurface, mCaptureFormat);
            } else {
                // Jpeg/blobs are expected to be configured with (w*h)x1.5 + 64k Jpeg APP1 segment
                mOutputWriter = ImageWriter.newInstance(mOutputSurface, 1 /*maxImages*/,
                        ImageFormat.JPEG,
                    (mResolution.width * mResolution.height * 3)/2 + JPEG_APP_SEGMENT_SIZE, 1);
            mYuvReader = ImageReader.newInstance(mResolution.width, mResolution.height, mFormat,
                    JPEG_QUEUE_SIZE);
                        (mResolution.width * mResolution.height * 3) / 2
                        + JPEG_APP_SEGMENT_SIZE, 1);
                mYuvReader = ImageReader.newInstance(mResolution.width, mResolution.height,
                        mFormat, JPEG_QUEUE_SIZE);
                mYuvReader.setOnImageAvailableListener(
                        new YuvCallback(mYuvReader, mOutputWriter), mHandler);
                mProcessor.onOutputSurface(mYuvReader.getSurface(), mFormat);
            }
            mProcessor.onResolutionUpdate(mResolution, mPostviewResolution);
            mProcessor.onImageFormatUpdate(mFormat);
            mProcessor.onImageFormatUpdate(ImageFormat.YUV_420_888);
        }
    }

    private void initializePostviewPipeline() throws RemoteException {
        if ((mFormat != -1) && (mPostviewOutputSurface != null) && (mPostviewResolution != null)
                && (mPostviewYuvReader == null)) {
            if (Flags.extension10Bit() && mPostviewFormat == ImageFormat.YUV_420_888) {
                // For the case when postview is YUV and capture is JPEG
                mProcessor.onPostviewOutputSurface(mPostviewOutputSurface);
            } else {
                // Jpeg/blobs are expected to be configured with (w*h)x1
            mPostviewOutputWriter = ImageWriter.newInstance(mPostviewOutputSurface, 1/*maxImages*/,
                    ImageFormat.JPEG, mPostviewResolution.width * mPostviewResolution.height, 1);
                mPostviewOutputWriter = ImageWriter.newInstance(mPostviewOutputSurface,
                        1/*maxImages*/, ImageFormat.JPEG,
                        mPostviewResolution.width * mPostviewResolution.height, 1);
                mPostviewYuvReader = ImageReader.newInstance(mPostviewResolution.width,
                        mPostviewResolution.height, mFormat, JPEG_QUEUE_SIZE);
                mPostviewYuvReader.setOnImageAvailableListener(
                        new YuvCallback(mPostviewYuvReader, mPostviewOutputWriter), mHandler);
                mProcessor.onPostviewOutputSurface(mPostviewYuvReader.getSurface());
            }
            mProcessor.onResolutionUpdate(mResolution, mPostviewResolution);
            mProcessor.onImageFormatUpdate(mFormat);
            mProcessor.onImageFormatUpdate(ImageFormat.YUV_420_888);
        }
    }

+9 −0
Original line number Diff line number Diff line
@@ -390,7 +390,16 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession {
                if (surfaceInfo.mFormat == ImageFormat.JPEG) {
                    mImageJpegProcessor = new CameraExtensionJpegProcessor(mImageProcessor);
                    mImageProcessor = mImageJpegProcessor;
                } else if (Flags.extension10Bit() && mClientPostviewSurface != null) {
                    // Handles case when postview is JPEG and capture is YUV
                    CameraExtensionUtils.SurfaceInfo postviewSurfaceInfo =
                            CameraExtensionUtils.querySurface(mClientPostviewSurface);
                    if (postviewSurfaceInfo.mFormat == ImageFormat.JPEG) {
                        mImageJpegProcessor = new CameraExtensionJpegProcessor(mImageProcessor);
                        mImageProcessor = mImageJpegProcessor;
                    }
                }

                mBurstCaptureImageReader = ImageReader.newInstance(surfaceInfo.mWidth,
                        surfaceInfo.mHeight, CameraExtensionCharacteristics.PROCESSING_INPUT_FORMAT,
                        mImageExtender.getMaxCaptureStage());
+22 −11
Original line number Diff line number Diff line
@@ -112,6 +112,16 @@ public final class CameraExtensionUtils {
        if (outputConfig == null) return null;

        SurfaceInfo surfaceInfo = querySurface(outputConfig.getSurface());

        if (Flags.extension10Bit()) {
            Size postviewSize = new Size(surfaceInfo.mWidth, surfaceInfo.mHeight);
            if (supportedPostviewSizes.get(surfaceInfo.mFormat)
                    .contains(postviewSize)) {
                return outputConfig.getSurface();
            } else {
                throw new IllegalArgumentException("Postview size not supported!");
            }
        } else {
            if (surfaceInfo.mFormat == captureFormat) {
                if (supportedPostviewSizes.containsKey(captureFormat)) {
                    Size postviewSize = new Size(surfaceInfo.mWidth, surfaceInfo.mHeight);
@@ -123,8 +133,9 @@ public final class CameraExtensionUtils {
                    }
                }
            } else {
            throw new IllegalArgumentException("Postview format should be equivalent to " +
                    " the capture format!");
                throw new IllegalArgumentException("Postview format should be equivalent to "
                        + " the capture format!");
            }
        }

        return null;