Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/dev video(4) changes to support analog tv capture devices:



details:   https://anonhg.NetBSD.org/src/rev/8cace29db1d1
branches:  trunk
changeset: 759636:8cace29db1d1
user:      jmcneill <jmcneill%NetBSD.org@localhost>
date:      Tue Dec 14 03:25:16 2010 +0000

description:
video(4) changes to support analog tv capture devices:
 - support interlacing with VIDIOC_G_FMT
 - set V4L2_CAP_TUNER if driver implements the set_tuner/get_tuner
   callbacks
 - set V4L2_CAP_AUDIO if driver implements the set_audio/get_audio/enum_audio
   callbacks
 - add support for the following ioctls: VIDIOC_ENUMSTD, VIDIOC_G_STD,
   VIDIOC_S_STD, VIDIOC_ENUMINPUT, VIDIOC_G_INPUT, VIDIOC_S_INPUT,
   VIDIOC_ENUMAUDIO, VIDIOC_G_AUDIO, VIDIOC_S_AUDIO, VIDIOC_G_TUNER,
   VIDIOC_S_TUNER, VIDIOC_G_FREQUENCY, VIDIOC_S_FREQUENCY
 - in video_submit_payload(), fix support for signaling sample complete
   using frame numbers
 - new optional callbacks for drivers: enum_standard, get_standard,
   set_standard, enum_input, get_input, set_input, enum_audio, get_audio,
   set_audio, get_tuner, set_tuner, get_frequency, set_frequency

for drivers that don't provide enum_standard, get_standard, set_standard,
enum_input, get_input and set_input, the original stub implementations are
provided

diffstat:

 sys/dev/video.c    |  627 +++++++++++++++++++++++++++++++++++++++++++++++++---
 sys/dev/video_if.h |  109 +++++++++-
 2 files changed, 696 insertions(+), 40 deletions(-)

diffs (truncated from 879 to 300 lines):

diff -r 1ad8ce018a9a -r 8cace29db1d1 sys/dev/video.c
--- a/sys/dev/video.c   Tue Dec 14 03:07:07 2010 +0000
+++ b/sys/dev/video.c   Tue Dec 14 03:25:16 2010 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: video.c,v 1.23 2009/12/06 22:42:48 dyoung Exp $ */
+/* $NetBSD: video.c,v 1.24 2010/12/14 03:25:16 jmcneill Exp $ */
 
 /*
  * Copyright (c) 2008 Patrick Mahoney <pat%polycrystal.org@localhost>
@@ -36,7 +36,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: video.c,v 1.23 2009/12/06 22:42:48 dyoung Exp $");
+__KERNEL_RCSID(0, "$NetBSD: video.c,v 1.24 2010/12/14 03:25:16 jmcneill Exp $");
 
 #include "video.h"
 #if NVIDEO > 0
@@ -224,8 +224,24 @@
                                            struct video_format *);
 static void    video_format_to_v4l2_format(const struct video_format *,
                                            struct v4l2_format *);
-
-/* V4L2 api functions, typically called from videoioclt() */
+static void    v4l2_standard_to_video_standard(v4l2_std_id,
+                                               enum video_standard *);
+static void    video_standard_to_v4l2_standard(enum video_standard,
+                                               struct v4l2_standard *);
+static void    v4l2_input_to_video_input(const struct v4l2_input *,
+                                         struct video_input *);
+static void    video_input_to_v4l2_input(const struct video_input *,
+                                         struct v4l2_input *);
+static void    v4l2_audio_to_video_audio(const struct v4l2_audio *,
+                                         struct video_audio *);
+static void    video_audio_to_v4l2_audio(const struct video_audio *,
+                                         struct v4l2_audio *);
+static void    v4l2_tuner_to_video_tuner(const struct v4l2_tuner *,
+                                         struct video_tuner *);
+static void    video_tuner_to_v4l2_tuner(const struct video_tuner *,
+                                         struct v4l2_tuner *);
+
+/* V4L2 api functions, typically called from videoioctl() */
 static int     video_enum_format(struct video_softc *, struct v4l2_fmtdesc *);
 static int     video_get_format(struct video_softc *,
                                 struct v4l2_format *);
@@ -233,6 +249,22 @@
                                 struct v4l2_format *);
 static int     video_try_format(struct video_softc *,
                                 struct v4l2_format *);
