- ( You have to unmute the audio )
srt.mp4
checkout SRTfu
- why can`t you be more cyclomatic like your brother?
- live SRT support is now stable for decoding.
- live SRT streaming support has been integrated, no special handling required.
- srtfu now build libsrt automatically the first time you use it.
- threefive functions with or without SRT support.
- Some people have complained that the callback functionality of Stream.decode is too limiting. So I made Stream.decode_next a full blown python generator, so now you can get the SCTE-35 cues as they happen and handle them however you like.
from threefive import Stream
strm =Stream(some_url)
for cue in strm.decode_next():
your_complicated_function(cue, one_arg , two_arg, 13,)-
Decode SCTE-35 from:
- MPEGTS ✔
- Base64 ✔
- Bytes ✔
- Hex ✔
- Integers
- ✔ JSON
- ✔ XML
- ✔ XML+Binary
- ✔ DASH ✔
- Dicts ✔
-
Encodes SCTE-35 to:
- MPEGTS ✔
- Base64 ✔
- Bytes ✔
- Hex ✔
- Integers ✔
- JSON ✔
- XML ✔
- XML+Binary ✔
-
threefive file protocols:
- Pipes(stdin, stdout) ✔
- Files ✔
-
threefive network protocols:
- HTTP(s) ✔
- Multicast ✔
- UDP ✔
- SRT ✔
-
Automatic AES decryption for MPEGTS and HLS. ✔
-
Built-in Multicast Sender and Receiver. ✔
-
Injects SCTE-35 Packets into MPEGTS video ✔.
If you want to have a Segmentation Descriptor without a UPID
set segmentation_upid_length= 0
set segmentation_upid_type= 0
- Install
- SCTE-35 Decoding Quick Start threefive makes decoding SCTE-35 fast and easy
- SCTE-35 Examples examples of all kinds of SCTE-35 stuff
- SCTE-35 Cli decode SCTE-35 on the command line
- Using the threefive library decode SCTE-35 with less than ten lines of code
- SCTE-35 HLS parse SCTE-35 in HLS_
- 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
- SCTE-35 Sidecar Files threefive supports SCTE-35 sidecar files
- SuperKabuki SCTE-35 MPEGTS Packet Injection inject SCTE-35 into MPEGTS streams
- threefive Classes threefive is OO, made to subclass
- Cue Class this class you'll use often
- Stream Class this is the class for parsing MPEGTS
- Use threefive to stream Multicast threefive is a multicast client and server
- SCTE-35 Online Parser powered by threefive, hosted on my server
- SCTE-35 As a Service if you can make an http request, you can parse SCTE-35, no install needed.
- Make your threefive script an executable with cython threefive is compatible with all python tools
- python3 via pip
python3 -mpip install threefive- pypy3
pypy3 -mpip install threefive- from the git repo
git clone https://github.com/superkabuki/scte35.git
cd threefive
make install- Most of the stuff in threefive all works the same way.
-
The default action is to read a input and write a SCTE-35 output.
-
Inputs: mpegts, base64, hex, json,and xml, and xmlbin.
-
Outputs: base64, bytes, hex, int, json, xml, and xmlbin.
-
Sources: SCTE35 can read from strings, files, stdin, http(s), multicast,srt and udp.
-
| Input | Output | How to use |
|---|---|---|
| mpegts | base64 | threefive https://example.com/video.ts base64 |
| base64 | hex | threefive '/DAWAAAAAAAAAP/wBQb+AKmKxwAACzuu2Q==' hex |
| xmlbin | int | threefive < xmlbin.xml int |
| xml | json | threefive < xml.xml |
| mpegts | xml+bin | threefive video.ts xmlbin |
| json | xml | threefive < json.json xml |
- Additional functionality in the threefive cli tool.
| Description | How To Use |
|---|---|
| Parse HLS for SCTE35 | threefive hls https://example.com/master.m3u8 |
| Inject SCTE35 packets | threefive inject -i in.video -s sidecar.txt -o out.ts |
| Show raw SCTE35 packets | threefive packets udp://@235.35.3.5:3535 |
| Create SCTE35 sidecar file | threefive sidecar video.ts |
| Fix SCTE-35 data mangled by ffmpeg | threefive sixfix video.ts |
| Show streams in mpegts stream | threefive show https://example.com/video.ts |
| Show iframes in mpegts stream | threefive iframes srt://10.10.1.3:9000 |
| Show PTS values from mpegts stream | threefive pts udp://192.168.1.10:9000 |
| Proxy the mpegts stream to stdout | threefive proxy https://wexample.com/video.ts |
| Multicast anything | threefive mcast some.file |
- XML New! updated 05/01/2025
- SCTE-35 Cli Super Tool Encodes, Decodes, and Recodes. This is pretty cool, it does SCTE-35 seven different ways.
- The cli tool comes with builtin documentation just type
threefive help
- The cli tool comes with builtin documentation just type
- 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?
- Decode SCTE-35 without installing anything. If you can make an https request, you can use Sassy to decode SCTE-35. .
- 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.
-
Online SCTE-35 Parser Supporte Base64, Bytes,Hex,Int, Json, Xml, and Xml+binary.
-
Encode SCTE-35 Some encoding code examples.
- ( You have to unmute the audio )
pvp.mp4
-
Let me show you how easy threefive is to use.
-
reading SCTE-35 xml from a file
a@fu:~/threefive$ pypy3
Python 3.9.16 (7.3.11+dfsg-2+deb12u3, Dec 30 2024, 22:36:23)
[PyPy 7.3.11 with GCC 12.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>> from threefive import reader
>>>> from threefive import Cue
>>>> data =reader('/home/a/xml.xml').read()- load it into a threefive.Cue instance
>>>> cue = Cue(data)- Show the data as JSON
>>>> cue.show()
{
"info_section": {
"table_id": "0xfc",
"section_syntax_indicator": false,
"private": false,
"sap_type": "0x03",
"sap_details": "No Sap Type",
"section_length": 92,
"protocol_version": 0,
"encrypted_packet": false,
"encryption_algorithm": 0,
"pts_adjustment": 0.0,
"cw_index": "0x00",
"tier": "0x0fff",
"splice_command_length": 15,
"splice_command_type": 5,
"descriptor_loop_length": 60,
"crc": "0x7632935"
},
"command": {
"command_length": 15,
"command_type": 5,
"name": "Splice Insert",
"break_auto_return": false,
"break_duration": 180.0,
"splice_event_id": 1073743095,
"splice_event_cancel_indicator": false,
"out_of_network_indicator": true,
"program_splice_flag": false,
"duration_flag": true,
"splice_immediate_flag": false,
"event_id_compliance_flag": true,
"unique_program_id": 1,
"avail_num": 12,
"avails_expected": 5
},
"descriptors": [
{
"tag": 0,
"identifier": "CUEI",
"name": "Avail Descriptor",
"provider_avail_id": 12,
"descriptor_length": 8
},
{
"tag": 0,
"identifier": "CUEI",
"name": "Avail Descriptor",
"provider_avail_id": 13,
"descriptor_length": 8
},
]
}- convert the data back to xml
>>>> print(cue.xml())
<scte35:SpliceInfoSection xmlns:scte35="https://scte.org/schemas/35" ptsAdjustment="0" protocolVersion="0" sapType="3" tier="4095">
<scte35:SpliceInsert spliceEventId="1073743095" spliceEventCancelIndicator="false" spliceImmediateFlag="false" eventIdComplianceFlag="true" availNum="12" availsExpected="5" outOfNetworkIndicator="true" uniqueProgramId="1">
<scte35:BreakDuration autoReturn="false" duration="16200000"/>
</scte35:SpliceInsert>
<scte35:AvailDescriptor providerAvailId="12"/>
<scte35:AvailDescriptor providerAvailId="13"/>
<scte35:AvailDescriptor providerAvailId="14"/>
<scte35:AvailDescriptor providerAvailId="15"/>
<scte35:AvailDescriptor providerAvailId="16"/>
<scte35:AvailDescriptor providerAvailId="17"/>
</scte35:SpliceInfoSection>- convert to xml+binary
>>>> print(cue.xmlbin())
<scte35:Signal xmlns:scte35="https://scte.org/schemas/35">
<scte35:Binary>/DBcAAAAAAAAAP/wDwVAAAT3f69+APcxQAABDAUAPAAIQ1VFSQAAAAwACENVRUkAAAANAAhDVUVJAAAADgAIQ1VFSQAAAA8ACENVRUkAAAAQAAhDVUVJAAAAEQdjKTU=</scte35:Binary>
</scte35:Signal>- convert to base64
>>>> print(cue.base64())
/DBcAAAAAAAAAP/wDwVAAAT3f69+APcxQAABDAUAPAAIQ1VFSQAAAAwACENVRUkAAAANAAhDVUVJAAAADgAIQ1VFSQAAAA8ACENVRUkAAAAQAAhDVUVJAAAAEQdjKTU=- convert to hex
>>>> print(cue.hex())
0xfc305c00000000000000fff00f05400004f77faf7e00f7314000010c05003c0008435545490000000c0008435545490000000d0008435545490000000e0008435545490000000f000843554549000000100008435545490000001107632935- show just the splice command
>>>> cue.command.show()
{
"command_length": 15,
"command_type": 5,
"name": "Splice Insert",
"break_auto_return": false,
"break_duration": 180.0,
"splice_event_id": 1073743095,
"splice_event_cancel_indicator": false,
"out_of_network_indicator": true,
"program_splice_flag": false,
"duration_flag": true,
"splice_immediate_flag": false,
"event_id_compliance_flag": true,
"unique_program_id": 1,
"avail_num": 12,
"avails_expected": 5
}- edit the break duration
>>>> cue.command.break_duration=30
>>>> cue.command.show()
{
"command_length": 15,
"command_type": 5,
"name": "Splice Insert",
"break_auto_return": false,
"break_duration": 30,
"splice_event_id": 1073743095,
"splice_event_cancel_indicator": false,
"out_of_network_indicator": true,
"program_splice_flag": false,
"duration_flag": true,
"splice_immediate_flag": false,
"event_id_compliance_flag": true,
"unique_program_id": 1,
"avail_num": 12,
"avails_expected": 5
}- re-encode to base64 with the new duration
>>>> cue.base64()
'/DBcAAAAAAAAAP/wDwVAAAT3f69+ACky4AABDAUAPAAIQ1VFSQAAAAwACENVRUkAAAANAAhDVUVJAAAADgAIQ1VFSQAAAA8ACENVRUkAAAAQAAhDVUVJAAAAEe1FB6g='- re-encode to xml with the new duration
>>>> print(cue.xml())
<scte35:SpliceInfoSection xmlns:scte35="https://scte.org/schemas/35" ptsAdjustment="0" protocolVersion="0" sapType="3" tier="4095">
<scte35:SpliceInsert spliceEventId="1073743095" spliceEventCancelIndicator="false" spliceImmediateFlag="false" eventIdComplianceFlag="true" availNum="12" availsExpected="5" outOfNetworkIndicator="true" uniqueProgramId="1">
<scte35:BreakDuration autoReturn="false" duration="2700000"/>
</scte35:SpliceInsert>
<scte35:AvailDescriptor providerAvailId="12"/>
<scte35:AvailDescriptor providerAvailId="13"/>
<scte35:AvailDescriptor providerAvailId="14"/>
<scte35:AvailDescriptor providerAvailId="15"/>
<scte35:AvailDescriptor providerAvailId="16"/>
<scte35:AvailDescriptor providerAvailId="17"/>
</scte35:SpliceInfoSection>- show just the descriptors
>>>> _ = [d.show() for d in cue.descriptors]
{
"tag": 0,
"identifier": "CUEI",
"name": "Avail Descriptor",
"provider_avail_id": 12,
"descriptor_length": 8
}
{
"tag": 0,
"identifier": "CUEI",
"name": "Avail Descriptor",
"provider_avail_id": 13,
"descriptor_length": 8
}
{
"tag": 0,
"identifier": "CUEI",
"name": "Avail Descriptor",
"provider_avail_id": 14,
"descriptor_length": 8
}
{
"tag": 0,
"identifier": "CUEI",
"name": "Avail Descriptor",
"provider_avail_id": 15,
"descriptor_length": 8
}
{
"tag": 0,
"identifier": "CUEI",
"name": "Avail Descriptor",
"provider_avail_id": 16,
"descriptor_length": 8
}
{
"tag": 0,
"identifier": "CUEI",
"name": "Avail Descriptor",
"provider_avail_id": 17,
"descriptor_length": 8
}- pop off the last descriptor and re-encode to xml
>>>> cue.descriptors.pop()
{'tag': 0, 'identifier': 'CUEI', 'name': 'Avail Descriptor', 'private_data': None, 'provider_avail_id': 17, 'descriptor_length': 8}
>>>> print(cue.xml())
<scte35:SpliceInfoSection xmlns:scte35="https://scte.org/schemas/35" ptsAdjustment="0" protocolVersion="0" sapType="3" tier="4095">
<scte35:SpliceInsert spliceEventId="1073743095" spliceEventCancelIndicator="false" spliceImmediateFlag="false" eventIdComplianceFlag="true" availNum="12" availsExpected="5" outOfNetworkIndicator="true" uniqueProgramId="1">
<scte35:BreakDuration autoReturn="false" duration="2700000"/>
</scte35:SpliceInsert>
<scte35:AvailDescriptor providerAvailId="12"/>
<scte35:AvailDescriptor providerAvailId="13"/>
<scte35:AvailDescriptor providerAvailId="14"/>
<scte35:AvailDescriptor providerAvailId="15"/>
<scte35:AvailDescriptor providerAvailId="16"/>
</scte35:SpliceInfoSection>- SCTE-35 Inputs
- SCTE-35 Outputs
- Parse MPEGTS streams for SCTE-35
- Parse SCTE-35 in hls
- Display MPEGTS iframes
- Display raw SCTE-35 packets from video streams
- Repair SCTE-35 streams changed to bin data by ffmpeg
- Most inputs are auto-detected.
- stdin is auto selected and auto detected.
- SCTE-35 data is printed to stderr
- stdout is used when piping video
- mpegts can be specified by file name or URI.
threefive udp://@235.2.5.35:3535- If a file comtains a SCTE-35 cue as a string( base64,hex,int,json,or xml+bin), redirect the file contents.
threefive < json.json
- quoted strings(( base64,hex,int,json or xml+bin), can be passed directly on the command line as well.
threefive '/DAWAAAAAAAAAP/wBQb+ztd7owAAdIbbmw=='
| Input Type | Cli Example |
|---|---|
| Base64 | threefive '/DAsAAAAAyiYAP/wCgUAAAABf1+ZmQEBABECD0NVRUkAAAAAf4ABADUAAC2XQZU=' |
| Hex | threefive 0xfc301600000000000000fff00506fed605225b0000b0b65f3b |
| HLS | threefive hls https://example.com/master.m3u8 |
| JSON | threefive < json.json |
| Xmlbin | js threefive < xmlbin.xml |
| Protocol | Cli Example |
|---|---|
| File | threefive video.ts |
| Http(s) | threefive https://example.com/video.ts |
| Stdin | threefive < video.ts |
| UDP Multicast | threefive udp://@235.35.3.5:9999 |
| UDP Unicast | threefive udp://10.0.0.7:5555 |
| HLS | threefive hls https://example.com/master.m3u8 |
- output type is determined by the key words base64, bytes, hex, int, json, and xmlbin.
- json is the default.
- Any input (except HLS,) can be returned as any output
- examples Base64 to Hex etc...)
| Output Type | Cli Example |
|---|---|
| Base 64 | threefive 0xfc301600000000000000fff00506fed605225b0000b0b65f3b base64 |
| Bytes | threefive 0xfc301600000000000000fff00506fed605225b0000b0b65f3b bytes |
| Hex | threefive '/DAsAAAAAyiYAP/wCgUAAAABf1+ZmQEBABECD0NVRUkAAAAAf4ABADUAAC2XQZU=' hex |
| Integer | threefive '/DAsAAAAAyiYAP/wCgUAAAABf1+ZmQEBABECD0NVRUkAAAAAf4ABADUAAC2XQZU=' int |
| JSON | threefive 0xfc301600000000000000fff00506fed605225b0000b0b65f3b json |
| Xml+bin | threefive 0xfc301600000000000000fff00506fed605225b0000b0b65f3b xmlbin |
- parse hls manifests and segments for SCTE-35
threefive hls https://example.com/master.m3u8- Show iframes PTS in an MPEGTS video
threefive iframes https://example.com/video.ts- Print raw SCTE-35 packets from multicast mpegts video
threefive packets udp://@235.35.3.5:3535- Parse a https stream and write raw video to stdout
threefive proxy video.ts- Print PTS from mpegts video
threefive pts video.ts- Parse a stream, write pts,write SCTE-35 Cues to sidecar.txt
threefive sidecar video.ts- Fix SCTE-35 data mangled by ffmpeg
threefive sixfix video.ts- Probe mpegts video ( kind of like ffprobe )
threefive show video.ts- Show version
threefive version- Help
threefive help- The threefive cli has long been a Multicast Receiver( client )
- The cli now comes with a builtin Multicast Sender( server).
- Start the Receiver first
- It's optimized for MPEGTS (1316 byte Datagrams) but you can send any video or file.
- The defaults will work in most situations, you don't even have to set the address.
- threefive cli also supports UDP Unicast Streaming.
a@fu:~$ threefive mcast help
usage: threefive mcast [-h] [-i INPUT] [-a ADDR] [-b BIND_ADDR] [-t TTL]
optional arguments:
-h, --help show this help message and exit
-i INPUT, --input INPUT
like "/home/a/vid.ts" or "udp://@235.35.3.5:3535" or
"https://futzu.com/xaa.ts"
[default:sys.stdin.buffer]
-a ADDR, --addr ADDR Destination IP:Port [default:235.35.3.5:3535]
-b BIND_ADDR, --bind_addr BIND_ADDR
Local IP to bind [default:0.0.0.0]
-t TTL, --ttl TTL Multicast TTL (1 - 255) [default:32]
a@fu:~$
Install |SCTE-35 Cli | SCTE-35 HLS | Cue Class | Stream Class | Online SCTE-35 Parser | Encode SCTE-35 | SCTE-35 Examples | SCTE-35 XML and More XML | threefive runs Four Times Faster on pypy3 | SuperKabuki SCTE-35 MPEGTS Packet Injection
-
MPEGTS streams can be Files, Http(s), Multicast, UDP Unicast, or stdin.
-
cli
threefive https://example.com/video.ts- wildcards work too.
threefive /mpegts/*.ts- lib
from threefive import Stream
stream = Stream('https://example.com/video.ts')
stream.decode()- cli
threefive '/DAsAAAAAyiYAP/wCgUAAAABf1+ZmQEBABECD0NVRUkAAAAAf4ABADUAAC2XQZU='- lib
from threefive import Cue
data = '/DAsAAAAAyiYAP/wCgUAAAABf1+ZmQEBABECD0NVRUkAAAAAf4ABADUAAC2XQZU='
cue=Cue(data)
cue.show()-
cli
- Bytes don't work on the cli
-
lib
from threefive import Cue
data = b'\xfc0\x16\x00\x00\x00\x00\x00\x00\x00\xff\xf0\x05\x06\xfe\x00\xc0D\xa0\x00\x00\x00\xb5k\x88'
cue=Cue(data)
cue.show()-
Can be a hex literal or hex string or bytes.
-
cli
threefive 0xfc301600000000000000fff00506fed605225b0000b0b65f3b- lib
from threefive import Cue
data = 0xfc301600000000000000fff00506fed605225b0000b0b65f3b
cue=Cue(data)
cue.show()-
Can be a literal integer or string or bytes.
-
cli
threefive 1583008701074197245727019716796221243043855984942057168199483- lib
from threefive import Cue
data = 1583008701074197245727019716796221243043855984942057168199483
cue=Cue(data)
cue.show()- cli
- put JSON SCTE-35 in a file and redirect it into threefive
threefive < json.json- lib
from threefive import Cue
data = '''{
"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": 0.0,
"cw_index": "0x00",
"tier": "0x0fff",
"splice_command_length": 5,
"splice_command_type": 6,
"descriptor_loop_length": 0,
"crc": "0xb56b88"
},
"command": {
"command_length": 5,
"command_type": 6,
"name": "Time Signal",
"time_specified_flag": true,
"pts_time": 140.005333
},
"descriptors": []
}
'''
cue=Cue(data)
cue.show()- cli
- put xml SCTE-35 in a file and redirect it into threefive
threefive < xml.xml
- lib
from threefive import Cue
data = '''
<scte35:SpliceInfoSection xmlns:scte35="https://scte.org/schemas/35"
ptsAdjustment="0" protocolVersion="0" sapType="3" tier="4095">
<scte35:TimeSignal>
<scte35:SpliceTime ptsTime="12600480"/>
</scte35:TimeSignal>
</scte35:SpliceInfoSection>
'''
cue=Cue(data)
cue.show()- cli
- write xml+binary to a file and redirect it to threefive
threefive < xmlbin.xml- lib
from threefive import Cue
data = '''<scte35:Signal xmlns:scte35="https://scte.org/schemas/35">
<scte35:Binary>/DAWAAAAAAAAAP/wBQb+AMBEoAAAALVriA==</scte35:Binary>
</scte35:Signal>
'''
cue=Cue(data)
cue.show()