From 688abaa2865dab9ba955a6543a965d10e4c506db Mon Sep 17 00:00:00 2001 From: Chong Zhang Date: Fri, 17 May 2019 16:32:23 -0700 Subject: [PATCH] Enumerate all hevc encoders to find one that support CQ @ 512x512 size bug: 132905160 test: ImageReaderTest#testHeic Change-Id: I497b203f7e21299eb4e322af4d4c5c925cf5a48a --- .../api2/HeicCompositeStream.cpp | 13 +- .../api2/HeicCompositeStream.h | 2 +- .../api2/HeicEncoderInfoManager.cpp | 113 +++++++++++++----- .../api2/HeicEncoderInfoManager.h | 4 +- 4 files changed, 94 insertions(+), 38 deletions(-) diff --git a/services/camera/libcameraservice/api2/HeicCompositeStream.cpp b/services/camera/libcameraservice/api2/HeicCompositeStream.cpp index 743c8163cc..5a87134743 100644 --- a/services/camera/libcameraservice/api2/HeicCompositeStream.cpp +++ b/services/camera/libcameraservice/api2/HeicCompositeStream.cpp @@ -330,9 +330,9 @@ status_t HeicCompositeStream::getCompositeStreamInfo(const OutputStreamInfo &str } 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 @@ status_t HeicCompositeStream::initializeCodec(uint32_t width, uint32_t height, 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 @@ status_t HeicCompositeStream::initializeCodec(uint32_t width, uint32_t height, } // 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 2aa3c38bc1..260c68e081 100644 --- a/services/camera/libcameraservice/api2/HeicCompositeStream.h +++ b/services/camera/libcameraservice/api2/HeicCompositeStream.h @@ -71,7 +71,7 @@ public: const CameraMetadata& ch, std::vector* 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 ed9be6e934..d7cc2bf113 100644 --- a/services/camera/libcameraservice/api2/HeicEncoderInfoManager.cpp +++ b/services/camera/libcameraservice/api2/HeicEncoderInfoManager.cpp @@ -49,7 +49,7 @@ HeicEncoderInfoManager::~HeicEncoderInfoManager() { } 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 @@ bool HeicEncoderInfoManager::isSizeSupported(int32_t width, int32_t height, bool (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 @@ status_t HeicEncoderInfoManager::initialize() { } sp heicDetails = getCodecDetails(codecsList, MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC); - sp 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 @@ status_t HeicEncoderInfoManager::initialize() { } 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 @@ status_t HeicEncoderInfoManager::initialize() { 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 @@ sp HeicEncoderInfoManager::getCodecDetails( return details; } + +bool HeicEncoderInfoManager::getHevcCodecDetails( + sp codecsList, const char* mime) { + bool found = false; + ssize_t idx = 0; + while ((idx = codecsList->findCodecByType(mime, true /*encoder*/, idx)) >= 0) { + const sp 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 caps = + info->getCapabilitiesFor(mime); + if (caps == nullptr) { + ALOGE("%s: [%s] Failed to get capabilities", __FUNCTION__, + info->getCodecName()); + break; + } + const sp 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 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 fb0b9140a9..58edba2d3c 100644 --- a/services/camera/libcameraservice/api2/HeicEncoderInfoManager.h +++ b/services/camera/libcameraservice/api2/HeicEncoderInfoManager.h @@ -36,7 +36,7 @@ public: } 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 @@ private: FrameRateMaps::const_iterator findClosestSize(const FrameRateMaps& maps, int32_t width, int32_t height) const; sp getCodecDetails(sp codecsList, const char* name); + bool getHevcCodecDetails(sp codecsList, const char* mime); bool mIsInited; std::pair mMinSizeHeic, mMaxSizeHeic; std::pair mMinSizeHevc, mMaxSizeHevc; bool mHasHEVC, mHasHEIC; + AString mHevcName; FrameRateMaps mHeicFrameRateMaps, mHevcFrameRateMaps; bool mDisableGrid;