Nota: questa pagina si riferisce al pacchetto Camera2. A meno che la tua app non richieda funzionalità specifiche di basso livello di Camera2, ti consigliamo di usare CameraX. Sia CameraX che Camera2 supportano Android 5.0 (livello API 21) e versioni successive.
Le fotocamere e le relative anteprime non hanno sempre lo stesso orientamento su Android dispositivi mobili.
Una videocamera è in una posizione fissa su un dispositivo, anche se quest'ultimo è un telefono, un tablet o un computer. Quando cambia l'orientamento del dispositivo, cambia l'orientamento della fotocamera.
Di conseguenza, le app della fotocamera di solito assumono una relazione fissa tra l'orientamento del dispositivo e le proporzioni dell'anteprima della fotocamera. Quando il telefono è in orientamento verticale, si presume che l'anteprima della fotocamera sia più alta piuttosto che largo. Quando lo smartphone e la fotocamera sono ruotati in orizzontale, il l'anteprima della fotocamera deve essere più larga dell'altezza.
Tuttavia, questi presupposti sono messi in discussione da nuovi fattori di forma, come foldable dispositivi mobili e modalità di visualizzazione come multi-finestra e multidisplay. I dispositivi pieghevoli cambiano le dimensioni del display e le proporzioni senza cambiare orientamento. La modalità multi-finestra vincola le app della fotocamera a una parte della schermo, ridimensionando l'anteprima della fotocamera indipendentemente dall'orientamento del dispositivo. La modalità multi-display consente di usare display secondari che potrebbero non nello stesso orientamento del display principale.
Orientamento della fotocamera
La Definizione di compatibilità Android specifica che il sensore fotografico di una fotocamera "DEVE essere orientato in modo tale che il della fotocamera si allinea alla dimensione lunga dello schermo. Ovvero, quando il dispositivo è tenuto in orientamento orizzontale, le videocamere DEVONO acquisire immagini in l'orientamento orizzontale. Ciò si applica a prescindere dalle impostazioni orientamento; vale a dire ai dispositivi principali per orientamento orizzontale e dispositivi principali con orientamento verticale".
La disposizione dalla fotocamera allo schermo ingrandisce l'area di visualizzazione della videocamera mirino in un'app Fotocamera. Inoltre, i sensori immagine in genere inviano i loro dati proporzioni orizzontali, 4:3 è il formato più comune.
L'orientamento naturale del sensore della fotocamera è orizzontale. Nella Figura 1, il sensore della fotocamera anteriore (quella che punta nella stessa direzione del display) sia ruotato di 270 gradi rispetto allo smartphone per rispettare le Definizione di compatibilità Android.
Per esporre la rotazione del sensore alle app,
L'API camera2 include una
SENSOR_ORIENTATION
:
costante. Per la maggior parte degli smartphone e dei tablet, il dispositivo segnala l'orientamento del sensore
di 270 gradi per le fotocamere anteriori e di 90 gradi (punto di vista dal
retro del dispositivo) per le fotocamere posteriori, allineando il bordo lungo
sensore con il bordo lungo del dispositivo. Le fotocamere dei laptop di solito segnalano
orientato del sensore di 0 o 180 gradi.
Poiché i sensori immagine della fotocamera emettono i propri dati (un buffer di immagine)
orientamento naturale (orizzontale) del sensore, il buffer di immagine deve essere ruotato
numero di gradi specificato da SENSOR_ORIENTATION
per l'anteprima della fotocamera
vengono visualizzati in verticale
nell'orientamento naturale del dispositivo. Per le fotocamere anteriori,
la rotazione è in senso antiorario; per le fotocamere posteriori, in senso orario.
Ad esempio, per la fotocamera anteriore nella figura 1, il buffer prodotto dal sensore della fotocamera ha il seguente aspetto:
L'immagine deve essere ruotata di 270 gradi in senso antiorario per visualizzare l'anteprima l'orientamento corrisponde a quello del dispositivo:
Una fotocamera posteriore produrrebbe un buffer di immagine con lo stesso orientamento
come il buffer sopra, ma SENSOR_ORIENTATION
è 90 gradi. Di conseguenza,
il buffer viene ruotato di 90 gradi in senso orario.
Rotazione del dispositivo
La rotazione del dispositivo è il numero di gradi in cui un dispositivo viene ruotato rispetto alla sua naturalezza orientamento. Ad esempio, un telefono con orientamento orizzontale ha un rotazione di 90 o 270 gradi, a seconda del senso di rotazione.
Un buffer d'immagine del sensore della fotocamera deve essere ruotato dello stesso numero di gradi del la rotazione del dispositivo (oltre ai gradi di orientamento del sensore) per dell'anteprima della fotocamera in verticale.
Calcolo dell'orientamento
Il corretto orientamento dell'anteprima della fotocamera prende in considerazione il sensore l'orientamento e la rotazione del dispositivo.
La rotazione complessiva del buffer di immagine del sensore può essere calcolata utilizzando seguente formula:
rotation = (sensorOrientationDegrees - deviceOrientationDegrees * sign + 360) % 360
dove sign
è 1
per le fotocamere anteriori e -1
per le fotocamere posteriori.
Per le fotocamere anteriori, il buffer di immagine viene ruotato in senso antiorario (da l'orientamento naturale del sensore). Per le fotocamere posteriori, il sensore buffer di immagine ruotato in senso orario.
L'espressione deviceOrientationDegrees * sign + 360
converte la rotazione dei dispositivi
da antiorario a senso orario per le fotocamere posteriori (ad esempio,
conversione di 270 gradi in senso antiorario a 90 gradi in senso orario). Il modulo
scala il risultato a meno di 360 gradi (ad esempio, scalando 540
gradi di rotazione a 180).
API diverse registrano la rotazione dei dispositivi in modo diverso:
Display#getRotation()
fornisce la rotazione antioraria del dispositivo (dal punto dell'utente di vista). Questo valore si collega così com'è alla formula precedente.OrientationEventListener#onOrientationChanged()
restituisce la rotazione in senso orario del dispositivo (dal punto di vista dell'utente). Annulla il valore da utilizzare nella formula riportata sopra.
Fotocamere anteriori
Ecco il buffer di immagine prodotto dal sensore della fotocamera nella Figura 2:
Il buffer deve essere ruotato di 270 gradi in senso antiorario per regolare il sensore orientamento (vedi Orientamento fotocamera sopra):
Quindi il tampone viene ruotato di altri 90 gradi in senso antiorario per tiene conto della rotazione del dispositivo, determinando il corretto orientamento anteprima della fotocamera nella figura 2:
Ecco la fotocamera girata a destra per passare all'orientamento orizzontale:
Ecco il buffer dell'immagine:
Il buffer deve essere ruotato di 270 gradi in senso antiorario per regolare il sensore orientamento:
Quindi il buffer viene ruotato di altri 270 gradi in senso antiorario per tenere conto la rotazione del dispositivo:
Fotocamere posteriori
Le fotocamere posteriori in genere hanno un orientamento del sensore di 90 gradi (come visto dal retro del dispositivo). Quando orienta l'anteprima della fotocamera, il valore il buffer di immagine del sensore viene ruotato in senso orario della quantità di rotazione del sensore (anziché in senso antiorario come le fotocamere anteriori), quindi l'immagine il buffer viene ruotato in senso antiorario per lo stesso numero di rotazione del dispositivo.
Ecco il buffer di immagine del sensore della fotocamera nella Figura 4:
Il buffer deve essere ruotato di 90 gradi in senso orario per regolarlo in base al sensore orientamento:
Quindi il buffer viene ruotato di 270 gradi in senso antiorario per tenere conto del dispositivo rotazione:
Proporzioni
Le proporzioni del display cambiano anche quando cambia l'orientamento del dispositivo i pieghevoli si piegano e si aprono quando le finestre vengono ridimensionate in modalità multi-finestra ambienti e quando le app si aprono su display secondari.
Il buffer d'immagine del sensore della fotocamera deve essere orientato e scalato in modo da corrispondere orientamento e proporzioni dell'elemento UI del mirino come UI cambia l'orientamento in modo dinamico, con o senza cambio di dispositivo orientamento.
In nuovi fattori di forma o in ambienti multi-finestra o multi-display, se l'app presuppone che l'anteprima della fotocamera abbia lo stesso orientamento del dispositivo (orizzontale o verticale) l'anteprima potrebbe essere orientata o ridimensionata in modo errato in modo errato, o entrambe le cose.
Nella figura 5, l'applicazione ha ipotizzato erroneamente che il dispositivo fosse ruotato di 90 gradi gradi in senso antiorario; per cui l'app ha ruotato l'anteprima dello stesso numero.
Nella Figura 6, l'app non ha regolato le proporzioni del buffer di immagine per consente di ridimensionarla in modo adeguato alle nuove dimensioni dell'interfaccia utente di anteprima della fotocamera .
Le app della fotocamera con orientamento fisso di solito riscontrano problemi sui pieghevoli e Altri dispositivi con schermi di grandi dimensioni, come i laptop:
Nella Figura 7, l'UI dell'app Fotocamera è ruotata perché l'orientamento dell'app è limitato solo alla modalità verticale. L'immagine del mirino è orientata correttamente rispetto al sensore della fotocamera.
Inserisci la modalità Ritratto
App fotocamera che non supportano la modalità multi-finestra
(resizeableActivity="false"
)
e limitarne l'orientamento
(screenOrientation="portrait"
)
o screenOrientation="landscape"
)
può essere attivata in modalità Ritratto sui dispositivi con schermi grandi per orientarsi correttamente
l'anteprima della fotocamera.
Inserimento di app solo con orientamento verticale in modalità verticale anche se le proporzioni del display sono orizzontali. Le app solo in orizzontale hanno un formato letterbox con orientamento orizzontale anche se le proporzioni del display sono verticali. L'immagine della fotocamera viene ruotata per allinearla con l'interfaccia utente dell'app, ritagliata per adattarla alle proporzioni dell'anteprima della fotocamera e e ridimensionato per riempire l'anteprima.
La modalità Ritratto inserita viene attivata quando le proporzioni dell'immagine della fotocamera tra il sensore e le proporzioni dell'attività principale dell'applicazione non corrispondono.
Nella Figura 8, l'app della fotocamera solo verticale è stata ruotata per visualizzare l'UI in posizione verticale sul display del laptop. L'app è in formato letterbox a causa della differenza di proporzioni tra l'app verticale e la visualizzazione orizzontale. La fotocamera l'immagine di anteprima è stata ruotata per compensare la rotazione dell'interfaccia utente dell'app (a causa inserisci la modalità Ritratto) e l'immagine è stata ritagliata e ridimensionata per adattarsi verticale, per ridurre il campo visivo.
Ruota, ritaglia, ridimensiona
La modalità Ritratto inserita viene attivata per un'app della fotocamera solo verticale su un display con proporzioni orizzontali:
L'app ha un letterbox con orientamento verticale:
L'immagine della fotocamera viene ruotata di 90 gradi per regolare il riorientamento della dell'app:
L'immagine viene ritagliata in base alle proporzioni dell'anteprima della fotocamera, quindi ridimensionata a riempi l'anteprima (il campo visivo è ridotto):
Sui dispositivi pieghevoli, l'orientamento del sensore della fotocamera può essere verticale mentre le proporzioni del display sono orizzontali:
Poiché l'anteprima della fotocamera viene ruotata per regolare l'orientamento del sensore, l'immagine sia orientata correttamente nel mirino, mentre l'app solo Ritratto è ruotata.
La modalità Ritratto inserita richiede l'inserimento dell'app in formato Lettera solo con orientamento verticale per orientare correttamente l'anteprima dell'app e della fotocamera:
API
A partire da Android 12 (livello API 31) le app possono anche controllare esplicitamente il formato verticale
mediante
SCALER_ROTATE_AND_CROP
proprietà del CaptureRequest
.
Il valore predefinito è
SCALER_ROTATE_AND_CROP_AUTO
,
che consente al sistema di richiamare la modalità verticale integrata.
SCALER_ROTATE_AND_CROP_90
è il comportamento del riquadro in modalità Ritratto, come descritto sopra.
Non tutti i dispositivi supportano tutti i valori SCALER_ROTATE_AND_CROP
. Per ottenere un elenco
dei valori supportati,
CameraCharacteristics#SCALER_AVAILABLE_ROTATE_AND_CROP_MODES
FotocameraX
La raccolta Jetpack CameraX consente di creare un mirino della fotocamera che si adatti all'orientamento del sensore la rotazione dei dispositivi è un'attività semplice.
L'elemento di layout PreviewView
crea un'anteprima della fotocamera, regolando
automaticamente l'orientamento del sensore,
la rotazione e il ridimensionamento dei dispositivi. PreviewView
mantiene le proporzioni del
dell'immagine della fotocamera
FILL_CENTER
tipo di scala, che centra l'immagine, ma potrebbe ritagliarla per farla corrispondere alle dimensioni
di PreviewView
. Per modificare l'immagine della fotocamera in modalità letterbox, imposta il tipo di scala su
FIT_CENTER
Per apprendere le nozioni di base sulla creazione di un'anteprima della fotocamera con PreviewView
, consulta
Implementa un'anteprima.
Per un'implementazione di esempio completa, consulta
CameraXBasic
su GitHub.
Mirino per fotocamera
Analogamente al caso d'uso dell'Anteprima, il CameraViewfinder offre una serie di strumenti per semplificare la creazione di un'anteprima della fotocamera. Non dipende da CameraX Core, quindi puoi integrarlo perfettamente nel tuo il codebase Camera2 esistente.
Invece di utilizzare
Surface
puoi utilizzare
CameraViewfinder
per visualizzare il feed videocamera per Camera2.
CameraViewfinder
utilizza internamente TextureView
o SurfaceView
per visualizzare il feed della videocamera e applica su di esse le trasformazioni richieste
visualizzare correttamente il mirino.
Ciò comporta la correzione di proporzioni, scala e rotazione.
Per richiedere la piattaforma dall'oggetto CameraViewfinder
, devi:
crea un ViewfinderSurfaceRequest
.
Questa richiesta contiene i requisiti relativi alla risoluzione della superficie e al dispositivo della fotocamera
informazioni da CameraCharacteristics
.
Chiamata a requestSurfaceAsync()
in corso...
invia la richiesta al fornitore di Surface, che è un TextureView
o
SurfaceView
e riceve ListenableFuture
di Surface
.
Chiamata a markSurfaceSafeToRelease()
in corso...
comunica al fornitore della piattaforma che la piattaforma non è necessaria e correlata
possono essere svincolate.
Kotlin
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)) }
Java
void startCamera(){ Size previewResolution = new Size(width, height); ViewfinderSurfaceRequest viewfinderSurfaceRequest = new ViewfinderSurfaceRequest(previewResolution, characteristics); ListenableFuture<Surface> surfaceListenableFuture = cameraViewfinder.requestSurfaceAsync(viewfinderSurfaceRequest); Futures.addCallback(surfaceListenableFuture, new FutureCallback<Surface>() { @Override public void onSuccess(Surface result) { /* create a CaptureSession using this surface as usual */ } @Override public void onFailure(Throwable t) { /* something went wrong */} }, ContextCompat.getMainExecutor(context)); }
Visualizzazione di superficie
SurfaceView
è un
approccio diretto alla creazione dell'anteprima della fotocamera se quest'ultima non
richiedono l'elaborazione e non sono animati.
SurfaceView
ruota automaticamente il buffer d'immagine del sensore della fotocamera per adattarlo
l'orientamento del display, tenendo conto sia dell'orientamento del sensore che del dispositivo
la rotazione. Tuttavia, il buffer di immagine viene ridimensionato per adattarsi a SurfaceView
dimensioni senza alcuna considerazione
delle proporzioni.
Devi assicurarti che le proporzioni del buffer di immagine corrispondano
di SurfaceView
, che puoi ottenere scalando i contenuti
di SurfaceView
nella classe
onMeasure()
:
(il codice sorgente di computeRelativeRotation()
è in
Rotazione relativa di seguito.
Kotlin
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) }
Java
@Override void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int width = MeasureSpec.getSize(widthMeasureSpec); int height = MeasureSpec.getSize(heightMeasureSpec); int relativeRotation = computeRelativeRotation(characteristics, surfaceRotationDegrees); if (previewWidth > 0f && previewHeight > 0f) { /* Scale factor required to scale the preview to its original size on the x-axis. */ float scaleX = (relativeRotation % 180 == 0) ? (float) width / previewWidth : (float) width / previewHeight; /* Scale factor required to scale the preview to its original size on the y-axis. */ float scaleY = (relativeRotation % 180 == 0) ? (float) height / previewHeight : (float) height / previewWidth; /* Scale factor required to fit the preview to the SurfaceView size. */ float finalScale = Math.min(scaleX, scaleY); setScaleX(1 / scaleX * finalScale); setScaleY(1 / scaleY * finalScale); } setMeasuredDimension(width, height); }
Per ulteriori dettagli sull'implementazione di SurfaceView
come anteprima della fotocamera, consulta
Orientamenti fotocamera.
Visualizzazione texture
TextureView
ha prestazioni inferiori
SurfaceView
—e altro ancora, ma TextureView
offre il massimo
controllo dell'anteprima della fotocamera.
TextureView
ruota il buffer d'immagine del sensore in base all'orientamento, ma
non gestisce la rotazione del dispositivo o il ridimensionamento dell'anteprima.
La scalabilità e la rotazione possono essere codificate
Trasformazione della matrice. Per scoprire come
scalare e ruotare correttamente un TextureView
, consulta
Supportare le superfici ridimensionabili nell'app Fotocamera
Rotazione relativa
La rotazione relativa del sensore della videocamera è il tempo di rotazione necessario per allinea l'output del sensore della fotocamera all'orientamento del dispositivo.
La rotazione relativa viene utilizzata da componenti quali SurfaceView
e TextureView
per determinare i fattori di ridimensionamento x e y per l'immagine di anteprima. È utilizzata anche per
specificare la rotazione del buffer immagine del sensore.
La
CameraCharacteristics
e
Le classi Surface
consentono il calcolo
Rotazione relativa del sensore della videocamera:
Kotlin
/** * 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)!! // 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 }
Java
/** * 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 int computeRelativeRotation( CameraCharacteristics characteristics, int surfaceRotationDegrees ){ Integer sensorOrientationDegrees = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION); // Reverse device orientation for back-facing cameras. int sign = characteristics.get(CameraCharacteristics.LENS_FACING) == CameraCharacteristics.LENS_FACING_FRONT ? 1 : -1; // Calculate desired orientation relative to camera orientation to make // the image upright relative to the device orientation. return (sensorOrientationDegrees - surfaceRotationDegrees * sign + 360) % 360; }
Metriche finestra
Le dimensioni dello schermo non devono essere utilizzate per determinare le dimensioni della fotocamera mirino; l'app Fotocamera potrebbe essere in esecuzione in una parte dello schermo in modalità multi-finestra sui dispositivi mobili o in modalità libero su ChromeOS.
WindowManager#getCurrentWindowMetrics()
(aggiunto nel livello API 30) restituisce la dimensione della finestra dell'applicazione anziché
le dimensioni dello schermo. Metodi della libreria Jetpack WindowManager
WindowMetricsCalculator#computeCurrentWindowMetrics()
e
WindowInfoTracker#currentWindowMetrics()
offrono un supporto simile, con compatibilità con le versioni precedenti al livello API 14.
Rotazione: 180°
Una rotazione di 180 gradi di un dispositivo (ad esempio, dall'orientamento naturale a
l'orientamento naturale al contrario) non attiva
onConfigurationChanged()
di Google. Di conseguenza, l'anteprima della fotocamera potrebbe essere capovolta.
Per rilevare una rotazione di 180 gradi, implementa una
DisplayListener
e controlla la rotazione del dispositivo con una chiamata
Display#getRotation()
nel
onDisplayChanged()
di Google.
Risorse esclusive
Prima di Android 10, solo l'attività più in alto visibile in una modalità multi-finestra
era nello stato RESUMED
. Questo non era chiaro per gli utenti perché
il sistema non ha fornito alcuna indicazione di quale attività è stata ripresa.
Android 10 (livello API 29) ha introdotto il ripristino multiplo in cui tutte le attività visibili
sono nello stato RESUMED
. Le attività visibili possono comunque accedere all'PAUSED
ad esempio se, ad esempio, un'attività trasparente si trova sopra l'attività o
non sia possibile mettere a fuoco l'attività, ad esempio in modalità Picture in picture (vedi
supporto di Picture in picture).
Un'applicazione che utilizza la fotocamera, il microfono o qualsiasi altra funzione
la risorsa singleton con livello API 29 o successivo deve supportare la ripresa multipla. Per
Ad esempio, se vuoi usare la fotocamera per tre attività riprese, solo una potrà
per accedere a questa risorsa esclusiva. Ogni attività deve implementare un
onDisconnected()
per essere a conoscenza dell'accesso preventivo alla videocamera da una priorità più elevata
attività.
Per ulteriori informazioni, vedi Riprendi multipli.
Risorse aggiuntive
- Per un esempio di Camera2, vedi l'app Camera2Basic su GitHub.
- Per informazioni sul caso d'uso dell'anteprima di CameraX, consulta CameraX Implementa un'anteprima.
- Per un esempio di implementazione dell'anteprima di una fotocamera CameraX, consulta FotocameraXBasic su GitHub.
- Per informazioni sull'anteprima della fotocamera su ChromeOS, consulta Orientamenti fotocamera.
- Per informazioni sullo sviluppo di dispositivi pieghevoli, vedi Informazioni sui pieghevoli.