futzu/threefive

ERROR while decoding TS: 21 since v.2.2.09

Closed this issue · 11 comments

When running examples/multicast/ts_scte_parser.py I only see ERROR while decoding TS: 21 for each SCTE-35 packet, using v.2.2.25 on Python 3.6. The latest working release is v.2.2.01, v.2.2.09 is the first release with this error.

futzu commented

I think I see the issue. I'll let you know shortly.

futzu commented

This is the previous multicast example from 2.2.01

it calls Stream.decode(func = foundit)
instead of Stream.decode_next()

2.2.01

Does this work correctly for you?

futzu commented

I had another guy have a similar issue today, I just pushed a new pip build, 2.2.29,
he's testing it now.

No difference with either 2.2.29 or 2.2.31 with the latest or old (2.2.01) multicast example, the same error appears in all cases. What can I do to help find what's happening?

futzu commented

Richard,
Do you have a lot of programs in the stream?
Can you run ffprobe for me and post the output?
With that info, I should be able to offer a solution.
Don't worry man, this won't take long.

futzu commented

Don't use 239.0.0.1, try 239.255.0.1

futzu commented

What is serving the multicast stream and what OS are you using?

futzu commented

I tested the script below with 2.2.33 tonight.
I've run it dozens of times without any issues.

I subclassed Stream so that the video pts is
displayed in the terminal so you can see progress..

import io
import socket
import struct
import threefive


def foundit(cue):
    print("""\n\t\tthis function was passed into Stream.decode
            it gets called with the cue instance as an arg
            for custom handling when a SCTE-35 packet is found\n""")
            
    print(f'\nCue methods can be called\n\tcue.get_command() returns:\n\t\t\t {cue.get_command()}')
    print(f'\nCue vars can be read.\n\t cue.command.name\n\t\t\t {cue.command.name}')

class StreamFu(threefive.Stream):
    '''
    StreamFu is a subclass of threefive.Stream.
    the _parse_pts method is modified so
    that the video PTS is displayed at the
    bottom of the screen to show progress
    '''
    def _parse_pts(self, pkt, pid):
        """
        parse pts with output
        """
        pts = ((pkt[13] >> 1) & 7) << 30
        pts |= ((pkt[14] << 7) | (pkt[15] >> 1)) << 15
        pts |= (pkt[16] << 7) | (pkt[17] >> 1)
        pts /= 90000.0
        ppp = self._pid_prog[pid]
        self._prog_pts[ppp] = pts
        print(f'PTS: \033[92m{round(pts,3)}\033[0m',end='\r\r\r')
    
class MCastParser():
    def __init__(self, mcast_ip, if_ip="0.0.0.0", hostname="0.0.0.0", port=9000):
        self.HOST = hostname
        self.PORT = port
        self.MCAST_IP = mcast_ip
        self.IF_IP = if_ip

    def do(self):
        with socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP) as sock:
            self.set_socket_options(sock)
            sock.bind((self.HOST, self.PORT))
            with sock.makefile(mode="rb") as socket_file:
                ts = StreamFu(socket_file)
                ts.decode() # without a function being passed in.

                # other method call examples

                # ts.decode(func=foundit)   # with a function passed in.
                
                # ts.show()   # will display stream types by program.

    def set_socket_options(self, sock):
        sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, socket.inet_aton(self.MCAST_IP)+socket.inet_aton(self.HOST))


if __name__ == "__main__":
    MCastParser(mcast_ip="239.255.0.1").do()
futzu commented

Richard,
you have figured out more than you realize.
I like your fix, but shouldn't it be
The issue you're describing shouldn't be able to happen,
but obviously is happening.
No I see what I broke.
in Stream._parser, I added returns after each if conditional,
that prevented the packets from also being checked for pts.
I added the returns in 2.2.1.
Nice work man.

If want to commit directly to this repo,
I'll add you.

futzu commented

I am adding you to the repo, I want you on the team.

All I ask is that you commit early and often,
and use black to format code.

Thanks for adding me!

In case of video and SCTE-35 in the same PID there will always be PTS. However in many cases the SCTE-35 data is on a separate PID without PTS and that's also normal. We could perhaps also try to read the PCR timestamps.