第
5
章
嵌入式人工智能多媒体开发架构
本章视频
资料
本章学习目标
.了解嵌入式人工智能多媒体开发架构。
.了解OpenCV 和FFmpeg开发方法。
.掌握设备内存和系统内存的同步方法。
本章首先介绍嵌入式人工智能多媒体开发架构,并以算能公司的BM1684 芯
片架构为例介绍嵌入式人工智能多媒体开发的基本要点,包括开发环境搭建、内
部功能应用等,其次介绍当前最主流的多媒体开发工具———OpenCV 和FFmpeg
及其使用方法,最后介绍嵌入式人工智能开发中的设备内存和系统内存的同步
方法。

..5.1 
概述

嵌入式人工智能通过底层多媒体处理接口向算法侧提供API,如OpenCV 、
FFmpeg和BMCV 接口。这些接口用于进行视频、图像的编解码以及图像的基本
处理(如色彩空间转换、尺度变换、仿射变换等)。嵌入式人工智能多媒体开发框
架如图5.编解码能力是

1所示。多媒体开发是嵌入式人工智能芯片的核心功能, 
评价嵌入式人工智能芯片能力的关键指标。


图5.嵌入式人工智能多媒体开发框架

1 


第5章嵌入式人工智能多媒体开发架构139
本章内容都以算能公司的BM1684 芯片架构为例,如图5.2所示。BM1684 芯片作为
比特大陆集团BM 系列的最新版,聚焦于云端及边缘应用的人工智能推理,具有集成视频及
图像编码和解码能力,实现了低功耗、高性能、全定制,可广泛应用于自动驾驶、城市大脑、智
能政务、智能安防、智能医疗等诸多人工智能场景。其中视频子系统主要负责视频后处理和
MJPEG 的编解码工作。
图5.2BM1684芯片架构
5.1.1开发架构
目前大部分嵌入式人工智能芯片基本都支持OpenCV 和FFmpeg,为用户提供统一的
OpenCV 或FFmpeg接口。嵌入式人工智能芯片通过修改底层,使其支持硬件加速等功能, 
能充分发挥芯片能力。

OpenCV 是目前视频图像处理领域应用最广的一个开源软件库,其目标是致力于提供
易于使用的计算机视觉接口,从而帮助人们快速建立精巧的视觉应用[10]。

FFmpeg作为音视频领域的开源工具,几乎可以实现所有针对音视频的处理。它不仅
提供了音视频开发最基本的功能,使用范围也十分广泛,可实现包括视频采集、视频格式转
换、视频抓图、给视频加水印等在内的功能。

以BM1684 芯片为例,其多媒体框架的覆盖范围包括视频编码VPU 模块、视频解码
VPU 模块、图像编码JPU 模块、图像解码JPU 模块、图像处理VPP 模块。这些模块的功能
都封装到OpenCV 和FFmpeg开源框架中。其主要使用OpenCV 、FFmpeg和BMCV 这3 
个API 。在这3个框架中,OpenCV 框架擅长图像处理,各种图像处理算法最初都先集成到
OpenCV 框架中,而视频编解码通过底层调用FFmpeg实现;FFmpeg框架擅长图像和视频
的编解码,几乎所有格式都可以支持,只有是否能用硬件加速的区别;BMCV 专注于图像处
理功能,且能使用BM168x硬件加速的部分。

OpenCV 、FFmpeg和BMCV 这3个API 在功能上的关系如图5.
之间可以灵活转换,不会发生大量数据复制所造成的性能损失。
3所示。这3个框架

(1)OpenCV 作为源计算机视觉库(计算机视觉工程师最常用的开源框架), 封装了
FFmpeg提供硬件加速的视频编解码接口和提供硬件加速的JPEG 编解码接口,保留了原
有的软件支持的图像处理功能。


