codecs: send metadata to the host side

From T and forward, the media framework
will configure addition color aspects.
Such information will be sent to host
side for it to pick the right yuv-to-rgb
color conversion shader.

Bug: 239368327

Change-Id: I6c85a2e04224526dfb93711bbe541ddca84d8fe8
diff --git a/system/codecs/c2/decoders/avcdec/C2GoldfishAvcDec.cpp b/system/codecs/c2/decoders/avcdec/C2GoldfishAvcDec.cpp
index 963558e..cbc7069 100644
--- a/system/codecs/c2/decoders/avcdec/C2GoldfishAvcDec.cpp
+++ b/system/codecs/c2/decoders/avcdec/C2GoldfishAvcDec.cpp
@@ -338,6 +338,8 @@
         if (me.v.matrix > C2Color::MATRIX_OTHER) {
             me.set().matrix = C2Color::MATRIX_OTHER;
         }
+        DDD("default primaries %d default range %d", me.set().primaries,
+            me.set().range);
         return C2R::Ok();
     }
 
@@ -357,6 +359,8 @@
         if (me.v.matrix > C2Color::MATRIX_OTHER) {
             me.set().matrix = C2Color::MATRIX_OTHER;
         }
+        DDD("coded primaries %d coded range %d", me.set().primaries,
+            me.set().range);
         return C2R::Ok();
     }
 
@@ -367,6 +371,7 @@
         (void)mayBlock;
         // take default values for all unspecified fields, and coded values for
         // specified ones
+        DDD("before change primaries %d range %d", me.v.primaries, me.v.range);
         me.set().range =
             coded.v.range == RANGE_UNSPECIFIED ? def.v.range : coded.v.range;
         me.set().primaries = coded.v.primaries == PRIMARIES_UNSPECIFIED
@@ -377,6 +382,8 @@
                                 : coded.v.transfer;
         me.set().matrix = coded.v.matrix == MATRIX_UNSPECIFIED ? def.v.matrix
                                                                : coded.v.matrix;
+
+        DDD("after change primaries %d range %d", me.v.primaries, me.v.range);
         return C2R::Ok();
     }
 
@@ -388,7 +395,13 @@
 
     int height() const { return mSize->height; }
 
-  private:
+    int primaries() const { return mColorAspects->primaries; }
+
+    int range() const { return mColorAspects->range; }
+
+    int transfer() const { return mColorAspects->transfer; }
+
+   private:
     std::shared_ptr<C2StreamProfileLevelInfo::input> mProfileLevel;
     std::shared_ptr<C2StreamPictureSizeInfo::output> mSize;
     std::shared_ptr<C2StreamMaxPictureSizeTuning::output> mMaxSize;
@@ -496,6 +509,30 @@
     return C2_OK;
 }
 
+void C2GoldfishAvcDec::sendMetadata() {
+    // compare and send if changed
+    MetaDataColorAspects currentMetaData = {1, 0, 0, 0};
+    currentMetaData.primaries = mIntf->primaries();
+    currentMetaData.range = mIntf->range();
+    currentMetaData.transfer = mIntf->transfer();
+
+    DDD("metadata primaries %d range %d transfer %d",
+            (int)(currentMetaData.primaries),
+            (int)(currentMetaData.range),
+            (int)(currentMetaData.transfer)
+       );
+
+    if (mSentMetadata.primaries == currentMetaData.primaries &&
+        mSentMetadata.range == currentMetaData.range &&
+        mSentMetadata.transfer == currentMetaData.transfer) {
+        DDD("metadata is the same, no need to update");
+        return;
+    }
+    std::swap(mSentMetadata, currentMetaData);
+
+    mContext->sendMetadata(&(mSentMetadata));
+}
+
 status_t C2GoldfishAvcDec::createDecoder() {
 
     DDD("creating avc context now w %d h %d", mWidth, mHeight);
@@ -720,7 +757,6 @@
 }
 
 void C2GoldfishAvcDec::getVuiParams(h264_image_t &img) {
-
     VuiColorAspects vuiColorAspects;
     vuiColorAspects.primaries = img.color_primaries;
     vuiColorAspects.transfer = img.color_trc;
@@ -969,6 +1005,8 @@
                 } // end of whChanged
             } // end of isSpsFrame
 
