# 模組

URL: https://flow.lanstar.dev/docs/architecture/modules

> 模組模型、Module API，以及各模組的實作。總覽見 [`architecture.md`](/docs/architecture)。

## 模組模型

所有實作（解碼器、runtime、輸出）皆為第一方模組：原始碼位於 `Modules/`，靜態連結進 App，由 composition root 組裝。不支援外部模組（無 bundle、manifest、下載或安裝）。

```swift
// Packages/Composition/Sources/FlowComposition/Modules.swift：唯一知道用了哪些實作的地方
import FlowAVAudio
import FlowFFmpeg
import FlowFile
import FlowMetal4
public import FlowModuleHost
import FlowVideoToolbox

@_spi(Benchmark) public enum FlowModules {
    public static let essential: [ModuleEntry] = [
        .essential(FileModule.self),
        .essential(FFmpegModule.self),       // 替換：改這行與對應 import（另加一行 package 依賴）
        .essential(VideoToolboxModule.self),
        .essential(AVAudioModule.self),
        .essential(Metal4Module.self),
    ]
}
```

- **FlowPlayer**：`FlowComposition` 以 `FlowPlayer` 組裝 `ComponentRegistry`、`PlayerController`、`ModuleHost`、`PlayerSession`，四者皆不對外公開。App 只用 `init()`（啟用 `FlowModules.essential`）、`api`（`PlayerAPI`）、`makeVideoView()`、`attach(_:)`（進行中開始的 load 會等它完成）、`shutdown()`，公開 API 不含 Kernel 型別；指定模組與 `EngineConfiguration` 的 init 及 `FlowModules` 只以 `@_spi(Benchmark)` 開放；影片 view 由 `PresenterFactory.makeSurface()` 提供，App 與 composition root 都不需知道 presenter 型別。Benchmarks 經同一個 `FlowPlayer` 組裝，量到的就是發行的。
- **替換**：同一介面的實作可互換，改模組名稱與 import 即可；依賴某 runtime 的模組需隨該 runtime 一起替換。
- **偏好順序**：清單順序即同級實作的偏好順序（見[解碼策略](/docs/architecture/engine#解碼策略)）。
- **必要性**：`.essential` 不可停用，啟用失敗時 `FlowPlayer` 初始化失敗；`.optional` 啟用失敗只記 log，`ModuleHost.setEnabled` 可停用與重新啟用。`FlowPlayer` 不開放 `ModuleHost`，App 無法停用模組；出貨的模組皆為 `.essential`。
- **in-process**：模組不使用 ExtensionKit／XPC；完整 SwiftUI、直接呼叫框架 API、熱路徑零開銷。
- **Library validation**：主程式不載入外部程式碼，Hardened Runtime 下無需 `disable-library-validation`。

> 不提供 Script（JavaScript）：帶來額外 runtime 與維護負擔。

## Module API

定義於 `FlowModuleAPI`；模組另可依賴 `FlowMedia`（媒體值型別）與 `FlowDiagnostics`（Logger、signpost、計數器）。

```swift
public protocol FlowModule: AnyObject, SendableMetatype {
    /// 穩定識別碼；預設為完整型別名稱
    static var id: String { get }
    init()
    /// 只在這裡註冊；停用時由 FlowModuleHost 撤銷所有註冊
    @MainActor func activate(_ context: any ModuleContext) throws
    @MainActor func deactivate()
}

@MainActor
public protocol ModuleContext {
    var media: any MediaRegistry { get }        // MediaSourceFactory、DemuxerFactory
    var decoders: any DecoderRegistry { get }   // VideoDecoderFactory、AudioDecoderFactory
    var outputs: any OutputRegistry { get }     // AudioOutputFactory、PresenterFactory
    var runtimes: any RuntimeRegistry { get }   // DisplayRuntime 等 NodeRuntime
    var player: any PlayerAPI { get }           // Command／Property／Event（見 player-api.md）
}
```

- **能力可任意組合**：一個模組可同時註冊多種實作並呼叫 API（如 `FlowMetal4` 註冊 runtime 與 presenter）。
- **版本**：與 App 一起建置，`FlowModuleAPI` 不需維持 ABI 穩定，可隨需求重構。
- **停用**：撤銷所有註冊即生效；播放中的媒體沿用已建立的元件，下次載入時 `FlowEngine` 改選其他實作。重新啟用後恢復原本的偏好順序。

## 模組一覽

| 模組 | 註冊 | 說明 |
| --- | --- | --- |
| `FlowFile` | `FileSourceFactory`（`file`） | 本機檔案 `MediaSource` |
| `FlowFFmpeg` | `FFmpegDemuxerFactory`、`FFmpegAudioDecoderFactory` | 見 [FFmpeg](#ffmpeg) |
| `FlowVideoToolbox` | `VTVideoDecoderFactory`（`.hardware`） | 硬解（格式見 [`codecs.md`](/docs/codecs#影像)），IOSurface-backed 輸出，`FrameReorder` 依 PTS 重排；啟用時背景預熱 |
| `FlowAVAudio` | `AVAudioOutputFactory` | 見 [`audio.md`](/docs/architecture/audio) |
| `FlowMetal4` | `Metal4DisplayRuntime`、`MetalLayerPresenterFactory` | 見 [Metal 4](#metal-4) |

### FFmpeg

- `FFmpegDemuxerFactory`：自訂 AVIO 經 `MediaSource` 讀取，packet 零拷貝；開檔不呼叫 `avformat_find_stream_info`。edit list 與 `AV_PKT_DATA_SKIP_SAMPLES` 對應到 `Packet.isDiscardable`、`Packet.trim`。格式見 [`codecs.md`](/docs/codecs#檔案格式)。
- **色度格式**（見[核心協定](/docs/architecture/engine#核心協定)）：H.264／HEVC 取自 avcC 的 SPS 與 hvcC 的 `chroma_format_idc`；libavformat 有 pixel format 時改用其描述：RGB、調色盤、Bayer、XYZ、硬體格式為 `nil`，扣除 alpha 只剩一個分量為單色，其餘依 `log2_chroma_w`／`log2_chroma_h`。
- `FFmpegAudioDecoderFactory`：libavcodec 解碼，libswresample 重取樣到輸出格式；只讀 `Packet` 的契約欄位，任何 demuxer 的 packet 都照樣修剪。格式見 [`codecs.md`](/docs/codecs#音訊)。
- package 依賴只有 FFmpeg 的 XCFramework 與契約（`FlowModuleAPI`、`FlowMedia`、`FlowDiagnostics`）；C 型別不越過模組邊界。
- 新增其他解碼器＝新增模組實作 `VideoDecoderFactory` 或 `AudioDecoderFactory`，選擇與 fallback 由 `FlowEngine` 處理。

### Metal 4

- **Runtime**：`Metal4DisplayRuntime` 實作 `DisplayRuntime`，接受本模組的 presenter（見 [DisplayRuntime](/docs/architecture/rendering#displayruntime)）。
- **Presenter**：`MetalLayerPresenter`（`MetalVideoView` 由 `makeSurface()` 提供）；`OffscreenPresenter` 以 `@_spi(Benchmark)` 開放，僅供 Benchmarks 自行註冊（見 [`benchmark.md`](/docs/benchmark#基礎設施)）。
- **Shader ABI**：`Shaders/Include/Flow/`（`FlowShader.h`：紋理／buffer 索引、function constant 與 `DisplayUniforms`；`Color.h`：轉換函式），供內建 shader 使用，建置期由 `MetalLibraryPlugin` 把 `FlowMetal4` 自身的 `Shaders/` 編譯為 metallib。破壞性變更遞增 `FLOW_SHADER_ABI_MAJOR`。
