媒体增强 API 提供了一种低延迟、可保护隐私的设备端 AI 解决方案,该解决方案利用硬件加速功能来提供高质量的媒体改进,且不会造成 APK 膨胀。如需了解详情,请参阅了解媒体增强功能。
静态位图模式 (EnhancementMode.BITMAP) 专为静态解码图像处理而设计。
在位图模式下运行需要操作系统序列化未压缩的像素数据,并将其从 CPU 内存通过系统总线复制到 GPU 内存,然后通过反向复制返回处理后的帧。它针对单帧执行进行了优化,但与实时视频流不兼容。
此工作流涉及创建会话、使用该会话处理单个位图,然后处理结果。前几部分中的代码示例详细介绍了此使用场景。
- 配置选项:创建一个
EnhancementOptions对象,确保enhancementMode设置为EnhancementMode.BITMAP。 - 创建会话:使用我们之前定义的
createSessionAsync封装容器来创建EnhancementSession。这是一个重量级对象,因此仅在需要时创建。 - 处理图片:调用会话、输入位图和所需选项。
- 处理结果:挂起函数在成功时返回新的增强型 Bitmap,在失败时抛出异常。
- 释放会话:至关重要的是,在完成操作后调用
session.release()以释放 GPU 资源。
EnhancementSession 是一个重量级上下文对象,用于维护持久的 GPU 或 NPU 内存流水线。它会分配专用视频 RAM (VRAM) 和原生系统句柄。为防止严重的内存泄漏和潜在的 OutOfMemoryError 崩溃,请遵循以下生命周期原则:
- 延迟实例化:在用户发起增强操作之前,不创建会话。
- 策略性重用:在处理具有相同配置(尺寸和切换的选项)的多张图片时,维护并重用单个会话实例。
- 提示拆解:在视觉任务终止时立即调用
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)
}
}
}
}
创建会话和位图进程封装容器
使用这些 Kotlin 协程封装容器将基于任务的客户端回调转换为标准挂起函数,从而实现更简洁的顺序执行。
// 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 管理会话生命周期。此方法可确保在清除 ViewModel 时释放大量 GPU 资源。
// 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()
}
}