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

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

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.9
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)

Table of built distributions (wheels) for threefive 3.1.9
File Interpreter ABI Platform Actions
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.

Release history Release notifications | RSS feed

This release

3.1.9 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