[libcamera-devel] android: yuv: Fix wrong access of source buffer
diff mbox series

Message ID 20210805132805.824754-1-hiroh@chromium.org
State Rejected
Headers show
Series
  • [libcamera-devel] android: yuv: Fix wrong access of source buffer
Related show

Commit Message

Hirokazu Honda Aug. 5, 2021, 1:28 p.m. UTC
File descriptors of FrameBuffer given in PostProcessor::process()
for all the planes point the same buffer. To access the beginning
of the second or later plane, it is necessary to add offsets to
the beginning of the buffer.
Fix the wrong access to the second plane of NV12 in
PostProcessorYuv.

Signed-off-by: Hirokazu Honda <hiroh@chromium.org>
---
 src/android/yuv/post_processor_yuv.cpp | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

Comments

Laurent Pinchart Aug. 5, 2021, 3:01 p.m. UTC | #1
Hi Hiro,

Thank you for the patch.

On Thu, Aug 05, 2021 at 10:28:05PM +0900, Hirokazu Honda wrote:
> File descriptors of FrameBuffer given in PostProcessor::process()
> for all the planes point the same buffer. To access the beginning
> of the second or later plane, it is necessary to add offsets to
> the beginning of the buffer.
> Fix the wrong access to the second plane of NV12 in
> PostProcessorYuv.

This is an issue that comes from V4L2, where NV12, a multi-planar
format, can be stored with the two planes contiguously in the same
dmabuf, or in separate dmabufs. We have two V4L2 pixel formats for those
(for instance, for NV12, that's V4L2_PIX_FMT_NV12 and
V4L2_PIX_FMT_NV12M), and two APIs, the V4L2 single-planar API that only
supports the single dmabuf format, and the V4L2 multi-planar API that
supports either formats.

This patch will work with V4L2_PIX_FMT_NV12 but not with
V4L2_PIX_FMT_NV12M. Let's not force applications to deal with this mess,
I don't want to expose it through the libcamera API. We should instead
handle it in the MappedBuffer class, so that maps()[1] will return the
correct value.

In order to support both NV12 and NV12M, we'll have to add an offset
field to FrameBuffer::Plane, but in the short term, as we only support
the single-dmabuf formats in our pipeline handlers, I think we can
hardcode the calculation below in the MappedBuffer class (I haven't
tried it though, so there may be something I'm missing).

> Signed-off-by: Hirokazu Honda <hiroh@chromium.org>
> ---
>  src/android/yuv/post_processor_yuv.cpp | 7 +++++--
>  1 file changed, 5 insertions(+), 2 deletions(-)
> 
> diff --git a/src/android/yuv/post_processor_yuv.cpp b/src/android/yuv/post_processor_yuv.cpp
> index 772e805b..3b801e96 100644
> --- a/src/android/yuv/post_processor_yuv.cpp
> +++ b/src/android/yuv/post_processor_yuv.cpp
> @@ -62,9 +62,12 @@ int PostProcessorYuv::process(const FrameBuffer &source,
>  		return -EINVAL;
>  	}
>  
> -	int ret = libyuv::NV12Scale(sourceMapped.maps()[0].data(),
> +	const uint8_t *sourceY = sourceMapped.maps()[0].data();
> +	const uint8_t *sourceUV = sourceY + sourceStride_[0] * sourceSize_.height;
> +
> +	int ret = libyuv::NV12Scale(sourceY,
>  				    sourceStride_[0],
> -				    sourceMapped.maps()[1].data(),
> +				    sourceUV,
>  				    sourceStride_[1],
>  				    sourceSize_.width, sourceSize_.height,
>  				    destination->plane(0).data(),
Hirokazu Honda Aug. 5, 2021, 3:21 p.m. UTC | #2
Hi Laurent,

On Fri, Aug 6, 2021 at 12:02 AM Laurent Pinchart
<laurent.pinchart@ideasonboard.com> wrote:
>
> Hi Hiro,
>
> Thank you for the patch.
>
> On Thu, Aug 05, 2021 at 10:28:05PM +0900, Hirokazu Honda wrote:
> > File descriptors of FrameBuffer given in PostProcessor::process()
> > for all the planes point the same buffer. To access the beginning
> > of the second or later plane, it is necessary to add offsets to
> > the beginning of the buffer.
> > Fix the wrong access to the second plane of NV12 in
> > PostProcessorYuv.
>
> This is an issue that comes from V4L2, where NV12, a multi-planar
> format, can be stored with the two planes contiguously in the same
> dmabuf, or in separate dmabufs. We have two V4L2 pixel formats for those
> (for instance, for NV12, that's V4L2_PIX_FMT_NV12 and
> V4L2_PIX_FMT_NV12M), and two APIs, the V4L2 single-planar API that only
> supports the single dmabuf format, and the V4L2 multi-planar API that
> supports either formats.
>
> This patch will work with V4L2_PIX_FMT_NV12 but not with
> V4L2_PIX_FMT_NV12M. Let's not force applications to deal with this mess,
> I don't want to expose it through the libcamera API. We should instead
> handle it in the MappedBuffer class, so that maps()[1] will return the
> correct value.
>
> In order to support both NV12 and NV12M, we'll have to add an offset
> field to FrameBuffer::Plane, but in the short term, as we only support
> the single-dmabuf formats in our pipeline handlers, I think we can
> hardcode the calculation below in the MappedBuffer class (I haven't
> tried it though, so there may be something I'm missing).
>

Yeah, that is what I would like to discuss through this patch.
I agree with handling this MappedBuffer.
The current libcamera implementation doesn't handle multi-planar format.
I filed https://bugs.libcamera.org/show_bug.cgi?id=9 previously.
Shall I also add strides() to MappedBuffer or FrameBuffer?

Regards,
-Hiro
> > Signed-off-by: Hirokazu Honda <hiroh@chromium.org>
> > ---
> >  src/android/yuv/post_processor_yuv.cpp | 7 +++++--
> >  1 file changed, 5 insertions(+), 2 deletions(-)
> >
> > diff --git a/src/android/yuv/post_processor_yuv.cpp b/src/android/yuv/post_processor_yuv.cpp
> > index 772e805b..3b801e96 100644
> > --- a/src/android/yuv/post_processor_yuv.cpp
> > +++ b/src/android/yuv/post_processor_yuv.cpp
> > @@ -62,9 +62,12 @@ int PostProcessorYuv::process(const FrameBuffer &source,
> >               return -EINVAL;
> >       }
> >
> > -     int ret = libyuv::NV12Scale(sourceMapped.maps()[0].data(),
> > +     const uint8_t *sourceY = sourceMapped.maps()[0].data();
> > +     const uint8_t *sourceUV = sourceY + sourceStride_[0] * sourceSize_.height;
> > +
> > +     int ret = libyuv::NV12Scale(sourceY,
> >                                   sourceStride_[0],
> > -                                 sourceMapped.maps()[1].data(),
> > +                                 sourceUV,
> >                                   sourceStride_[1],
> >                                   sourceSize_.width, sourceSize_.height,
> >                                   destination->plane(0).data(),
>
> --
> Regards,
>
> Laurent Pinchart
Laurent Pinchart Aug. 5, 2021, 3:57 p.m. UTC | #3
Hi Hiro,

On Fri, Aug 06, 2021 at 12:21:41AM +0900, Hirokazu Honda wrote:
> On Fri, Aug 6, 2021 at 12:02 AM Laurent Pinchart wrote:
> > On Thu, Aug 05, 2021 at 10:28:05PM +0900, Hirokazu Honda wrote:
> > > File descriptors of FrameBuffer given in PostProcessor::process()
> > > for all the planes point the same buffer. To access the beginning
> > > of the second or later plane, it is necessary to add offsets to
> > > the beginning of the buffer.
> > > Fix the wrong access to the second plane of NV12 in
> > > PostProcessorYuv.
> >
> > This is an issue that comes from V4L2, where NV12, a multi-planar
> > format, can be stored with the two planes contiguously in the same
> > dmabuf, or in separate dmabufs. We have two V4L2 pixel formats for those
> > (for instance, for NV12, that's V4L2_PIX_FMT_NV12 and
> > V4L2_PIX_FMT_NV12M), and two APIs, the V4L2 single-planar API that only
> > supports the single dmabuf format, and the V4L2 multi-planar API that
> > supports either formats.
> >
> > This patch will work with V4L2_PIX_FMT_NV12 but not with
> > V4L2_PIX_FMT_NV12M. Let's not force applications to deal with this mess,
> > I don't want to expose it through the libcamera API. We should instead
> > handle it in the MappedBuffer class, so that maps()[1] will return the
> > correct value.
> >
> > In order to support both NV12 and NV12M, we'll have to add an offset
> > field to FrameBuffer::Plane, but in the short term, as we only support
> > the single-dmabuf formats in our pipeline handlers, I think we can
> > hardcode the calculation below in the MappedBuffer class (I haven't
> > tried it though, so there may be something I'm missing).
> 
> Yeah, that is what I would like to discuss through this patch.
> I agree with handling this MappedBuffer.
> The current libcamera implementation doesn't handle multi-planar format.
> I filed https://bugs.libcamera.org/show_bug.cgi?id=9 previously.
> Shall I also add strides() to MappedBuffer or FrameBuffer?

I don't think so. Strides are a property of the format. They're
currently exposed in StreamConfiguration. We have a single stride there,
not a stride per plane, but I don't think it's urgent to rework this.

> > > Signed-off-by: Hirokazu Honda <hiroh@chromium.org>
> > > ---
> > >  src/android/yuv/post_processor_yuv.cpp | 7 +++++--
> > >  1 file changed, 5 insertions(+), 2 deletions(-)
> > >
> > > diff --git a/src/android/yuv/post_processor_yuv.cpp b/src/android/yuv/post_processor_yuv.cpp
> > > index 772e805b..3b801e96 100644
> > > --- a/src/android/yuv/post_processor_yuv.cpp
> > > +++ b/src/android/yuv/post_processor_yuv.cpp
> > > @@ -62,9 +62,12 @@ int PostProcessorYuv::process(const FrameBuffer &source,
> > >               return -EINVAL;
> > >       }
> > >
> > > -     int ret = libyuv::NV12Scale(sourceMapped.maps()[0].data(),
> > > +     const uint8_t *sourceY = sourceMapped.maps()[0].data();
> > > +     const uint8_t *sourceUV = sourceY + sourceStride_[0] * sourceSize_.height;
> > > +
> > > +     int ret = libyuv::NV12Scale(sourceY,
> > >                                   sourceStride_[0],
> > > -                                 sourceMapped.maps()[1].data(),
> > > +                                 sourceUV,
> > >                                   sourceStride_[1],
> > >                                   sourceSize_.width, sourceSize_.height,
> > >                                   destination->plane(0).data(),
Hirokazu Honda Aug. 5, 2021, 4:03 p.m. UTC | #4
Hi Laurent,

On Fri, Aug 6, 2021 at 12:57 AM Laurent Pinchart
<laurent.pinchart@ideasonboard.com> wrote:
>
> Hi Hiro,
>
> On Fri, Aug 06, 2021 at 12:21:41AM +0900, Hirokazu Honda wrote:
> > On Fri, Aug 6, 2021 at 12:02 AM Laurent Pinchart wrote:
> > > On Thu, Aug 05, 2021 at 10:28:05PM +0900, Hirokazu Honda wrote:
> > > > File descriptors of FrameBuffer given in PostProcessor::process()
> > > > for all the planes point the same buffer. To access the beginning
> > > > of the second or later plane, it is necessary to add offsets to
> > > > the beginning of the buffer.
> > > > Fix the wrong access to the second plane of NV12 in
> > > > PostProcessorYuv.
> > >
> > > This is an issue that comes from V4L2, where NV12, a multi-planar
> > > format, can be stored with the two planes contiguously in the same
> > > dmabuf, or in separate dmabufs. We have two V4L2 pixel formats for those
> > > (for instance, for NV12, that's V4L2_PIX_FMT_NV12 and
> > > V4L2_PIX_FMT_NV12M), and two APIs, the V4L2 single-planar API that only
> > > supports the single dmabuf format, and the V4L2 multi-planar API that
> > > supports either formats.
> > >
> > > This patch will work with V4L2_PIX_FMT_NV12 but not with
> > > V4L2_PIX_FMT_NV12M. Let's not force applications to deal with this mess,
> > > I don't want to expose it through the libcamera API. We should instead
> > > handle it in the MappedBuffer class, so that maps()[1] will return the
> > > correct value.
> > >
> > > In order to support both NV12 and NV12M, we'll have to add an offset
> > > field to FrameBuffer::Plane, but in the short term, as we only support
> > > the single-dmabuf formats in our pipeline handlers, I think we can
> > > hardcode the calculation below in the MappedBuffer class (I haven't
> > > tried it though, so there may be something I'm missing).
> >
> > Yeah, that is what I would like to discuss through this patch.
> > I agree with handling this MappedBuffer.
> > The current libcamera implementation doesn't handle multi-planar format.
> > I filed https://bugs.libcamera.org/show_bug.cgi?id=9 previously.
> > Shall I also add strides() to MappedBuffer or FrameBuffer?
>
> I don't think so. Strides are a property of the format. They're
> currently exposed in StreamConfiguration. We have a single stride there,
> not a stride per plane, but I don't think it's urgent to rework this.
>

I got it. I will abandon the patch in favor of  the suggested
MappedBuffer class change.

-Hiro
> > > > Signed-off-by: Hirokazu Honda <hiroh@chromium.org>
> > > > ---
> > > >  src/android/yuv/post_processor_yuv.cpp | 7 +++++--
> > > >  1 file changed, 5 insertions(+), 2 deletions(-)
> > > >
> > > > diff --git a/src/android/yuv/post_processor_yuv.cpp b/src/android/yuv/post_processor_yuv.cpp
> > > > index 772e805b..3b801e96 100644
> > > > --- a/src/android/yuv/post_processor_yuv.cpp
> > > > +++ b/src/android/yuv/post_processor_yuv.cpp
> > > > @@ -62,9 +62,12 @@ int PostProcessorYuv::process(const FrameBuffer &source,
> > > >               return -EINVAL;
> > > >       }
> > > >
> > > > -     int ret = libyuv::NV12Scale(sourceMapped.maps()[0].data(),
> > > > +     const uint8_t *sourceY = sourceMapped.maps()[0].data();
> > > > +     const uint8_t *sourceUV = sourceY + sourceStride_[0] * sourceSize_.height;
> > > > +
> > > > +     int ret = libyuv::NV12Scale(sourceY,
> > > >                                   sourceStride_[0],
> > > > -                                 sourceMapped.maps()[1].data(),
> > > > +                                 sourceUV,
> > > >                                   sourceStride_[1],
> > > >                                   sourceSize_.width, sourceSize_.height,
> > > >                                   destination->plane(0).data(),
>
> --
> Regards,
>
> Laurent Pinchart

Patch
diff mbox series

diff --git a/src/android/yuv/post_processor_yuv.cpp b/src/android/yuv/post_processor_yuv.cpp
index 772e805b..3b801e96 100644
--- a/src/android/yuv/post_processor_yuv.cpp
+++ b/src/android/yuv/post_processor_yuv.cpp
@@ -62,9 +62,12 @@  int PostProcessorYuv::process(const FrameBuffer &source,
 		return -EINVAL;
 	}
 
-	int ret = libyuv::NV12Scale(sourceMapped.maps()[0].data(),
+	const uint8_t *sourceY = sourceMapped.maps()[0].data();
+	const uint8_t *sourceUV = sourceY + sourceStride_[0] * sourceSize_.height;
+
+	int ret = libyuv::NV12Scale(sourceY,
 				    sourceStride_[0],
-				    sourceMapped.maps()[1].data(),
+				    sourceUV,
 				    sourceStride_[1],
 				    sourceSize_.width, sourceSize_.height,
 				    destination->plane(0).data(),