Quay video HDR

Lưu ý: Trang này đề cập đến gói Camera2. Bạn nên sử 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ợ quay video 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 động tiêu chuẩn (SDR), HDR cung cấp dải màu rộng hơn và tăng dải động của thành phần độ sáng (từ 100 cd/m2 hiện tại lên 1000 cd/m2). Điều này giúp chất lượng video gần với thực tế hơn, với màu sắc phong phú hơn, vùng sáng rực rỡ hơn và vùng tối sâu hơn.

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

Cảnh hoàng hôn được quay ở chất lượng video SDR Cảnh hoàng hôn được quay bằng video HDR
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ợ 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:

  • Nhắm đến Android 13 (API cấp 33).
  • Có cảm biến camera hỗ trợ 10 bit trở lên. Để biết thêm thông tin về tính năng hỗ trợ HDR, hãy xem phần Kiểm tra tính năng hỗ trợ HDR.

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 biệt khi thiết lập tính năng quay video HDR trong ứng dụng. Việc này cho phép ứng dụng của bạn quay lại 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 quay video của họ.

Kiến 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ơ đồ cấu trúc chụp ảnh HDR.
Hình 2. Sơ đồ cấu trúc chụp ảnh HDR.

Khi 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ảm biến camera đã xử lý. Nó cũng đính kèm siêu dữ liệu HDR tương ứng nếu cấu hình HDR yêu cầu. Sau đó, khung Camera2 sẽ đưa vùng đệm đã điền sẵn vào hàng đợi cho nền tảng đầ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 khả năng hỗ trợ HDR

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 chọn hay không.

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

Các bước sau đây giúp 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à nhà sản xuất thiết bị phải hỗ trợ trên máy ảnh có đầu ra 10 bit.

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

    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:

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

Nếu thiết bị hỗ trợ HDR, isHLGSupported() 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 tính năng chụp ảnh 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 để quay video HDR thô từ camera. Sử dụng setDynamicRangeProfile() để cung cấp OutputConfiguration của luồng bằng một hồ sơ HDR được thiết bị hỗ trợ, sau đó được truyền đến CameraCaptureSession khi tạo. Xem danh sách các cấu hình HDR được hỗ trợ.

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

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:

session.setRepeatingRequest(previewRequest, null, cameraHandler)

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

// 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 sử dụng MediaCodec.

Trước tiên, hãy lấy Surface đầu ra, liên kết với một vùng đệm lưu trữ dữ liệu video thô. Đối với MediaCodec, hãy sử dụng createInputSurface().

Để khởi chạy MediaCodec, ứng dụng phải tạo một 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:

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 để chụp ảnh HDR và phát lại. Ngoài ra, nhà sản xuất thiết bị có thể bật bất kỳ định dạng HDR nào mà họ chọn bằng kiến trúc chụp ảnh HDR.

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

Đị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

Để xem một ứng dụng công việc có chức năng quay video HDR, hãy xem mẫu Camera2Video trên GitHub.