更新时间:2021-03-18 GMT+08:00
分享

实现VDEC功能

对于一个视频码流,调用一次CreateVdecApi接口创建实例后,必须使用同一个实例调用VdecCtl接口进行视频解码,最后再调用一次DestroyVdecApi接口释放实例。

在视频解码时,如果需要从一个视频码流切换到另一个视频码流,则需要先调用DestroyVdecApi接口释放前一个码流的实例,再调用CreateVdecApi接口创建新的实例,用于处理新的视频码流。

此调用示例是读取文件名为“test_file”的h264码流文件,调用VDEC功能,将解码结果存放到“output_dir”目录。

// 自定义子类
class HIAI_DATA_SP_SON: public HIAI_DATA_SP {
public:
    ~ HIAI_DATA_SP_SON ()
    {
        //destruct here;
    }
    // 用户自定义新增一些成员函数,以用户需求为准,下述新增成员函数仅为示例    
    uint8_t GetTotalFrameNum()        
    {            
        return info_.totalFrameNum;        
    }   
	
private:        
    // 用户自定义一些成员变量,以用户需求为准,下述新增成员变量结构体info_仅为示例     
    struct INFO {            
        uint8_t totalFrameNum;            
        uint8_t frameRate;        
    }info_;
};
 
IDVPPAPI * pidvppapi_vpc = NULL; 
IDVPPAPI * pidvppapi_vdec = NULL;
 
