On Sun, Sep 13, 2020 at 09:23:36AM +0100, Laurence Tratt wrote:
> 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
I support this suggestion. I think the idea behind it is based on the
same concerns that led to "kern.audio.record" (though admittedly I
wasn't privy to the conversations leading up to it).
> 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.
I built a kernel and sysctl with this and can confirm it works with my
Logitech C310. Of note, in its current form, running video(1) while
kern.video.record is 0 leads to a window showing mostly green and pink colors.
>
> Comments welcome, including "this is a terrible idea full stop"!
Again, I'm in favor of this idea.
It might be worth considering combining kern.audio.record and
kern.video.record, as they serve the same purpose (just different
modalities). I doubt that granular controls with separate switches will
be very useful at this level; maybe rather leave this differentiation
to the application?
An added benefit would be that there would be less largely duplicated
code; and probably better maintainability.
>
>
> 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 }, \
> }
>