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.
Kameralar ve kamera önizlemeleri, Android cihazlarda her zaman aynı yönde olmaz.
Kamera, cihazın telefon, tablet veya bilgisayar olmasına bakılmaksızın cihazda sabit bir konumdadır. Cihazın yönü değiştiğinde kameranın yönü de değişir.
Bu nedenle, kamera uygulamaları genellikle cihazın yönü ile kamera önizlemesinin en boy oranı arasında sabit bir ilişki olduğunu varsayar. Telefon dikey yöndeyken kamera önizlemesinin genişliğinden daha uzun olduğu varsayılır. Telefon (ve kamera) yatay konuma döndürüldüğünde kamera önizlemesinin genişliğinin yüksekliğinden fazla olması beklenir.
Ancak katlanabilir cihazlar gibi yeni form faktörleri ve çoklu pencere ile çoklu ekran gibi görüntüleme modları bu varsayımları geçersiz kılıyor. Katlanabilir cihazlar, yönü değiştirmeden ekran boyutunu ve en boy oranını değiştirir. Çoklu pencere modu, kamera uygulamalarını ekranın bir bölümüyle sınırlandırarak kamera önizlemesini cihazın yönünden bağımsız olarak ölçeklendirir. Çoklu ekran modu, birincil ekranla aynı yönde olmayabilecek ikincil ekranların kullanılmasını sağlar.
Kamera yönü
Android Uyumluluk Tanımı, kamera görüntü sensörünün "kameranın uzun boyutu ekranın uzun boyutuyla hizalanacak şekilde yönlendirilmesi GEREKTİĞİNİ" belirtir. Yani cihaz yatay yönde tutulduğunda kameralar yatay yönde görüntü yakalamalıdır. Bu, cihazın doğal yönünden bağımsız olarak geçerlidir. Yani hem yatay birincil cihazlar hem de dikey birincil cihazlar için geçerlidir."
Kameranın ekrana göre düzeni, kamera uygulamasındaki kamera vizörünün görüntüleme alanını en üst düzeye çıkarır. Ayrıca görüntü sensörleri, verilerini genellikle yatay en boy oranlarında (en yaygın olanı 4:3'tür) verir.
Kamera sensörünün doğal yönü yataydır. Şekil 1'de, ön kameranın (ekranla aynı yöne bakan kamera) sensörü, Android Uyumluluk Tanımı'na uymak için telefona göre 270 derece döndürülmüştür.
Sensör rotasyonunu uygulamalara göstermek için camera2 API'si bir SENSOR_ORIENTATION sabiti içerir. Çoğu telefon ve tablette cihaz, ön kameralar için 270 derece, arka kameralar için ise 90 derece (cihazın arkasından bakış açısı) sensör yönü bildirir. Bu, sensörün uzun kenarını cihazın uzun kenarıyla hizalar. Dizüstü bilgisayar kameraları genellikle 0 veya 180 derecelik bir sensör yönü bildirir.
Kamera görüntü sensörleri, verilerini (görüntü arabelleği) sensörün doğal yönünde (yatay) çıkardığından, kamera önizlemesinin cihazın doğal yönünde dik görünmesi için görüntü arabelleğinin SENSOR_ORIENTATION tarafından belirtilen derece kadar döndürülmesi gerekir. Ön kameralar için dönüş saat yönünün tersine, arka kameralar için ise saat yönündedir.
Örneğin, Şekil 1'deki ön kamera için kamera sensörü tarafından üretilen görüntü arabelleği şu şekilde görünür:
Önizlemenin yönünün cihazın yönüyle eşleşmesi için resmin saat yönünün tersine 270 derece döndürülmesi gerekir:
Arka kamera, önceki arabellekle aynı yönde bir görüntü arabelleği oluşturur ancak SENSOR_ORIENTATION 90 derecedir. Sonuç olarak, arabellek saat yönünde 90 derece döndürülür.
Cihaz döndürme
Cihaz döndürme, bir cihazın doğal yönünden kaç derece döndürüldüğünü gösterir. Örneğin, yatay yöndeki bir telefonun cihaz dönüşü, dönüş yönüne bağlı olarak 90 veya 270 derecedir.
Kamera önizlemesinin dik görünmesi için kamera sensörü görüntü arabelleği, cihaz dönüşüyle aynı derece (sensör yönünün derecesine ek olarak) döndürülmelidir.
Yön hesaplama
Kamera önizlemesinin doğru yönü, sensör yönünü ve cihazın dönüşünü dikkate alır.
Sensör görüntü arabelleğinin genel dönüşü aşağıdaki formül kullanılarak hesaplanabilir:
rotation = (sensorOrientationDegrees - deviceOrientationDegrees * sign + 360) % 360
Burada sign, ön kameralar için 1, arka kameralar için -1 değerini alır.
Ön kameralarda görüntü arabelleği, saat yönünün tersine (sensörün doğal yönünden) döndürülür. Arka kameralarda sensör görüntü arabelleği saat yönünde döndürülür.
deviceOrientationDegrees * sign + 360 ifadesi, arka kameralar için cihazın dönüşünü saat yönünün tersinden saat yönüne dönüştürür (örneğin, saat yönünün tersine 270 dereceyi saat yönünde 90 dereceye dönüştürür). Modulo işlemi, sonucu 360 dereceden daha az olacak şekilde ölçeklendirir (örneğin, 540 derecelik dönüşü 180 dereceye ölçeklendirir).
Farklı API'ler, cihazın dönüşünü farklı şekilde raporlar:
Display#getRotation(), cihazın saat yönünün tersine dönüşünü (kullanıcının bakış açısından) sağlar. Bu değer, önceki formüle olduğu gibi eklenir.OrientationEventListener#onOrientationChanged()cihazın saat yönünde dönüşünü (kullanıcının bakış açısından) döndürür. Önceki formülde kullanılacak değeri negatif yapın.
Ön kameralar
Şekil 4'te kamera sensörü tarafından üretilen görüntü arabelleği gösterilmektedir:
Arabellek, sensör yönüne göre ayarlanmak için saat yönünün tersine 270 derece döndürülmelidir (yukarıdaki Kamera yönü bölümüne bakın):
Ardından, cihazın dönüşünü hesaba katmak için arabellek saat yönünün tersine 90 derece daha döndürülür. Bu işlem, Şekil 4'te kamera önizlemesinin doğru yönlendirilmesini sağlar:
Kameranın sağa doğru yatay yöne çevrilmiş hali:
Görsel arabelleği:
Sensör yönüne göre ayarlanması için arabelleğin saat yönünün tersine 270 derece döndürülmesi gerekir:
Ardından, cihazın dönüşünü hesaba katmak için arabellek saat yönünün tersine 270 derece daha döndürülür:
Arka kameralar
Arka kameraların sensör yönü genellikle 90 derecedir (cihazın arkasından bakıldığında). Kamera önizlemesi yönlendirilirken sensör görüntü arabelleği, sensör dönüşü miktarı kadar saat yönünde (ön kameralarda olduğu gibi saat yönünün tersine değil) döndürülür ve ardından görüntü arabelleği, cihaz dönüşü miktarı kadar saat yönünün tersine döndürülür.
Şekil 12'de kamera sensöründen alınan görüntü arabelleği gösterilmektedir:
Arabellek, sensör yönüne göre ayarlanmak için saat yönünde 90 derece döndürülmelidir:
Ardından, cihazın dönüşünü hesaba katmak için arabellek saat yönünün tersine 270 derece döndürülür:
En boy oranı
Ekran en boy oranı, cihazın yönü değiştiğinde, katlanabilir cihazlar katlandığında ve açıldığında, çok pencereli ortamlarda pencereler yeniden boyutlandırıldığında ve uygulamalar ikincil ekranlarda açıldığında değişir.
Kamera sensörü görüntü arabelleği, kullanıcı arayüzü yönü dinamik olarak değiştiğinde (cihaz yönü değişse de değişmese de) vizör kullanıcı arayüzü öğesinin yönü ve en boy oranıyla eşleşecek şekilde yönlendirilmeli ve ölçeklendirilmelidir.
Yeni form faktörlerinde veya çok pencereli ya da çok ekranlı ortamlarda, uygulamanız kamera önizlemesinin cihazla aynı yöne (dikey veya yatay) sahip olduğunu varsayarsa önizlemeniz yanlış yönlendirilebilir, yanlış ölçeklendirilebilir veya her ikisi birden olabilir.
Şekil 16'da uygulama, cihazın saat yönünün tersine 90 derece döndürüldüğünü yanlış bir şekilde varsaymıştır. Bu nedenle uygulama, önizlemeyi aynı miktarda döndürmüştür.
Şekil 17'de uygulama, kamera önizleme kullanıcı arayüzü öğesinin yeni boyutlarına uyacak şekilde düzgün ölçeklendirilmesini sağlamak için görüntü arabelleğinin en boy oranını ayarlamadı.
Sabit yönlü kamera uygulamaları genellikle katlanabilir cihazlarda ve dizüstü bilgisayarlar gibi diğer büyük ekranlı cihazlarda sorun yaşar:
Şekil 18'de, kamera uygulamasının kullanıcı arayüzü yan duruyor çünkü uygulamanın yönü yalnızca dikey olarak kısıtlanmış. Vizör görüntüsü, kamera sensörüne göre doğru şekilde yönlendirilir.
İç içe portre modu
Çoklu pencere modunu desteklemeyen (resizeableActivity="false") ve yönünü kısıtlayan (screenOrientation="portrait" veya screenOrientation="landscape") kamera uygulamaları, kamera önizlemesini doğru şekilde yönlendirmek için büyük ekranlı cihazlarda iç içe yerleştirilmiş dikey modda yerleştirilebilir.
İçe yerleştirilmiş dikey mod, ekran en boy oranı yatay olsa bile yalnızca dikey uygulamaları dikey yönde sinemaskop (içe yerleştirme) yapar. Yalnızca yatay uygulamalar, ekran en boy oranı dikey olsa bile yatay yönde sinemaskop olarak gösterilir. Kamera görüntüsü, uygulama kullanıcı arayüzüyle hizalanacak şekilde döndürülür, kamera önizlemesinin en boy oranına uyacak şekilde kırpılır ve ardından önizlemeyi dolduracak şekilde ölçeklendirilir.
İç içe yerleştirilmiş portre modu, kamera görüntü sensörünün en boy oranı ile uygulamanın birincil etkinliğinin en boy oranı eşleşmediğinde tetiklenir.
Şekil 19'da, yalnızca dikey kamera uygulaması, kullanıcı arayüzünü dizüstü bilgisayar ekranında dikey olarak gösterecek şekilde döndürülmüştür. Dikey uygulama ile yatay ekran arasındaki en boy oranı farkı nedeniyle uygulama, sinemaskop olarak gösteriliyor. Kamera önizleme resmi, uygulamanın kullanıcı arayüzü dönüşünü (içe yerleştirilmiş dikey mod nedeniyle) telafi etmek için döndürülmüştür. Resim, dikey yöne sığacak şekilde kırpılıp ölçeklendirilerek görüş alanı küçültülmüştür.
Döndürme, kırpma, ölçeklendirme
Yatay en-boy oranına sahip bir ekranda yalnızca dikey kamera uygulaması için iç içe yerleştirilmiş portre modu çağrılır:
Uygulama, dikey yönde sinemaskop olarak gösterilir:
Kamera görüntüsü, uygulamanın yeniden yönlendirilmesine uyum sağlamak için 90 derece döndürülür:
Resim, kamera önizlemesinin en boy oranına göre kırpılır ve ardından önizlemeyi dolduracak şekilde ölçeklendirilir (görüş alanı küçültülür):
Katlanabilir cihazlarda, ekranın en boy oranı yatayken kamera sensörünün yönü dikey olabilir:
Kamera önizlemesi, sensör yönüne göre ayarlanacak şekilde döndürüldüğünden görüntü, vizörde doğru şekilde yönlendirilir ancak yalnızca dikey modda kullanılabilen uygulama yan durur.
Ek portre modu, uygulamayı ve kamera önizlemesini doğru şekilde yönlendirmek için uygulamayı yalnızca dikey yönde sinemaskop olarak göstermelidir:
API
Android 12'den (API düzeyi 31) itibaren uygulamalar, CaptureRequest sınıfının SCALER_ROTATE_AND_CROP özelliği aracılığıyla iç içe yerleştirilmiş dikey modu açıkça kontrol edebilir.
Varsayılan değer SCALER_ROTATE_AND_CROP_AUTO olup sistemin iç içe yerleştirilmiş portre modunu çağırmasını sağlar.
SCALER_ROTATE_AND_CROP_90, daha önce açıklandığı gibi iç içe yerleştirilmiş portre modunun davranışıdır.
Tüm cihazlar tüm SCALER_ROTATE_AND_CROP değerlerini desteklemez. Desteklenen değerlerin listesini görmek için CameraCharacteristics#SCALER_AVAILABLE_ROTATE_AND_CROP_MODES sayfasına bakın.
CameraX
Jetpack CameraX kitaplığı, sensör yönünü ve cihaz dönüşünü hesaba katan bir kamera vizörü oluşturmayı kolaylaştırır.
PreviewView düzen öğesi, sensör yönü, cihaz dönüşü ve ölçeklendirme için otomatik olarak ayarlanan bir kamera önizlemesi oluşturur.
PreviewView, FILL_CENTER ölçek türünü uygulayarak kamera görüntüsünün en boy oranını korur. Bu tür, görüntüyü ortalar ancak PreviewView boyutlarına uyacak şekilde kırpabilir. Kamera görüntüsünü sinemaskop yapmak için ölçek türünü FIT_CENTER olarak ayarlayın.
PreviewView ile kamera önizlemesi oluşturmanın temel bilgilerini öğrenmek için Önizleme uygulama başlıklı makaleyi inceleyin.
Eksiksiz bir örnek uygulama için GitHub'daki CameraXBasic deposuna bakın.
CameraViewfinder
Önizleme kullanım alanına benzer şekilde, CameraViewfinder kitaplığı, kamera önizlemesi oluşturmayı basitleştiren bir dizi araç sunar. CameraX Core'a bağlı olmadığı için mevcut Camera2 kod tabanınıza sorunsuz bir şekilde entegre edebilirsiniz.
Doğrudan Surface kullanmak yerine Camera2 için kamera feed'ini görüntülemek üzere CameraViewfinder widget'ını kullanabilirsiniz.
CameraViewfinder, kamera feed'ini görüntülemek için dahili olarak TextureView veya SurfaceView kullanır ve vizörü doğru şekilde görüntülemek için gerekli dönüşümleri uygular. Bu işlem, en boy oranını, ölçeği ve
döndürmeyi düzeltmeyi içerir.
CameraViewfinder nesnesinden yüzey istemek için bir ViewfinderSurfaceRequest oluşturmanız gerekir.
Bu istek, CameraCharacteristics'den yüzey çözünürlüğü ve kamera cihazı bilgileriyle ilgili şartlar içerir.
requestSurfaceAsync() çağrıldığında istek, TextureView veya SurfaceView olan yüzey sağlayıcıya gönderilir ve Surface türünde bir ListenableFuture döndürülür.
markSurfaceSafeToRelease() çağrısı, yüzey sağlayıcıya yüzeye ihtiyaç duyulmadığını ve ilgili kaynakların serbest bırakılabileceğini bildirir.
fun startCamera() {
val previewResolution = Size(width, height)
val viewfinderSurfaceRequest =
ViewfinderSurfaceRequest(previewResolution, characteristics)
val surfaceListenableFuture =
cameraViewfinder.requestSurfaceAsync(viewfinderSurfaceRequest)
Futures.addCallback(surfaceListenableFuture, object : FutureCallback<Surface> {
override fun onSuccess(surface: Surface) {
/* create a CaptureSession using this surface as usual */
}
override fun onFailure(t: Throwable) { /* something went wrong */ }
}, ContextCompat.getMainExecutor(context))
}
SurfaceView
SurfaceView, önizlemenin işlenmesi gerekmiyorsa ve animasyonlu değilse kamera önizlemesi oluşturmak için basit bir yaklaşımdır.
SurfaceView, hem sensör yönünü hem de cihazın dönüşünü hesaba katarak kamera sensörü görüntü arabelleğini ekran yönüyle eşleşecek şekilde otomatik olarak döndürür.
Ancak resim arabelleği, en boy oranı dikkate alınmadan SurfaceView boyutlarına sığacak şekilde ölçeklendirilir.
Görüntü arabelleğinin en boy oranının SurfaceView en boy oranıyla eşleştiğinden emin olmanız gerekir. Bunu, bileşenin onMeasure() yönteminde SurfaceView içeriğini ölçeklendirerek yapabilirsiniz:
(computeRelativeRotation() kaynak kodu aşağıdaki Göreceli dönüş bölümünde yer alır.)
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { val width = MeasureSpec.getSize(widthMeasureSpec) val height = MeasureSpec.getSize(heightMeasureSpec) val relativeRotation = computeRelativeRotation(characteristics, surfaceRotationDegrees) if (previewWidth > 0f && previewHeight > 0f) { /* Scale factor required to scale the preview to its original size on the x-axis. */ val scaleX = if (relativeRotation % 180 == 0) { width.toFloat() / previewWidth } else { width.toFloat() / previewHeight } /* Scale factor required to scale the preview to its original size on the y-axis. */ val scaleY = if (relativeRotation % 180 == 0) { height.toFloat() / previewHeight } else { height.toFloat() / previewWidth } /* Scale factor required to fit the preview to the SurfaceView size. */ val finalScale = min(scaleX, scaleY) setScaleX(1 / scaleX * finalScale) setScaleY(1 / scaleY * finalScale) } setMeasuredDimension(width, height) }
SurfaceView öğesini kamera önizlemesi olarak uygulama hakkında daha fazla bilgi için Kamera yönleri başlıklı makaleyi inceleyin.
TextureView
TextureView, SurfaceView kadar performanslı değildir ve daha fazla çalışma gerektirir ancak TextureView, kamera önizlemesi üzerinde maksimum kontrol sağlar.
TextureView, sensör görüntü arabelleğini sensör yönüne göre döndürür ancak cihaz döndürme veya önizleme ölçeklendirme işlemlerini gerçekleştirmez.
Ölçeklendirme ve döndürme, Matrix dönüşümünde kodlanabilir.
TextureView öğesini doğru şekilde ölçeklendirmeyi ve döndürmeyi öğrenmek için Kamera uygulamanızda yeniden boyutlandırılabilir yüzeyleri destekleme başlıklı makaleyi inceleyin.
Göreli döndürme
Kamera sensörünün göreceli dönüşü, kamera sensörü çıkışını cihaz yönüyle hizalamak için gereken dönüş miktarıdır.
Göreceli döndürme, önizleme resminin x ve y ölçeklendirme faktörlerini belirlemek için SurfaceView ve TextureView gibi bileşenler tarafından kullanılır. Ayrıca sensör görüntü arabelleğinin dönüşünü belirtmek için de kullanılır.
CameraCharacteristics ve Surface sınıfları, kamera sensörünün göreceli dönüşünün hesaplanmasını sağlar:
/** * Computes rotation required to transform the camera sensor output orientation to the * device's current orientation in degrees. * * @param characteristics The CameraCharacteristics to query for the sensor orientation. * @param surfaceRotationDegrees The current device orientation as a Surface constant. * @return Relative rotation of the camera sensor output. */ public fun computeRelativeRotation( characteristics: CameraCharacteristics, surfaceRotationDegrees: Int ): Int { val sensorOrientationDegrees = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION) ?: 0 // Reverse device orientation for back-facing cameras. val sign = if (characteristics.get(CameraCharacteristics.LENS_FACING) == CameraCharacteristics.LENS_FACING_FRONT ) 1 else -1 // Calculate desired orientation relative to camera orientation to make // the image upright relative to the device orientation. return (sensorOrientationDegrees - surfaceRotationDegrees * sign + 360) % 360 }
Pencere metrikleri
Kamera vizörünün boyutlarını belirlemek için ekran boyutu kullanılmamalıdır. Kamera uygulaması, mobil cihazlarda çoklu pencere modunda veya ChromeOS'te serbest modda ekranın bir bölümünde çalışıyor olabilir.
WindowManager#getCurrentWindowMetrics()
(API düzeyi 30'da eklenmiştir) ekranın boyutu yerine uygulama penceresinin boyutunu döndürür. Jetpack WindowManager kitaplığı yöntemleri WindowMetricsCalculator#computeCurrentWindowMetrics() ve WindowInfoTracker#currentWindowMetrics(), API düzeyi 14'e kadar geriye dönük uyumlulukla benzer destek sağlar.
180 derece döndürme
Cihazın 180 derece döndürülmesi (ör. doğal yönden ters çevrilmiş doğal yöne) onConfigurationChanged() geri çağırma işlevini tetiklemez. Bu nedenle, kamera önizlemesi ters görünebilir.
180 derecelik bir dönüşü algılamak için DisplayListener uygulayın ve onDisplayChanged() geri çağırmada Display#getRotation() çağrısıyla cihazın dönüşünü kontrol edin.
Özel kaynaklar
Android 10'dan önce, çok pencereli bir ortamda yalnızca en üstteki görünür etkinlik RESUMED durumundaydı. Sistem, hangi etkinliğin devam ettirildiğini belirtmediği için bu durum kullanıcıların kafasını karıştırıyordu.
Android 10 (API düzeyi 29) ile birlikte, görünür tüm etkinliklerin RESUMED durumunda olduğu çoklu devam ettirme özelliği kullanıma sunuldu. Görünür etkinlikler, örneğin etkinliğin üzerinde şeffaf bir etkinlik varsa veya etkinlik odaklanabilir değilse (ör. pencere içinde pencere modunda) PAUSED durumuna girebilir (Pencere içinde pencere desteği bölümüne bakın).
API düzeyi 29 veya daha yüksek bir sürümde kamera, mikrofon ya da özel veya tekil kaynak kullanan uygulamalar çoklu devam ettirmeyi desteklemelidir. Örneğin, devam ettirilen üç etkinlik kamerayı kullanmak istiyorsa bu özel kaynağa yalnızca biri erişebilir. Her etkinlik, daha yüksek öncelikli bir etkinliğin kameraya öncelikli erişiminden haberdar olmak için bir onDisconnected() geri çağırma işlevi uygulamalıdır.
Daha fazla bilgi için Çoklu devam ettirme konusuna bakın.
Ek kaynaklar
- Camera2 örneği için GitHub'daki Camera2Basic uygulamasına bakın.
- CameraX önizleme kullanım alanı hakkında bilgi edinmek için CameraX Önizleme uygulama başlıklı makaleyi inceleyin.
- CameraX kamera önizlemesi örnek uygulaması için GitHub'daki CameraXBasic deposuna bakın.
- ChromeOS'te kamera önizlemesi hakkında bilgi edinmek için Kamera yönleri başlıklı makaleyi inceleyin.
- Katlanabilir cihazlar için geliştirme hakkında bilgi edinmek isterseniz Katlanabilir cihazlar hakkında bilgi başlıklı makaleyi inceleyin.