当前位置: 首页 > news >正文

CANN文档:VENC视频编码

VENC视频编码

【免费下载链接】docs该仓库用于维护cann公共文档项目地址: https://gitcode.com/cann/docs

本节介绍VENC视频编码的接口调用流程,同时配合示例代码辅助理解该接口调用流程。

VENC(Video Encoder)将YUV420SP格式的图片编码成H264/H265格式的视频码流。关于VENC功能的详细介绍及使用约束请参见《DVPP媒体加速库》。

接口调用流程

图 1视频编码流程
![](https://raw.gitcode.com/cann/docs/raw/a173bdbfa81bbfd36d1c4da672d78301fb678d36/docs/app-dev/zh/figures/视频编码流程.png "视频编码流程"?utm_source=gitcode_repo_files)

实现视频的编码,关键接口的说明如下:

  1. 调用aclvencCreateChannel接口创建视频编码处理的通道。

    • 创建视频编码处理通道前,需先执行以下操作:

      1. 调用aclvencCreateChannelDesc接口创建通道描述信息

      2. 调用aclvencSetChannelDescParam接口设置通道描述信息的属性,包括线程、回调函数、视频编码协议、输入图片格式等,其中:

        1. 回调函数需由用户提前创建,用于在视频编码后,获取编码数据,并及时释放相关资源,回调函数的原型请参见aclvencCallback。

          视频编码结束后,建议用户在回调函数内及时释放输入图片内存、以及相应的图片描述信息。视频编码的输出内存由系统管理,不由用户管理,因此无需用户释放。

        2. 线程需由用户提前创建,并自定义线程函数,在线程函数内调用aclrtProcessReport接口,等待指定时间后,触发前一步中的回调函数。

        说明:推荐使用aclvencSetChannelDescParam接口设置通道描述信息的属性,通过枚举值来选择通过该接口设置某一个属性的值。 但为兼容旧版本,也可以调用aclvencSetChannelDesc系列接口设置通道描述信息的属性,每个属性的设置对应一个set接口。

    • aclvencCreateChannel接口内部封装了如下接口,无需用户单独调用:

      1. aclrtCreateStream接口:显式创建Stream,VENC内部使用。
      2. aclrtSubscribeReport接口:指定处理Stream上回调函数的线程,回调函数和线程是由用户调用aclvencSetChannelDescParam接口时指定的。
  2. 调用aclvencSendFrame接口将YUV420SP格式的图片编码成H264/H265格式的视频码流。

    • 视频编码前,需先执行以下操作:

      • 调用acldvppCreatePicDesc接口创建输入图片描述信息,并调用acldvppSetPicDesc系列接口设置输入图片的内存地址、内存大小、图片格式等属性。
      • 调用aclvencCreateFrameConfig接口创建单帧编码配置数据,并调用aclvencSetFrameConfig系列接口设置是否强制重新开始I帧间隔、是否结束帧。
    • 视频编码时,aclvencSendFrame接口内部封装了aclrtLaunchCallback接口,用于在Stream的任务队列中增加一个需要执行的回调函数。用户无需单独调用aclrtLaunchCallback接口。

    • 视频编码后,视频编码的结果数据通过回调函数获取。

  3. 调用aclvencDestroyChannel接口销毁视频处理的通道。

    • 系统会等待已发送帧编码完成且用户的回调函数处理完成后再销毁通道。

    • aclvencDestroyChannel接口内部封装了如下接口,无需用户单独调用:

      • aclrtUnSubscribeReport接口:取消线程注册(Stream上的回调函数不再由指定线程处理)。
      • aclrtDestroyStream接口:销毁Stream。
    • 销毁通道后,需调用aclvencDestroyChannelDesc接口销毁通道描述信息。

    • 销毁通道描述信息后,用户才可以销毁第1步中创建的线程。

示例代码

以下是VENC视频编码功能关键步骤的代码示例,不能直接拷贝编译运行,仅供参考。调用接口后,需增加异常处理的分支,并记录报错日志、提示日志,此处不一一列举。

您可以单击venc_image获取样例。

// 1. 创建执行回调函数的线程及线程函数 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); // 2. 创建回调函数 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); } // 3. 创建视频编码处理通道时的通道描述信息,设置通道描述信息的属性,其中线程、callback回调函数需要用户提前创建 // vencChannelDesc_是aclvdecChannelDesc类型 vencChannelDesc_ = aclvencCreateChannelDesc(); aclError 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); // 4. 创建视频码流处理的通道、单帧编码配置数据 ret = aclvencCreateChannel(vencChannelDesc_); // vencFrameConfig_是aclvencFrameConfig类型 vencFrameConfig_ = aclvencCreateFrameConfig(); // 5. 申请Device内存dataDev,存放视频编码的输入数据 // 读入图片数据 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); } // 6. 执行视频编码 size_t g_vencCnt = 16; // 6.1 创建输入图片描述信息,设置输入图片数据的内存地址和内存大小 inputPicputDesc_ = acldvppCreatePicDesc(); ret = acldvppSetPicDescData(inputPicputDesc_, dataDev); ret = acldvppSetPicDescSize(inputPicputDesc_, dataSize); // 6.2 设置单帧编码配置数据,不是结束帧 ret = aclvencSetFrameConfigEos(vencFrameConfig_, 0); ret = aclvencSetFrameConfigForceIFrame(vencFrameConfig_, 0); // 6.3 创建输出码流描述信息 acldvppStreamDesc *outputStreamDesc = nullptr; // 6.4 执行视频编码 while (g_vencCnt > 0) { ret = aclvencSendFrame(vencChannelDesc_, inputPicputDesc_, static_cast<void *>(outputStreamDesc), vencFrameConfig_, nullptr); g_vencCnt--; } // 6.5 设置单帧编码配置数据,是结束帧 ret = aclvencSetFrameConfigEos(vencFrameConfig_, 1); ret = aclvencSetFrameConfigForceIFrame(vencFrameConfig_, 0); // 6.6 执行最后一帧的视频编码 ret = aclvencSendFrame(vencChannelDesc_, nullptr, nullptr, vencFrameConfig_, nullptr); // 7. 释放资源 (void)aclvencDestroyChannel(vencChannelDesc_); (void)aclvencDestroyChannelDesc(vencChannelDesc_); (void)acldvppDestroyPicDesc(inputPicputDesc_); (void)aclvencDestroyFrameConfig(vencFrameConfig_); // 释放内存和销毁线程 (void)acldvppFree(inBufferDev_); void *res = nullptr; int joinThreadErr = pthread_join(threadId_, &res); ......

如果调用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);

