diff mbox

[v2,1/4] pxa_camera: Enforce YUV422P frame sizes to be 16 multiples

Message ID 1236986240-24115-2-git-send-email-robert.jarzmik@free.fr (mailing list archive)
State RFC
Headers show

Commit Message

Robert Jarzmik March 13, 2009, 11:17 p.m. UTC
Due to DMA constraints, the DMA chain always transfers bytes
from the QIF fifos to memory in 8 bytes units. In planar
formats, that could mean 0 padding between Y and U plane
(and between U and V plane), which is against YUV422P
standard.

Therefore, a frame size is required to be a multiple of 16
(so U plane size is a multiple of 8). It is enforced in
try_fmt() and set_fmt() primitives, be aligning height then
width on 4 multiples as need be, to reach a 16 multiple.

Signed-off-by: Robert Jarzmik <robert.jarzmik@free.fr>
---
 drivers/media/video/pxa_camera.c |   28 +++++++++++++++++++---------
 1 files changed, 19 insertions(+), 9 deletions(-)

Comments

Guennadi Liakhovetski March 16, 2009, 9:25 a.m. UTC | #1
On Sat, 14 Mar 2009, Robert Jarzmik wrote:

> Due to DMA constraints, the DMA chain always transfers bytes
> from the QIF fifos to memory in 8 bytes units. In planar
> formats, that could mean 0 padding between Y and U plane
> (and between U and V plane), which is against YUV422P
> standard.
> 
> Therefore, a frame size is required to be a multiple of 16
> (so U plane size is a multiple of 8). It is enforced in
> try_fmt() and set_fmt() primitives, be aligning height then
> width on 4 multiples as need be, to reach a 16 multiple.
> 
> Signed-off-by: Robert Jarzmik <robert.jarzmik@free.fr>
> ---
>  drivers/media/video/pxa_camera.c |   28 +++++++++++++++++++---------
>  1 files changed, 19 insertions(+), 9 deletions(-)
> 
> diff --git a/drivers/media/video/pxa_camera.c b/drivers/media/video/pxa_camera.c
> index e3e6b29..8e5611b 100644
> --- a/drivers/media/video/pxa_camera.c
> +++ b/drivers/media/video/pxa_camera.c
> @@ -162,6 +162,8 @@
>  			CICR0_PERRM | CICR0_QDM | CICR0_CDM | CICR0_SOFM | \
>  			CICR0_EOFM | CICR0_FOM)
>  
> +#define PIX_YUV422P_ALIGN 16	/* YUV422P pix size should be a multiple of 16 */

What is a "pix size?" Did you mean "picture size?"

> +
>  /*
>   * Structures
>   */
> @@ -241,15 +243,11 @@ static int pxa_videobuf_setup(struct videobuf_queue *vq, unsigned int *count,
>  
>  	dev_dbg(&icd->dev, "count=%d, size=%d\n", *count, *size);
>  
> -	/* planar capture requires Y, U and V buffers to be page aligned */
> -	if (pcdev->channels == 3) {
> -		*size = PAGE_ALIGN(icd->width * icd->height); /* Y pages */
> -		*size += PAGE_ALIGN(icd->width * icd->height / 2); /* U pages */
> -		*size += PAGE_ALIGN(icd->width * icd->height / 2); /* V pages */
> -	} else {
> -		*size = icd->width * icd->height *
> -			((icd->current_fmt->depth + 7) >> 3);
> -	}
> +	if (pcdev->channels == 3)
> +		*size = icd->width * icd->height * 2;

This is not very obvious, why "* 2". Maybe use

pxa_camera_formats[0].depth / 8 or at least add a comment?

> +	else
> +		*size = roundup(icd->width * icd->height *
> +				((icd->current_fmt->depth + 7) >> 3), 8);
>  
>  	if (0 == *count)
>  		*count = 32;
> @@ -1234,6 +1232,18 @@ static int pxa_camera_try_fmt(struct soc_camera_device *icd,
>  		pix->width = 2048;
>  	pix->width &= ~0x01;
>  
> +	/*
> +	 * YUV422P planar format requires images size to be a 16 bytes
> +	 * multiple. If not, zeros will be inserted between Y and U planes, and
> +	 * U and V planes, and YUV422P standard would be violated.
> +	 */
> +	if (xlate->host_fmt->fourcc == V4L2_PIX_FMT_YUV422P) {
> +		if (!IS_ALIGNED(pix->width * pix->height, PIX_YUV422P_ALIGN))
> +			pix->height = ALIGN(pix->height, PIX_YUV422P_ALIGN / 2);
> +		if (!IS_ALIGNED(pix->width * pix->height, PIX_YUV422P_ALIGN))
> +			pix->width = ALIGN(pix->width, PIX_YUV422P_ALIGN / 2);

Shouldn't this have been sqrt(PIX_YUV422P_ALIGN) (of course, not 
literally) instead of PIX_YUV422P_ALIGN / 2? At least above you say, 
height and width shall be 4 bytes aligned, not 8.

> +	}
> +
>  	pix->bytesperline = pix->width *
>  		DIV_ROUND_UP(xlate->host_fmt->depth, 8);
>  	pix->sizeimage = pix->height * pix->bytesperline;
> -- 
> 1.5.6.5

Thanks
Guennadi
---
Guennadi Liakhovetski, Ph.D.
Freelance Open-Source Software Developer
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Robert Jarzmik March 16, 2009, 6:26 p.m. UTC | #2
Guennadi Liakhovetski <g.liakhovetski@gmx.de> writes:

>> @@ -162,6 +162,8 @@
>>  			CICR0_PERRM | CICR0_QDM | CICR0_CDM | CICR0_SOFM | \
>>  			CICR0_EOFM | CICR0_FOM)
>>  
>> +#define PIX_YUV422P_ALIGN 16	/* YUV422P pix size should be a multiple of 16 */
>
> What is a "pix size?" Did you mean "picture size?"
Yes. I'll change the comment from "pix size" into "picture size"

>> -	/* planar capture requires Y, U and V buffers to be page aligned */
>> -	if (pcdev->channels == 3) {
>> -		*size = PAGE_ALIGN(icd->width * icd->height); /* Y pages */
>> -		*size += PAGE_ALIGN(icd->width * icd->height / 2); /* U pages */
>> -		*size += PAGE_ALIGN(icd->width * icd->height / 2); /* V pages */
>> -	} else {
>> -		*size = icd->width * icd->height *
>> -			((icd->current_fmt->depth + 7) >> 3);
>> -	}
>> +	if (pcdev->channels == 3)
>> +		*size = icd->width * icd->height * 2;
>
> This is not very obvious, why "* 2". Maybe use
>
> pxa_camera_formats[0].depth / 8 or at least add a comment?

Yes.
I was wondering about simplifying the if (removing it actually), and changing :
>> +	if (pcdev->channels == 3)
>> +		*size = icd->width * icd->height * 2;
>> +	else
>> +		*size = roundup(icd->width * icd->height *
>> +				((icd->current_fmt->depth + 7) >> 3), 8);
into:
	*size = roundup(icd->width * icd->height *
			((icd->current_fmt->depth + 7) >> 3), 8);

>> +	if (xlate->host_fmt->fourcc == V4L2_PIX_FMT_YUV422P) {
>> +		if (!IS_ALIGNED(pix->width * pix->height, PIX_YUV422P_ALIGN))
>> +			pix->height = ALIGN(pix->height, PIX_YUV422P_ALIGN / 2);
>> +		if (!IS_ALIGNED(pix->width * pix->height, PIX_YUV422P_ALIGN))
>> +			pix->width = ALIGN(pix->width, PIX_YUV422P_ALIGN / 2);
>
> Shouldn't this have been sqrt(PIX_YUV422P_ALIGN) (of course, not 
> literally) instead of PIX_YUV422P_ALIGN / 2? At least above you say, 
> height and width shall be 4 bytes aligned, not 8.
That's a very good catch.
Maybe 2 defines will fit better, as I'm not very please with log2 logic here ... :

/*
 * YUV422P picture size should be a multiple of 16, so the heuristic aligns
 * height, width on 4 byte boundaries to reach the 16 multiple for the size.
 */
#define YUV422P_X_Y_ALIGN 4
#define YUV422P_SIZE_ALIGN YUV422P_X_Y_ALIGN * YUV422P_X_Y_ALIGN

Cheers.

--
Robert
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Trent Piepho March 16, 2009, 8:29 p.m. UTC | #3
On Mon, 16 Mar 2009, Robert Jarzmik wrote:
> >> +	if (xlate->host_fmt->fourcc == V4L2_PIX_FMT_YUV422P) {
> >> +		if (!IS_ALIGNED(pix->width * pix->height, PIX_YUV422P_ALIGN))
> >> +			pix->height = ALIGN(pix->height, PIX_YUV422P_ALIGN / 2);
> >> +		if (!IS_ALIGNED(pix->width * pix->height, PIX_YUV422P_ALIGN))
> >> +			pix->width = ALIGN(pix->width, PIX_YUV422P_ALIGN / 2);
> >
> > Shouldn't this have been sqrt(PIX_YUV422P_ALIGN) (of course, not
> > literally) instead of PIX_YUV422P_ALIGN / 2? At least above you say,
> > height and width shall be 4 bytes aligned, not 8.
> That's a very good catch.
> Maybe 2 defines will fit better, as I'm not very please with log2 logic here ... :
>
> /*
>  * YUV422P picture size should be a multiple of 16, so the heuristic aligns
>  * height, width on 4 byte boundaries to reach the 16 multiple for the size.
>  */
> #define YUV422P_X_Y_ALIGN 4
> #define YUV422P_SIZE_ALIGN YUV422P_X_Y_ALIGN * YUV422P_X_Y_ALIGN

Before you spend too much time on this, maybe I could offer a patch to use
the generic alignment function I posted before?  I beleive the method in
that code will produce better results I think there are multiple drivers
that could make use of it.
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Guennadi Liakhovetski March 16, 2009, 8:47 p.m. UTC | #4
On Mon, 16 Mar 2009, Trent Piepho wrote:

> On Mon, 16 Mar 2009, Robert Jarzmik wrote:
> > >> +	if (xlate->host_fmt->fourcc == V4L2_PIX_FMT_YUV422P) {
> > >> +		if (!IS_ALIGNED(pix->width * pix->height, PIX_YUV422P_ALIGN))
> > >> +			pix->height = ALIGN(pix->height, PIX_YUV422P_ALIGN / 2);
> > >> +		if (!IS_ALIGNED(pix->width * pix->height, PIX_YUV422P_ALIGN))
> > >> +			pix->width = ALIGN(pix->width, PIX_YUV422P_ALIGN / 2);
> > >
> > > Shouldn't this have been sqrt(PIX_YUV422P_ALIGN) (of course, not
> > > literally) instead of PIX_YUV422P_ALIGN / 2? At least above you say,
> > > height and width shall be 4 bytes aligned, not 8.
> > That's a very good catch.
> > Maybe 2 defines will fit better, as I'm not very please with log2 logic here ... :
> >
> > /*
> >  * YUV422P picture size should be a multiple of 16, so the heuristic aligns
> >  * height, width on 4 byte boundaries to reach the 16 multiple for the size.
> >  */
> > #define YUV422P_X_Y_ALIGN 4
> > #define YUV422P_SIZE_ALIGN YUV422P_X_Y_ALIGN * YUV422P_X_Y_ALIGN
> 
> Before you spend too much time on this, maybe I could offer a patch to use
> the generic alignment function I posted before?  I beleive the method in
> that code will produce better results I think there are multiple drivers
> that could make use of it.

As Robert already replied to you: submit your patches, get them into 
mainline, then we'll gladly switch to them if they suit our purpose.

Thanks
Guennadi
---
Guennadi Liakhovetski, Ph.D.
Freelance Open-Source Software Developer
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/drivers/media/video/pxa_camera.c b/drivers/media/video/pxa_camera.c
index e3e6b29..8e5611b 100644
--- a/drivers/media/video/pxa_camera.c
+++ b/drivers/media/video/pxa_camera.c
@@ -162,6 +162,8 @@ 
 			CICR0_PERRM | CICR0_QDM | CICR0_CDM | CICR0_SOFM | \
 			CICR0_EOFM | CICR0_FOM)
 
+#define PIX_YUV422P_ALIGN 16	/* YUV422P pix size should be a multiple of 16 */
+
 /*
  * Structures
  */
@@ -241,15 +243,11 @@  static int pxa_videobuf_setup(struct videobuf_queue *vq, unsigned int *count,
 
 	dev_dbg(&icd->dev, "count=%d, size=%d\n", *count, *size);
 
-	/* planar capture requires Y, U and V buffers to be page aligned */
-	if (pcdev->channels == 3) {
-		*size = PAGE_ALIGN(icd->width * icd->height); /* Y pages */
-		*size += PAGE_ALIGN(icd->width * icd->height / 2); /* U pages */
-		*size += PAGE_ALIGN(icd->width * icd->height / 2); /* V pages */
-	} else {
-		*size = icd->width * icd->height *
-			((icd->current_fmt->depth + 7) >> 3);
-	}
+	if (pcdev->channels == 3)
+		*size = icd->width * icd->height * 2;
+	else
+		*size = roundup(icd->width * icd->height *
+				((icd->current_fmt->depth + 7) >> 3), 8);
 
 	if (0 == *count)
 		*count = 32;
@@ -1234,6 +1232,18 @@  static int pxa_camera_try_fmt(struct soc_camera_device *icd,
 		pix->width = 2048;
 	pix->width &= ~0x01;
 
+	/*
+	 * YUV422P planar format requires images size to be a 16 bytes
+	 * multiple. If not, zeros will be inserted between Y and U planes, and
+	 * U and V planes, and YUV422P standard would be violated.
+	 */
+	if (xlate->host_fmt->fourcc == V4L2_PIX_FMT_YUV422P) {
+		if (!IS_ALIGNED(pix->width * pix->height, PIX_YUV422P_ALIGN))
+			pix->height = ALIGN(pix->height, PIX_YUV422P_ALIGN / 2);
+		if (!IS_ALIGNED(pix->width * pix->height, PIX_YUV422P_ALIGN))
+			pix->width = ALIGN(pix->width, PIX_YUV422P_ALIGN / 2);
+	}
+
 	pix->bytesperline = pix->width *
 		DIV_ROUND_UP(xlate->host_fmt->depth, 8);
 	pix->sizeimage = pix->height * pix->bytesperline;