Skip to content

Instantly share code, notes, and snippets.

@BusterNeece
Last active June 16, 2025 16:20
Show Gist options
  • Save BusterNeece/5dbfb4dbc1846055c9ab07a7c685899c to your computer and use it in GitHub Desktop.
Save BusterNeece/5dbfb4dbc1846055c9ab07a7c685899c to your computer and use it in GitHub Desktop.
Liquidsoap 2.1 Video Stream with HLS
# What is This Script?
# This script allows you to broadcast your AzuraCast radio signal to a remote video stream, using a
# static video file that loops in the background and dynamically writing the currently playing track
# on top of that video file.
#
# This script replaces the previous "radio-video-stream" project, allowing you to manage files directly from
# within AzuraCast and not requiring any changes to your Docker configuration at all.
#
# To use this script, you must be running at least AzuraCast 0.19.0 or a later Rolling Release version.
#
# Before Using This Script:
# - Upload a video file to a folder under your station's media library (in the example below, named "videostream")
# - Choose a font to display Now Playing data and upload a TTF version of that font to the same folder
#
# How to Use This Script
# - Copy the section below.
# - Visit your station's "Edit Liquidsoap Configuration" section (under "Broadcasting" in newer versions)
# - Paste the code into the bottom-most configuration section
# - Customize as necessary with your station's media directory and font specifications
# - Click "Save Changes" and then "Restart Broadcasting"
# - Enjoy!
#
# VIDEO STREAM
#
# Edit This: Station Base Directory
station_base_dir = "/var/azuracast/stations/station_name"
# Edit This: YouTube Stream Key
youtube_key = "abcd-1234-abcd-1234"
# Path to the video file that will loop behind the Now Playing text (you have to provide this)
video_file = station_base_dir ^ "/media/videostream/video.mp4"
# Path to a font (TTF) file that will be used to draw the Now Playing text (you have to provide this)
font_file = station_base_dir ^ "/media/videostream/font.ttf"
# A static file auto-generated by AzuraCast in the "config" dir.
nowplaying_file = station_base_dir ^ "/config/nowplaying.txt"
# Align text
font_size = "50"
font_x = "340"
font_y = "990"
font_color = "white"
# Method to overlay now playing text
def add_nowplaying_text(s) =
def mkfilter(graph)
let {video = video_track} = source.tracks(s)
video_track = ffmpeg.filter.video.input(graph, video_track)
video_track = ffmpeg.filter.drawtext(fontfile=font_file,fontsize=font_size,x=font_x,y=font_y,fontcolor=font_color,textfile=nowplaying_file,reload=5,graph,video_track)
video_track = ffmpeg.filter.video.output(graph, video_track)
source({
video = video_track
})
end
ffmpeg.filter.create(mkfilter)
end
videostream = single(video_file)
videostream = add_nowplaying_text(videostream)
videostream = source.mux.video(video=videostream, radio)
# Output to YouTube
enc = %ffmpeg(
format="mpegts",
%video.raw(codec="libx264", pixel_format="yuv420p", b="300k", preset="superfast", r=25, g=50),
%audio(
codec="aac",
samplerate=44100,
channels=2,
b="96k",
profile="aac_low"
)
)
output.youtube.live.hls(key=youtube_key, fallible=true, encoder=enc, videostream)
@radiorecordua
Copy link

radiorecordua commented Apr 27, 2025 via email

@Ferz0id
Copy link

Ferz0id commented May 6, 2025

2025/05/06 14:09:30 [request:3] Nonexistent file or ill-formed URI "/var/azuracast/stations/melodic_drumnbass_radio/video/render.mp4"!

How can I fix this?

@radiorecordua
Copy link

radiorecordua commented May 6, 2025 via email

@alexaungmyooo
Copy link

Rolling Release #d183997 (2025-02-05 17:30) • Docker • PHP 8.4
`Server CPU Specification Summary
Architecture: x86_64 (64-bit)

CPU Model: AMD EPYC Milan Processor @ 2.0 GHz (virtualized under KVM)

CPU Cores: 2 cores (1 socket, 1 core per socket, 2 threads per core / Hyperthreading enabled)

Cache:

L1d: 32 KiB

L1i: 32 KiB

L2: 512 KiB

L3: 32 MiB

Virtualization: KVM full virtualization

Features: SSE, SSE2, AVX, AVX2, AES, Hypervisor support, and others

CPU Usage: (Your monitoring shows max ~70% under load, typical 16%)

Load Average: (1-min: 0.57, 5-min: 0.94, 15-min: 0.74) — indicates light to moderate load`

We're using the Liquidsoap script provided to stream our station to YouTube. As soon as we enabled it, both the radio stream and the video started buffering. This only happens when the YouTube streaming is active—without it, everything runs smoothly.

Our server has sufficient CPU and RAM available, and there's no disk or network bottleneck that we can identify. We suspect the issue may be related to the YouTube streaming configuration, ffmpeg encoder settings, or how the script is handling video looping and audio muxing.

Can you help us identify what might be causing the buffering? Any advice or recommended changes to improve stability would be greatly appreciated.

@alexaungmyooo
Copy link

Может ли кто-нибудь помочь мне настроить это?
Да, я могу.

@radiorecorduaМожете ли вы мне помочь, пожалуйста?
есть 5 разделов, куда я могу вставить этот скрипт. он должен быть в самом нижнем разделе под "# Remote Relays"? должен ли я объединить URL и ключ следующим образом? stream_key = "rtmp://ВАШ RTMP URL/КЛЮЧ-ПОТОКА"

`#

VIDEO STREAM

Edit This: Station Base Directory

station_base_dir = "/var/azuracast/stations/"

Stream Key

url = " "

Fetch and encode video

video_file = station_base_dir ^ "/media/.mp4"

Write now playing to the video file

font_file = station_base_dir ^ "/media/ttmussels-bolditalic.ttf"

A static file auto-generated by AzuraCast in the "config" dir.

nowplaying_file = station_base_dir ^ "/config/nowplaying.txt"

Align text

font_size = "40" font_x = "20" font_y = "900" font_color = "white"

Method to overlay now playing text

def add_nowplaying_text(s) = def mkfilter(graph) let {video = video_track} = source.tracks(s) video_track = ffmpeg.filter.video.input(graph, video_track) video_track = ffmpeg.filter.drawtext(fontfile=font_file,fontsize=font_size,x=font_x,y=font_y,fontcolor=font_color,textfile=nowplaying_file,reload=5,graph,video_track) video_track = ffmpeg.filter.video.output(graph, video_track)

source({
  video = video_track
})

end

ffmpeg.filter.create(mkfilter) end

videostream = single(video_file) videostream = add_nowplaying_text(videostream) videostream = source.mux.video(video=videostream, radio)

Output to YouTube

enc = %ffmpeg( format="flv", %video.raw(codec="libx264", pixel_format="yuv420p", b="2500k", preset="superfast", r=25, g=50), %audio( codec="aac", samplerate=44100, channels=2, b="96k", profile="aac_low" ) )

output.url(fallible=true, url=url, enc, videostream)`

Good afternoon, here is a working configuration for video broadcasting, suitable for any platforms and services, not limited to YouTube, you just need to specify the paths to your working directory and files.

May I know what is the different

format="flv"
output.url(fallible=true, url=url, enc, videostream)

format="mpegts"
output.youtube.live.hls(key=youtube_key, fallible=true, encoder=enc, videostream)

I use your but i got the error

@ruohki
Copy link

ruohki commented Jun 16, 2025

Is there any way to make this work with hardware encoding like h264_vaapi?
just using something like
%video.raw(codec="h264_vaapi", pixel_format="nv12", b="2000k", r=25, g=50) will end up horribly desync or not playabale at all

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment