Skip to main content

threefive, Pythonic SCTE-35.

Project description

threefive is a SCTE-35 Decoder / Parser library in Python3. If you need to parse SCTE-35, this is probably what you want to use.

threefive can parse SCTE-35 from Base64, Binary, Hex Strings, Hex literals, Integers, Mpegts files, and Mpegts HTTP/HTTPS Streams in one function call.

Mpegts is well supported in threefive.

  • Multiple Programs
  • Multiple SCTE35 Streams
  • Multi-Packet PAT, PMT, and SCTE35 tables
  • PCR and PTS to the microsecond.

Multicast? HLS? Custom Upid Handling? Frame Accurate Preroll timings? Oh yeah.

You feedback is welcome and encouraged. The best parts of threefive have come from other people.

If you have something to say, I want to hear it.

If you have a question, ask it. If it's a stupid question, that's okay, I ask stupid questions all the time.

Requirements

threefive requires python 3.6+ or pypy3

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

The decode Function

threefive.decode is a SCTE-35 decoder function with input type auto-detection.

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.

threefive.decode 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')

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
    • 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, version
>>>> version()
'2.2.69'
>>>> with open('video.ts','rb') as tsdata:
....     strm = Stream(tsdata)
....     strm.show()
....     

Program:1030
        PID: 1034(0x40a) Type: 0x6
        PID: 1035(0x40b) Type: 0x86 SCTE35

Program:1100
        PID: 1104(0x450) Type: 0x6
        PID: 1105(0x451) Type: 0x86 SCTE35

Program:1080
        PID: 1084(0x43c) Type: 0x6

Stream.decode(func=show_cue)

import sys
from threefive import Stream

if __name__ =='__main__':
   with open(sys.argv[1],'rb') as tsdata:
       sp = Stream(tsdata)
       sp.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():
   with open(sys.argv[1],'rb') as tsdata:
    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

with open('../35.ts','rb') as tsdata:
    threefive.Stream(tsdata).decode_program(1)

Stream.decode_proxy(func = show_cue)

  • Writes all packets to sys.stdout.

  • Writes scte35 data to sys.stderr.

import threefive

with open('vid.ts','rb') as tsdata:
    sp = threefive.Stream(tsdata)
    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.

If you want help resolving a video parsing issue, a sample of the video is required .

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

threefive-2.2.99.tar.gz (20.1 kB view hashes)

Uploaded Source

Built Distribution

threefive-2.2.99-py3-none-any.whl (20.8 kB view hashes)

Uploaded Python 3

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page