Enumerate all hevc encoders to find one that support CQ @ 512x512 size

bug: 132905160
test: ImageReaderTest#testHeic
Change-Id: I497b203f7e21299eb4e322af4d4c5c925cf5a48a
diff --git a/services/camera/libcameraservice/api2/HeicCompositeStream.cpp b/services/camera/libcameraservice/api2/HeicCompositeStream.cpp
index 743c816..5a87134 100644
--- a/services/camera/libcameraservice/api2/HeicCompositeStream.cpp
+++ b/services/camera/libcameraservice/api2/HeicCompositeStream.cpp
@@ -330,9 +330,9 @@
 }
 
 bool HeicCompositeStream::isSizeSupportedByHeifEncoder(int32_t width, int32_t height,
-        bool* useHeic, bool* useGrid, int64_t* stall) {
+        bool* useHeic, bool* useGrid, int64_t* stall, AString* hevcName) {
     static HeicEncoderInfoManager& heicManager = HeicEncoderInfoManager::getInstance();
-    return heicManager.isSizeSupported(width, height, useHeic, useGrid, stall);
+    return heicManager.isSizeSupported(width, height, useHeic, useGrid, stall, hevcName);
 }
 
 bool HeicCompositeStream::isInMemoryTempFileSupported() {
@@ -1115,8 +1115,9 @@
     ALOGV("%s", __FUNCTION__);
 
     bool useGrid = false;
+    AString hevcName;
     bool isSizeSupported = isSizeSupportedByHeifEncoder(width, height,
-            &mUseHeic, &useGrid, nullptr);
+            &mUseHeic, &useGrid, nullptr, &hevcName);
     if (!isSizeSupported) {
         ALOGE("%s: Encoder doesnt' support size %u x %u!",
                 __FUNCTION__, width, height);
@@ -1138,7 +1139,11 @@
     }
 
     // Create HEIC/HEVC codec.
-    mCodec = MediaCodec::CreateByType(mCodecLooper, desiredMime, true /*encoder*/);
+    if (mUseHeic) {
+        mCodec = MediaCodec::CreateByType(mCodecLooper, desiredMime, true /*encoder*/);
+    } else {
+        mCodec = MediaCodec::CreateByComponentName(mCodecLooper, hevcName);
+    }
     if (mCodec == nullptr) {
         ALOGE("%s: Failed to create codec for %s", __FUNCTION__, desiredMime);
         return NO_INIT;
diff --git a/services/camera/libcameraservice/api2/HeicCompositeStream.h b/services/camera/libcameraservice/api2/HeicCompositeStream.h
index 2aa3c38..260c68e 100644
--- a/services/camera/libcameraservice/api2/HeicCompositeStream.h
+++ b/services/camera/libcameraservice/api2/HeicCompositeStream.h
@@ -71,7 +71,7 @@
             const CameraMetadata& ch, std::vector<OutputStreamInfo>* compositeOutput /*out*/);
 
     static bool isSizeSupportedByHeifEncoder(int32_t width, int32_t height,
-            bool* useHeic, bool* useGrid, int64_t* stall);
+            bool* useHeic, bool* useGrid, int64_t* stall, AString* hevcName = nullptr);
     static bool isInMemoryTempFileSupported();
 protected:
 
diff --git a/services/camera/libcameraservice/api2/HeicEncoderInfoManager.cpp b/services/camera/libcameraservice/api2/HeicEncoderInfoManager.cpp
index ed9be6e..d7cc2bf 100644
--- a/services/camera/libcameraservice/api2/HeicEncoderInfoManager.cpp
+++ b/services/camera/libcameraservice/api2/HeicEncoderInfoManager.cpp
@@ -49,7 +49,7 @@
 }
 
 bool HeicEncoderInfoManager::isSizeSupported(int32_t width, int32_t height, bool* useHeic,
-        bool* useGrid, int64_t* stall) const {
+        bool* useGrid, int64_t* stall, AString* hevcName) const {
     if (useHeic == nullptr || useGrid == nullptr) {
         ALOGE("%s: invalid parameters: useHeic %p, useGrid %p",
                 __FUNCTION__, useHeic, useGrid);
@@ -72,6 +72,9 @@
                 (width <= 1920 && height <= 1080))) {
             enableGrid = false;
         }
+        if (hevcName != nullptr) {
+            *hevcName = mHevcName;
+        }
     } else {
         // No encoder available for the requested size.
         return false;
@@ -113,9 +116,8 @@
     }
 
     sp<AMessage> heicDetails = getCodecDetails(codecsList, MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC);
-    sp<AMessage> hevcDetails = getCodecDetails(codecsList, MEDIA_MIMETYPE_VIDEO_HEVC);
 
-    if (hevcDetails == nullptr) {
+    if (!getHevcCodecDetails(codecsList, MEDIA_MIMETYPE_VIDEO_HEVC)) {
         if (heicDetails != nullptr) {
             ALOGE("%s: Device must support HEVC codec if HEIC codec is available!",
                     __FUNCTION__);
@@ -123,22 +125,7 @@
         }
         return OK;
     }
-
-    // Check CQ mode for HEVC codec
-    {
-        AString bitrateModes;
-        auto hasItem = hevcDetails->findString("feature-bitrate-modes", &bitrateModes);
-        if (!hasItem) {
-            ALOGE("%s: Failed to query bitrate modes for HEVC codec", __FUNCTION__);
-            return BAD_VALUE;
-        }
-        ALOGV("%s: HEVC codec's feature-bitrate-modes value is %d, %s",
-                __FUNCTION__, hasItem, bitrateModes.c_str());
-        std::regex pattern("(^|,)CQ($|,)", std::regex_constants::icase);
-        if (!std::regex_search(bitrateModes.c_str(), pattern)) {
-            return OK;
-        }
-    }
+    mHasHEVC = true;
 
     // HEIC size range
     if (heicDetails != nullptr) {
@@ -152,19 +139,6 @@
         mHasHEIC = true;
     }
 
-    // HEVC size range
-    {
-        auto res = getCodecSizeRange(MEDIA_MIMETYPE_VIDEO_HEVC,
-                hevcDetails, &mMinSizeHevc, &mMaxSizeHevc, &mHevcFrameRateMaps);
-        if (res != OK) {
-            ALOGE("%s: Failed to get HEVC codec size range: %s (%d)", __FUNCTION__,
-                    strerror(-res), res);
-            return BAD_VALUE;
-        }
-
-        mHasHEVC = true;
-    }
-
     return OK;
 }
 
@@ -290,5 +264,80 @@
 
     return details;
 }
+
+bool HeicEncoderInfoManager::getHevcCodecDetails(
+        sp<IMediaCodecList> codecsList, const char* mime) {
+    bool found = false;
+    ssize_t idx = 0;
+    while ((idx = codecsList->findCodecByType(mime, true /*encoder*/, idx)) >= 0) {
+        const sp<MediaCodecInfo> info = codecsList->getCodecInfo(idx++);
+        if (info == nullptr) {
+            ALOGE("%s: Failed to get codec info for %s", __FUNCTION__, mime);
+            break;
+        }
+
+        // Filter out software ones as they may be too slow
+        if (!(info->getAttributes() & MediaCodecInfo::kFlagIsHardwareAccelerated)) {
+            continue;
+        }
+
+        const sp<MediaCodecInfo::Capabilities> caps =
+                info->getCapabilitiesFor(mime);
+        if (caps == nullptr) {
+            ALOGE("%s: [%s] Failed to get capabilities", __FUNCTION__,
+                    info->getCodecName());
+            break;
+        }
+        const sp<AMessage> details = caps->getDetails();
+        if (details == nullptr) {
+            ALOGE("%s: [%s] Failed to get details", __FUNCTION__,
+                    info->getCodecName());
+            break;
+        }
+
+        // Check CQ mode
+        AString bitrateModes;
+        auto hasItem = details->findString("feature-bitrate-modes", &bitrateModes);
+        if (!hasItem) {
+            ALOGE("%s: [%s] Failed to query bitrate modes", __FUNCTION__,
+                    info->getCodecName());
+            break;
+        }
+        ALOGV("%s: [%s] feature-bitrate-modes value is %d, %s",
+                __FUNCTION__, info->getCodecName(), hasItem, bitrateModes.c_str());
+        std::regex pattern("(^|,)CQ($|,)", std::regex_constants::icase);
+        if (!std::regex_search(bitrateModes.c_str(), pattern)) {
+            continue; // move on to next encoder
+        }
+
+        std::pair<int32_t, int32_t> minSizeHevc, maxSizeHevc;
+        FrameRateMaps hevcFrameRateMaps;
+        auto res = getCodecSizeRange(MEDIA_MIMETYPE_VIDEO_HEVC,
+                details, &minSizeHevc, &maxSizeHevc, &hevcFrameRateMaps);
+        if (res != OK) {
+            ALOGE("%s: [%s] Failed to get size range: %s (%d)", __FUNCTION__,
+                    info->getCodecName(), strerror(-res), res);
+            break;
+        }
+        if (kGridWidth < minSizeHevc.first
+                || kGridWidth > maxSizeHevc.first
+                || kGridHeight < minSizeHevc.second
+                || kGridHeight > maxSizeHevc.second) {
+            continue; // move on to next encoder
+        }
+
+        // Found: save name, size, frame rate
+        mHevcName = info->getCodecName();
+        mMinSizeHevc = minSizeHevc;
+        mMaxSizeHevc = maxSizeHevc;
+        mHevcFrameRateMaps = hevcFrameRateMaps;
+
+        found = true;
+        break;
+    }
+
+    return found;
+}
+
 } //namespace camera3
 } // namespace android
diff --git a/services/camera/libcameraservice/api2/HeicEncoderInfoManager.h b/services/camera/libcameraservice/api2/HeicEncoderInfoManager.h
index fb0b914..58edba2 100644
--- a/services/camera/libcameraservice/api2/HeicEncoderInfoManager.h
+++ b/services/camera/libcameraservice/api2/HeicEncoderInfoManager.h
@@ -36,7 +36,7 @@
     }
 
     bool isSizeSupported(int32_t width, int32_t height,
-            bool* useHeic, bool* useGrid, int64_t* stall) const;
+            bool* useHeic, bool* useGrid, int64_t* stall, AString* hevcName) const;
 
     static const auto kGridWidth = 512;
     static const auto kGridHeight = 512;
@@ -61,11 +61,13 @@
     FrameRateMaps::const_iterator findClosestSize(const FrameRateMaps& maps,
             int32_t width, int32_t height) const;
     sp<AMessage> getCodecDetails(sp<IMediaCodecList> codecsList, const char* name);
+    bool getHevcCodecDetails(sp<IMediaCodecList> codecsList, const char* mime);
 
     bool mIsInited;
     std::pair<int32_t, int32_t> mMinSizeHeic, mMaxSizeHeic;
     std::pair<int32_t, int32_t> mMinSizeHevc, mMaxSizeHevc;
     bool mHasHEVC, mHasHEIC;
+    AString mHevcName;
     FrameRateMaps mHeicFrameRateMaps, mHevcFrameRateMaps;
     bool mDisableGrid;