移植EMCV到DM6467(4)——video_copy例程的xDM算法封装

来源:互联网 发布:sql中count的用法 编辑:程序博客网 时间:2024/05/17 04:53

要移植EMCV(EmbeddedComputer Vision,OpenCV的嵌入式版本)到DM6467是一件挺繁杂的工作,要修改很多代码以及配置文件。以下将对整个移植过程进行简单介绍。注意:以下内容只是移植工作的主要部分,有很多小地方就忽略了。

整个移植的思路是:首先对EMCV源文件进行裁剪,将未用到的函数都去掉,以降低代码复杂度,同时也减小程序出错的可能性;然后,通过对Codec Engine中videnc_copy这个codec的修改来实现将EMCV封装成一个符合xDM算法标准的codec,这部分是移植的重点;接下来,通过修改Codec Engine中的video_copy应用程序来调用新的videnc_copy,实现对单幅图像的处理,图像以文件形式读入;最后,通过修改encodedecode demo以集成含有EMCV源码的videnc_copy,实现视频采集、处理和显示的功能。

 

1        编译example

按照移植思路,我们首先要将EMCV封装到videnc_copy这个codec中,videnc_copy所在路径为codec_engine_2_25_05_16/examples/ti/sdo/ce/examples/codecs/videnc_copy。在封装之前,需要保证examples能够正确编译,也即确保各编译路径是正确的。要编译examples,需按照examples目录下build_instructions.html中的步骤进行。

1.1  修改xdcpath.mak

xdcpath.mak是与编译相关的一个文件,examples中的所有Makefile都要调用它。用户需要修改xdcpath.mak来指定各组件的安装路径,例如DSPLINK、LINUXUTIL等。用户也可以修改xdcpath.mak来指定编译的目标平台,以缩短编译时间。

对于xdxpath.mak,用户需要修改的包括:DEVICES,GPPOS,PROGRAMS和各种组件的安装路径。修改过后的各变量如下所示。

 

 

DEVICES  := DM6467

 

GPPOS := LINUX_GCC

 

PROGRAMS := APP_CLIENT DSP_SERVER

 

CE_INSTALL_DIR        := /opt/dvsdk/dvsdk_3_10_00_19/codec_engine_2_25_05_16

XDC_INSTALL_DIR       := /opt/dvsdk/dvsdk_3_10_00_19/xdctools_3_16_01_27

BIOS_INSTALL_DIR      := /opt/dvsdk/dvsdk_3_10_00_19/bios_5_41_00_06

DSPLINK_INSTALL_DIR   := /opt/dvsdk/dvsdk_3_10_00_19/dsplink_linux_1_64

 

USE_CETOOLS_IF_EXISTS := 1

XDAIS_INSTALL_DIR     := /opt/dvsdk/dvsdk_3_10_00_19/xdais_6_25_02_11

FC_INSTALL_DIR      := /opt/dvsdk/dvsdk_3_10_00_19/framework_components_2_25_02_06

CMEM_INSTALL_DIR      := /opt/dvsdk/dvsdk_3_10_00_19/linuxutils_2_25_04_10

WINCEUTILS_INSTALL_DIR:= _your_WINCEUTILS_installation_directory/winceutils_1_00_03_13

BIOSUTILS_INSTALL_DIR := /opt/dvsdk/dvsdk_3_10_00_19/biosutils_1_02_02

EDMA3_LLD_INSTALL_DIR := /opt/dvsdk/dvsdk_3_10_00_19/edma3_lld_01_11_00_03

LPM_INSTALL_DIR   := _your_LPM_installation_directory/local_power_manager_1_24_02_09

 

CGTOOLS_V5T := /opt/arm-2009q1

CC_V5T := bin/arm-none-linux-gnueabi-gcc

CGTARGET := gnu.targets.arm.GCArmv5T

 

CGTOOLS_C64P := /opt/ti/C6000CGT7.3.5

CC_C64P      := bin/cl6x

 

 

1.2  编译codec,server和app

修改好xdcpath.mak之后就可以进行编译了。编译必须按照codec->server->app的顺序进行,因为只有codec编译好之后server才能将codec集成到一起,也只有server编译好之后app才能创建codecengine。编译步骤如下所示(假设当前目录为examples)。

 

 

cd ./ti/sdo/ce/examples/codecs

make clean

make

 

cd ../servers

make clean

make

 

cd ../apps

make clean

make

 

 

1.3  运行程序

编译完成之后,需要确认程序是否能够正常运行。这里对video_copy程序进行测试。要运行该应用程序,需要将以下文件复制到目标路径。

 

文件名

用途

dsplink.ko

dsplink的linux驱动,双核通信

cmem.ko

cmem的linux驱动,分配连续内存

loadmodule.sh

用于加载dsplink和cmem模块

servers/all_codecs/bin/ti_paltforms_evmDM6467/all.x64p

Codec Server

apps/video_copy/bin/ti_paltforms_evmDM6467/app.xv5t

应用程序

apps/video_copy/in.dat

应用程序的输入文件

 

将以上文件复制到开发板可以通过NFS访问的路径,然后在串口调试终端输入以下命令运行程序。

 

cd /opt/dvsdk/algorithm

./loadmodule.sh

./app_remote.xv5t

 

串口调试终端会输出以下程序运行信息。

 

    App-> Application started.

    CEapp-> Allocating contiguous buffer for 'input data' of size 1024...

    CEapp-> Contiguous buffer allocated OK (phys. addr=0x87fff000)

    CEapp-> Allocating contiguous buffer for 'encoded data' of size 1024...

    CEapp-> Contiguous buffer allocated OK (phys. addr=0x87ffe000)

    CEapp-> Allocating contiguous buffer for 'output data' of size 1024...

    CEapp-> Contiguous buffer allocated OK (phys. addr=0x87ffd000)

App-> Processing frame 0...

……

……

    App-> Finished encoding and decoding 128 frames

App-> Application finished successfully.

 

 

同时,在当前目录下会生成out.dat文件,大小应该是与in.dat文件一样。

 


 

2        修改videnc_copy

2.1  裁剪EMCV

为了减轻调试难度,我们可以先对EMCV进行裁剪,去掉没有用到的函数、宏定义和一些静态数组等代码。当前我们只使用EMCV进行很简单的功能,即在输入图像中间添加一个绿色矩形框。对于这个功能,所需要的函数不是很多,但最核心的一些基本数据结构还是用到了,包括IplImage,CvMat,CvSize,CvArray等。对于当前所需的功能,只需要使用cxarray.c,cxdatastructs.c,cxerror.c,cxdrawing.c,cxmisc.c,cxtables.c以及所有的头文件。对于需要使用的.c文件也要进行再次裁剪,将其中未用到的函数删掉,等以后需要使用某种功能时再将需要的函数添加进来。至于具体删减了哪些代码就不赘述了,请参考源文件。

在删减完无用代码之后,还需要对EMCV进行一定修改:xDAIS算法标准不允许算法分配内存,也即不允许算法使用malloc,alloc内存操作函数,而在EMCV中有不少地方使用了这些函数,所以需要修改。

修改的办法其实很简单:假如某个函数需要分配内存区域,则将所需的内存通过该函数的形参传递进去,最终的内存分配是通过framework component统一分配管理。例如对于cvCreateImage函数,其原始定义为:

 

IplImage * cvCreateImageHeader(CvSize size, int depth, int channels )

{

……

CV_CALL( img = (IplImage *)cvAlloc( sizeof( *img )));

……

}

 

修改之后的函数定义为:

 

void cvCreateImageHeader( IplImage *img, CvSize size, int depth, int channels )

{

……

// CV_CALL( img = (IplImage *)cvAlloc( sizeof( *img )));

……

}

 

EMCV中还有一些用到了cvAlloc的函数,也需要一一将其修改过来,否则最终的算法运行会出错(编译可能会通过)。另外,xDAIS算法不允许程序中使用static定义的临时变量,需要在代码中去掉static前缀。

2.2  xDM封装

当前我们需要实现封装一个包含EMCV的codec,能够对输入图像进行一定处理,鉴于之前已经在CCS中调试好了代码,并且已经符合xDAIS算法标准,现在要将其封装为xDM标准,这是非常容易的。

