0

I want to pipe images to a virtual video device (e.g. /dev/video0), the images are created inside a loop with the desired frame rate.

In this minimal example i only two arrays which alternate in the cv2 window. Now i look for a good solution to pipe the arrays to the virtual device.

I saw that ffmpeg-python can run asynchronous with ffmpeg.run_async(), but so far i could not make anything work with this package.

example code without the ffmpeg stuff:

#!/usr/bin/env python3

import cv2
import numpy as np
import time

window_name = 'virtual-camera'
cv2.namedWindow(window_name, cv2.WINDOW_GUI_EXPANDED)

img1 = np.random.uniform(0, 255, (1080, 1440, 3)).astype('uint8')
img2 = np.random.uniform(0, 255, (1080, 1440, 3)).astype('uint8')

for i in range(125):
    time.sleep(0.04)
    if i % 2:
        img = img1
    else:
        img = img2
    cv2.imshow(window_name, img)
    cv2.waitKey(1)
cv2.destroyAllWindows()
sre
  • 31
  • 5
  • Does this answer your question? [Pipe opencv images to ffmpeg using python](https://stackoverflow.com/questions/34167691/pipe-opencv-images-to-ffmpeg-using-python) – TheEagle Mar 15 '21 at 13:18
  • The accepted answer is from 2015 and uses ffmpeg as a subprocess. I hope that i could avoid that and use ffmpeg-python instead. The last answer on that link is sadly not completed. The target is a video device and in the `vidgear ` package you have to name an output, in the example 'output.mp4' which is not what i want, or at least it's confusing. – sre Mar 15 '21 at 15:26
  • Okay, I didn't get at first that you want to use ffmpeg-python for that. – TheEagle Mar 15 '21 at 16:29
  • But why do you want to pipe the images there at all ? – TheEagle Mar 15 '21 at 16:31
  • I get the arrays from another python API and want to use them in a different 3rd-party application (the live pictures) which scans for /dev/video* devices. So i have to work inbetween those boundaries. – sre Mar 15 '21 at 17:40

2 Answers2

1

First of all, you would have to setup a virtual camera, with for example v4l2loopback. See here for how to install it (ignore the usage examples).
Then, you can just write to the virtual camera like to a normal file (that is, let openCV write the images to say /dev/video0; how to do that you have to find out yourself because im not an expert with openCV).
In the end, you can use ffmpeg-python with /dev/video0 as input file, do something with the video, and that's it !

TheEagle
  • 5,808
  • 3
  • 11
  • 39
  • Correct, i already found the link you posted and was able to pipe the saved images, videos and desktop to the dummy device. But it seems i forgot to mention that my problem was to pipe directly from the python script to the dummy device. Thats the reason i was looking for a solution with ffmpeg-python. I found a working solution and posted a answer. Thanks for the advice and the help Programmer! – sre Mar 16 '21 at 08:44
1

As Programmer wrote in his answer, it is possible to create a dummy device with the package v4l2loopback. To publish images, videos or the desktop to the dummy device was already easy with ffmpeg, but i want to pipe it directly from the python script - where i capture the images - to the dummy device. I still think it's possible with ffmpeg-python, but i found this great answer from Alp which sheds light on the darkness. The package pyfakewebcam is a perfect solution for the problem.

For the sake of completeness, here is my extended minimal working example:

#!/usr/bin/env python3

import time

import cv2
import numpy as np
import pyfakewebcam

WIDTH = 1440
HEIGHT = 1080
DEVICE = '/dev/video0'

fake_cam = pyfakewebcam.FakeWebcam(DEVICE, WIDTH, HEIGHT)

window_name = 'virtual-camera'
cv2.namedWindow(window_name, cv2.WINDOW_GUI_EXPANDED)

img1 = np.random.uniform(0, 255, (HEIGHT, WIDTH, 3)).astype('uint8')
img2 = np.random.uniform(0, 255, (HEIGHT, WIDTH, 3)).astype('uint8')

for i in range(125):
    time.sleep(0.04)
    if i % 2:
        img = img1
    else:
        img = img2
    fake_cam.schedule_frame(img)
    cv2.imshow(window_name, img)
    cv2.waitKey(1)
cv2.destroyAllWindows()
sre
  • 31
  • 5