Merge "stagefright: move all codecs into codec process unless excluded" into nyc-dev
diff --git a/media/libstagefright/HevcUtils.cpp b/media/libstagefright/HevcUtils.cpp
index e7e99ff..718710a 100644
--- a/media/libstagefright/HevcUtils.cpp
+++ b/media/libstagefright/HevcUtils.cpp
@@ -18,6 +18,7 @@
 #define LOG_TAG "HevcUtils"
 
 #include <cstring>
+#include <utility>
 
 #include "include/HevcUtils.h"
 #include "include/avc_utils.h"
@@ -39,7 +40,8 @@
     kHevcNalUnitTypeSuffixSei,
 };
 
-HevcParameterSets::HevcParameterSets() {
+HevcParameterSets::HevcParameterSets()
+    : mInfo(kInfoNone) {
 }
 
 status_t HevcParameterSets::addNalUnit(const uint8_t* data, size_t size) {
@@ -221,6 +223,127 @@
     mParams.add(kBitDepthLumaMinus8, parseUEWithFallback(&reader, 0));
     mParams.add(kBitDepthChromaMinus8, parseUEWithFallback(&reader, 0));
 
+    // log2_max_pic_order_cnt_lsb_minus4
+    size_t log2MaxPicOrderCntLsb = parseUEWithFallback(&reader, 0) + (size_t)4;
+    bool spsSubLayerOrderingInfoPresentFlag = reader.getBitsWithFallback(1, 0);
+    for (uint32_t i = spsSubLayerOrderingInfoPresentFlag ? 0 : maxSubLayersMinus1;
+            i <= maxSubLayersMinus1; ++i) {
+        skipUE(&reader); // sps_max_dec_pic_buffering_minus1[i]
+        skipUE(&reader); // sps_max_num_reorder_pics[i]
+        skipUE(&reader); // sps_max_latency_increase_plus1[i]
+    }
+
+    skipUE(&reader); // log2_min_luma_coding_block_size_minus3
+    skipUE(&reader); // log2_diff_max_min_luma_coding_block_size
+    skipUE(&reader); // log2_min_luma_transform_block_size_minus2
+    skipUE(&reader); // log2_diff_max_min_luma_transform_block_size
+    skipUE(&reader); // max_transform_hierarchy_depth_inter
+    skipUE(&reader); // max_transform_hierarchy_depth_intra
+    if (reader.getBitsWithFallback(1, 0)) { // scaling_list_enabled_flag u(1)
+        // scaling_list_data
+        if (reader.getBitsWithFallback(1, 0)) { // sps_scaling_list_data_present_flag
+            for (uint32_t sizeId = 0; sizeId < 4; ++sizeId) {
+                for (uint32_t matrixId = 0; matrixId < 6; matrixId += (sizeId == 3) ? 3 : 1) {
+                    if (!reader.getBitsWithFallback(1, 1)) {
+                        // scaling_list_pred_mode_flag[sizeId][matrixId]
+                        skipUE(&reader); // scaling_list_pred_matrix_id_delta[sizeId][matrixId]
+                    } else {
+                        uint32_t coefNum = std::min(64, (1 << (4 + (sizeId << 1))));
+                        if (sizeId > 1) {
+                            skipSE(&reader); // scaling_list_dc_coef_minus8[sizeId − 2][matrixId]
+                        }
+                        for (uint32_t i = 0; i < coefNum; ++i) {
+                            skipSE(&reader); // scaling_list_delta_coef
+                        }
+                    }
+                }
+            }
+        }
+    }
+    reader.skipBits(1); // amp_enabled_flag
+    reader.skipBits(1); // sample_adaptive_offset_enabled_flag u(1)
+    if (reader.getBitsWithFallback(1, 0)) { // pcm_enabled_flag
+        reader.skipBits(4); // pcm_sample_bit_depth_luma_minus1
+        reader.skipBits(4); // pcm_sample_bit_depth_chroma_minus1 u(4)
+        skipUE(&reader); // log2_min_pcm_luma_coding_block_size_minus3
+        skipUE(&reader); // log2_diff_max_min_pcm_luma_coding_block_size
+        reader.skipBits(1); // pcm_loop_filter_disabled_flag
+    }
+    uint32_t numShortTermRefPicSets = parseUEWithFallback(&reader, 0);
+    uint32_t numPics = 0;
+    for (uint32_t i = 0; i < numShortTermRefPicSets; ++i) {
+        // st_ref_pic_set(i)
+        if (i != 0 && reader.getBitsWithFallback(1, 0)) { // inter_ref_pic_set_prediction_flag
+            reader.skipBits(1); // delta_rps_sign
+            skipUE(&reader); // abs_delta_rps_minus1
+            uint32_t nextNumPics = 0;
+            for (uint32_t j = 0; j <= numPics; ++j) {
+                if (reader.getBitsWithFallback(1, 0) // used_by_curr_pic_flag[j]
+                        || reader.getBitsWithFallback(1, 0)) { // use_delta_flag[j]
+                    ++nextNumPics;
+                }
+            }
+            numPics = nextNumPics;
+        } else {
+            uint32_t numNegativePics = parseUEWithFallback(&reader, 0);
+            uint32_t numPositivePics = parseUEWithFallback(&reader, 0);
+            if (numNegativePics > UINT32_MAX - numPositivePics) {
+                return ERROR_MALFORMED;
+            }
+            numPics = numNegativePics + numPositivePics;
+            for (uint32_t j = 0; j < numPics; ++j) {
+                skipUE(&reader); // delta_poc_s0|1_minus1[i]
+                reader.skipBits(1); // used_by_curr_pic_s0|1_flag[i]
+            }
+        }
+    }
+    if (reader.getBitsWithFallback(1, 0)) { // long_term_ref_pics_present_flag
+        uint32_t numLongTermRefPicSps = parseUEWithFallback(&reader, 0);
+        for (uint32_t i = 0; i < numLongTermRefPicSps; ++i) {
+            reader.skipBits(log2MaxPicOrderCntLsb); // lt_ref_pic_poc_lsb_sps[i]
+            reader.skipBits(1); // used_by_curr_pic_lt_sps_flag[i]
+        }
+    }
+    reader.skipBits(1); // sps_temporal_mvp_enabled_flag
+    reader.skipBits(1); // strong_intra_smoothing_enabled_flag
+    if (reader.getBitsWithFallback(1, 0)) { // vui_parameters_present_flag
+        if (reader.getBitsWithFallback(1, 0)) { // aspect_ratio_info_present_flag
+            uint32_t aspectRatioIdc = reader.getBitsWithFallback(8, 0);
+            if (aspectRatioIdc == 0xFF /* EXTENDED_SAR */) {
+                reader.skipBits(16); // sar_width
+                reader.skipBits(16); // sar_height
+            }
+        }
+        if (reader.getBitsWithFallback(1, 0)) { // overscan_info_present_flag
+            reader.skipBits(1); // overscan_appropriate_flag
+        }
+        if (reader.getBitsWithFallback(1, 0)) { // video_signal_type_present_flag
+            reader.skipBits(3); // video_format
+            uint32_t videoFullRangeFlag;
+            if (reader.getBitsGraceful(1, &videoFullRangeFlag)) {
+                mParams.add(kVideoFullRangeFlag, videoFullRangeFlag);
+            }
+            if (reader.getBitsWithFallback(1, 0)) { // colour_description_present_flag
+                mInfo = (Info)(mInfo | kInfoHasColorDescription);
+                uint32_t colourPrimaries, transferCharacteristics, matrixCoeffs;
+                if (reader.getBitsGraceful(8, &colourPrimaries)) {
+                    mParams.add(kColourPrimaries, colourPrimaries);
+                }
+                if (reader.getBitsGraceful(8, &transferCharacteristics)) {
+                    mParams.add(kTransferCharacteristics, transferCharacteristics);
+                    if (transferCharacteristics == 16 /* ST 2084 */
+                            || transferCharacteristics == 18 /* ARIB STD-B67 HLG */) {
+                        mInfo = (Info)(mInfo | kInfoIsHdr);
+                    }
+                }
+                if (reader.getBitsGraceful(8, &matrixCoeffs)) {
+                    mParams.add(kMatrixCoeffs, matrixCoeffs);
+                }
+            }
+            // skip rest of VUI
+        }
+    }
+
     return reader.overRead() ? ERROR_MALFORMED : OK;
 }
 
diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp
index 208b238..c461ca0 100644
--- a/media/libstagefright/Utils.cpp
+++ b/media/libstagefright/Utils.cpp
@@ -141,6 +141,28 @@
     }
 }
 
+static bool isHdr(const sp<AMessage> &format) {
+    // if CSD specifies HDR transfer(s), we assume HDR. Otherwise, if it specifies non-HDR
+    // transfers, we must assume non-HDR. This is because CSD trumps any color-transfer key
+    // in the format.
+    int32_t isHdr;
+    if (format->findInt32("android._is-hdr", &isHdr)) {
+        return isHdr;
+    }
+
+    // if user/container supplied HDR static info without transfer set, assume true
+    if (format->contains("hdr-static-info") && !format->contains("color-transfer")) {
+        return true;
+    }
+    // otherwise, verify that an HDR transfer function is set
+    int32_t transfer;
+    if (format->findInt32("color-transfer", &transfer)) {
+        return transfer == ColorUtils::kColorTransferST2084
+                || transfer == ColorUtils::kColorTransferHLG;
+    }
+    return false;
+}
+
 static void parseAacProfileFromCsd(const sp<ABuffer> &csd, sp<AMessage> &format) {
     if (csd->size() < 2) {
         return;
@@ -322,6 +344,12 @@
             return;
         }
     }
+
+    // bump to HDR profile
+    if (isHdr(format) && codecProfile == OMX_VIDEO_HEVCProfileMain10) {
+        codecProfile = OMX_VIDEO_HEVCProfileMain10HDR10;
+    }
+
     format->setInt32("profile", codecProfile);
     if (levels.map(std::make_pair(tier, level), &codecLevel)) {
         format->setInt32("level", codecLevel);
@@ -514,8 +542,18 @@
                         { 3, OMX_VIDEO_VP9Profile3 },
                     };
 
+                    const static ALookup<OMX_VIDEO_VP9PROFILETYPE, OMX_VIDEO_VP9PROFILETYPE> toHdr {
+                        { OMX_VIDEO_VP9Profile2, OMX_VIDEO_VP9Profile2HDR },
+                        { OMX_VIDEO_VP9Profile3, OMX_VIDEO_VP9Profile3HDR },
+                    };
+
                     OMX_VIDEO_VP9PROFILETYPE profile;
                     if (profiles.map(data[0], &profile)) {
+                        // convert to HDR profile
+                        if (isHdr(format)) {
+                            toHdr.lookup(profile, &profile);
+                        }
+
                         format->setInt32("profile", profile);
                     }
                 }
@@ -818,7 +856,7 @@
             return BAD_VALUE;
         }
 
-        parseHevcProfileLevelFromHvcc(ptr, size, msg);
+        const size_t dataSize = size; // save for later
         ptr += 22;
         size -= 22;
 
@@ -833,6 +871,8 @@
         }
         buffer->setRange(0, 0);
 
+        HevcParameterSets hvcc;
+
         for (i = 0; i < numofArrays; i++) {
             if (size < 3) {
                 ALOGE("b/23680780");
@@ -864,6 +904,7 @@
                 if (err != OK) {
                     return err;
                 }
+                (void)hvcc.addNalUnit(ptr, length);
 
                 ptr += length;
                 size -= length;
@@ -873,6 +914,14 @@
         buffer->meta()->setInt64("timeUs", 0);
         msg->setBuffer("csd-0", buffer);
 
+        // if we saw VUI color information we know whether this is HDR because VUI trumps other
+        // format parameters for HEVC.
+        HevcParameterSets::Info info = hvcc.getInfo();
+        if (info & hvcc.kInfoHasColorDescription) {
+            msg->setInt32("android._is-hdr", (info & hvcc.kInfoIsHdr) != 0);
+        }
+
+        parseHevcProfileLevelFromHvcc((const uint8_t *)data, dataSize, msg);
     } else if (meta->findData(kKeyESDS, &type, &data, &size)) {
         ESDS esds((const char *)data, size);
         if (esds.InitCheck() != (status_t)OK) {
diff --git a/media/libstagefright/include/HevcUtils.h b/media/libstagefright/include/HevcUtils.h
index 0d7bb2f..0f59631 100644
--- a/media/libstagefright/include/HevcUtils.h
+++ b/media/libstagefright/include/HevcUtils.h
@@ -56,10 +56,24 @@
     kBitDepthLumaMinus8,
     // uint8_t
     kBitDepthChromaMinus8,
+    // uint8_t
+    kVideoFullRangeFlag,
+    // uint8_t
+    kColourPrimaries,
+    // uint8_t
+    kTransferCharacteristics,
+    // uint8_t
+    kMatrixCoeffs,
 };
 
 class HevcParameterSets {
 public:
+    enum Info : uint32_t {
+        kInfoNone                = 0,
+        kInfoIsHdr               = 1 << 0,
+        kInfoHasColorDescription = 1 << 1,
+    };
+
     HevcParameterSets();
 
     status_t addNalUnit(const uint8_t* data, size_t size);
@@ -77,6 +91,8 @@
     bool write(size_t index, uint8_t* dest, size_t size);
     status_t makeHvcc(uint8_t *hvcc, size_t *hvccSize, size_t nalSizeLength);
 
+    Info getInfo() const { return mInfo; }
+
 private:
     status_t parseVps(const uint8_t* data, size_t size);
     status_t parseSps(const uint8_t* data, size_t size);
@@ -84,6 +100,7 @@
 
     KeyedVector<uint32_t, uint64_t> mParams;
     Vector<sp<ABuffer>> mNalUnits;
+    Info mInfo;
 
     DISALLOW_EVIL_CONSTRUCTORS(HevcParameterSets);
 };