/*
 * 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 <memory>
#include "exif_metadata.h"
#include "picture.h"
#include "pixel_yuv.h"
#include "pixel_yuv_ext.h"
#include "image_utils.h"
#include "image_log.h"
#include "image_source.h"
#include "media_errors.h"                                                // Operation success
#ifdef IMAGE_COLORSPACE_FLAG
#include "color_space.h"
#endif
#include "surface_buffer.h"
#include "securec.h"
#include "tiff_parser.h"
#include "metadata_helper.h"
#include "v1_0/cm_color_space.h"
#include "vpe_utils.h"

namespace OHOS {
namespace Media {
using namespace OHOS::HDI::Display::Graphic::Common::V1_0;
namespace {
    static const std::map<int32_t, PixelFormat> PIXEL_FORMAT_MAP = {
        { GRAPHIC_PIXEL_FMT_RGBA_8888, PixelFormat::RGBA_8888 },
        { GRAPHIC_PIXEL_FMT_YCBCR_420_SP, PixelFormat::NV12 },
        { GRAPHIC_PIXEL_FMT_YCRCB_420_SP, PixelFormat::NV21 },
        { GRAPHIC_PIXEL_FMT_RGBA_1010102, PixelFormat::RGBA_1010102 },
        { GRAPHIC_PIXEL_FMT_BGRA_8888, PixelFormat::BGRA_8888 },
        { GRAPHIC_PIXEL_FMT_RGB_888, PixelFormat::RGB_888 },
        { GRAPHIC_PIXEL_FMT_RGB_565, PixelFormat::RGB_565 },
        { GRAPHIC_PIXEL_FMT_RGBA16_FLOAT, PixelFormat::RGBA_F16 },
        { GRAPHIC_PIXEL_FMT_YCBCR_P010, PixelFormat::YCBCR_P010 },
        { GRAPHIC_PIXEL_FMT_YCRCB_P010, PixelFormat::YCRCB_P010 },
    };

    static const std::map<CM_ColorSpaceType, ColorSpace> CM_COLORSPACE_MAP = {
        { CM_COLORSPACE_NONE, ColorSpace::UNKNOWN },
        { CM_BT709_FULL, ColorSpace::ITU_709 },
        { CM_BT2020_HLG_FULL, ColorSpace::ITU_2020 },
        { CM_BT2020_PQ_FULL, ColorSpace::ITU_2020 },
        { CM_BT709_LIMIT, ColorSpace::ITU_709 },
        { CM_BT2020_HLG_LIMIT, ColorSpace::ITU_2020 },
        { CM_BT2020_PQ_LIMIT, ColorSpace::ITU_2020 },
        { CM_SRGB_FULL, ColorSpace::SRGB },
        { CM_P3_FULL, ColorSpace::DCI_P3 },
        { CM_P3_HLG_FULL, ColorSpace::DCI_P3 },
        { CM_P3_PQ_FULL, ColorSpace::DCI_P3 },
        { CM_ADOBERGB_FULL, ColorSpace::ADOBE_RGB_1998 },
        { CM_SRGB_LIMIT, ColorSpace::SRGB },
        { CM_P3_LIMIT, ColorSpace::DCI_P3 },
        { CM_P3_HLG_LIMIT, ColorSpace::DCI_P3 },
        { CM_P3_PQ_LIMIT, ColorSpace::DCI_P3 },
        { CM_ADOBERGB_LIMIT, ColorSpace::ADOBE_RGB_1998 },
        { CM_LINEAR_SRGB, ColorSpace::LINEAR_SRGB },
        { CM_LINEAR_BT709, ColorSpace::ITU_709 },
        { CM_LINEAR_P3, ColorSpace::DISPLAY_P3 },
        { CM_LINEAR_BT2020, ColorSpace::ITU_2020 },
        { CM_DISPLAY_SRGB, ColorSpace::SRGB },
        { CM_DISPLAY_P3_SRGB, ColorSpace::DISPLAY_P3 },
        { CM_DISPLAY_P3_HLG, ColorSpace::DISPLAY_P3 },
        { CM_DISPLAY_P3_PQ, ColorSpace::DISPLAY_P3 },
        { CM_DISPLAY_BT2020_SRGB, ColorSpace::ITU_2020 },
        { CM_DISPLAY_BT2020_HLG, ColorSpace::ITU_2020 },
        { CM_DISPLAY_BT2020_PQ, ColorSpace::ITU_2020 },
    };

#ifdef IMAGE_COLORSPACE_FLAG
    static const std::map<CM_ColorSpaceType, ColorManager::ColorSpaceName> CM_COLORSPACE_NAME_MAP = {
        { CM_COLORSPACE_NONE, ColorManager::NONE },
        { CM_BT601_EBU_FULL, ColorManager::BT601_EBU },
        { CM_BT601_SMPTE_C_FULL, ColorManager::BT601_SMPTE_C },
        { CM_BT709_FULL, ColorManager::BT709 },
        { CM_BT2020_HLG_FULL, ColorManager::BT2020_HLG },
        { CM_BT2020_PQ_FULL, ColorManager::BT2020_PQ },
        { CM_BT601_EBU_LIMIT, ColorManager::BT601_EBU_LIMIT },
        { CM_BT601_SMPTE_C_LIMIT, ColorManager::BT601_SMPTE_C_LIMIT },
        { CM_BT709_LIMIT, ColorManager::BT709_LIMIT },
        { CM_BT2020_HLG_LIMIT, ColorManager::BT2020_HLG_LIMIT },
        { CM_BT2020_PQ_LIMIT, ColorManager::BT2020_PQ_LIMIT },
        { CM_SRGB_FULL, ColorManager::SRGB },
        { CM_P3_FULL, ColorManager::DCI_P3 },
        { CM_P3_HLG_FULL, ColorManager::P3_HLG },
        { CM_P3_PQ_FULL, ColorManager::P3_PQ },
        { CM_ADOBERGB_FULL, ColorManager::ADOBE_RGB },
        { CM_SRGB_LIMIT, ColorManager::SRGB_LIMIT },
        { CM_P3_LIMIT, ColorManager::DISPLAY_P3_LIMIT },
        { CM_P3_HLG_LIMIT, ColorManager::P3_HLG_LIMIT },
        { CM_P3_PQ_LIMIT, ColorManager::P3_PQ_LIMIT },
        { CM_ADOBERGB_LIMIT, ColorManager::ADOBE_RGB_LIMIT },
        { CM_LINEAR_SRGB, ColorManager::LINEAR_SRGB },
        { CM_LINEAR_BT709, ColorManager::LINEAR_BT709 },
        { CM_LINEAR_P3, ColorManager::LINEAR_P3 },
        { CM_LINEAR_BT2020, ColorManager::LINEAR_BT2020 },
        { CM_DISPLAY_SRGB, ColorManager::DISPLAY_SRGB },
        { CM_DISPLAY_P3_SRGB, ColorManager::DISPLAY_P3_SRGB },
        { CM_DISPLAY_P3_HLG, ColorManager::DISPLAY_P3_HLG },
        { CM_DISPLAY_P3_PQ, ColorManager::DISPLAY_P3_PQ },
        { CM_DISPLAY_BT2020_SRGB, ColorManager::DISPLAY_BT2020_SRGB },
        { CM_DISPLAY_BT2020_HLG, ColorManager::DISPLAY_BT2020_HLG },
        { CM_DISPLAY_BT2020_PQ, ColorManager::DISPLAY_BT2020_PQ },
    };
#endif
}
const static uint64_t MAX_AUXILIARY_PICTURE_COUNT = 32;
const static uint64_t MAX_EXIFMETADATA_SIZE = 1024 * 1024;
static const uint8_t NUM_0 = 0;
static const uint8_t NUM_1 = 1;
static const uint8_t NUM_2 = 2;
static const std::string EXIF_DATA_SIZE_TAG = "exifDataSize";

static bool IsYuvFormat(PixelFormat format)
{
    return format == PixelFormat::NV21 || format == PixelFormat::NV12 ||
        format == PixelFormat::YCRCB_P010 || format == PixelFormat::YCBCR_P010;
}

static bool IsAlphaFormat(PixelFormat format)
{
    return format == PixelFormat::RGBA_8888 || format == PixelFormat::BGRA_8888 ||
        format == PixelFormat::RGBA_1010102 || format == PixelFormat::RGBA_F16;
}

static PixelFormat SbFormat2PixelFormat(int32_t sbFormat)
{
    auto iter = PIXEL_FORMAT_MAP.find(sbFormat);
    if (iter == PIXEL_FORMAT_MAP.end()) {
        return PixelFormat::UNKNOWN;
    }
    return iter->second;
}

static CM_ColorSpaceType GetCMColorSpaceType(sptr<SurfaceBuffer> buffer)
{
    if (buffer == nullptr) {
        return CM_ColorSpaceType::CM_COLORSPACE_NONE;
    }
    CM_ColorSpaceType type;
    MetadataHelper::GetColorSpaceType(buffer, type);
    return type;
}

static ColorSpace CMColorSpaceType2ColorSpace(CM_ColorSpaceType type)
{
    auto iter = CM_COLORSPACE_MAP.find(type);
    if (iter == CM_COLORSPACE_MAP.end()) {
        return ColorSpace::UNKNOWN;
    }
    return iter->second;
}

#ifdef IMAGE_COLORSPACE_FLAG
static ColorManager::ColorSpaceName CMColorSpaceType2ColorSpaceName(CM_ColorSpaceType type)
{
    auto iter = CM_COLORSPACE_NAME_MAP.find(type);
    if (iter == CM_COLORSPACE_NAME_MAP.end()) {
        return ColorManager::NONE;
    }
    return iter->second;
}
#endif

static ImageInfo MakeImageInfo(int width, int height, PixelFormat pf, AlphaType at, ColorSpace cs)
{
    ImageInfo info;
    info.size.width = width;
    info.size.height = height;
    info.pixelFormat = pf;
    info.alphaType = at;
    info.colorSpace = cs;
    return info;
}

static void SetYuvDataInfo(std::unique_ptr<PixelMap> &pixelMap, sptr<OHOS::SurfaceBuffer> &sBuffer)
{
    if (pixelMap == nullptr || sBuffer == nullptr) {
        return;
    }
    int32_t width = sBuffer->GetWidth();
    int32_t height = sBuffer->GetHeight();
    OH_NativeBuffer_Planes *planes = nullptr;
    GSError retVal = sBuffer->GetPlanesInfo(reinterpret_cast<void**>(&planes));
    YUVDataInfo info;
    info.imageSize = { width, height };
    if (retVal != OHOS::GSERROR_OK || planes == nullptr || planes->planeCount <= NUM_1) {
        IMAGE_LOGE("Get planesInfo failed, retVal:%{public}d", retVal);
        return;
    } else if (planes->planeCount >= NUM_2) {
        int32_t pixelFmt = sBuffer->GetFormat();
        int uvPlaneOffset = (pixelFmt == GRAPHIC_PIXEL_FMT_YCBCR_420_SP || pixelFmt == GRAPHIC_PIXEL_FMT_YCBCR_P010) ?
                NUM_1 : NUM_2;
        info.yStride = planes->planes[NUM_0].columnStride;
        info.uvStride = planes->planes[uvPlaneOffset].columnStride;
        info.yOffset = planes->planes[NUM_0].offset;
        info.uvOffset = planes->planes[uvPlaneOffset].offset;
    }
    pixelMap->SetImageYUVInfo(info);
}

static void SetImageInfoToHdr(std::shared_ptr<PixelMap> &mainPixelMap, std::unique_ptr<PixelMap> &hdrPixelMap)
{
    if (mainPixelMap != nullptr && hdrPixelMap != nullptr) {
        ImageInfo mainInfo;
        mainPixelMap->GetImageInfo(mainInfo);
        ImageInfo hdrInfo;
        hdrPixelMap->GetImageInfo(hdrInfo);
        hdrInfo.size = mainInfo.size;
        hdrInfo.encodedFormat = mainInfo.encodedFormat;
        hdrPixelMap->SetImageInfo(hdrInfo, true);
    }
}

Picture::~Picture() {}

std::unique_ptr<Picture> Picture::Create(std::shared_ptr<PixelMap> &pixelMap)
{
    if (pixelMap == nullptr) {
        return nullptr;
    }
    std::unique_ptr<Picture> dstPicture = std::make_unique<Picture>();
    if (pixelMap->GetExifMetadata() != nullptr) {
        dstPicture->SetExifMetadata(pixelMap->GetExifMetadata());
    }
    dstPicture->mainPixelMap_ = pixelMap;
    return dstPicture;
}

std::unique_ptr<Picture> Picture::Create(sptr<SurfaceBuffer> &surfaceBuffer)
{
    std::shared_ptr<PixelMap> pixelmap = SurfaceBuffer2PixelMap(surfaceBuffer);
    return Create(pixelmap);
}

std::unique_ptr<PixelMap> Picture::SurfaceBuffer2PixelMap(sptr<OHOS::SurfaceBuffer> &surfaceBuffer)
{
    if (surfaceBuffer == nullptr) {
        return nullptr;
    }
    PixelFormat pixelFormat = SbFormat2PixelFormat(surfaceBuffer->GetFormat());
    ColorSpace colorSpace = CMColorSpaceType2ColorSpace(GetCMColorSpaceType(surfaceBuffer));
    AlphaType alphaType = IsAlphaFormat(pixelFormat) ?
             AlphaType::IMAGE_ALPHA_TYPE_PREMUL : AlphaType::IMAGE_ALPHA_TYPE_OPAQUE;
    void* nativeBuffer = surfaceBuffer.GetRefPtr();
    int32_t err = ImageUtils::SurfaceBuffer_Reference(nativeBuffer);
    if (err != OHOS::GSERROR_OK) {
        IMAGE_LOGE("NativeBufferReference failed");
        return nullptr;
    }

    std::unique_ptr<PixelMap> pixelMap;
    if (IsYuvFormat(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) {
        return nullptr;
    }

    ImageInfo imageInfo = MakeImageInfo(surfaceBuffer->GetWidth(),
                                        surfaceBuffer->GetHeight(), pixelFormat, alphaType, colorSpace);
    pixelMap->SetImageInfo(imageInfo, true);
    pixelMap->SetPixelsAddr(surfaceBuffer->GetVirAddr(),
                            nativeBuffer, pixelMap->GetRowBytes() * pixelMap->GetHeight(),
                            AllocatorType::DMA_ALLOC, nullptr);
#ifdef IMAGE_COLORSPACE_FLAG
    ColorManager::ColorSpaceName colorSpaceName =
        CMColorSpaceType2ColorSpaceName(GetCMColorSpaceType(surfaceBuffer));
    pixelMap->InnerSetColorSpace(ColorManager::ColorSpace(colorSpaceName));
#endif
    if (IsYuvFormat(pixelFormat)) {
        SetYuvDataInfo(pixelMap, surfaceBuffer);
    }
    return pixelMap;
}

std::shared_ptr<PixelMap> Picture::GetMainPixel()
{
    return mainPixelMap_;
}

void Picture::SetMainPixel(std::shared_ptr<PixelMap> PixelMap)
{
    mainPixelMap_ = PixelMap;
}

static int32_t GetHdrAllocFormat(PixelFormat pixelFormat)
{
    int32_t hdrAllocFormat = GRAPHIC_PIXEL_FMT_RGBA_1010102;
    switch (pixelFormat) {
        case PixelFormat::RGBA_8888:
            hdrAllocFormat = GRAPHIC_PIXEL_FMT_RGBA_1010102;
            break;
        case PixelFormat::NV21:
            hdrAllocFormat = GRAPHIC_PIXEL_FMT_YCRCB_P010;
            break;
        case PixelFormat::NV12:
            hdrAllocFormat = GRAPHIC_PIXEL_FMT_YCBCR_P010;
            break;
        default:
            IMAGE_LOGW("%{public}s no corresponding hdrAllocFormat for format: %{public}d", __func__, pixelFormat);
            break;
    }
    IMAGE_LOGD("%{public}s use hdrAllocFormat: %{public}d for format: %{public}d",
        __func__, hdrAllocFormat, pixelFormat);
    return hdrAllocFormat;
}

static void TryFixGainmapHdrMetadata(sptr<SurfaceBuffer> &gainmapSptr)
{
    std::vector<uint8_t> gainmapDynamicMetadata;
    VpeUtils::GetSbDynamicMetadata(gainmapSptr, gainmapDynamicMetadata);
    if (gainmapDynamicMetadata.size() != sizeof(ISOMetadata)) {
        IMAGE_LOGI("%{public}s no need to fix gainmap dynamic metadata, size: %{public}zu",
            __func__, gainmapDynamicMetadata.size());
        return;
    }

    HDRVividExtendMetadata extendMetadata = {};
    int32_t memCpyRes = memcpy_s(&extendMetadata.metaISO, sizeof(ISOMetadata),
        gainmapDynamicMetadata.data(), gainmapDynamicMetadata.size());
    if (memCpyRes != EOK) {
        IMAGE_LOGE("%{public}s memcpy_s ISOMetadata fail, error: %{public}d", __func__, memCpyRes);
        return;
    }
    if (extendMetadata.metaISO.useBaseColorFlag != 0) {
        extendMetadata.baseColorMeta.baseColorPrimary = COLORPRIMARIES_SRGB;
        extendMetadata.gainmapColorMeta.combineColorPrimary = COLORPRIMARIES_SRGB;
    } else {
        extendMetadata.gainmapColorMeta.combineColorPrimary = COLORPRIMARIES_BT2020;
        extendMetadata.gainmapColorMeta.alternateColorPrimary = COLORPRIMARIES_BT2020;
    }
    std::vector<uint8_t> extendMetadataVec(sizeof(HDRVividExtendMetadata));
    memCpyRes = memcpy_s(extendMetadataVec.data(), extendMetadataVec.size(),
        &extendMetadata, sizeof(HDRVividExtendMetadata));
    if (memCpyRes != EOK) {
        IMAGE_LOGE("%{public}s memcpy_s HDRVividExtendMetadata fail, error: %{public}d", __func__, memCpyRes);
        return;
    }
    VpeUtils::SetSbDynamicMetadata(gainmapSptr, extendMetadataVec);
}

static bool ShouldComposeAsCuva(const sptr<SurfaceBuffer> &baseSptr, const sptr<SurfaceBuffer> &gainmapSptr)
{
    std::vector<uint8_t> baseStaticMetadata;
    VpeUtils::GetSbStaticMetadata(baseSptr, baseStaticMetadata);
    std::vector<uint8_t> baseDynamicMetadata;
    VpeUtils::GetSbDynamicMetadata(gainmapSptr, baseDynamicMetadata);
    if (baseStaticMetadata.size() == 0 || baseDynamicMetadata.size() == 0) {
        return true;
    }

    std::vector<uint8_t> gainmapDynamicMetadata;
    VpeUtils::GetSbDynamicMetadata(gainmapSptr, gainmapDynamicMetadata);
    if (gainmapDynamicMetadata.size() != sizeof(HDRVividExtendMetadata)) {
        return true;
    }
    return false;
}

static std::unique_ptr<PixelMap> ComposeHdrPixelMap(
    std::shared_ptr<PixelMap> &mainPixelMap, sptr<SurfaceBuffer> &baseSptr, sptr<SurfaceBuffer> &gainmapSptr)
{
    sptr<SurfaceBuffer> hdrSptr = SurfaceBuffer::Create();
    ImageInfo imageInfo;
    mainPixelMap->GetImageInfo(imageInfo);
    BufferRequestConfig requestConfig = {
        .width = imageInfo.size.width,
        .height = imageInfo.size.height,
        .strideAlignment = imageInfo.size.width,
        .format = GetHdrAllocFormat(imageInfo.pixelFormat),
        .usage = BUFFER_USAGE_CPU_READ | BUFFER_USAGE_CPU_WRITE | BUFFER_USAGE_MEM_DMA | BUFFER_USAGE_MEM_MMZ_CACHE,
        .timeout = 0,
    };

    GSError error = hdrSptr->Alloc(requestConfig);
    if (error != GSERROR_OK) {
        IMAGE_LOGE("HDR SurfaceBuffer Alloc failed, error: %{public}s", GSErrorStr(error).c_str());
        return nullptr;
    }
    VpeUtils::SetSbMetadataType(hdrSptr, CM_IMAGE_HDR_VIVID_SINGLE);
    VpeUtils::SetSbColorSpaceType(hdrSptr, CM_BT2020_HLG_FULL);

    VpeSurfaceBuffers buffers = {
        .sdr = baseSptr,
        .gainmap = gainmapSptr,
        .hdr = hdrSptr,
    };
    bool isCuva = ShouldComposeAsCuva(baseSptr, gainmapSptr);
    IMAGE_LOGD("HDR Compose image, isCuva: %{public}d", isCuva);
    int32_t res = VpeUtils().ColorSpaceConverterComposeImage(buffers, isCuva);
    if (res != VPE_ERROR_OK) {
        IMAGE_LOGE("Compose HDR image failed, res: %{public}d", res);
        return nullptr;
    }
    return Picture::SurfaceBuffer2PixelMap(hdrSptr);
}

std::unique_ptr<PixelMap> Picture::GetHdrComposedPixelMap()
{
    std::shared_ptr<PixelMap> gainmap = GetGainmapPixelMap();
    if (mainPixelMap_ == nullptr || gainmap == nullptr) {
        IMAGE_LOGE("picture mainPixelMap_ or gainmap is empty.");
        return nullptr;
    }
    if (mainPixelMap_->GetAllocatorType() != AllocatorType::DMA_ALLOC || mainPixelMap_->GetFd() == nullptr ||
        gainmap->GetAllocatorType() != AllocatorType::DMA_ALLOC || gainmap->GetFd() == nullptr) {
        IMAGE_LOGE("Unsupport HDR compose, only support the DMA allocation.");
        return nullptr;
    }
    sptr<SurfaceBuffer> baseSptr(reinterpret_cast<SurfaceBuffer*>(mainPixelMap_->GetFd()));
    VpeUtils::SetSbMetadataType(baseSptr, CM_IMAGE_HDR_VIVID_DUAL);
    sptr<SurfaceBuffer> gainmapSptr(reinterpret_cast<SurfaceBuffer*>(gainmap->GetFd()));
    VpeUtils::SetSbMetadataType(gainmapSptr, CM_METADATA_NONE);
    TryFixGainmapHdrMetadata(gainmapSptr);
    auto hdrPixelMap = ComposeHdrPixelMap(mainPixelMap_, baseSptr, gainmapSptr);
    SetImageInfoToHdr(mainPixelMap_, hdrPixelMap);
    return hdrPixelMap;
}

std::shared_ptr<PixelMap> Picture::GetGainmapPixelMap()
{
    if (!HasAuxiliaryPicture(AuxiliaryPictureType::GAINMAP)) {
        IMAGE_LOGE("Unsupport gain map.");
        return nullptr;
    } else {
        auto auxiliaryPicture = GetAuxiliaryPicture(AuxiliaryPictureType::GAINMAP);
        if (auxiliaryPicture == nullptr) {
            return nullptr;
        }
        return auxiliaryPicture->GetContentPixel();
    }
}

std::shared_ptr<AuxiliaryPicture> Picture::GetAuxiliaryPicture(AuxiliaryPictureType type)
{
    auto iter = auxiliaryPictures_.find(type);
    if (iter == auxiliaryPictures_.end()) {
        return nullptr;
    }
    return iter->second;
}

void Picture::SetAuxiliaryPicture(std::shared_ptr<AuxiliaryPicture> &picture)
{
    if (picture == nullptr) {
        IMAGE_LOGE("Auxiliary picture is nullptr.");
        return;
    }
    if (auxiliaryPictures_.size() >= MAX_AUXILIARY_PICTURE_COUNT) {
        IMAGE_LOGE("The size of auxiliary picture exceeds the maximum limit %{public}llu.",
            static_cast<unsigned long long>(MAX_AUXILIARY_PICTURE_COUNT));
        return;
    }
    AuxiliaryPictureType type = picture->GetType();
    auxiliaryPictures_[type] = picture;
}

bool Picture::HasAuxiliaryPicture(AuxiliaryPictureType type)
{
    auto item = auxiliaryPictures_.find(type);
    return item != auxiliaryPictures_.end() && item->second != nullptr;
}

bool Picture::Marshalling(Parcel &data) const
{
    if (!mainPixelMap_) {
        IMAGE_LOGE("Main PixelMap is null.");
        return false;
    }
    if (!mainPixelMap_->Marshalling(data)) {
        IMAGE_LOGE("Failed to marshal main PixelMap.");
        return false;
    }

    size_t numAuxiliaryPictures = auxiliaryPictures_.size();
    if (numAuxiliaryPictures > MAX_AUXILIARY_PICTURE_COUNT) {
        return false;
    }
    if (!data.WriteUint64(numAuxiliaryPictures)) {
        IMAGE_LOGE("Failed to write number of auxiliary pictures.");
        return false;
    }

    for (const auto &auxiliaryPicture : auxiliaryPictures_) {
        AuxiliaryPictureType type =  auxiliaryPicture.first;

        if (!data.WriteInt32(static_cast<int32_t>(type))) {
            IMAGE_LOGE("Failed to write auxiliary picture type.");
            return false;
        }

        if (!auxiliaryPicture.second || !auxiliaryPicture.second->Marshalling(data)) {
            IMAGE_LOGE("Failed to marshal auxiliary picture of type %d.", static_cast<int>(type));
            return false;
        }
    }

    if (!data.WriteBool(maintenanceData_ != nullptr)) {
        IMAGE_LOGE("Failed to write maintenance data existence value.");
        return false;
    }

    if (maintenanceData_ != nullptr) {
        if (maintenanceData_->WriteToMessageParcel(reinterpret_cast<MessageParcel&>(data)) != GSError::GSERROR_OK) {
            IMAGE_LOGE("Failed to write maintenance data content.");
            return false;
        }
    }

    if (!data.WriteBool(exifMetadata_ != nullptr)) {
        IMAGE_LOGE("Failed to write exif data existence value.");
        return false;
    }

    if (exifMetadata_ != nullptr) {
        if (!exifMetadata_->Marshalling(data)) {
            IMAGE_LOGE("Failed to marshal exif metadata.");
            return false;
        }
    }

    return true;
}

Picture *Picture::Unmarshalling(Parcel &data)
{
    PICTURE_ERR error;
    Picture* dstPicture = Picture::Unmarshalling(data, error);
    if (dstPicture == nullptr || error.errorCode != SUCCESS) {
        IMAGE_LOGE("unmarshalling failed errorCode:%{public}d, errorInfo:%{public}s",
            error.errorCode, error.errorInfo.c_str());
    }
    return dstPicture;
}

Picture *Picture::Unmarshalling(Parcel &parcel, PICTURE_ERR &error)
{
    std::unique_ptr<Picture> picture = std::make_unique<Picture>();
    std::shared_ptr<PixelMap> pixelmapPtr(PixelMap::Unmarshalling(parcel));

    if (!pixelmapPtr) {
        IMAGE_LOGE("Failed to unmarshal main PixelMap.");
        return nullptr;
    }
    picture->SetMainPixel(pixelmapPtr);
    uint64_t numAuxiliaryPictures = parcel.ReadUint64();
    if (numAuxiliaryPictures > MAX_AUXILIARY_PICTURE_COUNT) {
        return nullptr;
    }

    for (size_t i = NUM_0; i < numAuxiliaryPictures; ++i) {
        int32_t type = parcel.ReadInt32();
        std::shared_ptr<AuxiliaryPicture> auxPtr(AuxiliaryPicture::Unmarshalling(parcel));
        if (!auxPtr) {
            IMAGE_LOGE("Failed to unmarshal auxiliary picture of type %d.", type);
            return nullptr;
        }
        picture->SetAuxiliaryPicture(auxPtr);
    }

    bool hasMaintenanceData = parcel.ReadBool();
    if (hasMaintenanceData) {
        sptr<SurfaceBuffer> surfaceBuffer = SurfaceBuffer::Create();
        if (surfaceBuffer == nullptr) {
            IMAGE_LOGE("SurfaceBuffer failed to be created.");
            return nullptr;
        }
        if (surfaceBuffer->ReadFromMessageParcel(reinterpret_cast<MessageParcel&>(parcel)) != GSError::GSERROR_OK) {
            IMAGE_LOGE("Failed to unmarshal maintenance data");
            return nullptr;
        }
        picture->maintenanceData_ = surfaceBuffer;
    }

    bool hasExifData = parcel.ReadBool();
    if (hasExifData) {
        picture->exifMetadata_ = std::shared_ptr<ExifMetadata>(ExifMetadata::Unmarshalling(parcel));
    }

    return picture.release();
}

int32_t Picture::SetExifMetadata(sptr<SurfaceBuffer> &surfaceBuffer)
{
    if (surfaceBuffer == nullptr) {
        return ERR_IMAGE_INVALID_PARAMETER;
    }

    auto extraData = surfaceBuffer->GetExtraData();
    if (extraData == nullptr) {
        return ERR_IMAGE_INVALID_PARAMETER;
    }

    int32_t size = NUM_0;
    extraData->ExtraGet(EXIF_DATA_SIZE_TAG, size);
    if (size <= 0) {
        IMAGE_LOGE("Invalid buffer size: %d.", size);
        return ERR_IMAGE_INVALID_PARAMETER;
    }

    size_t tiffHeaderPos = TiffParser::FindTiffPos(reinterpret_cast<const byte *>(surfaceBuffer->GetVirAddr()), size);
    if (tiffHeaderPos == std::numeric_limits<size_t>::max()) {
        IMAGE_LOGE("Input image stream is not tiff type.");
        return ERR_IMAGE_SOURCE_DATA;
    }

    if (size > surfaceBuffer->GetSize() || tiffHeaderPos > surfaceBuffer->GetSize()) {
        IMAGE_LOGE("The size of exif metadata exceeds the buffer size.");
        return ERR_IMAGE_INVALID_PARAMETER;
    }

    if (size - tiffHeaderPos > MAX_EXIFMETADATA_SIZE) {
        IMAGE_LOGE("Failed to set exif metadata, the size of exif metadata exceeds the maximum limit %{public}llu.",
            static_cast<unsigned long long>(MAX_EXIFMETADATA_SIZE));
        return ERR_IMAGE_INVALID_PARAMETER;
    }
    ExifData *exifData;
    TiffParser::Decode(static_cast<const unsigned char *>(surfaceBuffer->GetVirAddr()) + tiffHeaderPos,
        size - tiffHeaderPos, &exifData);
    if (exifData == nullptr) {
        IMAGE_LOGE("Failed to decode EXIF data from image stream.");
        return ERR_EXIF_DECODE_FAILED;
    }

    exifMetadata_ = std::make_shared<OHOS::Media::ExifMetadata>(exifData);
    return SUCCESS;
}

int32_t Picture::SetExifMetadata(std::shared_ptr<ExifMetadata> exifMetadata)
{
    if (exifMetadata == nullptr) {
        return ERR_IMAGE_INVALID_PARAMETER;
    }
    exifMetadata_ = exifMetadata;
    return SUCCESS;
}

std::shared_ptr<ExifMetadata> Picture::GetExifMetadata()
{
    return exifMetadata_;
}

bool Picture::SetMaintenanceData(sptr<SurfaceBuffer> &surfaceBuffer)
{
    if (surfaceBuffer == nullptr) {
        return false;
    }
    maintenanceData_ = surfaceBuffer;
    return true;
}

sptr<SurfaceBuffer> Picture::GetMaintenanceData() const
{
    return maintenanceData_;
}

} // namespace Media
} // namespace OHOS