Since I recently opened my big fat mouth and suggested that
"kern.video.record" (analogous to kern.audio.record) might be a good idea, I
decided to put together a quick prototype (heavily based on the
kern.audio.record code). This at least roughly works for me but raises some
questions such as:
* Is uvideo the only driver that can capture video? [I imagine not, but I
don't really know.]
* I've taken the same approach as kern.audio.record which is to keep on
handing out data even when kern.video.record=0 *but* it's harder to work
out what data we should hand out. At the moment we just pass on whatever
happened to be in the buffer beforehand (which is clearly not a good
idea in the long term, but proves the point for now). For uncompressed
video, handing over (say) an entirely black image is probably easy; for
compressed video we'd have to think about whether we also want to
manipulate frame headers etc. It would probably be easier to simply
intercept the "opening video" event but that would mean that if
something is already streaming video, setting kern.video.record=0 would
allow it to keep recording.
Comments welcome, including "this is a terrible idea full stop"!
Laurie
Index: sbin/sysctl/sysctl.c
===================================================================
RCS file: /cvs/src/sbin/sysctl/sysctl.c,v
retrieving revision 1.252
diff -u -p -r1.252 sysctl.c
--- sbin/sysctl/sysctl.c 15 Jul 2020 07:13:56 -0000 1.252
+++ sbin/sysctl/sysctl.c 13 Sep 2020 08:08:57 -0000
@@ -130,6 +130,7 @@ struct ctlname machdepname[] = CTL_MACHD
#endif
struct ctlname ddbname[] = CTL_DDB_NAMES;
struct ctlname audioname[] = CTL_KERN_AUDIO_NAMES;
+struct ctlname videoname[] = CTL_KERN_VIDEO_NAMES;
struct ctlname witnessname[] = CTL_KERN_WITNESS_NAMES;
char names[BUFSIZ];
int lastused;
@@ -219,6 +220,7 @@ void print_sensor(struct sensor *);
int sysctl_chipset(char *, char **, int *, int, int *);
#endif
int sysctl_audio(char *, char **, int *, int, int *);
+int sysctl_video(char *, char **, int *, int, int *);
int sysctl_witness(char *, char **, int *, int, int *);
void vfsinit(void);
@@ -517,6 +519,11 @@ parse(char *string, int flags)
if (len < 0)
return;
break;
+ case KERN_VIDEO:
+ len = sysctl_video(string, &bufp, mib, flags, &type);
+ if (len < 0)
+ return;
+ break;
case KERN_WITNESS:
len = sysctl_witness(string, &bufp, mib, flags, &type);
if (len < 0)
@@ -1766,6 +1773,7 @@ struct list shmlist = { shmname, KERN_SH
struct list watchdoglist = { watchdogname, KERN_WATCHDOG_MAXID };
struct list tclist = { tcname, KERN_TIMECOUNTER_MAXID };
struct list audiolist = { audioname, KERN_AUDIO_MAXID };
+struct list videolist = { audioname, KERN_VIDEO_MAXID };
struct list witnesslist = { witnessname, KERN_WITNESS_MAXID };
/*
@@ -2813,6 +2821,25 @@ sysctl_audio(char *string, char **bufpp,
return (-1);
mib[2] = indx;
*typep = audiolist.list[indx].ctl_type;
+ return (3);
+}
+
+/*
+ * Handle video support
+ */
+int
+sysctl_video(char *string, char **bufpp, int mib[], int flags, int *typep)
+{
+ int indx;
+
+ if (*bufpp == NULL) {
+ listall(string, &videolist);
+ return (-1);
+ }
+ if ((indx = findname(string, "third", bufpp, &videolist)) == -1)
+ return (-1);
+ mib[2] = indx;
+ *typep = videolist.list[indx].ctl_type;
return (3);
}
Index: sys/dev/usb/uvideo.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/uvideo.c,v
retrieving revision 1.209
diff -u -p -r1.209 uvideo.c
--- sys/dev/usb/uvideo.c 31 Jul 2020 10:49:33 -0000 1.209
+++ sys/dev/usb/uvideo.c 13 Sep 2020 08:08:58 -0000
@@ -386,6 +386,12 @@ struct uvideo_devs {
#define uvideo_lookup(v, p) \
((struct uvideo_devs *)usb_lookup(uvideo_devs, v, p))
+/*
+ * Global flag to control if video recording is enabled when the
+ * kern.video.record setting is set to 1.
+ */
+int video_record_enable = 0;
+
int
uvideo_enable(void *v)
{
@@ -2210,7 +2216,8 @@ uvideo_vs_decode_stream_header(struct uv
/* save sample */
sample_len = frame_size - sh->bLength;
if ((fb->offset + sample_len) <= fb->buf_size) {
- bcopy(frame + sh->bLength, fb->buf + fb->offset, sample_len);
+ if (video_record_enable)
+ bcopy(frame + sh->bLength, fb->buf + fb->offset,
sample_len);
fb->offset += sample_len;
}
@@ -2299,7 +2306,8 @@ uvideo_vs_decode_stream_header_isight(st
/* save sample */
sample_len = frame_size;
if ((fb->offset + sample_len) <= fb->buf_size) {
- bcopy(frame, fb->buf + fb->offset, sample_len);
+ if (video_record_enable)
+ bcopy(frame, fb->buf + fb->offset, sample_len);
fb->offset += sample_len;
}
}
@@ -2327,7 +2335,8 @@ uvideo_mmap_queue(struct uvideo_softc *s
}
/* copy frame to mmap buffer and report length */
- bcopy(buf, sc->sc_mmap[i].buf, len);
+ if (video_record_enable)
+ bcopy(buf, sc->sc_mmap[i].buf, len);
sc->sc_mmap[i].v4l2_buf.bytesused = len;
/* timestamp it */
Index: sys/kern/kern_sysctl.c
===================================================================
RCS file: /cvs/src/sys/kern/kern_sysctl.c,v
retrieving revision 1.379
diff -u -p -r1.379 kern_sysctl.c
--- sys/kern/kern_sysctl.c 1 Sep 2020 01:53:50 -0000 1.379
+++ sys/kern/kern_sysctl.c 13 Sep 2020 08:08:58 -0000
@@ -125,6 +125,7 @@ extern long numvnodes;
#if NAUDIO > 0
extern int audio_record_enable;
#endif
+extern int video_record_enable;
int allowkmem;
int allowdt;
@@ -141,6 +142,7 @@ int sysctl_cptime2(int *, u_int, void *,
#if NAUDIO > 0
int sysctl_audio(int *, u_int, void *, size_t *, void *, size_t);
#endif
+int sysctl_video(int *, u_int, void *, size_t *, void *, size_t);
int sysctl_cpustats(int *, u_int, void *, size_t *, void *, size_t);
int sysctl_utc_offset(void *, size_t *, void *, size_t);
@@ -313,6 +315,7 @@ kern_sysctl(int *name, u_int namelen, vo
case KERN_FILE:
case KERN_WITNESS:
case KERN_AUDIO:
+ case KERN_VIDEO:
case KERN_CPUSTATS:
break;
default:
@@ -672,6 +675,9 @@ kern_sysctl(int *name, u_int namelen, vo
return (sysctl_audio(name + 1, namelen - 1, oldp, oldlenp,
newp, newlen));
#endif
+ case KERN_VIDEO:
+ return (sysctl_video(name + 1, namelen - 1, oldp, oldlenp,
+ newp, newlen));
case KERN_CPUSTATS:
return (sysctl_cpustats(name + 1, namelen - 1, oldp, oldlenp,
newp, newlen));
@@ -2462,6 +2468,19 @@ sysctl_audio(int *name, u_int namelen, v
return (sysctl_int(oldp, oldlenp, newp, newlen, &audio_record_enable));
}
#endif
+
+int
+sysctl_video(int *name, u_int namelen, void *oldp, size_t *oldlenp,
+ void *newp, size_t newlen)
+{
+ if (namelen != 1)
+ return (ENOTDIR);
+
+ if (name[0] != KERN_VIDEO_RECORD)
+ return (ENOENT);
+
+ return (sysctl_int(oldp, oldlenp, newp, newlen, &video_record_enable));
+}
int
sysctl_cpustats(int *name, u_int namelen, void *oldp, size_t *oldlenp,
Index: sys/sys/sysctl.h
===================================================================
RCS file: /cvs/src/sys/sys/sysctl.h,v
retrieving revision 1.211
diff -u -p -r1.211 sysctl.h
--- sys/sys/sysctl.h 1 Sep 2020 01:53:50 -0000 1.211
+++ sys/sys/sysctl.h 13 Sep 2020 08:08:58 -0000
@@ -189,7 +189,8 @@ struct ctlname {
#define KERN_PFSTATUS 86 /* struct: pf status and stats
*/
#define KERN_TIMEOUT_STATS 87 /* struct: timeout status and
stats */
#define KERN_UTC_OFFSET 88 /* int: adjust RTC time to UTC
*/
-#define KERN_MAXID 89 /* number of valid kern ids */
+#define KERN_VIDEO 89 /* struct: video properties */
+#define KERN_MAXID 90 /* number of valid kern ids */
#define CTL_KERN_NAMES { \
{ 0, 0 }, \
@@ -281,6 +282,7 @@ struct ctlname {
{ "pfstatus", CTLTYPE_STRUCT }, \
{ "timeout_stats", CTLTYPE_STRUCT }, \
{ "utc_offset", CTLTYPE_INT }, \
+ { "video", CTLTYPE_STRUCT }, \
}
/*
@@ -318,6 +320,17 @@ struct ctlname {
#define KERN_AUDIO_MAXID 2
#define CTL_KERN_AUDIO_NAMES { \
+ { 0, 0 }, \
+ { "record", CTLTYPE_INT }, \
+}
+
+/*
+ * KERN_VIDEO
+ */
+#define KERN_VIDEO_RECORD 1
+#define KERN_VIDEO_MAXID 2
+
+#define CTL_KERN_VIDEO_NAMES { \
{ 0, 0 }, \
{ "record", CTLTYPE_INT }, \
}