+            sendMetadata();
+
             uint32_t delay;
             GETTIME(&mTimeStart, nullptr);
             TIME_DIFF(mTimeEnd, mTimeStart, delay);
diff --git a/system/codecs/c2/decoders/avcdec/C2GoldfishAvcDec.h b/system/codecs/c2/decoders/avcdec/C2GoldfishAvcDec.h
index 5b5e760..d90b11a 100644
--- a/system/codecs/c2/decoders/avcdec/C2GoldfishAvcDec.h
+++ b/system/codecs/c2/decoders/avcdec/C2GoldfishAvcDec.h
@@ -142,6 +142,10 @@
         }
     } mBitstreamColorAspects;
 
+    MetaDataColorAspects mSentMetadata = {1, 0, 0, 0};
+
+    void sendMetadata();
+
     // profile
     struct timeval mTimeStart;
     struct timeval mTimeEnd;
diff --git a/system/codecs/c2/decoders/avcdec/MediaH264Decoder.cpp b/system/codecs/c2/decoders/avcdec/MediaH264Decoder.cpp
index 7909aa9..6560772 100644
--- a/system/codecs/c2/decoders/avcdec/MediaH264Decoder.cpp
+++ b/system/codecs/c2/decoders/avcdec/MediaH264Decoder.cpp
@@ -49,7 +49,7 @@
         }
         mSlot = slot;
         mAddressOffSet = static_cast<unsigned int>(mSlot) * (1 << 20);
-        DDD("got memory lot %d addrr %x", mSlot, mAddressOffSet);
+        DDD("got memory lot %d addrr %lu", mSlot, mAddressOffSet);
         mHasAddressSpaceMemory = true;
     }
     transport->writeParam(mVersion, 0, mAddressOffSet);
@@ -62,7 +62,7 @@
                              MediaOperation::InitContext, mAddressOffSet);
     auto *retptr = transport->getReturnAddr(mAddressOffSet);
     mHostHandle = *(uint64_t *)(retptr);
-    DDD("initH264Context: got handle to host %lld", mHostHandle);
+    DDD("initH264Context: got handle to host %lu", mHostHandle);
 }
 
 void MediaH264Decoder::resetH264Context(unsigned int width, unsigned int height,
@@ -87,7 +87,7 @@
 
 void MediaH264Decoder::destroyH264Context() {
 
-    DDD("return memory lot %d addrr %x", (int)(mAddressOffSet >> 23),
+    DDD("return memory lot %d addrr %lu", (int)(mAddressOffSet >> 23),
         mAddressOffSet);
     auto transport = GoldfishMediaTransport::getInstance();
     transport->writeParam((uint64_t)mHostHandle, 0, mAddressOffSet);
@@ -99,7 +99,7 @@
 
 h264_result_t MediaH264Decoder::decodeFrame(uint8_t *img, size_t szBytes,
                                             uint64_t pts) {
-    DDD("decode frame: use handle to host %lld", mHostHandle);
+    DDD("decode frame: use handle to host %lu", mHostHandle);
     h264_result_t res = {0, 0};
     if (!mHasAddressSpaceMemory) {
         ALOGE("%s no address space memory", __func__);
@@ -126,12 +126,28 @@
     return res;
 }
 
+void MediaH264Decoder::sendMetadata(MetaDataColorAspects *ptr) {
+    DDD("send metadata to host %p", ptr);
+    if (!mHasAddressSpaceMemory) {
+        ALOGE("%s no address space memory", __func__);
+        return;
+    }
+    MetaDataColorAspects& meta = *ptr;
+    auto transport = GoldfishMediaTransport::getInstance();
+    transport->writeParam((uint64_t)mHostHandle, 0, mAddressOffSet);
+    transport->writeParam(meta.type, 1, mAddressOffSet);
+    transport->writeParam(meta.primaries, 2, mAddressOffSet);
+    transport->writeParam(meta.range, 3, mAddressOffSet);
+    transport->writeParam(meta.transfer, 4, mAddressOffSet);
+    transport->sendOperation(MediaCodecType::H264Codec, MediaOperation::SendMetadata, mAddressOffSet);
+}
+
 void MediaH264Decoder::flush() {
     if (!mHasAddressSpaceMemory) {
         ALOGE("%s no address space memory", __func__);
         return;
     }
-    DDD("flush: use handle to host %lld", mHostHandle);
+    DDD("flush: use handle to host %lu", mHostHandle);
     auto transport = GoldfishMediaTransport::getInstance();
     transport->writeParam((uint64_t)mHostHandle, 0, mAddressOffSet);
     transport->sendOperation(MediaCodecType::H264Codec, MediaOperation::Flush,
@@ -139,7 +155,7 @@
 }
 
 h264_image_t MediaH264Decoder::getImage() {
-    DDD("getImage: use handle to host %lld", mHostHandle);
+    DDD("getImage: use handle to host %lu", mHostHandle);
     h264_image_t res{};
     if (!mHasAddressSpaceMemory) {
         ALOGE("%s no address space memory", __func__);
@@ -174,7 +190,7 @@
 
 h264_image_t
 MediaH264Decoder::renderOnHostAndReturnImageMetadata(int hostColorBufferId) {
-    DDD("%s: use handle to host %lld", __func__, mHostHandle);
+    DDD("%s: use handle to host %lu", __func__, mHostHandle);
     h264_image_t res{};
     if (hostColorBufferId < 0) {
         ALOGE("%s negative color buffer id %d", __func__, hostColorBufferId);
diff --git a/system/codecs/c2/decoders/avcdec/MediaH264Decoder.h b/system/codecs/c2/decoders/avcdec/MediaH264Decoder.h
index 1c1b262..e184cbd 100644
--- a/system/codecs/c2/decoders/avcdec/MediaH264Decoder.h
+++ b/system/codecs/c2/decoders/avcdec/MediaH264Decoder.h
@@ -17,6 +17,8 @@
 #ifndef GOLDFISH_MEDIA_H264_DEC_H_
 #define GOLDFISH_MEDIA_H264_DEC_H_
 
+#include "goldfish_media_utils.h"
+
 struct h264_init_result_t {
     uint64_t host_handle;
     int ret;
@@ -89,5 +91,14 @@
     // ask host to render to hostColorBufferId, return only image metadata back
     // to guest
     h264_image_t renderOnHostAndReturnImageMetadata(int hostColorBufferId);
+
+    // send metadata about the bitstream to host, such as color aspects that
+    // are set by the framework, e.g., color primaries (601, 709 etc), range
+    // (full range or limited range), transfer etc. given metadata could be
+    // of all kinds of types, the convention is that the first field server as
+    // metadata type id. host will check the type id to decide what to do with
+    // it; unrecognized typeid will be discarded by host side.
+
+    void sendMetadata(MetaDataColorAspects *ptr);
 };
 #endif
diff --git a/system/codecs/c2/decoders/base/include/goldfish_media_utils.h b/system/codecs/c2/decoders/base/include/goldfish_media_utils.h
index efa8859..a45cda9 100644
--- a/system/codecs/c2/decoders/base/include/goldfish_media_utils.h
+++ b/system/codecs/c2/decoders/base/include/goldfish_media_utils.h
@@ -26,6 +26,13 @@
     Max = 4,
 };
 
+struct MetaDataColorAspects {
+    uint64_t type = 1;
+    uint64_t primaries;
+    uint64_t range;
+    uint64_t transfer;
+};
+
 enum class MediaOperation : __u8 {
     InitContext = 0,
     DestroyContext = 1,
@@ -33,7 +40,8 @@
     GetImage = 3,
     Flush = 4,
     Reset = 5,
-    Max = 6,
+    SendMetadata = 6,
+    Max = 7,
 };
 
 // This class will abstract away the knowledge required to send media codec data
diff --git a/system/codecs/c2/decoders/hevcdec/C2GoldfishHevcDec.cpp b/system/codecs/c2/decoders/hevcdec/C2GoldfishHevcDec.cpp
index 7914c29..990f4c2 100644
--- a/system/codecs/c2/decoders/hevcdec/C2GoldfishHevcDec.cpp
+++ b/system/codecs/c2/decoders/hevcdec/C2GoldfishHevcDec.cpp
@@ -347,6 +347,13 @@
 
     int height() const { return mSize->height; }
 
+    int primaries() const { return mColorAspects->primaries; }
+
+    int range() const { return mColorAspects->range; }
+
+    int transfer() const { return mColorAspects->transfer; }
+
+
   private:
     std::shared_ptr<C2StreamProfileLevelInfo::input> mProfileLevel;
     std::shared_ptr<C2StreamPictureSizeInfo::output> mSize;
@@ -448,6 +455,30 @@
     return C2_OK;
 }
 
+void C2GoldfishHevcDec::sendMetadata() {
+    // compare and send if changed
+    MetaDataColorAspects currentMetaData = {1, 0, 0, 0};
+    currentMetaData.primaries = mIntf->primaries();
+    currentMetaData.range = mIntf->range();
+    currentMetaData.transfer = mIntf->transfer();
+
+    DDD("metadata primaries %d range %d transfer %d",
+            (int)(currentMetaData.primaries),
+            (int)(currentMetaData.range),
+            (int)(currentMetaData.transfer)
+       );
+
+    if (mSentMetadata.primaries == currentMetaData.primaries &&
+        mSentMetadata.range == currentMetaData.range &&
+        mSentMetadata.transfer == currentMetaData.transfer) {
+        DDD("metadata is the same, no need to update");
+        return;
+    }
+    std::swap(mSentMetadata, currentMetaData);
+
+    mContext->sendMetadata(&(mSentMetadata));
+}
+
 status_t C2GoldfishHevcDec::createDecoder() {
 
     DDD("creating hevc context now w %d h %d", mWidth, mHeight);
@@ -920,6 +951,8 @@
                 } // end of whChanged
             } // end of isVpsFrame
 
+            sendMetadata();
+
             uint32_t delay;
             GETTIME(&mTimeStart, nullptr);
             TIME_DIFF(mTimeEnd, mTimeStart, delay);
diff --git a/system/codecs/c2/decoders/hevcdec/C2GoldfishHevcDec.h b/system/codecs/c2/decoders/hevcdec/C2GoldfishHevcDec.h
index fe080cf..bc3d65b 100644
--- a/system/codecs/c2/decoders/hevcdec/C2GoldfishHevcDec.h
+++ b/system/codecs/c2/decoders/hevcdec/C2GoldfishHevcDec.h
@@ -142,6 +142,10 @@
         }
     } mBitstreamColorAspects;
 
+    MetaDataColorAspects mSentMetadata = {1, 0, 0, 0};
+
+    void sendMetadata();
+
     // profile
     struct timeval mTimeStart;
     struct timeval mTimeEnd;
diff --git a/system/codecs/c2/decoders/hevcdec/MediaHevcDecoder.cpp b/system/codecs/c2/decoders/hevcdec/MediaHevcDecoder.cpp
index bb2fbfa..f1bc356 100644
--- a/system/codecs/c2/decoders/hevcdec/MediaHevcDecoder.cpp
+++ b/system/codecs/c2/decoders/hevcdec/MediaHevcDecoder.cpp
@@ -126,6 +126,22 @@
     return res;
 }
 
+void MediaHevcDecoder::sendMetadata(MetaDataColorAspects *ptr) {
+    DDD("send metadata to host %p", ptr);
+    if (!mHasAddressSpaceMemory) {
+        ALOGE("%s no address space memory", __func__);
+        return;
+    }
+    MetaDataColorAspects& meta = *ptr;
+    auto transport = GoldfishMediaTransport::getInstance();
+    transport->writeParam((uint64_t)mHostHandle, 0, mAddressOffSet);
+    transport->writeParam(meta.type, 1, mAddressOffSet);
+    transport->writeParam(meta.primaries, 2, mAddressOffSet);
+    transport->writeParam(meta.range, 3, mAddressOffSet);
+    transport->writeParam(meta.transfer, 4, mAddressOffSet);
+    transport->sendOperation(MediaCodecType::HevcCodec, MediaOperation::SendMetadata, mAddressOffSet);
+}
+
 void MediaHevcDecoder::flush() {
     if (!mHasAddressSpaceMemory) {
         ALOGE("%s no address space memory", __func__);
diff --git a/system/codecs/c2/decoders/hevcdec/MediaHevcDecoder.h b/system/codecs/c2/decoders/hevcdec/MediaHevcDecoder.h
index 8dfb0cf..878950e 100644
--- a/system/codecs/c2/decoders/hevcdec/MediaHevcDecoder.h
+++ b/system/codecs/c2/decoders/hevcdec/MediaHevcDecoder.h
@@ -17,6 +17,8 @@
 #ifndef GOLDFISH_MEDIA_Hevc_DEC_H_
 #define GOLDFISH_MEDIA_Hevc_DEC_H_
 
+#include "goldfish_media_utils.h"
+
 struct hevc_init_result_t {
     uint64_t host_handle;
     int ret;
@@ -89,5 +91,8 @@
     // ask host to render to hostColorBufferId, return only image metadata back
     // to guest
     hevc_image_t renderOnHostAndReturnImageMetadata(int hostColorBufferId);
+
+    void sendMetadata(MetaDataColorAspects *ptr);
+
 };
 #endif
diff --git a/system/codecs/c2/decoders/vpxdec/C2GoldfishVpxDec.cpp b/system/codecs/c2/decoders/vpxdec/C2GoldfishVpxDec.cpp
index 99f0469..be6428e 100644
--- a/system/codecs/c2/decoders/vpxdec/C2GoldfishVpxDec.cpp
+++ b/system/codecs/c2/decoders/vpxdec/C2GoldfishVpxDec.cpp
@@ -324,6 +324,12 @@
 
     int height() const { return mSize->height; }
 
+    int primaries() const { return mDefaultColorAspects->primaries; }
+
+    int range() const { return mDefaultColorAspects->range; }
+
+    int transfer() const { return mDefaultColorAspects->transfer; }
+
     static C2R Hdr10PlusInfoInputSetter(bool mayBlock,
                                         C2P<C2StreamHdr10PlusInfo::input> &me) {
         (void)mayBlock;
@@ -416,6 +422,30 @@
 
 void C2GoldfishVpxDec::onRelease() { destroyDecoder(); }
 
+void C2GoldfishVpxDec::sendMetadata() {
+    // compare and send if changed
+    MetaDataColorAspects currentMetaData = {1, 0, 0, 0};
+    currentMetaData.primaries = mIntf->primaries();
+    currentMetaData.range = mIntf->range();
+    currentMetaData.transfer = mIntf->transfer();
+
+    DDD("metadata primaries %d range %d transfer %d",
+            (int)(currentMetaData.primaries),
+            (int)(currentMetaData.range),
+            (int)(currentMetaData.transfer)
+       );
+
+    if (mSentMetadata.primaries == currentMetaData.primaries &&
+        mSentMetadata.range == currentMetaData.range &&
+        mSentMetadata.transfer == currentMetaData.transfer) {
+        DDD("metadata is the same, no need to update");
+        return;
+    }
+    std::swap(mSentMetadata, currentMetaData);
+
+    vpx_codec_send_metadata(mCtx, &(mSentMetadata));
+}
+
 c2_status_t C2GoldfishVpxDec::onFlush_sm() {
     if (mFrameParallelMode) {
         // Flush decoder by passing nullptr data ptr and 0 size.
@@ -609,6 +639,8 @@
         }
     }
 
+    sendMetadata();
+
     if (inSize) {
         uint8_t *bitstream = const_cast<uint8_t *>(rView.data() + inOffset);
         vpx_codec_err_t err = vpx_codec_decode(
diff --git a/system/codecs/c2/decoders/vpxdec/C2GoldfishVpxDec.h b/system/codecs/c2/decoders/vpxdec/C2GoldfishVpxDec.h
index 4b356da..738d9fc 100644
--- a/system/codecs/c2/decoders/vpxdec/C2GoldfishVpxDec.h
+++ b/system/codecs/c2/decoders/vpxdec/C2GoldfishVpxDec.h
@@ -16,6 +16,7 @@
 
 #pragma once
 
+#include "goldfish_media_utils.h"
 #include "goldfish_vpx_defs.h"
 #include <SimpleC2Component.h>
 
@@ -95,6 +96,9 @@
                               const std::shared_ptr<C2BlockPool> &pool,
                               const std::unique_ptr<C2Work> &work);
 
+    MetaDataColorAspects mSentMetadata = {1, 0, 0, 0};
+    void sendMetadata();
+
     C2_DO_NOT_COPY(C2GoldfishVpxDec);
 };
 
diff --git a/system/codecs/c2/decoders/vpxdec/goldfish_vpx_defs.h b/system/codecs/c2/decoders/vpxdec/goldfish_vpx_defs.h
index bbcc805..1be05c9 100644
--- a/system/codecs/c2/decoders/vpxdec/goldfish_vpx_defs.h
+++ b/system/codecs/c2/decoders/vpxdec/goldfish_vpx_defs.h
@@ -61,4 +61,6 @@
 int vpx_codec_decode(vpx_codec_ctx_t *ctx, const uint8_t *data,
                      unsigned int data_sz, void *user_priv, long deadline);
 
+void vpx_codec_send_metadata(vpx_codec_ctx_t *ctx, void*ptr);
+
 #endif // MY_VPX_DEFS_H_
diff --git a/system/codecs/c2/decoders/vpxdec/goldfish_vpx_impl.cpp b/system/codecs/c2/decoders/vpxdec/goldfish_vpx_impl.cpp
index d008efe..e1fa879 100644
--- a/system/codecs/c2/decoders/vpxdec/goldfish_vpx_impl.cpp
+++ b/system/codecs/c2/decoders/vpxdec/goldfish_vpx_impl.cpp
@@ -142,6 +142,17 @@
     return &(ctx->myImg);
 }
 
+void vpx_codec_send_metadata(vpx_codec_ctx_t *ctx, void *ptr) {
+    MetaDataColorAspects& meta = *(MetaDataColorAspects*)ptr;
+    auto transport = GoldfishMediaTransport::getInstance();
+    transport->writeParam(ctx->id, 0, ctx->address_offset);
+    transport->writeParam(meta.type, 1, ctx->address_offset);
+    transport->writeParam(meta.primaries, 2, ctx->address_offset);
+    transport->writeParam(meta.range, 3, ctx->address_offset);
+    transport->writeParam(meta.transfer, 4, ctx->address_offset);
+    sendVpxOperation(ctx, MediaOperation::SendMetadata);
+}
+
 int vpx_codec_flush(vpx_codec_ctx_t *ctx) {
     DDD("%s %d", __func__, __LINE__);
     if (!ctx) {