Skip to main content

[ 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.7

  • threefive now parses ID3 streams for SCTE-35 in MPEGTS stream parsing.
  • HLS Parser has been tuned up. DATERANGE tag fixed.
  • Iframer has been merged into the Stream class.
  • check the change log

[ 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.

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


⇧

[XML]

  • XML New! updated 05/01/2025

[HLS]

⇧

[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)

⇧

[threefive now supports SRT]

  • ( You have to unmute the audio )

https://github.com/user-attachments/assets/a323ea90-867f-480f-a55f-e9339263e511



⇧

[more]

⇧

Metadata

Release files for threefive 3.1.7

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for threefive 3.1.7
File Size Uploaded Provenance Actions
threefive-3.1.7.tar.gz 79.9 kB Without provenance Details for threefive-3.1.7.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for threefive 3.1.7
File Interpreter ABI Platform Actions
threefive-3.1.7-py3-none-any.whl Python 3 none any Details for threefive-3.1.7-py3-none-any.whl

Total release size: 161.5 kB

Release files / threefive-3.1.7.tar.gz

Download URL threefive-3.1.7.tar.gz
Size 79.9 kB
Tags Source
SHA-256 checksum
How to use checksums
a1f39e4e7fb5ad3f420b8f8ad77bbe76d63fede8a320fabc6570917bf1f29595
BLAKE2b-256 checksum
How to use checksums
3564ec03ffa6a06f16bfac6dbe5f695b03f3d99727196ee014bd0a8b5c50f405
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.7-py3-none-any.whl

Download URL threefive-3.1.7-py3-none-any.whl
Size 81.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
4bb6f582f868a9a59ec1e10c6e6a9e4f9d496b3fee164cd31d9db1ee86b9d1da
BLAKE2b-256 checksum
How to use checksums
72f51f4e521a47762ba259fb32dfcec3fe9ba23eff5f2def32b3318cbd823a94
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.7

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.

Release history Release notifications | RSS feed

This release

3.1.7 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page