1 /* 2 * Copyright (C) 2021 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.hardware.camera2.impl; 18 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.graphics.ImageFormat; 22 import android.graphics.PixelFormat; 23 import android.hardware.camera2.CameraExtensionCharacteristics; 24 import android.hardware.camera2.params.OutputConfiguration; 25 import android.hardware.camera2.params.StreamConfigurationMap; 26 import android.hardware.camera2.utils.SurfaceUtils; 27 import android.media.Image; 28 import android.media.ImageWriter; 29 import android.os.Handler; 30 import android.util.Log; 31 import android.util.Size; 32 import android.view.Surface; 33 34 import java.util.HashMap; 35 import java.util.List; 36 import java.util.concurrent.Executor; 37 import java.util.concurrent.RejectedExecutionException; 38 39 public final class CameraExtensionUtils { 40 private static final String TAG = "CameraExtensionUtils"; 41 42 public final static int JPEG_DEFAULT_QUALITY = 100; 43 public final static int JPEG_DEFAULT_ROTATION = 0; 44 45 public static final int[] SUPPORTED_CAPTURE_OUTPUT_FORMATS = { 46 CameraExtensionCharacteristics.PROCESSING_INPUT_FORMAT, 47 ImageFormat.JPEG 48 }; 49 50 public static class SurfaceInfo { 51 public int mWidth = 0; 52 public int mHeight = 0; 53 public int mFormat = PixelFormat.RGBA_8888; 54 public long mUsage = 0; 55 } 56 57 public static final class HandlerExecutor implements Executor { 58 private final Handler mHandler; 59 HandlerExecutor(Handler handler)60 public HandlerExecutor(Handler handler) { 61 mHandler = handler; 62 } 63 64 @Override execute(Runnable runCmd)65 public void execute(Runnable runCmd) { 66 try { 67 mHandler.post(runCmd); 68 } catch (RejectedExecutionException e) { 69 Log.w(TAG, "Handler thread unavailable, skipping message!"); 70 } 71 } 72 } 73 querySurface(@onNull Surface s)74 public static @NonNull SurfaceInfo querySurface(@NonNull Surface s) { 75 ImageWriter writer = null; 76 Image img = null; 77 SurfaceInfo surfaceInfo = new SurfaceInfo(); 78 int nativeFormat = SurfaceUtils.detectSurfaceFormat(s); 79 int dataspace = SurfaceUtils.getSurfaceDataspace(s); 80 Size surfaceSize = SurfaceUtils.getSurfaceSize(s); 81 surfaceInfo.mFormat = nativeFormat; 82 surfaceInfo.mWidth = surfaceSize.getWidth(); 83 surfaceInfo.mHeight = surfaceSize.getHeight(); 84 surfaceInfo.mUsage = SurfaceUtils.getSurfaceUsage(s); 85 // Jpeg surfaces cannot be queried for their usage and other parameters 86 // in the usual way below. A buffer can only be de-queued after the 87 // producer overrides the surface dimensions to (width*height) x 1. 88 if ((nativeFormat == StreamConfigurationMap.HAL_PIXEL_FORMAT_BLOB) && 89 (dataspace == StreamConfigurationMap.HAL_DATASPACE_V0_JFIF)) { 90 surfaceInfo.mFormat = ImageFormat.JPEG; 91 return surfaceInfo; 92 } 93 94 return surfaceInfo; 95 } 96 getBurstCaptureSurface( @onNull List<OutputConfiguration> outputConfigs, @NonNull HashMap<Integer, List<Size>> supportedCaptureSizes)97 public static Surface getBurstCaptureSurface( 98 @NonNull List<OutputConfiguration> outputConfigs, 99 @NonNull HashMap<Integer, List<Size>> supportedCaptureSizes) { 100 for (OutputConfiguration config : outputConfigs) { 101 SurfaceInfo surfaceInfo = querySurface(config.getSurface()); 102 for (int supportedFormat : SUPPORTED_CAPTURE_OUTPUT_FORMATS) { 103 if (surfaceInfo.mFormat == supportedFormat) { 104 Size captureSize = new Size(surfaceInfo.mWidth, surfaceInfo.mHeight); 105 if (supportedCaptureSizes.containsKey(supportedFormat)) { 106 if (supportedCaptureSizes.get(surfaceInfo.mFormat).contains(captureSize)) { 107 return config.getSurface(); 108 } else { 109 throw new IllegalArgumentException("Capture size not supported!"); 110 } 111 } 112 return config.getSurface(); 113 } 114 } 115 } 116 117 return null; 118 } 119 getRepeatingRequestSurface( @onNull List<OutputConfiguration> outputConfigs, @Nullable List<Size> supportedPreviewSizes)120 public static @Nullable Surface getRepeatingRequestSurface( 121 @NonNull List<OutputConfiguration> outputConfigs, 122 @Nullable List<Size> supportedPreviewSizes) { 123 for (OutputConfiguration config : outputConfigs) { 124 SurfaceInfo surfaceInfo = querySurface(config.getSurface()); 125 if ((surfaceInfo.mFormat == 126 CameraExtensionCharacteristics.NON_PROCESSING_INPUT_FORMAT) || 127 // The default RGBA_8888 is also implicitly supported because camera will 128 // internally override it to 129 // 'CameraExtensionCharacteristics.NON_PROCESSING_INPUT_FORMAT' 130 (surfaceInfo.mFormat == PixelFormat.RGBA_8888)) { 131 Size repeatingRequestSurfaceSize = new Size(surfaceInfo.mWidth, 132 surfaceInfo.mHeight); 133 if ((supportedPreviewSizes == null) || 134 (!supportedPreviewSizes.contains(repeatingRequestSurfaceSize))) { 135 throw new IllegalArgumentException("Repeating request surface size " + 136 repeatingRequestSurfaceSize + " not supported!"); 137 } 138 139 return config.getSurface(); 140 } 141 } 142 143 return null; 144 } 145 } 146