+static int     video_enum_standard(struct video_softc *,
+                                   struct v4l2_standard *);
+static int     video_get_standard(struct video_softc *, v4l2_std_id *);
+static int     video_set_standard(struct video_softc *, v4l2_std_id);
+static int     video_enum_input(struct video_softc *, struct v4l2_input *);
+static int     video_get_input(struct video_softc *, int *);
+static int     video_set_input(struct video_softc *, int);
+static int     video_enum_audio(struct video_softc *, struct v4l2_audio *);
+static int     video_get_audio(struct video_softc *, struct v4l2_audio *);
+static int     video_set_audio(struct video_softc *, struct v4l2_audio *);
+static int     video_get_tuner(struct video_softc *, struct v4l2_tuner *);
+static int     video_set_tuner(struct video_softc *, struct v4l2_tuner *);
+static int     video_get_frequency(struct video_softc *,
+                                   struct v4l2_frequency *);
+static int     video_set_frequency(struct video_softc *,
+                                   struct v4l2_frequency *);
 static int     video_query_control(struct video_softc *,
                                    struct v4l2_queryctrl *);
 static int     video_get_control(struct video_softc *,
@@ -586,14 +618,25 @@
        dest->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        dest->fmt.pix.width = src->width;
        dest->fmt.pix.height = src->height;
-       dest->fmt.pix.field = V4L2_FIELD_NONE; /* TODO: for now,
-                                                 * just set to
-                                                 * progressive */
+       if (VIDEO_INTERLACED(src->interlace_flags))
+               dest->fmt.pix.field = V4L2_FIELD_INTERLACED;
+       else
+               dest->fmt.pix.field = V4L2_FIELD_NONE;
        dest->fmt.pix.bytesperline = src->stride;
        dest->fmt.pix.sizeimage = src->sample_size;
-       dest->fmt.pix.colorspace = 0;   /* XXX */
        dest->fmt.pix.priv = src->priv;
        
+       switch (src->color.primaries) {
+       case VIDEO_COLOR_PRIMARIES_SMPTE_170M:
+               dest->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+               break;
+       /* XXX */
+       case VIDEO_COLOR_PRIMARIES_UNSPECIFIED:
+       default:
+               dest->fmt.pix.colorspace = 0;
+               break;
+       }
+
        switch (src->pixel_format) {
        case VIDEO_FORMAT_UYVY:
                dest->fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY;
@@ -652,6 +695,23 @@
                dest->stride = src->fmt.pix.bytesperline;
                dest->sample_size = src->fmt.pix.sizeimage;
 
+               if (src->fmt.pix.field == V4L2_FIELD_INTERLACED)
+                       dest->interlace_flags = VIDEO_INTERLACE_ON;
+               else
+                       dest->interlace_flags = VIDEO_INTERLACE_OFF;
+
+               switch (src->fmt.pix.colorspace) {
+               case V4L2_COLORSPACE_SMPTE170M:
+                       dest->color.primaries =
+                           VIDEO_COLOR_PRIMARIES_SMPTE_170M;
+                       break;
+               /* XXX */
+               default:
+                       dest->color.primaries =
+                           VIDEO_COLOR_PRIMARIES_UNSPECIFIED;
+                       break;
+               }
+
                switch (src->fmt.pix.pixelformat) {
                case V4L2_PIX_FMT_UYVY:
                        dest->pixel_format = VIDEO_FORMAT_UYVY;
@@ -720,6 +780,7 @@
        video_format_to_v4l2_format(&vfmt, &fmt);
 
        fmtdesc->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; /* TODO: only one type for now */
+       fmtdesc->flags = 0;
        if (vfmt.pixel_format >= VIDEO_FORMAT_MJPEG)
                fmtdesc->flags = V4L2_FMT_FLAG_COMPRESSED;
        strlcpy(fmtdesc->description,
@@ -798,6 +859,475 @@
        return 0;
 }
 
+static void
+v4l2_standard_to_video_standard(v4l2_std_id stdid,
+    enum video_standard *vstd)
+{
+#define VSTD(id, vid)  case (id):      *vstd = (vid); break;
+       switch (stdid) {
+       VSTD(V4L2_STD_NTSC_M, VIDEO_STANDARD_NTSC_M)
+       default:
+               *vstd = VIDEO_STANDARD_UNKNOWN;
+               break;
+       }
+#undef VSTD
+}
+
+static void
+video_standard_to_v4l2_standard(enum video_standard vstd,
+    struct v4l2_standard *std)
+{
+       switch (vstd) {
+       case VIDEO_STANDARD_NTSC_M:
+               std->id = V4L2_STD_NTSC_M;
+               strlcpy(std->name, "NTSC-M", sizeof(std->name));
+               std->frameperiod.numerator = 1001;
+               std->frameperiod.denominator = 30000;
+               std->framelines = 525;
+               break;
+       default:
+               std->id = V4L2_STD_UNKNOWN;
+               strlcpy(std->name, "Unknown", sizeof(std->name));
+               break;
+       }
+}
+
+static int
+video_enum_standard(struct video_softc *sc, struct v4l2_standard *std)
+{
+       const struct video_hw_if *hw = sc->hw_if;
+       enum video_standard vstd;
+       int err;
+
+       /* simple webcam drivers don't need to implement this callback */
+       if (hw->enum_standard == NULL) {
+               if (std->index != 0)
+                       return EINVAL;
+               std->id = V4L2_STD_UNKNOWN;
+               strlcpy(std->name, "webcam", sizeof(std->name));
+               return 0;
+       }
+
+       v4l2_standard_to_video_standard(std->id, &vstd);
+
+       err = hw->enum_standard(sc->hw_softc, std->index, &vstd);
+       if (err != 0)
+               return err;
+
+       video_standard_to_v4l2_standard(vstd, std);
+
+       return 0;
+}
+
+static int
+video_get_standard(struct video_softc *sc, v4l2_std_id *stdid)
+{
+       const struct video_hw_if *hw = sc->hw_if;
+       struct v4l2_standard std;
+       enum video_standard vstd;
+       int err;
+
+       /* simple webcam drivers don't need to implement this callback */
+       if (hw->get_standard == NULL) {
+               *stdid = V4L2_STD_UNKNOWN;
+               return 0;
+       }
+
+       err = hw->get_standard(sc->hw_softc, &vstd);
+       if (err != 0)
+               return err;
+
+       video_standard_to_v4l2_standard(vstd, &std);
+       *stdid = std.id;
+       
+       return 0;
+}
+
+static int
+video_set_standard(struct video_softc *sc, v4l2_std_id stdid)
+{
+       const struct video_hw_if *hw = sc->hw_if;
+       enum video_standard vstd;
+
+       /* simple webcam drivers don't need to implement this callback */
+       if (hw->set_standard == NULL) {
+               if (stdid != V4L2_STD_UNKNOWN)
+                       return EINVAL;
+               return 0;
+       }
+
+       v4l2_standard_to_video_standard(stdid, &vstd);
+
+       return hw->set_standard(sc->hw_softc, vstd);
+}
+
+static void
+v4l2_input_to_video_input(const struct v4l2_input *input,
+    struct video_input *vi)
+{
+       vi->index = input->index;
+       strlcpy(vi->name, input->name, sizeof(vi->name));
+       switch (input->type) {
+       case V4L2_INPUT_TYPE_TUNER:
+               vi->type = VIDEO_INPUT_TYPE_TUNER;
+               break;
+       case V4L2_INPUT_TYPE_CAMERA:
+               vi->type = VIDEO_INPUT_TYPE_CAMERA;
+               break;
+       }
+       vi->audiomask = input->audioset;
+       vi->tuner_index = input->tuner;
+       vi->standards = input->std;     /* ... values are the same */
+       vi->status = 0;
+       if (input->status & V4L2_IN_ST_NO_POWER)
+               vi->status |= VIDEO_STATUS_NO_POWER;
+       if (input->status & V4L2_IN_ST_NO_SIGNAL)
+               vi->status |= VIDEO_STATUS_NO_SIGNAL;
+       if (input->status & V4L2_IN_ST_NO_COLOR)
+               vi->status |= VIDEO_STATUS_NO_COLOR;
+       if (input->status & V4L2_IN_ST_NO_H_LOCK)
+               vi->status |= VIDEO_STATUS_NO_HLOCK;
+       if (input->status & V4L2_IN_ST_MACROVISION)
+               vi->status |= VIDEO_STATUS_MACROVISION;
+}
+
+static void
+video_input_to_v4l2_input(const struct video_input *vi,
+    struct v4l2_input *input)
+{
+       input->index = vi->index;
+       strlcpy(input->name, vi->name, sizeof(input->name));
+       switch (vi->type) {
+       case VIDEO_INPUT_TYPE_TUNER:
+               input->type = V4L2_INPUT_TYPE_TUNER;
+               break;
+       case VIDEO_INPUT_TYPE_CAMERA:
+               input->type = V4L2_INPUT_TYPE_CAMERA;
+               break;
+       }
+       input->audioset = vi->audiomask;
+       input->tuner = vi->tuner_index;
+       input->std = vi->standards;     /* ... values are the same */
+       input->status = 0;
+       if (vi->status & VIDEO_STATUS_NO_POWER)
+               input->status |= V4L2_IN_ST_NO_POWER;
+       if (vi->status & VIDEO_STATUS_NO_SIGNAL)
+               input->status |= V4L2_IN_ST_NO_SIGNAL;
+       if (vi->status & VIDEO_STATUS_NO_COLOR)
+               input->status |= V4L2_IN_ST_NO_COLOR;
+       if (vi->status & VIDEO_STATUS_NO_HLOCK)
+               input->status |= V4L2_IN_ST_NO_H_LOCK;
+       if (vi->status & VIDEO_STATUS_MACROVISION)
+               input->status |= V4L2_IN_ST_MACROVISION;
+}
+
+static int
+video_enum_input(struct video_softc *sc, struct v4l2_input *input)
+{
+       const struct video_hw_if *hw = sc->hw_if;



Home | Main Index | Thread Index | Old Index