//回调函数举例,调用方需根据自己的需求来重新定义回调函数
void FrameReturn(FRAME* frame, void* hiaiData)
{
    static int32_t imageCount = 0;
    imageCount++;
    HIAI_ENGINE_LOG("call save frame number:[%d], width:[%d], height:[%d]", imageCount, frame->width, frame->height);
    // The image directly output by vdec is an image of hfbc compression format, which cannot be directly displayed.
    // It is necessary to call vpc to convert hfbc to an image of uncompressed format to display.
    HIAI_ENGINE_LOG("start call vpc interface to translate hfbc.");
    IDVPPAPI* dvppHandle = nullptr;
    int32_t ret = CreateDvppApi(dvppHandle);
    if (ret != 0) {
        HIAI_ENGINE_LOG(HIAI_CREATE_DVPP_ERROR, "creat dvpp api fail.");
        return;
    }

    // Construct vpc input configuration.
    std::shared_ptr<VpcUserImageConfigure> userImage(new VpcUserImageConfigure);
    // bareDataAddr should be null which the image is hfbc.
    userImage->bareDataAddr = nullptr;
    userImage->bareDataBufferSize = 0;
    userImage->widthStride = frame->width;
    userImage->heightStride = frame->height;
    // Configuration input format
    string imageFormat(frame->image_format);
    if (frame->bitdepth == 8) {
        if (imageFormat == "nv12") {
            userImage->inputFormat = INPUT_YUV420_SEMI_PLANNER_UV;
        } else {
            userImage->inputFormat = INPUT_YUV420_SEMI_PLANNER_VU;
        }
    } else {
        if (imageFormat == "nv12") {
            userImage->inputFormat = INPUT_YUV420_SEMI_PLANNER_UV_10BIT;
        } else {
            userImage->inputFormat = INPUT_YUV420_SEMI_PLANNER_VU_10BIT;
        }
    }
    userImage->outputFormat = OUTPUT_YUV420SP_UV;
    userImage->isCompressData = true;
    // Configure hfbc input address
    VpcCompressDataConfigure* compressDataConfigure = &userImage->compressDataConfigure;
    uint64_t baseAddr = (uint64_t)frame->buffer;
    compressDataConfigure->lumaHeadAddr = baseAddr + frame->offset_head_y;
    compressDataConfigure->chromaHeadAddr = baseAddr + frame->offset_head_c;
    compressDataConfigure->lumaPayloadAddr = baseAddr + frame->offset_payload_y;
    compressDataConfigure->chromaPayloadAddr = baseAddr + frame->offset_payload_c;
    compressDataConfigure->lumaHeadStride = frame->stride_head;
    compressDataConfigure->chromaHeadStride = frame->stride_head;
    compressDataConfigure->lumaPayloadStride = frame->stride_payload;
    compressDataConfigure->chromaPayloadStride = frame->stride_payload;

    userImage->yuvSumEnable = false;
    userImage->cmdListBufferAddr = nullptr;
    userImage->cmdListBufferSize = 0;
    // Configure the roi area and output area
    std::shared_ptr<VpcUserRoiConfigure> roiConfigure(new VpcUserRoiConfigure);
    roiConfigure->next = nullptr;
    userImage->roiConfigure = roiConfigure.get();
    VpcUserRoiInputConfigure* roiInput = &roiConfigure->inputConfigure;
    roiInput->cropArea.leftOffset = 0;
    roiInput->cropArea.rightOffset = frame->width - 1;
    roiInput->cropArea.upOffset = 0;
    roiInput->cropArea.downOffset = frame->height - 1;
    VpcUserRoiOutputConfigure* roiOutput = &roiConfigure->outputConfigure;
    roiOutput->outputArea.leftOffset = 0;
    roiOutput->outputArea.rightOffset = frame->width - 1;
    roiOutput->outputArea.upOffset = 0;
    roiOutput->outputArea.downOffset = frame->height - 1;
    roiOutput->bufferSize = ALIGN_UP(frame->width, 16) * ALIGN_UP(frame->height, 2) * 3 / 2;
    roiOutput->addr = (uint8_t*)HIAI_DVPP_DMalloc(roiOutput->bufferSize);
    if (roiOutput->addr == nullptr) {
        HIAI_ENGINE_LOG(HIAI_VPC_CTL_ERROR, "can not alloc roiOutput buffer");
        DestroyDvppApi(dvppHandle);
        return;
    }
    roiOutput->widthStride = ALIGN_UP(frame->width, 16);
    roiOutput->heightStride = ALIGN_UP(frame->height, 2);

    dvppapi_ctl_msg dvppApiCtlMsg;
    dvppApiCtlMsg.in = (void*)(userImage.get());
    dvppApiCtlMsg.in_size = sizeof(VpcUserImageConfigure);
    ret = DvppCtl(dvppHandle, DVPP_CTL_VPC_PROC, &dvppApiCtlMsg);
    if (ret != 0) {
        HIAI_ENGINE_LOG(HIAI_ERROR, "call dvppctl fail");
        HIAI_DVPP_DFree(roiOutput->addr);
        roiOutput->addr = nullptr;
        DestroyDvppApi(dvppHandle);
        return;
    }
    ret = FrameReturnSaveVpcResult(frame, roiOutput->addr, imageCount);
    if (ret != 0) {
        HIAI_ENGINE_LOG(HIAI_ERROR, "save vpc result fail");
    }
    HIAI_DVPP_DFree(roiOutput->addr);
    roiOutput->addr = nullptr;
    DestroyDvppApi(dvppHandle);
    return;
}

/*
*错误上报回调函数,用户若不需要错误信息,可不定义此函数
*/
void ErrReport(VDECERR* vdecErr)
{
    if (vdecErr != nullptr) {
        HIAI_ENGINE_LOG(HIAI_CREATE_DVPP_ERROR, "vdec error code is %d, channelId = %u\n", vdecErr->errType, vdecErr->channelId);
    }
}

//测试函数主入口
void TEST_VDEC()
{
    char outputDir[20] = {0};
    int32_t safeFuncRet = memset_s(outputDir, sizeof(outputDir), 0, 20);
    if (safeFuncRet != EOK) {
        HIAI_ENGINE_LOG(HIAI_ERROR, "memset_s fail");
        return;
    }
    safeFuncRet = strncpy_s(outputDir, sizeof(outputDir), "output_dir", strlen("output_dir"));
    if (safeFuncRet != EOK) {
        HIAI_ENGINE_LOG(HIAI_ERROR, "strncpy_s fail");
        return;
    }
    if (access(outputDir, F_OK) == -1) {
        if (mkdir(outputDir, 0700) < 0) { // directory authority: 0700
            HIAI_ENGINE_LOG(HIAI_VDEC_CTL_ERROR, "create dir failed.");
            return;
        }
    } else if (access(outputDir, R_OK | W_OK | X_OK) == -1) {
        HIAI_ENGINE_LOG(HIAI_VDEC_CTL_ERROR, "output directory authority is not correct, use 700 instead.");
        return;
    }
    IDVPPAPI *pidvppapi = nullptr;
    int32_t ret = CreateVdecApi(pidvppapi, 0);
    if (ret != 0) {
        HIAI_ENGINE_LOG(HIAI_CREATE_DVPP_ERROR, "create dvpp api fail.");
        return;
    }
    if (pidvppapi != nullptr) {
        FILE* fp = fopen(g_inFileName, "rb");
        if (fp == nullptr) {
            HIAI_ENGINE_LOG(HIAI_OPEN_FILE_ERROR, "open file: %s failed.", g_inFileName);
            DestroyVdecApi(pidvppapi, 0);
            return;
        }
        fseek(fp, 0L, SEEK_END);
        int file_size = ftell(fp);
        fseek(fp, 0L, SEEK_SET);
        int rest_len = file_size;
        int len = file_size;

        vdec_in_msg vdec_msg;
        vdec_msg.call_back = FrameReturn;
        vdec_msg.err_report = ErrReport; // can be unassigned, if user does not need error info
        vdec_msg.hiai_data = nullptr;
        int32_t safeFuncRet = 0;
        if (g_format == 0) {
            safeFuncRet = memcpy_s(vdec_msg.video_format, sizeof(vdec_msg.video_format), "h264", 4);
            if (safeFuncRet != EOK) {
                HIAI_ENGINE_LOG(HIAI_ERROR, "memcpy_s fail");
                DestroyVdecApi(pidvppapi, 0);
                fclose(fp);
                fp = nullptr;
                return;
            }
        } else {
            safeFuncRet = memcpy_s(vdec_msg.video_format, sizeof(vdec_msg.video_format), "h265", 4);
            if (safeFuncRet != EOK) {
                HIAI_ENGINE_LOG(HIAI_ERROR, "memcpy_s fail");
                DestroyVdecApi(pidvppapi, 0);
                fclose(fp);
                fp = nullptr;
                return;
            }
        }
        vdec_msg.in_buffer = (char*)malloc(len);
        if (vdec_msg.in_buffer == nullptr) {
            HIAI_ENGINE_LOG(HIAI_ERROR, "malloc fail");
            fclose(fp);
            fp = nullptr;
            DestroyVdecApi(pidvppapi, 0);
            return;
        }

        dvppapi_ctl_msg dvppApiCtlMsg;
        dvppApiCtlMsg.in = (void*)(&vdec_msg);
        dvppApiCtlMsg.in_size = sizeof(vdec_in_msg);

        while (rest_len > 0) {
            int read_len = fread(vdec_msg.in_buffer, 1, len, fp);
            HIAI_ENGINE_LOG("rest_len is %d,read len is %d.", rest_len, read_len);
            vdec_msg.in_buffer_size = read_len;
            fclose(fp);
            fp = nullptr;
            if (VdecCtl(pidvppapi, DVPP_CTL_VDEC_PROC, &dvppApiCtlMsg, 0) != 0) {
                HIAI_ENGINE_LOG(HIAI_VDEC_CTL_ERROR, "call dvppctl process faild!");
                free(vdec_msg.in_buffer);
                vdec_msg.in_buffer = nullptr;
                DestroyVdecApi(pidvppapi, 0);
                return;
            }
            HIAI_ENGINE_LOG(HIAI_OK, "call vdec process success!");
            rest_len = rest_len - len;
        }
        free(vdec_msg.in_buffer);
        vdec_msg.in_buffer = nullptr;
    } else {
        HIAI_ENGINE_LOG(HIAI_VDEC_CTL_ERROR, "pidvppapi is null!");
    }
    DestroyVdecApi(pidvppapi, 0);
    return;
}
分享:

    相关文档

    相关产品