/*
 * Copyright (C) 2023 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 "fcodec.h"
#include <iostream>
#include <set>
#include <thread>
#include <malloc.h>
#include <sstream>
#include <sys/ioctl.h>
#include <linux/dma-buf.h>
#include "syspara/parameters.h"
#include "securec.h"
#include "avcodec_trace.h"
#include "avcodec_log.h"
#include "utils.h"
#include "avcodec_codec_name.h"
#include "dma_swap.h"
#include "fcodec_surport_codec.h"
#ifndef EMULATOR_ENABLED
#include "fcodec_utils.h"
#endif

namespace OHOS {
namespace MediaAVCodec {
namespace Codec {
namespace {
constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN_FRAMEWORK, "FCodec"};
constexpr uint32_t INDEX_INPUT = 0;
constexpr uint32_t INDEX_OUTPUT = 1;
constexpr int32_t DEFAULT_IN_BUFFER_CNT = 4;
constexpr int32_t DEFAULT_OUT_SURFACE_CNT = 4;
constexpr int32_t DEFAULT_OUT_BUFFER_CNT = 3;
constexpr int32_t DEFAULT_MIN_BUFFER_CNT = 2;
constexpr uint32_t VIDEO_PIX_DEPTH_YUV = 3;
constexpr int32_t VIDEO_MIN_BUFFER_SIZE = 1474560;
constexpr int32_t VIDEO_MIN_SIZE = 2;
constexpr int32_t VIDEO_MAX_WIDTH_SIZE = 5120;
constexpr int32_t VIDEO_MAX_HEIGHT_SIZE = 5120;
constexpr int32_t DEFAULT_VIDEO_WIDTH = 1920;
constexpr int32_t DEFAULT_VIDEO_HEIGHT = 1080;
constexpr uint32_t DEFAULT_TRY_DECODE_TIME = 1;
constexpr uint32_t DEFAULT_DECODE_WAIT_TIME = 200;
constexpr uint32_t LOG_FREQUENCE = 2000;
constexpr int32_t DEFAULT_THREAD_COUNT = 2;

#ifdef BUILD_ENG_VERSION
constexpr uint32_t PATH_MAX_LEN = 128;
constexpr char DUMP_PATH[] = "/data/misc/fcodecdump";
#endif // BUILD_ENG_VERSION

static std::map<RawVideoPixelFormat, AVPixelFormat> g_convertFfmpegPixFmt = {
    {RawVideoPixelFormat::YUV420P, AVPixelFormat::AV_PIX_FMT_YUV420P},
    {RawVideoPixelFormat::NV12, AVPixelFormat::AV_PIX_FMT_NV12},
    {RawVideoPixelFormat::NV21, AVPixelFormat::AV_PIX_FMT_NV21},
    {RawVideoPixelFormat::RGBA, AVPixelFormat::AV_PIX_FMT_RGBA},
};
#define DMA_BUF_SET_LEAK_TYPE _IOW(DMA_BUF_BASE, 5, const char *)
} // namespace
using namespace OHOS::Media;
using FMTKey = Media::Tag;

FCodec::FCodec(const std::string &name) : codecName_(name), state_(State::UNINITIALIZED) {}

FCodec::~FCodec()
{
    ReleaseResource();
    callback_ = nullptr;
#ifdef BUILD_ENG_VERSION
    if (dumpInFile_ != nullptr) {
        dumpInFile_->close();
    }
    if (dumpOutFile_ != nullptr) {
        dumpOutFile_->close();
    }
#endif // BUILD_ENG_VERSION
    mallopt(M_FLUSH_THREAD_CACHE, 0);
}

int32_t FCodec::Init(Meta &callerInfo)
{
    if (callerInfo.GetData(Tag::AV_CODEC_FORWARD_CALLER_PID, fDecInfo_.pid) &&
        callerInfo.GetData(Tag::AV_CODEC_FORWARD_CALLER_PROCESS_NAME, fDecInfo_.processName)) {
        fDecInfo_.calledByAvcodec = false;
    } else if (callerInfo.GetData(Tag::AV_CODEC_CALLER_PID, fDecInfo_.pid) &&
               callerInfo.GetData(Tag::AV_CODEC_CALLER_PROCESS_NAME, fDecInfo_.processName)) {
        fDecInfo_.calledByAvcodec = true;
    }
    callerInfo.GetData("av_codec_event_info_instance_id", instanceId_);
    int32_t ret = Initialize();
    CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, ret, "Failed to initialize");
    return AVCS_ERR_OK;
}

#ifdef BUILD_ENG_VERSION
void FCodec::OpenDumpFile()
{
    std::string dumpModeStr = OHOS::system::GetParameter("fcodec.dump", "0");
    AVCODEC_LOGI("dumpModeStr %{public}s", dumpModeStr.c_str());
    CHECK_AND_RETURN_LOG(dumpModeStr.length() == 2, "dumpModeStr length should equal 2"); // 2
    char fileName[PATH_MAX_LEN] = {0};
    int ret;
    if (dumpModeStr[0] == '1') {
        ret = sprintf_s(fileName, sizeof(fileName), "%s/input_%p.h264", DUMP_PATH, this);
        CHECK_AND_RETURN_LOG(ret > 0, "Fail to sprintf input fileName");
        dumpInFile_ = std::make_shared<std::ofstream>();
        dumpInFile_->open(fileName, std::ios::out | std::ios::binary);
        if (!dumpInFile_->is_open()) {
            AVCODEC_LOGW("fail open file %{public}s", fileName);
            dumpInFile_ = nullptr;
        }
    }

    if (dumpModeStr[1] == '1') {
        ret = sprintf_s(fileName, sizeof(fileName), "%s/output_%p.yuv", DUMP_PATH, this);
        CHECK_AND_RETURN_LOG(ret > 0, "Fail to sprintf output fileName");
        dumpOutFile_ = std::make_shared<std::ofstream>();
        dumpOutFile_->open(fileName, std::ios::out | std::ios::binary);
        if (!dumpOutFile_->is_open()) {
            AVCODEC_LOGW("fail open file %{public}s", fileName);
            dumpOutFile_ = nullptr;
        }
    }
}
#endif // BUILD_ENG_VERSION

int32_t FCodec::Initialize()
{
    AVCODEC_SYNC_TRACE;
    fDecInfo_.instanceId = std::to_string(instanceId_);
    decName_ = "fdecoder_[" + std::to_string(instanceId_) + "]";
    AVCODEC_LOGI("current decoder name: %{public}s, codec name: %{public}s", decName_.c_str(), codecName_.c_str());
    CHECK_AND_RETURN_RET_LOG(!codecName_.empty(), AVCS_ERR_INVALID_VAL, "Init codec failed: empty name");
    pid_ = getpid();
    std::string fcodecName;
    std::string_view mime;
    for (uint32_t i = 0; i < SUPPORT_VCODEC_NUM; ++i) {
        if (SUPPORT_VCODEC[i].codecName == codecName_) {
            fcodecName = SUPPORT_VCODEC[i].ffmpegCodec;
            mime = SUPPORT_VCODEC[i].mimeType;
            break;
        }
    }
    CHECK_AND_RETURN_RET_LOG(!fcodecName.empty(), AVCS_ERR_INVALID_VAL,
                             "Init codec failed: not support name: %{public}s", codecName_.c_str());
    format_.PutStringValue(FMTKey::MIME_TYPE, mime);
    format_.PutStringValue(FMTKey::MEDIA_CODEC_NAME, codecName_);
    fDecInfo_.mimeType = mime;
    avCodec_ = std::shared_ptr<AVCodec>(const_cast<AVCodec *>(avcodec_find_decoder_by_name(fcodecName.c_str())),
                                        [](void *ptr) {});
    CHECK_AND_RETURN_RET_LOG(avCodec_ != nullptr, AVCS_ERR_INVALID_VAL,
                             "Init codec failed: cannot find codec with name %{public}s", codecName_.c_str());
    sendTask_ = std::make_shared<TaskThread>("SendFrame");
    sendTask_->RegisterHandler([this] { SendFrame(); });
    receiveTask_ = std::make_shared<TaskThread>("ReceiveFrame");
    receiveTask_->RegisterHandler([this] { ReceiveFrame(); });
#ifdef BUILD_ENG_VERSION
    OpenDumpFile();
#endif // BUILD_ENG_VERSION
    state_ = State::INITIALIZED;
    AVCODEC_LOGI("Init codec successful, state: Uninitialized -> Initialized");
    return AVCS_ERR_OK;
}

void FCodec::GetSurfaceCfgFromFmt(const Format &format)
{
    int32_t val = -1;
    std::lock_guard<std::mutex> fLock(formatMutex_);
    if (format.GetIntValue(FMTKey::VIDEO_PIXEL_FORMAT, val)) {
        if (IsValidPixelFormat(val)) {
            outputPixelFmt_ = static_cast<VideoPixelFormat>(val);
            GraphicPixelFormat surfacePixelFmt = TranslateSurfaceFormat(outputPixelFmt_);
            format_.PutIntValue(FMTKey::VIDEO_PIXEL_FORMAT, val);
            format_.PutIntValue(FMTKey::VIDEO_GRAPHIC_PIXEL_FORMAT, static_cast<int32_t>(surfacePixelFmt));
            AVCODEC_LOGI("Set parameter pixel_format: %{public}d success.", val);
        } else {
            AVCODEC_LOGE("Invalid pixel_format: %{public}d.", val);
        }
    }
    if (format.GetIntValue(FMTKey::VIDEO_SCALE_TYPE, val)) {
        if (IsValidScaleType(val)) {
            format_.PutIntValue(FMTKey::VIDEO_SCALE_TYPE, val);
            AVCODEC_LOGI("Set parameter scale_type: %{public}d success.", val);
        } else {
            AVCODEC_LOGE("Invalid scale_type: %{public}d.", val);
        }
    }
    std::optional<int32_t> orientation = std::nullopt;
    if (format.GetIntValue(FMTKey::VIDEO_ORIENTATION_TYPE, val)) {
        orientation = val;
        AVCODEC_LOGI("Get parameter video_orientation_type: %{public}d success.", orientation.value());
    }
    if (!orientation.has_value() && format.GetIntValue(FMTKey::VIDEO_ROTATION, val)) {
        if (IsValidRotation(val)) {
            orientation = static_cast<int32_t>(TranslateSurfaceRotation(static_cast<VideoRotation>(val)));
            AVCODEC_LOGI("Get parameter rotation_angle: %{public}d success.", orientation.value());
        } else {
            AVCODEC_LOGE("Invalid rotation_angle: %{public}d.", val);
        }
    }
    if (orientation) {
        format_.PutIntValue(FMTKey::VIDEO_ORIENTATION_TYPE, orientation.value());
    }
}

void FCodec::ConfigureDefaultVal(const Format &format, const std::string_view &formatKey, int32_t minVal,
                                 int32_t maxVal)
{
    int32_t val32 = 0;
    if (format.GetIntValue(formatKey, val32) && val32 >= minVal && val32 <= maxVal) {
        format_.PutIntValue(formatKey, val32);
    } else {
        AVCODEC_LOGW("Set parameter failed: %{public}s, which minimum threshold=%{public}d, "
                     "maximum threshold=%{public}d",
                     std::string(formatKey).c_str(), minVal, maxVal);
    }
}

int32_t FCodec::AllocateCodecContext()
{
    avCodecContext_ = std::shared_ptr<AVCodecContext>(avcodec_alloc_context3(avCodec_.get()), [](AVCodecContext *p) {
        if (p != nullptr) {
            if (p->extradata) {
                av_free(p->extradata);
                p->extradata = nullptr;
            }
            avcodec_free_context(&p);
        }
    });
    CHECK_AND_RETURN_RET_LOG(avCodecContext_ != nullptr, AVCS_ERR_INVALID_OPERATION,
                             "Configure codec failed: Allocate context error");
    avCodecContext_->codec_type = AVMEDIA_TYPE_VIDEO;
    return AVCS_ERR_OK;
}

int32_t FCodec::ValidateAndSetVideoResolutionFormat(const Format &format)
{
    CHECK_AND_RETURN_RET_LOG(format.GetIntValue(FMTKey::VIDEO_WIDTH, width_), AVCS_ERR_INVALID_VAL,
                             "Get video width failed");
    CHECK_AND_RETURN_RET_LOG(format.GetIntValue(FMTKey::VIDEO_HEIGHT, height_), AVCS_ERR_INVALID_VAL,
                             "Get video height failed");
    bool isValid = (width_ >= VIDEO_MIN_SIZE && width_ <= VIDEO_MAX_WIDTH_SIZE && height_ >= VIDEO_MIN_SIZE &&
                    height_ <= VIDEO_MAX_HEIGHT_SIZE);
    CHECK_AND_RETURN_RET_LOG(isValid, AVCS_ERR_INVALID_VAL,
                             "Invalid video resolution: width=%{public}d, height=%{public}d", width_, height_);
    format_.PutIntValue(FMTKey::VIDEO_STRIDE,
                        outputPixelFmt_ == VideoPixelFormat::RGBA ? width_ * VIDEO_PIX_DEPTH_RGBA : width_);
    format_.PutIntValue(FMTKey::VIDEO_SLICE_HEIGHT, height_);
    format_.PutIntValue(FMTKey::VIDEO_PIC_WIDTH, width_);
    format_.PutIntValue(FMTKey::VIDEO_PIC_HEIGHT, height_);
    return AVCS_ERR_OK;
}

int32_t FCodec::ConfigureRawVideoPixelFormat(const Format &format)
{
    int32_t pixelFormat = 0;
    if (!format.GetIntValue(FMTKey::VIDEO_RAWVIDEO_INPUT_PIXEL_FORMAT, pixelFormat)) {
        return AVCS_ERR_OK;
    }
    rawvideoPixFmt_ = static_cast<RawVideoPixelFormat>(pixelFormat);
    CHECK_AND_RETURN_RET_LOG(
        rawvideoPixFmt_ >= RawVideoPixelFormat::YUV420P && rawvideoPixFmt_ <= RawVideoPixelFormat::RGBA,
        AVCS_ERR_INVALID_VAL, "Unsupported rawvideo pixel format %{public}d!", static_cast<int32_t>(rawvideoPixFmt_));
    avCodecContext_->pix_fmt = g_convertFfmpegPixFmt[rawvideoPixFmt_];
    return AVCS_ERR_OK;
}

void FCodec::ConfigureThread(const Format &format)
{
    avCodecContext_->width = width_;
    avCodecContext_->height = height_;
    avCodecContext_->thread_count = DEFAULT_THREAD_COUNT;
    int32_t decodeOrder = 0;
    format.GetIntValue(FMTKey::VIDEO_DECODER_OUTPUT_IN_DECODING_ORDER, decodeOrder);
    if (codecName_ == AVCodecCodecName::VIDEO_DECODER_AVC_NAME && decodeOrder != 0) {
        CHECK_AND_RETURN_LOG(av_opt_set(avCodecContext_.get(), "output_decode_order", "1", AV_OPT_SEARCH_CHILDREN) == 0,
                             "H264 decode order enable failed");
        AVCODEC_LOGI("H264 decode order enabled by %{public}d", decodeOrder);
    }
}

int32_t FCodec::ConfigureContext(const Format &format)
{
    int32_t ret = AllocateCodecContext();
    CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, ret, "Configure codec failed: Allocate context error");

    ret = ValidateAndSetVideoResolutionFormat(format);
    CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, ret, "Invalid video resolution");

    ret = ConfigureRawVideoPixelFormat(format);
    CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, ret, "Configure pixel format failed");

    ConfigureThread(format);

#if (defined SUPPORT_CODEC_RV) || (defined SUPPORT_CODEC_MP4V_ES) || (defined SUPPORT_CODEC_VC1)
    return SetCodecExtradata(format);
#else
    return AVCS_ERR_OK;
#endif
}

#if (defined SUPPORT_CODEC_RV) || (defined SUPPORT_CODEC_MP4V_ES) || (defined SUPPORT_CODEC_VC1)
int32_t FCodec::SetCodecExtradata(const Format &format)
{
    size_t extraSize = 0;
    uint8_t *extraData = nullptr;
    if (format.GetBuffer(FMTKey::MEDIA_CODEC_CONFIG, &extraData, extraSize)) {
        if (extraData == nullptr || extraSize == 0) {
            AVCODEC_LOGE("extradata getBufer failed!");
            return AVCS_ERR_INVALID_VAL;
        }
        avCodecContext_->extradata = static_cast<uint8_t *>(av_mallocz(extraSize + AV_INPUT_BUFFER_PADDING_SIZE));
        if (avCodecContext_->extradata == nullptr) {
            AVCODEC_LOGE("extradata malloc failed!");
            return AVCS_ERR_INVALID_VAL;
        }
        avCodecContext_->extradata_size = static_cast<int>(extraSize);
        errno_t rc = memcpy_s(avCodecContext_->extradata, extraSize, extraData, extraSize);
        if (rc != EOK) {
            AVCODEC_LOGE("extradata memcpy_s failed.");
            return AVCodecServiceErrCode::AVCS_ERR_INVALID_VAL;
        }
        rc = memset_s(avCodecContext_->extradata + extraSize, AV_INPUT_BUFFER_PADDING_SIZE, 0,
                      AV_INPUT_BUFFER_PADDING_SIZE);
        if (rc != EOK) {
            AVCODEC_LOGE("extradata memset_s failed.");
            return AVCodecServiceErrCode::AVCS_ERR_INVALID_VAL;
        }
    }
    return AVCS_ERR_OK;
}
#endif

int32_t FCodec::Configure(const Format &format)
{
    AVCODEC_SYNC_TRACE;
    CHECK_AND_RETURN_RET_LOG((state_ == State::INITIALIZED), AVCS_ERR_INVALID_STATE,
                             "Configure codec failed: not in Initialized state");
    format_.PutIntValue(FMTKey::VIDEO_WIDTH, DEFAULT_VIDEO_WIDTH);
    format_.PutIntValue(FMTKey::VIDEO_HEIGHT, DEFAULT_VIDEO_HEIGHT);
    format_.PutIntValue(FMTKey::REQUIRED_OUT_BUFFER_CNT, DEFAULT_OUT_BUFFER_CNT);
    format_.PutIntValue(FMTKey::REQUIRED_IN_BUFFER_CNT, DEFAULT_IN_BUFFER_CNT);
    for (auto &it : format.GetFormatMap()) {
        if (it.first == FMTKey::REQUIRED_OUT_BUFFER_CNT) {
            isOutBufSetted_ = true;
            ConfigureDefaultVal(format, it.first, DEFAULT_MIN_BUFFER_CNT);
        } else if (it.first == FMTKey::REQUIRED_IN_BUFFER_CNT) {
            ConfigureDefaultVal(format, it.first, DEFAULT_MIN_BUFFER_CNT);
        } else if (it.first == FMTKey::VIDEO_WIDTH) {
            ConfigureDefaultVal(format, it.first, VIDEO_MIN_SIZE, VIDEO_MAX_WIDTH_SIZE);
        } else if (it.first == FMTKey::VIDEO_HEIGHT) {
            ConfigureDefaultVal(format, it.first, VIDEO_MIN_SIZE, VIDEO_MAX_HEIGHT_SIZE);
        } else if (it.first == FMTKey::MEDIA_BITRATE) {
            int64_t val64 = 0L;
            CHECK_AND_RETURN_RET_LOG(format.GetLongValue(FMTKey::MEDIA_BITRATE, val64) && val64 > 0L,
                                     AVCS_ERR_INVALID_VAL, "Cannot get bit rate!");
            format_.PutLongValue(FMTKey::MEDIA_BITRATE, val64);
        } else if (it.first == FMTKey::VIDEO_FRAME_RATE) {
            double val = 0;
            CHECK_AND_RETURN_RET_LOG(format.GetDoubleValue(FMTKey::VIDEO_FRAME_RATE, val) && val > 0.0f,
                                     AVCS_ERR_INVALID_VAL, "Cannot get frame rate!");
            format_.PutDoubleValue(FMTKey::VIDEO_FRAME_RATE, val);
        } else if (it.first == FMTKey::VIDEO_PIXEL_FORMAT || it.first == FMTKey::VIDEO_ROTATION ||
                   it.first == FMTKey::VIDEO_ORIENTATION_TYPE || it.first == FMTKey::VIDEO_SCALE_TYPE ||
                   it.first == FMTKey::VIDEO_DECODER_OUTPUT_IN_DECODING_ORDER) {
            continue;
        } else {
            AVCODEC_LOGW("Set parameter failed: %{public}s, unsupport key", it.first.data());
        }
    }
    GetSurfaceCfgFromFmt(format);
    if (outputPixelFmt_ == VideoPixelFormat::UNKNOWN) {
        outputPixelFmt_ = VideoPixelFormat::NV12;
        format_.PutIntValue(FMTKey::VIDEO_PIXEL_FORMAT, static_cast<int32_t>(VideoPixelFormat::NV12));
    }
    AVCODEC_LOGI("current output pixel format %{public}d", static_cast<int32_t>(outputPixelFmt_));
    int32_t ret = ConfigureContext(format);

    state_ = State::CONFIGURED;
    AVCODEC_LOGI("Configured codec successful: state: Initialized -> Configured");
    return ret;
}

bool FCodec::IsActive() const
{
    return state_ == State::RUNNING || state_ == State::FLUSHED || state_ == State::EOS;
}

void FCodec::FreeExtraData()
{
    if (avCodecContext_->extradata) {
        av_free(avCodecContext_->extradata);
        avCodecContext_->extradata = nullptr;
        avCodecContext_->extradata_size = 0;
    }
    avCodecContext_->coded_width = 0;
    avCodecContext_->coded_height = 0;
}

void FCodec::ResetContext(bool isNeedFree)
{
    CHECK_AND_RETURN_LOG(avCodecContext_ != nullptr, "Avcodec context is nullptr");
    if (isNeedFree) {
        FreeExtraData();
        avCodecContext_->width = 0;
        avCodecContext_->height = 0;
        avCodecContext_->get_buffer2 = nullptr;
        return;
    }
    if (codecName_ == AVCodecCodecName::VIDEO_DECODER_AVC_NAME) {
        FreeExtraData();
    }
}

int32_t FCodec::Start()
{
    AVCODEC_SYNC_TRACE;
    CHECK_AND_RETURN_RET_LOG(callback_ != nullptr, AVCS_ERR_INVALID_OPERATION, "Start codec failed: callback is null");
    CHECK_AND_RETURN_RET_LOG((state_ == State::CONFIGURED || state_ == State::FLUSHED), AVCS_ERR_INVALID_STATE,
                             "Start codec failed: not in Configured or Flushed state");
    if (state_ != State::FLUSHED) {
        CHECK_AND_RETURN_RET_LOG(avcodec_open2(avCodecContext_.get(), avCodec_.get(), nullptr) == 0, AVCS_ERR_UNKNOWN,
                                 "Start codec failed: cannot open avcodec");
    }
    if (!isBufferAllocated_) {
        cachedFrame_ = std::shared_ptr<AVFrame>(av_frame_alloc(), [](AVFrame *p) { av_frame_free(&p); });
        avPacket_ = std::shared_ptr<AVPacket>(av_packet_alloc(), [](AVPacket *p) { av_packet_free(&p); });
        CHECK_AND_RETURN_RET_LOG((cachedFrame_ != nullptr && avPacket_ != nullptr), AVCS_ERR_UNKNOWN,
                                 "Start codec failed: cannot allocate frame or packet");
        for (int32_t i = 0; i < AV_NUM_DATA_POINTERS; i++) {
            scaleData_[i] = nullptr;
            scaleLineSize_[i] = 0;
        }
        isConverted_ = false;
        int32_t ret = AllocateBuffers();
        CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, ret, "Start codec failed: cannot allocate buffers");
        isBufferAllocated_ = true;
    }
    InitBuffers();
    isSendEos_ = false;
    sendTask_->Start();
    receiveTask_->Start();
    state_ = State::RUNNING;
    AVCODEC_LOGI("%{public}s Start codec successful, state: Running", decName_.c_str());
    return AVCS_ERR_OK;
}

void FCodec::InitBuffers()
{
    inputAvailQue_->SetActive(true);
    codecAvailQue_->SetActive(true);
    CHECK_AND_RETURN_LOG(buffers_[INDEX_INPUT].size() > 0, "Input buffers is null!");
    for (uint32_t i = 0u; i < buffers_[INDEX_INPUT].size(); i++) {
        buffers_[INDEX_INPUT][i]->owner_ = Owner::OWNED_BY_USER;
        callback_->OnInputBufferAvailable(i, buffers_[INDEX_INPUT][i]->avBuffer_);
        AVCODEC_LOGI("%{public}s OnInputBufferAvailable frame index = %{public}u, owner = %{public}d",
                     decName_.c_str(), i, buffers_[INDEX_INPUT][i]->owner_.load());
    }
    std::lock_guard<std::mutex> oLock(outputMutex_);
    CHECK_AND_RETURN_LOG(buffers_[INDEX_OUTPUT].size() > 0, "Output buffers is null!");
    // for buffer mode or state is CONFIGURED
    if (sInfo_.surface == nullptr || state_ == State::CONFIGURED) {
        for (uint32_t i = 0u; i < buffers_[INDEX_OUTPUT].size(); i++) {
            buffers_[INDEX_OUTPUT][i]->owner_ = Owner::OWNED_BY_CODEC;
            codecAvailQue_->Push(i);
        }
        return;
    }
    // for surface mode on FlUSHED
    for (uint32_t i = 0u; i < buffers_[INDEX_OUTPUT].size(); i++) {
        if (buffers_[INDEX_OUTPUT][i]->owner_ != Owner::OWNED_BY_SURFACE) {
            buffers_[INDEX_OUTPUT][i]->owner_ = Owner::OWNED_BY_CODEC;
            codecAvailQue_->Push(i);
        }
    }
}

void FCodec::ResetData()
{
    if (scaleData_[0] != nullptr) {
        if (isConverted_) {
            av_free(scaleData_[0]);
            isConverted_ = false;
            scale_.reset();
        }
        for (int32_t i = 0; i < AV_NUM_DATA_POINTERS; i++) {
            scaleData_[i] = nullptr;
            scaleLineSize_[i] = 0;
        }
    }
}

void FCodec::FlushBuffers()
{
    inputAvailQue_->Clear();
    std::unique_lock<std::mutex> iLock(inputMutex_);
    synIndex_ = std::nullopt;
    iLock.unlock();
    codecAvailQue_->Clear();
    ResetData();
    av_frame_unref(cachedFrame_.get());
    av_packet_unref(avPacket_.get());
}

void FCodec::StopThread()
{
    if (sendTask_ != nullptr && inputAvailQue_ != nullptr) {
        std::unique_lock<std::mutex> sLock(sendMutex_);
        sendCv_.notify_one();
        sLock.unlock();
        inputAvailQue_->SetActive(false, false);
        sendTask_->Stop();
    }
    if (receiveTask_ != nullptr && codecAvailQue_ != nullptr) {
        std::unique_lock<std::mutex> rLock(recvMutex_);
        recvCv_.notify_one();
        rLock.unlock();
        codecAvailQue_->SetActive(false, false);
        receiveTask_->Stop();
    }
}

int32_t FCodec::Stop()
{
    AVCODEC_SYNC_TRACE;
    CHECK_AND_RETURN_RET_LOG((IsActive()), AVCS_ERR_INVALID_STATE, "Stop codec failed: not in executing state");
    state_ = State::STOPPING;
    AVCODEC_LOGI("step into STOPPING status");
    StopThread();
    avcodec_close(avCodecContext_.get());
    ResetContext(false);
    ReleaseBuffers();
    state_ = State::CONFIGURED;
    AVCODEC_LOGI("Stop codec successful, state: Configured");
    return AVCS_ERR_OK;
}

int32_t FCodec::Flush()
{
    AVCODEC_SYNC_TRACE;
    CHECK_AND_RETURN_RET_LOG((state_ == State::RUNNING || state_ == State::EOS), AVCS_ERR_INVALID_STATE,
                             "%{public}s Flush codec failed: not in running or Eos state", decName_.c_str());
    state_ = State::FLUSHING;
    AVCODEC_LOGI("%{public}s step into FLUSHING status", decName_.c_str());
    std::unique_lock<std::mutex> sLock(sendMutex_);
    sendCv_.notify_one();
    sLock.unlock();
    inputAvailQue_->SetActive(false, false);
    sendTask_->Pause();

    std::unique_lock<std::mutex> rLock(recvMutex_);
    recvCv_.notify_one();
    rLock.unlock();
    codecAvailQue_->SetActive(false, false);
    receiveTask_->Pause();

    avcodec_flush_buffers(avCodecContext_.get());
    ResetContext(false);
    FlushBuffers();
    state_ = State::FLUSHED;
    AVCODEC_LOGI("%{public}s Flush codec successful, state: Flushed", decName_.c_str());
    return AVCS_ERR_OK;
}

int32_t FCodec::Reset()
{
    AVCODEC_SYNC_TRACE;
    AVCODEC_LOGI("Reset codec called");
    int32_t ret = Release();
    CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, ret, "Reset codec failed: cannot release codec");
    ret = Initialize();
    CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, ret, "Reset codec failed: cannot init codec");
    AVCODEC_LOGI("Reset codec successful, state: Initialized");
    return AVCS_ERR_OK;
}

void FCodec::ReleaseResource()
{
    StopThread();
    if (avCodecContext_ != nullptr) {
        avcodec_close(avCodecContext_.get());
        ResetContext();
    }
    ReleaseBuffers();
    format_ = Format();
    {
        std::lock_guard<std::mutex> sLock(surfaceMutex_);
        CHECK_AND_RETURN_LOG(sInfo_.surface != nullptr, "Surface is nullptr!");
        transform_ = GRAPHIC_ROTATE_NONE;
        AVCODEC_LOGI("Reset surface video_orientation_type: %{public}d", static_cast<int32_t>(transform_));
        sInfo_.surface->SetTransform(transform_);
        UnRegisterListenerToSurface(sInfo_.surface);
        sInfo_.surface = nullptr;
    }
    StopRequestSurfaceBufferThread();
}

int32_t FCodec::Release()
{
    AVCODEC_SYNC_TRACE;
    state_ = State::STOPPING;
    AVCODEC_LOGI("step into STOPPING status");
    ReleaseResource();
    state_ = State::UNINITIALIZED;
    AVCODEC_LOGI("Release codec successful, state: Uninitialized");
    return AVCS_ERR_OK;
}

void FCodec::SetSurfaceParameter()
{
    int32_t val = -1;
    std::optional<GraphicPixelFormat> surfacePixelFmt = std::nullopt;
    std::optional<ScalingMode> scaling = std::nullopt;
    std::optional<GraphicTransformType> orientation = std::nullopt;
    std::unique_lock<std::mutex> fLock(formatMutex_);
    if (format_.GetIntValue(FMTKey::VIDEO_PIXEL_FORMAT, val)) {
        surfacePixelFmt = TranslateSurfaceFormat(static_cast<VideoPixelFormat>(val));
    }
    if (format_.GetIntValue(FMTKey::VIDEO_SCALE_TYPE, val)) {
        scaling = static_cast<ScalingMode>(val);
    }
    if (format_.GetIntValue(FMTKey::VIDEO_ORIENTATION_TYPE, val)) {
        orientation = static_cast<GraphicTransformType>(val);
    }
    fLock.unlock();
    std::lock_guard<std::mutex> sLock(surfaceMutex_);
    if (surfacePixelFmt) {
        sInfo_.requestConfig.format = surfacePixelFmt.value();
    }
    if (scaling) {
        sInfo_.scalingMode = scaling.value();
        sInfo_.surface->SetScalingMode(sInfo_.scalingMode.value());
    }
    if (orientation) {
        transform_ = orientation.value();
        AVCODEC_LOGI("Set surface video_orientation_type: %{public}d success.", static_cast<int32_t>(transform_));
        sInfo_.surface->SetTransform(transform_);
    }
}

int32_t FCodec::SetParameter(const Format &format)
{
    AVCODEC_SYNC_TRACE;
    if (sInfo_.surface != nullptr) {
        GetSurfaceCfgFromFmt(format);
        SetSurfaceParameter();
    }
    AVCODEC_LOGI("Set parameter successful");
    return AVCS_ERR_OK;
}

int32_t FCodec::GetOutputFormat(Format &format)
{
    AVCODEC_SYNC_TRACE;
    std::lock_guard<std::mutex> lock(formatMutex_);
    if (!format_.ContainKey(FMTKey::MEDIA_BITRATE)) {
        if (avCodecContext_ != nullptr) {
            format_.PutLongValue(FMTKey::MEDIA_BITRATE, avCodecContext_->bit_rate);
        }
    }
    if (!format_.ContainKey(FMTKey::VIDEO_FRAME_RATE)) {
        if (avCodecContext_ != nullptr && avCodecContext_->framerate.den > 0) {
            double value = static_cast<double>(avCodecContext_->framerate.num) /
                           static_cast<double>(avCodecContext_->framerate.den);
            format_.PutDoubleValue(FMTKey::VIDEO_FRAME_RATE, value);
        }
    }
    format = format_;
    if (!format.ContainKey(FMTKey::REQUIRED_IN_BUFFER_SIZE)) {
        int32_t stride = AlignUp(width_, VIDEO_ALIGN_SIZE);
        int32_t maxInputSize = static_cast<int32_t>((stride * height_ * VIDEO_PIX_DEPTH_YUV) / UV_SCALE_FACTOR);
        format.PutIntValue(FMTKey::REQUIRED_IN_BUFFER_SIZE, maxInputSize);
    }
    AVCODEC_LOGI("Get outputFormat successful");
    return AVCS_ERR_OK;
}

void FCodec::CalculateBufferSize()
{
    const int64_t stride = AlignUp(width_, VIDEO_ALIGN_SIZE);
    int64_t size = stride * height_ * VIDEO_PIX_DEPTH_RGBA;
    if (outputPixelFmt_ != VideoPixelFormat::RGBA) {
        size = stride * height_ * VIDEO_PIX_DEPTH_YUV / UV_SCALE_FACTOR;
    }
    if (size >= INT32_MAX || size <= 0) {
        outputBufferSize_ = 0;
        AVCODEC_LOGE("width = %{public}d, height = %{public}d invalid", width_, height_);
        return;
    }
    outputBufferSize_ = static_cast<int32_t>(size);
    if (rawvideoPixFmt_ == RawVideoPixelFormat::RGBA) {
        size = stride * height_ * VIDEO_PIX_DEPTH_RGBA;
    } else {
        size = std::max(VIDEO_MIN_BUFFER_SIZE, outputBufferSize_);
    }
    if (size >= INT32_MAX || size <= 0) {
        inputBufferSize_ = 0;
        AVCODEC_LOGE("width = %{public}d, height = %{public}d invalid", width_, height_);
        return;
    }
    inputBufferSize_ = static_cast<int32_t>(size);
    AVCODEC_LOGI("width = %{public}d, height = %{public}d, stride = %{public}d, Input buffer size = %{public}d, output "
                 "buffer size = %{public}d",
                 width_, height_, static_cast<int32_t>(stride), inputBufferSize_, outputBufferSize_);
}

int32_t FCodec::AllocateInputBuffer(int32_t inBufferSize)
{
    int32_t valBufferCnt = 0;
    for (uint32_t i = 0u; i < inputBufferCnt_; i++) {
        std::shared_ptr<FBuffer> buf = std::make_shared<FBuffer>();
        std::shared_ptr<AVAllocator> allocator =
            AVAllocatorFactory::CreateSharedAllocator(MemoryFlag::MEMORY_READ_WRITE);
        CHECK_AND_CONTINUE_LOG(allocator != nullptr, "input buffer %{public}u allocator is nullptr", i);
        buf->avBuffer_ = AVBuffer::CreateAVBuffer(allocator, inBufferSize);
        CHECK_AND_CONTINUE_LOG(buf->avBuffer_ != nullptr && buf->avBuffer_->memory_ != nullptr,
                               "Allocate input buffer failed, index=%{public}u", i);
        AVCODEC_LOGI("Allocate input buffer success: index=%{public}u, size=%{public}d",
                     i, buf->avBuffer_->memory_->GetCapacity());
        buffers_[INDEX_INPUT].emplace_back(buf);
        valBufferCnt++;
    }
    CHECK_AND_RETURN_RET_LOGD(valBufferCnt < DEFAULT_MIN_BUFFER_CNT, AVCS_ERR_OK, "Allocate input buffers successful");
    AVCODEC_LOGE("Allocate input buffer failed: only %{public}d buffer is allocated, no memory", valBufferCnt);
    buffers_[INDEX_INPUT].clear();
    return AVCS_ERR_NO_MEMORY;
}

int32_t FCodec::SetSurfaceCfg()
{
    int32_t val = -1;
    std::optional<ScalingMode> scaling = std::nullopt;
    std::optional<GraphicTransformType> orientation = std::nullopt;
    std::unique_lock<std::mutex> fLock(formatMutex_);
    int32_t pixelFormat = 0;
    format_.GetIntValue(FMTKey::VIDEO_PIXEL_FORMAT, pixelFormat);
    GraphicPixelFormat surfacePixelFmt = TranslateSurfaceFormat(static_cast<VideoPixelFormat>(pixelFormat));
    CHECK_AND_RETURN_RET_LOG(surfacePixelFmt != GraphicPixelFormat::GRAPHIC_PIXEL_FMT_BUTT, AVCS_ERR_UNSUPPORT,
                             "Failed to allocate output buffer: unsupported surface format");
    format_.PutIntValue(FMTKey::VIDEO_GRAPHIC_PIXEL_FORMAT, static_cast<int32_t>(surfacePixelFmt));
    if (format_.GetIntValue(FMTKey::VIDEO_SCALE_TYPE, val)) {
        CHECK_AND_RETURN_RET_LOG(IsValidScaleType(val), AVCS_ERR_INVALID_VAL, "Invalid scale_type: %{public}d", val);
        scaling = static_cast<ScalingMode>(val);
    }
    if (format_.GetIntValue(FMTKey::VIDEO_ORIENTATION_TYPE, val)) {
        orientation = static_cast<GraphicTransformType>(val);
    }
    fLock.unlock();
    {
        std::lock_guard<std::mutex> sLock(surfaceMutex_);
        sInfo_.requestConfig.width = width_;
        sInfo_.requestConfig.height = height_;
        sInfo_.requestConfig.format = surfacePixelFmt;
        if (scaling) {
            sInfo_.scalingMode = scaling.value();
            sInfo_.surface->SetScalingMode(scaling.value());
        }
        if (orientation) {
            transform_ = orientation.value();
        }
        AVCODEC_LOGI("Set surface video_orientation_type: %{public}d success.", static_cast<int32_t>(transform_));
        sInfo_.surface->SetTransform(transform_);
    }
    return AVCS_ERR_OK;
}

void FCodec::RequestSurfaceBuffer(SurfaceBufferInfo &bufInfo)
{
    std::unique_lock<std::mutex> sLock(surfaceMutex_);
    AVCODEC_LOGD(
        "surface request config, width: %{public}d, height: %{public}d, strideAlignment: %{public}d, "
        "format: %{public}d, usage: %{public}" PRIu64 ", timeout: %{public}d",
        sInfo_.requestConfig.width,
        sInfo_.requestConfig.height,
        sInfo_.requestConfig.strideAlignment,
        sInfo_.requestConfig.format,
        sInfo_.requestConfig.usage,
        sInfo_.requestConfig.timeout);
    GSError err = sInfo_.surface->RequestBuffer(bufInfo.buf, bufInfo.fence, sInfo_.requestConfig);
    if (err != GSERROR_OK || bufInfo.buf == nullptr || bufInfo.buf->GetBufferHandle() == nullptr) {
        AVCODEC_LOGE("Request surface buffer fail, ret:%{public}d", static_cast<int32_t>(err));
        return;
    }
    sLock.unlock();
    bufInfo.seqNum = bufInfo.buf->GetSeqNum();
    AVCODEC_LOGD("Request surface buffer seqNum: %{public}u", bufInfo.seqNum);
}

bool FCodec::FBufferAvailable(const std::shared_ptr<FBuffer> &buffer, SurfaceBufferInfo &bufInfo)
{
    int32_t sw = bufInfo.buf->GetWidth();
    int32_t sh = bufInfo.buf->GetHeight();
    int32_t format = bufInfo.buf->GetFormat();
    uint64_t usage = bufInfo.buf->GetUsage();
    std::shared_ptr<FSurfaceMemory> surfaceMemory = buffer->sMemory_;
    if (surfaceMemory == nullptr) {
        return false;
    }
    return buffer->owner_ == Owner::OWNED_BY_SURFACE &&
           (buffer->width_ != sw || buffer->height_ != sh || buffer->format_ != format || buffer->usage_ != usage) &&
           surfaceMemory->isAttached;
}

void FCodec::OnSurfaceBufferAvailable(SurfaceBufferInfo &bufInfo)
{
    CHECK_AND_RETURN_LOG(bufInfo.buf != nullptr, "Surface buffer is nullptr!");
    uint32_t bufIdx = static_cast<uint32_t>(buffers_[INDEX_OUTPUT].size());
    if (seqNumToFbufMap_.count(bufInfo.seqNum) == 0) {
        AVCODEC_LOGI("surface buffer %{public}u not in map", bufInfo.seqNum);
        for (const std::shared_ptr<FBuffer> &buffer : buffers_[INDEX_OUTPUT]) {
            if (FBufferAvailable(buffer, bufInfo)) {
                uint32_t oldSeqNum = buffer->sMemory_->GetSurfaceBufferSeqNum();
                bufIdx = seqNumToFbufMap_[oldSeqNum];
                seqNumToFbufMap_.erase(oldSeqNum);
                seqNumToFbufMap_[bufInfo.seqNum] = bufIdx;
                AVCODEC_LOGI("buf(%{public}u), %{public}u -> %{public}u", bufIdx, oldSeqNum, bufInfo.seqNum);
                buffers_[INDEX_OUTPUT][bufIdx]->avBuffer_ = AVBuffer::CreateAVBuffer(bufInfo.buf);
                break;
            }
        }
    } else {
        bufIdx = seqNumToFbufMap_[bufInfo.seqNum];
    }
    if (bufIdx >= buffers_[INDEX_OUTPUT].size() || buffers_[INDEX_OUTPUT][bufIdx]->avBuffer_ == nullptr) {
        AVCODEC_LOGE("surfae buffer(%{public}u) cannot match available output buffer", bufInfo.seqNum);
        callback_->OnError(AVCodecErrorType::AVCODEC_ERROR_INTERNAL, AVCodecServiceErrCode::AVCS_ERR_UNKNOWN);
        state_ = State::ERROR;
        return;
    }
    std::shared_ptr<FSurfaceMemory> surfaceMemory = buffers_[INDEX_OUTPUT][bufIdx]->sMemory_;
    surfaceMemory->SetSurfaceBuffer(bufInfo.buf, Owner::OWNED_BY_CODEC, bufInfo.fence);
    buffers_[INDEX_OUTPUT][bufIdx]->format_ = sInfo_.requestConfig.format;
    buffers_[INDEX_OUTPUT][bufIdx]->usage_ = sInfo_.requestConfig.usage,
    buffers_[INDEX_OUTPUT][bufIdx]->owner_ = Owner::OWNED_BY_CODEC;
    codecAvailQue_->Push(bufIdx);
    AVCODEC_LOGD("Request output buffer %{public}u, available index %{public}d", bufInfo.seqNum, bufIdx);
}

void FCodec::RequestSurfaceBufferThread()
{
    while (!requestBufferThreadExit_.load()) {
        std::unique_lock<std::mutex> lck(requestBufferMutex_);
        if (count_ == 0) {
            requestBufferCV_.wait(lck, [this]() { return requestBufferThreadExit_.load() || count_ != 0; });
        }
        if (requestBufferThreadExit_.load()) {
            count_ = 0u;
            break;
        }
        std::lock_guard<std::mutex> oLock(outputMutex_);
        SurfaceBufferInfo bufInfo;
        RequestSurfaceBuffer(bufInfo);
        OnSurfaceBufferAvailable(bufInfo);
        count_--;
    }
    AVCODEC_LOGI("RequestSurfaceBufferThread exit.");
}

void FCodec::StartRequestSurfaceBufferThread()
{
    if (!mRequestSurfaceBufferThread_.joinable()) {
        requestBufferThreadExit_ = false;
        count_ = 0u;
        mRequestSurfaceBufferThread_ = std::thread(&FCodec::RequestSurfaceBufferThread, this);
    }
}

void FCodec::StopRequestSurfaceBufferThread()
{
    if (mRequestSurfaceBufferThread_.joinable()) {
        requestBufferThreadExit_ = true;
        requestBufferCV_.notify_all();
        mRequestSurfaceBufferThread_.join();
    }
}

void FCodec::RequestSurfaceBufferOnce()
{
    CHECK_AND_RETURN_LOG(!requestBufferThreadExit_.load(), "request surfacebuffer thread exited!");
    std::unique_lock<std::mutex> lck(requestBufferMutex_);
    count_++;
    requestBufferCV_.notify_one();
}

int32_t FCodec::AllocateSurfaceBuffer(sptr<SurfaceBuffer> &surfacebuffer)
{
    GraphicPixelFormat surfacePixelFmt = TranslateSurfaceFormat(outputPixelFmt_);
    BufferRequestConfig reqConfig = {.width = width_,
                                     .height = height_,
                                     .strideAlignment = SURFACE_STRIDE_ALIGN,
                                     .format = static_cast<int32_t>(surfacePixelFmt),
                                     .usage = SURFACE_DEFAULT_USAGE,
                                     .timeout = TIMEOUT};
    surfacebuffer = SurfaceBuffer::Create();
    CHECK_AND_RETURN_RET_LOG(surfacebuffer, AVCS_ERR_UNKNOWN, "Create surface buffer failed!");
    GSError err = surfacebuffer->Alloc(reqConfig);
    CHECK_AND_RETURN_RET_LOG(err == GSERROR_OK && surfacebuffer != nullptr, err,
                             "Alloc surface buffer failed, GSERROR=%{public}d", err);
    int32_t fd = surfacebuffer->GetFileDescriptor();
    CHECK_AND_RETURN_RET_LOG(fd > 0, AVCS_ERR_UNKNOWN, "Invalid fd %{public}d, surface buffer(%{public}u)", fd,
                             surfacebuffer->GetSeqNum());
    std::string type = "sw-video-decoder";
    std::string mime(fDecInfo_.mimeType);
    std::vector<std::string> splitMime;
    std::string token;
    std::istringstream iss(mime);
    while (std::getline(iss, token, '/')) {
        splitMime.push_back(token);
    }
    if (!splitMime.empty()) {
        mime = splitMime.back();
    }
    std::string name = fDecInfo_.processName + "-" + std::to_string(width_) + "x" + std::to_string(height_)
                       + "-" + mime + "-" + fDecInfo_.instanceId;
    ioctl(fd, DMA_BUF_SET_LEAK_TYPE, type.c_str());
    std::string pid = std::to_string(fDecInfo_.pid);
    ioctl(fd, DMA_BUF_SET_NAME_A, pid.c_str());
    ioctl(fd, DMA_BUF_SET_NAME_A, name.c_str());
    return AVCS_ERR_OK;
}

int32_t FCodec::AllocateOutputBuffer()
{
    CHECK_AND_RETURN_RET_LOG(sInfo_.surface == nullptr, AVCS_ERR_UNKNOWN, "Not in buffer mode!");
    int32_t valBufferCnt = 0;
    for (uint32_t i = 0u; i < outputBufferCnt_; i++) {
        std::shared_ptr<FBuffer> buf = std::make_shared<FBuffer>();
        CHECK_AND_RETURN_RET_LOG(buf != nullptr, AVCS_ERR_UNKNOWN, "Creata output buffer failed!");
        buf->width_ = width_;
        buf->height_ = height_;
#ifdef EMULATOR_ENABLED
        std::shared_ptr<AVAllocator> allocator =
            AVAllocatorFactory::CreateSharedAllocator(MemoryFlag::MEMORY_READ_WRITE);
        CHECK_AND_CONTINUE_LOG(allocator != nullptr, "output buffer %{public}u allocator is nullptr", i);
        buf->avBuffer_ = AVBuffer::CreateAVBuffer(allocator, outputBufferSize_);
#else
        sptr<SurfaceBuffer> sb = nullptr;
        int32_t ret = AllocateSurfaceBuffer(sb);
        CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK && sb != nullptr, ret,
                                 "Alloc surface buffer failed, ret=%{public}d", ret);
        buf->avBuffer_ = AVBuffer::CreateAVBuffer(sb);
#endif
        CHECK_AND_CONTINUE_LOG(buf->avBuffer_ != nullptr && buf->avBuffer_->memory_ !=nullptr,
                               "create output avbuffer failed, index=%{public}d", i);
        int32_t curBufSize = buf->avBuffer_->memory_->GetCapacity();
        AVCODEC_LOGI("Allocate output buffer success: index=%{public}u, size=%{public}d", i, curBufSize);
        buffers_[INDEX_OUTPUT].emplace_back(buf);
        valBufferCnt++;
    }
    CHECK_AND_RETURN_RET_LOGD(valBufferCnt < DEFAULT_MIN_BUFFER_CNT, AVCS_ERR_OK, "Allocate output buffers successful");
    AVCODEC_LOGE("Allocate output buffer failed: only %{public}d buffer is allocated, no memory", valBufferCnt);
    buffers_[INDEX_INPUT].clear();
    buffers_[INDEX_OUTPUT].clear();
    return AVCS_ERR_NO_MEMORY;
}

int32_t FCodec::ClearSurfaceAndSetQueueSize()
{
    std::unique_lock<std::mutex> sLock(surfaceMutex_);
    sInfo_.surface->Connect();
    sInfo_.surface->CleanCache(); // clean cache will work only if the surface is connected by us.
    sInfo_.surface->Disconnect();
    int32_t ret = SetQueueSize(sInfo_.surface, outputBufferCnt_);
    CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, ret, "Set surface queue size failed!");
    sLock.unlock();
    ret = SetSurfaceCfg();
    CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, ret, "Set surface cfg failed!");
    std::lock_guard<std::mutex> oLock(outputMutex_);
    CHECK_AND_RETURN_RET_LOGD(buffers_[INDEX_OUTPUT].size() > 0u, AVCS_ERR_OK, "Set surface cfg & queue size success.");
    uint32_t valBufferCnt = 0;
    for (auto &it : buffers_[INDEX_OUTPUT]) {
        std::shared_ptr<FSurfaceMemory> surfaceMemory = it->sMemory_;
        surfaceMemory->isAttached = false;
        valBufferCnt++;
    }
    CHECK_AND_RETURN_RET_LOG(valBufferCnt == outputBufferCnt_, AVCS_ERR_UNKNOWN, "Outbuf cnt(%{public}u) != %{public}u",
                             valBufferCnt, outputBufferCnt_);
    return AVCS_ERR_OK;
}

int32_t FCodec::AllocateOutputBuffersFromSurface()
{
    CHECK_AND_RETURN_RET_LOG(sInfo_.surface != nullptr, AVCS_ERR_UNKNOWN, "Not in surface mode!");
    int32_t ret = ClearSurfaceAndSetQueueSize();
    CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, ret, "Clean surface and set queue size failed!");
    StartRequestSurfaceBufferThread();
    for (uint32_t i = 0u; i < outputBufferCnt_; i++) {
        std::shared_ptr<FSurfaceMemory> surfaceMemory = std::make_shared<FSurfaceMemory>(&sInfo_, fDecInfo_);
        CHECK_AND_RETURN_RET_LOG(surfaceMemory != nullptr, AVCS_ERR_UNKNOWN, "Creata surface memory failed!");
        ret = surfaceMemory->AllocSurfaceBuffer(width_, height_);
        CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, ret, "Alloc surface buffer failed!");
        sptr<SurfaceBuffer> surfaceBuffer = surfaceMemory->GetSurfaceBuffer();
        CHECK_AND_RETURN_RET_LOG(surfaceBuffer != nullptr, AVCS_ERR_UNKNOWN, "surface buf(%{public}u) is null.", i);
        ret = Attach(surfaceBuffer);
        CHECK_AND_CONTINUE_LOG(ret == AVCS_ERR_OK, "surface buf(%{public}u) attach to surface failed.", i);
        surfaceMemory->isAttached = true;
        uint32_t seqNum = surfaceBuffer->GetSeqNum();
        seqNumToFbufMap_[seqNum] = i;
        AVCODEC_LOGI("Surface buffer seqNum: %{public}u -> index: [%{public}u]", seqNum, i);
        std::shared_ptr<FBuffer> buf = std::make_shared<FBuffer>();
        CHECK_AND_RETURN_RET_LOG(buf != nullptr, AVCS_ERR_UNKNOWN, "Creata output buffer failed!");
        buf->sMemory_ = surfaceMemory;
        buf->height_ = height_;
        buf->width_ = width_;
        outAVBuffer4Surface_.emplace_back(AVBuffer::CreateAVBuffer());
        buf->avBuffer_ = AVBuffer::CreateAVBuffer(surfaceBuffer);
        CHECK_AND_RETURN_RET_LOG(buf->avBuffer_ != nullptr, AVCS_ERR_UNKNOWN, "avbuffer is nullptr!");
        AVCODEC_LOGI("Allocate output surface buffer success, index=%{public}u, size=%{public}d, stride=%{public}d", i,
                     buf->sMemory_->GetSize(), buf->sMemory_->GetSurfaceBufferStride());
        buffers_[INDEX_OUTPUT].emplace_back(buf);
    }
    uint32_t outputBufferNum = static_cast<uint32_t>(buffers_[INDEX_OUTPUT].size());
    CHECK_AND_RETURN_RET_LOG(outputBufferNum == outputBufferCnt_, AVCS_ERR_UNKNOWN,
                             "Only alloc %{public}u buffers, less %{public}u", outputBufferNum, outputBufferCnt_);
    return AVCS_ERR_OK;
}

int32_t FCodec::AllocateBuffers()
{
    AVCODEC_SYNC_TRACE;
    CalculateBufferSize();
    CHECK_AND_RETURN_RET_LOG(inputBufferSize_ > 0 && outputBufferSize_ > 0, AVCS_ERR_INVALID_VAL,
                             "Allocate buffer with input size=%{public}d, output size=%{public}d failed",
                             inputBufferSize_, outputBufferSize_);
    if (sInfo_.surface != nullptr && isOutBufSetted_ == false) {
        format_.PutIntValue(FMTKey::REQUIRED_OUT_BUFFER_CNT, DEFAULT_OUT_SURFACE_CNT);
    }
    int32_t val = -1;
    CHECK_AND_RETURN_RET_LOG(format_.GetIntValue(FMTKey::REQUIRED_IN_BUFFER_CNT, val) && val >= DEFAULT_MIN_BUFFER_CNT,
        AVCS_ERR_INVALID_VAL, "Invalid input buffer cnt: %{public}d", val);
    inputBufferCnt_ = static_cast<uint32_t>(val);
    CHECK_AND_RETURN_RET_LOG(
        format_.GetIntValue(FMTKey::REQUIRED_OUT_BUFFER_CNT, val) &&
        val >= DEFAULT_MIN_BUFFER_CNT, AVCS_ERR_INVALID_VAL,
        "Invalid output buffer cnt: %{public}d", val);
    outputBufferCnt_ = static_cast<uint32_t>(val);
    inputAvailQue_ = std::make_shared<BlockQueue<uint32_t>>("inputAvailQue", inputBufferCnt_);
    codecAvailQue_ = std::make_shared<BlockQueue<uint32_t>>("codecAvailQue", outputBufferCnt_);
    int32_t ret = AllocateInputBuffer(inputBufferSize_);
    CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, ret, "Allocate input buffers failed!");
    ret = sInfo_.surface ? AllocateOutputBuffersFromSurface()
                         : AllocateOutputBuffer();
    CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, ret, "Allocate output buffers failed!");
    return AVCS_ERR_OK;
}

int32_t FCodec::UpdateBuffers(uint32_t index)
{
    if (buffers_[INDEX_OUTPUT][index]->width_ != width_ || buffers_[INDEX_OUTPUT][index]->height_ != height_) {
        std::shared_ptr<FBuffer> buf = std::make_shared<FBuffer>();
        CHECK_AND_RETURN_RET_LOG(buf != nullptr, AVCS_ERR_UNKNOWN, "Creata output buffer failed!");
        buf->width_ = width_;
        buf->height_ = height_;
#ifdef EMULATOR_ENABLED
        std::shared_ptr<AVAllocator> allocator =
            AVAllocatorFactory::CreateSharedAllocator(MemoryFlag::MEMORY_READ_WRITE);
        CHECK_AND_RETURN_RET_LOG(allocator != nullptr, AVCS_ERR_NO_MEMORY,
                                 "buffer %{public}u allocator is nullptr", index);
        buf->avBuffer_ = AVBuffer::CreateAVBuffer(allocator, outputBufferSize_);
#else
        sptr<SurfaceBuffer> sb = nullptr;
        int32_t ret = AllocateSurfaceBuffer(sb);
        CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK && sb != nullptr, ret,
                                 "Alloc surface buffer failed, ret=%{public}d", ret);
        buf->avBuffer_ = AVBuffer::CreateAVBuffer(sb);
        CHECK_AND_RETURN_RET_LOG(buf->avBuffer_ != nullptr, AVCS_ERR_UNKNOWN,
                                 "create output avbuffer failed, index=%{public}d", index);
#endif
        int32_t curBufSize = buf->avBuffer_->memory_->GetCapacity();
        AVCODEC_LOGI("update output buffer success: index=%{public}u, size=%{public}d", index, curBufSize);
        buf->owner_ = Owner::OWNED_BY_CODEC;
        buffers_[INDEX_OUTPUT][index] = buf;
    }
    return AVCS_ERR_OK;
}

int32_t FCodec::UpdateSurfaceMemory(uint32_t index)
{
    AVCODEC_SYNC_TRACE;
    std::shared_ptr<FBuffer> outputBuffer = buffers_[INDEX_OUTPUT][index];
    if (width_ != outputBuffer->width_ || height_ != outputBuffer->height_) {
        std::shared_ptr<FSurfaceMemory> surfaceMemory = outputBuffer->sMemory_;
        CHECK_AND_RETURN_RET_LOG(surfaceMemory != nullptr, AVCS_ERR_UNKNOWN, "Surface memory is nullptr!");
        AVCODEC_LOGI("Update surface memory, width=%{public}d, height=%{public}d", width_, height_);
        if (surfaceMemory->isAttached) {
            sptr<SurfaceBuffer> surfaceBuffer = surfaceMemory->GetSurfaceBuffer();
            CHECK_AND_RETURN_RET_LOG(surfaceBuffer != nullptr, AVCS_ERR_UNKNOWN, "Get surface buffer failed!");
            int32_t ret = Detach(surfaceBuffer);
            CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, ret, "Surface buffer detach failed!");
            surfaceMemory->isAttached = false;
            seqNumToFbufMap_.erase(surfaceBuffer->GetSeqNum());
            AVCODEC_LOGI("detach surfacebuffer(%{public}u) -> index: [%{public}u]", surfaceBuffer->GetSeqNum(), index);
        }
        surfaceMemory->ReleaseSurfaceBuffer();
        std::unique_lock<std::mutex> sLock(surfaceMutex_);
        int32_t ret = surfaceMemory->AllocSurfaceBuffer(width_, height_);
        sLock.unlock();
        CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, ret, "Alloc surface buffer failed!");
        sptr<SurfaceBuffer> newSurfaceBuffer = surfaceMemory->GetSurfaceBuffer();
        CHECK_AND_RETURN_RET_LOG(newSurfaceBuffer != nullptr, AVCS_ERR_UNKNOWN, "Alloc surface buffer failed!");
        ret = Attach(newSurfaceBuffer);
        CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, ret, "Surface buffer attach failed!");
        surfaceMemory->isAttached = true;
        uint32_t seqNum = newSurfaceBuffer->GetSeqNum();
        seqNumToFbufMap_[seqNum] = index;
        AVCODEC_LOGI("Surface buffer seqNum: %{public}u -> index: [%{public}u]", seqNum, index);
        outputBuffer->avBuffer_ = AVBuffer::CreateAVBuffer(newSurfaceBuffer);
        CHECK_AND_RETURN_RET_LOG(outputBuffer->avBuffer_ != nullptr, AVCS_ERR_UNKNOWN, "avbuffer is nullptr!");
        outputBuffer->width_ = width_;
        outputBuffer->height_ = height_;
    }
    return AVCS_ERR_OK;
}

bool FCodec::CheckStrideChange(uint32_t index, bool& isChanged)
{
    if (sInfo_.surface != nullptr) {
        std::shared_ptr<FBuffer> frameBuffer = buffers_[INDEX_OUTPUT][index];
        if (!frameBuffer || frameBuffer->sMemory_ == nullptr) {
            AVCODEC_LOGE("frameBuffer or surfaceMemory is nullptr");
            return false;
        }
        int32_t stride = frameBuffer->sMemory_->GetSurfaceBufferStride();
        int32_t formatStride = 0;
        format_.GetIntValue(FMTKey::VIDEO_STRIDE, formatStride);
        if (stride != formatStride) {
            AVCODEC_LOGI("format change, stride: %{public}d->%{public}d", formatStride, stride);
            std::lock_guard<std::mutex> lock(formatMutex_);
            format_.PutIntValue(FMTKey::VIDEO_STRIDE, stride);
            isChanged = true;
        }
    }
    return true;
}

void FCodec::PutFormatValue()
{
    std::lock_guard<std::mutex> lock(formatMutex_);
    format_.PutIntValue(FMTKey::VIDEO_WIDTH, width_);
    format_.PutIntValue(FMTKey::VIDEO_HEIGHT, height_);
    format_.PutIntValue(FMTKey::VIDEO_STRIDE,
                        outputPixelFmt_ == VideoPixelFormat::RGBA ? width_ * VIDEO_PIX_DEPTH_RGBA : width_);
    format_.PutIntValue(FMTKey::VIDEO_SLICE_HEIGHT, height_);
    format_.PutIntValue(FMTKey::VIDEO_PIC_WIDTH, width_);
    format_.PutIntValue(FMTKey::VIDEO_PIC_HEIGHT, height_);
}

int32_t FCodec::CheckFormatChange(uint32_t index, bool &isChanged)
{
    if (width_ != cachedFrame_->width || height_ != cachedFrame_->height) {
        AVCODEC_LOGI("format change, width: %{public}d->%{public}d, height: %{public}d->%{public}d", width_,
                     cachedFrame_->width, height_, cachedFrame_->height);
        width_ = cachedFrame_->width;
        height_ = cachedFrame_->height;
        CHECK_AND_RETURN_RET_LOG(ValidateVideoResolution(codecName_, width_, height_), AVCS_ERR_INVALID_VAL,
            "Current decoder:%{public}s dosn't support width of %{public}d and height of %{public}d!",
            codecName_.c_str(), width_, height_);
        ResetData();
        scale_ = nullptr;
        CalculateBufferSize();
        CHECK_AND_RETURN_RET_LOG(inputBufferSize_ > 0 && outputBufferSize_ > 0, AVCS_ERR_INVALID_VAL,
                                 "new buffer with input size=%{public}d, output size=%{public}d failed",
                                 inputBufferSize_, outputBufferSize_);
        PutFormatValue();
        {
            std::lock_guard<std::mutex> sLock(surfaceMutex_);
            if (sInfo_.surface) {
                sInfo_.requestConfig.width = width_;
                sInfo_.requestConfig.height = height_;
            }
        }
        isChanged = true;
    }
    CHECK_AND_RETURN_RET_LOG(CheckStrideChange(index, isChanged), AVCS_ERR_UNKNOWN,
                             "frameBuffer or surfaceMemory is nullptr!");
    return AVCS_ERR_OK;
}

void FCodec::ReleaseBuffers()
{
    ResetData();
    if (!isBufferAllocated_) {
        return;
    }

    inputAvailQue_->Clear();
    std::unique_lock<std::mutex> iLock(inputMutex_);
    buffers_[INDEX_INPUT].clear();
    inputBufferCnt_ = 0u;
    synIndex_ = std::nullopt;
    iLock.unlock();

    codecAvailQue_->Clear();
    if (sInfo_.surface != nullptr) {
        StopRequestSurfaceBufferThread();
        {
            std::lock_guard<std::mutex> mLock(renderBufferMapMutex_);
            renderSurfaceBufferMap_.clear();
        }
        {
            std::lock_guard<std::mutex> sLock(surfaceMutex_);
            sInfo_.surface->CleanCache();
        }
        AVCODEC_LOGI("surface cleancache success");
    }
    std::unique_lock<std::mutex> oLock(outputMutex_);
    buffers_[INDEX_OUTPUT].clear();
    outAVBuffer4Surface_.clear();
    seqNumToFbufMap_.clear();
    outputBufferCnt_ = 0u;
    oLock.unlock();
    isBufferAllocated_ = false;
}

int32_t FCodec::QueueInputBuffer(uint32_t index)
{
    AVCODEC_SYNC_TRACE;
    CHECK_AND_RETURN_RET_LOG(state_ == State::RUNNING, AVCS_ERR_INVALID_STATE,
                             "Queue input buffer failed: not in Running state");
    CHECK_AND_RETURN_RET_LOG(index < buffers_[INDEX_INPUT].size(), AVCS_ERR_INVALID_VAL,
                             "Queue input buffer failed with bad index, index=%{public}u, buffer_size=%{public}zu",
                             index, buffers_[INDEX_INPUT].size());
    std::shared_ptr<FBuffer> inputBuffer = buffers_[INDEX_INPUT][index];
    CHECK_AND_RETURN_RET_LOG(inputBuffer->owner_ == Owner::OWNED_BY_USER, AVCS_ERR_INVALID_OPERATION,
                             "Queue input buffer failed: buffer with index=%{public}u is not available", index);

    inputBuffer->owner_ = Owner::OWNED_BY_CODEC;
    std::shared_ptr<AVBuffer> &inputAVBuffer = inputBuffer->avBuffer_;
    if (synIndex_) {
        const std::shared_ptr<AVBuffer> &curAVBuffer = buffers_[INDEX_INPUT][synIndex_.value()]->avBuffer_;
        int32_t curAVBufferSize = curAVBuffer->memory_->GetSize();
        int32_t inputAVBufferSize = inputAVBuffer->memory_->GetSize();
        if ((curAVBufferSize + inputAVBufferSize <= curAVBuffer->memory_->GetCapacity()) &&
            memcpy_s(curAVBuffer->memory_->GetAddr() + curAVBufferSize, inputAVBufferSize,
                     inputAVBuffer->memory_->GetAddr(), inputAVBufferSize) == EOK) {
            curAVBuffer->memory_->SetSize(curAVBufferSize + inputAVBufferSize);
            curAVBuffer->flag_ = inputAVBuffer->flag_;
            curAVBuffer->pts_ = inputAVBuffer->pts_;

            if (inputAVBuffer->flag_ != AVCODEC_BUFFER_FLAG_CODEC_DATA &&
                inputAVBuffer->flag_ != AVCODEC_BUFFER_FLAG_PARTIAL_FRAME) {
                inputAvailQue_->Push(synIndex_.value());
                synIndex_ = std::nullopt;
            }
            inputBuffer->owner_ = Owner::OWNED_BY_USER;
            callback_->OnInputBufferAvailable(index, inputAVBuffer);
            return AVCS_ERR_OK;
        } else {
            AVCODEC_LOGE("packet size %{public}d over buffer size %{public}d", curAVBufferSize + inputAVBufferSize,
                         curAVBuffer->memory_->GetCapacity());
            callback_->OnError(AVCodecErrorType::AVCODEC_ERROR_INTERNAL, AVCodecServiceErrCode::AVCS_ERR_NO_MEMORY);
            state_ = State::ERROR;
            return AVCS_ERR_NO_MEMORY;
        }
    } else {
        if ((inputAVBuffer->flag_ == AVCODEC_BUFFER_FLAG_CODEC_DATA) ||
            (inputAVBuffer->flag_ == AVCODEC_BUFFER_FLAG_PARTIAL_FRAME)) {
            synIndex_ = index;
        } else {
            inputAvailQue_->Push(index);
        }
    }

    return AVCS_ERR_OK;
}

void FCodec::SendFrame()
{
    CHECK_AND_RETURN_LOG_LIMIT(state_ != State::STOPPING && state_ != State::FLUSHING, LOG_FREQUENCE, "Invalid state");
    if (state_ != State::RUNNING || isSendEos_ || inputAvailQue_->Size() == 0u) {
        std::this_thread::sleep_for(std::chrono::milliseconds(DEFAULT_TRY_DECODE_TIME));
        return;
    }
    uint32_t index = inputAvailQue_->Front();
    CHECK_AND_RETURN_LOG(state_ == State::RUNNING, "Not in running state");
    std::shared_ptr<FBuffer> &inputBuffer = buffers_[INDEX_INPUT][index];
    std::shared_ptr<AVBuffer> &inputAVBuffer = inputBuffer->avBuffer_;
    if (inputAVBuffer->flag_ & AVCODEC_BUFFER_FLAG_EOS) {
        avPacket_->data = nullptr;
        avPacket_->size = 0;
        avPacket_->pts = 0;
        std::unique_lock<std::mutex> sendLock(sendMutex_);
        isSendEos_ = true;
        sendCv_.wait_for(sendLock, std::chrono::milliseconds(DEFAULT_DECODE_WAIT_TIME));
        AVCODEC_LOGI("Send eos end");
    } else {
        avPacket_->data = inputAVBuffer->memory_->GetAddr();
        avPacket_->size = static_cast<int32_t>(inputAVBuffer->memory_->GetSize());
        avPacket_->pts = inputAVBuffer->pts_;
    }
    std::unique_lock<std::mutex> sLock(syncMutex_);
    int ret = avcodec_send_packet(avCodecContext_.get(), avPacket_.get());
    sLock.unlock();
    if (ret == 0 || ret == AVERROR_INVALIDDATA) {
        EXPECT_AND_LOGD(ret == AVERROR_INVALIDDATA, "ffmpeg ret = %{public}s", AVStrError(ret).c_str());
        std::unique_lock<std::mutex> recvLock(recvMutex_);
        recvCv_.notify_one();
        recvLock.unlock();
        inputAvailQue_->Pop();
        inputBuffer->owner_ = Owner::OWNED_BY_USER;
#ifdef BUILD_ENG_VERSION
        if (dumpInFile_ && dumpInFile_->is_open()) {
            dumpInFile_->write(reinterpret_cast<char *>(inputAVBuffer->memory_->GetAddr()),
                               static_cast<int32_t>(inputAVBuffer->memory_->GetSize()));
        }
#endif // BUILD_ENG_VERSION
        callback_->OnInputBufferAvailable(index, inputAVBuffer);
    } else if (ret == AVERROR(EAGAIN)) {
        std::unique_lock<std::mutex> sendLock(sendMutex_);
        isSendWait_ = true;
        sendCv_.wait_for(sendLock, std::chrono::milliseconds(DEFAULT_DECODE_WAIT_TIME));
    } else {
        AVCODEC_LOGE("Cannot send frame to codec: ffmpeg ret = %{public}s", AVStrError(ret).c_str());
        callback_->OnError(AVCodecErrorType::AVCODEC_ERROR_INTERNAL, AVCodecServiceErrCode::AVCS_ERR_UNKNOWN);
        state_ = State::ERROR;
    }
}

int32_t FCodec::FillFrameBuffer(const std::shared_ptr<FBuffer> &frameBuffer)
{
    VideoPixelFormat targetPixelFmt = outputPixelFmt_;
    if (outputPixelFmt_ == VideoPixelFormat::UNKNOWN) {
        targetPixelFmt = VideoPixelFormat::NV12;
    }
    AVPixelFormat ffmpegFormat = ConvertPixelFormatToFFmpeg(targetPixelFmt);
    int32_t ffpixfmt = cachedFrame_->format;
    AVCODEC_LOGD("decode output ffmpeg pixfmt: %{public}d, target output ffmpeg pixfmt: %{public}d", ffpixfmt,
                 static_cast<int32_t>(ffmpegFormat));
    int32_t ret;
    if (ffmpegFormat == static_cast<AVPixelFormat>(ffpixfmt)) {
        for (int32_t i = 0; i < AV_NUM_DATA_POINTERS && cachedFrame_->linesize[i] > 0; i++) {
            scaleData_[i] = cachedFrame_->data[i];
            scaleLineSize_[i] = cachedFrame_->linesize[i];
        }
    } else {
        ret = ConvertVideoFrame(&scale_, cachedFrame_, scaleData_, scaleLineSize_, ffmpegFormat);
        CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, ret, "Scale video frame failed: %{public}d", ret);
        isConverted_ = true;
    }
    {
        std::lock_guard<std::mutex> lock(formatMutex_);
        format_.PutIntValue(FMTKey::VIDEO_PIXEL_FORMAT, static_cast<int32_t>(targetPixelFmt));
        GraphicPixelFormat surfacePixelFmt = TranslateSurfaceFormat(targetPixelFmt);
        format_.PutIntValue(FMTKey::VIDEO_GRAPHIC_PIXEL_FORMAT, static_cast<int32_t>(surfacePixelFmt));
    }
    std::shared_ptr<AVMemory> &bufferMemory = frameBuffer->avBuffer_->memory_;
    CHECK_AND_RETURN_RET_LOG(bufferMemory != nullptr, AVCS_ERR_INVALID_VAL, "bufferMemory is nullptr");
    bufferMemory->SetSize(0);
    if (sInfo_.surface) {
        struct SurfaceInfo surfaceInfo;
        surfaceInfo.surfaceStride = static_cast<uint32_t>(frameBuffer->sMemory_->GetSurfaceBufferStride());
        surfaceInfo.surfaceFence = frameBuffer->sMemory_->GetFence();
        surfaceInfo.scaleData = scaleData_;
        surfaceInfo.scaleLineSize = scaleLineSize_;
        ret = WriteSurfaceData(bufferMemory, surfaceInfo, format_);
    } else {
        ret = WriteBufferData(bufferMemory, scaleData_, scaleLineSize_, format_);
    }
    frameBuffer->avBuffer_->pts_ = cachedFrame_->pts;
    AVCODEC_LOGD("Fill frame buffer successful");
    return ret;
}

void FCodec::FramePostProcess(std::shared_ptr<FBuffer> &frameBuffer, uint32_t index, int32_t status, int ret)
{
    if (status == AVCS_ERR_OK) {
        codecAvailQue_->Pop();
        frameBuffer->owner_ = Owner::OWNED_BY_USER;
        if (sInfo_.surface) {
            outAVBuffer4Surface_[index]->pts_ = frameBuffer->avBuffer_->pts_;
            outAVBuffer4Surface_[index]->flag_ = frameBuffer->avBuffer_->flag_;
        }
        if (ret == AVERROR_EOF) {
            std::unique_lock<std::mutex> sLock(syncMutex_);
            avcodec_flush_buffers(avCodecContext_.get());
            sLock.unlock();
        } else {
            if (isSendWait_) {
                std::lock_guard<std::mutex> sLock(sendMutex_);
                isSendWait_ = false;
                sendCv_.notify_one();
            }
        }
        callback_->OnOutputBufferAvailable(index,
                                           sInfo_.surface ? outAVBuffer4Surface_[index] : frameBuffer->avBuffer_);
    } else if (status == AVCS_ERR_UNSUPPORT) {
        AVCODEC_LOGE("Recevie frame from codec failed: OnError");
        callback_->OnError(AVCodecErrorType::AVCODEC_ERROR_INTERNAL, AVCodecServiceErrCode::AVCS_ERR_UNSUPPORT);
        state_ = State::ERROR;
    } else {
        AVCODEC_LOGE("Recevie frame from codec failed");
        callback_->OnError(AVCodecErrorType::AVCODEC_ERROR_INTERNAL, AVCodecServiceErrCode::AVCS_ERR_UNKNOWN);
        state_ = State::ERROR;
    }
}

#ifdef BUILD_ENG_VERSION
void FCodec::DumpOutputBuffer()
{
    if (!dumpOutFile_ || !dumpOutFile_->is_open()) {
        return;
    }
    for (int32_t i = 0; i < cachedFrame_->height; i++) {
        dumpOutFile_->write(reinterpret_cast<char *>(cachedFrame_->data[0] + i * cachedFrame_->linesize[0]),
                            static_cast<int32_t>(cachedFrame_->width));
    }
    for (int32_t i = 0; i < cachedFrame_->height / 2; i++) { // 2
        dumpOutFile_->write(reinterpret_cast<char *>(cachedFrame_->data[1] + i * cachedFrame_->linesize[1]),
                            static_cast<int32_t>(cachedFrame_->width / 2)); // 2
    }
    for (int32_t i = 0; i < cachedFrame_->height / 2; i++) { // 2
        dumpOutFile_->write(reinterpret_cast<char *>(cachedFrame_->data[2] + i * cachedFrame_->linesize[2]),
                            static_cast<int32_t>(cachedFrame_->width / 2)); // 2
    }
}
#endif // BUILD_ENG_VERSION

#ifndef EMULATOR_ENABLED
void FCodec::GetCropInfo(std::vector<uint8_t> &vec, bool isFmtChanged)
{
    int32_t cropTop = static_cast<int32_t>(cachedFrame_->crop_top);
    int32_t cropBottom = static_cast<int32_t>(cachedFrame_->crop_bottom);
    int32_t cropLeft = static_cast<int32_t>(cachedFrame_->crop_left);
    int32_t cropRight = static_cast<int32_t>(cachedFrame_->crop_right);
    AVCODEC_LOGD("ffmpeg decode crop info top: %{public}d, bottom: %{public}d, left: %{public}d, right: %{public}d",
                 cropTop, cropBottom, cropLeft, cropRight);
    BufferHandleMetaRegion *crop = reinterpret_cast<BufferHandleMetaRegion *>(vec.data());
    crop->left = static_cast<uint32_t>(cropLeft);
    crop->top = static_cast<uint32_t>(cropTop);
    crop->width = static_cast<uint32_t>(width_ - 1);
    crop->height = static_cast<uint32_t>(height_ - 1);
    if (isFmtChanged || decNum_ == 0) {
        std::lock_guard<std::mutex> fLock(formatMutex_);
        format_.PutIntValue(FMTKey::VIDEO_CROP_TOP, cropTop);
        format_.PutIntValue(FMTKey::VIDEO_CROP_BOTTOM, cropBottom);
        format_.PutIntValue(FMTKey::VIDEO_CROP_LEFT, cropLeft);
        format_.PutIntValue(FMTKey::VIDEO_CROP_RIGHT, cropRight);
    }
}

void FCodec::GetColorAspectsInfo(std::vector<uint8_t> &vec, bool isFmtChanged)
{
    AVColorPrimaries colorPrimaries = cachedFrame_->color_primaries;
    AVColorTransferCharacteristic colorTransFunc = cachedFrame_->color_trc;
    AVColorSpace colorMatrix = cachedFrame_->colorspace;
    AVColorRange colorRange = cachedFrame_->color_range;
    AVCODEC_LOGD("ffmpeg color aspects info range: %{public}d, primaries: %{public}d, transferCharacteristic: "
                 "%{public}d, space: %{public}d",
                 static_cast<int32_t>(colorRange), static_cast<int32_t>(colorPrimaries),
                 static_cast<int32_t>(colorTransFunc), static_cast<int32_t>(colorMatrix));
    CM_ColorPrimaries cmColorPrimaries = AVColorPrimariesToCM(colorPrimaries);
    CM_TransFunc cmTrcFunc = AVColorTransferCharacteristicToCM(colorTransFunc);
    CM_Matrix cmMatrix = AVColorSpaceToMatrix(colorMatrix);
    CM_Range cmRange = AVColorRangeToRange(colorRange);
    AVCODEC_LOGD("CM color range: %{public}d, colorprimaries: %{public}d, trans func: %{public}d, matrix: %{public}d",
                 static_cast<int32_t>(cmRange), static_cast<int32_t>(cmColorPrimaries), static_cast<int32_t>(cmTrcFunc),
                 static_cast<int32_t>(cmMatrix));
    CM_ColorSpaceInfo *colorSpaceInfo = reinterpret_cast<CM_ColorSpaceInfo *>(vec.data());
    colorSpaceInfo->primaries = cmColorPrimaries;
    colorSpaceInfo->transfunc = cmTrcFunc;
    colorSpaceInfo->matrix = cmMatrix;
    colorSpaceInfo->range = cmRange;
    int32_t colPrimary = static_cast<int32_t>(CMColorPrimariesToColorPrimary(cmColorPrimaries));
    int32_t colTrcFunc = static_cast<int32_t>(CMTransFuncToTransferCharacteristic(cmTrcFunc));
    int32_t colMatrix = static_cast<int32_t>(CMMatrixToMatrixCoefficient(cmMatrix));
    int32_t colRange = CMRangeToBoolean(cmRange);
    if (isFmtChanged || decNum_ == 0) {
        std::lock_guard<std::mutex> fLock(formatMutex_);
        format_.PutIntValue(FMTKey::VIDEO_COLOR_PRIMARIES, colPrimary);
        format_.PutIntValue(FMTKey::VIDEO_COLOR_TRC, colTrcFunc);
        format_.PutIntValue(FMTKey::VIDEO_COLOR_MATRIX_COEFF, colMatrix);
        format_.PutIntValue(FMTKey::VIDEO_COLOR_RANGE, colRange);
    }
}
#endif

int32_t FCodec::DecodedFrameProcess(uint32_t index)
{
    AVCODEC_LOGD("cur decNum: %{public}u", decNum_);
#ifdef BUILD_ENG_VERSION
    DumpOutputBuffer();
#endif // BUILD_ENG_VERSION
    bool isChanged = false;
    int32_t ret = CheckFormatChange(index, isChanged);
    CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, ret, "Check format change failed");
#ifndef EMULATOR_ENABLED
    std::vector<uint8_t> cropVec(sizeof(BufferHandleMetaRegion));
    std::vector<uint8_t> colorSpaceInfoData(sizeof(CM_ColorSpaceInfo));
    GetCropInfo(cropVec, isChanged);
    GetColorAspectsInfo(colorSpaceInfoData, isChanged);
#endif
    if (decNum_ == 0) {
        callback_->OnOutputFormatChanged(format_);
    }
    if (isChanged) {
        callback_->OnOutputFormatChanged(format_);
    }
    std::unique_lock<std::mutex> oLock(outputMutex_);
    if (sInfo_.surface == nullptr) {
        CHECK_AND_RETURN_RET_LOG((UpdateBuffers(index) == AVCS_ERR_OK), AVCS_ERR_NO_MEMORY,
                                 "Update output buffer failed, index=%{public}u", index);
    } else {
        CHECK_AND_RETURN_RET_LOG((UpdateSurfaceMemory(index) == AVCS_ERR_OK), AVCS_ERR_NO_MEMORY,
                                 "Update buffer failed");
    }
    oLock.unlock();
#ifndef EMULATOR_ENABLED
    std::shared_ptr<FBuffer> frameBuffer = buffers_[INDEX_OUTPUT][index];
    std::shared_ptr<AVMemory> &bufferMemory = frameBuffer->avBuffer_->memory_;
    sptr<SurfaceBuffer> surfacebuffer = bufferMemory->GetSurfaceBuffer();
    CHECK_AND_RETURN_RET_LOG(surfacebuffer != nullptr, AVCS_ERR_UNKNOWN, "surfacebuffer is nullptr");
    GSError err = surfacebuffer->SetMetadata(ATTRKEY_CROP_REGION, cropVec);
    CHECK_AND_RETURN_RET_LOG(err == GSERROR_OK, AVCS_ERR_UNKNOWN, "SetBufferMeta ATTRKEY_CROP_REGION failed");
    err = surfacebuffer->SetMetadata(ATTRKEY_COLORSPACE_INFO, colorSpaceInfoData);
    CHECK_AND_RETURN_RET_LOG(err == GSERROR_OK, AVCS_ERR_UNKNOWN, "SetBufferMeta ATTRKEY_COLORSPACE_INFO failed");
#endif
    decNum_++;
    return AVCS_ERR_OK;
}

void FCodec::ReceiveFrame()
{
    CHECK_AND_RETURN_LOG_LIMIT(state_ != State::STOPPING && state_ != State::FLUSHING, LOG_FREQUENCE, "Invalid state");
    if (state_ != State::RUNNING || codecAvailQue_->Size() == 0u) {
        std::this_thread::sleep_for(std::chrono::milliseconds(DEFAULT_TRY_DECODE_TIME));
        return;
    }
    CHECK_AND_RETURN_LOG(state_ == State::RUNNING, "Not in running state");
    std::unique_lock<std::mutex> sLock(syncMutex_);
    int ret = avcodec_receive_frame(avCodecContext_.get(), cachedFrame_.get());
    sLock.unlock();
    int32_t status = AVCS_ERR_OK;
    auto index = codecAvailQue_->Front();
    std::shared_ptr<FBuffer> frameBuffer = buffers_[INDEX_OUTPUT][index];
    CHECK_AND_RETURN_LOG(ret != AVERROR_INVALIDDATA, "ffmpeg ret = %{public}s", AVStrError(ret).c_str());
    if (ret >= 0) {
        if (DecodedFrameProcess(index) == AVCS_ERR_OK) {
            CHECK_AND_RETURN_LOG(state_ == State::RUNNING, "Not in running state");
            frameBuffer = buffers_[INDEX_OUTPUT][index];
            status = FillFrameBuffer(frameBuffer);
        } else {
            CHECK_AND_RETURN_LOG(state_ == State::RUNNING, "Not in running state");
            callback_->OnError(AVCODEC_ERROR_EXTEND_START, AVCS_ERR_NO_MEMORY);
            state_ = State::ERROR;
            return;
        }
        frameBuffer->avBuffer_->flag_ = AVCODEC_BUFFER_FLAG_NONE;
    } else if (ret == AVERROR_EOF) {
        AVCODEC_LOGI("Receive eos");
        frameBuffer->avBuffer_->flag_ = AVCODEC_BUFFER_FLAG_EOS;
        frameBuffer->avBuffer_->memory_->SetSize(0);
        state_ = State::EOS;
    } else if (ret == AVERROR(EAGAIN)) {
        std::unique_lock<std::mutex> sendLock(sendMutex_);
        if (isSendWait_ || isSendEos_) {
            isSendWait_ = false;
            sendCv_.notify_one();
        }
        sendLock.unlock();
        std::unique_lock<std::mutex> recvLock(recvMutex_);
        recvCv_.wait_for(recvLock, std::chrono::milliseconds(DEFAULT_DECODE_WAIT_TIME));
        return;
    } else {
        AVCODEC_LOGE("Cannot recv frame from codec: ffmpeg ret = %{public}s", AVStrError(ret).c_str());
        callback_->OnError(AVCodecErrorType::AVCODEC_ERROR_INTERNAL, AVCodecServiceErrCode::AVCS_ERR_UNKNOWN);
        state_ = State::ERROR;
        return;
    }
    FramePostProcess(frameBuffer, index, status, ret);
}

int32_t FCodec::ReleaseOutputBuffer(uint32_t index)
{
    AVCODEC_SYNC_TRACE;
    std::unique_lock<std::mutex> oLock(outputMutex_);
    CHECK_AND_RETURN_RET_LOG(index < buffers_[INDEX_OUTPUT].size(), AVCS_ERR_INVALID_VAL,
                             "Failed to release output buffer: invalid index");
    std::shared_ptr<FBuffer> frameBuffer = buffers_[INDEX_OUTPUT][index];
    oLock.unlock();
    if (frameBuffer->owner_ == Owner::OWNED_BY_USER) {
        frameBuffer->owner_ = Owner::OWNED_BY_CODEC;
        codecAvailQue_->Push(index);
        return AVCS_ERR_OK;
    } else {
        AVCODEC_LOGE("Release output buffer failed: check your index=%{public}u", index);
        return AVCS_ERR_INVALID_VAL;
    }
}

int32_t FCodec::Attach(sptr<SurfaceBuffer> surfaceBuffer)
{
    std::lock_guard<std::mutex> sLock(surfaceMutex_);
    int32_t err = sInfo_.surface->AttachBufferToQueue(surfaceBuffer);
    CHECK_AND_RETURN_RET_LOG(
        err == 0, err, "Surface(%{public}" PRIu64 "), attach buffer(%{public}u) to queue failed, GSError=%{public}d",
        sInfo_.surface->GetUniqueId(), surfaceBuffer->GetSeqNum(), err);
    return AVCS_ERR_OK;
}

int32_t FCodec::Detach(sptr<SurfaceBuffer> surfaceBuffer)
{
    std::lock_guard<std::mutex> sLock(surfaceMutex_);
    int32_t err = sInfo_.surface->DetachBufferFromQueue(surfaceBuffer);
    CHECK_AND_RETURN_RET_LOG(
        err == 0, err, "Surface(%{public}" PRIu64 "), detach buffer(%{public}u) to queue failed, GSError=%{public}d",
        sInfo_.surface->GetUniqueId(), surfaceBuffer->GetSeqNum(), err);
    return AVCS_ERR_OK;
}

int32_t FCodec::FlushSurfaceMemory(std::shared_ptr<FSurfaceMemory> &surfaceMemory, uint32_t index)
{
    sptr<SurfaceBuffer> surfaceBuffer = surfaceMemory->GetSurfaceBuffer();
    CHECK_AND_RETURN_RET_LOG(surfaceBuffer != nullptr, AVCS_ERR_UNKNOWN, "Get surface buffer failed!");
    if (!surfaceMemory->isAttached) {
        int32_t ret = Attach(surfaceBuffer);
        CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, ret, "Surface buffer attach failed!");
        surfaceMemory->isAttached = true;
    }
    OHOS::BufferFlushConfig flushConfig = {{0, 0, surfaceBuffer->GetWidth(), surfaceBuffer->GetHeight()},
        outAVBuffer4Surface_[index]->pts_, -1};
    if (outAVBuffer4Surface_[index]->meta_->Find(FMTKey::VIDEO_DECODER_DESIRED_PRESENT_TIMESTAMP) !=
        outAVBuffer4Surface_[index]->meta_->end()) {
        outAVBuffer4Surface_[index]->meta_->Get<FMTKey::VIDEO_DECODER_DESIRED_PRESENT_TIMESTAMP>(
            flushConfig.desiredPresentTimestamp);
        outAVBuffer4Surface_[index]->meta_->Remove(FMTKey::VIDEO_DECODER_DESIRED_PRESENT_TIMESTAMP);
    }
    GSError res = GSERROR_OK;
    {
        std::lock_guard<std::mutex> sLock(surfaceMutex_);
        res = sInfo_.surface->FlushBuffer(surfaceBuffer, -1, flushConfig);
    }
    if (res == GSERROR_BUFFER_NOT_INCACHE) {
        AVCODEC_LOGW("Surface(%{public}" PRIu64 "), flush buffer(seq=%{public}u) failed, try to recover",
                     sInfo_.surface->GetUniqueId(), surfaceBuffer->GetSeqNum());
        int32_t ret = ClearSurfaceAndSetQueueSize();
        CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, ret, "Clean surface and set queue size failed!");
        ret = Attach(surfaceBuffer);
        CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, ret, "Surface buffer attach failed!");
        surfaceMemory->isAttached = true;
        std::lock_guard<std::mutex> sLock(surfaceMutex_);
        res = sInfo_.surface->FlushBuffer(surfaceBuffer, -1, flushConfig);
    }
    if (res != OHOS::SurfaceError::SURFACE_ERROR_OK) {
        AVCODEC_LOGW("Failed to update surface memory: %{public}d", res);
        return AVCS_ERR_UNKNOWN;
    }
    surfaceMemory->owner = Owner::OWNED_BY_SURFACE;
    {
        std::lock_guard<std::mutex> mLock(renderBufferMapMutex_);
        renderSurfaceBufferMap_[index] = std::make_pair(surfaceBuffer, flushConfig);
    }
    return AVCS_ERR_OK;
}

int32_t FCodec::RenderOutputBuffer(uint32_t index)
{
    AVCODEC_SYNC_TRACE;
    CHECK_AND_RETURN_RET_LOG(sInfo_.surface != nullptr, AVCS_ERR_UNSUPPORT,
                             "Render output buffer failed, surface is nullptr!");
    std::unique_lock<std::mutex> oLock(outputMutex_);
    CHECK_AND_RETURN_RET_LOG(index < buffers_[INDEX_OUTPUT].size(), AVCS_ERR_INVALID_VAL,
                             "Failed to render output buffer: invalid index");
    std::shared_ptr<FBuffer> frameBuffer = buffers_[INDEX_OUTPUT][index];
    oLock.unlock();
    std::shared_ptr<AVMemory> &bufferMemory = frameBuffer->avBuffer_->memory_;
    CHECK_AND_RETURN_RET_LOG(bufferMemory != nullptr, AVCS_ERR_INVALID_VAL, "bufferMemory is nullptr");
    int32_t size = bufferMemory->GetSize();
    CHECK_AND_RETURN_RET_LOGW(size > 0, AVCS_ERR_OK, "buf(%{public}u) size=%{public}d", index, size);
    if (frameBuffer->owner_ == Owner::OWNED_BY_USER) {
        std::shared_ptr<FSurfaceMemory> surfaceMemory = frameBuffer->sMemory_;
        int32_t ret = FlushSurfaceMemory(surfaceMemory, index);
        EXPECT_AND_LOGW(ret != AVCS_ERR_OK, "Flush surface memory(index=%{public}u) failed: %{public}d", index, ret);
        frameBuffer->owner_ = Owner::OWNED_BY_SURFACE;
        AVCODEC_LOGD("Render output buffer with index, index=%{public}u", index);
        return AVCS_ERR_OK;
    } else {
        AVCODEC_LOGE("Failed to render outbuf(%{public}u), owner=%{public}d", index, frameBuffer->owner_.load());
        return AVCS_ERR_INVALID_VAL;
    }
}

int32_t FCodec::ReplaceOutputSurfaceWhenRunning(sptr<Surface> newSurface)
{
    CHECK_AND_RETURN_RET_LOG(sInfo_.surface != nullptr, AV_ERR_OPERATE_NOT_PERMIT,
                             "Not support convert from AVBuffer Mode to Surface Mode");
    sptr<Surface> oldSurface = sInfo_.surface;
    uint64_t oldId = oldSurface->GetUniqueId();
    uint64_t newId = newSurface->GetUniqueId();
    AVCODEC_LOGI("Begin to switch surface %{public}" PRIu64 " -> %{public}" PRIu64 ".", oldId, newId);
    if (oldId == newId) {
        return AVCS_ERR_OK;
    }
    int32_t ret = RegisterListenerToSurface(newSurface);
    CHECK_AND_RETURN_RET_LOG(ret == GSERROR_OK, ret,
        "surface %{public}" PRIu64 ", RegisterListenerToSurface failed, GSError=%{public}d", newId, ret);
    int32_t outputBufferCnt = 0;
    CHECK_AND_RETURN_RET_LOG(
        format_.GetIntValue(FMTKey::REQUIRED_OUT_BUFFER_CNT, outputBufferCnt) &&
        outputBufferCnt >= DEFAULT_MIN_BUFFER_CNT, AVCS_ERR_INVALID_VAL,
        "Invalid output buffer cnt: %{public}d", outputBufferCnt);
    ret = SetQueueSize(newSurface, static_cast<uint32_t>(outputBufferCnt));
    if (ret != AVCS_ERR_OK) {
        UnRegisterListenerToSurface(newSurface);
        return ret;
    }
    std::unique_lock<std::mutex> sLock(surfaceMutex_);
    ret = SwitchBetweenSurface(newSurface);
    if (ret != AVCS_ERR_OK) {
        UnRegisterListenerToSurface(newSurface);
        sInfo_.surface = oldSurface;
        CombineConsumerUsage();
        return ret;
    }
    sLock.unlock();
    AVCODEC_LOGI("Switch surface %{public}" PRIu64 " -> %{public}" PRIu64 ".", oldId, newId);
    return AVCS_ERR_OK;
}

int32_t FCodec::SetQueueSize(const sptr<Surface> &surface, uint32_t targetSize)
{
    uint64_t surfaceId = surface->GetUniqueId();
    int32_t err = surface->SetQueueSize(targetSize);
    CHECK_AND_RETURN_RET_LOG(err == 0, err,
                             "Surface(%{public}" PRIu64 ") set queue size %{public}u failed, GSError=%{public}d",
                             surfaceId, targetSize, err);
    AVCODEC_LOGI("Surface(%{public}" PRIu64 ") set queue size %{public}u succss.", surfaceId, targetSize);
    return AVCS_ERR_OK;
}

int32_t FCodec::SwitchBetweenSurface(const sptr<Surface> &newSurface)
{
    newSurface->Connect(); // cleancache will work only if the surface is connected by us
    newSurface->CleanCache(); // make sure new surface is empty
    newSurface->Disconnect();
    std::vector<uint32_t> ownedBySurfaceBufferIndex;
    uint64_t newId = newSurface->GetUniqueId();
    for (uint32_t index = 0; index < buffers_[INDEX_OUTPUT].size(); index++) {
        if (buffers_[INDEX_OUTPUT][index]->sMemory_ == nullptr) {
            continue;
        }
        sptr<SurfaceBuffer> surfaceBuffer = nullptr;
        if (buffers_[INDEX_OUTPUT][index]->owner_ == Owner::OWNED_BY_SURFACE) {
            std::lock_guard<std::mutex> mLock(renderBufferMapMutex_);
            if (renderSurfaceBufferMap_.count(index)) {
                surfaceBuffer = renderSurfaceBufferMap_[index].first;
                ownedBySurfaceBufferIndex.push_back(index);
            }
        } else {
            surfaceBuffer = buffers_[INDEX_OUTPUT][index]->sMemory_->GetSurfaceBuffer();
        }
        CHECK_AND_RETURN_RET_LOG(surfaceBuffer != nullptr, AVCS_ERR_UNKNOWN, "Get old surface buffer error!");
        int32_t err = newSurface->AttachBufferToQueue(surfaceBuffer);
        CHECK_AND_RETURN_RET_LOG(
            err == 0, err, "surface(%{public}" PRIu64 ")attach buffer(seq=%{public}u) to queue failed,"
            "GSError=%{public}d", newId, surfaceBuffer->GetSeqNum(), err);
        buffers_[INDEX_OUTPUT][index]->sMemory_->isAttached = true;
    }
    newSurface->SetTransform(transform_);
    sptr<Surface> curSurface = sInfo_.surface;
    sInfo_.surface = newSurface;
    CombineConsumerUsage();
    for (uint32_t index: ownedBySurfaceBufferIndex) {
        int32_t ret = RenderNewSurfaceWithOldBuffer(newSurface, index);
        CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, ret, "Old surface buffer render failed!");
    }
    UnRegisterListenerToSurface(curSurface);
    curSurface->SetTransform(GRAPHIC_ROTATE_NONE);
    curSurface->CleanCache(true); // make sure old surface is empty and go black
    return AVCS_ERR_OK;
}

int32_t FCodec::RenderNewSurfaceWithOldBuffer(const sptr<Surface> &newSurface, uint32_t index)
{
    std::unique_lock<std::mutex> mLock(renderBufferMapMutex_);
    sptr<SurfaceBuffer> surfaceBuffer = renderSurfaceBufferMap_[index].first;
    OHOS::BufferFlushConfig flushConfig = renderSurfaceBufferMap_[index].second;
    mLock.unlock();
    if (sInfo_.scalingMode) {
        newSurface->SetScalingMode(surfaceBuffer->GetSeqNum(), static_cast<ScalingMode>(sInfo_.scalingMode.value()));
    }
    auto res = newSurface->FlushBuffer(surfaceBuffer, -1, flushConfig);
    if (res != OHOS::SurfaceError::SURFACE_ERROR_OK) {
        AVCODEC_LOGE("Failed to update surface memory: %{public}d", res);
        return AVCS_ERR_UNKNOWN;
    }
    return AVCS_ERR_OK;
}

GSError FCodec::BufferReleasedByConsumer(uint64_t surfaceId)
{
    CHECK_AND_RETURN_RET_LOG(state_ == State::RUNNING || state_ == State::EOS || state_ == State::FLUSHING ||
                             state_ == State::FLUSHED, GSERROR_NO_PERMISSION, "Invalid state");
    std::unique_lock<std::mutex> sLock(surfaceMutex_);
    CHECK_AND_RETURN_RET_LOG(surfaceId == sInfo_.surface->GetUniqueId(), GSERROR_INVALID_ARGUMENTS,
                             "Ignore callback from old surface");
    sLock.unlock();
    RequestSurfaceBufferOnce();
    return GSERROR_OK;
}

void FCodec::UnRegisterListenerToSurface(const sptr<Surface> &surface)
{
    CHECK_AND_RETURN_LOGW(surface != nullptr, "Surface is null, not need to unregister listener.");
    SurfaceTools::GetInstance().ReleaseSurface(instanceId_, surface, false);
}

int32_t FCodec::RegisterListenerToSurface(const sptr<Surface> &surface)
{
    uint64_t surfaceId = surface->GetUniqueId();
    wptr<FCodec> wp = this;
    bool ret =
        SurfaceTools::GetInstance().RegisterReleaseListener(instanceId_, surface,
            [wp, surfaceId](sptr<SurfaceBuffer> &) {
                sptr<FCodec> codec = wp.promote();
                if (!codec) {
                    AVCODEC_LOGD("decoder is nullptr");
                    return GSERROR_OK;
                }
                return codec->BufferReleasedByConsumer(surfaceId);
            });
    CHECK_AND_RETURN_RET_LOG(ret, AVCS_ERR_UNKNOWN, "surface(%" PRIu64 ") register listener failed", surfaceId);
    return AVCS_ERR_OK;
}

void FCodec::CombineConsumerUsage()
{
    uint64_t defaultUsage = SURFACE_DEFAULT_USAGE;
    uint64_t consumerUsage = sInfo_.surface->GetDefaultUsage();
    uint64_t cfgedUsage = sInfo_.requestConfig.usage;
    uint64_t finalUsage = defaultUsage | consumerUsage | cfgedUsage;
    sInfo_.requestConfig.usage = finalUsage;
    AVCODEC_LOGI("Usage: default(0x%{public}" PRIu64 ") | consumer(0x%{public}" PRIu64 ") | cfged(0x%{public}" PRIu64
                 ") -> final(0x%{public}" PRIu64 ").",
                 defaultUsage, consumerUsage, cfgedUsage, finalUsage);
}

int32_t FCodec::SetOutputSurface(sptr<Surface> surface)
{
    AVCODEC_SYNC_TRACE;
    CHECK_AND_RETURN_RET_LOG(state_ != State::UNINITIALIZED, AV_ERR_INVALID_VAL,
                             "set output surface fail: not initialized or configured");
    CHECK_AND_RETURN_RET_LOG((state_ == State::CONFIGURED || state_ == State::FLUSHED ||
        state_ == State::RUNNING || state_ == State::EOS), AVCS_ERR_INVALID_STATE,
        "set output surface fail: state %{public}d not support set output surface",
        static_cast<int32_t>(state_.load()));
    if (surface == nullptr || surface->IsConsumer()) {
        AVCODEC_LOGE("Set surface fail");
        return AVCS_ERR_INVALID_VAL;
    }
    if (state_ == State::FLUSHED || state_ == State::RUNNING || state_ == State::EOS) {
        return ReplaceOutputSurfaceWhenRunning(surface);
    }
    UnRegisterListenerToSurface(sInfo_.surface);
    uint64_t surfaceId = surface->GetUniqueId();
    sInfo_.surface = surface;
    CombineConsumerUsage();
    int32_t ret = RegisterListenerToSurface(sInfo_.surface);
    CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, ret,
                             "surface(%{public}" PRIu64 ") register listener to surface failed, GSError=%{public}d",
                             sInfo_.surface->GetUniqueId(), ret);
    AVCODEC_LOGI("%{public}s Set surface(%{public}" PRIu64 ") success.", decName_.c_str(), surfaceId);
    return AVCS_ERR_OK;
}

int32_t FCodec::SetCallback(const std::shared_ptr<MediaCodecCallback> &callback)
{
    AVCODEC_SYNC_TRACE;
    CHECK_AND_RETURN_RET_LOG(callback != nullptr, AVCS_ERR_INVALID_VAL, "Set callback failed: callback is NULL");
    callback_ = callback;
    return AVCS_ERR_OK;
}

// for memory recycle
bool FCodec::CanSwapOut(bool isOutputBuffer, std::shared_ptr<FBuffer> &fBuffer)
{
    if (!isOutputBuffer) {
        AVCODEC_LOGD("Current buffers unsupport.");
        return false;
    }
    std::shared_ptr<FSurfaceMemory> surfaceMemory = fBuffer->sMemory_;
    CHECK_AND_RETURN_RET_LOGD(surfaceMemory != nullptr, false, "Current buffer->sMemory error!");
    Owner ownerValue = surfaceMemory->owner;
    AVCODEC_LOGD("Buffer type: [%{public}u], fBuffer->owner_: [%{public}d], fBuffer->hasSwapedOut_: [%{public}d].",
                 isOutputBuffer, ownerValue, fBuffer->hasSwapedOut_.load());
    return !(ownerValue == Owner::OWNED_BY_SURFACE || fBuffer->hasSwapedOut_);
}

int32_t FCodec::SwapOutBuffers(bool isOutputBuffer, State curState)
{
    uint32_t bufferType = isOutputBuffer ? INDEX_OUTPUT : INDEX_INPUT;
    CHECK_AND_RETURN_RET_LOGD(bufferType == INDEX_OUTPUT, AVCS_ERR_OK, "Input buffers can't be swapped out!");
    for (uint32_t i = 0u; i < buffers_[bufferType].size(); i++) {
        std::shared_ptr<FBuffer> fBuffer = buffers_[bufferType][i];
        if (!CanSwapOut(isOutputBuffer, fBuffer)) {
            AVCODEC_LOGW("Buf: [%{public}u] can't freeze, owner: [%{public}d] swaped out: [%{public}d]!", i,
                         fBuffer->owner_.load(), fBuffer->hasSwapedOut_.load());
            continue;
        }
        std::shared_ptr<FSurfaceMemory> surfaceMemory = fBuffer->sMemory_;
        CHECK_AND_RETURN_RET_LOG(surfaceMemory != nullptr, AVCS_ERR_UNKNOWN, "Buf[%{public}u]->sMemory error!", i);
        sptr<SurfaceBuffer> surfaceBuffer = surfaceMemory->GetSurfaceBuffer();
        CHECK_AND_RETURN_RET_LOG(surfaceBuffer != nullptr, AVCS_ERR_UNKNOWN, "Buf[%{public}u]->surfaceBuf error!", i);
        int32_t fd = surfaceBuffer->GetFileDescriptor();
        int32_t ret = DmaSwaper::GetInstance().SwapOutDma(pid_, fd);
        if (ret != AVCS_ERR_OK) {
            AVCODEC_LOGE("Buffer type[%{public}u] bufferId[%{public}u], fd[%{public}d], pid[%{public}d] freeze failed!",
                         bufferType, i, fd, pid_);
            int32_t errCode = ActiveBuffers();
            state_ = curState;
            CHECK_AND_RETURN_RET_LOG(errCode == AVCS_ERR_OK, errCode, "Active buffers failed!");
            return ret;
        }
        AVCODEC_LOGI("Buf[%{public}u] fd[%{public}u] swap out success!", i, fd);
        fBuffer->hasSwapedOut_ = true;
    }
    return AVCS_ERR_OK;
}

int32_t FCodec::SwapInBuffers(bool isOutputBuffer)
{
    uint32_t bufferType = isOutputBuffer ? INDEX_OUTPUT : INDEX_INPUT;
    CHECK_AND_RETURN_RET_LOGD(bufferType == INDEX_OUTPUT, AVCS_ERR_OK, "Input buffers can't be swapped in!");
    for (uint32_t i = 0u; i < buffers_[bufferType].size(); i++) {
        std::shared_ptr<FBuffer> fBuffer = buffers_[bufferType][i];
        if (!fBuffer->hasSwapedOut_) {
            continue;
        }
        std::shared_ptr<FSurfaceMemory> surfaceMemory = fBuffer->sMemory_;
        CHECK_AND_CONTINUE_LOG(surfaceMemory != nullptr, "Buf[%{public}u]->sMemory error!", i);
        sptr<SurfaceBuffer> surfaceBuffer = surfaceMemory->GetSurfaceBuffer();
        CHECK_AND_CONTINUE_LOG(surfaceBuffer != nullptr, "Buf[%{public}u]->surfaceBuf error!", i);
        int32_t fd = surfaceBuffer->GetFileDescriptor();
        int32_t ret = DmaSwaper::GetInstance().SwapInDma(pid_, fd);
        CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, ret, "Buf[%{public}u] fd[%{public}u] swap in error!", i, fd);
        AVCODEC_LOGI("Buf[%{public}u] fd[%{public}u] swap in success!", i, fd);
        fBuffer->hasSwapedOut_ = false;
    }
    return AVCS_ERR_OK;
}

int32_t FCodec::FreezeBuffers(State curState)
{
    CHECK_AND_RETURN_RET_LOGD(state_ != State::FROZEN, AVCS_ERR_OK, "FCodec had been frozen!");
    std::lock_guard<std::mutex> sLock(surfaceMutex_);
    int32_t ret = SwapOutBuffers(INDEX_INPUT, curState);
    CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, ret, "Input buffers swap out failed!");
    ret = SwapOutBuffers(INDEX_OUTPUT, curState);
    CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, ret, "Output buffers swap out failed!");
    return AVCS_ERR_OK;
}

int32_t FCodec::ActiveBuffers()
{
    CHECK_AND_RETURN_RET_LOGD(state_ == State::FREEZING || state_ == State::FROZEN, AVCS_ERR_INVALID_STATE,
                              "Only freezing or frozen state can swap in dma buffer!");
    int32_t ret = SwapInBuffers(INDEX_INPUT);
    CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, ret, "Input buffers swap in failed!");
    ret = SwapInBuffers(INDEX_OUTPUT);
    CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, ret, "Output buffers swap in failed!");
    return AVCS_ERR_OK;
}

int32_t FCodec::NotifyMemoryRecycle()
{
    CHECK_AND_RETURN_RET_LOG(sInfo_.surface != nullptr, AVCS_ERR_UNKNOWN, "Only surface mode support!");
    CHECK_AND_RETURN_RET_LOGD(state_ == State::RUNNING || state_ == State::FLUSHED || state_ == State::EOS,
                              AVCS_ERR_INVALID_STATE, "Current state can't recycle memory!");
    AVCODEC_LOGI("Begin to freeze this codec!");
    State currentState = state_;
    state_ = State::FREEZING;
    int32_t errCode = FreezeBuffers(currentState);
    CHECK_AND_RETURN_RET_LOG(errCode == AVCS_ERR_OK, errCode, "Fcodec freeze buffers failed!");
    state_ = State::FROZEN;
    return AVCS_ERR_OK;
}

int32_t FCodec::NotifyMemoryWriteBack()
{
    CHECK_AND_RETURN_RET_LOG(sInfo_.surface != nullptr, AVCS_ERR_UNKNOWN, "Only surface mode support!");
    AVCODEC_LOGI("Begin to active this codec!");
    int32_t errCode = ActiveBuffers();
    CHECK_AND_RETURN_RET_LOG(errCode == AVCS_ERR_OK, errCode, "Fcodec active buffers failed!");
    state_ = State::RUNNING;
    return AVCS_ERR_OK;
}
} // namespace Codec
} // namespace MediaAVCodec
} // namespace OHOS