Not: Bu sayfa, Kamera2 paketiyle ilgilidir. Uygulamanız Camera2'nin belirli, alt düzey özelliklerini gerektirmiyorsa KameraX'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 CameraDevice
şeklindedir ve CameraDevice
aynı anda birden fazla yayın çıkışı yapabilir.
Bunu yapmanın bir nedeni, CameraDevice
kaynağından gelen ardışık kamera kareleri olan bir akışın belirli bir görev (ör. vizör görüntülemek) için optimize edilmesidir. Diğerleri ise fotoğraf çekmek veya video kaydı yapmak için kullanılabilir. Akışlar, her defasında bir kare olmak üzere kameradan çıkan ham kareleri işleyen paralel ardışık düzenler olarak çalışır:
![](https://developer.android.com/static/images/training/camera/camera2/capture-sessions-requests-1.png?authuser=5&hl=tr)
Paralel işleme, CPU, GPU veya başka bir işlemciden gelen mevcut 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 bunları atmaya başlar.
Her ardışık düzenin kendi çıkış biçimi vardır. Gelen ham veriler, her bir ardışık düzenle ilişkilendirilen dolaylı mantık tarafından otomatik olarak uygun çıkış biçimine dönüştürülür. Bu sayfanın kod örneklerinde kullanılan CameraDevice
spesifik değildir. Bu nedenle, devam etmeden önce mevcut tüm kameraları numaralandırmanız gerekir.
Söz konusu CameraDevice
öğesine özgü bir CameraCaptureSession
oluşturmak için CameraDevice
öğesini kullanabilirsiniz. CameraDevice
, CameraCaptureSession
kullanan her ham kare için bir çerçeve 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, herhangi bir zamanda kamera sensöründe yalnızca tek bir yapılandırma aktif olur. Buna etkin yapılandırma denir.
Ancak akış kullanım alanları, çekim oturumlarını canlı yayınlamak için CameraDevice
kullanmanın önceki yollarını iyileştirir ve genişletir. Bu sayede, kamera akışını belirli kullanım alanınıza göre optimize edebilirsiniz. Örneğin, görüntülü görüşmeleri optimize ederken
pil ömrünü iyileştirebilir.
CameraCaptureSession
, CameraDevice
öğesine bağlı tüm olası ardışık düzenleri açıklar. Bir oturum oluşturulduğunda, ardışık düzenler ekleyemez veya kaldıramazsınız.
CameraCaptureSession
, CaptureRequest
'lerden oluşan bir sıra tutar ve bunlar etkin yapılandırma haline gelir.
CaptureRequest
, sıraya bir yapılandırma ekler ve CameraDevice
ürününden çerçeve alması için mevcut ardışık düzenlerden birini, birkaçını veya tümünü seçer. Bir yakalama oturumunun süresi boyunca ç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 kümesini değiştirebilir.
Daha iyi performans için Akış Kullanım Alanları'nı kullanın
Akış Kullanım Alanları, Camera2 yakalama oturumlarının performansını iyileştirmenin bir yoludur. Bunlar, parametreleri ayarlamak için donanım cihazına daha fazla bilgi verir. Böylece, belirli bir görev için daha iyi bir kamera deneyimi sağlanır.
Bu sayede kamera cihazı, her bir akış için kullanıcı senaryolarına göre kamera donanımı ve yazılım ardışık düzenlerini optimize edebilir. Akış Kullanım Alanları hakkında daha fazla bilgi için bkz. setStreamUseCase
.
Akış Kullanım Alanları, CameraDevice.createCaptureRequest()
içinde bir şablon ayarlamaya ek olarak belirli bir kamera akışının nasıl kullanıldığını daha ayrıntılı olarak belirtmenizi sağlar. Bu sayede kamera donanımı, belirli kullanım alanlarına uygun kalite veya gecikme değerlerine göre ince ayar, sensör modu veya kamera sensörü ayarları gibi parametreleri optimize edebilir.
Akış kullanım alanları aşağıdakileri içerir:
DEFAULT
: Mevcut tüm uygulama davranışını kapsar. Herhangi bir Akış Kullanım Alanı ayarlamamakla 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ın korunması beklenmiyor.VIDEO_RECORD
: Cihaz tarafından destekleniyor ve uygulama tarafından etkinleştirildiyse yüksek kaliteli görüntü sabitleme dahil olmak üzere yüksek kaliteli video çekimleri için optimize edilmiştir. Bu seçenek, en yüksek kalitede sabitleme veya diğer işleme sağlamak için gerçek zamanlıdan önemli bir gecikmeli çıkış kareleri üretebilir.VIDEO_CALL
: Güç kaybının sorunlu 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. Bu çok amaçlı bir akış.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ış karesi yazabileceği bir veya daha fazla çıkış arabelleği sağlayın. Her tampon bir ardışık düzeni temsil eder. Bunu kamerayı kullanmaya başlamadan önce yapmanız gerekir. Böylece çerçeve, cihazın dahili ardışık düzenlerini yapılandırabilir ve kareleri gereken çıkış hedeflerine göndermek için bellek arabellekleri ayırabilir.
Aşağıdaki kod snippet'inde, biri SurfaceView
ve diğeri ImageReader
'e ait olan iki çıkış arabelleğiyle nasıl bir kamera oturumu hazırlayabileceğiniz gösterilmektedir. previewSurface
için PREVIEW
Akış Kullanım Alanı ve
STILL_CAPTURE
Akış Kullanım Alanı'nın imReaderSurface
içine eklenmesi, cihaz donanımının bu akışları daha da
iyi optimize etmesine olanak tanır.
Kotlin
// 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) }
Java
// 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. RenderScript.Allocation, if you want to do parallel processing // 4. OpenGL Texture or TextureView, although discouraged for maintainability reasons Surface surfaceView = findViewById<SurfaceView>(...); ImageReader imageReader = ImageReader.newInstance(...); // Remember to call this only *after* SurfaceHolder.Callback.surfaceCreated() Surface previewSurface = surfaceView.getHolder().getSurface(); Surface imageSurface = imageReader.getSurface(); List<Surface> targets = Arrays.asList(previewSurface, imageSurface); // 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 private void configureSession(CameraDevice device, List<Surface> targets){ ArrayList<OutputConfiguration> configs= new ArrayList() String streamUseCase= CameraMetadata .SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW_VIDEO_STILL for(Surface s : targets){ OutputConfiguration config = new OutputConfiguration(s) config.setStreamUseCase(String.toLong(streamUseCase)) configs.add(config) } device.createCaptureSession(session) }
Bu noktada, kameranın etkin yapılandırmasını tanımlamadınız. Oturum yapılandırıldığında, bunu yapmak için yakalama istekleri oluşturup gönderebilirsiniz.
Tamponlarına yazılırken girişlere uygulanan dönüşüm, her bir hedefin türüne göre belirlenir. Bu değer bir Surface
olmalıdır. Android çerçevesi, etkin yapılandırmadaki ham bir görüntüyü her bir hedefe uygun bir biçime nasıl dönüştüreceğini bilir. Dönüştürme, belirli Surface
öğesinin piksel biçimi ve boyutu ile 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ı, bir isteği gönderdiğinizde çalışma zamanı hatasının verilmesi veya performansın düşmesi gibi sorunlara neden olabilir. Bu çerçeve belirli cihaz, yüzey ve istek parametrelerinin kombinasyonları için garantiler sağlar. createCaptureSession()
dokümanlarında daha fazla bilgi bulabilirsiniz.
Tek Yakalama İstekleri
Her kare için kullanılan yapılandırma, kameraya gönderilen bir CaptureRequest
olarak kodlanır. Yakalama isteği oluşturmak için önceden tanımlanmış şablonlardan birini veya tam kontrol için TEMPLATE_MANUAL
kullanabilirsiniz. Şablon seçtiğinizde istekle birlikte kullanılacak bir veya daha fazla çıkış arabelleği sağlamanız gerekir. Yalnızca kullanmayı düşündüğünüz yakalama oturumunda tanımlanmış arabellekleri kullanabilirsiniz.
Yakalama istekleri oluşturucu kalıbı kullanır ve geliştiricilere otomatik pozlama, otomatik odaklama ve lens diyafram dahil olmak üzere birçok farklı seçeneği ayarlama fırsatı sunar.
Alan ayarlamadan önce, CameraCharacteristics.getAvailableCaptureRequestKeys()
numaralı telefonu arayarak belirli bir seçeneğin kullanılabilir olduğundan ve kullanılabilir otomatik pozlama modları gibi uygun kamera özelliklerini kontrol ederek istenilen değerin desteklendiğinden emin olun.
Önizleme amacıyla tasarlanan şablonu, herhangi bir değişiklik yapmadan SurfaceView
için yakalama isteği oluşturmak istiyorsanız CameraDevice.TEMPLATE_PREVIEW
işlevini kullanın:
Kotlin
val session: CameraCaptureSession = ... // from CameraCaptureSession.StateCallback val captureRequest = session.device.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW) captureRequest.addTarget(previewSurface)
Java
CameraCaptureSession session = ...; // from CameraCaptureSession.StateCallback CaptureRequest.Builder captureRequest = session.getDevice().createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); captureRequest.addTarget(previewSurface);
Yakalama isteği tanımlandıktan sonra bu isteği kamera oturumuna gönderebilirsiniz:
Kotlin
val session: CameraCaptureSession = ... // from CameraCaptureSession.StateCallback val captureRequest: CaptureRequest = ... // 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)
Java
CameraCaptureSession session = ...; // from CameraCaptureSession.StateCallback CaptureRequest captureRequest = ...; // 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);
Çıkış çerçevesi belirli bir arabelleğe yerleştirildiğinde, yakalama geri çağırma tetiklenir. Çoğu durumda, içerdiği çerçeve işlendiğinde ImageReader.OnImageAvailableListener
gibi ek geri çağırmalar tetiklenir. Bu noktada, resim verilerini belirtilen arabelleğin içinden alabilirsiniz.
Yinelenen Yakalama İstekleri
Tek kamera istekleri basit bir şekilde yapılabilir, ancak canlı önizleme veya video görüntülemek için pek faydalı olmaz. Bu durumda, yalnızca bir kare değil, sürekli bir kare akışı almanız gerekir. Aşağıdaki kod snippet'inde oturuma tekrarlanan isteğin nasıl ekleneceği gösterilmektedir:
Kotlin
val session: CameraCaptureSession = ... // from CameraCaptureSession.StateCallback val captureRequest: CaptureRequest = ... // 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)
Java
CameraCaptureSession session = ...; // from CameraCaptureSession.StateCallback CaptureRequest captureRequest = ...; // 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);
Tekrarlanan çekim 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 Kamera2 örnek deposunda gösterildiği gibi yinelenen CaptureRequests
göndererek kameradan video çekmesini de sağlar. GitHub'daki Kamera2 ağır çekim video örnek uygulamasında gösterildiği gibi, tekrar eden seri çekim CaptureRequests
özelliğini kullanarak yüksek hızlı (yavaş çekim) videolar çekerek de ağır çekim video oluşturabilir.
Aralık Yakalama İstekleri
Tekrarlanan çekim isteği etkinken ikinci bir çekim isteği göndermek (ör. vizör görüntülemek ve kullanıcıların fotoğraf çekmesine izin vermek) için yinelenen isteği durdurmanız gerekmez. Bunun yerine, tekrarlanan istek çalışmaya devam ederken tekrarlanmayan bir yakalama isteği gönderirsiniz.
Kullanılan çıkış arabelleği, oturum ilk oluşturulduğunda kamera oturumunun bir parçası olarak yapılandırılmalıdır. Tekrarlanan istekler, tek kare veya seri isteklerden daha düşük önceliğe sahiptir, bu da aşağıdaki örneğin çalışmasını sağlar:
Kotlin
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)
Java
CameraCaptureSession session = ...; // from CameraCaptureSession.StateCallback // Create the repeating request and dispatch it CaptureRequest.Builder repeatingRequest = session.getDevice().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 CaptureRequest.Builder singleRequest = session.getDevice().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ğiyse oturum istek sırasını şu şekilde işler:
![](https://developer.android.com/static/images/training/camera/camera2/capture-sessions-requests-2.png?authuser=5&hl=tr)
A isteği etkinleştirilmeden önce A'dan gelen son istek ile A'nın tekrar kullanılması arasındaki gecikmenin garantisi yoktur. Bu nedenle bazı kare atlamalarıyla karşılaşabilirsiniz. Bu sorunu azaltmak için yapabileceğiniz bazı şeyler vardır:
A isteğindeki çıkış hedeflerini B isteğine ekleyin. Bu şekilde, B'nin çerçevesi hazır olduğunda A'nın çıkış hedeflerine kopyalanır. Örneğin, video anlık görüntülerini çekerken sabit bir kare hızı sağlamak için bu gereklidir. Önceki kodda, isteği oluşturmadan önce
singleRequest.addTarget(previewSurface)
eklersiniz.Bu özel senaryoda çalışmak üzere tasarlanmış, sıfır gecikme süresi gibi şablonların bir kombinasyonunu kullanın.