实现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; }