140智能多媒体理论与实战(微课版) 
图5.3OpenCV、FFmpeg和BMCV之间的关系
(2)FFmpeg包含开源音视频及图像处理接口,提供硬件加速的H.264和HEVC视频
编解码、JPEG编解码、图像加速功能和所有软件支持的视频/图像编解码接口(即所有
FFmpeg开源支持的格式)。
(3)BMCV拥有自有图像处理加速接口,提供带硬件加速的图像处理功能。
注意,在视频编解码上,OpenCV只是对FFmpeg接口的一层封装。使用FFmpeg时, 
控制粒度更细,灵活性更高,但开发代码量较大;而使用OpenCV接口时,代码更加简洁,开
发速度更快,但可控程度较弱。
5.2 
硬件加速
1.
硬件加速是指通过硬件代替软件实现加速的方法,这充分利用了硬件本身处理速度快
的性质,直接将代码存储在硬件中。目前人工智能、数据中心等技术热点对计算性能的需求
向传统处理器提出了新的挑战,因此对采用FPGA或者ASIC进行硬件加速以获得更高能
耗比的硬件加速计算方法有着非常迫切的需求。

硬件加速是嵌入式人工智能芯片的核心,利用芯片硬件提升复杂的编解码、图像处理能
力。以BM1684芯片为例,硬件加速模块包括视频编解码模块、图像编解码模块和图像处理

模块
(
。
1)视频编解码。支持H.和HEVC视频格式的硬件编解码加速,最高支持

264(AVC)
HD(1080P)视频的实时编码和4K视频的实时解码。其编码的速度受到编码配置参数的影
响,单芯片最高可以支持2路HD高清实时编码;而解码的速度则与输入视频码流的格式有
关,一般单芯片可以支持32路HD高清实时解码。

(2)图像编解码。支持JPEGbaseline格式的硬件编解码加速。对于其他图像格式,包
括JPEG2000 、BMP 、PNG以及JPEG标准的progresive、losles 
等,均自动采用软解支
持。图像硬件编解码的处理速度和图像的分辨率、图像色彩空间(YUV420p/422p/444p)有
比较大的关系,一般而言,对于1920×1080分辨率、色彩空间为YUV420p的图像,单芯片
硬件编解码可以达到600fps左右。
(3)图像处理。BM1684芯片中有专门对图像进行硬件加速处理的视频处理单元。支
持的图像操作有色彩转换、图像缩放、图像切割(crop)、图像拼接(stitch)。VPP不支持的复

第5章嵌入式人工智能多媒体开发架构141
杂图像处理功能则在BMCV 接口中利用其他硬件单元作了特殊的加速处理。
5.1.3工作模式
BM1684 芯片有两种工作模式:SoC模式和PCI-E模式。如图5.4所示,SoC模式是指
用人工智能芯片中的处理器作为主控CPU,可独立运行应用程序。PCI-E模式是指以PCI-
E板卡形态插到服务器主机上进行工作,作为一个硬件加速卡,其应用程序运行在服务器
CPU 上。
图5.4SoC模式与PCI-E模式
图5.5与图5.6展示了上述两种模式的应用环境。
图5.C模式的应用环境

5 
So


图5.6 
PCI-E模式的应用环境

5.4 
设备内存
1.
当程序开发过程中对性能有进一步要求的时候,对于内存同步需要通过手动更加精准
地控制,以避免一些不必要的内存同步导致的开销。此时需要理解BM1684 芯片内部的内
存同步控制机制,才能更好地用手动的方式进行内存控制。首先,在SoC模式下,设备内存
和系统内存代表同一块内存,系统内存是操作系统对于物理内存的一个虚拟映射,在物理表
现上其实仍然是同一块内存;而在PCI-E模式下,设备内存和系统内存就是真实的两块内
存,称为主机内存和板卡内存。在这两种模式下,BM1684 芯片都对同步的方向作了设定, 
分别称为Upload方向和Downloa如图5.

d方向,7所示。
在SoC模式下,Upload就是将物理内存的数据同步到Cache中,Download就是将


142智能多媒体理论与实战(微课版) 
图5.7内存同步
Cache中的数据同步到物理内存中,这里的两部分内存在主板上是同一块内存,同步的速度
很快,开销很小。在PCI-E模式下,Download指的是从主机内存将数据传输到板卡内存, 
Upload指的是从板卡内存将数据传输到主机内存,这里的两部分内存代表两块不同的物理
内存,因此同步时需要经过总线,同步速度较慢,开销大。
5.1.5内存同步的时机
原则上,当需要处理的数据从软件处理切换到使用硬件模块加速的交界处,就要进行内
存同步。下面分别介绍3种工具下的同步操作。
1.OpnCV 
下的内存同步在使用Op(e) enCV工具时,BM1684芯片采用以下方式进行内存同步:当调用cv:: 
BMCV::namespace中的函数时,开发者根据要求设定update为false或者true即可进行
内存同步。但是使用OpenCV的开发者需要注意的是:当使用yuvMat格式的数据进行开
发的时候,最新的数据均在设备内存中;当使用bgrMat数据格式的时候,此时最新的数据
均在系统内存中。开发者可以根据需要自行选择是否进行内存同步,以避免不必要的同步
开销。OpenCV下具体的手动内存同步的接口为BMCV::downloadMat()或者BMCV:: 
upload()。

2.FFmpeg下的内存同步
使用FFmpeg接口时,对于是否需要内存同步,FFmpeg模块提供了相应的标志位, 
BM1684芯片底层也对模块进行了改动。当开发者设定相应的标志位时,FFmpeg会根据
用户需要自动调用硬件加速,进行内存同步。

(1)对于硬件解码模块的输入数据,开发者需要设置正确的is_dma_bufer标志位或者
hwuploadfilter,当设定为true时,即可开启硬件加速,启用内存同步。
(2)对于硬件解码模块的输出数据,开发者需要设置正确的zero_copy标志位或者
hwdownloadfilter。
3.BMCV 
下的内存同步
BMCV的所有接口始终面向设备内存操作,所以当在BMCV提供的函数间进行数据
交互时,开发者无须考虑内存同步。只有在以下情况的时候,才需要注意内存同步: 

(1)当前主机内存数据作为BMCV接口的输入。此时,当软件处理的数据需要用到
BMCV模块中的函数,第一次调用BMCV函数接口时,要注意手动内存同步,将数据传输

第5章嵌入式人工智能多媒体开发架构143
到设备内存中,需要做一次Upload操作,将主机内存中的数据传输至板卡内存中去。
(2)当前内存数据作为BMCV 接口的输出。此时主机需要获取板卡内存中处理好的
数据,需要进行一次Download操作,进行内存同步,将数据从板卡内传输至主机内存中。
需要注意的是,在SoC模式下,当使用Downlaod同步物理内存到Cache内存中的时
候,需要提前同步内存,这是由于SoC模式下的内存在物理上是同一块内存,当进行内存同
步的时候,如果Cache中有数据,同步数据时也会将Cache中的数据再次写到物理内存中
去,容易导致数据的覆盖,造成数据的破坏。而对于PCI-E模式来说就没有这个问题,PCI-
E模式在获得输出后直接同步内存即可。
5.1.6手动内存同步的原因
当对数据进行处理时,最重要的就是数据不相互干扰,在PCI-E模式下,如果所有的数
据均在设备内存上处理,不需要主操作系统的介入,此时不进行内存同步也没有关系;但是
在大多数应用场景下,数据的处理都需要主操作系统的介入,必须进行内存同步。而内存同
步又分手动内存同步和自动内存同步两种,对于PCI-E模式下的内存同步,自动同步会产
生很多不必要的开销,例如简单的创建空间操作就会导致自动内存同步,数据在设备内存和
主机内存之间不断地交互,对性能影响很大,所以要进行手动内存同步。而在SoC模式下, 
自动内存同步的开销很小,仅在同一块内存中进行覆写,使用自动同步没有问题。
5.1.7内存同步示例
FFmpeg是一个开源的跨平台音视频处理库,可以用于对音视频文件进行编码、解码、
转码等操作。FFmpeg支持多种格式的音视频文件,包括常见的mp4、avi、flv等格式。
OpenCV 是一个开源的计算机视觉库,可以用于图像处理、目标识别、运动跟踪等方面。它
支持多种编程语言,包括C++、Python等,并且具有良好的跨平台性能。这两个库在音视
频处理和图像处理领域都非常流行,它们可以互相配合使用,例如,使用FFmpeg进行视频
解码,然后使用OpenCV 进行图像处理和分析。FFmpeg和OpenCV 都是常用的多媒体处
理库,它们在不同的方面都有着优秀的表现。而有时候需要将它们配合使用的原因如下: 

(1)FFmpeg可以编码和解码多种视频格式,而OpenCV 可以对视频图像进行分析和
处理。因此,当需要从视频文件中提取图像进行进一步处理时,可以使用FFmpeg进行视
频解码,然后使用OpenCV 对图像进行分析和处理。

(2)OpenCV 的图像处理能力非常强大,但是对于大规模的视频处理任务,OpenCV 可
能无法满足需求。而FFmpeg可以通过多线程和GPU 加速等技术提高视频处理的效率和
速度。当需要处理大规模的视频数据时,可以使用FFmpeg进行视频解码,然后使用
OpenCV 进行图像处理。

(3)有些特殊的视频格式,如一些实时视频流,可能不支持OpenCV 直接读取。这时候
就需要使用FFmpeg进行解码,并将解码后的视频帧转换成OpenCV 支持的格式,才能进
行进一步的图像处理。
因此,将FFmpeg和OpenCV 结合使用可以发挥它们各自的优势,在多媒体处理和图
像处理方面取得更好的效果。算能公司为了更好地利用硬件计算资源,又自行开发了
BMCV 库,其作用和OpenCV 一致,只是在程序的底层做了更多的硬件适配,能够更好地利


1 44 智能多媒体理论与实战(微课版) 
用硬件资源。
综合以上分析,开发者可以根据个人需求自行选择习惯的开发套件,例如选择OpenCV 
或者BMCV,必要时也可以利用不同的开发套件进行转换。下面给出了几种场景下各工具
相互转换的范例。
1.FFmpeg转换为OpenCV 
本例当使用完FFmpeg后需要调用OpenCV 接口。 
AVFrame *picture; 
... 
/* 中间经过FFmpeg 的一系列处理,例如avcodec_decode_video2()或者avcodec_receive_ 
frame(),然后将得到的结果转成Mat */ 
... 
/* card_id 为进行FFmpeg 硬件加速解码的设备序号,在常规Codec API 中,可以通过av_dict 
_set()的sophon_idx 指定,也可以在hwaccel 设备初始化的时候指定。SoC 模式下默认为
0 */ 
cv::Mat ocv_frame(picture,card_id) 
/* 还可以通过分步方式进行格式转换*/ 
cv::Mat ocv_frame; 
ocv_frame.create(picture,card_id); 
... 
/* 然后可以用ocv_frame 进行OpenCV 的操作,此时ocv_frame 格式为BM168x 扩展的yuv_ 
mat 类型。如果后续想转成OpenCV 标准的bgr_mat 格式,可以进行下列操作。注意:这里就有内
存同步的操作,如果没有设置,FFmpeg 默认是在设备内存中的,如果update= false,那么转换成
bgr 的数据也一直在设备内存中,系统内存中为无效数据;如果update= true,则设备内存同步到
系统内存中。如果后续还是用硬件加速处理,可以使update= false,这样可以提高效率。当需要
用到系统内存数据的时候,显式调用bmcv::downloadMat()同步即可*/ 
cv::Mat bgr_mat; 
/* 根据需要设定update 进行内存同步*/ 
cv::bmcv::toMAT(ocv_frame, bgr_mat,update); 
... 
/* 最后AVFrame *picture 会被Mat 中的ocv_frame()释放,因此不需要对picture 进行av 
_frame_free()操作。如果希望外部调用av_frame_free()释放图像,则可以加上card_id= 
card_id | UMatData::AVFRAME_ATTACHED,该标准表明AVFrame 的创建和释放由外部管理*/ 
ocv_frame.release(); 
picture = nullptr; 
2.OpenCV 转换为FFmpeg 
下面给出OpenCV 接口使用FFmpeg接口的实例。 
/* 创建yuv Mat。如果yuv Mat 已经存在,可以忽略此步。card_id 为BM168x 设备序号,SoC 
模式下默认为0 */ 
AVFrame *f = cv::av::create(height, width,AV_PIX_FMT_YUV420P,NULL,0,1,NULL, 
NULL,AVCOL_SPC_BT709,AVCOL_RANGE_MPEG,card_id); 
cv::Mat image(f,card_id); 
... 
/* 进行一些OpenCV 操作*/ 
...

第5章 嵌入式人工智能多媒体开发架构1 45 
AVFrame *frame = image.u->frame; 
/* call FFmpeg API */ 
... 
/* 注意: 在FFmpeg 调用完成前,必须保证Mat image 没有被释放,否则AVFrame 会和Mat 
image 一起释放。如果需要将这两个的声明周期分离开来,则上面的image 声明要改成如下格
式*/ 
cv::Mat image(f,card_id | UMatData::AVFRAME_ATTACHED); 
/* 这样Mat 就不会接管AVFrame 的内存释放工作*/ 
1)OpenCV 转换为BMCV 
下面给出OpenCV 接口转换为BMCV 接口的实例。 
cv::Mat m(height, width, CV_8UC3, card_id); 
... 
/* OpenCV 操作*/ 
... 
bm_image BMCV_image; 
/* 这里update 用来控制内存同步,是否需要内存同步取决于前面的OpenCV 操作。如果前面的
操作都是用硬件加速完成的,设备内存中就是最新数据,就没必要进行内存同步,如果前面的操作
调用了OpenCV 函数,没有使用硬件加速(5.3 节中提到了哪些函数采用了硬件加速),对于bgr 
mat 格式就需要进行内存同步。也可以在调用下面的函数之前,显式调用cv::BMCV::uploadMat 
(m)实现内存同步*/ 
cv::BMCV::toBMI(m,&BMCV image,update); 
... 
/* 使用BMCV_image 就可以进行BMCV 调用,调用期间注意保证Mat m 不能被释放,因为BMCV_ 
image 使用的是Mat m 中分配的内存空间,handle 可以通过bm_image_get_handle()获得*/ 
... 
/* 释放内存。必须调用此函数,因为在toBMI 中创建了bm_image,否则会有内存泄漏*/ 
bm image destroy(BMCV_image); 
m.release(); 
2)BMCV 转换为OpenCV 
下面给出BMCV 接口转换为OpenCV 接口的实例。 
bm_image BMCV_image; 
... 
/* 调用BMCV API 给BMCV_image 分配内存空间,并进行操作*/ 
... 
Mat m_copy,m_nocopy; 
/* 下面的接口将发生内存数据复制,转换成标准bgr mat 格式。update 控制内存同步,也可以
在调用完这个函数后用BMCV::downloadMat()控制内存同步。csc_type 是控制颜色转换的系
数矩阵,控制不同YUV 色彩空间转换到bgr */ 
cv::BMCV::toMAT(&BMCV_image, m_copy, update, csc_type); 
/* 下面的接口将直接引用bm_image 内存(nocopy 标志位为true),update 仍然按照前面的描
述,选择是否同步内存。在后续OpenCV 操作中,必须保证BMCV_image 没有释放,因为mat 的内
存直接引用自bm_image */ 
cv::BMCV::toMAT(&BMCV_image, &m_nocopy,AVCOL_SPC_BT709,AVCOL_RANGE_MPEG,NULL. 
-1,update, true); 
/* 往下可以进行OpenCV 操作*/

146智能多媒体理论与实战(微课版) 
..5.2FFmpeg5.2.1FFmpeg概述
FFmpeg是一套可以用来记录、转换数字音频、视频,并能将其转换为流的开源计算机
程序。它有非常强大的功能,包括视频采集、视频格式转换、视频抓图、给视频加水印等。
FFmpeg是在Linux平台下开发的开源项目,但它同样也可以在其他操作系统环境中编译
运行,包括Windows、macOS 等。
FFmpeg框架的基本组成包括AVFormat、AVCodec、AVFilter、AVDevice、AVUtil、
swresample和swscale模块库,如图5.8所示。
图5.g框架的基本模块

8 
FFmpe

(1)FFmpeg的封装模块AVFormat。FFmpeg中的媒体封装格式主要由编译时是否
包含该格式的封装库决定。一般通过在AVFormat中定制自己的封装格式以满足实际需
求。而AVFormat包含目前多媒体领域中的绝大多数媒体封装格式,如MP4 、FLV 、KV 、
TS 等文件封装格式,RTMP 、RTSP 、MMS 、HLS 等网络协议封装格式。

(2)FFmpeg的编解码模块AVCodec。该模块中实现了目前多媒体领域绝大多数常用
的编解码格式,既支持编码,也支持解码。AVCodec除了支持MPEG4 、AAC 、MJPEG 等自
带的媒体编解码格式之外,还支持第三方的编解码器。如果要使用第三方编码方式,则需要
安装对应的编码器。

