Surface モードでのメディア エンハンスメントのライフサイクルについて

Media Enhancement API は、ハードウェア アクセラレーションを活用して高品質のメディア改善を実現する、低レイテンシでプライバシーの保護に配慮したオンデバイス AI ソリューションです。APK の肥大化は発生しません。詳しくは、メディア拡張機能についてをご覧ください。

次のアーキテクチャ図は、Media Enhancement API の非同期サーフェス モードの実行ライフサイクルを示しています。このモードでは、ハードウェア バッファを直接リンクして、CPU と GPU のメモリバッファ間で非圧縮フレームをコピーする際のパフォーマンスのボトルネックを解消します。

Media Enhancement API の 7 ステップの非同期サーフェス間ライフサイクルを示す図。
図 1. 非同期サーフェス モードの実行ライフサイクルと、拡張パイプラインの 7 つの実行可能なステップ。

拡張パイプラインは、次の手順で実装されます。

フェーズ 1. 拡張セッションを設定する

1. 入力サーフェスを提供する: アプリは、処理するフレームにアクセスするための入力サーフェス ハンドルを拡張フレームワークに提供します。

2. 出力サーフェスを設定する: アプリがレンダリング ターゲット(SurfaceViewTextureView など)をプロビジョニングして、フレームワークに直接バインドします。

フェーズ 2: 入力フレームを生成する

3. ベース メディアを準備する: アプリがベースの非圧縮メディアを取得します。たとえば、ローカル ディスクからファイルを読み取ります。

4. フレームデータを挿入: アプリがバインドされた入力サーフェス パイプラインに未加工の画像ペイロードを直接書き込みます。

フェーズ 3. 処理と補正

5. AI 処理を実行: フレームワークはデバイスの GPU または NPU でフレームを処理し、トーンマッピング、ぼかし除去、アップスケーリングなどの ML 拡張機能を適用します。

6. 拡張フレームを配信: エンジンは、拡張されたフル解像度のフレームをバインドされた出力サーフェスに直接出力します。

フェーズ 4. 結果を表示または保存する

7. 出力の最終処理: 処理されたハードウェア ストリーム バッファがアプリに渡され、UI でレンダリングされるか、ストレージに保存されます。

EnhancementSession は、永続的な GPU または NPU メモリ パイプラインを維持するヘビーウェイト コンテキスト オブジェクトです。専用のビデオ RAM(VRAM)とネイティブ システム ハンドルを割り当てます。重大なメモリリークや OutOfMemoryError クラッシュの可能性を防ぐため、次のライフサイクル原則を遵守してください。

  • 遅延インスタンス化: ユーザーが拡張アクションを開始するまでセッションを作成しません。
  • 戦略的な再利用: 同じ構成(ディメンションと切り替えオプション)でストリームまたはフレームを処理するときに、単一のセッション インスタンスを維持して再利用します。
  • プロンプトのティアダウン: 視覚タスクが終了するとすぐに 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)
            }
        }
    }
}

実装: サーフェス モード(サーフェス イン、サーフェス アウト)

Surface 実行モード(EnhancementMode.SURFACE)では、CPU と GPU のメモリバッファ間でフレームを移動する際のパフォーマンス オーバーヘッドを回避できます。代わりに、拡張ライブラリは未加工のハードウェア バッファを直接マッピングし、入力 Surface からフレームを読み取ってネイティブに処理し、出力 Surface に直接パイプします。

単一フレームのサーフェス スナップショット

このメソッドは、ハードウェア デコードされた単一の画像フレームに効果を効率的に適用するために使用されます。

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