API di gestione del buffer HAL3 della fotocamera

Android 10 introduce API opzionali 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 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 output 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ò anche essere vantaggioso 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.

Gestione del buffer in 9 o inferiore

Figura 1. Interfaccia HAL della fotocamera in Android 9 e versioni precedenti

Gestione del buffer in Android 10

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, l'HAL della telecamera deve:

L'HAL della fotocamera utilizza i metodi requestStreamBuffers e returnStreamBuffers in ICameraDeviceCallback.hal per richiedere e restituire buffer. L'HAL deve anche implementare il metodo signalStreamFlush in ICameraDeviceSession.hal per segnalare all'HAL della fotocamera di restituire i buffer.

requestStreamBuffers

Utilizza il metodo requestStreamBuffers per richiedere buffer dal framework della fotocamera. Quando si utilizzano le API di gestione del 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 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 tra richiesta e risultato. Inoltre, poiché le chiamate a requestStreamBuffers vengono 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 riesce, l'HAL della fotocamera deve essere in grado di gestire correttamente gli errori non irreversibili. Nell'elenco seguente vengono descritti i motivi comuni per cui le richieste buffer non riescono e il modo in cui devono essere gestite dall'HAL della fotocamera.

  • L'app si disconnette dal flusso di output: si tratta di un errore non irreversibile. L'HAL della telecamera dovrebbe inviare ERROR_REQUEST per qualsiasi richiesta di acquisizione destinata a un flusso disconnesso ed essere pronto a elaborare normalmente le richieste successive.
  • Timeout: ciò può verificarsi quando un'app è impegnata in un'elaborazione intensiva mentre mantiene alcuni buffer. L'HAL della telecamera dovrebbe inviare ERROR_REQUEST per le richieste di acquisizione che non possono essere soddisfatte a causa di un errore di timeout ed essere pronto a elaborare normalmente le richieste successive.
  • Il framework della fotocamera sta preparando una nuova configurazione del flusso: l'HAL della fotocamera dovrebbe attendere fino al completamento della successiva chiamata configureStreams prima di chiamare nuovamente requestStreamBuffers .
  • L'HAL della fotocamera ha raggiunto il limite del buffer (il campo maxBuffers ): l'HAL della fotocamera deve attendere finché non restituisce almeno un buffer del flusso prima di chiamare nuovamente requestStreamBuffers .

returnStreamBuffers

Utilizza il metodo returnStreamBuffers per restituire buffer aggiuntivi al framework della fotocamera. L'HAL della fotocamera normalmente restituisce i buffer al framework della fotocamera tramite il metodo processCaptureResult , ma può tenere conto solo delle richieste di acquisizione che sono state inviate all'HAL della fotocamera. Con il metodo requestStreamBuffers , è possibile che l'implementazione dell'HAL della fotocamera conservi più buffer di quanto richiesto dal framework della fotocamera. Questo è il momento in cui dovrebbe essere utilizzato il metodo returnStreamBuffers . Se l'implementazione dell'HAL non contiene mai più buffer di quanto richiesto, non è necessario che l'implementazione dell'HAL della fotocamera chiami il metodo returnStreamBuffers .

signalStreamFlush

Il metodo signalStreamFlush viene chiamato dal framework della fotocamera per notificare all'HAL della fotocamera di restituire tutti i buffer a portata di mano. Questo viene normalmente chiamato quando il framework della fotocamera sta per chiamare configureStreams e deve svuotare la pipeline di acquisizione della fotocamera. Similmente al metodo returnStreamBuffers , se l'implementazione dell'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 tutti i buffer vengono restituiti, le chiamate al metodo requestStreamBuffers falliscono e il framework della fotocamera può continuare a funzionare in uno stato pulito. Il framework della fotocamera chiama quindi il metodo configureStreams o processCaptureRequest . Se il framework della fotocamera chiama il metodo configureStreams , l'HAL della fotocamera 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 per 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 completare 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 fotocamera 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 fotocamera in un ordine diverso rispetto all'ordine in cui sono stati chiamati nel framework della fotocamera. Per risolvere questo problema di asincronia, il campo streamConfigCounter è stato aggiunto a StreamConfiguration e aggiunto come argomento al metodo signalStreamFlush . L'implementazione dell'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.

Gestire le chiamate che arrivano in ritardo

Figura 3. Come l'HAL della telecamera deve 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 fotocamera e dell'implementazione dell'HAL della fotocamera:

  • 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 fotocamera non ha più bisogno di attendere i buffer e può quindi inviare prima le richieste di acquisizione all'HAL della fotocamera.

    Inoltre, senza API di gestione del buffer, il framework della fotocamera 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 fotocamera nel file HalStream::maxBuffers nel valore restituito di una chiamata configureStreams ). Con le API di gestione del buffer, questo comportamento di limitazione non esiste più e l'implementazione dell'HAL della fotocamera non deve accettare chiamate processCaptureRequest quando l'HAL ha troppe richieste di acquisizione in coda.

  • La latenza delle chiamate requestStreamBuffers varia in modo significativo: esistono molti motivi per cui una chiamata requestStreamBuffers 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 in proporzione al numero di buffer richiesti in ciascuna chiamata.
    • L'app contiene 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 garantisce alcun risparmio di memoria, ma può fungere da 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 buffer di output solo immediatamente prima che sia necessario riempirne uno. Questa strategia consente il massimo risparmio di memoria. Il potenziale svantaggio è un ulteriore rallentamento della pipeline della fotocamera quando le richieste di buffer impiegano 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 influenzato da una richiesta occasionale di buffer lento.

L'HAL della fotocamera può adottare strategie diverse per casi d'uso particolari, ad esempio utilizzando la strategia di risparmio di memoria massimizzata per casi d'uso che utilizzano molta memoria e utilizzando la strategia di compatibilità con le versioni precedenti per altri casi d'uso.

Esempio di implementazione nell'HAL della fotocamera esterna

L'HAL della fotocamera esterna è stato introdotto in Android 9 e può essere trovato 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. Questo HAL per fotocamera esterna implementa la strategia di risparmio di memoria massimizzata menzionata in Strategie di gestione del buffer in poche centinaia di righe di codice C++.