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 yêu cầu các tính năng cụ thể ở cấp thấp trong Camera2. Cả CameraX và Camera2 đều hỗ trợ Android 5.0 (API cấp 21) trở lên.

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

Xem cách video HDR ghi lại cảnh hoàng hôn với độ chi tiết rực rỡ hơn.

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

Đ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 máy ảnh 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 bài viết Kiểm tra xem có hỗ trợ HDR 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 của mình. Điều này cho phép ứng dụng quay lại dùng SDR trên các thiết bị không tương thích. Ngoài ra, hãy cân nhắc việc thêm tuỳ 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 theo nhu cầu quay video của mình.

Cấu trúc chụp HDR

Sơ đồ dưới đâ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 HDR.
Hình 2. Sơ đồ cấu trúc chụp HDR.

Khi thiết bị máy ảnh chụp một khung hình ở chế độ HDR, khung Camera2 sẽ phân bổ một bộ đệm lưu trữ đầu ra của cảm biến máy ảnh đã xử lý. Thiết bị 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 bộ đệm điền sẵn vào hàng đợi bề mặt đầu ra được tham chiếu trong CaptureRequest, chẳng hạn như bộ mã hoá màn hình hoặc video, như minh hoạ trong sơ đồ.

Kiểm tra xem có hỗ trợ HDR 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 mong muốn của bạn hay không.

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

Các bước sau đây để kiểm tra xem một thiết bị có hỗ trợ HLG10 hay không. HLG10 là tiêu chuẩn HDR cơ sở mà các nhà sản xuất thiết bị phải hỗ trợ trên các 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 hay không (độ sâu bit của 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. Tiếp theo, hãy kiểm tra xem thiết bị có hỗ trợ HLG10 (hoặc một hồ sơ đượ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() 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 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 luồng video HDR thô từ máy ảnh. Sử dụng setDynamicRangeProfile() để cung cấp cho OutputConfiguration của luồng phát với một cấu hình HDR được thiết bị hỗ trợ. Sau đó, cấu hình này sẽ được truyền vào 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 để đảm bảo rằng thiết bị đang chạy Android 13. Sau đó, thiết bị này sẽ thiết lập CameraCaptureSession với hồ sơ HDR được 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 khởi chạy máy ảnh, ứng dụng máy ảnh sẽ gửi một CaptureRequest lặp lại để xem trước bản ghi:

Kotlin

session.setRepeatingRequest(previewRequest, null, cameraHandler)

Và cách 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 máy ảnh HDR

Để mã hoá luồng máy ảnh HDR và ghi tệp vào ổ đĩa, hãy sử dụng MediaCodec.

Trước tiên, hãy tải OutputSurface. Lớp này sẽ 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 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ị máy ảnh có khả năng đầu ra 10 bit phải hỗ trợ HLG10 để chụp và phát lại HDR. 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 kiến trúc chụp HDR.

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

Định dạng Chức năng chuyển (TF) Metadata Bộ mã hoá và giải mã Độ sâu bit
HLG10 HLG (Nhóm địa điểm toàn cầu) Không HEVC (lượt chuyển đổi từ lượt xem được thực hiện) 10 bit
HDR10 PQ Tĩnh HEVC (lượt chuyển đổi từ lượt xem được thực hiện) 10 bit
HDR10+ PQ Động HEVC (lượt chuyển đổi từ lượt xem được thực hiện) 10 bit
Dolby Vision 8.4 HLG (Nhóm địa điểm toàn cầu) Động HEVC (lượt chuyển đổi từ lượt xem được thực hiện) 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.