Skip to main content

An HLS Segmenter with SCTE-35 Parsing and Injection

Project description

Use | CUE-OUT | CUE-IN | SCTE-35 Tags | Sidecar SCTE35 | Byterange m3u8 | Playlists | Live hls |

x9k3 is a SCTE-35 injector for HLS

https://github.com/superkabuki/x9k3 is the new home of x9k3

State of the Union Address

    One of the things I have spent the most time on with x9k3 is improving 
the accuracy of SCTE-35 Splice Points when the given Splice Point does not fall on an IFrame.
    I had light bulb turn on over my head this weekend, I made several small edits and boom, 
I'm getting much better results with misaligned splice points.
    
    I've also added code to handle missing segments when using an m3u8 as input, 
x9k3 drops in a DISCO tag to cover the jump in pts and just keeps going.
It's pretty slick.

I'm about to do a new release is my point.

Current Version: v1.0.3

Yeah, it's been a while.

  • Some of the new stuff:
    • __Big increase in accuracy of misaligned SCTE-35 splice points.
    • -e or --exclude_mpegts flag added to exclude parsing SCTE-35 embedded in MPEGTS.
    • fixed eleven bugs you didn't even know existed. I'm not going to tell you :)
    • x9k3 now adds PAT and PMT to the start of every segment.
    • PTS values are only parsed from the PCR PID to prevent backwards PTS values.
    • x9k3 can now generate byterange m3u8 files with -b or --byterange
    • Playlists`of m3u8 and/or MPEGTS files can now be used as input.
    • Segment start time is now always read, never calculated.
    • Segment duration verification for segments that exceed the target duration.
    • m3u8 files as input. Resegment and add SCTE-35 to an existing m3u8. -i INPUT, --input INPUT
    • Continue an m3u8 file.Segments may be added to an existing m3u8, VOD or live. -c, --continue_m3u8 `
    • discontinuity tags may now be omitted. -n, --no_discontinuity
    • Automatic CUE-IN
    • live throttling can be disabled with the -N, --no_throttle flag

Features

  • 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, and Unicast UDP streams.
  • Supports Live Streaming.
  • amt-play uses x9k3.

Install

  • Use pip to install the the x9k3 lib and executable script x9k3 (will install threefive,m3ufu too)
# python3

python3 -mpip install x9k3

# pypy3 

pypy3 -mpip install x9k3

⇪ top

Details

  • X-SCTE35, X-CUE, X-DATERANGE, or X-SPLICEPOINT HLS tags can be generated. set with the --hls_tag switch.

  • 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 -t switch or by setting X9K3.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.

How to Use

