Skip to content

AudioDan/scte35-threefive

 
 

Repository files navigation

threefive is the most advanced SCTE35 parser lib available, probably.


Welcome to the show.

Requirements

  • threefive requires pypy3 or python 3.6+
    • (pypy3 runs threefive 4x Faster than python3)
  • threefive 2.3.02+ requires crcmod for encoding and pyaes for decrypting.

Install

pip3 install threefive

# for pypy3
pypy3 -m pip install threefive

Versions and Releases

Release versions are odd. Unstable testing versions are even.

threefive.version() returns the version as a string.

threefive.version_number() returns an int for easy version comparisons.


Easy threefive

threefive.decode is a SCTE-35 decoder function with input type auto-detection. Base64, Binary, Hex Strings,Hex literals, Integers, Mpegts files and Mpegts HTTP/HTTPS Streams

SCTE-35 data can be parsed with just one function call.

the arg stuff is the input. if stuff is not set, decode will attempt to read from sys.stdin.buffer.

if stuff is a file, the file data will be read and the type of the data will be autodetected and decoded.

SCTE-35 data is printed in JSON format.

Examples:

Base64
import threefive 

stuff = '/DAvAAAAAAAA///wBQb+dGKQoAAZAhdDVUVJSAAAjn+fCAgAAAAALKChijUCAKnMZ1g='
threefive.decode(stuff)
Bytes
import threefive 

payload = b'\xfc0\x11\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\x00\x00\x00O%3\x96'
threefive.decode(payload)
Hex String
import threefive 

stuff = '0XFC301100000000000000FFFFFF0000004F253396'
threefive.decode(stuff)
Hex Literal
import threefive 

threefive.decode(0XFC301100000000000000FFFFFF0000004F253396)
Integer
big_int = 1439737590925997869941740173214217318917816529814
threefive.decode(big_int)
Mpegts File
import threefive 

threefive.decode('/path/to/mpegts')
Mpegts HTTP/HTTPS Streams
import threefive 

threefive.decode('https://futzu.com/xaa.ts')
Read from File cue.txt
from threefive import decode

decode('cue.txt')

A threefive SCTE-35 Cue

{
    "info_section": {
        "table_id": "0xfc",
        "section_syntax_indicator": false,
        "private": false,
        "sap_type": "0x3",
        "sap_details": "No Sap Type",
        "section_length": 47,
        "protocol_version": 0,
        "encrypted_packet": false,
        "encryption_algorithm": 0,
        "pts_adjustment": 0.0,
        "cw_index": "0x0",
        "tier": "0xfff",
        "splice_command_length": 4095,
        "splice_command_type": 5,
        "descriptor_loop_length": 10,
        "crc": "0x10fa4d9e"
    },
    "command": {
        "calculated_length": 20,
        "name": "Splice Insert",
        "time_specified_flag": true,
        "pts_time": 89742.161689,
        "break_auto_return": false,
        "break_duration": 242.0,
        "splice_event_id": 662,
        "splice_event_cancel_indicator": false,
        "out_of_network_indicator": true,
        "program_splice_flag": true,
        "duration_flag": true,
        "splice_immediate_flag": false,
        "unique_program_id": 1,
        "avail_num": 0,
        "avail_expected": 0
    },
    "descriptors": [
        {
            "tag": 0,
            "descriptor_length": 8,
            "name": "Avail Descriptor",
            "identifier": "CUEI",
            "provider_avail_id": 0
        }
    ],
    "packet_data": {
        "pid": "0x135",
        "program": 1,
        "pcr": 89730.281789,
        "pts": 89730.289522
    }
}

Advanced threefive


Cue Class

  • src cue.py
  • The threefive.Cue class decodes a SCTE35 binary, base64, or hex encoded string.
  • threefive.Cue provides several methods to access the parsed data.
    >>>> 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 SCTE35 Cues from MPEGTS streams, threefive attempts to include as many of the following as possible.'

  • pid of the packet
  • program of the pid
  • pts of the packet
  • pcr of the packet

  • call one or more of these methods after decode.
Cue Method Description
cue.get() returns cue as a dict
cue.get_json() returns cue as a JSON string
cue.show() prints cue as JSON

Stream Class

 threefive.Stream(tsdata, show_null = False)
  • src stream.py
  • The threefive.Stream class parses SCTE35 messages from a file or stream.
  • Supports
  • __file and http(s) URIs directly. * Multiple Programs. * Multiple SCTE35 Streams. * Multi-Packet PAT, PMT, and SCTE35 tables. * Constant Data Parsing. * threefive.Stream is designed to run continuously
Method Description
Stream.show() Prints Streams that will be checked for SCTE35
Stream.decode(func=show_cue) Prints SCTE-35 cues for SCTE-35 packets. Accepts an optional function, func, as arg.
Stream.decode_next() Returns the next SCTE35 cue as a threefive.Cue instance.
Stream.decode_program(the_program=None, func=show_cue) Same as Stream.decode except only packets where program == the_program
Stream.decode_proxy(func=show_cue) Same as Stream.decode except raw packets are written to stdout for piping to another program.

Stream.show()

  • List programs and streams that will be checked for SCTE35 data.
>>>> from threefive import Stream
>>>> Stream('https://slo.me/plp0.ts').show()

Program:1030

   1031 [0x407] Type: 0x1b   PCR 
   1032 [0x408] Type: 0x3  
   1034 [0x40a] Type: 0x6  
   1035 [0x40b] Type: 0x86   SCTE35 

Program:1100

   1101 [0x44d] Type: 0x1b   PCR 
   1102 [0x44e] Type: 0x3  
   1104 [0x450] Type: 0x6  
   1105 [0x451] Type: 0x86   SCTE35 

Program:1080

   1081 [0x439] Type: 0x1b   PCR 
   1082 [0x43a] Type: 0x3  
   1084 [0x43c] Type: 0x6  

Stream.decode(func=show_cue)

import sys
from threefive import Stream
>>>> Stream('plp0.ts').decode()
  • Pass in custom function

  • func should match the interface func(cue)

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.decode_next()

  • Stream.decode_next returns the next SCTE35 cue as a threefive.Cue instance.
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_program(the_program, func = show_cue)

  • Use Stream.decode_program() instead of Stream.decode() to decode SCTE-35 from packets where program == the_program
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.

import threefive
sp = threefive.Stream('https://futzu.com/xaa.ts')
sp.proxy_decode()
  • Pipe to mplayer
$ python3 proxy.py | mplayer -

Issues and Bugs and Feature Requests


Speak up. I want to hear what you have to say.

If threefive doesn't work as expected,

or if you find a bug ,

or if you have feature request,

please open an issue.


About

threefive is the Best SCTE35 Parser on the Planet. Quite Possibly the Most Advanced SCTE 35 Parser/Decoder. Ever. Maybe. threefive Parses SCTE35 from Base64, Binary, Hex Strings, Hex Literals, HLS, Integers, and MPEGTS files, and HTTP/HTTPS Streams. SCTE35 Cue Encoding is Now Enabled.

Resources

License

Code of conduct

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages

  • Python 74.6%
  • Go 24.8%
  • Other 0.6%