معماری ضبط ویدیو CameraX

سیستم ضبط معمولاً جاری‌سازی‌های ویدیویی و صوتی را ضبط می‌کند، آن‌ها را فشرده می‌کند، دو جاری‌سازی را ادغام می‌کند، سپس جاری‌سازی حاصل را روی دیسک می‌نویسد.

نمودار مفهومی برای سیستم ضبط ویدیو و صدا
شکل ۱. نمودار مفهومی برای سیستم ضبط ویدیو و صدا.

در CameraX، راهکار ضبط ویدیو مورد استفاده VideoCapture است:

نمودار مفهومی که نشان می‌دهد camera x چگونه مورد استفاده ضبط ویدیو را مدیریت می‌کند
شکل ۲. نمودار مفهومی که نشان می‌دهد CameraX چگونه مورد استفاده VideoCapture را مدیریت می‌کند.

همان‌طور که در شکل ۲ نشان داده شده است، ضبط ویدیو CameraX شامل چند مؤلفه معماری سطح بالا است:

  • SurfaceProvider برای منبع ویدیو.
  • AudioSource برای منبع صوتی.
  • دو کدبند برای کدبندی و فشرده‌سازی ویدیو/صدا.
  • یک مالتی‌پلکسر رسانه برای مالتی‌پلکس کردن دو جاری‌سازی.
  • ذخیره‌کننده فایل برای نوشتن نتیجه.

‫VideoCapture API موتور ضبط پیچیده را خلاصه می‌کند و میانای برنامه‌سازی کاربردی بسیار ساده‌تر و سرراست‌تری را برای برنامه‌ها ارائه می‌دهد.

نمای کلی VideoCapture API

VideoCapture یک مورد استفاده CameraX است که به‌خوبی به‌تنهایی یا در ترکیب با موارد استفاده دیگر کار می‌کند. ترکیب‌های پشتیبانی‌شده خاص به قابلیت‌های سخت‌افزاری دوربین بستگی دارد، اما Preview و VideoCapture ترکیب مورد استفاده معتبری در همه دستگاه‌ها است.

‫VideoCapture API از اشیاء زیر تشکیل شده است که با برنامه‌ها ارتباط برقرار می‌کنند:

  • VideoCapture کلاس مورد استفاده سطح بالا است. VideoCapture به LifecycleOwner با CameraSelector و دیگر UseCases CameraX متصل می‌شود. برای اطلاعات بیشتر درباره این مفاهیم و کاربردها، معماری CameraX را ببینید.
  • Recorder پیاده‌سازی VideoOutput است که به‌طور تنگاتنگی با VideoCapture جفت شده است. ‫Recorder برای ضبط ویدیو و صدا استفاده می‌شود. برنامه‌ای ایجاد قطعه‌های ضبط‌شده از Recorder.
  • PendingRecording ضبط را پیکربندی می‌کند و گزینه‌هایی مانند فعال کردن صدا و تنظیم شنونده رویداد را ارائه می‌دهد. برای ایجاد PendingRecording باید از Recorder استفاده کنید. ‫PendingRecording چیزی ضبط نمی‌کند.
  • Recording ضبط واقعی را انجام می‌دهد. برای ایجاد Recording باید از PendingRecording استفاده کنید.

شکل ۳ روابط بین این اشیاء را نشان می‌دهد:

نموداری که تعاملات رخ‌داده در مورد استفاده از ضبط ویدیو را نشان می‌دهد
شکل ۳.‏ نموداری که تعاملات رخ‌داده در مورد استفاده از 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 متصل شوید.

CameraX VideoCapture API از الگوی طراحی سازنده پیروی می‌کند. برنامه‌ها از Recorder.Builder برای ایجاد Recorder استفاده می‌کنند. همچنین می‌توانید وضوح ویدیو را برای Recorder ازطریق شیء QualitySelector پیکربندی کنید.

CameraX Recorder از Qualities ازپیش تعریف‌شده زیر برای وضوح ویدیو پشتیبانی می‌کند:

  • Quality.UHD برای اندازه ویدیو 4K Ultra HD‏ (۲۱۶۰ پیکسل)
  • Quality.QHD برای اندازه ویدیو Quad HD‏ (۱۴۴۰ پیکسل)، معرفی‌شده در CameraX 1.7.0-alpha02
  • Quality.FHD برای اندازه ویدیو تمام HD‏ (1080p)
  • Quality.HD برای اندازه ویدیو HD‏ (۷۲۰ پیکسل)
  • Quality.SD برای اندازه ویدیو SD‏ (۴۸۰ پیکسل)

توجه داشته باشید که 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 شنونده استفاده کنید و ضبط ویدیو را شروع کنید.

وقتی تابع start() را فراخوانی می‌کنید، Recorder شیء Recording را برمی‌گرداند. برنامه شما می‌تواند از این شیء 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() را ببینید.

کاتلین

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

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

useCases.add(videoCapture);

جاوا

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 از ضبط ویدیو با دامنه پویای بالا (HDR) ۱۰ بیتی، مانند HLG10،‏ HDR10،‏ HDR10+‎، یا Dolby Vision، بااستفاده از DynamicRange پشتیبانی می‌کند.

برای استفاده از ضبط ویدیو HDR، مراحل زیر را تکمیل کنید:

  1. بااستفاده از VideoCapabilities.getSupportedDynamicRanges()، دامنه‌های پویای پشتیبانی‌شده دوربین را جستجو کنید.
  2. اختیاری: اگر QualitySelector سفارشی را پیکربندی می‌کنید، بااستفاده از getSupportedQualities(DynamicRange) بررسی کنید که کدام کیفیت‌ها برای آن محدوده پویا پشتیبانی می‌شود.
  3. پیکربندی VideoCapture.Builder با setDynamicRange().

مثال زیر ضبط HDR‏ ۱۰ بیتی HLG را درصورت پشتیبانی دوربین فعال می‌کند:

کاتلین

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()

جاوا

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) فعال کنید.

مثال زیر پایدارسازی را درصورت پشتیبانی دوربین فعال می‌کند:

کاتلین

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

جاوا

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.

مثال زیر دامنه صوتی را از رویداد وضعیت می‌خواند:

کاتلین

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

جاوا

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 از ضبط ویدیو با سرعت بالا، مانند ۱۲۰، ۲۴۰، یا ۴۸۰ فریم در ثانیه، پشتیبانی می‌کند که دو مورد استفاده متمایز را ممکن می‌سازد:

  • ویدیو با نرخ فریم بالا (صحنه آهسته با مدیریت پخش‌کننده): CameraX فریم‌ها را با نرخ فریم بالا (مثلاً ۱۲۰ فریم در ثانیه) ضبط و ذخیره می‌کند. پخش‌کننده ویدیو سرعت بازپخش را کنترل می‌کند و به کاربران امکان می‌دهد بین سرعت عادی و حرکت آهسته جابه‌جا شوند یا تحلیل فریم‌به‌فریم انجام دهند.
  • ویدیو صحنه آهسته آماده پخش: CameraX جاری‌سازی پرسرعت را پردازش می‌کند و فایل ویدیویی استاندارد ۳۰ فریم در ثانیه با مُهرهای زمان قاب تنظیم‌شده را خروجی می‌دهد. جلوه حرکت آهسته «درون‌ساخت» است، بنابراین ویدیو به‌طور خودکار در هر پخش‌کننده استانداردی بدون نیاز به پشتیبانی ویژه پخش‌کننده به‌صورت حرکت آهسته پخش می‌شود. برای مثال، ضبط با سرعت ۱۲۰ فریم در ثانیه که با سرعت ۳۰ فریم در ثانیه بازپخش می‌شود، ویدیویی با حرکت آهسته ۱/۴ برابر تولید می‌کند.

بررسی قابلیت‌های سرعت بالا

ضبط ویدیو با سرعت بالا به پشتیبانی سخت‌افزاری و تعاریف CamcorderProfile مربوطه از سازندگان دستگاه نیاز دارد، مانند CamcorderProfile.QUALITY_HIGH_SPEED_1080P یا QUALITY_HIGH_SPEED_720P.

قبل‌از پیکربندی ضبط با سرعت بالا، قابلیت‌های سرعت بالا را بااستفاده از Recorder.getHighSpeedVideoCapabilities(CameraInfo) جستجو کنید:

کاتلین

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

جاوا

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() متصل کنید.

مثال زیر یک جلسه حرکت آهسته آماده پخش را پیکربندی و متصل می‌کند:

کاتلین

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
)

جاوا

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، که در CameraX 1.7.0-alpha02 معرفی شده است، برای پیکربندی مختصر جلسه‌های پرسرعت استفاده کنید:

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

ضبط ویدیو با سرعت بالا یا حرکت آهسته

پس‌از اتصال HighSpeedVideoSessionConfig، ضبط را بااستفاده از VideoCapture به همان روش ضبط ویدیو استاندارد شروع کنید:

کاتلین

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}")
                }
            }
        }
    }

جاوا

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، منابع اضافی زیر را ببینید: