چرخه عمر بهبود رسانه در حالت Bitmap را درک کنید

رابط برنامه‌نویسی کاربردی بهبود رسانه (Media Enhancement API) یک راهکار هوش مصنوعی با تأخیر کم و حفظ حریم خصوصی روی دستگاه ارائه می‌دهد که از شتاب سخت‌افزاری برای ارائه بهبودهای رسانه‌ای با کیفیت بالا و بدون حجم زیاد APK استفاده می‌کند. برای اطلاعات بیشتر، به درک قابلیت‌های بهبود رسانه مراجعه کنید.

حالت استاتیک بیت‌مپ ( EnhancementMode.BITMAP ) برای پردازش تصویر استاتیک و رمزگشایی شده طراحی شده است.

عملکرد در حالت Bitmap مستلزم آن است که سیستم عامل داده‌های پیکسلی فشرده نشده را سریالی کرده و آن را از حافظه CPU از طریق گذرگاه سیستم به حافظه GPU کپی کند و فریم پردازش شده را از طریق یک کپی معکوس بازگرداند. این حالت برای اجرای تک فریم بهینه شده است و با پخش ویدیوی بلادرنگ سازگار نیست.

این گردش کار شامل ایجاد یک جلسه، پردازش یک بیت‌مپ واحد با آن و سپس مدیریت نتیجه است. نمونه‌های کد از بخش‌های قبلی این مورد استفاده را به تفصیل پوشش می‌دهند.

  1. پیکربندی گزینه‌ها : یک شیء EnhancementOptions ایجاد کنید و مطمئن شوید که enhancementMode روی EnhancementMode.BITMAP تنظیم شده است.
  2. ایجاد جلسه : از پوشش createSessionAsync که قبلاً تعریف کردیم برای ایجاد یک EnhancementSession استفاده کنید. این یک شیء سنگین است، بنابراین فقط در صورت نیاز آن را ایجاد کنید.
  3. تصویر پردازش : فراخوانی جلسه، بیت‌مپ ورودی شما و گزینه‌های مورد نظر.
  4. نتیجه را مدیریت کنید : تابع suspend در صورت موفقیت، یک Bitmap جدید و بهبود یافته را برمی‌گرداند یا در صورت شکست، یک استثنا ایجاد می‌کند.
  5. جلسه انتشار : نکته مهم این است که وقتی کارتان تمام شد، تابع session.release() را فراخوانی کنید تا منابع GPU آزاد شوند.

EnhancementSession یک شیء context سنگین است که یک خط لوله حافظه GPU یا NPU پایدار را حفظ می‌کند. این شیء، RAM ویدیویی اختصاصی (VRAM) و هندل‌های سیستم بومی را اختصاص می‌دهد. برای جلوگیری از نشت شدید حافظه و خرابی‌های احتمالی OutOfMemoryError ، به اصول چرخه عمر زیر پایبند باشید:

  1. نمونه‌سازی تنبل : تا زمانی که کاربر یک اقدام بهبود را آغاز نکند، جلسه‌ای ایجاد نمی‌شود.
  2. استفاده مجدد استراتژیک : هنگام پردازش چندین تصویر با پیکربندی‌های یکسان (ابعاد و گزینه‌های فعال و غیرفعال)، یک نمونه جلسه واحد را حفظ و مجدداً استفاده کنید.
  3. باز کردن سریع : بلافاصله پس از پایان یافتن وظایف بصری، session.release() را فراخوانی کنید تا منابع سخت‌افزاری مشترک آزاد شوند.

موتور بهبود را مقداردهی اولیه کنید

این روش یک بررسی دو مرحله‌ای را هماهنگ می‌کند. این بررسی تأیید می‌کند که آیا سخت‌افزار دستگاه از شتاب‌دهی پشتیبانی می‌کند یا خیر، و سپس از وجود ماژول‌های یادگیری ماشین مورد نیاز اطمینان حاصل می‌کند.

اجرای این مرحله به عنوان یک مرحله پیش‌نیاز، با اعتبارسنجی قابلیت‌ها قبل از تلاش برنامه شما برای پردازش رسانه، از خرابی‌های مقداردهی اولیه در زمان اجرا جلوگیری می‌کند.

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

ایجاد پوشش‌های فرآیند جلسه و بیت‌مپ

از این پوشش‌دهنده‌های کوروتین کاتلین برای تبدیل فراخوانی‌های کلاینت مبتنی بر وظیفه به توابع تعلیق استاندارد استفاده کنید و اجرای تمیزتر و متوالی را امکان‌پذیر سازید.

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