[libcamera-devel,v2,2/2] android: Fix generation of thumbnail for EXIF data
diff mbox series

Message ID 20210913040110.13789-3-umang.jain@ideasonboard.com
State Accepted
Delegated to: Umang Jain
Headers show
Series
  • android: Fix generation of thumbnail for EXIF
Related show

Commit Message

Umang Jain Sept. 13, 2021, 4:01 a.m. UTC
Generation of thumbnail is not occuring currently because
ANDROID_JPEG_THUMBNAIL_SIZE is not set for request metadata passed
to PostProcessorJpeg::process(). This is a regression introduced in
1264628d3c92("android: jpeg: Configure thumbnailer based on request
metadata").

The patch fixes this issue by setting ANDROID_JPEG_THUMBNAIL_SIZE in
the request metadata template populated by
CameraCapabilities::requestTemplatePreview(). The value for
ANDROID_JPEG_THUMBNAIL_SIZE is set to be the first non-zero size
reported by static metadata ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES.

Fixes: 1264628d3c92("android: jpeg: Configure thumbnailer based on request metadata")
Signed-off-by: Umang Jain <umang.jain@ideasonboard.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 src/android/camera_capabilities.cpp | 14 ++++++++++++--
 1 file changed, 12 insertions(+), 2 deletions(-)

Comments

Jacopo Mondi Sept. 13, 2021, 2:08 p.m. UTC | #1
Hi Umang,

On Mon, Sep 13, 2021 at 09:31:10AM +0530, Umang Jain wrote:
> Generation of thumbnail is not occuring currently because
> ANDROID_JPEG_THUMBNAIL_SIZE is not set for request metadata passed
> to PostProcessorJpeg::process(). This is a regression introduced in
> 1264628d3c92("android: jpeg: Configure thumbnailer based on request
> metadata").

I see the issue, but I'm not sure those commit was wrong. I mean, what
that commit does that itroduced a regression is:

--- a/src/android/jpeg/post_processor_jpeg.cpp
+++ b/src/android/jpeg/post_processor_jpeg.cpp
+       ret = requestMetadata.getEntry(ANDROID_JPEG_THUMBNAIL_SIZE, &entry);
+       if (ret) {
+               const int32_t *data = entry.data.i32;
+               Size thumbnailSize = { static_cast<uint32_t>(data[0]),
+                                      static_cast<uint32_t>(data[1]) };
+
+               if (thumbnailSize != Size(0, 0)) {
+                       std::vector<unsigned char> thumbnail;
+                       generateThumbnail(source, thumbnailSize, &thumbnail);
+                       if (!thumbnail.empty())
+                               exif.setThumbnail(thumbnail, Exif::Compression::JPEG);
+               }
+
+               resultMetadata->addEntry(ANDROID_JPEG_THUMBNAIL_SIZE, data, 2);
+
+               /* \todo Use this quality as a parameter to the encoder */
+               ret = requestMetadata.getEntry(ANDROID_JPEG_THUMBNAIL_QUALITY, &entry);
+               if (ret)
+                       resultMetadata->addEntry(ANDROID_JPEG_THUMBNAIL_QUALITY,
+                                                entry.data.u8, 1);
+       }


Which I read as: "If ANDROID_JPEG_THUMBNAIL_SIZE is not specified in
the request's settings, do not populate it in result metadata".

Is this correct in your opinion, or should we populate it regardless
of the fact the tag was passed in ?

>
> The patch fixes this issue by setting ANDROID_JPEG_THUMBNAIL_SIZE in
> the request metadata template populated by
> CameraCapabilities::requestTemplatePreview(). The value for
> ANDROID_JPEG_THUMBNAIL_SIZE is set to be the first non-zero size
> reported by static metadata ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES.

Let's say just that this patch adds ANDROID_JPEG_THUMBNAIL_SIZE to the
capture request template generated for the preview use case. I wonder
if the JPEG thunbnail size should be part of the preview template now.

>
> Fixes: 1264628d3c92("android: jpeg: Configure thumbnailer based on request metadata")
> Signed-off-by: Umang Jain <umang.jain@ideasonboard.com>
> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> ---
>  src/android/camera_capabilities.cpp | 14 ++++++++++++--
>  1 file changed, 12 insertions(+), 2 deletions(-)
>
> diff --git a/src/android/camera_capabilities.cpp b/src/android/camera_capabilities.cpp
> index e92bca42..76dddafd 100644
> --- a/src/android/camera_capabilities.cpp
> +++ b/src/android/camera_capabilities.cpp
> @@ -1341,9 +1341,9 @@ std::unique_ptr<CameraMetadata> CameraCapabilities::requestTemplatePreview() con
>  {
>  	/*
>  	 * \todo Keep this in sync with the actual number of entries.
> -	 * Currently: 20 entries, 35 bytes
> +	 * Currently: 21 entries, 37 bytes
>  	 */
> -	auto requestTemplate = std::make_unique<CameraMetadata>(21, 36);
> +	auto requestTemplate = std::make_unique<CameraMetadata>(22, 38);

Comment says 21, code says 22.

It was there already as the comment was not aligned with the code, but
since you're at it you could fix it

>  	if (!requestTemplate->isValid()) {
>  		return nullptr;
>  	}
> @@ -1364,6 +1364,16 @@ std::unique_ptr<CameraMetadata> CameraCapabilities::requestTemplatePreview() con
>  	requestTemplate->addEntry(ANDROID_CONTROL_AE_TARGET_FPS_RANGE,
>  				  entry.data.i32, 2);
>
> +	/*
> +	 * Get thumbnail sizes from static metadata and add the first non-zero
> +	 * size to the template.
> +	 */
> +	found = staticMetadata_->getEntry(ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES,
> +					  &entry);
> +	ASSERT(found && entry.count >= 4);
> +	requestTemplate->addEntry(ANDROID_JPEG_THUMBNAIL_SIZE,
> +				  entry.data.i32 + 2, 2);
> +

If I were to be extra paranoid I would make sure we actually discard
(0, 0). The code assumes the first two entries are (0, 0) which is
fine as we populate it after all.

If you don't want to

        unsigned int j = 0;
        while (j < entry.count / 2) {
                if (entry.data.i32[j] == 0 || entry.data.i32[j + 1] == 0)
                        continue;

                requestTemplate->addEntry(ANDROID_JPEG_THUMBNAIL_SIZE,
                                          entry.data.i32 + j, 2);
        }

Could you at least capture that we assume the first two entries are
(0,0) ?

Thanks
   j


>  	uint8_t aeMode = ANDROID_CONTROL_AE_MODE_ON;
>  	requestTemplate->addEntry(ANDROID_CONTROL_AE_MODE, aeMode);
>
> --
> 2.31.1
>
Jacopo Mondi Sept. 13, 2021, 2:16 p.m. UTC | #2
On Mon, Sep 13, 2021 at 04:08:05PM +0200, Jacopo Mondi wrote:
> Hi Umang,
>
> On Mon, Sep 13, 2021 at 09:31:10AM +0530, Umang Jain wrote:
> > Generation of thumbnail is not occuring currently because
> > ANDROID_JPEG_THUMBNAIL_SIZE is not set for request metadata passed
> > to PostProcessorJpeg::process(). This is a regression introduced in
> > 1264628d3c92("android: jpeg: Configure thumbnailer based on request
> > metadata").
>
> I see the issue, but I'm not sure those commit was wrong. I mean, what
> that commit does that itroduced a regression is:
>
> --- a/src/android/jpeg/post_processor_jpeg.cpp
> +++ b/src/android/jpeg/post_processor_jpeg.cpp
> +       ret = requestMetadata.getEntry(ANDROID_JPEG_THUMBNAIL_SIZE, &entry);
> +       if (ret) {
> +               const int32_t *data = entry.data.i32;
> +               Size thumbnailSize = { static_cast<uint32_t>(data[0]),
> +                                      static_cast<uint32_t>(data[1]) };
> +
> +               if (thumbnailSize != Size(0, 0)) {
> +                       std::vector<unsigned char> thumbnail;
> +                       generateThumbnail(source, thumbnailSize, &thumbnail);
> +                       if (!thumbnail.empty())
> +                               exif.setThumbnail(thumbnail, Exif::Compression::JPEG);
> +               }
> +
> +               resultMetadata->addEntry(ANDROID_JPEG_THUMBNAIL_SIZE, data, 2);
> +
> +               /* \todo Use this quality as a parameter to the encoder */
> +               ret = requestMetadata.getEntry(ANDROID_JPEG_THUMBNAIL_QUALITY, &entry);
> +               if (ret)
> +                       resultMetadata->addEntry(ANDROID_JPEG_THUMBNAIL_QUALITY,
> +                                                entry.data.u8, 1);
> +       }
>
>
> Which I read as: "If ANDROID_JPEG_THUMBNAIL_SIZE is not specified in
> the request's settings, do not populate it in result metadata".
>
> Is this correct in your opinion, or should we populate it regardless
> of the fact the tag was passed in ?
>
> >
> > The patch fixes this issue by setting ANDROID_JPEG_THUMBNAIL_SIZE in
> > the request metadata template populated by
> > CameraCapabilities::requestTemplatePreview(). The value for
> > ANDROID_JPEG_THUMBNAIL_SIZE is set to be the first non-zero size
> > reported by static metadata ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES.
>
> Let's say just that this patch adds ANDROID_JPEG_THUMBNAIL_SIZE to the
> capture request template generated for the preview use case. I wonder
> if the JPEG thunbnail size should be part of the preview template now.
>
> >
> > Fixes: 1264628d3c92("android: jpeg: Configure thumbnailer based on request metadata")
> > Signed-off-by: Umang Jain <umang.jain@ideasonboard.com>
> > Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > ---
> >  src/android/camera_capabilities.cpp | 14 ++++++++++++--
> >  1 file changed, 12 insertions(+), 2 deletions(-)
> >
> > diff --git a/src/android/camera_capabilities.cpp b/src/android/camera_capabilities.cpp
> > index e92bca42..76dddafd 100644
> > --- a/src/android/camera_capabilities.cpp
> > +++ b/src/android/camera_capabilities.cpp
> > @@ -1341,9 +1341,9 @@ std::unique_ptr<CameraMetadata> CameraCapabilities::requestTemplatePreview() con
> >  {
> >  	/*
> >  	 * \todo Keep this in sync with the actual number of entries.
> > -	 * Currently: 20 entries, 35 bytes
> > +	 * Currently: 21 entries, 37 bytes
> >  	 */
> > -	auto requestTemplate = std::make_unique<CameraMetadata>(21, 36);
> > +	auto requestTemplate = std::make_unique<CameraMetadata>(22, 38);
>
> Comment says 21, code says 22.
>
> It was there already as the comment was not aligned with the code, but
> since you're at it you could fix it
>
> >  	if (!requestTemplate->isValid()) {
> >  		return nullptr;
> >  	}
> > @@ -1364,6 +1364,16 @@ std::unique_ptr<CameraMetadata> CameraCapabilities::requestTemplatePreview() con
> >  	requestTemplate->addEntry(ANDROID_CONTROL_AE_TARGET_FPS_RANGE,
> >  				  entry.data.i32, 2);
> >
> > +	/*
> > +	 * Get thumbnail sizes from static metadata and add the first non-zero
> > +	 * size to the template.
> > +	 */
> > +	found = staticMetadata_->getEntry(ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES,
> > +					  &entry);
> > +	ASSERT(found && entry.count >= 4);
> > +	requestTemplate->addEntry(ANDROID_JPEG_THUMBNAIL_SIZE,
> > +				  entry.data.i32 + 2, 2);
> > +
>
> If I were to be extra paranoid I would make sure we actually discard
> (0, 0). The code assumes the first two entries are (0, 0) which is
> fine as we populate it after all.
>
> If you don't want to
>
>         unsigned int j = 0;
>         while (j < entry.count / 2) {
>                 if (entry.data.i32[j] == 0 || entry.data.i32[j + 1] == 0) {
                          j += 2;

                          :)

>                         continue;
                  }
>
>                 requestTemplate->addEntry(ANDROID_JPEG_THUMBNAIL_SIZE,
>                                           entry.data.i32 + j, 2);
>         }
>
> Could you at least capture that we assume the first two entries are
> (0,0) ?
>
> Thanks
>    j
>
>
> >  	uint8_t aeMode = ANDROID_CONTROL_AE_MODE_ON;
> >  	requestTemplate->addEntry(ANDROID_CONTROL_AE_MODE, aeMode);
> >
> > --
> > 2.31.1
> >
Umang Jain Sept. 13, 2021, 2:41 p.m. UTC | #3
Hi Jacopo

On 9/13/21 7:38 PM, Jacopo Mondi wrote:
> Hi Umang,
>
> On Mon, Sep 13, 2021 at 09:31:10AM +0530, Umang Jain wrote:
>> Generation of thumbnail is not occuring currently because
>> ANDROID_JPEG_THUMBNAIL_SIZE is not set for request metadata passed
>> to PostProcessorJpeg::process(). This is a regression introduced in
>> 1264628d3c92("android: jpeg: Configure thumbnailer based on request
>> metadata").
> I see the issue, but I'm not sure those commit was wrong. I mean, what
> that commit does that itroduced a regression is:
>
> --- a/src/android/jpeg/post_processor_jpeg.cpp
> +++ b/src/android/jpeg/post_processor_jpeg.cpp
> +       ret = requestMetadata.getEntry(ANDROID_JPEG_THUMBNAIL_SIZE, &entry);
> +       if (ret) {
> +               const int32_t *data = entry.data.i32;
> +               Size thumbnailSize = { static_cast<uint32_t>(data[0]),
> +                                      static_cast<uint32_t>(data[1]) };
> +
> +               if (thumbnailSize != Size(0, 0)) {
> +                       std::vector<unsigned char> thumbnail;
> +                       generateThumbnail(source, thumbnailSize, &thumbnail);
> +                       if (!thumbnail.empty())
> +                               exif.setThumbnail(thumbnail, Exif::Compression::JPEG);
> +               }
> +
> +               resultMetadata->addEntry(ANDROID_JPEG_THUMBNAIL_SIZE, data, 2);
> +
> +               /* \todo Use this quality as a parameter to the encoder */
> +               ret = requestMetadata.getEntry(ANDROID_JPEG_THUMBNAIL_QUALITY, &entry);
> +               if (ret)
> +                       resultMetadata->addEntry(ANDROID_JPEG_THUMBNAIL_QUALITY,
> +                                                entry.data.u8, 1);
> +       }
>
>
> Which I read as: "If ANDROID_JPEG_THUMBNAIL_SIZE is not specified in
> the request's settings, do not populate it in result metadata".
>
> Is this correct in your opinion, or should we populate it regardless
> of the fact the tag was passed in ?


This is correct, but the counterpart of the patch seems missing from 
that commit, which actually resulted in regression

>
>> The patch fixes this issue by setting ANDROID_JPEG_THUMBNAIL_SIZE in
>> the request metadata template populated by
>> CameraCapabilities::requestTemplatePreview(). The value for
>> ANDROID_JPEG_THUMBNAIL_SIZE is set to be the first non-zero size
>> reported by static metadata ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES.
> Let's say just that this patch adds ANDROID_JPEG_THUMBNAIL_SIZE to the
> capture request template generated for the preview use case. I wonder
> if the JPEG thunbnail size should be part of the preview template now.


I wonder that too...

>
>> Fixes: 1264628d3c92("android: jpeg: Configure thumbnailer based on request metadata")
>> Signed-off-by: Umang Jain <umang.jain@ideasonboard.com>
>> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
>> ---
>>   src/android/camera_capabilities.cpp | 14 ++++++++++++--
>>   1 file changed, 12 insertions(+), 2 deletions(-)
>>
>> diff --git a/src/android/camera_capabilities.cpp b/src/android/camera_capabilities.cpp
>> index e92bca42..76dddafd 100644
>> --- a/src/android/camera_capabilities.cpp
>> +++ b/src/android/camera_capabilities.cpp
>> @@ -1341,9 +1341,9 @@ std::unique_ptr<CameraMetadata> CameraCapabilities::requestTemplatePreview() con
>>   {
>>   	/*
>>   	 * \todo Keep this in sync with the actual number of entries.
>> -	 * Currently: 20 entries, 35 bytes
>> +	 * Currently: 21 entries, 37 bytes
>>   	 */
>> -	auto requestTemplate = std::make_unique<CameraMetadata>(21, 36);
>> +	auto requestTemplate = std::make_unique<CameraMetadata>(22, 38);
> Comment says 21, code says 22.
>
> It was there already as the comment was not aligned with the code, but
> since you're at it you could fix it


Looking at both #entries and #bytes, that gives me an impression that 
extra entry and data buffer bytes are **intentional**, so I went ahead 
with it! Are both of them a typo? I'll need some checking tomorrow.

>
>>   	if (!requestTemplate->isValid()) {
>>   		return nullptr;
>>   	}
>> @@ -1364,6 +1364,16 @@ std::unique_ptr<CameraMetadata> CameraCapabilities::requestTemplatePreview() con
>>   	requestTemplate->addEntry(ANDROID_CONTROL_AE_TARGET_FPS_RANGE,
>>   				  entry.data.i32, 2);
>>
>> +	/*
>> +	 * Get thumbnail sizes from static metadata and add the first non-zero
>> +	 * size to the template.
>> +	 */
>> +	found = staticMetadata_->getEntry(ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES,
>> +					  &entry);
>> +	ASSERT(found && entry.count >= 4);
>> +	requestTemplate->addEntry(ANDROID_JPEG_THUMBNAIL_SIZE,
>> +				  entry.data.i32 + 2, 2);
>> +
> If I were to be extra paranoid I would make sure we actually discard
> (0, 0). The code assumes the first two entries are (0, 0) which is
> fine as we populate it after all.


Not only we populate it, it's a requirement that Size (0,0) should be in 
the vector /and/ the vector needs to be sorted in ascending order [1] if 
more sizes are provided with. We do the right thing when populating 
ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES so I won't be extra paranoid here.


[1]: 
https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics#JPEG_AVAILABLE_THUMBNAIL_SIZES

>
> If you don't want to
>
>          unsigned int j = 0;
>          while (j < entry.count / 2) {
>                  if (entry.data.i32[j] == 0 || entry.data.i32[j + 1] == 0)
>                          continue;
>
>                  requestTemplate->addEntry(ANDROID_JPEG_THUMBNAIL_SIZE,
>                                            entry.data.i32 + j, 2);
>          }
>
> Could you at least capture that we assume the first two entries are
> (0,0) ?


As said above, it's a requirement for 
ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES, so should I make it extra clear 
again here?

>
> Thanks
>     j
>
>
>>   	uint8_t aeMode = ANDROID_CONTROL_AE_MODE_ON;
>>   	requestTemplate->addEntry(ANDROID_CONTROL_AE_MODE, aeMode);
>>
>> --
>> 2.31.1
>>
Umang Jain Sept. 21, 2021, 11:50 a.m. UTC | #4
Hi Jacopo

On 9/13/21 8:11 PM, Umang Jain wrote:
> Hi Jacopo
>
> On 9/13/21 7:38 PM, Jacopo Mondi wrote:
>> Hi Umang,
>>
>> On Mon, Sep 13, 2021 at 09:31:10AM +0530, Umang Jain wrote:
>>> Generation of thumbnail is not occuring currently because
>>> ANDROID_JPEG_THUMBNAIL_SIZE is not set for request metadata passed
>>> to PostProcessorJpeg::process(). This is a regression introduced in
>>> 1264628d3c92("android: jpeg: Configure thumbnailer based on request
>>> metadata").
>> I see the issue, but I'm not sure those commit was wrong. I mean, what
>> that commit does that itroduced a regression is:
>>
>> --- a/src/android/jpeg/post_processor_jpeg.cpp
>> +++ b/src/android/jpeg/post_processor_jpeg.cpp
>> +       ret = requestMetadata.getEntry(ANDROID_JPEG_THUMBNAIL_SIZE, 
>> &entry);
>> +       if (ret) {
>> +               const int32_t *data = entry.data.i32;
>> +               Size thumbnailSize = { static_cast<uint32_t>(data[0]),
>> + static_cast<uint32_t>(data[1]) };
>> +
>> +               if (thumbnailSize != Size(0, 0)) {
>> +                       std::vector<unsigned char> thumbnail;
>> +                       generateThumbnail(source, thumbnailSize, 
>> &thumbnail);
>> +                       if (!thumbnail.empty())
>> +                               exif.setThumbnail(thumbnail, 
>> Exif::Compression::JPEG);
>> +               }
>> +
>> + resultMetadata->addEntry(ANDROID_JPEG_THUMBNAIL_SIZE, data, 2);
>> +
>> +               /* \todo Use this quality as a parameter to the 
>> encoder */
>> +               ret = 
>> requestMetadata.getEntry(ANDROID_JPEG_THUMBNAIL_QUALITY, &entry);
>> +               if (ret)
>> + resultMetadata->addEntry(ANDROID_JPEG_THUMBNAIL_QUALITY,
>> +                                                entry.data.u8, 1);
>> +       }
>>
>>
>> Which I read as: "If ANDROID_JPEG_THUMBNAIL_SIZE is not specified in
>> the request's settings, do not populate it in result metadata".
>>
>> Is this correct in your opinion, or should we populate it regardless
>> of the fact the tag was passed in ?
>
>
> This is correct, but the counterpart of the patch seems missing from 
> that commit, which actually resulted in regression
>
>>
>>> The patch fixes this issue by setting ANDROID_JPEG_THUMBNAIL_SIZE in
>>> the request metadata template populated by
>>> CameraCapabilities::requestTemplatePreview(). The value for
>>> ANDROID_JPEG_THUMBNAIL_SIZE is set to be the first non-zero size
>>> reported by static metadata ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES.
>> Let's say just that this patch adds ANDROID_JPEG_THUMBNAIL_SIZE to the
>> capture request template generated for the preview use case. I wonder
>> if the JPEG thunbnail size should be part of the preview template now.
>
>
> I wonder that too...
>
>>
>>> Fixes: 1264628d3c92("android: jpeg: Configure thumbnailer based on 
>>> request metadata")
>>> Signed-off-by: Umang Jain <umang.jain@ideasonboard.com>
>>> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
>>> ---
>>>   src/android/camera_capabilities.cpp | 14 ++++++++++++--
>>>   1 file changed, 12 insertions(+), 2 deletions(-)
>>>
>>> diff --git a/src/android/camera_capabilities.cpp 
>>> b/src/android/camera_capabilities.cpp
>>> index e92bca42..76dddafd 100644
>>> --- a/src/android/camera_capabilities.cpp
>>> +++ b/src/android/camera_capabilities.cpp
>>> @@ -1341,9 +1341,9 @@ std::unique_ptr<CameraMetadata> 
>>> CameraCapabilities::requestTemplatePreview() con
>>>   {
>>>       /*
>>>        * \todo Keep this in sync with the actual number of entries.
>>> -     * Currently: 20 entries, 35 bytes
>>> +     * Currently: 21 entries, 37 bytes
>>>        */
>>> -    auto requestTemplate = std::make_unique<CameraMetadata>(21, 36);
>>> +    auto requestTemplate = std::make_unique<CameraMetadata>(22, 38);
>> Comment says 21, code says 22.
>>
>> It was there already as the comment was not aligned with the code, but
>> since you're at it you could fix it
>
>
> Looking at both #entries and #bytes, that gives me an impression that 
> extra entry and data buffer bytes are **intentional**, so I went ahead 
> with it! Are both of them a typo? I'll need some checking tomorrow.


Indeed, my assumption was a mistake. I think the mismatch was long 
sitting under the hood, and never really sync-ed with all the rework 
around CameraMetadata and request templates however,

I found this ancient mistake where it was supposed to match, but 
unfortunately didn't, and the development/increment (as new entries were 
added) kept happening on top of it.

https://git.linuxtv.org/libcamera.git/commit/?id=637034742f2b0b7524

I'll mention this as a point of divergence in v3 for this particular patch.

>
>>
>>>       if (!requestTemplate->isValid()) {
>>>           return nullptr;
>>>       }
>>> @@ -1364,6 +1364,16 @@ std::unique_ptr<CameraMetadata> 
>>> CameraCapabilities::requestTemplatePreview() con
>>> requestTemplate->addEntry(ANDROID_CONTROL_AE_TARGET_FPS_RANGE,
>>>                     entry.data.i32, 2);
>>>
>>> +    /*
>>> +     * Get thumbnail sizes from static metadata and add the first 
>>> non-zero
>>> +     * size to the template.
>>> +     */
>>> +    found = 
>>> staticMetadata_->getEntry(ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES,
>>> +                      &entry);
>>> +    ASSERT(found && entry.count >= 4);
>>> +    requestTemplate->addEntry(ANDROID_JPEG_THUMBNAIL_SIZE,
>>> +                  entry.data.i32 + 2, 2);
>>> +
>> If I were to be extra paranoid I would make sure we actually discard
>> (0, 0). The code assumes the first two entries are (0, 0) which is
>> fine as we populate it after all.
>
>
> Not only we populate it, it's a requirement that Size (0,0) should be 
> in the vector /and/ the vector needs to be sorted in ascending order 
> [1] if more sizes are provided with. We do the right thing when 
> populating ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES so I won't be extra 
> paranoid here.
>
>
> [1]: 
> https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics#JPEG_AVAILABLE_THUMBNAIL_SIZES
>
>>
>> If you don't want to
>>
>>          unsigned int j = 0;
>>          while (j < entry.count / 2) {
>>                  if (entry.data.i32[j] == 0 || entry.data.i32[j + 1] 
>> == 0)
>>                          continue;
>>
>> requestTemplate->addEntry(ANDROID_JPEG_THUMBNAIL_SIZE,
>>                                            entry.data.i32 + j, 2);
>>          }
>>
>> Could you at least capture that we assume the first two entries are
>> (0,0) ?


I am re-thinking this. It makes sense. It's one step more defensive than the

     ASSERT(found && entry.count >= 4);

It's atleast for the better.

I'll send a v3 for this patch (the 1/2 has already been merged) and also 
test out the thumbnail generation with the v3 and we can put an end to 
this thumbnail saga...

Thanks for your thoughts!


>
> As said above, it's a requirement for 
> ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES, so should I make it extra 
> clear again here?
>
>>
>> Thanks
>>     j
>>
>>
>>>       uint8_t aeMode = ANDROID_CONTROL_AE_MODE_ON;
>>>       requestTemplate->addEntry(ANDROID_CONTROL_AE_MODE, aeMode);
>>>
>>> -- 
>>> 2.31.1
>>>
Umang Jain Sept. 21, 2021, 11:52 a.m. UTC | #5
On 9/21/21 5:20 PM, Umang Jain wrote:
> Hi Jacopo
>
> On 9/13/21 8:11 PM, Umang Jain wrote:
>> Hi Jacopo
>>
>> On 9/13/21 7:38 PM, Jacopo Mondi wrote:
>>> Hi Umang,
>>>
>>> On Mon, Sep 13, 2021 at 09:31:10AM +0530, Umang Jain wrote:
>>>> Generation of thumbnail is not occuring currently because
>>>> ANDROID_JPEG_THUMBNAIL_SIZE is not set for request metadata passed
>>>> to PostProcessorJpeg::process(). This is a regression introduced in
>>>> 1264628d3c92("android: jpeg: Configure thumbnailer based on request
>>>> metadata").
>>> I see the issue, but I'm not sure those commit was wrong. I mean, what
>>> that commit does that itroduced a regression is:
>>>
>>> --- a/src/android/jpeg/post_processor_jpeg.cpp
>>> +++ b/src/android/jpeg/post_processor_jpeg.cpp
>>> +       ret = requestMetadata.getEntry(ANDROID_JPEG_THUMBNAIL_SIZE, 
>>> &entry);
>>> +       if (ret) {
>>> +               const int32_t *data = entry.data.i32;
>>> +               Size thumbnailSize = { static_cast<uint32_t>(data[0]),
>>> + static_cast<uint32_t>(data[1]) };
>>> +
>>> +               if (thumbnailSize != Size(0, 0)) {
>>> +                       std::vector<unsigned char> thumbnail;
>>> +                       generateThumbnail(source, thumbnailSize, 
>>> &thumbnail);
>>> +                       if (!thumbnail.empty())
>>> +                               exif.setThumbnail(thumbnail, 
>>> Exif::Compression::JPEG);
>>> +               }
>>> +
>>> + resultMetadata->addEntry(ANDROID_JPEG_THUMBNAIL_SIZE, data, 2);
>>> +
>>> +               /* \todo Use this quality as a parameter to the 
>>> encoder */
>>> +               ret = 
>>> requestMetadata.getEntry(ANDROID_JPEG_THUMBNAIL_QUALITY, &entry);
>>> +               if (ret)
>>> + resultMetadata->addEntry(ANDROID_JPEG_THUMBNAIL_QUALITY,
>>> + entry.data.u8, 1);
>>> +       }
>>>
>>>
>>> Which I read as: "If ANDROID_JPEG_THUMBNAIL_SIZE is not specified in
>>> the request's settings, do not populate it in result metadata".
>>>
>>> Is this correct in your opinion, or should we populate it regardless
>>> of the fact the tag was passed in ?
>>
>>
>> This is correct, but the counterpart of the patch seems missing from 
>> that commit, which actually resulted in regression
>>
>>>
>>>> The patch fixes this issue by setting ANDROID_JPEG_THUMBNAIL_SIZE in
>>>> the request metadata template populated by
>>>> CameraCapabilities::requestTemplatePreview(). The value for
>>>> ANDROID_JPEG_THUMBNAIL_SIZE is set to be the first non-zero size
>>>> reported by static metadata ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES.
>>> Let's say just that this patch adds ANDROID_JPEG_THUMBNAIL_SIZE to the
>>> capture request template generated for the preview use case. I wonder
>>> if the JPEG thunbnail size should be part of the preview template now.
>>
>>
>> I wonder that too...
>>
>>>
>>>> Fixes: 1264628d3c92("android: jpeg: Configure thumbnailer based on 
>>>> request metadata")
>>>> Signed-off-by: Umang Jain <umang.jain@ideasonboard.com>
>>>> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
>>>> ---
>>>>   src/android/camera_capabilities.cpp | 14 ++++++++++++--
>>>>   1 file changed, 12 insertions(+), 2 deletions(-)
>>>>
>>>> diff --git a/src/android/camera_capabilities.cpp 
>>>> b/src/android/camera_capabilities.cpp
>>>> index e92bca42..76dddafd 100644
>>>> --- a/src/android/camera_capabilities.cpp
>>>> +++ b/src/android/camera_capabilities.cpp
>>>> @@ -1341,9 +1341,9 @@ std::unique_ptr<CameraMetadata> 
>>>> CameraCapabilities::requestTemplatePreview() con
>>>>   {
>>>>       /*
>>>>        * \todo Keep this in sync with the actual number of entries.
>>>> -     * Currently: 20 entries, 35 bytes
>>>> +     * Currently: 21 entries, 37 bytes
>>>>        */
>>>> -    auto requestTemplate = std::make_unique<CameraMetadata>(21, 36);
>>>> +    auto requestTemplate = std::make_unique<CameraMetadata>(22, 38);
>>> Comment says 21, code says 22.
>>>
>>> It was there already as the comment was not aligned with the code, but
>>> since you're at it you could fix it
>>
>>
>> Looking at both #entries and #bytes, that gives me an impression that 
>> extra entry and data buffer bytes are **intentional**, so I went 
>> ahead with it! Are both of them a typo? I'll need some checking 
>> tomorrow.
>
>
> Indeed, my assumption was a mistake. I think the mismatch was long 
> sitting under the hood, and never really sync-ed with all the rework 
> around CameraMetadata and request templates however,
>
> I found this ancient mistake where it was supposed to match, but 
> unfortunately didn't, and the development/increment (as new entries 
> were added) kept happening on top of it.


errr, I mean s/ancient mistake/ancient commit/

>
> https://git.linuxtv.org/libcamera.git/commit/?id=637034742f2b0b7524
>
> I'll mention this as a point of divergence in v3 for this particular 
> patch.
>
>>
>>>
>>>>       if (!requestTemplate->isValid()) {
>>>>           return nullptr;
>>>>       }
>>>> @@ -1364,6 +1364,16 @@ std::unique_ptr<CameraMetadata> 
>>>> CameraCapabilities::requestTemplatePreview() con
>>>> requestTemplate->addEntry(ANDROID_CONTROL_AE_TARGET_FPS_RANGE,
>>>>                     entry.data.i32, 2);
>>>>
>>>> +    /*
>>>> +     * Get thumbnail sizes from static metadata and add the first 
>>>> non-zero
>>>> +     * size to the template.
>>>> +     */
>>>> +    found = 
>>>> staticMetadata_->getEntry(ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES,
>>>> +                      &entry);
>>>> +    ASSERT(found && entry.count >= 4);
>>>> + requestTemplate->addEntry(ANDROID_JPEG_THUMBNAIL_SIZE,
>>>> +                  entry.data.i32 + 2, 2);
>>>> +
>>> If I were to be extra paranoid I would make sure we actually discard
>>> (0, 0). The code assumes the first two entries are (0, 0) which is
>>> fine as we populate it after all.
>>
>>
>> Not only we populate it, it's a requirement that Size (0,0) should be 
>> in the vector /and/ the vector needs to be sorted in ascending order 
>> [1] if more sizes are provided with. We do the right thing when 
>> populating ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES so I won't be extra 
>> paranoid here.
>>
>>
>> [1]: 
>> https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics#JPEG_AVAILABLE_THUMBNAIL_SIZES
>>
>>>
>>> If you don't want to
>>>
>>>          unsigned int j = 0;
>>>          while (j < entry.count / 2) {
>>>                  if (entry.data.i32[j] == 0 || entry.data.i32[j + 1] 
>>> == 0)
>>>                          continue;
>>>
>>> requestTemplate->addEntry(ANDROID_JPEG_THUMBNAIL_SIZE,
>>>                                            entry.data.i32 + j, 2);
>>>          }
>>>
>>> Could you at least capture that we assume the first two entries are
>>> (0,0) ?
>
>
> I am re-thinking this. It makes sense. It's one step more defensive 
> than the
>
>     ASSERT(found && entry.count >= 4);
>
> It's atleast for the better.
>
> I'll send a v3 for this patch (the 1/2 has already been merged) and 
> also test out the thumbnail generation with the v3 and we can put an 
> end to this thumbnail saga...
>
> Thanks for your thoughts!
>
>
>>
>> As said above, it's a requirement for 
>> ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES, so should I make it extra 
>> clear again here?
>>
>>>
>>> Thanks
>>>     j
>>>
>>>
>>>>       uint8_t aeMode = ANDROID_CONTROL_AE_MODE_ON;
>>>>       requestTemplate->addEntry(ANDROID_CONTROL_AE_MODE, aeMode);
>>>>
>>>> -- 
>>>> 2.31.1
>>>>
Hirokazu Honda Sept. 22, 2021, 6:19 a.m. UTC | #6
Hi Umang,

On Tue, Sep 21, 2021 at 8:52 PM Umang Jain <umang.jain@ideasonboard.com> wrote:
>
>
> On 9/21/21 5:20 PM, Umang Jain wrote:
> > Hi Jacopo
> >
> > On 9/13/21 8:11 PM, Umang Jain wrote:
> >> Hi Jacopo
> >>
> >> On 9/13/21 7:38 PM, Jacopo Mondi wrote:
> >>> Hi Umang,
> >>>
> >>> On Mon, Sep 13, 2021 at 09:31:10AM +0530, Umang Jain wrote:
> >>>> Generation of thumbnail is not occuring currently because
> >>>> ANDROID_JPEG_THUMBNAIL_SIZE is not set for request metadata passed
> >>>> to PostProcessorJpeg::process(). This is a regression introduced in
> >>>> 1264628d3c92("android: jpeg: Configure thumbnailer based on request
> >>>> metadata").
> >>> I see the issue, but I'm not sure those commit was wrong. I mean, what
> >>> that commit does that itroduced a regression is:
> >>>
> >>> --- a/src/android/jpeg/post_processor_jpeg.cpp
> >>> +++ b/src/android/jpeg/post_processor_jpeg.cpp
> >>> +       ret = requestMetadata.getEntry(ANDROID_JPEG_THUMBNAIL_SIZE,
> >>> &entry);
> >>> +       if (ret) {
> >>> +               const int32_t *data = entry.data.i32;
> >>> +               Size thumbnailSize = { static_cast<uint32_t>(data[0]),
> >>> + static_cast<uint32_t>(data[1]) };
> >>> +
> >>> +               if (thumbnailSize != Size(0, 0)) {
> >>> +                       std::vector<unsigned char> thumbnail;
> >>> +                       generateThumbnail(source, thumbnailSize,
> >>> &thumbnail);
> >>> +                       if (!thumbnail.empty())
> >>> +                               exif.setThumbnail(thumbnail,
> >>> Exif::Compression::JPEG);
> >>> +               }
> >>> +
> >>> + resultMetadata->addEntry(ANDROID_JPEG_THUMBNAIL_SIZE, data, 2);
> >>> +
> >>> +               /* \todo Use this quality as a parameter to the
> >>> encoder */
> >>> +               ret =
> >>> requestMetadata.getEntry(ANDROID_JPEG_THUMBNAIL_QUALITY, &entry);
> >>> +               if (ret)
> >>> + resultMetadata->addEntry(ANDROID_JPEG_THUMBNAIL_QUALITY,
> >>> + entry.data.u8, 1);
> >>> +       }
> >>>
> >>>
> >>> Which I read as: "If ANDROID_JPEG_THUMBNAIL_SIZE is not specified in
> >>> the request's settings, do not populate it in result metadata".
> >>>
> >>> Is this correct in your opinion, or should we populate it regardless
> >>> of the fact the tag was passed in ?
> >>
> >>
> >> This is correct, but the counterpart of the patch seems missing from
> >> that commit, which actually resulted in regression
> >>
> >>>
> >>>> The patch fixes this issue by setting ANDROID_JPEG_THUMBNAIL_SIZE in
> >>>> the request metadata template populated by
> >>>> CameraCapabilities::requestTemplatePreview(). The value for
> >>>> ANDROID_JPEG_THUMBNAIL_SIZE is set to be the first non-zero size
> >>>> reported by static metadata ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES.
> >>> Let's say just that this patch adds ANDROID_JPEG_THUMBNAIL_SIZE to the
> >>> capture request template generated for the preview use case. I wonder
> >>> if the JPEG thunbnail size should be part of the preview template now.
> >>
> >>
> >> I wonder that too...
> >>
> >>>
> >>>> Fixes: 1264628d3c92("android: jpeg: Configure thumbnailer based on
> >>>> request metadata")
> >>>> Signed-off-by: Umang Jain <umang.jain@ideasonboard.com>
> >>>> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>

Reviewed-by: Hirokazu Honda <hiroh@chromium.org>

> >>>> ---
> >>>>   src/android/camera_capabilities.cpp | 14 ++++++++++++--
> >>>>   1 file changed, 12 insertions(+), 2 deletions(-)
> >>>>
> >>>> diff --git a/src/android/camera_capabilities.cpp
> >>>> b/src/android/camera_capabilities.cpp
> >>>> index e92bca42..76dddafd 100644
> >>>> --- a/src/android/camera_capabilities.cpp
> >>>> +++ b/src/android/camera_capabilities.cpp
> >>>> @@ -1341,9 +1341,9 @@ std::unique_ptr<CameraMetadata>
> >>>> CameraCapabilities::requestTemplatePreview() con
> >>>>   {
> >>>>       /*
> >>>>        * \todo Keep this in sync with the actual number of entries.
> >>>> -     * Currently: 20 entries, 35 bytes
> >>>> +     * Currently: 21 entries, 37 bytes
> >>>>        */
> >>>> -    auto requestTemplate = std::make_unique<CameraMetadata>(21, 36);
> >>>> +    auto requestTemplate = std::make_unique<CameraMetadata>(22, 38);
> >>> Comment says 21, code says 22.
> >>>
> >>> It was there already as the comment was not aligned with the code, but
> >>> since you're at it you could fix it
> >>
> >>
> >> Looking at both #entries and #bytes, that gives me an impression that
> >> extra entry and data buffer bytes are **intentional**, so I went
> >> ahead with it! Are both of them a typo? I'll need some checking
> >> tomorrow.
> >
> >
> > Indeed, my assumption was a mistake. I think the mismatch was long
> > sitting under the hood, and never really sync-ed with all the rework
> > around CameraMetadata and request templates however,
> >
> > I found this ancient mistake where it was supposed to match, but
> > unfortunately didn't, and the development/increment (as new entries
> > were added) kept happening on top of it.
>
>
> errr, I mean s/ancient mistake/ancient commit/
>
> >
> > https://git.linuxtv.org/libcamera.git/commit/?id=637034742f2b0b7524
> >
> > I'll mention this as a point of divergence in v3 for this particular
> > patch.
> >
> >>
> >>>
> >>>>       if (!requestTemplate->isValid()) {
> >>>>           return nullptr;
> >>>>       }
> >>>> @@ -1364,6 +1364,16 @@ std::unique_ptr<CameraMetadata>
> >>>> CameraCapabilities::requestTemplatePreview() con
> >>>> requestTemplate->addEntry(ANDROID_CONTROL_AE_TARGET_FPS_RANGE,
> >>>>                     entry.data.i32, 2);
> >>>>
> >>>> +    /*
> >>>> +     * Get thumbnail sizes from static metadata and add the first
> >>>> non-zero
> >>>> +     * size to the template.
> >>>> +     */
> >>>> +    found =
> >>>> staticMetadata_->getEntry(ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES,
> >>>> +                      &entry);
> >>>> +    ASSERT(found && entry.count >= 4);
> >>>> + requestTemplate->addEntry(ANDROID_JPEG_THUMBNAIL_SIZE,
> >>>> +                  entry.data.i32 + 2, 2);
> >>>> +
> >>> If I were to be extra paranoid I would make sure we actually discard
> >>> (0, 0). The code assumes the first two entries are (0, 0) which is
> >>> fine as we populate it after all.
> >>
> >>
> >> Not only we populate it, it's a requirement that Size (0,0) should be
> >> in the vector /and/ the vector needs to be sorted in ascending order
> >> [1] if more sizes are provided with. We do the right thing when
> >> populating ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES so I won't be extra
> >> paranoid here.
> >>
> >>
> >> [1]:
> >> https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics#JPEG_AVAILABLE_THUMBNAIL_SIZES
> >>
> >>>
> >>> If you don't want to
> >>>
> >>>          unsigned int j = 0;
> >>>          while (j < entry.count / 2) {
> >>>                  if (entry.data.i32[j] == 0 || entry.data.i32[j + 1]
> >>> == 0)
> >>>                          continue;
> >>>
> >>> requestTemplate->addEntry(ANDROID_JPEG_THUMBNAIL_SIZE,
> >>>                                            entry.data.i32 + j, 2);
> >>>          }
> >>>
> >>> Could you at least capture that we assume the first two entries are
> >>> (0,0) ?
> >
> >
> > I am re-thinking this. It makes sense. It's one step more defensive
> > than the
> >
> >     ASSERT(found && entry.count >= 4);
> >
> > It's atleast for the better.
> >
> > I'll send a v3 for this patch (the 1/2 has already been merged) and
> > also test out the thumbnail generation with the v3 and we can put an
> > end to this thumbnail saga...
> >
> > Thanks for your thoughts!
> >
> >
> >>
> >> As said above, it's a requirement for
> >> ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES, so should I make it extra
> >> clear again here?
> >>
> >>>
> >>> Thanks
> >>>     j
> >>>
> >>>
> >>>>       uint8_t aeMode = ANDROID_CONTROL_AE_MODE_ON;
> >>>>       requestTemplate->addEntry(ANDROID_CONTROL_AE_MODE, aeMode);
> >>>>
> >>>> --
> >>>> 2.31.1
> >>>>

Patch
diff mbox series

diff --git a/src/android/camera_capabilities.cpp b/src/android/camera_capabilities.cpp
index e92bca42..76dddafd 100644
--- a/src/android/camera_capabilities.cpp
+++ b/src/android/camera_capabilities.cpp
@@ -1341,9 +1341,9 @@  std::unique_ptr<CameraMetadata> CameraCapabilities::requestTemplatePreview() con
 {
 	/*
 	 * \todo Keep this in sync with the actual number of entries.
-	 * Currently: 20 entries, 35 bytes
+	 * Currently: 21 entries, 37 bytes
 	 */
-	auto requestTemplate = std::make_unique<CameraMetadata>(21, 36);
+	auto requestTemplate = std::make_unique<CameraMetadata>(22, 38);
 	if (!requestTemplate->isValid()) {
 		return nullptr;
 	}
@@ -1364,6 +1364,16 @@  std::unique_ptr<CameraMetadata> CameraCapabilities::requestTemplatePreview() con
 	requestTemplate->addEntry(ANDROID_CONTROL_AE_TARGET_FPS_RANGE,
 				  entry.data.i32, 2);
 
+	/*
+	 * Get thumbnail sizes from static metadata and add the first non-zero
+	 * size to the template.
+	 */
+	found = staticMetadata_->getEntry(ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES,
+					  &entry);
+	ASSERT(found && entry.count >= 4);
+	requestTemplate->addEntry(ANDROID_JPEG_THUMBNAIL_SIZE,
+				  entry.data.i32 + 2, 2);
+
 	uint8_t aeMode = ANDROID_CONTROL_AE_MODE_ON;
 	requestTemplate->addEntry(ANDROID_CONTROL_AE_MODE, aeMode);