cli

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, --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 (
                        enables --live) [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

⇪ top

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
>>>> print(x9.args)

Namespace(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)
  • Setting parameters
from x9k3 import X9K3
x9 = X9K3()
  • input source
x9.args.input = "https://futzu.com/xaa.ts"   
  • hls_tag can be x_scte35, x_cue, x_daterange, or x_splicepoint
x9.args.hls tag = x_cue 
  • output directory default is "."
x9.args.output_dir="/home/a/stuff"
  • live
x9.args.live = True
  • replay (loop video) ( also sets live )
x9.args.replay = True
  • delete segments when they expire ( also sets live )
x9.args.delete = True
  • add program date time tags ( also sets live )
x9.args.program_date_time= True
  • set window size for live mode ( requires live )
x9.args.window_size = 5 
  • run
x9.decode()

⇪ top

byterange

  • with the cli tool
    • use full path to video file when creating byterange m3u8.
x9k3 -i /home/a/input.ts -b
  • programmatically
from x9k3 import X9K3
x9 = X9K3()
x9.self.args.byterange = True
x9.decode()
  • output
#EXTM3U
#EXT-X-VERSION:4
#EXT-X-TARGETDURATION:3
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-DISCONTINUITY-SEQUENCE:0
#EXT-X-X9K3-VERSION:0.2.55
#EXTINF:2.000000,
#EXT-X-BYTERANGE:135548@0
msnbc1000.ts
#EXTINF:2.000000,
#EXT-X-BYTERANGE:137992@135548
msnbc1000.ts
#EXTINF:2.000000,
#EXT-X-BYTERANGE:134796@273540
msnbc1000.ts
#EXTINF:2.000000,
#EXT-X-BYTERANGE:140436@408336
msnbc1000.ts
#EXTINF:2.000000,
#EXT-X-BYTERANGE:130096@548772
msnbc1000.ts
<SNIP>

playlists

  • playlists can be used as input

  • playlist files must end in .playlist

  • lines are video or video, sidecar

    • if video,sidecar, the sidecar file only applies to that video
  • playlists can have mpegts video, mpegts m3u8, and playlists.

  • example playlist

f10.ts,f10sidecar.txt # comments can be here
f17.ts
f60.ts
flat-striped.ts
# Comments can go here too.
flat.ts
input.ts
nmax.ts
nmx.ts,nmx-sidecar.txt
https://futzu.com/xaa.ts
https://example.com/index.m3u8,another-sidecar.txt
  • using
 x9k3 -i out.playlist

Sidecar Files

load scte35 cues from a Sidecar file

Sidecar Cues will be handled the same as SCTE35 cues from a video stream.
line format for text file insert_pts, cue

pts is the insert time for the cue, A four second preroll is standard. cue can be base64,hex, int, or bytes

a@debian:~/x9k3$ cat sidecar.txt

38103.868589, /DAxAAAAAAAAAP/wFAUAAABdf+/+zHRtOn4Ae6DOAAAAAAAMAQpDVUVJsZ8xMjEqLYemJQ== 
38199.918911, /DAsAAAAAAAAAP/wDwUAAABef0/+zPACTQAAAAAADAEKQ1VFSbGfMTIxIxGolm0= 

    
x9k3 -i  noscte35.ts  -s sidecar.txt 

In Live Mode you can do dynamic cue injection with a Sidecar file

touch sidecar.txt

x9k3 -i vid.ts -s sidecar.txt -l 

# Open another terminal and printf cues into sidecar.txt

printf '38103.868589, /DAxAAAAAAAAAP/wFAUAAABdf+/+zHRtOn4Ae6DOAAAAAAAMAQpDVUVJsZ8xMjEqLYemJQ==\n' > sidecar.txt

Sidecar files can now accept 0 as the PTS insert time for Splice Immediate.

Specify 0 as the insert time, the cue will be insert at the start of the next segment. Using 0 only works in live mode

printf '0,/DAhAAAAAAAAAP/wEAUAAAAJf78A/gASZvAACQAAAACokv3z\n' > sidecar.txt

⇪ top

A CUE-OUT can be terminated early using a sidecar file.

In the middle of a CUE-OUT send a splice insert with the out_of_network_indicator flag not set and the splice immediate flag set. Do the steps above , and then do this

printf '0,/DAcAAAAAAAAAP/wCwUAAAABfx8AAAEAAAAA3r8DiQ==\n' > sidecar.txt

It will cause the CUE-OUT to end at the next segment start.

#EXT-X-CUE-OUT 13.4
./seg5.ts:	start:112.966667	end:114.966667	duration:2.233334
#EXT-X-CUE-OUT-CONT 2.233334/13.4
./seg6.ts:	start:114.966667	end:116.966667	duration:2.1
#EXT-X-CUE-OUT-CONT 4.333334/13.4
./seg7.ts:	start:116.966667	end:118.966667	duration:2.0
#EXT-X-CUE-OUT-CONT 6.333334/13.4
./seg8.ts:	start:117.0	        end:119.0	duration:0.033333
#EXT-X-CUE-IN None
./seg9.ts:	start:119.3	        end:121.3	duration:2.3

Using 0 only works in live mode


CUES

CUE-OUT

A CUE-OUT is defined as:

  • A Splice Insert Command with:

    • the out_of_network_indicator set to True
    • a break_duration.
  • A Time Signal Command and a Segmentation Descriptor with:

    • a segmentation_duration
    • a segmentation_type_id of:
      • 0x22: "Break Start",
      • 0x30: "Provider Advertisement Start",
      • 0x32: "Distributor Advertisement Start",
      • 0x34: "Provider Placement Opportunity Start",
      • 0x36: "Distributor Placement Opportunity Start",
      • 0x44: "Provider Ad Block Start",
      • 0x46: "Distributor Ad Block Start",

⇪ top

CUE-IN

A CUE-IN is defined as:

  • A Splice Insert Command

    • with the out_of_network_indicator set to False
  • A Time Signal Command and a Segmentation Descriptor with:

    • a segmentation_type_id of:

      • 0x23: "Break End",
      • 0x31: "Provider Advertisement End",
      • 0x33: "Distributor Advertisement End",
      • 0x35: "Provider Placement Opportunity End",
      • 0x37: "Distributor Placement Opportunity End",
      • 0x45: "Provider Ad Block End",
      • 0x47: "Distributor Ad Block End",
  • For CUE-OUT and CUE-IN, only the first Segmentation Descriptor will be used


Supported HLS Tags

  • #EXT-X-CUE
  • #EXT-X-DATERANGE
  • #EXT-X-SCTE35
  • #EXT-X-SPLICEPOINT

x_cue

  • CUE-OUT
#EXT-X-DISCONTINUITY
#EXT-X-CUE-OUT:242.0
#EXTINF:4.796145,
seg32.ts
  • CUE-OUT-CONT
#EXT-X-CUE-OUT-CONT:4.796145/242.0
#EXTINF:2.12,
  • CUE-IN
#EXT-X-DISCONTINUITY
#EXT-X-CUE-IN
#EXTINF:5.020145,
seg145.ts

x_scte35

  • CUE-OUT
#EXT-X-DISCONTINUITY
#EXT-X-SCTE35:CUE="/DAvAAAAAAAAAP/wFAUAAAKWf+//4WoauH4BTFYgAAEAAAAKAAhDVUVJAAAAAOv1oqc=" ,CUE-OUT=YES 
#EXTINF:4.796145,
seg32.ts
  • CUE-OUT-CONT
#EXT-X-SCTE35:CUE="/DAvAAAAAAAAAP/wFAUAAAKWf+//4WoauH4BTFYgAAEAAAAKAAhDVUVJAAAAAOv1oqc=" ,CUE-OUT=CONT
#EXTINF:2.12,
seg33.ts
  • CUE-IN
#EXT-X-DISCONTINUITY
#EXT-X-SCTE35:CUE="/DAqAAAAAAAAAP/wDwUAAAKWf0//4rZw2AABAAAACgAIQ1VFSQAAAAAtegE5" ,CUE-IN=YES 
#EXTINF:5.020145,
seg145.ts

x_daterange

  • CUE-OUT
#EXT-X-DISCONTINUITY
#EXT-X-DATERANGE:ID="1",START-DATE="2022-10-14T17:36:58.321731Z",PLANNED-DURATION=242.0,SCTE35-OUT=0xfc302f00000000000000fff01405000002967fefffe16a1ab87e014c562000010000000a00084355454900000000ebf5a2a7
#EXTINF:4.796145,
seg32.ts
  • CUE-IN
#EXT-X-DISCONTINUITY
#EXT-X-DATERANGE:ID="2",END-DATE="2022-10-14T17:36:58.666073Z",SCTE35-IN=0xfc302a00000000000000fff00f05000002967f4fffe2b670d800010000000a000
843554549000000002d7a0139
#EXTINF:5.020145,
seg145.ts

x_splicepoint

  • CUE-OUT
#EXT-X-DISCONTINUITY
#EXT-X-SPLICEPOINT-SCTE35:/DAvAAAAAAAAAP/wFAUAAAKWf+//4WoauH4BTFYgAAEAAAAKAAhDVUVJAAAAAOv1oqc=
#EXTINF:4.796145,
seg32.ts
  • CUE-IN
#EXT-X-DISCONTINUITY
#EXT-X-SPLICEPOINT-SCTE35:/DAqAAAAAAAAAP/wDwUAAAKWf0//4rZw2AABAAAACgAIQ1VFSQAAAAAtegE5
#EXTINF:5.020145,
seg145.ts

⇪ top

VOD

  • x9k3 defaults to VOD style playlist generation.
  • All segment are listed in the m3u8 file.

Live

  • Activated by the --live, --delete, or --replay switch or by setting X9K3.live=True

--live

  • Like VOD except:
    • M3u8 manifests are regenerated every time a segment is written
    • Segment creation is throttled when using non-live sources to simulate live streaming. ( like ffmpeg's "-re" )
    • default Sliding Window size is 5, it can be changed with the -w switch or by setting X9k3.window.size

--delete

  • implies --live
  • deletes segments when they move out of the sliding window of the m3u8.

--replay

  • implies --live
  • implies --delete
  • loops a video file and throttles segment creation to fake a live stream.

⇪ top

image

Project details


Release history Release notifications | RSS feed

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

x9k3-1.0.3.tar.gz (22.9 kB view details)

Uploaded Source

Built Distribution

x9k3-1.0.3-py3-none-any.whl (18.4 kB view details)

Uploaded Python 3

File details

Details for the file x9k3-1.0.3.tar.gz.

File metadata

  • Download URL: x9k3-1.0.3.tar.gz
  • Upload date:
  • Size: 22.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.2 CPython/3.11.2

File hashes

Hashes for x9k3-1.0.3.tar.gz
Algorithm Hash digest
SHA256 07bb600f7b4b10e8f92630e78ae9eb3acaed621b7bc368990fb24f9035c00b39
MD5 6c5467d1c0e9a91017d0f2147f6f4621
BLAKE2b-256 dc8931d933baa1797474a64b15a79dc8d6e84d7c0e115c28717a5c9ce3bfb329

See more details on using hashes here.

File details

Details for the file x9k3-1.0.3-py3-none-any.whl.

File metadata

  • Download URL: x9k3-1.0.3-py3-none-any.whl
  • Upload date:
  • Size: 18.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.2 CPython/3.11.2

File hashes

Hashes for x9k3-1.0.3-py3-none-any.whl
Algorithm Hash digest
SHA256 dc390f53de09cdb138f18390d0949413e54ea79bfb14817a6f583c8ac3499850
MD5 3c0c19438ae62942ada5150f8d16cbc2
BLAKE2b-256 4af05ccef2f027a77cf0b9451309bd2034348c6db263c1e6e441081524ae8926

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page