Bu sayfada, CameraX'in mimarisi (yapısı, API ile çalışma, yaşam döngüleriyle çalışma ve kullanım alanlarını birleştirme dahil) ele alınmaktadır.
CameraX yapısı
Kullanım alanı adı verilen bir soyutlama aracılığıyla cihazın kamerasıyla arayüz oluşturmak için CameraX'i kullanabilirsiniz. Aşağıdaki kullanım alanları mevcuttur:
- Önizleme: Önizleme görüntülemek için bir yüzey (ör.
PreviewView) kabul eder. - Görüntü analizi: Makine öğrenimi gibi analizler için CPU'nun erişebileceği arabellekler sağlar.
- Resim yakalama: Fotoğraf çeker ve kaydeder.
- Video yakalama:
VideoCaptureile video ve ses yakalama
Kullanım alanları birleştirilebilir ve aynı anda etkin olabilir. Örneğin, bir uygulama, kullanıcının kameranın gördüğü görüntüyü önizleme kullanım alanını kullanarak görüntülemesine, fotoğraftaki kişilerin gülümseyip gülümsemediğini belirleyen bir görüntü analizi kullanım alanına sahip olmasına ve gülümsediklerinde fotoğraf çekmek için bir Resim Yakalama kullanım alanı içermesine olanak tanıyabilir.
API modeli
Kitaplıkla çalışmak için aşağıdakileri belirtirsiniz:
- Yapılandırma seçenekleriyle istenen kullanım alanı.
- Dinleyiciler ekleyerek çıkış verileriyle ne yapılacağı.
- Kullanım alanını Android Mimari Yaşam Döngüleri'ne bağlayarak kameraların ne zaman etkinleştirileceği ve ne zaman ürün verileri üretileceği gibi amaçlanan akış.
CameraX uygulaması yazmanın iki yolu vardır: CameraController (CameraX'i kullanmanın en basit yolunu istiyorsanız idealdir) veya CameraProvider (daha fazla esnekliğe ihtiyacınız varsa idealdir).
CameraController
CameraController, CameraX'in temel işlevlerinin çoğunu tek bir sınıfta sunar. Çok az kurulum kodu gerektirir ve kamera başlatma, kullanım alanı yönetimi, hedef döndürme, dokunarak odaklama, sıkıştırarak yakınlaştırma ve daha fazlasını otomatik olarak gerçekleştirir. CameraController sınıfını genişleten somut sınıf LifecycleCameraController sınıfıdır.
Kotlin
val previewView: PreviewView = viewBinding.previewView var cameraController = LifecycleCameraController(baseContext) cameraController.bindToLifecycle(this) cameraController.cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA previewView.controller = cameraController
Java
PreviewView previewView = viewBinding.previewView; LifecycleCameraController cameraController = new LifecycleCameraController(baseContext); cameraController.bindToLifecycle(this); cameraController.setCameraSelector(CameraSelector.DEFAULT_BACK_CAMERA); previewView.setController(cameraController);
CameraController için varsayılan UseCase'ler Preview, ImageCapture ve ImageAnalysis'dir. ImageCapture veya ImageAnalysis ayarını kapatmak ya da VideoCapture ayarını açmak için setEnabledUseCases() yöntemini kullanın.
CameraController ile ilgili diğer kullanım alanları için QR kodu tarayıcı örneğine veya CameraController ile ilgili temel bilgileri içeren videoya göz atın.
CameraProvider
CameraProvider kullanımı kolaydır ancak uygulama geliştirici kurulumun daha büyük bir kısmını üstlendiği için yapılandırmayı özelleştirmek için daha fazla fırsat vardır. Örneğin, çıkış görüntüsü döndürmeyi etkinleştirebilir veya çıkış görüntüsü biçimini ImageAnalysis olarak ayarlayabilirsiniz. Kamera önizlemesi için özel bir Surface da kullanabilirsiniz. Bu sayede daha fazla esneklik elde edersiniz. CameraController ile ise PreviewView kullanmanız gerekir. Mevcut Surface kodunuzu kullanmak, uygulamanızın diğer bölümlerine giriş olarak kullanılıyorsa faydalı olabilir.
Kullanım alanlarını set() yöntemlerini kullanarak yapılandırır ve build() yöntemiyle sonlandırırsınız. Her kullanım alanı nesnesi, kullanım alanına özel bir API grubu sağlar. Örneğin, Resim Yakalama kullanım alanı bir takePicture() yöntem çağrısı sağlar.
Uygulama, onResume() ve onPause() içinde belirli başlatma ve durdurma yöntem çağrıları yapmak yerine, cameraProvider.bindToLifecycle() kullanarak kameranın ilişkilendirileceği bir yaşam döngüsü belirtir.
Bu yaşam döngüsü, kamera yakalama oturumunun ne zaman yapılandırılacağını CameraX'e bildirir ve kamera durumunun yaşam döngüsü geçişlerine uygun şekilde değişmesini sağlar.
Her kullanım alanının uygulama adımları için Önizleme uygulama, Görüntüleri analiz etme, Görüntü yakalama ve Video yakalama bölümlerine bakın.
Önizleme kullanım alanı, görüntüleme için bir Surface ile etkileşim kurar. Applications
Aşağıdaki kodu kullanarak yapılandırma seçenekleriyle kullanım alanını oluşturun:
Kotlin
val preview = Preview.Builder().build() val viewFinder: PreviewView = findViewById(R.id.previewView) // The use case is bound to an Android Lifecycle with the following code val camera = cameraProvider.bindToLifecycle(lifecycleOwner, cameraSelector, preview) // PreviewView creates a surface provider and is the recommended provider preview.setSurfaceProvider(viewFinder.getSurfaceProvider())
Java
Preview preview = new Preview.Builder().build(); PreviewView viewFinder = findViewById(R.id.view_finder); // The use case is bound to an Android Lifecycle with the following code Camera camera = cameraProvider.bindToLifecycle(lifecycleOwner, cameraSelector, preview); // PreviewView creates a surface provider, using a Surface from a different // kind of view will require you to implement your own surface provider. preview.previewSurfaceProvider = viewFinder.getSurfaceProvider();
Daha fazla örnek kod için resmi CameraX örnek uygulamasına bakın.
CameraX yaşam döngüleri
CameraX, kameranın ne zaman açılacağını, ne zaman çekim oturumu oluşturulacağını ve ne zaman durdurulup kapatılacağını belirlemek için bir yaşam döngüsü gözlemler. Kullanım alanı API'leri, ilerleme durumunu izlemek için yöntem çağrıları ve geri çağırmalar sağlar.
Kullanım alanlarını birleştirme bölümünde açıklandığı gibi, bazı kullanım alanı karışımlarını tek bir yaşam döngüsüne bağlayabilirsiniz. Uygulamanızın birleştirilemeyen kullanım alanlarını desteklemesi gerektiğinde aşağıdakilerden birini yapabilirsiniz:
- Uyumlu kullanım alanlarını birden fazla parça halinde gruplandırın ve ardından parçalar arasında geçiş yapın.
- Özel bir yaşam döngüsü bileşeni oluşturup bunu kullanarak kamera yaşam döngüsünü manuel olarak kontrol etme
Görüntüleme ve kamera kullanım alanlarınızın yaşam döngüsü sahiplerini ayırırsanız (örneğin, özel bir yaşam döngüsü veya retain fragment kullanıyorsanız) ProcessCameraProvider.unbindAll() kullanarak veya her kullanım alanının bağlantısını ayrı ayrı kaldırarak tüm kullanım alanlarının CameraX ile bağlantısının kaldırıldığından emin olmanız gerekir. Alternatif olarak, kullanım alanlarını bir yaşam döngüsüne bağladığınızda CameraX'in yakalama oturumunu açıp kapatmasını ve kullanım alanlarının bağlantısını kaldırmasını sağlayabilirsiniz.
Kameranızın tüm işlevleri, AppCompatActivity veya AppCompat parçası gibi yaşam döngüsüne duyarlı tek bir bileşenin yaşam döngüsüne karşılık geliyorsa istenen tüm kullanım alanlarını bağlarken bu bileşenin yaşam döngüsünü kullanmak, yaşam döngüsüne duyarlı bileşen etkin olduğunda kamera işlevinin hazır olmasını ve aksi takdirde herhangi bir kaynak tüketmeden güvenli bir şekilde imha edilmesini sağlar.
Özel LifecycleOwner'lar
İleri düzey durumlarda, uygulamanızın CameraX oturum yaşam döngüsünü standart bir Android LifecycleOwner'e bağlamak yerine açıkça kontrol etmesini sağlamak için özel bir LifecycleOwner oluşturabilirsiniz.
Aşağıdaki kod örneğinde, basit bir özel LifecycleOwner'ın nasıl oluşturulacağı gösterilmektedir:
Kotlin
class CustomLifecycle : LifecycleOwner { private val lifecycleRegistry: LifecycleRegistry init { lifecycleRegistry = LifecycleRegistry(this); lifecycleRegistry.markState(Lifecycle.State.CREATED) } ... fun doOnResume() { lifecycleRegistry.markState(State.RESUMED) } ... override fun getLifecycle(): Lifecycle { return lifecycleRegistry } }
Java
public class CustomLifecycle implements LifecycleOwner { private LifecycleRegistry lifecycleRegistry; public CustomLifecycle() { lifecycleRegistry = new LifecycleRegistry(this); lifecycleRegistry.markState(Lifecycle.State.CREATED); } ... public void doOnResume() { lifecycleRegistry.markState(State.RESUMED); } ... public Lifecycle getLifecycle() { return lifecycleRegistry; } }
Bu LifecycleOwner kullanılarak uygulamanız, kodunda istediğiniz noktalara durum geçişleri yerleştirebilir. Bu işlevi uygulamanızda kullanma hakkında daha fazla bilgi için Özel LifecycleOwner uygulama başlıklı makaleyi inceleyin.
Eşzamanlı kullanım alanları
Kullanım alanları aynı anda çalıştırılabilir. Kullanım alanları bir yaşam döngüsüne sırayla bağlanabilir ancak tüm kullanım alanlarını CameraProcessProvider.bindToLifecycle() için tek bir çağrıyla bağlamak daha iyidir. Yapılandırma değişiklikleriyle ilgili en iyi uygulamalar hakkında daha fazla bilgi için Yapılandırma değişikliklerini işleme başlıklı makaleyi inceleyin.
Aşağıdaki kod örneğinde uygulama, oluşturulacak ve aynı anda çalıştırılacak iki kullanım alanını belirtir. Ayrıca her iki kullanım alanında kullanılacak yaşam döngüsünü de belirtir. Böylece her ikisi de yaşam döngüsüne göre başlar ve durur.
Kotlin
private lateinit var imageCapture: ImageCapture override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val cameraProviderFuture = ProcessCameraProvider.getInstance(this) cameraProviderFuture.addListener(Runnable { // Camera provider is now guaranteed to be available val cameraProvider = cameraProviderFuture.get() // Set up the preview use case to display camera preview. val preview = Preview.Builder().build() // Set up the capture use case to allow users to take photos. imageCapture = ImageCapture.Builder() .setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY) .build() // Choose the camera by requiring a lens facing val cameraSelector = CameraSelector.Builder() .requireLensFacing(CameraSelector.LENS_FACING_FRONT) .build() // Attach use cases to the camera with the same lifecycle owner val camera = cameraProvider.bindToLifecycle( this as LifecycleOwner, cameraSelector, preview, imageCapture) // Connect the preview use case to the previewView preview.setSurfaceProvider( previewView.getSurfaceProvider()) }, ContextCompat.getMainExecutor(this)) }
Java
private ImageCapture imageCapture; @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); PreviewView previewView = findViewById(R.id.previewView); ListenableFuture<ProcessCameraProvider> cameraProviderFuture = ProcessCameraProvider.getInstance(this); cameraProviderFuture.addListener(() -> { try { // Camera provider is now guaranteed to be available ProcessCameraProvider cameraProvider = cameraProviderFuture.get(); // Set up the view finder use case to display camera preview Preview preview = new Preview.Builder().build(); // Set up the capture use case to allow users to take photos imageCapture = new ImageCapture.Builder() .setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY) .build(); // Choose the camera by requiring a lens facing CameraSelector cameraSelector = new CameraSelector.Builder() .requireLensFacing(lensFacing) .build(); // Attach use cases to the camera with the same lifecycle owner Camera camera = cameraProvider.bindToLifecycle( ((LifecycleOwner) this), cameraSelector, preview, imageCapture); // Connect the preview use case to the previewView preview.setSurfaceProvider( previewView.getSurfaceProvider()); } catch (InterruptedException | ExecutionException e) { // Currently no exceptions thrown. cameraProviderFuture.get() // shouldn't block since the listener is being called, so no need to // handle InterruptedException. } }, ContextCompat.getMainExecutor(this)); }
CameraX; Preview, VideoCapture, ImageAnalysis ve ImageCapture örneklerinin her birinin aynı anda kullanılmasına olanak tanır. Ayrıca,
- Her kullanım alanı kendi başına çalışabilir. Örneğin, bir uygulama önizleme kullanmadan video kaydedebilir.
- Uzantılar etkinleştirildiğinde yalnızca
ImageCapturevePreviewkombinasyonunun çalışması garanti edilir. OEM uygulamasına bağlı olarakImageAnalysiseklemek mümkün olmayabilir. UzantılarVideoCapturekullanım alanı için etkinleştirilemez. Ayrıntılar için Uzantı referans belgesini inceleyin. - Kamera özelliklerine bağlı olarak bazı kameralar, kombinasyonu daha düşük çözünürlük modlarında destekleyebilir ancak daha yüksek çözünürlüklerde destekleyemeyebilir.
- Kamera donanım düzeyi
FULLveya daha düşük olan cihazlardaPreview,VideoCaptureveImageCaptureya daImageAnalysisbirleştirildiğinde CameraX, kameranınPRIVakışınıPreviewveVideoCaptureiçin kopyalamak zorunda kalabilir. Akış paylaşımı olarak adlandırılan bu kopyalama, bu özelliklerin aynı anda kullanılmasını sağlar ancak işlem taleplerinin artmasına neden olur. Bunun sonucunda biraz daha yüksek gecikme süresi ve daha kısa pil ömrü yaşayabilirsiniz.
Desteklenen donanım seviyesi, Camera2CameraInfo üzerinden alınabilir. Örneğin, aşağıdaki kod, varsayılan arka kameranın LEVEL_3 cihaz olup olmadığını kontrol eder:
Kotlin
@androidx.annotation.OptIn(ExperimentalCamera2Interop::class) fun isBackCameraLevel3Device(cameraProvider: ProcessCameraProvider) : Boolean { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { return CameraSelector.DEFAULT_BACK_CAMERA .filter(cameraProvider.availableCameraInfos) .firstOrNull() ?.let { Camera2CameraInfo.from(it) } ?.getCameraCharacteristic(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL) == CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_3 } return false }
Java
@androidx.annotation.OptIn(markerClass = ExperimentalCamera2Interop.class) Boolean isBackCameraLevel3Device(ProcessCameraProvider cameraProvider) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { List\<CameraInfo\> filteredCameraInfos = CameraSelector.DEFAULT_BACK_CAMERA .filter(cameraProvider.getAvailableCameraInfos()); if (!filteredCameraInfos.isEmpty()) { return Objects.equals( Camera2CameraInfo.from(filteredCameraInfos.get(0)).getCameraCharacteristic( CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL), CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_3); } } return false; }
İzinler
Uygulamanızda CAMERA izni olmalıdır. Resimleri dosyalara kaydetmek için Android 10 veya sonraki sürümlerin yüklü olduğu cihazlar hariç WRITE_EXTERNAL_STORAGE izni de gerekir.
Uygulamanızın izinlerini yapılandırma hakkında daha fazla bilgi için Uygulama İzinleri İsteme başlıklı makaleyi okuyun.
Şartlar
CameraX için aşağıdaki minimum sürüm gereksinimleri geçerlidir:
- Android API düzeyi 21
- Android Mimari Bileşenleri 1.1.1
Yaşam döngüsüne duyarlı etkinlikler için FragmentActivity veya AppCompatActivity kullanın.
Bağımlılıkları bildirme
CameraX'e bağımlılık eklemek için projenize Google Maven deposunu eklemeniz gerekir.
Projeniz için settings.gradle dosyasını açın ve google() deposunu aşağıdaki gibi ekleyin:
Modern
dependencyResolutionManagement { repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) repositories { google() mavenCentral() } }
Kotlin
dependencyResolutionManagement { repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) repositories { google() mavenCentral() } }
Android bloğunun sonuna aşağıdakileri ekleyin:
Modern
android { compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } // For Kotlin projects kotlinOptions { jvmTarget = "1.8" } }
Kotlin
android { compileOptions { sourceCompatibility = JavaVersion.VERSION_1_8 targetCompatibility = JavaVersion.VERSION_1_8 } // For Kotlin projects kotlinOptions { jvmTarget = "1.8" } }
Bir uygulamanın her modülünün build.gradle dosyasına aşağıdakileri ekleyin:
Groovy
dependencies { // CameraX core library using the camera2 implementation def camerax_version = "1.7.0-rc01" // The following line is optional, as the core library is included indirectly by camera-camera2 implementation "androidx.camera:camera-core:${camerax_version}" implementation "androidx.camera:camera-camera2:${camerax_version}" // If you want to additionally use the CameraX Lifecycle library implementation "androidx.camera:camera-lifecycle:${camerax_version}" // If you want to additionally use the CameraX VideoCapture library implementation "androidx.camera:camera-video:${camerax_version}" // If you want to additionally use the CameraX View class implementation "androidx.camera:camera-view:${camerax_version}" // If you want to additionally add CameraX ML Kit Vision Integration implementation "androidx.camera:camera-mlkit-vision:${camerax_version}" // If you want to additionally use the CameraX Extensions library implementation "androidx.camera:camera-extensions:${camerax_version}" }
Kotlin
dependencies { // CameraX core library using the camera2 implementation val camerax_version = "1.7.0-rc01" // The following line is optional, as the core library is included indirectly by camera-camera2 implementation("androidx.camera:camera-core:${camerax_version}") implementation("androidx.camera:camera-camera2:${camerax_version}") // If you want to additionally use the CameraX Lifecycle library implementation("androidx.camera:camera-lifecycle:${camerax_version}") // If you want to additionally use the CameraX VideoCapture library implementation("androidx.camera:camera-video:${camerax_version}") // If you want to additionally use the CameraX View class implementation("androidx.camera:camera-view:${camerax_version}") // If you want to additionally add CameraX ML Kit Vision Integration implementation("androidx.camera:camera-mlkit-vision:${camerax_version}") // If you want to additionally use the CameraX Extensions library implementation("androidx.camera:camera-extensions:${camerax_version}") }
Uygulamanızı bu şartlara uyacak şekilde yapılandırma hakkında daha fazla bilgi için Bağımlılıkları bildirme başlıklı makaleyi inceleyin.
CameraX'in Camera2 ile birlikte çalışabilirliği
CameraX, Camera2 üzerine kuruludur ve CameraX, Camera2 uygulamasındaki özellikleri okuma ve hatta yazma yöntemlerini gösterir. Tüm ayrıntılar için Birlikte çalışabilirlik paketi'ne bakın.
CameraX'in Camera2 özelliklerini nasıl yapılandırdığı hakkında daha fazla bilgi edinmek için Camera2CameraInfo yöntemini kullanarak temel CameraCharacteristics nesnesini okuyun. Temel Camera2 özelliklerini aşağıdaki iki yöntemden biriyle de yazabilirsiniz:
Temel
CaptureRequestüzerinde otomatik odaklama modu gibi özellikleri ayarlamanıza olanak tanıyanCamera2CameraControlkullanın.CameraX
UseCase'iCamera2Interop.Extenderile genişletin. Bu sayede, tıpkıCamera2CameraControlgibi CaptureRequest'te özellikleri ayarlayabilirsiniz. Ayrıca, kamerayı kullanım senaryonuza göre optimize etmek için akış kullanım alanını ayarlama gibi bazı ek kontroller de sağlar. Bilgi için Daha iyi performans için akış kullanım alanlarını kullanma başlıklı makaleyi inceleyin.
Aşağıdaki kod örneğinde, görüntülü görüşme için optimizasyon yapmak amacıyla akış kullanım alanları kullanılmaktadır.
Görüntülü görüşme akışı kullanım alanının kullanılabilir olup olmadığını öğrenmek için Camera2CameraInfo yöntemini kullanın. Ardından, temel akış kullanım alanını ayarlamak için Camera2Interop.Extender kullanın.
Kotlin
// Set underlying Camera2 stream use case to optimize for video calls. val videoCallStreamId = CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_CALL.toLong() // Check available CameraInfos to find the first one that supports // the video call stream use case. val frontCameraInfo = cameraProvider.getAvailableCameraInfos() .first { cameraInfo -> val isVideoCallStreamingSupported = Camera2CameraInfo.from(cameraInfo) .getCameraCharacteristic( CameraCharacteristics.SCALER_AVAILABLE_STREAM_USE_CASES )?.contains(videoCallStreamId) val isFrontFacing = (cameraInfo.getLensFacing() == CameraSelector.LENS_FACING_FRONT) (isVideoCallStreamingSupported == true) && isFrontFacing } val cameraSelector = frontCameraInfo.cameraSelector // Start with a Preview Builder. val previewBuilder = Preview.Builder() .setTargetAspectRatio(screenAspectRatio) .setTargetRotation(rotation) // Use Camera2Interop.Extender to set the video call stream use case. Camera2Interop.Extender(previewBuilder).setStreamUseCase(videoCallStreamId) // Bind the Preview UseCase and the corresponding CameraSelector. val preview = previewBuilder.build() camera = cameraProvider.bindToLifecycle(this, cameraSelector, preview)
Java
// Set underlying Camera2 stream use case to optimize for video calls. Long videoCallStreamId = CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_CALL.toLong(); // Check available CameraInfos to find the first one that supports // the video call stream use case. List<CameraInfo> cameraInfos = cameraProvider.getAvailableCameraInfos(); CameraInfo frontCameraInfo = null; for (cameraInfo in cameraInfos) { Long[] availableStreamUseCases = Camera2CameraInfo.from(cameraInfo) .getCameraCharacteristic( CameraCharacteristics.SCALER_AVAILABLE_STREAM_USE_CASES ); boolean isVideoCallStreamingSupported = Arrays.List(availableStreamUseCases) .contains(videoCallStreamId); boolean isFrontFacing = (cameraInfo.getLensFacing() == CameraSelector.LENS_FACING_FRONT); if (isVideoCallStreamingSupported && isFrontFacing) { frontCameraInfo = cameraInfo; } } if (frontCameraInfo == null) { // Handle case where video call streaming is not supported. } CameraSelector cameraSelector = frontCameraInfo.getCameraSelector(); // Start with a Preview Builder. Preview.Builder previewBuilder = Preview.Builder() .setTargetAspectRatio(screenAspectRatio) .setTargetRotation(rotation); // Use Camera2Interop.Extender to set the video call stream use case. Camera2Interop.Extender(previewBuilder).setStreamUseCase(videoCallStreamId); // Bind the Preview UseCase and the corresponding CameraSelector. Preview preview = previewBuilder.build() Camera camera = cameraProvider.bindToLifecycle(this, cameraSelector, preview)
Ek kaynaklar
CameraX hakkında daha fazla bilgi edinmek için aşağıdaki ek kaynakları inceleyin.
Codelab
Kod örneği