Very basic PoC to try out HLS with multiple audio and video tracks, with live transcoding using NVENC and scaling with CUDA.
Find a file
2025-10-09 22:21:38 +02:00
ffmpeg init 2025-10-09 22:21:38 +02:00
model init 2025-10-09 22:21:38 +02:00
.gitignore init 2025-10-09 22:21:38 +02:00
db.go init 2025-10-09 22:21:38 +02:00
go.mod init 2025-10-09 22:21:38 +02:00
go.sum init 2025-10-09 22:21:38 +02:00
handlersMedia.go init 2025-10-09 22:21:38 +02:00
handlersPreset.go init 2025-10-09 22:21:38 +02:00
import.go init 2025-10-09 22:21:38 +02:00
index.html init 2025-10-09 22:21:38 +02:00
main.go init 2025-10-09 22:21:38 +02:00
middleware.go init 2025-10-09 22:21:38 +02:00
player.html init 2025-10-09 22:21:38 +02:00
README.md init 2025-10-09 22:21:38 +02:00
server.go init 2025-10-09 22:21:38 +02:00

stream-poc2

Very basic PoC to try out HLS with multiple audio and video tracks, with live transcoding using NVENC. (Subtitles are not supported) (Only 16:9 video is supported)

High-level overview

There is a "db" where all imported media data is stored.

The code is split into two: "import" and "serve".

"import" used to import various media files into that "db". During import, streams are extracted, and sliced up to be served by HLS. All audio streams are encoded to mp3 if needed, for better compatibility. Also, a few video slices are pre-encoded and stored in the "cache" folder.

"serve" runs the http server to watch the imported media and tune the various dials.

Those dials are:

  • "Video" here are all the video "profiles" in the HLS stream, all of them except "orig" is transcoded live with ffmpeg and NVENC (if not served from the cache)
  • "Audio" is the audio stream.
  • "NVENC Preset" The various AVC/HEVC presets supported by NVENC this sets the value globally on the server

When tuning the dials, the video buffer is flushed, so the effect can be seen immanently. This is only for showcase as it is not desired in a real-world scenario.

Usage

Create a new folder for the "db":

This is where all metadata, original media chunks and cache is stored.

mkdir db

Import media files:

go run . import <path to media file> <media id>

"media id" is a url-safe string used to identify the media file on http and in the db folder.

Then start the server:

go run . server

Then open http://localhost:8080 in your browser, select the media and enjoy!

Code notes

chunks, slices and segments all mean the same trough the code.

db structure:

  • db/ Root folder for the "db".
    • {id}/ Folder for each imported media, identified by "id".
      • meta.json All metadata used by the server to handle the video.
      • ffprobe.json Output of ffprobe stored for debugging purposes.
      • segments_video.csv Output of the segment data for the video stream. Used during import, kept for debugging.
      • segments_audio_{idx}.csv Output of the segment data for the audio stream identified by "idx". Used during import, kept for debugging.
      • video/ Folder for the video segments in the original format.
        • s{i}.ts Video segment number "i".
      • audio/ Folder for the audio segments in mp3 format.
        • {idx}/ Folder for the audio segments for the audio stream identified by "idx".
          • s{i}.ts Audio segment number "i".
      • cache/ Cache folder for pre-transcoded video segments.
        • video/ Video cache folder.
          • {profile}/ Folder for a specific transcoding profile.
            • s{i}.ts Transcoded video segment number "i".