فیلمبرداری HDR

توجه: این صفحه به پکیج Camera2 اشاره دارد. توصیه می‌کنیم از CameraX استفاده کنید، مگر اینکه برنامه شما به ویژگی‌های خاص و سطح پایین Camera2 نیاز داشته باشد. هر دو CameraX و Camera2 از اندروید 5.0 (سطح API 21) و بالاتر پشتیبانی می کنند.

API های Camera2 از فیلم برداری با محدوده دینامیکی بالا (HDR) پشتیبانی می کنند، که به شما امکان می دهد با استفاده از دوربین خود، پیش نمایش و ضبط محتوای ویدیوی HDR را داشته باشید. در مقایسه با محدوده دینامیکی استاندارد (SDR)، HDR طیف وسیع تری از رنگ ها را ارائه می دهد و محدوده دینامیکی جزء روشنایی را افزایش می دهد (از 100 cd/m2 فعلی تا 1000s cd/m2). این منجر به کیفیت ویدیویی می شود که بیشتر با زندگی واقعی مطابقت دارد، با رنگ های غنی تر، هایلایت روشن تر و سایه های تیره تر.

ببینید چگونه ویدیوی HDR با جزئیات پر جنب و جوش غروب خورشید را ثبت می کند.

شکل 1. مقایسه کیفیت ویدئو SDR (بالا) در مقابل HDR (پایین).

پیش نیاز دستگاه

همه دستگاه های اندرویدی از فیلم برداری HDR پشتیبانی نمی کنند. قبل از ضبط ویدیوی HDR در برنامه خود، تعیین کنید که آیا دستگاه شما شرایط زیر را دارد یا خیر:

  • اندروید 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):

    کاتلین

    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 (یا پروفایل پشتیبانی شده دیگری ) پشتیبانی می کند یا خیر:

    کاتلین

    @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() ابتدا بررسی می کند که دستگاه اندروید 13 را اجرا می کند. سپس CameraCaptureSession با نمایه HDR پشتیبانی شده توسط دستگاه به عنوان یک OutputConfiguration راه اندازی می کند:

کاتلین

  /**
  * 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 تکراری برای پیش نمایش ضبط ارسال می کند:

کاتلین

session.setRepeatingRequest(previewRequest, null, cameraHandler)

و همچنین برای شروع ضبط ویدیو:

کاتلین

// 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 با نمایه کدک مشخص، فضای رنگ، محدوده رنگ و تابع انتقال ایجاد کند:

کاتلین

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)

برای جزئیات بیشتر در مورد پیاده سازی، به EncoderWrapper.kt برنامه نمونه Camera2Video مراجعه کنید.

فرمت های HDR

از Android 13، دستگاه‌های دوربین با قابلیت خروجی 10 بیتی باید از HLG10 برای ضبط و پخش HDR پشتیبانی کنند. علاوه بر این، سازندگان دستگاه‌ها می‌توانند هر فرمت HDR را با استفاده از معماری ضبط HDR فعال کنند.

جدول زیر فرمت های HDR موجود و قابلیت های آن ها برای فیلم برداری HDR را خلاصه می کند.

قالب تابع انتقال (TF) فراداده کدک عمق بیت
HLG10 HLG خیر HEVC 10 بیتی
HDR10 پی کیو استاتیک HEVC 10 بیتی
HDR10+ پی کیو پویا HEVC 10 بیتی
Dolby Vision 8.4 HLG پویا HEVC 10 بیتی

منابع

برای یک برنامه کاربردی با قابلیت ضبط ویدیوی HDR، نمونه Camera2Video را در GitHub ببینید.