I would like to put a video overlay onto an incoming webcam stream via OpenCV. As a first step I'm trying to stream the incoming video from a webcam at /dev/video0
to a virtual video device at /dev/video1
(v4l2loopback). Unfortunately I'm not able to forward the webcam stream to the v4l2loopback device.
I found this thread: How to write/pipe to a virtual webcam created by V4L2loopback module? but the links there didn't really help me.
Getting and watching the stream from the webcam works well with some little demo code from the OpenCV page. As well the example code from the v4l2loopback page, for e.g. playing a static video file out to /dev/video1
works well. I can watch the video when I connect VLC to /dev/video1
I already read that the v4l2loopback device must be controlled via regular Linux driver commands (open, ioctl, write etc.). So there is no wrapper class from within OpenCV to write to the loopback device. My webcam streams with 640x480 and as MJPG. The interesting thing is that I can connect to the loopback device with VLC and I can see the correct resolution, Codec and FPS displayed when I press play. The time counter on the progress bar also starts running. But the screen remains black (with VLC Logo).
What I'm roughly doing is this (BTW: the code might not compile ... didn't want clutter everything here ... let me know if you need more details):
int main ( int argc, char **argv ) {
cv::VideoCapture cap;
struct v4l2_format vid_format;
size_t framesize = 640 * 480 * 3; // 3 Bytes per pixel
__u8 *buffer = null;
int fd = null;
cap.open ( "/dev/video0" );
fd = open ( "/dev/video1", O_RDWR );
memset ( &vid_format, 0, sizeof(vid_format) );
vid_format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
vid_format.fmt.pix.width = cap.get(CV_CAP_PROP_FRAME_WIDTH);
vid_format.fmt.pix.height = cap.get(CV_CAP_PROP_FRAME_HEIGHT);
vid_format.fmt.pix.pixelformat = { 'M', 'J', 'P', 'G' };
vid_format.fmt.pix.sizeimage = framesize;
vid_format.fmt.pix.field = V4L2_FIELD_NONE;
vid_format.fmt.pix.colorspace = V4L2_COLORSPACE_SRGB;
ioctl ( fd, VIDIOC_S_FMT, &vid_format );
buffer = (__u8*) malloc ( sizeof(__u8) *framesize );
memset ( buffer, 0, framesize );
for(;;) {
cv::Mat frame;
cap >> frame;
write ( fd, &frame.data, framesize );
}
}
It would be really great if somebody could give me a hint how I need to convert the wecam data in order to get it accepted by VLC.