Skip to main content

Southern Fried SCTE35

Project description

threefive is the highest rated SCTE-35 decoder lib in the World.

threefive/go is now cuei

Cool New Stuff
  • the threefive executable script is now automatically installed

    • Example Usage:
threefive '/DAvAAAAAAAA///wBQb+dGKQoAAZAhdDVUVJSAAAjn+fCAgAAAAALKChijUCAKnMZ1g='

cat video.ts | threefive

threefive https://so.slo.me/longb.ts

threefive /home/a/video.ts

threefive udp://@235.35.3.5:3535
  • Helper functions for SCTE35 Cue encoding
Python 3.8.13 (7.3.9+dfsg-5, Oct 30 2022, 09:55:31)
[PyPy 7.3.9 with GCC 12.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>> import threefive.encode
>>>> help(threefive.encode)



Help on module threefive.encode in threefive:

NAME
    threefive.encode - encode.py

DESCRIPTION
    threefive.encode has helper functions for Cue encoding.

FUNCTIONS
    mk_splice_insert(event_id, pts=None, duration=None, out=False)
        mk_cue returns a Cue with a Splice Insert.
        
        The args set the SpliceInsert vars.
        
        splice_event_id = event_id
        
        if pts is None (default):
            splice_immediate_flag      True
            time_specified_flag        False
        
        if pts:
            splice_immediate_flag      False
            time_specified_flag        True
            pts_time                   pts
        
        If duration is None (default)
            duration_flag              False
        
        if duration IS set:
            out_of_network_indicator   True
            duration_flag              True
            break_auto_return          True
            break_duration             duration
            pts_time                   pts
        
        if out is True:
            out_of_network_indicator   True
        
        if out is False (default):
            out_of_network_indicator   False
    
    mk_splice_null()
        mk_splice_null returns a Cue
        with a Splice Null
    
    mk_time_signal(pts=None)
         mk_time_signal returns a Cue
         with a Time Signal
        if pts is None:
             time_specified_flag   False
        
        if pts IS set:
             time_specified_flag   True
             pts_time              pts
Heads Up PCR wil no long be included in threefive.Stream as of v.2.3.65
  • SCTE-35 Never uses PCR
  • Parsing PCR times accounts for about 30% of of the parse time for python3.
  • If this change negatively impacts you, let me know.
threefive parses All 2022 SCTE35
Latest release is 2.3.69
  • 2.3.69 fixes threefive.encode.mk_splice_insert for Cues with splice_immediate_flag and auto_break_return.

  • set pts=None for splice_immediate_flag

  • if duration is set, break_auto_return is set

>>>> from threefive.encode import mk_splice_insert
>>>> cue =mk_splice_insert(evnt_id,pts=None,duration=100.0)
Installation and Getting Started
Requirements
  • threefive requires
  • optional dependencies:
    • pyaes If you want AES decryption for HLS segments.
threefive classes.
threefive related projects
  • x9k3 HLS segmenter powered by threefive
  • amt-play Uses x9k3 and threefive
  • m3ufu M3U8 parser with SCTE-35 support.
  • kabuki changes stream types set to bin data by ffmpeg back to SCTE-35.
  • Project Super Kabuki SCTE35 MPEGTS Packet Injection.
  • cuei is the fastest SCTE-35 parser allowed by law, writtern In Go.

Diagram of a threefive SCTE-35 Cue.

ffmpeg and SCTE35 and 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.

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

>>> from threefive import version
>>> version()
'2.3.63'
>>> 
  • Release versions are odd.
  • Unstable testing versions are even.

image

Easy Examples

Mpegts Multicast
import threefive 

strm = threefive.Stream('udp://@239.35.0.35:1234')
strm.decode()

(need an easy multicast server? gumd )


Mpegts over Https
import threefive
strm = threefive.Stream('https://iodisco.com/ch1/ready.ts')
strm.decode()

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

Documentation for classes and methods

Cue Class

  • src cue.py
  • The threefive.Cue class decodes a SCTE35 binary, base64, or hex encoded string.
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
  • 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'
  • 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.
  • threefive tries to include pid, program, anf pts of the SCTE-35 packet.

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
  • 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.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_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()
    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
 


upids.charset

Specify a charset for Upid data by setting threefive.upids.charset issue #55

  • default charset is ascii
  • python charsets info Here
  • setting charset to None will return raw bytes.

Example Usage:

>>> from threefive import Cue,upids
>>> i="/DBKAAAAAAAAAP/wBQb+YtC8/AA0AiZDVUVJAAAD6X/CAAD3W3ACEmJibG5kcHBobkQCAsGDpQIAAAAAAAEKQ1VFSRSAIyowMljRk9c="

>>> upids.charset
'ascii'
>>> cue=Cue(i)
>>> cue.decode()
ascii
True
>>> cue.descriptors[0].segmentation_upid
'bblndpphnD\x02\x02���\x02\x00\x00'

>>> upids.charset="utf16"
>>> cue.decode()
utf16
True
>>> cue.descriptors[0].segmentation_upid
'扢湬灤桰䑮Ȃ菁ʥ\x00'

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.3.71.tar.gz (31.6 kB view hashes)

Uploaded Source

Built Distribution

threefive-2.3.71-py3-none-any.whl (31.5 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