Skip to content
Blog

What it takes to self-host an AI video generation pipeline

Hardware sizing, container layout, the shared-directory trap, and the throughput maths for running slide-to-video rendering on your own GPU.

Running a slide-to-video pipeline on your own hardware is very achievable, and there is one specific thing that trips up almost everyone who tries it. This is a practical note on sizing and layout.

Hardware

The pipeline splits cleanly across two resource types, which is what makes a modest machine viable:

  • CPU only: slide rasterisation, text extraction, text-to-speech, final encoding.
  • GPU: lip-sync generation. This is the only stage that needs one.

A single NVIDIA card with 8 GB of VRAM is enough to run the renderer comfortably. More VRAM does not buy much for this workload; a second card buys roughly double throughput, because rendering is serialised per device.

Budget storage generously. Models plus intermediate artifacts for a large batch add up fast, and rendered video is large. 100 GB is a reasonable floor, more if you retain output locally.

Container layout

Keep the rendering service in its own container with GPU passthrough, and keep the orchestrating application separate. The boundary between them is a shared filesystem, not an API:

  • The application writes a narration audio file into a directory it owns.
  • The renderer reads that file from what it sees as its own data directory.
  • The renderer writes the completed clip back to the same directory.
  • The application picks it up and uploads it to your storage.

The shared-directory trap

This is the part that fails. The application and the container must be looking at the same directory, not two directories that happen to have the same name.

On a single host, that is a bind mount: -v /opt/heygem/data:/code/data. The application is configured with the host path; the container sees the mount path.

If the application runs on a different host from the GPU, you need NFS (or equivalent) mounting the same export at the same path on both machines. People frequently mount it at different paths and then spend a day debugging “file not found” on a file they can see.

Verify it directly: write a file from the application host, then list the directory from inside the container. If you cannot see it, nothing downstream will work.

The other half of the trap is result-file discovery. Do not have the application guess filenames (<code>-r.mp4, temp/<code>.mp4, …). Take the path from the renderer’s completion response and map it onto the host path. Guessing works until two jobs race, at which point you silently pick up the wrong file.

Throughput maths

Measure two numbers on your own content:

  • GPU seconds per rendered page — typically tens of seconds
  • CPU seconds per page for TTS — typically a few seconds, and it parallelises

Then:

total_time ≈ pages × gpu_seconds_per_page / gpu_count  +  pages × tts_seconds / tts_parallelism

Rendering dominates. A 20-page deck is tens of minutes on one card. Five hundred decks of twenty pages is an overnight job on one card, or a couple of hours across several.

Worth noting: do not put TTS in the same serial queue as rendering. It is CPU work, and serialising it behind GPU jobs wastes wall-clock time for no reason.

Failure handling you need from day one

  • Page-level retry. If page 12 fails, re-render page 12, not pages 1 through 20. A pipeline that resets the whole deck on a single failure multiplies your GPU spend by your failure rate.
  • Stale task recovery. Jobs live in an in-memory queue. If the process restarts mid-render, the status stays “running” forever and the job becomes undeletable. Add a startup sweep that marks anything untouched beyond a timeout as failed.
  • Audio is the master clock. Cut each page to the narration length, explicitly. Do not let a shorter rendered clip silently truncate the audio, and do not attach audio from the renderer’s output — use the TTS file you synthesised, so a missing audio stream cannot fail the encode.

The operational payoff

Once it runs, the marginal cost of another video is electricity. That is the whole argument for self-hosting, and it is why the upfront work pays off specifically for large existing libraries rather than one-off videos.

engineering self-hosted gpu
Private beta

See it run on one of your own decks

Send us a representative deck and we will render a few pages with your presenter choice. You will see real output from your own material before committing to anything.

No spam. One email when the private beta opens.

No credit card. No self-serve signup yet — we onboard pilot teams by hand.