OSD link是所谓的process link。即,该link没有output queue,而是直接在input queue的buffer上做操作。其数据流向如下图
1. prev link将frame buffer送给process的input queue
2. process link在input queue中取出buffer,对buffer的数据进行操作
3. process link将该buffer归还给prev link的empty queue
4. prev link检测到该buffer是从一个process link还回来的,于是又将其发送到next link去。
OSD Link功能运行在C67 DSP核上,一般工作在Capture Link之后,用来在采集到的视频帧上叠加一个图片(LOGO或是标题等)。待叠加的图片pic存放在共享内存SR0中(RGB或者YUV点阵格式)。当一帧数据frame从capture link送到OSD link,DSP首先启动EDMA将pic和frame的一部分从共享内存和DDR中搬移到内部L2中去。然后DSP根据预先设置的alpha参数,对pic和frame相应位置的每一点做alpha blend。计算好的结果被EDMA搬回输入的frame buffer中去覆盖原有的数据。由于OSD link属于Process link,该frame buffer会被送到下一个link中去,从而完成OSD效果。
1. DSP的main程序创建system_main线程,system_main中调用AlgLink_init。
2. 进入AlgLink_init,创建两个AlgLink的实例。对于每一个实例,调用System_registerLink和创建task。
System_registerLink主要是为了注册下面几个回调函数
linkObj.linkGetFullFrames = NULL;
linkObj.linkPutEmptyFrames = NULL;
linkObj.linkGetFullBitBufs = AlgLink_getFullBufs;
linkObj.linkPutEmptyBitBufs = AlgLink_putEmptyBufs;
linkObj.getLinkInfo = AlgLink_getInfo;
其中linkGetFullBitBufs是为了给next link从本link的output queue获取bitstream buffer,而linkPutEmptyBitBufs则给next link将用完的buffer归还给本link。
由于OSD本身没有output queue,所以这两个函数实际是给共用Alglink的SCD算法使用的。
3. 创建AlgLink_tskMain线程。
4. 进入AlgLink_tskMain,当收到一条create消息时,进入下列处理,否则直接丢掉该消息返回。
5. 进入AlgLink_algCreate,内部实际是调用AlgLink_OsdalgCreate。
6. 进入AlgLink_OsdalgCreate。该函数主要做了两方面的事,一是根据传入的create arg,设置OSD的运行context(其实就是拷贝到本地的一些变量中保存啦)。二是调用SWOSD_open。
7. SWOSD_open主要为了注册两个数据结构:SWOSD_TI_IALG和SWOSD_TI_IRES。这两个是TI XDAIS标准规定的算法标准接口。前一个主要关注算法的memory需求和分配,后一个关注算法对DMA资源的需求。我们下面分开来说。
l SWOSD_TI_IALG
#define IALGFXNS \
&SWOSD_TI_IALG, /* module ID */ \
NULL, /* activate */ \
SWOSD_TI_alloc, /* alloc */ \
NULL, /* control (NULL => no control ops) */ \
NULL, /* deactivate */ \
SWOSD_TI_free, /* free */ \
SWOSD_TI_initObj,/* init */ \
NULL, /* moved */ \
SWOSD_TI_numAlloc /* numAlloc (NULL => IALG_MAXMEMRECS) */
这几个函数都是为了让Application来分配算法所需要的memory资源。Application首先调用SWOSD_TI_numAlloc,得到需要的IALG_MemRec个数。每一个memRec代表一个内存块的需求,包括分配区域,内存块大小,对齐等属性。然后Application根据该个数,分配相应个数的IALG_MemRec大小的buffer,将该buffer当做参数调用SWOSD_TI_alloc。算法的SWOSD_TI_alloc函数负责填写各个IALG_MemRec结构的大小,内存区域,对齐等属性,除了base address。Application然后根据填好的各IALG_MemRec从相应的内存区分配memory,并将分配好的memory buffer地址填入base address字段。最后将整个IALG_MemRec数组传入SWOSD_TI_initObj。算法用Application分配好的memory来完成自己的初始化。
实际上,TI为了简化操作,实现了一套framework来完成这些。在SWOSD_OPEN中,我们可以看到,通过调用DSKT2_createAlg函数,将SWOSD_TI_IALG这一套函数指针传入即可完成上面的交互过程。
对于OSD ALG来说,其需要的内存区有两个(memTab[2])。memTab[0]用来存放OSD_obj的内容,也就是运行的一些context。memTab[1]用来进行一行的blend运算。假设一行宽度为N个pixel,每个pixel需要Mbytes,则需要的内存大小为N*M*[1(blend输入1)+1(blend输入2)+ 1( output buffer) +1 (alpha matrix)]*2(ping pong buffer)
其中blend输入1和2分别对应video buffer和osd picture的一行。Alpha matrix暂时并未实现,其目的本来是为了可以对每一个像素点指定一个alpha值。这两个内存区都是从DSP的L2里分配。
l SWOSD_TI_IRES
该结构与SWOSD_TI_IALG类似,只不过其分配的是DMA资源。这里不再详细描述。注意framework也封装了一个类似的RMAN_assignResources来完成交互过程。
OSD alg总共需要5个EDMA通道
#define SWOSD_DMA_CH_IN_A 0x0
#define SWOSD_DMA_CH_IN_B 0x1
#define SWOSD_DMA_CH_ALP 0x2 //传送alpha matrix,暂无试用
#define SWOSD_DMA_CH_OUT 0x3
#define SWOSD_DMA_CH_AUX 0x4 //用来在alpha值为0x80时,用来完成单纯的覆盖而不是blend。暂无使用。
8. SWOSD_open执行完,AlgLink_algCreate执行完,即可进入消息处理循环。与OSD功能相关的是两个消息: ALG_LINK_OSD_CMD_SET_CHANNEL_WIN_PRM和SYSTEM_CMD_NEW_DATA。
9. 一般来说,create后应该先收到ALG_LINK_OSD_CMD_SET_CHANNEL_WIN_PRM消息来设置每一通道的OSD属性。存放OSD图片的SR0 buffer地址也是在这时传入。在demo程序中,这一动作是在Vcap_setDynamicParamChn中完成。
10. 当收到SYSTEM_CMD_NEW_DATA时,进入AlgLink_algProcessData。该函数首先调用System_getLinksFullFrames,从prev link中取得frame buffers。然后调用AlgLink_OsdalgProcessFrame处理每一个frame buffer,最后调用System_putLinksEmptyFrames将处理完的frame buffer返还前一个link。
11. AlgLink_OsdalgProcessFrame调用SWOSD_blendWindow分别对Y plane(亮度)和C plane(UV通道)进行处理。
12. SWOSD_blendWindow首先调用RMAN_activateAllResources,在OSD算法中,这实际是一个空操作。然后调用SWOSD_TI_algRun核心算法。
13. SWOSD_TI_algRun使用了3个EDMA通道,记为SWOSD_DMA_CH_IN_A,SWOSD_DMA_CH_IN_B,SWOSD_DMA_CH_OUT。SWOSD_DMA_CH_IN_A负责将OSD图像中的一行从SR0搬移到L2的ping-pong buffer中,SWOSD_DMA_CH_IN_B负责将video frame中的一行从frame buffer中搬移到L2的ping-pong buffer,而SWOSD_DMA_CH_OUT负责将blend后的数据从L2 ping pongbuffer中搬移到video frame中。
其流程如下:
等待SWOSD_DMA_CH_IN_A和SWOSD_DMA_CH_IN_B 对ping buffer的搬移完成
SWOSD_DMA_CH_IN_A和SWOSD_DMA_CH_IN_B启动pong buffer的搬移。
DSP计算alpha blend的值,写入L2的out pong buffer。
等待SWOSD_DMA_CH_OUT ping buffer搬移完成
启动SWOSD_DMA_CH_OUT pong buffer的搬移
其中ping pong buffer的切换由EDMA参数自动变换,运行过程中无需再手动切换ping pong buffer地址。