e2669154创建于 7月20日历史提交
/*
 * Copyright (C) 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 "auxiliary_generator.h"
#include "abs_image_decoder.h"
#include "fragment_metadata.h"
#include "hdr_type.h"
#include "image_log.h"
#include "image_trace.h"
#include "image_utils.h"
#include "image_mime_type.h"
#include "image_source.h"
#include "jpeg_mpf_parser.h"
#include "metadata.h"
#include "pixel_map.h"
#include "pixel_yuv.h"
#ifdef EXT_PIXEL
#include "pixel_yuv_ext.h"
#endif
#include "securec.h"
#include "surface_buffer.h"

namespace OHOS {
namespace Media {
using namespace ImagePlugin;

static constexpr uint32_t FIRST_FRAME = 0;
static constexpr int32_t DEFAULT_SCALE_DENOMINATOR = 1;
static constexpr int32_t DEPTH_SCALE_DENOMINATOR = 4;
static constexpr int32_t LINEAR_SCALE_DENOMINATOR = 4;
static constexpr uint32_t NV12_PLANE_UV_INDEX = 1;
static constexpr uint32_t NV21_PLANE_UV_INDEX = 2;
static const uint8_t NUM_1 = 1;

static inline bool IsSizeVailed(const Size &size)
{
    return (size.width != 0 && size.height != 0);
}

static int32_t GetAuxiliaryPictureDenominator(AuxiliaryPictureType type)
{
    int32_t denominator = DEFAULT_SCALE_DENOMINATOR;
    switch (type) {
        case AuxiliaryPictureType::DEPTH_MAP:
            denominator = DEPTH_SCALE_DENOMINATOR;
            break;
        case AuxiliaryPictureType::LINEAR_MAP:
            denominator = LINEAR_SCALE_DENOMINATOR;
            break;
        default:
            break;
    }
    return denominator;
}

static uint32_t SetAuxiliaryDecodeOption(std::unique_ptr<AbsImageDecoder> &decoder, PixelFormat mainPixelFormat,
    PlImageInfo &plInfo, AuxiliaryPictureType type)
{
    Size size;
    uint32_t errorCode = decoder->GetImageSize(FIRST_FRAME, size);
    if (errorCode != SUCCESS || !IsSizeVailed(size)) {
        return ERR_IMAGE_DATA_ABNORMAL;
    }
    PixelDecodeOptions plOptions;
    plOptions.desiredSize = size;
    bool useF16Format = (type == AuxiliaryPictureType::LINEAR_MAP || type == AuxiliaryPictureType::DEPTH_MAP);
    plOptions.desiredPixelFormat = useF16Format ? PixelFormat::RGBA_F16 : mainPixelFormat;
    IMAGE_LOGI("%{public}s desiredPixelFormat is %{public}d", __func__, plOptions.desiredPixelFormat);
    errorCode = decoder->SetDecodeOptions(FIRST_FRAME, plOptions, plInfo);
    return errorCode;
}

static void FreeContextBuffer(const Media::CustomFreePixelMap &func, AllocatorType allocType, PlImageBuffer &buffer)
{
    if (func != nullptr) {
        func(buffer.buffer, buffer.context, buffer.bufferSize);
        return;
    }

#if !defined(_WIN32) && !defined(_APPLE) && !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
    if (allocType == AllocatorType::SHARE_MEM_ALLOC) {
        int *fd = static_cast<int *>(buffer.context);
        if (buffer.buffer != nullptr) {
            ::munmap(buffer.buffer, buffer.bufferSize);
        }
        if (fd != nullptr) {
            ::close(*fd);
        }
        return;
    } else if (allocType == AllocatorType::DMA_ALLOC) {
        if (buffer.buffer != nullptr) {
            ImageUtils::SurfaceBuffer_Unreference(static_cast<SurfaceBuffer *>(buffer.context));
            buffer.context = nullptr;
        }
    } else if (allocType == AllocatorType::HEAP_ALLOC) {
        if (buffer.buffer != nullptr) {
            free(buffer.buffer);
            buffer.buffer = nullptr;
        }
    }
#else
    if (buffer.buffer != nullptr) {
        free(buffer.buffer);
        buffer.buffer = nullptr;
    }
#endif
}

ImageInfo AuxiliaryGenerator::MakeImageInfo(const Size &size, PixelFormat format, AlphaType alphaType,
    ColorSpace colorSpace, const std::string &encodedFormat)
{
    ImageInfo info;
    info.size.width = size.width;
    info.size.height = size.height;
    info.pixelFormat = format;
    info.alphaType = alphaType;
    info.colorSpace = colorSpace;
    info.encodedFormat = encodedFormat;
    return info;
}

static AuxiliaryPictureInfo MakeAuxiliaryPictureInfo(AuxiliaryPictureType type,
    const Size &size, uint32_t rowStride, PixelFormat format, ColorSpace colorSpace)
{
    AuxiliaryPictureInfo info;
    info.auxiliaryPictureType = type;
    info.size.width = size.width;
    info.size.height = size.height;
    info.rowStride = rowStride;
    info.pixelFormat = format;
    info.colorSpace = colorSpace;
    return info;
}

static void SetDmaYuvInfo(SurfaceBuffer *&surfaceBuffer, PixelFormat format, YUVDataInfo &yuvInfo)
{
    if (surfaceBuffer == nullptr) {
        IMAGE_LOGE("%{public}s: surfacebuffer is nullptr", __func__);
        return;
    }
    OH_NativeBuffer_Planes *planes = nullptr;
    GSError retVal = surfaceBuffer->GetPlanesInfo(reinterpret_cast<void **>(&planes));
    if (retVal != OHOS::GSERROR_OK || planes == nullptr) {
        IMAGE_LOGE("%{public}s: GetPlanesInfo failed retVal: %{public}d", __func__, retVal);
        return;
    }
    const OH_NativeBuffer_Plane &planeY = planes->planes[0];
    bool isNV21 = (format == PixelFormat::NV21 || format == PixelFormat::YCRCB_P010);
    const OH_NativeBuffer_Plane &planeUV = planes->planes[isNV21 ? NV21_PLANE_UV_INDEX : NV12_PLANE_UV_INDEX];
    if (format == PixelFormat::YCRCB_P010 || format == PixelFormat::YCBCR_P010) {
        yuvInfo.yStride = planeY.columnStride / 2;
        yuvInfo.uvStride = planeUV.columnStride / 2;
        yuvInfo.yOffset = planeY.offset / 2;
        yuvInfo.uvOffset = planeUV.offset / 2;
    } else {
        yuvInfo.yStride = planeY.columnStride;
        yuvInfo.uvStride = planeUV.columnStride;
        yuvInfo.yOffset = planeY.offset;
        yuvInfo.uvOffset = planeUV.offset;
    }
}

static void SetNonDmaYuvInfo(int32_t width, int32_t height, YUVDataInfo &yuvInfo)
{
    yuvInfo.imageSize.width = width;
    yuvInfo.imageSize.height = height;
    yuvInfo.yWidth = static_cast<uint32_t>(width);
    yuvInfo.yHeight = static_cast<uint32_t>(height);
    yuvInfo.uvWidth = static_cast<uint32_t>((width + 1) / 2);
    yuvInfo.uvHeight = static_cast<uint32_t>((height + 1) / 2);
    yuvInfo.yStride = static_cast<uint32_t>(width);
    yuvInfo.uvStride = static_cast<uint32_t>(((width + 1) / 2) * 2);
    yuvInfo.uvOffset = static_cast<uint32_t>(width) * static_cast<uint32_t>(height);
}

static void TrySetYUVDataInfo(std::unique_ptr<PixelMap> &pixelMap)
{
    if (pixelMap == nullptr) {
        IMAGE_LOGE("%{public}s pixelMap is nullptr", __func__);
        return;
    }
    PixelFormat format = pixelMap->GetPixelFormat();
    if (!ImageSource::IsYuvFormat(format)) {
        IMAGE_LOGI("%{public}s pixelMap is not YUV format", __func__);
        return;
    }

    YUVDataInfo info;
    if (pixelMap->GetAllocatorType() == AllocatorType::DMA_ALLOC && pixelMap->GetFd() != nullptr) {
        SurfaceBuffer *surfaceBuffer = reinterpret_cast<SurfaceBuffer *>(pixelMap->GetFd());
        SetDmaYuvInfo(surfaceBuffer, format, info);
    } else {
        SetNonDmaYuvInfo(pixelMap->GetWidth(), pixelMap->GetHeight(), info);
    }
    pixelMap->SetImageYUVInfo(info);
}

static bool ResizeAuxPixelMap(std::unique_ptr<PixelMap>& pixelMap, DecodeContext &context)
{
    if (context.outInfo.size.height != pixelMap->GetHeight() ||
        context.outInfo.size.width != pixelMap->GetWidth()) {
        if (ImageSource::IsYuvFormat(pixelMap->GetPixelFormat())) {
#ifdef EXT_PIXEL
            auto pixelYuv = reinterpret_cast<PixelYuvExt *>(pixelMap.get());
            bool cond = !pixelYuv->resizeForPicture(context.outInfo.size.width, context.outInfo.size.height);
            CHECK_ERROR_RETURN_RET(cond, false);
#else
            auto pixelYuv = reinterpret_cast<PixelYuv *>(pixelMap.get());
            bool cond = !pixelYuv->resizeForPicture(context.outInfo.size.width, context.outInfo.size.height);
            CHECK_ERROR_RETURN_RET(cond, false);
#endif
        } else {
            float xScale = static_cast<float>(context.outInfo.size.width) / pixelMap->GetWidth();
            float yScale = static_cast<float>(context.outInfo.size.height) / pixelMap->GetHeight();
            bool cond = !pixelMap->resize(xScale, yScale);
            CHECK_ERROR_RETURN_RET(cond, false);
        }
    }
    return true;
}

std::unique_ptr<PixelMap> AuxiliaryGenerator::CreatePixelMapByContext(DecodeContext &context,
    std::unique_ptr<AbsImageDecoder> &decoder, const std::string &encodedFormat, uint32_t &errorCode)
{
    std::unique_ptr<PixelMap> pixelMap;
    if (ImageSource::IsYuvFormat(context.info.pixelFormat)) {
#ifdef EXT_PIXEL
        pixelMap = std::make_unique<PixelYuvExt>();
#else
        pixelMap = std::make_unique<PixelYuv>();
#endif
    } else {
        pixelMap = std::make_unique<PixelMap>();
    }
    if (pixelMap == nullptr) {
        errorCode = ERR_IMAGE_ADD_PIXEL_MAP_FAILED;
        return nullptr;
    }

    ImageInfo imageinfo = AuxiliaryGenerator::MakeImageInfo(context.info.size, context.info.pixelFormat,
        context.info.alphaType, context.colorSpace, encodedFormat);
    pixelMap->SetImageInfo(imageinfo, true);

    PixelMapAddrInfos addrInfos;
    ImageSource::ContextToAddrInfos(context, addrInfos);
    pixelMap->SetPixelsAddr(addrInfos.addr, addrInfos.context, addrInfos.size, addrInfos.type, addrInfos.func);
    TrySetYUVDataInfo(pixelMap);
    CHECK_ERROR_RETURN_RET_LOG(!ResizeAuxPixelMap(pixelMap, context), nullptr,
        "[ImageSource]Resize auxiliary pixelmap fail.");
#ifdef IMAGE_COLORSPACE_FLAG
    if (context.hdrType > ImageHdrType::SDR) {
        pixelMap->InnerSetColorSpace(ColorManager::ColorSpace(context.grColorSpaceName));
    } else if (decoder->IsSupportICCProfile()) {
        pixelMap->InnerSetColorSpace(decoder->GetPixelMapColorSpace());
    }
#endif
    return pixelMap;
}

static uint32_t DecodeHdrMetadata(ImageHdrType hdrType, std::unique_ptr<AbsImageDecoder> &extDecoder,
    std::unique_ptr<AuxiliaryPicture> &auxPicture)
{
    bool cond = (auxPicture == nullptr);
    CHECK_ERROR_RETURN_RET_LOG(cond, ERR_IMAGE_GET_DATA_ABNORMAL, "DecodeHdrMetadata: AuxiliaryPicture is null");
    std::shared_ptr<HdrMetadata> hdrMetadata = std::make_shared<HdrMetadata>(extDecoder->GetHdrMetadata(hdrType));
    std::shared_ptr<PixelMap> pixelMap = auxPicture->GetContentPixel();
    cond = (pixelMap == nullptr);
    CHECK_ERROR_RETURN_RET_LOG(cond, ERR_IMAGE_GET_DATA_ABNORMAL, "Get invalid content pixel map for hdr metadata");
    pixelMap->SetHdrMetadata(hdrMetadata);
    pixelMap->SetHdrType(hdrType);
    return SUCCESS;
}

std::shared_ptr<ImageMetadata> AuxiliaryGenerator::MakeFragmentMetadata(Rect fragmentRect)
{
    std::shared_ptr<ImageMetadata> fragmentMetadata = std::make_shared<FragmentMetadata>();
    fragmentMetadata->SetValue(FRAGMENT_METADATA_KEY_X, std::to_string(fragmentRect.left));
    fragmentMetadata->SetValue(FRAGMENT_METADATA_KEY_Y, std::to_string(fragmentRect.top));
    fragmentMetadata->SetValue(FRAGMENT_METADATA_KEY_WIDTH, std::to_string(fragmentRect.width));
    fragmentMetadata->SetValue(FRAGMENT_METADATA_KEY_HEIGHT, std::to_string(fragmentRect.height));
    return fragmentMetadata;
}

static uint32_t DecodeHeifFragmentMetadata(std::unique_ptr<AbsImageDecoder> &extDecoder,
    std::unique_ptr<AuxiliaryPicture> &auxPicture)
{
    Rect fragmentRect;
    bool cond = extDecoder->GetHeifFragmentMetadata(fragmentRect);
    CHECK_ERROR_RETURN_RET_LOG(!cond, ERR_IMAGE_GET_DATA_ABNORMAL, "Heif parsing fragment metadata failed");
    auto fragmentMetadata = AuxiliaryGenerator::MakeFragmentMetadata(fragmentRect);
    auxPicture->SetMetadata(MetadataType::FRAGMENT, fragmentMetadata);
    return SUCCESS;
}

static uint32_t DecodeJpegFragmentMetadata(std::unique_ptr<InputDataStream> &auxStream,
    std::unique_ptr<AuxiliaryPicture> &auxPicture)
{
    uint8_t *data = auxStream->GetDataPtr();
    uint32_t size = auxStream->GetStreamSize();
    Rect fragmentRect;
    bool cond = JpegMpfParser::ParsingFragmentMetadata(data, size, fragmentRect);
    CHECK_ERROR_RETURN_RET_LOG(!cond, ERR_IMAGE_GET_DATA_ABNORMAL, "Jpeg parsing fragment metadata failed");
    auto fragmentMetadata = AuxiliaryGenerator::MakeFragmentMetadata(fragmentRect);
    auxPicture->SetMetadata(MetadataType::FRAGMENT, fragmentMetadata);
    return SUCCESS;
}

static sptr<SurfaceBuffer> AllocSurfaceBuffer(Size &size, int32_t format, uint32_t &errorCode)
{
    IMAGE_LOGD("SurfaceBuffer alloc width: %{public}d, height: %{public}d, format: %{public}d",
        size.width, size.height, format);
    sptr<SurfaceBuffer> sb = SurfaceBuffer::Create();
    BufferRequestConfig requestConfig = {
        .width = size.width,
        .height = size.height,
        .strideAlignment = 0x8, // set 0x8 as default value to alloc SurfaceBufferImpl
        .format = format,
        .usage = BUFFER_USAGE_CPU_READ | BUFFER_USAGE_CPU_WRITE | BUFFER_USAGE_MEM_DMA | BUFFER_USAGE_MEM_MMZ_CACHE,
        .timeout = 0,
    };
    GSError ret = sb->Alloc(requestConfig);
    if (ret != GSERROR_OK) {
        IMAGE_LOGE("SurfaceBuffer alloc failed, %{public}s", GSErrorStr(ret).c_str());
        errorCode = ERR_DMA_NOT_EXIST;
        return nullptr;
    }
    errorCode = SUCCESS;
    return sb;
}

static uint32_t CopyToSurfaceBuffer(std::unique_ptr<InputDataStream> &stream, sptr<SurfaceBuffer> &surfaceBuffer)
{
    uint8_t *src = stream->GetDataPtr();
    uint32_t srcSize = stream->GetStreamSize();
    uint8_t *dst = static_cast<uint8_t *>(surfaceBuffer->GetVirAddr());
    uint32_t dstSize = surfaceBuffer->GetSize();
    bool cond = (src == nullptr || dst == nullptr || srcSize == 0 || dstSize == 0);
    CHECK_ERROR_RETURN_RET_LOG(cond, ERR_IMAGE_INVALID_PARAMETER, "%{public}s: invalid input data", __func__);
    IMAGE_LOGD("SurfaceBuffer size: %{public}u, stream size: %{public}u", dstSize, srcSize);
    cond = (memcpy_s(dst, dstSize, src, srcSize) != EOK);
    CHECK_ERROR_RETURN_RET_LOG(cond, ERR_MEMORY_COPY_FAILED, "%{public}s: memcpy failed", __func__);
    return SUCCESS;
}

static void SetUncodedAuxilaryPictureInfo(std::unique_ptr<AuxiliaryPicture> &auxPicture)
{
    if (auxPicture == nullptr || auxPicture->GetContentPixel() == nullptr) {
        IMAGE_LOGE("%{public}s auxPicture or auxPixelMap is nullptr", __func__);
        return;
    }
    auto auxPixelMap = auxPicture->GetContentPixel();
    ImageInfo imageInfo;
    auxPixelMap->GetImageInfo(imageInfo);
    auto auxInfo = MakeAuxiliaryPictureInfo(auxPicture->GetType(), imageInfo.size, auxPixelMap->GetRowStride(),
        imageInfo.pixelFormat, imageInfo.colorSpace);
    auxPicture->SetAuxiliaryPictureInfo(auxInfo);
}

void GetAuxiliaryPictureSize(const AuxiliaryPictureDecodeInfo& auxiliaryPictureDecodeInfo,
    DecodeContext& context)
{
    if (fabs(auxiliaryPictureDecodeInfo.downSamplingScaleFactor.widthScaleFactor - NUM_1) > EPSILON) {
        context.outInfo.size.width = context.outInfo.size.width *
            auxiliaryPictureDecodeInfo.downSamplingScaleFactor.widthScaleFactor;
    }
    if (fabs(auxiliaryPictureDecodeInfo.downSamplingScaleFactor.heightScaleFactor - NUM_1) > EPSILON) {
        context.outInfo.size.height = context.outInfo.size.height *
            auxiliaryPictureDecodeInfo.downSamplingScaleFactor.heightScaleFactor;
    }
}
static std::unique_ptr<AuxiliaryPicture> GenerateAuxiliaryPicture(const MainPictureInfo &mainInfo, uint32_t &errorCode,
    std::unique_ptr<AbsImageDecoder> &extDecoder, const AuxiliaryPictureDecodeInfo& auxiliaryPictureDecodeInfo)
{
    IMAGE_LOGI("Generate by decoder, type: %{public}d, format: %{public}s",
        static_cast<int>(auxiliaryPictureDecodeInfo.type), auxiliaryPictureDecodeInfo.imageType.c_str());
    DecodeContext context;
    context.allocatorType = AllocatorType::DMA_ALLOC;
    errorCode = SetAuxiliaryDecodeOption(extDecoder, mainInfo.imageInfo.pixelFormat, context.info,
        auxiliaryPictureDecodeInfo.type);
    if (errorCode != SUCCESS) {
        IMAGE_LOGE("Set auxiliary decode option failed! errorCode: %{public}u", errorCode);
        return nullptr;
    }
    if (auxiliaryPictureDecodeInfo.imageType == IMAGE_HEIF_FORMAT) {
#ifdef HEIF_HW_DECODE_ENABLE
        if (auxiliaryPictureDecodeInfo.type == AuxiliaryPictureType::LINEAR_MAP ||
            auxiliaryPictureDecodeInfo.type == AuxiliaryPictureType::DEPTH_MAP) {
            context.pixelFormat = PixelFormat::RGBA_F16;
            context.info.pixelFormat = PixelFormat::RGBA_F16;
        }
        if (!extDecoder->DecodeHeifAuxiliaryMap(context, auxiliaryPictureDecodeInfo.type)) {
            errorCode = ERR_IMAGE_DECODE_FAILED;
        }
#else
        errorCode = ERR_IMAGE_HW_DECODE_UNSUPPORT;
#endif
    } else if (auxiliaryPictureDecodeInfo.imageType == IMAGE_JPEG_FORMAT) {
        errorCode = extDecoder->Decode(FIRST_FRAME, context);
        context.hdrType = mainInfo.hdrType;
    } else {
        errorCode = ERR_MEDIA_DATA_UNSUPPORT;
    }
    if (errorCode != SUCCESS) {
        IMAGE_LOGE("Decode failed! Format: %{public}s, errorCode: %{public}u",
            auxiliaryPictureDecodeInfo.imageType.c_str(), errorCode);
        FreeContextBuffer(context.freeFunc, context.allocatorType, context.pixelsBuffer);
        return nullptr;
    }
    GetAuxiliaryPictureSize(auxiliaryPictureDecodeInfo, context);
    std::string encodedFormat = ImageUtils::IsAuxiliaryPictureEncoded(auxiliaryPictureDecodeInfo.type) ?
        auxiliaryPictureDecodeInfo.imageType : "";
    std::shared_ptr<PixelMap> pixelMap = AuxiliaryGenerator::CreatePixelMapByContext(
        context, extDecoder, encodedFormat, errorCode);
    bool cond = pixelMap == nullptr || errorCode != SUCCESS;
    CHECK_ERROR_RETURN_RET_LOG(cond, nullptr, "%{public}s CreatePixelMapByContext failed!", __func__);
    context.pixelFormat = pixelMap->GetPixelFormat();
    auto auxPicture = AuxiliaryPicture::Create(pixelMap, auxiliaryPictureDecodeInfo.type, context.outInfo.size);
    CHECK_ERROR_RETURN_RET_LOG(!auxPicture, nullptr, "auxPicture is nullptr");
    auxPicture->SetAuxiliaryPictureInfo(MakeAuxiliaryPictureInfo(auxiliaryPictureDecodeInfo.type,
        context.outInfo.size, pixelMap->GetRowStride(), context.pixelFormat, context.outInfo.colorSpace));
    return auxPicture;
}

std::shared_ptr<AuxiliaryPicture> AuxiliaryGenerator::GenerateHeifAuxiliaryPicture(const MainPictureInfo &mainInfo,
    std::unique_ptr<AbsImageDecoder> &extDecoder, uint32_t &errorCode,
    const AuxiliaryPictureDecodeInfo& auxiliaryPictureDecodeInfo)
{
    IMAGE_LOGI("Generate heif auxiliary picture, type: %{public}d", static_cast<int>(auxiliaryPictureDecodeInfo.type));
    if (!ImageUtils::IsAuxiliaryPictureTypeSupported(auxiliaryPictureDecodeInfo.type) || extDecoder == nullptr) {
        errorCode = ERR_IMAGE_INVALID_PARAMETER;
        return nullptr;
    }

    auto auxPicture = GenerateAuxiliaryPicture(mainInfo, errorCode, extDecoder, auxiliaryPictureDecodeInfo);
    bool cond = (errorCode != SUCCESS);
    CHECK_ERROR_RETURN_RET_LOG(cond, nullptr,
        "Generate heif auxiliary picture failed! errorCode: %{public}u", errorCode);
    if (auxiliaryPictureDecodeInfo.type == AuxiliaryPictureType::GAINMAP) {
        errorCode = DecodeHdrMetadata(mainInfo.hdrType, extDecoder, auxPicture);
    } else if (auxiliaryPictureDecodeInfo.type == AuxiliaryPictureType::FRAGMENT_MAP) {
        errorCode = DecodeHeifFragmentMetadata(extDecoder, auxPicture);
    }
    cond = (errorCode != SUCCESS);
    CHECK_ERROR_RETURN_RET_LOG(cond, nullptr, "Decode heif metadata failed! errorCode: %{public}u", errorCode);
    return std::move(auxPicture);
}

std::shared_ptr<AuxiliaryPicture> AuxiliaryGenerator::GenerateJpegAuxiliaryPicture(const MainPictureInfo &mainInfo,
    std::unique_ptr<InputDataStream> &auxStream, std::unique_ptr<AbsImageDecoder> &extDecoder, uint32_t &errorCode,
    const AuxiliaryPictureDecodeInfo& auxiliaryPictureDecodeInfo)
{
    ImageTrace trace("GenerateJpegAuxiliaryPicture Type:(%d)", static_cast<int>(auxiliaryPictureDecodeInfo.type));
    IMAGE_LOGI("Generate jpeg auxiliary picture, type: %{public}d", static_cast<int>(auxiliaryPictureDecodeInfo.type));
    if (!ImageUtils::IsAuxiliaryPictureTypeSupported(auxiliaryPictureDecodeInfo.type) || auxStream == nullptr ||
        extDecoder == nullptr) {
        errorCode = ERR_IMAGE_INVALID_PARAMETER;
        return nullptr;
    }

    if (ImageUtils::IsAuxiliaryPictureEncoded(auxiliaryPictureDecodeInfo.type)) {
        auto auxPicture = GenerateAuxiliaryPicture(mainInfo, errorCode, extDecoder, auxiliaryPictureDecodeInfo);
        if (errorCode != SUCCESS) {
            IMAGE_LOGE("Generate jpeg auxiliary picture failed! errorCode: %{public}u", errorCode);
            return nullptr;
        }
        if (auxiliaryPictureDecodeInfo.type == AuxiliaryPictureType::GAINMAP) {
            errorCode = DecodeHdrMetadata(mainInfo.hdrType, extDecoder, auxPicture);
        } else if (auxiliaryPictureDecodeInfo.type == AuxiliaryPictureType::FRAGMENT_MAP) {
            errorCode = DecodeJpegFragmentMetadata(auxStream, auxPicture);
        }
        if (errorCode != SUCCESS) {
            IMAGE_LOGE("Decode jpeg metadata failed! errorCode: %{public}u", errorCode);
            return nullptr;
        }
        return auxPicture;
    }

    int32_t denominator = GetAuxiliaryPictureDenominator(auxiliaryPictureDecodeInfo.type);
    denominator = (denominator == 0) ? DEFAULT_SCALE_DENOMINATOR : denominator;
    Size size = {mainInfo.imageInfo.size.width / denominator, mainInfo.imageInfo.size.height / denominator};
    sptr<SurfaceBuffer> surfaceBuffer = AllocSurfaceBuffer(size, GRAPHIC_PIXEL_FMT_RGBA16_FLOAT, errorCode);
    bool cond = (errorCode != SUCCESS || surfaceBuffer == nullptr);
    CHECK_ERROR_RETURN_RET_LOG(cond, nullptr, "Alloc surface buffer failed! errorCode: %{public}u", errorCode);
    errorCode = CopyToSurfaceBuffer(auxStream, surfaceBuffer);
    cond = (errorCode != SUCCESS);
    CHECK_ERROR_RETURN_RET_LOG(cond, nullptr,
        "Convert stream to surface buffer failed! errorCode: %{public}u", errorCode);
    auto auxPicture = AuxiliaryPicture::Create(surfaceBuffer, auxiliaryPictureDecodeInfo.type, size);
    CHECK_ERROR_RETURN_RET_LOG(!auxPicture, nullptr, "auxPicture is nullptr");
    SetUncodedAuxilaryPictureInfo(auxPicture);
    return auxPicture;
}

} // namespace Media
} // namespace OHOS