[media] vivid: add xfer_func support
authorHans Verkuil <hans.verkuil@cisco.com>
Tue, 28 Apr 2015 12:41:37 +0000 (09:41 -0300)
committerMauro Carvalho Chehab <mchehab@osg.samsung.com>
Fri, 5 Jun 2015 14:49:53 +0000 (11:49 -0300)
Add support for the transfer function: create a new control for it,
and support it for both capture and output sides.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
drivers/media/platform/vivid/vivid-core.h
drivers/media/platform/vivid/vivid-ctrls.c
drivers/media/platform/vivid/vivid-tpg.c
drivers/media/platform/vivid/vivid-tpg.h
drivers/media/platform/vivid/vivid-vid-cap.c
drivers/media/platform/vivid/vivid-vid-common.c
drivers/media/platform/vivid/vivid-vid-out.c

index aa1b5232a963dea40c369bcad90ad32544e48a1c..3755b185842661e893f80f9e1fbb6fcd402e89b3 100644 (file)
@@ -332,6 +332,7 @@ struct vivid_dev {
        u32                             colorspace_out;
        u32                             ycbcr_enc_out;
        u32                             quantization_out;
+       u32                             xfer_func_out;
        u32                             service_set_out;
        unsigned                        bytesperline_out[TPG_MAX_PLANES];
        unsigned                        tv_field_out;
index 2b9070098b084cb73048cf6fbb56fac7d18cc12d..1898751c20c81cf12eab7beb54fed07baf38681a 100644 (file)
 #define VIVID_CID_DV_TIMINGS_ASPECT_RATIO      (VIVID_CID_VIVID_BASE + 23)
 #define VIVID_CID_TSTAMP_SRC           (VIVID_CID_VIVID_BASE + 24)
 #define VIVID_CID_COLORSPACE           (VIVID_CID_VIVID_BASE + 25)
-#define VIVID_CID_YCBCR_ENC            (VIVID_CID_VIVID_BASE + 26)
-#define VIVID_CID_QUANTIZATION         (VIVID_CID_VIVID_BASE + 27)
-#define VIVID_CID_LIMITED_RGB_RANGE    (VIVID_CID_VIVID_BASE + 28)
-#define VIVID_CID_ALPHA_MODE           (VIVID_CID_VIVID_BASE + 29)
-#define VIVID_CID_HAS_CROP_CAP         (VIVID_CID_VIVID_BASE + 30)
-#define VIVID_CID_HAS_COMPOSE_CAP      (VIVID_CID_VIVID_BASE + 31)
-#define VIVID_CID_HAS_SCALER_CAP       (VIVID_CID_VIVID_BASE + 32)
-#define VIVID_CID_HAS_CROP_OUT         (VIVID_CID_VIVID_BASE + 33)
-#define VIVID_CID_HAS_COMPOSE_OUT      (VIVID_CID_VIVID_BASE + 34)
-#define VIVID_CID_HAS_SCALER_OUT       (VIVID_CID_VIVID_BASE + 35)
-#define VIVID_CID_LOOP_VIDEO           (VIVID_CID_VIVID_BASE + 36)
-#define VIVID_CID_SEQ_WRAP             (VIVID_CID_VIVID_BASE + 37)
-#define VIVID_CID_TIME_WRAP            (VIVID_CID_VIVID_BASE + 38)
-#define VIVID_CID_MAX_EDID_BLOCKS      (VIVID_CID_VIVID_BASE + 39)
-#define VIVID_CID_PERCENTAGE_FILL      (VIVID_CID_VIVID_BASE + 40)
+#define VIVID_CID_XFER_FUNC            (VIVID_CID_VIVID_BASE + 26)
+#define VIVID_CID_YCBCR_ENC            (VIVID_CID_VIVID_BASE + 27)
+#define VIVID_CID_QUANTIZATION         (VIVID_CID_VIVID_BASE + 28)
+#define VIVID_CID_LIMITED_RGB_RANGE    (VIVID_CID_VIVID_BASE + 29)
+#define VIVID_CID_ALPHA_MODE           (VIVID_CID_VIVID_BASE + 30)
+#define VIVID_CID_HAS_CROP_CAP         (VIVID_CID_VIVID_BASE + 31)
+#define VIVID_CID_HAS_COMPOSE_CAP      (VIVID_CID_VIVID_BASE + 32)
+#define VIVID_CID_HAS_SCALER_CAP       (VIVID_CID_VIVID_BASE + 33)
+#define VIVID_CID_HAS_CROP_OUT         (VIVID_CID_VIVID_BASE + 34)
+#define VIVID_CID_HAS_COMPOSE_OUT      (VIVID_CID_VIVID_BASE + 35)
+#define VIVID_CID_HAS_SCALER_OUT       (VIVID_CID_VIVID_BASE + 36)
+#define VIVID_CID_LOOP_VIDEO           (VIVID_CID_VIVID_BASE + 37)
+#define VIVID_CID_SEQ_WRAP             (VIVID_CID_VIVID_BASE + 38)
+#define VIVID_CID_TIME_WRAP            (VIVID_CID_VIVID_BASE + 39)
+#define VIVID_CID_MAX_EDID_BLOCKS      (VIVID_CID_VIVID_BASE + 40)
+#define VIVID_CID_PERCENTAGE_FILL      (VIVID_CID_VIVID_BASE + 41)
 
 #define VIVID_CID_STD_SIGNAL_MODE      (VIVID_CID_VIVID_BASE + 60)
 #define VIVID_CID_STANDARD             (VIVID_CID_VIVID_BASE + 61)
@@ -360,6 +361,13 @@ static int vivid_vid_cap_s_ctrl(struct v4l2_ctrl *ctrl)
                vivid_send_source_change(dev, HDMI);
                vivid_send_source_change(dev, WEBCAM);
                break;
+       case VIVID_CID_XFER_FUNC:
+               tpg_s_xfer_func(&dev->tpg, ctrl->val);
+               vivid_send_source_change(dev, TV);
+               vivid_send_source_change(dev, SVID);
+               vivid_send_source_change(dev, HDMI);
+               vivid_send_source_change(dev, WEBCAM);
+               break;
        case VIVID_CID_YCBCR_ENC:
                tpg_s_ycbcr_enc(&dev->tpg, ctrl->val);
                vivid_send_source_change(dev, TV);
@@ -709,6 +717,25 @@ static const struct v4l2_ctrl_config vivid_ctrl_colorspace = {
        .qmenu = vivid_ctrl_colorspace_strings,
 };
 
+static const char * const vivid_ctrl_xfer_func_strings[] = {
+       "Default",
+       "Rec. 709",
+       "sRGB",
+       "AdobeRGB",
+       "SMPTE 240M",
+       "None",
+       NULL,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_xfer_func = {
+       .ops = &vivid_vid_cap_ctrl_ops,
+       .id = VIVID_CID_XFER_FUNC,
+       .name = "Transfer Function",
+       .type = V4L2_CTRL_TYPE_MENU,
+       .max = 5,
+       .qmenu = vivid_ctrl_xfer_func_strings,
+};
+
 static const char * const vivid_ctrl_ycbcr_enc_strings[] = {
        "Default",
        "ITU-R 601",
@@ -1365,6 +1392,7 @@ int vivid_create_controls(struct vivid_dev *dev, bool show_ccs_cap,
                v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_tstamp_src, NULL);
                dev->colorspace = v4l2_ctrl_new_custom(hdl_vid_cap,
                        &vivid_ctrl_colorspace, NULL);
+               v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_xfer_func, NULL);
                v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_ycbcr_enc, NULL);
                v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_quantization, NULL);
                v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_alpha_mode, NULL);
