您的位置:首页 > 其它

移植EMCV到DM6467(5)——修改encodedecode demo测试算法封装

2013-10-20 10:08 405 查看

1 修改encodedecode demo测试codec

接下来,我们需要将修改过后的videnc_copy集成到encodedecodedemo中,实现实时采集视频、使用EMCV添加矩形框、然后输出显示的功能。

1.1 修改demo

(1)修改encodedecode.cfg

要使用videnc_copy,需要在encodedecode.cfg中修改createFromServer函数的参数,如下所示。

var demoEngine = Engine.createFromServer(

"encodedecode",

"bin/ti_platforms_evmDM6467/all.x64P",

"ti.sdo.ce.examples.servers.all_codecs"

);

(2)修改codecs.c

由于我们不对视频进行H264编码,所以需要在codecs中注释掉相关的参数定义。

#if 0

/* Use extended dynamic parameters to allow tweaking of the QP value */

static IH264VENC_DynamicParams extDynParams = {

{

sizeof(IVIDENC1_DynamicParams), /* size */

576, /* inputHeight */

720, /* inputWidth */

25000, /* refFrameRate */

25000, /* targetFrameRate */

2000000, /* targetBitRate (override in app) */

30, /* intraFrameInterval */

XDM_DECODE_AU, /* generateHeader */

0, /* captureWidth */

IVIDEO_NA_FRAME, /* forceFrame */

1, /* interFrameInterval */

0 /* mbDataFlag */

},

18, /* QPISlice */

20, /* QPSlice */

51, /* RateCtrlQpMax */

0, /* RateCtrlQpMin */

0, /* NumRowsInSlice */

0, /* LfDisableIdc */

0, /* LFAlphaC0Offset */

0, /* LFBetaOffset */

0, /* ChromaQPOffset */

0, /* SecChromaQPOffset */

};

#endif

(3)修改capture.c

由于encodedecode中默认是要将输入的YUV422视频流转换为YUV420再传递给video线程,而我们的videnc_copy是直接处理YUV422视频流,不需要进行转换,所以需要在Capture.c中修改部分代码。

#if 0

/* Configure color conversion job */

if (Ccv_config(hCcv, hInBuf, hDstBuf) < 0) {

ERR("Failed to configure 422 to 420 color conversion job\n");

cleanup(THREAD_FAILURE);

}

else

printf("Succeed to configure 422 to 420 color conversion job.\n");

#endif

frameSkip = TRUE;

/* Signal that initialization is done and wait for other threads */

Rendezvous_meet(envp->hRendezvousInit);

while (!gblGetQuit()) {

if (frameSkip) {

/* Capture an extra frame to halve the frame rate */

if (Capture_get(hCapture, &hCapBuf) < 0) {

ERR("Failed to get capture buffer\n");

cleanup(THREAD_FAILURE);

}

if (Capture_put(hCapture, hCapBuf) < 0) {

ERR("Failed to put capture buffer\n");

cleanup(THREAD_FAILURE);

}

}

/* Get a buffer from the capture driver to encode */

if (Capture_get(hCapture, &hCapBuf) < 0) {

ERR("Failed to get capture buffer\n");

cleanup(THREAD_FAILURE);

}

if (resize) {

/* Resize buffer from 720P to a smaller resolution */

if (Resize_execute(hRsz, hCapBuf, hIntBuf) < 0) {

ERR("Failed to execute resize job\n");

cleanup(THREAD_FAILURE);

}

hInBuf = hIntBuf;

}

else {

hInBuf = hCapBuf;

}

//if (Ccv_execute(hCcv, hInBuf, hDstBuf) < 0) {

// ERR("Failed to execute color conversion job\n");

// cleanup(THREAD_FAILURE);

//}

/* Send color converted buffer to video thread for encoding */

if (Fifo_put(envp->hOutFifo, hInBuf) < 0) {

ERR("Failed to send buffer to display thread\n");

cleanup(THREAD_FAILURE);

}

/* Return a buffer to the capture driver */

if (Capture_put(hCapture, hCapBuf) < 0) {

ERR("Failed to put capture buffer\n");

cleanup(THREAD_FAILURE);

}

/* Get a buffer from the video thread */

fifoRet = Fifo_get(envp->hInFifo, &hInBuf);

if (fifoRet < 0) {

ERR("Failed to get buffer from video thread\n");

cleanup(THREAD_FAILURE);

}

/* Did the video thread flush the fifo? */

if (fifoRet == Dmai_EFLUSH) {

cleanup(THREAD_SUCCESS);

}

}

(4)修改display.c

同样,由于videnc_copy输出的视频流为YUV422格式,不需要进行转换就可以直接传递给驱动进行显示,所以在display.c中也要修改部分代码。

static Int config(Ccv_Handle hCcv, Blend_Handle hBlend, UI_Handle hUI,

Buffer_Handle hSrcBuf, Buffer_Handle hDstBuf, UInt8 trans)

{

Blend_Config_Params bConfigParams = Blend_Config_Params_DEFAULT;

Buffer_Handle hBmpBuf;

Int i;

#if 0

/* Configure the 420->422 color conversion job */

if (Ccv_config(hCcv, hSrcBuf, hDstBuf) < 0) {

ERR("Failed to configure color conversion job\n");

return FAILURE;

}

#endif

……

/*

* Color convert the 420Psemi decoded buffer from

* the video thread to the 422Psemi display.

*/

//if (Ccv_execute(hCcv, hSrcBuf, hDstBuf) < 0) {

// ERR("Failed to execute color conversion job\n");

// cleanup(THREAD_FAILURE);

//}

(5)修改video.c

video.c中的修改较多,只讲一下主要部分。

首先,注释掉与H264编解码相关的变量和参数,添加一些用于videnc_copy的变量。

VIDENC_Handle enc = NULL;

String encoderName = "videnc_copy";

VIDENC_InArgs encInArgs;

VIDENC_OutArgs encOutArgs;

VIDENC_DynamicParams encDynParams;

VIDENC_Status encStatus;

XDAS_Int8 *inBuf;

XDAS_Int8 *encodedBuf;

XDM_BufDesc inBufDesc;

XDAS_Int8 *src[XDM_MAX_IO_BUFFERS];

XDAS_Int32 inBufSizes[XDM_MAX_IO_BUFFERS];

XDM_BufDesc encodedBufDesc;

XDAS_Int8 *encoded[XDM_MAX_IO_BUFFERS];

XDAS_Int32 encBufSizes[XDM_MAX_IO_BUFFERS];

Memory_AllocParams allocParams;

encInArgs.size = sizeof(encInArgs);

encOutArgs.size = sizeof(encOutArgs);

encDynParams.size = sizeof(encDynParams);

encStatus.size = sizeof(encStatus);

allocParams.type = Memory_CONTIGPOOL;

allocParams.flags = Memory_NONCACHED;

allocParams.align = BUFALIGN;

allocParams.seg = 0;

inBuf = (XDAS_Int8 *)Memory_alloc(IFRAMESIZE, &allocParams);

encodedBuf = (XDAS_Int8 *)Memory_alloc(EFRAMESIZE, &allocParams);

/* clear and initialize the buffer descriptors */

memset(src, 0, sizeof(src[0]) * XDM_MAX_IO_BUFFERS);

memset(encoded, 0, sizeof(encoded[0]) * XDM_MAX_IO_BUFFERS);

src[0] = inBuf;

encoded[0] = encodedBuf;

inBufDesc.numBufs = encodedBufDesc.numBufs = 1;

inBufDesc.bufSizes = inBufSizes;

encodedBufDesc.bufSizes = encBufSizes;

inBufSizes[0] = IFRAMESIZE;

encBufSizes[0] = EFRAMESIZE;

inBufDesc.bufs = src;

encodedBufDesc.bufs = encoded;

然后,修改颜色空间定义,从原来的YUV420PSEMI修改为YUV422PSEMI。

gfxAttrs.colorSpace = ColorSpace_YUV422PSEMI;

gfxAttrs.dim.width = envp->imageWidth;

gfxAttrs.dim.height = envp->imageHeight;

gfxAttrs.dim.lineLength = BufferGfx_calcLineLength(gfxAttrs.dim.width,

gfxAttrs.colorSpace);

接下来,需要对buffer进行一定修改,再传递给videnc_copy进行处理。

if (!envp->passThrough) {

fifoRet = Fifo_get(envp->hDisplayOutFifo, &hDispBuf);

memcpy(inBuf, Buffer_getUserPtr(hVidBuf), IFRAMESIZE);

#ifdef CACHE_ENABLED

#ifdef xdc_target__isaCompatible_64P

Memory_cacheWbInv(inBuf, IFRAMESIZE);

#else

#error Unvalidated config - add appropriate fread-related cache maintenance

#endif

Memory_cacheInv(encodedBuf, EFRAMESIZE);

#endif

//memcpy(encodedBuf, inBuf, EFRAMESIZE);

ret = VIDENC_process(enc, &inBufDesc, &encodedBufDesc, &encInArgs, &encOutArgs);

if (ret < 0) {

cleanup(THREAD_FAILURE);

}

#ifdef CACHE_ENABLED

Memory_cacheWb(encodedBuf, EFRAMESIZE);

#endif

memcpy(Buffer_getUserPtr(hDispBuf), encodedBuf, EFRAMESIZE);

Buffer_setNumBytesUsed(hDispBuf, EFRAMESIZE);

/* Update global data for user interface */

gblIncVideoBytesProcessed(EFRAMESIZE);

if (Fifo_put(envp->hDisplayInFifo, hDispBuf) < 0) {

ERR("Failed to send buffer to display thread\n");

cleanup(THREAD_FAILURE);

}

/* and return input video frame to capture thread */

if (Fifo_put(envp->hCaptureInFifo, hVidBuf) < 0) {

ERR("Failed to send buffer to capture thread\n");

cleanup(THREAD_FAILURE);

}

}

else {

/* Send the buffer through to the display thread unmodified */

if (Fifo_put(envp->hDisplayInFifo, hVidBuf) < 0) {

ERR("Failed to send buffer to display thread\n");

cleanup(THREAD_FAILURE);

}

}

最后,需要特别注意的是:在上面的代码中使用了Fifo_put(envp->hDisplayInFifo, hDispBuf)将buffer传递给display线程,这就要注释掉后面部分代码,否则程序运行时video线程会阻塞,因为无法从display线程的fifo得到buffer(已经全部传递给capture线程了)。

#if 0

/* Get a buffer from the display thread to send to the capture thread */

if ((ret != Dmai_EFIRSTFIELD) && (Fifo_getNumEntries(envp->hDisplayOutFifo))) {

do {

fifoRet = Fifo_get(envp->hDisplayOutFifo, &hDispBuf);

if (fifoRet < 0) {

ERR("Failed to get buffer from video thread\n");

cleanup(THREAD_FAILURE);

}

/* Did the display thread flush the fifo? */

if (fifoRet == Dmai_EFLUSH) {

cleanup(THREAD_SUCCESS);

}

/* The display thread is no longer using the buffer */

Buffer_freeUseMask(BufTab_getBuf(hBufTab, Buffer_getId(hDispBuf)),

/*Buffer_getUseMask(BufTab_getBuf(hBufTab, Buffer_getId(hDispBuf)))*/DISPLAY_FREE);

/* Get a free buffer */

hDstBuf = BufTab_getFreeBuf(hBufTab);

if (hDstBuf == NULL) {

ERR("Failed to get free buffer from BufTab\n");

BufTab_print(hBufTab);

cleanup(THREAD_FAILURE);

}

/*

* Reset the dimensions of the buffer in case the decoder has

* changed them due to padding.

*/

BufferGfx_resetDimensions(hDstBuf);

/* Send a buffer to the capture thread */

if (Fifo_put(envp->hCaptureInFifo, hDstBuf) < 0) {

ERR("Failed to send buffer to capture thread\n");

cleanup(THREAD_FAILURE);

}

} while (Fifo_getNumEntries(envp->hDisplayOutFifo) > 0);

}

#endif

1.2 程序运行结果

修改完之后,确认编译通过,然后下载到开发板上运行,串口调试终端输出信息如下所示。



在显示器上的显示效果如下所示,证明程序运行成功。



1.3 遗留问题

从串口终端的输出信息可以看出,DSP端一直处于满负荷状态,视频处理的帧率还没有达到1fps,大约每处理1帧图像需要1.5秒左右的时间。这说明算法的效率很低,后期需要进行很多优化,主要考虑是将所有浮点运算转换为定点运算,因为DM6467的DSP是C64x+型定点DSP,做浮点运算时速度特别低。

另外,可以考虑使用TI提供的DSPLIB、FastRTSLIB、IQMathLIB、IMGLIB和VLIB等库。用VLIB和IMGLIB替换掉MECV中的部分函数,用VLIB进行颜色空间转换,用FastRTS、IQMathLIB和DSPLIB来进行一些基本的数据处理,例如浮点运算、矩阵运算和乘除运算等操作。

以上这些库其实都已经集成到C6Accel中了,所以接下来的工作就是学习使用C6Accel,并将OpenCV集成进去。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: