Camera1'i CameraX'e taşı

Uygulamanızda orijinal Camera kullanılıyorsa class ("Kamera1") Android 5.0 (API düzeyi 21), Modern bir Android kamera API'sine güncellemenizi önemle tavsiye ederiz. Android teklifleri KameraX (standartlaştırılmış, sağlam bir Jetpack kamera) API) ve Kamera2 (alt düzey, çerçeve API). çoğu durumda uygulamanızı CameraX'e taşımanızı öneririz. Bunun nedeni aşağıda açıklanmıştır:

  • Kullanım kolaylığı: CameraX, alt düzey ayrıntıları işler. Böylece şunları yapabilirsiniz: sıfırdan kamera deneyimi oluşturmaya daha az, öne çıkarmaya çalışın.
  • KameraX parçalanmayı sizin için halleder: CameraX, uzun vadede bakım maliyetlerini ve cihaza özgü kodları içerir, böylece daha kaliteli deneyimler değer teslim eder. Bu konuda daha fazla bilgi için KameraX ile Daha İyi Cihaz Uyumluluğu blog yayınımıza göz atın.
  • Gelişmiş özellikler: CameraX, gelişmiş göz atma deneyiminin işlevselliğini kolayca kullanabilirsiniz. Örneğin, ekip arkadaşlarınızın Boke, Yüz Rötuşu, HDR (Yüksek Dinamik Aralık) ve düşük ışıkta parlaklık uygula Fotoğraflarınıza gece çekimi modu KameraX Uzantıları.
  • Güncellenebilirlik: Android, CameraX'e yeni özellikler ve hata düzeltmeleri yayınlar teslim etmeye odaklandı. KameraX'e geçiş yaptığınızda uygulamanız en yeni Android sürümüne sahip olur kamera teknolojisi her CameraX sürümüyle birlikte test edin. yıllık Android sürümü sayısı.

Bu kılavuzda, kamera uygulamaları için yaygın senaryoları bulabilirsiniz. Her biri bir Kamera1 uygulaması ve kamera X uygulamasını içeren isteyebilirsiniz.

Taşıma söz konusu olduğunda bazen entegrasyon için daha fazla esnekliğe ihtiyaç duyabilirsiniz. yeni bir kod tabanı oluşturun. Bu kılavuzdaki tüm CameraX kodlarında bir CameraController (KameraX'ı kullanmanın en basit yolunu arıyorsanız harikadır) CameraProvider uygulayabilirsiniz. Daha fazla esnekliğe ihtiyacınız varsa harikadır. Hangi proje yönetiminin size uygun olanı seçmekle ilgili, her birinin avantajları aşağıda belirtilmiştir:

Kamera Kumandası

Kamera Sağlayıcısı

Az kurulum kodu gerektirir Daha fazla kontrol olanağı sağlar
CameraX'in kurulum işleminin daha büyük bir kısmını işlemesine izin vermek, dokunmak için dokunma ve yakınlaştırmak için sıkıştırma gibi işlevler otomatik olarak çalışır Kurulumu uygulama geliştirici yaptığı için daha fazla fırsat vardır (örneğin, çıkış resmi döndürmesini etkinleştirmek) yapılandırmayı özelleştirmek için veya çıkış resmi biçimini ImageAnalysis olarak ayarlayın
Kamera önizlemesi için PreviewView gerekli olduğunda şunlara izin verilir: KameraX, Makine Öğrenimi Kiti'nde olduğu gibi sorunsuz uçtan uca entegrasyon sunar ML modeli sonuç koordinatlarını (ör. yüz modeli) sınırlayıcı kutular) doğrudan önizleme koordinatlarına Kamera önizlemesi için özel bir "Yüzey" kullanma olanağı Örneğin, mevcut "Yüzey" kodunuzun kullanılması gibi daha fazla esneklik uygulamanızın diğer bölümlerine

Taşıma işlemini yapmaya çalışırken sorun yaşarsanız şuradan bize ulaşın: KameraX Tartışma Grubu.

Taşıma işleminden önce

CameraX ile Camera1 kullanımını karşılaştırın

Kod farklı görünse de Camera1 ve CameraX çok benzer. KameraX yaygın kamera işlevlerini kullanım alanlarına dönüştürerek Sonuç olarak Kamera1'de geliştiriciye bırakılan birçok görev, kameraX tarafından otomatik olarak işlenir. Dört adet KameraX'te UseCase, şunları yapabilirsiniz: Preview, ImageCapture, VideoCapture ve ImageAnalysis.

KameraX'in geliştiriciler için alt düzey ayrıntıları işlemesine örnek olarak Şu kullanıcılar arasında paylaşılan ViewPort: etkin UseCase. Bu, tüm UseCase öğelerinin tam olarak aynı pikselleri görmesini sağlar. Kamera1'de bu ayrıntıları kendiniz yönetmeniz ve değişkenlik farklı en boy oranlarında kamera sensörleri ve ekranlara bakın, önizlemenizin çekilen fotoğraflarla ve videolarla eşleştiğinden emin olun.

Başka bir örnek olarak CameraX, Lifecycle geri çağırmasını Lifecycle örneği ilettiniz. Bu da CameraX'in, uygulamanızın boyunca kamerayla bağlantı kurmanız Android etkinlik yaşam döngüsü, Aşağıdaki durumlar da dahil olmak üzere: Uygulamanız arka plan; ekranda artık ihtiyaç kalmadığında kamera önizlemesinin kaldırılması içeriği görüntülemek, ve başka bir etkinlik başladığında kamera önizlemesini duraklatarak ön plan önceliğini kontrol edin (ör. gelen görüntülü görüşme).

Son olarak, CameraX döndürme ve ölçeklendirme işlemlerini ek bir kod gerekmeden gerçekleştirir sizin sorumluluğunuzdadır. Yönü kilitsiz olan Activity için Sistem her cihazı yok ettiği için cihaz her döndürüldüğünde UseCase kurulumu yapılır. ve yön değişikliklerinde Activity değerini yeniden oluşturur. Bu durum, UseCases, hedef döndürmeyi ekranın yönüyle eşleşecek şekilde ayarlayarak her seferinde varsayılan olarak ayarlar. KameraX'teki döndürmeler hakkında daha fazla bilgi edinin.

Ayrıntılara geçmeden önce, CameraX'in genel performansı UseCase ve Camera1 uygulamasının nasıl bağlantılı olduğu. (KameraX kavramlarını mavi ve Kamera1 pek çok sektörde yeşil.)

KameraX

CameraController / CameraProvider Yapılandırması
Önizle Resim Yakalama Video Yakalama Görüntü Analizi
Önizleme yüzeyini yönetme ve Kamera'da ayarlama Kamerada PictureCallback'i ayarlama ve takePicture() çağrısını yapma Kamera ve MediaRecorder yapılandırmasını belirli bir sırada yönet Önizleme yüzeyinin üzerine inşa edilen özel analiz kodu
Cihaza Özel Kod
Cihaz Döndürme ve Ölçeklendirme Yönetimi
Kamera Oturumu Yönetimi (Kamera Seçimi, Yaşam Döngüsü Yönetimi)

Kamera1

CameraX'te uyumluluk ve performans

CameraX, çalışan cihazları destekler Android 5.0 (API düzeyi 21) ve sonraki sürümler. Bu mevcut Android cihazların% 98'inden fazlasını temsil ediyor. CameraX, sorunsuz çalışacak şekilde tasarlanmıştır cihazlar arasındaki farkları otomatik olarak azaltarak, cihaza özgü ekleyebilirsiniz. Dahası, tüm Android sürümlerinde 150'den fazla fiziksel cihazı test ediyoruz. sürümleri KameraX Test Lab hizmetimizde 5.0'dan beri verilmiştir. Siz tam listesini şu anda Test Lab'de olan cihazlar hakkında daha fazla bilgi edinin.

CameraX, aşağıdaki işlemler için Executor kullanır: fotoğraf makinesi yığınını görmenizi sağlar. Şunları yapabilirsiniz: KameraX'ta kendi yürütücünüzü ayarlayın Belirli ileti dizisi gereksinimleri varsa bunları kontrol edin. Politika ayarlanmazsa CameraX ve optimize edilmiş varsayılan bir dahili Executor kullanır. İnternette kullanılan platform API'lerinin çoğu, CameraX'in bu amaçla geliştirilmiş olduğu başka bir makineyle işlemler arası iletişimin (IPC) engellenmesi, donanımlarının yanıt vermesi bazen yüzlerce milisaniye sürebilir. Bunun için Bu nedenle, CameraX bu API'leri yalnızca arka plan iş parçacıklarından çağırır. Böylece, ana iş parçacığı engellenmez ve kullanıcı arayüzünün değişken kalması sağlanır. Mesaj dizileri hakkında daha fazla bilgi edinin.

Uygulamanızın hedef pazarında düşük özellikli cihazlar varsa CameraX size bir kurulum süresini azaltmanın bir yolunu bulmak için kamera sınırlayıcı. çok fazla zaman ve çaba gerektirebilir. özellikle de düşük segment cihazlarda, uygulamanızın sunduğu kamera grubunu belirtebilirsiniz gerekiyor. CameraX bu kameralara yalnızca kurulum sırasında bağlanır. Örneğin, Uygulama yalnızca arka kamera kullanıyor, bu yapılandırmayı ayarlayabilir DEFAULT_BACK_CAMERA ile ve ardından CameraX ön yüzün başlatılmasını engelliyor kameraları kullanarak gecikmeyi azaltın.

Android geliştirme kavramları

Bu kılavuzda, Android geliştirme konusunda genel bilgi sahibi olmanız varsayılır. Şunun ötesinde: şu temel kavramlara değineceğiz: girerek aşağıdaki kodu inceleyebilirsiniz:

Sık karşılaşılan senaryoları taşıma

Bu bölümde, sık karşılaşılan senaryoların Camera1'den CameraX'e nasıl taşınacağı açıklanmaktadır. Her senaryoda bir Camera1 uygulaması, bir CameraX CameraProvider ve CameraX CameraController uygulaması.

Kamera seçme

Kamera uygulamanızda sunmak isteyebileceğiniz ilk şeylerden biri, başka kameralar seçmenin bir yoludur.

Kamera1

Kamera1'de, telefon görüşmesi yapmak için Parametre içermeyen Camera.open() ilk arka kamerayı açmak ya da arkadaki kameraya bir tam sayı kamerayı açın. Aşağıda, bunun nasıl görünebileceğine dair bir örnek verilmiştir:

// Camera1: select a camera from id.

// Note: opening the camera is a non-trivial task, and it shouldn't be
// called from the main thread, unlike CameraX calls, which can be
// on the main thread since CameraX kicks off background threads
// internally as needed.

private fun safeCameraOpen(id: Int): Boolean {
    return try {
        releaseCameraAndPreview()
        camera = Camera.open(id)
        true
    } catch (e: Exception) {
        Log.e(TAG, "failed to open camera", e)
        false
    }
}

private fun releaseCameraAndPreview() {
    preview?.setCamera(null)
    camera?.release()
    camera = null
}

CameraX: KameraDenetleyici

CameraX'te kamera seçimi CameraSelector sınıfı tarafından işlenir. KameraX varsayılan kamera kullanımını kolaylaştırır. Kullanıcı adı olarak Varsayılan ön kamerayı mı yoksa varsayılan arka kamerayı mı kullanmak istiyorsunuz? Ayrıca, CameraX'in CameraControl nesnesi, kolayca gezinmenizi uygulamanızın yakınlaştırma düzeyini ayarlayın; dolayısıyla uygulamanızın, mantıksal kameralar kullanıyorsanız doğru lense götürebilir.

Burada, varsayılan arka kamerayı kameraya doğru bir şekilde kullanmak için CameraController:

// CameraX: select a camera with CameraController

var cameraController = LifecycleCameraController(baseContext)
val selector = CameraSelector.Builder()
    .requireLensFacing(CameraSelector.LENS_FACING_BACK).build()
cameraController.cameraSelector = selector

CameraX: CameraProvider

CameraProvider ile varsayılan ön kamerayı seçmeyle ilgili bir örneği aşağıda bulabilirsiniz (ön veya arka kamera CameraController veya CameraProvider):

// CameraX: select a camera with CameraProvider.

// Use await() within a suspend function to get CameraProvider instance.
// For more details on await(), see the "Android development concepts"
// section above.
private suspend fun startCamera() {
    val cameraProvider = ProcessCameraProvider.getInstance(this).await()

    // Set up UseCases (more on UseCases in later scenarios)
    var useCases:Array = ...

    // Set the cameraSelector to use the default front-facing (selfie)
    // camera.
    val cameraSelector = CameraSelector.DEFAULT_FRONT_CAMERA

    try {
        // Unbind UseCases before rebinding.
        cameraProvider.unbindAll()

        // Bind UseCases to camera. This function returns a camera
        // object which can be used to perform operations like zoom,
        // flash, and focus.
        var camera = cameraProvider.bindToLifecycle(
            this, cameraSelector, useCases)

    } catch(exc: Exception) {
        Log.e(TAG, "UseCase binding failed", exc)
    }
})

...

// Call startCamera in the setup flow of your app, such as in onViewCreated.
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)

    ...

    lifecycleScope.launch {
        startCamera()
    }
}

Hangi kameranın seçileceğini kontrol etmek istiyorsanız bunu numaralı telefonu arayarak CameraProvider kullanıyorsanız CameraX getAvailableCameraInfos(), Bu, aşağıdaki gibi belirli kamera özelliklerini kontrol etmeniz için size bir CameraInfo nesnesi sağlar: isFocusMeteringSupported(). Ardından, yukarıdaki gibi kullanmak üzere bunu bir CameraSelector biçimine dönüştürebilirsiniz. CameraInfo.getCameraSelector() yöntemi için örnekler.

Her kamera hakkında daha fazla bilgi edinmek için Camera2CameraInfo sınıfını kullanır. Telefonla arama getCameraCharacteristic() bir anahtarla ekleyebilirsiniz. Kontrol edin CameraCharacteristics sınıfını kullanabilirsiniz.

Aşağıdaki örnekte, kullanabileceğiniz özel bir checkFocalLength() işlevi görebilirsiniz: kendinizi tanımlayın:

// CameraX: get a cameraSelector for first camera that matches the criteria
// defined in checkFocalLength().

val cameraInfo = cameraProvider.getAvailableCameraInfos()
    .first { cameraInfo ->
        val focalLengths = Camera2CameraInfo.from(cameraInfo)
            .getCameraCharacteristic(
                CameraCharacteristics.LENS_INFO_AVAILABLE_FOCAL_LENGTHS
            )
        return checkFocalLength(focalLengths)
    }
val cameraSelector = cameraInfo.getCameraSelector()

Önizleme gösterme

Kamera uygulamalarının çoğunun kamera feed'ini ekranda göstermesi gerekir. puan. Kamera1 ile, yaşam döngüsü geri çağırmalarını doğru şekilde yönetmeniz ve önizlemeniz için döndürme ve ölçeklendirmeyi de belirlemeniz gerekir.

Buna ek olarak, Kamera1'de bir kameranın mı kullanılacağına TextureView veya bir Önizleme yüzeyiniz olarak SurfaceView. Her iki seçenekte de bazı ödünler vardır. Her iki durumda da Kamera1'de ve ölçeklendirmeyi doğru şekilde ele alacağız. Diğer tarafta CameraX'in PreviewView cihazı hem TextureView hem de SurfaceView için temel uygulamaları vardır. CameraX, aşağıdakiler gibi faktörlere bağlı olarak en iyi uygulamanın hangisi olduğuna karar verir: Cihazın türü ve uygulamanızın yüklü olduğu Android sürümü. İkisinden biri uyumlu olduğundan emin olduktan sonra, tercihinizi belirtmek için PreviewView.ImplementationMode. COMPATIBLE seçeneği, önizleme için bir TextureView kullanır ve PERFORMANCE değeri, (mümkün olduğunda) SurfaceView kullanır.

Kamera1

Önizleme göstermek için kendi Preview sınıfınızı uygulanması android.view.SurfaceHolder.Callback kamera donanımından cihaza aktarılan görüntü verilerini bir uygulamadır. Ardından, canlı resim önizlemesini başlatmadan önce Preview class'ı Camera nesnesine iletilmelidir.

// Camera1: set up a camera preview.

class Preview(
        context: Context,
        private val camera: Camera
) : SurfaceView(context), SurfaceHolder.Callback {

    private val holder: SurfaceHolder = holder.apply {
        addCallback(this@Preview)
        setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS)
    }

    override fun surfaceCreated(holder: SurfaceHolder) {
        // The Surface has been created, now tell the camera
        // where to draw the preview.
        camera.apply {
            try {
                setPreviewDisplay(holder)
                startPreview()
            } catch (e: IOException) {
                Log.d(TAG, "error setting camera preview", e)
            }
        }
    }

    override fun surfaceDestroyed(holder: SurfaceHolder) {
        // Take care of releasing the Camera preview in your activity.
    }

    override fun surfaceChanged(holder: SurfaceHolder, format: Int,
                                w: Int, h: Int) {
        // If your preview can change or rotate, take care of those
        // events here. Make sure to stop the preview before resizing
        // or reformatting it.
        if (holder.surface == null) {
            return  // The preview surface does not exist.
        }

        // Stop preview before making changes.
        try {
            camera.stopPreview()
        } catch (e: Exception) {
            // Tried to stop a non-existent preview; nothing to do.
        }

        // Set preview size and make any resize, rotate or
        // reformatting changes here.

        // Start preview with new settings.
        camera.apply {
            try {
                setPreviewDisplay(holder)
                startPreview()
            } catch (e: Exception) {
                Log.d(TAG, "error starting camera preview", e)
            }
        }
    }
}

class CameraActivity : AppCompatActivity() {
    private lateinit var viewBinding: ActivityMainBinding
    private var camera: Camera? = null
    private var preview: Preview? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        viewBinding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(viewBinding.root)

        // Create an instance of Camera.
        camera = getCameraInstance()

        preview = camera?.let {
            // Create the Preview view.
            Preview(this, it)
        }

        // Set the Preview view as the content of the activity.
        val cameraPreview: FrameLayout = viewBinding.cameraPreview
        cameraPreview.addView(preview)
    }
}

CameraX: KameraDenetleyici

KameraX'te, geliştirici olarak sizin yönetmeniz gereken çok daha az şey vardır. Bir CameraController, ayrıca PreviewView kullanmanız gerekir. Bu, Preview UseCase örtülü olduğundan kurulumun çok daha az çalışmasını sağlar:

// CameraX: set up a camera preview with a CameraController.

class MainActivity : AppCompatActivity() {
    private lateinit var viewBinding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        viewBinding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(viewBinding.root)

        // Create the CameraController and set it on the previewView.
        var cameraController = LifecycleCameraController(baseContext)
        cameraController.bindToLifecycle(this)
        val previewView: PreviewView = viewBinding.cameraPreview
        previewView.controller = cameraController
    }
}

CameraX: CameraProvider

KameraX'in CameraProvider özelliği ile PreviewView uygulamasını kullanmanız gerekmez, ancak kamera1 üzerinden önizleme kurulumunu da büyük ölçüde basitleştiriyor. Demoda amacıyla, bu örnekte bir PreviewView kullanılmıştır, ancak Daha karmaşık siteleriniz varsa setSurfaceProvider() öğesine geçmek için SurfaceProvider gerekiyor.

Burada Preview UseCase, CameraController ile olduğu gibi ima edilmez. O yüzden ayarlamanız gerekir:

// CameraX: set up a camera preview with a CameraProvider.

// Use await() within a suspend function to get CameraProvider instance.
// For more details on await(), see the "Android development concepts"
// section above.
private suspend fun startCamera() {
    val cameraProvider = ProcessCameraProvider.getInstance(this).await()

    // Create Preview UseCase.
    val preview = Preview.Builder()
        .build()
        .also {
            it.setSurfaceProvider(
                viewBinding.viewFinder.surfaceProvider
            )
        }

    // Select default back camera.
    val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA

    try {
        // Unbind UseCases before rebinding.
        cameraProvider.unbindAll()

        // Bind UseCases to camera. This function returns a camera
        // object which can be used to perform operations like zoom,
        // flash, and focus.
        var camera = cameraProvider.bindToLifecycle(
            this, cameraSelector, useCases)

    } catch(exc: Exception) {
        Log.e(TAG, "UseCase binding failed", exc)
    }
})

...

// Call startCamera() in the setup flow of your app, such as in onViewCreated.
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)

    ...

    lifecycleScope.launch {
        startCamera()
    }
}

Odaklamak için dokunun

Kamera önizlemeniz ekrandayken yaygın olarak kullanılan kontrollerden biri, odağı ayarlamaktır. Kullanıcı önizlemeye dokunduğunda

Kamera1

Kamera1'de dokunarak odaklamayı uygulamak için optimum odağı hesaplamanız gerekir Camera öğesinin odaklanmaya çalışması gereken yeri belirtmek için Area. Bu Area setFocusAreas() tarihine aktarıldı. Ayrıca Camera Odak alanı yalnızca geçerli odak modu FOCUS_MODE_AUTO, FOCUS_MODE_MACRO, FOCUS_MODE_CONTINUOUS_VIDEO veya FOCUS_MODE_CONTINUOUS_PICTURE.

Her Area, belirtilen ağırlığa sahip bir dikdörtgendir. Ağırlık, 1 ve 1000'dir ve birden fazla değer ayarlanırsa Areas odağına öncelik vermek için kullanılır. Bu örnek yalnızca bir Area kullandığından ağırlık değeri önemli değildir. Koordinatları dikdörtgen aralığı -1000 ile 1000 arasındadır. Sol üst nokta (-1000, -1000) şeklindedir. Sağ alt nokta (1000, 1000) şeklindedir. Yön, sensöre bağlıdır yani sensörün gördüğü yönü seçin. Yön, şundan etkilenmez: Camera.setDisplayOrientation() yansıtması nedeniyle iki tarafın da dokunma etkinliği koordinatlarını sensör koordinatlarına dönüştürür.

// Camera1: implement tap-to-focus.

class TapToFocusHandler : Camera.AutoFocusCallback {
    private fun handleFocus(event: MotionEvent) {
        val camera = camera ?: return
        val parameters = try {
            camera.getParameters()
        } catch (e: RuntimeException) {
            return
        }

        // Cancel previous auto-focus function, if one was in progress.
        camera.cancelAutoFocus()

        // Create focus Area.
        val rect = calculateFocusAreaCoordinates(event.x, event.y)
        val weight = 1  // This value's not important since there's only 1 Area.
        val focusArea = Camera.Area(rect, weight)

        // Set the focus parameters.
        parameters.setFocusMode(Parameters.FOCUS_MODE_AUTO)
        parameters.setFocusAreas(listOf(focusArea))

        // Set the parameters back on the camera and initiate auto-focus.
        camera.setParameters(parameters)
        camera.autoFocus(this)
    }

    private fun calculateFocusAreaCoordinates(x: Int, y: Int) {
        // Define the size of the Area to be returned. This value
        // should be optimized for your app.
        val focusAreaSize = 100

        // You must define functions to rotate and scale the x and y values to
        // be values between 0 and 1, where (0, 0) is the upper left-hand side
        // of the preview, and (1, 1) is the lower right-hand side.
        val normalizedX = (rotateAndScaleX(x) - 0.5) * 2000
        val normalizedY = (rotateAndScaleY(y) - 0.5) * 2000

        // Calculate the values for left, top, right, and bottom of the Rect to
        // be returned. If the Rect would extend beyond the allowed values of
        // (-1000, -1000, 1000, 1000), then crop the values to fit inside of
        // that boundary.
        val left = max(normalizedX - (focusAreaSize / 2), -1000)
        val top = max(normalizedY - (focusAreaSize / 2), -1000)
        val right = min(left + focusAreaSize, 1000)
        val bottom = min(top + focusAreaSize, 1000)

        return Rect(left, top, left + focusAreaSize, top + focusAreaSize)
    }

    override fun onAutoFocus(focused: Boolean, camera: Camera) {
        if (!focused) {
            Log.d(TAG, "tap-to-focus failed")
        }
    }
}

CameraX: KameraDenetleyici

CameraController, PreviewView adlı kullanıcının işlemek için dokunma etkinliklerini dinler otomatik olarak dokunarak odaklama. Dokunarak odaklamayı şu özellik aracılığıyla etkinleştirebilir ve devre dışı bırakabilirsiniz: setTapToFocusEnabled() ve değeri ilgili alıcı ile kontrol edin. isTapToFocusEnabled().

İlgili içeriği oluşturmak için kullanılan getTapToFocusState() yöntem LiveData nesnesi döndürür CameraController üzerindeki odak durumunda yapılan değişiklikleri izlemek için kullanılır.

// CameraX: track the state of tap-to-focus over the Lifecycle of a PreviewView,
// with handlers you can define for focused, not focused, and failed states.

val tapToFocusStateObserver = Observer { state ->
    when (state) {
        CameraController.TAP_TO_FOCUS_NOT_STARTED ->
            Log.d(TAG, "tap-to-focus init")
        CameraController.TAP_TO_FOCUS_STARTED ->
            Log.d(TAG, "tap-to-focus started")
        CameraController.TAP_TO_FOCUS_FOCUSED ->
            Log.d(TAG, "tap-to-focus finished (focus successful)")
        CameraController.TAP_TO_FOCUS_NOT_FOCUSED ->
            Log.d(TAG, "tap-to-focus finished (focused unsuccessful)")
        CameraController.TAP_TO_FOCUS_FAILED ->
            Log.d(TAG, "tap-to-focus failed")
    }
}

cameraController.getTapToFocusState().observe(this, tapToFocusStateObserver)

CameraX: CameraProvider

CameraProvider kullanırken dokunarak odaklanmak için bazı kurulum gerekir çalışmadır. Bu örnekte PreviewView kullandığınız varsayılmıştır. Aksi halde mantığı, özel Surface öğenize uygulanacak şekilde uyarlayabilirsiniz.

PreviewView kullanılırken izlenecek adımlar aşağıda verilmiştir:

  1. Dokunma etkinliklerini işlemek için bir hareket algılayıcısı ayarlayın.
  2. Dokunma etkinliğiyle bir MeteringPoint oluşturun: MeteringPointFactory.createPoint().
  3. MeteringPoint ile bir FocusMeteringAction oluşturun.
  4. Camera cihazınızdaki CameraControl nesnesiyle ( bindToLifecycle()), startFocusAndMetering(), FocusMeteringAction.
  5. (İsteğe bağlı) FocusMeteringResult uyarınca yanıt verin.
  6. Hareket dedektörünüzü dokunma etkinliklerine yanıt verecek şekilde ayarlayın: PreviewView.setOnTouchListener()
// CameraX: implement tap-to-focus with CameraProvider.

// Define a gesture detector to respond to tap events and call
// startFocusAndMetering on CameraControl. If you want to use a
// coroutine with await() to check the result of focusing, see the
// "Android development concepts" section above.
val gestureDetector = GestureDetectorCompat(context,
    object : SimpleOnGestureListener() {
        override fun onSingleTapUp(e: MotionEvent): Boolean {
            val previewView = previewView ?: return
            val camera = camera ?: return
            val meteringPointFactory = previewView.meteringPointFactory
            val focusPoint = meteringPointFactory.createPoint(e.x, e.y)
            val meteringAction = FocusMeteringAction
                .Builder(meteringPoint).build()
            lifecycleScope.launch {
                val focusResult = camera.cameraControl
                    .startFocusAndMetering(meteringAction).await()
                if (!result.isFocusSuccessful()) {
                    Log.d(TAG, "tap-to-focus failed")
                }
            }
        }
    }
)

...

// Set the gestureDetector in a touch listener on the PreviewView.
previewView.setOnTouchListener { _, event ->
    // See pinch-to-zooom scenario for scaleGestureDetector definition.
    var didConsume = scaleGestureDetector.onTouchEvent(event)
    if (!scaleGestureDetector.isInProgress) {
        didConsume = gestureDetector.onTouchEvent(event)
    }
    didConsume
}

Yakınlaştırmak için sıkıştırma

Önizlemeyi yakınlaştırmak ve uzaklaştırmak da kamera önizlemesi. Cihazlardaki kamera sayısının artmasıyla birlikte kullanıcılar, en iyi odak uzaklığına sahip merceğin otomatik olarak çok fazla resim var.

Kamera1

Kamera1'i kullanarak yakınlaştırmanın iki yolu vardır. Camera.startSmoothZoom() yöntemi mevcut yakınlaştırma düzeyinden geçtiğiniz yakınlaştırma düzeyine geçiş yapar. İlgili içeriği oluşturmak için kullanılan Camera.Parameters.setZoom() yöntemi doğrudan geçtiğiniz yakınlaştırma seviyesine atlar inç Bunlardan birini kullanmadan önce isSmoothZoomSupported() veya İhtiyacınız olan ilgili yakınlaştırma yöntemlerinin sağlandığından emin olmak için sırasıyla isZoomSupported() Kameranızda mevcut.

Bu örnekte yakınlaştırmak için sıkıştırmayı uygulamak üzere setZoom() kullanılmıştır. Bunun nedeni, önizleme yüzeyindeki dinleyici, sıkıştırma sırasında etkinlikleri sürekli olarak tetikler. hareketi gerçekleştiğinden, yakınlaştırma düzeyini her seferinde hemen günceller. İlgili içeriği oluşturmak için kullanılan Aşağıda ZoomTouchListener sınıfı tanımlanmıştır ve geri çağırma olarak ayarlanmalıdır. dokunun.

// Camera1: implement pinch-to-zoom.

// Define a scale gesture detector to respond to pinch events and call
// setZoom on Camera.Parameters.
val scaleGestureDetector = ScaleGestureDetector(context,
    object : ScaleGestureDetector.OnScaleGestureListener {
        override fun onScale(detector: ScaleGestureDetector): Boolean {
            val camera = camera ?: return false
            val parameters = try {
                camera.parameters
            } catch (e: RuntimeException) {
                return false
            }

            // In case there is any focus happening, stop it.
            camera.cancelAutoFocus()

            // Set the zoom level on the Camera.Parameters, and set
            // the Parameters back onto the Camera.
            val currentZoom = parameters.zoom
            parameters.setZoom(detector.scaleFactor * currentZoom)
        camera.setParameters(parameters)
            return true
        }
    }
)

// Define a View.OnTouchListener to attach to your preview view.
class ZoomTouchListener : View.OnTouchListener {
    override fun onTouch(v: View, event: MotionEvent): Boolean =
        scaleGestureDetector.onTouchEvent(event)
}

// Set a ZoomTouchListener to handle touch events on your preview view
// if zoom is supported by the current camera.
if (camera.getParameters().isZoomSupported()) {
    view.setOnTouchListener(ZoomTouchListener())
}

CameraX: KameraDenetleyici

Dokunarak odaklamaya benzer şekilde, CameraController PreviewView'un dokunmasını dinler otomatik olarak iki parmak ucunuzu yakınlaştırın veya uzaklaştırın. Bu seçeneği etkinleştirebilir ve devre dışı bırakabilirsiniz iki parmağı yakınlaştırmak ya da uzaklaştırmak setPinchToZoomEnabled() ve değeri ilgili alıcı ile kontrol edin. isPinchToZoomEnabled().

İlgili içeriği oluşturmak için kullanılan getZoomState() yöntemi,LiveData ZoomState CameraController.

// CameraX: track the state of pinch-to-zoom over the Lifecycle of
// a PreviewView, logging the linear zoom ratio.

val pinchToZoomStateObserver = Observer { state ->
    val zoomRatio = state.getZoomRatio()
    Log.d(TAG, "ptz-zoom-ratio $zoomRatio")
}

cameraController.getZoomState().observe(this, pinchToZoomStateObserver)

CameraX: CameraProvider

İki parmak ucunu yakınlaştırma ya da uzaklaştırma özelliğini CameraProvider ile kullanmak için bazı ayarlar gerekir. Eğer PreviewView kullanmıyorsanız, mantığınıza, uygulamanıza uygulamak için özel Surface.

PreviewView kullanılırken izlenecek adımlar aşağıda verilmiştir:

  1. Sıkıştırma etkinliklerini işlemek için bir ölçek hareketi dedektörü ayarlayın.
  2. Camera öğesinin olduğu Camera.CameraInfo nesnesinden ZoomState değerini alın şu örneği çağırdığınızda döndürülür: bindToLifecycle().
  3. ZoomState için zoomRatio değeri varsa bunu geçerli yakınlaştırma olarak kaydedin oranı. ZoomState cihazında zoomRatio yoksa kameranın varsayılan ayarını kullanın yakınlaştırma hızı (1,0).
  4. scaleFactor ile geçerli yakınlaştırma oranının çarpımını elde edin yeni yakınlaştırma oranını belirleyip CameraControl.setZoomRatio() hedefine iletebilir.
  5. Hareket dedektörünüzü dokunma etkinliklerine yanıt verecek şekilde ayarlayın: PreviewView.setOnTouchListener()
// CameraX: implement pinch-to-zoom with CameraProvider.

// Define a scale gesture detector to respond to pinch events and call
// setZoomRatio on CameraControl.
val scaleGestureDetector = ScaleGestureDetector(context,
    object : SimpleOnGestureListener() {
        override fun onScale(detector: ScaleGestureDetector): Boolean {
            val camera = camera ?: return
            val zoomState = camera.cameraInfo.zoomState
            val currentZoomRatio: Float = zoomState.value?.zoomRatio ?: 1f
            camera.cameraControl.setZoomRatio(
                detector.scaleFactor * currentZoomRatio
            )
        }
    }
)

...

// Set the scaleGestureDetector in a touch listener on the PreviewView.
previewView.setOnTouchListener { _, event ->
    var didConsume = scaleGestureDetector.onTouchEvent(event)
    if (!scaleGestureDetector.isInProgress) {
        // See pinch-to-zooom scenario for gestureDetector definition.
        didConsume = gestureDetector.onTouchEvent(event)
    }
    didConsume
}

Fotoğraf çekme

Bu bölümde, fotoğraf çekme işlemini bir cihazda yapmanız gerekip gerekmediğine süre geçtikten sonra ya da seçebilirsiniz.

Kamera1

Kamera1'de ilk olarak bir Camera.PictureCallback resim verilerini yönetebilirsiniz. Bu proje bağlamında JPEG resim verilerini işlemek için PictureCallback:

// Camera1: define a Camera.PictureCallback to handle JPEG data.

private val picture = Camera.PictureCallback { data, _ ->
    val pictureFile: File = getOutputMediaFile(MEDIA_TYPE_IMAGE) ?: run {
        Log.d(TAG,
              "error creating media file, check storage permissions")
        return@PictureCallback
    }

    try {
        val fos = FileOutputStream(pictureFile)
        fos.write(data)
        fos.close()
    } catch (e: FileNotFoundException) {
        Log.d(TAG, "file not found", e)
    } catch (e: IOException) {
        Log.d(TAG, "error accessing file", e)
    }
}

Daha sonra, her fotoğraf çekmek istediğinizde takePicture() yöntemini çağırırsınız Camera örneğinizde. Bu takePicture() yönteminde üç farklı farklı veri türleri için parametreler sağlar. İlk parametre ShutterCallback (bu örnekte tanımlanmamıştır). İkinci parametre işlenmemiş (sıkıştırılmamış) kamera verilerini işleyecek bir PictureCallback için. Üçüncü parametresi, işlenecek bir PictureCallback olduğundan bu örnekte kullanılan parametredir. JPEG resim verileri.

// Camera1: call takePicture on Camera instance, passing our PictureCallback.

camera?.takePicture(null, null, picture)

CameraX: KameraDenetleyici

KameraX'in CameraController özelliği, Kamera1'in sadeliğini korur takePicture() kendi yöntemini uygulayarak. Burada bir işlevini kullanın.MediaStore

// CameraX: define a function that uses CameraController to take a photo.

private val FILENAME_FORMAT = "yyyy-MM-dd-HH-mm-ss-SSS"

private fun takePhoto() {
   // Create time stamped name and MediaStore entry.
   val name = SimpleDateFormat(FILENAME_FORMAT, Locale.US)
              .format(System.currentTimeMillis())
   val contentValues = ContentValues().apply {
       put(MediaStore.MediaColumns.DISPLAY_NAME, name)
       put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg")
       if(Build.VERSION.SDK_INT > Build.VERSION_CODES.P) {
           put(MediaStore.Images.Media.RELATIVE_PATH, "Pictures/CameraX-Image")
       }
   }

   // Create output options object which contains file + metadata.
   val outputOptions = ImageCapture.OutputFileOptions
       .Builder(context.getContentResolver(),
            MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues)
       .build()

   // Set up image capture listener, which is triggered after photo has
   // been taken.
   cameraController.takePicture(
       outputOptions,
       ContextCompat.getMainExecutor(this),
       object : ImageCapture.OnImageSavedCallback {
           override fun onError(e: ImageCaptureException) {
               Log.e(TAG, "photo capture failed", e)
           }

           override fun onImageSaved(
               output: ImageCapture.OutputFileResults
           ) {
               val msg = "Photo capture succeeded: ${output.savedUri}"
               Toast.makeText(baseContext, msg, Toast.LENGTH_SHORT).show()
               Log.d(TAG, msg)
           }
       }
   )
}

CameraX: CameraProvider

CameraProvider ile fotoğraf çekmenin işleyiş şekli, CameraController, ancak önce bir ImageCapture oluşturup bağlamanız gerekiyor takePicture() öğesini çağıracak bir nesneye sahip olmak için UseCase:

// CameraX: create and bind an ImageCapture UseCase.

// Make a reference to the ImageCapture UseCase at a scope that can be accessed
// throughout the camera logic in your app.
private var imageCapture: ImageCapture? = null

...

// Create an ImageCapture instance (can be added with other
// UseCase definitions).
imageCapture = ImageCapture.Builder().build()

...

// Bind UseCases to camera (adding imageCapture along with preview here, but
// preview is not required to use imageCapture). This function returns a camera
// object which can be used to perform operations like zoom, flash, and focus.
var camera = cameraProvider.bindToLifecycle(
    this, cameraSelector, preview, imageCapture)

Daha sonra, fotoğraf çekmek istediğinizde ImageCapture.takePicture() Bu bölümdeki CameraController kodunu inceleyin takePhoto() işlevinin tam örneği için.

// CameraX: define a function that uses CameraController to take a photo.

private fun takePhoto() {
    // Get a stable reference of the modifiable ImageCapture UseCase.
    val imageCapture = imageCapture ?: return

    ...

    // Call takePicture on imageCapture instance.
    imageCapture.takePicture(
        ...
    )
}

Video kaydetme

Video kaydetmek, izlenen senaryolardan çok daha karmaşıktır. yaptık. Sürecin her bölümü düzgün şekilde, genellikle belirli bir yardımcı olur. Ayrıca görüntü ve sesin senkronizasyona veya ek cihaz tutarsızlıklarıyla başa çıkmaya yardımcı olur.

Göreceğiniz gibi CameraX, bu karmaşıklığın büyük bir kısmını sizin için yine halleder.

Kamera1

Kamera1 ile video çekmek için Camera ve MediaRecorder ve yöntemler belirli bir sırada çağrılması gerekir. Şunun için bu siparişi takip etmeniz gerekir: düzgün çalışmasını sağlamalısınız:

  1. Kamerayı açın.
  2. Bir önizleme hazırlayıp başlatın (uygulamanızda kaydedilen video gösteriliyorsa Bu genellikle böyledir).
  3. Camera.unlock() numaralı telefonu arayarak MediaRecorder tarafından kullanılması için kameranın kilidini açın.
  4. MediaRecorder uygulamasında aşağıdaki yöntemleri çağırarak kaydı yapılandırın:
    1. Camera örneğinizi setCamera(camera) ile bağlayın.
    2. Şu numaraya telefon et: setAudioSource(MediaRecorder.AudioSource.CAMCORDER).
    3. Şu numaraya telefon et: setVideoSource(MediaRecorder.VideoSource.CAMERA).
    4. Telefon et: setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_1080P)) kaliteyi ayarlayın. Görüntüleyin Şunların tümü için CamcorderProfile seçenekleri var.
    5. Şu numaraya telefon et: setOutputFile(getOutputMediaFile(MEDIA_TYPE_VIDEO).toString()).
    6. Uygulamanızda videonun önizlemesi varsa setPreviewDisplay(preview?.holder?.surface)
    7. Şu numaraya telefon et: setOutputFormat(MediaRecorder.OutputFormat.MPEG_4).
    8. Şu numaraya telefon et: setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT).
    9. Şu numaraya telefon et: setVideoEncoder(MediaRecorder.VideoEncoder.DEFAULT).
    10. MediaRecorder yapılandırmanızı tamamlamak için prepare() numaralı telefonu arayın.
  5. Kaydetmeye başlamak için MediaRecorder.start() numaralı telefonu arayın.
  6. Kaydı durdurmak için aşağıdaki yöntemleri çağırın. Yine tam olarak aşağıdaki sırayı izleyin:
    1. Şu numaraya telefon et: MediaRecorder.stop().
    2. İsteğe bağlı olarak, şunu çağırarak geçerli MediaRecorder yapılandırmasını kaldırın: MediaRecorder.reset().
    3. Şu numaraya telefon et: MediaRecorder.release().
    4. Sonraki MediaRecorder oturumun şu tarihe kadar kullanması için kamerayı kilitleyin: Camera.lock() aranıyor.
  7. Önizlemeyi durdurmak için Camera.stopPreview() numaralı telefonu arayın.
  8. Son olarak, diğer işlemlerin kullanabilmesi için Camera öğesini yayınlamak üzere Camera.release().

Bu adımların tümü şu şekildedir:

// Camera1: set up a MediaRecorder and a function to start and stop video
// recording.

// Make a reference to the MediaRecorder at a scope that can be accessed
// throughout the camera logic in your app.
private var mediaRecorder: MediaRecorder? = null
private var isRecording = false

...

private fun prepareMediaRecorder(): Boolean {
    mediaRecorder = MediaRecorder()

    // Unlock and set camera to MediaRecorder.
    camera?.unlock()

    mediaRecorder?.run {
        setCamera(camera)

        // Set the audio and video sources.
        setAudioSource(MediaRecorder.AudioSource.CAMCORDER)
        setVideoSource(MediaRecorder.VideoSource.CAMERA)

        // Set a CamcorderProfile (requires API Level 8 or higher).
        setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH))

        // Set the output file.
        setOutputFile(getOutputMediaFile(MEDIA_TYPE_VIDEO).toString())

        // Set the preview output.
        setPreviewDisplay(preview?.holder?.surface)

        setOutputFormat(MediaRecorder.OutputFormat.MPEG_4)
        setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT)
        setVideoEncoder(MediaRecorder.VideoEncoder.DEFAULT)

        // Prepare configured MediaRecorder.
        return try {
            prepare()
            true
        } catch (e: IllegalStateException) {
            Log.d(TAG, "preparing MediaRecorder failed", e)
            releaseMediaRecorder()
            false
        } catch (e: IOException) {
            Log.d(TAG, "setting MediaRecorder file failed", e)
            releaseMediaRecorder()
            false
        }
    }
    return false
}

private fun releaseMediaRecorder() {
    mediaRecorder?.reset()
    mediaRecorder?.release()
    mediaRecorder = null
    camera?.lock()
}

private fun startStopVideo() {
    if (isRecording) {
        // Stop recording and release camera.
        mediaRecorder?.stop()
        releaseMediaRecorder()
        camera?.lock()
        isRecording = false

        // This is a good place to inform user that video recording has stopped.
    } else {
        // Initialize video camera.
        if (prepareVideoRecorder()) {
            // Camera is available and unlocked, MediaRecorder is prepared, now
            // you can start recording.
            mediaRecorder?.start()
            isRecording = true

            // This is a good place to inform the user that recording has
            // started.
        } else {
            // Prepare didn't work, release the camera.
            releaseMediaRecorder()

            // Inform user here.
        }
    }
}

CameraX: KameraDenetleyici

CameraX'in CameraController cihazındaki ImageCapture, VideoCapture ve ImageAnalysis UseCase bağımsız olarak Kullanım alanları listesinin eşzamanlı olarak kullanılabildiği sürece. ImageCapture ve ImageAnalysis UseCase varsayılan olarak etkindir. Bu nedenle fotoğraf çekmek için setEnabledUseCases() numaralı telefonu aramanız gerekmedi.

Video kaydı için CameraController kullanmak istiyorsanız öncelikle şunu kullanmanız gerekir: VideoCapture UseCase uygulamasına izin vermek için setEnabledUseCases().

// CameraX: Enable VideoCapture UseCase on CameraController.

cameraController.setEnabledUseCases(VIDEO_CAPTURE);

Video kaydetmeye başlamak istediğinizde CameraController.startRecording() işlevini kullanın. Bu işlev, aşağıdaki örnekte gösterildiği gibi, kaydedilen videoyu bir File klasörüne kaydedebilir: aşağıdaki örnekte görebilirsiniz. Ayrıca, bir Executor ve bir sınıfı geçmeniz gerekir. Google Analytics 4'teki OnVideoSavedCallback başarılı ve hatalı geri çağırmaları vardır. Kaydın bitmesi gerektiğinde şunu arayın: CameraController.stopRecording().

Not: CameraX 1.3.0-alpha02 veya sonraki bir sürümü kullanıyorsanız AudioConfig parametresi videonuzda ses kaydını etkinleştirmenize veya devre dışı bırakmanıza olanak tanır. Etkinleştirmek için mikrofon izinlerini aldığınızdan emin olmanız gerekir. Buna ek olarak, stopRecording() yöntemi 1.3.0-alpha02 sürümünden kaldırılmıştır ve startRecording(), duraklatma için kullanılabilecek bir Recording nesnesi döndürür, devam ettirebilir ve video kaydını durdurabilirsiniz.

// CameraX: implement video capture with CameraController.

private val FILENAME_FORMAT = "yyyy-MM-dd-HH-mm-ss-SSS"

// Define a VideoSaveCallback class for handling success and error states.
class VideoSaveCallback : OnVideoSavedCallback {
    override fun onVideoSaved(outputFileResults: OutputFileResults) {
        val msg = "Video capture succeeded: ${outputFileResults.savedUri}"
        Toast.makeText(baseContext, msg, Toast.LENGTH_SHORT).show()
        Log.d(TAG, msg)
    }

    override fun onError(videoCaptureError: Int, message: String,
                         cause: Throwable?) {
        Log.d(TAG, "error saving video: $message", cause)
    }
}

private fun startStopVideo() {
    if (cameraController.isRecording()) {
        // Stop the current recording session.
        cameraController.stopRecording()
        return
    }

    // Define the File options for saving the video.
    val name = SimpleDateFormat(FILENAME_FORMAT, Locale.US)
        .format(System.currentTimeMillis())

    val outputFileOptions = OutputFileOptions
        .Builder(File(this.filesDir, name))
        .build()

    // Call startRecording on the CameraController.
    cameraController.startRecording(
        outputFileOptions,
        ContextCompat.getMainExecutor(this),
        VideoSaveCallback()
    )
}

CameraX: CameraProvider

CameraProvider kullanıyorsanız bir VideoCapture oluşturmanız gerekir UseCase ve bir Recorder nesnesini iletin. Recorder.Builder uygulamasında şunları yapabilirsiniz: video kalitesini ayarlayın ve isteğe bağlı olarak FallbackStrategy, bir cihazın istediğiniz kalite spesifikasyonlarını karşılayamadığı durumlarda kullanılır. Sonra VideoCapture örneğini CameraProvider öğesine bağlayın ve diğer örnek UseCase sn.

// CameraX: create and bind a VideoCapture UseCase with CameraProvider.

// Make a reference to the VideoCapture UseCase and Recording at a
// scope that can be accessed throughout the camera logic in your app.
private lateinit var videoCapture: VideoCapture
private var recording: Recording? = null

...

// Create a Recorder instance to set on a VideoCapture instance (can be
// added with other UseCase definitions).
val recorder = Recorder.Builder()
    .setQualitySelector(QualitySelector.from(Quality.FHD))
    .build()
videoCapture = VideoCapture.withOutput(recorder)

...

// Bind UseCases to camera (adding videoCapture along with preview here, but
// preview is not required to use videoCapture). This function returns a camera
// object which can be used to perform operations like zoom, flash, and focus.
var camera = cameraProvider.bindToLifecycle(
    this, cameraSelector, preview, videoCapture)

Bu noktada, Recorder uygulamasına videoCapture.output üzerinden erişilebilir Recorder, File içine kaydedilen video kayıtlarını başlatabilir, ParcelFileDescriptor veya MediaStore. Bu örnekte MediaStore kullanılmıştır.

Recorder üzerinde, hazırlanmak için çağrıda bulunabilirsiniz. Telefonla arama MediaStore çıkış seçeneklerini ayarlamak için prepareRecording() tuşlarına basın. Uygulamanızda mikrofonu kullanma izni varsa withAudioEnabled() numaralı telefonu da arayın. Ardından, kayda başlamak için start() öğesini bir bağlamda ileterek ve Video kaydı etkinliklerini işlemek için Consumer<VideoRecordEvent> etkinlik işleyici. Eğer başarılı olursa döndürülen Recording, son 30 güne ait kaydediyorum.

// CameraX: implement video capture with CameraProvider.

private val FILENAME_FORMAT = "yyyy-MM-dd-HH-mm-ss-SSS"

private fun startStopVideo() {
   val videoCapture = this.videoCapture ?: return

   if (recording != null) {
       // Stop the current recording session.
       recording.stop()
       recording = null
       return
   }

   // Create and start a new recording session.
   val name = SimpleDateFormat(FILENAME_FORMAT, Locale.US)
       .format(System.currentTimeMillis())
   val contentValues = ContentValues().apply {
       put(MediaStore.MediaColumns.DISPLAY_NAME, name)
       put(MediaStore.MediaColumns.MIME_TYPE, "video/mp4")
       if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) {
           put(MediaStore.Video.Media.RELATIVE_PATH, "Movies/CameraX-Video")
       }
   }

   val mediaStoreOutputOptions = MediaStoreOutputOptions
       .Builder(contentResolver, MediaStore.Video.Media.EXTERNAL_CONTENT_URI)
       .setContentValues(contentValues)
       .build()

   recording = videoCapture.output
       .prepareRecording(this, mediaStoreOutputOptions)
       .withAudioEnabled()
       .start(ContextCompat.getMainExecutor(this)) { recordEvent ->
           when(recordEvent) {
               is VideoRecordEvent.Start -> {
                   viewBinding.videoCaptureButton.apply {
                       text = getString(R.string.stop_capture)
                       isEnabled = true
                   }
               }
               is VideoRecordEvent.Finalize -> {
                   if (!recordEvent.hasError()) {
                       val msg = "Video capture succeeded: " +
                           "${recordEvent.outputResults.outputUri}"
                       Toast.makeText(
                           baseContext, msg, Toast.LENGTH_SHORT
                       ).show()
                       Log.d(TAG, msg)
                   } else {
                       recording?.close()
                       recording = null
                       Log.e(TAG, "video capture ends with error",
                             recordEvent.error)
                   }
                   viewBinding.videoCaptureButton.apply {
                       text = getString(R.string.start_capture)
                       isEnabled = true
                   }
               }
           }
       }
}

Ek kaynaklar

Kamera Örnekleri GitHub Deposu. Bu örnekler, bu kılavuzdaki senaryoların nasıl tam kapsamlı bir Android uygulaması.

KameraX'e geçişle ilgili ek desteğe ihtiyacınız varsa veya hakkında daha fazla bilgi için lütfen KameraX Tartışması Grup.