التقاط فيديو بنطاق عالي الديناميكية

ملاحظة: تشير هذه الصفحة إلى حزمة Camera2. ننصحك باستخدام CameraX ما لم يكن تطبيقك يتطلّب ميزات محدّدة منخفضة المستوى من Camera2. تتوافق كل من CameraX وCamera2 مع الإصدار 5.0 من نظام التشغيل Android (المستوى 21 من واجهة برمجة التطبيقات) والإصدارات الأحدث.

تتيح واجهات برمجة التطبيقات Camera2 التقاط فيديوهات بنطاق عالي الديناميكية (HDR)، ما يتيح لك معاينة محتوى الفيديو بنطاق عالي الديناميكية وتسجيله باستخدام الكاميرا. مقارنةً بالنطاق العادي الديناميكية (SDR)، يوفّر النطاق العالي الديناميكية (HDR) نطاقًا أوسع من الألوان ويزيد من النطاق الديناميكي لمكوّن الإضاءة (من 100 شمعة/متر مربع حاليًا إلى آلاف الشمعات/متر مربع). ويؤدي ذلك إلى جودة فيديو أقرب إلى الواقع، مع ألوان أكثر ثراءً، ومناطق أكثر سطوعًا، وظلال داكنة.

شاهِد كيف يلتقط فيديو بتقنية النطاق العالي الديناميكية (HDR) مشهد غروب الشمس بتفاصيل أكثر حيوية.

مشهد غروب الشمس تم التقاطه بجودة فيديو SDR مشهد غروب الشمس تم التقاطه بجودة فيديو HDR
الشكل 1: مقارنة بين جودة فيديو بتقنية النطاق العادي الديناميكية (في الأعلى) وتقنية النطاق العالي الديناميكية (في الأسفل)

المتطلبات الأساسية للأجهزة

لا تتيح بعض أجهزة Android التقاط فيديوهات بتقنية النطاق العالي الديناميكية. قبل تسجيل فيديو بتقنية النطاق العالي الديناميكية في تطبيقك، تأكَّد من أنّ جهازك يستوفي المتطلبات الأساسية التالية:

  • يستهدف الإصدار 13 من نظام التشغيل Android (المستوى 33 لواجهة برمجة التطبيقات).
  • يحتوي على أداة استشعار للكاميرا بدقة 10 بت أو أعلى. لمزيد من المعلومات حول التوافق مع تقنية HDR، يُرجى الاطّلاع على التحقّق من التوافق مع تقنية HDR.

بما أنّ بعض الأجهزة لا تستوفي المتطلبات الأساسية، يمكنك إضافة مسار برمجي منفصل عند إعداد ميزة التقاط الفيديو بتقنية HDR في تطبيقك، ما يتيح له استخدام تقنية SDR على الأجهزة غير المتوافقة. ننصحك أيضًا بإضافة خيار واجهة مستخدم للنطاق العادي الديناميكية. ويمكن للمستخدم بعد ذلك التبديل بين النطاق العادي الديناميكية والنطاق العالي الديناميكية لتلبية احتياجات تسجيل الفيديو.

بنية التقاط صور HDR

يوضّح المخطّط البياني التالي المكوّنات الرئيسية لبنية التقاط الصور بتقنية النطاق العالي الديناميكية (HDR).

مخطّط بياني لبنية التقاط صور HDR
الشكل 2. مخطّط بياني لبنية التقاط صور HDR

عندما يلتقط جهاز الكاميرا إطارًا بتقنية النطاق العالي الديناميكية (HDR)، يخصّص إطار عمل Camera2 مخزنًا مؤقتًا يحفظ مخرجات أداة استشعار الكاميرا التي تمت معالجتها. وتُرفق أيضًا البيانات الوصفية ذات النطاق العالي الديناميكية (HDR) ذات الصلة إذا كان ملف HDR يتطلب ذلك. بعد ذلك، يضع إطار عمل Camera2 المخزن المؤقت الذي تمت تعبئته في قائمة انتظار لسطح الإخراج المُشار إليه في CaptureRequest، مثل شاشة عرض أو برنامج ترميز فيديو، كما هو موضّح في المخطّط البياني.

التحقّق من التوافق مع النطاق العالي الديناميكية (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 chosen profile, in this case HLG10
        return availableProfiles.contains(DynamicRangeProfiles.HLG10)
      }
      return false;
    }
    

إذا كان الجهاز متوافقًا مع تقنية HDR، ستعرض السمة isHLGSupported() دائمًا القيمة true. لمزيد من المعلومات، يُرجى الاطّلاع على المستندات المرجعية حول CameraCharacteristics.

إعداد ميزة التقاط صور HDR

بعد التأكّد من أنّ جهازك متوافق مع تقنية HDR، اضبط تطبيقك لالتقاط بث فيديو HDR خام من الكاميرا. استخدِم setDynamicRangeProfile() لتزويد OutputConfiguration للبث بملف شخصي للنطاق العالي الديناميكية (HDR) متوافق مع الجهاز، ويتم نقله بعد ذلك إلى CameraCaptureSession عند الإنشاء. اطّلِع على قائمة الملفات الشخصية المتوافقة مع تقنية HDR.

In the following code sample, setupSessionDynamicRangeProfile() first checks that the device is running Android 13. بعد ذلك، يتم إعداد CameraCaptureSession باستخدام الملف الشخصي لتقنية HDR المتوافق مع الجهاز كـ 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
      }
  }

عندما يبدأ تطبيق الكاميرا تشغيل الكاميرا، يرسل 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.

أولاً، احصل على الناتج Surface الذي يربط بمخزن مؤقت يخزّن بيانات الفيديو الأولية. بالنسبة إلى 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)

لمزيد من التفاصيل حول التنفيذ، يُرجى الاطّلاع على نموذج تطبيق Camera2Video EncoderWrapper.kt.

تنسيقات HDR

اعتبارًا من الإصدار 13 من نظام التشغيل Android، يجب أن تتوافق أجهزة الكاميرا التي تتضمّن إمكانات إخراج 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 بت

الموارد

للحصول على تطبيق يعمل مع وظيفة التقاط فيديو بنطاق عالي الديناميكية، يمكنك الاطّلاع على نموذج Camera2Video على GitHub.