summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
author Edward W. Koenig2020-06-26 15:15:20 +0200
committer Willy Sudiarto Raharjo2020-06-28 03:16:53 +0200
commitd48943afb0027332e26afecc418b20e92a526fc5 (patch)
treeb608ed6b379875709da6faf520667670e348090d
parente1097e3fadd39dd0326f917932c4a0b5d30d894b (diff)
downloadslackbuilds-d48943afb0027332e26afecc418b20e92a526fc5.tar.gz
system/v4l2loopback: Added (k/ module for V4L2 loopback devices)
Signed-off-by: Dave Woodfall <dave@slackbuilds.org> Signed-off-by: Willy Sudiarto Raharjo <willysr@slackbuilds.org>
-rw-r--r--system/v4l2loopback/README9
-rw-r--r--system/v4l2loopback/doinst.sh3
-rw-r--r--system/v4l2loopback/slack-desc19
-rw-r--r--system/v4l2loopback/update_to_master_17JUN2020.patch671
-rw-r--r--system/v4l2loopback/v4l2loopback.SlackBuild98
-rw-r--r--system/v4l2loopback/v4l2loopback.info10
6 files changed, 810 insertions, 0 deletions
diff --git a/system/v4l2loopback/README b/system/v4l2loopback/README
new file mode 100644
index 0000000000..2c78fe244c
--- /dev/null
+++ b/system/v4l2loopback/README
@@ -0,0 +1,9 @@
+v4l2loopback - a kernel module to create V4L2 loopback devices
+
+This module allows you to create "virtual video devices".
+Normal (v4l2) applications will read these devices as if they
+were ordinary video devices, but the video will not be read
+from, e.g. a capture card or webcam, but instead video generated
+by another application.
+
+You must rebuild this package if you upgrade your kernel.
diff --git a/system/v4l2loopback/doinst.sh b/system/v4l2loopback/doinst.sh
new file mode 100644
index 0000000000..dcfb80855f
--- /dev/null
+++ b/system/v4l2loopback/doinst.sh
@@ -0,0 +1,3 @@
+
+chroot . /sbin/depmod -a @KERNEL@ 2>/dev/null
+
diff --git a/system/v4l2loopback/slack-desc b/system/v4l2loopback/slack-desc
new file mode 100644
index 0000000000..32972147b4
--- /dev/null
+++ b/system/v4l2loopback/slack-desc
@@ -0,0 +1,19 @@
+# HOW TO EDIT THIS FILE:
+# The "handy ruler" below makes it easier to edit a package description.
+# Line up the first '|' above the ':' following the base package name, and
+# the '|' on the right side marks the last column you can put a character in.
+# You must make exactly 11 lines for the formatting to be correct. It's also
+# customary to leave one space after the ':' except on otherwise blank lines.
+
+ |-----handy-ruler------------------------------------------------------|
+v4l2loopback: v4l2loopback (kernel module to create V4L2 loopback devices)
+v4l2loopback:
+v4l2loopback: This module allows you to create "virtual video devices". Normal (v4l2)
+v4l2loopback: applications will read these devices as if they were ordinary video devices,
+v4l2loopback: but the video will not be read from, e.g. a capture card or webcam, but
+v4l2loopback: instead video generated by another application.
+v4l2loopback:
+v4l2loopback:
+v4l2loopback: Project URL:
+v4l2loopback: http://github.com/umlaeute/v4l2loopback/
+v4l2loopback:
diff --git a/system/v4l2loopback/update_to_master_17JUN2020.patch b/system/v4l2loopback/update_to_master_17JUN2020.patch
new file mode 100644
index 0000000000..cd44185102
--- /dev/null
+++ b/system/v4l2loopback/update_to_master_17JUN2020.patch
@@ -0,0 +1,671 @@
+diff --git a/README.md b/README.md
+index d8b295a..d8d338b 100644
+--- a/README.md
++++ b/README.md
+@@ -18,9 +18,31 @@ only be of limited use...
+
+ # ISSUES
+ for current issues, checkout https://github.com/umlaeute/v4l2loopback/issues
+-please use the issue-tracker for reporting any problems
++please use the issue-tracker for reporting any problems.
++
++before you create a new ticket in our issue tracker, please make sure that you have read
++*this* document and followed any instructions found within.
++
++also, please search the issue-tracker *before* reporting any problems: it's much better
++to add your information to an existing ticket than to create a new ticket with essentially
++the same information.
++
++## SEEKING HELP
++the issue tracker is meant to track specific bugs in the code (and new features).
++however, it is ill-suited as a user support forum.
++
++if you have general questions or problems, please use the `v4l2loopback` tag
++on [Stack Overflow](https://stackoverflow.com/questions/tagged/v4l2loopback) instead:
++https://stackoverflow.com/questions/tagged/v4l2loopback
++
+
+ # DEPENDENCIES
++in order to build (compile,...) anything, you must have a *working* build-environment
++(compiler, GNU make,...).
++the kernel can be somewhat picky if you try to load a module that was compiled with
++a different compiler than was used to compile the kernel itself.
++so make sure to have the right compiler in place.
++
+ the v4l2loopback module is a *kernel module*.
+ in order to build it, you *must have* the kernel headers installed that match
+ the linux kernel with which you want to use the module (in most cases this will
+@@ -31,6 +53,12 @@ the first few number are the same.
+ (modules will be incompatible if the versions don't match. if you are lucky, the module will
+ simply refuse to load. if you are unlucky, your computer will spit in your eye or do worse.)
+
++there are distribution-specific differences on how to get the correct kernel headers
++(or to install a compilation toolchain).
++documenting all those possibilities would go far beyond the scope of `v4l2loopback`.
++please understnd that we cannot provide support for questions regarding dependencies.
++
++
+ # BUILD
+ to build the kernel module run:
+
+diff --git a/v4l2loopback.c b/v4l2loopback.c
+index bcf7667..b0f7b93 100644
+--- a/v4l2loopback.c
++++ b/v4l2loopback.c
+@@ -48,9 +48,9 @@
+
+ MODULE_DESCRIPTION("V4L2 loopback video device");
+ MODULE_AUTHOR("Vasily Levin, " \
+- "IOhannes m zmoelnig <zmoelnig@iem.at>," \
+- "Stefan Diewald," \
+- "Anton Novikov" \
++ "IOhannes m zmoelnig <zmoelnig@iem.at>," \
++ "Stefan Diewald," \
++ "Anton Novikov" \
+ "et al." \
+ );
+ MODULE_LICENSE("GPL");
+@@ -61,18 +61,18 @@ MODULE_LICENSE("GPL");
+ #define STRINGIFY(s) #s
+ #define STRINGIFY2(s) STRINGIFY(s)
+
+-#define dprintk(fmt, args...) \
+- do { if (debug > 0) { \
++#define dprintk(fmt, args...) \
++ do { if (debug > 0) { \
+ printk(KERN_INFO "v4l2-loopback[" STRINGIFY2(__LINE__) "]: " fmt, ##args); \
+ } } while (0)
+
+-#define MARK() \
+- do { if (debug > 1) { \
++#define MARK() \
++ do { if (debug > 1) { \
+ printk(KERN_INFO "%s:%d[%s]\n", __FILE__, __LINE__, __func__); \
+ } } while (0)
+
+-#define dprintkrw(fmt, args...) \
+- do { if (debug > 2) { \
++#define dprintkrw(fmt, args...) \
++ do { if (debug > 2) { \
+ printk(KERN_INFO "v4l2-loopback[" STRINGIFY2(__LINE__)"]: " fmt, ##args); \
+ } } while (0)
+
+@@ -85,14 +85,14 @@ struct v4l2_ctrl_handler {
+ int error;
+ };
+ struct v4l2_ctrl_config {
+- void *ops;
+- u32 id;
++ void *ops;
++ u32 id;
+ const char *name;
+ int type;
+- s32 min;
+- s32 max;
+- u32 step;
+- s32 def;
++ s32 min;
++ s32 max;
++ u32 step;
++ s32 def;
+ };
+ int v4l2_ctrl_handler_init(struct v4l2_ctrl_handler*hdl,
+ unsigned nr_of_controls_hint)
+@@ -119,7 +119,7 @@ struct v4l2_device {
+ char name[V4L2_DEVICE_NAME_SIZE];
+ struct v4l2_ctrl_handler*ctrl_handler;
+ };
+-static inline int v4l2_device_register (void *dev, void *v4l2_dev) { return 0; }
++static inline int v4l2_device_register(void *dev, void *v4l2_dev) { return 0; }
+ static inline void v4l2_device_unregister(struct v4l2_device *v4l2_dev) { return; }
+ #endif /* HAVE__V4L2_DEVICE */
+
+@@ -155,7 +155,7 @@ static inline void v4l2l_get_timestamp(struct v4l2_buffer *b) {
+
+ /* module constants
+ * can be overridden during he build process using something like
+- * make KCPPFLAGS="-DMAX_DEVICES=100"
++ * make KCPPFLAGS="-DMAX_DEVICES=100"
+ */
+
+
+@@ -235,13 +235,13 @@ MODULE_PARM_DESC(max_height, "maximum frame height");
+
+ /* control IDs */
+ #ifndef HAVE__V4L2_CTRLS
+-# define V4L2LOOPBACK_CID_BASE (V4L2_CID_PRIVATE_BASE)
++# define V4L2LOOPBACK_CID_BASE (V4L2_CID_PRIVATE_BASE)
+ #else
+-# define V4L2LOOPBACK_CID_BASE (V4L2_CID_USER_BASE | 0xf000)
++# define V4L2LOOPBACK_CID_BASE (V4L2_CID_USER_BASE | 0xf000)
+ #endif
+-#define CID_KEEP_FORMAT (V4L2LOOPBACK_CID_BASE + 0)
++#define CID_KEEP_FORMAT (V4L2LOOPBACK_CID_BASE + 0)
+ #define CID_SUSTAIN_FRAMERATE (V4L2LOOPBACK_CID_BASE + 1)
+-#define CID_TIMEOUT (V4L2LOOPBACK_CID_BASE + 2)
++#define CID_TIMEOUT (V4L2LOOPBACK_CID_BASE + 2)
+ #define CID_TIMEOUT_IMAGE_IO (V4L2LOOPBACK_CID_BASE + 3)
+
+ static int v4l2loopback_s_ctrl(struct v4l2_ctrl *ctrl);
+@@ -249,44 +249,44 @@ static const struct v4l2_ctrl_ops v4l2loopback_ctrl_ops = {
+ .s_ctrl = v4l2loopback_s_ctrl,
+ };
+ static const struct v4l2_ctrl_config v4l2loopback_ctrl_keepformat = {
+- .ops = &v4l2loopback_ctrl_ops,
+- .id = CID_KEEP_FORMAT,
+- .name = "keep_format",
+- .type = V4L2_CTRL_TYPE_BOOLEAN,
+- .min = 0,
+- .max = 1,
+- .step = 1,
+- .def = 0,
++ .ops = &v4l2loopback_ctrl_ops,
++ .id = CID_KEEP_FORMAT,
++ .name = "keep_format",
++ .type = V4L2_CTRL_TYPE_BOOLEAN,
++ .min = 0,
++ .max = 1,
++ .step = 1,
++ .def = 0,
+ };
+ static const struct v4l2_ctrl_config v4l2loopback_ctrl_sustainframerate = {
+- .ops = &v4l2loopback_ctrl_ops,
+- .id = CID_SUSTAIN_FRAMERATE,
+- .name = "sustain_framerate",
+- .type = V4L2_CTRL_TYPE_BOOLEAN,
+- .min = 0,
+- .max = 1,
+- .step = 1,
+- .def = 0,
++ .ops = &v4l2loopback_ctrl_ops,
++ .id = CID_SUSTAIN_FRAMERATE,
++ .name = "sustain_framerate",
++ .type = V4L2_CTRL_TYPE_BOOLEAN,
++ .min = 0,
++ .max = 1,
++ .step = 1,
++ .def = 0,
+ };
+ static const struct v4l2_ctrl_config v4l2loopback_ctrl_timeout = {
+- .ops = &v4l2loopback_ctrl_ops,
+- .id = CID_TIMEOUT,
+- .name = "timeout",
+- .type = V4L2_CTRL_TYPE_INTEGER,
+- .min = 0,
+- .max = MAX_TIMEOUT,
+- .step = 1,
+- .def = 0,
++ .ops = &v4l2loopback_ctrl_ops,
++ .id = CID_TIMEOUT,
++ .name = "timeout",
++ .type = V4L2_CTRL_TYPE_INTEGER,
++ .min = 0,
++ .max = MAX_TIMEOUT,
++ .step = 1,
++ .def = 0,
+ };
+ static const struct v4l2_ctrl_config v4l2loopback_ctrl_timeoutimageio = {
+- .ops = &v4l2loopback_ctrl_ops,
+- .id = CID_TIMEOUT_IMAGE_IO,
+- .name = "timeout_image_io",
+- .type = V4L2_CTRL_TYPE_BOOLEAN,
+- .min = 0,
+- .max = 1,
+- .step = 1,
+- .def = 0,
++ .ops = &v4l2loopback_ctrl_ops,
++ .id = CID_TIMEOUT_IMAGE_IO,
++ .name = "timeout_image_io",
++ .type = V4L2_CTRL_TYPE_BOOLEAN,
++ .min = 0,
++ .max = 1,
++ .step = 1,
++ .def = 0,
+ };
+
+
+@@ -321,7 +321,7 @@ struct v4l2_loopback_device {
+ (close to) nominal framerate */
+
+ /* buffers stuff */
+- u8 *image; /* pointer to actual buffers data */
++ u8 *image; /* pointer to actual buffers data */
+ unsigned long int imagesize; /* size of buffers data */
+ int buffers_number; /* should not be big, 4 is a good choice */
+ struct v4l2l_buffer buffers[MAX_BUFFERS]; /* inner driver buffers */
+@@ -386,13 +386,13 @@ struct v4l2_loopback_opener {
+ /* this is heavily inspired by the bttv driver found in the linux kernel */
+ struct v4l2l_format {
+ char *name;
+- int fourcc; /* video4linux 2 */
+- int depth; /* bit/pixel */
++ int fourcc; /* video4linux 2 */
++ int depth; /* bit/pixel */
+ int flags;
+ };
+ /* set the v4l2l_format.flags to PLANAR for non-packed formats */
+-#define FORMAT_FLAGS_PLANAR 0x01
+-#define FORMAT_FLAGS_COMPRESSED 0x02
++#define FORMAT_FLAGS_PLANAR 0x01
++#define FORMAT_FLAGS_COMPRESSED 0x02
+
+ #ifndef V4L2_PIX_FMT_VP9
+ #define V4L2_PIX_FMT_VP9 v4l2_fourcc('V', 'P', '9', '0')
+@@ -446,7 +446,7 @@ static void pix_format_set_size(struct v4l2_pix_format *f,
+ f->bytesperline = width; /* Y plane */
+ f->sizeimage = (width * height * fmt->depth) >> 3;
+ } else if (fmt->flags & FORMAT_FLAGS_COMPRESSED) {
+- /* doesn't make sense for compressed formats */
++ /* doesn't make sense for compressed formats */
+ f->bytesperline = 0;
+ f->sizeimage = (width * height * fmt->depth) >> 3;
+ } else {
+@@ -458,7 +458,7 @@ static void pix_format_set_size(struct v4l2_pix_format *f,
+ static int set_timeperframe(struct v4l2_loopback_device *dev,
+ struct v4l2_fract *tpf)
+ {
+- if((tpf->denominator < 1) || (tpf->numerator < 1)) {
++ if((tpf->denominator < 1) || (tpf->numerator < 1)) {
+ return -EINVAL;
+ }
+ dev->capture_param.timeperframe = *tpf;
+@@ -485,7 +485,7 @@ static ssize_t attr_show_format(struct device *cd,
+ tpf = &dev->capture_param.timeperframe;
+
+ fourcc2str(dev->pix_format.pixelformat, buf4cc);
+- buf4cc[4]=0;
++ buf4cc[4]=0;
+ if (tpf->numerator == 1)
+ snprintf(buf_fps, sizeof(buf_fps), "%d", tpf->denominator);
+ else
+@@ -578,7 +578,7 @@ static void v4l2loopback_create_sysfs(struct video_device *vdev)
+ {
+ int res = 0;
+
+-#define V4L2_SYSFS_CREATE(x) res = device_create_file(&vdev->dev, &dev_attr_##x); if (res < 0) break
++#define V4L2_SYSFS_CREATE(x) res = device_create_file(&vdev->dev, &dev_attr_##x); if (res < 0) break
+ if (!vdev)
+ return;
+ do {
+@@ -671,7 +671,7 @@ static int vidioc_querycap(struct file *file, void *priv, struct v4l2_capability
+ {
+ struct v4l2_loopback_device *dev = v4l2loopback_getdevice(file);
+ int devnr = ((struct v4l2loopback_private *)video_get_drvdata(dev->vdev))->devicenr;
+- __u32 capabilities = V4L2_CAP_STREAMING | V4L2_CAP_READWRITE;
++ __u32 capabilities = V4L2_CAP_STREAMING | V4L2_CAP_READWRITE;
+
+ strlcpy(cap->driver, "v4l2 loopback", sizeof(cap->driver));
+ vidioc_fill_name(cap->card, sizeof(cap->card), devnr);
+@@ -698,7 +698,10 @@ static int vidioc_querycap(struct file *file, void *priv, struct v4l2_capability
+ }
+ }
+
+- dev->vdev->device_caps = cap->device_caps = cap->capabilities = capabilities;
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0)
++ dev->vdev->device_caps =
++#endif /* >=linux-4.7.0 */
++ cap->device_caps = cap->capabilities = capabilities;
+
+ #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)
+ cap->capabilities |= V4L2_CAP_DEVICE_CAPS;
+@@ -891,7 +894,7 @@ static int vidioc_enum_fmt_out(struct file *file, void *fh, struct v4l2_fmtdesc
+ f->pixelformat = dev->pix_format.pixelformat;
+ } else {
+ /* fill in a dummy format */
+- /* coverity[unsigned_compare] */
++ /* coverity[unsigned_compare] */
+ if (f->index < 0 || f->index >= FORMATS)
+ return -EINVAL;
+
+@@ -1069,11 +1072,11 @@ static int vidioc_s_parm(struct file *file, void *priv, struct v4l2_streamparm *
+
+ switch (parm->type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+- if ((err=set_timeperframe(dev, &parm->parm.capture.timeperframe)) < 0)
++ if ((err=set_timeperframe(dev, &parm->parm.capture.timeperframe)) < 0)
+ return err;
+ break;
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+- if ((err=set_timeperframe(dev, &parm->parm.capture.timeperframe)) < 0)
++ if ((err=set_timeperframe(dev, &parm->parm.capture.timeperframe)) < 0)
+ return err;
+ break;
+ default:
+@@ -1249,7 +1252,7 @@ static int vidioc_enum_output(struct file *file, void *fh, struct v4l2_output *o
+ struct v4l2_loopback_device *dev = v4l2loopback_getdevice(file);
+ MARK();
+
+- if (!dev->announce_all_caps && !dev->ready_for_output)
++ if (!dev->announce_all_caps && !dev->ready_for_output)
+ return -ENOTTY;
+
+ if (0 != index)
+@@ -1279,7 +1282,7 @@ static int vidioc_enum_output(struct file *file, void *fh, struct v4l2_output *o
+ static int vidioc_g_output(struct file *file, void *fh, unsigned int *i)
+ {
+ struct v4l2_loopback_device *dev = v4l2loopback_getdevice(file);
+- if (!dev->announce_all_caps && !dev->ready_for_output)
++ if (!dev->announce_all_caps && !dev->ready_for_output)
+ return -ENOTTY;
+ if (i)
+ *i = 0;
+@@ -1292,7 +1295,7 @@ static int vidioc_g_output(struct file *file, void *fh, unsigned int *i)
+ static int vidioc_s_output(struct file *file, void *fh, unsigned int i)
+ {
+ struct v4l2_loopback_device *dev = v4l2loopback_getdevice(file);
+- if (!dev->announce_all_caps && !dev->ready_for_output)
++ if (!dev->announce_all_caps && !dev->ready_for_output)
+ return -ENOTTY;
+
+ if (i)
+@@ -1340,7 +1343,7 @@ static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *inp
+ static int vidioc_g_input(struct file *file, void *fh, unsigned int *i)
+ {
+ struct v4l2_loopback_device *dev = v4l2loopback_getdevice(file);
+- if (!dev->announce_all_caps && !dev->ready_for_capture)
++ if (!dev->announce_all_caps && !dev->ready_for_capture)
+ return -ENOTTY;
+ if (i)
+ *i = 0;
+@@ -1353,7 +1356,7 @@ static int vidioc_g_input(struct file *file, void *fh, unsigned int *i)
+ static int vidioc_s_input(struct file *file, void *fh, unsigned int i)
+ {
+ struct v4l2_loopback_device *dev = v4l2loopback_getdevice(file);
+- if (!dev->announce_all_caps && !dev->ready_for_capture)
++ if (!dev->announce_all_caps && !dev->ready_for_capture)
+ return -ENOTTY;
+ if (i == 0)
+ return 0;
+@@ -1527,7 +1530,7 @@ static int vidioc_qbuf(struct file *file, void *private_data, struct v4l2_buffer
+ /* Hopefully fix 'DQBUF return bad index if queue bigger then 2 for capture'
+ https://github.com/umlaeute/v4l2loopback/issues/60 */
+ buf->flags &= ~V4L2_BUF_FLAG_DONE;
+- buf->flags |= V4L2_BUF_FLAG_QUEUED;
++ buf->flags |= V4L2_BUF_FLAG_QUEUED;
+
+ wake_up_all(&dev->read_event);
+ return 0;
+@@ -1666,7 +1669,7 @@ static int vidioc_streamon(struct file *file, void *private_data, enum v4l2_buf_
+ default:
+ return -EINVAL;
+ }
+- return -EINVAL;
++ return -EINVAL;
+ }
+
+ /* stop streaming
+@@ -1896,8 +1899,8 @@ static ssize_t v4l2_loopback_read(struct file *file,
+ dev = v4l2loopback_getdevice(file);
+
+ read_index = get_capture_buffer(file);
+- if (read_index < 0)
+- return read_index;
++ if (read_index < 0)
++ return read_index;
+ if (count > dev->buffer_size)
+ count = dev->buffer_size;
+ b = &dev->buffers[read_index].buffer;
+@@ -2034,20 +2037,20 @@ static void init_buffers(struct v4l2_loopback_device *dev)
+
+ for (i = 0; i < dev->buffers_number; ++i) {
+ struct v4l2_buffer *b = &dev->buffers[i].buffer;
+- b->index = i;
+- b->bytesused = bytesused;
+- b->length = buffer_size;
+- b->field = V4L2_FIELD_NONE;
+- b->flags = 0;
++ b->index = i;
++ b->bytesused = bytesused;
++ b->length = buffer_size;
++ b->field = V4L2_FIELD_NONE;
++ b->flags = 0;
+ #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 1)
+- b->input = 0;
++ b->input = 0;
+ #endif
+- b->m.offset = i * buffer_size;
+- b->memory = V4L2_MEMORY_MMAP;
+- b->sequence = 0;
++ b->m.offset = i * buffer_size;
++ b->memory = V4L2_MEMORY_MMAP;
++ b->sequence = 0;
+ b->timestamp.tv_sec = 0;
+ b->timestamp.tv_usec = 0;
+- b->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
++ b->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ v4l2l_get_timestamp(b);
+ }
+@@ -2077,29 +2080,29 @@ static void init_vdev(struct video_device *vdev, int nr)
+ vidioc_fill_name(vdev->name, sizeof(vdev->name), nr);
+
+ #ifdef V4L2LOOPBACK_WITH_STD
+- vdev->tvnorms = V4L2_STD_ALL;
++ vdev->tvnorms = V4L2_STD_ALL;
+ #endif /* V4L2LOOPBACK_WITH_STD */
+
+- vdev->vfl_type = VFL_TYPE_VIDEO;
+- vdev->fops = &v4l2_loopback_fops;
+- vdev->ioctl_ops = &v4l2_loopback_ioctl_ops;
+- vdev->release = &video_device_release;
+- vdev->minor = -1;
++ vdev->vfl_type = VFL_TYPE_VIDEO;
++ vdev->fops = &v4l2_loopback_fops;
++ vdev->ioctl_ops = &v4l2_loopback_ioctl_ops;
++ vdev->release = &video_device_release;
++ vdev->minor = -1;
+ #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0)
+ vdev->device_caps =
+- V4L2_CAP_DEVICE_CAPS |
++ V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT |
++ V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
+ #ifdef V4L2_CAP_VIDEO_M2M
+- V4L2_CAP_VIDEO_M2M |
+-#endif
+- V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT |
+- V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
++ vdev->device_caps |= V4L2_CAP_VIDEO_M2M;
+ #endif
++#endif /* >=linux-4.7.0 */
++
+ if (debug > 1)
+- #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 20, 0)
++#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 20, 0)
+ vdev->debug = V4L2_DEBUG_IOCTL | V4L2_DEBUG_IOCTL_ARG;
+- #else
++#else
+ vdev->dev_debug = V4L2_DEV_DEBUG_IOCTL | V4L2_DEV_DEBUG_IOCTL_ARG;
+- #endif
++#endif
+
+ /* since kernel-3.7, there is a new field 'vfl_dir' that has to be
+ * set to VFL_DIR_M2M for bidrectional devices */
+@@ -2114,11 +2117,11 @@ static void init_vdev(struct video_device *vdev, int nr)
+ static void init_capture_param(struct v4l2_captureparm *capture_param)
+ {
+ MARK();
+- capture_param->capability = 0;
+- capture_param->capturemode = 0;
+- capture_param->extendedmode = 0;
+- capture_param->readbuffers = max_buffers;
+- capture_param->timeperframe.numerator = 1;
++ capture_param->capability = 0;
++ capture_param->capturemode = 0;
++ capture_param->extendedmode = 0;
++ capture_param->readbuffers = max_buffers;
++ capture_param->timeperframe.numerator = 1;
+ capture_param->timeperframe.denominator = 30;
+ }
+
+@@ -2177,10 +2180,10 @@ static int v4l2_loopback_init(struct v4l2_loopback_device *dev, int nr)
+ int ret;
+ struct v4l2_ctrl_handler *hdl = &dev->ctrl_handler;
+ snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name),
+- "v4l2loopback-%03d", nr);
+- ret = v4l2_device_register(NULL, &dev->v4l2_dev);
+- if (ret)
+- return ret;
++ "v4l2loopback-%03d", nr);
++ ret = v4l2_device_register(NULL, &dev->v4l2_dev);
++ if (ret)
++ return ret;
+
+ MARK();
+ dev->vdev = video_device_alloc();
+@@ -2230,7 +2233,7 @@ static int v4l2_loopback_init(struct v4l2_loopback_device *dev, int nr)
+ setup_timer(&dev->sustain_timer, sustain_timer_clb, nr);
+ setup_timer(&dev->timeout_timer, timeout_timer_clb, nr);
+ #endif
+- dev->reread_count = 0;
++ dev->reread_count = 0;
+ dev->timeout_jiffies = 0;
+ dev->timeout_image = NULL;
+ dev->timeout_happened = 0;
+@@ -2242,10 +2245,10 @@ static int v4l2_loopback_init(struct v4l2_loopback_device *dev, int nr)
+ v4l2_ctrl_new_custom(hdl, &v4l2loopback_ctrl_sustainframerate, NULL);
+ v4l2_ctrl_new_custom(hdl, &v4l2loopback_ctrl_timeout, NULL);
+ v4l2_ctrl_new_custom(hdl, &v4l2loopback_ctrl_timeoutimageio, NULL);
+- if (hdl->error) {
+- ret = hdl->error;
+- goto error;
+- }
++ if (hdl->error) {
++ ret = hdl->error;
++ goto error;
++ }
+ dev->v4l2_dev.ctrl_handler = hdl;
+
+ /* FIXME set buffers to 0 */
+@@ -2267,55 +2270,55 @@ static int v4l2_loopback_init(struct v4l2_loopback_device *dev, int nr)
+ return 0;
+
+ error:
+- v4l2_ctrl_handler_free(&dev->ctrl_handler);
+- v4l2_device_unregister(&dev->v4l2_dev);
++ v4l2_ctrl_handler_free(&dev->ctrl_handler);
++ v4l2_device_unregister(&dev->v4l2_dev);
+ kfree(dev->vdev);
+- return ret;
++ return ret;
+
+ };
+
+ /* LINUX KERNEL */
+ static const struct v4l2_file_operations v4l2_loopback_fops = {
+- .owner = THIS_MODULE,
+- .open = v4l2_loopback_open,
++ .owner = THIS_MODULE,
++ .open = v4l2_loopback_open,
+ .release = v4l2_loopback_close,
+- .read = v4l2_loopback_read,
+- .write = v4l2_loopback_write,
+- .poll = v4l2_loopback_poll,
+- .mmap = v4l2_loopback_mmap,
+- .unlocked_ioctl = video_ioctl2,
++ .read = v4l2_loopback_read,
++ .write = v4l2_loopback_write,
++ .poll = v4l2_loopback_poll,
++ .mmap = v4l2_loopback_mmap,
++ .unlocked_ioctl = video_ioctl2,
+ };
+
+ static const struct v4l2_ioctl_ops v4l2_loopback_ioctl_ops = {
+- .vidioc_querycap = &vidioc_querycap,
++ .vidioc_querycap = &vidioc_querycap,
+ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
+- .vidioc_enum_framesizes = &vidioc_enum_framesizes,
++ .vidioc_enum_framesizes = &vidioc_enum_framesizes,
+ .vidioc_enum_frameintervals = &vidioc_enum_frameintervals,
+ #endif
+
+ #ifndef HAVE__V4L2_CTRLS
+- .vidioc_queryctrl = &vidioc_queryctrl,
+- .vidioc_g_ctrl = &vidioc_g_ctrl,
+- .vidioc_s_ctrl = &vidioc_s_ctrl,
++ .vidioc_queryctrl = &vidioc_queryctrl,
++ .vidioc_g_ctrl = &vidioc_g_ctrl,
++ .vidioc_s_ctrl = &vidioc_s_ctrl,
+ #endif /* HAVE__V4L2_CTRLS */
+
+- .vidioc_enum_output = &vidioc_enum_output,
+- .vidioc_g_output = &vidioc_g_output,
+- .vidioc_s_output = &vidioc_s_output,
++ .vidioc_enum_output = &vidioc_enum_output,
++ .vidioc_g_output = &vidioc_g_output,
++ .vidioc_s_output = &vidioc_s_output,
+
+- .vidioc_enum_input = &vidioc_enum_input,
+- .vidioc_g_input = &vidioc_g_input,
+- .vidioc_s_input = &vidioc_s_input,
++ .vidioc_enum_input = &vidioc_enum_input,
++ .vidioc_g_input = &vidioc_g_input,
++ .vidioc_s_input = &vidioc_s_input,
+
+ .vidioc_enum_fmt_vid_cap = &vidioc_enum_fmt_cap,
+- .vidioc_g_fmt_vid_cap = &vidioc_g_fmt_cap,
+- .vidioc_s_fmt_vid_cap = &vidioc_s_fmt_cap,
+- .vidioc_try_fmt_vid_cap = &vidioc_try_fmt_cap,
++ .vidioc_g_fmt_vid_cap = &vidioc_g_fmt_cap,
++ .vidioc_s_fmt_vid_cap = &vidioc_s_fmt_cap,
++ .vidioc_try_fmt_vid_cap = &vidioc_try_fmt_cap,
+
+ .vidioc_enum_fmt_vid_out = &vidioc_enum_fmt_out,
+- .vidioc_s_fmt_vid_out = &vidioc_s_fmt_out,
+- .vidioc_g_fmt_vid_out = &vidioc_g_fmt_out,
+- .vidioc_try_fmt_vid_out = &vidioc_try_fmt_out,
++ .vidioc_s_fmt_vid_out = &vidioc_s_fmt_out,
++ .vidioc_g_fmt_vid_out = &vidioc_g_fmt_out,
++ .vidioc_try_fmt_vid_out = &vidioc_try_fmt_out,
+
+ #ifdef V4L2L_OVERLAY
+ .vidioc_s_fmt_vid_overlay = &vidioc_s_fmt_overlay,
+@@ -2323,24 +2326,24 @@ static const struct v4l2_ioctl_ops v4l2_loopback_ioctl_ops = {
+ #endif
+
+ #ifdef V4L2LOOPBACK_WITH_STD
+- .vidioc_s_std = &vidioc_s_std,
+- .vidioc_g_std = &vidioc_g_std,
+- .vidioc_querystd = &vidioc_querystd,
++ .vidioc_s_std = &vidioc_s_std,
++ .vidioc_g_std = &vidioc_g_std,
++ .vidioc_querystd = &vidioc_querystd,
+ #endif /* V4L2LOOPBACK_WITH_STD */
+
+- .vidioc_g_parm = &vidioc_g_parm,
+- .vidioc_s_parm = &vidioc_s_parm,
++ .vidioc_g_parm = &vidioc_g_parm,
++ .vidioc_s_parm = &vidioc_s_parm,
+
+- .vidioc_reqbufs = &vidioc_reqbufs,
+- .vidioc_querybuf = &vidioc_querybuf,
+- .vidioc_qbuf = &vidioc_qbuf,
+- .vidioc_dqbuf = &vidioc_dqbuf,
++ .vidioc_reqbufs = &vidioc_reqbufs,
++ .vidioc_querybuf = &vidioc_querybuf,
++ .vidioc_qbuf = &vidioc_qbuf,
++ .vidioc_dqbuf = &vidioc_dqbuf,
+
+- .vidioc_streamon = &vidioc_streamon,
+- .vidioc_streamoff = &vidioc_streamoff,
++ .vidioc_streamon = &vidioc_streamon,
++ .vidioc_streamoff = &vidioc_streamoff,
+
+ #ifdef CONFIG_VIDEO_V4L1_COMPAT
+- .vidiocgmbuf = &vidiocgmbuf,
++ .vidiocgmbuf = &vidiocgmbuf,
+ #endif
+ };
+
+@@ -2459,10 +2462,10 @@ static void v4l2loopback_cleanup_module(void)
+ #ifdef MODULE
+ int __init init_module(void)
+ {
+- return v4l2loopback_init_module();
++ return v4l2loopback_init_module();
+ }
+ void __exit cleanup_module(void) {
+- return v4l2loopback_cleanup_module();
++ return v4l2loopback_cleanup_module();
+ }
+ #else
+ late_initcall(v4l2loopback_init_module);
diff --git a/system/v4l2loopback/v4l2loopback.SlackBuild b/system/v4l2loopback/v4l2loopback.SlackBuild
new file mode 100644
index 0000000000..7d7fadd788
--- /dev/null
+++ b/system/v4l2loopback/v4l2loopback.SlackBuild
@@ -0,0 +1,98 @@
+#!/bin/sh
+
+# Slackware build script for v4l2loopback
+
+# Copyright 2020 Edward W. Koenig <kingbeowulf@gmail.com>
+# All rights reserved.
+#
+# Redistribution and use of this script, with or without modification, is
+# permitted provided that the following conditions are met:
+#
+# 1. Redistributions of this script must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED
+# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+# EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+PRGNAM=v4l2loopback
+VERSION=${VERSION:-0.12.5}
+BUILD=${BUILD:-1}
+TAG=${TAG:-_SBo}
+
+if [ -z "$ARCH" ]; then
+ case "$( uname -m )" in
+ i?86) ARCH=i586 ;;
+ arm*) ARCH=arm ;;
+ *) ARCH=$( uname -m ) ;;
+ esac
+fi
+
+CWD=$(pwd)
+TMP=${TMP:-/tmp/SBo}
+PKG=$TMP/package-$PRGNAM
+OUTPUT=${OUTPUT:-/tmp}
+
+if [ "$ARCH" = "i586" ]; then
+ SLKCFLAGS="-O2 -march=i586 -mtune=i686"
+ LIBDIRSUFFIX=""
+elif [ "$ARCH" = "i686" ]; then
+ SLKCFLAGS="-O2 -march=i686 -mtune=i686"
+ LIBDIRSUFFIX=""
+elif [ "$ARCH" = "x86_64" ]; then
+ SLKCFLAGS="-O2 -fPIC"
+ LIBDIRSUFFIX="64"
+else
+ SLKCFLAGS="-O2"
+ LIBDIRSUFFIX=""
+fi
+
+set -e
+
+rm -rf $PKG
+mkdir -p $TMP $PKG $OUTPUT
+cd $TMP
+rm -rf $PRGNAM-$VERSION
+tar -xvf $CWD/$PRGNAM-$VERSION.tar.gz
+cd $PRGNAM-$VERSION
+chown -R root:root .
+find -L . \
+ \( -perm 777 -o -perm 775 -o -perm 750 -o -perm 711 -o -perm 555 \
+ -o -perm 511 \) -exec chmod 755 {} \; -o \
+ \( -perm 666 -o -perm 664 -o -perm 640 -o -perm 600 -o -perm 444 \
+ -o -perm 440 -o -perm 400 \) -exec chmod 644 {} \;
+
+# Fix for older kernels, etc...
+# https://github.com/umlaeute/v4l2loopback/commit/d26e624b4ead762d34152f9f825b3a51fb92fb9c
+# https://github.com/umlaeute/v4l2loopback/commit/7dced0f9e6641b7e9e54ced74c5c7611d10f729f
+# https://github.com/umlaeute/v4l2loopback/commit/72a32a67dee3a67dff76f565551907a2fc7e88e6
+# only set (struct video_device).device_caps on linux>=4.7.0
+# Set device_caps in init_vdev() for all kernel-versions (not just >4.7.0)
+# Don't set the V4L2_CAP_DEVICE_CAPS on device_caps
+patch -p1 < $CWD/update_to_master_17JUN2020.patch
+
+make
+
+install -D -m 644 $PRGNAM.ko $PKG/lib/modules/$(uname -r)/kernel/extra/$PRGNAM.ko
+install -D -m 755 utils/$PRGNAM-ctl $PKG/usr/bin/$PRGNAM-ctl
+
+find $PKG -print0 | xargs -0 file | grep -e "executable" -e "shared object" | grep ELF \
+ | cut -f 1 -d : | xargs strip --strip-unneeded 2> /dev/null || true
+
+mkdir -p $PKG/usr/doc/$PRGNAM-$VERSION
+cp -a AUTHORS COPYING NEWS README.md TODO doc/ $PKG/usr/doc/$PRGNAM-$VERSION
+cat $CWD/$PRGNAM.SlackBuild > $PKG/usr/doc/$PRGNAM-$VERSION/$PRGNAM.SlackBuild
+
+mkdir -p $PKG/install
+cat $CWD/slack-desc > $PKG/install/slack-desc
+cat $CWD/doinst.sh > $PKG/install/doinst.sh
+
+cd $PKG
+/sbin/makepkg -l y -c n $OUTPUT/$PRGNAM-$VERSION-$ARCH-$BUILD$TAG.${PKGTYPE:-tgz}
diff --git a/system/v4l2loopback/v4l2loopback.info b/system/v4l2loopback/v4l2loopback.info
new file mode 100644
index 0000000000..f475983a79
--- /dev/null
+++ b/system/v4l2loopback/v4l2loopback.info
@@ -0,0 +1,10 @@
+PRGNAM="v4l2loopback"
+VERSION="0.12.5"
+HOMEPAGE="https://github.com/umlaeute/v4l2loopback/"
+DOWNLOAD="https://github.com/umlaeute/v4l2loopback/archive/v0.12.5/v4l2loopback-0.12.5.tar.gz"
+MD5SUM="4b0aaae5dd8c4f5dd0f9e2142e92e390"
+DOWNLOAD_x86_64=""
+MD5SUM_x86_64=""
+REQUIRES=""
+MAINTAINER="Edward W. Koenig"
+EMAIL="kingbeowulf@gmail.com"