بنية التقاط الفيديوهات باستخدام CameraX

يسجّل نظام الالتقاط عادةً بث الفيديو والبث الصوتي، ويضغطهما، ويجمعهما، ثم يكتب البث الناتج على القرص.

مخطّط بياني مفاهيمي لنظام التقاط الفيديو والصوت
الشكل 1. مخطّط بياني مفاهيمي لنظام تسجيل الفيديو والصوت

في CameraX، الحلّ لالتقاط الفيديو هو حالة الاستخدام VideoCapture:

مخطّط مفاهيمي يوضّح كيفية تعامل CameraX مع حالة استخدام التقاط الفيديو
الشكل 2. مخطّط بياني مفاهيمي يوضّح كيفية تعامل CameraX مع حالة استخدام VideoCapture

كما هو موضّح في الشكل 2، يتضمّن التقاط الفيديو في CameraX بعض المكوّنات المعمارية العالية المستوى:

  • ‫SurfaceProvider لمصدر الفيديو
  • ‫AudioSource لمصدر الصوت
  • برنامجا ترميز لترميز الفيديو والصوت وضغطهما
  • مُضاعِف وسائط لمضاعفة البثَّين
  • أداة حفظ ملفات لكتابة النتيجة

تستخلص واجهة برمجة التطبيقات VideoCapture API محرّك التسجيل المعقّد وتوفّر للتطبيقات واجهة برمجة تطبيقات أبسط وأسهل بكثير.

نظرة عامة على VideoCapture API

‫VideoCapture هي حالة استخدام في CameraX تعمل بشكل جيد بمفردها أو عند دمجها مع حالات استخدام أخرى. تعتمد المجموعات المحدّدة المتوافقة على إمكانات أجهزة الكاميرا، ولكن Preview وVideoCapture هما مجموعة حالات استخدام صالحة على جميع الأجهزة.

تتألف واجهة برمجة التطبيقات VideoCapture من العناصر التالية التي تتواصل مع التطبيقات:

  • VideoCapture هي فئة حالة الاستخدام الأعلى مستوى. يرتبط VideoCapture بـ LifecycleOwner مع CameraSelector وحالات استخدام CameraX الأخرى. لمزيد من المعلومات حول هذه المفاهيم والاستخدامات، يُرجى الاطّلاع على بنية CameraX.
  • Recorder هو تنفيذ لـ VideoOutput مرتبط بشكل وثيق بـ VideoCapture. يُستخدَم "Recorder" لالتقاط الفيديو والصوت. ينشئ تطبيق تسجيلات من Recorder.
  • يضبط PendingRecording التسجيل، ويوفّر خيارات مثل تفعيل الصوت وضبط متتبِّع الأحداث. يجب استخدام Recorder لإنشاء PendingRecording. لا يسجّل جهاز PendingRecording أي شيء.
  • يُجري Recording التسجيل الفعلي. يجب استخدام PendingRecording لإنشاء Recording.

يوضّح الشكل 3 العلاقات بين هذه العناصر:

مخطّط بياني يعرض التفاعلات التي تحدث في حالة استخدام
         تسجيل الفيديو
الشكل 3. مخطّط بياني يعرض التفاعلات التي تحدث في حالة استخدام VideoCapture

التسمية التوضيحية:

  1. أنشئ Recorder باستخدام QualitySelector.
  2. اضبط Recorder باستخدام أحد OutputOptions.
  3. فعِّل الصوت باستخدام withAudioEnabled() إذا لزم الأمر.
  4. اتصل بـ start() باستخدام مستمع VideoRecordEvent لبدء التسجيل.
  5. استخدِم pause()/resume()/stop() على Recording للتحكّم في التسجيل.
  6. الرد على VideoRecordEvents داخل متتبِّع الأحداث

تتوفّر قائمة واجهات برمجة التطبيقات المفصّلة في ملف current.txt داخل الرمز المصدر.

استخدام VideoCapture API