index 7a3ed580626abe5bd6e27a486be0802279a9088c..c1883a8533c523e177f54a538236ff973d72097f 100644 (file)
@@ -1651,8 +1651,14 @@ static void tpg_recalc(struct tpg_data *tpg)
        if (tpg->recalc_colors) {
                tpg->recalc_colors = false;
                tpg->recalc_lines = true;
+               tpg->real_xfer_func = tpg->xfer_func;
                tpg->real_ycbcr_enc = tpg->ycbcr_enc;
                tpg->real_quantization = tpg->quantization;
+
+               if (tpg->xfer_func == V4L2_XFER_FUNC_DEFAULT)
+                       tpg->real_xfer_func =
+                               V4L2_MAP_XFER_FUNC_DEFAULT(tpg->colorspace);
+
                if (tpg->ycbcr_enc == V4L2_YCBCR_ENC_DEFAULT)
                        tpg->real_ycbcr_enc =
                                V4L2_MAP_YCBCR_ENC_DEFAULT(tpg->colorspace);
@@ -1716,6 +1722,7 @@ void tpg_log_status(struct tpg_data *tpg)
        pr_info("tpg compose: %ux%u@%dx%d\n", tpg->compose.width, tpg->compose.height,
                        tpg->compose.left, tpg->compose.top);
        pr_info("tpg colorspace: %d\n", tpg->colorspace);
+       pr_info("tpg transfer function: %d/%d\n", tpg->xfer_func, tpg->real_xfer_func);
        pr_info("tpg Y'CbCr encoding: %d/%d\n", tpg->ycbcr_enc, tpg->real_ycbcr_enc);
        pr_info("tpg quantization: %d/%d\n", tpg->quantization, tpg->real_quantization);
        pr_info("tpg RGB range: %d/%d\n", tpg->rgb_range, tpg->real_rgb_range);
index ef8638f945bed00e53f2c61b015881dbaf772300..9baed6a1033433e9ebd3f23eb35d7d65b7d2f2ca 100644 (file)
@@ -122,7 +122,13 @@ struct tpg_data {
        u32                             fourcc;
        bool                            is_yuv;
        u32                             colorspace;
+       u32                             xfer_func;
        u32                             ycbcr_enc;
+       /*
+        * Stores the actual transfer function, i.e. will never be
+        * V4L2_XFER_FUNC_DEFAULT.
+        */
+       u32                             real_xfer_func;
        /*
         * Stores the actual Y'CbCr encoding, i.e. will never be
         * V4L2_YCBCR_ENC_DEFAULT.
@@ -329,6 +335,19 @@ static inline u32 tpg_g_ycbcr_enc(const struct tpg_data *tpg)
        return tpg->ycbcr_enc;
 }
 
+static inline void tpg_s_xfer_func(struct tpg_data *tpg, u32 xfer_func)
+{
+       if (tpg->xfer_func == xfer_func)
+               return;
+       tpg->xfer_func = xfer_func;
+       tpg->recalc_colors = true;
+}
+
+static inline u32 tpg_g_xfer_func(const struct tpg_data *tpg)
+{
+       return tpg->xfer_func;
+}
+
 static inline void tpg_s_quantization(struct tpg_data *tpg, u32 quantization)
 {
        if (tpg->quantization == quantization)
index fd7adc43f63d9cc1598a4697819f1aa8c5287bd4..7b80bda4c34c1267872b61b0f6113cc0331ae352 100644 (file)
@@ -501,6 +501,13 @@ static unsigned vivid_colorspace_cap(struct vivid_dev *dev)
        return dev->colorspace_out;
 }
 
+static unsigned vivid_xfer_func_cap(struct vivid_dev *dev)
+{
+       if (!dev->loop_video || vivid_is_webcam(dev) || vivid_is_tv_cap(dev))
+               return tpg_g_xfer_func(&dev->tpg);
+       return dev->xfer_func_out;
+}
+
 static unsigned vivid_ycbcr_enc_cap(struct vivid_dev *dev)
 {
        if (!dev->loop_video || vivid_is_webcam(dev) || vivid_is_tv_cap(dev))
@@ -527,6 +534,7 @@ int vivid_g_fmt_vid_cap(struct file *file, void *priv,
        mp->field        = dev->field_cap;
        mp->pixelformat  = dev->fmt_cap->fourcc;
        mp->colorspace   = vivid_colorspace_cap(dev);
+       mp->xfer_func    = vivid_xfer_func_cap(dev);
        mp->ycbcr_enc    = vivid_ycbcr_enc_cap(dev);
        mp->quantization = vivid_quantization_cap(dev);
        mp->num_planes = dev->fmt_cap->buffers;
@@ -616,6 +624,7 @@ int vivid_try_fmt_vid_cap(struct file *file, void *priv,
        }
        mp->colorspace = vivid_colorspace_cap(dev);
        mp->ycbcr_enc = vivid_ycbcr_enc_cap(dev);
+       mp->xfer_func = vivid_xfer_func_cap(dev);
        mp->quantization = vivid_quantization_cap(dev);
        memset(mp->reserved, 0, sizeof(mp->reserved));
        return 0;
index 45f10a7f9b46c36ae7f4c11243a67b9dadab2a64..fc73927a4abccfec01e02b64f18bd7255737699f 100644 (file)
@@ -524,6 +524,7 @@ void fmt_sp2mp(const struct v4l2_format *sp_fmt, struct v4l2_format *mp_fmt)
        mp->pixelformat = pix->pixelformat;
        mp->field = pix->field;
        mp->colorspace = pix->colorspace;
+       mp->xfer_func = pix->xfer_func;
        mp->ycbcr_enc = pix->ycbcr_enc;
        mp->quantization = pix->quantization;
        mp->num_planes = 1;
@@ -552,6 +553,7 @@ int fmt_sp2mp_func(struct file *file, void *priv,
        pix->pixelformat = mp->pixelformat;
        pix->field = mp->field;
        pix->colorspace = mp->colorspace;
+       pix->xfer_func = mp->xfer_func;
        pix->ycbcr_enc = mp->ycbcr_enc;
        pix->quantization = mp->quantization;
        pix->sizeimage = ppix->sizeimage;
index 00f42df947c0f22cf9ffc645306c7a3897de278e..0862c1f24f5703fecd64657d6e8f07847aeb43e4 100644 (file)
@@ -258,6 +258,7 @@ void vivid_update_format_out(struct vivid_dev *dev)
                }
                break;
        }
+       dev->xfer_func_out = V4L2_XFER_FUNC_DEFAULT;
        dev->ycbcr_enc_out = V4L2_YCBCR_ENC_DEFAULT;
        dev->quantization_out = V4L2_QUANTIZATION_DEFAULT;
        dev->compose_out = dev->sink_rect;
@@ -320,6 +321,7 @@ int vivid_g_fmt_vid_out(struct file *file, void *priv,
        mp->field        = dev->field_out;
        mp->pixelformat  = fmt->fourcc;
        mp->colorspace   = dev->colorspace_out;
+       mp->xfer_func    = dev->xfer_func_out;
        mp->ycbcr_enc    = dev->ycbcr_enc_out;
        mp->quantization = dev->quantization_out;
        mp->num_planes = fmt->buffers;
@@ -407,6 +409,7 @@ int vivid_try_fmt_vid_out(struct file *file, void *priv,
        for (p = fmt->buffers; p < fmt->planes; p++)
                pfmt[0].sizeimage += (pfmt[0].bytesperline * fmt->bit_depth[p]) /
                                     (fmt->bit_depth[0] * fmt->vdownsampling[p]);
+       mp->xfer_func = V4L2_XFER_FUNC_DEFAULT;
        mp->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
        mp->quantization = V4L2_QUANTIZATION_DEFAULT;
        if (vivid_is_svid_out(dev)) {
@@ -546,6 +549,7 @@ int vivid_s_fmt_vid_out(struct file *file, void *priv,
 
 set_colorspace:
        dev->colorspace_out = mp->colorspace;
+       dev->xfer_func_out = mp->xfer_func;
        dev->ycbcr_enc_out = mp->ycbcr_enc;
        dev->quantization_out = mp->quantization;
        if (dev->loop_video) {