CameraX video yakalama mimarisi

Yakalama sistemi, genellikle video ve ses akışlarını kaydeder, sıkıştırır, iki akışı muslaştırır ve ardından elde edilen akışı diske yazar.

video ve ses yakalama sistemine ait kavramsal diyagram
Şekil 1. Video ve ses yakalama sisteminin kavramsal diyagramı.

CameraX'te video yakalama çözümü VideoCapture kullanım alanıdır:

x kamerasının video çekimi kullanım alanını nasıl yerine getirdiğini gösteren kavramsal diyagram
Şekil 2. CameraX'in VideoCapture kullanım alanını nasıl işlediğini gösteren kavramsal şema.

Şekil 2'de gösterildiği gibi CameraX video çekimi birkaç üst düzey mimari bileşen içerir:

  • Video kaynağı için SurfaceProvider.
  • Ses kaynağı için AudioSource.
  • Videoyu/sesi kodlamak ve sıkıştırmak için iki kodlayıcı.
  • İki akışı birleştirmek için bir medya muxer.
  • Sonucu yazmak için bir dosya tasarrufu aracı.

VideoCapture API, karmaşık yakalama motorunu soyutlar ve uygulamalara çok daha basit ve anlaşılır bir API sunar.

VideoCapture API'ye genel bakış

VideoCapture, kendi başına veya diğer kullanım alanlarıyla birlikte kullanıldığında iyi performans gösteren bir CameraX kullanım alanıdır. Desteklenen belirli kombinasyonlar, kamera donanımı özelliklerine bağlıdır ancak Preview ve VideoCapture tüm cihazlarda geçerli bir kullanım alanı kombinasyonudur.

VideoCapture API, uygulamalarla iletişim kuran aşağıdaki nesnelerden oluşur:

  • VideoCapture, üst düzey kullanım alanı sınıfıdır. VideoCapture, CameraSelector ve diğer CameraX kullanım alanları ile LifecycleOwner öğesine bağlanır. Bu kavramlar ve kullanımlar hakkında daha fazla bilgi edinmek için KameraX Mimarisi sayfasına bakın.
  • Recorder, VideoCapture ile sıkı bir şekilde bağlantılı olan VideoÇıkış uygulamasıdır. Recorder, video ve ses yakalama işlemini gerçekleştirmek için kullanılır. Bir uygulama, bir Recorder cihazından kayıt oluşturur.
  • PendingRecording, sesi etkinleştirme ve etkinlik işleyici ayarlama gibi seçenekler sunarak kaydı yapılandırır. PendingRecording oluşturmak için Recorder kullanmanız gerekir. PendingRecording hiçbir şey kaydetmez.
  • Gerçek kaydı Recording gerçekleştirir. Recording oluşturmak için PendingRecording kullanmanız gerekir.

Şekil 3, bu nesneler arasındaki ilişkileri göstermektedir:

video yakalama kullanım alanında gerçekleşen etkileşimleri gösteren şema
Şekil 3. Video Yakalama kullanım alanında gerçekleşen etkileşimleri gösteren şema.

Açıklamalar:

  1. QualitySelector ile bir Recorder oluşturun.
  2. Recorder özelliğini OutputOptions özelliklerinden biriyle yapılandırın.
  3. Gerekirse sesi withAudioEnabled() ile etkinleştirin.
  4. Kaydı başlatmak için bir VideoRecordEvent ile start() numaralı telefonu arayın.
  5. Kaydı kontrol etmek için Recording üzerinde pause()/resume()/stop() ifadesini kullanın.
  6. Etkinlik işleyicinizin içinden VideoRecordEvents yanıtını verin.

Ayrıntılı API listesi, kaynak kodunun içindeki current.txt dosyasında bulunur.

VideoCapture API'yi kullanma

CameraX VideoCapture kullanım alanını uygulamanıza entegre etmek için aşağıdakileri yapın:

  1. VideoCapture ile bağlantı oluşturun.
  2. Kaydı hazırlayıp yapılandırın.
  3. Çalışma zamanı kaydını başlatın ve kontrol edin.

Aşağıdaki bölümlerde, uçtan uca kayıt oturumu almak için her adımda neler yapabileceğiniz özetlenmiştir.

Video Yakalamayı Bağla

VideoCapure kullanım alanını bağlamak için aşağıdakileri yapın:

  1. Bir Recorder nesnesi oluşturun.
  2. VideoCapture nesnesi oluştur.
  3. Lifecycle öğesine bağlayın.

CameraX VideoCapture API, oluşturucu tasarım kalıbını izler. Uygulamalar bir Recorder oluşturmak için Recorder.Builder kullanır. Recorder için video çözünürlüğünü QualitySelector nesnesi aracılığıyla da yapılandırabilirsiniz.

CameraX Recorder, video çözünürlükleri için önceden tanımlanmış aşağıdaki Qualities özelliklerini destekler:

  • 4K ultra HD video boyutu (2160p) için Quality.UHD
  • Tam HD video boyutu için Quality.FHD (1080p)
  • HD video boyutu (720p) için Quality.HD
  • SD video boyutu (480p) için Quality.SD

CameraX'in uygulama tarafından yetkilendirildiğinde başka çözünürlükler de seçebileceğini unutmayın.

Her seçimin tam video boyutu kamera ve kodlayıcının özelliklerine bağlıdır. Daha fazla bilgi için CamcorderProfile belgelerine göz atın.

Uygulamalar, QualitySelector oluşturarak çözünürlüğü yapılandırabilir. Aşağıdaki yöntemlerden birini kullanarak bir QualitySelector oluşturabilirsiniz:

  • fromOrderedList() kullanarak tercih edilen birkaç çözüm sağlayın ve tercih edilen çözümlerin hiçbirinin desteklenmediği durumlarda kullanılacak bir yedek stratejisi ekleyin.

    CameraX, seçilen kameranın kapasitesine göre en iyi yedek eşleşmeye karar verebilir. Daha ayrıntılı bilgi için QualitySelector FallbackStrategy specification bölümüne bakın. Örneğin, aşağıdaki kod kayıt için desteklenen en yüksek çözünürlüğü ister ve istek çözünürlüklerinin hiçbiri desteklenmiyorsa CameraX'i Kalite.SD çözünürlüğüne en yakın olanı seçmesi için yetkilendirin:

    val qualitySelector = QualitySelector.fromOrderedList(
             listOf(Quality.UHD, Quality.FHD, Quality.HD, Quality.SD),
             FallbackStrategy.lowerQualityOrHigherThan(Quality.SD))
    
  • Önce kamera özelliklerini sorgulayın ve QualitySelector::from() kullanarak desteklenen çözünürlükler arasından seçim yapın:

    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.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.FHD -> "FHD"
            Quality.HD -> "HD"
            Quality.SD -> "SD"
            else -> throw IllegalArgumentException()
        }
    }
    
    

    QualitySelector.getSupportedQualities()'ten döndürülen özelliğin, VideoCapture kullanım alanı veya VideoCapture ve Preview kullanım alanlarının kombinasyonu için çalışacağının garanti edildiğini unutmayın. ImageCapture veya ImageAnalysis kullanım alanıyla bağlanırken, gerekli kombinasyon istenen kamerada desteklenmediğinde CameraX bağlama işlemi başarısız olabilir.

QualitySelector sahibi olduğunuzda uygulama bir VideoCapture nesnesi oluşturabilir ve bağlamayı gerçekleştirebilir. Bu bağlamanın diğer kullanım alanlarıyla aynı olduğunu unutmayın:

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() işlevinin bir Camera nesnesi döndürdüğünü unutmayın. Yakınlaştırma ve pozlama gibi kamera çıkışını kontrol etmeyle ilgili daha fazla bilgi için bu kılavuza bakın.

Recorder, sistem için en uygun biçimi seçer. En yaygın video codec'i, MPEG-4 container biçimine sahip H.264 AVC'dir.

Kayıt yapılandırma ve oluşturma

Uygulama, video ve ses yakalama işlemlerini gerçekleştirmek için Recorder cihazından kayıt nesneleri oluşturabilir. Uygulamalar aşağıdakileri yaparak kayıt oluşturur:

  1. OutputOptions öğesini prepareRecording() ile yapılandırın.
  2. (İsteğe bağlı) Ses kaydını etkinleştirin.
  3. start() kullanarak bir VideoRecordEvent dinleyicisi kaydedin ve video yakalamaya başlayın.

start() işlevini çağırdığınızda Recorder, bir Recording nesnesi döndürür. Uygulamanız, yakalama işlemini tamamlamak veya duraklatma ya da devam ettirme gibi başka işlemler gerçekleştirmek için bu Recording nesnesini kullanabilir.

Recorder, aynı anda bir Recording nesnesini destekler. Önceki Recording nesnesinde Recording.stop() veya Recording.close() çağrısı yaptıktan sonra yeni bir kayıt başlatabilirsiniz.

