Zum Inhalt

apple/PhysarumApp/Sources/Capture/ClipRecorder.swift

import Foundation
import CoreMedia

/// Abstracts the video sink so the orchestration loop is testable without AVFoundation.
protocol ClipRecorder {
    func begin() throws
    func appendFrame(index: Int, pts: CMTime) throws
    func finish() async throws -> URL
}

/// Deterministic offline append loop: render frame n, append it at n/fps, report
/// progress. On cancel it stops appending but still finalizes the file cleanly.
func runClip(frameCount: Int, fps: Int, recorder: ClipRecorder,
             renderFrame: (Int) throws -> Void,
             isCancelled: () -> Bool,
             progress: (Double) -> Void) async throws -> URL {
    try recorder.begin()
    for n in 0..<frameCount {
        if isCancelled() { break }
        try renderFrame(n)
        try recorder.appendFrame(index: n, pts: clipPresentationTime(frameIndex: n, fps: fps))
        progress(Double(n + 1) / Double(frameCount))
    }
    return try await recorder.finish()
}