简体   繁体   中英

Python Multithreading Help! Video Display/Capture

I am trying to simultaneously:

  1. display a saved video on screen (duration 60seconds)
  2. capture computer webcam video and save to file. (duration 60 seconds, started at the beginning of saved video being broadcast to screen)

I have tried to handle this with multithreading, but am running into an issue where Thread1 (func1) instantly broadcasts video to the screen, while Thread 2 (func2) can take 10-20 seconds (varies for some reason) to start capturing video. (a sleep() function wont help due to unpredictability). Think I need to Pause/Resume the first thread to wait for the second one to start capturing video. Or, have the second thread trigger the first.

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()

Simply use threading.Event to synchronize both thread.

  1. Create threading.Event instance
  2. Pass instance to both thread
  3. Call .wait() on waiting side, .set() on other side.

Example:

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!

Applied code:

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()

This should wait until it's prepared, and exit pyglet after capture.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM