Concept

How it works

The stages between submitting a source file to the master and receiving a finished encode. Read this page before scaling past one machine.

Every stage described below runs automatically; chunks are not scheduled and workers are not managed by hand. The stages are documented because failure reports name them, and because the boundaries described here determine whether output is deliverable.

Two programs#

TRNSCODE consists of one master service and any number of worker services.

The master owns everything that must be true exactly once: the job queue, the database, the web interface, the chunk plan, and the final assembly. There is exactly one master; it is the machine the browser connects to.

A worker owns no persistent state. It connects to the master, reports its capabilities, receives chunks, runs FFmpeg, and reports results. Workers are disposable by design: a worker can be added mid-job, and a worker can be lost mid-job without losing the job.

Note

The master machine can also run a worker. On a single machine, running both still provides parallel encoding across the CPU cores. Adding a second machine later does not change the workflow.

A fresh master does not begin in normal operation. On first boot the web console walks a guided first run — a forced change of the administrator password, then license registration and activation, then sign-in — and the master blocks job submission and worker registration until it is activated. See Licensing.

The pipeline#

A job moves through five stages. The queue displays the current stage.

Probe

The master runs ffprobe against the source and reads the container, duration, resolution, frame rate, and audio layout. The review screen displays this information before submission, and the chunk planner works from it.

Plan the chunks

The source is divided into segments. The default target is 12 seconds per chunk, adjusted so boundaries land on keyframes rather than arbitrary timestamps.

Distribute

The scheduler matches each chunk to a worker capable of encoding it: the required codec, accelerator, and FFmpeg build. Workers pull work as they become free, so a fast machine takes more chunks than a slow one without any configuration.

Encode

Each worker runs an ordinary FFmpeg command that can be read and reproduced. Progress streams back to the master frame by frame and drives the live chunk map.

Assemble and verify

When every chunk is complete, the master concatenates them, muxes the audio back in, and verifies the result before marking the job complete.

Chunk boundary placement#

Boundary placement determines whether the assembled output is free of visible seams. The mechanism applies to every job, whether or not any setting is changed.

A compressed video cannot be cut at an arbitrary frame. Inter-frame codecs describe most frames as differences from other frames, so a cut in the middle of a group of pictures leaves frames whose references are in a different chunk. Encoding those segments independently produces visible seams at every boundary.

TRNSCODE cuts on keyframes. A scene-detection pass finds real cut points in the picture, then adjacent segments are merged toward the target duration. The boundary lands where the encoder would place a keyframe in any case, so joining the chunks afterwards is a stream copy rather than a re-encode.

Important

Chunk size is a trade-off. Shorter chunks spread work more evenly across a fleet but force more keyframes, which costs bitrate at a given quality. Longer chunks are more efficient but leave fast workers idle at the end of a job while one slow chunk completes. The 12-second default is a balanced setting, not a fixed constraint.

Codec parity across the fleet#

Every chunk of a job must be encoded the same way, or the finished file is inconsistent in ways that are difficult to see and impossible to fix after the fact. Two different FFmpeg builds can produce measurably different output from identical arguments.

The scheduler therefore treats a worker's reported capability set as a matching constraint, not a hint. A worker that cannot produce the required codec does not receive those chunks. For this reason, every bundle ships its own tested FFmpeg in bin/ rather than using whatever build is installed on each machine.

Important

Pointing a worker at a host-installed FFmpeg with TRNSCODE_WORKER_FFMPEG_BINARY removes this guarantee. Output from that build may differ from the rest of the fleet.

Source and output transfer#

Workers need the source to encode from, and the master needs the results back. Transfer happens in one of two ways, selected per job automatically.

SituationBehaviour
Worker can already read the path: the same machine, or a shared mount visible at the same path on every machineThe worker opens the file directly. Nothing is copied across the network.
Worker cannot read the path: for example, a laptop on Wi-Fi with no shared mountThe master serves the bytes each chunk needs and accepts the encoded result back over HTTP, authorised by a signed, expiring token.

A shared filesystem is faster because the source is never copied, but it is not a requirement. A machine with only a network route to the master can still contribute.

Worker failure handling#

Chunks are independent units of work, which limits the cost of failure. If a worker stops responding mid-chunk, that chunk is reassigned to another worker. Chunks that already finished remain finished. The job loses the time spent on the one incomplete chunk, not the whole encode.

The same mechanism allows a worker to be shut down deliberately during a job: drain the worker, allow in-flight chunks to finish, and the fleet absorbs the loss.

The verification step#

Assembly is not the last stage. Once the chunks are joined and the audio is muxed back in, the master checks the result against what it expected: the duration must match the source within a one-frame tolerance, and if the source had audio, the output must have audio.

A job that fails verification is reported as failed rather than delivered. This check catches the failure mode in which FFmpeg exits 0 but produces a file that is incorrect without any error being raised.