解码/显示概述:从共享文件夹获取H264流,对264流进行解析,生成hdr文件,hdr文件中包含每一帧的信息,将视频帧信息存放在A8核分配的共享内存空间,供其他核或其他的link调用,M3 Video核调用Display函数通过HDMI输出显示。
/** 解码显示函数流程图 */ Demo_run() { Demo_startStop(demoId, TRUE) { VcapVdis_start() { VdecVdis_bitsRdInit() { /*重置文件处理句柄*/ VdecVdis_bitsRdResetFileHandles(); /*从.ini文件中获取源H264流,并调用iniparser()解析得到hdr文件,hdr文件中有每一帧的数据信息。 如果已经解析过在运行程序时可以选择否。 gVdecVdis_config中保存.ini文件的属性 gVdecVdis_obj.fdRdData 保存H264流 gVdecVdis_obj.fpRdHdr 保存hdr解析流 */ VdecVdis_bitsRdGetFileInfoFromIniFile(); /*创建发送和接收数据流的线程*/ VdecVdis_bitsRdInitThrObj() { OSA_semCreate(&gVdecVdis_obj.thrStartSem,1,0);//创建信号量 status = OSA_thrCreate(&gVdecVdis_obj.thrHandle, //线程句柄,用于指向各种系统资源,比如信号量,线程,和文件等 VdecVdis_bitsRdSendFxn, //线程函数 MCFW_IPCBITS_SENDFXN_TSK_PRI, MCFW_IPCBITS_SENDFXN_TSK_STACK_SIZE, //线程其实地址 &gVdecVdis_obj); //线程运行的参数 VdecVdis_bitsRdSendFxn(Void * prm) { OSA_semWait(&gVdecVdis_obj.thrStartSem,OSA_TIMEOUT_FOREVER);//等待系统消息 while (FALSE == gVdecVdis_obj.thrExit) { OSA_waitMsecs(MCFW_IPCBITS_SENDFXN_PERIOD_MS);//每8秒是一个时钟周期 /**/ VdecVdis_bitsRdGetEmptyBitBufs(&emptyBufList, i) { VDEC_BUF_REQUEST_S reqInfo.bufSize = gVdecVdis_config.chBufSize[chId];//得到每一个channel的buf Vdec_requestBitstreamBuffer(&reqInfo, emptyBufList, 0)//reqInfo指示通道i和bufSize大小 { IpcBitsOutLinkHLOS_BitstreamBufReqInfo ipcReqInfo=reqInfo; IpcBitsOutLink_getEmptyVideoBitStreamBufs(gVdecModuleContext.ipcBitsOutHLOSId, &ipcBufList,&ipcReqInfo); { linkId=gVdecModuleContext.ipcBitsOutHLOSId; OSA_TskHndl * pTsk=System_getLinkTskHndl(linkId);//得到OutLink的线程Id IpcBitsOutLink_Obj * pObj= pTsk->appData;;//pObj包含OutLink的基本信息 if (pObj->startProcessing) { IpcBitsOutLink_releaseBitBufs(pObj);//清空pObj->listElemQue reqInfo=ipcReqInfo;bufList=ipcBufList;//参数变化 IpcBitsOutLink_getEmptyBufs(pObj,bufList,reqInfo);// { //&pListElem=&pObj->listElemQue[chNum] OSA_queGet(&pObj->listElemQue[chNum],(Int32 *) (&pListElem), OSA_TIMEOUT_NONE); bufList=&pListElem;//最后共享空间的数据放在bufList中 } } }//以上函数功能:将共享区域的数据流放在临时空间&ipcBufList /*最后将从共享空间获取的数据流放入空队列emptyBufList中*/ Vdec_copyBitBufInfoLink2McFw(emptyBufList,&ipcBufList); } }//VdecVdis_bitsRdGetEmptyBitBufs(&emptyBufList, i) if (emptyBufList.numBufs) { VdecVdis_bitsRdReadData(&emptyBufList);//读取gVdecVdis_obj.fdRdData的帧数据,并填充emptyBufList VdecVdis_bitsRdSendFullBitBufs(&emptyBufList) { Vdec_putBitstreamBuffer(fullBufList) { Vdec_copyBitBufInfoMcFw2Link(ipcBufList,fullBufList); IpcBitsOutLink_putFullVideoBitStreamBufs(gVdecModuleContext.ipcBitsOutHLOSId,&ipcBufList) { linkId=gVdecModuleContext.ipcBitsOutHLOSId; OSA_TskHndl * pTsk=System_getLinkTskHndl(linkId); IpcBitsOutLink_Obj * pObj=pTsk->appData; bufList=ipcBufList; IpcBitsOutLink_putFullBufs(pObj,bufList)//将读取的数据帧放入pObj即共享空间 { Bitstream_Buf *pBitBuf=pBufList->bufs[bufId]; SharedRegion_getPtr(pListElem->srBufPtr)=pBitBuf->addr);//得到共享空间地址 freeBitBufList.bufs[freeBitBufList.numBufs] = pBitBuf; IpcBitsOutLink_listMPPut(pObj, pListElem);//??? IpcBitsOutLink_putEmptyBufs(pObj, &freeBitBufList) { pBufList=freeBitBufList; pListElem = (SystemIpcBits_ListElem *) pBufList->bufs[bufId]; SharedRegion_getPtr(pListElem->srBufPtr) =pBufList->bufs[bufId]->addr; OSA_quePut(&(pObj->listElemQue),pListElem, OSA_TIMEOUT_NONE);//pObj得到freeBitBufList的数据流 } } } } } //VdecVdis_bitsRdSendFullBitBufs(&emptyBufList)将新的数据帧放入共享空间 }if (emptyBufList.numBufs) }//while() } }//创建发送和接收数据流的线程 }//VdecVdis_bitsRdInit() /*初始化系统变量vsysParams*/ Vsys_params_init(&vsysParams); /*系统初始化*/ Vsys_init(&vsysParams) { Vcap_init(NULL);//init gVcapModuleContext Vdis_init(NULL);//init gVdisModuleContext Vdis_hdmiCtrl_init(); Vdec_init(NULL);//init gVdecModuleContext Venc_init(NULL);//init gVencModuleContext System_init();//mcfw/src_linux/links/system/system_common.c { //创建信号量,用于控制线程 OSA_mutexCreate(&gSystem_objCommon.linkControlMutex); System_ipcInit(); { SysLink_setup (); system_ipc_reset_srheaps();//gSystem_ipcObj.srHeaps=0 System_ipcMsgQInit(); { System_ipcMsgQHeapCreate();//创建共享堆区gSystem_ipcObj System_ipcMsgQCreate(); //创建消息队列并初始化msgQParams System_ipcMsgQTskCreate(); //创建线程 { OSA_thrCreate( &gSystem_ipcObj.msgQTask, System_ipcMsgQTaskMain, SYSTEM_MSGQ_TSK_PRI, SYSTEM_MSGQ_TSK_STACK_SIZE, NULL ); System_ipcMsgQTaskMain()//管理消息队列的线程,线程调度 } } System_ipcNotifyInit(); } IpcBitsInLink_init(); { status = OSA_tskCreate(&pObj->tsk, //线程句柄 IpcBitsInLink_tskMain, //线程主函数 IPC_LINK_TSK_PRI, IPC_LINK_TSK_STACK_SIZE, 0, pObj); IpcBitsInLink_tskMain() { while (!done) { cmd = OSA_msgGetCmd(pMsg);//get系统消息 switch (cmd) { case SYSTEM_CMD_NEW_DATA: OSA_tskAckOrFreeMsg(pMsg, status);//释放消息 IpcBitsInLink_processBitBufs(pObj);//缓冲流处理 { while (1) { pListElem = ListMP_getHead(pObj->listMPOutHndl); //得到共享区头部 IpcBitsInLink_getBitBuf(pObj, pListElem, &pBitBuf);//pBitBuf指向共享内存区 //outBitBufQue得到共享内存区数据用于其他link调用 OSA_quePut(&pObj->outBitBufQue, (Int32) pBitBuf, OSA_TIMEOUT_NONE); } } break; } } } } IpcBitsOutLink_init(); { System_registerLink(pObj->tskId, &linkObj);//注册link IpcBitsOutLink_initListMP(pObj); //创建多通道句柄 &pObj->listMPOutHndl, &pObj->listMPInHndl status = OSA_tskCreate(&pObj->tsk, //创建线程 IpcBitsOutLink_tskMain, //线程 IPC_LINK_TSK_PRI, IPC_LINK_TSK_STACK_SIZE, 0, pObj); IpcBitsOutLink_tskMain()//线程主函数 { IpcBitsOutLink_create(pObj, OSA_msgGetPrm(pMsg));//创建link { IpcBitsOutLink_createOutObj(pObj); { IpcBitsOutLink_createFreeListElemQue(pObj);// { //&pObj->listElemFreeQue= (Int32)pObj->listElem[i] IpcBitsOutLink_createFreeListElemQue(pObj); } //创建队列 OSA_queCreate(&pObj->listElemQue[chId],SYSTEM_IPC_BITS_MAX_LIST_ELEM); //&listElem->&pObj->listElemFreeQue status = OSA_queGet(&pObj->listElemFreeQue,(Int32 *)&listElem,OSA_TIMEOUT_NONE); //set listElem //&pObj->listElemQue[chId]=listElem status =OSA_quePut(&pObj->listElemQue[chId], (Int32) listElem,OSA_TIMEOUT_NONE); } IpcBitsOutLink_createPrdObj(pObj); { OSA_thrCreate(&pObj->prd.thrHandle, IpcBitsOutLink_periodicTaskFxn, IPC_LINK_TSK_PRI, IPC_LINK_TSK_STACK_SIZE, pObj); //线程管理,用于向arm发送任务消息 IpcBitsOutLink_periodicTaskFxn() } }//create done while (!done) { cmd = OSA_msgGetCmd(pMsg); switch (cmd) { //case...... case SYSTEM_CMD_START: IpcBitsOutLink_start(pObj); OSA_tskAckOrFreeMsg(pMsg, status); break; case IPCBITSOUT_LINK_CMD_CREATE_CH_BUFFER: { status = IpcBitsOutLink_CreateChBuffer(pObj,//创建buf OSA_msgGetPrm(pMsg)); { //创建缓冲池 ipcbitsoutlink_validate_createbuf_params(pObj,bufCreatePrms); status = IpcBitsOutLink_doChBufCreate(pObj,bufCreatePrms); { //读取内存中的数据 RingBufferInit(&pObj->ringBufHdnl[chId], pObj->bitBufBasePtr[chId], totBufSize); //listElem->&pObj->listElemFreeQue(listElem是临时变量) OSA_queGet(&pObj->listElemFreeQue,(Int32 *)&listElem,OSA_TIMEOUT_NONE); //&pObj->listElemQue[chId]=listElem OSA_quePut(&pObj->listElemQue[chId], (Int32) listElem,OSA_TIMEOUT_NONE); } } OSA_tskAckOrFreeMsg(pMsg, status); break; } } } } } IpcFramesInLink_init(); IpcFramesOutLink_init(); AvsyncLink_init(); SystemLink_init(); } } }//VcapVdis_start() } while(!done) { ch = Demo_getChar();//设置 switch(ch) case '1': Demo_captureSettings(demoId); break; case '2': Demo_encodeSettings(demoId); break; case '3': Demo_decodeSettings(demoId); break; case '4': Demo_displaySettings(demoId); break; //... case 'e': done = TRUE; break; } /*结束demo,正常退出并释放内存资源 如果在程序运行期间采取ctrl+c的方式中断程序会因为内存没用正常释放从而导致 在下一次重新启动demo是出错。这种错误需要reboot开发板并重新init load */ Demo_startStop(demoId, FALSE) { VdecVdis_stop() { VdecVdis_bitsRdStop(); /* Stop components */ Vdec_stop(); Vdis_stop(); grpx_exit(); Vsys_delete(); /* De-configure display */ Vsys_deConfigureDisplay(); /* De-initialize components */ Vdec_exit(); Vdis_exit(); Vsys_exit(); VdecVdis_bitsRdExit(); } } return 0; }