diff mbox series

v4l2 utils: Support V4L2_PIX_FMT_YUV[AX]32

Message ID 20220630092904.19053-1-laurent.pinchart@ideasonboard.com (mailing list archive)
State New, archived
Headers show
Series v4l2 utils: Support V4L2_PIX_FMT_YUV[AX]32 | expand

Commit Message

Laurent Pinchart June 30, 2022, 9:29 a.m. UTC
Add support for the V4L2_PIX_FMT_YUVA32 and V4L2_PIX_FMT_YUVX32 pixel
formats in the v4l2-ctl, v4l2-compliance, qvidcap and qv4l2 utilities.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
This patch depends on the addition of the new YUVA32 and YUVX32 pixel
formats to the kernel, which I plan to post a pull request for in the
near future.

While working on this, I've noticed what could be a bug in the qv4l2 GL
shaders. It seems to me that at least the V4L2_PIX_FMT_VUYA32 and
V4L2_PIX_FMT_VUYX32 formats are not correctly handled. Hans, could you
have a look at this ?
---
 utils/qv4l2/capture-win-gl.cpp             | 17 +++++++++++++++++
 utils/qv4l2/qv4l2.cpp                      |  2 ++
 utils/qvidcap/capture.cpp                  |  4 ++++
 utils/qvidcap/paint.cpp                    | 10 ++++++++++
 utils/qvidcap/v4l2-convert.glsl            |  6 ++++++
 utils/v4l2-compliance/v4l2-test-colors.cpp |  4 ++++
 utils/v4l2-ctl/v4l2-ctl.cpp                |  2 ++
 7 files changed, 45 insertions(+)

Comments

Hans Verkuil July 4, 2022, 11:08 a.m. UTC | #1
Hi Laurent,

On 6/30/22 11:29, Laurent Pinchart wrote:
> Add support for the V4L2_PIX_FMT_YUVA32 and V4L2_PIX_FMT_YUVX32 pixel
> formats in the v4l2-ctl, v4l2-compliance, qvidcap and qv4l2 utilities.
> 
> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> ---
> This patch depends on the addition of the new YUVA32 and YUVX32 pixel
> formats to the kernel, which I plan to post a pull request for in the
> near future.
> 
> While working on this, I've noticed what could be a bug in the qv4l2 GL
> shaders. It seems to me that at least the V4L2_PIX_FMT_VUYA32 and
> V4L2_PIX_FMT_VUYX32 formats are not correctly handled. Hans, could you
> have a look at this ?

It looks good to me. Do you actually see something wrong? I've tested with
vivid and qv4l2, but you may be testing with another driver.

Regards,

	Hans

> ---
>  utils/qv4l2/capture-win-gl.cpp             | 17 +++++++++++++++++
>  utils/qv4l2/qv4l2.cpp                      |  2 ++
>  utils/qvidcap/capture.cpp                  |  4 ++++
>  utils/qvidcap/paint.cpp                    | 10 ++++++++++
>  utils/qvidcap/v4l2-convert.glsl            |  6 ++++++
>  utils/v4l2-compliance/v4l2-test-colors.cpp |  4 ++++
>  utils/v4l2-ctl/v4l2-ctl.cpp                |  2 ++
>  7 files changed, 45 insertions(+)
> 
> diff --git a/utils/qv4l2/capture-win-gl.cpp b/utils/qv4l2/capture-win-gl.cpp
> index 05659259d42f..6cbeb426b6ba 100644
> --- a/utils/qv4l2/capture-win-gl.cpp
> +++ b/utils/qv4l2/capture-win-gl.cpp
> @@ -196,6 +196,8 @@ void CaptureWinGLEngine::setColorspace(unsigned colorspace, unsigned xfer_func,
>  	case V4L2_PIX_FMT_XYUV32:
>  	case V4L2_PIX_FMT_VUYA32:
>  	case V4L2_PIX_FMT_VUYX32:
> +	case V4L2_PIX_FMT_YUVA32:
> +	case V4L2_PIX_FMT_YUVX32:
>  	case V4L2_PIX_FMT_HSV24:
>  	case V4L2_PIX_FMT_HSV32:
>  		is_rgb = false;
> @@ -415,6 +417,8 @@ bool CaptureWinGLEngine::hasNativeFormat(__u32 format)
>  		V4L2_PIX_FMT_XYUV32,
>  		V4L2_PIX_FMT_VUYA32,
>  		V4L2_PIX_FMT_VUYX32,
> +		V4L2_PIX_FMT_YUVA32,
> +		V4L2_PIX_FMT_YUVX32,
>  		V4L2_PIX_FMT_GREY,
>  		V4L2_PIX_FMT_Z16,
>  		V4L2_PIX_FMT_INZI,
> @@ -483,6 +487,8 @@ void CaptureWinGLEngine::changeShader()
>  	case V4L2_PIX_FMT_XYUV32:
>  	case V4L2_PIX_FMT_VUYA32:
>  	case V4L2_PIX_FMT_VUYX32:
> +	case V4L2_PIX_FMT_YUVA32:
> +	case V4L2_PIX_FMT_YUVX32:
>  		shader_YUV_packed(m_frameFormat);
>  		break;
>  
> @@ -651,6 +657,8 @@ void CaptureWinGLEngine::paintGL()
>  	case V4L2_PIX_FMT_XYUV32:
>  	case V4L2_PIX_FMT_VUYA32:
>  	case V4L2_PIX_FMT_VUYX32:
> +	case V4L2_PIX_FMT_YUVA32:
> +	case V4L2_PIX_FMT_YUVX32:
>  		render_YUV_packed(m_frameFormat);
>  		break;
>  
> @@ -2100,6 +2108,13 @@ void CaptureWinGLEngine::shader_YUV_packed(__u32 format)
>  		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, m_frameWidth, m_frameHeight, 0,
>  			     GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, NULL);
>  		break;
> +	case V4L2_PIX_FMT_YUVA32:
> +		hasAlpha = true;
> +		// fall-through
> +	case V4L2_PIX_FMT_YUVX32:
> +		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, m_frameWidth, m_frameHeight, 0,
> +			     GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
> +		break;
>  	}
>  
>  	checkError("Packed YUV shader");
> @@ -2173,6 +2188,8 @@ void CaptureWinGLEngine::render_YUV_packed(__u32 format)
>  		break;
>  	case V4L2_PIX_FMT_VUYA32:
>  	case V4L2_PIX_FMT_VUYX32:
> +	case V4L2_PIX_FMT_YUVA32:
> +	case V4L2_PIX_FMT_YUVX32:
>  		glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_frameWidth, m_frameHeight,
>  				GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, m_frameData);
>  		break;
> diff --git a/utils/qv4l2/qv4l2.cpp b/utils/qv4l2/qv4l2.cpp
> index d9141ad1372d..4cbaa98e0ee0 100644
> --- a/utils/qv4l2/qv4l2.cpp
> +++ b/utils/qv4l2/qv4l2.cpp
> @@ -1567,12 +1567,14 @@ void ApplicationWindow::capStart(bool start)
>  	case V4L2_PIX_FMT_YUV32:
>  	case V4L2_PIX_FMT_XYUV32:
>  	case V4L2_PIX_FMT_VUYX32:
> +	case V4L2_PIX_FMT_YUVX32:
>  		dstFmt = QImage::Format_RGB32;
>  		break;
>  	case V4L2_PIX_FMT_ARGB32:
>  	case V4L2_PIX_FMT_ABGR32:
>  	case V4L2_PIX_FMT_AYUV32:
>  	case V4L2_PIX_FMT_VUYA32:
> +	case V4L2_PIX_FMT_YUVA32:
>  		dstFmt = QImage::Format_ARGB32;
>  		break;
>  	case V4L2_PIX_FMT_INZI:
> diff --git a/utils/qvidcap/capture.cpp b/utils/qvidcap/capture.cpp
> index cfcbb89660e5..0b4c4115cf1b 100644
> --- a/utils/qvidcap/capture.cpp
> +++ b/utils/qvidcap/capture.cpp
> @@ -57,6 +57,8 @@ const __u32 formats[] = {
>  	V4L2_PIX_FMT_XYUV32,
>  	V4L2_PIX_FMT_VUYA32,
>  	V4L2_PIX_FMT_VUYX32,
> +	V4L2_PIX_FMT_YUVA32,
> +	V4L2_PIX_FMT_YUVX32,
>  	V4L2_PIX_FMT_RGB32,
>  	V4L2_PIX_FMT_XRGB32,
>  	V4L2_PIX_FMT_ARGB32,
> @@ -882,6 +884,8 @@ bool CaptureWin::updateV4LFormat(const cv4l_fmt &fmt)
>  	case V4L2_PIX_FMT_XYUV32:
>  	case V4L2_PIX_FMT_VUYA32:
>  	case V4L2_PIX_FMT_VUYX32:
> +	case V4L2_PIX_FMT_YUVA32:
> +	case V4L2_PIX_FMT_YUVX32:
>  		m_is_rgb = false;
>  		m_accepts_srgb = false;
>  		break;
> diff --git a/utils/qvidcap/paint.cpp b/utils/qvidcap/paint.cpp
> index 745e40031149..c5aadb09ffa4 100644
> --- a/utils/qvidcap/paint.cpp
> +++ b/utils/qvidcap/paint.cpp
> @@ -159,6 +159,8 @@ void CaptureWin::paintGL()
>  	case V4L2_PIX_FMT_XYUV32:
>  	case V4L2_PIX_FMT_VUYA32:
>  	case V4L2_PIX_FMT_VUYX32:
> +	case V4L2_PIX_FMT_YUVA32:
> +	case V4L2_PIX_FMT_YUVX32:
>  		render_YUV_packed(m_v4l_fmt.g_pixelformat());
>  		break;
>  
> @@ -355,6 +357,8 @@ static const struct define defines[] = {
>  	DEF(V4L2_PIX_FMT_XYUV32),
>  	DEF(V4L2_PIX_FMT_VUYA32),
>  	DEF(V4L2_PIX_FMT_VUYX32),
> +	DEF(V4L2_PIX_FMT_YUVA32),
> +	DEF(V4L2_PIX_FMT_YUVX32),
>  	DEF(V4L2_PIX_FMT_RGB32),
>  	DEF(V4L2_PIX_FMT_XRGB32),
>  	DEF(V4L2_PIX_FMT_ARGB32),
> @@ -595,6 +599,8 @@ void CaptureWin::changeShader()
>  	case V4L2_PIX_FMT_XYUV32:
>  	case V4L2_PIX_FMT_VUYA32:
>  	case V4L2_PIX_FMT_VUYX32:
> +	case V4L2_PIX_FMT_YUVA32:
> +	case V4L2_PIX_FMT_YUVX32:
>  		shader_YUV_packed();
>  		break;
>  
> @@ -945,6 +951,8 @@ void CaptureWin::shader_YUV_packed()
>  	case V4L2_PIX_FMT_XYUV32:
>  	case V4L2_PIX_FMT_VUYA32:
>  	case V4L2_PIX_FMT_VUYX32:
> +	case V4L2_PIX_FMT_YUVA32:
> +	case V4L2_PIX_FMT_YUVX32:
>  		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, m_v4l_fmt.g_width(), m_v4l_fmt.g_height(), 0,
>  			     GL_RGBA, GL_UNSIGNED_BYTE, NULL);
>  		break;
> @@ -1310,6 +1318,8 @@ void CaptureWin::render_YUV_packed(__u32 format)
>  	case V4L2_PIX_FMT_XYUV32:
>  	case V4L2_PIX_FMT_VUYA32:
>  	case V4L2_PIX_FMT_VUYX32:
> +	case V4L2_PIX_FMT_YUVA32:
> +	case V4L2_PIX_FMT_YUVX32:
>  		glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_v4l_fmt.g_width(), m_v4l_fmt.g_height(),
>  				GL_RGBA, GL_UNSIGNED_BYTE, m_curData[0]);
>  		break;
> diff --git a/utils/qvidcap/v4l2-convert.glsl b/utils/qvidcap/v4l2-convert.glsl
> index 458901c43838..8bd5694b3165 100644
> --- a/utils/qvidcap/v4l2-convert.glsl
> +++ b/utils/qvidcap/v4l2-convert.glsl
> @@ -292,6 +292,12 @@ void main()
>  	yuv.r = color.b;
>  	yuv.g = color.g;
>  	yuv.b = color.r;
> +#elif PIXFMT == V4L2_PIX_FMT_YUVA32 || PIXFMT == V4L2_PIX_FMT_YUVX32
> +	vec4 color = texture(tex, xy);
> +#if PIXFMT == V4L2_PIX_FMT_YUVA32
> +	alpha = color.a;
> +#endif
> +	yuv = color.rgb;
>  #elif PIXFMT == V4L2_PIX_FMT_YUV565
>  	yuv = texture(tex, xy).rgb;
>  #elif PIXFMT == V4L2_PIX_FMT_YUV422P || PIXFMT == V4L2_PIX_FMT_YUV420 || PIXFMT == V4L2_PIX_FMT_YVU420 || \
> diff --git a/utils/v4l2-compliance/v4l2-test-colors.cpp b/utils/v4l2-compliance/v4l2-test-colors.cpp
> index 887b2fd418d7..87bf0cd7f3ab 100644
> --- a/utils/v4l2-compliance/v4l2-test-colors.cpp
> +++ b/utils/v4l2-compliance/v4l2-test-colors.cpp
> @@ -200,6 +200,8 @@ static void getColor(const cv4l_fmt &fmt, __u8 * const planes[3],
>  		break;
>  	case V4L2_PIX_FMT_RGBX32:
>  	case V4L2_PIX_FMT_RGBA32:
> +	case V4L2_PIX_FMT_YUVA32:
> +	case V4L2_PIX_FMT_YUVX32:
>  		v32 = p8[4 * x + 2] + (p8[4 * x + 1] << 8) +
>  		      (p8[4 * x] << 16) + (p8[4 * x + 3] << 24);
>  		break;
> @@ -386,6 +388,8 @@ static void getColor(const cv4l_fmt &fmt, __u8 * const planes[3],
>  	case V4L2_PIX_FMT_XYUV32:
>  	case V4L2_PIX_FMT_VUYA32:
>  	case V4L2_PIX_FMT_VUYX32:
> +	case V4L2_PIX_FMT_YUVA32:
> +	case V4L2_PIX_FMT_YUVX32:
>  	case V4L2_PIX_FMT_YUYV:
>  	case V4L2_PIX_FMT_UYVY:
>  	case V4L2_PIX_FMT_YVYU:
> diff --git a/utils/v4l2-ctl/v4l2-ctl.cpp b/utils/v4l2-ctl/v4l2-ctl.cpp
> index 6bf0a1c7d201..577cf37ec901 100644
> --- a/utils/v4l2-ctl/v4l2-ctl.cpp
> +++ b/utils/v4l2-ctl/v4l2-ctl.cpp
> @@ -345,6 +345,8 @@ static bool is_rgb_or_hsv(__u32 pixelformat)
>  	case V4L2_PIX_FMT_XYUV32:
>  	case V4L2_PIX_FMT_VUYA32:
>  	case V4L2_PIX_FMT_VUYX32:
> +	case V4L2_PIX_FMT_YUVA32:
> +	case V4L2_PIX_FMT_YUVX32:
>  	case V4L2_PIX_FMT_YUV410:
>  	case V4L2_PIX_FMT_YUV420:
>  	case V4L2_PIX_FMT_HI240:
Laurent Pinchart July 4, 2022, 6:23 p.m. UTC | #2
Hi Hans,

On Mon, Jul 04, 2022 at 01:08:04PM +0200, Hans Verkuil wrote:
> On 6/30/22 11:29, Laurent Pinchart wrote:
> > Add support for the V4L2_PIX_FMT_YUVA32 and V4L2_PIX_FMT_YUVX32 pixel
> > formats in the v4l2-ctl, v4l2-compliance, qvidcap and qv4l2 utilities.
> > 
> > Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > ---
> > This patch depends on the addition of the new YUVA32 and YUVX32 pixel
> > formats to the kernel, which I plan to post a pull request for in the
> > near future.
> > 
> > While working on this, I've noticed what could be a bug in the qv4l2 GL
> > shaders. It seems to me that at least the V4L2_PIX_FMT_VUYA32 and
> > V4L2_PIX_FMT_VUYX32 formats are not correctly handled. Hans, could you
> > have a look at this ?
> 
> It looks good to me. Do you actually see something wrong? I've tested with
> vivid and qv4l2, but you may be testing with another driver.

I haven't tested it, only read the code. Here's how the texture is
configured, first in CaptureWinGLEngine::shader_YUV_packed():

        case V4L2_PIX_FMT_AYUV32:
                hasAlpha = true;
                // fall-through
        case V4L2_PIX_FMT_YUV32:
        case V4L2_PIX_FMT_XYUV32:
                glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, m_frameWidth, m_frameHeight, 0,
                             GL_BGRA, GL_UNSIGNED_INT_8_8_8_8, NULL);
                break;
        case V4L2_PIX_FMT_VUYA32:
                hasAlpha = true;
                // fall-through
        case V4L2_PIX_FMT_VUYX32:
                glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, m_frameWidth, m_frameHeight, 0,
                             GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, NULL);
                break;

