/* * Copyright (C) 2021-2024 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "avmetadatahelper_impl.h" #include #include #include "v1_0/cm_color_space.h" #include "v1_0/hdr_static_metadata.h" #include "v1_0/buffer_handle_meta_key_type.h" #include "securec.h" #include "image_source.h" #include "i_media_service.h" #include "media_log.h" #include "media_errors.h" #include "scope_guard.h" #include "hisysevent.h" #include "image_format_convert.h" #include "color_space.h" #include "param_wrapper.h" namespace { constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_DOMAIN_METADATA, "AVMetadatahelperImpl" }; constexpr int32_t SCENE_CODE_EFFECTIVE_DURATION_MS = 20000; static constexpr char PERFORMANCE_STATS[] = "PERFORMANCE"; static std::atomic concurrentWorkCount_ = 0; static constexpr uint8_t HIGH_CONCRENT_WORK_NUM = 4; static constexpr int32_t PLANE_Y = 0; static constexpr int32_t PLANE_U = 1; static constexpr uint8_t HDR_PIXEL_SIZE = 2; static constexpr uint8_t SDR_PIXEL_SIZE = 1; constexpr int32_t NUM_180 = 180; static const std::string FILE_DIR_IN_THE_SANDBOX = "/data/storage/el2/base/files/"; const std::string DUMP_FILE_NAME_AVBUFFER = "_avbuffer.dat"; const std::string DUMP_FILE_NAME_PIXEMAP = "_pixelMap.dat"; const std::string DUMP_FILE_NAME_AFTER_SCLAE = "_afterScale.dat"; const std::string DUMP_FILE_NAME_AFTER_ROTATE = "_afterRotate.dat"; } namespace OHOS { namespace Media { using namespace OHOS::HDI::Display::Graphic::Common::V1_0; static constexpr uint8_t PIXEL_SIZE_HDR_YUV = 3; static std::map SCENE_CODE_MAP = { { Scene::AV_META_SCENE_CLONE, 1 }, { Scene::AV_META_SCENE_BATCH_HANDLE, 2 } }; static std::map SCENE_TIMESTAMP_MAP = { { Scene::AV_META_SCENE_CLONE, 0 }, { Scene::AV_META_SCENE_BATCH_HANDLE, 0 } }; struct PixelMapMemHolder { bool isShmem; std::shared_ptr shmem; uint8_t *heap; }; struct AVBufferHolder { std::shared_ptr buffer; }; static void FreePixelMapData(void *addr, void *context, uint32_t size) { (void)size; MEDIA_LOGD("free pixel map data"); CHECK_AND_RETURN_LOG(context != nullptr, "context is nullptr"); PixelMapMemHolder *holder = reinterpret_cast(context); if (holder->isShmem) { if (holder->shmem == nullptr) { MEDIA_LOGE("shmem is nullptr"); } holder->shmem = nullptr; holder->heap = nullptr; } else { if (holder->heap == nullptr || holder->heap != addr) { MEDIA_LOGE("heap is invalid"); } else { delete [] holder->heap; holder->heap = nullptr; } } delete holder; } static void FreeAvBufferData(void *addr, void *context, uint32_t size) { (void)addr; (void)size; CHECK_AND_RETURN_LOG(context != nullptr, "context is nullptr"); AVBufferHolder *holder = reinterpret_cast(context); delete holder; } static void FreeSurfaceBuffer(void *addr, void *context, uint32_t size) { (void)addr; (void)size; CHECK_AND_RETURN_LOG(context != nullptr, "context is nullptr"); void* nativeBuffer = context; RefBase *ref = reinterpret_cast(nativeBuffer); ref->DecStrongRef(ref); } static PixelMapMemHolder *CreatePixelMapData(const std::shared_ptr &mem, const OutputFrame &frame) { PixelMapMemHolder *holder = new (std::nothrow) PixelMapMemHolder; CHECK_AND_RETURN_RET_LOG(holder != nullptr, nullptr, "alloc pixelmap mem holder failed"); ON_SCOPE_EXIT(0) { delete holder; }; int32_t minStride = frame.width_ * frame.bytesPerPixel_; CHECK_AND_RETURN_RET_LOG(minStride <= frame.stride_, nullptr, "stride info wrong"); if (frame.stride_ == minStride) { CANCEL_SCOPE_EXIT_GUARD(0); holder->isShmem = true; holder->shmem = mem; holder->heap = frame.GetFlattenedData(); return holder; } static constexpr int64_t maxAllowedSize = 100 * 1024 * 1024; int64_t memSize = static_cast(minStride) * frame.height_; CHECK_AND_RETURN_RET_LOG(memSize <= maxAllowedSize, nullptr, "alloc heap size too large"); uint8_t *heap = new (std::nothrow) uint8_t[memSize]; CHECK_AND_RETURN_RET_LOG(heap != nullptr, nullptr, "alloc heap failed"); ON_SCOPE_EXIT(1) { delete [] heap; }; uint8_t *currDstPos = heap; uint8_t *currSrcPos = frame.GetFlattenedData(); for (int32_t row = 0; row < frame.height_; ++row) { errno_t rc = memcpy_s(currDstPos, static_cast(memSize), currSrcPos, static_cast(minStride)); CHECK_AND_RETURN_RET_LOG(rc == EOK, nullptr, "memcpy_s failed"); currDstPos += minStride; currSrcPos += frame.stride_; memSize -= minStride; } holder->isShmem = false; holder->heap = heap; CANCEL_SCOPE_EXIT_GUARD(0); CANCEL_SCOPE_EXIT_GUARD(1); return holder; } static AVBufferHolder *CreateAVBufferHolder(const std::shared_ptr &avBuffer) { CHECK_AND_RETURN_RET(avBuffer != nullptr && avBuffer->memory_ != nullptr, nullptr); AVBufferHolder *holder = new (std::nothrow) AVBufferHolder; CHECK_AND_RETURN_RET_LOG(holder != nullptr, nullptr, "alloc avBuffer holder failed"); holder->buffer = avBuffer; return holder; } static std::shared_ptr CreatePixelMap(const std::shared_ptr &mem, PixelFormat color, int32_t &rotation) { CHECK_AND_RETURN_RET_LOG(mem != nullptr, nullptr, "Fetch frame failed"); CHECK_AND_RETURN_RET_LOG(mem->GetBase() != nullptr, nullptr, "Addr is nullptr"); CHECK_AND_RETURN_RET_LOG(mem->GetSize() > 0, nullptr, "size is incorrect"); CHECK_AND_RETURN_RET_LOG(static_cast(mem->GetSize()) >= sizeof(OutputFrame), nullptr, "size is incorrect"); OutputFrame *frame = reinterpret_cast(mem->GetBase()); MEDIA_LOGD("width: %{public}d, stride : %{public}d, height: %{public}d, size: %{public}d, format: %{public}d", frame->width_, frame->stride_, frame->height_, frame->size_, color); rotation = frame->rotation_; InitializationOptions opts; opts.size.width = frame->width_; opts.size.height = frame->height_; opts.pixelFormat = color; opts.editable = true; std::shared_ptr pixelMap = PixelMap::Create(opts); CHECK_AND_RETURN_RET_LOG(pixelMap != nullptr, nullptr, "pixelMap create failed"); CHECK_AND_RETURN_RET_LOG(pixelMap->GetByteCount() <= frame->size_, nullptr, "Size inconsistent !"); PixelMapMemHolder *holder = CreatePixelMapData(mem, *frame); CHECK_AND_RETURN_RET_LOG(holder != nullptr, nullptr, "create pixel map data failed"); pixelMap->SetPixelsAddr(holder->heap, holder, static_cast(pixelMap->GetByteCount()), AllocatorType::CUSTOM_ALLOC, FreePixelMapData); return pixelMap; } int32_t AVMetadataHelperImpl::SaveDataToFile(const std::string &fileName, const char *data, const size_t &totalSize) { CHECK_AND_RETURN_RET_LOG(data != nullptr, MSERR_INVALID_VAL, "data is nullptr"); std::ofstream outFile(FILE_DIR_IN_THE_SANDBOX + fileName, std::ofstream::out); if (!outFile.is_open()) { MEDIA_LOGI("winddraw::SaveDataToFile write error, path=%{public}s", fileName.c_str()); return MSERR_UNKNOWN; } outFile.write(data, totalSize); return MSERR_OK; } void AVMetadataHelperImpl::InitDumpFlag() { const std::string dumpTag = "sys.media.avmetadatahelper.dump.enable"; std::string dumpEnable; int32_t dumpRes = OHOS::system::GetStringParameter(dumpTag, dumpEnable, "false"); isDump_ = (dumpEnable == "true"); MEDIA_LOGI("get dump flag, dumpRes: %{public}d, isDump_: %{public}d", dumpRes, isDump_); } int32_t AVMetadataHelperImpl::DumpPixelMap(bool isDump, std::shared_ptr pixelMap, const std::string &fileNameSuffix) { if (!isDump) { return MSERR_INVALID_VAL; } CHECK_AND_RETURN_RET_LOG(pixelMap != nullptr, MSERR_INVALID_VAL, "invalid pixelMap"); std::string width = std::to_string(pixelMap->GetWidth()); std::string height = std::to_string(pixelMap->GetHeight()); std::string pixelFormat = pixelFormatToString(pixelMap->GetPixelFormat()); auto fileName = GetLocalTime() + "_" + width + "_" + height + "_" + pixelFormat + fileNameSuffix; if (pixelMap->GetAllocatorType() == AllocatorType::DMA_ALLOC) { auto surfaceBuffer = static_cast(pixelMap->GetFd()); CHECK_AND_RETURN_RET_LOG(surfaceBuffer != nullptr, MSERR_INVALID_VAL, "invalid surface buffer"); return SaveDataToFile(fileName, reinterpret_cast(surfaceBuffer->GetVirAddr()), surfaceBuffer->GetSize()); } return SaveDataToFile(fileName, reinterpret_cast(pixelMap->GetPixels()), pixelMap->GetByteCount()); } int32_t AVMetadataHelperImpl::DumpAVBuffer(bool isDump, const std::shared_ptr &frameBuffer, const std::string &fileNameSuffix) { if (!isDump) { return MSERR_INVALID_VAL; } bool isValid = frameBuffer != nullptr && frameBuffer->meta_ != nullptr && frameBuffer->memory_ != nullptr; CHECK_AND_RETURN_RET_LOG(isValid, MSERR_INVALID_VAL, "invalid frame buffer"); auto bufferMeta = frameBuffer->meta_; int32_t width = 0; int32_t height = 0; bool isHdr = false; bufferMeta->Get(width); bufferMeta->Get(height); bufferMeta->Get(isHdr); std::string widthStr = std::to_string(width); std::string heightStr = std::to_string(height); std::string pixelFormat = isHdr ? pixelFormatToString(PixelFormat::YCBCR_P010): pixelFormatToString(PixelFormat::NV12); auto fileName = GetLocalTime() + "_" + widthStr + "_" + heightStr + "_" + pixelFormat + fileNameSuffix; auto surfaceBuffer = frameBuffer->memory_->GetSurfaceBuffer(); if (surfaceBuffer == nullptr) { return SaveDataToFile(fileName, reinterpret_cast(frameBuffer->memory_->GetAddr()), frameBuffer->memory_->GetSize()); } return SaveDataToFile(fileName, reinterpret_cast(surfaceBuffer->GetVirAddr()), surfaceBuffer->GetSize()); } std::string AVMetadataHelperImpl::pixelFormatToString(PixelFormat pixelFormat) { switch (pixelFormat) { case PixelFormat::RGB_565: return "RGB_565"; case PixelFormat::RGBA_8888: return "RGBA_8888"; case PixelFormat::RGB_888: return "RGB_888"; case PixelFormat::NV12: return "NV12"; case PixelFormat::YCBCR_P010: return "YCBCR_P010"; default: return "UNKNOWN"; } } std::shared_ptr AVMetadataHelperImpl::CreatePixelMapYuv(const std::shared_ptr &frameBuffer, PixelMapInfo &pixelMapInfo) { bool isValid = frameBuffer != nullptr && frameBuffer->meta_ != nullptr && frameBuffer->memory_ != nullptr; CHECK_AND_RETURN_RET_LOG(isValid, nullptr, "invalid frame buffer"); auto bufferMeta = frameBuffer->meta_; int32_t width = 0; auto hasProperty = bufferMeta->Get(width); CHECK_AND_RETURN_RET_LOG(hasProperty, nullptr, "invalid width"); int32_t height = 0; hasProperty = bufferMeta->Get(height); CHECK_AND_RETURN_RET_LOG(hasProperty, nullptr, "invalid height"); Plugins::VideoRotation rotation = Plugins::VideoRotation::VIDEO_ROTATION_0; bufferMeta->Get(rotation); pixelMapInfo.rotation = static_cast(rotation); bufferMeta->Get(pixelMapInfo.isHdr); if (frameBuffer->memory_->GetSize() != 0 && frameBuffer->memory_->GetSurfaceBuffer() == nullptr) { InitializationOptions options = { .size = { .width = width, .height = height }, .pixelFormat = PixelFormat::NV12 }; return CreatePixelMapFromAVShareMemory(frameBuffer, pixelMapInfo, options); } auto surfaceBuffer = frameBuffer->memory_->GetSurfaceBuffer(); CHECK_AND_RETURN_RET_LOG(surfaceBuffer != nullptr, nullptr, "srcSurfaceBuffer is nullptr"); sptr mySurfaceBuffer = CopySurfaceBuffer(surfaceBuffer); CHECK_AND_RETURN_RET_LOG(mySurfaceBuffer != nullptr, nullptr, "Create SurfaceBuffer failed"); int32_t outputHeight = height; bufferMeta->Get(outputHeight); pixelMapInfo.outputHeight = outputHeight; MEDIA_LOGD("pixelMapInfo.outputHeight = %{public}d", pixelMapInfo.outputHeight); return CreatePixelMapFromSurfaceBuffer(mySurfaceBuffer, pixelMapInfo); } std::shared_ptr AVMetadataHelperImpl::CreatePixelMapFromAVShareMemory(const std::shared_ptr &frameBuffer, PixelMapInfo &pixelMapInfo, InitializationOptions &options) { bool isValid = frameBuffer != nullptr && frameBuffer->memory_ != nullptr; CHECK_AND_RETURN_RET_LOG(isValid, nullptr, "invalid frame buffer"); std::shared_ptr pixelMap = PixelMap::Create(options); CHECK_AND_RETURN_RET_LOG(pixelMap != nullptr, nullptr, "Create pixelMap failed"); AVBufferHolder *holder = CreateAVBufferHolder(frameBuffer); CHECK_AND_RETURN_RET_LOG(holder != nullptr, nullptr, "Create buffer holder failed"); uint8_t *pixelAddr = frameBuffer->memory_->GetAddr(); pixelMap->SetPixelsAddr(pixelAddr, holder, pixelMap->GetByteCount(), AllocatorType::CUSTOM_ALLOC, FreeAvBufferData); const InitializationOptions opts = { .size = { .width = pixelMap->GetWidth(), .height = pixelMap->GetHeight() }, .srcPixelFormat = PixelFormat::NV12, .pixelFormat = pixelMapInfo.pixelFormat }; pixelMap = PixelMap::Create(reinterpret_cast(pixelMap->GetPixels()), pixelMap->GetByteCount(), opts); sptr surfaceBuffer = nullptr; SetPixelMapYuvInfo(surfaceBuffer, pixelMap, pixelMapInfo); return pixelMap; } std::shared_ptr AVMetadataHelperImpl::CreatePixelMapFromSurfaceBuffer(sptr &surfaceBuffer, PixelMapInfo &pixelMapInfo) { CHECK_AND_RETURN_RET_LOG(surfaceBuffer != nullptr, nullptr, "surfaceBuffer is nullptr"); InitializationOptions options = { .size = { .width = surfaceBuffer->GetWidth(), .height = surfaceBuffer->GetHeight() } }; bool isHdr = pixelMapInfo.isHdr; options.srcPixelFormat = isHdr ? PixelFormat::YCBCR_P010 : PixelFormat::NV12; options.pixelFormat = isHdr ? PixelFormat::YCBCR_P010 : PixelFormat::NV12; options.useDMA = (isHdr || pixelMapInfo.pixelFormat == PixelFormat::NV12) ? true : false; int32_t colorLength = surfaceBuffer->GetWidth() * surfaceBuffer->GetHeight() * PIXEL_SIZE_HDR_YUV; colorLength = isHdr ? colorLength : colorLength / HDR_PIXEL_SIZE; std::shared_ptr pixelMap; if (!options.useDMA) { pixelMap = PixelMap::Create(options); CHECK_AND_RETURN_RET_LOG(pixelMap != nullptr, nullptr, "Create pixelMap failed"); auto ret = CopySurfaceBufferToPixelMap(surfaceBuffer, pixelMap, pixelMapInfo); CHECK_AND_RETURN_RET_LOG(ret == MSERR_OK, nullptr, "CopySurfaceBufferToPixelMap failed"); options.pixelFormat = pixelMapInfo.pixelFormat; pixelMap = PixelMap::Create(reinterpret_cast(pixelMap->GetPixels()), pixelMap->GetByteCount(), options); CHECK_AND_RETURN_RET_LOG(pixelMap != nullptr, nullptr, "Create non-DMA pixelMap failed"); } else { pixelMap = PixelMap::Create(reinterpret_cast(surfaceBuffer->GetVirAddr()), static_cast(colorLength), options); CHECK_AND_RETURN_RET_LOG(pixelMap != nullptr, nullptr, "Create DMA pixelMap failed"); void* nativeBuffer = surfaceBuffer.GetRefPtr(); RefBase *ref = reinterpret_cast(nativeBuffer); ref->IncStrongRef(ref); if (isHdr) { pixelMap->InnerSetColorSpace(OHOS::ColorManager::ColorSpace(ColorManager::ColorSpaceName::BT2020_HLG)); } pixelMap->SetPixelsAddr(surfaceBuffer->GetVirAddr(), surfaceBuffer.GetRefPtr(), surfaceBuffer->GetSize(), AllocatorType::DMA_ALLOC, FreeSurfaceBuffer); } SetPixelMapYuvInfo(surfaceBuffer, pixelMap, pixelMapInfo); return pixelMap; } int32_t AVMetadataHelperImpl::CopySurfaceBufferToPixelMap(sptr &surfaceBuffer, std::shared_ptr pixelMap, PixelMapInfo &pixelMapInfo) { CHECK_AND_RETURN_RET(surfaceBuffer != nullptr && pixelMap != nullptr, MSERR_INVALID_VAL); int32_t width = surfaceBuffer->GetWidth(); int32_t height = surfaceBuffer->GetHeight(); int32_t stride = surfaceBuffer->GetStride(); uint8_t *srcPtr = static_cast(surfaceBuffer->GetVirAddr()); uint8_t *dstPtr = const_cast(pixelMap->GetPixels()); // copy src Y component to dst int32_t lineByteCount = width; for (int32_t y = 0; y < height; y++) { auto ret = memcpy_s(dstPtr, lineByteCount, srcPtr, lineByteCount); TRUE_LOG(ret != EOK, MEDIA_LOGW, "Memcpy Y component failed."); srcPtr += stride; dstPtr += lineByteCount; } srcPtr = static_cast(surfaceBuffer->GetVirAddr()) + stride * pixelMapInfo.outputHeight; // copy src UV component to dst, height(UV) = height(Y) / 2 for (int32_t uv = 0; uv < height / 2; uv++) { auto ret = memcpy_s(dstPtr, lineByteCount, srcPtr, lineByteCount); TRUE_LOG(ret != EOK, MEDIA_LOGW, "Memcpy UV component failed."); srcPtr += stride; dstPtr += lineByteCount; } return MSERR_OK; } void AVMetadataHelperImpl::SetPixelMapYuvInfo(sptr &surfaceBuffer, std::shared_ptr pixelMap, PixelMapInfo &pixelMapInfo) { CHECK_AND_RETURN_LOG(pixelMap != nullptr, "invalid pixelMap"); uint8_t ratio = pixelMapInfo.isHdr ? HDR_PIXEL_SIZE : SDR_PIXEL_SIZE; int32_t srcWidth = pixelMap->GetWidth(); int32_t srcHeight = pixelMap->GetHeight(); YUVDataInfo yuvDataInfo = { .yWidth = srcWidth, .yHeight = srcHeight, .uvWidth = srcWidth / 2, .uvHeight = srcHeight / 2, .yStride = srcWidth, .uvStride = srcWidth, .uvOffset = srcWidth * srcHeight}; if (surfaceBuffer == nullptr) { pixelMap->SetImageYUVInfo(yuvDataInfo); return; } OH_NativeBuffer_Planes *planes = nullptr; GSError retVal = surfaceBuffer->GetPlanesInfo(reinterpret_cast(&planes)); if (retVal != OHOS::GSERROR_OK || planes == nullptr) { pixelMap->SetImageYUVInfo(yuvDataInfo); return; } yuvDataInfo.yStride = planes->planes[PLANE_Y].columnStride / ratio; yuvDataInfo.uvStride = planes->planes[PLANE_U].columnStride / ratio; yuvDataInfo.yOffset = planes->planes[PLANE_Y].offset / ratio; yuvDataInfo.uvOffset = planes->planes[PLANE_U].offset / ratio; pixelMap->SetImageYUVInfo(yuvDataInfo); } sptr AVMetadataHelperImpl::CopySurfaceBuffer(sptr &srcSurfaceBuffer) { CHECK_AND_RETURN_RET_LOG(srcSurfaceBuffer != nullptr, nullptr, "srcSurfaceBuffer is nullptr"); sptr dstSurfaceBuffer = SurfaceBuffer::Create(); BufferRequestConfig requestConfig = { .width = srcSurfaceBuffer->GetWidth(), .height = srcSurfaceBuffer->GetHeight(), .strideAlignment = 0x2, .format = srcSurfaceBuffer->GetFormat(), // always yuv .usage = srcSurfaceBuffer->GetUsage(), .timeout = 0, }; CHECK_AND_RETURN_RET_LOG(dstSurfaceBuffer != nullptr, nullptr, "Create surfaceBuffer failed"); GSError allocRes = dstSurfaceBuffer->Alloc(requestConfig); CHECK_AND_RETURN_RET_LOG(allocRes == 0, nullptr, "Alloc surfaceBuffer failed, ecode %{public}d", allocRes); CopySurfaceBufferInfo(srcSurfaceBuffer, dstSurfaceBuffer); int32_t copyRes = memcpy_s(dstSurfaceBuffer->GetVirAddr(), dstSurfaceBuffer->GetSize(), srcSurfaceBuffer->GetVirAddr(), srcSurfaceBuffer->GetSize()); CHECK_AND_RETURN_RET_LOG(copyRes == EOK, nullptr, "copy surface buffer pixels failed, copyRes %{public}d", copyRes); return dstSurfaceBuffer; } void AVMetadataHelperImpl::CopySurfaceBufferInfo(sptr &source, sptr &dst) { if (source == nullptr || dst == nullptr) { MEDIA_LOGI("CopySurfaceBufferInfo failed, source or dst is nullptr"); return; } std::vector hdrMetadataTypeVec; std::vector colorSpaceInfoVec; std::vector staticData; std::vector dynamicData; if (source->GetMetadata(ATTRKEY_HDR_METADATA_TYPE, hdrMetadataTypeVec) == GSERROR_OK) { dst->SetMetadata(ATTRKEY_HDR_METADATA_TYPE, hdrMetadataTypeVec); } if (source->GetMetadata(ATTRKEY_COLORSPACE_INFO, colorSpaceInfoVec) == GSERROR_OK) { dst->SetMetadata(ATTRKEY_COLORSPACE_INFO, colorSpaceInfoVec); } if (GetSbStaticMetadata(source, staticData) && (staticData.size() > 0)) { SetSbStaticMetadata(dst, staticData); } if (GetSbDynamicMetadata(source, dynamicData) && (dynamicData.size()) > 0) { SetSbDynamicMetadata(dst, dynamicData); } } bool AVMetadataHelperImpl::GetSbStaticMetadata(sptr &buffer, std::vector &staticMetadata) { return buffer->GetMetadata(ATTRKEY_HDR_STATIC_METADATA, staticMetadata) == GSERROR_OK; } bool AVMetadataHelperImpl::GetSbDynamicMetadata(sptr &buffer, std::vector &dynamicMetadata) { return buffer->GetMetadata(ATTRKEY_HDR_DYNAMIC_METADATA, dynamicMetadata) == GSERROR_OK; } bool AVMetadataHelperImpl::SetSbStaticMetadata(sptr &buffer, const std::vector &staticMetadata) { return buffer->SetMetadata(ATTRKEY_HDR_STATIC_METADATA, staticMetadata) == GSERROR_OK; } bool AVMetadataHelperImpl::SetSbDynamicMetadata(sptr &buffer, const std::vector &dynamicMetadata) { return buffer->SetMetadata(ATTRKEY_HDR_DYNAMIC_METADATA, dynamicMetadata) == GSERROR_OK; } std::shared_ptr AVMetadataHelperFactory::CreateAVMetadataHelper() { std::shared_ptr impl = std::make_shared(); CHECK_AND_RETURN_RET_LOG(impl != nullptr, nullptr, "failed to new AVMetadataHelperImpl"); int32_t ret = impl->Init(); CHECK_AND_RETURN_RET_LOG(ret == MSERR_OK, nullptr, "failed to init AVMetadataHelperImpl"); return impl; } int32_t AVMetadataHelperImpl::Init() { avMetadataHelperService_ = MediaServiceFactory::GetInstance().CreateAVMetadataHelperService(); CHECK_AND_RETURN_RET_LOG(avMetadataHelperService_ != nullptr, MSERR_NO_MEMORY, "failed to create avmetadatahelper service"); InitDumpFlag(); return MSERR_OK; } AVMetadataHelperImpl::AVMetadataHelperImpl() { MEDIA_LOGD("AVMetadataHelperImpl:0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this)); } AVMetadataHelperImpl::~AVMetadataHelperImpl() { if (avMetadataHelperService_ != nullptr) { (void)MediaServiceFactory::GetInstance().DestroyAVMetadataHelperService(avMetadataHelperService_); avMetadataHelperService_ = nullptr; } MEDIA_LOGD("AVMetadataHelperImpl:0x%{public}06" PRIXPTR " Instances destroy", FAKE_POINTER(this)); } int32_t AVMetadataHelperImpl::SetHelperCallback(const std::shared_ptr &callback) { MEDIA_LOGD("AVMetadataHelperImpl:0x%{public}06" PRIXPTR " SetHelperCallback in", FAKE_POINTER(this)); CHECK_AND_RETURN_RET_LOG(avMetadataHelperService_ != nullptr, MSERR_SERVICE_DIED, "metadata helper service does not exist.."); CHECK_AND_RETURN_RET_LOG(callback != nullptr, MSERR_INVALID_VAL, "callback is nullptr"); return avMetadataHelperService_->SetHelperCallback(callback); } void AVMetadataHelperImpl::SetScene(Scene scene) { ReportSceneCode(scene); } void AVMetadataHelperImpl::ReportSceneCode(Scene scene) { if (scene != Scene::AV_META_SCENE_CLONE && scene != Scene::AV_META_SCENE_BATCH_HANDLE) { return; } if (scene == Scene::AV_META_SCENE_BATCH_HANDLE && concurrentWorkCount_ < HIGH_CONCRENT_WORK_NUM) { return; } auto sceneCode = SCENE_CODE_MAP[scene]; auto lastTsp = SCENE_TIMESTAMP_MAP[scene]; auto now = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()); auto duration = now - std::chrono::milliseconds(lastTsp); if (duration < std::chrono::milliseconds(SCENE_CODE_EFFECTIVE_DURATION_MS)) { return; } SCENE_TIMESTAMP_MAP[scene] = now.count(); MEDIA_LOGI("Report scene code %{public}ld", sceneCode); int32_t ret = HiSysEventWrite( PERFORMANCE_STATS, "CPU_SCENE_ENTRY", OHOS::HiviewDFX::HiSysEvent::EventType::BEHAVIOR, "PACKAGE_NAME", "media_service", "SCENE_ID", std::to_string(sceneCode).c_str(), "HAPPEN_TIME", now.count()); if (ret != MSERR_OK) { MEDIA_LOGW("report error"); } } int32_t AVMetadataHelperImpl::SetSource(const std::string &uri, int32_t usage) { CHECK_AND_RETURN_RET_LOG(avMetadataHelperService_ != nullptr, MSERR_NO_MEMORY, "avmetadatahelper service does not exist.."); CHECK_AND_RETURN_RET_LOG(!uri.empty(), MSERR_INVALID_VAL, "uri is empty."); concurrentWorkCount_++; ReportSceneCode(AV_META_SCENE_BATCH_HANDLE); auto res = avMetadataHelperService_->SetSource(uri, usage); concurrentWorkCount_--; return res; } int32_t AVMetadataHelperImpl::SetSource(int32_t fd, int64_t offset, int64_t size, int32_t usage) { CHECK_AND_RETURN_RET_LOG(avMetadataHelperService_ != nullptr, MSERR_NO_MEMORY, "avmetadatahelper service does not exist.."); MEDIA_LOGI("Set file source fd: %{public}d, offset: %{public}" PRIu64 ", size: %{public}" PRIu64, fd, offset, size); concurrentWorkCount_++; ReportSceneCode(AV_META_SCENE_BATCH_HANDLE); auto res = avMetadataHelperService_->SetSource(fd, offset, size, usage); concurrentWorkCount_--; return res; } int32_t AVMetadataHelperImpl::SetSource(const std::shared_ptr &dataSrc) { MEDIA_LOGD("AVMetadataHelperImpl:0x%{public}06" PRIXPTR " SetSource in(dataSrc)", FAKE_POINTER(this)); CHECK_AND_RETURN_RET_LOG(dataSrc != nullptr, MSERR_INVALID_VAL, "failed to create data source"); concurrentWorkCount_++; ReportSceneCode(AV_META_SCENE_BATCH_HANDLE); auto res = avMetadataHelperService_->SetSource(dataSrc); concurrentWorkCount_--; return res; } std::string AVMetadataHelperImpl::ResolveMetadata(int32_t key) { CHECK_AND_RETURN_RET_LOG(avMetadataHelperService_ != nullptr, "", "avmetadatahelper service does not exist."); concurrentWorkCount_++; auto res = avMetadataHelperService_->ResolveMetadata(key); concurrentWorkCount_--; return res; } std::unordered_map AVMetadataHelperImpl::ResolveMetadata() { CHECK_AND_RETURN_RET_LOG(avMetadataHelperService_ != nullptr, {}, "avmetadatahelper service does not exist."); concurrentWorkCount_++; auto res = avMetadataHelperService_->ResolveMetadata(); concurrentWorkCount_--; return res; } std::shared_ptr AVMetadataHelperImpl::GetAVMetadata() { CHECK_AND_RETURN_RET_LOG(avMetadataHelperService_ != nullptr, nullptr, "avmetadatahelper service does not exist."); concurrentWorkCount_++; auto res = avMetadataHelperService_->GetAVMetadata(); concurrentWorkCount_--; return res; } std::shared_ptr AVMetadataHelperImpl::FetchArtPicture() { CHECK_AND_RETURN_RET_LOG(avMetadataHelperService_ != nullptr, nullptr, "avmetadatahelper service does not exist."); concurrentWorkCount_++; auto res = avMetadataHelperService_->FetchArtPicture(); concurrentWorkCount_--; return res; } std::shared_ptr AVMetadataHelperImpl::FetchFrameAtTime( int64_t timeUs, int32_t option, const PixelMapParams ¶m) { CHECK_AND_RETURN_RET_LOG(avMetadataHelperService_ != nullptr, nullptr, "avmetadatahelper service does not exist."); concurrentWorkCount_++; ReportSceneCode(AV_META_SCENE_BATCH_HANDLE); OutputConfiguration config; config.colorFormat = param.colorFormat; config.dstHeight = param.dstHeight; config.dstWidth = param.dstWidth; auto mem = avMetadataHelperService_->FetchFrameAtTime(timeUs, option, config); auto pixelMap = CreatePixelMap(mem, PixelFormat::NV12, rotation_); concurrentWorkCount_--; CHECK_AND_RETURN_RET_LOG(pixelMap != nullptr, nullptr, "pixelMap does not exist."); const InitializationOptions opts = { .size = { .width = pixelMap->GetWidth(), .height = pixelMap->GetHeight() }, .srcPixelFormat = PixelFormat::NV12 }; pixelMap = PixelMap::Create(reinterpret_cast(pixelMap->GetPixels()), pixelMap->GetByteCount(), opts); if (pixelMap == nullptr) { return nullptr; } if (rotation_ > 0) { pixelMap->rotate(rotation_); } int32_t srcWidth = pixelMap->GetWidth(); int32_t srcHeight = pixelMap->GetHeight(); bool needScale = (param.dstWidth > 0 && param.dstHeight > 0) && (param.dstWidth <= srcWidth && param.dstHeight <= srcHeight) && (param.dstWidth < srcWidth || param.dstHeight < srcHeight) && srcWidth > 0 && srcHeight > 0; if (needScale) { pixelMap->scale((1.0f * param.dstWidth) / srcWidth, (1.0f * param.dstHeight) / srcHeight); } return pixelMap; } void AVMetadataHelperImpl::ScalePixelMap( std::shared_ptr &pixelMap, PixelMapInfo &info, const PixelMapParams ¶m) { int32_t srcWidth = pixelMap->GetWidth(); int32_t srcHeight = pixelMap->GetHeight(); int32_t dstWidth = info.rotation % NUM_180 == 0 ? param.dstWidth : param.dstHeight; int32_t dstHeight = info.rotation % NUM_180 == 0 ? param.dstHeight : param.dstWidth; bool needScale = (dstWidth > 0 && dstHeight > 0) && (dstWidth <= srcWidth && dstHeight <= srcHeight) && (dstWidth < srcWidth || dstHeight < srcHeight) && srcWidth > 0 && srcHeight > 0; CHECK_AND_RETURN(needScale); pixelMap->scale((1.0f * dstWidth) / srcWidth, (1.0f * dstHeight) / srcHeight); } std::shared_ptr AVMetadataHelperImpl::FetchFrameYuv(int64_t timeUs, int32_t option, const PixelMapParams ¶m) { CHECK_AND_RETURN_RET_LOG(avMetadataHelperService_ != nullptr, nullptr, "avmetadatahelper service does not exist."); concurrentWorkCount_++; ReportSceneCode(AV_META_SCENE_BATCH_HANDLE); OutputConfiguration config = { .dstWidth = param.dstWidth, .dstHeight = param.dstHeight, .colorFormat = param.colorFormat }; auto frameBuffer = avMetadataHelperService_->FetchFrameYuv(timeUs, option, config); CHECK_AND_RETURN_RET(frameBuffer != nullptr && frameBuffer->memory_ != nullptr, nullptr); concurrentWorkCount_--; DumpAVBuffer(isDump_, frameBuffer, DUMP_FILE_NAME_AVBUFFER); PixelMapInfo pixelMapInfo = { .pixelFormat = param.colorFormat }; auto pixelMap = CreatePixelMapYuv(frameBuffer, pixelMapInfo); CHECK_AND_RETURN_RET_LOG(pixelMap != nullptr, nullptr, "convert to pixelMap failed"); DumpPixelMap(isDump_, pixelMap, DUMP_FILE_NAME_PIXEMAP); ScalePixelMap(pixelMap, pixelMapInfo, param); DumpPixelMap(isDump_, pixelMap, DUMP_FILE_NAME_AFTER_SCLAE); if (pixelMapInfo.rotation > 0) { pixelMap->rotate(pixelMapInfo.rotation); } DumpPixelMap(isDump_, pixelMap, DUMP_FILE_NAME_AFTER_ROTATE); return pixelMap; } int32_t AVMetadataHelperImpl::GetTimeByFrameIndex(uint32_t index, uint64_t &time) { CHECK_AND_RETURN_RET_LOG(avMetadataHelperService_ != nullptr, 0, "avmetadatahelper service does not exist."); concurrentWorkCount_++; auto res = avMetadataHelperService_->GetTimeByFrameIndex(index, time); concurrentWorkCount_--; return res; } int32_t AVMetadataHelperImpl::GetFrameIndexByTime(uint64_t time, uint32_t &index) { CHECK_AND_RETURN_RET_LOG(avMetadataHelperService_ != nullptr, 0, "avmetadatahelper service does not exist."); concurrentWorkCount_++; auto res = avMetadataHelperService_->GetFrameIndexByTime(time, index); concurrentWorkCount_--; return res; } void AVMetadataHelperImpl::Release() { MEDIA_LOGI("0x%{public}06" PRIXPTR " Release", FAKE_POINTER(this)); CHECK_AND_RETURN_LOG(avMetadataHelperService_ != nullptr, "avmetadatahelper service does not exist."); avMetadataHelperService_->Release(); (void)MediaServiceFactory::GetInstance().DestroyAVMetadataHelperService(avMetadataHelperService_); avMetadataHelperService_ = nullptr; } void AVMetadataHelperImpl::SetIsNapiInstance(bool isNapiInstance) { CHECK_AND_RETURN_LOG(avMetadataHelperService_ != nullptr, "avmetadatahelper service does not exist."); avMetadataHelperService_->SetIsNapiInstance(isNapiInstance); } } // namespace Media } // namespace OHOS