C2SoftAvc: handle flexible YUV

Bug: 182286649
Test: atest android.video.cts.VideoEncoderDecoderTest#testAvcGoog0Perf1920x1080
Change-Id: I7cb2ed2cedf39a534866ecd6ac72ceb8512696ac
diff --git a/media/codec2/components/avc/C2SoftAvcDec.cpp b/media/codec2/components/avc/C2SoftAvcDec.cpp
index e8287f9..f4a6e17 100644
--- a/media/codec2/components/avc/C2SoftAvcDec.cpp
+++ b/media/codec2/components/avc/C2SoftAvcDec.cpp
@@ -22,6 +22,7 @@
 
 #include <C2Debug.h>
 #include <C2PlatformSupport.h>
+#include <Codec2BufferUtils.h>
 #include <Codec2Mapper.h>
 #include <SimpleC2Interface.h>
 
@@ -331,6 +332,14 @@
     free(mem);
 }
 
+static IV_COLOR_FORMAT_T GetIvColorFormat() {
+    static IV_COLOR_FORMAT_T sColorFormat =
+        (GetYuv420FlexibleLayout() == FLEX_LAYOUT_SEMIPLANAR_UV) ? IV_YUV_420SP_UV :
+        (GetYuv420FlexibleLayout() == FLEX_LAYOUT_SEMIPLANAR_VU) ? IV_YUV_420SP_VU :
+        IV_YUV_420P;
+    return sColorFormat;
+}
+
 C2SoftAvcDec::C2SoftAvcDec(
         const char *name,
         c2_node_id_t id,
@@ -339,7 +348,6 @@
       mIntf(intfImpl),
       mDecHandle(nullptr),
       mOutBufferFlush(nullptr),
-      mIvColorFormat(IV_YUV_420P),
       mOutputDelay(kDefaultOutputDelay),
       mWidth(320),
       mHeight(240),
@@ -418,7 +426,13 @@
     s_create_ip.s_ivd_create_ip_t.u4_size = sizeof(ivdext_create_ip_t);
     s_create_ip.s_ivd_create_ip_t.e_cmd = IVD_CMD_CREATE;
     s_create_ip.s_ivd_create_ip_t.u4_share_disp_buf = 0;
-    s_create_ip.s_ivd_create_ip_t.e_output_format = mIvColorFormat;
+    s_create_ip.s_ivd_create_ip_t.e_output_format = GetIvColorFormat();
+    switch (s_create_ip.s_ivd_create_ip_t.e_output_format) {
+        case IV_YUV_420P:       ALOGD("Flex Planar");           break;
+        case IV_YUV_420SP_UV:   ALOGD("Flex Semi-planar UV");   break;
+        case IV_YUV_420SP_VU:   ALOGD("Flex Semi-planar VU");   break;
+        default:                ALOGD("Unknown");               break;
+    }
     s_create_ip.s_ivd_create_ip_t.pf_aligned_alloc = ivd_aligned_malloc;
     s_create_ip.s_ivd_create_ip_t.pf_aligned_free = ivd_aligned_free;
     s_create_ip.s_ivd_create_ip_t.pv_mem_ctxt = nullptr;
@@ -555,8 +569,12 @@
         ps_decode_ip->u4_num_Bytes = 0;
     }
     ps_decode_ip->s_out_buffer.u4_min_out_buf_size[0] = lumaSize;
-    ps_decode_ip->s_out_buffer.u4_min_out_buf_size[1] = chromaSize;
-    ps_decode_ip->s_out_buffer.u4_min_out_buf_size[2] = chromaSize;
+    if (GetIvColorFormat() == IV_YUV_420P) {
+        ps_decode_ip->s_out_buffer.u4_min_out_buf_size[1] = chromaSize;
+        ps_decode_ip->s_out_buffer.u4_min_out_buf_size[2] = chromaSize;
+    } else {
+        ps_decode_ip->s_out_buffer.u4_min_out_buf_size[1] = chromaSize * 2;
+    }
     if (outBuffer) {
         if (outBuffer->height() < displayHeight) {
             ALOGE("Output buffer too small: provided (%dx%d) required (%ux%u)",
@@ -565,13 +583,23 @@
         }
         ps_decode_ip->s_out_buffer.pu1_bufs[0] = outBuffer->data()[C2PlanarLayout::PLANE_Y];
         ps_decode_ip->s_out_buffer.pu1_bufs[1] = outBuffer->data()[C2PlanarLayout::PLANE_U];
-        ps_decode_ip->s_out_buffer.pu1_bufs[2] = outBuffer->data()[C2PlanarLayout::PLANE_V];
+        if (GetIvColorFormat() == IV_YUV_420P) {
+            ps_decode_ip->s_out_buffer.pu1_bufs[2] = outBuffer->data()[C2PlanarLayout::PLANE_V];
+        } else if (GetIvColorFormat() == IV_YUV_420SP_VU) {
+            ps_decode_ip->s_out_buffer.pu1_bufs[1] = outBuffer->data()[C2PlanarLayout::PLANE_V];
+        }
     } else {
         ps_decode_ip->s_out_buffer.pu1_bufs[0] = mOutBufferFlush;
         ps_decode_ip->s_out_buffer.pu1_bufs[1] = mOutBufferFlush + lumaSize;
-        ps_decode_ip->s_out_buffer.pu1_bufs[2] = mOutBufferFlush + lumaSize + chromaSize;
+        if (GetIvColorFormat() == IV_YUV_420P) {
+            ps_decode_ip->s_out_buffer.pu1_bufs[2] = mOutBufferFlush + lumaSize + chromaSize;
+        }
     }
-    ps_decode_ip->s_out_buffer.u4_num_bufs = 3;
+    if (GetIvColorFormat() == IV_YUV_420P) {
+        ps_decode_ip->s_out_buffer.u4_num_bufs = 3;
+    } else {
+        ps_decode_ip->s_out_buffer.u4_num_bufs = 2;
+    }
     ps_decode_op->u4_size = sizeof(ih264d_video_decode_op_t);
 
     return true;
@@ -781,7 +809,7 @@
         mOutBlock.reset();
     }
     if (!mOutBlock) {
-        uint32_t format = HAL_PIXEL_FORMAT_YV12;
+        uint32_t format = HAL_PIXEL_FORMAT_YCBCR_420_888;
         C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
         c2_status_t err =
             pool->fetchGraphicBlock(ALIGN32(mWidth), mHeight, format, usage, &mOutBlock);
@@ -797,8 +825,6 @@
 }
 
 // TODO: can overall error checking be improved?
-// TODO: allow configuration of color format and usage for graphic buffers instead
-//       of hard coding them to HAL_PIXEL_FORMAT_YV12
 // TODO: pass coloraspects information to surface
 // TODO: test support for dynamic change in resolution
 // TODO: verify if the decoder sent back all frames
diff --git a/media/codec2/components/avc/C2SoftAvcDec.h b/media/codec2/components/avc/C2SoftAvcDec.h
index 5c07d29..ed99ad1 100644
--- a/media/codec2/components/avc/C2SoftAvcDec.h
+++ b/media/codec2/components/avc/C2SoftAvcDec.h
@@ -155,7 +155,6 @@
     uint8_t *mOutBufferFlush;
 
     size_t mNumCores;
-    IV_COLOR_FORMAT_T mIvColorFormat;
     uint32_t mOutputDelay;
     uint32_t mWidth;
     uint32_t mHeight;
diff --git a/media/codec2/components/avc/C2SoftAvcEnc.cpp b/media/codec2/components/avc/C2SoftAvcEnc.cpp
index bab651f..fc5b75d 100644
--- a/media/codec2/components/avc/C2SoftAvcEnc.cpp
+++ b/media/codec2/components/avc/C2SoftAvcEnc.cpp
@@ -454,11 +454,19 @@
 
 }  // namespace
 
+static IV_COLOR_FORMAT_T GetIvColorFormat() {
+    static IV_COLOR_FORMAT_T sColorFormat =
+        (GetYuv420FlexibleLayout() == FLEX_LAYOUT_SEMIPLANAR_UV) ? IV_YUV_420SP_UV :
+        (GetYuv420FlexibleLayout() == FLEX_LAYOUT_SEMIPLANAR_VU) ? IV_YUV_420SP_VU :
+        IV_YUV_420P;
+    return sColorFormat;
+}
+
 C2SoftAvcEnc::C2SoftAvcEnc(
         const char *name, c2_node_id_t id, const std::shared_ptr<IntfImpl> &intfImpl)
     : SimpleC2Component(std::make_shared<SimpleInterface<IntfImpl>>(name, id, intfImpl)),
       mIntf(intfImpl),
-      mIvVideoColorFormat(IV_YUV_420P),
+      mIvVideoColorFormat(GetIvColorFormat()),
       mAVCEncProfile(IV_PROFILE_BASE),
       mAVCEncLevel(41),
       mStarted(false),
@@ -1026,8 +1034,7 @@
     // Assume worst case output buffer size to be equal to number of bytes in input
     mOutBufferSize = std::max(width * height * 3 / 2, kMinOutBufferSize);
 
-    // TODO
-    mIvVideoColorFormat = IV_YUV_420P;
+    mIvVideoColorFormat = GetIvColorFormat();
 
     ALOGD("Params width %d height %d level %d colorFormat %d bframes %d", width,
             height, mAVCEncLevel, mIvVideoColorFormat, mBframes);
@@ -1325,7 +1332,6 @@
               mSize->width, input->height(), mSize->height);
         return C2_BAD_VALUE;
     }
-    ALOGV("width = %d, height = %d", input->width(), input->height());
     const C2PlanarLayout &layout = input->layout();
     uint8_t *yPlane = const_cast<uint8_t *>(input->data()[C2PlanarLayout::PLANE_Y]);
     uint8_t *uPlane = const_cast<uint8_t *>(input->data()[C2PlanarLayout::PLANE_U]);
@@ -1362,7 +1368,8 @@
                 return C2_BAD_VALUE;
             }
 
-            if (layout.planes[layout.PLANE_Y].colInc == 1
+            if (mIvVideoColorFormat == IV_YUV_420P
+                    && layout.planes[layout.PLANE_Y].colInc == 1
                     && layout.planes[layout.PLANE_U].colInc == 1
                     && layout.planes[layout.PLANE_V].colInc == 1
                     && uStride == vStride
@@ -1370,21 +1377,61 @@
                 // I420 compatible - already set up above
                 break;
             }
+            if (mIvVideoColorFormat == IV_YUV_420SP_UV
+                    && layout.planes[layout.PLANE_Y].colInc == 1
+                    && layout.planes[layout.PLANE_U].colInc == 2
+                    && layout.planes[layout.PLANE_V].colInc == 2
+                    && uStride == vStride
+                    && yStride == vStride
+                    && uPlane + 1 == vPlane) {
+                // NV12 compatible - already set up above
+                break;
+            }
+            if (mIvVideoColorFormat == IV_YUV_420SP_VU
+                    && layout.planes[layout.PLANE_Y].colInc == 1
+                    && layout.planes[layout.PLANE_U].colInc == 2
+                    && layout.planes[layout.PLANE_V].colInc == 2
+                    && uStride == vStride
+                    && yStride == vStride
+                    && uPlane == vPlane + 1) {
+                // NV21 compatible - already set up above
+                break;
+            }
 
             // copy to I420
             yStride = width;
             uStride = vStride = yStride / 2;
             MemoryBlock conversionBuffer = mConversionBuffers.fetch(yPlaneSize * 3 / 2);
             mConversionBuffersInUse.emplace(conversionBuffer.data(), conversionBuffer);
-            MediaImage2 img = CreateYUV420PlanarMediaImage2(width, height, yStride, height);
+            MediaImage2 img;
+            switch (mIvVideoColorFormat) {
+                case IV_YUV_420P:
+                    img = CreateYUV420PlanarMediaImage2(width, height, yStride, height);
+                    yPlane = conversionBuffer.data();
+                    uPlane = yPlane + yPlaneSize;
+                    vPlane = uPlane + yPlaneSize / 4;
+                    break;
+                case IV_YUV_420SP_VU:
+                    img = CreateYUV420SemiPlanarMediaImage2(width, height, yStride, height);
+                    img.mPlane[MediaImage2::U].mOffset++;
+                    img.mPlane[MediaImage2::V].mOffset--;
+                    yPlane = conversionBuffer.data();
+                    vPlane = yPlane + yPlaneSize;
+                    uPlane = vPlane + 1;
+                    break;
+                case IV_YUV_420SP_UV:
+                default:
+                    img = CreateYUV420SemiPlanarMediaImage2(width, height, yStride, height);
+                    yPlane = conversionBuffer.data();
+                    uPlane = yPlane + yPlaneSize;
+                    vPlane = uPlane + 1;
+                    break;
+            }
             status_t err = ImageCopy(conversionBuffer.data(), &img, *input);
             if (err != OK) {
                 ALOGE("Buffer conversion failed: %d", err);
                 return C2_BAD_VALUE;
             }
-            yPlane = conversionBuffer.data();
-            uPlane = yPlane + yPlaneSize;
-            vPlane = uPlane + yPlaneSize / 4;
             break;
 
         }
@@ -1430,15 +1477,17 @@
             break;
         }
 
-        case IV_YUV_420SP_UV:
         case IV_YUV_420SP_VU:
+            uPlane = vPlane;
+            [[fallthrough]];
+        case IV_YUV_420SP_UV:
         default:
         {
             ps_inp_raw_buf->apv_bufs[0] = yPlane;
             ps_inp_raw_buf->apv_bufs[1] = uPlane;
 
             ps_inp_raw_buf->au4_wd[0] = mSize->width;
-            ps_inp_raw_buf->au4_wd[1] = mSize->width;
+            ps_inp_raw_buf->au4_wd[1] = mSize->width / 2;
 
             ps_inp_raw_buf->au4_ht[0] = mSize->height;
             ps_inp_raw_buf->au4_ht[1] = mSize->height / 2;