roninpawn / ffmpeg_videostream

FFmpeg-enabled Python Video
9 stars 1 forks source link

Read frames and frame info simultaneously #2

Closed Happy-hub closed 2 years ago

Happy-hub commented 2 years ago

Hi, thank you for this useful script. I was wondering if you found a way to read frames and their info at the same time.

Currently my code is as follows:

video = VideoStream("rtsp://username:password@192.168.0.102:554")
video.open_stream(showinfo=True)
frames = 0

print("\r\nReading VideoStream...")

while True:
    eof, frame = video.read()
    print(video.showinfo())
    if eof:
        break

    frames += 1

print(f"\r\nRead {frames} frames at {video.shape()} resolution from '{video.path}'")

The code seems to work at the beginning, but after about 9 frames, it freezes. I added a print statement each time it reads showinfo.

if self._si_active:
    print("showinfo")
    self._read_showinfo()

and the output is as follows:

Reading VideoStream...
showinfo
[Parsed_showinfo_2 @ 0x55720530eb00] n:   0 pts:      0 pts_time:0       pos:       -1 fmt:bgr24 sar:1/1 s:1920x1080 i:P iskey:1 type:I checksum:3F602568 plane_checksum:[3F602568] mean:[93] stdev:[65.1]

showinfo
[Parsed_showinfo_2 @ 0x55720530eb00] n:   1 pts:-114300 pts_time:-1.27   pos:       -1 fmt:bgr24 sar:1/1 s:1920x1080 i:P iskey:0 type:P checksum:318612CA plane_checksum:[318612CA] mean:[93] stdev:[65.1]

showinfo
[Parsed_showinfo_2 @ 0x55720530eb00] n:   2 pts: -89100 pts_time:-0.99   pos:       -1 fmt:bgr24 sar:1/1 s:1920x1080 i:P iskey:0 type:P checksum:2DAD38F4 plane_checksum:[2DAD38F4] mean:[93] stdev:[65.1]

showinfo
[Parsed_showinfo_2 @ 0x55720530eb00] n:   3 pts: -67500 pts_time:-0.75   pos:       -1 fmt:bgr24 sar:1/1 s:1920x1080 i:P iskey:0 type:P checksum:18CC4C1C plane_checksum:[18CC4C1C] mean:[93] stdev:[65.1]

showinfo
[Parsed_showinfo_2 @ 0x55720530eb00] n:   4 pts: -45900 pts_time:-0.51   pos:       -1 fmt:bgr24 sar:1/1 s:1920x1080 i:P iskey:0 type:P checksum:FEA81DA2 plane_checksum:[FEA81DA2] mean:[93] stdev:[65.0]

showinfo
[Parsed_showinfo_2 @ 0x55720530eb00] n:   5 pts: -24300 pts_time:-0.27   pos:       -1 fmt:bgr24 sar:1/1 s:1920x1080 i:P iskey:0 type:P checksum:2A53D294 plane_checksum:[2A53D294] mean:[93] stdev:[65.0]

showinfo
[Parsed_showinfo_2 @ 0x55720530eb00] n:   6 pts:    900 pts_time:0.01    pos:       -1 fmt:bgr24 sar:1/1 s:1920x1080 i:P iskey:0 type:P checksum:E8E50C81 plane_checksum:[E8E50C81] mean:[93] stdev:[65.1]

showinfo
[Parsed_showinfo_2 @ 0x55720530eb00] n:   7 pts:  22500 pts_time:0.25    pos:       -1 fmt:bgr24 sar:1/1 s:1920x1080 i:P iskey:0 type:P checksum:F73CF0E8 plane_checksum:[F73CF0E8] mean:[93] stdev:[65.1]

showinfo
[Parsed_showinfo_2 @ 0x55720530eb00] n:   8 pts:  44100 pts_time:0.49    pos:       -1 fmt:bgr24 sar:1/1 s:1920x1080 i:P iskey:1 type:I checksum:8788376C plane_checksum:[8788376C] mean:[93] stdev:[65.1]

showinfo
[Parsed_showinfo_2 @ 0x55720530eb00] n:   9 pts:  65700 pts_time:0.73    pos:       -1 fmt:bgr24 sar:1/1 s:1920x1080 i:P iskey:0 type:P checksum:10FD111A plane_checksum:[10FD111A] mean:[93] stdev:[65.1]

showinfo

My assumption is that it tries to read from stderr but it doesn't have anything to read so it blocks for ever. Is there already a solution to this? thanks

roninpawn commented 2 years ago

You're exactly right that its the stderr pipe getting blocked. I certainly had this issue while I was building the showinfo() function up, but thought I'd solved it. Off the top of my head, here's a thought that might lead to a workaround for you:

   def _read_showinfo(self):
        raw_out = bytes()
        raw_info = self._pipe.stderr.readline()
        while re.search(self._si_read_key, raw_info) is None:
            raw_info = self._pipe.stderr.readline()
        raw_out += raw_info
        self._si = raw_out.decode()

The _read_showinfo() function reads the stderr a line at a time until it matches the regular expression defined in self._si_read_key = re.compile(rb'(\[Parsed_showinfo).*] n:') So, I imagine a scenario where the 10th frame of your video input source produces a stderr output in FFmpeg that contains TWO lines that match that expression. If that were the case, I think _read_showinfo() would stop reading at the first match, leaving the stderr pipe unemptied. And that might block the process too?

It's a shot in the dark, (and maybe I'm forgetting everything about how these pipes work) but I'm dealing with some health issues right now and I doubt I'll be tinkering with the code any time soon. If you trace it down and solve it, do pass your fix along! And feel free to ask me anything you need to know, if it isn't obvious in the code.

Happy-hub commented 2 years ago

Hi, sorry for the late response.

Unfortunately, the 10th frame does not produce two lines that match the expression. I ended up writing something quite similar to yours, and it sorta works for me (tested on Dahua and Hikvision cameras) but I'm still not sure how it's different from yours.

Anyways, hope you will get well soon and continue writing amazing scripts. thank you for the response