لدمج حالة استخدام CameraX VideoCapture في تطبيقك، اتّبِع الخطوات التالية:

  1. ربط VideoCapture
  2. إعداد التسجيل وضبطه
  3. بدء تسجيل وقت التشغيل والتحكّم فيه

توضّح الأقسام التالية ما يمكنك فعله في كل خطوة للحصول على جلسة تسجيل شاملة.

ربط VideoCapture

لربط حالة استخدام VideoCapture، اتّبِع الخطوات التالية:

  1. أنشِئ عنصر Recorder.
  2. إنشاء عنصر واحد (VideoCapture)
  3. الربط بـ Lifecycle

تتّبع واجهة برمجة التطبيقات VideoCapture في CameraX نمط تصميم أداة الإنشاء. تستخدم التطبيقات Recorder.Builder لإنشاء Recorder. يمكنك أيضًا ضبط درجة دقة الفيديو في "Recorder" من خلال عنصر "QualitySelector".

تتيح واجهة برمجة التطبيقات CameraX Recorder استخدام Qualities المحدّدة مسبقًا التالية لدرجات دقة الفيديو:

  • ‫Quality.UHD لحجم الفيديو بدقة 4K الفائقة للغاية (2160p)
  • Quality.QHD لحجم فيديو بدقة Quad HD ‏ (1440p)، تم تقديمه في CameraX 1.7.0-alpha02
  • ‫Quality.FHD لحجم الفيديو بدقة فائقة (1080p)
  • ‫Quality.HD لحجم الفيديو بدقة عالية (720p)
  • ‫Quality.SD لحجم الفيديو بدقة عادية (480p)

يُرجى العِلم أنّ CameraX يمكنها أيضًا اختيار درجات دقة أخرى عندما يسمح التطبيق بذلك.

يعتمد حجم الفيديو الدقيق لكل خيار على إمكانات الكاميرا وبرنامج الترميز. لمزيد من المعلومات، يُرجى الاطّلاع على مستندات CamcorderProfile.

يمكن للتطبيقات ضبط الدقة من خلال إنشاء QualitySelector. يمكنك إنشاء QualitySelector باستخدام إحدى الطرق التالية:

  • يُرجى تقديم بعض درجات الدقة المفضّلة باستخدام fromOrderedList()، وتضمين استراتيجية احتياطية لاستخدامها في حال عدم توفّر أي من درجات الدقة المفضّلة.

    يمكن لـ CameraX تحديد أفضل مطابقة احتياطية استنادًا إلى إمكانات الكاميرا المحدّدة، يُرجى الرجوع إلى FallbackStrategy specification في QualitySelector لمزيد من التفاصيل. على سبيل المثال، يطلب الرمز التالي أعلى درجة دقة متاحة للتسجيل، وإذا لم تكن أي من درجات الدقة المطلوبة متاحة، يتم السماح لـ CameraX باختيار درجة دقة تكون الأقرب إلى Quality.SD:

    val qualitySelector = QualitySelector.fromOrderedList(
             listOf(Quality.UHD, Quality.QHD, Quality.FHD, Quality.HD, Quality.SD),
             FallbackStrategy.lowerQualityOrHigherThan(Quality.SD))
    
  • يمكنك الاستعلام عن إمكانات الكاميرا أولاً، ثم الاختيار من بين درجات الدقة المتوافقة باستخدام QualitySelector::from():

    val cameraInfo = cameraProvider.availableCameraInfos.filter {
        Camera2CameraInfo
        .from(it)
        .getCameraCharacteristic(CameraCharacteristics.LENS\_FACING) == CameraMetadata.LENS_FACING_BACK
    }
    
    val supportedQualities = QualitySelector.getSupportedQualities(cameraInfo[0])
    val filteredQualities = arrayListOf (Quality.UHD, Quality.QHD, Quality.FHD, Quality.HD, Quality.SD)
                           .filter { supportedQualities.contains(it) }
    
    // Use a simple ListView with the id of simple_quality_list_view
    viewBinding.simpleQualityListView.apply {
        adapter = ArrayAdapter(context,
                               android.R.layout.simple_list_item_1,
                               filteredQualities.map { it.qualityToString() })
    
        // Set up the user interaction to manually show or hide the system UI.
        setOnItemClickListener { _, _, position, _ ->
            // Inside View.OnClickListener,
            // convert Quality.* constant to QualitySelector
            val qualitySelector = QualitySelector.from(filteredQualities[position])
    
            // Create a new Recorder/VideoCapture for the new quality
            // and bind to lifecycle
            val recorder = Recorder.Builder()
                .setQualitySelector(qualitySelector).build()
    
             // ...
        }
    }
    
    // A helper function to translate Quality to a string
    fun Quality.qualityToString() : String {
        return when (this) {
            Quality.UHD -> "UHD"
            Quality.QHD -> "QHD"
            Quality.FHD -> "FHD"
            Quality.HD -> "HD"
            Quality.SD -> "SD"
            else -> throw IllegalArgumentException()
        }
    }
    
    

    يُرجى العِلم أنّ الإمكانية التي يتم عرضها من QualitySelector.getSupportedQualities() مضمونة للعمل إما مع حالة الاستخدام VideoCapture أو مزيج من حالتي الاستخدام VideoCapture وPreview. عند الربط مع حالة استخدام ImageCapture أو ImageAnalysis، قد يتعذّر على CameraX الربط إذا كانت المجموعة المطلوبة غير متوافقة مع الكاميرا المطلوبة.

بعد الحصول على QualitySelector، يمكن للتطبيق إنشاء عنصر VideoCapture وتنفيذ عملية الربط. يُرجى العِلم أنّ عملية الربط هذه هي نفسها في حالات الاستخدام الأخرى:

val recorder = Recorder.Builder()
    .setExecutor(cameraExecutor).setQualitySelector(qualitySelector)
    .build()
val videoCapture = VideoCapture.withOutput(recorder)

try {
    // Bind use cases to camera
    cameraProvider.bindToLifecycle(
            this, CameraSelector.DEFAULT_BACK_CAMERA, preview, videoCapture)
} catch(exc: Exception) {
    Log.e(TAG, "Use case binding failed", exc)
}

يُرجى العِلم أنّ bindToLifecycle() يعرض عنصر Camera. يُرجى الاطّلاع على هذا الدليل لمزيد من المعلومات حول التحكّم في مخرجات الكاميرا، مثل التكبير/التصغير والتعرّض للضوء.

يختار Recorder التنسيق الأنسب للنظام. برنامج ترميز الفيديو الأكثر شيوعًا هو H.264 AVC بتنسيق الحاوية MPEG-4.

ضبط التسجيل وإنشاؤه

من خلال Recorder، يمكن للتطبيق إنشاء عناصر تسجيل لالتقاط الفيديو والصوت. تنشئ التطبيقات تسجيلات من خلال تنفيذ ما يلي:

  1. اضبط "OutputOptions" باستخدام "prepareRecording()".
  2. (اختياري) فعِّل ميزة تسجيل الصوت.
  3. استخدِم start() لتسجيل مستمع VideoRecordEvent وبدء التقاط الفيديو.

تعرض السمة Recorder عنصر Recording عند استدعاء الدالة start(). يمكن لتطبيقك استخدام عنصر Recording هذا لإنهاء عملية التسجيل أو لتنفيذ إجراءات أخرى، مثل الإيقاف المؤقت أو الاستئناف.

يتيح Recorder استخدام عنصر Recording واحد في كل مرة. يمكنك بدء تسجيل جديد بعد استدعاء Recording.stop() أو Recording.close() على كائن Recording السابق.

لنلقِ نظرة على هذه الخطوات بمزيد من التفصيل. أولاً، يضبط التطبيق OutputOptions لـ "المسجّلة الذكية" باستخدام Recorder.prepareRecording(). يتيح Recorder استخدام الأنواع التالية من OutputOptions:

  • FileDescriptorOutputOptions لالتقاط الصور في FileDescriptor.
  • FileOutputOptions لالتقاط الصور في File.
  • MediaStoreOutputOptions لالتقاط الصور في MediaStore.

تتيح لك جميع أنواع OutputOptions ضبط الحد الأقصى لحجم الملف باستخدام setFileSizeLimit(). تتعلّق الخيارات الأخرى بنوع الإخراج الفردي، مثل ParcelFileDescriptor لـ FileDescriptorOutputOptions.

يعرض prepareRecording() عنصر PendingRecording، وهو عنصر وسيط يُستخدَم لإنشاء عنصر Recording المقابل. PendingRecording هي فئة عابرة يجب أن تكون غير مرئية في معظم الحالات ونادرًا ما يتم تخزينها مؤقتًا بواسطة التطبيق.

يمكن للتطبيقات ضبط التسجيل بشكل أكبر، مثل:

  • فعِّل الصوت باستخدام withAudioEnabled().
  • يمكنك تسجيل أداة معالجة لتلقّي أحداث تسجيل الفيديو باستخدام start(Executor, Consumer<VideoRecordEvent>).
  • يمكنك السماح بتسجيل متواصل أثناء إعادة ربط VideoCapture المرتبط به بكاميرا أخرى، باستخدام PendingRecording.asPersistentRecording().

لبدء التسجيل، اتصل بالرقم PendingRecording.start(). تحوّل واجهة برمجة التطبيقات CameraX PendingRecording إلى Recording، وتضع طلب التسجيل في قائمة الانتظار، وتُعيد كائن Recording الذي تم إنشاؤه حديثًا إلى التطبيق. بعد بدء التسجيل على جهاز الكاميرا المقابل، ترسل CameraX حدث VideoRecordEvent.EVENT_TYPE_START.

يوضّح المثال التالي كيفية تسجيل الفيديو والصوت في ملف MediaStore:

// Create MediaStoreOutputOptions for our recorder
val name = "CameraX-recording-" +
        SimpleDateFormat(FILENAME_FORMAT, Locale.US)
                .format(System.currentTimeMillis()) + ".mp4"
val contentValues = ContentValues().apply {
   put(MediaStore.Video.Media.DISPLAY_NAME, name)
}
val mediaStoreOutput = MediaStoreOutputOptions.Builder(this.contentResolver,
                              MediaStore.Video.Media.EXTERNAL_CONTENT_URI)
                              .setContentValues(contentValues)
                              .build()

// 2. Configure Recorder and Start recording to the mediaStoreOutput.
val recording = videoCapture.output
                .prepareRecording(context, mediaStoreOutput)
                .withAudioEnabled()
                .start(ContextCompat.getMainExecutor(this), captureListener)

على الرغم من أنّ معاينة الكاميرا تكون معكوسة على الكاميرا الأمامية تلقائيًا، فإنّ الفيديوهات المسجّلة باستخدام VideoCapture لا تكون معكوسة تلقائيًا. باستخدام CameraX 1.3، أصبح من الممكن الآن عكس تسجيلات الفيديو بحيث تتطابق معاينة الكاميرا الأمامية مع الفيديو المسجّل.

هناك ثلاثة خيارات لـ MirrorMode: MIRROR_MODE_OFF وMIRROR_MODE_ON وMIRROR_MODE_ON_FRONT_ONLY. للمحاذاة مع معاينة الكاميرا، تنصح Google باستخدام MIROR_MODE_ON_FRONT_ONLY، ما يعني أنّ وضع المرآة غير مفعَّل للكاميرا الخلفية، ولكنّه مفعَّل للكاميرا الأمامية. لمزيد من المعلومات حول MirrorMode، يُرجى الاطّلاع على MirrorMode constants.

يوضّح مقتطف الرمز هذا كيفية استدعاء VideoCapture.Builder.setMirrorMode() باستخدام MIRROR_MODE_ON_FRONT_ONLY. لمزيد من المعلومات، يُرجى الاطّلاع على setMirrorMode().

Kotlin

val recorder = Recorder.Builder().build()

val videoCapture = VideoCapture.Builder(recorder)
    .setMirrorMode(MIRROR_MODE_ON_FRONT_ONLY)
    .build()

useCases.add(videoCapture);

Java

Recorder.Builder builder = new Recorder.Builder();
if (mVideoQuality != QUALITY_AUTO) {
    builder.setQualitySelector(
        QualitySelector.from(mVideoQuality));
}
  VideoCapture<Recorder> videoCapture = new VideoCapture.Builder<>(builder.build())
      .setMirrorMode(MIRROR_MODE_ON_FRONT_ONLY)
      .build();
    useCases.add(videoCapture);

النطاق الديناميكي (فيديو HDR)

تتيح واجهة برمجة التطبيقات CameraX تسجيل فيديوهات 10 بت بنطاق عالي الديناميكية (HDR)، مثل HLG10 أو HDR10 أو HDR10+‎ أو Dolby Vision، باستخدام DynamicRange.

لاستخدام ميزة تسجيل الفيديو بنطاق عالي الديناميكية، أكمِل الخطوات التالية:

  1. يمكنك الاستعلام عن النطاقات الديناميكية المتوافقة مع الكاميرا باستخدام VideoCapabilities.getSupportedDynamicRanges().
  2. اختياري: في حال ضبط QualitySelector مخصّص، تحقَّق من الجودة المتاحة لهذا النطاق الديناميكي باستخدام getSupportedQualities(DynamicRange).
  3. اضبط "VideoCapture.Builder" باستخدام setDynamicRange().

يُفعِّل المثال التالي تسجيل فيديو 10 بت بنطاق عالي الديناميكية (HDR) بتقنية HLG عندما تتيح الكاميرا ذلك:

Kotlin

val videoCapabilities = Recorder.getVideoCapabilities(cameraInfo)
val supportedHdrRanges = videoCapabilities.supportedDynamicRanges
    .filter { it != DynamicRange.SDR }

val recorder = Recorder.Builder().build()
val videoCapture = VideoCapture.Builder(recorder)
    .apply {
        if (supportedHdrRanges.contains(DynamicRange.HLG_10_BIT)) {
            setDynamicRange(DynamicRange.HLG_10_BIT)
        }
    }
    .build()

Java

VideoCapabilities videoCapabilities = Recorder.getVideoCapabilities(cameraInfo);
Set<DynamicRange> supportedRanges = videoCapabilities.getSupportedDynamicRanges();

Recorder recorder = new Recorder.Builder().build();
VideoCapture.Builder<Recorder> builder = new VideoCapture.Builder<>(recorder);
if (supportedRanges.contains(DynamicRange.HLG_10_BIT)) {
    builder.setDynamicRange(DynamicRange.HLG_10_BIT);
}
VideoCapture<Recorder> videoCapture = builder.build();

تثبيت صورة الفيديو

تتيح واجهة CameraX تثبيت صورة الفيديو لتقليل الاهتزاز والتشويش أثناء حمل الجهاز باليد عند تسجيل الفيديو.

لتفعيل ميزة "تثبيت الفيديو"، اتّبِع الخطوات التالية:

  1. تحقَّق مما إذا كان جهاز الكاميرا يتيح ميزة التثبيت باستخدام VideoCapabilities.isStabilizationSupported().
  2. يمكنك تفعيلها على "VideoCapture.Builder" باستخدام setVideoStabilizationEnabled(true).

يؤدي المثال التالي إلى تفعيل ميزة التثبيت عندما تكون الكاميرا متوافقة معها:

Kotlin

val videoCapabilities = Recorder.getVideoCapabilities(cameraInfo)
val videoCapture = VideoCapture.Builder(recorder)
    .setVideoStabilizationEnabled(videoCapabilities.isStabilizationSupported)
    .build()

Java

VideoCapabilities videoCapabilities = Recorder.getVideoCapabilities(cameraInfo);
VideoCapture<Recorder> videoCapture = new VideoCapture.Builder<>(recorder)
    .setVideoStabilizationEnabled(videoCapabilities.isStabilizationSupported())
    .build();

التحكّم في تسجيل نشط

يمكنك إيقاف Recording جارية مؤقتًا واستئنافها وإيقافها باستخدام الطرق التالية:

  • pause لإيقاف التسجيل النشط الحالي مؤقتًا
  • resume() لاستئناف تسجيل نشط تم إيقافه مؤقتًا
  • stop() لإنهاء التسجيل ومحو أي عناصر تسجيل مرتبطة به
  • mute() لكتم صوت التسجيل الحالي أو إعادته

يُرجى العِلم أنّه يمكنك استدعاء stop() لإنهاء Recording بغض النظر عمّا إذا كان التسجيل في حالة إيقاف مؤقت أو نشط.

إذا سجّلت EventListener في PendingRecording.start()، يتواصل Recording باستخدام VideoRecordEvent.

  • يُستخدم VideoRecordEvent.EVENT_TYPE_STATUS لتسجيل الإحصاءات، مثل حجم الملف الحالي والمدة الزمنية المسجَّلة.
  • يتم استخدام VideoRecordEvent.EVENT_TYPE_FINALIZE لنتيجة التسجيل وتتضمّن معلومات مثل معرّف الموارد المنتظم (URI) للملف النهائي بالإضافة إلى أي أخطاء ذات صلة.

بعد أن يتلقّى تطبيقك EVENT_TYPE_FINALIZE يشير إلى نجاح جلسة التسجيل، يمكنك الوصول إلى الفيديو الذي تم تسجيله من الموقع الجغرافي المحدّد في OutputOptions.

سعة الصوت وحالته في الوقت الفعلي

أثناء التسجيل، توفّر أحداث VideoRecordEvent.Status إحصاءات صوتية في الوقت الفعلي من خلال AudioStats:

  • تعرض الدالة AudioStats.getAudioAmplitude() سعة ذروة الصوت الحالية، وتتراوح قيمتها بين 0.0 و1.0. يمكنك استخدام هذه القيمة لتشغيل عدّادات واجهة المستخدم أو أدوات عرض الشكل الموجي الصوتي.
  • AudioStats.getAudioState() يشير إلى الحالة الحالية للبث الصوتي، مثل AUDIO_STATE_ACTIVE أو AUDIO_STATE_MUTED أو AUDIO_STATE_SOURCE_SILENCED.

يقرأ المثال التالي سعة الصوت من حدث حالة:

Kotlin

when (event) {
    is VideoRecordEvent.Status -> {
        val audioStats = event.recordingStats.audioStats
        if (audioStats.hasAudio()) {
            val amplitude = audioStats.audioAmplitude
            updateAudioWaveform(amplitude)
        }
    }
    // ...
}

Java

if (event instanceof VideoRecordEvent.Status) {
    VideoRecordEvent.Status status = (VideoRecordEvent.Status) event;
    AudioStats audioStats = status.getRecordingStats().getAudioStats();
    if (audioStats.hasAudio()) {
        double amplitude = audioStats.getAudioAmplitude();
        updateAudioWaveform(amplitude);
    }
}

فيديو عالي السرعة وبالتصوير البطيء

