51 lines
1.5 KiB
Python
51 lines
1.5 KiB
Python
from argparse import Namespace
|
|
import time
|
|
|
|
import cv2
|
|
import zmq
|
|
|
|
|
|
class FrameEmitter:
|
|
'''
|
|
Emit frame in a separate threat so they can be throttled,
|
|
or thrown away when the rest of the system cannot keep up
|
|
'''
|
|
def __init__(self, config: Namespace) -> None:
|
|
self.config = config
|
|
|
|
context = zmq.Context()
|
|
self.frame_sock = context.socket(zmq.PUB)
|
|
self.frame_sock.bind(config.zmq_frame_addr)
|
|
self.frame_sock.setsockopt(zmq.CONFLATE, 1) # only keep latest frame
|
|
|
|
def emit_video(self):
|
|
video = cv2.VideoCapture(str(self.config.video_src))
|
|
fps = video.get(cv2.CAP_PROP_FPS)
|
|
frame_duration = 1./fps
|
|
|
|
prev_time = time.time()
|
|
while True:
|
|
ret, frame = video.read()
|
|
|
|
# seek to 0 if video has finished. Infinite loop
|
|
if not ret:
|
|
video.set(cv2.CAP_PROP_POS_FRAMES, 0)
|
|
ret, frame = video.read()
|
|
assert ret is not False # not really error proof...
|
|
|
|
self.frame_sock.send(frame)
|
|
|
|
# defer next loop
|
|
new_frame_time = time.time()
|
|
time_diff = (new_frame_time - prev_time)
|
|
if time_diff < frame_duration:
|
|
time.sleep(frame_duration - time_diff)
|
|
new_frame_time += frame_duration - time_diff
|
|
else:
|
|
prev_time = new_frame_time
|
|
|
|
|
|
|
|
def run_frame_emitter(config: Namespace):
|
|
router = FrameEmitter(config)
|
|
router.emit_video() |