从接触这个平台到现在已接近一年时间,之前很多时间虽然一直在这个平台做应用还有部分的驱动,但是一直没真正理解这个平台到底真正的优势和技术难点在哪里,其实也就是最近搞这个平台的SWMS时才有了更进一步的认识,从底层的硬件到上层的dvrrdk的学习,学习了这个四核视频协处理平台的软件框架。
介绍
DVR RDK是一个为ti816x,ti814x,ti810x平台设计的多处理器的软件开发框架,专门优化了多路视频主要应用在DVR, NVR, Hybrid-DVR, HD-DVR 。在DVR RDK软件框架允许用户创建不同的多路视频数据流包括:视频采集、视频处理(DEI、缩放、噪声滤波、软件拼接,SWMS, OSD,运动检测等),视频编码(H264,MJPEG)、视频解码(H264、MPEG4、mpjeg)和视频显示(HDMI,hddac,CVBS等)。
DVR RDK的用户接口或API叫做McFW(多通道框架)。软件本身是建立在一个称为“Links and chains”的多处理器框架。该框架优化的多通道视频,因而成千上万的视频帧需要在不同的视频处理任务交换的应用程序。这个框架的内部接口被称为““Link API”。
DVR RDK组件
DVR RDK关键部件的总结:
软件框架
软件组件分布在四个处理器之间去共享处理:
• VPSS M3 - is used for Video capture, display, scaling, de-interlacing
• Video M3 - is used H264, MPEG4, MJPEG encode/decode
• DSP - is used for additional SW based video processing and video analytics
• A8 - is used for system control, GUI, SATA, Ethernet, USB and other IO
编程接口
McFW API
这个接口将视频系统分为四个主要子系统:
视频采集、显示、编码、解码
Link API
(1)、link api的概念
link在上图中的视频数据流中是最基本的单元模块,每个link中包含了一个基于BIOS6/Linux的任务、线程、消息盒(使用操作系统的信号量实现)。由于每个link运行一个独立的现成,因此link之间可以并行运行。消息盒是关联用户指定的link,让link之间有个互相对话的机制,用来传递信令。而对于视频流数据、帧数据的传递link实现了专门的接口来实现,只传递指针,而不是数据。
在实现上节所介绍的数据流可以通过将多个link连接来实现chain,link API允许用户Create、Start、Stop、Delete、Control各个link。在Rdk中TI基于link API进行再次封装,用于特定的应用场合,其各种参数均是为特定的产品定制,可以是相关业务的开发更迅速。
(2)、link内部结构
(3)、link的特性
视频处理的工作量可以均衡到每个核心上去执行,如下表:
-每个link都有自己独立的任务/线程用于完成视频采集或播放等处理;
-每个link都可以处理来自多个通道的视频帧数据,每个通道的视频宽高和数据格式都可以不同;
-A8作为HOST可以用来连接多个link形成数据流的链并对其进行控制;
-数据链被建立并启动时,数据链中的每个link将和它的下游link进行帧数据的交互;
-links之间的帧数据交互可以在多个核心之间进行,并且并不需要A8 HOST的干涉,从而降低A8的开销;
-在数据链运行过程中用户可以发送控制信令给任意link来动态设置相关的link参数;
(4)、link接口
link接口可以分成以下几类:
-link API——被用户调用来配置和控制link的接口;
-Inter link API——被其他links调用来交换帧数据的接口;
-link output queue——被其他links通过Inter Link API接口实用的帧buffer队列;
(5)、link间的消息传递
每个Link通过一个32位的该LinkId来识别,ID高4位标识了这个Link是在哪个核上运行,低24位标识了该Link的名称:
每个Link API都需要这个LinkID参数来发送消息,当用户发送消息到一个Link时,根据这ID函数内部判断这个消息是发给本地的Link还是远端核心的Link;如果是本地的直接调用BIOS/LINUX API函数,否则就通过Syslink模块的MessageQ发送这个消息到指定的核心,让对端的核心调用对应的函数处理。
(6)、link API
(7)、Inter link API
在每个link中必须实现一些函数并在初始化时注册这些函数指针给link管理的核心模块,用于帧数据的获取、释放、dump相关状态等。
对于任一个link想从它的上游link获取帧数据都需要调用link管理核心函数System_getLinksFullFrames(),该函数内部会发送消息到对应的上游link,触发该link向管理模块注册的回调函数System_LinkGetOutputFramesCb()将帧数据传递给该link;
同样的,在当一个link想释放处理完毕的帧buffer给上游link时需要调用link管理核心函数System_putLinksEmptyFrames(),该函数内部会发送消息到对应的上游link,触发它注册的回调函数System_LinkPutEmptyFramesCb()将帧buffer回收,用于后续的数据处理;
建立chain时,你肯定还会关注一个信息,那就是上游link的相关参数如何传递给下游的link,从源程序仔细琢磨琢磨就可以看出来,和上面的处理类似,所有有下游link的link都会注册一个System_GetLinkInfoCb()的回调函数,在下游link的driver中会在创建driver时调用System_linkGetInfo()函数来获取上游link的相关参数。
通过上述的方法,对于一个link来说就不需要关心和它交互的是哪一个link,所有的寻址都通过linkID来自动查找,并且同一个link实现可以和不同的link交互,而不需要改变函数的实现。
(8)、Link Output Queues 的管理
一个Link可以有一个或多个输出队列用来存放采集到的或处理完毕的帧数据,每个Link的输出队列内存由自己分配;
大多数Links只有一个输出队列,但是有些link有多个,从而可以实现多路不同的输出数据流满足不同的应用需求,例如,Noise filter Link可以输出16路帧数据到2个输出队列,每个输出队列输出8路通道数据跟别给2个DEI Links模块处理。
一个输出队列中可以有多个视频channels的数据,每个channel可以有不同的大小和数据格式;
数据结构 FVID2_Frame是在VPSS驱动中定义的,Links之间就通过该结构参数传递帧数据的信息,如帧数据的Buf指针,而帧数据本身并不会被拷贝,从而节省内存开销;
当一个Link采集完或处理完一帧数据后会发送一个消息“SYSTEM_CMD_NEW_DATA”给下游的Link,从而通知它有数据可取;当下游Link收到该消息后会调用System_getLinksFullFrames()函数来获取对用的帧数据,处理完后再调用System_putLinksEmptyFrames()函数来归还给上游Link继续使用。
因此一个Link需要知道:
--上游Link的LinkID和QueID,从而从该队列里面获取帧数据
--下游LinkID,从而在有新数据产生时通知下游Link来取
上游Link的LinkID和QueID 以及下游LinkID 都是在System_linkCreate()时由A8 HOST端来指定的。
(9)、IPC link核间帧数据交互
IPC Link,是用来多核之间的帧数据传递的。
如VPSS上的采集Link想把帧数据发送给Video Link处理,先将帧数据传递给本地的IPC Link,然后IPC Link再通过Syslink/IPC发送到Video Link上的IPC Link,然后再转发给Video Link,这样的话对于采集Link的实现来说就非常清晰简单,它的实现都是发送给本地的另一个Link;
IPC Link的实现有点复杂,因为它涉及的帧数据传递是在多个核之间,这里面就牵扯到cache的一致性问题,考虑到每个核的特性以及高效性,总共设计了3个内部Links用于帧数据的传递机制:
Intra-processor links
即同一核心内部的link,如采集与降噪之间的帧数据传递,这种内部的link间传递帧数据都是在VPSS M3内部完成,因此采用简单且高效的队列机制实现。
Inter M3 (Video / VPSS) links
即M3内部核心之间的link,由于Video和Vpss所在的2个M3核心是同属于一个双核M3处理器,它们的cache是共享的;如降噪模块(VPSS NF)到编码模块(VIDEO Enc)之间传递帧数据,带有Notify的IPC ListMP机制被用来在这2个M3核心之间传递帧信息(FVID2_Frame),该过程中不需要任何cache操作和地址转换。
Inter processor (M3 to A8 or DSP)
即处理器内部核心之间,如编码(VideoM3)到BitStream In(HostA8)之间传递帧数据,同样使用带Notify的IPC ListMP机制在2个核心之间传递帧信息(FVID2_Frame),但该过程中需要做cache同步和地址转换操作。
(10)、chain数据链路的建立
一个Chain是由多个links按照一定的应用需求按顺序连接成一条视频处理的数据流。
一个Chain可以销毁后重新按照新的需求组成新的Chain,不需要重启系统。
Chain创建是特别需要相关link的顺序
-通过System_linkCreate()函数按照由source>>sink 的顺序创建需要的Links,Source Link即没有上游Link的Link,如:视频采集;Sink Link是没有下游Link的Link,如:视频播放;这个创建顺序是非常重要的,因为一个Link创建时它会查询上游Link的一些信息,如上游Link需要的channel的个数和属性,从而按照这些参数配置自己。
-下一步调用System_linkStart()函数启动每个Link,启动顺序一般从Sink Link往前到Sorce Link,当然你也可以不按照这个顺序,不过不推荐,因为这样可以保证每个Link在它的上游Link启动前准备好接收数据,避免过多的缓冲引入额外的时延。
-当一个Chain运行后控制命令就可以发送到各个Links来控制它,如调用System_linkControl()函数发送改变画面合成风格的命令给相应的Link,具体的命令定义由每个Link的功能实现来决定;
-注意:一般来说System_linkControl()函数是在System_linkCreate()创建了Link之后才能调用,不过有些控制命令可以在System_linkCreate()调用之前调用,以完成Link创建之前必须的一些初始化,如复位;
-当Chain工作完成或销毁时可以调用System_linkStop()函数先停止每个Link,注意:停止的顺序必须从Source开始依次到Sink结束;因为一个Link可能阻塞着等待下游Link释放当前Link的输出Buffer,如果下游Link先停止的话当前Link可能会出于wait for ever的状态而永久退不出来,因此上游Link必须先停止,之后才能停止下游Link;
-最后等所有Link全部停止后,可以调用System_linkDelete()函数删除所有Links,删除顺序没有要求;
-当Chain销毁后就可以按照之前的顺序重新创建一个新的Chain来完成另一个工作了。
关键术语
基于rdk框架的一个四库输入两路输出的一个实例:
/*******************************************************************************
* *
* Copyright (c) 2009 Texas Instruments Incorporated - http://www.ti.com/ *
* ALL RIGHTS RESERVED *
* *
******************************************************************************/
/* This usecase assumes that all 3 outputs - D1 + CIF + D1 are enabled */
/*------------------------------ D1 + CIF + D1 -------------------------------------
Capture (YUV422I) 4CH D1 60fps
|
|
|
|
DEI
|+------------------------------------------------------------------------
| | |
(DEI-SC YUV422I) (VIP-SC YUV420 ) (VIP-SC1 YUV420 )
D1 D1 | CIF|
| | |
| | |
| | |
----------------- | |
D1_DUP_LINK_IDX | |
----------------- | |
| | | |
| | | |
| | | |
| NSF | |
| (YUV420) | |
| | | |
| | | |-----------------
| |----------------------------- | |
| | | |
| 2| |0 | 1
| | ||
| | | |
| | | |
| ---------------------------------
| D1_CIF_MERGE_LINK_IDX
| ---------------------------------
| |
| |
| |
| FRAMESOUT(VPSS)---------------<<>>----FramesInDSP--------ALG_LINK
| |
| |
| |
| |
| IPCM3OUT(VPSS)------IPCM3IN(VID)----ENC-----IPCBITS_RTOSOUT(VID)-----IPCBITS_HLOSIN(HOST)-----FILEOUT
| |
| |
| |
| |
|+--------------------------IPCM3IN(VPSS)---------IPCM3OUT(VID)---------DEC---------------IPCBITS_RTOSIN(VID)-----------IPCBITS_HLOSOUT(HOST)
|
|
LIVE_DECODE_MERGE_LINK_IDX
|
|
|
LIVE_DECODE_DUP_LINK_IDX
|||
|||
|||
+---------------+|+----------------+
| |
| |
SW Mosaic 1 SW Mosaic 0
(SC2 YUV422I) (SC5 YUV422I)
| |
| |
| |
| |
| |
| |
------------- -------------
DISPLAY 1 DISPLAY 0
------------- -------------
---------
PAL/NTSC 1080p60 1080p60
*/
#include "mcfw/src_linux/mcfw_api/usecases/multich_common.h"
#include "mcfw/src_linux/mcfw_api/usecases/multich_ipcbits.h"
// Keeping TILER disabled for 4D1 usecase
#define TILER_ENABLE FALSE
/* =============================================================================
* Use case code
* =============================================================================
*/
static SystemVideo_Ivahd2ChMap_Tbl systemVid_encDecIvaChMapTbl =
{
.isPopulated = 1,
.ivaMap[0] =
{
.EncNumCh = 16,
.EncChList = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 , 14, 15},
.DecNumCh = 16,
.DecChList = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 , 14, 15},
},
};
// #define ADD_NSF_AFTER_CAPTURE
#define NUM_MERGE_LINK 2
#define D1_CIF_MERGE_LINK_IDX 0
#define LIVE_DECODE_MERGE_LINK_IDX 1
#define NUM_DUP_LINK 2
#define D1_DUP_LINK_IDX 0
#define LIVE_DECODE_DUP_LINK_IDX 1
#if(defined(TI_814X_BUILD) || defined(DDR_MEM_256M))
#define NUM_CAPTURE_BUFFERS 8
#define NUM_NSF_BUFFERS 4
#define NUM_ENCODE_D1_BUFFERS 4
#define NUM_ENCODE_CIF_BUFFERS 4
#define NUM_DECODE_BUFFERS 4
#define NUM_SWMS_MAX_BUFFERS 8
#define BIT_BUF_LENGTH_LIMIT_FACTOR_SD 4
#else
#define NUM_CAPTURE_BUFFERS 8
#define NUM_NSF_BUFFERS 6
#define NUM_ENCODE_D1_BUFFERS 6
#define NUM_ENCODE_CIF_BUFFERS 6
#define NUM_DECODE_BUFFERS 6
#define NUM_SWMS_MAX_BUFFERS 8
#define BIT_BUF_LENGTH_LIMIT_FACTOR_SD 6
#endif
#define MAX_BUFFERING_QUEUE_LEN_PER_CH (50)
#define NUM_CAPTURE_DEVICES 1
/* This usecase assumes CIF , MJPEG are enabled */
Void MultiCh_createProgressive4D1VcapVencVdecVdis()
{
CaptureLink_CreateParams capturePrm;
NsfLink_CreateParams nsfPrm;
DeiLink_CreateParams deiPrm;
MergeLink_CreateParams mergePrm[NUM_MERGE_LINK];
DupLink_CreateParams dupPrm[NUM_DUP_LINK];
static SwMsLink_CreateParams swMsPrm[VDIS_DEV_MAX];
DisplayLink_CreateParams displayPrm[VDIS_DEV_MAX];
IpcLink_CreateParams ipcOutVpssPrm;
IpcLink_CreateParams ipcInVpssPrm;
IpcLink_CreateParams ipcOutVideoPrm;
IpcLink_CreateParams ipcInVideoPrm;
EncLink_CreateParams encPrm;
DecLink_CreateParams decPrm;
IpcBitsOutLinkHLOS_CreateParams ipcBitsOutHostPrm;
IpcBitsOutLinkRTOS_CreateParams ipcBitsOutVideoPrm;
IpcBitsInLinkHLOS_CreateParams ipcBitsInHostPrm[2];
IpcBitsInLinkRTOS_CreateParams ipcBitsInVideoPrm;
CaptureLink_VipInstParams *pCaptureInstPrm;
CaptureLink_OutParams *pCaptureOutPrm;
IpcFramesInLinkRTOS_CreateParams ipcFramesInDspPrm;
IpcFramesOutLinkRTOS_CreateParams ipcFramesOutVpssPrm;
AlgLink_CreateParams dspAlgPrm;
System_LinkInfo bitsProducerLinkInfo;
UInt32 mergeId[NUM_MERGE_LINK];
UInt32 dupId[NUM_DUP_LINK];
UInt32 ipcOutVpssId, ipcInVpssId;
UInt32 ipcOutVideoId, ipcInVideoId;
IpcBitsOutLinkRTOS_CreateParams ipcBitsOutDspPrm;
VCAP_DEVICE_CREATE_PARAM_S vidDecVideoModeArgs[NUM_CAPTURE_DEVICES];
UInt32 vipInstId;
UInt32 i, j;
Bool enableAlgLink;
Bool enableScd = gVsysModuleContext.vsysConfig.enableScd;
Bool enableOsd = gVsysModuleContext.vsysConfig.enableOsd;
UInt32 chId;
#ifdef ADD_NSF_AFTER_CAPTURE
NsfLink_CreateParams nsfPrm2;
#endif
enableScd = TRUE;
enableAlgLink = FALSE;
if(enableOsd||enableScd)
enableAlgLink = TRUE;
MULTICH_INIT_STRUCT(IpcLink_CreateParams,ipcOutVpssPrm);
MULTICH_INIT_STRUCT(IpcLink_CreateParams,ipcInVpssPrm);
MULTICH_INIT_STRUCT(IpcLink_CreateParams,ipcOutVideoPrm);
MULTICH_INIT_STRUCT(IpcLink_CreateParams,ipcInVideoPrm);
MULTICH_INIT_STRUCT(IpcBitsOutLinkHLOS_CreateParams,ipcBitsOutHostPrm);
MULTICH_INIT_STRUCT(IpcBitsOutLinkRTOS_CreateParams,ipcBitsOutVideoPrm);
MULTICH_INIT_STRUCT(IpcBitsOutLinkRTOS_CreateParams,ipcBitsOutDspPrm);
MULTICH_INIT_STRUCT(IpcBitsInLinkHLOS_CreateParams,ipcBitsInHostPrm[0]);
MULTICH_INIT_STRUCT(IpcBitsInLinkHLOS_CreateParams,ipcBitsInHostPrm[1]);
MULTICH_INIT_STRUCT(IpcBitsInLinkRTOS_CreateParams,ipcBitsInVideoPrm);
MULTICH_INIT_STRUCT(DecLink_CreateParams, decPrm);
MULTICH_INIT_STRUCT(IpcFramesInLinkRTOS_CreateParams,ipcFramesInDspPrm);
MULTICH_INIT_STRUCT(IpcFramesOutLinkRTOS_CreateParams,ipcFramesOutVpssPrm);
MULTICH_INIT_STRUCT(EncLink_CreateParams, encPrm);
MULTICH_INIT_STRUCT(AlgLink_CreateParams, dspAlgPrm);
for (i = 0; i < VDIS_DEV_MAX;i++)
{
MULTICH_INIT_STRUCT(DisplayLink_CreateParams,
displayPrm[i]);
MULTICH_INIT_STRUCT(SwMsLink_CreateParams ,swMsPrm[i]);
}
MULTICH_INIT_STRUCT(NsfLink_CreateParams, nsfPrm);
MULTICH_INIT_STRUCT(DeiLink_CreateParams, deiPrm);
printf("\n********* Entered usecase 4CH <814x> Enc/Dec OSD %s SCD %s \n\n",
enableOsd == TRUE ? "Enabled" : "Disabled",
enableScd == TRUE ? "Enabled" : "Disabled"
);
MultiCh_detectBoard();
System_linkControl(
SYSTEM_LINK_ID_M3VPSS,
SYSTEM_M3VPSS_CMD_RESET_VIDEO_DEVICES,
NULL,
0,
TRUE
);
System_linkControl(
SYSTEM_LINK_ID_M3VIDEO,
SYSTEM_COMMON_CMD_SET_CH2IVAHD_MAP_TBL,
&systemVid_encDecIvaChMapTbl,
sizeof(SystemVideo_Ivahd2ChMap_Tbl),
TRUE
);
vipInstId = 0;
gVcapModuleContext.captureId = SYSTEM_LINK_ID_CAPTURE;
if(enableAlgLink)
{
gVcapModuleContext.dspAlgId[0] = SYSTEM_LINK_ID_VIDEO_ALG_0 ;
}
gVcapModuleContext.nsfId[0] = SYSTEM_LINK_ID_NSF_0;
#ifdef ADD_NSF_AFTER_CAPTURE
gVcapModuleContext.nsfId[1] =SYSTEM_LINK_ID_NSF_1;
#endif
gVcapModuleContext.deiId[0] = SYSTEM_LINK_ID_DEI_0;
gVencModuleContext.encId = SYSTEM_LINK_ID_VENC_0;
gVdecModuleContext.decId = SYSTEM_LINK_ID_VDEC_0;
gVdisModuleContext.swMsId[0] = SYSTEM_LINK_ID_SW_MS_MULTI_INST_0;
gVdisModuleContext.swMsId[1] = SYSTEM_LINK_ID_SW_MS_MULTI_INST_1;
swMsPrm[0].numSwMsInst = 1;
swMsPrm[1].numSwMsInst = 1;
/* use AUX scaler (SC2), since SC1 is used for DEI */
swMsPrm[0].swMsInstId[0] = SYSTEM_SW_MS_SC_INST_DEI_SC_NO_DEI;
swMsPrm[1].swMsInstId[0] = SYSTEM_SW_MS_SC_INST_SC5;
gVdisModuleContext.displayId[0] = SYSTEM_LINK_ID_DISPLAY_0; /* ON AND OFF CHIP HDMI */
gVdisModuleContext.displayId[1] = SYSTEM_LINK_ID_DISPLAY_2; /* SDTV */
mergeId[LIVE_DECODE_MERGE_LINK_IDX] = SYSTEM_VPSS_LINK_ID_MERGE_0;
mergeId[D1_CIF_MERGE_LINK_IDX] = SYSTEM_VPSS_LINK_ID_MERGE_1;
dupId[D1_DUP_LINK_IDX] = SYSTEM_VPSS_LINK_ID_DUP_0;
dupId[LIVE_DECODE_DUP_LINK_IDX] = SYSTEM_VPSS_LINK_ID_DUP_1;
ipcOutVpssId = SYSTEM_VPSS_LINK_ID_IPC_OUT_M3_0;
ipcInVideoId = SYSTEM_VIDEO_LINK_ID_IPC_IN_M3_0;
ipcOutVideoId= SYSTEM_VIDEO_LINK_ID_IPC_OUT_M3_0;
ipcInVpssId = SYSTEM_VPSS_LINK_ID_IPC_IN_M3_0;
gVencModuleContext.ipcBitsOutRTOSId = SYSTEM_VIDEO_LINK_ID_IPC_BITS_OUT_0;
gVencModuleContext.ipcBitsInHLOSId = SYSTEM_HOST_LINK_ID_IPC_BITS_IN_0;
gVdecModuleContext.ipcBitsOutHLOSId = SYSTEM_HOST_LINK_ID_IPC_BITS_OUT_0;
gVdecModuleContext.ipcBitsInRTOSId = SYSTEM_VIDEO_LINK_ID_IPC_BITS_IN_0;
CaptureLink_CreateParams_Init(&capturePrm);
#ifdef ADD_NSF_AFTER_CAPTURE
capturePrm.outQueParams[0].nextLink = gVcapModuleContext.nsfId[1];
#else
capturePrm.outQueParams[0].nextLink = gVcapModuleContext.deiId[0];
#endif
capturePrm.numVipInst = 1;
capturePrm.tilerEnable = FALSE;
capturePrm.numBufsPerCh = NUM_CAPTURE_BUFFERS;
capturePrm.maxBlindAreasPerCh = 4;
pCaptureInstPrm = &capturePrm.vipInst[0];
pCaptureInstPrm->vipInstId = (SYSTEM_CAPTURE_INST_VIP0_PORTA+
vipInstId)%SYSTEM_CAPTURE_INST_MAX;
pCaptureInstPrm->videoDecoderId = SYSTEM_DEVICE_VID_DEC_TVP5158_DRV;
pCaptureInstPrm->inDataFormat = SYSTEM_DF_YUV422P;
pCaptureInstPrm->standard = SYSTEM_STD_MUX_4CH_D1;
pCaptureInstPrm->numOutput = 1;
pCaptureOutPrm = &pCaptureInstPrm->outParams[0];
pCaptureOutPrm->dataFormat = SYSTEM_DF_YUV422I_YUYV;
pCaptureOutPrm->scEnable = FALSE;
pCaptureOutPrm->scOutWidth = 0;
pCaptureOutPrm->scOutHeight = 0;
pCaptureOutPrm->outQueId = 0;
for(i = 0; i < NUM_CAPTURE_DEVICES; i++)
{
vidDecVideoModeArgs[i].vipInstId = SYSTEM_CAPTURE_INST_VIP0_PORTA+i;
vidDecVideoModeArgs[i].deviceId = DEVICE_VID_DEC_TVP5158_DRV;
vidDecVideoModeArgs[i].numChInDevice = 4;
vidDecVideoModeArgs[i].modeParams.videoIfMode = DEVICE_CAPT_VIDEO_IF_MODE_8BIT;
vidDecVideoModeArgs[i].modeParams.videoDataFormat = SYSTEM_DF_YUV422P;
vidDecVideoModeArgs[i].modeParams.standard = SYSTEM_STD_MUX_4CH_D1;
vidDecVideoModeArgs[i].modeParams.videoCaptureMode =
DEVICE_CAPT_VIDEO_CAPTURE_MODE_MULTI_CH_PIXEL_MUX_EMBEDDED_SYNC;
vidDecVideoModeArgs[i].modeParams.videoSystem =
DEVICE_VIDEO_DECODER_VIDEO_SYSTEM_AUTO_DETECT;
vidDecVideoModeArgs[i].modeParams.videoCropEnable = FALSE;
vidDecVideoModeArgs[i].modeParams.videoAutoDetectTimeout = -1;
}
Vcap_configVideoDecoder(vidDecVideoModeArgs, NUM_CAPTURE_DEVICES);
#ifdef ADD_NSF_AFTER_CAPTURE
nsfPrm2.bypassNsf = TRUE;
nsfPrm2.tilerEnable = FALSE;
nsfPrm2.inQueParams.prevLinkId = gVcapModuleContext.captureId;
nsfPrm2.inQueParams.prevLinkQueId = 0;
nsfPrm2.numOutQue = 1;
nsfPrm2.outQueParams[0].nextLink = gVcapModuleContext.deiId[0];
nsfPrm2.numBufsPerCh = NUM_NSF_BUFFERS;
nsfPrm2.inputFrameRate = 30;
nsfPrm2.outputFrameRate = 30;
deiPrm.inQueParams.prevLinkId = gVcapModuleContext.nsfId[1];
#else
deiPrm.inQueParams.prevLinkId = gVcapModuleContext.captureId;
#endif
deiPrm.inQueParams.prevLinkQueId = 0;
/* Set Output Scaling at DEI based on ratio */
deiPrm.outScaleFactor[DEI_LINK_OUT_QUE_DEI_SC][0].scaleMode = DEI_SCALE_MODE_RATIO;
deiPrm.outScaleFactor[DEI_LINK_OUT_QUE_DEI_SC][0].ratio.widthRatio.numerator = 1;
deiPrm.outScaleFactor[DEI_LINK_OUT_QUE_DEI_SC][0].ratio.widthRatio.denominator = 1;
deiPrm.outScaleFactor[DEI_LINK_OUT_QUE_DEI_SC][0].ratio.heightRatio.numerator = 1;
deiPrm.outScaleFactor[DEI_LINK_OUT_QUE_DEI_SC][0].ratio.heightRatio.denominator = 1;
for (i=1; i < DEI_LINK_MAX_CH; i++)
deiPrm.outScaleFactor[DEI_LINK_OUT_QUE_DEI_SC][i] = deiPrm.outScaleFactor[DEI_LINK_OUT_QUE_DEI_SC][0];
deiPrm.outScaleFactor[DEI_LINK_OUT_QUE_VIP_SC][0].scaleMode = DEI_SCALE_MODE_RATIO;
deiPrm.outScaleFactor[DEI_LINK_OUT_QUE_VIP_SC][0].ratio.heightRatio.numerator = 1;
deiPrm.outScaleFactor[DEI_LINK_OUT_QUE_VIP_SC][0].ratio.heightRatio.denominator = 1;
deiPrm.outScaleFactor[DEI_LINK_OUT_QUE_VIP_SC][0].ratio.widthRatio.numerator = 1;
deiPrm.outScaleFactor[DEI_LINK_OUT_QUE_VIP_SC][0].ratio.widthRatio.denominator = 1;
for (i=1; i < DEI_LINK_MAX_CH; i++)
deiPrm.outScaleFactor[DEI_LINK_OUT_QUE_VIP_SC][i] = deiPrm.outScaleFactor[DEI_LINK_OUT_QUE_VIP_SC][0];
deiPrm.outScaleFactor[DEI_LINK_OUT_QUE_VIP_SC_SECONDARY_OUT][0].scaleMode = DEI_SCALE_MODE_RATIO;
deiPrm.outScaleFactor[DEI_LINK_OUT_QUE_VIP_SC_SECONDARY_OUT][0].ratio.heightRatio.numerator = 1;
deiPrm.outScaleFactor[DEI_LINK_OUT_QUE_VIP_SC_SECONDARY_OUT][0].ratio.heightRatio.denominator = 2;
deiPrm.outScaleFactor[DEI_LINK_OUT_QUE_VIP_SC_SECONDARY_OUT][0].ratio.widthRatio.numerator = 1;
deiPrm.outScaleFactor[DEI_LINK_OUT_QUE_VIP_SC_SECONDARY_OUT][0].ratio.widthRatio.denominator = 2;
for (i=1; i < DEI_LINK_MAX_CH; i++)
deiPrm.outScaleFactor[DEI_LINK_OUT_QUE_VIP_SC_SECONDARY_OUT][i] = deiPrm.outScaleFactor[DEI_LINK_OUT_QUE_VIP_SC_SECONDARY_OUT][0];
deiPrm.enableOut[DEI_LINK_OUT_QUE_DEI_SC] = TRUE;
deiPrm.enableOut[DEI_LINK_OUT_QUE_VIP_SC] = TRUE;
deiPrm.enableOut[DEI_LINK_OUT_QUE_VIP_SC_SECONDARY_OUT] = TRUE;
deiPrm.outQueParams[DEI_LINK_OUT_QUE_DEI_SC].nextLink = dupId[D1_DUP_LINK_IDX];
deiPrm.outQueParams[DEI_LINK_OUT_QUE_VIP_SC].nextLink = mergeId[D1_CIF_MERGE_LINK_IDX];
deiPrm.outQueParams[DEI_LINK_OUT_QUE_VIP_SC_SECONDARY_OUT].nextLink = mergeId[D1_CIF_MERGE_LINK_IDX];
deiPrm.tilerEnable[DEI_LINK_OUT_QUE_VIP_SC] = TILER_ENABLE;
deiPrm.comprEnable = FALSE;
deiPrm.setVipScYuv422Format = FALSE;
dupPrm[D1_DUP_LINK_IDX].inQueParams.prevLinkId = gVcapModuleContext.deiId[0];
dupPrm[D1_DUP_LINK_IDX].inQueParams.prevLinkQueId = DEI_LINK_OUT_QUE_DEI_SC;
dupPrm[D1_DUP_LINK_IDX].numOutQue = 2;
dupPrm[D1_DUP_LINK_IDX].outQueParams[0].nextLink = mergeId[LIVE_DECODE_MERGE_LINK_IDX];
dupPrm[D1_DUP_LINK_IDX].outQueParams[1].nextLink = gVcapModuleContext.nsfId[0];
dupPrm[D1_DUP_LINK_IDX].notifyNextLink = TRUE;
nsfPrm.bypassNsf = TRUE;
nsfPrm.tilerEnable = TILER_ENABLE;
nsfPrm.inQueParams.prevLinkId = dupId[D1_DUP_LINK_IDX];
nsfPrm.inQueParams.prevLinkQueId = 1;
nsfPrm.numOutQue = 1;
nsfPrm.outQueParams[0].nextLink = mergeId[D1_CIF_MERGE_LINK_IDX];
nsfPrm.numBufsPerCh = NUM_NSF_BUFFERS;
nsfPrm.inputFrameRate = 30;
nsfPrm.outputFrameRate = 1;
/* Merge Q0 - D1 , Q1 - CIF , Q2 -D1 for MJPEG */
mergePrm[D1_CIF_MERGE_LINK_IDX].inQueParams[0].prevLinkId = gVcapModuleContext.deiId[0];
mergePrm[D1_CIF_MERGE_LINK_IDX].inQueParams[0].prevLinkQueId = DEI_LINK_OUT_QUE_VIP_SC;
mergePrm[D1_CIF_MERGE_LINK_IDX].inQueParams[1].prevLinkId = gVcapModuleContext.deiId[0];
mergePrm[D1_CIF_MERGE_LINK_IDX].inQueParams[1].prevLinkQueId = DEI_LINK_OUT_QUE_VIP_SC_SECONDARY_OUT;
mergePrm[D1_CIF_MERGE_LINK_IDX].inQueParams[2].prevLinkId = gVcapModuleContext.nsfId[0];
mergePrm[D1_CIF_MERGE_LINK_IDX].inQueParams[2].prevLinkQueId = 0;
mergePrm[D1_CIF_MERGE_LINK_IDX].notifyNextLink = TRUE;
mergePrm[D1_CIF_MERGE_LINK_IDX].numInQue = 3;
ipcOutVpssPrm.inQueParams.prevLinkQueId = 0;
mergePrm[D1_CIF_MERGE_LINK_IDX].outQueParams.nextLink = ipcOutVpssId;
ipcOutVpssPrm.inQueParams.prevLinkId = mergeId[D1_CIF_MERGE_LINK_IDX];
ipcOutVpssPrm.numOutQue = 1;
ipcOutVpssPrm.outQueParams[0].nextLink = ipcInVideoId;
ipcOutVpssPrm.notifyNextLink = TRUE;
ipcOutVpssPrm.notifyPrevLink = TRUE;
ipcOutVpssPrm.noNotifyMode = FALSE;
ipcInVideoPrm.inQueParams.prevLinkId = ipcOutVpssId;
ipcInVideoPrm.inQueParams.prevLinkQueId = 0;
ipcInVideoPrm.numOutQue = 1;
if (enableAlgLink)
{
ipcInVideoPrm.outQueParams[0].nextLink = gVcapModuleContext.dspAlgId[0];
dspAlgPrm.inQueParams.prevLinkId = ipcInVideoId;
dspAlgPrm.inQueParams.prevLinkQueId = 0;
dspAlgPrm.outQueParams[ALG_LINK_FRAMES_OUT_QUE].nextLink = gVencModuleContext.encId;
}
else {
ipcInVideoPrm.outQueParams[0].nextLink = gVencModuleContext.encId;
}
ipcInVideoPrm.notifyNextLink = TRUE;
ipcInVideoPrm.notifyPrevLink = TRUE;
ipcInVideoPrm.noNotifyMode = FALSE;
{
EncLink_ChCreateParams *pLinkChPrm;
EncLink_ChDynamicParams *pLinkDynPrm;
VENC_CHN_DYNAMIC_PARAM_S *pDynPrm;
VENC_CHN_PARAMS_S *pChPrm;
EncLink_CreateParams_Init(&encPrm);
encPrm.numBufPerCh[0] = NUM_ENCODE_D1_BUFFERS;
encPrm.numBufPerCh[1] = NUM_ENCODE_CIF_BUFFERS;
/* Primary Stream Params - D1 */
for (i=0; idefaultDynamicParams;
pChPrm = &gVencModuleContext.vencConfig.encChannelParams[i];
pDynPrm = &pChPrm->dynamicParam;
pLinkChPrm->format = IVIDEO_H264HP;
pLinkChPrm->profile = gVencModuleContext.vencConfig.h264Profile[i];
pLinkChPrm->dataLayout = VCODEC_FIELD_SEPARATED;
pLinkChPrm->fieldMergeEncodeEnable = FALSE;
pLinkChPrm->enableAnalyticinfo = pChPrm->enableAnalyticinfo;
pLinkChPrm->enableWaterMarking = pChPrm->enableWaterMarking;
pLinkChPrm->maxBitRate = pChPrm->maxBitRate;
pLinkChPrm->encodingPreset = pChPrm->encodingPreset;
pLinkChPrm->rateControlPreset = pChPrm->rcType;
pLinkChPrm->enableSVCExtensionFlag = pChPrm->enableSVCExtensionFlag;
pLinkChPrm->numTemporalLayer = pChPrm->numTemporalLayer;
pLinkDynPrm->intraFrameInterval = pDynPrm->intraFrameInterval;
pLinkDynPrm->targetBitRate = pDynPrm->targetBitRate;
pLinkDynPrm->interFrameInterval = 1;
pLinkDynPrm->mvAccuracy = IVIDENC2_MOTIONVECTOR_QUARTERPEL;
pLinkDynPrm->inputFrameRate = pDynPrm->inputFrameRate;
pLinkDynPrm->rcAlg = pDynPrm->rcAlg;
pLinkDynPrm->qpMin = pDynPrm->qpMin;
pLinkDynPrm->qpMax = pDynPrm->qpMax;
pLinkDynPrm->qpInit = pDynPrm->qpInit;
pLinkDynPrm->vbrDuration = pDynPrm->vbrDuration;
pLinkDynPrm->vbrSensitivity = pDynPrm->vbrSensitivity;
}
/* Secondary Out Params */
for (i=gVencModuleContext.vencConfig.numPrimaryChn, j=VENC_PRIMARY_CHANNELS;
i<(gVencModuleContext.vencConfig.numPrimaryChn
+ gVencModuleContext.vencConfig.numSecondaryChn);
i++, j++)
{
pLinkChPrm = &encPrm.chCreateParams[i];
pLinkDynPrm = &pLinkChPrm->defaultDynamicParams;
pChPrm = &gVencModuleContext.vencConfig.encChannelParams[j];
pDynPrm = &pChPrm->dynamicParam;
pLinkChPrm->format = IVIDEO_H264HP;
pLinkChPrm->profile = gVencModuleContext.vencConfig.h264Profile[i];
pLinkChPrm->dataLayout = VCODEC_FIELD_SEPARATED;
pLinkChPrm->fieldMergeEncodeEnable = FALSE;
pLinkChPrm->enableAnalyticinfo = pChPrm->enableAnalyticinfo;
pLinkChPrm->enableWaterMarking = pChPrm->enableWaterMarking;
pLinkChPrm->maxBitRate = pChPrm->maxBitRate;
pLinkChPrm->encodingPreset = pChPrm->encodingPreset;
pLinkChPrm->rateControlPreset = pChPrm->rcType;
pLinkChPrm->enableSVCExtensionFlag = pChPrm->enableSVCExtensionFlag;
pLinkChPrm->numTemporalLayer = pChPrm->numTemporalLayer;
pLinkDynPrm->intraFrameInterval = pDynPrm->intraFrameInterval;
pLinkDynPrm->targetBitRate = pDynPrm->targetBitRate;
pLinkDynPrm->interFrameInterval = 1;
pLinkDynPrm->mvAccuracy = IVIDENC2_MOTIONVECTOR_QUARTERPEL;
pLinkDynPrm->inputFrameRate = pDynPrm->inputFrameRate;
pLinkDynPrm->qpMin = pDynPrm->qpMin;
pLinkDynPrm->qpMax = pDynPrm->qpMax;
pLinkDynPrm->qpInit = pDynPrm->qpInit;
pLinkDynPrm->vbrDuration = pDynPrm->vbrDuration;
pLinkDynPrm->vbrSensitivity = pDynPrm->vbrSensitivity;
}
/* MJPEG Params */
for (i=gVencModuleContext.vencConfig.numPrimaryChn + gVencModuleContext.vencConfig.numSecondaryChn;
i<(VENC_CHN_MAX); i++)
{
pLinkChPrm = &encPrm.chCreateParams[i];
pLinkDynPrm = &pLinkChPrm->defaultDynamicParams;
pChPrm = &gVencModuleContext.vencConfig.encChannelParams[i];
pDynPrm = &pChPrm->dynamicParam;
pLinkChPrm->format = IVIDEO_MJPEG;
pLinkChPrm->profile = 0;
pLinkChPrm->dataLayout = VCODEC_FIELD_SEPARATED;
pLinkChPrm->fieldMergeEncodeEnable = FALSE;
pLinkChPrm->enableAnalyticinfo = 0;
pLinkChPrm->enableWaterMarking = 0;
pLinkChPrm->maxBitRate = 0;
pLinkChPrm->encodingPreset = 0;
pLinkChPrm->rateControlPreset = 0;
pLinkChPrm->enableSVCExtensionFlag = 0;
pLinkChPrm->numTemporalLayer = 0;
pLinkDynPrm->intraFrameInterval = 0;
pLinkDynPrm->targetBitRate = 100*1000;
pLinkDynPrm->interFrameInterval = 0;
pLinkDynPrm->mvAccuracy = 0;
pLinkDynPrm->inputFrameRate = pDynPrm->inputFrameRate;
pLinkDynPrm->qpMin = 0;
pLinkDynPrm->qpMax = 0;
pLinkDynPrm->qpInit = -1;
pLinkDynPrm->vbrDuration = 0;
pLinkDynPrm->vbrSensitivity = 0;
}
if (enableAlgLink)
{
encPrm.inQueParams.prevLinkId = gVcapModuleContext.dspAlgId[0];
encPrm.inQueParams.prevLinkQueId = ALG_LINK_FRAMES_OUT_QUE;
}
else {
encPrm.inQueParams.prevLinkId = ipcInVideoId;
encPrm.inQueParams.prevLinkQueId = 0;
}
encPrm.outQueParams.nextLink = gVencModuleContext.ipcBitsOutRTOSId;
}
ipcBitsOutVideoPrm.baseCreateParams.inQueParams.prevLinkId = gVencModuleContext.encId;
ipcBitsOutVideoPrm.baseCreateParams.inQueParams.prevLinkQueId = 0;
ipcBitsOutVideoPrm.baseCreateParams.numOutQue = 1;
ipcBitsOutVideoPrm.baseCreateParams.outQueParams[0].nextLink = gVencModuleContext.ipcBitsInHLOSId;
MultiCh_ipcBitsInitCreateParams_BitsOutRTOS(&ipcBitsOutVideoPrm,
TRUE);
ipcBitsInHostPrm[0].baseCreateParams.inQueParams.prevLinkId = gVencModuleContext.ipcBitsOutRTOSId;
ipcBitsInHostPrm[0].baseCreateParams.inQueParams.prevLinkQueId = 0;
MultiCh_ipcBitsInitCreateParams_BitsInHLOS(&ipcBitsInHostPrm[0]);
dspAlgPrm.enableOSDAlg = enableOsd;
if(enableOsd)
{
int chId;
for(chId = 0; chId < ALG_LINK_OSD_MAX_CH; chId++)
{
AlgLink_OsdChWinParams * chWinPrm = &dspAlgPrm.osdChCreateParams[chId].chDefaultParams;
/* set osd window max width and height */
dspAlgPrm.osdChCreateParams[chId].maxWidth = EXAMPLE_OSD_WIN_MAX_WIDTH;
dspAlgPrm.osdChCreateParams[chId].maxHeight = EXAMPLE_OSD_WIN_MAX_HEIGHT;
chWinPrm->chId = chId;
chWinPrm->numWindows = 0;
}
}
dspAlgPrm.enableSCDAlg = enableScd;
dspAlgPrm.outQueParams[ALG_LINK_SCD_OUT_QUE].nextLink = SYSTEM_LINK_ID_INVALID;
if (enableScd)
{
UInt32 i, startChId;
AlgLink_ScdCreateParams *pScdCreatePrm;
AlgLink_ScdChParams *pScdChPrm;
pScdCreatePrm = &dspAlgPrm.scdCreateParams;
pScdCreatePrm->maxWidth = 352;
pScdCreatePrm->maxHeight = 288;
pScdCreatePrm->maxStride = 352;
pScdCreatePrm->numValidChForSCD = 4;
pScdCreatePrm->numSecs2WaitB4Init = 3;
pScdCreatePrm->numSecs2WaitB4FrmAlert = 1;
pScdCreatePrm->inputFrameRate = 30;
pScdCreatePrm->outputFrameRate = 5;
pScdCreatePrm->numSecs2WaitAfterFrmAlert = 1;
pScdCreatePrm->enableTamperNotify = FALSE;
/* enable SCD only for CIF CHs */
startChId = 4;
for(i=0; inumValidChForSCD; i++)
{
pScdChPrm = &pScdCreatePrm->chDefaultParams[i];
pScdChPrm->chId = startChId;
pScdChPrm->mode = ALG_LINK_SCD_DETECTMODE_MONITOR_FULL_FRAME;
pScdChPrm->frmIgnoreLightsON = FALSE;
pScdChPrm->frmIgnoreLightsOFF = FALSE;
pScdChPrm->frmSensitivity = ALG_LINK_SCD_SENSITIVITY_VERYHIGH;
pScdChPrm->frmEdgeThreshold = 0;
pScdChPrm->blkNumBlksInFrame = 0;
startChId++;
}
}
capturePrm.isPalMode = Vcap_isPalMode();
System_linkCreate (gVcapModuleContext.captureId, &capturePrm, sizeof(capturePrm));
#ifdef ADD_NSF_AFTER_CAPTURE
System_linkCreate(gVcapModuleContext.nsfId[1], &nsfPrm2, sizeof(nsfPrm2));
#endif
System_linkCreate(gVcapModuleContext.deiId[0], &deiPrm, sizeof(deiPrm));
System_linkCreate(dupId[D1_DUP_LINK_IDX], &dupPrm[D1_DUP_LINK_IDX], sizeof(dupPrm[D1_DUP_LINK_IDX]));
System_linkCreate(gVcapModuleContext.nsfId[0] , &nsfPrm, sizeof(nsfPrm));
System_linkCreate(mergeId[D1_CIF_MERGE_LINK_IDX], &mergePrm[D1_CIF_MERGE_LINK_IDX], sizeof(mergePrm[D1_CIF_MERGE_LINK_IDX]));
System_linkCreate(ipcOutVpssId , &ipcOutVpssPrm , sizeof(ipcOutVpssPrm) );
System_linkCreate(ipcInVideoId , &ipcInVideoPrm , sizeof(ipcInVideoPrm) );
if(enableAlgLink)
{
/* only create OSD alg */
System_linkCreate(gVcapModuleContext.dspAlgId[0] , &dspAlgPrm, sizeof(dspAlgPrm));
}
System_linkCreate(gVencModuleContext.encId, &encPrm, sizeof(encPrm));
System_linkCreate(gVencModuleContext.ipcBitsOutRTOSId, &ipcBitsOutVideoPrm, sizeof(ipcBitsOutVideoPrm));
System_linkCreate(gVencModuleContext.ipcBitsInHLOSId, &ipcBitsInHostPrm[0], sizeof(ipcBitsInHostPrm[0]));
System_linkGetInfo(gVencModuleContext.ipcBitsInHLOSId,&bitsProducerLinkInfo);
OSA_assert(bitsProducerLinkInfo.numQue == 1);
ipcBitsOutHostPrm.baseCreateParams.outQueParams[0].nextLink = gVdecModuleContext.ipcBitsInRTOSId;
printf ("\n\n========bitsProducerLinkInfo============\n");
printf ("numQ %d, numCh %d\n",
bitsProducerLinkInfo.numQue,
bitsProducerLinkInfo.queInfo[0].numCh);
{
int i;
for (i=0; i gVencModuleContext.vencConfig.numPrimaryChn)
bitsProducerLinkInfo.queInfo[0].numCh = gVencModuleContext.vencConfig.numPrimaryChn;
printf ("Reducing bitsProducerLinkInfo.numCh to %d\n", bitsProducerLinkInfo.queInfo[0].numCh);
MultiCh_ipcBitsInitCreateParams_BitsOutHLOS(&ipcBitsOutHostPrm,
&bitsProducerLinkInfo.queInfo[0]);
if(gVdecModuleContext.vdecConfig.forceUseDecChannelParams)
{
/* use channel info provided by user instead of from encoder */
System_LinkChInfo *pChInfo;
ipcBitsOutHostPrm.inQueInfo.numCh = gVdecModuleContext.vdecConfig.numChn;
for(chId=0; chIdbufType = 0;
pChInfo->codingformat = 0;
pChInfo->dataFormat = 0;
pChInfo->memType = 0;
pChInfo->startX = 0;
pChInfo->startY = 0;
pChInfo->pitch[0] = 0;
pChInfo->pitch[1] = 0;
pChInfo->pitch[2] = 0;
/* Not Used - End */
pChInfo->width = gVdecModuleContext.vdecConfig.decChannelParams[chId].maxVideoWidth;
pChInfo->height = gVdecModuleContext.vdecConfig.decChannelParams[chId].maxVideoHeight;
pChInfo->scanFormat = SYSTEM_SF_PROGRESSIVE;
}
}
/* ipcBitsOut params - num of buffers, bitstream buffer size */
for (chId=0; chId
他的博客说的很详细,基本上link的语句都分析了一下,在此我只是借用自己来学习,谢谢!
其实link就是对几个核怎么运作进行设计,凡是用这个平台的link没有太大的区别,都是按照自己的需求进行定制,单是修改link也会很费工夫。