
视频转码这件事只要做过一次批量任务就会明白纯CPU方案有多熬人。我手头有一批监控视频需要从H.265转成H.264做归档用一台双路服务器跑FFmpeg1080p的视频大概只能跑到1.2倍速一个200路的小项目排下来要跑整整两天。后来拿到了一块昇腾310P的推理卡想着这东西本来就是做AI推理的视频编解码单元DVPP应该也能派上用场于是花了大概一周时间把FFmpeg和昇腾的硬件加速对接起来。实测下来同样的1080p H.265转H.264任务单路速度从1.2倍速提到了8倍速以上功耗还降了一半多。这篇文章就把整个对接过程、踩过的坑、以及实测数据完整地分享出来适合正在做视频转码、流媒体处理、或者手上有昇腾设备想榨干性能的同行参考。1. 为什么纯CPU转码会成为瓶颈1.1 转码到底在算什么要理解为什么需要NPU或者专用硬件来加速得先搞清楚FFmpeg转码时CPU到底在忙什么。一个完整的转码流程大致分三步解码Decode、处理Filter、编码Encode。解码是把压缩码流还原成YUV原始帧编码是把YUV帧重新压缩成目标格式。这两步都是计算密集型任务尤其是H.265HEVC的编码复杂度比H.264高出好几倍。以1080p 25fps的H.265视频为例纯CPU软解一帧大概需要3到5毫秒软编一帧H.264大概需要8到15毫秒。加起来一帧就是十几毫秒理论上单核跑满也就60到70fps但实际因为内存拷贝、线程调度、滤镜处理等开销能跑到30fps就算不错了。这就是为什么很多人用FFmpeg转码时发现CPU占用100%但速度还是上不去。1.2 CPU转码的隐性成本除了速度慢纯CPU转码还有几个容易被忽略的成本。第一是功耗一颗服务器CPU满载功耗动辄150W到250W转码任务跑满时整机功耗轻松上300W。第二是并发能力CPU核心数是固定的转码任务一多就得排队想提高并发只能加机器。第三是CPU被占满之后同一台机器上跑的其他服务比如Web服务、数据库会受严重影响这在生产环境里是很要命的。我之前就遇到过这种情况一台机器上同时跑着Nginx和FFmpeg转码转码任务一启动Nginx的响应时间从20毫秒飙到800毫秒用户直接投诉。后来只能把转码任务单独拆到一台机器上成本又上去了。1.3 硬件加速的几种路线目前视频转码的硬件加速主要有几条路线GPU比如NVIDIA的NVENC/NVDEC、专用编解码芯片比如海思的VPU、以及NPU上集成的视频编解码单元。GPU方案最成熟FFmpeg原生就支持NVENC/NVDEC但GPU价格贵、功耗高。专用编解码芯片功耗低但灵活性差。NPU方案是最近几年起来的昇腾310P就是典型代表它集成了DVPPDigital Vision Pre-Processing模块支持H.264和H.265的硬件编解码同时还有AI推理能力一块卡能干两件事。我选昇腾310P的原因很简单手头正好有而且它的DVPP编解码能力在规格上支持到4K 60fps功耗只有几十瓦性价比很高。下面就来详细说怎么把FFmpeg和它对接起来。2. 昇腾310P的DVPP编解码能力摸底2.1 DVPP是什么能做什么DVPP全称Digital Vision Pre-Processing是昇腾芯片里专门处理图像和视频的硬件模块。它包含几个子单元VDEC视频解码、VENC视频编码、VPC视觉预处理做缩放、裁剪、格式转换、JPEGD/JPEGEJPEG编解码。对于转码场景我们主要用VDEC和VENC。昇腾310P的VDEC支持H.264、H.265、VP9等格式的解码VENC支持H.264和H.265的编码。规格上310P的VDEC能支持到4K 60fps多路VENC支持到4K 30fps。具体路数取决于分辨率和码率官方文档里有详细的规格表但实际能跑多少路还得自己测。2.2 和CPU软编解码的差异硬件编解码和软件编解码最大的差异在质量上。软件编码器比如x264、x265有大量的心理视觉优化、码率控制算法能在同等码率下获得更好的画质。硬件编码器为了追求速度算法简化了很多同等码率下画质通常差一档。这一点在做归档转码时要有心理准备如果对画质要求极高硬件编码可能不满足要求。但硬件编码也有优势速度快、功耗低、CPU占用几乎为零。对于监控视频归档、直播转码、视频会议这类对画质要求不是极致、但对速度和成本敏感的场景硬件编码是更好的选择。2.3 实测前的准备工作在开始对接之前需要确认几件事。第一是驱动和固件版本昇腾310P需要安装对应的驱动包和固件包版本不匹配会导致DVPP初始化失败。第二是CANN工具包这是昇腾的软件开发套件里面包含了DVPP的API和FFmpeg的硬件加速插件。第三是FFmpeg版本昇腾官方提供的FFmpeg插件对版本有要求太新或太旧的FFmpeg可能编译不过。我用的环境是Ubuntu 20.04驱动版本是23.0.rc2CANN版本是7.0.RC1FFmpeg用的是4.4.4。这个组合实测是能跑通的后面会详细说编译和配置过程。3. 环境搭建从驱动到FFmpeg的完整链路3.1 驱动和固件的安装顺序昇腾设备的驱动安装有个坑驱动和固件必须版本匹配而且安装顺序有讲究。正确的顺序是先装驱动再装固件最后重启。如果顺序反了或者版本不匹配设备可能识别不到或者DVPP初始化时报错。安装驱动的命令大致是这样的# 给驱动包加执行权限 chmod x Ascend-hdk-310p-npu-driver_23.0.rc2_linux-x86-64.run # 执行安装 ./Ascend-hdk-310p-npu-driver_23.0.rc2_linux-x86-64.run --full # 安装固件 chmod x Ascend-hdk-310p-npu-firmware_7.1.0.5.220.run ./Ascend-hdk-310p-npu-firmware_7.1.0.5.220.run --full # 重启 reboot重启后用npu-smi info命令检查设备状态如果能看到设备信息、温度、功耗等说明驱动装好了。如果报错“device not found”大概率是驱动和固件版本不匹配或者PCIe插槽有问题。提示安装驱动前最好先卸载旧版本驱动用./xxx.run --uninstall命令。如果直接覆盖安装有时候会出现残留文件导致新驱动加载失败。3.2 CANN工具包的安装与验证CANN是昇腾的软件开发套件DVPP的API和FFmpeg插件都在里面。安装CANN之前需要先装一些依赖比如Python、gcc、make等。安装命令# 给CANN包加执行权限 chmod x Ascend-cann-toolkit_7.0.RC1_linux-x86_64.run # 执行安装--install-path指定安装目录 ./Ascend-cann-toolkit_7.0.RC1_linux-x86_64.run --install --install-path/usr/local/Ascend安装完成后需要设置环境变量把CANN的库路径加到LD_LIBRARY_PATH里。通常安装脚本会提示你source一个set_env.sh文件source /usr/local/Ascend/ascend-toolkit/set_env.sh验证CANN是否装好可以跑一个简单的样例程序或者用atc --version命令看版本信息。如果命令找不到说明环境变量没设置对。3.3 FFmpeg的编译与昇腾插件对接这是整个流程里最麻烦的一步。昇腾官方提供的FFmpeg硬件加速插件不是直接可用的二进制需要自己编译。大致流程是下载FFmpeg源码下载昇腾的FFmpeg补丁打补丁配置编译选项编译。我用的FFmpeg版本是4.4.4昇腾提供的补丁包里有对应的patch文件。编译配置大概是这样./configure --prefix/usr/local/ffmpeg \ --enable-shared \ --enable-libx264 \ --enable-libx265 \ --enable-nonfree \ --enable-ascend \ --extra-cflags-I/usr/local/Ascend/ascend-toolkit/latest/include \ --extra-ldflags-L/usr/local/Ascend/ascend-toolkit/latest/lib64关键参数是--enable-ascend这个选项会启用昇腾的硬件加速模块。编译过程中如果报错找不到头文件检查extra-cflags路径是否正确。编译完成后用ffmpeg -hwaccels命令查看支持的硬件加速类型如果能看到ascend说明插件编译成功了。注意编译FFmpeg时如果同时启用了x264和x265需要先装好这两个库的开发包。另外昇腾插件对FFmpeg的版本比较敏感建议严格按照官方文档推荐的版本组合来不要随意升级FFmpeg。4. 转码命令的写法与参数调优4.1 硬件解码的启用方式FFmpeg启用硬件解码的方式是通过-hwaccel参数指定加速类型。对于昇腾命令大概是这样ffmpeg -hwaccel ascend -i input.mp4 -c:v h264_ascend -b:v 4M output.mp4这里-hwaccel ascend指定用昇腾做硬件解码-c:v h264_ascend指定用昇腾的硬件编码器做H.264编码。如果只是解码用硬件、编码用软件可以把-c:v换成libx264。实测下来硬件解码的加速比大概在3到5倍具体取决于分辨率和码流复杂度。1080p的H.265视频软解大概30fps硬解能到120fps以上。4.2 硬件编码的参数调校硬件编码器的参数和软件编码器不太一样。软件编码器有preset、crf这些参数硬件编码器通常只有码率控制模式CBR、VBR和GOP大小这些基础参数。昇腾的硬件编码器支持的命令参数包括-b:v目标码率-gGOP大小默认是帧率的2倍-rc_mode码率控制模式0是CBR1是VBR-profile编码profile支持baseline、main、high我实测下来-rc_mode 1VBR的画质比CBR好一些但码率波动大。如果是做归档建议用VBR码率上限设为目标码率的1.5倍。GOP大小建议设成帧率的2到4倍太小会影响压缩率太大影响随机访问。4.3 实测数据与性能对比我用一段10分钟的1080p H.265视频码率8Mbps做了对比测试结果如下方案转码速度CPU占用功耗输出画质PSNR纯CPU软解软编1.2x800%280W42.5dB昇腾硬解软编4.5x400%180W42.3dB昇腾硬解硬编8.2x50%95W40.1dB从数据可以看出全硬件方案的速度是纯CPU方案的近7倍功耗只有三分之一但画质下降了约2.4dB。这个画质差距在监控视频归档场景下是可以接受的但在影视转码场景下可能就不行了。提示PSNR下降2dB左右肉眼在大部分场景下不太容易察觉但在暗部细节和快速运动场景下会有明显差异。如果对画质敏感建议用硬解软编的方案速度也有3到4倍提升。5. 踩坑记录那些文档里不会写的问题5.1 内存对齐导致的解码失败昇腾的DVPP对输入数据的内存对齐有要求解码器的输入缓冲区地址必须按128字节对齐。如果直接用FFmpeg的默认内存分配有时候会报“invalid argument”错误。这个问题的排查花了我大半天时间最后发现是内存对齐的问题。解决办法是在FFmpeg的AVCodecContext里设置CODEC_FLAG_ALIGN标志或者用昇腾提供的内存分配接口acldvppMalloc来分配对齐内存。昇腾的FFmpeg插件里其实已经处理了这个问题但如果自己写代码调用DVPP API就需要注意。5.2 多路并发时的资源竞争单路转码跑通之后我想试试多路并发。结果发现同时跑4路的时候第3路和第4路会随机失败报“device busy”错误。查了文档才知道昇腾310P的DVPP模块有并发路数限制解码和编码各有最大并发数超过之后需要排队或者复用通道。解决办法是用昇腾提供的通道管理接口在启动转码任务前先申请通道任务结束后释放通道。FFmpeg插件里可以通过设置环境变量ASCEND_RT_VISIBLE_DEVICES来指定使用的设备但通道管理需要自己在应用层做。5.3 码流格式的兼容性问题昇腾的硬件解码器对输入码流有一些要求比如不支持某些特殊的SEI信息不支持隔行扫描的视频。我遇到过一个视频用软件解码正常用硬件解码就花屏。后来分析发现那个视频是隔行扫描的硬件解码器不支持。解决办法是在转码前先用ffprobe检查视频的扫描方式如果是隔行扫描先用软件解码做反隔行处理再送硬件编码。或者直接用软件解码硬件编码这样也能获得不错的加速比。5.4 驱动版本升级后的兼容性断裂有一次我手贱升级了驱动版本从23.0.rc2升到了23.0.rc3结果FFmpeg的昇腾插件直接加载失败报“symbol not found”错误。原因是CANN的库和驱动版本不匹配新驱动改了API接口旧版CANN的库找不到对应的符号。解决办法是驱动、固件、CANN三个组件的版本必须严格匹配升级其中一个就要同步升级另外两个。昇腾官方有版本配套表升级前一定要查一下。6. 生产环境部署的几点经验6.1 转码任务的队列管理在生产环境里转码任务不能直接扔给FFmpeg就跑需要有一个队列管理机制。我的做法是用Redis做一个简单的任务队列转码worker从队列里取任务取到之后调用FFmpeg命令行执行。这样做的目的是控制并发数避免同时启动太多转码任务把DVPP通道占满。队列管理还需要考虑任务优先级和超时处理。比如紧急任务插队、超时任务自动重试等。这些逻辑用Python写一个简单的调度器就能实现不需要太复杂。6.2 监控与告警昇腾设备的状态监控很重要尤其是温度和功耗。npu-smi info命令可以查看设备状态但生产环境需要自动化监控。我的做法是写一个脚本定时采集npu-smi的输出解析出温度、功耗、显存占用等指标推到Prometheus里再用Grafana做面板。告警规则主要设两条温度超过85度告警DVPP通道占用率超过90%告警。温度过高会导致降频影响转码速度通道占用率过高说明并发数设大了需要调整。6.3 故障恢复与降级策略硬件加速不是100%可靠的偶尔会出现DVPP初始化失败或者转码中途报错的情况。生产环境需要有降级策略当硬件加速失败时自动切换到软件转码保证任务能完成只是速度慢一些。实现方式是在转码脚本里加一个重试逻辑先用硬件加速跑如果失败记录错误日志然后用软件编码重跑一遍。这样虽然牺牲了一些速度但保证了任务的可靠性。7. 这套方案适合什么场景7.1 监控视频归档监控视频归档是这套方案最典型的应用场景。监控视频通常对画质要求不高但对存储成本和转码速度敏感。用昇腾硬件加速可以把转码速度提升5到7倍同时功耗降低三分之二。一个200路监控的小区原来需要两台服务器跑两天现在一台服务器加一块310P卡半天就能跑完。7.2 直播转码直播转码对延迟要求高硬件编码的低延迟特性正好合适。昇腾的硬件编码器支持低延迟模式编码延迟可以控制在几十毫秒以内。不过直播转码通常需要多路输出不同分辨率、不同码率昇腾310P的VENC支持多路编码但需要合理规划通道分配。7.3 视频会议录制视频会议录制场景下转码任务通常是突发的会议结束后需要快速完成录制文件的转码。硬件加速的高吞吐能力可以缩短转码窗口减少对后续任务的阻塞。而且视频会议的视频通常分辨率不高720p或1080p硬件编码的画质损失相对较小。7.4 不适合的场景这套方案不适合对画质要求极高的场景比如影视后期、蓝光压制等。硬件编码器的画质在低码率下和软件编码器差距明显如果目标是“同码率下画质最优”还是得用软件编码。另外如果视频源有大量隔行扫描、特殊SEI信息等硬件解码器可能不支持需要先做预处理。8. 一些可以继续优化的方向8.1 用AI做智能转码昇腾310P本身有AI推理能力可以在转码流程里加入AI处理。比如用AI做场景检测对不同场景用不同的编码参数或者用AI做超分辨率把低分辨率视频放大后再编码。这些玩法能把NPU的价值发挥得更充分。8.2 多卡并行单块310P的转码能力有限如果任务量再大可以考虑多卡并行。昇腾支持多卡FFmpeg插件也可以通过指定设备号来分配任务到不同卡上。多卡并行的难点在于任务调度和负载均衡需要根据每块卡的实时负载来分配任务。8.3 容器化部署把FFmpeg和昇腾驱动打包到容器里可以简化部署流程。昇腾提供了Docker镜像和容器运行时插件支持在容器里访问NPU设备。容器化之后转码服务的扩缩容会方便很多也更容易做版本管理。我在实际使用中的体会是昇腾310P做视频转码的性价比确实很高但生态成熟度还不如GPU方案很多地方需要自己摸索。驱动版本匹配、内存对齐、通道管理这几个坑是必踩的提前了解能省不少时间。另外硬件编码的画质损失要有预期如果业务对画质敏感建议用硬解软编的折中方案。最后再分享一个小技巧转码前先用ffprobe检查视频的编码格式和扫描方式能避免很多兼容性问题。