Bu adımları daha ayrıntılı bir şekilde inceleyelim. İlk olarak uygulama, Recorder.prepareRecording() ile Kaydedici için OutputOptions bilgisini yapılandırır. Recorder aşağıdaki OutputOptions türlerini destekler:

  • FileDescriptor içine yakalama işlemi için FileDescriptorOutputOptions.
  • File içine yakalama işlemi için FileOutputOptions.
  • MediaStore içine yakalama işlemi için MediaStoreOutputOptions.

Tüm OutputOptions türleri, setFileSizeLimit() ile maksimum dosya boyutu ayarlamanıza olanak tanır. Diğer seçenekler her bir bağımsız çıkış türüne özgüdür (ör. FileDescriptorOutputOptions için ParcelFileDescriptor).

prepareRecording(), PendingRecording nesnesini döndürür. Bu nesne, karşılık gelen Recording nesnesini oluşturmak için kullanılan bir ara nesnedir. PendingRecording geçici bir sınıftır. Bu sınıf çoğu durumda görünmez ve uygulama tarafından nadiren önbelleğe alınır.

Uygulamalar, kaydı aşağıdakiler gibi daha ayrıntılı şekilde yapılandırabilir:

  • withAudioEnabled() ile sesi etkinleştir.
  • start(Executor, Consumer<VideoRecordEvent>) ile video kayıt etkinliklerini almak için bir işleyici kaydedin.
  • Bir kaydın, bağlı olduğu Video Yakalama özelliği PendingRecording.asPersistentRecording() ile başka bir kameraya rehin edilirken sürekli kayıt yapmasına izin verin.

Kaydı başlatmak için PendingRecording.start() numaralı telefonu arayın. CameraX, PendingRecording öğesini Recording biçimine dönüştürür, kayıt isteğini sıraya alır ve yeni oluşturulan Recording nesnesini uygulamaya döndürür. İlgili Kamera cihazında kayıt başladığında CameraX bir VideoRecordEvent.EVENT_TYPE_START etkinliği gönderir.

Aşağıdaki örnekte video ve sesin bir MediaStore dosyasına nasıl kaydedileceği gösterilmektedir:

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

Kamera önizlemesi varsayılan olarak ön kamerada yansıtılsa da Video Yakalama ile kaydedilen videolar varsayılan olarak yansıtılmaz. CameraX 1.3 ile artık video kayıtlarını yansıtarak ön kamera önizlemesinin ve kaydedilen videonun eşleşmesini sağlayabilirsiniz.

Üç MirrorMode seçeneği vardır: MIRROR_MODE_OFF, MIRROR_MODE_ON ve MIRROR_MODE_ON_FRONT_ONLY. Google, kamera önizlemesine hizalamak için MIROR_MODE_ON_FRONT_ONLY kullanmanızı önerir. Bu, yansıtmanın arka kamera için etkinleştirilmediği, ön kamera için etkinleştirilmiş olduğu anlamına gelir. MirrorMode hakkında daha fazla bilgi edinmek için MirrorMode constants bölümüne bakın.

Bu kod snippet'inde, MIRROR_MODE_ON_FRONT_ONLY kullanarak VideoCapture.Builder.setMirrorMode() çağrısının nasıl yapılacağı gösterilmektedir. Daha fazla bilgi için setMirrorMode() sayfasını inceleyin.

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

Etkin bir kaydı kontrol etme

Aşağıdaki yöntemleri kullanarak devam eden bir Recording öğesini duraklatabilir, devam ettirebilir ve durdurabilirsiniz:

  • Geçerli etkin kaydı duraklatmak için pause.
  • resume() (Duraklatılmış etkin kaydı devam ettirmek için).
  • stop() seçeneğine dokunun.
  • mute() (Geçerli kaydın sesini kapatmak veya açmak için).

Kaydın duraklatılmış veya etkin durumda olmasına bakılmaksızın, Recording işlemini sonlandırmak için stop() çağırabilirsiniz.

PendingRecording.start() ile bir EventListener kaydettirdiyseniz Recording, VideoRecordEvent kullanarak iletişim kurar.

  • VideoRecordEvent.EVENT_TYPE_STATUS; geçerli dosya boyutu ve kaydedilen zaman aralığı gibi istatistikleri kaydetmek için kullanılır.
  • VideoRecordEvent.EVENT_TYPE_FINALIZE, kayıt sonucu için kullanılır ve ilgili tüm hatalarla birlikte nihai dosyanın URI'sı gibi bilgileri içerir.

Uygulamanız başarılı bir kayıt oturumunu gösteren EVENT_TYPE_FINALIZE aldıktan sonra, yakalanan videoya OutputOptions politikasında belirtilen konumdan erişebilirsiniz.

Ek kaynaklar

CameraX hakkında daha fazla bilgi edinmek için aşağıdaki ek kaynaklara bakın: