Die Media Enhancement API bietet eine datenschutzfreundliche KI-Lösung auf dem Gerät mit niedriger Latenz, die Hardwarebeschleunigung nutzt, um hochwertige Medienverbesserungen ohne APK-Bloat zu ermöglichen. Weitere Informationen zu den Funktionen zur Medienoptimierung
Das folgende Architekturdiagramm zeigt den asynchronen Oberflächenmodus-Ausführungslebenszyklus der Media Enhancement API. In diesem Modus werden Hardwarepuffer direkt verknüpft, um den Leistungsengpass zu vermeiden, der durch das Hin- und Herkopieren unkomprimierter Frames zwischen CPU- und GPU-Arbeitsspeicherpuffern entsteht.
Die Pipeline zur Optimierung wird in den folgenden Schritten implementiert:
Phase 1: Optimierungssitzung einrichten
1. Eingabeoberfläche bereitstellen: Ihre App stellt dem Enhancement-Framework ein Handle für die Eingabeoberfläche zur Verfügung, um auf Frames für die Verarbeitung zuzugreifen.
2. Ausgabeoberfläche festlegen: Ihre App stellt Rendering-Ziele (z. B. SurfaceView oder TextureView) bereit und bindet sie direkt an das Framework.
Phase 2: Eingabe-Frame erstellen
3. Basismedien vorbereiten: Ihre App ruft die unkomprimierten Basismedien ab. Beispielsweise durch das Lesen einer Datei von einer lokalen Festplatte.
4. Bilddaten einfügen: Ihre App schreibt die Rohbildnutzlast direkt in die Pipeline der gebundenen Eingabeoberfläche.
Phase 3: Verarbeiten und optimieren
5. KI-Verarbeitung ausführen: Das Framework verarbeitet den Frame auf der GPU oder NPU des Geräts und wendet Verbesserungen durch maschinelles Lernen wie Tonemapping, Unschärfe entfernen oder Hochskalieren an.
6. Verbesserten Frame ausgeben: Die Engine gibt den verbesserten Frame in voller Auflösung direkt an die gebundene Ausgabefläche aus.
Phase 4: Ergebnis anzeigen oder speichern
7. Ausgabe fertigstellen: Ihre App empfängt den verarbeiteten Hardware-Stream-Puffer, um ihn in der Benutzeroberfläche zu rendern oder im Speicher zu speichern.
Das EnhancementSession ist ein schwergewichtiges Kontextobjekt, das eine persistente GPU- oder NPU-Speicherpipeline verwaltet. Es weist dedizierten Video-RAM (VRAM) und native Systemhandles zu. Um schwerwiegende Speicherlecks und potenzielle OutOfMemoryError-Abstürze zu vermeiden, sollten Sie die folgenden Lebenszyklusprinzipien beachten:
- Lazy Instantiation (verzögerte Instanziierung): Erstellen Sie erst dann eine Sitzung, wenn der Nutzer eine Optimierungsaktion startet.
- Strategische Wiederverwendung: Behalten Sie eine einzelne Sitzungsinstanz bei und verwenden Sie sie wieder, wenn Streams oder Frames mit identischen Konfigurationen (Dimensionen und aktivierten Optionen) verarbeitet werden.
- Prompt-Analyse: Rufen Sie
session.release()sofort auf, wenn visuelle Aufgaben beendet werden, um freigegebene Hardwareressourcen freizugeben.
Engine für die Optimierung initialisieren
Diese Methode führt eine zweistufige Prüfung durch. Es wird geprüft, ob die Hardware des Geräts die Beschleunigung unterstützt, und dann wird dafür gesorgt, dass die erforderlichen Module für maschinelles Lernen vorhanden sind.
Wenn Sie diesen Schritt als Voraussetzung ausführen, werden Laufzeitinitialisierungsfehler vermieden, da die Funktionen validiert werden, bevor Ihre App versucht, Medien zu verarbeiten.
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)
}
}
}
}
Implementierung: Oberflächenmodus (Oberfläche ein, Oberfläche aus)
Im Surface-Ausführungsmodus (EnhancementMode.SURFACE) wird der Leistungsaufwand vermieden, der durch das Verschieben von Frames zwischen CPU- und GPU-Arbeitsspeicherpuffern entsteht. Stattdessen werden in der Erweiterungsbibliothek Roh-Hardwarepuffer direkt zugeordnet, Frames aus einer Eingabe-Surface gelesen, nativ verarbeitet und direkt an eine Ausgabe-Surface weitergeleitet.
Oberflächen-Snapshots mit einem einzelnen Frame
Mit dieser Methode können Effekte effizient auf einen einzelnen hardwaredecodierten Frame angewendet werden.
// Provisions input Surface (for example, ImageReader) and output Surface (for
// example, SurfaceView)
val inputSurface: Surface = imageReader.surface
val outputSurface: Surface = surfaceView.holder.surface
// 1. Configure parameters for SURFACE mode
val surfaceOptions = EnhancementOptions(
imageReader.width,
imageReader.height,
EnhancementMode.SURFACE,
enableTonemap = true,
enableDeblurDenoise = true,
enableFaceDetection = false
).also {
// 2. Bind hardware surfaces
it.setInputSurface(inputSurface)
it.setOutputSurface(outputSurface)
}
// 3. Create the session to process the hardware frame
val singleFrameSession = enhancementClient.createSessionAsync(surfaceOptions, executor)
// The API processes the single frame. Upon completion, release the session.
singleFrameSession.release()