تتيح واجهة CameraX تسجيل الفيديو بسرعة عالية، مثل 120 أو 240 أو 480 لقطة في الثانية، ما يتيح حالتي استخدام مختلفتين:

  • فيديو بمعدّل عدد اللقطات في الثانية مرتفع (تصوير بطيء يعالجه المشغّل): تلتقط واجهة CameraX اللقطات وتحفظها بمعدّل عدد اللقطات في الثانية مرتفع (على سبيل المثال، 120 لقطة في الثانية). يتحكّم مشغّل الفيديو في سرعة التشغيل، ما يتيح للمستخدمين التبديل بين السرعة العادية والحركة البطيئة أو إجراء تحليل لكل لقطة على حدة.
  • فيديو بالحركة البطيئة جاهز للتشغيل: تعالج واجهة CameraX البث العالي السرعة وتُخرج ملف فيديو عاديًا بمعدل 30 لقطة في الثانية مع طوابع زمنية معدَّلة للقطات. يتم "دمج" تأثير الحركة البطيئة، لذا يتم تشغيل الفيديو بالحركة البطيئة تلقائيًا في أي مشغّل عادي بدون الحاجة إلى مشغّل خاص. على سبيل المثال، إذا تم التقاط فيديو بمعدّل 120 لقطة في الثانية وتشغيله بمعدّل 30 لقطة في الثانية، سيتم إنتاج فيديو بالتصوير البطيء بسرعة 1/4.

التحقّق من إمكانات السرعة العالية

يتطلّب التقاط الفيديو بسرعة عالية توفُّر دعم من الأجهزة وتعريفات CamcorderProfile ذات الصلة من الشركات المصنّعة للأجهزة، مثل CamcorderProfile.QUALITY_HIGH_SPEED_1080P أو QUALITY_HIGH_SPEED_720P.

قبل ضبط التسجيل العالي السرعة، يمكنك الاستعلام عن الإمكانات العالية السرعة باستخدام Recorder.getHighSpeedVideoCapabilities(CameraInfo):

Kotlin

val highSpeedCapabilities = Recorder.getHighSpeedVideoCapabilities(cameraInfo)
if (highSpeedCapabilities == null) {
    // Camera does not support high-speed video capture
    return
}
val supportedQualities = highSpeedCapabilities.getSupportedQualities(DynamicRange.SDR)

Java

VideoCapabilities highSpeedCapabilities = Recorder.getHighSpeedVideoCapabilities(cameraInfo);
if (highSpeedCapabilities == null) {
    // Camera does not support high-speed video capture
    return;
}
List<Quality> supportedQualities = highSpeedCapabilities.getSupportedQualities(DynamicRange.SDR);

ضبط HighSpeedVideoSessionConfig

لاستخدام ميزة "الالتقاط العالي السرعة"، ادمج حالات استخدام VideoCapture وPreview في HighSpeedVideoSessionConfig. لضبط الجلسة، أكمِل الخطوات التالية:

  1. أنشئ حالة استخدام VideoCapture وحالة استخدام Preview.
  2. ابدأ HighSpeedVideoSessionConfig.Builder باستخدام حالة الاستخدام VideoCapture وأرفِق Preview.
  3. يمكنك الاستعلام عن نطاقات عدد اللقطات في الثانية المتوافقة باستخدام CameraInfo.getSupportedFrameRateRanges(SessionConfig) وضبط النطاق المحدّد.
  4. يمكنك الاختيار بين فيديو بمعدّل لقطات مرتفع أو فيديو بالحركة البطيئة جاهز للتشغيل:
    • لإنشاء فيديو بمعدّل لقطات مرتفع، اترك setSlowMotionEnabled(false) (الإعداد التلقائي).
    • لإنشاء فيديو بالحركة البطيئة جاهز للتشغيل، استخدِم setSlowMotionEnabled(true).
  5. اربط إعدادات الجلسة باستخدام cameraProvider.bindToLifecycle().

يضبط المثال التالي جلسة حركة بطيئة جاهزة للتشغيل ويربطها:

Kotlin

val preview = Preview.Builder().build()
val recorder = Recorder.Builder()
    .setQualitySelector(QualitySelector.from(supportedQualities.first()))
    .build()
val videoCapture = VideoCapture.withOutput(recorder)

