Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/futzu/SCTE-35_HLS_x9k3

HLS and SCTE-35 x9k3 is a HLS Segmenter with SCTE 35, and Live Streaming from Non-Live Soures and Looping.
https://github.com/futzu/SCTE-35_HLS_x9k3

ad-insertion boobs h264 h265 hls hls-scte35 m3u8 mpegts python3 scte35 sexy threefive video

Last synced: 3 months ago
JSON representation

HLS and SCTE-35 x9k3 is a HLS Segmenter with SCTE 35, and Live Streaming from Non-Live Soures and Looping.

Awesome Lists containing this project

README

        

td, th { border: 1px solid #c3c3c3; padding: 0 3px 0 3px; }
table { border-collapse: collapse; }
img { max-width: 100%; }

README

Install |
Use |
CUE-OUT |
CUE-IN |
SCTE-35 Tags |
Sidecar SCTE35 |
Live |
Bugs




HLS + SCTE35 = x9k3



x9k3 is a HLS segmenter with SCTE-35 injection and parsing, powered by threefive.




Heads Up


Segment duration is open to interpretation... wait, let me explain.




threefive and ffmpeg may report different durations for segments.

threefive use absolute PTS values and always start on an iframe.


In the tables below, four segments are compared.

Reported start and reported duration are values returned from the tool.

Calculate duration is (next segment start - this segment start)






* threefive (what x9k3 uses)

| segment| reported start| reported duration|calculated duration|
|--------|---------------|-------------------|-------------------|
| seg0.ts| 3164.376089 | 2.0 | 2.0 |
| seg1.ts| 3166.376089 | 2.0 | 2.0 |
| seg2.ts| 3168.376089 | 2.0 | 2.0 |
| seg3.ts| 3170.376089 | 2.0 | 2.0 |

* ffmpeg

| segment| reported start| reported duration|calculated duration|
|--------|---------------|-------------------|-------------------|
| seg0.ts| 3164.376089 | 2.0 | 0.361333 |
| seg1.ts| 3164.737422 | 3.64 | 2.047999 |
| seg2.ts| 3166.785422 | 3.59 | 3.59 |
| seg3.ts| 3170.376089 | 2.0 | 0.356000 |

#### What does it all mean?
> I don't know.
>
___


Current Version:


v.0.2.35

test
command
score
previous

cyclomatic complexity
radon cc -s -a x9k3.py
A (2.769230)
A (2.818181)

pylint
pylint x9k3.py
9.97 / 10
9.94 / 10



  • Some of the new stuff:

  • m3u8 files as input. Resegment and add SCTE-35 to an existing m3u8. -i INPUT, --input INPUT

  • segments may be added to an existing m3u8, VOD or live. -c, --continue_m3u8

  • discontinuity tags may now be omitted. -n, --no_discontinuity

  • auto CUE-IN


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.




Requires



Install



  • Use pip to install the the x9k3 lib and executable script x9k3 (will install threefive, new_reader and iframes too)


# python3

python3 -mpip install x9k3

# pypy3

pypy3 -mpip install x9k3


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


All x9k3 options

| switch| description|
|-------|------------|
| `-h`, `--help` | show this help message and exit |
|` -i INPUT`, `--input INPUT`| Input source, like /home/a/vid.ts or udp://@235.35.3.5:3535 or https://futzu.com/xaa.ts or https://example.com/not_a_master.m3u8 [default: stdin] |
| `-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] |
| `-N`, `--no-throttle`| disable live throttling [default:False] |
| `-o OUTPUT_DIR`, `--output_dir OUTPUT_DIR` | Directory for segments and index.m3u8(created if needed) [default:'.'] |
| `-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|

a@fu:~/x9k3-repo$ x9k3 -h

usage: x9k3 [-h] [-i INPUT] [-c] [-d] [-l] [-n] [-o OUTPUT_DIR] [-p] [-r]
[-s SIDECAR_FILE] [-S] [-t TIME] [-T HLS_TAG] [-w WINDOW_SIZE]
[-v]

options:

-h, --help show this help message and exit

-i INPUT, --input INPUT
Input source, like /home/a/vid.ts or
udp://@235.35.3.5:3535 or https://futzu.com/xaa.ts or
https://example.com/not_a_master.m3u8 [default: stdin]

-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]