(1)修改头文件及函数定义

首先需要添加对EMCV头文件的引用,然后对于自定义的两个颜色空间转换函数也需要在头文件中添加声明,这只需要在videnc_copy_ti_priv.h中添加如下代码。

 

#include "cv.h"

 

extern Void YUV422_C_RGB( XDAS_UInt8* pYUV, XDAS_UInt8* pRGB, XDAS_Int32 height, XDAS_Int32 width);

extern Void RGB_C_YUV422( XDAS_UInt8* pRGB, XDAS_UInt8* pYUV, XDAS_Int32 height, XDAS_Int32 width);

 

(2)分配算法所需内存

由于xDAIS算法不允许算法自己分配内存资源,而EMCV里有内存需求,这可以通过xDAIS算法定义的的初始化函数initObj和内存分配函数alloc进行分配。

首先,需要修改VIDENCCOPY_TI_Obj的定义,添加所需的内存支持,也即在其中添加两个指针变量IplImage *img和XDAS_Uint8 *pRGB。

 

typedef struct VIDENCCOPY_TI_Obj {

    IALG_Obj    alg;            /* MUST be first field of all XDAS algs */

    IplImage    *img;

    XDAS_UInt8  *pRGB;

#ifdef USE_ACPY3

    IDMA3_Handle dmaHandle1D1D8B;  /* DMA logical channel for 1D to 1D xfers */

#endif

} VIDENCCOPY_TI_Obj;

 

然后,在VIDENCCOPY_TI_alloc中分配内存。由于img和pRGB所指向的内存区域都较大,所以都放在外部存储空间DDR2中(IALG_EXTERNAL)。同时,由于img和pRGB所指向的内存区域都是在算法激活之后才有效,所以属性都可以设置为IALG_SCRATCH。另外,需要注意alloc函数最后的返回值为分配的内存块数量,这里分配了VIDENCCOPY_TI_Obj,img和pRGB三块内存,所以返回的值是3。如果这里的参数设置错误就会内存分配错误,导致算法因没有可以使用的内存而运行失败。

 

Int VIDENCCOPY_TI_alloc(const IALG_Params *algParams,

    IALG_Fxns **pf, IALG_MemRec memTab[])

{

    memTab[0].size = sizeof(VIDENCCOPY_TI_Obj);

    memTab[0].alignment = 0;

    memTab[0].space = IALG_EXTERNAL;

    memTab[0].attrs = IALG_PERSIST;

 

    memTab[1].size = sizeof(IplImage);

    memTab[1].alignment = 0;

    memTab[1].space = IALG_EXTERNAL;

    memTab[1].attrs = IALG_PERSIST;

 

    memTab[2].size = 720 * 576 * 3* sizeof(XDAS_UInt8);

    memTab[2].alignment = 0;

    memTab[2].space = IALG_EXTERNAL;

memTab[2].attrs = IALG_SCRATCH;

  return (3);

}

 

接下来需要在算法初始化时将分配的内存赋给对应的指针变量。

 

Int VIDENCCOPY_TI_initObj(IALG_Handle handle,

    const IALG_MemRec memTab[], IALG_Handle p,

    const IALG_Params *algParams)

{

    VIDENCCOPY_TI_Obj *VIDENC_COPY = (Void *)handle;

 

    VIDENC_COPY->img  = memTab[1].base;

    VIDENC_COPY->pRGB = memTab[2].base;

 

    return (IALG_EOK);

}

 

最后,需要在free函数中修改相关内存配置参数。注意这里的返回值也是3。

 

Int VIDENCCOPY_TI_free(IALG_Handle handle, IALG_MemRec memTab[])

{

    VIDENCCOPY_TI_Obj *VIDENC_COPY = (Void *)handle;

    VIDENCCOPY_TI_alloc(NULL, NULL, memTab);

 

    memTab[0].base = handle;

    memTab[1].base = VIDENC_COPY->img;

    memTab[1].size = sizeof(IplImage);

    memTab[2].base = VIDENC_COPY->pRGB;

    memTab[2].size = 720 * 576 * 3 *sizeof(XDAS_UInt8);

    return (3);

}

 

(3)实现process函数

由于前期我们在CCS中创建xDAIS算法时就是用了process作为IALG的扩展算法,所以要移植到xDM定义的process中就很容易了,这里不详细讲解,只需要注意其中的以下代码。

 

 

VIDENCCOPY_TI_YUV422_C_RGB((XDAS_UInt8 *)inBufs->bufs[curBuf], VIDENC_COPY->pRGB, size.height, size.width);

 

VIDENCCOPY_TI_cvSetData(VIDENC_COPY->img, VIDENC_COPY->pRGB, size.width * 3);

 

VIDENCCOPY_TI_cvRectangle(VIDENC_COPY->img, point1, point2, color, CV_AA, 8, 0);

 

VIDENCCOPY_TI_RGB_C_YUV422((XDAS_UInt8 *)VIDENC_COPY->img->imageData, (XDAS_UInt8 *)outBufs->bufs[curBuf], size.height, size.width);

 

 

2.3  修改xdc配置文件

对于配置文件的修改非常简单,只需要将使用到的EMCV源文件添加进编译列表中就可以了,这是通过修改package.bld实现。

 

var SRCS = ["videnc_copy","cxarray","cxdatastructs","cxdrawing","cxtables"];

 

2.4  使用qualiTI检查是否符合xDAIS标准

由于编写的算法包是否符合算法标准是一件很难判别的事,为了解决这个问题,TI提供了qualiTI这个工具对算法进行静态检测,判断其是否符合xDAIS标准,至于是否符合xDM标准则不进行检查。但是由于xDM只是xDAIS标准的轻量级扩展,所以只要能够通过xDAIS标准检测那基本上就没问题了。

qualiTI这个工具位于DVSDK的XDAIS安装目录下,使用非常方便,只需要在终端中export XDC环境变量,然后再输入qualiTI的文件名运行脚本即可,如下图所示。

 

然后,可以看到qualiTI的界面,配置好相关选项之后点击run进行测试。

 

运行qualiTI之后,可以在videnc_copy的目录下看到生成的html网页版测试结果文件qualiti--VIDENCCOPY_TI_a64P--report.html。打开之后看到以下错误信息:

 

这是由于xDAIS算法标准要求所有由Vendor实现的非内部函数都需要在函数名前添加MODULE_VENDOR_前缀,对于我们这里前缀为VIDENCCOPY_TI_。对于EMCV中的函数,添加上相应前缀之后再用qualiTI进行测试就没有这个错误了。

 

在qualiTI测试通过之后,按照第1节叙述的步骤对codecs进行编译,根据错误进行修改,直到编译通过。

然后,对server(all_codecs)进行编译,将新的codec集成进sever中。


 

3        修改video_copy测试videnc_copy

在codec和server编译通过之后,需要编写应用程序对codec进行测试,这里选用apps中的video_copy程序进行测试。这里使用由TVP5150传递来的一帧原始YUV图像进行处理,分辨率为720 X 576,颜色空间为YCbCr 4:2:2 SemiPlanar.

3.1  修改app.c

由于我们只是修改了videnc_copy这个codec,所以对于应用程序的修改就很小了,配置部分不用修改,只需要修改app.c中的部分代码,确保传递给codec的数据格式正确。

首先,需要定义输入输出缓冲的大小。

#define IMAGESIZE   (720 * 576)

#define IFRAMESIZE  (IMAGESIZE * 2 * sizeof(Int8))  /* raw frame (input) */

#define EFRAMESIZE  (IMAGESIZE * 3 * sizeof(Int8))  /* encoded frame */

然后,去掉与未使用的viddec_copy相关的头文件引用、宏定义、缓冲区和变量等。接下来,注释掉使用DMA进行memcpy的部分代码。这是因为video_copy程序默认是使用DMA将输入缓冲区数据复制给输出,所以需要注释掉。其他还有一些小修改(例如修改encode函数的形参表)就不再一一赘述,详情请直接参考源文件。

3.2  程序运行结果

程序编译通过之后,按照第1节所述使其在开发板上运行,得到输出文件out.264,通过Matlab显示出来的结果如下所示,这证明程序运行成功。

 


原创粉丝点击