1 /*
2  * Copyright (C) 2023 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.extension;
18 
19 import android.annotation.FlaggedApi;
20 import android.annotation.NonNull;
21 import android.annotation.SystemApi;
22 import android.hardware.camera2.CameraAccessException;
23 import android.hardware.camera2.CameraCharacteristics;
24 import android.hardware.camera2.CameraManager;
25 import android.hardware.camera2.CaptureRequest;
26 import android.hardware.camera2.CaptureResult;
27 import android.hardware.camera2.impl.CameraMetadataNative;
28 import android.hardware.camera2.impl.CaptureCallback;
29 import android.util.Log;
30 import android.util.Pair;
31 import android.util.Size;
32 
33 import com.android.internal.camera.flags.Flags;
34 
35 import java.util.ArrayList;
36 import java.util.HashMap;
37 import java.util.List;
38 import java.util.Map;
39 
40 /**
41  * Advanced contract for implementing Extensions. ImageCapture/Preview
42  * Extensions are both implemented on this interface.
43  *
44  * <p>This advanced contract empowers implementations to gain access to
45  * more Camera2 capability. This includes: (1) Add custom surfaces with
46  * specific formats like {@link android.graphics.ImageFormat#YUV_420_888},
47  * {@link android.graphics.ImageFormat#RAW10}, {@link android.graphics.ImageFormat#RAW_DEPTH10}.
48  * (2) Access to the capture request callbacks as well as all the images retrieved of
49  * various image formats. (3)
50  * Able to triggers single or repeating request with the capabilities to
51  * specify target surfaces, template id and parameters.
52  *
53  * @hide
54  */
55 @SystemApi
56 @FlaggedApi(Flags.FLAG_CONCERT_MODE)
57 public abstract class AdvancedExtender {
58     private HashMap<String, Long> mMetadataVendorIdMap = new HashMap<>();
59     private final CameraManager mCameraManager;
60 
61     private CameraUsageTracker mCameraUsageTracker;
62     private static final String TAG = "AdvancedExtender";
63 
64     /**
65      * Initialize a camera extension advanced extender instance.
66      *
67      * @param cameraManager the system camera manager
68      */
69     @FlaggedApi(Flags.FLAG_CONCERT_MODE)
AdvancedExtender(@onNull CameraManager cameraManager)70     public AdvancedExtender(@NonNull CameraManager cameraManager) {
71         mCameraManager = cameraManager;
72         try {
73             String [] cameraIds = mCameraManager.getCameraIdListNoLazy();
74             if (cameraIds != null) {
75                 for (String cameraId : cameraIds) {
76                     CameraCharacteristics chars = mCameraManager.getCameraCharacteristics(cameraId);
77                     Object thisClass = CameraCharacteristics.Key.class;
78                     Class<CameraCharacteristics.Key<?>> keyClass =
79                             (Class<CameraCharacteristics.Key<?>>)thisClass;
80                     ArrayList<CameraCharacteristics.Key<?>> vendorKeys =
81                             chars.getNativeMetadata().getAllVendorKeys(keyClass);
82                     if ((vendorKeys != null) && !vendorKeys.isEmpty()) {
83                         mMetadataVendorIdMap.put(cameraId, vendorKeys.get(0).getVendorId());
84                     }
85                 }
86             }
87         } catch (CameraAccessException e) {
88             Log.e(TAG, "Failed to query camera characteristics!");
89         }
90     }
91 
setCameraUsageTracker(CameraUsageTracker tracker)92     void setCameraUsageTracker(CameraUsageTracker tracker) {
93         mCameraUsageTracker = tracker;
94     }
95 
96     /**
97      * Returns the camera metadata vendor id, that can be used to
98      * configure and enable vendor tag support for a particular
99      * camera metadata buffer.
100      *
101      * @param cameraId           The camera2 id string of the camera.
102      * @return the camera metadata vendor Id associated with the given camera
103      */
104     @FlaggedApi(Flags.FLAG_CONCERT_MODE)
getMetadataVendorId(@onNull String cameraId)105     public long getMetadataVendorId(@NonNull String cameraId) {
106         long vendorId = mMetadataVendorIdMap.containsKey(cameraId) ?
107                 mMetadataVendorIdMap.get(cameraId) : Long.MAX_VALUE;
108         return vendorId;
109     }
110 
111     /**
112      * Indicates whether the extension is supported on the device.
113      *
114      * @param cameraId           The camera2 id string of the camera.
115      * @param charsMap           A map consisting of the camera ids and
116      *                           the {@link android.hardware.camera2.CameraCharacteristics}s. For
117      *                           every camera, the map contains at least
118      *                           the CameraCharacteristics for the camera
119      *                           id.
120      *                           If the camera is logical camera, it will
121      *                           also contain associated
122      *                           physical camera ids and their
123      *                           CameraCharacteristics.
124      * @return true if the extension is supported, otherwise false
125      */
126     @FlaggedApi(Flags.FLAG_CONCERT_MODE)
isExtensionAvailable(@onNull String cameraId, @NonNull CharacteristicsMap charsMap)127     public abstract boolean isExtensionAvailable(@NonNull String cameraId,
128             @NonNull CharacteristicsMap charsMap);
129 
130     /**
131      * Initializes the extender to be used with the specified camera.
132      *
133      * <p>This should be called before any other method on the extender.
134      * The exception is {@link #isExtensionAvailable}.
135      *
136      * @param cameraId           The camera2 id string of the camera.
137      * @param map                A map consisting of the camera ids and
138      *                           the {@link android.hardware.camera2.CameraCharacteristics}s. For
139      *                           every camera, the map contains at least
140      *                           the CameraCharacteristics for the camera
141      *                           id.
142      *                           If the camera is logical camera, it will
143      *                           also contain associated
144      *                           physical camera ids and their
145      *                           CameraCharacteristics.
146      */
147     @FlaggedApi(Flags.FLAG_CONCERT_MODE)
initialize(@onNull String cameraId, @NonNull CharacteristicsMap map)148     public abstract void initialize(@NonNull String cameraId, @NonNull CharacteristicsMap map);
149 
150     /**
151      * Returns supported output format/size map for preview. The format
152      * could be {@link android.graphics.ImageFormat#PRIVATE} or
153      * {@link android.graphics.ImageFormat#YUV_420_888}. Implementations must support
154      * {@link android.graphics.ImageFormat#PRIVATE} format at least.
155      * An example of how the map is parsed can be found in
156      * {@link #initializeParcelable(Map)}
157      *
158      * <p>The preview surface format in the CameraCaptureSession may not
159      * be identical to the supported preview output format returned here.
160      * @param cameraId           The camera2 id string of the camera.
161      */
162     @FlaggedApi(Flags.FLAG_CONCERT_MODE)
163     @NonNull
getSupportedPreviewOutputResolutions( @onNull String cameraId)164     public abstract Map<Integer, List<Size>> getSupportedPreviewOutputResolutions(
165             @NonNull String cameraId);
166 
167     /**
168      * Returns supported output format/size map for image capture. OEM is
169      * required to support both {@link android.graphics.ImageFormat#JPEG} and
170      * {@link android.graphics.ImageFormat#YUV_420_888} format output.
171      * An example of how the map is parsed can be found in
172      * {@link #initializeParcelable(Map)}
173      *
174      * <p>The surface created with this supported
175      * format/size could be either added in CameraCaptureSession with HAL
176      * processing OR it  configures intermediate surfaces(
177      * {@link android.graphics.ImageFormat#YUV_420_888}/
178      * {@link android.graphics.ImageFormat#RAW10}..) and
179      * writes the output to the output surface.
180      * @param cameraId           The camera2 id string of the camera.
181      */
182     @FlaggedApi(Flags.FLAG_CONCERT_MODE)
183     @NonNull
getSupportedCaptureOutputResolutions( @onNull String cameraId)184     public abstract Map<Integer, List<Size>> getSupportedCaptureOutputResolutions(
185             @NonNull String cameraId);
186 
187     /**
188      * Returns a processor for activating extension sessions. It
189      * implements all the interactions required for starting an extension
190      * and cleanup.
191      */
192     @FlaggedApi(Flags.FLAG_CONCERT_MODE)
193     @NonNull
getSessionProcessor()194     public abstract SessionProcessor getSessionProcessor();
195 
196     /**
197      * Returns a list of orthogonal capture request keys.
198      *
199      * <p>Any keys included in the list will be configurable by clients of
200      * the extension and will affect the extension functionality.</p>
201      *
202      * <p>Please note that the keys {@link CaptureRequest#JPEG_QUALITY}
203      * and {@link CaptureRequest#JPEG_ORIENTATION} are always supported
204      * regardless of being added to the list or not. To support common
205      * camera operations like zoom, tap-to-focus, flash and
206      * exposure compensation, we recommend supporting the following keys
207      * if  possible.
208      * <pre>
209      *  zoom:  {@link CaptureRequest#CONTROL_ZOOM_RATIO}
210      *         {@link CaptureRequest#SCALER_CROP_REGION}
211      *  tap-to-focus:
212      *         {@link CaptureRequest#CONTROL_AF_MODE}
213      *         {@link CaptureRequest#CONTROL_AF_TRIGGER}
214      *         {@link CaptureRequest#CONTROL_AF_REGIONS}
215      *         {@link CaptureRequest#CONTROL_AE_REGIONS}
216      *         {@link CaptureRequest#CONTROL_AWB_REGIONS}
217      *  flash:
218      *         {@link CaptureRequest#CONTROL_AE_MODE}
219      *         {@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER}
220      *         {@link CaptureRequest#FLASH_MODE}
221      *  exposure compensation:
222      *         {@link CaptureRequest#CONTROL_AE_EXPOSURE_COMPENSATION}
223      * </pre>
224      *
225      * @param cameraId           The camera2 id string of the camera.
226      *
227      * @return The list of supported orthogonal capture keys, or empty
228      * list if no capture settings are not supported.
229      */
230     @FlaggedApi(Flags.FLAG_CONCERT_MODE)
231     @NonNull
getAvailableCaptureRequestKeys( @onNull String cameraId)232     public abstract List<CaptureRequest.Key> getAvailableCaptureRequestKeys(
233             @NonNull String cameraId);
234 
235     /**
236      * Returns a list of supported capture result keys.
237      *
238      * <p>Any keys included in this list must be available as part of the
239      * registered {@link CaptureCallback#onCaptureCompleted} callback.</p>
240      *
241      * <p>At the very minimum, it is expected that the result key list is
242      * a superset of the capture request keys.</p>
243      *
244      * @param cameraId           The camera2 id string of the camera.
245      * @return The list of supported capture result keys, or
246      * empty list if capture results are not supported.
247      */
248     @FlaggedApi(Flags.FLAG_CONCERT_MODE)
249     @NonNull
getAvailableCaptureResultKeys( @onNull String cameraId)250     public abstract List<CaptureResult.Key> getAvailableCaptureResultKeys(
251             @NonNull String cameraId);
252 
253     /**
254      * Returns a list of {@link CameraCharacteristics} key/value pairs for apps to use when
255      * querying the Extensions specific {@link CameraCharacteristics}.
256      *
257      * <p>To ensure the correct {@link CameraCharacteristics} are used when an extension is
258      * enabled, an application should prioritize the value returned from the list if the
259      * {@link CameraCharacteristics} key is present. If the key doesn't exist in the returned list,
260      * then the application should query the value using
261      * {@link CameraCharacteristics#get(CameraCharacteristics.Key)}.
262      *
263      * <p>For example, an extension may limit the zoom ratio range. In this case, an OEM can return
264      * a new zoom ratio range for the key {@link CameraCharacteristics#CONTROL_ZOOM_RATIO_RANGE}.
265      *
266      * <p> Currently, the only synthetic keys supported for override are
267      * {@link CameraCharacteristics#REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES} and
268      * {@link CameraCharacteristics#REQUEST_AVAILABLE_COLOR_SPACE_PROFILES}. To enable them, an OEM
269      * should override the respective native keys
270      * {@link CameraCharacteristics#REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP} and
271      *  {@link CameraCharacteristics#REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP}.
272      */
273     @FlaggedApi(Flags.FLAG_CAMERA_EXTENSIONS_CHARACTERISTICS_GET)
274     @NonNull
275     public abstract List<Pair<CameraCharacteristics.Key, Object>>
getAvailableCharacteristicsKeyValues()276             getAvailableCharacteristicsKeyValues();
277 
278     private final class AdvancedExtenderImpl extends IAdvancedExtenderImpl.Stub {
279         @Override
isExtensionAvailable(String cameraId, Map<String, CameraMetadataNative> charsMapNative)280         public boolean isExtensionAvailable(String cameraId,
281                 Map<String, CameraMetadataNative> charsMapNative) {
282             return AdvancedExtender.this.isExtensionAvailable(cameraId,
283                     new CharacteristicsMap(charsMapNative));
284         }
285 
286         @Override
init(String cameraId, Map<String, CameraMetadataNative> charsMapNative)287         public void init(String cameraId, Map<String, CameraMetadataNative> charsMapNative) {
288             AdvancedExtender.this.initialize(cameraId, new CharacteristicsMap(charsMapNative));
289         }
290 
291         @Override
getSupportedPostviewResolutions( android.hardware.camera2.extension.Size captureSize)292         public List<SizeList> getSupportedPostviewResolutions(
293                 android.hardware.camera2.extension.Size captureSize) {
294             // Feature is currently unsupported
295             return null;
296         }
297 
298         @Override
getSupportedPreviewOutputResolutions(String cameraId)299         public List<SizeList> getSupportedPreviewOutputResolutions(String cameraId) {
300                 return initializeParcelable(
301                         AdvancedExtender.this.getSupportedPreviewOutputResolutions(cameraId));
302         }
303 
304         @Override
getSupportedCaptureOutputResolutions(String cameraId)305         public List<SizeList> getSupportedCaptureOutputResolutions(String cameraId) {
306             return initializeParcelable(
307                     AdvancedExtender.this.getSupportedCaptureOutputResolutions(cameraId));
308         }
309 
310         @Override
getEstimatedCaptureLatencyRange(String cameraId, android.hardware.camera2.extension.Size outputSize, int format)311         public LatencyRange getEstimatedCaptureLatencyRange(String cameraId,
312                 android.hardware.camera2.extension.Size outputSize, int format) {
313             // Feature is currently unsupported
314             return null;
315         }
316 
317         @Override
getSessionProcessor()318         public ISessionProcessorImpl getSessionProcessor() {
319             SessionProcessor processor =AdvancedExtender.this.getSessionProcessor();
320             processor.setCameraUsageTracker(mCameraUsageTracker);
321             return processor.getSessionProcessorBinder();
322         }
323 
324         @Override
getAvailableCaptureRequestKeys(String cameraId)325         public CameraMetadataNative getAvailableCaptureRequestKeys(String cameraId) {
326             List<CaptureRequest.Key> supportedCaptureKeys =
327                     AdvancedExtender.this.getAvailableCaptureRequestKeys(cameraId);
328 
329             if (!supportedCaptureKeys.isEmpty()) {
330                 CameraMetadataNative ret = new CameraMetadataNative();
331                 long vendorId = getMetadataVendorId(cameraId);
332                 ret.setVendorId(vendorId);
333                 int requestKeyTags[] = new int[supportedCaptureKeys.size()];
334                 int i = 0;
335                 for (CaptureRequest.Key key : supportedCaptureKeys) {
336                     requestKeyTags[i++] = CameraMetadataNative.getTag(key.getName(), vendorId);
337                 }
338                 ret.set(CameraCharacteristics.REQUEST_AVAILABLE_REQUEST_KEYS, requestKeyTags);
339 
340                 return ret;
341             }
342 
343             return null;
344         }
345 
346         @Override
getAvailableCaptureResultKeys(String cameraId)347         public CameraMetadataNative getAvailableCaptureResultKeys(String cameraId) {
348             List<CaptureResult.Key> supportedResultKeys =
349                     AdvancedExtender.this.getAvailableCaptureResultKeys(cameraId);
350 
351             if (!supportedResultKeys.isEmpty()) {
352                 CameraMetadataNative ret = new CameraMetadataNative();
353                 long vendorId = getMetadataVendorId(cameraId);
354                 ret.setVendorId(vendorId);
355                 int resultKeyTags [] = new int[supportedResultKeys.size()];
356                 int i = 0;
357                 for (CaptureResult.Key key : supportedResultKeys) {
358                     resultKeyTags[i++] = CameraMetadataNative.getTag(key.getName(), vendorId);
359                 }
360                 ret.set(CameraCharacteristics.REQUEST_AVAILABLE_RESULT_KEYS, resultKeyTags);
361 
362                 return ret;
363             }
364 
365             return null;
366         }
367 
368         @Override
isCaptureProcessProgressAvailable()369         public boolean isCaptureProcessProgressAvailable() {
370             // Feature is currently unsupported
371             return false;
372         }
373 
374         @Override
isPostviewAvailable()375         public boolean isPostviewAvailable() {
376             // Feature is currently unsupported
377             return false;
378         }
379 
380         @FlaggedApi(Flags.FLAG_CAMERA_EXTENSIONS_CHARACTERISTICS_GET)
381         @Override
getAvailableCharacteristicsKeyValues(String cameraId)382         public CameraMetadataNative getAvailableCharacteristicsKeyValues(String cameraId) {
383             List<Pair<CameraCharacteristics.Key, Object>> entries =
384                     AdvancedExtender.this.getAvailableCharacteristicsKeyValues();
385 
386             if ((entries != null) && !entries.isEmpty()) {
387                 CameraMetadataNative ret = new CameraMetadataNative();
388                 long vendorId = mMetadataVendorIdMap.containsKey(cameraId)
389                         ? mMetadataVendorIdMap.get(cameraId) : Long.MAX_VALUE;
390                 ret.setVendorId(vendorId);
391                 int[] characteristicsKeyTags = new int[entries.size()];
392                 int i = 0;
393                 for (Pair<CameraCharacteristics.Key, Object> entry : entries) {
394                     int tag = CameraMetadataNative.getTag(entry.first.getName(), vendorId);
395                     characteristicsKeyTags[i++] = tag;
396                     ret.set(entry.first, entry.second);
397                 }
398                 ret.set(CameraCharacteristics.REQUEST_AVAILABLE_CHARACTERISTICS_KEYS,
399                         characteristicsKeyTags);
400 
401                 return ret;
402             }
403 
404             return null;
405         }
406     }
407 
getAdvancedExtenderBinder()408     @NonNull IAdvancedExtenderImpl getAdvancedExtenderBinder() {
409         return new AdvancedExtenderImpl();
410     }
411 
initializeParcelable( Map<Integer, List<android.util.Size>> sizes)412     private static List<SizeList> initializeParcelable(
413             Map<Integer, List<android.util.Size>> sizes) {
414         if (sizes == null) {
415             return null;
416         }
417         ArrayList<SizeList> ret = new ArrayList<>(sizes.size());
418         for (Map.Entry<Integer, List<android.util.Size>> entry : sizes.entrySet()) {
419             SizeList sizeList = new SizeList();
420             sizeList.format = entry.getKey();
421             sizeList.sizes = new ArrayList<>();
422             for (android.util.Size size : entry.getValue()) {
423                 android.hardware.camera2.extension.Size sz =
424                         new android.hardware.camera2.extension.Size();
425                 sz.width = size.getWidth();
426                 sz.height = size.getHeight();
427                 sizeList.sizes.add(sz);
428             }
429             ret.add(sizeList);
430         }
431 
432         return ret;
433     }
434 }
435