1、我想在 AlgLink_OsdalgProcessFrame 里用自己的算法替换osd算法,输入的视频流是
SWOSD_FORMAT_YUV420sp,我想分别处理 y_buffer, cb_buffer and cr_buffer ,但是我不知道
如何分别提取cb_buffer and cr_buffer,是不是我需要创建两个数组用来临时存储cb_buffer and cr_buffer,
处理完后在把处理后的值赋值回去,如下:
int i=0,j=0;
UInt8 *y_buffer = pFrame->addr[0][0];
UInt8 cbbuffer_arr[pFrameInfo->rtChInfo.height*(pFrameInfo->rtChInfo.width/4)];
UInt8 crbuffer_arr[pFrameInfo->rtChInfo.height*(pFrameInfo->rtChInfo.width/4)];
UInt8 *pBufferStart = pFrame->addr[0][1];
for (i= 0; i<(pFrameInfo->rtChInfo.height*pFrameInfo->rtChInfo.width)>>1; i+=2)
{
cbbuffer_arr[j] = *(pBufferStart+i);
crbuffer_arr[j] = *(pBufferStart+i+1);
j++;
}
/*—-我的算法接口——*/
YUV420_PROCESS(y_buffer,cbbuffer_arr,crbuffer_arr);
j=0;
/*—-处理完后的y_buffer,cbbuffer_arr,crbuffer_arr再赋值回去——*/
for (i= 0; i<(pFrameInfo->rtChInfo.height*pFrameInfo->rtChInfo.width)>>1; i+=2)
{
*(pBufferStart+i) = cbbuffer_arr[j];
*(pBufferStart+i+1)= crbuffer_arr[j];
j++;
}
这样对吗?
2、If I do that in AlgLink_OsdalgProcessFrame,whether I rewrite
UInt8 *y_buffer = pFrame->addr[0][0]+0x30000000;
UInt8 *pBufferStart = pFrame->addr[0][1]+0x30000000;
han yang1:
建议你看下dsp下面的va_link,你把数据放回去的意思都理解错了,你是想在dsp里面做数据处理吧,那va_link可以满足你的要求,我通过修改这个link已经实现了自己的算法,你得看懂这个valink的结构,大概意思是里面有两个线程,一个主线程负责接收上一个link发过来的数据System_getLinksFullFrames,然后调用VaLink_algCopyFrames通过DMA方式将数据拷贝到自己的队列里面Utils_bufPutFullFrame,然后将数据还回去System_putLinksEmptyFrames,通知处理线程处理数据Utils_tskSendCmd(&pObj->processTsk,SYSTEM_CMD_NEW_DATA);,
结合mcfw user guide 然后看一个link,不懂就反复看反复琢磨,我看了半个月才有点头绪,这个RDK因为是新出来的资料和手册都比较少,上手确实有点难,贵在坚持。
herobin:
回复 han yang1:
han yang1,非常感谢您的回答,我就是想在dsp里添加自己的算法,我用的是DVRRDK_04.00.00.03,在/mcfw/src_bios6/links_c6xdsp/alg_link下有个
algLink_priv.c函数
Int32 AlgLink_algProcessData(AlgLink_Obj * pObj)
{
UInt32 frameId, status = FVID2_SOK;
System_LinkInQueParams *pInQueParams;
FVID2_Frame *pFrame;
FVID2_FrameList frameList;
pInQueParams = &pObj->createArgs.inQueParams;
System_getLinksFullFrames(pInQueParams->prevLinkId,
pInQueParams->prevLinkQueId, &frameList);
#ifdef ENABLE_FXN_PROFILE
AlgLink_drvFxnProfileControl(pObj);
#endif /* #ifdef ENABLE_FXN_PROFILE */
if (frameList.numFrames)
{
pObj->inFrameGetCount += frameList.numFrames;
/* SCD should be done first as it requires to operate on raw YUV */
if (pObj->createArgs.enableSCDAlg)
{
status = AlgLink_ScdAlgSubmitFrames(&pObj->scdAlg, &frameList);
}
for(frameId=0; frameId<frameList.numFrames; frameId++)
{
pFrame = frameList.frames[frameId];
if(pFrame->channelNum >= pObj->inQueInfo.numCh)
continue;
// do SW OSD
if (pObj->createArgs.enableOSDAlg)
{
AlgLink_OsdalgProcessFrame(&pObj->osdAlg, pFrame);
}
}
System_putLinksEmptyFrames(pInQueParams->prevLinkId,
pInQueParams->prevLinkQueId, &frameList);
}
return status;
}
我用蓝色标记的就是你说的接收上个link发送过来的数据和把数据换回去的函数,我是在红色标记的这个函数里添加自己的算法的AlgLink_OsdalgProcessFrame(&pObj->osdAlg, pFrame);这个函数里面就是负责数据的处理的,里面应该跟你说的哪个意思吧?我真是个初学者,才看了一个星期,我会按照你说的思路好好研究一下,非常感谢你的回答。
han yang1:
回复 herobin:
对的,你只需要修改红色标记的函数内容来实现你的算法,pFrame结构体有你要的YUV数据,不知道你们的算法处理时间是否过长,像我们的算法处理时间比较长,所以需要另外一个线程来处理,如果仍然在这个线程里面处理的话会导致数据不能及时还回去,而造成队列阻塞出错,这点需要注意,我当时就遇到过。一个星期时间有点短,我上手这个RDK到现在差不多2个月,才有点感觉,心得就是反复看代码,还有那个mcfw手册,不过这个手册写的确实有点简陋。
herobin:
回复 han yang1:
我这个版本里没有va_link
herobin:
回复 han yang1:
我们要在里面添加车牌识别的接口函数,处理的图像大小是2448*2048,具体我也不大懂,刚接触。现在lib库函数加进去了,就剩接口函数的调用不知道该如何添加了。应该就剩在下面这个函数里改,我还得好好研究研究
Int32 AlgLink_OsdalgProcessFrame(AlgLink_OsdObj * pObj, FVID2_Frame *pFrame){ UInt32 winId, fid, scaleX, divY, scaleStartX; AlgLink_OsdChObj *pChObj; SWOSD_Obj *pSwOsdObj; System_FrameInfo *pFrameInfo; UInt32 algColorKey[2]; Bool isInterlaced, isTiled;
isInterlaced = FALSE; isTiled = FALSE; fid = 0; scaleX = 1; /* Video frame Scale X */ scaleStartX = 1; /* Scale graphics X */ divY = 1;
pChObj = &pObj->chObj[pFrame->channelNum];
pSwOsdObj = &pChObj->osdObj;
if(pObj->inQueInfo->chInfo[pFrame->channelNum].scanFormat == SYSTEM_SF_INTERLACED) isInterlaced = TRUE;
if(SYSTEM_MT_TILEDMEM == pObj->inQueInfo->chInfo[pFrame->channelNum].memType) isTiled = TRUE;
if(isInterlaced) { /* OSD plane is always progressive Input can be interlaced in this case we need to skip alternate lines in OSD plane and feed for blending */ if(pFrame->fid==1) fid = 1;
/* this will half the processing height */ divY = 2; }
if(pSwOsdObj->graphicsWindowPrm.format == SWOSD_FORMAT_YUV422i) scaleX = 2;/* Pixel offset multiplier, 2 as in 422p format each pixel is of 2 bytes.*/
if(pSwOsdObj->graphicsWindowPrm.format == SWOSD_FORMAT_RGB888) { scaleX = 3; /* Pixel offset multiplier, 3 as in RGB format each pixel is of 3 bytes.*/ if(pChObj->osdObj.videoWindowPrm.format == SWOSD_FORMAT_YUV422i) scaleStartX = 2; /* Pixel offset multiplier, 2 as in 422p format each pixel is of 2 bytes.*/ } algColorKey[0] = AlgLink_OsdalgGetColorKey( pChObj->colorKey, pSwOsdObj->graphicsWindowPrm.format, 0 );
algColorKey[1] = 0;
if(pSwOsdObj->graphicsWindowPrm.format == SWOSD_FORMAT_YUV420sp) { algColorKey[1] = AlgLink_OsdalgGetColorKey( pChObj->colorKey, pSwOsdObj->graphicsWindowPrm.format, 1 ); }
/* NOT SUPPORTED */ pSwOsdObj->alphaWindowAddr = NULL;
pFrameInfo = (System_FrameInfo*)pFrame->appData; UTILS_assert(pFrameInfo!=NULL);
if(pFrameInfo->rtChInfoUpdate) { /* Need to comment this as we dont update this when we update frameInfo in IPCFrameIn*/// pSwOsdObj->videoWindowPrm.format = pFrameInfo->rtChInfo.dataFormat; pSwOsdObj->videoWindowPrm.startX = pFrameInfo->rtChInfo.startX; pSwOsdObj->videoWindowPrm.startY = pFrameInfo->rtChInfo.startY; pSwOsdObj->videoWindowPrm.width = pFrameInfo->rtChInfo.width; pSwOsdObj->videoWindowPrm.height = pFrameInfo->rtChInfo.height; pSwOsdObj->videoWindowPrm.lineOffset = pFrameInfo->rtChInfo.pitch[0]; } for(winId=0; winId<pChObj->numWindows; winId++) { if(!pChObj->osdWinObj[winId].enableWin) continue;
/* YUV422i or YUV420SP – Y-plane processing */
pSwOsdObj->videoWindowAddr = pFrame->addr[0][0];
if (isTiled) { pSwOsdObj->videoWindowAddr = (Ptr)Utils_tilerAddr2CpuAddr((UInt32)pFrame->addr[0][0]); pSwOsdObj->videoWindowPrm.lineOffset = VPSUTILS_TILER_CNT_8BIT_PITCH; }
pSwOsdObj->globalPrm.globalAlpha = pChObj->osdWinObj[winId].globalAlpha; pSwOsdObj->globalPrm.transperencyEnable = pChObj->osdWinObj[winId].transperencyEnable; pSwOsdObj->globalPrm.transperencyColor32= algColorKey[0]; pSwOsdObj->graphicsWindowPrm = pChObj->osdWinObj[winId].osdWinPrm; pSwOsdObj->graphicsWindowAddr = pChObj->osdWinObj[winId].addr[0][0] + fid*pSwOsdObj->graphicsWindowPrm.lineOffset*scaleX;
/* Hori.(X) startX offset in a frame, Gpx will start from this offset */ if(pSwOsdObj->graphicsWindowPrm.format == SWOSD_FORMAT_RGB888) pSwOsdObj->graphicsWindowPrm.startX *= scaleStartX; else pSwOsdObj->graphicsWindowPrm.startX *= scaleX;
pSwOsdObj->graphicsWindowPrm.startY /= divY; pSwOsdObj->graphicsWindowPrm.width *= scaleX;
pSwOsdObj->graphicsWindowPrm.height /= divY; pSwOsdObj->graphicsWindowPrm.lineOffset *= (scaleX * divY); // double line offset pSwOsdObj->videoWindowPrm.dataPlane = SWOSD_DATAPLANE_LUMA; #if 0 AlgLink_OsdalgPrintInfo(pSwOsdObj, pFrame); #endif
SWOSD_blendWindow(pSwOsdObj);
/* YUV420SP – C -plane processing */ if(pSwOsdObj->graphicsWindowPrm.format == SWOSD_FORMAT_YUV420sp) { pSwOsdObj->videoWindowAddr = pFrame->addr[0][1]; if (isTiled) { pSwOsdObj->videoWindowAddr = (Ptr)Utils_tilerAddr2CpuAddr((UInt32)pFrame->addr[0][1]); pSwOsdObj->videoWindowPrm.lineOffset = VPSUTILS_TILER_CNT_16BIT_PITCH; }
pSwOsdObj->graphicsWindowAddr = pChObj->osdWinObj[winId].addr[0][1] + fid*pSwOsdObj->graphicsWindowPrm.lineOffset*scaleX;
pSwOsdObj->graphicsWindowPrm.startY /= 2; // half width for C plane pSwOsdObj->graphicsWindowPrm.height /= 2; // half height for C plane
pSwOsdObj->globalPrm.transperencyColor32= algColorKey[1]; pSwOsdObj->videoWindowPrm.dataPlane = SWOSD_DATAPLANE_CHROMA; #if 0 AlgLink_OsdalgPrintInfo(pSwOsdObj, pFrame); #endif
SWOSD_blendWindow(pSwOsdObj); } /* YUV420SP Frame – C -plane processing */ if((pSwOsdObj->graphicsWindowPrm.format == SWOSD_FORMAT_RGB888) && (pChObj->osdObj.videoWindowPrm.format == SWOSD_FORMAT_YUV420sp)) { pSwOsdObj->videoWindowAddr = pFrame->addr[0][1]; if (isTiled) { pSwOsdObj->videoWindowAddr = (Ptr)Utils_tilerAddr2CpuAddr((UInt32)pFrame->addr[0][1]); pSwOsdObj->videoWindowPrm.lineOffset = VPSUTILS_TILER_CNT_16BIT_PITCH; }
pSwOsdObj->graphicsWindowAddr = pChObj->osdWinObj[winId].addr[0][0] + fid*pSwOsdObj->graphicsWindowPrm.lineOffset*scaleX;
pSwOsdObj->graphicsWindowPrm.startY /= 2; // half width for C plane pSwOsdObj->graphicsWindowPrm.height /= 2; // half height for C plane
pSwOsdObj->graphicsWindowPrm.lineOffset *= 2; // Double line offset of RGB888 pSwOsdObj->globalPrm.transperencyColor32= algColorKey[0]; pSwOsdObj->videoWindowPrm.dataPlane = SWOSD_DATAPLANE_CHROMA; #if 0 AlgLink_OsdalgPrintInfo(pSwOsdObj, pFrame); #endif
SWOSD_blendWindow(pSwOsdObj); }
}
return 0;}
comeback:
回复 han yang1:
@ han yang1
你说的“如果算法处理时间比较长,需要另外一个线程来处理,否则会造成队列阻塞出错“,能再具体说说吗?我们现在就碰到类似的问题,算法处理的时间较长,运行时发现程序没过多久就死掉了,一直都没找到原因。
han yang1:
回复 herobin:
你说的功能我已经实现了,不过我们的要求还很多,所以还需要往深点挖,如果需要帮助私下聊。
han yang1:
回复 comeback:
你可以看VAlink的代码或者fdlink,里面有两个任务,一个主任务,一个处理任务,打个简单的比方,水桶装水,一共有10个空桶,前面一个link装满水后把桶给下一个link,下一个link用完水后就把桶还给上一个link这样这个流水线才能继续,否则上一个link没有空桶装水就挂掉了,所以如果当前link在使用某个桶的水时当又有装满水的桶过来了他如果不用则要把桶还回去,所以要两个任务来做,而且还桶的那个任务优先级要比处理某桶水的任务优先级高这样才能及时处理不要的桶。
simon blak:
回复 han yang1:
就我的理解来看。
herobin 兄弟的意思是要将处理后的数据“水”还回去,而不是缓冲队列“桶”。
Valink是没有Nextlink的。所以需要实现一个自己的link,该link应该有Nextlink。
而且Valink应该只存在于IPNC RDK中,而不是DVR RDK。
herobin:
回复 simon blak:
你好,simon blak :
是这个意思,因为uv分量存储在pFrame->addr[0][1],uv是连续存储的,我想把uv分量分别提取出来分别进行处理。我不知道怎么在dsp里分配临时内存用来存储u和v分,希望您能给讲解一下。