API di gestione del buffer HAL3 della fotocamera

Android 10 introduce API di gestione dei buffer HAL3 della videocamera facoltative che ti consentono di implementare la logica di gestione dei buffer per ottenere diversi compromessi tra memoria e latenza di acquisizione nelle implementazioni HAL della videocamera.

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 buffer di output solo per le due richieste nelle fasi finali della pipeline. Sui dispositivi con Android 9 e versioni precedenti, il framework della videocamera 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 dei buffer HAL3 della fotocamera consentono di separare i buffer di output per liberare i sei set di buffer. Ciò può portare a un risparmio di centinaia di megabyte di memoria sui dispositivi di fascia alta e può essere utile anche per i dispositivi con poca memoria.

La Figura 1 mostra un diagramma dell'interfaccia HAL della videocamera 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.

Gestione del buffer in Android 9 o versioni precedenti

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 dei buffer

Implementa le API di gestione dei buffer

Per implementare le API di gestione dei buffer, l'HAL della videocamera deve:

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 buffer dal framework della videocamera. 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 i 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 numero inferiore di chiamate HIDL IPC. Tuttavia, le chiamate richiedono più tempo quando vengono richiesti più buffer contemporaneamente e ciò potrebbe influire negativamente sulla latenza totale dalla richiesta al risultato. Inoltre, poiché le chiamate a requestStreamBuffers vengono serializzate nel servizio della videocamera, è consigliabile che l'HAL della videocamera utilizzi un thread dedicato ad alta priorità per richiedere i buffer.

Se una richiesta di buffer non va a buon fine, l'HAL della fotocamera 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 vanno a buon fine e come devono essere gestite dall'HAL della fotocamera.

  • L'app si disconnette 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 pronto a elaborare normalmente le richieste successive.
  • Timeout:questo può verificarsi quando un'app è impegnata in un'elaborazione intensiva mentre 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 pronto a 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 successiva chiamata configureStreams prima di chiamare di nuovo requestStreamBuffers.
  • L'HAL della videocamera ha raggiunto il limite del buffer (il campo maxBuffers): l'HAL della videocamera deve attendere di restituire almeno un buffer dello stream prima di chiamare di nuovo requestStreamBuffers.

returnStreamBuffers

Utilizza il metodo returnStreamBuffers per restituire i buffer aggiuntivi al framework della videocamera. Normalmente, la fotocamera HAL restituisce i buffer al framework della fotocamera tramite il metodo processCaptureResult, ma può tenere conto solo delle richieste di acquisizione inviate alla fotocamera HAL. Con il metodo requestStreamBuffers, l'implementazione HAL della videocamera può conservare più buffer di quelli richiesti dal framework della videocamera. È in questi casi che conviene utilizzare il metodo returnStreamBuffers. Se l'implementazione HAL non contiene mai più buffer di quelli richiesti, l'implementazione HAL della videocamera non deve chiamare il metodo returnStreamBuffers.

signalStreamFlush

Il metodo signalStreamFlush viene chiamato dal framework della videocamera per notificare all'HAL della videocamera di restituire tutti i buffer a disposizione. Questo metodo viene normalmente chiamato quando il framework della videocamera sta per chiamare configureStreams e deve svuotare la pipeline di acquisizione della videocamera. 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 i buffer non vengono 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 il suo lavoro in uno stato pulito. Il framework della videocamera chiama quindi il metodo configureStreams o processCaptureRequest. Se il framework della videocamera chiama il metodo configureStreams, l'HAL della videocamera può iniziare a richiedere nuovamente i buffer dopo che la chiamata configureStreams viene 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 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 videocamera 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 ed è stato aggiunto 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 un esempio nella Figura 3.

Gestione delle chiamate che arrivano in ritardo

Figura 3. In che modo l'HAL della videocamera deve rilevare e gestire le chiamate signalStreamFlush che arrivano in ritardo

Modifiche al comportamento durante l'implementazione delle API di gestione del buffer

Quando utilizzi le API di gestione del buffer per implementare la logica di gestione del buffer, considera i seguenti possibili cambiamenti di comportamento della fotocamera e dell'implementazione HAL della fotocamera:

  • Le richieste di acquisizione arrivano all'HAL della videocamera più velocemente e più frequentemente:senza le API di gestione dei buffer, il framework della videocamera richiede buffer di output per ogni richiesta di acquisizione prima di inviare una richiesta di acquisizione all'HAL della videocamera. 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 videocamera 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 videocamera nel campo 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 HAL della fotocamera non deve accettare chiamate processCaptureRequest quando HAL ha troppe richieste di acquisizione in coda.

  • La latenza delle chiamate requestStreamBuffers varia in modo significativo:ci sono molti motivi per cui una chiamata requestStreamBuffers potrebbe richiedere più tempo della media. Ad esempio:

    • Per i primi buffer di un flusso appena creato, le chiamate possono richiedere più tempo perché il dispositivo deve allocare la memoria.
    • La latenza prevista aumenta in proporzione al numero di buffer richiesti in ogni chiamata.
    • L'app sta memorizzando i buffer ed è impegnata nell'elaborazione. Ciò può causare un rallentamento o un timeout delle richieste di buffer a causa di una 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 buffer per una richiesta di acquisizione durante la chiamata processCaptureRequest. Questa strategia non offre alcun risparmio di memoria, ma può fungere da prima implementazione delle API di gestione dei buffer, richiedendo pochissime modifiche al codice dell'HAL della fotocamera esistente.
  • Risparmio di memoria massimizzato:l'HAL della fotocamera richiede buffer di output immediatamente prima che sia necessario riempirne uno. Questa strategia consente di massimizzare il risparmio di memoria. Il potenziale svantaggio è un maggiore sfarfallio della pipeline della videocamera quando le richieste di buffer richiedono un tempo insolitamente lungo per essere completate.
  • Memorizzato nella cache:l'HAL della videocamera memorizza nella cache alcuni buffer in modo che sia meno probabile che venga interessato da una richiesta di buffer lenta occasionale.

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

Esempio di implementazione nell'HAL della fotocamera esterna

L'HAL della videocamera esterna è stato introdotto in Android 9 e si trova nell'albero delle origini 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 videocamera esterna implementa la strategia di risparmio di memoria massimizzato menzionata in Strategie di gestione dei buffer in poche centinaia di righe di codice C++.