And then in CaptureWinGLEngine::render_YUV_packed():

        case V4L2_PIX_FMT_YUV32:
        case V4L2_PIX_FMT_AYUV32:
        case V4L2_PIX_FMT_XYUV32:
                glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_frameWidth, m_frameHeight,
                                GL_BGRA, GL_UNSIGNED_INT_8_8_8_8, m_frameData);
                break;
        case V4L2_PIX_FMT_VUYA32:
        case V4L2_PIX_FMT_VUYX32:
                glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_frameWidth, m_frameHeight,
                                GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, m_frameData);
                break;

So, as far as I understand, for V4L2_PIX_FMT_VUYA32, the combination of
GL_BGRA and GL_UNSIGNED_INT_8_8_8_8_REV specify the components order in
memory as A, R, G, B (BGRA reversed). This thus map

V -> A
U -> R
Y -> G
A -> B

But he shader unconditionally maps the components as follows:

        codeHead += "   float y = color.r;"
                    "   float u = color.g - 0.5;"
                    "   float v = color.b - 0.5;";

What am I missing ?

> > ---
> >  utils/qv4l2/capture-win-gl.cpp             | 17 +++++++++++++++++
> >  utils/qv4l2/qv4l2.cpp                      |  2 ++
> >  utils/qvidcap/capture.cpp                  |  4 ++++
> >  utils/qvidcap/paint.cpp                    | 10 ++++++++++
> >  utils/qvidcap/v4l2-convert.glsl            |  6 ++++++
> >  utils/v4l2-compliance/v4l2-test-colors.cpp |  4 ++++
> >  utils/v4l2-ctl/v4l2-ctl.cpp                |  2 ++
> >  7 files changed, 45 insertions(+)
> > 
> > diff --git a/utils/qv4l2/capture-win-gl.cpp b/utils/qv4l2/capture-win-gl.cpp
> > index 05659259d42f..6cbeb426b6ba 100644
> > --- a/utils/qv4l2/capture-win-gl.cpp
> > +++ b/utils/qv4l2/capture-win-gl.cpp
> > @@ -196,6 +196,8 @@ void CaptureWinGLEngine::setColorspace(unsigned colorspace, unsigned xfer_func,
> >  	case V4L2_PIX_FMT_XYUV32:
> >  	case V4L2_PIX_FMT_VUYA32:
> >  	case V4L2_PIX_FMT_VUYX32:
> > +	case V4L2_PIX_FMT_YUVA32:
> > +	case V4L2_PIX_FMT_YUVX32:
> >  	case V4L2_PIX_FMT_HSV24:
> >  	case V4L2_PIX_FMT_HSV32:
> >  		is_rgb = false;
> > @@ -415,6 +417,8 @@ bool CaptureWinGLEngine::hasNativeFormat(__u32 format)
> >  		V4L2_PIX_FMT_XYUV32,
> >  		V4L2_PIX_FMT_VUYA32,
> >  		V4L2_PIX_FMT_VUYX32,
> > +		V4L2_PIX_FMT_YUVA32,
> > +		V4L2_PIX_FMT_YUVX32,
> >  		V4L2_PIX_FMT_GREY,
> >  		V4L2_PIX_FMT_Z16,
> >  		V4L2_PIX_FMT_INZI,
> > @@ -483,6 +487,8 @@ void CaptureWinGLEngine::changeShader()
> >  	case V4L2_PIX_FMT_XYUV32:
> >  	case V4L2_PIX_FMT_VUYA32:
> >  	case V4L2_PIX_FMT_VUYX32:
> > +	case V4L2_PIX_FMT_YUVA32:
> > +	case V4L2_PIX_FMT_YUVX32:
> >  		shader_YUV_packed(m_frameFormat);
> >  		break;
> >  
> > @@ -651,6 +657,8 @@ void CaptureWinGLEngine::paintGL()
> >  	case V4L2_PIX_FMT_XYUV32:
> >  	case V4L2_PIX_FMT_VUYA32:
> >  	case V4L2_PIX_FMT_VUYX32:
> > +	case V4L2_PIX_FMT_YUVA32:
> > +	case V4L2_PIX_FMT_YUVX32:
> >  		render_YUV_packed(m_frameFormat);
> >  		break;
> >  
> > @@ -2100,6 +2108,13 @@ void CaptureWinGLEngine::shader_YUV_packed(__u32 format)
> >  		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, m_frameWidth, m_frameHeight, 0,
> >  			     GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, NULL);
> >  		break;
> > +	case V4L2_PIX_FMT_YUVA32:
> > +		hasAlpha = true;
> > +		// fall-through
> > +	case V4L2_PIX_FMT_YUVX32:
> > +		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, m_frameWidth, m_frameHeight, 0,
> > +			     GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
> > +		break;
> >  	}
> >  
> >  	checkError("Packed YUV shader");
> > @@ -2173,6 +2188,8 @@ void CaptureWinGLEngine::render_YUV_packed(__u32 format)
> >  		break;
> >  	case V4L2_PIX_FMT_VUYA32:
> >  	case V4L2_PIX_FMT_VUYX32:
> > +	case V4L2_PIX_FMT_YUVA32:
> > +	case V4L2_PIX_FMT_YUVX32:
> >  		glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_frameWidth, m_frameHeight,
> >  				GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, m_frameData);
> >  		break;
> > diff --git a/utils/qv4l2/qv4l2.cpp b/utils/qv4l2/qv4l2.cpp
> > index d9141ad1372d..4cbaa98e0ee0 100644
> > --- a/utils/qv4l2/qv4l2.cpp
> > +++ b/utils/qv4l2/qv4l2.cpp
> > @@ -1567,12 +1567,14 @@ void ApplicationWindow::capStart(bool start)
> >  	case V4L2_PIX_FMT_YUV32:
> >  	case V4L2_PIX_FMT_XYUV32:
> >  	case V4L2_PIX_FMT_VUYX32:
> > +	case V4L2_PIX_FMT_YUVX32:
> >  		dstFmt = QImage::Format_RGB32;
> >  		break;
> >  	case V4L2_PIX_FMT_ARGB32:
> >  	case V4L2_PIX_FMT_ABGR32:
> >  	case V4L2_PIX_FMT_AYUV32:
> >  	case V4L2_PIX_FMT_VUYA32:
> > +	case V4L2_PIX_FMT_YUVA32:
> >  		dstFmt = QImage::Format_ARGB32;
> >  		break;
> >  	case V4L2_PIX_FMT_INZI:
> > diff --git a/utils/qvidcap/capture.cpp b/utils/qvidcap/capture.cpp
> > index cfcbb89660e5..0b4c4115cf1b 100644
> > --- a/utils/qvidcap/capture.cpp
> > +++ b/utils/qvidcap/capture.cpp
> > @@ -57,6 +57,8 @@ const __u32 formats[] = {
> >  	V4L2_PIX_FMT_XYUV32,
> >  	V4L2_PIX_FMT_VUYA32,
> >  	V4L2_PIX_FMT_VUYX32,
> > +	V4L2_PIX_FMT_YUVA32,
> > +	V4L2_PIX_FMT_YUVX32,
> >  	V4L2_PIX_FMT_RGB32,
> >  	V4L2_PIX_FMT_XRGB32,
> >  	V4L2_PIX_FMT_ARGB32,
> > @@ -882,6 +884,8 @@ bool CaptureWin::updateV4LFormat(const cv4l_fmt &fmt)
> >  	case V4L2_PIX_FMT_XYUV32:
> >  	case V4L2_PIX_FMT_VUYA32:
> >  	case V4L2_PIX_FMT_VUYX32:
> > +	case V4L2_PIX_FMT_YUVA32:
> > +	case V4L2_PIX_FMT_YUVX32:
> >  		m_is_rgb = false;
> >  		m_accepts_srgb = false;
> >  		break;
> > diff --git a/utils/qvidcap/paint.cpp b/utils/qvidcap/paint.cpp
> > index 745e40031149..c5aadb09ffa4 100644
> > --- a/utils/qvidcap/paint.cpp
> > +++ b/utils/qvidcap/paint.cpp
> > @@ -159,6 +159,8 @@ void CaptureWin::paintGL()
> >  	case V4L2_PIX_FMT_XYUV32:
> >  	case V4L2_PIX_FMT_VUYA32:
> >  	case V4L2_PIX_FMT_VUYX32:
> > +	case V4L2_PIX_FMT_YUVA32:
> > +	case V4L2_PIX_FMT_YUVX32:
> >  		render_YUV_packed(m_v4l_fmt.g_pixelformat());
> >  		break;
> >  
> > @@ -355,6 +357,8 @@ static const struct define defines[] = {
> >  	DEF(V4L2_PIX_FMT_XYUV32),
> >  	DEF(V4L2_PIX_FMT_VUYA32),
> >  	DEF(V4L2_PIX_FMT_VUYX32),
> > +	DEF(V4L2_PIX_FMT_YUVA32),
> > +	DEF(V4L2_PIX_FMT_YUVX32),
> >  	DEF(V4L2_PIX_FMT_RGB32),
> >  	DEF(V4L2_PIX_FMT_XRGB32),
> >  	DEF(V4L2_PIX_FMT_ARGB32),
> > @@ -595,6 +599,8 @@ void CaptureWin::changeShader()
> >  	case V4L2_PIX_FMT_XYUV32:
> >  	case V4L2_PIX_FMT_VUYA32:
> >  	case V4L2_PIX_FMT_VUYX32:
> > +	case V4L2_PIX_FMT_YUVA32:
> > +	case V4L2_PIX_FMT_YUVX32:
> >  		shader_YUV_packed();
> >  		break;
> >  
> > @@ -945,6 +951,8 @@ void CaptureWin::shader_YUV_packed()
> >  	case V4L2_PIX_FMT_XYUV32:
> >  	case V4L2_PIX_FMT_VUYA32:
> >  	case V4L2_PIX_FMT_VUYX32:
> > +	case V4L2_PIX_FMT_YUVA32:
> > +	case V4L2_PIX_FMT_YUVX32:
> >  		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, m_v4l_fmt.g_width(), m_v4l_fmt.g_height(), 0,
> >  			     GL_RGBA, GL_UNSIGNED_BYTE, NULL);
> >  		break;
> > @@ -1310,6 +1318,8 @@ void CaptureWin::render_YUV_packed(__u32 format)
> >  	case V4L2_PIX_FMT_XYUV32:
> >  	case V4L2_PIX_FMT_VUYA32:
> >  	case V4L2_PIX_FMT_VUYX32:
> > +	case V4L2_PIX_FMT_YUVA32:
> > +	case V4L2_PIX_FMT_YUVX32:
> >  		glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_v4l_fmt.g_width(), m_v4l_fmt.g_height(),
> >  				GL_RGBA, GL_UNSIGNED_BYTE, m_curData[0]);
> >  		break;
> > diff --git a/utils/qvidcap/v4l2-convert.glsl b/utils/qvidcap/v4l2-convert.glsl
> > index 458901c43838..8bd5694b3165 100644
> > --- a/utils/qvidcap/v4l2-convert.glsl
> > +++ b/utils/qvidcap/v4l2-convert.glsl
> > @@ -292,6 +292,12 @@ void main()
> >  	yuv.r = color.b;
> >  	yuv.g = color.g;
> >  	yuv.b = color.r;
> > +#elif PIXFMT == V4L2_PIX_FMT_YUVA32 || PIXFMT == V4L2_PIX_FMT_YUVX32
> > +	vec4 color = texture(tex, xy);
> > +#if PIXFMT == V4L2_PIX_FMT_YUVA32
> > +	alpha = color.a;
> > +#endif
> > +	yuv = color.rgb;
> >  #elif PIXFMT == V4L2_PIX_FMT_YUV565
> >  	yuv = texture(tex, xy).rgb;
> >  #elif PIXFMT == V4L2_PIX_FMT_YUV422P || PIXFMT == V4L2_PIX_FMT_YUV420 || PIXFMT == V4L2_PIX_FMT_YVU420 || \
> > diff --git a/utils/v4l2-compliance/v4l2-test-colors.cpp b/utils/v4l2-compliance/v4l2-test-colors.cpp
> > index 887b2fd418d7..87bf0cd7f3ab 100644
> > --- a/utils/v4l2-compliance/v4l2-test-colors.cpp
> > +++ b/utils/v4l2-compliance/v4l2-test-colors.cpp
> > @@ -200,6 +200,8 @@ static void getColor(const cv4l_fmt &fmt, __u8 * const planes[3],
> >  		break;
> >  	case V4L2_PIX_FMT_RGBX32:
> >  	case V4L2_PIX_FMT_RGBA32:
> > +	case V4L2_PIX_FMT_YUVA32:
> > +	case V4L2_PIX_FMT_YUVX32:
> >  		v32 = p8[4 * x + 2] + (p8[4 * x + 1] << 8) +
> >  		      (p8[4 * x] << 16) + (p8[4 * x + 3] << 24);
> >  		break;
> > @@ -386,6 +388,8 @@ static void getColor(const cv4l_fmt &fmt, __u8 * const planes[3],
> >  	case V4L2_PIX_FMT_XYUV32:
> >  	case V4L2_PIX_FMT_VUYA32:
> >  	case V4L2_PIX_FMT_VUYX32:
> > +	case V4L2_PIX_FMT_YUVA32:
> > +	case V4L2_PIX_FMT_YUVX32:
> >  	case V4L2_PIX_FMT_YUYV:
> >  	case V4L2_PIX_FMT_UYVY:
> >  	case V4L2_PIX_FMT_YVYU:
> > diff --git a/utils/v4l2-ctl/v4l2-ctl.cpp b/utils/v4l2-ctl/v4l2-ctl.cpp
> > index 6bf0a1c7d201..577cf37ec901 100644
> > --- a/utils/v4l2-ctl/v4l2-ctl.cpp
> > +++ b/utils/v4l2-ctl/v4l2-ctl.cpp
> > @@ -345,6 +345,8 @@ static bool is_rgb_or_hsv(__u32 pixelformat)
> >  	case V4L2_PIX_FMT_XYUV32:
> >  	case V4L2_PIX_FMT_VUYA32:
> >  	case V4L2_PIX_FMT_VUYX32:
> > +	case V4L2_PIX_FMT_YUVA32:
> > +	case V4L2_PIX_FMT_YUVX32:
> >  	case V4L2_PIX_FMT_YUV410:
> >  	case V4L2_PIX_FMT_YUV420:
> >  	case V4L2_PIX_FMT_HI240:
Hans Verkuil July 4, 2022, 6:49 p.m. UTC | #3
On 7/4/22 20:23, Laurent Pinchart wrote:
> Hi Hans,
> 
> On Mon, Jul 04, 2022 at 01:08:04PM +0200, Hans Verkuil wrote:
>> On 6/30/22 11:29, Laurent Pinchart wrote:
>>> Add support for the V4L2_PIX_FMT_YUVA32 and V4L2_PIX_FMT_YUVX32 pixel
>>> formats in the v4l2-ctl, v4l2-compliance, qvidcap and qv4l2 utilities.
>>>
>>> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
>>> ---
>>> This patch depends on the addition of the new YUVA32 and YUVX32 pixel
>>> formats to the kernel, which I plan to post a pull request for in the
>>> near future.
>>>
>>> While working on this, I've noticed what could be a bug in the qv4l2 GL
>>> shaders. It seems to me that at least the V4L2_PIX_FMT_VUYA32 and
>>> V4L2_PIX_FMT_VUYX32 formats are not correctly handled. Hans, could you
>>> have a look at this ?
>>
>> It looks good to me. Do you actually see something wrong? I've tested with
>> vivid and qv4l2, but you may be testing with another driver.
> 
> I haven't tested it, only read the code. Here's how the texture is
> configured, first in CaptureWinGLEngine::shader_YUV_packed():
> 
>         case V4L2_PIX_FMT_AYUV32:
>                 hasAlpha = true;
>                 // fall-through
>         case V4L2_PIX_FMT_YUV32:
>         case V4L2_PIX_FMT_XYUV32:
>                 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, m_frameWidth, m_frameHeight, 0,
>                              GL_BGRA, GL_UNSIGNED_INT_8_8_8_8, NULL);
>                 break;
>         case V4L2_PIX_FMT_VUYA32:
>                 hasAlpha = true;
>                 // fall-through
>         case V4L2_PIX_FMT_VUYX32:
>                 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, m_frameWidth, m_frameHeight, 0,
>                              GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, NULL);
>                 break;
> 
> And then in CaptureWinGLEngine::render_YUV_packed():
> 
>         case V4L2_PIX_FMT_YUV32:
>         case V4L2_PIX_FMT_AYUV32:
>         case V4L2_PIX_FMT_XYUV32:
>                 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_frameWidth, m_frameHeight,
>                                 GL_BGRA, GL_UNSIGNED_INT_8_8_8_8, m_frameData);
>                 break;
>         case V4L2_PIX_FMT_VUYA32:
>         case V4L2_PIX_FMT_VUYX32:
>                 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_frameWidth, m_frameHeight,
>                                 GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, m_frameData);
>                 break;
> 
> So, as far as I understand, for V4L2_PIX_FMT_VUYA32, the combination of
> GL_BGRA and GL_UNSIGNED_INT_8_8_8_8_REV specify the components order in
> memory as A, R, G, B (BGRA reversed). This thus map
> 
> V -> A
> U -> R
> Y -> G
> A -> B

VUYA is the order in memory (first byte V, second U, etc). GL_UNSIGNED_INT_8_8_8_8_REV
reads this as, effectively, big-endian order, and GL_BGRA then interprets the unsigned
int from MSB to the LSB, so:

V -> B
U -> G
Y -> R
A -> A

At least, I think that was the reason. In any case, I know it is correct, since it works
with vivid and this pixelformat.

I also strongly suspect it will be wrong on a big-endian architecture.

But yes, it is very confusing. In qvidcap I abandoned the use of GL_UNSIGNED_INT_8_8_8_8
and just use GL_UNSIGNED_BYTE. It makes it easier to understand. On of these days (hah!)
qv4l2 should start using the qvidcap openGL code.

Regards,

	Hans

> 
> But he shader unconditionally maps the components as follows:
> 
>         codeHead += "   float y = color.r;"
>                     "   float u = color.g - 0.5;"
>                     "   float v = color.b - 0.5;";
> 
> What am I missing ?
> 
>>> ---
>>>  utils/qv4l2/capture-win-gl.cpp             | 17 +++++++++++++++++
>>>  utils/qv4l2/qv4l2.cpp                      |  2 ++
>>>  utils/qvidcap/capture.cpp                  |  4 ++++
>>>  utils/qvidcap/paint.cpp                    | 10 ++++++++++
>>>  utils/qvidcap/v4l2-convert.glsl            |  6 ++++++
>>>  utils/v4l2-compliance/v4l2-test-colors.cpp |  4 ++++
>>>  utils/v4l2-ctl/v4l2-ctl.cpp                |  2 ++
>>>  7 files changed, 45 insertions(+)
>>>
>>> diff --git a/utils/qv4l2/capture-win-gl.cpp b/utils/qv4l2/capture-win-gl.cpp
>>> index 05659259d42f..6cbeb426b6ba 100644
>>> --- a/utils/qv4l2/capture-win-gl.cpp
>>> +++ b/utils/qv4l2/capture-win-gl.cpp
>>> @@ -196,6 +196,8 @@ void CaptureWinGLEngine::setColorspace(unsigned colorspace, unsigned xfer_func,
>>>  	case V4L2_PIX_FMT_XYUV32:
>>>  	case V4L2_PIX_FMT_VUYA32:
>>>  	case V4L2_PIX_FMT_VUYX32:
>>> +	case V4L2_PIX_FMT_YUVA32:
>>> +	case V4L2_PIX_FMT_YUVX32:
>>>  	case V4L2_PIX_FMT_HSV24:
>>>  	case V4L2_PIX_FMT_HSV32:
>>>  		is_rgb = false;
>>> @@ -415,6 +417,8 @@ bool CaptureWinGLEngine::hasNativeFormat(__u32 format)
>>>  		V4L2_PIX_FMT_XYUV32,
>>>  		V4L2_PIX_FMT_VUYA32,
>>>  		V4L2_PIX_FMT_VUYX32,
>>> +		V4L2_PIX_FMT_YUVA32,
>>> +		V4L2_PIX_FMT_YUVX32,
>>>  		V4L2_PIX_FMT_GREY,
>>>  		V4L2_PIX_FMT_Z16,
>>>  		V4L2_PIX_FMT_INZI,
>>> @@ -483,6 +487,8 @@ void CaptureWinGLEngine::changeShader()
>>>  	case V4L2_PIX_FMT_XYUV32:
>>>  	case V4L2_PIX_FMT_VUYA32:
>>>  	case V4L2_PIX_FMT_VUYX32:
>>> +	case V4L2_PIX_FMT_YUVA32:
>>> +	case V4L2_PIX_FMT_YUVX32:
>>>  		shader_YUV_packed(m_frameFormat);
>>>  		break;
>>>  
>>> @@ -651,6 +657,8 @@ void CaptureWinGLEngine::paintGL()
>>>  	case V4L2_PIX_FMT_XYUV32:
>>>  	case V4L2_PIX_FMT_VUYA32:
>>>  	case V4L2_PIX_FMT_VUYX32:
>>> +	case V4L2_PIX_FMT_YUVA32:
>>> +	case V4L2_PIX_FMT_YUVX32:
>>>  		render_YUV_packed(m_frameFormat);
>>>  		break;
>>>  
>>> @@ -2100,6 +2108,13 @@ void CaptureWinGLEngine::shader_YUV_packed(__u32 format)
>>>  		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, m_frameWidth, m_frameHeight, 0,
>>>  			     GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, NULL);
>>>  		break;
>>> +	case V4L2_PIX_FMT_YUVA32:
>>> +		hasAlpha = true;
>>> +		// fall-through
>>> +	case V4L2_PIX_FMT_YUVX32:
>>> +		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, m_frameWidth, m_frameHeight, 0,
>>> +			     GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
>>> +		break;
>>>  	}
>>>  
>>>  	checkError("Packed YUV shader");
>>> @@ -2173,6 +2188,8 @@ void CaptureWinGLEngine::render_YUV_packed(__u32 format)
>>>  		break;
>>>  	case V4L2_PIX_FMT_VUYA32:
>>>  	case V4L2_PIX_FMT_VUYX32:
>>> +	case V4L2_PIX_FMT_YUVA32:
>>> +	case V4L2_PIX_FMT_YUVX32:
>>>  		glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_frameWidth, m_frameHeight,
>>>  				GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, m_frameData);
>>>  		break;
>>> diff --git a/utils/qv4l2/qv4l2.cpp b/utils/qv4l2/qv4l2.cpp
>>> index d9141ad1372d..4cbaa98e0ee0 100644
>>> --- a/utils/qv4l2/qv4l2.cpp
>>> +++ b/utils/qv4l2/qv4l2.cpp
>>> @@ -1567,12 +1567,14 @@ void ApplicationWindow::capStart(bool start)
>>>  	case V4L2_PIX_FMT_YUV32:
>>>  	case V4L2_PIX_FMT_XYUV32:
>>>  	case V4L2_PIX_FMT_VUYX32:
>>> +	case V4L2_PIX_FMT_YUVX32:
>>>  		dstFmt = QImage::Format_RGB32;
>>>  		break;
>>>  	case V4L2_PIX_FMT_ARGB32:
>>>  	case V4L2_PIX_FMT_ABGR32:
>>>  	case V4L2_PIX_FMT_AYUV32:
>>>  	case V4L2_PIX_FMT_VUYA32:
>>> +	case V4L2_PIX_FMT_YUVA32:
>>>  		dstFmt = QImage::Format_ARGB32;
>>>  		break;
>>>  	case V4L2_PIX_FMT_INZI:
>>> diff --git a/utils/qvidcap/capture.cpp b/utils/qvidcap/capture.cpp
>>> index cfcbb89660e5..0b4c4115cf1b 100644
>>> --- a/utils/qvidcap/capture.cpp
>>> +++ b/utils/qvidcap/capture.cpp
>>> @@ -57,6 +57,8 @@ const __u32 formats[] = {
>>>  	V4L2_PIX_FMT_XYUV32,
>>>  	V4L2_PIX_FMT_VUYA32,
>>>  	V4L2_PIX_FMT_VUYX32,
>>> +	V4L2_PIX_FMT_YUVA32,
>>> +	V4L2_PIX_FMT_YUVX32,
>>>  	V4L2_PIX_FMT_RGB32,
>>>  	V4L2_PIX_FMT_XRGB32,
>>>  	V4L2_PIX_FMT_ARGB32,
>>> @@ -882,6 +884,8 @@ bool CaptureWin::updateV4LFormat(const cv4l_fmt &fmt)
>>>  	case V4L2_PIX_FMT_XYUV32:
>>>  	case V4L2_PIX_FMT_VUYA32:
>>>  	case V4L2_PIX_FMT_VUYX32:
>>> +	case V4L2_PIX_FMT_YUVA32:
>>> +	case V4L2_PIX_FMT_YUVX32:
>>>  		m_is_rgb = false;
>>>  		m_accepts_srgb = false;
>>>  		break;
>>> diff --git a/utils/qvidcap/paint.cpp b/utils/qvidcap/paint.cpp
>>> index 745e40031149..c5aadb09ffa4 100644
>>> --- a/utils/qvidcap/paint.cpp
>>> +++ b/utils/qvidcap/paint.cpp
>>> @@ -159,6 +159,8 @@ void CaptureWin::paintGL()
>>>  	case V4L2_PIX_FMT_XYUV32:
>>>  	case V4L2_PIX_FMT_VUYA32:
>>>  	case V4L2_PIX_FMT_VUYX32:
>>> +	case V4L2_PIX_FMT_YUVA32:
>>> +	case V4L2_PIX_FMT_YUVX32:
>>>  		render_YUV_packed(m_v4l_fmt.g_pixelformat());
>>>  		break;
>>>  
>>> @@ -355,6 +357,8 @@ static const struct define defines[] = {
>>>  	DEF(V4L2_PIX_FMT_XYUV32),
>>>  	DEF(V4L2_PIX_FMT_VUYA32),
>>>  	DEF(V4L2_PIX_FMT_VUYX32),
>>> +	DEF(V4L2_PIX_FMT_YUVA32),
>>> +	DEF(V4L2_PIX_FMT_YUVX32),
>>>  	DEF(V4L2_PIX_FMT_RGB32),
>>>  	DEF(V4L2_PIX_FMT_XRGB32),
>>>  	DEF(V4L2_PIX_FMT_ARGB32),
>>> @@ -595,6 +599,8 @@ void CaptureWin::changeShader()
>>>  	case V4L2_PIX_FMT_XYUV32:
>>>  	case V4L2_PIX_FMT_VUYA32:
>>>  	case V4L2_PIX_FMT_VUYX32:
>>> +	case V4L2_PIX_FMT_YUVA32:
>>> +	case V4L2_PIX_FMT_YUVX32:
>>>  		shader_YUV_packed();
>>>  		break;
>>>  
>>> @@ -945,6 +951,8 @@ void CaptureWin::shader_YUV_packed()
>>>  	case V4L2_PIX_FMT_XYUV32:
>>>  	case V4L2_PIX_FMT_VUYA32:
>>>  	case V4L2_PIX_FMT_VUYX32:
>>> +	case V4L2_PIX_FMT_YUVA32:
>>> +	case V4L2_PIX_FMT_YUVX32:
>>>  		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, m_v4l_fmt.g_width(), m_v4l_fmt.g_height(), 0,
>>>  			     GL_RGBA, GL_UNSIGNED_BYTE, NULL);
>>>  		break;
>>> @@ -1310,6 +1318,8 @@ void CaptureWin::render_YUV_packed(__u32 format)
>>>  	case V4L2_PIX_FMT_XYUV32:
>>>  	case V4L2_PIX_FMT_VUYA32:
>>>  	case V4L2_PIX_FMT_VUYX32:
>>> +	case V4L2_PIX_FMT_YUVA32:
>>> +	case V4L2_PIX_FMT_YUVX32:
>>>  		glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_v4l_fmt.g_width(), m_v4l_fmt.g_height(),
>>>  				GL_RGBA, GL_UNSIGNED_BYTE, m_curData[0]);
>>>  		break;
>>> diff --git a/utils/qvidcap/v4l2-convert.glsl b/utils/qvidcap/v4l2-convert.glsl
>>> index 458901c43838..8bd5694b3165 100644
>>> --- a/utils/qvidcap/v4l2-convert.glsl
>>> +++ b/utils/qvidcap/v4l2-convert.glsl
>>> @@ -292,6 +292,12 @@ void main()
>>>  	yuv.r = color.b;
>>>  	yuv.g = color.g;
>>>  	yuv.b = color.r;
>>> +#elif PIXFMT == V4L2_PIX_FMT_YUVA32 || PIXFMT == V4L2_PIX_FMT_YUVX32
>>> +	vec4 color = texture(tex, xy);
>>> +#if PIXFMT == V4L2_PIX_FMT_YUVA32
>>> +	alpha = color.a;
>>> +#endif
>>> +	yuv = color.rgb;
>>>  #elif PIXFMT == V4L2_PIX_FMT_YUV565
>>>  	yuv = texture(tex, xy).rgb;
>>>  #elif PIXFMT == V4L2_PIX_FMT_YUV422P || PIXFMT == V4L2_PIX_FMT_YUV420 || PIXFMT == V4L2_PIX_FMT_YVU420 || \
>>> diff --git a/utils/v4l2-compliance/v4l2-test-colors.cpp b/utils/v4l2-compliance/v4l2-test-colors.cpp
>>> index 887b2fd418d7..87bf0cd7f3ab 100644
>>> --- a/utils/v4l2-compliance/v4l2-test-colors.cpp
>>> +++ b/utils/v4l2-compliance/v4l2-test-colors.cpp
>>> @@ -200,6 +200,8 @@ static void getColor(const cv4l_fmt &fmt, __u8 * const planes[3],
>>>  		break;
>>>  	case V4L2_PIX_FMT_RGBX32:
>>>  	case V4L2_PIX_FMT_RGBA32:
>>> +	case V4L2_PIX_FMT_YUVA32:
>>> +	case V4L2_PIX_FMT_YUVX32:
>>>  		v32 = p8[4 * x + 2] + (p8[4 * x + 1] << 8) +
>>>  		      (p8[4 * x] << 16) + (p8[4 * x + 3] << 24);
>>>  		break;
>>> @@ -386,6 +388,8 @@ static void getColor(const cv4l_fmt &fmt, __u8 * const planes[3],
>>>  	case V4L2_PIX_FMT_XYUV32:
>>>  	case V4L2_PIX_FMT_VUYA32:
>>>  	case V4L2_PIX_FMT_VUYX32:
>>> +	case V4L2_PIX_FMT_YUVA32:
>>> +	case V4L2_PIX_FMT_YUVX32:
>>>  	case V4L2_PIX_FMT_YUYV:
>>>  	case V4L2_PIX_FMT_UYVY:
>>>  	case V4L2_PIX_FMT_YVYU:
>>> diff --git a/utils/v4l2-ctl/v4l2-ctl.cpp b/utils/v4l2-ctl/v4l2-ctl.cpp
>>> index 6bf0a1c7d201..577cf37ec901 100644
>>> --- a/utils/v4l2-ctl/v4l2-ctl.cpp
>>> +++ b/utils/v4l2-ctl/v4l2-ctl.cpp
>>> @@ -345,6 +345,8 @@ static bool is_rgb_or_hsv(__u32 pixelformat)
>>>  	case V4L2_PIX_FMT_XYUV32:
>>>  	case V4L2_PIX_FMT_VUYA32:
>>>  	case V4L2_PIX_FMT_VUYX32:
>>> +	case V4L2_PIX_FMT_YUVA32:
>>> +	case V4L2_PIX_FMT_YUVX32:
>>>  	case V4L2_PIX_FMT_YUV410:
>>>  	case V4L2_PIX_FMT_YUV420:
>>>  	case V4L2_PIX_FMT_HI240:
>
Laurent Pinchart July 4, 2022, 7:16 p.m. UTC | #4
Hi Hans,

On Mon, Jul 04, 2022 at 08:49:28PM +0200, Hans Verkuil wrote:
> On 7/4/22 20:23, Laurent Pinchart wrote:
> > On Mon, Jul 04, 2022 at 01:08:04PM +0200, Hans Verkuil wrote:
> >> On 6/30/22 11:29, Laurent Pinchart wrote:
> >>> Add support for the V4L2_PIX_FMT_YUVA32 and V4L2_PIX_FMT_YUVX32 pixel
> >>> formats in the v4l2-ctl, v4l2-compliance, qvidcap and qv4l2 utilities.
> >>>
> >>> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> >>> ---
> >>> This patch depends on the addition of the new YUVA32 and YUVX32 pixel
> >>> formats to the kernel, which I plan to post a pull request for in the
> >>> near future.
> >>>
> >>> While working on this, I've noticed what could be a bug in the qv4l2 GL
> >>> shaders. It seems to me that at least the V4L2_PIX_FMT_VUYA32 and
> >>> V4L2_PIX_FMT_VUYX32 formats are not correctly handled. Hans, could you
> >>> have a look at this ?
> >>
> >> It looks good to me. Do you actually see something wrong? I've tested with
> >> vivid and qv4l2, but you may be testing with another driver.
> > 
> > I haven't tested it, only read the code. Here's how the texture is
> > configured, first in CaptureWinGLEngine::shader_YUV_packed():
> > 
> >         case V4L2_PIX_FMT_AYUV32:
> >                 hasAlpha = true;
> >                 // fall-through
> >         case V4L2_PIX_FMT_YUV32:
> >         case V4L2_PIX_FMT_XYUV32:
> >                 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, m_frameWidth, m_frameHeight, 0,
> >                              GL_BGRA, GL_UNSIGNED_INT_8_8_8_8, NULL);
> >                 break;
> >         case V4L2_PIX_FMT_VUYA32:
> >                 hasAlpha = true;
> >                 // fall-through
> >         case V4L2_PIX_FMT_VUYX32:
> >                 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, m_frameWidth, m_frameHeight, 0,
> >                              GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, NULL);
> >                 break;
> > 
> > And then in CaptureWinGLEngine::render_YUV_packed():
> > 
> >         case V4L2_PIX_FMT_YUV32:
> >         case V4L2_PIX_FMT_AYUV32:
> >         case V4L2_PIX_FMT_XYUV32:
> >                 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_frameWidth, m_frameHeight,
> >                                 GL_BGRA, GL_UNSIGNED_INT_8_8_8_8, m_frameData);
> >                 break;
> >         case V4L2_PIX_FMT_VUYA32:
> >         case V4L2_PIX_FMT_VUYX32:
> >                 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_frameWidth, m_frameHeight,
> >                                 GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, m_frameData);
> >                 break;
> > 
> > So, as far as I understand, for V4L2_PIX_FMT_VUYA32, the combination of
> > GL_BGRA and GL_UNSIGNED_INT_8_8_8_8_REV specify the components order in
> > memory as A, R, G, B (BGRA reversed). This thus map
> > 
> > V -> A
> > U -> R
> > Y -> G
> > A -> B
> 
> VUYA is the order in memory (first byte V, second U, etc). GL_UNSIGNED_INT_8_8_8_8_REV
> reads this as, effectively, big-endian order, and GL_BGRA then interprets the unsigned
> int from MSB to the LSB, so:
> 
> V -> B
> U -> G
> Y -> R
> A -> A
> 
> At least, I think that was the reason. In any case, I know it is correct, since it works
> with vivid and this pixelformat.

You're right, now that I re-read this, I wonder how I got it wrong.

By the way, is there a reason why glTexImage2D() uses GL_RGBA and
GL_UNSIGNED_INT_8_8_8_8 while glTexSubImage2D() uses GL_BGRA and
GL_UNSIGNED_INT_8_8_8_8_REV ?

> I also strongly suspect it will be wrong on a big-endian architecture.
> 
> But yes, it is very confusing. In qvidcap I abandoned the use of GL_UNSIGNED_INT_8_8_8_8
> and just use GL_UNSIGNED_BYTE. It makes it easier to understand. On of these days (hah!)
> qv4l2 should start using the qvidcap openGL code.

The code in qvidcap is a bit nicer indeed, and also more compatible with
OpenGL ES 2.0. Many open-source GPU drivers for embedded devices will
have trouble with qv4l2.

> > But he shader unconditionally maps the components as follows:
> > 
> >         codeHead += "   float y = color.r;"
> >                     "   float u = color.g - 0.5;"
> >                     "   float v = color.b - 0.5;";
> > 
> > What am I missing ?
> > 
> >>> ---
> >>>  utils/qv4l2/capture-win-gl.cpp             | 17 +++++++++++++++++
> >>>  utils/qv4l2/qv4l2.cpp                      |  2 ++
> >>>  utils/qvidcap/capture.cpp                  |  4 ++++
> >>>  utils/qvidcap/paint.cpp                    | 10 ++++++++++
> >>>  utils/qvidcap/v4l2-convert.glsl            |  6 ++++++
> >>>  utils/v4l2-compliance/v4l2-test-colors.cpp |  4 ++++
> >>>  utils/v4l2-ctl/v4l2-ctl.cpp                |  2 ++
> >>>  7 files changed, 45 insertions(+)
> >>>
> >>> diff --git a/utils/qv4l2/capture-win-gl.cpp b/utils/qv4l2/capture-win-gl.cpp
> >>> index 05659259d42f..6cbeb426b6ba 100644
> >>> --- a/utils/qv4l2/capture-win-gl.cpp
> >>> +++ b/utils/qv4l2/capture-win-gl.cpp
> >>> @@ -196,6 +196,8 @@ void CaptureWinGLEngine::setColorspace(unsigned colorspace, unsigned xfer_func,
> >>>  	case V4L2_PIX_FMT_XYUV32:
> >>>  	case V4L2_PIX_FMT_VUYA32:
> >>>  	case V4L2_PIX_FMT_VUYX32:
> >>> +	case V4L2_PIX_FMT_YUVA32:
> >>> +	case V4L2_PIX_FMT_YUVX32:
> >>>  	case V4L2_PIX_FMT_HSV24:
> >>>  	case V4L2_PIX_FMT_HSV32:
> >>>  		is_rgb = false;
> >>> @@ -415,6 +417,8 @@ bool CaptureWinGLEngine::hasNativeFormat(__u32 format)
> >>>  		V4L2_PIX_FMT_XYUV32,
> >>>  		V4L2_PIX_FMT_VUYA32,
> >>>  		V4L2_PIX_FMT_VUYX32,
> >>> +		V4L2_PIX_FMT_YUVA32,
> >>> +		V4L2_PIX_FMT_YUVX32,
> >>>  		V4L2_PIX_FMT_GREY,
> >>>  		V4L2_PIX_FMT_Z16,
> >>>  		V4L2_PIX_FMT_INZI,
> >>> @@ -483,6 +487,8 @@ void CaptureWinGLEngine::changeShader()
> >>>  	case V4L2_PIX_FMT_XYUV32:
> >>>  	case V4L2_PIX_FMT_VUYA32:
> >>>  	case V4L2_PIX_FMT_VUYX32:
> >>> +	case V4L2_PIX_FMT_YUVA32:
> >>> +	case V4L2_PIX_FMT_YUVX32:
> >>>  		shader_YUV_packed(m_frameFormat);
> >>>  		break;
> >>>  
> >>> @@ -651,6 +657,8 @@ void CaptureWinGLEngine::paintGL()
> >>>  	case V4L2_PIX_FMT_XYUV32:
> >>>  	case V4L2_PIX_FMT_VUYA32:
> >>>  	case V4L2_PIX_FMT_VUYX32:
> >>> +	case V4L2_PIX_FMT_YUVA32:
> >>> +	case V4L2_PIX_FMT_YUVX32:
> >>>  		render_YUV_packed(m_frameFormat);
> >>>  		break;
> >>>  
> >>> @@ -2100,6 +2108,13 @@ void CaptureWinGLEngine::shader_YUV_packed(__u32 format)
> >>>  		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, m_frameWidth, m_frameHeight, 0,
> >>>  			     GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, NULL);
> >>>  		break;
> >>> +	case V4L2_PIX_FMT_YUVA32:
> >>> +		hasAlpha = true;
> >>> +		// fall-through
> >>> +	case V4L2_PIX_FMT_YUVX32:
> >>> +		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, m_frameWidth, m_frameHeight, 0,
> >>> +			     GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
> >>> +		break;
> >>>  	}
> >>>  
> >>>  	checkError("Packed YUV shader");
> >>> @@ -2173,6 +2188,8 @@ void CaptureWinGLEngine::render_YUV_packed(__u32 format)
> >>>  		break;
> >>>  	case V4L2_PIX_FMT_VUYA32:
> >>>  	case V4L2_PIX_FMT_VUYX32:
> >>> +	case V4L2_PIX_FMT_YUVA32:
> >>> +	case V4L2_PIX_FMT_YUVX32:
> >>>  		glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_frameWidth, m_frameHeight,
> >>>  				GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, m_frameData);
> >>>  		break;
> >>> diff --git a/utils/qv4l2/qv4l2.cpp b/utils/qv4l2/qv4l2.cpp
> >>> index d9141ad1372d..4cbaa98e0ee0 100644
> >>> --- a/utils/qv4l2/qv4l2.cpp
> >>> +++ b/utils/qv4l2/qv4l2.cpp
> >>> @@ -1567,12 +1567,14 @@ void ApplicationWindow::capStart(bool start)
> >>>  	case V4L2_PIX_FMT_YUV32:
> >>>  	case V4L2_PIX_FMT_XYUV32:
> >>>  	case V4L2_PIX_FMT_VUYX32:
> >>> +	case V4L2_PIX_FMT_YUVX32:
> >>>  		dstFmt = QImage::Format_RGB32;
> >>>  		break;
> >>>  	case V4L2_PIX_FMT_ARGB32:
> >>>  	case V4L2_PIX_FMT_ABGR32:
> >>>  	case V4L2_PIX_FMT_AYUV32:
> >>>  	case V4L2_PIX_FMT_VUYA32:
> >>> +	case V4L2_PIX_FMT_YUVA32:
> >>>  		dstFmt = QImage::Format_ARGB32;
> >>>  		break;
> >>>  	case V4L2_PIX_FMT_INZI:
> >>> diff --git a/utils/qvidcap/capture.cpp b/utils/qvidcap/capture.cpp
> >>> index cfcbb89660e5..0b4c4115cf1b 100644
> >>> --- a/utils/qvidcap/capture.cpp
> >>> +++ b/utils/qvidcap/capture.cpp
> >>> @@ -57,6 +57,8 @@ const __u32 formats[] = {
> >>>  	V4L2_PIX_FMT_XYUV32,
> >>>  	V4L2_PIX_FMT_VUYA32,
> >>>  	V4L2_PIX_FMT_VUYX32,
> >>> +	V4L2_PIX_FMT_YUVA32,
> >>> +	V4L2_PIX_FMT_YUVX32,
> >>>  	V4L2_PIX_FMT_RGB32,
> >>>  	V4L2_PIX_FMT_XRGB32,
> >>>  	V4L2_PIX_FMT_ARGB32,
> >>> @@ -882,6 +884,8 @@ bool CaptureWin::updateV4LFormat(const cv4l_fmt &fmt)
> >>>  	case V4L2_PIX_FMT_XYUV32:
> >>>  	case V4L2_PIX_FMT_VUYA32:
> >>>  	case V4L2_PIX_FMT_VUYX32:
> >>> +	case V4L2_PIX_FMT_YUVA32:
> >>> +	case V4L2_PIX_FMT_YUVX32:
> >>>  		m_is_rgb = false;
> >>>  		m_accepts_srgb = false;
> >>>  		break;
> >>> diff --git a/utils/qvidcap/paint.cpp b/utils/qvidcap/paint.cpp
> >>> index 745e40031149..c5aadb09ffa4 100644
> >>> --- a/utils/qvidcap/paint.cpp
> >>> +++ b/utils/qvidcap/paint.cpp
> >>> @@ -159,6 +159,8 @@ void CaptureWin::paintGL()
> >>>  	case V4L2_PIX_FMT_XYUV32:
> >>>  	case V4L2_PIX_FMT_VUYA32:
> >>>  	case V4L2_PIX_FMT_VUYX32:
> >>> +	case V4L2_PIX_FMT_YUVA32:
> >>> +	case V4L2_PIX_FMT_YUVX32:
> >>>  		render_YUV_packed(m_v4l_fmt.g_pixelformat());
> >>>  		break;
> >>>  
> >>> @@ -355,6 +357,8 @@ static const struct define defines[] = {
> >>>  	DEF(V4L2_PIX_FMT_XYUV32),
> >>>  	DEF(V4L2_PIX_FMT_VUYA32),
> >>>  	DEF(V4L2_PIX_FMT_VUYX32),
> >>> +	DEF(V4L2_PIX_FMT_YUVA32),
> >>> +	DEF(V4L2_PIX_FMT_YUVX32),
> >>>  	DEF(V4L2_PIX_FMT_RGB32),
> >>>  	DEF(V4L2_PIX_FMT_XRGB32),
> >>>  	DEF(V4L2_PIX_FMT_ARGB32),
> >>> @@ -595,6 +599,8 @@ void CaptureWin::changeShader()
> >>>  	case V4L2_PIX_FMT_XYUV32:
> >>>  	case V4L2_PIX_FMT_VUYA32:
> >>>  	case V4L2_PIX_FMT_VUYX32:
> >>> +	case V4L2_PIX_FMT_YUVA32:
> >>> +	case V4L2_PIX_FMT_YUVX32:
> >>>  		shader_YUV_packed();
> >>>  		break;
> >>>  
> >>> @@ -945,6 +951,8 @@ void CaptureWin::shader_YUV_packed()
> >>>  	case V4L2_PIX_FMT_XYUV32:
> >>>  	case V4L2_PIX_FMT_VUYA32:
> >>>  	case V4L2_PIX_FMT_VUYX32:
> >>> +	case V4L2_PIX_FMT_YUVA32:
> >>> +	case V4L2_PIX_FMT_YUVX32:
> >>>  		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, m_v4l_fmt.g_width(), m_v4l_fmt.g_height(), 0,
> >>>  			     GL_RGBA, GL_UNSIGNED_BYTE, NULL);
> >>>  		break;
> >>> @@ -1310,6 +1318,8 @@ void CaptureWin::render_YUV_packed(__u32 format)
> >>>  	case V4L2_PIX_FMT_XYUV32:
> >>>  	case V4L2_PIX_FMT_VUYA32:
> >>>  	case V4L2_PIX_FMT_VUYX32:
> >>> +	case V4L2_PIX_FMT_YUVA32:
> >>> +	case V4L2_PIX_FMT_YUVX32:
> >>>  		glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_v4l_fmt.g_width(), m_v4l_fmt.g_height(),
> >>>  				GL_RGBA, GL_UNSIGNED_BYTE, m_curData[0]);
> >>>  		break;
> >>> diff --git a/utils/qvidcap/v4l2-convert.glsl b/utils/qvidcap/v4l2-convert.glsl
> >>> index 458901c43838..8bd5694b3165 100644
> >>> --- a/utils/qvidcap/v4l2-convert.glsl
> >>> +++ b/utils/qvidcap/v4l2-convert.glsl
> >>> @@ -292,6 +292,12 @@ void main()
> >>>  	yuv.r = color.b;
> >>>  	yuv.g = color.g;
> >>>  	yuv.b = color.r;
> >>> +#elif PIXFMT == V4L2_PIX_FMT_YUVA32 || PIXFMT == V4L2_PIX_FMT_YUVX32
> >>> +	vec4 color = texture(tex, xy);
> >>> +#if PIXFMT == V4L2_PIX_FMT_YUVA32
> >>> +	alpha = color.a;
> >>> +#endif
> >>> +	yuv = color.rgb;
> >>>  #elif PIXFMT == V4L2_PIX_FMT_YUV565
> >>>  	yuv = texture(tex, xy).rgb;
> >>>  #elif PIXFMT == V4L2_PIX_FMT_YUV422P || PIXFMT == V4L2_PIX_FMT_YUV420 || PIXFMT == V4L2_PIX_FMT_YVU420 || \
> >>> diff --git a/utils/v4l2-compliance/v4l2-test-colors.cpp b/utils/v4l2-compliance/v4l2-test-colors.cpp
> >>> index 887b2fd418d7..87bf0cd7f3ab 100644
> >>> --- a/utils/v4l2-compliance/v4l2-test-colors.cpp
> >>> +++ b/utils/v4l2-compliance/v4l2-test-colors.cpp
> >>> @@ -200,6 +200,8 @@ static void getColor(const cv4l_fmt &fmt, __u8 * const planes[3],
> >>>  		break;
> >>>  	case V4L2_PIX_FMT_RGBX32:
> >>>  	case V4L2_PIX_FMT_RGBA32:
> >>> +	case V4L2_PIX_FMT_YUVA32:
> >>> +	case V4L2_PIX_FMT_YUVX32:
> >>>  		v32 = p8[4 * x + 2] + (p8[4 * x + 1] << 8) +
> >>>  		      (p8[4 * x] << 16) + (p8[4 * x + 3] << 24);
> >>>  		break;
> >>> @@ -386,6 +388,8 @@ static void getColor(const cv4l_fmt &fmt, __u8 * const planes[3],
> >>>  	case V4L2_PIX_FMT_XYUV32:
> >>>  	case V4L2_PIX_FMT_VUYA32:
> >>>  	case V4L2_PIX_FMT_VUYX32:
> >>> +	case V4L2_PIX_FMT_YUVA32:
> >>> +	case V4L2_PIX_FMT_YUVX32:
> >>>  	case V4L2_PIX_FMT_YUYV:
> >>>  	case V4L2_PIX_FMT_UYVY:
> >>>  	case V4L2_PIX_FMT_YVYU:
> >>> diff --git a/utils/v4l2-ctl/v4l2-ctl.cpp b/utils/v4l2-ctl/v4l2-ctl.cpp
> >>> index 6bf0a1c7d201..577cf37ec901 100644
> >>> --- a/utils/v4l2-ctl/v4l2-ctl.cpp
> >>> +++ b/utils/v4l2-ctl/v4l2-ctl.cpp
> >>> @@ -345,6 +345,8 @@ static bool is_rgb_or_hsv(__u32 pixelformat)
> >>>  	case V4L2_PIX_FMT_XYUV32:
> >>>  	case V4L2_PIX_FMT_VUYA32:
> >>>  	case V4L2_PIX_FMT_VUYX32:
> >>> +	case V4L2_PIX_FMT_YUVA32:
> >>> +	case V4L2_PIX_FMT_YUVX32:
> >>>  	case V4L2_PIX_FMT_YUV410:
> >>>  	case V4L2_PIX_FMT_YUV420:
> >>>  	case V4L2_PIX_FMT_HI240:
diff mbox series

Patch

diff --git a/utils/qv4l2/capture-win-gl.cpp b/utils/qv4l2/capture-win-gl.cpp
index 05659259d42f..6cbeb426b6ba 100644
--- a/utils/qv4l2/capture-win-gl.cpp
+++ b/utils/qv4l2/capture-win-gl.cpp
@@ -196,6 +196,8 @@  void CaptureWinGLEngine::setColorspace(unsigned colorspace, unsigned xfer_func,
 	case V4L2_PIX_FMT_XYUV32:
 	case V4L2_PIX_FMT_VUYA32:
 	case V4L2_PIX_FMT_VUYX32:
+	case V4L2_PIX_FMT_YUVA32:
+	case V4L2_PIX_FMT_YUVX32:
 	case V4L2_PIX_FMT_HSV24:
 	case V4L2_PIX_FMT_HSV32:
 		is_rgb = false;
@@ -415,6 +417,8 @@  bool CaptureWinGLEngine::hasNativeFormat(__u32 format)
 		V4L2_PIX_FMT_XYUV32,
 		V4L2_PIX_FMT_VUYA32,
 		V4L2_PIX_FMT_VUYX32,
+		V4L2_PIX_FMT_YUVA32,
+		V4L2_PIX_FMT_YUVX32,
 		V4L2_PIX_FMT_GREY,
 		V4L2_PIX_FMT_Z16,
 		V4L2_PIX_FMT_INZI,
@@ -483,6 +487,8 @@  void CaptureWinGLEngine::changeShader()
 	case V4L2_PIX_FMT_XYUV32:
 	case V4L2_PIX_FMT_VUYA32:
 	case V4L2_PIX_FMT_VUYX32:
+	case V4L2_PIX_FMT_YUVA32:
+	case V4L2_PIX_FMT_YUVX32:
 		shader_YUV_packed(m_frameFormat);
 		break;
 
@@ -651,6 +657,8 @@  void CaptureWinGLEngine::paintGL()
 	case V4L2_PIX_FMT_XYUV32:
 	case V4L2_PIX_FMT_VUYA32:
 	case V4L2_PIX_FMT_VUYX32:
+	case V4L2_PIX_FMT_YUVA32:
+	case V4L2_PIX_FMT_YUVX32:
 		render_YUV_packed(m_frameFormat);
 		break;
 
@@ -2100,6 +2108,13 @@  void CaptureWinGLEngine::shader_YUV_packed(__u32 format)
 		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, m_frameWidth, m_frameHeight, 0,
 			     GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, NULL);
 		break;
+	case V4L2_PIX_FMT_YUVA32:
+		hasAlpha = true;
+		// fall-through
+	case V4L2_PIX_FMT_YUVX32:
+		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, m_frameWidth, m_frameHeight, 0,
+			     GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
+		break;
 	}
 
 	checkError("Packed YUV shader");
@@ -2173,6 +2188,8 @@  void CaptureWinGLEngine::render_YUV_packed(__u32 format)
 		break;
 	case V4L2_PIX_FMT_VUYA32:
 	case V4L2_PIX_FMT_VUYX32:
+	case V4L2_PIX_FMT_YUVA32:
+	case V4L2_PIX_FMT_YUVX32:
 		glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_frameWidth, m_frameHeight,
 				GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, m_frameData);
 		break;
diff --git a/utils/qv4l2/qv4l2.cpp b/utils/qv4l2/qv4l2.cpp
index d9141ad1372d..4cbaa98e0ee0 100644
--- a/utils/qv4l2/qv4l2.cpp
+++ b/utils/qv4l2/qv4l2.cpp
@@ -1567,12 +1567,14 @@  void ApplicationWindow::capStart(bool start)
 	case V4L2_PIX_FMT_YUV32:
 	case V4L2_PIX_FMT_XYUV32:
 	case V4L2_PIX_FMT_VUYX32:
+	case V4L2_PIX_FMT_YUVX32:
 		dstFmt = QImage::Format_RGB32;
 		break;
 	case V4L2_PIX_FMT_ARGB32:
 	case V4L2_PIX_FMT_ABGR32:
 	case V4L2_PIX_FMT_AYUV32:
 	case V4L2_PIX_FMT_VUYA32:
+	case V4L2_PIX_FMT_YUVA32:
 		dstFmt = QImage::Format_ARGB32;
 		break;
 	case V4L2_PIX_FMT_INZI:
diff --git a/utils/qvidcap/capture.cpp b/utils/qvidcap/capture.cpp
index cfcbb89660e5..0b4c4115cf1b 100644
--- a/utils/qvidcap/capture.cpp
+++ b/utils/qvidcap/capture.cpp
@@ -57,6 +57,8 @@  const __u32 formats[] = {
 	V4L2_PIX_FMT_XYUV32,
 	V4L2_PIX_FMT_VUYA32,
 	V4L2_PIX_FMT_VUYX32,
+	V4L2_PIX_FMT_YUVA32,
+	V4L2_PIX_FMT_YUVX32,
 	V4L2_PIX_FMT_RGB32,
 	V4L2_PIX_FMT_XRGB32,
 	V4L2_PIX_FMT_ARGB32,
@@ -882,6 +884,8 @@  bool CaptureWin::updateV4LFormat(const cv4l_fmt &fmt)
 	case V4L2_PIX_FMT_XYUV32:
 	case V4L2_PIX_FMT_VUYA32:
 	case V4L2_PIX_FMT_VUYX32:
+	case V4L2_PIX_FMT_YUVA32:
+	case V4L2_PIX_FMT_YUVX32:
 		m_is_rgb = false;
 		m_accepts_srgb = false;
 		break;
diff --git a/utils/qvidcap/paint.cpp b/utils/qvidcap/paint.cpp
index 745e40031149..c5aadb09ffa4 100644
--- a/utils/qvidcap/paint.cpp
+++ b/utils/qvidcap/paint.cpp
@@ -159,6 +159,8 @@  void CaptureWin::paintGL()
 	case V4L2_PIX_FMT_XYUV32:
 	case V4L2_PIX_FMT_VUYA32:
 	case V4L2_PIX_FMT_VUYX32:
+	case V4L2_PIX_FMT_YUVA32:
+	case V4L2_PIX_FMT_YUVX32:
 		render_YUV_packed(m_v4l_fmt.g_pixelformat());
 		break;
 
@@ -355,6 +357,8 @@  static const struct define defines[] = {
 	DEF(V4L2_PIX_FMT_XYUV32),
 	DEF(V4L2_PIX_FMT_VUYA32),
 	DEF(V4L2_PIX_FMT_VUYX32),
+	DEF(V4L2_PIX_FMT_YUVA32),
+	DEF(V4L2_PIX_FMT_YUVX32),
 	DEF(V4L2_PIX_FMT_RGB32),
 	DEF(V4L2_PIX_FMT_XRGB32),
 	DEF(V4L2_PIX_FMT_ARGB32),
@@ -595,6 +599,8 @@  void CaptureWin::changeShader()
 	case V4L2_PIX_FMT_XYUV32:
 	case V4L2_PIX_FMT_VUYA32:
 	case V4L2_PIX_FMT_VUYX32:
+	case V4L2_PIX_FMT_YUVA32:
+	case V4L2_PIX_FMT_YUVX32:
 		shader_YUV_packed();
 		break;
 
@@ -945,6 +951,8 @@  void CaptureWin::shader_YUV_packed()
 	case V4L2_PIX_FMT_XYUV32:
 	case V4L2_PIX_FMT_VUYA32:
 	case V4L2_PIX_FMT_VUYX32:
+	case V4L2_PIX_FMT_YUVA32:
+	case V4L2_PIX_FMT_YUVX32:
 		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, m_v4l_fmt.g_width(), m_v4l_fmt.g_height(), 0,
 			     GL_RGBA, GL_UNSIGNED_BYTE, NULL);
 		break;
@@ -1310,6 +1318,8 @@  void CaptureWin::render_YUV_packed(__u32 format)
 	case V4L2_PIX_FMT_XYUV32:
 	case V4L2_PIX_FMT_VUYA32:
 	case V4L2_PIX_FMT_VUYX32:
+	case V4L2_PIX_FMT_YUVA32:
+	case V4L2_PIX_FMT_YUVX32:
 		glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_v4l_fmt.g_width(), m_v4l_fmt.g_height(),
 				GL_RGBA, GL_UNSIGNED_BYTE, m_curData[0]);
 		break;
diff --git a/utils/qvidcap/v4l2-convert.glsl b/utils/qvidcap/v4l2-convert.glsl
index 458901c43838..8bd5694b3165 100644
--- a/utils/qvidcap/v4l2-convert.glsl
+++ b/utils/qvidcap/v4l2-convert.glsl
@@ -292,6 +292,12 @@  void main()
 	yuv.r = color.b;
 	yuv.g = color.g;
 	yuv.b = color.r;
+#elif PIXFMT == V4L2_PIX_FMT_YUVA32 || PIXFMT == V4L2_PIX_FMT_YUVX32
+	vec4 color = texture(tex, xy);
+#if PIXFMT == V4L2_PIX_FMT_YUVA32
+	alpha = color.a;
+#endif
+	yuv = color.rgb;
 #elif PIXFMT == V4L2_PIX_FMT_YUV565
 	yuv = texture(tex, xy).rgb;
 #elif PIXFMT == V4L2_PIX_FMT_YUV422P || PIXFMT == V4L2_PIX_FMT_YUV420 || PIXFMT == V4L2_PIX_FMT_YVU420 || \
diff --git a/utils/v4l2-compliance/v4l2-test-colors.cpp b/utils/v4l2-compliance/v4l2-test-colors.cpp
index 887b2fd418d7..87bf0cd7f3ab 100644
--- a/utils/v4l2-compliance/v4l2-test-colors.cpp
+++ b/utils/v4l2-compliance/v4l2-test-colors.cpp
@@ -200,6 +200,8 @@  static void getColor(const cv4l_fmt &fmt, __u8 * const planes[3],
 		break;
 	case V4L2_PIX_FMT_RGBX32:
 	case V4L2_PIX_FMT_RGBA32:
+	case V4L2_PIX_FMT_YUVA32:
+	case V4L2_PIX_FMT_YUVX32:
 		v32 = p8[4 * x + 2] + (p8[4 * x + 1] << 8) +
 		      (p8[4 * x] << 16) + (p8[4 * x + 3] << 24);
 		break;
@@ -386,6 +388,8 @@  static void getColor(const cv4l_fmt &fmt, __u8 * const planes[3],
 	case V4L2_PIX_FMT_XYUV32:
 	case V4L2_PIX_FMT_VUYA32:
 	case V4L2_PIX_FMT_VUYX32:
+	case V4L2_PIX_FMT_YUVA32:
+	case V4L2_PIX_FMT_YUVX32:
 	case V4L2_PIX_FMT_YUYV:
 	case V4L2_PIX_FMT_UYVY:
 	case V4L2_PIX_FMT_YVYU:
diff --git a/utils/v4l2-ctl/v4l2-ctl.cpp b/utils/v4l2-ctl/v4l2-ctl.cpp
index 6bf0a1c7d201..577cf37ec901 100644
--- a/utils/v4l2-ctl/v4l2-ctl.cpp
+++ b/utils/v4l2-ctl/v4l2-ctl.cpp
@@ -345,6 +345,8 @@  static bool is_rgb_or_hsv(__u32 pixelformat)
 	case V4L2_PIX_FMT_XYUV32:
 	case V4L2_PIX_FMT_VUYA32:
 	case V4L2_PIX_FMT_VUYX32:
+	case V4L2_PIX_FMT_YUVA32:
+	case V4L2_PIX_FMT_YUVX32:
 	case V4L2_PIX_FMT_YUV410:
 	case V4L2_PIX_FMT_YUV420:
 	case V4L2_PIX_FMT_HI240: