Camera: call encodeJPEGR method in libjpegrecoverymap

Bug: b/20133417, b/252835416
Test: Test: atest -c -d \
cts/tests/camera/src/android/hardware/camera2/cts/ImageReaderTest.java#testJpegR

Change-Id: I4a85a915f6b91022b605f5c9fb86aafbb8cce72a
diff --git a/services/camera/libcameraservice/api2/JpegRCompositeStream.cpp b/services/camera/libcameraservice/api2/JpegRCompositeStream.cpp
index 367a0c8..8f9d813 100644
--- a/services/camera/libcameraservice/api2/JpegRCompositeStream.cpp
+++ b/services/camera/libcameraservice/api2/JpegRCompositeStream.cpp
@@ -26,6 +26,7 @@
 
 #include "common/CameraProviderManager.h"
 #include <gui/Surface.h>
+#include <jpegrecoverymap/recoverymap.h>
 #include <utils/ExifUtils.h>
 #include <utils/Log.h>
 #include "utils/SessionConfigurationUtils.h"
@@ -225,19 +226,19 @@
     int fenceFd;
     void *dstBuffer;
 
-    size_t maxJpegBufferSize = 0;
+    size_t maxJpegRBufferSize = 0;
     if (mMaxJpegBufferSize > 0) {
         // If this is an ultra high resolution sensor and the input frames size
         // is > default res jpeg.
         if (mUHRMaxJpegSize.width != 0 &&
                 inputFrame.jpegBuffer.width * inputFrame.jpegBuffer.height >
                 mDefaultMaxJpegSize.width * mDefaultMaxJpegSize.height) {
-            maxJpegBufferSize = mUHRMaxJpegBufferSize;
+            maxJpegRBufferSize = mUHRMaxJpegBufferSize;
         } else {
-            maxJpegBufferSize = mMaxJpegBufferSize;
+            maxJpegRBufferSize = mMaxJpegBufferSize;
         }
     } else {
-        maxJpegBufferSize = inputFrame.p010Buffer.width * inputFrame.p010Buffer.height;
+        maxJpegRBufferSize = inputFrame.p010Buffer.width * inputFrame.p010Buffer.height;
     }
 
     uint8_t jpegQuality = 100;
@@ -252,10 +253,10 @@
         jpegOrientation = entry.data.i32[0];
     }
 
-    if ((res = native_window_set_buffers_dimensions(mOutputSurface.get(), maxJpegBufferSize, 1))
+    if ((res = native_window_set_buffers_dimensions(mOutputSurface.get(), maxJpegRBufferSize, 1))
             != OK) {
         ALOGE("%s: Unable to configure stream buffer dimensions"
-                " %zux%u for stream %d", __FUNCTION__, maxJpegBufferSize, 1U, mP010StreamId);
+                " %zux%u for stream %d", __FUNCTION__, maxJpegRBufferSize, 1U, mP010StreamId);
         return res;
     }
 
@@ -276,31 +277,68 @@
         return res;
     }
 
-    if ((gb->getWidth() < maxJpegBufferSize) || (gb->getHeight() != 1)) {
+    if ((gb->getWidth() < maxJpegRBufferSize) || (gb->getHeight() != 1)) {
         ALOGE("%s: Blob buffer size mismatch, expected %zux%u received %dx%d", __FUNCTION__,
-                maxJpegBufferSize, 1, gb->getWidth(), gb->getHeight());
+                maxJpegRBufferSize, 1, gb->getWidth(), gb->getHeight());
         outputANW->cancelBuffer(mOutputSurface.get(), anb, /*fence*/ -1);
         return BAD_VALUE;
     }
 
-    if (mOutputColorSpace == ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_DISPLAY_P3) {
-        // Configure Jpeg/R for P3 output and possibly input in case of concurrent SDR Jpeg support
-    } else {
-        // Configure Jpeg/R for SRGB output
-    }
-
-    size_t actualJpegSize = 0;
+    size_t actualJpegRSize = 0;
     if (mSupportInternalJpeg) {
-        actualJpegSize = android::camera2::JpegProcessor::findJpegSize(inputFrame.jpegBuffer.data,
+        recoverymap::jpegr_uncompressed_struct p010;
+        recoverymap::jpegr_compressed_struct jpeg;
+        recoverymap::jpegr_compressed_struct jpegR;
+
+        p010.height = inputFrame.p010Buffer.height;
+        p010.width = inputFrame.p010Buffer.width;
+        p010.colorGamut = recoverymap::jpegr_color_gamut::JPEGR_COLORGAMUT_BT2100;
+        size_t yChannelSizeInByte = p010.width * p010.height * 2;
+        size_t uvChannelSizeInByte = p010.width * p010.height;
+        p010.data = new uint8_t[yChannelSizeInByte + uvChannelSizeInByte];
+        std::unique_ptr<uint8_t[]> p010_data;
+        p010_data.reset(reinterpret_cast<uint8_t*>(p010.data));
+        memcpy((uint8_t*)p010.data, inputFrame.p010Buffer.data, yChannelSizeInByte);
+        memcpy((uint8_t*)p010.data + yChannelSizeInByte, inputFrame.p010Buffer.dataCb,
+               uvChannelSizeInByte);
+
+        jpeg.data = inputFrame.jpegBuffer.data;
+        jpeg.length = android::camera2::JpegProcessor::findJpegSize(inputFrame.jpegBuffer.data,
                 inputFrame.jpegBuffer.width);
-        if (actualJpegSize == 0) {
+        if (jpeg.length == 0) {
             ALOGW("%s: Failed to find input jpeg size, default to using entire buffer!",
                     __FUNCTION__);
-            actualJpegSize = inputFrame.jpegBuffer.width;
+            jpeg.length = inputFrame.jpegBuffer.width;
         }
-        if (actualJpegSize <= maxJpegBufferSize) {
-            memcpy(dstBuffer, inputFrame.jpegBuffer.data, actualJpegSize);
+
+        if (mOutputColorSpace == ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_DISPLAY_P3) {
+            jpeg.colorGamut = recoverymap::jpegr_color_gamut::JPEGR_COLORGAMUT_P3;
+        } else {
+            jpeg.colorGamut = recoverymap::jpegr_color_gamut::JPEGR_COLORGAMUT_BT709;
         }
+
+        recoverymap::jpegr_transfer_function transferFunction;
+        switch (mP010DynamicRange) {
+            case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HDR10:
+            case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HDR10_PLUS:
+                transferFunction = recoverymap::jpegr_transfer_function::JPEGR_TF_PQ;
+                break;
+            default:
+                transferFunction = recoverymap::jpegr_transfer_function::JPEGR_TF_HLG;
+        }
+
+        jpegR.data = dstBuffer;
+        jpegR.maxLength = maxJpegRBufferSize;
+
+        recoverymap::RecoveryMap recoveryMap;
+        res = recoveryMap.encodeJPEGR(&p010, &jpeg, transferFunction, &jpegR);
+        if (res != OK) {
+            ALOGE("%s: Error trying to encode JPEG/R: %s (%d)", __FUNCTION__, strerror(-res), res);
+            return res;
+        }
+
+        actualJpegRSize = jpegR.length;
+        p010_data.release();
     } else {
         const uint8_t* exifBuffer = nullptr;
         size_t exifBufferSize = 0;
@@ -316,10 +354,8 @@
         }
     }
 
-    //TODO: Process JpegR here and retrieve the final jpeg/r size
-
-    size_t finalJpegSize = actualJpegSize + sizeof(CameraBlob);
-    if (finalJpegSize > maxJpegBufferSize) {
+    size_t finalJpegRSize = actualJpegRSize + sizeof(CameraBlob);
+    if (finalJpegRSize > maxJpegRBufferSize) {
         ALOGE("%s: Final jpeg buffer not large enough for the jpeg blob header", __FUNCTION__);
         outputANW->cancelBuffer(mOutputSurface.get(), anb, /*fence*/ -1);
         return NO_MEMORY;
@@ -332,12 +368,12 @@
         return res;
     }
 
-    ALOGV("%s: Final jpeg size: %zu", __func__, finalJpegSize);
+    ALOGV("%s: Final jpeg size: %zu", __func__, finalJpegRSize);
     uint8_t* header = static_cast<uint8_t *> (dstBuffer) +
         (gb->getWidth() - sizeof(CameraBlob));
     CameraBlob blobHeader = {
         .blobId = CameraBlobId::JPEG,
-        .blobSizeBytes = static_cast<int32_t>(actualJpegSize)
+        .blobSizeBytes = static_cast<int32_t>(actualJpegRSize)
     };
     memcpy(header, &blobHeader, sizeof(CameraBlob));
     outputANW->queueBuffer(mOutputSurface.get(), anb, /*fence*/ -1);