ทําความเข้าใจวงจรการเพิ่มประสิทธิภาพสื่อในโหมดบิตแมป

Media Enhancement API เป็นโซลูชัน AI ในอุปกรณ์ที่มีเวลาในการตอบสนองต่ำ รักษาความเป็นส่วนตัว และใช้ประโยชน์จากการเร่งฮาร์ดแวร์เพื่อมอบการปรับปรุงสื่อคุณภาพสูงโดยไม่มีการขยายขนาด APK ดูข้อมูลเพิ่มเติมได้ที่ทำความเข้าใจ ความสามารถในการปรับปรุงสื่อ

โหมด Bitmap แบบคงที่ (EnhancementMode.BITMAP) ออกแบบมาสำหรับการประมวลผลรูปภาพแบบคงที่ที่ถอดรหัสแล้ว

การทำงานในโหมด Bitmap กำหนดให้ระบบปฏิบัติการต้องทำให้ข้อมูลพิกเซลที่ไม่ได้บีบอัดเป็นอนุกรมและคัดลอกจากหน่วยความจำ CPU ผ่านบัสระบบไปยังหน่วยความจำ GPU โดยส่งคืนเฟรมที่ประมวลผลแล้วผ่านการคัดลอกแบบย้อนกลับ โหมดนี้ได้รับการเพิ่มประสิทธิภาพสำหรับการดำเนินการเฟรมเดียวและไม่สามารถใช้งานร่วมกับการสตรีมวิดีโอแบบเรียลไทม์

เวิร์กโฟลว์นี้เกี่ยวข้องกับการสร้างเซสชัน การประมวลผลบิตแมปเดียวด้วยเซสชันนั้น แล้วจัดการผลลัพธ์ ตัวอย่างโค้ดจากส่วนก่อนหน้าครอบคลุมกรณีการใช้งานนี้โดยละเอียด

  1. กำหนดค่าตัวเลือก: สร้างออบเจ็กต์ EnhancementOptions โดยตรวจสอบว่าได้ตั้งค่า enhancementMode เป็น EnhancementMode.BITMAP แล้ว
  2. สร้างเซสชัน: ใช้ Wrapper createSessionAsync ที่เรากำหนดไว้ก่อนหน้านี้ เพื่อสร้าง EnhancementSession ซึ่งเป็นออบเจ็กต์ขนาดใหญ่ ดังนั้นให้สร้างเฉพาะเมื่อจำเป็นเท่านั้น
  3. ประมวลผลรูปภาพ: เรียกใช้เซสชัน บิตแมปอินพุต และตัวเลือก ที่ต้องการ
  4. จัดการผลลัพธ์: ฟังก์ชันระงับจะแสดงผลบิตแมปใหม่ที่ปรับปรุงแล้วเมื่อ สำเร็จ หรือแสดงข้อยกเว้นเมื่อล้มเหลว
  5. ปล่อยเซสชัน: สิ่งสำคัญคือต้องเรียกใช้ session.release() เมื่อคุณ เสร็จสิ้นเพื่อเพิ่มทรัพยากร GPU

EnhancementSession เป็นออบเจ็กต์บริบทขนาดใหญ่ที่รักษาไปป์ไลน์หน่วยความจำ GPU หรือ NPU แบบถาวร โดยจะจัดสรร RAM วิดีโอ (VRAM) โดยเฉพาะและจัดการระบบเนทีฟ ปฏิบัติตามหลักการวงจรต่อไปนี้เพื่อป้องกันการรั่วไหลของหน่วยความจำอย่างรุนแรงและการขัดข้องที่อาจเกิดขึ้นจาก OutOfMemoryError

  1. การสร้างอินสแตนซ์แบบเลื่อน: อย่าสร้างเซสชันจนกว่าผู้ใช้จะเริ่มการดำเนินการ ปรับปรุง
  2. การนำกลับมาใช้ซ้ำอย่างมีกลยุทธ์: รักษาและนำอินสแตนซ์เซสชันเดียวกลับมาใช้ซ้ำเมื่อ ประมวลผลรูปภาพหลายรูปที่มีการกำหนดค่าเหมือนกัน (ขนาดและ ตัวเลือกที่สลับ)
  3. การล้างข้อมูลทันที: เรียกใช้ session.release() ทันทีเมื่อมีการสิ้นสุดงานภาพ เพื่อเพิ่มทรัพยากรฮาร์ดแวร์ที่แชร์

เริ่มต้นใช้งานเครื่องมือปรับปรุง

เมธอดนี้จะจัดระเบียบการตรวจสอบ 2 ขั้นตอน โดยจะตรวจสอบว่าฮาร์ดแวร์ของอุปกรณ์รองรับการเร่งความเร็วหรือไม่ แล้วตรวจสอบว่ามีโมดูลแมชชีนเลิร์นนิงที่จำเป็นอยู่

การเรียกใช้เมธอดนี้เป็นขั้นตอนเบื้องต้นจะป้องกันไม่ให้เกิดข้อผิดพลาดในการเริ่มต้นใช้งานรันไทม์โดยการตรวจสอบความสามารถก่อนที่แอปจะพยายามประมวลผลสื่อ

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

สร้าง Wrapper สำหรับเซสชันและกระบวนการบิตแมป

ใช้ Wrapper โครูทีน Kotlin เหล่านี้เพื่อแปลง Callback ของไคลเอ็นต์ตามงานให้เป็นฟังก์ชันระงับมาตรฐาน ซึ่งจะช่วยให้การดำเนินการเป็นไปอย่างราบรื่นและเป็นลำดับ

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

เรียกใช้ไปป์ไลน์บิตแมปใน ViewModel

หากต้องการผสานรวมไปป์ไลน์การปรับปรุงเข้ากับสถาปัตยกรรมแอปพลิเคชัน ให้ใช้ ViewModel เพื่อจัดการวงจรของเซสชัน แนวทางนี้จะช่วยให้มั่นใจได้ว่าทรัพยากร GPU ขนาดใหญ่จะได้รับการปล่อยเมื่อ ViewModel ถูกล้าง

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