opencv python Multi Threading Video Capture

12,953

*edit: I'll leave the code below, but I guess you have a codec problem? I installed the xvid codec (which is what the sample Megamind.avi is encoded with) and the program works fine with either or both threads running the megamind video. Can you get the megamind video to run in the single threaded version?

Here is an SO post on opencv video codecs in case it helps. Here is the xvid download that I used (k-lite didn't work for me).


The code you wrote basically works for me. For you and anyone else that wants to try, I did the following:

  • applied PEP 8 recommendations
  • removed the unnecessary read attempt code (which also removes the misleading thread re-read warnings after the last frame of a working video)
  • used a video file that perhaps everyone with opencv has
  • removed the thread locking which didn't seem to matter to opencv at least on my system
  • moved a few other little things around

There may be other errors that come up with VideoCapture.read that would make a read_attempt method worthwhile, but I could only find the two errors the docs mention. For those it just returns false which the code already tests for.

import os
import threading

import cv2

my_opencv_path = "C:/opencv2.4.3"
video_path_1 = os.path.join(my_opencv_path, "samples", "cpp", "tutorial_code",
                            "HighGUI", "video-input-psnr-ssim", "video",
                            "Megamind.avi")
video_path_2 = os.path.join(my_opencv_path, "samples", "c", "tree.avi")
assert os.path.isfile(video_path_1)
assert os.path.isfile(video_path_2)


class MyThread (threading.Thread):
    maxRetries = 20

    def __init__(self, thread_id, name, video_url, thread_lock):
        threading.Thread.__init__(self)
        self.thread_id = thread_id
        self.name = name
        self.video_url = video_url
        self.thread_lock = thread_lock

    def run(self):
        print "Starting " + self.name
        window_name = self.name
        cv2.namedWindow(window_name)
        video = cv2.VideoCapture(self.video_url)
        while True:
            # self.thread_lock.acquire()  # These didn't seem necessary
            got_a_frame, image = video.read()
            # self.thread_lock.release()
            if not got_a_frame:  # error on video source or last frame finished
                break
            cv2.imshow(window_name, image)
            key = cv2.waitKey(50)
            if key == 27:
                break
        cv2.destroyWindow(window_name)
        print self.name + " Exiting"


def main():
    thread_lock = threading.Lock()
    thread1 = MyThread(1, "Thread 1", video_path_1, thread_lock)
    thread2 = MyThread(2, "Thread 2", video_path_2, thread_lock)
    thread1.start()
    thread2.start()
    print "Exiting Main Thread"

if __name__ == '__main__':
    main()
Share:
12,953
Colenso Castellino
Author by

Colenso Castellino

Updated on June 05, 2022

Comments

  • Colenso Castellino
    Colenso Castellino almost 2 years

    I am trying to read to 2 Video Files and show them in separate Windows Simultaneously. This is my code:

    import threading
    import cv2
    threadLock=threading.Lock()
    class myThread (threading.Thread):
        maxRetries=20
        def __init__(self, threadID, name,video_url):
            threading.Thread.__init__(self)
            self.threadID = threadID
            self.name = name
            self.video_url=video_url
    
        def attemptRead(self,cvVideo):
            threadLock.acquire()
            (isRead,cvImage)=cvVideo.read()
            threadLock.release()
            if isRead==False:
                count=1
                while isRead==False and count<myThread.maxRetries:
                    threadLock.acquire()
                    (isRead,cvImage)=cvVideo.read()
                    threadLock.release()
                    print self.name+' try no: ',count
                    count+=1
            return (isRead,cvImage)
    
        def run(self):
            print "Starting " + self.name
            windowName = self.name
            cv2.namedWindow(windowName)
            cvVideo = cv2.VideoCapture(self.video_url)
    
    
            while True:
                (isRead,cvImage)=self.attemptRead(cvVideo)
                if isRead==False:
                    break
                cv2.imshow(windowName,cvImage)
                key=cv2.waitKey(50)
                if key==27:
                    break
    
            cv2.destroyWindow(windowName)
            print self.name + "Exiting"
    
    def main():
        thread1 = myThread(1, "Thread1",'C:/Traffic Pics/Videos/Panjim Capture.mp4')
        thread2 = myThread(2, "Thread2",'C:/Traffic Pics/Videos/Miramar Capture.mp4')
    
        thread1.start()
        thread2.start()
    
    print "Exiting Main Thread"
    
    if __name__ == '__main__':
        main()
    

    What's happening is that, only the Thread 2 Window is showing. Thread 1 exits after attempting to read the video beyond the max_retries limit(10 in my case). The problem is that although I create separate cvVideo objects, I can't seem to use them simultaneously. What could be the problem?

  • Colenso Castellino
    Colenso Castellino about 11 years
    Thanks for the information about the errors and the extra code. However, the code you provided doesn't work either. As I mentioned in my earlier comments, Multi-threading only seems to work with the tree.avi file in the samples folder. It doesn't work for anything else. Maybe this is just an issue on my system, even so, what could be the reason behind this? Some Codec issues maybe?
  • KobeJohn
    KobeJohn about 11 years
    Please check my edit. After installing the codec, everything is fine with Megamind for me.
  • Colenso Castellino
    Colenso Castellino about 11 years
    Thank you very much! It was a codec problem after all! :D I installed K-lite Mega Codec pack and can now see both the windows opening and playing the videos. Thanks again!