Uwaga: ta strona dotyczy pakietu Camera2. Jeśli Twoja aplikacja nie wymaga określonych funkcji niskiego poziomu z Camera2, zalecamy używanie CameraX. Zarówno CameraX, jak i Camera2 obsługują Androida 5.0 (poziom interfejsu API 21) i nowsze wersje.
Interfejsy API Camera2 obsługują nagrywanie filmów w technologii High Dynamic Range (HDR), co umożliwia wyświetlanie podglądu i nagrywanie treści wideo HDR za pomocą aparatu. W porównaniu ze standardowym zakresem dynamiki (SDR) HDR oferuje szerszy zakres kolorów i zwiększa zakres dynamiki komponentu luminancji (z obecnych 100 cd/m2 do tysięcy cd/m2). Dzięki temu jakość filmu jest bardziej zbliżona do rzeczywistości, z bogatszymi kolorami, jaśniejszymi światłami i ciemniejszymi cieniami.
Zobacz, jak film HDR pozwala uchwycić zachód słońca z większą ilością szczegółów.
Wymagania wstępne dotyczące urządzeń
Nie wszystkie urządzenia z Androidem obsługują nagrywanie filmów HDR. Zanim zaczniesz nagrywać filmy HDR w aplikacji, sprawdź, czy urządzenie spełnia te wymagania:
- jest kierowana na Androida 13 (poziom API 33);
- ma matrycę aparatu obsługującą co najmniej 10 bitów, Więcej informacji o obsłudze HDR znajdziesz w artykule Sprawdzanie obsługi HDR.
Nie wszystkie urządzenia spełniają wymagania wstępne, dlatego podczas konfigurowania nagrywania filmów HDR w aplikacji możesz dodać osobną ścieżkę kodu. Dzięki temu aplikacja będzie mogła przełączyć się na SDR na niezgodnych urządzeniach. Rozważ też dodanie opcji interfejsu dla SDR. Użytkownik może przełączać się między trybami SDR i HDR podczas nagrywania filmów.
Architektura przechwytywania HDR
Poniższy diagram przedstawia główne komponenty architektury przechwytywania HDR.
Gdy aparat rejestruje klatkę w trybie HDR, platforma Camera2 przydziela bufor, w którym przechowywane są przetworzone dane wyjściowe z czujnika aparatu. W razie potrzeby dołącza też odpowiednie metadane HDR, jeśli wymaga tego profil HDR. Następnie platforma Camera2 umieszcza wypełniony bufor w kolejce do powierzchni wyjściowej, do której odwołuje się CaptureRequest, np. wyświetlacza lub kodera wideo, jak pokazano na diagramie.
Sprawdzanie obsługi HDR
Zanim zaczniesz nagrywać filmy HDR w aplikacji, sprawdź, czy urządzenie obsługuje wybrany profil HDR.
Użyj metody CameraManager
getCameraCharacteristics(), aby uzyskać instancję CameraCharacteristics, którą możesz odpytać o możliwości HDR urządzenia.
Aby sprawdzić, czy urządzenie obsługuje HLG10, wykonaj te czynności. HLG10 to podstawowy standard HDR, który producenci urządzeń muszą obsługiwać w aparatach z 10-bitowym wyjściem.
Najpierw sprawdź, czy urządzenie obsługuje profile 10-bitowe (głębia bitowa dla HLG10):
private fun isTenBitProfileSupported(cameraId: String): Boolean { val cameraCharacteristics = cameraManager.getCameraCharacteristics(cameraId) val availableCapabilities = cameraCharacteristics.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES) for (capability in availableCapabilities!!) { if (capability == CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT) { return true } } return false }Następnie sprawdź, czy urządzenie obsługuje HLG10 (lub inny obsługiwany profil):
@RequiresApi(api = 33) private fun isHLGSupported(cameraId: String): Boolean { if (isTenBitProfileSupported(cameraId)) { Val cameraCharacteristics = cameraManager.getCameraCharacteristics(cameraId) val availableProfiles = cameraCharacteristics .get(CameraCharacteristics.REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES)!! .getSupportedProfiles() // Checks for the chosen profile, in this case HLG10 return availableProfiles.contains(DynamicRangeProfiles.HLG10) } return false; }
Jeśli urządzenie obsługuje HDR, isHLGSupported() zawsze zwraca true. Więcej informacji znajdziesz w dokumentacji referencyjnej CameraCharacteristics.
Konfigurowanie przechwytywania HDR
Po upewnieniu się, że urządzenie obsługuje HDR, skonfiguruj aplikację tak, aby rejestrowała nieprzetworzony strumień wideo HDR z aparatu. Użyj setDynamicRangeProfile(), aby przekazać do OutputConfiguration strumienia obsługiwany przez urządzenie profil HDR, który następnie zostanie przekazany do CameraCaptureSession podczas tworzenia. Zobacz listę obsługiwanych profili HDR.
W poniższym przykładowym kodzie setupSessionDynamicRangeProfile() najpierw sprawdza, czy na urządzeniu jest zainstalowany Android 13. Następnie konfiguruje CameraCaptureSession z profilem HDR obsługiwanym przez urządzenie jako OutputConfiguration:
/**
* Creates a [CameraCaptureSession] with a dynamic range profile.
*/
private fun setupSessionWithDynamicRangeProfile(
dynamicRange: Long,
device: CameraDevice,
targets: List<Surface>,
handler: Handler? = null,
stateCallback: CameraCaptureSession.StateCallback
): Boolean {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.TIRAMISU) {
val outputConfigs = mutableListOf<OutputConfiguration>()
for (target in targets) {
val outputConfig = OutputConfiguration(target)
//sets the dynamic range profile, for example DynamicRangeProfiles.HLG10
outputConfig.setDynamicRangeProfile(dynamicRange)
outputConfigs.add(outputConfig)
}
device.createCaptureSessionByOutputConfigurations(
outputConfigs, stateCallback, handler
)
return true
} else {
device.createCaptureSession(targets, stateCallback, handler)
return false
}
}
Gdy aplikacja aparatu inicjuje aparat, wysyła powtarzający się obiekt CaptureRequest, aby wyświetlić podgląd nagrania:
session.setRepeatingRequest(previewRequest, null, cameraHandler)
Aby rozpocząć nagrywanie filmu:
// Start recording repeating requests, which stops the ongoing preview
// repeating requests without having to explicitly call
// `session.stopRepeating`
session.setRepeatingRequest(recordRequest,
object : CameraCaptureSession.CaptureCallback() {
override fun onCaptureCompleted(session: CameraCaptureSession,
request: CaptureRequest, result: TotalCaptureResult) {
if (currentlyRecording) {
encoder.frameAvailable()
}
}
}, cameraHandler)
Kodowanie strumienia z kamery HDR
Aby zakodować strumień z kamery HDR i zapisać plik na dysku, użyj MediaCodec.
Najpierw pobierz dane wyjściowe Surface, które są mapowane na bufor przechowujący nieprzetworzone dane wideo. W polu MediaCodec użyj createInputSurface().
Aby zainicjować MediaCodec, aplikacja musi utworzyć MediaFormat z określonym profilem kodeka, przestrzenią barw, zakresem kolorów i funkcją transferu:
val mimeType = when {
dynamicRange == DynamicRangeProfiles.STANDARD -> MediaFormat.MIMETYPE_VIDEO_AVC
dynamicRange < DynamicRangeProfiles.PUBLIC_MAX ->
MediaFormat.MIMETYPE_VIDEO_HEVC
else -> throw IllegalArgumentException("Unknown dynamic range format")
}
val codecProfile = when {
dynamicRange == DynamicRangeProfiles.HLG10 ->
MediaCodecInfo.CodecProfileLevel.HEVCProfileMain10
dynamicRange == DynamicRangeProfiles.HDR10 ->
MediaCodecInfo.CodecProfileLevel.HEVCProfileMain10HDR10
dynamicRange == DynamicRangeProfiles.HDR10_PLUS ->
MediaCodecInfo.CodecProfileLevel.HEVCProfileMain10HDR10Plus
else -> -1
}
// Failing to correctly set color transfer causes quality issues
// for example, washout and color clipping
val transferFunction = when (codecProfile) {
MediaCodecInfo.CodecProfileLevel.HEVCProfileMain10 ->
MediaFormat.COLOR_TRANSFER_HLG
MediaCodecInfo.CodecProfileLevel.HEVCProfileMain10HDR10 ->
MediaFormat.COLOR_TRANSFER_ST2084
MediaCodecInfo.CodecProfileLevel.HEVCProfileMain10HDR10Plus ->
MediaFormat.COLOR_TRANSFER_ST2084
else -> MediaFormat.COLOR_TRANSFER_SDR_VIDEO
}
val format = MediaFormat.createVideoFormat(mimeType, width, height)
// Set some properties. Failing to specify some of these can cause the MediaCodec
// configure() call to throw an exception.
format.setInteger(MediaFormat.KEY_COLOR_FORMAT,
MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface)
format.setInteger(MediaFormat.KEY_BIT_RATE, bitRate)
format.setInteger(MediaFormat.KEY_FRAME_RATE, frameRate)
format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, IFRAME_INTERVAL)
if (codecProfile != -1) {
format.setInteger(MediaFormat.KEY_PROFILE, codecProfile)
format.setInteger(MediaFormat.KEY_COLOR_STANDARD,
MediaFormat.COLOR_STANDARD_BT2020)
format.setInteger(MediaFormat.KEY_COLOR_RANGE, MediaFormat.COLOR_RANGE_LIMITED)
format.setInteger(MediaFormat.KEY_COLOR_TRANSFER, transferFunction)
format.setFeatureEnabled(MediaCodecInfo.CodecCapabilities.FEATURE_HdrEditing,
true)
}
mediaCodec.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE)
Więcej informacji o implementacji znajdziesz w EncoderWrapper.kt przykładowej aplikacji Camera2Video.
Formaty HDR
Od Androida 13 urządzenia z aparatem, które mogą generować 10-bitowe dane wyjściowe, muszą obsługiwać HLG10 do nagrywania i odtwarzania w trybie HDR. Dodatkowo producenci urządzeń mogą włączyć dowolny format HDR, korzystając z architektury przechwytywania HDR.
Tabela poniżej zawiera podsumowanie dostępnych formatów HDR i ich możliwości w zakresie nagrywania filmów HDR.
| Format | Funkcja transferu (TF) | Metadane | Kodek | Głębia bitowa |
|---|---|---|---|---|
| HLG10 | HLG | Nie | HEVC | 10-bitowa |
| HDR10 | PQ | Statyczny | HEVC | 10-bitowa |
| HDR10+ | PQ | Dynamiczna | HEVC | 10-bitowa |
| Dolby Vision 8.4 | HLG | Dynamiczna | HEVC | 10-bitowa |
Zasoby
Działającą aplikację z funkcją nagrywania filmów HDR znajdziesz w przykładzie Camera2Video na GitHubie.