-o OUTPUT_DIR, --output_dir OUTPUT_DIR
Directory for segments and index.m3u8 (created if
needed) [default:'.']

-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
smalltalk
x9k3 -i video.mpegts

#### multicast stream as input with a live sliding window

smalltalk
x9k3 --live -i udp://@235.35.3.5:3535

#### Live mode works with a live source or static files.
* x9k3 will throttle segment creation to mimic a live stream.
js
x9k3 --live -i /some/video.ts

#### live sliding window and deleting expired segments
smalltalk
x9k3 -i udp://@235.35.3.5:3535 --delete


https stream for input, and writing segments to an output directory



  • directory will be created if it does not exist.
    smalltalk
    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


smalltalk
x9k3 -i https://slow.golf/longb.m3u8 --output_dir /home/a/variant0 -continue_m3u8 -s sidecar.txt


using stdin as input


smalltalk
cat video.ts | x9k3


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


Cli tool


New Option, -c or --continue_m3u8 Continue an existing index.m3u8. (Only works with x9k3 generated m3u8 files)


a@fu:~/x9k3-repo$ x9k3 -h

usage: x9k3 [-h] [-i INPUT] [-c] [-d] [-l] [-n] [-o OUTPUT_DIR] [-p] [-r]
[-s SIDECAR_FILE] [-S] [-t TIME] [-T HLS_TAG] [-w WINDOW_SIZE]
[-v]

options:

-h, --help show this help message and exit

-i INPUT, --input INPUT
Input source, like /home/a/vid.ts or
udp://@235.35.3.5:3535 or https://futzu.com/xaa.ts or
https://example.com/not_a_master.m3u8 [default: stdin]

-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]

-o OUTPUT_DIR, --output_dir OUTPUT_DIR
Directory for segments and index.m3u8 (created if
needed) [default:'.']

-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


Programmatically (writing code with x9k3)


x9 = X9K3("https://iodisco.com/fu.ts")

x9.decode()

Setting parameters
* create an instance.


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 )


self.args.program_date_time= True



  • set window size for live mode ( requires live )


x9.args.window_size = 5 



  • run


x9.run()



  • you can get a complete set of args and the defaults like this


from x9k3 import X9K3

x9 = X9K3()
print(x9.args)

Namespace(input=<_io.BufferedReader name='<stdin>'>, continue_m3u8=False, delete=False, live=False, no_discontinuity=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)



  • argue can also be called to get the defaults


>>>> from x9k3 import X9K3, argue

>>>> args = argue()

>>>> args
Namespace(input=<_io.BufferedReader name='<stdin>'>, continue_m3u8=False, delete=False, live=False, no_discontinuity=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)

>>>> args.replay =True
>>>> args.live = True
>>>> args.time = 6
>>>> args.window_size = 10

>>>> args
Namespace(input=<_io.BufferedReader name='<stdin>'>, continue_m3u8=False, delete=False, live=True, no_discontinuity=False, output_dir='.', program_date_time=False, replay=True, sidecar_file=None, shulga=False, time=6, hls_tag='x_cue', window_size=10, version=False)

>>>> x9 = X9K3()
>>>> x9.args = args

>>>> x9.args
Namespace(input=<_io.BufferedReader name='<stdin>'>, continue_m3u8=False, delete=False, live=True, no_discontinuity=False, output_dir='.', program_date_time=False, replay=True, sidecar_file=None, shulga=False, time=6, hls_tag='x_cue', window_size=10, version=False)


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


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


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


  ```smalltalk

x9k3 -i noscte35.ts -s sidecar.txt
```
#### In Live Mode you can do dynamic cue injection with a `Sidecar file`
```js
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__

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

```

#### 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
```js
printf '0,/DAcAAAAAAAAAP/wCwUAAAABfx8AAAEAAAAA3r8DiQ==\n' > sidecar.txt


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


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",

## `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
```lua
#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


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.


image