【免费下载链接】docs该仓库用于维护cann公共文档项目地址: https://gitcode.com/cann/docs

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

http://www.jsqmd.com/news/1129777/

相关文章:

  • RetinexNet实战教程:5分钟完成低光图像增强,附代码示例
  • BilibiliDown:你的B站视频离线收藏专家
  • Pillar Valley游戏美术资源管理:Three.js材质与纹理的最佳实践
  • 如何用Python自动化脚本高效参与B站抽奖活动:BiliBili-Lucky-Draw技术深度解析
  • 6DoF运动感知技术:从IMU到嵌入式系统设计
  • 如何在浏览器中实现人体姿态搜索:免费开源pose-search完整使用指南
  • 10分钟掌握防撤回神器:RevokeMsgPatcher从新手到高手的完整指南
  • Jellyscrub开发者入门:从TrickplayController到VideoProcessor,插件架构详解
  • 为什么选择 Swift Protobuf?探索苹果官方 protobuf 实现的核心优势
  • InGate源码解析:深入理解Gateway API控制器的核心组件设计
  • Project Restoration技术架构深度解析:游戏补丁开发原理与实践
  • RDiscount高级特性解析:智能引号、脚注和TOC生成的完整教程
  • COCO 数据集 80 类目标检测:YOLOv8 训练与 mAP 0.5:0.95 评估指南
  • Coding Coach社区治理指南:开源项目的协作与贡献流程
  • Denoising Diffusion GANs环境搭建教程:快速上手CIFAR-10图像生成
  • StreamPETR:革命性3D物体检测框架快速入门指南
  • 恶意软件分析入门:Security-Paper项目中的Linux恶意软件研究资料
  • Instatic部署自动化平台:GitHub Actions与GitLab CI完整指南
  • 10 个 ConfigArgParse 实用技巧:让你的 CLI 工具更专业、更易用
  • Vue Content Loading:打造Facebook风格SVG加载卡片的终极指南
  • 嵌入式系统中的高效电压管理:KMR221与PIC18F96J65应用
  • Twitter API Client部署指南:从开发到生产环境的最佳实践
  • Dev Proxy路线图:未来功能与社区贡献指南
  • 逻辑设备与窗口表面:Vulkan图形渲染的基础架构解析
  • Mastering Embedded Linux Programming安全部署指南:OTA更新与系统安全加固
  • Team IDE中的Zookeeper和Kafka管理:集群配置与消息处理实战
  • Subliminal实战教程:5个核心测试用例详解
  • Seti_ST3主题扩展生态:Seti_UX与JetBrains版本全解析
  • CANN/docs DVPP算子
  • 嵌入式Linux设备驱动开发:Mastering Embedded Linux Programming中的GPIO和I2C实战