Android 10 introduce API di gestione del buffer HAL3 della fotocamera opzionali che consentono di implementare la logica di gestione del buffer per ottenere memoria diversa e acquisire compromessi di latenza nelle implementazioni HAL della fotocamera.
L'HAL della telecamera richiede N richieste (dove N è uguale alla profondità della pipeline ) accodate nella sua pipeline, ma spesso non richiede tutti gli N set di buffer di output contemporaneamente.
Ad esempio, l'HAL potrebbe avere otto richieste accodate nella pipeline, ma richiede solo buffer di output per le due richieste nelle ultime fasi della pipeline. Sui dispositivi che eseguono Android 9 e versioni precedenti, il framework della fotocamera alloca i buffer quando la richiesta viene accodata nell'HAL, quindi potrebbero esserci sei set di buffer nell'HAL che non sono in uso. In Android 10, le API di gestione del buffer HAL3 della fotocamera consentono il disaccoppiamento dei buffer di uscita per liberare i sei set di buffer. Ciò può portare a centinaia di megabyte di risparmio di memoria sui dispositivi di fascia alta e può essere vantaggioso anche per i dispositivi con poca memoria.
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 del buffer HAL3 della fotocamera implementate.
Figura 1. Interfaccia HAL della fotocamera in Android 9 e versioni precedenti
Figura 2. Interfaccia HAL della fotocamera in Android 10 che utilizza le API di gestione del buffer
Implementazione delle API di gestione del buffer
Per implementare le API di gestione del buffer, la telecamera HAL deve:
- Implementare HIDL
ICameraDevice@3.5
. - Imposta la chiave delle caratteristiche della fotocamera
android.info.supportedBufferManagementVersion
suHIDL_DEVICE_3_5
.
L'HAL della telecamera utilizza i metodi requestStreamBuffers
e returnStreamBuffers
in ICameraDeviceCallback.hal
per richiedere e restituire i buffer. L'HAL deve inoltre implementare il metodo signalStreamFlush
in ICameraDeviceSession.hal
per segnalare all'HAL della telecamera di restituire i buffer.
requestStreamBuffers
Usa il metodo requestStreamBuffers
per richiedere buffer dal framework della fotocamera. Quando si utilizzano le API di gestione del buffer HAL3 della telecamera, le richieste di acquisizione dal framework della telecamera non contengono buffer di output, ovvero il campo bufferId
in StreamBuffer
è 0
. Pertanto, l'HAL della telecamera deve utilizzare requestStreamBuffers
per richiedere i buffer dal framework della telecamera.
Il metodo requestStreamBuffers
consente al chiamante di richiedere più buffer da più flussi di output in una singola chiamata, consentendo un minor numero di chiamate IPC HIDL. Tuttavia, le chiamate richiedono più tempo quando vengono richiesti più buffer contemporaneamente e ciò potrebbe influire negativamente sulla latenza totale da richiesta a risultato. Inoltre, poiché le chiamate a requestStreamBuffers
vengono serializzate nel servizio fotocamera, è consigliabile che l'HAL della fotocamera utilizzi un thread dedicato ad alta priorità per richiedere i buffer.
Se una richiesta del buffer non riesce, l'HAL della telecamera deve essere in grado di gestire correttamente gli errori non fatali. L'elenco seguente descrive i motivi comuni per cui le richieste di buffer non riescono e come dovrebbero essere gestite dall'HAL della telecamera.
- L'app si disconnette dal flusso di output: questo è un errore non irreversibile. La telecamera HAL dovrebbe inviare
ERROR_REQUEST
per qualsiasi richiesta di acquisizione destinata a un flusso disconnesso ed essere pronta per elaborare normalmente le richieste successive. - Timeout: questo può verificarsi quando un'app è impegnata in un'elaborazione intensiva mentre trattiene alcuni buffer. La telecamera HAL dovrebbe 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 telecamera sta preparando una nuova configurazione del flusso: l'HAL della telecamera deve attendere fino al completamento della successiva chiamata
configureStreams
prima di chiamare nuovamenterequestStreamBuffers
. - L'HAL della telecamera ha raggiunto il limite di buffer (il campo
maxBuffers
): l'HAL della telecamera deve attendere fino a quando non restituisce almeno un buffer del flusso prima di chiamare nuovamenterequestStreamBuffers
.
returnStreamBuffers
Usa il metodo returnStreamBuffers
per restituire buffer extra al framework della fotocamera. L'HAL della telecamera normalmente restituisce i buffer al framework della telecamera tramite il metodo processCaptureResult
, ma può solo tenere conto delle richieste di acquisizione che sono state inviate all'HAL della telecamera. Con il metodo requestStreamBuffers
, è possibile che l'implementazione HAL della telecamera conservi più buffer di quanto richiesto dal framework della telecamera. Questo è il momento in cui dovrebbe essere utilizzato il metodo returnStreamBuffers
. Se l'implementazione HAL non contiene mai più buffer di quelli richiesti, l'implementazione HAL della telecamera non deve chiamare il metodo returnStreamBuffers
.
signalStreamFlush
Il metodo signalStreamFlush
viene chiamato dal framework della telecamera per notificare all'HAL della telecamera di restituire tutti i buffer disponibili. Viene normalmente chiamato quando il framework della fotocamera sta per chiamare configureStreams
e deve svuotare la pipeline di acquisizione della fotocamera. Simile al metodo returnStreamBuffers
, se un'implementazione HAL della telecamera non contiene più buffer di quelli richiesti, è possibile avere un'implementazione vuota di questo metodo.
Dopo che il framework della fotocamera ha chiamato signalStreamFlush
, il framework interrompe l'invio di nuove richieste di acquisizione all'HAL della fotocamera finché tutti i buffer non sono stati restituiti al framework della fotocamera. Quando vengono restituiti tutti i buffer, le chiamate al metodo requestStreamBuffers
non riescono e il framework della fotocamera può continuare il proprio lavoro in uno stato pulito. Il framework della telecamera chiama quindi il metodo configureStreams
o processCaptureRequest
. Se il framework della telecamera chiama il metodo configureStreams
, l'HAL della telecamera può iniziare a richiedere nuovamente i buffer dopo che la chiamata configureStreams
è stata restituita correttamente. Se il framework della fotocamera chiama il metodo processCaptureRequest
, l'HAL della fotocamera può iniziare a richiedere buffer durante la chiamata processCaptureRequest
.
La semantica è diversa per il metodo signalStreamFlush
e il metodo flush
. Quando viene chiamato il metodo flush
, l'HAL può interrompere le richieste di acquisizione in sospeso con ERROR_REQUEST
per svuotare la pipeline il prima possibile. Quando viene chiamato il metodo signalStreamFlush
, l'HAL deve terminare normalmente tutte le richieste di acquisizione in sospeso e restituire tutti i buffer al framework della fotocamera.
Un'altra differenza tra il metodo signalStreamFlush
e altri metodi è che signalStreamFlush
è un metodo HIDL unidirezionale , il che significa che il framework della telecamera potrebbe chiamare altre API di blocco 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 telecamera in un ordine diverso da quello in cui sono stati chiamati nel framework della telecamera. Per risolvere questo problema di asincronia, il campo streamConfigCounter
è stato aggiunto a StreamConfiguration
e aggiunto come argomento al metodo signalStreamFlush
. L'implementazione HAL della telecamera deve utilizzare l'argomento streamConfigCounter
per determinare se una chiamata signalStreamFlush
arriva dopo la chiamata configureStreams
corrispondente. Vedere la Figura 3 per un esempio.
Figura 3. Come la telecamera HAL dovrebbe rilevare e gestire le chiamate signalStreamFlush che arrivano in ritardo
Il comportamento cambia durante l'implementazione delle API di gestione del buffer
Quando si utilizzano le API di gestione del buffer per implementare la logica di gestione del buffer, considerare le seguenti possibili modifiche al comportamento della telecamera e dell'implementazione HAL della telecamera:
Le richieste di acquisizione arrivano all'HAL della fotocamera più velocemente e con maggiore frequenza: senza API di gestione del 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 del buffer, il framework della telecamera non deve più attendere i buffer e può quindi inviare richieste di acquisizione all'HAL della telecamera in anticipo.
Inoltre, senza API di gestione del buffer, il framework della telecamera interrompe l'invio delle richieste di acquisizione se uno dei flussi 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 telecamera nel
HalStream::maxBuffers
nel valore restituito di una chiamataconfigureStreams
). Con le API di gestione del buffer, questo comportamento di limitazione non esiste più e l'implementazione HAL della telecamera non deve accettare le chiamateprocessCaptureRequest
quando l'HAL ha troppe richieste di acquisizione in coda.La latenza delle chiamate
requestStreamBuffers
varia in modo significativo: ci sono molte ragioni per cui una chiamatarequestStreamBuffers
potrebbe richiedere più tempo della media. Per esempio:- Per i primi buffer di un flusso appena creato, le chiamate possono richiedere più tempo perché il dispositivo deve allocare memoria.
- La latenza prevista aumenta proporzionalmente al numero di buffer richiesti in ciascuna chiamata.
- L'app sta trattenendo i buffer ed è impegnata nell'elaborazione. Ciò può causare un rallentamento delle richieste di buffer o un timeout a causa della mancanza di buffer o di una CPU occupata.
Strategie di gestione del buffer
Le API di gestione del buffer consentono di implementare diversi tipi di strategie di gestione del buffer. Alcuni esempi sono:
- Compatibile con le versioni precedenti: l'HAL richiede buffer per una richiesta di acquisizione durante la chiamata
processCaptureRequest
. Questa strategia non fornisce alcun risparmio di memoria, ma può servire come prima implementazione delle API di gestione del buffer, richiedendo pochissime modifiche al codice dell'HAL della telecamera esistente. - Risparmio di memoria massimizzato: la telecamera HAL richiede solo i buffer di output immediatamente prima che sia necessario riempirne uno. Questa strategia consente il massimo risparmio di memoria. Il potenziale svantaggio è un maggiore jak della pipeline della fotocamera quando le richieste di buffer richiedono un tempo insolitamente lungo per essere completate.
- Memorizzato nella cache: l'HAL della fotocamera memorizza nella cache alcuni buffer in modo che sia meno probabile che venga influenzata da una richiesta di buffer lenta occasionale.
La fotocamera HAL può adottare strategie diverse per casi d'uso particolari, ad esempio, utilizzando la strategia di risparmio di memoria massimizzato per casi d'uso che utilizzano molta memoria e utilizzando la strategia compatibile con le versioni precedenti per altri casi d'uso.
Esempio di implementazione nella telecamera esterna HAL
La fotocamera esterna HAL è stata introdotta in Android 9 e può essere trovata nell'albero dei sorgenti in hardware/interfaces/camera/device/3.5/
. In Android 10, è stato aggiornato per includere ExternalCameraDeviceSession.cpp
, un'implementazione dell'API di gestione del buffer. Questa telecamera esterna HAL implementa la strategia di risparmio di memoria massimizzata menzionata in Strategie di gestione del buffer in poche centinaia di righe di codice C++.