/**
 * Render Orchestrator Service
 *
 * Coordinates the entire video rendering pipeline:
 * 1. Parse composition metadata
 * 2. Pre-extract video frames
 * 3. Pre-process audio tracks
 * 4. Parallel frame capture
 * 5. Video encoding
 * 6. Final assembly (audio mux + faststart)
 *
 * Heavy observability: every stage logs timing, errors include
 * full context, and failures produce a diagnostic summary.
 */
import { type EngineConfig, type ExtractionPhaseBreakdown, type VideoElement, type AudioElement, type ImageElement, type WorkerTask } from "@hyperframes/engine";
import { type CompiledComposition } from "./htmlCompiler.js";
import { type ProducerLogger } from "../logger.js";
export type RenderStatus = "queued" | "preprocessing" | "rendering" | "encoding" | "assembling" | "complete" | "failed" | "cancelled";
export interface RenderConfig {
    fps: 24 | 30 | 60;
    quality: "draft" | "standard" | "high";
    /**
     * Output container format. Defaults to `"mp4"`; existing renders are
     * unaffected unless this field is set explicitly.
     *
     * - `"mp4"`: H.264 by default, or H.265 + HDR10 when HDR auto-detect
     *   engages or `hdrMode: "force-hdr"` is set. Opaque. The
     *   default streaming/social deliverable. Faststart is applied so the
     *   `moov` atom sits at the file start and the file plays from a
     *   partial download.
     * - `"webm"`: VP9 + `yuva420p` pixel format → **true alpha channel**, no
     *   chroma key. Plays in Chrome, Edge, and Firefox; Safari support for
     *   alpha-WebM is incomplete. Use this when the output should drop
     *   straight into a `<video>` over a colored background on the web.
     *   Audio is muxed as Opus.
     * - `"mov"`: ProRes 4444 + `yuva444p10le` → **true alpha channel +
     *   10-bit color**. Sized for editor ingest (Premiere, Final Cut Pro,
     *   DaVinci Resolve), not direct web playback. Audio is muxed as AAC.
     * - `"png-sequence"`: a directory of zero-padded RGBA PNGs
     *   (`frame_000001.png` …). Lossless alpha, largest on disk, no muxed
     *   audio (an `audio.aac` sidecar is written alongside the PNGs when
     *   the composition has audio elements). Use for After Effects / Nuke
     *   / Fusion ingest, or when frames need post-processing before
     *   encoding. `outputPath` is treated as a directory; it is created if
     *   it doesn't exist.
     *
     * Alpha output (`"webm"`, `"mov"`, `"png-sequence"`) automatically
     * forces screenshot capture (Chrome's BeginFrame compositor does not
     * preserve alpha on Linux headless-shell) and disables HDR — HDR +
     * alpha is not a supported combination, a warning is logged and HDR
     * falls back to SDR. The transparent-background CSS is injected by
     * the engine's `initTransparentBackground` helper, so authors should
     * not paint a fullscreen `body` / `#root` background in their
     * compositions when targeting alpha output.
     */
    format?: "mp4" | "webm" | "mov" | "png-sequence";
    workers?: number;
    useGpu?: boolean;
    debug?: boolean;
    /** Entry HTML file relative to projectDir. Defaults to "index.html". */
    entryFile?: string;
    /** Full producer config. When provided, env vars are not read. */
    producerConfig?: EngineConfig;
    /** Custom logger. Defaults to console-based defaultLogger. */
    logger?: ProducerLogger;
    /** Override CRF for the video encoder. Mutually exclusive with `videoBitrate`. */
    crf?: number;
    /** Target video bitrate (e.g. "10M"). Mutually exclusive with `crf`. */
    videoBitrate?: string;
    /** HDR rendering mode.
     * - `auto` (default): probe sources; enable HDR if any HDR content is found.
     * - `force-hdr`: enable HDR even on SDR-only compositions (falls back to HLG transfer).
     * - `force-sdr`: skip probing entirely; always render SDR.
     */
    hdrMode?: "auto" | "force-hdr" | "force-sdr";
}
export interface RenderPerfSummary {
    renderId: string;
    totalElapsedMs: number;
    fps: number;
    quality: string;
    workers: number;
    chunkedEncode: boolean;
    chunkSizeFrames: number | null;
    compositionDurationSeconds: number;
    totalFrames: number;
    resolution: {
        width: number;
        height: number;
    };
    videoCount: number;
    audioCount: number;
    stages: Record<string, number>;
    /** Per-phase breakdown of the Phase 2 video extraction (resolve, HDR probe, HDR preflight, VFR probe/preflight, per-video extract). Undefined when the composition has no videos. */
    videoExtractBreakdown?: ExtractionPhaseBreakdown;
    /** Bytes on disk in the render's workDir at assembly time (sampled before cleanup). Lets callers correlate peak temp usage with render duration. */
    tmpPeakBytes?: number;
    captureAvgMs?: number;
    capturePeakMs?: number;
    captureCalibration?: {
        sampledFrames: number[];
        p95Ms?: number;
        multiplier: number;
        reasons: string[];
    };
    captureAttempts?: CaptureAttemptSummary[];
    /**
     * Peak resident set size (RSS) observed during the render, in MiB.
     *
     * Sampled every 250ms by a process-wide poller; surfaces gross memory
     * regressions (e.g. unbounded image-cache growth) that wall-clock numbers
     * miss. Optional because callers can serialize older `RenderPerfSummary`
     * shapes back into this type.
     */
    peakRssMb?: number;
    /**
     * Peak V8 heap used observed during the render, in MiB.
     *
     * Useful as a finer-grained complement to {@link peakRssMb} — RSS includes
     * native ffmpeg/Chrome allocations, while heapUsed isolates JS-object growth
     * inside the orchestrator. Optional for the same back-compat reason.
     */
    peakHeapUsedMb?: number;
    hdrDiagnostics?: HdrDiagnostics;
    hdrPerf?: HdrPerfSummary;
}
export interface HdrDiagnostics {
    videoExtractionFailures: number;
    imageDecodeFailures: number;
}
export interface HdrPerfSummary {
    frames: number;
    normalFrames: number;
    transitionFrames: number;
    domLayerCaptures: number;
    hdrVideoLayerBlits: number;
    hdrImageLayerBlits: number;
    timings: Record<string, number>;
    avgMs: Record<string, number>;
}
export interface CaptureCostEstimate {
    multiplier: number;
    reasons: string[];
    p95Ms?: number;
}
export interface CaptureCalibrationSample {
    frameIndex: number;
    captureTimeMs: number;
}
export interface FrameRange {
    startFrame: number;
    endFrame: number;
}
export interface CaptureAttemptSummary {
    attempt: number;
    workers: number;
    frameCount: number;
    reason: "initial" | "retry";
}
export interface RenderJob {
    id: string;
    config: RenderConfig;
    status: RenderStatus;
    progress: number;
    currentStage: string;
    createdAt: Date;
    startedAt?: Date;
    completedAt?: Date;
    error?: string;
    outputPath?: string;
    duration?: number;
    totalFrames?: number;
    framesRendered?: number;
    perfSummary?: RenderPerfSummary;
    failedStage?: string;
    errorDetails?: {
        message: string;
        stack?: string;
        elapsedMs: number;
        freeMemoryMB: number;
        browserConsoleTail?: string[];
        perfStages?: Record<string, number>;
        hdrDiagnostics?: HdrDiagnostics;
    };
}
export type ProgressCallback = (job: RenderJob, message: string) => void;
export declare class RenderCancelledError extends Error {
    reason: "user_cancelled" | "timeout" | "aborted";
    constructor(message?: string, reason?: "user_cancelled" | "timeout" | "aborted");
}
export interface CompositionMetadata {
    duration: number;
    videos: VideoElement[];
    audios: AudioElement[];
    images: ImageElement[];
    width: number;
    height: number;
}
/**
 * Browser-discovered media inside inlined sub-compositions can still report
 * scene-local timing from the merged DOM (e.g. start=0, end=85.52) while the
 * compiled metadata is already offset into the parent host timeline
 * (e.g. start=4.417, end=89.937). Reproject browser end-time into the
 * compiled element's time origin before reconciling it back into the render
 * metadata.
 */
export declare function projectBrowserEndToCompositionTimeline(existingStart: number, browserStart: number, browserEnd: number): number;
/**
 * Write compiled HTML and sub-compositions to the work directory.
 */
export declare function writeCompiledArtifacts(compiled: CompiledComposition, workDir: string, includeSummary: boolean): void;
export declare function applyRenderModeHints(cfg: EngineConfig, compiled: CompiledComposition, log?: ProducerLogger): void;
export declare function resolveRenderWorkerCount(totalFrames: number, requestedWorkers: number | undefined, cfg: EngineConfig, compiled: Pick<CompiledComposition, "hasShaderTransitions" | "renderModeHints">, composition: Pick<CompositionMetadata, "videos" | "audios">, log?: ProducerLogger, measuredCaptureCost?: CaptureCostEstimate): number;
export declare function estimateCaptureCostMultiplier(compiled: Pick<CompiledComposition, "hasShaderTransitions" | "renderModeHints">, composition: Pick<CompositionMetadata, "videos" | "audios">): CaptureCostEstimate;
export declare function createCaptureCalibrationConfig(cfg: EngineConfig): EngineConfig;
export declare function estimateMeasuredCaptureCostMultiplier(samples: CaptureCalibrationSample[]): CaptureCostEstimate;
export declare function selectCaptureCalibrationFrames(totalFrames: number): number[];
export declare function findMissingFrameRanges(totalFrames: number, framesDir: string, frameExt: "jpg" | "png"): FrameRange[];
export declare function buildMissingFrameRetryBatches(ranges: FrameRange[], maxWorkers: number, workDir: string, attempt: number): WorkerTask[][];
export declare function getNextRetryWorkerCount(currentWorkers: number): number;
export declare function isRecoverableParallelCaptureError(error: unknown): boolean;
export declare function shouldFallbackToScreenshotAfterCalibrationError(error: unknown): boolean;
export declare function createRenderJob(config: RenderConfig): RenderJob;
/**
 * Main render pipeline
 */
export declare function extractStandaloneEntryFromIndex(indexHtml: string, entryFile: string): string | null;
export declare function executeRenderJob(job: RenderJob, projectDir: string, outputPath: string, onProgress?: ProgressCallback, abortSignal?: AbortSignal): Promise<void>;
//# sourceMappingURL=renderOrchestrator.d.ts.map