Nagrywanie filmów HDR

Uwaga: ta strona dotyczy pakietu Camera2. Jeśli aplikacja nie wymaga określonych, niskiego poziomu funkcji z Aparatu2, zalecamy użycie CameraX. Zarówno aplikacja CameraX, jak i Aparat 2 obsługują Androida 5.0 (poziom interfejsu API 21) i nowsze wersje.

Interfejsy Camera2 API obsługują nagrywanie filmów w trybie High Dynamic Range (HDR), dzięki czemu możesz wyświetlać podgląd filmów w trybie HDR i nagrywać je za pomocą kamery. W porównaniu ze standardowym zakresem dynamiki (SDR) HDR oferuje szerszy zakres kolorów i zwiększa zakres dynamiczny komponentu luminancji (od 100 cd/m2 do 1000 s pojemności cd/m2). W rezultacie film o jakości bardziej przypominającej obraz w rzeczywistości – ma bogatsze kolory, jaśniejsze podświetlenia i ciemniejsze cienie.

Zobacz, jak filmy HDR uchwycą zachód słońca z większą ostrością.

Rysunek 1. Porównanie jakości filmów SDR (u góry i u dołu) i HDR (u dołu).

Wymagania wstępne urządzenia

Nie wszystkie urządzenia z Androidem obsługują nagrywanie filmów w technologii HDR. Przed nagraniem filmów HDR w swojej aplikacji sprawdź, czy Twoje urządzenie spełnia te wymagania wstępne:

  • Aplikacja jest kierowana na Androida 13 (poziom API 33).
  • Ma czujnik 10-bitowy lub szybszy. 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 na niezgodnych urządzeniach aplikacja będzie wracała do SDR. Zastanów się też nad dodaniem opcji interfejsu do obsługi SDR. Następnie użytkownik może przełączać się między SDR a HDR w zależności od potrzeb związanych z nagrywaniem filmów.

Architektura nagrywania HDR

Poniższy schemat przedstawia główne elementy architektury HDR.

Diagram architektury HDR.
Rysunek 2. Diagram architektury HDR.

Gdy aparat rejestruje klatkę w trybie HDR, platforma Camera2 przydziela bufor, w którym przechowywane są przetworzone dane wyjściowe czujnika aparatu. Dołącza też odpowiednie metadane HDR, jeśli jest to wymagane przez profil HDR. Platforma Camera2 doda do kolejki wypełniony bufor dla platformy wyjściowej określonej w CaptureRequest, takiej jak wyświetlacz lub koder wideo, jak widać na schemacie.

Sprawdzanie obsługi HDR

Przed nagraniem filmu HDR w aplikacji sprawdź, czy urządzenie obsługuje wybrany profil HDR.

Aby uzyskać instancję CameraCharacteristics, do której możesz wysyłać zapytania o funkcje HDR Twojego urządzenia, użyj metody CameraManager getCameraCharacteristics().

Wykonaj te czynności, aby sprawdzić, czy urządzenie obsługuje HLG10. HLG10 to podstawowy standard HDR, który producenci urządzeń muszą obsługiwać w przypadku kamer z 10-bitowym wyjściem.

  1. Najpierw sprawdź, czy urządzenie obsługuje 10-bitowe profile (głębokość bitową w przypadku HLG10):

    Kotlin

    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
    }
    
  2. Następnie sprawdź, czy urządzenie obsługuje HLG10 (lub inny obsługiwany profil):

    Kotlin

    @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 desired profile, in this case HLG10
      return availableProfiles.contains(DynamicRangeProfiles.HLG10)
    }
    return false;
    }
    

Jeśli urządzenie obsługuje HDR, isHLGSupported() zawsze zwraca wartość true. Więcej informacji znajdziesz w dokumentacji referencyjnej CameraCharacteristics.

Skonfiguruj robienie zdjęć HDR

Gdy upewnisz się, że Twoje urządzenie obsługuje HDR, skonfiguruj aplikację, aby nagrywać nieprzetworzony strumień wideo HDR z aparatu. Za pomocą setDynamicRangeProfile() możesz udostępnić do strumienia OutputConfiguration profil HDR obsługiwany przez urządzenie, który po utworzeniu jest przekazywany do CameraCaptureSession. Zobacz listę obsługiwanych profili HDR.

W tym przykładowym kodzie setupSessionDynamicRangeProfile() najpierw sprawdza, czy na urządzeniu działa Android 13. Następnie konfiguruje CameraCaptureSession z profilem HDR obsługiwanym przez urządzenie jako OutputConfiguration:

Kotlin

  /**
  * Creates a [CameraCaptureSession] with a dynamic range profile.
  */
  private fun setupSessionWithDynamicRangeProfile(
          dynamicRange: Long,
          device: CameraDevice,
          targets: List,
          handler: Handler? = null,
          stateCallback: CameraCaptureSession.StateCallback
  ): Boolean {
      if (android.os.Build.VERSION.SDK_INT >=
              android.os.Build.VERSION_CODES.TIRAMISU) {
          val outputConfigs = mutableListOf()
              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 uruchamia kamerę, wysyła powtarzający się kod CaptureRequest w celu wyświetlenia podglądu nagrania:

Kotlin

session.setRepeatingRequest(previewRequest, null, cameraHandler)

Aby rozpocząć nagrywanie filmu:

Kotlin

// 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 danych HDR z kamery

Aby zakodować strumień z kamery HDR i zapisać plik na dysku, użyj narzędzia MediaCodec.

Najpierw pobierz parametr OutputSurface, który jest mapowany na bufor przechowujący nieprzetworzone dane wideo. W przypadku MediaCodec użyj createInputSurface().

Aby zainicjować MediaCodec, aplikacja musi utworzyć MediaFormat z określonym profilem kodeka, przestrzenią kolorów, zakresem kolorów i funkcją transferu:

Kotlin

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 dokumencie EncoderWrapper.kt dotyczącym przykładowej aplikacji Camera2Video.

Formaty HDR

Od Androida 13 aparaty z 10-bitowym wyjściem muszą obsługiwać HLG10, aby można było robić zdjęcia w trybie HDR i odtwarzać treści. Producenci urządzeń mogą też włączyć dowolny wybrany przez siebie format HDR za pomocą architektury nagrywania HDR.

W tabeli poniżej znajdziesz podsumowanie dostępnych formatów HDR oraz ich możliwości w zakresie nagrywania filmów HDR.

Format Funkcja transferu (TF) Metadane Kodek Głębia bitowa
HLG10 HLG Nie Ogrzewanie, wentylacja i klimatyzacja 10-bitowy
HDR10 PQ Statyczne Ogrzewanie, wentylacja i klimatyzacja 10-bitowy
HDR10+ PQ Dynamiczne Ogrzewanie, wentylacja i klimatyzacja 10-bitowy
Dolby Vision 8.4 HLG Dynamiczne Ogrzewanie, wentylacja i klimatyzacja 10-bitowy

Zasoby

Informacje o działającej aplikacji z funkcją nagrywania filmów HDR znajdziesz w tym artykule na GitHubie.