Implementing the VDEC Function
For a video stream, after you create an instance by calling CreateVdecApi, you must use the same instance to call VdecCtl for video decoding, and then call DestroyVdecApi to release the instance.
During video decoding, if you need to switch from a video stream to another video stream, you must release the instance of the previous stream by calling DestroyVdecApi, and then create an instance by calling CreateVdecApi to process the new video stream.
This example reads the H.264 stream file named test_file, calls the VDEC function, and saves the decoding result to the output_dir directory.
// User-defined sub-class class HIAI_DATA_SP_SON: public HIAI_DATA_SP { public: ~ HIAI_DATA_SP_SON () { //destruct here; } // User-defined member functions. The following is only an example. uint8_t GetTotalFrameNum() { return info_.totalFrameNum; } private: // User-defined member variables. The INFO structure is only an example. struct INFO { uint8_t totalFrameNum; uint8_t frameRate; }info_; }; IDVPPAPI * pidvppapi_vpc = NULL; IDVPPAPI * pidvppapi_vdec = NULL; // The callback function is used as an example. The caller needs to redefine the callback function as required. 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; } /* *Error reporting callback function. If you do not need error information, you do not need to define this function. */ 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); } } // Main entry of the test function 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; }
Feedback
Was this page helpful?
Provide feedbackThank you very much for your feedback. We will continue working to improve the documentation.See the reply and handling status in My Cloud VOC.
For any further questions, feel free to contact us through the chatbot.
Chatbot