Python多线程帮助!视频显示/捕获



我正在尝试同时:

  1. 在屏幕上显示保存的视频(持续时间60秒(
  2. 捕获计算机网络摄像头视频并保存到文件。(持续时间60秒,从保存的视频开始广播到屏幕(

我曾尝试用多线程处理这一问题,但遇到了一个问题,线程1(func1(会立即向屏幕广播视频,而线程2(func2(可能需要10-20秒(因某些原因而有所不同(才能开始捕获视频。(sleep((函数由于不可预测性而没有帮助(。我想我需要暂停/恢复第一个线程,等待第二个线程开始拍摄视频。或者,让第二个线程触发第一个线程。

import pyglet
import numpy as np
import cv2
import time
from threading import Thread
from screeninfo import get_monitors
for monitor in get_monitors():
width = monitor.width
height = monitor.height
def func1():
vid_path='path/to/video'
window= pyglet.window.Window(width, height, fullscreen=True)
player = pyglet.media.Player()
source = pyglet.media.StreamingSource()
MediaLoad = pyglet.media.load(vid_path)

player.queue(MediaLoad)
player.play()
@window.event
def on_draw():
if player.source and player.source.video_format:
player.get_texture().blit(0,0)
pyglet.app.run()
def func2():
capture_duration = 60                                         #This portion of code
cap = cv2.VideoCapture(0)                                     #takes about 10 seconds to 
fourcc = cv2.VideoWriter_fourcc(*'XVID')                      #execute causing a time dif
out = cv2.VideoWriter('output.avi',fourcc, 30.0, (640,480))   #btw video play and 
start_time = time.time()                                      #capture
while( int(time.time() - start_time) < capture_duration ):
ret, frame = cap.read()
if ret==True:
out.write(frame)
else:
break
# Release everything if job is finished
cap.release()
out.release()
cv2.destroyAllWindows()

if __name__ == '__main__':
Thread(target = func1).start()
Thread(target = func2).start()

只需使用threading.Event即可同步两个线程。

  1. 创建threading.Event实例
  2. 将实例传递给两个线程
  3. 呼叫等待侧的.wait(),呼叫另一侧的.set()

示例:

import threading
import time

def takes_long(event: threading.Event):
time.sleep(5)
print("[Long ] Started!")
event.set()

def takes_short(event: threading.Event):
print("[Short] Waiting for other thread!")
event.wait()
print("[Short] Started!")

event_ = threading.Event()
threading.Thread(target=takes_long, args=[event_]).start()
threading.Thread(target=takes_short, args=[event_]).start()
[Short] Waiting for other thread!
[Long ] Started!
[Short] Started!

应用代码:

import time
import threading
import pyglet
import cv2

# hard-coding for simplification
WIDTH, HEIGHT = 2560, 1440
DURATION = 10
# source / output path
SOURCE_PATH = "./sample.mp4"
OUTPUT_PATH = "X:/Temp/output.avi"

def func1(started_event: threading.Event):
"""Waits for func2 then plays the video for fixed duration"""
window = pyglet.window.Window(WIDTH, HEIGHT, fullscreen=True)
player = pyglet.media.Player()
media = pyglet.media.load(SOURCE_PATH)
player.queue(media)
# wait for event then play
started_event.wait()
player.play()
@window.event
def on_draw():
if player.source and player.source.video_format:
player.get_texture().blit(0, 0)
pyglet.app.run()

def func2(started_event: threading.Event):
cap = cv2.VideoCapture(0)
fourcc = cv2.VideoWriter_fourcc(*'XVID')
out = cv2.VideoWriter(OUTPUT_PATH, fourcc, 30.0, (640, 480))
# now all required steps are done, fire event so video playback can start
started_event.set()
# now start capturing
start_time = time.time()
while (time.time() - start_time) < DURATION:
ret, frame = cap.read()
if ret:
out.write(frame)
else:
break
cap.release()
out.release()
cv2.destroyAllWindows()
pyglet.app.exit()

if __name__ == '__main__':
event = threading.Event()
threading.Thread(target=func1, args=(event,)).start()
threading.Thread(target=func2, args=(event,)).start()

这应该等到它准备好了,然后在捕获后退出pyglet。

最新更新