Package: threefive
It's not just me sayingthreefive is the best SCTE-35 parser.threefiveis the  highest rated SCTE-35 parser.  Ever.cli tool and library for encoding and decoding SCTE-35.ParsesSCTE-35from multiple streams inMPEGTSandMultiple Program Transport StreamsParsesSCTE-35from  Cues encoded inBase64,Bytes,Hex,Integers.ParsesSCTE-35fromfiles,http(s),Multicast,UDPand evenstdin( you can pipe to it).ParsesSCTE-35from streams converted tobin data(type 0x06) byffmpeg.Latestthreefiverelease is2.4.35New stuff inthreefivethreefive cli tool now accepts keywordsthreefivesupports the latest SCTE-35 specificationSCTE-35 2023r1NEW!threefivenow has experimental DVB DAS SupportETSI TS 103 752-1SCTE-35 code examplesEncodingandEncoding | moreDocumentationSupported Platformsthreefive is expected to work on any platform that runs python3.6 and up.There are no known platform specific issues.Requirementsthreefive requirespypy3or python 3.6+ (pypy3 runs threefive 2-3 times faster than python 3.10)new_readerpyaesInstall threefiveFast StartSuper Cool ExamplesVersions and ReleasesVersions and ReleasesEvery time I fix a bug or add a feature, I do a new release.
I only support the latest version. Stay up with me.a@fu:~$pypy3Python3.9.17(7.3.12+dfsg-1,Jun162023,18:55:49)[PyPy7.3.12withGCC12.3.0]onlinuxType"help","copyright","credits"or"license"formoreinformation.>>>>importthreefive>>>>threefive.version'2.4.9'>>>>Releaseversions areodd.Unstabletesting versions areeven.Parse SCTE-35 on the command line.Parse base64threefive'/DAvAAAAAAAA///wFAVIAACPf+/+c2nALv4AUsz1AAAAAAAKAAhDVUVJAAABNWLbowo='Parse a hex valuethreefive0xFC302F000000000000FFFFF014054800008F7FEFFE7369C02EFE0052CCF500000000000A0008435545490000013562DBA30AParse MPEGTS from stdincatvideo.ts|threefiveParse MPEGTS video over httpsthreefivehttps://so.slo.me/longb.tsParse multicastthreefiveudp://@235.35.3.5:3535display realtime program -> ptsa@fu:~$threefivepts/home/a/msnbc.ts1->3164.4427561->3164.4094221->3164.4760891->3164.4760891->3164.4760891->3164.6427561->3164.576089display mpegts stream infoa@fu:~$threefiveshowhttps://futzu.com/xaa.tsProgram:1Service:Service01Provider:FFmpegPid:4096PcrPid:256Streams:Pid:134[0x86]Type:0x86SCTE35DataPid:256[0x100]Type:0x1bAVCVideoPid:257[0x101]Type:0xfAACAudioParse SCTE-35 programmatically with a few lines of code.Mpegts Multicast in three lines of code.importthreefivestrm=threefive.Stream('udp://@239.35.0.35:1234')strm.decode()(need an easy multicast server?gumd)Mpegts over Https in three lines of code.importthreefivestrm=threefive.Stream('https://iodisco.com/ch1/ready.ts')strm.decode()</details><details><summary>Base64infivelinesofcode.</summary>```python3>>>fromthreefiveimportCue>>>stuff='/DAvAAAAAAAA///wBQb+dGKQoAAZAhdDVUVJSAAAjn+fCAgAAAAALKChijUCAKnMZ1g='>>>cue=Cue(stuff)>>>cue.decode()True>>>cue.show()Bytes in five lines of code.>>>importthreefive>>>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 in 4 lines of code.importthreefivecue=threefive.Cue("0XFC301100000000000000FFFFFF0000004F253396")cue.decode()cue.show()Easy SCTE-35 encoding with threefive.Need SCTE-35 Packet Injection?SuperKabuki, powered by threefive.Helper functions for SCTE35 Cue encodingPython3.8.13(7.3.9+dfsg-5,Oct302022,09:55:31)[PyPy7.3.9withGCC12.2.0]onlinuxType"help","copyright","credits"or"license"formoreinformation.>>>>importthreefive.encode>>>>help(threefive.encode)Helponmodulethreefive.encodeinthreefive:NAMEthreefive.encode-encode.pyDESCRIPTIONthreefive.encodehashelperfunctionsforCueencoding.FUNCTIONSmk_splice_insert(event_id,pts=None,duration=None,out=False)mk_cuereturnsaCuewithaSpliceInsert.TheargssettheSpliceInsertvars.splice_event_id=event_idifptsisNone(default):splice_immediate_flagTruetime_specified_flagFalseifpts:splice_immediate_flagFalsetime_specified_flagTruepts_timeptsIfdurationisNone(default)duration_flagFalseifdurationISset:out_of_network_indicatorTrueduration_flagTruebreak_auto_returnTruebreak_durationdurationpts_timeptsifoutisTrue:out_of_network_indicatorTrueifoutisFalse(default):out_of_network_indicatorFalsemk_splice_null()mk_splice_nullreturnsaCuewithaSpliceNullmk_time_signal(pts=None)mk_time_signalreturnsaCuewithaTimeSignalifptsisNone:time_specified_flagFalseifptsISset:time_specified_flagTruepts_timeptsCue Classsrccue.pyThethreefive.Cueclass decodes a SCTE35 binary, base64, or hex encoded string.classCue(threefive.base.SCTE35Base)|Cue(data=None,packet_data=None)|__init__(self,data=None,packet_data=None)|datamaybepacketbitesorencodedstring|packet_dataisainstancepassedfromaStreaminstanceCue.decode()|decode(self)|Cue.decode()parsesforSCTE35dataAfter Calling cue.decode() theinstance 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_time21695.740089>>>>cue.info_section.table_id'0xfc'Cue.get()|get(self)|Cue.getreturnstheSCTE-35Cue|dataasadictofdicts.Cue.get() Example>>>fromthreefiveimportCue>>>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_descriptorsreturnsalistof|SCTE35splicedescriptorsasdicts.Cue.get_json()|get_json(self)|Cue.get_jsonreturnstheCueinstance|datainjson.Cue.show()|show(self)|Cue.showprintstheCueasJSONCue.to_stderr()|to_stderr(self)|Cue.to_stderrprintstheCueStream Classsrcstream.pyThe threefive.Streamclass parsesSCTE35fromMpegts.Supports:FileandHttp(s)andUdpandMulticastprotocols.Multiple Programs.Multi-Packet PAT, PMT, and SCTE35 tables.threefive tries to includepid,program, anfptsof the SCTE-35 packet.classStream(builtins.object)|Stream(tsdata,show_null=True)||StreamclassforparsingMPEG-TSdata.|__init__(self,tsdata,show_null=True)||tsdataisafileorhttp,https,|udpormulticasturl.||setshow_null=FalsetoexcludeSpliceNullsStream.decode(func=show_cue)|decode(self,func=show_cue)|Stream.decodereadsself.tsdatatofindSCTE35packets.|funccanbesettoacustomfunctionthataccepts|athreefive.Cueinstanceasit's only argument.Stream.decode ExampleimportsysfromthreefiveimportStream>>>>Stream('plp0.ts').decode()Pass in custom functionfuncshould match the interfacefunc(cue)Stream.decode with custom function Exampleimportsysimportthreefivedefdisplay(cue):print(f'\033[92m{cue.packet_data}\033[00m')print(f'{cue.command.name}')defdo():sp=threefive.Stream(tsdata)sp.decode(func=display)if__name__=='__main__':do()Stream.decode_next()|decode_next(self)|Stream.decode_nextreturnsthenext|SCTE35cueasathreefive.Cueinstance.Stream.decode_next Exampleimportsysimportthreefivedefdo():arg=sys.argv[1]withopen(arg,'rb',encoding="utf-8")astsdata:st=threefive.Stream(tsdata)whileTrue:cue=st.decode_next()ifnotcue:returnFalseifcue:cue.show()if__name__=="__main__":do()Stream.proxy(func = show_cue)Writes all packets to sys.stdout.Writes scte35 data to sys.stderr.|decode(self,func=show_cue_stderr)|Stream.decode_proxywritesalltspacketsarewrittentostdout|forpipingintoanotherprogramlikemplayer.|SCTE-35cuesareprintedtostderr.Stream.proxy Exampleimportthreefivesp=threefive.Stream('https://futzu.com/xaa.ts')sp.decode_proxy()Pipe to mplayer$python3proxy.py|mplayer-Stream.show()|show(self)|ListprogramsandstreamsandinfoforMPEGTSStream.show() Example>>>>fromthreefiveimportStream>>>>Stream('https://slo.me/plp0.ts').show()Service:fancy˹Provider:fu-corpPcrPid:1051[0x41b]Streams:Pid:1051[0x41b]Type:0x1bAVCVideoPid:1052[0x41c]Type:0x3MP2AudioPid:1054[0x41e]Type:0x6PESPackets/PrivateDataPid:1055[0x41f]Type:0x86SCTE35DataNeed to verify your splice points?Trycue2vtt.pyin the examples.cue2vtt.py creates webvtt subtitles out of SCTE-35 Cue datause it like thispypy3cue2vtt.pyvideo.ts|mplayervideo.ts-sub-threefive cli toolnow acceptsversion,showandptskeywords.versiona@fu:~$threefiveversion2.4.25showa@fu:~$threefiveshowf10.tsProgram:1Service:Service01Provider:FFmpegPid:4096PcrPid:256Streams:Pid:256[0x100]Type:0x1bAVCVideoPid:257[0x101]Type:0xfAACAudioPid:258[0x102]Type:0x6PESPackets/PrivateDataPid:259[0x103]Type:0x6PESPackets/PrivateDataPid:260[0x104]Type:0x15ID3TimedMetaDataptsa@fu:~$threefiveptsf10.ts1->1.4666671->1.61->1.5333331->1.5333331->1.5333331->1.51->1.5666671->1.7333331->1.733333threefiveis nowaddressable TVcompatible"tag":2,"descriptor_length":31,"name":"Segmentation Descriptor","identifier":"CUEI","components":[],"segmentation_event_id":"0x065eff","segmentation_event_cancel_indicator":false,"segmentation_event_id_compliance_indicator":true,"program_segmentation_flag":true,"segmentation_duration_flag":false,"delivery_not_restricted_flag":true,"segmentation_message":"Call Ad Server",<---Boom"segmentation_upid_type":12,"segmentation_upid_type_name":"MPU","segmentation_upid_length":16,"segmentation_upid":{"format_identifier":"ADFR",<---Boom"private_data":"0x0133f10134b04f065e060220","version":1,<----Boom"channel_identifier":"0x33f1",<----Boom"date":20230223,<----Boom"break_code":1630,<----Boom"duration":"0x602"<----Boom},"segmentation_type_id":2,<----Boom"segment_num":0,"segments_expected":0},Custom charsets for UPIDS aka upids.charsetSpecify a charset for Upid data by setting threefive.upids.charsetissue #55default charset is asciipython charsets infoHeresetting charset to None will return raw bytes.Example Usage:>>>fromthreefiveimportCue,upids>>>i="/DBKAAAAAAAAAP/wBQb+YtC8/AA0AiZDVUVJAAAD6X/CAAD3W3ACEmJibG5kcHBobkQCAsGDpQIAAAAAAAEKQ1VFSRSAIyowMljRk9c=">>>upids.charset'ascii'>>>cue=Cue(i)>>>cue.decode()asciiTrue>>>cue.descriptors[0].segmentation_upid'bblndpphnD\x02\x02���\x02\x00\x00'>>>upids.charset="utf16">>>cue.decode()utf16True>>>cue.descriptors[0].segmentation_upid'扢湬灤桰䑮Ȃ菁ʥ\x00'Custom Private Splice Descriptors ( new! )threefive now supports custom private splice descriptors, right out the box.The first byte of the descriptor is read as an int for the Descriptor tagThe second byte is read as an int for  the desciptor lengthThe next four bytes are read as ASCII for the Identifierremanining bytes are returned as private datafromthreefiveimportCue,TimeSignalfromthreefive.descriptorsimportSpliceDescriptormake a Cuec=Cue()add a Time Signalc.command=TimeSignal()c.command.time_specified_flag=Truec.command.pts_time=1234.567890add Splice Descriptorsd=SpliceDescriptor()sd.tag=47sd.identifier='fufu'sd.private_data=b'threefivekicksass'c.descriptors.append(sd)encodec.encode()'/DAvAAAAAAAAAP/wBQb+Bp9rxgAZLxdmdWZ1dGhyZWVmaXZlIGtpY2tzIGFzc1m+EsU='showc.show()
{"info_section":{"table_id":"0xfc","section_syntax_indicator":false,"private":false,"sap_type":"0x03","sap_details":"No Sap Type","section_length":47,"protocol_version":0,"encrypted_packet":false,"encryption_algorithm":0,"pts_adjustment_ticks":0,"cw_index":"0x0","tier":"0xfff","splice_command_length":5,"splice_command_type":6,"descriptor_loop_length":25,"crc":"0x59be12c5"},"command":{"command_length":5,"command_type":6,"name":"Time Signal","time_specified_flag":true,"pts_time":1234.56789,"pts_time_ticks":111111110},"descriptors":[
        {"tag":47,"descriptor_length":23,"identifier":"fufu","private_data":[116,104,114,101,101,102,105,118,101,32,107,105,99,107,115,32,97,115,115]
        }
    ]
}the custom Splice Descriptorc.descriptors[0]{'tag':47,'descriptor_length':23,'name':None,'identifier':'fufu','bites':None,'provider_avail_id':None,'components':None,'private_data':b'threefive kicks ass'}Cool dictionaary comprehension to print the Splice Descriptor with only relevant values{print(f'{k} = {v}')fork,vinvars(c.descriptors[0]).items()ifvisnotNone}tag=47descriptor_length=23identifier=fufuprivate_data=b'threefive kicks ass'Powered by threefive⚡sidewaysinject SCTE-35 into HLS via maanifest manipulation.⚡adbreak2a cli tool that quickly and easily generates SCTE-35 Cues for HLS and stuff.⚡Ultra Mega Zoom ZoomABR HLS segmenter and SCTE-35 inserter.⚡POIS Serveris Super Cool.⚡bpkio-cli: A command line interface to the broadpeak.io APIs.⚡x9k3: SCTE-35 HLS Segmenter and Cue Inserter.⚡amt-playuses x9k3.⚡m3ufu: SCTE-35 m3u8 Parser.⚡six2scte35: ffmpeg changes SCTE-35 stream type to 0x06 bin data, six2scte35 changes it back.⚡SuperKabuki: SCTE-35 Packet Injection.⚡showcuesm3u8 SCTE-35 parser.⚡threefive online SCTE-35 Encoder⚡threefiveonline SCTE-35 parserthreefive | more⚡Diagramof a threefive SCTE-35 Cue.⚡ffmpeg and threefiveand SCTE35 and Stream Type 0x6 bin data.⚡Issues and Bugs and Feature Requestsare no longer being accepted.datathis might be wild baseless speculation.