Quay video HDR

Lưu ý: Trang này đề cập đến gói Camera2. Bạn nên dùng CameraX, trừ phi ứng dụng của bạn yêu cầu các tính năng cụ thể, cấp thấp của Camera2. Cả CameraX và Camera2 đều hỗ trợ Android 5.0 (API cấp 21) trở lên.

Camera2 API hỗ trợ tính năng quay video có Dải động cao (HDR), cho phép bạn xem trước và quay nội dung video HDR bằng camera. So với Dải màu động tiêu chuẩn (SDR), HDR cung cấp dải màu rộng hơn và tăng dải màu động của thành phần độ chói (từ 100 cd/m2 hiện tại lên đến hàng nghìn cd/m2). Điều này giúp video có chất lượng gần với thực tế hơn, với màu sắc phong phú hơn, điểm sáng tươi sáng hơn và bóng tối tối hơn.

Xem video HDR ghi lại cảnh hoàng hôn với nhiều chi tiết sống động hơn.

Hình 1. So sánh chất lượng video SDR (trên) và HDR (dưới).

Điều kiện tiên quyết về thiết bị

Không phải thiết bị Android nào cũng hỗ trợ tính năng quay video HDR. Trước khi quay video HDR trong ứng dụng, hãy xác định xem thiết bị của bạn có đáp ứng các điều kiện tiên quyết sau đây hay không:

Vì không phải thiết bị nào cũng đáp ứng các điều kiện tiên quyết, nên bạn có thể thêm một đường dẫn mã riêng khi thiết lập tính năng quay video HDR trong ứng dụng. Nhờ đó, ứng dụng của bạn có thể quay về SDR trên các thiết bị không tương thích. Ngoài ra, hãy cân nhắc thêm một lựa chọn giao diện người dùng cho SDR. Sau đó, người dùng có thể chuyển đổi giữa SDR và HDR cho nhu cầu ghi hình của mình.

Cấu trúc chụp ảnh HDR

Sơ đồ sau đây cho thấy các thành phần chính của cấu trúc chụp HDR.

Sơ đồ kiến trúc chụp ảnh HDR.
Hình 2. Sơ đồ kiến trúc chụp ảnh HDR.

Khi một thiết bị camera chụp một khung hình ở chế độ HDR, khung Camera2 sẽ phân bổ một vùng đệm lưu trữ đầu ra của cảm biến camera đã xử lý. Công cụ này cũng đính kèm siêu dữ liệu HDR tương ứng nếu hồ sơ HDR yêu cầu. Sau đó, khung Camera2 sẽ xếp hàng bộ đệm đã điền cho bề mặt đầu ra được tham chiếu trong CaptureRequest, chẳng hạn như màn hình hoặc bộ mã hoá video, như minh hoạ trong sơ đồ.

Kiểm tra xem có hỗ trợ HDR hay không

Trước khi quay video HDR trong ứng dụng, hãy xác định xem thiết bị có hỗ trợ hồ sơ HDR mà bạn muốn hay không.

Sử dụng phương thức CameraManager getCameraCharacteristics() để lấy một thực thể CameraCharacteristics. Bạn có thể truy vấn thực thể này để biết các chức năng HDR của thiết bị.

Các bước sau đây sẽ kiểm tra xem thiết bị có hỗ trợ HLG10 hay không. HLG10 là tiêu chuẩn HDR cơ bản mà các nhà sản xuất thiết bị phải hỗ trợ trên camera có đầu ra 10 bit.

  1. Trước tiên, hãy kiểm tra xem thiết bị có hỗ trợ các cấu hình 10 bit (độ sâu bit cho HLG10) hay không:

    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. Tiếp theo, hãy kiểm tra xem thiết bị có hỗ trợ HLG10 (hoặc một cấu hình được hỗ trợ khác) hay không:

    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;
    }

Nếu thiết bị hỗ trợ HDR, isHLGSupported() sẽ luôn trả về true. Để biết thêm thông tin, hãy xem tài liệu tham khảo về CameraCharacteristics.

Thiết lập chế độ chụp HDR

Sau khi đảm bảo rằng thiết bị của bạn hỗ trợ HDR, hãy thiết lập ứng dụng để ghi lại luồng video HDR thô từ camera. Sử dụng setDynamicRangeProfile() để cung cấp OutputConfiguration của luồng bằng một hồ sơ HDR do thiết bị hỗ trợ, sau đó hồ sơ này sẽ được truyền đến CameraCaptureSession khi được tạo. Xem danh sách các cấu hình HDR được hỗ trợ.

Trong mẫu mã sau, setupSessionDynamicRangeProfile() trước tiên sẽ kiểm tra xem thiết bị có đang chạy Android 13 hay không. Sau đó, nó thiết lập CameraCaptureSession bằng hồ sơ HDR mà thiết bị hỗ trợ dưới dạng 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
      }
  }
  

Khi ứng dụng camera khởi động camera, ứng dụng sẽ gửi một CaptureRequest lặp lại để xem trước bản ghi:

Kotlin

session.setRepeatingRequest(previewRequest, null, cameraHandler)

Và để bắt đầu quay video:

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)

Mã hoá luồng video HDR của camera

Để mã hoá luồng video của camera HDR và ghi tệp vào ổ đĩa, hãy dùng MediaCodec.

Trước tiên, hãy lấy OutputSurface, ánh xạ đến một vùng đệm lưu trữ dữ liệu video thô. Đối với MediaCodec, hãy dùng createInputSurface().

Để khởi chạy MediaCodec, ứng dụng phải tạo MediaFormat có hồ sơ bộ mã hoá và giải mã, không gian màu, dải màu và hàm truyền được chỉ định:

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)

Để biết thêm thông tin chi tiết về cách triển khai, hãy xem EncoderWrapper.kt của ứng dụng mẫu Camera2Video.

Định dạng HDR

Kể từ Android 13, các thiết bị camera có khả năng xuất 10 bit phải hỗ trợ HLG10 để quay video HDR và phát. Ngoài ra, các nhà sản xuất thiết bị có thể bật mọi định dạng HDR mà họ chọn bằng cách sử dụng cấu trúc chụp HDR.

Bảng sau đây tóm tắt các định dạng HDR hiện có và khả năng của chúng đối với việc quay video HDR.

Định dạng Hàm truyền (TF) Siêu dữ liệu Bộ mã hoá và giải mã Độ sâu bit
HLG10 HLG Không HEVC 10 bit
HDR10 PQ Tĩnh HEVC 10 bit
HDR10+ PQ Động HEVC 10 bit
Dolby Vision 8.4 HLG Động HEVC 10 bit

Tài nguyên

Đối với một ứng dụng đang hoạt động có chức năng quay video HDR, hãy xem mẫu Camera2Video trên GitHub.