视频编码的结果数据通过回调函数获取。
您可以从样例介绍中获取完整样例代码。
调用接口后,需增加异常处理的分支,并记录报错日志、提示日志,此处不一一列举。以下是关键步骤的代码示例,不可以直接拷贝编译运行,仅供参考。
// 1.AscendCL初始化 aclRet = aclInit(nullptr); // 2.运行管理资源申请(依次申请Device、Context、Stream) aclrtContext context_; aclrtStream stream_; aclrtSetDevice(0); aclrtCreateContext(&context_, 0); aclrtCreateStream(&stream_); // 3.创建执行回调函数的线程及线程函数 static bool runFlag = true; void *ThreadFunc(void *arg) { // Notice: create context for this thread int deviceId = 0; aclrtContext context = nullptr; aclError ret = aclrtCreateContext(&context, deviceId); INFO_LOG("process callback thread start "); while (runFlag) { // Notice: timeout 1000ms (void)aclrtProcessReport(1000); } // ...... ret = aclrtDestroyContext(context); return (void*)0; } int createThreadErr = pthread_create(&threadId_, nullptr, ThreadFunc, nullptr); // 4.创建回调函数 void callback(acldvppPicDesc *input, acldvppStreamDesc *outputStreamDesc, void *userdata) { // 获取视频编码结果数据,并写入文件 void *outputDev = acldvppGetStreamDescData(outputStreamDesc); uint32_t streamDescSize = acldvppGetStreamDescSize(outputStreamDesc); if (!Utils::WriteToFile(g_outFileFp, outputDev, streamDescSize)) { ERROR_LOG("write file:%s failed.", g_outFile.c_str()); } INFO_LOG("success to callback, stream size:%u", streamDescSize); } // 5.创建视频编码处理通道时的通道描述信息,设置通道描述信息的属性,其中线程、callback回调函数需要用户提前创建 // vencChannelDesc_是aclvdecChannelDesc类型 vencChannelDesc_ = aclvencCreateChannelDesc(); auto ret = aclvencSetChannelDescThreadId(vencChannelDesc_, threadId_); ret = aclvencSetChannelDescCallback(vencChannelDesc_, callback); ret = aclvencSetChannelDescEnType(vencChannelDesc_, enType_); ret = aclvencSetChannelDescPicFormat(vencChannelDesc_, format_); ret = aclvencSetChannelDescPicWidth(vencChannelDesc_, 128); ret = aclvencSetChannelDescPicHeight(vencChannelDesc_, 128); ret = aclvencSetChannelDescKeyFrameInterval(vencChannelDesc_, 16); // 6.创建视频码流处理的通道、单帧编码配置数据 ret = aclvencCreateChannel(vencChannelDesc_); // vencFrameConfig_是aclvencFrameConfig类型 vencFrameConfig_ = aclvencCreateFrameConfig(); // 7.申请Device内存dataDev,存放视频编码的输入数据 // 7.1 读入图片数据 const char *fileName = "../dvpp_venc_128x128_nv12.yuv"; FILE *fp = fopen(fileName, "rb+"); fseek(fp, 0, SEEK_END); long fileLenLong = ftell(fp); fseek(fp, 0, SEEK_SET); auto fileLen = static_cast<uint32_t>(fileLenLong); uint32_t dataSize = fileLen; // 调用aclrtGetRunMode接口获取软件栈的运行模式,如果调用aclrtGetRunMode接口获取软件栈的运行模式为ACL_HOST,则需要通过aclrtMemcpy接口将输入图片数据传输到Device,数据传输完成后,需及时释放内存;否则直接申请并使用Device的内存 aclrtRunMode runMode; ret = aclrtGetRunMode(&runMode); if(runMode == ACL_HOST) { void *dataHost = malloc(fileLen); size_t readSize = fread(dataHost, 1, fileLen, fp) void *dataDev = nullptr; ret = acldvppMalloc(&dataDev, dataSize); ret = aclrtMemcpy(dataDev, dataSize, dataHost, fileLen, ACL_MEMCPY_HOST_TO_DEVICE); // 完成数据传输后,需及时释放内存 free(dataHost); } else { ret = acldvppMalloc(&dataDev, dataSize); } // 8.执行视频编码 size_t g_vencCnt = 16; // 8.1 创建输入图片描述信息,设置输入图片数据的内存地址和内存大小 inputPicputDesc_ = acldvppCreatePicDesc(); ret = acldvppSetPicDescData(inputPicputDesc_, dataDev); ret = acldvppSetPicDescSize(inputPicputDesc_, dataSize); // 8.2 设置单帧编码配置数据,不是结束帧 ret = aclvencSetFrameConfigEos(vencFrameConfig_, 0); ret = aclvencSetFrameConfigForceIFrame(vencFrameConfig_, 0) // 8.3 创建输出码流描述信息 acldvppStreamDesc *outputStreamDesc = nullptr; // 8.4 执行视频编码 while (g_vencCnt > 0) { ret = aclvencSendFrame(vencChannelDesc_, inputPicputDesc_, static_cast<void *>(outputStreamDesc), vencFrameConfig_, nullptr); g_vencCnt--; } // 8.5 设置单帧编码配置数据,是结束帧 ret = aclvencSetFrameConfigEos(vencFrameConfig_, 1); ret = aclvencSetFrameConfigForceIFrame(vencFrameConfig_, 0) // 8.6 执行最后一帧的视频编码 ret = aclvencSendFrame(vencChannelDesc_, nullptr, nullptr, vencFrameConfig_, nullptr); // 9.释放资源 (void)aclvencDestroyChannel(vencChannelDesc_); (void)aclvencDestroyChannelDesc(vencChannelDesc_); (void)acldvppDestroyPicDesc(inputPicputDesc_); (void)aclvencDestroyFrameConfig(vencFrameConfig_); // 释放内存和销毁线程 (void)acldvppFree(inBufferDev_); void *res = nullptr; int joinThreadErr = pthread_join(threadId_, &res); // 10. 释放运行管理资源(依次释放Stream、Context、Device) aclrtDestroyStream(stream_); aclrtDestroyContext(context_); aclrtResetDevice(0); // 11.AscendCL去初始化 aclRet = aclFinalize(); // ......
如果调用aclvencSetChannelDescParam接口设置通道描述信息的属性,调用aclvencGetChannelDescParam接口获取通道描述信息中的属性值,示例代码如下:
// 设置回调函数 void *func = (void *)callback; aclvencSetChannelDescParam(vencChannelDesc_, ACL_VENC_CALLBACK_PTR, 8, &func); // 获取回调函数 void *func1 = nullptr; aclvencGetChannelDescParam(vencChannelDesc_, ACL_VENC_CALLBACK_PTR, 8, &len, &func1); // 设置输入图片格式 acldvppPixelFormat format = PIXEL_FORMAT_YUV_SEMIPLANAR_420; aclvencSetChannelDescParam(vencChannelDesc_, ACL_VENC_PIXEL_FORMAT_UINT32, 4, &format); // 获取输入图片格式 acldvppPixelFormat format1 = PIXEL_FORMAT_YUV_SEMIPLANAR_420; aclvencGetChannelDescParam(vencChannelDesc_, ACL_VENC_PIXEL_FORMAT_UINT32, 4, &len, &format1); // 设置图片宽度 uint32_t width = 128; aclvencSetChannelDescParam(vencChannelDesc_, ACL_VENC_PIC_WIDTH_UINT32, 4, &width); // 获取图片高度 uint32_t width1 = 0; aclvencGetChannelDescParam(vencChannelDesc_, ACL_VENC_PIC_WIDTH_UINT32, 4, &len, &width1); // 设置图片高度 uint32_t height = 128; aclvencSetChannelDescParam(vencChannelDesc_, ACL_VENC_PIC_HEIGHT_UINT32, 4, &height); // 获取图片高度 uint32_t height1 = 0; aclvencGetChannelDescParam(vencChannelDesc_, ACL_VENC_PIC_HEIGHT_UINT32, 4, &len, &height1); // 设置编码输出缓存地址 ret = acldvppMalloc(&buf, bufSize); aclvencSetChannelDescParam(vencChannelDesc_, ACL_VENC_BUF_ADDR_PTR, 8, &buf); // 获取编码输出缓存地址 void *buf1 = nullptr; aclvencGetChannelDescParam(vencChannelDesc_, ACL_VENC_BUF_ADDR_PTR, 8, &len, &buf1);