Skip to content

Latest commit

 

History

History
94 lines (65 loc) · 4.31 KB

ARCHITECTURE.md

File metadata and controls

94 lines (65 loc) · 4.31 KB

StreamMuxer Architecture

Overview

StreamMuxer follows an MVVM-like structure with a clear separation between the UI and the FFmpeg integration:

  • Views: SwiftUI components for interaction and display
  • ViewModel: UI state + orchestration of probe/export actions
  • Services: process integration with ffprobe and ffmpeg
  • Models: typed representation of files, streams, capabilities, per-stream settings and export sessions

Export pipeline

Configuration never becomes a shell string. The flow is:

UI
 ↓
StreamSettings (per stream) + ExportSession
 ↓
FFmpegCommandBuilder  →  BuiltCommand (executable + [String] arguments)
 ↓
FFmpegRunner (Process, async)

Services

  • FFmpegPaths — resolves ffmpeg/ffprobe (app bundle → Homebrew dirs → which).
  • FFmpegCapabilityScanner — startup environment check: versions plus ffmpeg -encoders. The UI only offers encoders that are actually present (including VideoToolbox hardware encoders).
  • ProbeService — ffprobe -show_format -show_streams -show_chapters -print_format json, mapped into MediaStream/MediaFile models.
  • FFmpegCommandBuilder — turns an ExportSession into structured arguments: -map per included stream, per-stream codec args (-c:v:0, -crf:v:0, -q:v:0, -b:a:1…), container-aware subtitle handling and validation. Also produces the human-readable command preview.
  • FFmpegRunner — runs the job asynchronously, parses -progress pipe:1 key/value blocks into TranscodeProgress (fraction, speed, fps, ETA), captures the full stderr log, and supports cancellation via Process.terminate().

Main Flow

  1. On launch, FFmpegCapabilityScanner checks the environment. If FFmpeg/FFprobe are missing, a banner explains what's missing and exports are disabled.
  2. User drops/selects media files.
  3. StreamMuxerViewModel schedules probing with ProbeService.
  4. Parsed streams are mapped into MediaStream models; every stream defaults to Copy (no implicit destructive operations).
  5. User chooses per-stream: Copy / Transcode (codec + encoder + quality + speed preset) / Discard.
  6. FFmpegCommandBuilder validates the configuration against the target container and builds the command (also shown as a preview).
  7. FFmpegRunner executes ffmpeg; progress (percentage, processed time, speed, fps, ETA) is streamed back to the UI. The user can cancel; partial output is removed.
  8. On failure, a simplified error is shown and the full FFmpeg log is available via "Show FFmpeg Log".

Quality abstraction

The UI exposes quality levels (Higher quality / Balanced / Smaller file), not bitrates. Each VideoEncoderInfo translates the level into its own mechanism:

  • libx264 / libx265 → CRF + -preset
  • libsvtav1 → CRF + numeric preset
  • libaom-av1 → CRF + -b 0 + -cpu-used
  • h264_videotoolbox / hevc_videotoolbox → -q:v (1–100 scale)

HEVC output into MP4/MOV is tagged hvc1 for Apple-player compatibility.

Container validation

  • MP4/MOV: text subtitles (SRT/ASS/WebVTT…) auto-convert to mov_text; bitmap subtitles (PGS/VobSub) and attachment/data streams are rejected with a clear message before export.
  • MKV: everything copies; mov_text converts to SRT.

Stream Ordering Policy

Before export, included streams are sorted in fixed groups:

  1. video
  2. audio
  3. subtitle
  4. other

This ensures predictable output stream indexes regardless of selection order.

Output Naming Policy

Default output URL suggestion is generated from the first contributing source file:

  • Same directory as original file
  • Filename suffix _conf
  • Extension follows the selected output container

Example:

  • episode01.mkv + MKV output -> episode01_conf.mkv

Security Scope Handling

The app uses startAccessingSecurityScopedResource() where needed when reading input/output URLs via system file pickers; access is held for the duration of an export.

Error Handling

  • Missing binaries (ffprobe/ffmpeg) produce a persistent banner and disable exports.
  • Probe errors surface inline per file section in the stream list.
  • Configuration errors (container incompatibilities) surface in the export panel before running anything.
  • Export errors are shown via alert with a simplified message; the full FFmpeg stderr log is available in a sheet.
  • Cancelled exports remove the partial output file.