(3)FFmpeg的滤镜模块AVFilter。该模块提供了一个通用的音频、视频、字幕等滤镜
处理框架,它可以有多个输入和多个输出。
(4)FFmpeg的设备管理模块AVDevice。FFmpeg的设备包括音频设备和视频设备。
该模块提供了各种设备的输入输出接口。
(5)FFmpeg的工具模块AVUtil。该模块是FFmpeg中的基础模块之一,许多其他模
块要依赖该模块实现基本的音视频处理操作。
(6)FFmpeg的音频转换计算模块swresample。该模块提供了高级别的音频重采样
API 。例如,利用它可以操作音频采样、音频通道布局转换与布局调整。

(7)FFmpeg的视频图像转换计算模块swscale。该模块提供了高级别的图像转换
API 。例如,利用它可以进行图像缩放和像素格式转换,常见操作是将图像从1080P 转换成
720P 或者480P 等,或者将图像数据从YUV420p转换成YUYV,或者将YUV 转换成RGB 
等图像格式。


第5章嵌入式人工智能多媒体开发架构147
在FFmpeg中也有可以供开发者使用的SDK,是为各个不同平台编译完成的库,可以
根据自己的需求使用这些库开发应用程序。
(1)libavcodec。包含音视频编码器和解码器。编解码库,封装了Codec层,但是有一
些Codec是有自己的许可证的。FFmpeg不会默认添加libx264、FDK-AAC、Lame等库,但
是FFmpeg是一个平台,可以将其他的第三方Codec以插件的方式添加进来,为开发者提供
统一接口。
(2)libavutil。包含多媒体应用常用的简化编程的工具,如随机数生成器、数据结构、数
学函数等功能。它是核心工具库,是最基础的模块之一,其他模块都会依赖该库做一些基本
的音视频处理操作。
(3)libavformat。包含多种多媒体容器格式的封装、解封装工具。它是文件格式和协
议库,封装了Protocol层和Demuxer、Muxer层,使得协议和格式对于开发者来说是透
明的。
(4)libavfilter。包含多媒体处理常用的滤镜功能。它是音视频滤镜库,包含了音频特
效和视频特效的处理。在使用FFmpeg的API进行编解码的过程中,可以使用该库高效地
为音视频数据做特效处理。
(5)libavdevice。用于音视频数据采集和渲染等功能的输入输出设备库。例如需要编
译播放声音或者视频的工具ffplay,就需要确保该库是打开的,同时也需要libsdl库的预先
编译,该设备模块播放声音和视频都使用libsdl库。
(6)libswscale。用于图像缩放以及色彩空间和像素格式转换。该库用于图像格式转
换,可以将YUV的数据转换为RGB的数据。
(7)libswresample。用于音频重采样和格式转换等。可以对数字音频进行声道数、数
据格式、采样率等多种基本信息的转换。
(8)libpostproc。用于进行后期处理。当使用滤镜的时候,需要打开这个模块,滤镜会
用到这个模块的一些基础函数。

作为音视频开发领域中最流行的开发库,FFmpeg编解码主要有两种方式,分别是软解
和硬解。通常在Windows下用FFmpeg不经过硬件加速进行编解码,称为软解。软解通过
CPU执行算法进行解码,消耗CPU资源。通过设置,可以指定利用显卡的解码芯片对视频
进行解码,则可称为硬解。

在智能多媒体应用中,FFmpeg常用于从摄像头拉取视频流,并进行视频流的解码提取
图像。FFmpeg支持RTSP拉流, 264和H.eg已经成

支持对H.265码流进行解码。FFmp
为各大人工智能芯片厂家必然支持的开发库。厂家通常对外提供统一的、兼容的FFmpeg
接口,在底层通过硬件对FFmpeg的编码或解码进行加速,这样既可以保证用户开发的一
致性,又可以充分发挥人工智能芯片的硬件性能。

以解码过程为例,图5.e

9显示了利用FFmpg进行解码的关键步骤。人工智能芯片厂
家通常会基于开源FFmpeg封装自己的代码。

5.2.2 
BM_FFmpeg 
在BM1684芯片中,提供了FFmpegSDK开发包,同时也提供了视频、图像等相关硬件
加速模块。通过这些硬件接口,提供了如下模块:硬件视频编码器、硬件视频解码器、硬件