Skip to content

Latest commit

 

History

History
162 lines (119 loc) · 3.9 KB

trigger.md

File metadata and controls

162 lines (119 loc) · 3.9 KB

Triggering on SCTE-35 Events with threefive.Stream.

option 1 pass in a function


  • Most of the Stream methods take an optional arg func, a function to be called when a SCTE-35 Cue is found.

  • The func function must take only one arg, and that is a threefive.Cue object.


  • I use sidecar files for some of my other projects a sidecar file consists of (PTS, Cue) pairs, one per line.
  • A sidecar file looks this.
a@slow:~$ cat sidecar.txt 


41.273211,/DAWAAAAAAAAAP/wBQb+ADi52AAAp77zBQ==
42.240844,/DAWAAAAAAAAAP/wBQb+ADoZwgAAaVWytQ==
43.275211,/DAWAAAAAAAAAP/wBQb+ADt5rAAAXIo9lg==
44.276211,/DAWAAAAAAAAAP/wBQb+ADzZlgAAwI0IyA==
45.277211,/DAWAAAAAAAAAP/wBQb+AD45gAAA1tIPCQ==
46.244844,/DAWAAAAAAAAAP/wBQb+AD+ZagAAf8zc/g==
47.279211,/DAWAAAAAAAAAP/wBQb+AED5VAAAVMj9Dw==
48.246844,/DAWAAAAAAAAAP/wBQb+AEJZPgAAypfF7w==
49.281211,/DAWAAAAAAAAAP/wBQb+AEO5KAAAB99quQ==

One of the ways I use a sidecar file is to exact the SCTE-35 before using ffmpeg to encode to HLS, and then I use the sidecar file to generate HLS tags and insert them into the ffmpeg m3u8 files in real time.

  • To make a sidecar file, I write a function.
def mk_sidecar(cue):
    """
    mk_sidecar generates a sidecar file with the SCTE-35 Cues
    """
    pts = 0.0
    with open("sidecar.txt", "a") as sidecar:
        cue.show()
        if cue.packet_data.pts:
            pts = cue.packet_data.pts
        data = f"{pts},{cue.encode()}\n"
        sidecar.write(data)
  • The only other step is to call Stream.decode and pass in the mk_sidecar function.

  • Here's the complete example to generate a sidecar file.

#!/usr/bin/env python3

import sys
from threefive import Stream


def mk_sidecar(cue):
    """
    mk_sidecar generates a sidecar file with the SCTE-35 Cues
    """
    pts = 0.0
    with open("sidecar.txt", "a") as sidecar:
        cue.show()
        if cue.packet_data.pts:
            pts = cue.packet_data.pts
        data = f"{pts},{cue.encode()}\n"
        sidecar.write(data)


if __name__ == '__main__':
        strm = Stream(sys.argv[1])
        strm.decode(func=mk_sidecar)

  • Run it like this:
pypy3 sidecar_gen.py https://example.com/nmx.ts

  • If you want to limit your sidecar file to the SCTE-35 in a specific MPEGTS program, call decode_program instead.
if __name__ == '__main__':
	the_program = 3
        strm = Stream(sys.argv[1])
        strm.decode_program(the_program, func=mk_sidecar)

  • To limit the sidecar file to SCTE-35 from a list of pids, call decode_pids.
if __name__ == '__main__':
	scte35_pids =[259,1023,399]
        strm = Stream(sys.argv[1])
        strm.decode_pids(scte35_pids, func=mk_sidecar)

  • To parse the video and then pipe it to ffmpeg or another program, Stream.proxy writes the video stream sys.stdout.
if __name__ == '__main__':
	scte35_pids =[259,1023,399]
        strm = Stream(sys.argv[1])
        strm.proxy(func=mk_sidecar)

option 2 Stream.decode_next

  • Stream.decode_next returns the next Cue found.
    • This example uses a while loop with Stream.decode_next.
    • using Stream.decode_next gives you more control over processing the Cue.
import sys
import threefive
from new_reader import reader

def mk_sidecar(cue):
    """
    mk_sidecar generates a sidecar file with the SCTE-35 Cues
    """
    pts = 0.0
    with open("sidecar.txt", "a") as sidecar:
        cue.show()
        if cue.packet_data.pts:
            pts = cue.packet_data.pts
        data = f"{pts},{cue.encode()}\n"
        sidecar.write(data)


def do():
    arg = sys.argv[1]
    with reader(arg) as tsdata:
        st = threefive.Stream(tsdata)
        while True:
            cue = st.decode_next()
            if not cue:
                return False
            if cue:
               mk_sidecar(cue)


if __name__ == "__main__":
    do()