[media] vivid: add support for YCbCr encoding and quantization
authorHans Verkuil <hans.verkuil@cisco.com>
Mon, 17 Nov 2014 13:26:01 +0000 (10:26 -0300)
committerMauro Carvalho Chehab <mchehab@osg.samsung.com>
Tue, 2 Dec 2014 13:18:09 +0000 (11:18 -0200)
Implement controls to set the YCbCr encoding and the quantization
range for the colorspace.

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-vid-cap.c
drivers/media/platform/vivid/vivid-vid-common.c
drivers/media/platform/vivid/vivid-vid-out.c

index 9e41cbe2300659b3e1aecf94887043e31b444b5f..4b497df4b6a433f0522ffb334dc0ec570e3faa8e 100644 (file)
@@ -329,6 +329,8 @@ struct vivid_dev {
        v4l2_std_id                     std_out;
        struct v4l2_dv_timings          dv_timings_out;
        u32                             colorspace_out;
+       u32                             ycbcr_enc_out;
+       u32                             quantization_out;
        u32                             service_set_out;
        u32                             bytesperline_out[2];
        unsigned                        tv_field_out;
index dcb912d6e4ba4862c757dfed275b21f746264f43..857e7866e8bc5d8d64141a664db6548a73bb77eb 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_LIMITED_RGB_RANGE    (VIVID_CID_VIVID_BASE + 26)
-#define VIVID_CID_ALPHA_MODE           (VIVID_CID_VIVID_BASE + 27)
-#define VIVID_CID_HAS_CROP_CAP         (VIVID_CID_VIVID_BASE + 28)
-#define VIVID_CID_HAS_COMPOSE_CAP      (VIVID_CID_VIVID_BASE + 29)
-#define VIVID_CID_HAS_SCALER_CAP       (VIVID_CID_VIVID_BASE + 30)
-#define VIVID_CID_HAS_CROP_OUT         (VIVID_CID_VIVID_BASE + 31)
-#define VIVID_CID_HAS_COMPOSE_OUT      (VIVID_CID_VIVID_BASE + 32)
-#define VIVID_CID_HAS_SCALER_OUT       (VIVID_CID_VIVID_BASE + 33)
-#define VIVID_CID_LOOP_VIDEO           (VIVID_CID_VIVID_BASE + 34)
-#define VIVID_CID_SEQ_WRAP             (VIVID_CID_VIVID_BASE + 35)
-#define VIVID_CID_TIME_WRAP            (VIVID_CID_VIVID_BASE + 36)
-#define VIVID_CID_MAX_EDID_BLOCKS      (VIVID_CID_VIVID_BASE + 37)
-#define VIVID_CID_PERCENTAGE_FILL      (VIVID_CID_VIVID_BASE + 38)
+#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_STD_SIGNAL_MODE      (VIVID_CID_VIVID_BASE + 60)
 #define VIVID_CID_STANDARD             (VIVID_CID_VIVID_BASE + 61)
@@ -358,6 +360,20 @@ 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_YCBCR_ENC:
+               tpg_s_ycbcr_enc(&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_QUANTIZATION:
+               tpg_s_quantization(&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 V4L2_CID_DV_RX_RGB_RANGE:
                if (!vivid_is_hdmi_cap(dev))
                        break;
@@ -693,6 +709,44 @@ static const struct v4l2_ctrl_config vivid_ctrl_colorspace = {
        .qmenu = vivid_ctrl_colorspace_strings,
 };
 
+static const char * const vivid_ctrl_ycbcr_enc_strings[] = {
+       "Default",
+       "ITU-R 601",
+       "Rec. 709",
+       "xvYCC 601",
+       "xvYCC 709",
+       "sYCC",
+       "BT.2020 Non-Constant Luminance",
+       "BT.2020 Constant Luminance",
+       "SMPTE 240M",
+       NULL,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_ycbcr_enc = {
+       .ops = &vivid_vid_cap_ctrl_ops,
+       .id = VIVID_CID_YCBCR_ENC,
+       .name = "Y'CbCr Encoding",
+       .type = V4L2_CTRL_TYPE_MENU,
+       .max = 8,
+       .qmenu = vivid_ctrl_ycbcr_enc_strings,
+};
+
+static const char * const vivid_ctrl_quantization_strings[] = {
+       "Default",
+       "Full Range",
+       "Limited Range",
+       NULL,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_quantization = {
+       .ops = &vivid_vid_cap_ctrl_ops,
+       .id = VIVID_CID_QUANTIZATION,
+       .name = "Quantization",
+       .type = V4L2_CTRL_TYPE_MENU,
+       .max = 2,
+       .qmenu = vivid_ctrl_quantization_strings,
+};
+
 static const struct v4l2_ctrl_config vivid_ctrl_alpha_mode = {
        .ops = &vivid_vid_cap_ctrl_ops,
        .id = VIVID_CID_ALPHA_MODE,
@@ -769,8 +823,12 @@ static int vivid_vid_out_s_ctrl(struct v4l2_ctrl *ctrl)
                                dev->colorspace_out = V4L2_COLORSPACE_SMPTE170M;
                        else
                                dev->colorspace_out = V4L2_COLORSPACE_REC709;
+                       dev->quantization_out = V4L2_QUANTIZATION_DEFAULT;
                } else {
                        dev->colorspace_out = V4L2_COLORSPACE_SRGB;
+                       dev->quantization_out = dev->dvi_d_out ?
+                                       V4L2_QUANTIZATION_LIM_RANGE :
+                                       V4L2_QUANTIZATION_DEFAULT;
                }
                if (dev->loop_video)
                        vivid_send_source_change(dev, HDMI);
@@ -1307,6 +1365,8 @@ 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_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 923a4f854eba4f75a65530fc5ce7f23ff6241b5a..867a29a6d18f2fc1b8ef880659f788d309a38f52 100644 (file)
@@ -498,6 +498,20 @@ static unsigned vivid_colorspace_cap(struct vivid_dev *dev)
        return dev->colorspace_out;
 }
 
+static unsigned vivid_ycbcr_enc_cap(struct vivid_dev *dev)
+{
+       if (!dev->loop_video || vivid_is_webcam(dev) || vivid_is_tv_cap(dev))
+               return tpg_g_ycbcr_enc(&dev->tpg);
+       return dev->ycbcr_enc_out;
+}
+
+static unsigned vivid_quantization_cap(struct vivid_dev *dev)
+{
+       if (!dev->loop_video || vivid_is_webcam(dev) || vivid_is_tv_cap(dev))
+               return tpg_g_quantization(&dev->tpg);
+       return dev->quantization_out;
+}
+
 int vivid_g_fmt_vid_cap(struct file *file, void *priv,
                                        struct v4l2_format *f)
 {
@@ -510,6 +524,8 @@ 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->ycbcr_enc    = vivid_ycbcr_enc_cap(dev);
+       mp->quantization = vivid_quantization_cap(dev);
        mp->num_planes = dev->fmt_cap->planes;
        for (p = 0; p < mp->num_planes; p++) {
                mp->plane_fmt[p].bytesperline = tpg_g_bytesperline(&dev->tpg, p);
@@ -595,6 +611,8 @@ int vivid_try_fmt_vid_cap(struct file *file, void *priv,
                memset(pfmt[p].reserved, 0, sizeof(pfmt[p].reserved));
        }
        mp->colorspace = vivid_colorspace_cap(dev);
+       mp->ycbcr_enc = vivid_ycbcr_enc_cap(dev);
+       mp->quantization = vivid_quantization_cap(dev);
        memset(mp->reserved, 0, sizeof(mp->reserved));
        return 0;
 }
index 16cd6d2d2ed6cae26a89606b9411b1d2f6f5ee19..6bef1e6d6788929b93059738636e938490f4535b 100644 (file)
@@ -259,6 +259,8 @@ 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->ycbcr_enc = pix->ycbcr_enc;
+       mp->quantization = pix->quantization;
        mp->num_planes = 1;
        mp->flags = pix->flags;
        ppix->sizeimage = pix->sizeimage;
@@ -285,6 +287,8 @@ int fmt_sp2mp_func(struct file *file, void *priv,
        pix->pixelformat = mp->pixelformat;
        pix->field = mp->field;
        pix->colorspace = mp->colorspace;
+       pix->ycbcr_enc = mp->ycbcr_enc;
+       pix->quantization = mp->quantization;
        pix->sizeimage = ppix->sizeimage;
        pix->bytesperline = ppix->bytesperline;
        pix->flags = mp->flags;
index 078bc35571b45efee64f3e04aebd6c4b3fbfe3c6..ee5c3992b276b9e7e7b2ed5bd3144e4ba9f33346 100644 (file)
@@ -259,6 +259,8 @@ void vivid_update_format_out(struct vivid_dev *dev)
                }
                break;
        }
+       dev->ycbcr_enc_out = V4L2_YCBCR_ENC_DEFAULT;
+       dev->quantization_out = V4L2_QUANTIZATION_DEFAULT;
        dev->compose_out = dev->sink_rect;
        dev->compose_bounds_out = dev->sink_rect;
        dev->crop_out = dev->compose_out;
@@ -318,6 +320,8 @@ int vivid_g_fmt_vid_out(struct file *file, void *priv,
        mp->field        = dev->field_out;
        mp->pixelformat  = dev->fmt_out->fourcc;
        mp->colorspace   = dev->colorspace_out;
+       mp->ycbcr_enc    = dev->ycbcr_enc_out;
+       mp->quantization = dev->quantization_out;
        mp->num_planes = dev->fmt_out->planes;
        for (p = 0; p < mp->num_planes; p++) {
                mp->plane_fmt[p].bytesperline = dev->bytesperline_out[p];
@@ -394,16 +398,23 @@ int vivid_try_fmt_vid_out(struct file *file, void *priv,
                pfmt[p].sizeimage = pfmt[p].bytesperline * mp->height;
                memset(pfmt[p].reserved, 0, sizeof(pfmt[p].reserved));
        }
-       if (vivid_is_svid_out(dev))
+       mp->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
+       mp->quantization = V4L2_QUANTIZATION_DEFAULT;
+       if (vivid_is_svid_out(dev)) {
                mp->colorspace = V4L2_COLORSPACE_SMPTE170M;
-       else if (dev->dvi_d_out || !(bt->standards & V4L2_DV_BT_STD_CEA861))
+       } else if (dev->dvi_d_out || !(bt->standards & V4L2_DV_BT_STD_CEA861)) {
                mp->colorspace = V4L2_COLORSPACE_SRGB;
-       else if (bt->width == 720 && bt->height <= 576)
+               if (dev->dvi_d_out)
+                       mp->quantization = V4L2_QUANTIZATION_LIM_RANGE;
+       } else if (bt->width == 720 && bt->height <= 576) {
                mp->colorspace = V4L2_COLORSPACE_SMPTE170M;
-       else if (mp->colorspace != V4L2_COLORSPACE_SMPTE170M &&
-                mp->colorspace != V4L2_COLORSPACE_REC709 &&
-                mp->colorspace != V4L2_COLORSPACE_SRGB)
+       } else if (mp->colorspace != V4L2_COLORSPACE_SMPTE170M &&
+                  mp->colorspace != V4L2_COLORSPACE_REC709 &&
+                  mp->colorspace != V4L2_COLORSPACE_ADOBERGB &&
+                  mp->colorspace != V4L2_COLORSPACE_BT2020 &&
+                  mp->colorspace != V4L2_COLORSPACE_SRGB) {
                mp->colorspace = V4L2_COLORSPACE_REC709;
+       }
        memset(mp->reserved, 0, sizeof(mp->reserved));
        return 0;
 }
@@ -522,6 +533,8 @@ int vivid_s_fmt_vid_out(struct file *file, void *priv,
 
 set_colorspace:
        dev->colorspace_out = mp->colorspace;
+       dev->ycbcr_enc_out = mp->ycbcr_enc;
+       dev->quantization_out = mp->quantization;
        if (dev->loop_video) {
                vivid_send_source_change(dev, SVID);
                vivid_send_source_change(dev, HDMI);