Memahami siklus proses peningkatan kualitas media dalam mode Bitmap

Media Enhancement API menyediakan solusi AI di perangkat yang hemat latensi, menjaga privasi, dan memanfaatkan akselerasi hardware untuk memberikan peningkatan kualitas media dengan bloat APK nol. Untuk mengetahui informasi selengkapnya, lihat Memahami kemampuan peningkatan media.

Mode Bitmap statis (EnhancementMode.BITMAP) dirancang untuk pemrosesan gambar statis yang didekode.

Pengoperasian dalam mode Bitmap mengharuskan OS untuk membuat serialisasi data piksel yang tidak terkompresi dan menyalinnya dari memori CPU di seluruh bus sistem ke memori GPU, yang menampilkan frame yang diproses melalui salinan terbalik. Mode ini dioptimalkan untuk eksekusi satu frame dan tidak kompatibel dengan streaming video real-time.

Alur kerja ini melibatkan pembuatan sesi, pemrosesan satu bitmap dengannya, lalu menangani hasilnya. Contoh kode dari bagian sebelumnya membahas kasus penggunaan ini secara mendetail.

  1. Mengonfigurasi opsi: Buat objek EnhancementOptions, pastikan enhancementMode ditetapkan ke EnhancementMode.BITMAP.
  2. Membuat sesi: Gunakan wrapper createSessionAsync yang kami tentukan sebelumnya untuk membuat EnhancementSession. Ini adalah objek yang berat, jadi buat hanya jika diperlukan.
  3. Memproses gambar: Panggil sesi, bitmap input, dan opsi yang Anda inginkan.
  4. Menangani hasil: Fungsi penangguhan menampilkan Bitmap baru yang ditingkatkan jika berhasil atau menampilkan pengecualian jika gagal.
  5. Merilis sesi: Yang terpenting, panggil session.release() saat Anda selesai untuk mengosongkan resource GPU.

EnhancementSession adalah objek konteks yang berat yang mempertahankan pipeline memori GPU atau NPU persisten. Objek ini mengalokasikan RAM video (VRAM) khusus dan menangani sistem native. Untuk mencegah kebocoran memori yang parah dan potensi error OutOfMemoryError, patuhi prinsip siklus proses berikut:

  1. Instansiasi lambat: Jangan membuat sesi hingga pengguna memulai tindakan peningkatan.
  2. Penggunaan kembali strategis: Pertahankan dan gunakan kembali satu instance sesi saat memproses beberapa gambar dengan konfigurasi yang identik (dimensi dan opsi yang diaktifkan).
  3. Penghancuran cepat: Panggil session.release() segera saat tugas visual dihentikan untuk mengosongkan resource hardware bersama.

Menginisialisasi mesin peningkatan

Metode ini mengatur pemeriksaan dua langkah. Metode ini memverifikasi apakah hardware perangkat mendukung akselerasi, lalu memastikan modul machine learning yang diperlukan ada.

Menjalankan langkah ini sebagai prasyarat mencegah kegagalan inisialisasi runtime dengan memvalidasi kemampuan sebelum aplikasi Anda mencoba memproses media.

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)
            }
        }
    }
}

Membuat wrapper proses sesi dan bitmap

Gunakan wrapper coroutine Kotlin ini untuk mengonversi callback klien berbasis tugas menjadi fungsi penangguhan standar, sehingga memungkinkan eksekusi yang lebih bersih dan berurutan.

// 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)
}

Menjalankan pipeline bitmap di ViewModel

Untuk mengintegrasikan pipeline peningkatan ke dalam arsitektur aplikasi, gunakan ViewModel untuk mengelola siklus proses sesi. Pendekatan ini memastikan bahwa resource GPU yang berat dilepaskan saat ViewModel dihapus.

// 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()
    }
}