mosaic

Mosaic Architecture

Mosaic is intentionally small. The root package provides orchestration while lower-level packages own focused behavior.

Runtime Flow

Job
 └─ encode.go
    ├─ prepareInputForEncoding
    │  └─ optional orientation normalization
    ├─ probe.InputWithExecutor
    │  └─ ffprobe video stream + audio stream
    ├─ ladder.Build
    │  └─ aspect-preserving base ladder
    ├─ optimize.Apply
    │  └─ bitrate capping and rung trimming
    └─ encoder.Encode{HLS|DASH}CMAFWithExecutor
       └─ ffmpeg command assembly and execution

Packages

Root Package

Files:

encode.go
job.go
orientation.go

Responsibilities:

config

Files:

config/profiles.go

Responsibilities:

probe

Files:

probe/probe.go

Responsibilities:

Rotation metadata is read from FFprobe side data first, then tags.rotate.

ladder

Files:

ladder/types.go
ladder/ladder.go

Responsibilities:

optimize

Files:

optimize/cost.go
optimize/optimize.go

Responsibilities:

encoder

Files:

encoder/common.go
encoder/hls_cmaf.go
encoder/dash_cmaf.go

Responsibilities:

internal/executor

Files:

internal/executor/executor.go
internal/executor/mock.go

Responsibilities:

Dependency Direction

mosaic
 ├─ config
 ├─ encoder
 ├─ internal/executor
 ├─ ladder
 ├─ optimize
 └─ probe

Lower-level packages do not import the root package.

This keeps public API orchestration separate from command generation and makes package tests straightforward.

External Processes

Mosaic depends on external binaries:

All invocations go through executor.CommandExecutor.

This makes command behavior observable in tests without actually running FFmpeg.

State and Side Effects

Side effects are intentionally narrow:

Mosaic does not keep global encode state.

Error Boundaries

Important error boundaries:

Testing Strategy

Most behavior is tested with mocks:

Integration tests and smoke tests can use real FFmpeg and FFprobe where available.