فیلمبرداری HDR

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

رابط‌های برنامه‌نویسی Camera2 از ضبط ویدیوی HDR پشتیبانی می‌کنند که به شما امکان می‌دهد محتوای ویدیویی HDR را با استفاده از دوربین خود پیش‌نمایش و ضبط کنید. در مقایسه با SDR، HDR طیف وسیع‌تری از رنگ‌ها را ارائه می‌دهد و دامنه دینامیکی مؤلفه روشنایی را افزایش می‌دهد (از ۱۰۰ کاندلا بر متر مربع فعلی به ۱۰۰۰ کاندلا بر متر مربع). این امر منجر به کیفیت ویدیویی می‌شود که با رنگ‌های غنی‌تر، هایلایت‌های روشن‌تر و سایه‌های تیره‌تر، بیشتر به زندگی واقعی نزدیک است.

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

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

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

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

  • اندروید ۱۳ (سطح API ۳۳) را هدف قرار می‌دهد.
  • دارای حسگر دوربین با قابلیت ۱۰ بیت یا بالاتر است. برای اطلاعات بیشتر در مورد پشتیبانی HDR، به بخش «بررسی پشتیبانی HDR» مراجعه کنید.

از آنجا که همه دستگاه‌ها پیش‌نیازها را ندارند، می‌توانید هنگام تنظیم ضبط ویدیوی HDR در برنامه خود، یک مسیر کد جداگانه اضافه کنید. این به برنامه شما اجازه می‌دهد تا در دستگاه‌های ناسازگار به SDR بازگردد. همچنین، اضافه کردن یک گزینه رابط کاربری برای SDR را در نظر بگیرید. سپس کاربر می‌تواند برای نیازهای ضبط ویدیوی خود بین SDR و HDR جابجا شود.

معماری ضبط HDR

نمودار زیر اجزای اصلی معماری ضبط HDR را نشان می‌دهد.

نمودار معماری ضبط HDR.
شکل ۲. نمودار معماری ضبط HDR.

وقتی یک دستگاه دوربین یک فریم را با فرمت HDR ضبط می‌کند، فریم‌ورک Camera2 یک بافر اختصاص می‌دهد که خروجی پردازش‌شده حسگر دوربین را ذخیره می‌کند. همچنین در صورت نیاز پروفایل HDR، فراداده HDR مربوطه را نیز ضمیمه می‌کند. سپس فریم‌ورک Camera2 بافر پر شده را برای سطح خروجی ارجاع شده در CaptureRequest ، مانند نمایشگر یا رمزگذار ویدیو، همانطور که در نمودار نشان داده شده است، در صف قرار می‌دهد.

پشتیبانی از HDR را بررسی کنید

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

از متد getCameraCharacteristics() در CameraManager برای دریافت یک نمونه از CameraCharacteristics استفاده کنید، که می‌توانید از آن برای قابلیت‌های HDR دستگاه خود پرس‌وجو کنید.

مراحل زیر بررسی می‌کند که آیا دستگاه از HLG10 پشتیبانی می‌کند یا خیر. HLG10 استاندارد پایه HDR است که سازندگان دستگاه باید در دوربین‌هایی با خروجی ۱۰ بیتی از آن پشتیبانی کنند.

  1. ابتدا بررسی کنید که آیا دستگاه از پروفایل‌های ۱۰ بیتی (عمق بیت برای 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() برای ارائه یک پروفایل HDR پشتیبانی شده توسط دستگاه به OutputConfiguration جریان استفاده کنید، که سپس پس از ایجاد به CameraCaptureSession منتقل می‌شود. لیست پروفایل‌های HDR پشتیبانی شده را مشاهده کنید.

در نمونه کد زیر، setupSessionDynamicRangeProfile() ابتدا بررسی می‌کند که آیا دستگاه از اندروید ۱۳ استفاده می‌کند یا خیر. سپس، 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

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

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

قالب تابع انتقال (TF) فراداده کدک عمق بیت
HLG10 اچ ال جی خیر اچ‌ای‌وی‌سی ۱۰ بیتی
اچ‌دی‌آر۱۰ پی کیو استاتیک اچ‌ای‌وی‌سی ۱۰ بیتی
اچ‌دی‌آر۱۰+ پی کیو پویا اچ‌ای‌وی‌سی ۱۰ بیتی
دالبی ویژن ۸.۴ اچ ال جی پویا اچ‌ای‌وی‌سی ۱۰ بیتی

منابع

برای مشاهده‌ی یک برنامه‌ی کاربردی با قابلیت ضبط ویدیوی HDR، به نمونه‌ی Camera2Video در گیت‌هاب مراجعه کنید.