/** * Activity C of the distributed render pipeline. * * `assemble(planDir, chunkPaths, audioPath, outputPath)` stitches per-chunk * outputs into the final deliverable. For mp4 / mov / webm this is * `ffmpeg -f concat -c copy` (free of re-encode loss because every * chunk's first frame is an IDR keyframe — the chunk encoder sets * `lockGopForChunkConcat` to enforce this, which for libvpx-vp9 also * disables alt-ref frames so concat seams remain independently * decodable). For png-sequence chunks (each chunk is a directory of * frames) this is a straight directory merge with global re-numbering. * * Mux + faststart for mp4 / mov / webm go through the engine's * `muxVideoWithAudio` + `applyFaststart` helpers — same path the * in-process renderer uses; we just feed concat output rather than * streaming-encoder output. (Faststart is a no-op for webm and mov — * applyFaststart copies the input verbatim.) Audio length is * pad-or-trimmed to `frameCount / fps` via * `padOrTrimAudioToVideoFrameCount` so the mux step doesn't introduce * sub-millisecond drift at the end of long renders. * * Pure function over local paths. No networking. The caller is responsible * for moving `outputPath` to its orchestration-level storage. */ import { type ProducerLogger } from "../../logger.js"; /** * Result of {@link assemble}. `fileSize` reflects the final file on disk * (mp4/mov) or the cumulative byte total of the frame directory * (png-sequence). */ export interface AssembleResult { outputPath: string; durationMs: number; framesEncoded: number; fileSize: number; } /** * Assemble the chunk outputs into a single deliverable. * * @param planDir — absolute path to the planDir produced by `plan()`. * @param chunkPaths — ordered chunk outputs, length === `chunks.json` length. * For mp4/mov each entry is a path to an encoded chunk file; for * png-sequence each entry is a path to a directory of frames. * @param audioPath — `/audio.aac` for mux'd formats. Pass `null` * when the composition has no audio (or `assemble` is being called for a * format whose audio is muxed elsewhere). `assemble` always normalizes * audio length against the assembled video's frame count when * `audioPath` is non-null. * @param outputPath — final on-disk output (file for mp4/mov; directory * for png-sequence — created if missing). */ export declare function assemble(planDir: string, chunkPaths: readonly string[], audioPath: string | null, outputPath: string, options?: { logger?: ProducerLogger; abortSignal?: AbortSignal; /** * Opt-in exact-CFR re-encode. When `true`, the assembled video is * re-encoded once at the end of the concat/single-chunk step with * `-fps_mode cfr -r ` so the stream-level `avg_frame_rate` * matches the container's `r_frame_rate` exactly (and the file's * duration lands on the requested `frameCount / fps` to ms * precision, with no PTS-derived drift). Trade-off: ~2-5x the * stitch time for a 60s 1080p clip plus second-generation H.264 * quality loss (negligible at `-crf 18` but non-zero). Default * `false` preserves the existing `-c copy` behavior. mp4 only * (libx264); webm / mov pass through unchanged because their * stream-copy paths don't exhibit the same avg-frame-rate drift. */ cfr?: boolean; }): Promise; //# sourceMappingURL=assemble.d.ts.map