Pythonic SCTE35
Project description
A SCTE-35 parser lib in Python
Welcome to the Show.
-
ffmpeg and
SCTE35and Stream Type 0x6 bin data and threefive -
Issues and `Bugs and Feature Requests No forms man, just open an issue and tell me what you need.
-
Diagram of a threefive SCTE-35 Cue
Requirements
- threefive requires pypy3 or python 3.6+
- optional dependencies:
- pyaes If you want AES decryption for HLS segments.
Install
python3 -mpip install threefive
# and / or
pypy3 -m pip install threefive
- To install the optional dependencies.
python3 -mpip install threefive[all]
# and / or
pypy3 -mpip install threefive[all]
Versions and Releases
Release versions are odd. Unstable testing versions are even.
threefive.version()returns the version as a string.
Easy Examples
Base64
>>> from threefive import Cue
>>> stuff = '/DAvAAAAAAAA///wBQb+dGKQoAAZAhdDVUVJSAAAjn+fCAgAAAAALKChijUCAKnMZ1g='
>>> cue=Cue(stuff)
>>> cue.decode()
True
Bytes
>>> import threefive
>>> stuff = b'\xfc0\x11\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\x00\x00\x00O%3\x96'
>>> cue=Cue(stuff)
>>> cue.decode()
True
>>> cue.show()
Hex
import threefive
cue = threefive.Cue("0XFC301100000000000000FFFFFF0000004F253396")
cue.decode()
cue.show()
Mpegts Multicast
- On my Debian Sid laptop I set the following,
## <dev> is the network device
ip link set <dev> multicast on allmulticast on
ethtool -G <dev> rx 4096
sysctl -w net.core.rmem_default=5000000
sysctl -w net.core.rmem_max=15000000
import threefive
strm = threefive.Stream('udp://@239.35.0.35:1234')
strm.decode()
Cue Class
- src cue.py
- The threefive.Cue class decodes a SCTE35 binary, base64, or hex encoded string.
>>>> import threefive
>>>> Base64 = "/DAvAAAAAAAA///wBQb+dGKQoAAZAhdDVUVJSAAAjn+fCAgAAAAALKChijUCAKnMZ1g="
>>>> cue = threefive.Cue(Base64)
- cue.decode() returns True on success,or False if decoding failed
>>>> cue.decode()
True
- After Calling cue.decode() the instance variables can be accessed via dot notation.
>>>> cue.command
{'calculated_length': 5, 'name': 'Time Signal', 'time_specified_flag': True, 'pts_time': 21695.740089}
>>>> cue.command.pts_time
21695.740089
>>>> cue.info_section.table_id
'0xfc'
- When parsing Cues from MPEGTS, threefive tries to include,
- pid of the packet
- program of the pid
- pts of the packet
- pcr of the packet
class Cue(threefive.base.SCTE35Base)
| Cue(data=None, packet_data=None)
| __init__(self, data=None, packet_data=None)
| data may be packet bites or encoded string
| packet_data is a instance passed from a Stream instance
Cue.decode()
| decode(self)
| Cue.decode() parses for SCTE35 data
Cue.get()
| get(self)
| Cue.get returns the SCTE-35 Cue
| data as a dict of dicts.
Cue.get() Example
>>> from threefive import Cue
>>> cue = Cue('0XFC301100000000000000FFFFFF0000004F253396')
>>> cue.decode()
True
>>> cue
{'bites': b'\xfc0\x11\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\x00\x00\x00O%3\x96',
'info_section': {'table_id': '0xfc', 'section_syntax_indicator': False, 'private': False, 'sap_type': '0x3',
'sap_details': 'No Sap Type', 'section_length': 17, 'protocol_version': 0, 'encrypted_packet': False,
'encryption_algorithm': 0, 'pts_adjustment_ticks': 0, 'pts_adjustment': 0.0, 'cw_index': '0x0', 'tier': '0xfff',
'splice_command_length': 4095, 'splice_command_type': 0, 'descriptor_loop_length': 0, 'crc': '0x4f253396'},
'command': {'command_length': None, 'command_type': 0, 'name': 'Splice Null'},
'descriptors': [], 'packet_data': None}
- Cue.get() omits cue.bites and empty values
>>> cue.get()
{'info_section': {'table_id': '0xfc', 'section_syntax_indicator': False,'private': False, 'sap_type': '0x3',
'sap_details': 'No Sap Type', 'section_length': 17, 'protocol_version': 0, 'encrypted_packet': False,
'encryption_algorithm': 0, 'pts_adjustment_ticks': 0, 'pts_adjustment': 0.0, 'cw_index': '0x0', 'tier': '0xfff',
'splice_command_length': 4095, 'splice_command_type': 0, 'descriptor_loop_length': 0, 'crc': '0x4f253396'},
'command': {'command_type': 0, 'name': 'Splice Null'},
'descriptors': []}
Cue.get_descriptors()
| get_descriptors(self)
| Cue.get_descriptors returns a list of
| SCTE 35 splice descriptors as dicts.
Cue.get_json()
| get_json(self)
| Cue.get_json returns the Cue instance
| data in json.
Cue.show()
| show(self)
| Cue.show prints the Cue as JSON
Cue.to_stderr()
| to_stderr(self)
| Cue.to_stderr prints the Cue
Stream Class
- src stream.py
- The threefive.Stream class parses SCTE35 from Mpegts.
- Supports:
- File and Http(s) and Udp and Multicast protocols.
- Multiple Programs.
- Multi-Packet PAT, PMT, and SCTE35 tables.
class Stream(builtins.object)
| Stream(tsdata, show_null=True)
|
| Stream class for parsing MPEG-TS data.
| __init__(self, tsdata, show_null=True)
|
| tsdata is a file or http, https,
| udp or multicast url.
|
| set show_null=False to exclude Splice Nulls
|
| Use like...
|
| from threefive import Stream
| strm = Stream("vid.ts",show_null=False)
| strm.decode()
Stream.decode(func=show_cue)
| decode(self, func=show_cue)
| Stream.decode reads self.tsdata to find SCTE35 packets.
| func can be set to a custom function that accepts
| a threefive.Cue instance as it's only argument.
Stream.decode Example
import sys
from threefive import Stream
>>>> Stream('plp0.ts').decode()
-
Pass in custom function
-
func should match the interface
func(cue)
Stream.decode with custom function Example
import sys
import threefive
def display(cue):
print(f'\033[92m{cue.packet_data}\033[00m')
print(f'{cue.command.name}')
def do():
sp = threefive.Stream(tsdata)
sp.decode(func = display)
if __name__ == '__main__':
do()
Stream.decode2(func = show_cue)
| decode2(self, func=show_cue)
| Same as Stream.decode, but optimized for pypy3.
|
Stream.decode_next()
| decode_next(self)
| Stream.decode_next returns the next
| SCTE35 cue as a threefive.Cue instance.
Stream.decode_next Example
import sys
import threefive
def do():
arg = sys.argv[1]
with open(arg,'rb') as tsdata:
st = threefive.Stream(tsdata)
while True:
cue = st.decode_next()
if not cue:
return False
if cue:
cue.show()
if __name__ == "__main__":
do()
Stream.decode_plus(func = show_cue)
___
| decode_plus(self, func=<function show_cue at 0x00007f25d50f6980>)
| Stream.decode_plus is Stream.decode plus
| continuity counter checking and pcr timestamps.
Stream.decode_program(the_program, func = show_cue)
| decode_program(self, the_program, func=show_cue)
| Stream.decode_program limits SCTE35 parsing
| to a specific MPEGTS program.
Stream.decode_program Example
import threefive
threefive.Stream('35.ts').decode_program(1)
Stream.decode_proxy(func = show_cue)
-
Writes all packets to sys.stdout.
-
Writes scte35 data to sys.stderr.
| decode_proxy(self, func=show_cue_stderr)
| Stream.decode_proxy writes all ts packets are written to stdout
| for piping into another program like mplayer.
| SCTE-35 cues are printed to stderr.
Stream.decode_proxy Example
import threefive
sp = threefive.Stream('https://futzu.com/xaa.ts')
sp.decode_proxy()
- Pipe to mplayer
$ python3 proxy.py | mplayer -
Stream.show()
| show(self)
| List programs and streams and info for MPEGTS
Stream.show() Example
>>>> from threefive import Stream
>>>> Stream('https://slo.me/plp0.ts').show()
Program: 1040
Service: fumatic
Provider: fu-labs
Pcr Pid: 1041[0x411]
Streams:
Pid: 1041[0x411] Type: 0x1b AVC Video
Pid: 1042[0x412] Type: 0x3 MP2 Audio
Pid: 1044[0x414] Type: 0x6 PES Packets/Private Data
Pid: 1045[0x415] Type: 0x86 SCTE35 Data
Program: 1050
Service: fancy ˹
Provider: fu-corp
Pcr Pid: 1051[0x41b]
Streams:
Pid: 1051[0x41b] Type: 0x1b AVC Video
Pid: 1052[0x41c] Type: 0x3 MP2 Audio
Pid: 1054[0x41e] Type: 0x6 PES Packets/Private Data
Pid: 1055[0x41f] Type: 0x86 SCTE35 Data
Stream.dump(fname)
| dump(self, fname)
| Stream.dump dumps all the packets to a file (fname).
Stream.strip_scte35(func=show_cue_stderr)
| strip_scte35(self, func=show_cue_stderr)
| Stream.strip_scte35 works just like Stream.decode_proxy,
| MPEGTS packets, ( Except the SCTE-35 packets) ,
| are written to stdout after being parsed.
| SCTE-35 cues are printed to stderr.
A lot of folks have been searching this repo for uuid, I'm not sure if they are looking for uuid in a upid, or a randomly generated uuid for an HLS tag or something else. Heres what I know about it.
>>> from uuid import uuid4, UUID
# generate a random uuid
>>> uu= uuid4()
>>> uu
UUID('7ae2e37e-3018-4c4e-8a10-f69d075828b4')
# uuid as bytes
>>> uu.bytes
b'z\xe2\xe3~0\x18LN\x8a\x10\xf6\x9d\x07X(\xb4'
# bytes to uuid
>>> UUID(bytes=uu.bytes)
UUID('7ae2e37e-3018-4c4e-8a10-f69d075828b4')
>>>
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file threefive-2.3.33.tar.gz.
File metadata
- Download URL: threefive-2.3.33.tar.gz
- Upload date:
- Size: 30.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/4.0.0 CPython/3.10.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ff01a62eddf6723cb046b075ed221b4b98ee3767a0615ae441c55597e2ce907c
|
|
| MD5 |
686917f3720d59482eaa09fc08e8046c
|
|
| BLAKE2b-256 |
b0afc8cacb0e99a5ef789036ea421a09ba83c6d7e9b82883061ed8a7b68bf598
|
File details
Details for the file threefive-2.3.33-py3-none-any.whl.
File metadata
- Download URL: threefive-2.3.33-py3-none-any.whl
- Upload date:
- Size: 30.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/4.0.0 CPython/3.10.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
be8f1ae7ff8e264596a22d055ca5ba9b56f9be5af58cc41938b7f8b3b6bd1a78
|
|
| MD5 |
35106bf539a78a5e45eff95271cfd59b
|
|
| BLAKE2b-256 |
25b383649ee147feddfe900f5faf3be5ce490bf707740f2422efd269420a4888
|