การจับภาพวิดีโอ HDR

หมายเหตุ: หน้านี้อ้างอิงถึงแพ็กเกจ Camera2 เราขอแนะนำให้ใช้ CameraX เว้นแต่ว่าแอปของคุณจะต้องใช้ฟีเจอร์เฉพาะระดับต่ำจาก Camera2 ทั้ง CameraX และ Camera2 รองรับ Android 5.0 (API ระดับ 21) ขึ้นไป

Camera2 API รองรับ การบันทึกวิดีโอแบบ High Dynamic Range (HDR) ซึ่งช่วยให้คุณแสดงตัวอย่างและ บันทึกเนื้อหาวิดีโอ HDR โดยใช้กล้องได้ เมื่อเทียบกับ Standard Dynamic Range (SDR) แล้ว HDR มีช่วงสีที่กว้างกว่าและเพิ่มช่วงไดนามิกของคอมโพเนนต์ความสว่าง (จาก 100 cd/m2 ปัจจุบันเป็น 1000 cd/m2) ซึ่งส่งผลให้วิดีโอมีคุณภาพใกล้เคียงกับชีวิตจริงมากขึ้น โดยมีสีสันที่สมบูรณ์ยิ่งขึ้น ไฮไลต์ที่สว่างขึ้น และเงาที่เข้มขึ้น

ดูวิธีที่วิดีโอ HDR จับภาพพระอาทิตย์ตกได้อย่างละเอียดและสดใสยิ่งขึ้น

รูปที่ 1 การเปรียบเทียบคุณภาพวิดีโอ SDR (ด้านบน) กับ HDR (ด้านล่าง)

ข้อกำหนดเบื้องต้นของอุปกรณ์

อุปกรณ์ Android บางรุ่นไม่รองรับการบันทึกวิดีโอ HDR ก่อนบันทึกวิดีโอ HDR ในแอป ให้ตรวจสอบว่าอุปกรณ์มีคุณสมบัติตรงตามข้อกำหนดเบื้องต้นต่อไปนี้

  • กำหนดเป้าหมายเป็น Android 13 (ระดับ API 33)
  • มีเซ็นเซอร์กล้องที่รองรับ 10 บิตขึ้นไป ดูข้อมูลเพิ่มเติมเกี่ยวกับการรองรับ HDR ได้ที่ ตรวจสอบการรองรับ HDR

เนื่องจากอุปกรณ์บางรุ่นไม่มีคุณสมบัติตรงตามข้อกำหนดเบื้องต้น คุณจึงเพิ่มเส้นทางโค้ดแยกต่างหากได้เมื่อตั้งค่าการบันทึกวิดีโอ HDR ในแอป ซึ่งจะช่วยให้แอปกลับไปใช้ SDR ในอุปกรณ์ที่ไม่เข้ากันได้ นอกจากนี้ ให้พิจารณาเพิ่มตัวเลือก UI สำหรับ SDR ด้วย จากนั้นผู้ใช้จะสลับระหว่าง SDR กับ HDR ได้ตามความต้องการในการบันทึกวิดีโอ

สถาปัตยกรรมการบันทึก HDR

แผนภาพต่อไปนี้แสดงคอมโพเนนต์หลักของสถาปัตยกรรมการบันทึก HDR

แผนภาพสถาปัตยกรรมการจับภาพ HDR
รูปที่ 2 แผนภาพสถาปัตยกรรมการบันทึก HDR

เมื่ออุปกรณ์กล้องจับภาพเฟรมใน HDR เฟรมเวิร์ก Camera2 จะจัดสรรบัฟเฟอร์ที่จัดเก็บเอาต์พุตเซ็นเซอร์กล้องที่ประมวลผลแล้ว นอกจากนี้ยังแนบข้อมูลเมตา HDR ที่เกี่ยวข้องหากโปรไฟล์ HDR กำหนดไว้ จากนั้นเฟรมเวิร์ก Camera2 จะจัดคิวบัฟเฟอร์ที่ป้อนข้อมูลแล้วสำหรับพื้นผิวเอาต์พุต ที่อ้างอิงใน CaptureRequest เช่น จอแสดงผลหรือ ตัวเข้ารหัสวิดีโอ ดังที่แสดงในแผนภาพ

ตรวจสอบการรองรับ HDR

ก่อนบันทึกวิดีโอ HDR ในแอป ให้ตรวจสอบว่าอุปกรณ์รองรับโปรไฟล์ HDR ที่ต้องการหรือไม่

ใช้เมธอด CameraManager getCameraCharacteristics() เพื่อรับอินสแตนซ์ CameraCharacteristics ซึ่งคุณสามารถใช้เพื่อค้นหาความสามารถ HDR ของอุปกรณ์ได้

ขั้นตอนต่อไปนี้จะตรวจสอบว่าอุปกรณ์รองรับ HLG10 หรือไม่ HLG10 เป็นมาตรฐาน HDR พื้นฐานที่ผู้ผลิตอุปกรณ์ต้องรองรับในกล้องที่มีเอาต์พุต 10 บิต

  1. ขั้นแรก ให้ตรวจสอบว่าอุปกรณ์รองรับโปรไฟล์ 10 บิต (ความลึกของบิตสำหรับ 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. จากนั้นตรวจสอบว่าอุปกรณ์รองรับ HLG10 (หรือ โปรไฟล์อื่นที่รองรับ) หรือไม่

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

หากอุปกรณ์รองรับ HDR ฟังก์ชัน isHLGSupported() จะแสดงผล true เสมอ ดูข้อมูลเพิ่มเติมได้ในเอกสารอ้างอิง CameraCharacteristics

ตั้งค่าการบันทึก HDR

หลังจากตรวจสอบว่าอุปกรณ์รองรับ HDR แล้ว ให้ตั้งค่าแอปเพื่อบันทึกสตรีมวิดีโอ HDR แบบดิบจากกล้อง ใช้ setDynamicRangeProfile() เพื่อระบุ OutputConfiguration ของสตรีมด้วยโปรไฟล์ HDR ที่อุปกรณ์รองรับ ซึ่งจะส่งไปยัง CameraCaptureSession เมื่อสร้าง ดูรายการโปรไฟล์ HDR ที่รองรับ

ในตัวอย่างโค้ดต่อไปนี้ setupSessionDynamicRangeProfile() จะตรวจสอบก่อนว่าอุปกรณ์ใช้ Android 13 หรือไม่ จากนั้นจะตั้งค่า CameraCaptureSession ด้วยโปรไฟล์ HDR ที่อุปกรณ์รองรับเป็น 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
      }
  }
  

เมื่อแอปกล้องถ่ายรูปเริ่มต้นกล้อง แอปจะส่ง ที่ทำซ้ำ CaptureRequest เพื่อแสดงตัวอย่างการบันทึก ดังนี้

Kotlin

session.setRepeatingRequest(previewRequest, null, cameraHandler)

และเพื่อเริ่มบันทึกวิดีโอ ดังนี้

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)

เข้ารหัสสตรีมจากกล้อง HDR

หากต้องการเข้ารหัสสตรีมจากกล้อง HDR และเขียนไฟล์ลงดิสก์ ให้ใช้ MediaCodec

ขั้นแรก ให้รับ OutputSurface, ซึ่งแมปกับบัฟเฟอร์ที่จัดเก็บข้อมูลวิดีโอดิบ สำหรับ MediaCodec, ให้ใช้ createInputSurface().

หากต้องการเริ่มต้น MediaCodec แอปต้องสร้าง MediaFormat ที่มีโปรไฟล์ตัวแปลงรหัส พื้นที่สี ช่วงสี และฟังก์ชันการโอนที่ระบุ ดังนี้

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)

ดูรายละเอียดเพิ่มเติมเกี่ยวกับการติดตั้งใช้งานได้ที่แอปตัวอย่าง Camera2Video EncoderWrapper.kt

รูปแบบ HDR

ตั้งแต่ Android 13 เป็นต้นไป อุปกรณ์กล้องที่มีความสามารถในการส่งออก 10 บิต ต้องรองรับ HLG10 สำหรับการบันทึก HDR และ การเล่น นอกจากนี้ ผู้ผลิตอุปกรณ์ยังเปิดใช้รูปแบบ HDR ที่ต้องการได้โดยใช้ สถาปัตยกรรมการบันทึก HDR

ตารางต่อไปนี้สรุปรูปแบบ HDR ที่มีและความสามารถในการบันทึกวิดีโอ HDR

รูปแบบ ฟังก์ชันการโอน (TF) ข้อมูลเมตา ตัวแปลงรหัส ความลึกของบิต
HLG10 HLG ไม่ HEVC 10 บิต
HDR10 PQ คงที่ HEVC 10 บิต
HDR10+ PQ ไดนามิก HEVC 10 บิต
Dolby Vision 8.4 HLG ไดนามิก HEVC 10 บิต

แหล่งข้อมูล

หากต้องการดูแอปที่ใช้งานได้ซึ่งมีฟังก์ชันการบันทึกวิดีโอ HDR ให้ดูตัวอย่าง Camera2Video ใน GitHub