diff options
author | Mauro Carvalho Chehab <mchehab+huawei@kernel.org> | 2021-11-08 13:34:46 +0000 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab+huawei@kernel.org> | 2021-11-09 09:12:09 +0000 |
commit | 6ead632c5d4de09e480e086f730b552b7ad81a1b (patch) | |
tree | 195fa329ef2f5a019c15d522e0814371c3bae640 | |
parent | 9d74b9a088e31b89313ae55d14b5a23cefaf29cf (diff) | |
download | v4l-utils-6ead632c5d4de09e480e086f730b552b7ad81a1b.tar.gz |
v4l2grab: properly implement quantization
Implement a logic to detect between full-range and limited
range, instead of hardcoding it.
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
-rw-r--r-- | contrib/test/v4l2grab.c | 72 |
1 files changed, 56 insertions, 16 deletions
diff --git a/contrib/test/v4l2grab.c b/contrib/test/v4l2grab.c index b63fadcc..de5fd8c0 100644 --- a/contrib/test/v4l2grab.c +++ b/contrib/test/v4l2grab.c @@ -74,6 +74,13 @@ struct video_formats { unsigned int is_rgb:1; }; +struct colorspace_parms { + enum v4l2_colorspace colorspace; + enum v4l2_xfer_func xfer_func; + enum v4l2_ycbcr_encoding ycbcr_enc; + enum v4l2_quantization quantization; +}; + static const struct video_formats supported_formats[] = { { V4L2_PIX_FMT_BGR32, 32, 0, 0, 1}, { V4L2_PIX_FMT_ABGR32, 32, 0, 0, 1}, @@ -111,7 +118,46 @@ static int is_format_supported(unsigned int pixformat) if (video_fmt_props(pixformat)) return 1; return 0; +} + +static void get_colorspace_data(struct colorspace_parms *c, + struct v4l2_format *fmt) +{ + const struct video_formats *video_fmt; + + memset(c, 0, sizeof(*c)); + + video_fmt = video_fmt_props(fmt->fmt.pix.pixelformat); + if (!video_fmt) + return; + + /* + * A more complete colorspace default detection would need to + * implement timings API, in order to check for SDTV/HDTV. + */ + if (fmt->fmt.pix.colorspace == V4L2_COLORSPACE_DEFAULT) + c->colorspace = video_fmt->is_rgb ? + V4L2_COLORSPACE_SRGB : + V4L2_COLORSPACE_REC709; + else + c->colorspace = fmt->fmt.pix.colorspace; + if (fmt->fmt.pix.xfer_func == V4L2_XFER_FUNC_DEFAULT) + c->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(c->colorspace); + else + c->xfer_func = fmt->fmt.pix.xfer_func; + + if (!video_fmt->is_rgb) { + if (fmt->fmt.pix.ycbcr_enc == V4L2_YCBCR_ENC_DEFAULT) + c->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(c->colorspace); + else + c->ycbcr_enc = fmt->fmt.pix.ycbcr_enc; + } + + if (fmt->fmt.pix.quantization == V4L2_QUANTIZATION_DEFAULT) + c->quantization = V4L2_MAP_QUANTIZATION_DEFAULT(video_fmt->is_rgb, + c->colorspace, + c->ycbcr_enc); } /* @@ -238,13 +284,11 @@ static void querycap(char *fname, int fd, enum io_method method) #define CLAMP(a) ((a) < 0 ? 0 : (a) > 255 ? 255 : (a)) -static void convert_yuv(enum v4l2_ycbcr_encoding enc, +static void convert_yuv(struct colorspace_parms *c, int32_t y, int32_t u, int32_t v, unsigned char **dst) { - int full_scale = 1; // FIXME: add support for non-full_scale - - if (full_scale) + if (c->quantization == V4L2_QUANTIZATION_FULL_RANGE) y *= 65536; else y = (y - 16) * 76284; @@ -256,7 +300,7 @@ static void convert_yuv(enum v4l2_ycbcr_encoding enc, * TODO: add BT2020 and SMPTE240M and better handle * other differences */ - switch (enc) { + switch (c->ycbcr_enc) { case V4L2_YCBCR_ENC_601: case V4L2_YCBCR_ENC_XV601: case V4L2_YCBCR_ENC_SYCC: @@ -285,7 +329,7 @@ static void convert_yuv(enum v4l2_ycbcr_encoding enc, } static void copy_two_pixels(struct v4l2_format *fmt, - enum v4l2_ycbcr_encoding enc, + struct colorspace_parms *c, unsigned char *plane0, unsigned char *plane1, unsigned char *plane2, @@ -330,7 +374,7 @@ static void copy_two_pixels(struct v4l2_format *fmt, v = plane0[(1 - y_off) + (2 - u_off)]; for (i = 0; i < 2; i++) - convert_yuv(enc, plane0[y_off + (i << 1)], u, v, dst); + convert_yuv(c, plane0[y_off + (i << 1)], u, v, dst); break; case V4L2_PIX_FMT_NV12: @@ -344,7 +388,7 @@ static void copy_two_pixels(struct v4l2_format *fmt, } for (i = 0; i < 2; i++) - convert_yuv(enc, plane0[i], u, v, dst); + convert_yuv(c, plane0[i], u, v, dst); break; case V4L2_PIX_FMT_YUV420: @@ -358,7 +402,7 @@ static void copy_two_pixels(struct v4l2_format *fmt, } for (i = 0; i < 2; i++) - convert_yuv(enc, plane0[i], u, v, dst); + convert_yuv(c, plane0[i], u, v, dst); break; case V4L2_PIX_FMT_RGB32: @@ -409,7 +453,7 @@ static unsigned int convert_to_rgb24(struct v4l2_format *fmt, unsigned char *plane2_start = NULL; unsigned char *plane1 = NULL; unsigned char *plane2 = NULL; - enum v4l2_ycbcr_encoding enc; + struct colorspace_parms c; unsigned int x, y, depth; uint32_t num_planes = 1; unsigned char *p_start; @@ -417,11 +461,7 @@ static unsigned int convert_to_rgb24(struct v4l2_format *fmt, uint32_t w_dec = 0; uint32_t h_dec = 0; - if (fmt->fmt.pix.ycbcr_enc == V4L2_YCBCR_ENC_DEFAULT) - enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->fmt.pix.colorspace); - else - enc = fmt->fmt.pix.ycbcr_enc; - + get_colorspace_data(&c, fmt); video_fmt = video_fmt_props(fmt->fmt.pix.pixelformat); if (!video_fmt) @@ -455,7 +495,7 @@ static unsigned int convert_to_rgb24(struct v4l2_format *fmt, plane2 = plane2_start + (bytesperline >> w_dec) * (y >> h_dec); for (x = 0; x < width >> 1; x++) { - copy_two_pixels(fmt, enc, plane0, plane1, plane2, &p_out); + copy_two_pixels(fmt, &c, plane0, plane1, plane2, &p_out); plane0 += depth >> 2; if (num_planes > 1) |