[ threefive ]
- Decodes SCTE-35 from MPEGTS✔ Base64✔ Bytes✔ DASH✔ Hex✔ HLS✔ Integer✔ JSON✔ XML✔ XML+Binary✔
- Encodes SCTE-35 to MPEGTS✔ Base64✔ Bytes✔ Hex✔ Integer✔ JSON ✔ XML✔ XML+Binary✔
*** if you need to encode SCTE-35 to HLS, use x9k3.
[ version ]
latest threefive version is v3.1.9
- threefive now parses ID3 streams for SCTE-35 in MPEGTS streams
- HLS Parser has been tuned up. DATERANGE tag fixed.
- Iframer has been merged into the Stream class.
- check the change log
- piping data into the threefive cli tool now works on Windows, the select call has been removed.
[ a really really quick start ]
- Install
python3 -m pip install threefive`
- decoding SCTE-35
threefive '/DAWAAAAAAAAAP/wBQb+AKmKxwAACzuu2Q=='
- decode SCTE-35 as base64 and convert SCTE-35 to hex
threefive '/DAWAAAAAAAAAP/wBQb+AKmKxwAACzuu2Q==' hex
- decode SCTE-35 from HLS ( a rendition or a master.m3u8)
threefive 'https://demo.unified-streaming.com/k8s/live/scte35.isml/.m3u8'
- decode SCTE-35 from MPEGTS
threefive 'https;//iodisco.com/longb2.ts'
- decode SCTE-35 from MPEGTS and convert SCTE-35 to bytes
threefive 'https;//iodisco.com/longb2.ts' bytes
- decode SCTE-35 from MPEGTS over Multicast
threefive udp://@235.3.5.35:3535
- threefive does a lot more, that was just to get you started.
[ Documentation ]
A Lot of Examples | Tip of the Week | Cheap Tricks |
Need to inject SCTE-35 into HLS? X9k3.
-
SCTE-35 on the command line
- the threefive cli tool If you work with SCTE-35, this is as cool as it gets.
-
the threefive library cool code for the cool kids.
- Using the threefive library with SCTE-35 decode SCTE-35 with less than ten lines of code
- triggering on SCTE-36 data in MPEGTS streams
-
other included tools
- scte35fix ffmpeg changes scte-35 streams into bin data, scte35fix changes them back.
- scte35inject scte35inject inject scte-35 into mpegts.
-
web based SCTE-35 tools - threefive and friends over HTTPS
-
SCTE-35 Sidecar Files threefive supports SCTE-35 sidecar files
-
SCTE-35 HLS parse SCTE-35 in HLS in MPEGTS,CMAF, or fmP4
-
SCTE-35 XML and More XML threefive can parse and encode SCTE-35 xml
-
Encode SCTE-35 threefive can encode SCTE-35 in every SCTE-35 format
-
Make your threefive script an executable with cython threefive is compatible with all python tools
[Install]
-
Requires python3 v3.9 or higher.
-
python3 via pip
python3 -mpip install threefive
- pypy3 via pip
pypy3 -mpip install threefive
- To add SRT support to threefive install srtfu
python3 -m pip install srtfu
- To add Automatic AES decryption (used to decrypted HLS to threefive install pyaes
python3 -mpip install pyaes
- From the git repo
git clone https://github.com/superkabuki/scte35.git
cd threefive
make install
- I've jazzed up the makefile to make it easier to install for different python versions and pypy3,
git clone https://github.com/superkabuki/threefive.git
cd threefive
``
* `python3` is the default for `make install`
make install
* setting py3 allows you to install for any type of python interpreter.
make install py3=pypy3
* absolute paths can also be used.
make install py3=/home/a/pypy3/bin/pypy3
# works for any python in your path or use a full path if needed.
⇧
[ CLI ]
threefive is designed to be easy to use. I'm not sure that it's served well by a long explaination, so I'm going to try and keep this brief.
The threefive cli tool.
the threefive cli tool decodes SCTE-35, formats are auto-detected, and they all work the same way.
threefive [media to parse for SCTE-35]
examples:
threefive '/DAWAAAAAAAAAP/wBQb+AKmKxwAACzuu2Q=='
threefive 0xfc301600000000000000fff00506fe00a98ac700000b3baed9
threefive 1583008701074197245727019716796221242036302348025116111908569
threefive video.ts
threefive https://demo.unified-streaming.com/k8s/live/scte35.isml/scte35-audio_eng=64000-video=500000.m3u8
-
Formats like _XML and JSON that may be to large to type on the command line,they can be redirected or piped in to threefive.
-
redirect
threefive < xml.xml
- pipe
cat json.json | threefive
cli outputs and encoding SCTE-35 Formats
-
the default output format for threefive is json
-
The cli tool can convert from one SCTE-35 format to another using keywords.
- The keywords are base64,bytes,hex, int,json,xml, and xmlbin
-
some converting and encoding examples
-
SCTE-35 Base64 to SCTE-35 Hex
threefive '/DAWAAAAAAAAAP/wBQb+AKmKxwAACzuu2Q==' hex
- SCTE-35 Int to SCTE-35 Xml
threefive 1583008701074197245727019716796221242036302348025116111908569 xml
- SCTE-35 Hex to SCTE-35 xml+binary
threefive 0xfc301600000000000000fff00506fe00a98ac700000b3baed9 xmlbin
threefive cli and MPEGTS
-
threefive can parse MPEGTS from stdin, local files, HTTP(s), Multicast, SRT, and unicast UDP.
-
some mpegts examples
-
local
threefive video.ts
- stdin
cat video.ts | threefive
- https
threefive https://iodisco.com/longb2.ts
- multicast
threefive udp://@235.35.3.5:3535
threefive cli MPEGTS outputs
-
the default output for MPEGTS is json
-
keywords can be used to specify other output formats
- The keywords are base64,bytes,hex, int,json,xml, and xmlbin
-
An example of mpegts with a keyword
threefive https://iodisco.com/longb2.ts xml
[ threefive hls ]
-
threefive is also an HLS SCTE-35 parser.
-
HLS is automatically detected.
threefive https://demo.unified-streaming.com/k8s/live/stable/scte35.isml/.m3u8
- The input m3u8 file can be a rendition or master m3u8.
- Automatic AES decryption for segments.
- Automatic AAC and AC3 ID3 Tag timestamp header parsing for audio only renditions.
- SCTE-35 Can be parsed from MPEGTS segments and from m3u8 files.
- All HLS SCTE-35 tags are supported.
- threefive hls also allows you to filter SCTE-35 Messages.
[ Help ]
To display hls help
threefive hls help
[ Input ]
-
threefive hls takes an m3u8 URI as input.
-
M3U8 formats supported:
- master ( When a master.m3u8 used, threefive hls parses the first rendition it finds )
- rendition
-
Segment types supported:
- AAC
- AC3
- MPEGTS
- MP4
- fMP4
-
Protocols supported:
- stdin
- file
- HTTP(S)
- Multicast
- Secure Reliable Transport
- UDP Unicast
-
Encryption supported:
- AES-128 (segments are automatically decrypted)
[ SCTE-35 ]
- threefive parses SCTE-35 from:
- Embedded MPEGTS SCTE-35
- ID3 PRIV tags in ID3 streams
- All SCTE-35 HLS Tags.
[ Cool Features ]
- threefive hls can resume when started in the middle of an ad break.
2023-10-13T05:59:50.24Z Resuming Ad Break
2023-10-13T05:59:50.34Z Setting Break Timer to 17.733
2023-10-13T05:59:50.44Z Setting Break Duration to 60.067
[ Example Usage ]
- Show this help:
threefive hls help
- parse an m3u8:
threefive https://demo.unified-streaming.com/k8s/live/stable/scte35.isml/.m3u8
⇧
Other tools
scte35inject
- SCTE-35 Packet Injection
a@fu:~/threefive$ scte35inject help
usage: scte35inject [-h] [-i INPUT] [-o OUTPUT] [-s SIDECAR] [-p SCTE35_PID] [-t]
[-v]
optional arguments:
-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" [
default:sys.stdin.buffer ]
-o OUTPUT, --output OUTPUT
Output file [ default:sys.stdout.buffer ]
-s SIDECAR, --sidecar SIDECAR
Sidecar file for SCTE35 [ default:sidecar.txt ]
-p SCTE35_PID, --scte35_pid SCTE35_PID
Pid for SCTE-35 packets [ default:0x86 ]
-t, --time_signals Flag to insert Time Signal cues at iframes.
-v, --version Show version
scte35inject is part of threefive
testing example
- insert a TimeSignal at every iframe
a@fu:~/threefive$ touch sidecar.txt
@fu:~/threefive$ scte35inject -t -i ~/mpegts2/mpegts/nmax.ts -p 777 -o injected-nmax.ts
⇧
scte35fix
- when ffmpeg changes a SCTE-35 stream to bin data stream, scte35fix changes it back.
$ scte35fix -h
scte35fix checks MPEGTS for SCTE-35 Streams
that have been change to bin data (type 0x06)
and changes them back to SCTE-35 (type 0x86) streams.
Output files are created in the current directory
and prefixed with 'sixfix-'.
Only bin data streams containing SCTE-35 will be converted.
Multiple files can be specified on the command line.
Wild cards work too.
Example Usage:
scte35fix video.ts
scte35fix video1.ts video2.ts
scte35fix video*.ts
scte35fix https://example.com/video.ts
scte35fix srt://10.10.10.13:4201
scte35fix is part of threefive.
⇧
[ Using the library ]
Writing Code with threefive.
-
threefive is designed so that you don't have to write a lot of code to parse SCTE-35 threefive is OO, everything in threefive, except a dozen or so functions, is a class.
-
The Cue class and the Stream class are the two classes most often used.
Cue class
- The Cue class represents a single SCTE-35 Cue.
- Use the Cue class when you have one SCTE-35 Cue or Message to parse.
- The Cue class autodetects the format of the SCTE-35.
- When you create a Cue instance, pass in the SCTE-35 data.
>>>> from threefive import Cue
>>>> cue=Cue('/DBAAAGRZOeYAAAABQb/mSvFcAAqAihDVUVJ/////3//AAFyyeABFG1zbmJjX0VQMDQ0MDc4NzUwMjY4IwEESCpzpg==')
-
The SCTE-35 Format can be Base64, Bytes, Hex, Integer, JSON, Raw MPEGTS Packet, XML or XML+Binary.
-
Cue will decode the SCTE-35 into a Splice Info Section, a Splice Command, and zero or More Splice Descriptors.
>>>> cue.info_section
{'table_id': '0xfc', 'section_syntax_indicator': False, 'private': False, 'sap_type': '0x03', 'sap_details': 'No Sap Type', 'section_length': 64, 'protocol_version': 0, 'encrypted_packet': False, 'encryption_algorithm': 0, 'pts_adjustment': 74825.294489, 'cw_index': '0x00', 'tier': '0x00', 'splice_command_length': 5, 'splice_command_type': 6, 'descriptor_loop_length': 42, 'crc': '0x482a73a6'}
>>>> cue.command
{'command_length': 5, 'command_type': 6, 'name': 'Time Signal', 'time_specified_flag': True, 'pts_time': 76274.999289}
>>>> cue.descriptors
[{'tag': 2, 'identifier': 'CUEI', 'name': 'Segmentation Descriptor', 'descriptor_length': 40, 'private_data': None, 'segmentation_event_cancel_indicator': False, 'segmentation_event_id': '0xffffffff', 'segmentation_event_id_compliance_indicator': True, 'program_segmentation_flag': True, 'segmentation_duration_flag': True, 'delivery_not_restricted_flag': True, 'web_delivery_allowed_flag': None, 'no_regional_blackout_flag': None, 'archive_allowed_flag': None, 'device_restrictions': None, 'segmentation_duration': 270.0, 'segmentation_message': 'Break End', 'segmentation_type_id': 35, 'segmentation_upid_length': 20, 'segmentation_upid_type': 1, 'segmentation_upid_type_name': 'Type 0x01 is deprecated, use MPU type 0x0C', 'segmentation_upid': 'msnbc_EP044078750268', 'segment_num': 1, 'segments_expected': 4, 'sub_segment_num': None, 'sub_segments_expected': None}]
- individual variables can be accessed via dot notation
>>>> cue.command.pts_time
76274.999289
- variables can be changed the same way
>>>> cue.command.pts_time= 1.23456
>>>> cue.command
{'command_length': 5, 'command_type': 6, 'name': 'Time Signal', 'time_specified_flag': True, 'pts_time': 1.23456}
-
cue.descriptors is a list, and descriptors can be acessed by index, like cue.descriptors[0]
-
since cue.descriptors is a list, so you can append or pop() descriptors
>>>> cue.descriptors.pop()
>>>> cue.descriptors
[]
-
after editing, you can re-encode
-
the default is base64
>>>> cue.encode()
'/DAWAAGRZOeYAAAABQb+AAGyBgAANqe8lw=='
-
or you can encode in a different SCTE-35 format
-
bytes
>>>> cue.bytes()
b'\xfc0\x16\x00\x01\x91d\xe7\x98\x00\x00\x00\x05\x06\xfe\x00\x01\xb2\x06\x00\x006\xa7\xbc\x97'
- hex
>>>> cue.hex()
'0xfc301600019164e7980000000506fe0001b206000036a7bc97'
- json
>>>> cue.show()
{
"info_section": {
"table_id": "0xfc",
"section_syntax_indicator": false,
"private": false,
"sap_type": "0x03",
"sap_details": "No Sap Type",
"section_length": 22,
"protocol_version": 0,
"encrypted_packet": false,
"encryption_algorithm": 0,
"pts_adjustment": 74825.294489,
"cw_index": "0x00",
"tier": "0x00",
"splice_command_length": 5,
"splice_command_type": 6,
"descriptor_loop_length": 0,
"crc": "0x36a7bc97"
},
"command": {
"command_length": 5,
"command_type": 6,
"name": "Time Signal",
"time_specified_flag": true,
"pts_time": 1.234556
},
"descriptors": []
}
- integer
>>>> cue.int()
1583008701076488801275299570612875276859137926425502632361111
- xml
>>>> cue.xml()
<scte35:SpliceInfoSectionxmlns:scte35="https://scte.org/schemas/35" ptsAdjustment="6734276504" protocolVersion="0" sapType="3" tier="0">
<scte35:TimeSignal>
<scte35:SpliceTime ptsTime="111110"/>
</scte35:TimeSignal>
</scte35:SpliceInfoSection>
- xml+bin
>>>> cue.xmlbin()
<scte35:Signalxmlns:scte35="https://scte.org/schemas/35">
<scte35:Binary>/DAWAAGRZOeYAAAABQb+AAGyBgAANqe8lw==</scte35:Binary>
</scte35:Signal>
- for more specifics help is built-in
help(Cue)
Stream class
-
The Stream class is used for Parsing SCTE-35 from MPEGTS streams.
-
The Stream class can open streams from stdout, files, HTTP(S), Multicast, SRT, and UDP.
-
Stream.init(self, tsdata, show_null=True, headers={})
-
tsdata is the only required arg, it is the stream
-
show_null is a boolean to show Splice Nulls or not.
-
headers is a dict for HTTP or SRT headers If needed.
>>>> from threefive import Stream
>>>> st =Stream('https://iodisco.com/longb2.ts')
- Stream.decode() prints SCTE-35 as JSON
>>>> st.decode()
Triggering on SCTE-35
- Stream.decode_next() is a python generator that yields a Cue instance when SCTE-35 is found in an MPEGTS stream
from threefive import Stream
>>>> st =Stream('https://iodisco.com/longb2.ts')
>>>> for cue in st.decode_next():
.... cmd = f"Command: {cue.command.name}"
.... if cue.command.has("pts_time"):
.... cmd += f"\t pts: {cue.command.pts_time}"
.... print(cmd)
....
Command: Time Signal pts: 1.433
Command: Time Signal pts: 6.772
Command: Time Signal pts: 9.141
Command: Time Signal pts: 12.11
Command: Time Signal pts: 17.449
Command: Time Signal pts: 22.788
Command: Time Signal pts: 28.126
Command: Time Signal pts: 33.465
Command: Time Signal pts: 38.804
Command: Time Signal pts: 44.142
Command: Time Signal pts: 49.481
Command: Time Signal pts: 54.82
Command: Time Signal pts: 60.158
Command: Time Signal pts: 65.497
Command: Time Signal pts: 70.836
Command: Time Signal pts: 76.174
Command: Time Signal pts: 81.513
Command: Time Signal pts: 86.852
Other Stream methods
- Stream.show() shows details of the MPEGTS stream
>>>> st =Stream('https://iodisco.com/longb2.ts')
>>>> st.show()
---------------------------------------------
https://iodisco.com/longb2.ts
Program: 1
PTS Start: 1.433
Program Pid: 4096
Pcr Pid: 256
Streams:
Pid Type
256 [0x100] 0x1b H.264
257 [0x101] 0xf ADTS AAC
258 [0x102] 0x86 SCTE-35
- Stream.Proxy() parses SCTE-35 and copies the stream to stdout for piping the stream to another program.
>>>> st =Stream('https://iodisco.com/longb2.ts')
>>>> st.proxy()
- Stream.show_pts()
>>>> st =Stream('https://iodisco.com/longb2.ts')
>>>> st.show_pts()
Prgm PTS
1 1.433
1 1.466
1 1.533
1 1.5
1 1.566
1 1.633
1 1.6
1 1.667
1 1.7
1 1.733
1 1.767
1 1.8
1 1.833
1 1.867
1 1.9
1 1.967
- for more Stream specifics, see the built in docs
>>>> from threefive import Stream
>>>> help(Stream)
⇧
[web]
- threefive SCTE-35 Online Parser hosted on my server iodisco.com
- Parse SCTE-35 in MPEGTS over HTTP, in your browser with Go, Wasm and Super Karate Death Car hosted om my server iodisco.com
- Parse SCTE-35 in MPEGTS over HTTP, in your browser with threefive.js,javascript, and a little sed just to keep things interesting. hosted om my server iodisco.com
- SCTE-35 Online Parser powered by threefive another online parser powered by threefive not hosted on my servers.
- SCTE-35 As a Service if you can make an http request, you can parse SCTE-35, no install needed. hosted on my server iodisco.com
⇧
[XML]
- XML New! updated 05/01/2025
[HLS]
- Advanced Parsing of SCTE-35 in HLS with threefive All HLS SCTE-35 tags, Sidecar Files, AAC ID3 Header Timestamps, SCTE-35 filters... Who loves you baby?
⇧
[Classes]
- The python built in help is always the most up to date docs for the library.
a@fu:~/build7/threefive$ pypy3
>>>> from threefive import Stream
>>>> help(Stream)
- Class Structure
- Cue Class Cue is the main SCTE-35 class to use.
- Stream Class The Stream class handles MPEGTS SCTE-35 streams local, Http(s), UDP, and Multicast.
⇧
[threefive now supports SRT]
- ( You have to unmute the audio )
https://github.com/user-attachments/assets/a323ea90-867f-480f-a55f-e9339263e511
-
checkout SRTfu
⇧
[more]
- Encode SCTE-35 Some encoding code examples.
⇧
Metadata
Release files for threefive 3.1.9
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| threefive-3.1.9.tar.gz | 79.9 kB | Without provenance | Details for threefive-3.1.9.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| threefive-3.1.9-py3-none-any.whl | Python 3 | none | any | Details for threefive-3.1.9-py3-none-any.whl |
Total release size: 161.5 kB
Release files / threefive-3.1.9.tar.gz
| Download URL | threefive-3.1.9.tar.gz |
|---|---|
| Size | 79.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
feb4cf98d57a411d502590ce14ee1c5d22296d7f935220c2fe79b94f3692ccb9
|
|
BLAKE2b-256 checksum How to use checksums |
ae2eccd7fd842c1e380a2b488157f386680c224c2d8deead86338db168b350ed
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.6
|
Release files / threefive-3.1.9-py3-none-any.whl
| Download URL | threefive-3.1.9-py3-none-any.whl |
|---|---|
| Size | 81.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
471bc446e90cde908133eaeea1ab1fd1732b75bc1ef760e6663238de95eafbe3
|
|
BLAKE2b-256 checksum How to use checksums |
d23c24efb8e23f35a0c8b24b09cd0ff319defe505f14b9831a85b5a52da1f97c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.6
|
Security for threefive 3.1.9
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.