海思MPP音视频总结

基础篇

1.常用图像格式介绍

常用图像像素格式 RGB 和 YUV。

1.1RGB

RGB分类通常指的是将图像或颜色按照RGB(红、绿、蓝)颜色空间进行分组或分类。RGB图像格式通常包括RGB24(RGB888)、RGB32、RGBA、RGB565等。

RGB24是一种常用的图像颜色格式,表示每个像素使用24位(8位红、8位绿、8位蓝)来存储颜色信息。

RGB32是在RGB24的基础上增加了一个8位的alpha通道,用于表示透明度。每个像素总共占用32位。

RGB565使用16位表示颜色,其中5位用于红色,6位用于绿色,5位用于蓝色,适用于减少内存占用的场景

1.2YUV

        YUV 图像是指将亮度参量 Y 和色度参量 U/V 分开表示的像素格式,主要用于优化彩色视频信号的传输。YUV 相比于 RGB 格式最大的好处是可以做到在保持图像质量降低不明显的前提下,减小文件大小。YUV 格式之所以能够做到,是因为进行了采样操作。主流的采样方式有三种:YUV 4:4:4(YUV444),YUV 4:2:2(YUV422),YUV 4:2:0(YUV420)。

若以以黑点表示采样该像素点的 Y 分量,以空心圆圈表示采用该像素点的 UV 分量,则这三种采样方式如下:

YUV 存储格式

YUV 存储可以分为两种:packed(打包)和 planar(平面);

  • packed:Y、U、V 分量穿插着排列,三个分量存在一个 Byte 型数组里;

  • planar:Y、U、V 分量分别存在三个 Byte 型数组中;

常见的像素格式

YUV422:YUYV、YVYU、UYVY、VYUY

这四种格式每一种又可以分为 2 类(packed和planar),以 YUYV 为例,一个 6*4 的图像的存储方式如下:

	Y Y Y Y Y Y                   
	Y Y Y Y Y Y                  
	Y Y Y Y Y Y                   
	Y Y Y Y Y Y                    
	U U U U U U                  Y U Y V Y U Y V Y U Y V
	U U U U U U                  Y U Y V Y U Y V Y U Y V
    V V V V V V                  Y U Y V Y U Y V Y U Y V
	V V V V V V                  Y U Y V Y U Y V Y U Y V
	- Planar -                          - Packed - 
YUV420:I420(YU12)、YV12、NV12、NV21
  • YUV420p: I420、YV12
  • YUV420sp: NV12、NV21

 同样,对于一个6*4的图像,这四种像素格式的存储方式如下:

	Y Y Y Y Y Y      Y Y Y Y Y Y      Y Y Y Y Y Y      Y Y Y Y Y Y
	Y Y Y Y Y Y      Y Y Y Y Y Y      Y Y Y Y Y Y      Y Y Y Y Y Y
	Y Y Y Y Y Y      Y Y Y Y Y Y      Y Y Y Y Y Y      Y Y Y Y Y Y
	Y Y Y Y Y Y      Y Y Y Y Y Y      Y Y Y Y Y Y      Y Y Y Y Y Y
	U U U U U U      V V V V V V      U V U V U V      V U V U V U
	V V V V V V      U U U U U U      U V U V U V      V U V U V U
     - I420 -          - YV12 -         - NV12 -         - NV21 -
  • I420、YV12 三个分量均为平面格式,即分别存在三个数组中;
  • NV12、NV21 的存储格式为 Y 平面,UV 打包,即 Y 信息存储在一个数组中,UV 信息存储在一个另一个数组中。

2.链表

2.1普通链表

2.1.1链表的难点

链表的难点  --->  指针。

口诀:

  • 变量变量,能变,就是能读能写,必定在内存里
  • 指针指针,保存的是地址,32处理器中地址都是32位的,无论是什么类型的指针变量,都是4字节

2.2改进链表

2.3常见双向链表宏
struct list_head
{
  struct list_head *next, *prev;
};
  • next:指向链表中下一个节点的指针。
  • prev:指向链表中上一个节点的指针。
  • 这个结构体用于表示链表的每个节点,允许在链表中双向遍历。
初始化链表头部
#define LIST_HEAD_INIT(name) { &(name), &(name) }
  • 这是一个宏,用于初始化链表头部。
  • 它将链表头部的 next 和 prev 指针都指向自身,表示这是一个空链表。
 声明和初始化一个新的链表头部
#define LIST_HEAD(name) \
    struct list_head name = LIST_HEAD_INIT(name)
  • 这个宏用于声明和初始化一个新的链表头部。
  • name 是用户指定的链表头的名称。该宏创建一个 struct list_head 类型的变量,并使用 LIST_HEAD_INIT 进行初始化。
 初始化已定义的链表头部
#define INIT_LIST_HEAD(ptr) do { \
    (ptr)->next = (ptr); (ptr)->prev = (ptr); \
} while (0)
  • 这个宏用于初始化已定义的链表头部。
  • ptr 是指向链表头的指针,宏将其 next 和 prev 指针都设置为指向自身,以表示它是一个空链表。
 在链表中增加链表项
static __inline__ void __list_add(struct list_head *new,
                                   struct list_head *prev,
                                   struct list_head *next)
{
    next->prev = new;   // 将新节点的下一个节点的 prev 指针指向新节点
    new->next = next;   // 新节点的 next 指向原本的下一个节点
    new->prev = prev;   // 新节点的 prev 指向前一个节点
    prev->next = new;   // 前一个节点的 next 指向新节点
}
  • 参数

    • new:要添加的新节点。
    • prev:新节点要插入的位置之前的节点。
    • next:新节点要插入的位置之后的节点。
  • 功能:将新节点 new 插入到链表中,位置在 prevnext 之间。函数首先更新 next 节点的 prev 指针,使其指向新节点,然后更新新节点的 nextprev 指针,最后更新 prev 节点的 next 指针,以完成插入操作。

 在链表中替换列表项
static inline void list_replace(struct list_head *old,
                                 struct list_head *new)
{
    new->next = old->next;               // 新节点的 next 指向旧节点的下一个节点
    new->next->prev = new;               // 旧节点下一个节点的 prev 指向新节点
    new->prev = old->prev;               // 新节点的 prev 指向旧节点的前一个节点
    new->prev->next = new;               // 旧节点的前一个节点的 next 指向新节点
}
  • 参数

    • old:要被替换的旧节点。
    • new:新的节点,将替换旧节点。
  • 功能:替换链表中的旧节点 old 为新节点 new。函数更新新节点的 nextprev 指针,并相应地调整链表中相邻节点的指针,使链表保持连贯。

帧类型

        在视频编解码中,帧类型的设计是为了优化压缩效率,同时平衡图像质量和解码复杂度。H.264/AVC、HEVC、VP9等现代视频编码标准采用了不同类型的帧,它们在视频流中扮演着不同的角色,协作完成视频的压缩和传输。以下是常见的视频帧类型及其特点:

I帧(Intra Frame,关键帧)

  • 特点:I帧是完全自包含的帧,它包含了完整的图像信息,解码时不依赖其他帧。这是视频序列中的基准帧。
  • 压缩效率:I帧通常是压缩效率最差的,因为它没有参考其他帧的信息,必须保存完整的图像数据,因此比P帧和B帧占用更多的比特率。
  • 用途:I帧常用于视频流的关键位置,如播放开始、快进、快退等地方,或者在发生数据丢失时需要恢复图像时(例如在流媒体传输中)。它也是随机访问的基础。
  • 特点总结
    • 无需参考其他帧即可解码。
    • 关键帧,用于帧间依赖关系的起点。
    • 相对压缩效率较低,文件较大。

P帧(Predictive Frame,预测帧) 

  • 特点:P帧是参考前一帧(I帧或P帧)来编码的帧。它只记录与参考帧之间的差异信息(运动矢量和预测误差),从而实现更高的压缩比。
  • 压缩效率:由于P帧仅记录变化部分,而不是整个图像,它的压缩效率远高于I帧,通常占用较少的比特率。
  • 用途:P帧常用于视频序列中较为稳定的场景,能够有效减少冗余数据,适用于动态场景但不涉及太大变化的部分。
  • 特点总结
    • 依赖于之前的帧(I帧或P帧)来进行解码。
    • 通过运动估计和差异编码减少数据量,压缩效率较高。
    • 用于编码有较小变化的部分,效率高于I帧。

B帧(Bidirectional Frame,双向预测帧) 

  • 特点:B帧是参考前后两帧(I帧或P帧)进行编码的帧。它通过前后帧之间的差异信息(运动矢量和预测误差)来进行编码,提供比P帧更高的压缩效率。
  • 压缩效率:B帧具有最高的压缩效率,因为它可以参考前后帧的信息进行预测,从而能够精确地描述当前帧的图像内容,减少冗余数据。
  • 用途:B帧常用于图像变化不大、动态平稳的部分,尤其是在高压缩比要求下。它们也有助于提高视频编码质量,尤其是在低比特率场景中。
  • 特点总结
    • 需要前后帧作为参考帧来解码。
    • 通过双向预测减少数据量,压缩效率最好。
    • 不适合实时编码,因为它依赖于前后的帧,解码过程延迟较高。

帧类型之间的关系和作用:

  • I帧(关键帧):不依赖任何其他帧,可以独立解码。作为基准帧,I帧是视频流中的关键组成部分,用于恢复丢失的帧或进行快速访问(如跳跃播放、快进快退)。
  • P帧(预测帧):依赖前一个帧(I帧或P帧),通过存储与参考帧的差异来提高压缩效率,减少冗余数据。
  • B帧(双向预测帧):依赖前后两帧进行预测,压缩效率最高,但解码时需要前后帧的缓存,这会增加延迟。

帧类型的编码策略:

  • 帧间压缩:P帧和B帧都依赖于其他帧进行编码,因此它们通过减少不必要的信息来有效地减小视频的大小。P帧通过参考之前的帧,B帧则参考前后两帧。
  • 关键帧与非关键帧:I帧是关键帧,P帧和B帧是非关键帧。关键帧是视频流的基础,用于提供完整的图像数据,而非关键帧则依赖于其他帧的图像信息来完成解码。

NAL单元(Network Abstraction Layer units) 网络抽象层单元

SPS(Sequence Parameter Set)包
  • 功能:SPS包包含了视频序列的全局配置信息,如视频的分辨率、帧率、色度格式、比特率等信息。它是解码视频流所必需的,定义了整个视频流的编码结构。
  • 在I帧中的作用:每个视频序列通常有一个SPS,它通常会出现在流的开头,用于设置解码器的参数。在I帧之前(或者在I帧内),需要SPS来告诉解码器如何解码视频的各个部分。
PPS(Picture Parameter Set)包
  • 功能:PPS包包含了图像层面的配置信息,例如量化参数、帧类型、解码表格等,它是解码单个帧所必需的。
  • 在I帧中的作用:PPS通常与SPS一起传输,用于指导解码器如何解码具体的图像(帧)。每一帧都可能有不同的PPS,尤其是在视频编码过程中,不同的帧可能会使用不同的参数。
SEI(Supplemental Enhancement Information)包
  • 功能:SEI包用于携带额外的信息,这些信息并不直接影响视频的显示,但可以用来提供额外的功能或支持,如色彩空间信息、场景切换标记、流的冗余数据等。
  • 在I帧中的作用:虽然SEI包不是必需的,但它可以在I帧中携带一些辅助信息,比如用于视频增强的元数据或解码器的行为指令。在一些高级应用中,SEI包可以用于辅助解码或提高视频质量。
I-slice包
  • 功能:I-slice包包含了I帧的具体数据。I帧是关键帧,包含完整的图像信息,不依赖其他帧。
  • 在I帧中的作用:I-slice包包含了视频帧的像素数据,是I帧的核心内容。每个I帧通常由一个或多个slice组成,每个slice可以被独立解码。
 为什么I帧包含这些不同的NAL包?
  • SPS和PPS包:它们是解码器所需的基本配置参数,SPS和PPS可以出现在视频流的开头或者在I帧之前,为解码器提供必要的信息。
  • SEI包:虽然它不是解码视频所必需的,但它可以携带额外的控制信息或辅助数据,在一些视频流中可以用于增强视频的播放效果或提供其他元数据。
  • I-slice包:这是实际的视频数据,是I帧的主要内容,I帧被用作视频流中的关键点(例如快速跳转时的参考点)。
是否每个I帧都包含4个NAL包?

并不是每个I帧都会严格包含这4种NAL包,具体情况依赖于编码设置和视频流的结构。例如:

  • I帧的NAL包:I帧的NAL单元至少会包含一个或多个I-slice包。SPS和PPS包并不是每个I帧都需要独立传输。它们通常在视频流的开始就已经发送过,之后的视频帧可以复用这些参数包。
  • SEI包:是否包含SEI包取决于编码器的设置以及是否有额外的增强信息需要传输。它不是必须的,因此并不是所有I帧都会包含SEI包。
总结
  • I帧包含多个NAL包,这些包分别承担不同的任务。
  • SPS包:包含视频序列参数,通常在I帧之前传输。
  • PPS包:包含帧参数,通常也会在I帧之前传输。
  • SEI包:可选,用于传输附加信息。
  • I-slice包:包含I帧的实际编码图像数据。

海思平台

媒体处理平台架构

主要的处理流程介绍如下:

        

        可以看到主要分为视频输入(VI)、视频处理(VPSS)、视频编码(VENC)、视频解码(VDEC)、视频输出(VO)、视频拼接(AVS)、音频输入(AI)、音频输出(AO)、音频编码(AENC)、音频解码(ADEC)、区 域管理(REGION)等模块,几个主要模块的大致功能为:

VI模块:捕获视频图像,可对其做剪切、去噪等处理,并输出多路不同分辨率的图像数据。

VDEC模块:解码模块对编码后的视频码流进行解码,并将解析后的图像数据送 VPSS 进行图像处理,再送 VO 显示。可对 H.265/H.264/JPEG 格式的视频码流进行解码。

VPSS模块:接收 VI 和解码模块发送过来的图像,可对图像进行图像增强、锐化等处理,并实现同源输出多路不同分辨率的图像数据用于编码、预览或抓拍。

VENC模块:编码模块接收 VI 捕获并经 VPSS 处理后输出的图像数据,可叠加用户通过 Region
模块设置的 OSD 图像,然后按不同协议进行编码并输出相应码流。

VO模块:接收 VPSS 处理后的输出图像,可进行播放控制等处理,最后按用户配置的协议输出给外围视频设备。

AVS模块:接收多路VI采集的图像,进行拼接合成全景图像(这里的AVS是指“视频拼接子系统”,我之前一直以为是编解码的AVS标准)。

AI模块:捕获音频数据,然后AENC模块支持按多种音频协议对其进行编码,最后输出音频码流。

ADEC模块:用户从网络或外围存储设备获取的音频码流可直接送给ADEC模块,ADEC支持解码多种不同的音频格式码流,解码后数据送给AO模块即可播放声音。

视频缓存池

功能:视频缓存池主要向媒体业务提供大块物理内存管理功能,负责内存的分配和回收,充
分发挥内存缓存池的作用,让物理内存资源在各个媒体处理模块中合理使用。
构成:一组大小相同、物理地址连续的缓存块组成一个视频缓存池。
使用注意点: 必须在系统初始化之前配置公共视频缓存池 。根据业务的不同,公共缓存池的数量、缓存块的大小和数量不同。
典型的公共视频缓存池数据流图:所有的视频输入通道都可以从公共视频缓存池中获取视频缓存块用于保存采集的图像,如图中所示 VI 从公共视频缓存池 B 中获取视频缓存块 Bm, 缓存块 Bm VI 发送给VPSS,输入缓存块 Bm 经过 VPSS 处理之后被释放回公共视频缓存池。假设 VPSS 通道的工作模式是USER ,则 VPSS 通道 0 从公共视频缓存池 B 中获取缓存块 Bi 作为输出图像缓存buffer发送给 VENC VPSS 通道 1 从公共视频缓存池 B 中获取缓存块 Bk 作为输出图像缓存buffer 发送给 VO Bi VENC 编码完之后释放回公共视频缓存池, Bk VO 显示完之后释放回公共视频缓存池。
                

系统绑定

        MPP提供系统绑定接口(HI_MPI_SYS_Bind),即通过数据接收者绑定数据源来建立两者之间的关联关系(只允许数据接收者绑定数据源)。绑定后,数据源生成的数据将自动发送给接收者。目前MPP支持的绑定关系如下:

数据源数据接受者
VIVO 、VENC、VPSS、PCIV、VI(虚拟PIPE)
VPSSVO、VENC、VPSS、PCIV、VI(虚拟PIPE)、AVS
VDECVO、VENC、VPSS、PCIV、VI(虚拟PIPE)
VO(WBC)VO、VENC、VPSS、PCIV、VI(虚拟PIPE)
AVSVO、VENC、VPSS、PCIV、VI(虚拟PIPE)
AIAO、AENC
ADECAO

海思提供绑定函数 HI_MPI_SYS_Bind 来实现数据源与数据接受者的绑定:

HI_S32 HI_MPI_SYS_Bind(const MPP_CHN_S *pstSrcChn, const MPP_CHN_S
*pstDestChn);
  •   pstSrcChn指源通道指针
  •   pstDestChn指目的通道指针
  •   API需求的头文件为:hi_comm_sys.h、mpi_sys.h,需求的库文件为:libmpi.a

 注意:同一个数据接收者只能绑定一个数据源

VENC绑定VI为数据源示例:

HI_S32 SAMPLE_COMM_VI_UnBind_VENC(VI_PIPE ViPipe, VI_CHN ViChn, VENC_CHN VencChn)
{
    MPP_CHN_S stSrcChn;
    MPP_CHN_S stDestChn;
 
    stSrcChn.enModId   = HI_ID_VI;
    stSrcChn.s32DevId  = ViPipe;
    stSrcChn.s32ChnId  = ViChn;
 
    stDestChn.enModId  = HI_ID_VENC;
    stDestChn.s32DevId = 0;
    stDestChn.s32ChnId = VencChn;
 
    CHECK_RET(HI_MPI_SYS_UnBind(&stSrcChn, &stDestChn), "HI_MPI_SYS_UnBind(VI-VENC)");
 
    return HI_SUCCESS;
}

解绑的API为 HI_MPI_SYS_UnBind 

HI_S32 HI_MPI_SYS_UnBind(const MPP_CHN_S *pstSrcChn, const MPP_CHN_S
*pstDestChn);

注意:pstDestChn如果找不到绑定的源通道,则直接返回成功。如果找到了绑定的源通道,但是绑定的源通道和pstSrcChn不匹配,则返回失败。

若需将上面的VENC和VI解绑,示例如下: 

HI_S32 SAMPLE_COMM_VI_UnBind_VENC(VI_PIPE ViPipe, VI_CHN ViChn, VENC_CHN VencChn)
{
    MPP_CHN_S stSrcChn;
    MPP_CHN_S stDestChn;
 
    stSrcChn.enModId   = HI_ID_VI;
    stSrcChn.s32DevId  = ViPipe;
    stSrcChn.s32ChnId  = ViChn;
 
    stDestChn.enModId  = HI_ID_VENC;
    stDestChn.s32DevId = 0;
    stDestChn.s32ChnId = VencChn;
 
    CHECK_RET(HI_MPI_SYS_UnBind(&stSrcChn, &stDestChn), "HI_MPI_SYS_UnBind(VI-VENC)");
 
    return HI_SUCCESS;
}

VO篇

        VO(Video Output,视频输出)模块主动从内存相应位置读取视频和图形数据,并通过相应的显示设备输出视频和图形。

        海思平台VO(视频输出)通常分为显示设备、视频层、图像层。

以海思SS528为例,说明如下

VO模块包含了三路显示设备

  • 超高清显示设备DHD0(Device HD0,高清设备0)

        视频层VHD0(Video layer of DHD0)
        视频层VHD2(Video PIP layer)
        图形层G0(Graphic layer 0)
        图形层G2(Graphic layer 2)
        图形层G3(Graphic layer 3)

  • 高清显示设备DHD1(Device HD1,高清设备1)

        视频层VHD1(Video layer of DHD1)
        视频层VHD2(Video PIP layer)
        图形层G1(Graphic layer 1)
        图形层G2(Graphic layer 2)
        图形层G3(Graphic layer 3)

  • 标清显示设备DSD0(Device SD0,标清设备0)

        视频层VSD0(Video layer of DSD0)
        图形层G2(Graphic layer 2)
        图形层G3(Graphic layer 3)

显示设备

        SS528平台支持三路显示设备,分别为两路高清DHD0和DHD1,支持1路标清DSD0,三路显示设备的输出接口和最大输出时序如下图:

视频层

        视频层建立在设备之上,用于视频显示,视频层可以把解码、视频处理子系统处理后的视频流数据显示到视频层的某个通道上。

        海思平台通常在每个显示设备都会对应一个视频层,来用于视频的显示,VHD0、VHD1、VSD0分别固定绑定在DHD0、DHD1、DSD0上面。而VHD2,也就是PIP层,支持动态绑定在DHD0或DHD1上。

VO通道

        在视频层之下,有多个通道,每一个通道都可以单独显示视频数据,视频被限制在通道内,通道被限制在视频层内。对于一个视频层,其上面的通道都是独立的。同时,不同的视频层上的通道也是独立的。对于通道的排号上面不存在跨层的连续,对于系统绑定,应该使用视频层号和通道号来进行绑定配置。

SS528各个视频层通道数:

        VHD0:支持64通道(SINGLE模式)、支持64通道(MULTI模式)
        VHD1:支持64通道(SINGLE模式)、支持64通道(MULTI模式)
        VHD2(PIP):支持64通道(SINGLE模式)、不支持通道(MULTI模式)
        VSD0:支持64通道(SINGLE模式)、不支持通道(MULTI模式)

1.如何读取一张YUV420格式的图片到内存(通常用于保存固定背景图)

  1. 根据显示图片文件名获取图片长和宽的大小(调用strstr函数获取文件名中特定字段的位置)
  2. 由图片长款大小,分别计算亮度、色度、图片字节大小(亮度大小=图片分辨率,色度大小=(图片分辨率>>4)*2,图片大小=二者相加)
  3. 创建视频缓存池VB(默认D1分辨率704*576,ipc子码流通常为D1大小)
  4. 从创建好的缓存池中,获取缓存块(大小为要显示图片的大小)
  5. 一个帧缓存块所在缓存池的 ID
  6. 获取缓存块的物理地址,并转化对应的虚拟地址。
  7. 到此准备工作结束
  8. 图像帧结构体进行赋值,(缓存池ID、图像数据物理地址、图像数据虚拟地址、宽、高、视频图像像素格式-yuv420图像数据跨距{图像宽大小}、帧场模式
  9. 只读模式fopen打开要显示图像文件,fread读取图像数据到虚拟地址中

2.如何通过VO的设备ID来获取VO设备的亮度、色度、对比度、锐度等参数

  1. 遍历VO设备的链表,从链表节点 pos 中获取对应的 VoDevEntry 结构体指针
  2. 判断找到的VO链表项的voID是否和传入的设备ID相等
  3. 如果相等,获取VO设备结构体中的亮度、色度、对比度等参数
static int GetVoDevData(int voId, VoDevStruct **devStruct)
{
    int result = ERR_DEVID;
    struct list_head *pos = NULL;
    struct list_head *save = NULL;

    //确保 voId 和 devStruct 参数的有效性
    VO_CHECK_VOID(voId);
    CHECK_POINTER(devStruct);

    //使用 list_for_each_safe 宏安全遍历链表 voDevs
    list_for_each_safe(pos, save, &voDevs) 
    {
        //通过链表节点获取对应的 VoDevStruct 结构体指针
        (*devStruct) = list_entry(pos, VoDevStruct , node);
        //检查 (*devStruct) 是否为 NULL,如果是,记录错误并返回
        if (NULL == (*devStruct))
        {
            LogErr("find vo info err. voId = %d\n", voId);
            result = ERR_INPOITERNULL;
            goto EXIT_0;
        }

        //如果找到匹配的 voId,则设置 result 为成功状态 ERR_OK,并跳出循环
        if ((*devStruct)->voId == voId)
        {
            result = ERR_OK;
            break;
        }
    }
    
EXIT_0:

    return result;
}

3.VO子系统如何接收VPSS发送的视频流

        以输出一张背景图举例,在此例子中,vpss会直接处理背景图数据。

        1.将背景图yuv数据保存到内存中,操作方法可参考上述第一条总结。

        2.解绑vo通道上的绑定关系

        3.清楚vo通道buffer内容(否则可能会出现残留上一帧内容的清空)

        4.将内存中的的yuv数据,保存到图像帧结构体中

        5.设置绑定参数,请求vpss与vo直接绑定,记录当前绑定关系,返回绑定句柄(用于后期解绑操作)

        6.给vpss发送帧图像数据,vpss会处理原图像数据,比如说原始图像是704*576(D1)大小,现在需要单画面在1920*1080显示器上显示,那这个分辨率的变化,就需要vpss这边自动去处理,等处理完成后,vpss自动将数据发送给vo去显示。由于vpss和vo直接是绑定关系,vo接收vpss的数据是自动进行的,不需要做其他操作。

        7.解绑vpss和vo的绑定关系

ps:在此示例中,vpss接收数据到处理数据可以理解为一个组,在这个组里面有物理通道和扩展通道,物理通道由硬件提供,负责数据的输出和处理,扩展通道通过绑定物理通道,实现图像的缩放功能,但没有对应的硬件,而是通过软件实现。

4. VO模块如何实现视频流的播放控制等操作

1.基本播放控制

        播放:启动视频流的播放

        暂停:暂停当前播放状态,保持当前帧

        停止:停止视频播放并重置状态。

2.快进/快退

允许用户在视频中快速前进或后退,调整播放速度

3.帧控制

        单帧播放:逐帧播放功能,适合于分析视频内容

        跳帧:可以跳过指定数量的帧,以加快播放进度

4.音视频同步

确保音频和视频在播放时保持同步,处理音频延迟或视频卡顿的情况

5.缓冲管理

动态管理视频帧缓冲区,优化播放性能,避免卡顿现象。

6.显示参数调整

支持分辨率、亮度、对比度等显示参数的调整,以适应不同显示设备的需求

5.VO模块如何按照用户配置的协议输出给外围设备

6.VO的开启和停止实现方式

1.VO开启

1.确定显示设备(DHD0、DHD1),构建vo公共参数,完成配置vo设备公共属性。

  • bg_color   背景色、
  • intf_type    接口类型(VGA、HDMI、BT1120、MIPI、RGB_24等)
  • intf_sync   接口时序(VO_OUT_1280x800_60、VO_OUT_1080P60等

2.使能视频输出设备,调用接口开启视频dev。

3.构建视频层属性结构体,获取视频显示宽、高、像素格式、等参数

4.设置视频层属性,使能视频层。调用SDK接口函数完成设置视频层属性,使能视频层。

视频层属性

  • display_rect   视频显示区域矩形结构体,SINGLE模式下display_rect为动态属性;MULTI模式下display_rect为静态属性。
  • img_size    图像分辨率结构体,即合成画面尺寸,静态属性。
  • display_frame_rate  视频显示帧率
  • pixel_format   视频层输入像素格式:YUV444、YUV422、YUV420
  • 其他参数等

5.设置通道属性参数并使能视频通道。获取窗口通道数,先获取再设置通道属性,使能视频通道。

通道属性:

  • priority 视频通道叠加优先级,数值越大优先级越大
  • rect        通道矩形显示区域
  • deflicker_en  是否使能抗闪烁

6.设置HDMI属性参数,开启HDMI输出。设置设备HDMI输出图像效果,设备HDMI属性,启动HDMI输出。

HDMI输出图像效果参数

  • csc_matrix CSC转换矩阵,YUV颜色空间转RGB颜色空间
  • luma 亮度值
  • contrast 对比度值
  • hue 色调值
  • saturation 饱和度值

HDMI属性参数

  • hdmi_en 是否强制HDMI输出。TD_TRUE:强制HDMI输出;TD_FALSE:DVI输出。
  • video_format 视频制式。此参数需要与VO配置的制式保持一致
  • deep_color_mode DeepColor输出模式。默认为HDMI_DEEP_COLOR_24BIT
  • audio_en 是否使能音频
  • sample_rate 音频采样率,此参数需要与AO的配置保持一致
  • bit_depth 音频位宽,默认为16,此参数需要与AO的配置保持一致
  • auth_mode_en 使能该模式,HDMI强制输出,不再去根据显示或认证设备的EDID信息来自适应调整
  • deep_color_adapt_en 是否打开驱动Deepcolor自适应策略
  • pix_clk 用户设置自定义时序的像素时钟

2.VO停止

VO停止是VO开启的逆过程

1.禁用指定的视频输出通道

2.禁用视频层

3.禁用视频输出设备

视频处理子系统(VPSS)篇

        支持对输入图像进行统一预处理,如去噪、去隔行、裁剪等,然后再对各通道分别进行处理,如缩放、加边框等。

常见的几个概念

Group:

VPSS对用户提供组(Group)的概念。最大个数请参见 VPSS_MAX_GRP_NUM定义,各Group分时复用VPSS硬件,硬件依次处理各个组提交的任务。

group实际上是对VPSS硬件功能的虚拟化,即若系统里只有一个group,那么这个group实际就是VPSS;若有多个group,那么就是一会给group0用一会给group1用,这就是分时复用。

Channel:

VPSS 组的通道。一个 VPSS组提供多个通道,每个通道具有缩放等功能。

通道分为 2 种:物理通道扩展通道。 VPSS 硬件提供多个物理通道,每个通道具有缩放、裁剪等功能。扩展通道具备缩放功能,它通过绑定物理通道,将物理通道输出作为自己的输入,把图像缩放成用户设置的目标分辨率输出。
chn是Grp里面的通道,这个通道有物理的有扩展的,物理通道有对应的硬件,扩展通道没有对应的硬件,扩展通道其实是对应了一些功能(缩放等)

  • 物理通道
    视频物理通道负责将输入设备解析后得到的视频数据输出到 DDR。在真正将数据 输出到 DDR 之前,它可以实现裁剪等功能,具体功能见各芯片的详细描述。
  • 扩展通道
    扩展通道是物理通道的扩展,主要实现缩放功能,其数据来源于物理通道。

FRC:

帧率控制分为两种:组帧率控制和通道帧率控制。
– 组帧率控制:用于控制各Group 对输入图像的接收。
– 通道帧率控制:用于控制各个通道图像的处理。

Crop:

从图像中裁剪指定区域。裁剪类型分为绝对坐标裁剪和相对比例裁剪。
– 组裁剪,对输入图像做裁剪;
– 物理通道裁剪,对物理通道图像做裁剪;
– 扩展通道裁剪,对扩展通道图像做裁剪。

DEI:

De-interlace,去隔行。将交错的隔行视频源还原成逐行视频源。

3DNR:

去噪。通过参数配置,把图像中的高斯噪声去除,使得图像变得平滑,有助于降低编码码率。

IE:

Image Enhance,图像增强。

Scale:

缩放,对图像进行缩小放大。缩放倍数指水平、垂直各缩放多少倍。

Mosaic

– 马赛克,对VPSS输出图像在指定区域填充马赛克块。
– 马赛克区域宽度要求4像素对齐,马赛克区域部分超出图像时,水平方向软件
会自适应向下4对齐裁剪掉超出部分。

固定角度

旋转物理通道支持0度、90度、180度以及270度固定角度的旋转功能。

等其他

功能描述

通过调用 SYS 模块的绑定接口,可与 VPSS/USER/VDEC/VI VO/VENC/SVP 等模块进行绑定,其中前者为VPSS 的输入源,后者为 VPSS 的接收者。用户可通过 MPI 接口对Group进行管理。每个 Group 仅可与一个输入源绑定。 Group 的物理通道有两种工作模式:AUTO USER ,两种模式间可动态切换。 AUTO 模式下各通道仅可与一个接收者绑定,主要用于预览和回放场景下做播放控制。USER 模式下各通道可与多个接收者绑定。
需要特别注意USER模式主要用于对同一通道图像进行多路编码的场景,此模式下播 放控制不生效,因此回放场景下不建议使用USER模式 VPSS 只有工作在离线模式下才支持AUTO 模式。

在VI对sensor采集完的图像做好处理后,可以让VPSS的group和VI的通道进行绑定,从而进行裁剪操作,然后VPSS的组输出多路channel产生不同分辨率的视频,用于不同操作。
实际上VPSS的作用大部分在于缩放,用于视频预览;一些帧率控制、裁剪的功能VI也能完成,那么用于功能性的视频通道,如算法处理、抓图,就可以直接使用VI出来的拓展通道,这样就能少一次传输,不用走VPSS再到算法,一定程度上节省DDR的带宽。

注:海思中的VI的chn和VPSS的chn是两回事,VI那边的chn是VI里面Dev里面的chn,VI那边DEV的地位有点类似于VPSS这边的Grp。对接的时候是VI这边的chn去绑定VPSS这边的Grp。
 
参考文档:https://blog.csdn.net/qq_28258885/article/details/118796350

VDEC篇

参考文档:【海思SS528 | VDEC】MPP媒体处理软件V5.0 | 视频解码模块——学习笔记-CSDN博客

VDEC模块提供驱动视频解码硬件工作的MPI接口,实现视频解码功能。不同硬件平台,对视频解码的能力也不相同,以海思平台SS528为例,其解码性能如下:

SS528V100平台

  • 硬件解码模块: VDH、JPEGD
  • 支持最大通道数:128
  • 支持协议:VDH:H.264/H.265    JPEGD:JPEG/MJPEG
  • 支持最大、最小分辨率

        VDH:

                H.264:最大:8192 * 8192    最小:96 * 96

                H.265:最大:8192 * 8192    最小:96 * 96

        JPEGD:

                JPEG/MPEG:最大:16384 * 16384        最小:8*8

                                

码流发送方式

1.流式发送

用户每次可发送任意长度码流到解码器,由解码器内部完成一帧码流的识别过程。

优点:不需自己检查帧的开始、结束;
缺点:不能希望马上开始解码图像,也就是解码可能会稍微延时。

2.按帧发送

用户每次发送完整一帧码流到解码器,每调用一次发送接口,解码器就认为该帧码流已经结束,开始解码图像,因此需保证每次调用发送接口发送的码流必须为一帧,否则会出现解码错误。

优点:可以达到快速解码的目的;
缺点:需要自己判断是否为完整的编码帧,要等一帧完整数据才可发送。

3.按兼容模式发送

支持一帧码流分多次发送给解码器,但是每帧码流结束时必须配置帧结束标志end_of_frame为TD_TRUE,否则认为当前帧码流还未结束。

优点:不需要等到一帧数据都到了才发送。
缺点:需要自己判断是否编码帧结束。

图像输出方式

根据H.264/H265/MPEG4协议,解码图像可能不会在解码后立即输出。VDEC解码
器可以通过设置不同的图像输出方式达到尽快输出的目的。图像输出方式包括以
下两种:

  • 解码序:解码图像按照解码的先后顺序输出。
  • 显示序:解码图像按照H.264/H.265/MPEG4协议输出。

根据H.264/H.265/MPEG4协议,视频的解码顺序未必是视频的输出顺序(即显示
序)
例如B帧解码时需要前后的P帧作为参考,所以B帧后的P帧先于B帧解码,
但B帧先于P帧输出
。按解码序输出是保证快速输出的一个必要条件,用户选择按
解码序输出,需保证码流的解码序与显示序相同。
按帧发送码流与按解码序输出相结合能达到快速解码和快速输出的目的,用户必
须保证每次发送的是完整的一帧码流以及码流的解码序和显示序相同。

解码帧存分配方式

1.解码ModuleVB池

创建解码通道时不分配图像Buffer,而是由用户调用相应的MPI接口创建专属于解码模块的ModuleVB池,该VB池只允许VDEC获取VB块,其它模块只能使用不能获取。

2.解码UserVB池

创建解码通道时不分配图像Buffer,而是由用户调用接口ss_mpi_vb_create_pool创建一个视频缓存VB池,再通过调用接口ss_mpi_vdec_attach_vb_pool把某个解码通道绑定到固定的视频缓存VB池中。

3.解码PrivateVB池

创建解码通道时由VDEC创建私有VB池作为该通道的图像Buffer,用户可以在创建通道接口ss_mpi_vdec_create_chn中设置私有VB池的个数frame_buf_cnt和VB块的大小frame_buf_size

        三种解码帧存分配方式可通过接口ss_mpi_vdec_set_mod_param的参数vb_src来设置。当解码帧存使用ModuleVB池或者UserVB池方式时,可以不用销毁解码通道直接销毁VB池,但是销毁解码VB池前用户必须保证没有任何模块正在使用这个VB池里的任何一块VB(可通过复位解码通道,以及复位解码直接绑定的后级模块实现,如VDEC绑定VPSS,则就要同时复位VDEC和VPSS;如果用户是从VDEC里获取图像上去,也必须保证全部图像释放回VDEC。),否则会出现程序异常的情况。

如何解码H264视频文件,输出显示

1.系统初始化及视频缓存池初始化

  1. 获取图像缓存区属性(图像的宽、高、像素格式、色彩深度、压缩模式等),计算一帧图像缓存块大小。
  2. 去初始化MPP系统,去初始化MPP视频缓存池
  3. 设置MPP视频缓存池属性(只能在系统处于未初始化的状态下,才可以设置缓存池属性
    1. blk_cnt 每个缓存池的缓存块个数。
    2. blk_size 缓存块大小,以Byte为单位。
    3. pool_size 缓存池大小,以Byte为单位。
    4. pool_phy_addr 缓存池首地址。
    5. remap_mode VB的内核态虚拟地址映射模式。
  4. 初始化MPP视频缓存池,初始化MPP系统(由于MPP系统的正常运行依赖于缓存池,因此需要先调用ss_mpi_vb_init初始化缓存池,再初始化MPP系统
  5. 设置vdec通道属性(解码类型、流宽高、码流发送方式【按帧发送】、解码模式【I P B帧】、数据为宽、参考帧个数、像素格式、透明度值)
  6. 计算视频缓存块大小,配置视频缓存池,初始化模块公共视频缓存池(解码ModuleVB池)

2.H264码流文件解码

  1. 根据vdec解码通道属性参数,创建视频解码通道
  2. 对创建的视频解码通道,设置解码通道参数(先获取,再设置)
  3. 解码器开始接收用户发送的码流。

3.视频处理(VPSS)

  1. 配置vpss组属性参数
    1. 视频流的宽、高
    2. 像素格式
    3. 关闭去交错功能(将交错扫描的视频转换为逐行扫描格式)
  2. 配置vpss通道属性参数
    1. vpss通道宽、高(画中画的大小也在此设置)
    2. 通道模式(AUTO和USER模式,AUTO模式下各通道仅可与一个接收者绑定,主要用于预览和回放场景下做播放控制。USER模式主要用于对同一通道图像进行多路编码的场景,此模式下播放控制不生效)
    3. 压缩模式
    4. 像素格式
    5. 宽高比模式
    6. 等……
  3. 启动vpss配置流程
    1. 创建一个VPSS Group
    2. 启动一个VPSS Group
    3. 分别设置VPSS组内的所有物理通道属性
    4. 分别启动VPSS组内的的所有通道(Group必须已创建
  4. vdec与vpss绑定(特别注意:vdec的通道和vpss的组进行绑定,而不是vpss的通道

4.输出显示使能

  1. 构建vo配置
    1. 参考VO篇最后的vo设备开启与停止内容。
  2. 启动vo
    1. 参考VO篇最后的vo设备开启与停止内容。
  3. vpss和vo进行绑定(特别注意:vpss的组和vo通道进行绑定,而不是vpss的通道

5.发送流到vdec

  1. 构建vdec线程参数结体,根据vdec通道数,创建对应通道线程。
  2. 构建视频解码的码流结构体,线程内部循环读取h264文件,并从读取的文件中定位h264码流的一帧图像的帧头和帧尾。
    1. 视频解码的码流结构体参数:
    2. end_of_frame 当前帧是否结束
    3. end_of_stream 是否发完所有码流
    4. need_display 当前帧是否输出显示
    5. pts 码流包的时间戳。以μs为单位
    6. private_data 私有数据,仅支持帧模式和兼容模式
    7. len 码流包的长度,以byte为单位
    8. addr 码流包的地址
  3. 调用海思结构向视频解码通道发送码流数据(指定vdec通道和码流结构体)。注:当发完所有码流后,把end_of_stream置为1,表示码流文件结束,这时解码器会解完发送下来的所有码流并输出所有图像。如果发完所有码流后把end_of_stream置为0,解码器内部可能残余大于等于一帧的图像未解码输出,因为解码器必须等到下一帧码流到来才能知道当前帧已经结束,送入解码。
  4. 当线程接收到结束指令,关闭视频解码通道,释放内存资源。

6.解绑绑定关系释放资源

VENC篇

如何监听venc各个通道处理的视频流数据

在venc视频编码处理流程中,用如下结构体来描述venc各通道是否有数据被编码处理。

typedef struct {
    FILE *file[VENC_MAX_CHN_NUM];            // 文件指针数组,用于存储多个视频通道输出的文件指针。
    int venc_fd[VENC_MAX_CHN_NUM];        // 视频编码器的文件描述符数组,用于操作每个编码通道的流。
    int maxfd;                              // 用于 `select` 系统调用中的最大文件描述符。
    int picture_cnt[VENC_MAX_CHN_NUM];    // 每个通道的图片计数,用于跟踪已经处理的帧数或图片数。
    char file_name[VENC_MAX_CHN_NUM][FILE_NAME_LEN];    // 存储每个视频通道的文件名(不带路径)。
    char real_file_name[VENC_MAX_CHN_NUM][PATH_MAX];    // 存储每个视频通道的完整文件路径。
    venc_chn venc_chn;                       // 视频编码通道的结构体,可能存储每个通道的配置或其他相关信息。
    char file_postfix[10];                   // 文件后缀名数组,最多存储10个后缀名。
    int chn_total;                           // 视频通道总数。
} sample_comm_venc_stream_proc_info;

参数说明:

file[VENC_MAX_CHN_NUM]:

        这个数组是一个 FILE * 类型的指针数组,用于存储每个编码通道输出流对应的文件指针。VENC_MAX_CHN_NUM 是宏定义,表示最大的视频编码通道数。

venc_fd[VENC_MAX_CHN_NUM]:

        这是一个 int 类型的数组,存储每个视频编码通道的文件描述符。文件描述符是与 I/O 操作相关的标识符,可以用于 read、write 或 select 等系统调用

maxfd:

        这是一个整数,可能用于存储所有文件描述符中的最大值。该值通常用于 select 调用中,告诉 select 监听的最大文件描述符

        该结构体的定义是用于一个视频流处理的系统。每个视频编码通道都有一个文件描述符(venc_fd)和一个文件指针(file)。程序会通过 select 来监听多个视频通道的数据流,或者管理输出文件的操作(例如,将编码后的视频数据写入到文件)。其他字段如 picture_cnt 和 file_name 用于跟踪每个通道的处理进度和文件路径。

代码实现如下:

while (para->thread_start == TRUE) {	//这个条件用来检查线程是否应该继续运行。TRUE 表示线程继续运行。
    FD_ZERO(&read_fds);		//清空文件描述符集 read_fds
    for (i = 0; (i < stream_proc_info.chn_total) && (i < VENC_MAX_CHN_NUM); i++) {
        FD_SET(stream_proc_info.venc_fd[i], &read_fds);		//将每个通道的视频编码器文件描述符 venc_fd[i] 添加到 read_fds 集合中。这些文件描述符代表从视频编码器(VENC)读取数据的通道。
    }

    timeout_val.tv_sec = 2; /* 2 is a number */	//设置为 2 秒,这意味着 select 系统调用会阻塞最多 2 秒,等待文件描述符有数据可读
    timeout_val.tv_usec = 0;
    ret = select(stream_proc_info.maxfd + 1, &read_fds, NULL, NULL, &timeout_val);	
    //用于等待文件描述符集合中的某些描述符就绪(可以读取)。它会阻塞,直到其中至少有一个描述符准备好,或者超时;stream_proc_info.maxfd 应该是当前监视的最大文件描述符值 + 1
    if (ret < 0) {		//如果 select 返回值小于 0,表示出错,打印错误信息并退出循环
        print("select failed!\n");
        break;
    } else if (ret == 0) {		//如果返回值为 0,表示在超时时间内没有文件描述符变为可读状态,打印超时信息并继续循环
        print("get venc stream time out, exit thread\n");
        continue;
    } else {		//如果返回值大于 0,表示有至少一个文件描述符变为可读状态,接着调用 sample_comm_fd_isset 函数处理这些文件描述符。
        sample_comm_fd_isset(&stream_proc_info, &read_fds, stream_buf_info, payload_type, para);
    }
}

static void sample_comm_fd_isset(sample_comm_venc_stream_proc_info *stream_proc_info, fd_set *read_fds,
    venc_stream_buf_info *stream_buf_info, payload_type *payload_type, sample_venc_getstream_para *para)
{
    int i, ret;

    for (i = 0; (i < stream_proc_info->chn_total) && (i < VENC_MAX_CHN_NUM); i++) {
        if (FD_ISSET(stream_proc_info->venc_fd[i], read_fds)) {		
    //对于每个通道,使用 FD_ISSET() 宏检查该通道的文件描述符 stream_proc_info->venc_fd[i] 是否被设置在 read_fds 中,即检查该文件描述符是否准备好读取。如果文件描述符可读,程序会继续处理该通道的数据。
            stream_proc_info->venc_chn = para->venc_chn[i];
            ret = sample_comm_get_stream_from_one_channl(stream_proc_info, i, stream_buf_info, payload_type);	//调用函数获取该通道的流数据,并将数据存储到 stream_buf_info 中,负载类型存储到 payload_type 中
            if (ret == SAMPLE_RETURN_CONTINUE) {
                continue;
            } else if (ret == SAMPLE_RETURN_BREAK) {
                break;
            }
        }
    }
}

如何配置vb,并设置视频缓存区的大小

1.获取vb属性参数

venc视频缓存块结构体

typedef struct {
    int valid_num;
    long blk_size[VB_MAX_COMMON_POOLS];
    int blk_cnt[VB_MAX_COMMON_POOLS];
    int supplement_config;
} sample_venc_vb_attr;
  • valid_num:该字段表示 sample_venc_vb_attr 结构体中有效的块池数量。通常这个值表示当前实际使用的块池数量。
  • blk_size:该数组定义了每个块池的块大小。每个块池都有一个对应的块大小,表示每个块池中每个块的大小
  • blk_cnt:该数组定义了每个块池中块的数量。每个块池有一个对应的块数量,表示该块池中可用块的个数。
  • supplement_config:该字段通常用于存储一些补充的配置选项
  1. 通常blk_size 等于一帧图像的大小根据图像的宽和高计算该图像的大小,在根据图像的像素格式,计算出一帧图像的大小。
  2.   blk_cnt:一个缓存池中,缓存块的数量。根据实际情况,进行计算。

2.初始化并设置缓存池

调用还是接口完成以下配置:

  1. 设置MPP视频缓存池属性
  2. 初始化MPP视频缓存池
  3. 初始化MPP系统。包括音频输入输出、视频输入输出、视频编解码、视频叠加区域、视频处理、图形处理等模块都会被初始化。

VENC编码模块配置流程

1.确定GOP图像组模式,并获取GOP属性参数

1)用户通过给定配置,来确定编码的GOP模式,通常GOP模式有如下几种:

单P帧模式

双P帧模式

B帧GOP模式

注:具体模式请参考上述GOP模式章节内容

2)根据GOP模式确定gop属性参数,不同的GOP模式对应不同的属性参数。

typedef struct {
    venc_gop_mode gop_mode;   // GOP 模式
    union {
        venc_gop_normal_p    normal_p;        // NORMAL_P 模式的编码参数
        venc_gop_dual_p      dual_p;          // DUAL_P 模式的编码参数
        venc_gop_smart_p     smart_p;         // SMART_P 模式的编码参数
        venc_gop_adv_smart_p adv_smart_p;      // ADV_SMART_P 模式的编码参数
        venc_gop_bipred_b    bipred_b;        // BIPRED_B 模式的编码参数
    };
} venc_gop_attr;

2.获取H.264/H.265视频编码通道参数

根据gop通道属性参数,设置H.264/H.265视频编码通道属性参数,它包括了与视频编码通道相关的一些关键配置,如帧率、GOP(图像组)参数、编码大小、视频类型等。结构体字段如下:

typedef struct {
    td_u32 frame_rate;               // 帧率,决定了视频每秒显示的帧数
    td_u32 stats_time;               // 统计时间
    td_u32 gop;                      // GOP 长度
    ot_size venc_size;               // 编码尺寸,视频编码时的宽度和高度
    ot_pic_size size;                // 图片尺寸,视频图像的实际分辨率,通常用于表示图像的宽高
    td_u32 profile;                  // 编码配置文件(如 H.264 或 H.265 的不同配置文件)
    td_bool is_rcn_ref_share_buf;    // 是否共享参考图像的缓冲区
    ot_venc_gop_attr gop_attr;       // GOP 属性
    ot_payload_type type;            // 视频编码的格式类型(例如 H.264 或 H.265)
    sample_rc rc_mode;               // 码率控制模式,常见的码率控制模式有 CBR(常码率)、VBR(可变码率)等
} sample_comm_venc_chnl_param;

3.H.264/H.265创建并启动视频编码通道

        此部分创建并启动视频编码通道以便开始接收并处理视频帧。它主要执行两个步骤:创建编码通道和启动接收编码图像。

创建编码通道
  1. 设置编码视频帧率和GOP长度;
  2. 获取图片的实际尺寸(可能是分辨率),并将其转化为适合编码的尺寸
  3. 将之前获取的编码通道参数(venc_create_param)转化成视频编码通道属性(venc_chn_attr)。
  4. 调用海思提供接口函数,创建编码通道。
  5. 设置码率控制器参数。根据通道属性参数下的码率控制器模式确定,码率控制器模式(VBR、CBR),并调用海思接口进行设置

开启接收编码图像
  1. 设置接口图像数量。通常该值设置为-1;表示不限制接收图像的数量,一直接收直到终止信号。
  2. 调用海思接口mpi_venc_start_chn 函数来启动视频编码通道。

4.视频处理系统(VPSS)通道组与视频编码系统(VENC)通道绑定

        调用海思接口,使vpss通道组venc通道进行绑定。

5.创建线程开启视频流接收

区域管理篇

        用户一般都需要在视频中叠加OSD(On-Screen Display)用于显示一些特定的信息(如:通道号、时间戳等),必要时还会填充色块。这些叠加在视频上的OSD和遮挡在视频上的色块统称为区域。REGION模块,用于统一管理这些区域资源。区域管理可以实现区域的创建,并叠加到视频中或对视频进行遮挡。例如,实际应用中,用户通过创建一个区域,通过ss_mpi_rgn_attach_to_chn,将该区域叠加到某个通道(如VENC通道)中。在通道进行调度时,则会将OSD叠加在视频中。一个区域支持通过设置通道显示属性接口指定到多个通道中(如:多个VENC通道,多个VI通道,甚至多个VENC和VI通道),且支持在每个通道的显示属性(如位置、层次、透明度等)都不同。

重要概念

区域类型

  • OVERLAY:视频叠加区域,其中区域支持位图的加载、背景色更新等功能
  • OVERLAYEX:扩展视频叠加区域,功能与OVERLAY类似,支持位图加载、背
    景色更新等
  • COVER:视频遮挡区域,其中区域支持纯色块遮挡。
  • COVEREX:扩展视频遮挡区域,功能与COVER类似,支持纯色块遮挡。
  • LINE:扩展的线条视频叠加区域,支持颜色、粗细等调节。
  • MOSAIC:马赛克遮挡区域,支持精度调节
  • MOSAICEX:扩展的马赛克遮挡区域,支持精度调节。
  • CORNER_RECTEX:角框区域,支持大小,颜色,粗细等调节。

注:OVERLAYEX/ COVEREX/MOSAICEX,分别相对于 OVERLAY/COVER/MOSAIC,功能上类似,但是会引入额外的系统带宽,OVERLAYEX/COVEREX/ MOSAICEX由VGS叠加到图像上,OVERLAYEX/ COVEREX区域越大,占用VGS的性能就越大,当VGS性能不足时,会导致帧率降低。建议只有当OVERLAY/COVER/MOSAIC不支持,或者数量无法满足需求时,再使用。

区域层次

        区域层次表示区域的叠加级别,对于相同的区域类型,层次值越大,表示区域的显示级别越高,当发生重叠时,层次值大的将会覆盖层次值小的,区域层次相同时以客户调用attach的顺序为准。不同的区域类型以模块的处理顺序为准。

区域公共属性

        用户创建一个区域时,需要设置该属性信息,它包含公共的资源信息。例如,OVERLAY包含像素格式,大小和背景色。

通道显示属性

        通道显示属性表明区域在某通道的显示特征。例如,OVERLAY的通道显示属性包含显示位置,层次,前景Alpha,背景Alpha,还有编码用到的qp信息。当通道显示属性中的区域是否显示(is_show)为TRUE时,表示显示在该通道中;反之,表示在该通道中存在,但处于隐藏状态。

音频篇

        AUDIO模块包括音频输入、音频输出、音频编码、音频解码四个子模块。音频输入和输出模块通过对芯片音频接口的控制实现音频输入输出功能。音频编码和解码模块提供对G711、G726、ADPCM格式的音频编解码功能,并支持录制和播放LPCM格式的原始音频文件。

视频图像子系统

        VGS是视频图形子系统,全称为Video Graphics Sub-System。支持对一幅输入图像进行处理,如进行缩放、像素格式转换、视频存储格式转换、压缩/解压、Cover、OSD、Mosaic、画线、旋转、亮度和统计、Corner_rect、拼接等处理。

基本概念

● job
        VGS管理task的结构,一个job里可以包含多个task,VGS保证task按照添加到job
的顺序执行,并且保证一个job里的所有task一次性提交硬件执行。用户可以在加
载VGS ko时设置模块参数(g_max_vgs_job)来设置VGS支持的最大job数。job数
取值范围为[20,400],默认为128。
● task
        对一幅图像完成具体的一个或多个操作,比如打OSD、缩放或像素格式转换等。
用户可以在加载VGS ko时设置模块参数(g_max_vgs_task)来设置VGS支持的最
大task数。task数取值范围为[20,800],默认为200。
● node
        VGS硬件的最小执行单位,一个task对应一个或多个node。node中包含硬件工作
需要的信息,比如源图像地址,目标图像地址,操作类型等,并按照硬件要求的
形式组织。用户可以在加载VGS ko时设置模块参数(g_max_vgs_node)来设置
VGS支持的最大node数。node数取值范围为[20,800],默认为200。
● HANDLE
        任务句柄,标识一个job。

功能描述

        VGS的功能主要有缩放、OSD、Cover、Mosaic、画线、像素格式转换、视频存储格式转换、压缩/解压、旋转、亮度和统计、Corner_rect、拼接、低功耗策略。

● Cover
        VGS支持对一幅图像进行遮挡操作,遮挡区域形状可以是矩形或者任意四边形,
遮挡区域颜色为纯色,支持批量打Cover。
● Mosaic
        VGS支持对一幅图像进行打Mosaic操作,Mosaic块大小有8x8、16x16、32x32、
64x64四种选择,Mosaic区域形状为矩形,每个Mosaic块为纯色,支持批量打Mosaic。
● 画线
VGS支持对一幅图像进行画线操作,支持批量画线。

● 像素格式转换
        VGS支持的输入输出像素格式包括semi-planar 420、semi-planar 422和单分量(Y)。支持semi-planar 420与semi-planar 422之间的格式转换,支持semiplanar 420、semi-planar 422到单分量(Y)格式的转换,做像素格式转换时,
支持UV先后顺序可调整。
● 视频存储格式转换
        VGS支持Tile格式转为linear格式。
● 压缩/解压
        VGS支持linear格式下semi-planar 422、semi-planar 420和单分量(Y)格式的压缩/解压。支持Tile格式下semi-planar 420格式的解压缩。
● 亮度和统计
        统计图像的指定区域亮度信息之和。支持批量统计。
● 旋转
        VGS支持0、90、180和270度的旋转。

视频侦测篇

        视频侦测分析(VDA)通过检测视频的亮度变化,得出视频侦测分析结果。VDA包含
运动侦测(MD)和遮挡检测(OD)两种工作模式,视频侦测分析结果也由当前工作
模式区分为运动侦测结果和遮挡检测结果:
        ● 运动侦测(MD)侦测VDA通道接收的视频的运动状态,并输出运动侦测结果。包
含每帧图像的宏块SAD值信息、运动区域(OBJ)信息和整帧报警像素个数。
        ● 遮挡检测(OD)检测VDA通道接收的视频是否出现被遮挡现象,并输出遮挡检测
结果。
        ● 用户通过创建VDA通道,绑定视频输入源,启动VDA。每个通道只能选择一种工
作模式,并根据工作模式配置相关通道属性,具体配置事项参见
ss_mpi_vda_create_chn。

文章持续更新中……

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值