Description
Normally out of the box ffmpeg uses threads=0 meaning all available threads, but with liquidsoap it seems stuck to a single thread. Am I just not seeing the right way to configure the encoder or is that being restricted somewhere else?
Using direct ffmpeg to transcode the same file easily loads up all cores and happily runs with -re as realtime rtmp output, but liquidsoap only running single thread struggles to transcode the video leading to catchup and stutter.
Steps to reproduce
Create basic script to transcode larger mp4 files, 4k for example
Expected behavior
Use all threads or obey threads parameter in encoder
Log extracts
Tons of catchup the moment liquidsoap starts transcoding
2026/03/17 23:35:03 >>> LOG START
2026/03/17 23:35:01 [ffmpeg.filter.bitstream:3] No valid mode found for filter pgs_frame_merge!
2026/03/17 23:35:01 [main:3] Liquidsoap 2.5.0+git@55b1c58af
2026/03/17 23:35:01 [main:3] Using: angstrom=0.16.1 base=v0.17.3 base.base_internalhash_types=v0.17.3 base.shadow_stdlib=v0.17.3 bigstringaf=0.10.0 bytes=[distributed with OCaml 4.02 or above] camlp-streams camomile.lib=2.0 cron=v2.2.0-1598-g55b1c58 cry=v2.2.0-1598-g55b1c58 ctypes=0.24.0 ctypes-foreign=0.24.0 curl=0.10.0 domain_shims dtools=v2.2.0-1598-g55b1c58 dune-build-info=3.21.1 dune-private-libs.dune-section=3.21.1 dune-site=3.21.1 dune-site.private=3.21.1 duppy=v2.2.0-1598-g55b1c58 ffmpeg-av=0a81aff ffmpeg-avcodec=0a81aff ffmpeg-avdevice=0a81aff ffmpeg-avfilter=0a81aff ffmpeg-avutil=0a81aff ffmpeg-swresample=0a81aff ffmpeg-swscale=0a81aff fileutils=v0.6.6 gen=1.1 integers lame=0.3.7 liquidsoap-lang=2.5.0 liquidsoap-lang.console=2.5.0 liquidsoap-lang.stdlib=2.5.0 liquidsoap-lang.tooling=2.5.0 liquidsoap_builtins=v2.2.0-1598-g55b1c58 liquidsoap_core=v2.2.0-1598-g55b1c58 liquidsoap_ffmpeg=v2.2.0-1598-g55b1c58 liquidsoap_file_watcher=v2.2.0-1598-g55b1c58 liquidsoap_lame=v2.2.0-1598-g55b1c58 liquidsoap_memtrace=v2.2.0-1598-g55b1c58 liquidsoap_ndi=v2.2.0-1598-g55b1c58 liquidsoap_ogg=v2.2.0-1598-g55b1c58 liquidsoap_optionals=v2.2.0-1598-g55b1c58 liquidsoap_oss=v2.2.0-1598-g55b1c58 liquidsoap_pulseaudio=v2.2.0-1598-g55b1c58 liquidsoap_runtime=v2.2.0-1598-g55b1c58 liquidsoap_sdl=v2.2.0-1598-g55b1c58 liquidsoap_speex=v2.2.0-1598-g55b1c58 liquidsoap_sqlite=v2.2.0-1598-g55b1c58 liquidsoap_ssl=v2.2.0-1598-g55b1c58 liquidsoap_stereotool=v2.2.0-1598-g55b1c58 liquidsoap_vorbis=v2.2.0-1598-g55b1c58 magic-mime=1.3.1 mem_usage=0.1.3 menhirLib=20260209 metadata=0.3.2 mm=0.8.6 mm.audio=0.8.6 mm.base=0.8.6 mm.image=0.8.6 mm.midi=0.8.6 mm.video=0.8.6 ndi=v2.2.0-1598-g55b1c58 ocaml_intrinsics_kernel=v0.17.1 ogg=1.0.0 ogg.decoder=1.0.0 ppx_compare.runtime-lib=v0.17.0 ppx_hash.runtime-lib=v0.17.0 ppx_sexp_conv.runtime-lib=v0.17.1 ppx_string.runtime=v0.17.0 pulseaudio=0.1.5 re sedlex=3.7 seq=[distributed with OCaml 4.07 or above] sexplib0=v0.17.0 speex=1.0.0 speex.decoder=1.0.0 sqlite3=5.4.0 ssl=0.7.0 stdlib-shims=0.3.0 stdlib_utils=v2.2.0-1598-g55b1c58 stereotool=v2.2.0-1598-g55b1c58 str=5.3.0 stringext=1.6.0 threads=5.3.0 tsdl=v1.2.0 tsdl-image=0.5 tsdl-ttf=0.6 unix=5.3.0 uri=4.4.0 vorbis=1.0.0 vorbis.decoder=1.0.0 xml-light=2.5
2026/03/17 23:35:01 [main:3]
2026/03/17 23:35:01 [main:3] DISCLAIMER: This version of Liquidsoap has been compiled from a snapshot of the
2026/03/17 23:35:01 [main:3] development code. As such, it should not be used in production unless you know
2026/03/17 23:35:01 [main:3] what you are doing!
2026/03/17 23:35:01 [main:3]
2026/03/17 23:35:01 [main:3] We are, however, very interested in any feedback about our development code and
2026/03/17 23:35:01 [main:3] committed to fix issues as soon as possible.
2026/03/17 23:35:01 [main:3]
2026/03/17 23:35:01 [main:3] If you are interested in collaborating to the development of Liquidsoap, feel
2026/03/17 23:35:01 [main:3] free to drop us a mail at <savonet-devl@lists.sf.net> or to join the slack chat
2026/03/17 23:35:01 [main:3] at <http://slack.liquidsoap.info>.
2026/03/17 23:35:01 [main:3]
2026/03/17 23:35:01 [main:3] Please send any bug report or feature request at
2026/03/17 23:35:01 [main:3] <https://github.com/savonet/liquidsoap/issues>.
2026/03/17 23:35:01 [main:3]
2026/03/17 23:35:01 [main:3] We hope you enjoy this snapshot build of Liquidsoap!
2026/03/17 23:35:01 [main:3]
2026/03/17 23:35:01 [clock:3] Using builtin (low-precision) implementation for latency control
2026/03/17 23:35:03 [main:3] User script loaded in 1.42 seconds.
2026/03/17 23:35:03 [frame:3] Using 44100Hz audio, 25Hz video, 44100Hz main.
2026/03/17 23:35:03 [frame:3] Default video frame size: 1280x720 (auto-detection enabled).
2026/03/17 23:35:03 [frame:3] Targeting 'frame.duration': 0.02s = 882 ticks.
2026/03/17 23:35:03 [sandbox:3] Sandboxing disabled
2026/03/17 23:35:03 [startup:3] FFmpeg filters registration: 0.04s
2026/03/17 23:35:03 [startup:3] FFmpeg bitstream filters registration: 0.00s
2026/03/17 23:35:03 [startup:3] main script hash computation: 0.05s
2026/03/17 23:35:03 [startup:3] main script cache retrieval: 0.05s
2026/03/17 23:35:03 [startup:3] stdlib hash computation: 0.05s
2026/03/17 23:35:03 [startup:3] Loading stdlib from cache!
2026/03/17 23:35:03 [startup:3] stdlib cache retrieval: 0.51s
2026/03/17 23:35:03 [startup:3] Typechecking main script: 0.05s
2026/03/17 23:35:03 [startup:3] Evaluating main script: 0.03s
2026/03/17 23:35:03 [clock:3] Starting top-level clock output.file with sources: output.file (output), mksafe (passive), playlist_list (passive), safe_blank (passive) and sync: auto
2026/03/17 23:35:03 [harbor:3] Adding handler for 'GET ^/control$' on port 6520
2026/03/17 23:35:03 [sdl:3] Loading SDL version 2.30.0
2026/03/17 23:35:03 [video.converter:3] Using preferred video converter: ffmpeg.
2026/03/17 23:35:03 [audio.converter:3] Using samplerate converter: ffmpeg.
2026/03/17 23:35:03 [video.text:3] Using sdl implementation
2026/03/17 23:35:03 [output.file:3] Content type is {audio=pcm(stereo),video=canvas}.
2026/03/17 23:35:03 [mksafe:3] Content type is {audio=pcm(stereo),video=canvas}.
2026/03/17 23:35:03 [playlist_list:3] Content type is {audio=pcm(stereo),video=canvas}.
2026/03/17 23:35:03 [safe_blank:3] Content type is {audio=pcm(stereo),video=canvas}.
2026/03/17 23:35:03 [mksafe:3] Switch to safe_blank.
2026/03/17 23:35:03 [insert_initial_track_mark:3] Content type is {audio=pcm(stereo),video=canvas}.
2026/03/17 23:35:34 [decoder.ffmpeg.description:3] Analyzing container for format: "mov,mp4,m4a,3gp,3g2,mj2", uri: "media/Blues Brothers 2160p color corrected.mp4"
2026/03/17 23:35:34 [decoder.ffmpeg:3] FFmpeg recognizes "media/Blues Brothers 2160p color corrected.mp4" as audio: {codec: aac, 48000Hz, 2 channel(s)}, video: {codec: h264, 3840x2076, yuv420p}
2026/03/17 23:35:34 [decoder.ffmpeg.description:3] Requested content-type: {audio=pcm(stereo),video=canvas}
2026/03/17 23:35:34 [decoder.ffmpeg.description:3] Decoded content-type: {audio=pcm(stereo),video=canvas}
2026/03/17 23:35:34 [playlist_list:3] Prepared "media/Blues Brothers 2160p color corrected.mp4" (RID 0).
2026/03/17 23:35:34 [mksafe:3] Switch to playlist_list with transition.
2026/03/17 23:35:34 [insert_initial_track_mark.1:3] Content type is {audio=pcm(stereo),video=canvas}.
[buffer @ 0x7bfaddfec580] Changing video frame properties on the fly is not supported by all filters.
[buffer @ 0x7bfaddfec580] filter context - w: 3840 h: 2076 fmt: 0 csp: unknown range: unknown, incoming frame - w: 3840 h: 2076 fmt: 0 csp: bt709 range: tv pts_time: 0
2026/03/17 23:35:37 [clock.output.file:2] Latency is too high: we must catchup 0.23 seconds! Check if your system can process your stream fast enough (CPU usage, disk access, etc) or if your stream should be self-sync (can happen when using `input.ffmpeg`). Refer to the latency control section of the documentation for more info.
2026/03/17 23:35:38 [clock.output.file:2] Latency is too high: we must catchup 0.59 seconds! Check if your system can process your stream fast enough (CPU usage, disk access, etc) or if your stream should be self-sync (can happen when using `input.ffmpeg`). Refer to the latency control section of the documentation for more info.
2026/03/17 23:35:39 [clock.output.file:2] Latency is too high: we must catchup 1.04 seconds! Check if your system can process your stream fast enough (CPU usage, disk access, etc) or if your stream should be self-sync (can happen when using `input.ffmpeg`). Refer to the latency control section of the documentation for more info.
2026/03/17 23:35:40 [clock.output.file:2] Latency is too high: we must catchup 1.50 seconds! Check if your system can process your stream fast enough (CPU usage, disk access, etc) or if your stream should be self-sync (can happen when using `input.ffmpeg`). Refer to the latency control section of the documentation for more info.
2026/03/17 23:35:41 [clock.output.file:2] Latency is too high: we must catchup 1.87 seconds! Check if your system can process your stream fast enough (CPU usage, disk access, etc) or if your stream should be self-sync (can happen when using `input.ffmpeg`). Refer to the latency control section of the documentation for more info.
2026/03/17 23:35:42 [clock.output.file:2] Latency is too high: we must catchup 2.20 seconds! Check if your system can process your stream fast enough (CPU usage, disk access, etc) or if your stream should be self-sync (can happen when using `input.ffmpeg`). Refer to the latency control section of the documentation for more info.
2026/03/17 23:35:43 [clock.output.file:2] Latency is too high: we must catchup 2.54 seconds! Check if your system can process your stream fast enough (CPU usage, disk access, etc) or if your stream should be self-sync (can happen when using `input.ffmpeg`). Refer to the latency control section of the documentation for more info.
Script extracts
enc = %ffmpeg(format="flv",
%audio(codec="aac"),
%video(codec="libx264", maxrate="10M", bufsize="20M", b="10M",
"x264-params"="keyint=12:scenecut=0",
preset="ultrafast"))
I tried adding threads=0 to it as well as to the x264-params, but that didn't work. Neither did any other values for threads.
Liquidsoap version
Liquidsoap 2.5.0+git@55b1c58af
Liquidsoap build config
* Liquidsoap version : 2.5.0+git@55b1c58af
* Compilation options
- Release build : false
- Git SHA : 55b1c58af
- OCaml version : 5.3.0
- OS type : Unix
- Libs versions : angstrom=0.16.1 base=v0.17.3 base.base_internalhash_types=v0.17.3 base.shadow_stdlib=v0.17.3 bigstringaf=0.10.0 bytes=[distributed with OCaml 4.02 or above] camlp-streams camomile.lib=2.0 cron=v2.2.0-1598-g55b1c58 cry=v2.2.0-1598-g55b1c58 ctypes=0.24.0 ctypes-foreign=0.24.0 curl=0.10.0 domain_shims dtools=v2.2.0-1598-g55b1c58 dune-build-info=3.21.1 dune-private-libs.dune-section=3.21.1 dune-site=3.21.1 dune-site.private=3.21.1 duppy=v2.2.0-1598-g55b1c58 ffmpeg-av=0a81aff ffmpeg-avcodec=0a81aff ffmpeg-avdevice=0a81aff ffmpeg-avfilter=0a81aff ffmpeg-avutil=0a81aff ffmpeg-swresample=0a81aff ffmpeg-swscale=0a81aff fileutils=v0.6.6 gen=1.1 integers lame=0.3.7 liquidsoap-lang=2.5.0 liquidsoap-lang.console=2.5.0 liquidsoap-lang.stdlib=2.5.0 liquidsoap-lang.tooling=2.5.0 liquidsoap_builtins=v2.2.0-1598-g55b1c58 liquidsoap_core=v2.2.0-1598-g55b1c58 liquidsoap_ffmpeg=v2.2.0-1598-g55b1c58 liquidsoap_file_watcher=v2.2.0-1598-g55b1c58 liquidsoap_lame=v2.2.0-1598-g55b1c58 liquidsoap_memtrace=v2.2.0-1598-g55b1c58 liquidsoap_ndi=v2.2.0-1598-g55b1c58 liquidsoap_ogg=v2.2.0-1598-g55b1c58 liquidsoap_optionals=v2.2.0-1598-g55b1c58 liquidsoap_oss=v2.2.0-1598-g55b1c58 liquidsoap_pulseaudio=v2.2.0-1598-g55b1c58 liquidsoap_runtime=v2.2.0-1598-g55b1c58 liquidsoap_sdl=v2.2.0-1598-g55b1c58 liquidsoap_speex=v2.2.0-1598-g55b1c58 liquidsoap_sqlite=v2.2.0-1598-g55b1c58 liquidsoap_ssl=v2.2.0-1598-g55b1c58 liquidsoap_stereotool=v2.2.0-1598-g55b1c58 liquidsoap_vorbis=v2.2.0-1598-g55b1c58 magic-mime=1.3.1 mem_usage=0.1.3 menhirLib=20260209 metadata=0.3.2 mm=0.8.6 mm.audio=0.8.6 mm.base=0.8.6 mm.image=0.8.6 mm.midi=0.8.6 mm.video=0.8.6 ndi=v2.2.0-1598-g55b1c58 ocaml_intrinsics_kernel=v0.17.1 ogg=1.0.0 ogg.decoder=1.0.0 ppx_compare.runtime-lib=v0.17.0 ppx_hash.runtime-lib=v0.17.0 ppx_sexp_conv.runtime-lib=v0.17.1 ppx_string.runtime=v0.17.0 pulseaudio=0.1.5 re sedlex=3.7 seq=[distributed with OCaml 4.07 or above] sexplib0=v0.17.0 speex=1.0.0 speex.decoder=1.0.0 sqlite3=5.4.0 ssl=0.7.0 stdlib-shims=0.3.0 stdlib_utils=v2.2.0-1598-g55b1c58 stereotool=v2.2.0-1598-g55b1c58 str=5.3.0 stringext=1.6.0 threads=5.3.0 tsdl=v1.2.0 tsdl-image=0.5 tsdl-ttf=0.6 unix=5.3.0 uri=4.4.0 vorbis=1.0.0 vorbis.decoder=1.0.0 xml-light=2.5
- architecture : amd64
- host : x86_64-pc-linux-gnu
- target : x86_64-pc-linux-gnu
- system : linux
- ocamlopt_cflags : -O2 -fno-strict-aliasing -fwrapv -pthread
- native_c_compiler : gcc -O2 -fno-strict-aliasing -fwrapv -pthread -D_FILE_OFFSET_BITS=64
- native_c_libraries : -lm -lpthread
* Configured paths
- mode : default
- standard library : (set by dune-site)
- scripted binaries : (set by dune-site)
- rundir : (set by dune-site)
- logdir : (set by dune-site)
- user cache : $HOME/.cache/liquidsoap (override with $LIQ_CACHE_USER_DIR)
- system cache : (set by dune-site) (override with $LIQ_CACHE_SYSTEM_DIR)
- camomile files : (set by dune-site)
* Supported input formats
- MP3 : no (requires mad)
- AAC : no (requires faad)
- Ffmpeg : yes
- Flac (native) : no (requires flac)
- Flac (ogg) : no (requires ogg)
- Opus : no (requires opus)
- Speex : yes
- Theora : no (requires theora)
- Vorbis : yes
- WAV/AIFF : yes (native)
* Supported output formats
- FDK-AAC : no (requires fdkaac)
- FFmpeg : yes
- MP3 : yes
- MP3 (fixed-point) : no (requires shine)
- Flac (native) : no (requires flac)
- Flac (ogg) : no (requires ogg)
- Opus : no (requires opus)
- Speex : yes
- Theora : no (requires theora)
- Vorbis : yes
- WAV/AIFF : yes (native)
* Tags
- AAC : no (requires faad)
- FFmpeg : yes
- FLAC (native) : no (requires flac)
- Flac (ogg) : no (requires ogg)
- Native decoder : yes
- Vorbis : yes
* Input / output
- ALSA : no (requires alsa)
- AO : no (requires ao)
- FFmpeg : yes
- JACK : no (requires bjack)
- NDI : yes
- OSS : yes
- Portaudio : no (requires portaudio)
- Pulseaudio : yes
- SRT : no (requires srt)
* Audio manipulation
- FFmpeg : yes
- LADSPA : no (requires ladspa)
- Lilv : no (requires lilv)
- Samplerate : no (requires samplerate)
- SoundTouch : no (requires soundtouch)
- StereoTool : yes
* Video manipulation
- camlimages : no (requires camlimages)
- FFmpeg : yes
- frei0r : no (requires frei0r)
- SDL : yes
* MIDI manipulation
- DSSI : no (requires dssi)
* Visualization
- GD : no (requires gd)
- Graphics : no (requires graphics)
- SDL : yes
* Additional libraries
- FFmpeg filters : yes
- FFmpeg devices : yes
- inotify : no (requires inotify)
- irc : no (requires irc-client-unix)
- jemalloc : no (requires jemalloc)
- lo : no (requires lo)
- memtrace : no (requires memtrace)
- osc : no (requires osc-unix)
- ssl : yes
- sqlite3 : yes
- tls : no (requires tls-liquidsoap)
- posix-time2 : no (requires posix)
- windows service : no (requires winsvc)
- YAML support : no (requires yaml)
- XML playlists : no (requires xmlm)
* Monitoring
- Prometheus : no (requires prometheus)
Installation method
From OPAM
FFmpeg CLI reproduction (if applicable)
No response
Additional Info
No response
Description
Normally out of the box ffmpeg uses threads=0 meaning all available threads, but with liquidsoap it seems stuck to a single thread. Am I just not seeing the right way to configure the encoder or is that being restricted somewhere else?
Using direct ffmpeg to transcode the same file easily loads up all cores and happily runs with -re as realtime rtmp output, but liquidsoap only running single thread struggles to transcode the video leading to catchup and stutter.
Steps to reproduce
Create basic script to transcode larger mp4 files, 4k for example
Expected behavior
Use all threads or obey threads parameter in encoder
Log extracts
Tons of catchup the moment liquidsoap starts transcoding
Script extracts
I tried adding threads=0 to it as well as to the x264-params, but that didn't work. Neither did any other values for threads.
Liquidsoap version
Liquidsoap build config
Installation method
From OPAM
FFmpeg CLI reproduction (if applicable)
No response
Additional Info
No response