L'API Media Enhancement fornisce una soluzione di AI a bassa latenza, che tutela la privacy e viene eseguita sul dispositivo. Sfrutta l'accelerazione hardware per offrire miglioramenti multimediali di alta qualità senza appesantire l'APK. Per saperne di più, consulta Informazioni sulle funzionalità di miglioramento dei contenuti multimediali.
La modalità Bitmap statico (EnhancementMode.BITMAP) è progettata per l'elaborazione di immagini statiche decodificate.
Il funzionamento in modalità Bitmap richiede al sistema operativo di serializzare i dati dei pixel non compressi e copiarli dalla memoria della CPU attraverso il bus di sistema alla memoria della GPU, restituendo il frame elaborato tramite una copia inversa. È ottimizzato per l'esecuzione di un singolo frame e non è compatibile con lo streaming video in tempo reale.
Questo flusso di lavoro prevede la creazione di una sessione, l'elaborazione di una singola bitmap e la gestione del risultato. Gli esempi di codice delle sezioni precedenti trattano in dettaglio questo caso d'uso.
- Configura le opzioni: crea un oggetto
EnhancementOptions, assicurandoti cheenhancementModesia impostato suEnhancementMode.BITMAP. - Crea sessione: utilizza il wrapper
createSessionAsyncdefinito in precedenza per creare unEnhancementSession. Si tratta di un oggetto pesante, quindi crealo solo quando necessario. - Elabora immagine: chiama la sessione, la bitmap di input e le opzioni che vuoi.
- Gestisci risultato: la funzione di sospensione restituisce una nuova bitmap migliorata in caso di esito positivo o genera un'eccezione in caso di errore.
- Rilascia sessione: è fondamentale chiamare
session.release()al termine per liberare le risorse GPU.
EnhancementSession è un oggetto di contesto pesante che mantiene una
pipeline di memoria GPU o NPU persistente. Alloca RAM video (VRAM) dedicata
e handle di sistema nativi. Per evitare gravi perdite di memoria e potenziali
OutOfMemoryError arresti anomali, rispetta i seguenti principi del ciclo di vita:
- Istanziazione differita: non creare una sessione finché l'utente non avvia un'azione di miglioramento.
- Riutilizzo strategico: mantieni e riutilizza una singola istanza di sessione durante l'elaborazione di più immagini con configurazioni identiche (dimensioni e opzioni attivate/disattivate).
- Smontaggio del prompt: richiama
session.release()immediatamente quando le attività visive terminano per liberare le risorse hardware condivise.
Inizializzare il motore di miglioramento
Questo metodo orchestra un controllo in due passaggi. Verifica se l'hardware del dispositivo supporta l'accelerazione e poi si assicura che siano presenti i moduli di machine learning richiesti.
L'esecuzione di questo passaggio preliminare impedisce errori di inizializzazione in fase di runtime convalidando le funzionalità prima che l'app tenti di elaborare i contenuti multimediali.
class MediaSetupViewModel(application: Application) : AndroidViewModel(application) {
private val enhancementClient = Enhancement.getClient(application)
fun initializeEnhancementEngine() {
viewModelScope.launch {
try {
// 1. Verify hardware capability
val isSupported = enhancementClient.isDeviceSupportedAsync()
if (!isSupported) {
notifyUiDeviceIncompatible()
return@launch
}
// 2. Verify and download the Google Play services ML modules
val isInstalled = enhancementClient.isModuleInstalledAsync()
if (!isInstalled) {
notifyUiDownloadingModels()
enhancementClient.installModule().await()
}
notifyUiEngineReady()
} catch (e: Exception) {
// Handle potential errors during session creation or image processing.
handleInitializationError(e)
}
}
}
}
Crea wrapper di sessione e di processo bitmap
Utilizza questi wrapper di coroutine Kotlin per convertire i callback client basati su attività in funzioni di sospensione standard, consentendo un'esecuzione più pulita e sequenziale.
// Wraps the task-based createSession callback into a suspending function.
suspend fun EnhancementClient.createSessionAsync(
options: EnhancementOptions,
executor: Executor
): EnhancementSession = withContext(Dispatchers.Main) {
suspendCancellableCoroutine { continuation ->
// EnhancementSessionCallback handles session success or failure.
val callback = object : EnhancementSessionCallback {
override fun onSessionCreated(session: EnhancementSession) {
continuation.resume(session)
}
override fun onSessionCreationFailed(status: Status) {
continuation.resumeWithException(
Exception("Session creation failed: ${status.statusMessage} (${status.statusCode})")
)
}
override fun onSessionDestroyed() {}
override fun onSessionDisconnected(status: Status) {}
}
// Handles errors during the initial request trigger.
this.createSession(options, callback).addOnFailureListener(executor) { e ->
if (continuation.isActive) {
continuation.resumeWithException(e)
}
}
}
}
// Wraps this process in a suspending function for cleaner execution.
suspend fun EnhancementSession.processBitmapAsync(
bitmap: Bitmap,
options: EnhancementOptions
): Bitmap = suspendCancellableCoroutine { continuation ->
// EnhancementCallback returns the processed bitmap or an error code.
val callback = object : EnhancementCallback {
override fun onBitmapProcessed(enhancedBitmap: Bitmap) {
continuation.resume(enhancedBitmap)
}
override fun onError(statusCode: Int) {
continuation.resumeWithException(
Exception("Bitmap processing failed with status code: $statusCode")
)
}
override fun onSurfaceProcessed(timestamp: Long) {}
}
this.process(bitmap, options, callback)
}
Esegui la pipeline bitmap in un ViewModel
Per integrare la pipeline di miglioramento nell'architettura dell'applicazione, utilizza un
ViewModel per gestire il ciclo di vita della sessione. Questo approccio garantisce che le
risorse GPU pesanti vengano rilasciate quando ViewModel viene cancellato.
// Define a data class to hold image information.
data class ImageInfo(val bitmap: Bitmap)
// Define a UI state class to hold loading status, errors, and enhanced image.
data class EnhancementUiState(
val isLoading: Boolean = false,
val enhancementError: String? = null,
val enhancedImage: ImageInfo? = null
)
class EnhancementViewModel(application: Application) : AndroidViewModel(application) {
// Backing field for UI state, initialized with default values.
private val _uiState = MutableStateFlow(EnhancementUiState())
// Publicly exposed UI state flow for observation.
val uiState: StateFlow<EnhancementUiState> = _uiState.asStateFlow()
// Initialize client to interact with the Media Enhancement service.
private val enhancementClient: EnhancementClient = Enhancement.getClient(application)
// Single-thread executor for processing background enhancement tasks.
private val enhancementExecutor = Executors.newSingleThreadExecutor()
// Track session state to enable reuse across multiple processing calls.
private var enhancementSession: EnhancementSession? = null
// Primary function to trigger the enhancement workflow for a provided bitmap.
fun enhanceImage(bitmap: Bitmap) {
viewModelScope.launch(Dispatchers.IO) {
_uiState.update { it.copy(isLoading = true, enhancementError = null) }
try {
// 1. Establish the session lazily on demand
// Define enhancement options (for example, enable upscale, tonemapping) based
// on bitmap dimensions.
if (enhancementSession == null) {
val options = EnhancementOptions(
bitmap.width,
bitmap.height,
EnhancementMode.BITMAP,
enableTonemap = true,
enableDeblurDenoise = true,
enableDenoiseOnly = false,
enableUpscale = false,
)
enhancementSession = enhancementClient.createSessionAsync(options, enhancementExecutor)
}
val session = enhancementSession ?: throw IllegalStateException("Session unavailable.")
// 2. Dispatch image through the neural pipeline
val enhancedBitmap = session.processBitmapAsync(bitmap, session.defaultOptions)
// 3. Render output to UI
_uiState.update {
it.copy(enhancedImage = ImageInfo(bitmap = enhancedBitmap))
}
} catch (e: Exception) {
_uiState.update { it.copy(enhancementError = e.message) }
} finally {
// Ensure loading state is reset regardless of the outcome.
_uiState.update { it.copy(isLoading = false) }
}
}
}
override fun onCleared() {
// 4. Critical: Release native GPU hardware resources
enhancementSession?.release()
enhancementSession = null
enhancementExecutor.shutdown()
super.onCleared()
}
}