模組
模組模型、Module API,以及各模組的實作。總覽見 architecture.md。
模組模型
所有實作(解碼器、runtime、輸出)皆為第一方模組:原始碼位於 Modules/,靜態連結進 App,由 composition root 組裝。不支援外部模組(無 bundle、manifest、下載或安裝)。
// 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 一起替換。
- 偏好順序:清單順序即同級實作的偏好順序(見解碼策略)。
- 必要性:
.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、計數器)。
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 |
FlowVideoToolbox | VTVideoDecoderFactory(.hardware) | 硬解(格式見 codecs.md),IOSurface-backed 輸出,FrameReorder 依 PTS 重排;啟用時背景預熱 |
FlowAVAudio | AVAudioOutputFactory | 見 audio.md |
FlowMetal4 | Metal4DisplayRuntime、MetalLayerPresenterFactory | 見 Metal 4 |
FFmpeg
FFmpegDemuxerFactory:自訂 AVIO 經MediaSource讀取,packet 零拷貝;開檔不呼叫avformat_find_stream_info。edit list 與AV_PKT_DATA_SKIP_SAMPLES對應到Packet.isDiscardable、Packet.trim。格式見codecs.md。- 色度格式(見核心協定):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。- package 依賴只有 FFmpeg 的 XCFramework 與契約(
FlowModuleAPI、FlowMedia、FlowDiagnostics);C 型別不越過模組邊界。 - 新增其他解碼器=新增模組實作
VideoDecoderFactory或AudioDecoderFactory,選擇與 fallback 由FlowEngine處理。
Metal 4
- Runtime:
Metal4DisplayRuntime實作DisplayRuntime,接受本模組的 presenter(見 DisplayRuntime)。 - Presenter:
MetalLayerPresenter(MetalVideoView由makeSurface()提供);OffscreenPresenter以@_spi(Benchmark)開放,僅供 Benchmarks 自行註冊(見benchmark.md)。 - Shader ABI:
Shaders/Include/Flow/(FlowShader.h:紋理/buffer 索引、function constant 與DisplayUniforms;Color.h:轉換函式),供內建 shader 使用,建置期由MetalLibraryPlugin把FlowMetal4自身的Shaders/編譯為 metallib。破壞性變更遞增FLOW_SHADER_ABI_MAJOR。