We offer customization solutions and support ([email protected]) | Visit us on bitbyte3 for complete VOD solutions with apps.
NixStream
Guides

Encoding & Transcoding

Video encoding pipeline, profiles, and output formats

When you upload a video, NixStream transcodes it into adaptive streaming packages using FFmpeg, Google Shaka Packager, and Bento4. Work runs in background queue jobs so the admin panel stays responsive.

Upload to playback flow

Here is what happens after you upload a file:

  1. Upload accepted. The file is stored and a VideoSource record is created with status "pending".
  2. Job dispatched. VideoEncodingJob is pushed to the video-encoding Redis queue.
  3. Transcoding starts. A queue worker calls bin/media-vod with your encoding profile settings.
  4. Packaging. FFmpeg creates video and audio renditions. Shaka Packager builds HLS and DASH manifests.
  5. Thumbnails. Preview images and a thumbnail VTT sprite are generated.
  6. Complete. Status changes to "completed". The video is playable, shareable, and available via API.

If something fails, status becomes "failed". Check queue logs for the error.

Customizing the encoder

bin/media-vod is the NixStream encoding CLI (upstream). It's a CLI tool, not an HTTP API.

Laravel never calls an encoder service over the network. Queue workers shell out to the binary path in media_cli_path with profile settings from the database. To customize behavior:

  • Tune encoding profiles in Settings > Encoding
  • Run bin/media-vod --help for CLI flags
  • Replace or rebuild the binary from the upstream repo if you need lower-level changes

Manifest edits after encode use bin/manifest (upstream), same subprocess pattern.

Output structure

Encoded files land in storage/app/public/videos/{date}/{slug}/outputs/:

outputs/
├── master.m3u8          # HLS master playlist
├── stream.mpd           # DASH manifest
├── video/avc1/{1..6}/   # Multiple resolutions
├── audio/{lang}/        # Multi-audio tracks
├── subtitles/{lang}/    # Caption files
└── thumbnails/          # Poster and sprite

Encoding profiles

Open Settings > Encoding to manage profiles. Each profile defines:

  • Name: Shown in the upload UI
  • Resolutions: Output ladder (360p through 1080p or higher)
  • Bitrates: Target video bitrates per resolution
  • Audio: AAC stereo settings
  • Encryption: AES-128 always applied for HLS/CMAF (Edge decrypts at playback)
  • Packaging: HLS, DASH, or both

New uploads use the default profile unless you override it per video or collection.

Queue workers

Encoding is CPU-heavy. You need dedicated workers processing the video-encoding queue.

Production command:

php artisan queue:work redis --queue=high,default,video-encoding --tries=3

Docker runs two workers in the nixstream_queue container via Supervisor. Scale when your backlog grows:

docker compose up -d --scale queue=3

Monitor worker status:

docker compose exec queue supervisorctl status

Check queue depth:

docker compose exec redis redis-cli llen queues:video-encoding

Edge delivery and AES-128 (VOD)

VOD HLS/CMAF packages are AES-128 encrypted when enabled on the encoding profile. Playback uses signed Edge URLs for HLS and DASH (MPD). Edge decrypts segments server-side; keys never reach the player.

Live streams use signed Edge URLs only. Segments are cleartext on disk (no #EXT-X-KEY in source playlists). Stream keys never appear in player URLs; Edge serves live media through opaque signed paths.

Local storage requires the Edge integration (auto-connected in Docker). AES-128 and signed tokens don't work with cloud storage alone, only if your CDN supports them. See Security, Edge media.

Configuration reference

KeyPurpose
media_cli_pathPath to bin/media-vod
APP_ENCODING_MAX_RESOLUTIONMax output height (default 4000)
FFMPEG_BINARIESFFmpeg binary path
SHAKA_PACKAGER_BINARIESShaka Packager path
REDIS_QUEUE_RETRY_AFTERJob timeout (7200 seconds in Docker)

Tuning tips

  • Match your resolution ladder to your audience. Mobile-first catalogs can use fewer rungs.
  • Higher bitrates improve quality but increase storage and bandwidth costs.
  • Test with a short clip before bulk-encoding a large library.
  • Scale workers before a big upload batch, not after jobs start piling up.
  • Watch disk space in storage/app/public/videos/ during heavy encoding periods.

When encoding gets stuck

If videos stay in "processing" for a long time, check worker status (supervisorctl status or docker compose exec queue supervisorctl status), read queue logs, confirm Redis is up, verify disk space, then restart workers if needed.

See troubleshooting for more detail.

On this page