Android 10 introduce API facoltative di gestione del buffer HAL3 della fotocamera che consentono di implementare la logica di gestione del buffer per ottenere diversi compromessi in termini di memoria e latenza di acquisizione nelle implementazioni HAL della fotocamera.
L'HAL della fotocamera richiede N richieste (dove N è uguale alla profondità della pipeline) in coda nella pipeline, ma spesso non richiede tutti gli N set di buffer di output contemporaneamente.
Ad esempio, l'HAL potrebbe avere otto richieste in coda nella pipeline, ma richiede solo buffer di output per le due richieste nelle ultime fasi della pipeline. Sui dispositivi con Android 9 e versioni precedenti, il framework della fotocamera alloca buffer quando la richiesta è in coda nell'HAL, quindi potrebbero essere presenti sei insiemi di buffer nell'HAL non in uso. In Android 10, le API di gestione dei buffer HAL3 della fotocamera consentono di disaccoppiare i buffer di output per liberare i sei set di buffer. Ciò può portare a un risparmio di memoria di centinaia di megabyte sui dispositivi di fascia alta, oltre a essere vantaggioso per i dispositivi con memoria ridotta.
La Figura 1 mostra un diagramma dell'interfaccia HAL della fotocamera per i dispositivi con Android 9 e versioni precedenti. La Figura 2 mostra l'interfaccia HAL della fotocamera in Android 10 con le API di gestione dei buffer HAL3 della fotocamera implementate.
Figura 1. Interfaccia HAL della fotocamera in Android 9 e versioni precedenti
Figura 2. Interfaccia della fotocamera HAL in Android 10 che utilizza le API di gestione del buffer
Implementa le API di gestione dei buffer
Per implementare le API di gestione dei buffer, l'HAL della fotocamera deve:
- Implementa l'HIDL
ICameraDevice@3.5
. - Imposta la chiave delle caratteristiche della fotocamera
android.info.supportedBufferManagementVersion
suHIDL_DEVICE_3_5
.
L'HAL della fotocamera utilizza i metodi requestStreamBuffers
e returnStreamBuffers
in ICameraDeviceCallback.hal
per richiedere e restituire i buffer. L'HAL deve anche implementare il metodo
signalStreamFlush
in
ICameraDeviceSession.hal
per segnalare all'HAL della videocamera di restituire i buffer.
requestStreamBuffers
Utilizza il metodo requestStreamBuffers
per richiedere i buffer dal framework della fotocamera. Quando utilizzi le API di gestione dei buffer HAL3 della fotocamera, le richieste di acquisizione dal framework della fotocamera non contengono buffer di output, ovvero il campo bufferId
in StreamBuffer
è 0
. Pertanto, l'HAL della fotocamera deve utilizzare requestStreamBuffers
per richiedere
buffer dal framework della fotocamera.
Il metodo requestStreamBuffers
consente all'autore della chiamata di richiedere più buffer
da più stream di output in un'unica chiamata, consentendo un numero inferiore di chiamate HIDL IPC. Tuttavia, le chiamate richiedono più tempo quando vengono richiesti più buffer contemporaneamente e questo potrebbe influire negativamente sulla latenza totale dalla richiesta al risultato.
Inoltre, poiché le chiamate a requestStreamBuffers
sono serializzate nel servizio della fotocamera, è consigliabile che l'HAL della fotocamera utilizzi un thread dedicato ad alta priorità per richiedere i buffer.
Se una richiesta di buffer non va a buon fine, l'HAL della videocamera deve essere in grado di gestire correttamente gli errori non irreversibili. L'elenco seguente descrive i motivi comuni per cui le richieste di buffer non vanno a buon fine e come devono essere gestite dall'HAL della fotocamera.
- L'app si scollega dallo stream di output:
si tratta di un errore non irreversibile. L'HAL della videocamera deve inviare
ERROR_REQUEST
per qualsiasi richiesta di acquisizione che ha come target uno stream disconnesso ed essere pronta a elaborare le richieste successive in modo normale. - Timeout:questo può verificarsi quando un'app è impegnata a eseguire
un'elaborazione intensiva e mantiene alcuni buffer. L'HAL della fotocamera deve inviare
ERROR_REQUEST
per le richieste di acquisizione che non possono essere soddisfatte a causa di un errore di timeout ed essere pronta per elaborare normalmente le richieste successive. - Il framework della videocamera sta preparando una nuova configurazione dello stream:
l'HAL della videocamera deve attendere il completamento della chiamata
configureStreams
successiva prima di chiamare di nuovorequestStreamBuffers
. - L'HAL della videocamera ha raggiunto il suo
limite di buffer
(campo
maxBuffers
): l'HAL della videocamera deve attendere fino a quando non restituisce almeno un buffer dello stream prima di chiamare nuovamenterequestStreamBuffers
.
returnStreamBuffers
Utilizza il metodo returnStreamBuffers
per restituire buffer aggiuntivi al framework della fotocamera. Normalmente, l'HAL della fotocamera restituisce i buffer al framework della fotocamera tramite il metodo processCaptureResult
, ma può tenere conto solo delle richieste di acquisizione inviate all'HAL della fotocamera. Con il metodo requestStreamBuffers
, è possibile che l'implementazione dell'HAL della fotocamera conservi più buffer di quelli richiesti dal framework della fotocamera. Questo è il momento in cui deve essere
utilizzato il metodo returnStreamBuffers
. Se l'implementazione HAL non contiene mai più buffer di quelli richiesti, l'implementazione HAL della fotocamera non deve chiamare il metodo returnStreamBuffers
.
signalStreamFlush
Il metodo signalStreamFlush
viene chiamato dal framework della videocamera per comunicare all'HAL della fotocamera di restituire tutti i buffer a disposizione. Questo metodo viene chiamato normalmente quando il framework della fotocamera sta per chiamare configureStreams
e deve svuotare la pipeline di acquisizione della fotocamera. Analogamente al metodo returnStreamBuffers
, se un'implementazione HAL della fotocamera non contiene più buffer di quelli richiesti, è possibile avere un'implementazione vuota di questo metodo.
Dopo che il framework della videocamera chiama
signalStreamFlush
,
il framework smette di inviare nuove richieste di acquisizione all'HAL della videocamera finché tutti
gli buffer non sono stati restituiti al framework della videocamera. Quando tutti i buffer vengono restituiti, le chiamate al metodo requestStreamBuffers
non vanno a buon fine e il framework della videocamera può continuare a lavorare in uno stato pulito. Il framework della videocamera chiama quindi il metodo configureStreams
o processCaptureRequest
. Se il framework della fotocamera chiama il metodo configureStreams
, l'HAL della fotocamera può iniziare di nuovo a richiedere i buffer dopo che la chiamata a configureStreams
è stata restituita. Se il framework della fotocamera chiama il metodo processCaptureRequest
,
l'HAL della fotocamera può iniziare a richiedere buffer durante la chiamataprocessCaptureRequest
.
La semantica è diversa per il metodo signalStreamFlush
e per il metodo
flush
. Quando viene chiamato il metodo flush
, l'HAL può annullare le richieste di acquisizione in attesa con ERROR_REQUEST
per svuotare la pipeline il prima possibile. Quando viene chiamato il metodo signalStreamFlush
, l'HAL deve completare normalmente tutte le richieste di acquisizione in attesa e restituire tutti i buffer al framework della fotocamera.
Un'altra differenza tra il metodo signalStreamFlush
e gli altri metodi è che signalStreamFlush
è un metodo HIDL unidirezionale, il che significa che il framework della fotocamera potrebbe chiamare altre API bloccanti prima che l'HAL riceva la chiamata signalStreamFlush
. Ciò significa che il metodo signalStreamFlush
e altri metodi (in particolare il metodo configureStreams
) potrebbero arrivare all'HAL della fotocamera in un ordine diverso rispetto a quello in cui sono stati chiamati nel framework della fotocamera. Per risolvere questo
problema di accoppiamento, il campo streamConfigCounter
è stato aggiunto a
StreamConfiguration
e come argomento al metodo signalStreamFlush
. L'implementazione dell'HAL della fotocamera deve utilizzare l'argomento streamConfigCounter
per determinare se una chiamata signalStreamFlush
arriva dopo la
chiamata configureStreams
corrispondente. Vedi la Figura 3 per un esempio.
Figura 3. In che modo l'HAL della videocamera deve rilevare e gestire le chiamate signalStreamFlush che arrivano in ritardo
Il comportamento cambia quando vengono implementate le API di gestione dei buffer
Quando utilizzi le API di gestione del buffer per implementare la logica di gestione del buffer, tieni conto delle seguenti possibili modifiche al comportamento della fotocamera e dell'implementazione dell'HAL della fotocamera:
Le richieste di acquisizione arrivano all'HAL della fotocamera più rapidamente e più spesso: senza le API di gestione dei buffer, il framework della fotocamera richiede buffer di output per ogni richiesta di acquisizione prima di inviare una richiesta di acquisizione all'HAL della fotocamera. Quando si utilizzano le API di gestione dei buffer, il framework della fotocamera non deve più attendere i buffer e può quindi inviare richieste di acquisizione all'HAL della fotocamera in precedenza.
Inoltre, senza le API di gestione dei buffer, il framework della fotocamera smette di inviare richieste di acquisizione se uno degli stream di output della richiesta di acquisizione ha raggiunto il numero massimo di buffer che l'HAL può contenere contemporaneamente (questo valore è designato dall'HAL della fotocamera nel campo
HalStream::maxBuffers
nel valore restituito di una chiamataconfigureStreams
). Con le API di gestione del buffer, questo comportamento di throttling non esiste più e l'implementazione dell'HAL della fotocamera non deve accettare chiamateprocessCaptureRequest
quando l'HAL ha troppe richieste di acquisizione in coda.La latenza di chiamata
requestStreamBuffers
varia in modo significativo:esistono molti motivi per cui una chiamatarequestStreamBuffers
potrebbe richiedere più tempo rispetto alla media. Ad esempio:- Per i primi buffer di uno stream appena creato, le chiamate possono richiedere più tempo perché il dispositivo deve allocare memoria.
- La latenza prevista aumenta in proporzione al numero di buffer richiesti in ogni chiamata.
- L'app sta trattenendo i buffer ed è in fase di elaborazione. Ciò può causare il rallentamento delle richieste di buffer o il raggiungimento di un timeout a causa della mancanza di buffer o di una CPU occupata.
Strategie di gestione del buffer
Le API di gestione dei buffer consentono di implementare diversi tipi di strategie di gestione dei buffer. Ecco alcuni esempi:
- Compatibile con le versioni precedenti: l'HAL richiede il buffer per una richiesta di acquisizione
durante la chiamata
processCaptureRequest
. Questa strategia non consente di risparmiare memoria, ma può essere utilizzata come prima implementazione delle API di gestione del buffer, richiedendo pochissime modifiche al codice dell'HAL della fotocamera esistente. - Risparmio di memoria massimizzato:l'HAL della fotocamera richiede i buffer di output solo immediatamente prima che sia necessario riempirne uno. Questa strategia consente di massimizzare il risparmio di memoria. Il potenziale svantaggio è un maggiore ritardo nella pipeline della fotocamera quando il completamento delle richieste di buffer richiede un tempo insolitamente lungo.
- Memorizzata nella cache:l'HAL della videocamera memorizza nella cache alcuni buffer in modo che sia meno probabile che venga interessata da una richiesta occasionale di buffer lento.
L'HAL della fotocamera può adottare strategie diverse per casi d'uso specifici, ad esempio utilizzare la strategia di risparmio di memoria massima per i casi d'uso che utilizzano molta memoria e la strategia di compatibilità con le versioni precedenti per altri casi d'uso.
Esempio di implementazione nella videocamera HAL esterna
L'HAL della fotocamera esterna è stato introdotto in Android 9 e si trova nella struttura ad albero delle sorgenti all'indirizzo hardware/interfaces/camera/device/3.5/
.
In Android 10 è stato aggiornato per includere
ExternalCameraDeviceSession.cpp
,
un'implementazione dell'API di gestione dei buffer. Questo HAL della fotocamera esterna implementa la strategia di risparmio di memoria massimizzata descritta in Strategie di gestione dei buffer in poche centinaia di righe di codice C++.