Not: Bu sayfa, Camera2 paketiyle ilgilidir. Uygulamanız Camera2'den belirli, alt düzey özellikler gerektirmiyorsa CameraX'i kullanmanızı öneririz. Hem CameraX hem de Camera2, Android 5.0 (API düzeyi 21) ve sonraki sürümleri destekler.
Android destekli tek bir cihazda birden fazla kamera olabilir. Her kamera bir CameraDevice'dir ve bir CameraDevice aynı anda birden fazla akış çıkışı verebilir.
Bunun bir nedeni, CameraDevice cihazından gelen ardışık kamera karelerinden oluşan bir akışın vizör görüntüleme gibi belirli bir görev için optimize edilmesi, diğerlerinin ise fotoğraf çekmek veya video kaydetmek için kullanılmasıdır. Akışlar, kameradan çıkan ham kareleri tek tek işleyen paralel ardışık düzenler olarak çalışır:
Paralel işleme, CPU, GPU veya diğer işlemcilerden gelen kullanılabilir işlem gücüne bağlı olarak performans sınırları olabileceğini gösterir. Bir ardışık düzen, gelen karelere yetişemezse kareleri bırakmaya başlar.
Her ardışık düzenin kendi çıkış biçimi vardır. Gelen ham veriler, her ardışık düzenle ilişkili örtük mantıkla otomatik olarak uygun çıkış biçimine dönüştürülür. Bu sayfanın kod örneklerinde kullanılan CameraDevice, belirli bir kameraya ait değildir. Bu nedenle, devam etmeden önce mevcut tüm kameraları numaralandırmanız gerekir.
CameraDevice kullanarak söz konusu CameraDevice için özel bir CameraCaptureSession oluşturabilirsiniz. CameraDevice, CameraCaptureSession kullanarak her ham kare için bir kare yapılandırması almalıdır. Yapılandırma; otomatik odaklama, diyafram açıklığı, efektler ve pozlama gibi kamera özelliklerini belirtir. Donanım kısıtlamaları nedeniyle, kamera sensöründe herhangi bir zamanda yalnızca tek bir yapılandırma etkin olur. Buna etkin yapılandırma denir.
Ancak akış kullanım alanları, yakalama oturumlarını yayınlamak için önceki CameraDevice kullanım yöntemlerini geliştirip genişletir. Bu sayede kamera görüntü akışını kendi kullanım alanınıza göre optimize edebilirsiniz. Örneğin, görüntülü görüşmeleri optimize ederken pil ömrünü uzatabilir.
CameraCaptureSession, CameraDevice ile ilişkili tüm olası ardışık düzenleri açıklar. Oturum oluşturulduktan sonra ardışık düzen ekleyemez veya kaldıramazsınız.
CameraCaptureSession, etkin yapılandırma haline gelen CaptureRequest'lerin sırasını korur.
CaptureRequest, sıraya bir yapılandırma ekler ve CameraDevice üzerinden kare almak için mevcut ardışık düzenlerden birini, birden fazlasını veya tümünü seçer. Bir yakalama oturumu süresince çok sayıda yakalama isteği gönderebilirsiniz. Her istek, etkin yapılandırmayı ve ham görüntüyü alan çıkış ardışık düzenleri grubunu değiştirebilir.
Daha iyi performans için Stream kullanım alanlarını kullanma
Akış kullanım alanları, Camera2 yakalama oturumlarının performansını artırmanın bir yoludur. Donanım cihazına parametreleri ayarlamak için daha fazla bilgi vererek belirli göreviniz için daha iyi bir kamera deneyimi sunarlar.
Bu sayede kamera cihazı, her akış için kullanıcı senaryolarına göre kamera donanımını ve yazılım ardışık düzenlerini optimize edebilir. Akış kullanım alanları hakkında daha fazla bilgi için setStreamUseCase adresini ziyaret edin.
Akış Kullanım Alanları, CameraDevice.createCaptureRequest() içinde bir şablon ayarlamanın yanı sıra belirli bir kamera görüntü akışının nasıl kullanıldığını daha ayrıntılı bir şekilde belirtmenize olanak tanır. Bu sayede kamera donanımı, belirli kullanım alanlarına uygun kalite veya gecikme dengelerine göre ayarlama, sensör modu ya da kamera sensörü ayarları gibi parametreleri optimize edebilir.
Akış kullanım alanları şunlardır:
DEFAULT: Mevcut tüm uygulama davranışlarını kapsar. Bu, herhangi bir akış kullanım alanı ayarlamamaya eşdeğerdir.PREVIEW: Vizör veya uygulama içi resim analizi için önerilir.STILL_CAPTURE: Yüksek kaliteli, yüksek çözünürlüklü çekim için optimize edilmiştir ve önizleme benzeri kare hızlarını koruması beklenmez.VIDEO_RECORD: Cihaz tarafından destekleniyorsa ve uygulama tarafından etkinleştirilmişse yüksek kaliteli görüntü sabitleme dahil olmak üzere yüksek kaliteli video çekimi için optimize edilmiştir. Bu seçenek, en yüksek kalitede sabitleme veya diğer işlemlere olanak tanımak için gerçek zamanlı olarak önemli bir gecikmeyle çıkış kareleri üretebilir.VIDEO_CALL: Güç tüketiminin sorun olduğu uzun süreli kamera kullanımları için önerilir.PREVIEW_VIDEO_STILL: Sosyal medya uygulamaları veya tek akış kullanım alanları için önerilir. Çok amaçlı bir akıştır.VENDOR_START: OEM tarafından tanımlanan kullanım alanları için kullanılır.
CameraCaptureSession oluşturma
Kamera oturumu oluşturmak için uygulamanızın çıkış karelerini yazabileceği bir veya daha fazla çıkış arabelleği sağlayın. Her arabellek bir ardışık düzeni temsil eder. Çerçevenin, cihazın dahili ardışık düzenlerini yapılandırabilmesi ve kareleri gerekli çıkış hedeflerine göndermek için bellek arabellekleri ayırabilmesi amacıyla kamerayı kullanmaya başlamadan önce bu işlemi yapmanız gerekir.
Aşağıdaki kod snippet'inde, biri SurfaceView, diğeri ise ImageReader'a ait iki çıkış arabelleği içeren bir kamera oturumunu nasıl hazırlayabileceğiniz gösterilmektedir. previewSurface için PREVIEW akış kullanım alanını ve imReaderSurface için STILL_CAPTURE akış kullanım alanını eklemek, cihaz donanımının bu akışları daha da optimize etmesini sağlar.
// Retrieve the target surfaces, which might be coming from a number of places: // 1. SurfaceView, if you want to display the image directly to the user // 2. ImageReader, if you want to read each frame or perform frame-by-frame // analysis // 3. OpenGL Texture or TextureView, although discouraged for maintainability // reasons // 4. RenderScript.Allocation, if you want to do parallel processing val surfaceView = findViewById<SurfaceView>( // ... ) val imageReader = ImageReader.newInstance( // ... ) // Remember to call this only *after* SurfaceHolder.Callback.surfaceCreated(). val previewSurface = surfaceView.holder.surface val imReaderSurface = imageReader.surface val targets = listOf(previewSurface, imReaderSurface) // Create a capture session using the predefined targets; this also involves // defining the session state callback to be notified of when the session is // ready. // Setup Stream Use Case while setting up your Output Configuration. @RequiresApi(Build.VERSION_CODES.TIRAMISU) fun configureSession(device: CameraDevice, targets: List<Surface>) { val configs = mutableListOf<OutputConfiguration>() val streamUseCase = CameraMetadata .SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW_VIDEO_STILL targets.forEach { val config = OutputConfiguration(it) config.streamUseCase = streamUseCase.toLong() configs.add(config) } // ... device.createCaptureSession(session) }
Bu noktada, kameranın etkin yapılandırmasını tanımlamadınız. Oturum yapılandırıldıktan sonra, yakalama istekleri oluşturup göndererek bu işlemi gerçekleştirebilirsiniz.
Girişler arabelleklerine yazılırken uygulanan dönüşüm, her bir hedefin türüne göre belirlenir. Bu tür, Surface olmalıdır. Android çerçevesi, etkin yapılandırmadaki ham görüntüyü her hedef için uygun bir biçime nasıl dönüştüreceğini bilir. Dönüşüm, belirli bir Surface öğesinin piksel biçimi ve boyutu tarafından kontrol edilir.
Çerçeve elinden gelenin en iyisini yapmaya çalışır ancak bazı Surface yapılandırma kombinasyonları çalışmayabilir. Bu durum, oturumun oluşturulmaması, istek gönderdiğinizde çalışma zamanı hatası oluşması veya performansın düşmesi gibi sorunlara neden olabilir. Çerçeve; cihaz, yüzey ve istek parametrelerinin belirli kombinasyonları için garanti sağlar. createCaptureSession() ile ilgili belgelerde daha fazla bilgi bulabilirsiniz.
Tekli CaptureRequest'ler
Her kare için kullanılan yapılandırma, kameraya gönderilen bir CaptureRequest içinde kodlanır. Yakalama isteği oluşturmak için önceden tanımlanmış şablonlardan birini kullanabilir veya tam kontrol için TEMPLATE_MANUAL kullanabilirsiniz. Bir şablon seçtiğinizde istekle birlikte kullanılacak bir veya daha fazla çıkış arabelleği sağlamanız gerekir. Yalnızca kullanmak istediğiniz yakalama oturumunda önceden tanımlanmış arabellekleri kullanabilirsiniz.
Yakalama istekleri, oluşturucu kalıbı kullanır ve geliştiricilere otomatik pozlama, otomatik odaklama ve lens diyafram açıklığı gibi birçok farklı seçeneği ayarlama imkanı sunar. Bir alanı ayarlamadan önce CameraCharacteristics.getAvailableCaptureRequestKeys() yöntemini çağırarak ilgili seçeneğin cihazda kullanılabildiğinden ve kullanılabilir otomatik pozlama modları gibi uygun kamera özelliklerini kontrol ederek seçilen değerin desteklendiğinden emin olun.
SurfaceView için önizleme amacıyla tasarlanmış şablonu kullanarak herhangi bir değişiklik yapmadan yakalama isteği oluşturmak istiyorsanız CameraDevice.TEMPLATE_PREVIEW komutunu kullanın:
val session: CameraCaptureSession = /* ... */ // from CameraCaptureSession.StateCallback val captureRequest = session.device.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW) captureRequest.addTarget(previewSurface)
Yakalama isteği tanımlandıktan sonra bunu kamera oturumuna gönderebilirsiniz:
val session: CameraCaptureSession = ... // from CameraCaptureSession.StateCallback val captureRequest: CaptureRequest.Builder = ... // from CameraDevice.createCaptureRequest() // The first null argument corresponds to the capture callback, which you // provide if you want to retrieve frame metadata or keep track of failed capture // requests that can indicate dropped frames; the second null argument // corresponds to the Handler used by the asynchronous callback, which falls // back to the current thread's looper if null. session.capture(captureRequest.build(), null, null)
Belirli bir arabelleğe çıkış karesi yerleştirildiğinde yakalama geri çağırma işlevi tetiklenir. Çoğu durumda, içerdiği kare işlendiğinde ImageReader.OnImageAvailableListener gibi ek geri çağırmalar tetiklenir. Bu noktada, belirtilen arabellekten görüntü verilerini alabilirsiniz.
CaptureRequest'leri tekrarlama
Tek kamera isteklerini yapmak kolaydır ancak canlı önizleme veya video görüntülemek için pek kullanışlı değildir. Bu durumda, tek bir kare değil, sürekli bir kare akışı almanız gerekir. Aşağıdaki kod snippet'i, oturuma yinelenen istek eklemeyi gösterir:
val session: CameraCaptureSession = ... // from CameraCaptureSession.StateCallback val captureRequest: CaptureRequest.Builder = ... // from CameraDevice.createCaptureRequest() // This keeps sending the capture request as frequently as possible until // the session is torn down or session.stopRepeating() is called. session.setRepeatingRequest(captureRequest.build(), null, null)
Yinelenen bir yakalama isteği, kamera cihazının sağlanan CaptureRequest içindeki ayarları kullanarak sürekli olarak görüntü yakalamasını sağlar. Camera2 API, kullanıcıların GitHub'daki bu Camera2 örnek deposunda görüldüğü gibi yinelenen CaptureRequests göndererek kameradan video çekmesine de olanak tanır. Ayrıca, GitHub'daki Camera2 ağır çekim video örnek uygulamasında gösterildiği gibi, tekrarlanan seri çekim CaptureRequests kullanarak yüksek hızlı (ağır çekim) video çekerek ağır çekim video oluşturabilir.
CaptureRequest'leri aralıklı olarak gönderme
Tekrarlanan yakalama isteği etkinken ikinci bir yakalama isteği göndermek için (ör. vizör görüntülemek ve kullanıcıların fotoğraf çekmesine izin vermek) devam eden tekrarlanan isteği durdurmanız gerekmez. Bunun yerine, tekrarlanan istek çalışmaya devam ederken tekrarlanmayan bir yakalama isteği gönderirsiniz.
Kullanılan tüm çıkış arabellekleri, oturum ilk oluşturulduğunda kamera oturumunun bir parçası olarak yapılandırılmalıdır. Tekrarlanan istekler, tek kare veya seri çekim isteklerinden daha düşük önceliğe sahiptir. Bu sayede aşağıdaki örnek çalışır:
val session: CameraCaptureSession = /* ... */ // from CameraCaptureSession.StateCallback // Create the repeating request and dispatch it. val repeatingRequest = session.device.createCaptureRequest( CameraDevice.TEMPLATE_PREVIEW ) repeatingRequest.addTarget(previewSurface) session.setRepeatingRequest(repeatingRequest.build(), null, null) // Some time later... // Create the single request and dispatch it. // NOTE: This can disrupt the ongoing repeating request momentarily. val singleRequest = session.device.createCaptureRequest( CameraDevice.TEMPLATE_STILL_CAPTURE ) singleRequest.addTarget(imReaderSurface) session.capture(singleRequest.build(), null, null)
Ancak bu yaklaşımın bir dezavantajı vardır: Tek isteğin tam olarak ne zaman gerçekleştiğini bilemezsiniz. Aşağıdaki şekilde, A tekrarlanan yakalama isteği ve B tek kare yakalama isteği ise oturum, istek sırasını şu şekilde işler:
B isteği etkinleştirilmeden önce A'dan gelen son yinelenen istek ile A'nın tekrar kullanılacağı bir sonraki sefer arasındaki gecikme için herhangi bir garanti yoktur. Bu nedenle, bazı kareler atlanabilir. Bu sorunu azaltmak için yapabileceğiniz bazı şeyler vardır:
A isteğindeki çıkış hedeflerini B isteğine ekleyin. Böylece B'nin karesi hazır olduğunda A'nın çıkış hedeflerine kopyalanır. Örneğin, sabit bir kare hızı sağlamak için video anlık görüntüleri alırken bu çok önemlidir. Önceki kodda, isteği oluşturmadan önce
singleRequest.addTarget(previewSurface)eklediniz.Sıfır deklanşör gecikmesi gibi bu senaryoya uygun olarak tasarlanmış şablonların bir kombinasyonunu kullanın.