Aperture: Hook up video dynamic range
Change-Id: Ia7bf123cfb6afca962e195c991b8919f985c1f49
diff --git a/LICENSES/CC-PDDC.txt b/LICENSES/CC-PDDC.txt
new file mode 100644
index 0000000..b64dfd6
--- /dev/null
+++ b/LICENSES/CC-PDDC.txt
@@ -0,0 +1,8 @@
+
+The person or persons who have associated work with this document (the "Dedicator" or "Certifier") hereby either (a) certifies that, to the best of his knowledge, the work of authorship identified is in the public domain of the country from which the work is published, or (b) hereby dedicates whatever copyright the dedicators holds in the work of authorship identified below (the "Work") to the public domain. A certifier, moreover, dedicates any copyright interest he may have in the associated work, and for these purposes, is described as a "dedicator" below.
+
+A certifier has taken reasonable steps to verify the copyright status of this work. Certifier recognizes that his good faith efforts may not shield him from liability if in fact the work certified is not in the public domain.
+
+Dedicator makes this dedication for the benefit of the public at large and to the detriment of the Dedicator's heirs and successors. Dedicator intends this dedication to be an overt act of relinquishment in perpetuity of all present and future rights under copyright law, whether vested or contingent, in the Work. Dedicator understands that such relinquishment of all rights includes the relinquishment of all rights to enforce (by lawsuit or otherwise) those copyrights in the Work.
+
+Dedicator recognizes that, once placed in the public domain, the Work may be freely reproduced, distributed, transmitted, used, modified, built upon, or otherwise exploited by anyone for any purpose, commercial or non-commercial, and in any way, including by methods that have not yet been invented or conceived.
diff --git a/app/src/main/java/org/lineageos/aperture/CameraActivity.kt b/app/src/main/java/org/lineageos/aperture/CameraActivity.kt
index 5032c0e..6045cb3 100644
--- a/app/src/main/java/org/lineageos/aperture/CameraActivity.kt
+++ b/app/src/main/java/org/lineageos/aperture/CameraActivity.kt
@@ -103,6 +103,8 @@
import org.lineageos.aperture.camera.HotPixelMode
import org.lineageos.aperture.camera.NoiseReductionMode
import org.lineageos.aperture.camera.ShadingMode
+import org.lineageos.aperture.camera.VideoDynamicRange
+import org.lineageos.aperture.camera.VideoQualityInfo
import org.lineageos.aperture.camera.VideoStabilizationMode
import org.lineageos.aperture.ext.*
import org.lineageos.aperture.qr.QrImageAnalyzer
@@ -173,6 +175,7 @@
private val videoFrameRateButton by lazy { findViewById<Button>(R.id.videoFrameRateButton) }
private val videoQualityButton by lazy { findViewById<Button>(R.id.videoQualityButton) }
private val videoRecordingStateButton by lazy { findViewById<ImageButton>(R.id.videoRecordingStateButton) }
+ private val videoDynamicRangeButton by lazy { findViewById<Button>(R.id.videoDynamicRangeButton) }
private val viewFinder by lazy { findViewById<PreviewView>(R.id.viewFinder) }
private val viewFinderFocus by lazy { findViewById<ImageView>(R.id.viewFinderFocus) }
private val zoomLevel by lazy { findViewById<HorizontalSlider>(R.id.zoomLevel) }
@@ -211,6 +214,7 @@
private var photoEffect by nonNullablePropertyDelegate { model.photoEffect }
private var videoQuality by nonNullablePropertyDelegate { model.videoQuality }
private var videoFrameRate by nullablePropertyDelegate { model.videoFrameRate }
+ private var videoDynamicRange by nonNullablePropertyDelegate { model.videoDynamicRange }
private var videoMicMode by nonNullablePropertyDelegate { model.videoMicMode }
private var videoRecording by nullablePropertyDelegate { model.videoRecording }
private var videoDuration by nonNullablePropertyDelegate { model.videoRecordingDuration }
@@ -228,10 +232,12 @@
// Video
private val supportedVideoQualities: Set<Quality>
get() = camera.supportedVideoQualities.keys
+ private val videoQualityInfo: VideoQualityInfo?
+ get() = camera.supportedVideoQualities[videoQuality]
private val supportedVideoFrameRates: Set<FrameRate>
- get() = camera.supportedVideoQualities.getOrDefault(
- videoQuality, setOf()
- )
+ get() = videoQualityInfo?.supportedFrameRates ?: setOf()
+ private val supportedVideoDynamicRanges: Set<VideoDynamicRange>
+ get() = videoQualityInfo?.supportedDynamicRanges ?: setOf()
private lateinit var videoAudioConfig: AudioConfig
// QR
@@ -573,6 +579,7 @@
photoEffect = sharedPreferences.photoEffect
videoQuality = sharedPreferences.videoQuality
videoFrameRate = sharedPreferences.videoFrameRate
+ videoDynamicRange = sharedPreferences.videoDynamicRange
videoMicMode = sharedPreferences.lastMicMode
// Handle intent
@@ -627,6 +634,7 @@
aspectRatioButton.setOnClickListener { cycleAspectRatio() }
videoQualityButton.setOnClickListener { cycleVideoQuality() }
videoFrameRateButton.setOnClickListener { cycleVideoFrameRate() }
+ videoDynamicRangeButton.setOnClickListener { cycleVideoDynamicRange() }
effectButton.setOnClickListener { cyclePhotoEffects() }
gridButton.setOnClickListener { cycleGridMode() }
timerButton.setOnClickListener { toggleTimerMode() }
@@ -868,6 +876,7 @@
aspectRatioButton.isVisible = cameraMode != CameraMode.VIDEO
videoQualityButton.isVisible = cameraMode == CameraMode.VIDEO
videoFrameRateButton.isVisible = cameraMode == CameraMode.VIDEO
+ videoDynamicRangeButton.isVisible = cameraMode == CameraMode.VIDEO
micButton.isVisible = cameraMode == CameraMode.VIDEO
updateSecondaryTopBarButtons()
@@ -1086,6 +1095,16 @@
} ?: resources.getString(R.string.video_framerate_auto)
}
+ model.videoDynamicRange.observe(this) {
+ val videoDynamicRange = it
+
+ // Update secondary bar buttons
+ videoDynamicRangeButton.setCompoundDrawablesWithIntrinsicBounds(
+ 0, videoDynamicRange.icon, 0, 0
+ )
+ videoDynamicRangeButton.setText(videoDynamicRange.title)
+ }
+
// Observe video mic mode
model.videoMicMode.observe(this) {
val videoMicMode = it ?: return@observe
@@ -1536,6 +1555,12 @@
videoFrameRate ?: FrameRate.FPS_30, supportedVideoFrameRates
)
+ // Set video dynamic range
+ videoDynamicRange = videoDynamicRange.takeIf {
+ supportedVideoDynamicRanges.contains(it)
+ } ?: supportedVideoDynamicRanges.first()
+ cameraController.videoCaptureDynamicRange = videoDynamicRange.dynamicRange
+
CameraController.VIDEO_CAPTURE
}
}
@@ -1862,9 +1887,9 @@
val videoRecording = model.videoRecording.value
val supportedVideoQualities = camera.supportedVideoQualities
- val supportedVideoFrameRates = supportedVideoQualities.getOrDefault(
- videoQuality, setOf()
- )
+ val videoQualityInfo = supportedVideoQualities[videoQuality]
+ val supportedVideoFrameRates = videoQualityInfo?.supportedFrameRates ?: setOf()
+ val supportedVideoDynamicRanges = videoQualityInfo?.supportedDynamicRanges ?: setOf()
flashButton.isEnabled =
cameraMode != CameraMode.PHOTO || cameraState == CameraState.IDLE
@@ -1875,6 +1900,8 @@
cameraState == CameraState.IDLE && supportedVideoQualities.size > 1
videoFrameRateButton.isEnabled =
cameraState == CameraState.IDLE && supportedVideoFrameRates.size > 1
+ videoDynamicRangeButton.isEnabled =
+ cameraState == CameraState.IDLE && supportedVideoDynamicRanges.size > 1
micButton.isEnabled =
cameraState == CameraState.IDLE || videoRecording?.isAudioSourceConfigured == true
}
@@ -1953,6 +1980,26 @@
bindCameraUseCases()
}
+ private fun cycleVideoDynamicRange() {
+ if (!canRestartCamera()) {
+ return
+ }
+
+ val currentVideoDynamicRange = videoDynamicRange
+ val newVideoDynamicRange =
+ supportedVideoDynamicRanges.toList().sorted().next(currentVideoDynamicRange)
+
+ if (newVideoDynamicRange == currentVideoDynamicRange) {
+ return
+ }
+
+ videoDynamicRange = newVideoDynamicRange
+
+ sharedPreferences.videoDynamicRange = videoDynamicRange
+
+ bindCameraUseCases()
+ }
+
/**
* Set the specified grid mode, also updating the icon
*/
diff --git a/app/src/main/java/org/lineageos/aperture/camera/Camera.kt b/app/src/main/java/org/lineageos/aperture/camera/Camera.kt
index 0a9cb88..7b78127 100644
--- a/app/src/main/java/org/lineageos/aperture/camera/Camera.kt
+++ b/app/src/main/java/org/lineageos/aperture/camera/Camera.kt
@@ -11,7 +11,6 @@
import androidx.camera.camera2.interop.Camera2CameraInfo
import androidx.camera.core.CameraInfo
import androidx.camera.core.CameraSelector
-import androidx.camera.core.DynamicRange
import androidx.camera.video.Recorder
import org.lineageos.aperture.ext.*
import kotlin.reflect.safeCast
@@ -49,11 +48,30 @@
private val supportedVideoFrameRates = cameraInfo.supportedFrameRateRanges.mapNotNull {
FrameRate.fromRange(it)
}.toSet()
+
+ private val videoCapabilities = Recorder.getVideoCapabilities(cameraInfo)
+
+ private val supportedVideoDynamicRanges = videoCapabilities.supportedDynamicRanges.map {
+ VideoDynamicRange.fromDynamicRange(it)
+ }
+
+ private val videoQualityForDynamicRanges = supportedVideoDynamicRanges.associateWith {
+ videoCapabilities.getSupportedQualities(it.dynamicRange)
+ }
+
val supportedVideoQualities =
- Recorder.getVideoCapabilities(cameraInfo).getSupportedQualities(DynamicRange.SDR)
- .associateWith {
- supportedVideoFrameRates + cameraManager.getAdditionalVideoFrameRates(cameraId, it)
- }.toMap()
+ videoQualityForDynamicRanges.values.flatten().toSet().associateWith {
+ VideoQualityInfo(
+ it,
+ supportedVideoFrameRates.plus(
+ cameraManager.getAdditionalVideoFrameRates(cameraId, it)
+ ),
+ videoQualityForDynamicRanges.entries.filter { dynamicRangeToQualities ->
+ dynamicRangeToQualities.value.contains(it)
+ }.map { dynamicRangeToQualities -> dynamicRangeToQualities.key }.toSet()
+ )
+ }
+
val supportsVideoRecording = supportedVideoQualities.isNotEmpty()
val supportedExtensionModes = cameraManager.extensionsManager.getSupportedModes(cameraSelector)
diff --git a/app/src/main/java/org/lineageos/aperture/camera/CameraViewModel.kt b/app/src/main/java/org/lineageos/aperture/camera/CameraViewModel.kt
index 2e88b2d..6e279c6 100644
--- a/app/src/main/java/org/lineageos/aperture/camera/CameraViewModel.kt
+++ b/app/src/main/java/org/lineageos/aperture/camera/CameraViewModel.kt
@@ -92,6 +92,11 @@
val videoFrameRate = MutableLiveData<FrameRate?>()
/**
+ * Video dynamic range.
+ */
+ val videoDynamicRange = MutableLiveData<VideoDynamicRange>()
+
+ /**
* Video mic mode.
*/
val videoMicMode = MutableLiveData<Boolean>()
diff --git a/app/src/main/java/org/lineageos/aperture/camera/VideoDynamicRange.kt b/app/src/main/java/org/lineageos/aperture/camera/VideoDynamicRange.kt
new file mode 100644
index 0000000..4f2779b
--- /dev/null
+++ b/app/src/main/java/org/lineageos/aperture/camera/VideoDynamicRange.kt
@@ -0,0 +1,60 @@
+/*
+ * SPDX-FileCopyrightText: 2022-2023 The LineageOS Project
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package org.lineageos.aperture.camera
+
+import androidx.annotation.DrawableRes
+import androidx.annotation.StringRes
+import androidx.camera.core.DynamicRange
+import org.lineageos.aperture.R
+
+/**
+ * Video dynamic range.
+ * @param dynamicRange The [DynamicRange] it refers to
+ * @param title A string resource used to represent the dynamic range
+ * @param icon An icon resource used to represent the dynamic range
+ */
+enum class VideoDynamicRange(
+ val dynamicRange: DynamicRange,
+ @StringRes val title: Int,
+ @DrawableRes val icon: Int,
+) {
+ SDR(
+ DynamicRange.SDR,
+ R.string.video_dynamic_range_sdr,
+ R.drawable.ic_hdr_off,
+ ),
+ HLG_10_BIT(
+ DynamicRange.HLG_10_BIT,
+ R.string.video_dynamic_range_hlg_10_bit,
+ R.drawable.ic_hdr_on,
+ ),
+ HDR10_10_BIT(
+ DynamicRange.HDR10_10_BIT,
+ R.string.video_dynamic_range_hdr10_10_bit,
+ R.drawable.ic_hdr_on,
+ ),
+ HDR10_PLUS_10_BIT(
+ DynamicRange.HDR10_PLUS_10_BIT,
+ R.string.video_dynamic_range_hdr10_plus_10_bit,
+ R.drawable.ic_hdr_off,
+ ),
+ DOLBY_VISION_10_BIT(
+ DynamicRange.DOLBY_VISION_10_BIT,
+ R.string.video_dynamic_range_dolby_vision_10_bit,
+ R.drawable.ic_dolby,
+ ),
+ DOLBY_VISION_8_BIT(
+ DynamicRange.DOLBY_VISION_8_BIT,
+ R.string.video_dynamic_range_dolby_vision_8_bit,
+ R.drawable.ic_dolby,
+ );
+
+ companion object {
+ fun fromDynamicRange(dynamicRange: DynamicRange) = values().first {
+ it.dynamicRange == dynamicRange
+ }
+ }
+}
diff --git a/app/src/main/java/org/lineageos/aperture/camera/VideoQualityInfo.kt b/app/src/main/java/org/lineageos/aperture/camera/VideoQualityInfo.kt
new file mode 100644
index 0000000..b2b9d53
--- /dev/null
+++ b/app/src/main/java/org/lineageos/aperture/camera/VideoQualityInfo.kt
@@ -0,0 +1,20 @@
+/*
+ * SPDX-FileCopyrightText: 2023 The LineageOS Project
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package org.lineageos.aperture.camera
+
+import androidx.camera.video.Quality
+
+/**
+ * Video [Quality] info.
+ * @param quality The quality
+ * @param supportedFrameRates The supported frame rates for this quality
+ * @param supportedDynamicRanges The supported dynamic ranges for this quality
+ */
+data class VideoQualityInfo(
+ val quality: Quality,
+ val supportedFrameRates: Set<FrameRate>,
+ val supportedDynamicRanges: Set<VideoDynamicRange>,
+)
diff --git a/app/src/main/java/org/lineageos/aperture/ext/SharedPreferences.kt b/app/src/main/java/org/lineageos/aperture/ext/SharedPreferences.kt
index c4eac57..e71c261 100644
--- a/app/src/main/java/org/lineageos/aperture/ext/SharedPreferences.kt
+++ b/app/src/main/java/org/lineageos/aperture/ext/SharedPreferences.kt
@@ -22,6 +22,7 @@
import org.lineageos.aperture.camera.HotPixelMode
import org.lineageos.aperture.camera.NoiseReductionMode
import org.lineageos.aperture.camera.ShadingMode
+import org.lineageos.aperture.camera.VideoDynamicRange
import org.lineageos.aperture.utils.GestureActions
import org.lineageos.aperture.utils.GridMode
import org.lineageos.aperture.utils.TimerMode
@@ -445,3 +446,30 @@
set(value) = edit {
putBoolean(FORCE_TORCH_HELP_SHOWN_KEY, value)
}
+
+// Video dynamic range
+private const val VIDEO_DYNAMIC_RANGE_KEY = "video_dynamic_range"
+private const val VIDEO_DYNAMIC_RANGE_DEFAULT = "sdr"
+internal var SharedPreferences.videoDynamicRange: VideoDynamicRange
+ get() = when (getString(VIDEO_DYNAMIC_RANGE_KEY, VIDEO_DYNAMIC_RANGE_DEFAULT)) {
+ "sdr" -> VideoDynamicRange.SDR
+ "hlg_10_bit" -> VideoDynamicRange.HLG_10_BIT
+ "hdr10_10_bit" -> VideoDynamicRange.HDR10_10_BIT
+ "hdr10_plus_10_bit" -> VideoDynamicRange.HDR10_PLUS_10_BIT
+ "dolby_vision_10_bit" -> VideoDynamicRange.DOLBY_VISION_10_BIT
+ "dolby_vision_8_bit" -> VideoDynamicRange.DOLBY_VISION_8_BIT
+ // Default to sdr
+ else -> VideoDynamicRange.SDR
+ }
+ set(value) = edit {
+ putString(
+ VIDEO_DYNAMIC_RANGE_KEY, when (value) {
+ VideoDynamicRange.SDR -> "sdr"
+ VideoDynamicRange.HLG_10_BIT -> "hlg_10_bit"
+ VideoDynamicRange.HDR10_10_BIT -> "hdr10_10_bit"
+ VideoDynamicRange.HDR10_PLUS_10_BIT -> "hdr10_plus_10_bit"
+ VideoDynamicRange.DOLBY_VISION_10_BIT -> "dolby_vision_10_bit"
+ VideoDynamicRange.DOLBY_VISION_8_BIT -> "dolby_vision_8_bit"
+ }
+ )
+ }
diff --git a/app/src/main/res/drawable/ic_dolby.xml b/app/src/main/res/drawable/ic_dolby.xml
new file mode 100644
index 0000000..421d535
--- /dev/null
+++ b/app/src/main/res/drawable/ic_dolby.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ SPDX-FileCopyrightText: Dolby Laboratories Inc.
+ SPDX-License-Identifier: CC-PDDC
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="279.08dp"
+ android:height="193.28dp"
+ android:tint="#000000"
+ android:viewportWidth="279.08"
+ android:viewportHeight="193.28">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="m279.08,193.28h-28.14c-53.82,0 -96.64,-44.04 -96.64,-96.64C154.31,44.04 198.35,0 250.95,0h28.14z" />
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="m0,0h28.14c53.82,0 96.64,44.04 96.64,96.64 0,52.6 -44.04,96.64 -96.64,96.64H0Z" />
+</vector>
diff --git a/app/src/main/res/drawable/ic_hdr_off.xml b/app/src/main/res/drawable/ic_hdr_off.xml
new file mode 100644
index 0000000..0ddbca9
--- /dev/null
+++ b/app/src/main/res/drawable/ic_hdr_off.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ SPDX-FileCopyrightText: Material Design Authors / Google LLC
+ SPDX-License-Identifier: Apache-2.0
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:tint="#000000"
+ android:viewportWidth="960"
+ android:viewportHeight="960">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M792,904L56,168L112,112L848,846L792,904ZM780,600L744,520L700,520L700,586L640,526L640,360L780,360Q804,360 822,378Q840,396 840,420L840,460Q840,478 829.5,492.5Q819,507 804,516L840,600L780,600ZM700,460L780,460Q780,460 780,460Q780,460 780,460L780,420Q780,420 780,420Q780,420 780,420L700,420L700,460ZM580,466L474,360L520,360Q544,360 562,378Q580,396 580,420L580,466ZM120,600L120,360L180,360L180,440L260,440L260,360L320,360L320,600L260,600L260,500L180,500L180,600L120,600ZM380,436L440,496L440,540L485,540Q485,540 485,540Q485,540 485,540L540,596Q535,598 530,599Q525,600 520,600L380,600L380,436Z" />
+</vector>
diff --git a/app/src/main/res/drawable/ic_hdr_on.xml b/app/src/main/res/drawable/ic_hdr_on.xml
new file mode 100644
index 0000000..4b9a996
--- /dev/null
+++ b/app/src/main/res/drawable/ic_hdr_on.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ SPDX-FileCopyrightText: Material Design Authors / Google LLC
+ SPDX-License-Identifier: Apache-2.0
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:tint="#000000"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M21,11.5v-1c0,-0.8 -0.7,-1.5 -1.5,-1.5L16,9v6h1.5v-2h1.1l0.9,2L21,15l-0.9,-2.1c0.5,-0.3 0.9,-0.8 0.9,-1.4zM19.5,11.5h-2v-1h2v1zM6.5,11h-2L4.5,9L3,9v6h1.5v-2.5h2L6.5,15L8,15L8,9L6.5,9v2zM13,9L9.5,9v6L13,15c0.8,0 1.5,-0.7 1.5,-1.5v-3c0,-0.8 -0.7,-1.5 -1.5,-1.5zM13,13.5h-2v-3h2v3z" />
+</vector>
diff --git a/app/src/main/res/layout/activity_camera.xml b/app/src/main/res/layout/activity_camera.xml
index 96783f4..9d9ca5a 100644
--- a/app/src/main/res/layout/activity_camera.xml
+++ b/app/src/main/res/layout/activity_camera.xml
@@ -174,18 +174,28 @@
android:drawableTop="@drawable/ic_video_frame_rate"
android:text="@string/video_framerate_auto"
app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintEnd_toStartOf="@+id/micButton"
+ app:layout_constraintEnd_toStartOf="@+id/videoDynamicRangeButton"
app:layout_constraintStart_toEndOf="@+id/videoQualityButton"
app:layout_constraintTop_toTopOf="parent" />
<Button
+ android:id="@+id/videoDynamicRangeButton"
+ style="@style/Theme.Aperture.Camera.SecondaryTopBarButton"
+ android:drawableTop="@drawable/ic_hdr_off"
+ android:text="@string/video_dynamic_range_sdr"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toStartOf="@+id/micButton"
+ app:layout_constraintStart_toEndOf="@+id/videoFrameRateButton"
+ app:layout_constraintTop_toTopOf="parent" />
+
+ <Button
android:id="@+id/micButton"
style="@style/Theme.Aperture.Camera.SecondaryTopBarButton"
android:drawableTop="@drawable/ic_mic_off"
android:text="@string/mic_off"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/timerButton"
- app:layout_constraintStart_toEndOf="@+id/videoFrameRateButton"
+ app:layout_constraintStart_toEndOf="@+id/videoDynamicRangeButton"
app:layout_constraintTop_toTopOf="parent" />
<!-- Common settings -->
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 7b5c5c5..6219fbf 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -185,4 +185,12 @@
<string name="camera_mode_photo">Photo</string>
<string name="camera_mode_video">Video</string>
<string name="camera_mode_qr">Scan</string>
+
+ <!-- Video dynamic ranges -->
+ <string name="video_dynamic_range_sdr" translatable="false">SDR</string>
+ <string name="video_dynamic_range_hlg_10_bit" translatable="false">HLG (10 bit)</string>
+ <string name="video_dynamic_range_hdr10_10_bit" translatable="false">HDR10 (10 bit)</string>
+ <string name="video_dynamic_range_hdr10_plus_10_bit" translatable="false">HDR10+ (10 bit)</string>
+ <string name="video_dynamic_range_dolby_vision_10_bit" translatable="false">Dolby Vision (10 bit)</string>
+ <string name="video_dynamic_range_dolby_vision_8_bit" translatable="false">Dolby Vision (8 bit)</string>
</resources>