// Build HighSpeedVideoSessionConfig
val sessionConfigBuilder = HighSpeedVideoSessionConfig.Builder(videoCapture)
    .setPreview(preview)
    // Enable automatic slow-motion playback at 30 fps
    .setSlowMotionEnabled(true)

// Query and set a supported high-speed frame rate range (such as 120 or 240 fps).
// The set is non-empty because getHighSpeedVideoCapabilities() returned non-null earlier.
val supportedFpsRanges = cameraInfo.getSupportedFrameRateRanges(sessionConfigBuilder.build())
sessionConfigBuilder.setFrameRateRange(supportedFpsRanges.first())

val sessionConfig = sessionConfigBuilder.build()

// Bind session config to lifecycle
cameraProvider.bindToLifecycle(
    lifecycleOwner,
    CameraSelector.DEFAULT_BACK_CAMERA,
    sessionConfig
)

Java

Preview preview = new Preview.Builder().build();
Recorder recorder = new Recorder.Builder()
    .setQualitySelector(QualitySelector.from(supportedQualities.get(0)))
    .build();
VideoCapture<Recorder> videoCapture = VideoCapture.withOutput(recorder);

HighSpeedVideoSessionConfig.Builder sessionConfigBuilder =
    new HighSpeedVideoSessionConfig.Builder(videoCapture)
        .setPreview(preview)
        .setSlowMotionEnabled(true);

// The set is non-empty because getHighSpeedVideoCapabilities() returned non-null earlier.
Set<Range<Integer>> supportedFpsRanges =
    cameraInfo.getSupportedFrameRateRanges(sessionConfigBuilder.build());
sessionConfigBuilder.setFrameRateRange(supportedFpsRanges.iterator().next());

HighSpeedVideoSessionConfig sessionConfig = sessionConfigBuilder.build();

cameraProvider.bindToLifecycle(
    lifecycleOwner,
    CameraSelector.DEFAULT_BACK_CAMERA,
    sessionConfig
);

يمكنك أيضًا استخدام لغة Kotlin DSL، التي تم تقديمها في الإصدار 1.7.0-alpha02 من CameraX، لضبط جلسات عالية السرعة بإيجاز:

val sessionConfig = highSpeedVideoSessionConfig(videoCapture) {
    this.preview = preview
    isSlowMotionEnabled = true
    frameRateRange = supportedFpsRanges.first()
}
cameraProvider.bindToLifecycle(
    lifecycleOwner,
    CameraSelector.DEFAULT_BACK_CAMERA,
    sessionConfig
)

تسجيل فيديو عالي السرعة أو بالحركة البطيئة

بعد ربط HighSpeedVideoSessionConfig، ابدأ التسجيل باستخدام VideoCapture بالطريقة نفسها التي تستخدمها في تسجيلات الفيديو العادية:

Kotlin

val recording = videoCapture.output
    .prepareRecording(context, mediaStoreOutput)
    .withAudioEnabled()
    .start(ContextCompat.getMainExecutor(context)) { event ->
        when (event) {
            is VideoRecordEvent.Start -> Log.d(TAG, "Recording started")
            is VideoRecordEvent.Finalize -> {
                if (!event.hasError()) {
                    Log.d(TAG, "Video saved: ${event.outputResults.outputUri}")
                }
            }
        }
    }

Java

Recording recording = videoCapture.getOutput()
    .prepareRecording(context, mediaStoreOutput)
    .withAudioEnabled()
    .start(ContextCompat.getMainExecutor(context), event -> {
        if (event instanceof VideoRecordEvent.Start) {
            Log.d(TAG, "Recording started");
        } else if (event instanceof VideoRecordEvent.Finalize) {
            VideoRecordEvent.Finalize finalize = (VideoRecordEvent.Finalize) event;
            if (!finalize.hasError()) {
                Log.d(TAG, "Video saved: " + finalize.getOutputResults().getOutputUri());
            }
        }
    });

مراجع إضافية

لمزيد من المعلومات حول CameraX، يمكنك الاطّلاع على المراجع الإضافية التالية: