How to read VideoCapture as parts in multiple threads

asked 2018-06-04 07:42:39 -0600

azdoud.y gravatar image

updated 2018-06-05 06:58:19 -0600

hello,

I have a video of more than 90k frames, and I want to divire it the read into multiple four or more threads for example a video on 20 mins, I want

the first thread read the VideoCapture from 0 to 5 min
the 2th thread read the VideoCapture from 5 to 10 min
the 3th thread read the VideoCapture from 10 to 15 min
the 4th thread read the VideoCapture from 15 to 20 min

I use these functions for Similarity check (PNSR and SSIM), In fact, I have a long video sequence, I want to make the code faster by spliting this sequence loaded in a VideoCapture variable into multiple parts, So, by doing this, I will use threads to process each part simultaneously. this is the need, I hope it's clear.

image description

any help would appreciated.

edit retag flag offensive close merge delete

Comments

and you want to keep 90k frames in memory ? it would only require 185GB for HD frames ;)

berak gravatar imageberak ( 2018-06-04 09:28:49 -0600 )edit

I already load 90k in VideoCapture variable and I loop through it, I'm using a frame of 480x320 in size. for illustration, we can use less than 90k frames

azdoud.y gravatar imageazdoud.y ( 2018-06-04 09:45:44 -0600 )edit

Are you familiar with the std C++ thread and mutex?

sjhalayka gravatar imagesjhalayka ( 2018-06-04 10:41:55 -0600 )edit

I'm quite enough familiar with c++ thread, however for mutex I've never worked with before.

azdoud.y gravatar imageazdoud.y ( 2018-06-04 10:53:45 -0600 )edit

the problem here with the thread is concurrency and multiple access to the same resource VideoCapture variable? how to deal with it ?

azdoud.y gravatar imageazdoud.y ( 2018-06-04 11:05:22 -0600 )edit

Yeah, you pass in a mutex instantiation into the thread function. You must pass the mutex by reference.

Whenever you want to be thread-safe, you call the mutex's lock() function before you use the non-atomic data/functions. Once you're done using the non-atomic data/functions you call the mutex's unlock() function.

It's that simple: Since you're passing by reference, all threads use the same mutex. The mutex blocks on lock(), waiting for the other thread to call unlock().

On the other hand, you might be able to avoid using a mutex. Just pass the data subset directly into each thread function. That way your main function can immediately call join() after all of the thread() calls.

sjhalayka gravatar imagesjhalayka ( 2018-06-04 11:21:36 -0600 )edit
1

assume, that a VideoCapture is NOT THREADSAFE AT ALL. (it's a matter of internal state, not locks)

@azdoud.y you'd have to use 1 seperate capture per thread

berak gravatar imageberak ( 2018-06-04 11:34:08 -0600 )edit

Sorry, I was assuming that these video clips were already stored to disk as images.

sjhalayka gravatar imagesjhalayka ( 2018-06-04 11:36:23 -0600 )edit
2

@azdoud.y again, please explain the need for multiple threads. which problem are you trying to solve here ?

berak gravatar imageberak ( 2018-06-04 12:20:09 -0600 )edit

okey, @berak I will explain

azdoud.y gravatar imageazdoud.y ( 2018-06-05 06:19:07 -0600 )edit
1

did you profile your code ? where is the bottleneck ?

if it turns out to be the psnr/ssim part,maybe a single producer with several consumers would be a better design ?

if it was too slow in a single thread before, tripling the work load and expect to make it faster, seems absurd.

berak gravatar imageberak ( 2018-06-05 06:47:49 -0600 )edit
1

Noting is absurd if we want to learn something new.

azdoud.y gravatar imageazdoud.y ( 2018-06-05 07:11:58 -0600 )edit

yes, when I profile my code it slows down at psnr/ssim functions

azdoud.y gravatar imageazdoud.y ( 2018-06-05 07:18:37 -0600 )edit

@berak Can you give us some documentation about single producer with several consumers would be a better design, please

azdoud.y gravatar imageazdoud.y ( 2018-06-05 07:36:20 -0600 )edit

maybe:

  • have a single VideoCapture
  • read your image
  • push_back() it into a std::deque (with locks around that code)
  • either start a new thread, or have a threadpool, and take the next free one
  • pop_front() an image from the deque (again with locks)
  • process your image
berak gravatar imageberak ( 2018-06-05 08:02:11 -0600 )edit

@berak, you said that I'd have to use 1 separate capture per thread, how can I separate the main capture into sub-capture parts?

azdoud.y gravatar imageazdoud.y ( 2018-06-05 08:53:57 -0600 )edit
1

start a new VideoCapture object in each of your 3 threads. seek to a certain frameno, and start reading/processing (and please don't put any gui code, like imshow() into any of those threads.)

berak gravatar imageberak ( 2018-06-05 09:17:49 -0600 )edit

Why don't you split your video into multiple files in a preprocessing function, and then create an array of VideoCapture objects equivalent to the number of different video files and make them work in parallel?

Pedro Batista gravatar imagePedro Batista ( 2018-06-05 09:55:39 -0600 )edit