X9k3
The Official X9k3 repo: x9k3 is an ABR HLS SCTE-35 Injector and Segmenter. Of course it's powered by threefive.
Install / Use
/learn @superkabuki/X9k3README
x9k3
x9k3 Injects SCTE-35 Into HLS
x9k3 News
-
<s>I'm trying add support for injesting SRT streams. I have SRT working with threefive.the issue I'm having with x9k3 is disconnecting and reconnecting takes about 5 seconds longer that I want it to, and I'm ironing that out.</s> SRT support for input videos is now working.
-
<s>Expect a new release with SRT support by February.</s> x9k3 v1.0.13 was released 01/31/2026.
-
python 3.14 makes changes to the default multiprocessing spawn method, I fixed that in x9k3 on 01/14/2026.
-
x9k3 runs perfectly on python3, but x9k3 runs best on pypy3. It's all about the JIT man.
Adrian
</samp>
Current Version: v1.0.21
- Updated threefive to 3.0.83
- Fixed adbreak3
- Auto-Enabbled Program Date Time tags when EXT-X-DATARANGE tags are used.
- other top secret Jmes Bond type stuff.
Features
- All SCTE-35 HLS Tags are Supported.
- Add SCTE-35 Tags to ABR HLS
- Segment MPEGTS streams into HLS and transfer SCTE-35 or add new SCTE-35 Tags
- SCTE-35 Cues in Mpegts Streams are Translated into HLS tags.
- SCTE-35 Cues can be added from a Sidecar File.
- Segments are Split on SCTE-35 Cues as needed.
- Segments Start on iframes.
- Supports h264 and h265 .
- Multi-protocol. Input sources may be Files, Http(s), Multicast, SRT, or Unicast UDP streams.
- Supports Live Streaming.
Want to see something cool?
I'm working with a friend of mine on his HLS analyzing web app. This is why he made threefive.js, which is pretty damn good actually. Stay tuned for details! <img width="1187" height="529" alt="image" src="https://github.com/user-attachments/assets/a3987808-b48e-4402-a750-8bf229770d17" />
Documentation
Q.
What`s up with all the releases?
A.
Whenever I figure something out or fix a bug, I make a new release. I'm not going to make you wait for a bug fix. This way, releases are incremental, rather than brand new software. Unless I have a really really good reason not to, I maintain backwards compatibilty and the interface, and by interface I mean function and method calls and such. New releases are designed to work with your existing code.<BR> Sometimes I just make a stupid mistake doing the build and have to do a new one.
- Install
- Use
- Cli
- Switches ( --this and --that)
- Usage Examples
- Lib (how to use x9k3 as a library)
- Sidecar Files (these are how you add the SCTE-35, super important)
- Adding SCTE-35 in real time
- SCTE-35 Splice Immediate (not the same as real time)
- SCTE-35 Generation with adbreak3
- Playlists (make a playlist of MPEGTS or M3u8 files and feed it to x9k3 as input)
- Cli
- HLS Stuff
- HLS as Input
- ABR HLS (there are some terms and conditions)
- ABR in Code (in less than ten lines)
- Byterange HLS
- Live HLS (sliding windows, deleting segments, all that jazz)
- Looping videos (play the same thing over and over)
- Cues
- SCTE-35 Tags
Install
- Use pip to install the x9k3 lib and the executable scripts x9k3, adbreak3, and adinterval3.
# python3
python3 -mpip install x9k3
# pypy3
pypy3 -mpip install x9k3
- Both OpenBSD and Debian now require '--break-system-packages' to be appended to the pip install command if you are not using a venv.
Details
-
X-SCTE35, X-CUE, X-DATERANGE, or X-SPLICEPOINT HLS tags can be generated. set with the
--hls_tagswitch. -
reading from stdin now available
-
Segments are cut on iframes.
-
Segment time is 2 seconds or more, determined by GOP size. Can be set with the
-tswitch or by settingX9K3.args.time -
Segments are named seg1.ts seg2.ts etc...
-
For SCTE-35, Video segments are cut at the the first iframe >= the splice point pts.
-
If no pts time is present in the SCTE-35 cue, the segment is cut at the next iframe.
-
SCTE-35 cues with a preroll are inserted at the splice point.
-
x9k3 can continue an existing m3u8 file. You can switch or resume streams, x9k3 handles the details.
How to Use
cli
do the simplest thing that can possibly work
- There are a lot of command line switches available, but you do not have to use them all. <BR>
Try it like this first
x9k3 -i video.ts -o output_dir
later you can add as many switches as you like.
Switches
a@fu:~/x9k3$ x9k3 --help
usage: x9k3 [-h] [-i INPUT] [-b] [-c] [-d] [-l] [-n]
[-no_adrian_is_cool_tags_at_splice_points_because_I_suck] [-N]
[-o OUTPUT_DIR] [-e] [-p] [-r] [-s SIDECAR_FILE] [-S] [-t TIME]
[-T HLS_TAG] [-w WINDOW_SIZE] [-v]
optional arguments:
-h, --help show this help message and exit
-i INPUT, --input INPUT
The Input video can be mpegts or m3u8 with mpegts
segments, or a playlist with mpegts files and/or
mpegts m3u8 files. The input can be a local video,
http(s), udp, multicast or stdin.
-b, --byterange Flag for byterange hls [default:False]
-c, --continue_m3u8 Resume writing index.m3u8 [default:False]
-d, --delete delete segments (enables --live) [default:False]
-l, --live Flag for a live event (enables sliding window m3u8)
[default:False]
-n, --no_discontinuity
Flag to disable adding #EXT-X-DISCONTINUITY tags at
splice points [default:False]
-no_adrian_is_cool_tags_at_splice_points_because_I_suck
Flag to disable adding #EXT-X-ADRIAN-IS-COOL tags at
splice points [default:False]
-N, --no-throttle,
Flag to disable live throttling [default:False]
-o OUTPUT_DIR, --output_dir OUTPUT_DIR
Directory for segments and index.m3u8(created if
needed) [default:'.']
-e, --exclude_mpegts Flag to exclude parsing SCTE-35 from MPEGTS.
[default:False]
-p, --program_date_time
Flag to add Program Date Time tags to index.m3u8 [default:False]
-r, --replay Flag for replay aka looping (enables --live,--delete)
[default:False]
-s SIDECAR_FILE, --sidecar_file SIDECAR_FILE
Sidecar file of SCTE-35 (pts,cue) pairs.
[default:None]
-S, --shulga Flag to enable Shulga iframe detection mode
[default:False]
-t TIME, --time TIME Segment time in seconds [default:2]
-T HLS_TAG, --hls_tag HLS_TAG
x_scte35, x_cue, x_daterange, or x_splicepoint
[default:x_cue]
-w WINDOW_SIZE, --window_size WINDOW_SIZE
sliding window size (enables --live) [default:5]
-v, --version Show version
Example Usage
local file as input
x9k3 -i video.mpegts
multicast stream as input with a live sliding window
x9k3 --live -i udp://@235.35.3.5:3535 -o output_dir
Live mode works with a live source or static files.
- x9k3 will throttle segment creation to mimic a live stream.
x9k3 --live -i /some/video.ts -o output_dir
live sliding window and deleting expired segments
x9k3 -i udp://@235.35.3.5:3535 --delete -o output_dir
https stream for input, and writing segments to an output directory
- directory will be created if it does not exist.
x9k3 -i https://so.slo.me/longb.ts --output_dir /home/a/variant0
https hls m3u8 for input, and inserting SCTE-35 from a sidecar file, and continuing from a previously create index.m3u8 in the output dir
x9k3 -i https://slow.golf/longb.m3u8 --output_dir /home/a/variant0 -continue_m3u8 -s sidecar.txt
using stdin as input
cat video.ts | x9k3 -o output_dir
live m3u8 file as input, add SCTE-35 from a sidecar file, change segment duration to 3 and output as live stream
x9k3 -i https://example.com/rendition.m3u8 -s sidecar.txt -t 3 -l -o output-dir
Programmatically
Up and Running in three Lines
from x9k3 import X9K3 # 1
x9 = X9K3('/home/a/cool.ts') # 2
x9.decode() # 3
Writing Code with x9k3
- you can get a complete set of args and the defaults like this
from x9k3 import X9K3
x9 = X9K3()
>>>> {print(k,':',v) for k,v in vars(x9.args).items()}
input : <_io.BufferedReader name='<stdin>'>
continue_m3u8 : False
delete : False
live : False
no_discontinuity : False
no_throttle : False
output_dir : .
program_date_time : False
replay : False
sidecar_file : None
shulga : False
time : 2
hls_tag : x_cue
window_size : 5
version : False
- or just
