/**
 * 视频流解码引擎
 * */

#include "VideoDecodeEngine.h"

using namespace std;
using namespace cv;
using namespace ai_matrix;

VideoDecodeEngine::VideoDecodeEngine() {}

VideoDecodeEngine::~VideoDecodeEngine() {}

APP_ERROR VideoDecodeEngine::Init()
{
    bUseEngine_ = true;
    dataSourceConfig_ = MyYaml::GetIns()->GetDataSourceConfigById(engineId_); // 获取摄像机参数

    strPort0_ = engineName_ + "_" + std::to_string(engineId_) + "_0";
    if (MyYaml::GetIns()->GetStringValue("gc_data_source") != "camera" || !dataSourceConfig_.bUse)
    {
        bUseEngine_ = false;
        LogWarn << "engineId_:" << engineId_ << " not use engine";
        return APP_ERR_OK;
    }

    LogInfo << "VideoDecodeEngine Init ok";
    return APP_ERR_OK;
}

APP_ERROR VideoDecodeEngine::DeInit()
{
    if (!bUseEngine_)
    {
        LogWarn << "engineId_:" << engineId_ << " not use engine";
        return APP_ERR_OK;
    }

    if (hard_h264_ffmpeg_decoder_ != nullptr)
    {
        hard_h264_ffmpeg_decoder_->HardH264FFmpegDecoderDeInit();
        delete hard_h264_ffmpeg_decoder_;
        hard_h264_ffmpeg_decoder_ = nullptr;
    }
    LogInfo << "VideoDecodeEngine DeInit ok";
    return APP_ERR_OK;
}

APP_ERROR VideoDecodeEngine::Process()
{
    if (!bUseEngine_)
    {
        LogWarn << "engineId_:" << engineId_ << " not use engine";
        return APP_ERR_OK;
    }

    int iRet = APP_ERR_OK;
	int iSkipCount = 1;
    int iNoCameraDataCnt = 0;
    while (!isStop_)
    {
        try
        {
            //从上一引擎接收图像数据
            std::shared_ptr<void> pVoidData0 = nullptr;
            inputQueMap_[strPort0_]->pop(pVoidData0);
            if (nullptr == pVoidData0)
            {
                usleep(10*1000); //10ms

//                iNoCameraDataCnt++;
//                if (iNoCameraDataCnt >= 1000) //10秒内收不到，认为相机断开
//                {
//                    LogError << "engineId:" << engineId_ << " 超过10秒获取到摄像头数据，疑似摄像头断开。计数：" << iNoCameraDataCnt;
//                    iNoCameraDataCnt = 0;
//                    //camera异常时，构造空的解码数据push，确保一直有数据流转到后面Engine
//                    std::shared_ptr<ProcessData> pProcessData = std::make_shared<ProcessData>();
//                    pProcessData->iDataSource = engineId_;
//                    pProcessData->i64TimeStamp = MyUtils::getins()->GetCurrentTimeMillis();
//                    pProcessData->iSize = 0;
//                    pProcessData->pData = nullptr;
//                    iRet = outputQueMap_[strPort0_]->push(std::static_pointer_cast<void>(pProcessData));
//                }

                continue;
            }

            iNoCameraDataCnt = 0;
            std::shared_ptr<ProcessData> pProcessData = std::static_pointer_cast<ProcessData>(pVoidData0);

            //创建解码类
            if (hard_h264_ffmpeg_decoder_ == nullptr)
            {
                hard_h264_ffmpeg_decoder_ = new HardH264FFmpegDecode;
                int iRet = hard_h264_ffmpeg_decoder_->HardH264FFmpegDecoderInit(pProcessData->iWidth, pProcessData->iHeight, pProcessData->iRate);
                if (iRet != 0)
                {
                    LogError << "engineId:" << engineId_ << " HardH264FFmpegDecoderInit Failed";
                    if (hard_h264_ffmpeg_decoder_ != nullptr)
                    {
                        delete hard_h264_ffmpeg_decoder_;
                        hard_h264_ffmpeg_decoder_ = nullptr;
                    }
                    continue;
                }
            }

            //构造YUV420M数据
            unsigned int pYUV420MBuffer_Size = pProcessData->iWidth * pProcessData->iHeight * 3 / 2;
            void *pYUV420MBuffer = nullptr;
            pYUV420MBuffer = new uint8_t[pYUV420MBuffer_Size];
            std::shared_ptr<void> pYUVData;
            pYUVData.reset(pYUV420MBuffer, [](void *data){if(data) {delete[] data; data = nullptr;}}); //智能指针管理内存

            hard_h264_ffmpeg_decoder_->pPacket_->data = static_cast<uint8_t *>(pProcessData->pData.get());	//这里填入一个指向完整H264数据帧的指针
            hard_h264_ffmpeg_decoder_->pPacket_->size = pProcessData->iSize;	//这个填入H264数据帧的大小

            // H264硬件解码
            int iDecodeRet= hard_h264_ffmpeg_decoder_->HardH264FFmpegDecoderV2(hard_h264_ffmpeg_decoder_->pCodecCtx_,
                                                                               hard_h264_ffmpeg_decoder_->pFrame_,
                                                                               hard_h264_ffmpeg_decoder_->pPacket_,
                                                                               pYUV420MBuffer,
                                                                               &pYUV420MBuffer_Size);

            // int iDecodeRet = hard_h264_ffmpeg_decoder_->HardH264FFmpegDecoderV2(hard_h264_ffmpeg_decoder_->pCodecCtx_,
            //                                                                     hard_h264_ffmpeg_decoder_->pSwsContext_,
            //                                                                     hard_h264_ffmpeg_decoder_->pSrcFrame_,
            //                                                                     hard_h264_ffmpeg_decoder_->pDstFrame_,
            //                                                                     hard_h264_ffmpeg_decoder_->pPacket_,
            //                                                                     pYUV420MBuffer,
            //                                                                     &pYUV420MBuffer_Size);

            if (iDecodeRet > 0)
            {
                if (iSkipCount++ % dataSourceConfig_.iSkipInterval != 0)
                {
                    continue;
                }
                iSkipCount = 1;

                //硬解码YUV转BGR
                cv::Mat matYUV(pProcessData->iHeight * 3 / 2, pProcessData->iWidth, CV_8UC1);
                memcpy(matYUV.data, static_cast<uint8_t *>(pYUVData.get()), pYUV420MBuffer_Size);

                cv::Mat matBGR(pProcessData->iHeight, pProcessData->iWidth, CV_8UC3);
                cv::cvtColor(matYUV, matBGR, cv::COLOR_YUV2BGR_I420);
                cv::resize(matBGR, matBGR, cv::Size(IMAGE_WIDTH, IMAGE_HEIGHT));
                unsigned int iResizeSize = IMAGE_WIDTH * IMAGE_HEIGHT * 3;
                void *pResizeBGRBuffer = nullptr;
                pResizeBGRBuffer = new uint8_t[iResizeSize];
                memcpy(pResizeBGRBuffer, matBGR.data, iResizeSize);
                pProcessData->pData.reset(pResizeBGRBuffer, [](void *data) {if(data) {delete[] data; data = nullptr;} });
                pProcessData->iSize = iResizeSize;
                pProcessData->iWidth = IMAGE_WIDTH;
                pProcessData->iHeight = IMAGE_HEIGHT;

                iRet = outputQueMap_[strPort0_]->push(std::static_pointer_cast<void>(pProcessData));
                if (iRet != APP_ERR_OK)
                {
                    LogError << "push the after hard h264 decode yuv420m frame data failed...";
                }
            }
            else if (iDecodeRet == -1)
            {
                // 视频结束  或者  数据量不足  一般为正常情况
            }
            else
            {
                LogError << "engineId:" << engineId_ << " HardH264FFmpegDecoderV2 failed...iDecodeRet:" << iDecodeRet;
                if (hard_h264_ffmpeg_decoder_ != nullptr)
                {
                    hard_h264_ffmpeg_decoder_->HardH264FFmpegDecoderDeInit();
                    delete hard_h264_ffmpeg_decoder_;
                    hard_h264_ffmpeg_decoder_ = nullptr;
                }
            }
        }
        catch(const std::exception& e)
        {
            LogError << "解码异常！报警：" << e.what();
            if (hard_h264_ffmpeg_decoder_ != nullptr)
            {
                hard_h264_ffmpeg_decoder_->HardH264FFmpegDecoderDeInit();
                delete hard_h264_ffmpeg_decoder_;
                hard_h264_ffmpeg_decoder_ = nullptr;
            }
        }
    }
}

