当前位置: 首页 > 工具软件 > Motion > 使用案例 >

Motion Detection详解

凌鹏程
2023-12-01

Motion Detection程序是指图像处理中用到的运动补偿方法,它先用当前视频帧和指定参考帧进行像素点之间的比较,然后把不同的像素点着色,最后将这些不同的像素点替换成当前帧相应的像素点即可。因此,这种方法有效的减小了图像处理过程中的时间冗余度。通过对Motion Detection程序的介绍,我们希望您对DM642平台系统有更加细致的认识和应用经验。本文就对此程序进行详细的介绍。
我们把Motion Detection分成以下几个部分进行介绍:
1. Cell
2. Capture
3. Display
4. XDAIS
5. RF5
6. 程序中的所有存储器以及其搬移图
以下就是对上面六个部分的单独介绍。
一、 关于cell
关于程序中rf5是如何用cell包装包装一个算法以及应用程序如何通过cell的接口最终调用到算法的c程序的说明。本文只说明应用程序是如何通过cell接口调用diff算法的 ,至于rotate算法是完全一致的。
为了说明清楚,先把几个复杂的结构这里说明一下:
首先是算法对象:
typedef struct IALG_Obj {
struct IALG_Fxns *fxns;
} IALG_Obj;
typedef struct IALG_Obj *IALG_Handle;
typedef struct IALG_Fxns {
Void *implementationId;
Void (*algActivate)(IALG_Handle);
Int (*algAlloc)(const IALG_Params *, struct IALG_Fxns **, IALG_MemRec *);
Int (*algControl)(IALG_Handle, IALG_Cmd, IALG_Status *);
Void (*algDeactivate)(IALG_Handle);
Int (*algFree)(IALG_Handle, IALG_MemRec *);
Int (*algInit)(IALG_Handle, const IALG_MemRec *, IALG_Handle, const IALG_Params *);
Void (*algMoved)(IALG_Handle, const IALG_MemRec *, IALG_Handle, const IALG_Params *);
Int (*algNumAlloc)(Void);
} IALG_Fxns;
这里定义了一个算法对象IALG_Obj,这个结构体里面只有一个成员算法函数列表 ialg_fxns,这个列表里面是实现xdias标准的几个函数。
接下来是cell对象:
typedef struct ICELL_Obj {
Int size; /* Number of MAU in the structure */
String name; /* User chosen name. */
ICELL_Fxns *cellFxns; /* Ptr to cell v-table function. */
Ptr cellEnv; /* Ptr to user defined cell env. Struct */
IALG_Fxns *algFxns; /* Ptr to alg v-table functions. */
IALG_Params *algParams; /* Ptr to alg parameters. */
IALG_Handle algHandle; /* Handle of alg managed by cell. */
Uns scrBucketIndex; /* Scratch bucket for XDAIS scratch mem. */
ICC_Handle *inputIcc; /* Array of input ICC objects */
Uns inputIccCnt; /* # of ICC objects in the input array */
ICC_Handle *outputIcc; /* Array of output ICC objects */
Uns outputIccCnt; /* # of ICC objects in the output array */
} ICELL_Obj;
typedef struct ICELL_Obj *ICELL_Handle;
typedef struct ICELL_Fxns {
Bool (*cellClose )(ICELL_Handle handle);
Int (*cellControl)(ICELL_Handle handle, IALG_Cmd cmd, IALG_Status *status);
Bool (*cellExecute)(ICELL_Handle handle, Arg arg);
Bool (*cellOpen )(ICELL_Handle handle);
} ICELL_Fxns;
这里定义了一个cell对象cell_obj里面有两个重要成员,一个是ICELL_Fxns,这个就是cell对外部的接口,这个结构里面又4个函数指针,其中cellExecute便是执行cell中算法的函数。还有一个重要的成员就是IALG_Fxns,这个函数便是算法函数指针赋值的地方。
首先在process.c中的CHAN_execute( &thrProcess.diffChans[ chanNum ], NULL ),函数调用了ICELL_Fxns中的cellExecute函数,但在本例中有这样一个定义:
ICELL_Fxns DIFF_CELLFXNS = {
NULL, // cellClose
NULL, // cellControl
DIFF_cellExecute, // cellExecute
NULL // cellOpen
};
这说明我们要调用的是上述结构中定义的DIFF_cellExecute函数,我们再来看看DIFF_cellExecute函数里面的代码:
Bool DIFF_cellExecute( ICELL_Handle handle, Arg arg )
{
IDIFF_Handle diffHandle = (IDIFF_Handle)handle->algHandle;
// activate instance object
ALGRF_activate( handle->algHandle );
runDIFF(diffHandle,
(Short **)handle->inputIcc[0]->buffer,
(Uint32 **)handle->outputIcc[0]->buffer,
(DIFF_Env *)handle->cellEnv);
// deactivate instance object
ALGRF_deactivate( handle->algHandle );
return(TRUE);
}
为了说清楚这个函数,我在先说明几个实现定义好的结构:
typedef struct IDIFF_Obj *IDIFF_Handle;
typedef struct IDIFF_Obj {
struct IDIFF_Fxns *fxns;
} IDIFF_Obj;
typedef struct IDIFF_Fxns {
IALG_Fxns ialg; /* IDIFF extends IALG */
Void (*apply)(IDIFF_Handle handle, unsigned char y[],
unsigned char cr[], unsigned char cb[],
unsigned char prevY[], unsigned char prevCr[],
unsigned char prevCb[], Int lumaSize, Int chromaSize,
Int yValue, Int crValue, Int cbValue, Int procWidth);
} IDIFF_Fxns;
现在来说明DIFF_cellExecute这个函数,在process.c中还有这样一个定义:
for (chanNum = 0; chanNum < NUMDIFFCHANS; chanNum++) {
/*
* cell 0 - DIFF: create an input and output linear ICC.
* The address to the input ICC will be set in the thrProcessRun()
* function via ICC_setBuf().
*/

cell = &thrProcess.diffCells[ chanNum * CHDIFFNUMCELLS ];
*cell = defaultCell;
cell->name = "DIFF";
cell->cellFxns = &DIFF_CELLFXNS;
cell->cellEnv = (Ptr *)&thrProcess.diffEnv[chanNum];
cell->algFxns = (IALG_Fxns *)&DIFF_IDIFF;
cell->algParams = (IALG_Params *)&diffParams;
cell->scrBucketIndex = VIDEOPROCSCRBUCKET;
在这个指针的传递中我们把DIFF_IDIFF这个结构(待会会说明这个结构里面有什么)的指针给了algfxns,然后在DIFF_cellExecute函数中的这条语句
IDIFF_Handle diffHandle = (IDIFF_Handle)handle->algHandle;中alghandle其实就是指向algfxn的,然后强制装换成了IDIFF_Handle,刚才我们已经把DIFF_IDIFF这个结构的指针赋给了algfxns,所以现在我们对DIFF_IDIFF这个结构的调用可以通过IDIFF_Handle这个句柄了。
在这个函数中我们调用了runDIFF函数,这个函数中最重要的一条语句:
handle->fxns->apply(handle,
(unsigned char *)(intYBuf + (toggle * ySingleBufSize)),
(unsigned char *)(intCrBuf + (toggle * crSingleBufSize)),
(unsigned char *)(intCbBuf + (toggle * cbSingleBufSize)),
(unsigned char *)ptrPrevY, (unsigned char *)ptrPrevCr,
(unsigned char *)ptrPrevCb, ySingleBufSize, crSingleBufSize,
env->yValue, env->crValue, env->cbValue, PROCF_WIDTH);
这个apply中参数handle就是刚才从上面函数传递下来的IDIFF_Handle,我们再来说明DIFF_IDIFF是个什么东西,再link.cmd中我们有这样一句话:-l ../../lib/diff_ti.l64
_DIFF_IDIFF = _DIFF_TI_IDIFF;
_DIFF_TI_IDIFF这个结构并不在工程中而是在
D:/ti/boards/evmdm642/examples/video/RF5_MotionDetect/diff_ti/src这个文件夹中,
IDIFF_Fxns DIFF_TI_IDIFF = { /* module_vendor_interface */
IALGFXNS,
DIFF_TI_apply
};
DIFF_TI_apply这个便是真的的算法,所以_DIFF_IDIFF = _DIFF_TI_IDIFF这条链接命令就是把另外一个工程下的算法包装赋给了本工程中的DIFF_IDIFF。到此刚才我们从handle->fxns->apply(handle,
(unsigned char *)(intYBuf + (toggle * ySingleBufSize)),
(unsigned char *)(intCrBuf + (toggle * crSingleBufSize)),
(unsigned char *)(intCbBuf + (toggle * cbSingleBufSize)),
(unsigned char *)ptrPrevY, (unsigned char *)ptrPrevCr,
(unsigned char *)ptrPrevCb, ySingleBufSize, crSingleBufSize,
env->yValue, env->crValue, env->cbValue, PROCF_WIDTH);
这个函数中调用的apply便是DIFF_TI_apply这个真正的c语言diff算法了。
建议用笔在纸上记下这些复杂的结构和指针是怎么指来指去的,相信对弄清楚这个调用方法会更深刻。

二、 关于capture
结构体定义如下:
typedef struct {
Int cmode; /* capture mode settings */
Int fldOp; /* field & frame operation */

/* bit 8-15 */
Int scale; /* indicate whether to enable 1/2 scaling */
Int resmpl; /* indicate whether to enable choroma */
/* sub-sampling */
Int bpk10Bit; /* 10-bit bit-pack mode */
/* bit 16-23 */
Int hCtRst; /* horizontal counter reset mode */
Int vCtRst; /* vertical counter reset mode */
Int fldDect; /* enable whether to use FID input or field */
/* detection logic based on the timing */
/* relation of hsync and vsync */
Int extCtl; /* enable external timing control */
Int fldInv; /* enable inversion of the detected fid */

Uint16 fldXStrt1; /* field 1 X start */
Uint16 fldYStrt1; /* field 1 Y start */
Uint16 fldXStrt2; /* field 2 X start */
Uint16 fldYStrt2; /* field 2 Y start */
Uint16 fldXStop1; /* field 1 X stop */
Uint16 fldYStop1; /* field 1 Y stop */
Uint16 fldXStop2; /* field 2 X stop */
Uint16 fldYStop2; /* field 2 Y stop */
Uint16 thrld; /* video FIFO threshold */
/* frame buffer settings */
Int numFrmBufs; /* number of frame buffers that the driver allocates */
Int alignment; /* frame buffer alignment */
Int mergeFlds; /* indicate to interleave data of the two fields in memory */
/* or just store them seperated */
Int segId; /* memory segment ID, used by MEM_alloc() to allocate */
/* video frame buffer */
/* EDMA priority */
Int edmaPri; /* channel EDMA priority */
Int irqId;
} VPORTCAP_Params;
现在对其中一些关键信息进行注释:
Cmode 为vport数据输入格式的选择,如图所示:
Int fldOp :帧和场的操作模式,在vport.h中定义,参考选择如下:
? VPORT_FLDOP_FLD1
? VPORT_FLDOP_FLD2
? VPORT_FLDOP_FRAME
? VPORT_FLDOP_PROGRESSIVE
Scale和resample的设置(具体操作见spru629 66页):
Int bpk10Bit; /* 10-bit bit-pack mode */
10bit数据打包成64bit数据包的方式,包括:
? VPORTCAP_BPK_10BIT_ZERO_EXTENDED
? VPORTCAP_BPK_10BIT_SIGN_EXTENDED
? VPORTCAP_BPK_10BIT_DENSE
HOUNT=0,VOUNT=1
Xstart~Xstop定义图像的宽度
Ystart~Ystop定义图像的高度
以上4个参数决定了捕获的图像帧的窗口中的位置
Uint16 thrld; /* video FIFO threshold */
指示FIFO的门限值,当捕获的数据达到门限值则出发DMA操作
如下图所示:
Int extCtl; /* enable external timing control */
Int vCtRst; /* vertical counter reset mode */
Exc和vrst定义了图象捕获中垂直计数器的复位点,如下图所示:

Int hCtRst; /* horizontal counter reset mode */
Exc和hrst定义了水平采样计数器的复位点:

当EXC=0,VRST=0:VCOUNT在场消隐开始时复位
当EXC=0,VRST=1:VCOUNT在有效行开始时复位
当EXC=0,HRST=0:HCOUNT在EAV代码结束时复位
当EXC=0,HRST=1:HCOUNT在SAV代码结束时复位
当EXC=1,VRST=0,HRST=0时,VCOUNT和HCOUNT都是在VCTL0控制信号的上升沿进行复位;VRST=1,HRST=1时,VCOUNT和HCOUNT都是VCTL0控制信号的下降沿复位
Int fldDect; 场检测使能定义
FID:FID=0,指场一的开始;FID=1指示场2的开始;使用FID输入判断场的方法适合Y/C图像数据流;
SAA7115_ConfParams EVMDM642_vCapParamsSAA7115 = {
SAA7115_MODE_NTSC720,
SAA7115_MODE_USER,
SAA7115_AFMT_COMPOSITE,
TRUE,
TRUE,
INV,
LIN
E_SZ,
NUM_LINES*2,
TRUE,
};
typedef struct {
SAA7115_Mode inMode;
SAA7115_Mode outMode;
SAA7115_AnalogFormat aFmt;
Bool enableBT656Sync;
Bool enableIPortOutput;
I2C_Handle hI2C;
/* optional parameters for inMode == SAA7115_MODE_USER */
Int hSize;
Int vSize;
Bool interlaced;
} SAA7115_ConfParams; (saa7115.h)
SAA7115_Mode的inMode和outMode可以是下面结构体定义的其中之一;
typedef enum SAA7115_Mode{
SAA7115_MODE_NTSC640,
SAA7115_MODE_NTSC720,
SAA7115_MODE_PAL720,
SAA7115_MODE_PAL768,
SAA7115_MODE_CIF,
SAA7115_MODE_QCIF,
SAA7115_MODE_SQCIF,
SAA7115_MODE_SIF
SAA7115_MODE_USER
}SAA7115_Mode;
SAA7115_AnalogFormat aFmt;(saa7115.h)指定编码器的模拟输出模式
typedef enum SAA7115_AnalogFormat {
SAA7115_AFMT_SVIDEO,
SAA7115_AFMT_COMPOSITE
} SAA7115_AnalogFormat;
Bool enableBT656Sync; 把ITU-R BT.656中定义的SAV/EAV代码插入到输出图像数据流
Bool enableIPortOutput; 选择图像数据的输出端口为I-PORT还是X-PORT
Int hSize; & Int vSize; 分别定义图像的水平宽度和垂直高度
Bool interlaced; 指定用户定义的图像采用interlaced模式或者progressive模式

三、 关于display
Display1
1.dmode:
当前值:VPORT_MODE_BT656_8BIT,
作用:co-sited luma and chroma data multiplexed into a single data stream

因当前位数为8bit,VDOUT9~ VDOUT2脚输出8位数据
图1:BT.656 Output Sequence

图2:模式选择
2.fldOp:field and frame operation mode.
当前值:VPORT_FLDOP_FRAME
类似于如下
3. Scale: horizontal 2x scaling enable。
当前值:VPORT_SCALING_DISABLE,不允许缩放。
4.defValEn:
default value output enable. Enable output of default value in the non-blanking period outside the image window。
在非空白时段图像输出是否指定为默认值,默认值配置见下面9段。
当前值:VPORTDIS_DEFVAL_ENABLE
5. Resmpl:
VPORT_RESMPL_DISABLE
chroma horizontal 4:2:0 to 4:2:2 re-sampling disable.
6. bpk10Bit:
VPORTDIS_BPK_10BIT_NORMAL, /*bpk10Bit:1 */
Fifo填充模式,普通模式,一字填充2个10bit
7.vctl1Config: vctl2Config: vctl3Config:vctl1~vctl3引脚的输出选择
其中vctl1: vctl2都有以下四种选择;
? VPORTDIS_VCTL2_VSYNC
? VPORTDIS_VCTL2_VBLNK
? VPORTDIS_VCTL2_CSYNC
? VPORTDIS_VCTL2_FLD
vctl3有以下2种选择
VPORTDIS_VCTL3_CBLNK
? VPORTDIS_VCTL3_FLD
在此程序中:VPORTDIS_VCTL1_HSYNC, /* vctl1Config:2 */
Vctl
1脚选择输出为水平同步信号
VPORTDIS_VCTL2_VSYNC, /* vctl2Config:2 */
Vctl2脚输出选择为垂直同步信号
VPORTDIS_VCTL3_FLD, /* vctl3Config:1 */
Vctl3脚输出选择为场信号,标志当前场序号(field1或field 2)
8.帧及图像等相关数据,已在下图中标识

9.指定Y,CB,CR分量的默认值:
Y为 0x10,
CB 0x80,
CR 0x80,
10. rgbX 仅在raw mode连续输出24/30-bit RGB模式中使用,是否执行3/4 fifo解包。本程序与其无关。指定为VPORTDIS_RGBX_DISABLE。
11. incPix:仅在 raw mode中使用。
12.thrld: 当fifo中数据达到此值,将触发edma事件。此处为360/8=45双字。
13. numFrmBufs
给driver分配的buffer个数,本程序为3个。
14. Alignment:
Buffer的字对齐,此处为128字节对齐,即buffer的开始地址为128的倍数。
15,mergeFlds:指定场1和场2 buffer是否在存储器中分开存放。
VPORT_FLDS_MERGED,此处不分开放置。
16. SegId:指定driver将buffer分配到的位置,初始值为null,后在初始化函数thrDisplayInit中指定为EXTERNALHEAP,由dsp/bios中mem模块分配可知EXTERNALHEAP是外部存储器中的堆。
17.edma传输的优先级,可指定为高或低。指定为高EDMA_OPT_PRI_HIGH。
18.edma 中断号id,为8,默认值。
19.EVMDM642_vDisParamsSAA7105配置
SAA7105_ConfParams EVMDM642_vDisParamsSAA7105 = {
SAA7105_AFMT_SVIDEO,
SAA7105_MODE_NTSC720,
SAA7105_IFMT_YCBCR422_INTERLACED,
TRUE,
FALSE,
INV
};
SAA7105_AFMT_SVIDEO,模拟输出的格式
可选格式有:
typedef enum SAA7105_AnalogFormat {
SAA7105_AFMT_SVIDEO = 0,
SAA7105_AFMT_RGB = 1,
SAA7105_AFMT_YPBPR = 1,
SAA7105_AFMT_COMPOSITE = 2
} SAA7105_AnalogFormat;
SAA7105_MODE_NTSC720,视屏模式,可选模式有
typedef enum
{
SAA7105_MODE_NTSC720,
SAA7105_MODE_PAL720,
SAA7105_MODE_QVGA,
SAA7105_MODE_VGA,
SAA7105_MODE_SVGA,
SAA7105_MODE_XGA,
SAA7105_MODE_HD480P60F,
SAA7105_MODE_HD720P24F,
SAA7105_MODE_HD720P60F,
SAA7105_MODE_HD1080I30F
}SAA7105_Mode;
SAA7105_IFMT_YCBCR422_INTERLACED,7105的输入格式,为ycbcr422格式。可选格式有
typedef enum SAA7105_InputFormat {
SAA7105_IFMT_RGB24_YCBCR444,
SAA7105_IFMT_RGB555,
SAA7105_IFMT_RGB565,
SAA7105_IFMT_YCBCR422_NONEINTERLACED,
SAA7105_IFMT_YCBCR422_INTERLACED
}SAA7105_InputFormat;
20.TRUE:指定7105为从模式
21.FALSE:是否使用 SAV/EAV code使能内置的同步
INV暂时不指定。在初始化函数中指定。

 

 

Display2
1. 初始化工作:
EVMDM642_vDisParamsChan.segId = EXTERNALHEAP;
EVMDM642_vDisParamsSAA7105.hI2C = EVMDM642_I2C_hI2C;
指定将用来分配视频帧缓冲区的存储段ID设置为EXTERNALHEAP。
I2c句柄指定为EVMDM642_I2C_hI2C。
disChan = FVID_create("/VP2DISPLAY", IOM_OUTPUT,
&status, (Ptr)&EVMDM642_vDisParamsChan, NULL);
建立FVID通道并初始化该通道;FVID即是GIO的一种封装,FVID通道即GIO通道。详见附录。
若成功建立,该函数返回fvid通道句柄,若不成功,返回NULL。
参数意义:
"/VP2DISPLAY ":字符串表示device driver的名字,该device driver在DSP/BIOS中定义。
IOM_OUTPUT指定设备的打开模式为输出。
status:该参量是application送给mini-driver的一个状态指针,由mini-driver来返回状态的;
EVMDM642_vDisParamsChan:是用来初始化FVID channel的具体参数,是用结构体的形式打包,并将指向该结构体的指针传送给mini-driver来进行处理,结构体中参数的具体含义已在display文档中介绍过。
NULL:为FVID_Attrs结构参数,为空,表FVID_alloc,FVID_free,FVID_exchange calls为非block形式,无论成功与否,立刻返回,详见附录。
FVID_control(disChan, VPORT_CMD_EDC_BASE+EDC_CONFIG, (Ptr)&EVMDM642_vDisParamsSAA7105)
应用程序发送一个控制命令给mini-driver,将由mini-driver做相应的响应,在这里将完成对saa7105寄存器的初始化;dischan为指定的fvid通道,由上FVID_create函数返回。VPORT_CMD_EDC_BASE+EDC_CONFIG为相应cmd命令,EVMDM642_vDisParamsSAA7105为一结构体,包含的是配置SAA7105的具体参数信息,该结构体成员已在display文档中介绍,此不再重叙。这里将该结构体的指针传送给mini-driver,mini-driver将通过i2c总线用其配置7105;该函数将导致mdcontrol函数的调用,详见附录。
scomReceive = SCOM_create("scomDisplay", NULL);
建立scom,scom为进程间用来同步,传递信息用的模块。"scomDisplay"为该csom的参考,相当于scom模块的名字,NULL为scom参数,目前仅支持空类型。该函数成功将返回建立的scom句柄,失败返回NULL。
UTL_assert( scomReceive != NULL);
判断scom是否成功建立。UTL为fc5中调试诊断模块。改模块本身并未实现什么具体新功能,只是dsp/bios中相关模块的一种封装及及整合。起简化fc5程序的调试诊断作用。
2. Display启动
FVID_control(disChan, VPORT_CMD_START, NULL);
应用程序发送一个控制命令给mini-driver,将由mini-driver做相应的响应,在这里通知vport口开始工作;dischan为指定的fvid通道,由上FVID_create函数返回。VPORT_CMD_EDC_BASE+EDC_CONFIG为相应cmd命令,函数第三参数为为该命令附带的信息,此处为空。该函数将导致mdcontrol函数的调用,详见附录。
3.Display运行
SCOM_Handle scomReceive, scomSend;
Char *inBuf[3];
Char *outBuf[3];
建立2个scom句柄及两个缓冲区。
UTL_logDebug1("thrDisplayRun: task = 0x%x", TSK_self());
显示当前运行的进程。UIL模块介绍见上。
scomReceive = SCOM_open( "scomDisplay" );
scomSend = SCOM_open( "scomToProcessFromDisplay" );
打开scom通道,为接收和发送缓冲区指针做准备。返回scom的句柄,待下面使用。"scomDisplay","scomToProcessFromDisplay"为已建立的scom。
FVID_alloc(disChan, &disFrameBuf);
从mini-dirver获取缓冲区指针。disChan为fvid通道句柄,指定fvid通道,disFrameBuf为指向driver分配的缓冲区指针。An application will call FVID_alloc to request the video device driver to give it ownership of a data buffer. 该函数将导致mdSubmit的调用。详见附录。
4.进入主工作循环:
scombufDisp = SCOM_getMsg( scomReceive, SYS_FOREVER );
为等待从process进程发过来的scom信息,scomReceive指定的scom模块,SYS_FOREVER为永久等待,因此若scom中此时无信息,因等待时间为SYS_FOREVER,执行到此,display进程将被挂起,直到从process进程发过来scom信息,改进程进入就绪状态,等待下一次的进程切换调度,根据优先极获得执行权。
第一参数为scom句柄,SYS_FOREVER为等待时间。若成功将返回scom信息。Scom信息结构见附录。
当获取该scom信息后,继续向下执行
inBuf[Y] = scombufDisp->bufYCRCB[Y];
inBuf[CR] = scombufDisp->bufYCRCB[CR];
inBuf[CB] = scombufDisp->bufYCRCB[CB];
outBuf[Y] = disFrameBuf->frame.iFrm.y1;
outBuf[CR] = disFrameBuf->frame.iFrm.cr1;
outBuf[CB] = disFrameBuf->frame.iFrm.cb1;
将inbuf指向从process获取的缓冲区。outBuf指向要传递给mini-driver的缓冲区。分别有y,cr,cb分量。
为显示方便,首先将获取的4:2:0图像转换为4:2:2格式,
yuv420to422(inBuf, outBuf, OPF_WIDTH, OPF_HEIGHT);
第一参数为输入缓冲区指针,第二参数为输出缓冲区指针,OPF_WIDTH, OPF_HEIGHT分别为图像的宽度和长度,OPF_WIDTH=720,OPF_HEIGHT=360.
FVID_exchange(disChan, &disFrameBuf);
将转换好的图像数据发送给mini-driver处理,并传回空缓冲区指针,FVID_exchange函数相当于顺序执行FVID_free和FVID_alloc函数。disChan为指定的fvid通道,disFrameBuf为交换的缓冲区指针。
An application calls FVID_exchange to request the video device driver to give it ownership of a data buffer in exchange for a buffer that the application owns and is ready to relinquish back to the driver. FVID_exchange 相当于顺序执行 FVID_free and FVID_alloc函数, 成功则返回IOM_COMPLETED,IOM_COMPLETED等在iom.h中定义,该函数将导致mdSubmit 的调用,详见附录。.
SCOM_putMsg( scomSend, scombufDisp );
将处理完的缓冲区重新发回给process进程。
scomSend为scom模块句柄,scombufDisp为scom信息,该信息指向一缓冲区。
继续执行该循环。
5.Fvid对gio的封装
从fvid.h中我们可以清晰的看出fvid即为gio的一种扩展封装。
#define FVID_alloc(gioChan, bufp) /
GIO_submit(gioChan, FVID_ALLOC, bufp, NULL, NULL)
……………………………………………
6.Fvid的属性结构
typedef struct FVID_Attrs {
Uns timeout;
} FVID_Attrs;
Fvid的属性,指定fvid函数(即相当于gio相关函数)等待时间。若函数不能立即返回将会导致进程被挂起。若果指定为非0, FVID_alloc, FVID_free and FVID_exchange 只能在 DSP/BIOS task (TSK)使用。因swi和hwi不可能因此挂起。
Fvid信息
typedef struct FVID_Frame {
QUE_Elem queElement; /* for queuing */
union {
FVID_Iframe iFrm; /* y/c frame buffer */
FVID_Pframe pFrm; /* y/c frame buffer */
FVID_RawIFrame riFrm; /* raw frame buffer */
FVID_RawPFrame rpFrm; /* raw frame buffer */
} frame;
} FVID_Frame;
typedef struct FVID_Iframe{
Char* y1;
Char* cb1;
Char* cr1;
Char* y2;
Char* cb2;
Char* cr2;
}FVID_Iframe;
/* progressive frame */
typedef struct FVID_Pframe {
Char* y;
Char* cb;
Char* cr;
} FVID_Pframe;
typedef struct FVID_RawIFrame{
Char* buf1;
Char* buf2;
} FVID_RawIFrame;
typedef struct FVID_RawPFrame{
Char* buf;
} FVID_RawPFrame;
QUE_Elem为该gio使用的队列,第二个成员为一指向缓冲区的指针。为联合体,即实例化结构对象第二个成员为指向该种联合体成员之一。该程序为iframe。
7.Class driver/mini-driver模型结构

在类/微型驱动模型中,类驱动通常用于完成多线程I/O请求的序列化功能和同步功能,同时对设备实例进行管理。在包括视频系统I/O和异步I/O的典型实时系统中,只有少数的类驱动需要表示出外部设备的类型。
类驱动通过每个外部设备独有的微型驱动对设备进行操作。微型驱动通过控制外设的寄存器、内存和中断资源对外部设备实现控制。微型驱动程序必须将特定的外部设备有效地表示给类驱动。例如:视频显示设备存在一些不同的帧存,应用软件会根据不同的I/O操作进行帧存的分配,此时微型驱动必须映射视频显存,使得类驱动可以对不连续的内存(分别存放RGB或YUV分量)设计特定的I/O请求。
类/微型驱动模型允许发送由开发者定义数据结构的I/O请求包给微型驱动来控制外部设备,此分层结构使设备驱动的复用能力得到加强,并且丰富了发送给微型驱动的I/0请求包的结构。
上层的应用程序不直接控制微型驱动,而是使用一个或一个以上的类驱动对其进行控制。每一个类驱动在应用程序代码中表现为一个API[3]函数并且通过微型驱动的接口IOM与微型驱动进行通信。类驱动使用DSP/BIOS中的API函数实现诸如同步等的系统服务。
类驱动通过标准的微型驱动接口调用微型驱动控制硬件设备。到目前为止DSP/BIOS共定义了三种类驱动:流输入输出管理模块(SIO)、管道管理模块(PIP)和通用输入输出模块(GIO)。在PIP和SIO类驱动中,调用的API函数已经存在于DSP/BIOS的PIP和SIO模块中。这些API函数需将参数传给相应的适配模块(adapter),才能与微型驱动交换数据。而在GIO类驱动中,调用的API函数则直接与微型驱动通信(需在CCS2.2以上)。
每一个微型驱动都为类驱动和DSP/BIOS设备驱动管理提供了标准接口。微型驱动采用芯片支持库管理外围设备的寄存器、内存和中断资源。
GIO模块
GIO模块在提供必要的同步读/写API函数及其扩展函数的同时,将代码和使用数据缓存的大小尽量简化。应用程序可以调用GIO的API函数直接与微型驱动的IOM交换数据,这些API函数使得GIO成为了类驱动。
当调用GIO_create创建一个外部设备的通道实例时,GIO在通道实例中增加了状态和I/O请求状态结构、IOM数据包(IOM_Packets)及一个GIO数据对象。GIO创建的通道实例的数据结构如下:
typedef stmct GIO_Obj{
IOM_Fxns *fxns; /* 函数表指针*/
Uns mode; /* 创建模式 */
Uns timeout; /* 超时时间 */
IOM_Packet syncPacket;/* 同步时使用的IOM_Packet */
QUE_Obj freeList; /* 异步I/O队列 */
Ptr syncObj; /* 同步对象地址 */
Ptr mdChan; /* 通道实例地址 */
}GIO_Obj,*GIO_Handle;
函数表指针是应用程序和微型驱动函数表(fxns)的接口;创建模式包括:输入(IOM_INPUT)、输出(IOM_OUTPUT)和双向(IOM_NOUT);IOM Packet在类驱动和微型驱动间的异步操作时使用;同步对象地址指向特定通道的同步信号;通道实例地址指向微型驱动创建的通道实例。
类/微型驱动模型中的微型驱动直接控制外部设备。只要微型驱动创建了规定的函数,应用程序就可以方便地通过DIO适配模块、PIO适配模块或(和)GIO类驱动调用。这些规定的函数包括:通道绑定函数(md—BindDev)、通道创建/删除函数(mdCreateChan/md—DeleteChan)、I/O请求发送函数(mdSubmitChan)、中断服务函数(ISRs)和设备控制函数(mdControlChan)。这些规定的函数将放入微型驱动的函数接口表(IOM_Fxns)中的相应位置,供应用程序通过适配模块或GIO类驱动调用。函数接口表的结构如下:
typedef struct IOM_Fxns
{
IOM_TmdBindDev mdBindDev;
IOM—TmdUnBindDev mdUnBindDev;
IOM—TmdControlChan mdControlChan;
IOM_TmdCreateChan mdCreateChan;
IOM_TmdDeleteChan mdDeleteChan;
IOM_TmdSubmitChan mdSubmitChan;
}IOM_Fxns;
在设备初始化使dsp/bios将调用用户自定义设备初始化程序后调用mdbinddev函数。Mdcontrolchan为回应sio_strl,pio_ctrl,gio_ctrl函数时调用,若class drive
r超时,则一个cmd为iom_chan_timedout的命令将发给mdcontrolchan函数。
同理mdsubmitchan回应sio_submit,pio_submit,gio_submit。。。。。。
四、 关于XDAIS
在process线程中,处理通过四个channel完成,第一个channel直通,第二个做diff运算,第三个做rotate运算,第四个是combination通道,就是先完成diff运算,再完成rotate运算后输出。对diff和rotate功能进行cell封装,在第二个channel中使用一个diffcell,第三个channel中使用一个rotatecell,第四个通道中使用一个diffcell和一个rotatecell。关于cell的封装,以diffcell为例进行说明。
RF5特征:CELL封装
/*
* ICELL_Obj
* ---------
* This structure is used to define a cell.
*/
typedef struct ICELL_Obj {
Int size; /* Number of MAU in the structure */
String name; /* User chosen name. */
ICELL_Fxns *cellFxns; /* Ptr to cell v-table function. */
Ptr cellEnv; /* Ptr to user defined cell env. Struct */
IALG_Fxns *algFxns; /* Ptr to alg v-table functions. */
IALG_Params *algParams; /* Ptr to alg parameters. */
IALG_Handle algHandle; /* Handle of alg managed by cell. */
Uns scrBucketIndex; /* Scratch bucket for XDAIS scratch mem. */
ICC_Handle *inputIcc; /* Array of input ICC objects */
Uns inputIccCnt; /* # of ICC objects in the input array */
ICC_Handle *outputIcc; /* Array of output ICC objects */
Uns outputIccCnt; /* # of ICC objects in the output array */
} ICELL_Obj;
// v-table for the diff cell
//提供对外的接口,也就是向channel提供功能作用的接口
ICELL_Fxns DIFF_CELLFXNS = {
NULL, // cellClose
NULL, // cellControl
DIFF_cellExecute, // cellExecute
NULL // cellOpen
};
* ======== DIFF_cellExecute ========
*
Bool DIFF_cellExecute( ICELL_Handle handle, Arg arg )
{
IDIFF_Handle diffHandle = (IDIFF_Handle)handle->algHandle
;//此处handle->algHandle返回的本来是IALG_Handle,此处用强制类型转换进行句柄类型转换
// activate instance object,DIFF算法的实例对象
ALGRF_activate( handle->algHandle );
runDIFF(diffHandle,
(Short **)handle->inputIcc[0]->buffer,
(Uint32 **)handle->outputIcc[0]->buffer,
(DIFF_Env *)handle->cellEnv);
// deactivate instance object
ALGRF_deactivate( handle->algHandle );
return(TRUE);
}
* ======== runDIFF ========
* Run DIFF algorithm.
*/
static void runDIFF(IDIFF_Handle handle, Short **inData,
Uint32 **outData, DIFF_Env *env)
这就是CELL中完成DIFF功能的函数,其参数包括IDFF实例对象句柄,CELL的输入BUFFER,CELL的输出BUFFER以及实例对象的环境参数。
这个函数完成数据的输入,处理和输出。关键功能是进行DIFF处理,在这个函数中有这样的代码:
// Now for the real work…call the algorithm.
handle->fxns->apply(handle,
(unsigned char *)(intYBuf + (toggle * ySingleBufSize)),
(unsigned char *)(intCrBuf + (toggle * crSingleBufSize)),
(unsigned char *)(intCbBuf + (toggle * cbSingleBufSize)),
(unsigned char *)ptrPrevY, (unsigned char *)ptrPrevCr,
(unsigned char *)ptrPrevCb, ySingleBufSize, crSingleBufSize,
env->yValue, env->crValue, env->cbValue, PROCF_WIDTH);
用来调用DIFF的具体算法。Handle就是IDIFF_Handle,是指向CELL实例对象的指针
定义如下:/*
* ======== IDIFF_Handle ========
* This handle is used to reference all DIFF instance objects
*/
typedef struct IDIFF_Obj *IDIFF_Handle;
实例对象定义如下:
* ======== IDIFF_Obj ========
* This structure must be the first field of all DIFF instance objects
*/
typedef struct IDIFF_Obj {
struct IDIFF_Fxns *fxns;
} IDIFF_Obj;
IDIFF_Fxns定义如下:
/*
* ======== IDIFF_Fxns ========
* This structure defines all of the operations on DIFF objects
*/
typedef struct IDIFF_Fxns {
IALG_Fxns ialg; /* IDIFF extends IALG */
Void (*apply)(IDIFF_Handle handle, unsigned char y[],
unsigned char cr[], unsigned char cb[],
unsigned char prevY[], unsigned char prevCr[],
unsigned char prevCb[], Int lumaSize, Int chromaSize,
Int yValue, Int crValue, Int cbValue, Int procWidth);
} IDIFF_Fxns;
可以看到,runDIFF最终调用的是IDFF_Fxns中的的Void (*apply)()算法函数。
// v-table for this cell's algorithm
此处定义了cell实例算法的v表,通过DIFF_IDIFF来调用具体的算法
至此,对上层(cell以及channel)可见的部分完成。在thrProcess中定义了cell的实例
cell = &thrProcess.diffCells[ chanNum * CHDIFFNUMCELLS ];
*cell = defaultCell;
cell->name = "DIFF";
cell->cellFxns = &DIFF_CELLFXNS;
//定义了cellDiff的cell v-table,提供了外部访问的接口
cell->cellEnv = (Ptr *)&thrProcess.diffEnv[chanNum];
//定义了cellDiff的环境变量,主要功能是完成buffer的指定和参量的设置
cell->algFxns = (IALG_Fxns *)&DIFF_IDIFF;
//定义了cellDiff的IALG v-table,是算法XDAIS标准的要求
cell->algParams = (IALG_Params *)&diffParams;
cell->scrBucketIndex = VIDEOPROCSCRBUCKET;
XDAIS部分:算法的封装
根据spru352e的规则12:所有的XDAIS 算法都必须使用IALG接口。IALG接口提供的功能有:对系统存储资源的管理,算法实例的建立,初始化和终止对象。
上面的IDIFF_Fxns(也就是DIFF_IDIFF)就是一个符合XDAIS标准的算法。它包括了IALG接口,IALG接口提供了一个结构IALG_Fxns,又称作V表。除了I
ALG接口,IDIFF_Fxns还定义了一个算法实例接口Void (*apply)(),该接口包含了算法的实现。该接口是DIFF算法接口的一个实例。
在这个工程中,IDIFF_Fxns对实现算法的函数进行了封装,通常情况下用module_vendor来命名算法接口的实例。Module为算法名, vendor是实现厂商或个人所特有的标示符,在本例中DIFF_TI_IDIFF就是IDIFF算法的一个实例。
在diff_ti64.pjt的头文件diff_ti.h中定义了DIFF_TI模块的接口:
* ======== DIFF_TI_IALG ========
* TI's implementation of the IALG interface for DIFF IALG接口
*/
extern IALG_Fxns DIFF_TI_IALG;
* ======== DIFF_TI_IDIFF ========
* TI's implementation of the IDIFF interface 算法接口
*/
extern IDIFF_Fxns DIFF_TI_IDIFF;
第一句实例化了模块的IALG接口,第二句实例化了模块的算法接口。两个接口的参数和v-table分别在头文件ialg.h和idiff.h中定义
ialg.h:
IALG_Fxns的定义如下:
typedef struct IALG_Fxns {
Void *implementationId;
Void (*algActivate)(IALG_Handle);
Int (*algAlloc)(const IALG_Params *, struct IALG_Fxns **, IALG_MemRec *);
Int (*algControl)(IALG_Handle, IALG_Cmd, IALG_Status *);
Void (*algDeactivate)(IALG_Handle);
Int (*algFree)(IALG_Handle, IALG_MemRec *);
Int (*algInit)(IALG_Handle, const IALG_MemRec *, IALG_Handle, const IALG_Params *);
Void (*algMoved)(IALG_Handle, const IALG_MemRec *, IALG_Handle, const IALG_Params *);
Int (*algNumAlloc)(Void);
} IALG_Fxns;
在这个结构中,除了algAlloc ( ) ,al2gInit () 和algFree () 是必须的外,其它的函数都是可选的。algAlloc () 实现存储管理;algInit ( ) 用来初始化算法实例对象;algFree ( ) 在销毁算法实例对象后,释放存储空间。
函数中关于存储区定义的参数是IALG_MemRec:
typedef struct IALG_MemRec {
Uns size; /* size in MAU of allocation */
Int alignment; /* alignment requirement (MAU) */
IALG_MemSpace space; /* allocation space *枚举类型,值不同在algrf.h中定义的存储区域(INTHEAP,EXTHEAP)也不同/
IALG_MemAttrs attrs; /* memory attributes *三种类型,scratch memory,persistent memory ,write-once persistent memory/
Void *base; /* base address of allocated buf */
} IALG_MemRec;
idiff.h:
定义了算法接口:
* ======== IDIFF_Fxns ========
* This structure defines all of the operations on DIFF objects
*/
typedef struct IDIFF_Fxns {
IALG_Fxns ialg; /* IDIFF extends IALG */
Void (*apply)(IDIFF_Handle handle, unsigned char y[],
unsigned char cr[], unsigned char cb[],
unsigned char prevY[], unsigned char prevCr[],
unsigned char prevCb[], Int lumaSize, Int chromaSize,
Int yValue, Int crValue, Int cbValue, Int procWidth); //算法实例接口
} IDIFF_Fxns;
头文件还定义了三个常量:
#define DIFFTHRESHOLD 50
#define YTHRESHOLD 15
#define CRCBTHRESHOLD 0
用在算法函数中作为比较的门限值。
diff.c:
定义了DIFF_TI_init()与DIFF_TI_exit()
diff_ti_ialg.c:
实例化IALG接口,定义了DIFF_TI_alloc,DIFF_TI_free,DIFF_TI_initObj和DIFF_TI_initObj函数
diff_ti_vt.c:
定义了DIFF_TI_IDIFF。如下:
#define IALGFXNS /
&DIFF_TI_IALG, /* module ID */ /
NULL, /* activate */ /
DIFF_TI_alloc, /* algAlloc */ /
NULL, /* control */ /
NULL, /* deactivate */ /
DIFF_TI_free, /* free */ /
DIFF_TI_initObj, /* init */ /
NULL, /* moved */ /
DIFF_TI_numAlloc /* numAlloc */
/*
* ======== DIFF_TI_IDIFF ========
* This structure defines TI's implementation of the IDIFF interface
* for the DIFF_TI module.
*/
IDIFF_Fxns DIFF_TI_IDIFF = { /* module_vendor_interface */
IALGFXNS,
DIFF_TI_apply
};
asm("_DIFF_TI_IALG .set _DIFF_TI_IDIFF");
第一部分是对IALG_Fxns 的初始化并将它包含进DIFF_TI_IDIFF中,然后把DIFF_TI_apply函数包含进来,就组成了DIFF_TI_IDIFF结构。DIFF_TI_apply函数是算法的实现函数。然后就可以声明:Extern IALG_Fxns DIFF_TI_IDIFF与extern IDIFF_Fxns DIFF_TI_IDIFF(在头文件diff_ti.h中),从而实现了IALG和IDIFF接口的实现。
工程diff_ti64.pjt的out文件是diff_ti.l64,在motiondectect中要使用diff算法只需要在Bulild options中进行设置,将diff_ti.l64文件包括到link.cmd文件中,并声明:
_DIFF_IDIFF = _DIFF_TI_IDIFF;
又,在cellDiff.c中给出声明:
extern far IDIFF_Fxns DIFF_IDIFF;
//cell接口,外部通过DIFF_IDIFF接口访问cell内部算法
在编译时指明工程中访问DIFF_IDIFF时就调用diff_ti64.pjt中的DIFF_TI_IDIFF,进而调用具体的实现算法。
diff_ti_apply.c:算法的具体实现函数

 

五、 关于RF5
A.RF的框架介绍
RF框架如图所示:
将RF现有的模块列表如下:

1. ALGMIN模块
由RF1提供的一个IALG执行接口成为ALGMIN。ALGMIN模块提供了静态应用的XDAIS算法函数,可以同时在C5000和C6000平台上使用。
ALGMIN包含的函数如下表所示:

它们的调用顺序如下图所示:
2. ALGRF模块
ALGRF模块可以使用DSP/BIOS存储管理器来创建和删除XDAIS算法,符合RF3和RF5的需要。它还可能适用于其他级别的RF。
ALGRF包含的函数如下表所示:

这些函数的调用顺序如下图所示:
3. CHAN模块
CHAN负责管理算法的封装,它使定义的结构符合ICELL接口。
CHAN包含的函数如下表所示:

函数的调用顺序如下图所示:
4. ICC模块
ICC负责管理内部CELL之间的通信。
ICC包含的函数如下表所示:

用ICC对象的时候允许一个channel有一个灵活的数据流,以数据流0为例,如下图所示:

图中这个channel有3个cell。第一个cell有两个输出,可以使用5个线性ICC对象对其进行简单的管理。
ICC模块中函数的调用顺序如下图所示:
5. SCOM模块
SCOM负责模块间的同步通信。
SCOM包含的函数如下表所示:

这些函数的调用顺序如下图所示:
6. SSCR模块
SSCR是共享的可改写存储模块。
SSCR包含的函数如下表所示:<BR
>
这些函数的调用顺序如下图所示:
7. UTL模块
UTL是调试和诊断的统一模块。
UTL包含的函数如下表所示:


B.RF小结
RF 主要实现三个主要的功能:存储管理,线程模型和通道封装。对于不同的应用,我们只需在这三个元素上做改变,而不用从头设计整个应用,这大大简化了开发者的开发难度,并节省了开发时间。
RF5针对大型系统,主要用于由C6 ×实现的高端系统。RF5 适用于包含大量的算法,且要求多线程、多通道的应用,像图像处理、多媒体应用等。
Motion Detection 程序是按照RF5框架来构造的,下面是针对该程序做简要介绍:
1.线程(Thread)
RF5 框架包含四个基本数据处理元素,处在最顶层是线程,线程总是顺次执行所包含的通道。线程在一个较高级别的层次上把数据组织在一起,它们可以与别的线程,设备驱动以及别的类似结构进行通讯。每个线程都是在不断地等待消息,处理数据,并将结果传给别的线程。每个线程之间是通过SCOM 来进行通讯的。
每个线程都是进行数据处理的一个单元。有的处理是很简单的,有些处理却很复杂,简单的线程可以不包含任何通道,而复杂的线程可以包含多个通道。
该系统有四个线程,分别为
Capture线程
Process线程
Display线程
Control线程
四个线程既是分工明确,又是有序的结合。Capture线程进行原始图像的捕获,并对捕获的图像进行转换,以便于接下来的处理;Process线程对采集进来的图像进行处理,主要包括DIFF和ROTATE两个处理过程,是这个程序的主要部分;Display线程将处理好的图像进行显示;Control线程主要是用来进行控制在DIFF算法中所涉及的参考帧和所着的颜色信息。
2.同步通讯机制(SCOM)
ThrProcess 中包含两个SCOM 对象。RF5 使用SCOM 对象来实现线程间的通讯。
SCOM 消息是用户自定义的一种结构。一个线程通过调用SCOM putMsg ( ),将SCOM 消息放到一个SCOM队列中,发送给别的线程,或者通过调用SCOM getMsg() 从队列中获取消息。一般情况下,发送消息指明接受线程所要读取的数据缓冲区的地址,接受消息指明发送线程所要写入的数据缓冲区的地址。在本例中,thrProcess 要从thrCapture 接受消息,并且要发送消息给thrDisplay。
RF5使用SCOM来实现线程间的通讯:thrProcess 拥有一些缓冲区,需要thrCapture写或thrDisplay读。故thrProcess 需要告诉thrCapture和thrDisplay这些缓冲区的位置,并且保证两个线程不会同时访问同一个缓冲区。这就要用到SCOM。thrProcess 创建了两种消息以分别与两个线程进行通讯。整个系统中包含许多存储区,它们可以被任何线程访问,但为了保证每次只能有一个线程访问某个存储区,当前访问该存储区的线程通过发送SCOM消息给另外一个线程,表示它放弃了访问该存储区的权利,而接受到SCOM消息的线程就可以访问该存储区了。
下面是一个利用SCOM通信的简单例子:
本程序中的应用示例如下:
在Capture线程中:
scomReceive = SCOM_create("scomCapture", &SCOM_ATTRS);
scomReceive = SCOM_open( "scomCapture" );
scomSend = SCOM_open( "scomToProcessFromCapture" );
在Process线程中:
scomReceiveFromCapture = SCOM_create( "scomToProcessFromCapture",
&SCOM_ATTRS );
scomReceiveFromDisplay = SCOM_create( "scomToProcessFromDisplay",
&SCOM_ATTRS );
scomSendToCapture = SCOM_open( "scomCapture" );
scomSendToDisplay = SCOM_open( "scomDisplay" );
在Display线程中:
scomReceive = SCOM_create("scomDisplay", NULL);
scomReceive = SCOM_open( "scomDisplay" );
scomSend = SCOM_open( "scomToProcessFromDisplay" );
一共创建了四个SCOM。Capture创建了“scomCapture”,用来接收Process发来的空缓冲区。Process创建了“scomToProcessFromCapture”和“scomToProcessFrom
Display”,前者用来接收Capture发来的满的缓冲区,后者用来接收Display发来的空的缓冲区。
3.通道(Channel)
RF5 提供了一种通道结构是为了更方便地封装算法。我们可以把通道理解为并行里的串行,因为线程的执行就由通道的串行执行来完成的。一个通道包含了一组核。通道的主要任务就是依次顺序地执行所包含的核。其主要执行流程为:首先需要初始化通道模块,然后建立通道对象,注册该通道所包含的核对象,接着依次执行每个核,执行完了后就销毁对象,最后退出。要注意的是,每个通道可以包含多个核,每一个核都要进行初始化后再调用CHAN regCell 注册。
本程序的Process线程中,安排了四个通道,分别为:
1. Passthrough Channel
2. Diff Channel
3. Rotate Channel
4. Combo Channel
4.核(Icell)
核实际上就是ICELL 接口对象。基于RF5 的应用常常包含大量的算法和通道。为了便于算法集中到应用中,RF5 提出了核的概念。一个核就是包含一种XDAIS 算法的容器。一个RF5 通道对象可以包含多个核,也即是包含多个算法。通道通过核来调用算法。实际上, 真正的数据处理是在XDAIS 算法,核只是提供了一个调用算法的接口。这大大简化了工作量,便于移植。RF5 提供了一个核对象接口,称为ICELL 。该接口包含一个重要的结构: ICELL Fxns ,该结构包含一组函数指针。通道通过调用这些函数来调用算法。其中包含一个关键的函数cellExecute ,这个函数的功能是调用XDAIS 算法来执行。上面的通道执行函数CHAN execute 就包含了对每一个cellExecute 的调用。
实际情况和和上面的图稍有不同,就是四个通道都没有包含“YUV2RGB”这个CELL。所以四个通道包含的CELL数分别是:0,1,1,2。
拿“DIFF”核来说,它的具体算法的源代码存放在referenceframeworks/apps/rf5_iek/diff_ti目录下,以库文件diff_ti.l64的形式输出,存放在/lib目录下。在.cmd file文件中,有如下代码:
_l diff_ti.l64
_DIFF_IDIFF = _DIFF_TI_IDIFF;
运用这套算法,需要为它做一个CELL外壳。工程中的文件cellDiff.h和cellDiff.c就是来实现这个外壳的。
5.ICC
ICC 模块是用来管理在核之间以及核与它们的线程之间的数据通讯的,我们知道线程间的数据传输是通过SCOM 模块来实现的。每个ICC 模块管理一个或多个ICC 对象。每个核都有一组输入和输出ICC 对象。这些对象是通过CHAN regCell() 来注册到相应的通道中的。
六、 关于程序中的所有存储器以及其搬移图
在一个程序中,存储器的选择和数据的搬移是至关重要的,直接影响到程序的可实现性和效率,下图就详细标明了Motion Detection程序中的所有存储器以及搬移图,使您对DM642系统的工作情况更加直观明了。

 

 类似资料: