/* * Copyright (C) 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.hardware.camera2.params; import android.annotation.LongDef; import android.annotation.NonNull; import android.hardware.camera2.CameraMetadata; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Set; /** * Immutable class with information about supported 10-bit dynamic range profiles. * *

An instance of this class can be queried by retrieving the value of * {@link android.hardware.camera2.CameraCharacteristics#REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES}. *

* *

All camera devices supporting the * {@link android.hardware.camera2.CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT} * capability must advertise the supported 10-bit dynamic range profiles in * {@link #getSupportedProfiles}

* *

Some devices may not be able to support 8-bit and/or 10-bit output with different dynamic * range profiles within the same capture request. Such device specific constraints can be queried * by calling {@link #getProfileCaptureRequestConstraints}. Do note that unsupported * combinations will result in {@link IllegalArgumentException} when trying to submit a capture * request. Capture requests that only reference outputs configured using the same dynamic range * profile value will never fail due to such constraints.

* * @see OutputConfiguration#setDynamicRangeProfile */ public final class DynamicRangeProfiles { /** * This the default 8-bit standard profile that will be used in case where camera clients do not * explicitly configure a supported dynamic range profile by calling * {@link OutputConfiguration#setDynamicRangeProfile}. */ public static final long STANDARD = CameraMetadata.REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD; /** * 10-bit pixel samples encoded using the Hybrid log-gamma transfer function * *

All 10-bit output capable devices are required to support this profile.

*/ public static final long HLG10 = CameraMetadata.REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HLG10; /** * 10-bit pixel samples encoded using the SMPTE ST 2084 transfer function. * *

This profile utilizes internal static metadata to increase the quality * of the capture.

*/ public static final long HDR10 = CameraMetadata.REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HDR10; /** * 10-bit pixel samples encoded using the SMPTE ST 2084 transfer function. * *

In contrast to HDR10, this profile uses internal per-frame metadata * to further enhance the quality of the capture.

*/ public static final long HDR10_PLUS = CameraMetadata.REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HDR10_PLUS; /** *

This is a camera mode for Dolby Vision capture optimized for a more scene * accurate capture. This would typically differ from what a specific device * might want to tune for a consumer optimized Dolby Vision general capture.

*/ public static final long DOLBY_VISION_10B_HDR_REF = CameraMetadata.REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_REF; /** *

This is the power optimized mode for 10-bit Dolby Vision HDR Reference Mode.

*/ public static final long DOLBY_VISION_10B_HDR_REF_PO = CameraMetadata.REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_REF_PO; /** *

This is the camera mode for the default Dolby Vision capture mode for the * specific device. This would be tuned by each specific device for consumer * pleasing results that resonate with their particular audience. We expect * that each specific device would have a different look for their default * Dolby Vision capture.

*/ public static final long DOLBY_VISION_10B_HDR_OEM = CameraMetadata.REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_OEM; /** *

This is the power optimized mode for 10-bit Dolby Vision HDR device specific capture * Mode.

*/ public static final long DOLBY_VISION_10B_HDR_OEM_PO = CameraMetadata.REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_OEM_PO; /** *

This is the 8-bit version of the Dolby Vision reference capture mode optimized * for scene accuracy.

*/ public static final long DOLBY_VISION_8B_HDR_REF = CameraMetadata.REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_REF; /** *

This is the power optimized mode for 8-bit Dolby Vision HDR Reference Mode.

*/ public static final long DOLBY_VISION_8B_HDR_REF_PO = CameraMetadata.REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_REF_PO; /** *

This is the 8-bit version of device specific tuned and optimized Dolby Vision * capture mode.

*/ public static final long DOLBY_VISION_8B_HDR_OEM = CameraMetadata.REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_OEM; /** *

This is the power optimized mode for 8-bit Dolby Vision HDR device specific * capture Mode.

*/ public static final long DOLBY_VISION_8B_HDR_OEM_PO = CameraMetadata.REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_OEM_PO; /* * @hide */ public static final long PUBLIC_MAX = CameraMetadata.REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_MAX; /** @hide */ @Retention(RetentionPolicy.SOURCE) @LongDef(prefix = {"PROFILE_"}, value = {STANDARD, HLG10, HDR10, HDR10_PLUS, DOLBY_VISION_10B_HDR_REF, DOLBY_VISION_10B_HDR_REF_PO, DOLBY_VISION_10B_HDR_OEM, DOLBY_VISION_10B_HDR_OEM_PO, DOLBY_VISION_8B_HDR_REF, DOLBY_VISION_8B_HDR_REF_PO, DOLBY_VISION_8B_HDR_OEM, DOLBY_VISION_8B_HDR_OEM_PO}) public @interface Profile { } private final HashMap> mProfileMap = new HashMap<>(); private final HashMap mLookahedLatencyMap = new HashMap<>(); /** * Create a new immutable DynamicRangeProfiles instance. * *

This constructor takes over the array; do not write to the array afterwards.

* *

Do note that the constructor is available for testing purposes only! * Camera clients must always retrieve the value of * {@link android.hardware.camera2.CameraCharacteristics#REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES}. * for a given camera id in order to retrieve the device capabilities.

* * @param elements * An array of elements describing the map. It contains three elements per entry. The * first element describes the supported dynamic range profile value. The * second element contains a bitmap of concurrently supported dynamic range profiles * within the same capture request. The third element contains a hint about * extra latency associated with the corresponding dynamic range. Bitmap values of 0 * indicate that there are no constraints. * * @throws IllegalArgumentException * if the {@code elements} array length is invalid, not divisible by 3 or contains * invalid element values * @throws NullPointerException * if {@code elements} is {@code null} * */ public DynamicRangeProfiles(@NonNull final long[] elements) { if ((elements.length % 3) != 0) { throw new IllegalArgumentException("Dynamic range profile map length " + elements.length + " is not even!"); } for (int i = 0; i < elements.length; i += 3) { checkProfileValue(elements[i]); // STANDARD is not expected to be included if (elements[i] == STANDARD) { throw new IllegalArgumentException("Dynamic range profile map must not include a" + " STANDARD profile entry!"); } HashSet profiles = new HashSet<>(); if (elements[i+1] != 0) { for (long profile = STANDARD; profile < PUBLIC_MAX; profile <<= 1) { if ((elements[i+1] & profile) != 0) { profiles.add(profile); } } } mProfileMap.put(elements[i], profiles); mLookahedLatencyMap.put(elements[i], elements[i+2] != 0L); } // Build the STANDARD constraints depending on the advertised 10-bit limitations HashSet standardConstraints = new HashSet<>(); standardConstraints.add(STANDARD); for(Long profile : mProfileMap.keySet()) { if (mProfileMap.get(profile).isEmpty() || mProfileMap.get(profile).contains(STANDARD)) { standardConstraints.add(profile); } } mProfileMap.put(STANDARD, standardConstraints); mLookahedLatencyMap.put(STANDARD, false); } /** * @hide */ public static void checkProfileValue(long profile) { if (profile == STANDARD || profile == HLG10 || profile == HDR10 || profile == HDR10_PLUS || profile == DOLBY_VISION_10B_HDR_REF || profile == DOLBY_VISION_10B_HDR_REF_PO || profile == DOLBY_VISION_10B_HDR_OEM || profile == DOLBY_VISION_10B_HDR_OEM_PO || profile == DOLBY_VISION_8B_HDR_REF || profile == DOLBY_VISION_8B_HDR_REF_PO || profile == DOLBY_VISION_8B_HDR_OEM || profile == DOLBY_VISION_8B_HDR_OEM_PO) {//No-op } else { throw new IllegalArgumentException("Unknown profile " + profile); } } /** * Return a set of supported dynamic range profiles. * * @return non-modifiable set of dynamic range profiles */ public @NonNull Set getSupportedProfiles() { return Collections.unmodifiableSet(mProfileMap.keySet()); } /** * Return a list of supported dynamic range profiles that * can be referenced in a single capture request along with a given * profile. * *

For example if assume that a particular 10-bit output capable device * returns ({@link #STANDARD}, {@link #HLG10}, {@link #HDR10}) as result from calling * {@link #getSupportedProfiles()} and {@link #getProfileCaptureRequestConstraints} * returns ({@link #STANDARD}, {@link #HLG10}) when given an argument of {@link #STANDARD}. * This means that the corresponding camera device will only accept and process capture requests * that reference outputs configured using {@link #HDR10} dynamic profile or alternatively * some combination of {@link #STANDARD} and {@link #HLG10}. However trying to * queue capture requests to outputs that reference both {@link #HDR10} and * {@link #STANDARD}/{@link #HLG10} will result in {@link IllegalArgumentException}.

* *

The list will be empty in case there are no constraints for the given * profile.

* * @return non-modifiable set of dynamic range profiles * @throws IllegalArgumentException If the profile argument is not * within the list returned by * getSupportedProfiles() * * @see OutputConfiguration#setDynamicRangeProfile */ public @NonNull Set getProfileCaptureRequestConstraints(@Profile long profile) { Set ret = mProfileMap.get(profile); if (ret == null) { throw new IllegalArgumentException("Unsupported profile!"); } return Collections.unmodifiableSet(ret); } /** * Check whether a given dynamic range profile is suitable for latency sensitive use cases. * *

Due to internal lookahead logic, camera outputs configured with some dynamic range * profiles may experience additional latency greater than 3 buffers. Using camera outputs * with such profiles for latency sensitive use cases such as camera preview is not * recommended. Profiles that have such extra streaming delay are typically utilized for * scenarios such as offscreen video recording.

* * @return true if the given profile is not suitable for latency sensitive use cases, false * otherwise * @throws IllegalArgumentException If the profile argument is not * within the list returned by * getSupportedProfiles() * * @see OutputConfiguration#setDynamicRangeProfile */ public boolean isExtraLatencyPresent(@Profile long profile) { Boolean ret = mLookahedLatencyMap.get(profile); if (ret == null) { throw new IllegalArgumentException("Unsupported profile!"); } return ret; } }