Commit ca5316db authored by Hans Verkuil's avatar Hans Verkuil Committed by Mauro Carvalho Chehab

[media] vivid: add xfer_func support

Add support for the transfer function: create a new control for it,
and support it for both capture and output sides.
Signed-off-by: default avatarHans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@osg.samsung.com>
parent c62cda97
...@@ -332,6 +332,7 @@ struct vivid_dev { ...@@ -332,6 +332,7 @@ struct vivid_dev {
u32 colorspace_out; u32 colorspace_out;
u32 ycbcr_enc_out; u32 ycbcr_enc_out;
u32 quantization_out; u32 quantization_out;
u32 xfer_func_out;
u32 service_set_out; u32 service_set_out;
unsigned bytesperline_out[TPG_MAX_PLANES]; unsigned bytesperline_out[TPG_MAX_PLANES];
unsigned tv_field_out; unsigned tv_field_out;
......
...@@ -62,21 +62,22 @@ ...@@ -62,21 +62,22 @@
#define VIVID_CID_DV_TIMINGS_ASPECT_RATIO (VIVID_CID_VIVID_BASE + 23) #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_TSTAMP_SRC (VIVID_CID_VIVID_BASE + 24)
#define VIVID_CID_COLORSPACE (VIVID_CID_VIVID_BASE + 25) #define VIVID_CID_COLORSPACE (VIVID_CID_VIVID_BASE + 25)
#define VIVID_CID_YCBCR_ENC (VIVID_CID_VIVID_BASE + 26) #define VIVID_CID_XFER_FUNC (VIVID_CID_VIVID_BASE + 26)
#define VIVID_CID_QUANTIZATION (VIVID_CID_VIVID_BASE + 27) #define VIVID_CID_YCBCR_ENC (VIVID_CID_VIVID_BASE + 27)
#define VIVID_CID_LIMITED_RGB_RANGE (VIVID_CID_VIVID_BASE + 28) #define VIVID_CID_QUANTIZATION (VIVID_CID_VIVID_BASE + 28)
#define VIVID_CID_ALPHA_MODE (VIVID_CID_VIVID_BASE + 29) #define VIVID_CID_LIMITED_RGB_RANGE (VIVID_CID_VIVID_BASE + 29)
#define VIVID_CID_HAS_CROP_CAP (VIVID_CID_VIVID_BASE + 30) #define VIVID_CID_ALPHA_MODE (VIVID_CID_VIVID_BASE + 30)
#define VIVID_CID_HAS_COMPOSE_CAP (VIVID_CID_VIVID_BASE + 31) #define VIVID_CID_HAS_CROP_CAP (VIVID_CID_VIVID_BASE + 31)
#define VIVID_CID_HAS_SCALER_CAP (VIVID_CID_VIVID_BASE + 32) #define VIVID_CID_HAS_COMPOSE_CAP (VIVID_CID_VIVID_BASE + 32)
#define VIVID_CID_HAS_CROP_OUT (VIVID_CID_VIVID_BASE + 33) #define VIVID_CID_HAS_SCALER_CAP (VIVID_CID_VIVID_BASE + 33)
#define VIVID_CID_HAS_COMPOSE_OUT (VIVID_CID_VIVID_BASE + 34) #define VIVID_CID_HAS_CROP_OUT (VIVID_CID_VIVID_BASE + 34)
#define VIVID_CID_HAS_SCALER_OUT (VIVID_CID_VIVID_BASE + 35) #define VIVID_CID_HAS_COMPOSE_OUT (VIVID_CID_VIVID_BASE + 35)
#define VIVID_CID_LOOP_VIDEO (VIVID_CID_VIVID_BASE + 36) #define VIVID_CID_HAS_SCALER_OUT (VIVID_CID_VIVID_BASE + 36)
#define VIVID_CID_SEQ_WRAP (VIVID_CID_VIVID_BASE + 37) #define VIVID_CID_LOOP_VIDEO (VIVID_CID_VIVID_BASE + 37)
#define VIVID_CID_TIME_WRAP (VIVID_CID_VIVID_BASE + 38) #define VIVID_CID_SEQ_WRAP (VIVID_CID_VIVID_BASE + 38)
#define VIVID_CID_MAX_EDID_BLOCKS (VIVID_CID_VIVID_BASE + 39) #define VIVID_CID_TIME_WRAP (VIVID_CID_VIVID_BASE + 39)
#define VIVID_CID_PERCENTAGE_FILL (VIVID_CID_VIVID_BASE + 40) #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_STD_SIGNAL_MODE (VIVID_CID_VIVID_BASE + 60)
#define VIVID_CID_STANDARD (VIVID_CID_VIVID_BASE + 61) #define VIVID_CID_STANDARD (VIVID_CID_VIVID_BASE + 61)
...@@ -360,6 +361,13 @@ static int vivid_vid_cap_s_ctrl(struct v4l2_ctrl *ctrl) ...@@ -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, HDMI);
vivid_send_source_change(dev, WEBCAM); vivid_send_source_change(dev, WEBCAM);
break; 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: case VIVID_CID_YCBCR_ENC:
tpg_s_ycbcr_enc(&dev->tpg, ctrl->val); tpg_s_ycbcr_enc(&dev->tpg, ctrl->val);
vivid_send_source_change(dev, TV); vivid_send_source_change(dev, TV);
...@@ -709,6 +717,25 @@ static const struct v4l2_ctrl_config vivid_ctrl_colorspace = { ...@@ -709,6 +717,25 @@ static const struct v4l2_ctrl_config vivid_ctrl_colorspace = {
.qmenu = vivid_ctrl_colorspace_strings, .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[] = { static const char * const vivid_ctrl_ycbcr_enc_strings[] = {
"Default", "Default",
"ITU-R 601", "ITU-R 601",
...@@ -1365,6 +1392,7 @@ int vivid_create_controls(struct vivid_dev *dev, bool show_ccs_cap, ...@@ -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); v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_tstamp_src, NULL);
dev->colorspace = v4l2_ctrl_new_custom(hdl_vid_cap, dev->colorspace = v4l2_ctrl_new_custom(hdl_vid_cap,
&vivid_ctrl_colorspace, NULL); &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_ycbcr_enc, NULL);
v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_quantization, NULL); v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_quantization, NULL);
v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_alpha_mode, NULL); v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_alpha_mode, NULL);
......
...@@ -1651,8 +1651,14 @@ static void tpg_recalc(struct tpg_data *tpg) ...@@ -1651,8 +1651,14 @@ static void tpg_recalc(struct tpg_data *tpg)
if (tpg->recalc_colors) { if (tpg->recalc_colors) {
tpg->recalc_colors = false; tpg->recalc_colors = false;
tpg->recalc_lines = true; tpg->recalc_lines = true;
tpg->real_xfer_func = tpg->xfer_func;
tpg->real_ycbcr_enc = tpg->ycbcr_enc; tpg->real_ycbcr_enc = tpg->ycbcr_enc;
tpg->real_quantization = tpg->quantization; 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) if (tpg->ycbcr_enc == V4L2_YCBCR_ENC_DEFAULT)
tpg->real_ycbcr_enc = tpg->real_ycbcr_enc =
V4L2_MAP_YCBCR_ENC_DEFAULT(tpg->colorspace); V4L2_MAP_YCBCR_ENC_DEFAULT(tpg->colorspace);
...@@ -1716,6 +1722,7 @@ void tpg_log_status(struct tpg_data *tpg) ...@@ -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, pr_info("tpg compose: %ux%u@%dx%d\n", tpg->compose.width, tpg->compose.height,
tpg->compose.left, tpg->compose.top); tpg->compose.left, tpg->compose.top);
pr_info("tpg colorspace: %d\n", tpg->colorspace); 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 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 quantization: %d/%d\n", tpg->quantization, tpg->real_quantization);
pr_info("tpg RGB range: %d/%d\n", tpg->rgb_range, tpg->real_rgb_range); pr_info("tpg RGB range: %d/%d\n", tpg->rgb_range, tpg->real_rgb_range);
......
...@@ -122,7 +122,13 @@ struct tpg_data { ...@@ -122,7 +122,13 @@ struct tpg_data {
u32 fourcc; u32 fourcc;
bool is_yuv; bool is_yuv;
u32 colorspace; u32 colorspace;
u32 xfer_func;
u32 ycbcr_enc; 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 * Stores the actual Y'CbCr encoding, i.e. will never be
* V4L2_YCBCR_ENC_DEFAULT. * V4L2_YCBCR_ENC_DEFAULT.
...@@ -329,6 +335,19 @@ static inline u32 tpg_g_ycbcr_enc(const struct tpg_data *tpg) ...@@ -329,6 +335,19 @@ static inline u32 tpg_g_ycbcr_enc(const struct tpg_data *tpg)
return tpg->ycbcr_enc; 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) static inline void tpg_s_quantization(struct tpg_data *tpg, u32 quantization)
{ {
if (tpg->quantization == quantization) if (tpg->quantization == quantization)
......
...@@ -501,6 +501,13 @@ static unsigned vivid_colorspace_cap(struct vivid_dev *dev) ...@@ -501,6 +501,13 @@ static unsigned vivid_colorspace_cap(struct vivid_dev *dev)
return dev->colorspace_out; 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) static unsigned vivid_ycbcr_enc_cap(struct vivid_dev *dev)
{ {
if (!dev->loop_video || vivid_is_webcam(dev) || vivid_is_tv_cap(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, ...@@ -527,6 +534,7 @@ int vivid_g_fmt_vid_cap(struct file *file, void *priv,
mp->field = dev->field_cap; mp->field = dev->field_cap;
mp->pixelformat = dev->fmt_cap->fourcc; mp->pixelformat = dev->fmt_cap->fourcc;
mp->colorspace = vivid_colorspace_cap(dev); mp->colorspace = vivid_colorspace_cap(dev);
mp->xfer_func = vivid_xfer_func_cap(dev);
mp->ycbcr_enc = vivid_ycbcr_enc_cap(dev); mp->ycbcr_enc = vivid_ycbcr_enc_cap(dev);
mp->quantization = vivid_quantization_cap(dev); mp->quantization = vivid_quantization_cap(dev);
mp->num_planes = dev->fmt_cap->buffers; mp->num_planes = dev->fmt_cap->buffers;
...@@ -616,6 +624,7 @@ int vivid_try_fmt_vid_cap(struct file *file, void *priv, ...@@ -616,6 +624,7 @@ int vivid_try_fmt_vid_cap(struct file *file, void *priv,
} }
mp->colorspace = vivid_colorspace_cap(dev); mp->colorspace = vivid_colorspace_cap(dev);
mp->ycbcr_enc = vivid_ycbcr_enc_cap(dev); mp->ycbcr_enc = vivid_ycbcr_enc_cap(dev);
mp->xfer_func = vivid_xfer_func_cap(dev);
mp->quantization = vivid_quantization_cap(dev); mp->quantization = vivid_quantization_cap(dev);
memset(mp->reserved, 0, sizeof(mp->reserved)); memset(mp->reserved, 0, sizeof(mp->reserved));
return 0; return 0;
......
...@@ -524,6 +524,7 @@ void fmt_sp2mp(const struct v4l2_format *sp_fmt, struct v4l2_format *mp_fmt) ...@@ -524,6 +524,7 @@ void fmt_sp2mp(const struct v4l2_format *sp_fmt, struct v4l2_format *mp_fmt)
mp->pixelformat = pix->pixelformat; mp->pixelformat = pix->pixelformat;
mp->field = pix->field; mp->field = pix->field;
mp->colorspace = pix->colorspace; mp->colorspace = pix->colorspace;
mp->xfer_func = pix->xfer_func;
mp->ycbcr_enc = pix->ycbcr_enc; mp->ycbcr_enc = pix->ycbcr_enc;
mp->quantization = pix->quantization; mp->quantization = pix->quantization;
mp->num_planes = 1; mp->num_planes = 1;
...@@ -552,6 +553,7 @@ int fmt_sp2mp_func(struct file *file, void *priv, ...@@ -552,6 +553,7 @@ int fmt_sp2mp_func(struct file *file, void *priv,
pix->pixelformat = mp->pixelformat; pix->pixelformat = mp->pixelformat;
pix->field = mp->field; pix->field = mp->field;
pix->colorspace = mp->colorspace; pix->colorspace = mp->colorspace;
pix->xfer_func = mp->xfer_func;
pix->ycbcr_enc = mp->ycbcr_enc; pix->ycbcr_enc = mp->ycbcr_enc;
pix->quantization = mp->quantization; pix->quantization = mp->quantization;
pix->sizeimage = ppix->sizeimage; pix->sizeimage = ppix->sizeimage;
......
...@@ -258,6 +258,7 @@ void vivid_update_format_out(struct vivid_dev *dev) ...@@ -258,6 +258,7 @@ void vivid_update_format_out(struct vivid_dev *dev)
} }
break; break;
} }
dev->xfer_func_out = V4L2_XFER_FUNC_DEFAULT;
dev->ycbcr_enc_out = V4L2_YCBCR_ENC_DEFAULT; dev->ycbcr_enc_out = V4L2_YCBCR_ENC_DEFAULT;
dev->quantization_out = V4L2_QUANTIZATION_DEFAULT; dev->quantization_out = V4L2_QUANTIZATION_DEFAULT;
dev->compose_out = dev->sink_rect; dev->compose_out = dev->sink_rect;
...@@ -320,6 +321,7 @@ int vivid_g_fmt_vid_out(struct file *file, void *priv, ...@@ -320,6 +321,7 @@ int vivid_g_fmt_vid_out(struct file *file, void *priv,
mp->field = dev->field_out; mp->field = dev->field_out;
mp->pixelformat = fmt->fourcc; mp->pixelformat = fmt->fourcc;
mp->colorspace = dev->colorspace_out; mp->colorspace = dev->colorspace_out;
mp->xfer_func = dev->xfer_func_out;
mp->ycbcr_enc = dev->ycbcr_enc_out; mp->ycbcr_enc = dev->ycbcr_enc_out;
mp->quantization = dev->quantization_out; mp->quantization = dev->quantization_out;
mp->num_planes = fmt->buffers; mp->num_planes = fmt->buffers;
...@@ -407,6 +409,7 @@ int vivid_try_fmt_vid_out(struct file *file, void *priv, ...@@ -407,6 +409,7 @@ int vivid_try_fmt_vid_out(struct file *file, void *priv,
for (p = fmt->buffers; p < fmt->planes; p++) for (p = fmt->buffers; p < fmt->planes; p++)
pfmt[0].sizeimage += (pfmt[0].bytesperline * fmt->bit_depth[p]) / pfmt[0].sizeimage += (pfmt[0].bytesperline * fmt->bit_depth[p]) /
(fmt->bit_depth[0] * fmt->vdownsampling[p]); (fmt->bit_depth[0] * fmt->vdownsampling[p]);
mp->xfer_func = V4L2_XFER_FUNC_DEFAULT;
mp->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; mp->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
mp->quantization = V4L2_QUANTIZATION_DEFAULT; mp->quantization = V4L2_QUANTIZATION_DEFAULT;
if (vivid_is_svid_out(dev)) { if (vivid_is_svid_out(dev)) {
...@@ -546,6 +549,7 @@ int vivid_s_fmt_vid_out(struct file *file, void *priv, ...@@ -546,6 +549,7 @@ int vivid_s_fmt_vid_out(struct file *file, void *priv,
set_colorspace: set_colorspace:
dev->colorspace_out = mp->colorspace; dev->colorspace_out = mp->colorspace;
dev->xfer_func_out = mp->xfer_func;
dev->ycbcr_enc_out = mp->ycbcr_enc; dev->ycbcr_enc_out = mp->ycbcr_enc;
dev->quantization_out = mp->quantization; dev->quantization_out = mp->quantization;
if (dev->loop_video) { if (dev->loop_video) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment