b.telnet到ip为172.16.66.29的MCU设备,然后使用pkt_prof 命令罗列所有监测点
c.录制指定点的数据流
d.使用自己编写的播放工具播放录制下来的视频图象(感兴趣的网友可以留下email,可以发给你们)
e.几个监测点的代码 这些demo来自于视频会议的。 demo1:将数据包发送到网络 NW_BOOL rtpDataSendFromCodec2Net(IN NW_VOID * pData, IN NW_INT32 nLen, IN TRtpParam * pRtpParam, IN NW_INT32 nDestNum, IN TForwardUnit * pDests) ... { static NW_UINT8 tempBuf[1600] = ...{0}; NW_INT32 nMaxCallID = 0; NW_INT32 nIndex; NW_UINT8 nStackCallId; NW_UINT8 *ptr; NW_UINT8 *tempBuf1 = NULL; NW_INT32 operationCode = OP_STREAM; EStRtpMediaType eRtpMediaType = pDests[0].oUnit.tRtpUnit.eRtpMediaType; tempBuf1 = tempBuf; ((TIPBoardPacketHdr*)tempBuf1)->sIdentifier = PKT_ID; ((TIPBoardPacketHdr*)tempBuf1)->byVersion = PKT_VER; ((TIPBoardPacketHdr*)tempBuf1)->byDirection = PKT_DIR_MAIN_2_IP; ((TIPBoardPacketHdr*)tempBuf1)->byDataType = PKT_DATATYPE_STREAM; ((TIPBoardPacketHdr*)tempBuf1)->byOperation = operationCode; ((TIPBoardPacketHdr*)tempBuf1)->byOperationType = eRtpMediaType; ((TIPBoardPacketHdr*)tempBuf1)->sPayloadLen = /**//*36*/24 + nLen + nDestNum; memcpy(tempBuf1+16,&nLen,4); memcpy(tempBuf1+20,&nDestNum,4); for (nIndex = 0; nIndex < nDestNum; nIndex++) ...{ /**//* 进行判断防止因定义时是Union而导致了nDevID和nCallID的复用。[zhengxb, 2006-04-30] */ if(FU_NET != pDests[nIndex].eUnitType) ...{ continue; } nStackCallId = pDests[nIndex].oUnit.tRtpUnit.nCallId; memcpy(tempBuf1+24+nIndex,&nStackCallId, 1); if ( nStackCallId < MIN_GW_VCALLID && nMaxCallID < nStackCallId) ...{ nMaxCallID = nStackCallId; } #ifdef _PACKET_PROFILER_ ...{ if (AUDIO_FIRST == eRtpMediaType) ...{ static NW_INT32 nCallerID = INVALID_VALUE; static const EStreamType eStreamType = STREAM_AUDIO; static EStreamIdType eStreamIdType = STREAM_ID_CALL; NW_INT32 nStreamID = nStackCallId; TStream tStream; tStream.nSequence = pRtpParam->sequenceNumber; tStream.nMarker = pRtpParam->marker; tStream.nLen = nLen - RTP_HEADER_LEN; tStream.pData = pData + RTP_HEADER_LEN; tStream.bKeyframe = FALSE; pkt_probe(ADD_PREFIX("DP"),__LINE__,&nCallerID,eStreamIdType,nStreamID,eStreamType,&tStream); } else ...{ static NW_INT32 nCallerID = INVALID_VALUE; static const EStreamType eStreamType = STREAM_VIDEO; static EStreamIdType eStreamIdType = STREAM_ID_CALL; NW_INT32 nStreamID = nStackCallId; TStream tStream; tStream.nSequence = pRtpParam->sequenceNumber; tStream.nMarker = pRtpParam->marker; tStream.nLen = nLen - RESERVE_HEADER_LEN; tStream.pData = pData + RESERVE_HEADER_LEN; tStream.bKeyframe = mdfIsKeyFrame(pRtpParam->payload, pData + RESERVE_HEADER_LEN); pkt_probe(ADD_PREFIX("DP"),__LINE__,&nCallerID,eStreamIdType,nStreamID,eStreamType,&tStream); } }#endif } stRtpPack(nMaxCallID, eRtpMediaType, pData, nLen, pRtpParam); memcpy(tempBuf1+24+nDestNum,pData, nLen); if (NULL != ibCallBackSendData) ...{ ibCallBackSendData(0, tempBuf,24+nLen+nDestNum,eRtpMediaType,nMaxCallID,TRUE); } return TRUE;} 在1.c中录制的监测点位于 sfDataWrite中 demo2:将数据从编码缓冲写到平滑缓冲,平滑处理后调用 rtpDataSendFromCodec2Net发送到网络 NW_BOOL sfDataWrite(IN NW_INT32 nRingId, IN NW_VOID * pContext) ... { PTSfEntryInfo pEntry = NULL; PTSfRingInfo pRing = NULL; NW_INT32 nCodecId; NW_INT32 nSfPacketNum; NW_INT32 nIndex; NW_UINT8 *pData = NULL; NW_INT32 nLen = 0; NW_INT32 nPacketNum = 0; NW_UINT16 nSequenceNum; NW_UINT32 nTimestamp; TRtpParam *pRtpParam = NULL; EPayload ePayload; TFrameBufferInfo *pFrame = (TFrameBufferInfo*)pContext; TVBufferInfoFromCodec *pBuffer = NULL; if(nRingId<0 || nRingId>=DP_SF_MAX_RING_NUM) return FALSE; pRing = &(g_pStRingInfo[nRingId]); nSfPacketNum = pRing->nRxPacketNum; pBuffer = &(pFrame->buffer_info.bufferInfoFromVCoder); pData = pBuffer->buffer; nLen = pBuffer->dataLen; 。。。 if (nSfPacketNum < DP_SF_MAX_RX_PACKET_NUM) ...{ for (nIndex = 0; nIndex < nPacketNum; nIndex++) ...{ pEntry = &(pRing->pEntry[pRing->nWrite]); nSequenceNum = rtpVideoSequenceNumGet(MIXER_INDEX(nCodecId)); pRtpParam = &(pEntry->tRtpParam); pEntry->nLen = mdfLenGet(pData); pEntry->bKeyframe = pBuffer->bKeyFrame; pRtpParam->payload = ePayload; pRtpParam->sequenceNumber = nSequenceNum; pRtpParam->timestamp = nTimestamp; pRtpParam->sByte = RTP_HEADER_LEN; pRtpParam->len = pEntry->nLen; if (nIndex == nPacketNum - 1) ...{ pRtpParam->marker = TRUE; } else ...{ pRtpParam->marker = FALSE; } #ifdef _PACKET_PROFILER_ ...{ static NW_INT32 nCallerID = INVALID_VALUE; static const EStreamType eStreamType = STREAM_VIDEO; static const EStreamIdType eStreamIdType = STREAM_ID_CHAN; static TStream tStream; NW_INT32 nStreamID = nRingId; tStream.nSequence = pRtpParam->sequenceNumber; tStream.nMarker = pRtpParam->marker; tStream.nLen = pRtpParam->len - RESERVE_HEADER_LEN; tStream.pData = pData + BUFFER_NODE_HEADER_SIZE + RESERVE_HEADER_LEN; tStream.bKeyframe = pBuffer->bKeyFrame; pkt_probe(ADD_PREFIX("DP"),__LINE__,&nCallerID,eStreamIdType,nStreamID,eStreamType,&tStream); }#endif memcpy(pEntry->pData, pData + BUFFER_NODE_HEADER_SIZE, pEntry->nLen); pEntry->bState = TRUE; ++(pRing->nRxPacketNum); pRing->nWrite = (pRing->nWrite + 1 + DP_SF_MAX_ENTRY_NUM)%DP_SF_MAX_ENTRY_NUM; pData += NET_BUFFER_VIDEO_NODE_SIZE; pEntry->bState = TRUE; } return TRUE; } else ...{ sfRingReset(nRingId, TRUE); return FALSE; }} 2.pkt_profiler.h ... #define _PACKET_PROFILER_ #ifdef _PACKET_PROFILER_ #define ADD_PREFIX(x) (x##"@"##__FUNCTION__) /*添加模块名前缀,可用于模块检索*/ typedef struct _tagStream ... { NW_BYTE nMarker; /**//*一帧数据的尾包吗*/ NW_UINT16 nSequence; /**//*数据包序列号*/ NW_BOOL bKeyframe; /**//*I 帧标识*/ NW_UINT8* pData; /**//*裸数据包地址*/ NW_INT32 nLen; /**//*裸数据包长度*/} TStream;typedef enum _tagStreamType ... { STREAM_NONE = 0, STREAM_AUDIO = 1 << 0, STREAM_VIDEO = 1 << 1} EStreamType;typedef enum _tagStreamIdType ... { STREAM_ID_INVALID = 0, STREAM_ID_DSP = 1, /**//*数据包发给DSP 或从DSP 接收*/ STREAM_ID_CHAN = 2, /**//*数据包写入缓冲 或从 缓冲读取*/ STREAM_ID_CALL = 3 /**//*数据包发给协议栈 或从 协议栈读取*/} EStreamIdType;NW_VOID pkt_probe( const NW_CHAR * pchFuncName, /**/ /*监测点所在函数的函数名信息*/ const NW_INT32 nLine, /**/ /*监测点所在位置*/ NW_INT32 * pCallerID, /**/ /*监测点所在函数的调用ID ,唯一*/ EStreamIdType eStreamIdType, /**/ /*监测点数据来源类型*/ NW_INT32 nStreamId, /**/ /*监测点数据通道ID,唯一*/ EStreamType eStreamType, /**/ /*监测点数据类型,音频或视频*/ TStream * pStream ); /**/ /*监测点数据流详细信息*/ #endif /*_PACKET_PROFILER_*/ 3.pkt_profiler.c ...#ifdef _PACKET_PROFILER_ /**/ /** * 1.工具介绍: * a.<功能>:数据诊断工具packet profiler 主要用于查看全部或某 * 具体监测点(每个监测点使用pkt_probe 探测数据) * 的数据流状况并在出现异常情况时可以使用 * pkt_prof、pkt_show、pkt_rec、pkt_check 等命令诊断数据流。 * 这些命令的具体功能和用法可以使用pkt_help 查看。 * b.<用法>:这些命令的提供提高了数据流bug 的诊断能力, * 也提高了对数据流bug 定位的正确性、便利性、 * 快捷性。如果你想查看某个检测点的状况,可以 * 先使用pkt_prof 显示音频或视频类型某模块下的所有 * 检测点的Caller ID ,接着使用pkt_show、pkt_rec、pkt_check * 查看具体检测点下的异常情况。我们可以使用 * pkt_probe 添加检测点。 * c.<建议>:该工具支持多任务支持跨模块调用,建议以后 * 单独拿出来作为一个公共工具模块放在common目录下 * 让更多的模块享受这种调式的乐趣。 * 2.工具命令: * a.<pkt_prof>:可以在异常情况下打印所有或某模块中的 * 数据流的流向。 虽然有fdtShow 提供流向表查询功能 * 但它无法知晓某数据通道是否确实有数据流经已经 * 以及以多少码流流过。 * b.<pkt_show>:可以在异常情况下打印某具体监测点数据 * 详细信息包括数据长度、数据地址、序列号等信息。 * 这个命令用于代码开发阶段很使用。 * c.<pkt_rec/sync>:可以在异常情况下录制声音或图象。 * 比如发现某路数据声音出现断断续续或重音现象 * 就可以使用该功能去检查有嫌疑的检测点并最终 * 定位异常源自模块中的哪个位置。*/ static NW_UINT32 dword_swap(NW_UINT32 x) ... { return ( ((x & 0x000000FF) << 24) | ((x & 0xFF000000) >> 24) | (((x) & 0xFF00) << 8) | (((x) & 0xFF0000) >> 8));} #define CALLER_ID0 (1) #define MAX_CALLERS (50) /*流量统计监测点的最大数目*/ #define MAX_CHANNELS (200) /*每个监测点支持通道的最大数目*/ #define MAX_FUNC_NAME_LEN (50) /*监测点调用函数的函数名最大长度*/ #define MAX_HINT_INFO_LEN (80) /*监测点调用函数的函数名最大长度*/ #define TICKS_PER_SECOND (60) /**/ /* NOTE: * 1.为了不干扰正在运行的其它程序,profiler 的录制功能 * (record) 块使用静态内存。虽然可以在初始化阶段为其分 * 配动态内存,但为了坚守profiler 模块的独立性,还是不建议。 * 2.如果考虑内存消耗,可以关闭_PACKET_WRITE_FILE_ 来关闭录制 * (record) 功能。目前不支持多路数据同时保存。 */ #define _PACKET_WRITE_FILE_ /*如果要考虑到内存分配,那么可以关闭此功能*/ typedef struct _TagPacketInfo ... { NW_INT32 nPackets; /**//*监测点流经总包数*/ NW_INT32 nPacketRate; /**//*监测点流量*/ NW_INT32 nPrevPackets; /**//*该点上一次监测的累计包数*/ NW_INT32 nPrevTicks; /**//*该点上一次监测的累计时间*/ NW_INT32 nPacketShown; /**//*显示数据包头的数目*/ NW_INT32 nInterval; /**//*前后两次监测的时间跨度*/ NW_BOOL bFrame; /**//*如果统计单位为帧*/ #ifdef _PACKET_WRITE_FILE_ NW_BOOL bSaved; /**//*录制该通道*/ NW_INT32 nOffsetPrev; /**//*录制开始标志*/ NW_INT32 nOffsetCurr; /**//*录制起始偏移量*/ NW_INT32 nFrameLen; NW_BOOL bFisrtPacket; NW_BOOL bStart; NW_BOOL bReady; #endif EStreamIdType eStreamIdType; /**//*数据流来源ID 类型,可以是DSP ID,可以是CHANNEL ID*/} TPacketInfo;typedef struct _TagCallerInfo ... { NW_CHAR pchFuncName[MAX_FUNC_NAME_LEN]; /**//*调用函数的函数名,caller名称*/ NW_CHAR nFuncLen; /**//*调用函数的函数名实际长度*/ NW_SHORT nLine; /**//*调用函数的调用点位置*/ TPacketInfo tPacket[MAX_CHANNELS]; /**//*调用函数的调用的统计信息*/} TCallerInfo; static TCallerInfo g_tCaller[MAX_CALLERS]; static NW_INT32 g_nCallers = CALLER_ID0; /**/ /*不从0 开始,可以提供更多灵活性,见pkt_rec*/ static NW_BOOL g_bActivated = FALSE; static NW_BOOL g_bInitialized = FALSE; static NW_INT32 g_eStreamType = 0 ; static NW_CHAR g_strModulePrefix[MAX_FUNC_NAME_LEN]; static NW_BOOL g_bModulePrefixFiltered = FALSE;NW_VOID pkt_start( void );NW_VOID pkt_stop( void );NW_BOOL pkt_started( void );NW_VOID pkt_stat( void );NW_VOID pkt_help(NW_INT32 nSelection); NW_VOID pkt_check(NW_INT32 nCallerID,NW_INT32 nStreamId);#ifdef _PACKET_WRITE_FILE_NW_VOID pkt_rec(NW_INT32 nCallerID,NW_INT32 nStreamId,NW_INT32 nRecoredLen); #endif #ifdef _PACKET_WRITE_FILE_ #define MAX_MULTI_RECORD_POINTS 16 #define MAX_BUF_SIZE 200*1024 /*录制缓冲区大小*/ typedef struct _TagRec ... { NW_INT32 nCallerID; NW_INT32 nChannelID; } TRec; static NW_UINT8 s_pFileBuf[MAX_BUF_SIZE]; static NW_UINT32 s_nFileBufLen = 0 ;NW_VOID pkt_dump( const NW_CHAR * pchFuncName,NW_INT32 nStreamId,EStreamType eStreamType,TPacketInfo * ptPacket);NW_VOID pkt_dump( const NW_CHAR * pchFuncName,NW_INT32 nStreamId,EStreamType eStreamType,TPacketInfo * ptPacket) ... { FILE * fptr = NULL; static NW_BYTE nFilename[100] = ...{0}; EStreamIdType eStreamIdType = 0; NW_INT32 nOffset = 0; if (NULL == pchFuncName) ...{ printf("Invalid function name! "); return; } if (NULL == ptPacket) ...{ printf("%s:Invalid packet info! ",pchFuncName); return; } eStreamIdType = ptPacket->eStreamIdType; nOffset = ptPacket->nOffsetCurr - ptPacket->nOffsetPrev; if (STREAM_ID_DSP != eStreamIdType && STREAM_ID_CHAN != eStreamIdType && STREAM_ID_CALL != eStreamIdType) ...{ printf("%s:Invalid stream id type %d! ",pchFuncName,eStreamIdType); return; } if (nStreamId>=0 && nStreamId<MAX_CHANNELS) ...{ sprintf(nFilename,"%s.%s_%s_%d.%s", pchFuncName,STREAM_AUDIO==eStreamType?"audio":"video", STREAM_ID_DSP == eStreamIdType?"dsp":(STREAM_ID_CHAN == eStreamIdType? "chan":"call"), nStreamId,STREAM_AUDIO==eStreamType?"dat":"mpeg4"); fptr = fopen(nFilename,"wb"); if (NULL == fptr) ...{ printf("%s:Failed to open %s! ",pchFuncName,nFilename); return; } else ...{ if (nOffset > 0) ...{ if (nOffset > s_nFileBufLen) ...{ nOffset = s_nFileBufLen; } fwrite(s_pFileBuf+ptPacket->nOffsetPrev,1,nOffset, fptr); } } fclose(fptr); } else ...{ printf("%s:Invalid stream id %d! ",pchFuncName,nStreamId); }} #endif /*_PACKET_WRITE_FILE_*/ NW_VOID pkt_probe( const NW_CHAR * pchFuncName, const NW_INT32 nLine,NW_INT32 * pCallerID,EStreamIdType eStreamIdType,NW_INT32 nStreamId,EStreamType eStreamType,TStream * pStream) ... { NW_INT32 nCaller = 0; NW_INT32 nChannel = 0; NW_INT32 nCurrTicks = 0; NW_INT32 nModulePrefixLen = 0; NW_INT32 nPrefix = 0; TCallerInfo* ptCaller = NULL; TPacketInfo* ptPacket = NULL; if (!pkt_started()) ...{ return; } if (!g_bInitialized) ...{ return; } if (NULL == pchFuncName || NULL == pCallerID) ...{ printf("Invalid function name or caller ID pointer!"); return; } if (nStreamId < 0 || nStreamId >= MAX_CHANNELS) ...{ printf("%s:Invalid stream id %d!",pchFuncName,nStreamId); return; } if (STREAM_ID_DSP != eStreamIdType && STREAM_ID_CHAN != eStreamIdType && STREAM_ID_CALL != eStreamIdType) ...{ printf("%s:Invalid stream id type %d!",pchFuncName,eStreamIdType); return; } if (!(eStreamType & g_eStreamType)) ...{/**//*过滤不想统计的通道*/ return; } if (INVALID_VALUE == *pCallerID) ...{ /**//*分配CALLER ID , 支持多任务!*/ if ((nCaller = g_nCallers++) >= MAX_CALLERS) ...{ printf("%s:Falied to allocate caller ID %d!",pchFuncName,nCaller); return; } ptCaller = &g_tCaller[nCaller]; ptCaller->nFuncLen = strlen(pchFuncName); if (ptCaller->nFuncLen >= MAX_FUNC_NAME_LEN) ...{ printf("%s:Too long function name! ",pchFuncName); return; } ptCaller->nFuncLen = sprintf(ptCaller->pchFuncName,"%s",pchFuncName); ptCaller->nLine = nLine; *pCallerID = nCaller;/**//*返回当前监测点的ID,以备后用*/ } else ...{ nCaller = *pCallerID; } ptCaller = &g_tCaller[nCaller]; ptPacket = &g_tCaller[nCaller].tPacket[nStreamId]; if (nCaller >= CALLER_ID0 && nCaller < MAX_CALLERS) ...{ if (STREAM_ID_DSP != ptPacket->eStreamIdType && STREAM_ID_CHAN != ptPacket->eStreamIdType && STREAM_ID_CALL != ptPacket->eStreamIdType) ...{ ptPacket->eStreamIdType = eStreamIdType; } if (NULL != pStream && ptPacket->nPacketShown>0 && ptPacket->nPacketShown-->0) ...{ printf("%s(M):len M,seqence %d,marker %d,keyframe %d ", ptCaller->pchFuncName,ptCaller->nLine,pStream->nLen,pStream->nSequence,pStream->nMarker,pStream->bKeyframe); return; } if (g_bModulePrefixFiltered) ...{ nModulePrefixLen = strlen(g_strModulePrefix); if (nModulePrefixLen> 0 && nModulePrefixLen< MAX_FUNC_NAME_LEN) ...{ while (nModulePrefixLen>0) ...{ if (ptCaller->pchFuncName[nModulePrefixLen-1] != g_strModulePrefix[nModulePrefixLen-1]) ...{ return; } nModulePrefixLen--; } } } #ifdef _PACKET_WRITE_FILE_ /**//*录制声音或图象*/ if (ptPacket->bSaved && NULL != pStream && NULL != pStream->pData && pStream->nLen >0 && pStream->nLen < 1600) ...{ NW_BYTE* pData = NULL; NW_INT32 nDataLen = 0; NW_INT32 nMarker = FALSE; pData = pStream->pData; nDataLen = pStream->nLen; nMarker = pStream->nMarker; if(!ptPacket->bReady && ptPacket->nOffsetPrev == ptPacket->nOffsetCurr) ...{ ptPacket->bStart = TRUE; if (STREAM_VIDEO == eStreamType) ...{ if (pStream->bKeyframe) ...{ ptPacket->bReady = TRUE; ptPacket->bFisrtPacket = FALSE; ptPacket->nFrameLen = 0; if (0 == ptPacket->nOffsetPrev) ...{ printf("0%s ","%"); } } } else ...{ ptPacket->bReady = TRUE; if (0 == ptPacket->nOffsetPrev) ...{ printf("0%s ","%"); } } } /**//* *audio:|pkt 1||pkt 2|...|pkt n|... *video:|frame len|pkt 1||pkt 2|...|pkt n|... */ if(ptPacket->bReady) ...{ if (!ptPacket->bFisrtPacket && STREAM_VIDEO == eStreamType) /**//*first packet of a frame*/ ...{ ptPacket->bFisrtPacket = TRUE; ptPacket->nFrameLen = 0; ptPacket->nOffsetCurr += sizeof(ptPacket->nFrameLen); } if (ptPacket->nOffsetCurr - ptPacket->nOffsetPrev + nDataLen < s_nFileBufLen) ...{ memcpy(s_pFileBuf + ptPacket->nOffsetCurr,pData,nDataLen); if (0 == ptPacket->nOffsetPrev && ((10*(ptPacket->nOffsetCurr - ptPacket->nOffsetPrev))/s_nFileBufLen) != ((10*(ptPacket->nOffsetCurr - ptPacket->nOffsetPrev + nDataLen))/s_nFileBufLen)) ...{ printf("█ "); } ptPacket->nOffsetCurr += (nDataLen+0x3)&~0x3; if (STREAM_VIDEO == eStreamType) ...{ ptPacket->nFrameLen += (nDataLen+0x3)&~0x3; if (nMarker) /**//*last packet of a frame*/ ...{ *(NW_INT32*)(s_pFileBuf+ptPacket->nOffsetCurr - ptPacket->nFrameLen - sizeof(ptPacket->nFrameLen)) = dword_swap(ptPacket->nFrameLen); ptPacket->nFrameLen = 0; ptPacket->bFisrtPacket = FALSE; } } } else ...{ ptPacket->bSaved = FALSE; ptPacket->bReady = FALSE; pkt_dump(ptCaller->pchFuncName,nStreamId,eStreamType,ptPacket); for (nCaller = CALLER_ID0; nCaller < g_nCallers; nCaller++) ...{ for (nChannel = 0; nChannel < MAX_CHANNELS; nChannel++) ...{ if (g_tCaller[nCaller].tPacket[nChannel].bStart && g_tCaller[nCaller].tPacket[nChannel].bSaved) ...{ break; } } if (MAX_CHANNELS != nChannel) ...{ break; } } if (nCaller == g_nCallers) ...{ printf("█ 100%s","%"); pkt_stop(); } } } } #endif /**//*等待用户设置检测时间*/ if (1 > ptPacket->nInterval) ...{ return; } /**//*如果统计单位是帧*/ if (STREAM_VIDEO == eStreamType) ...{ if (NULL != pStream && pStream->nMarker && !ptPacket->bFrame) ...{ ptPacket->bFrame = TRUE; } if (NULL != pStream && ptPacket->bFrame && !pStream->nMarker) ...{ return; } } ptPacket->nPackets++; nCurrTicks = tickGet(); if (0 == ptPacket->nPrevTicks) ...{ ptPacket->nPrevPackets = ptPacket->nPackets; ptPacket->nPrevTicks = nCurrTicks; } else ...{ if (nCurrTicks != ptPacket->nPrevTicks && nCurrTicks-ptPacket->nPrevTicks >= ptPacket->nInterval) ...{ ptPacket->nPacketRate = TICKS_PER_SECOND*(ptPacket->nPackets - ptPacket->nPrevPackets) /(nCurrTicks - ptPacket->nPrevTicks); ptPacket->nPrevTicks = 0; ptPacket->nInterval = 0; } } }} NW_VOID pkt_prof(NW_CHAR * pchMediaType,NW_CHAR * pchModulePrefix) ... { TCallerInfo* ptCaller = NULL; TPacketInfo* ptPacket = NULL; NW_INT32 nCaller = 0; NW_INT32 nChannel = 0; NW_INT32 nModulePrefixLen = 0; static const NW_INT32 nInterval = 4*TICKS_PER_SECOND;/**//*second*/ static const NW_INT32 nErrorPercentage = 5;/**//*误差占整个计时的百分比*/ if (NULL == pchMediaType && NULL == pchModulePrefix) ...{ if (g_eStreamType > 0) ...{ pkt_stat(); return; } pkt_help(1); return; } if (1 > nInterval || 1 > nErrorPercentage) ...{ printf("%s:Invalid param,interval %d,error %d! ",pchMediaType,nInterval,nErrorPercentage); return; } pkt_stop(); if (NULL != pchModulePrefix) ...{ nModulePrefixLen = strlen(pchModulePrefix); if (nModulePrefixLen> MAX_FUNC_NAME_LEN) ...{ printf("%s:Too long module prefix! ",pchModulePrefix); return; } g_bModulePrefixFiltered = FALSE; taskDelay(3);/**//*等待pkt_prof g_bModulePrefixFiltered 相关代码执行完毕*/ memset(&g_strModulePrefix[0],0,sizeof(NW_CHAR)*MAX_FUNC_NAME_LEN); sprintf(g_strModulePrefix,"%s",pchModulePrefix); g_bModulePrefixFiltered = TRUE; } else ...{ g_bModulePrefixFiltered = FALSE; taskDelay(3); memset(&g_strModulePrefix[0],0,sizeof(NW_CHAR)*MAX_FUNC_NAME_LEN); } g_eStreamType = 0; if (0 == strcmp(pchMediaType,"audio")) ...{ g_eStreamType |= STREAM_AUDIO; } else if (0 == strcmp(pchMediaType,"video")) ...{ g_eStreamType |= STREAM_VIDEO; } else ...{ pkt_help(1); return; } /**//*如果有数据流,设置统计时间*/ if (!g_bInitialized) ...{ /**//*第一次要初始化*/ memset(&g_tCaller[0],0,sizeof(TCallerInfo)*MAX_CALLERS); for (nCaller = CALLER_ID0; nCaller < MAX_CALLERS; nCaller++) ...{ for (nChannel = 0; nChannel < MAX_CHANNELS; nChannel++) ...{ g_tCaller[nCaller].tPacket[nChannel].bFrame = FALSE; #ifdef _PACKET_WRITE_FILE_ g_tCaller[nCaller].tPacket[nChannel].bSaved = FALSE; #endif g_tCaller[nCaller].tPacket[nChannel].eStreamIdType = STREAM_ID_INVALID; } } g_bInitialized = TRUE; } for (nCaller = CALLER_ID0; nCaller < MAX_CALLERS; nCaller++) ...{ for (nChannel = 0; nChannel < MAX_CHANNELS; nChannel++) ...{ g_tCaller[nCaller].tPacket[nChannel].nInterval = nInterval; g_tCaller[nCaller].tPacket[nChannel].nPackets = 0; g_tCaller[nCaller].tPacket[nChannel].nPacketRate = 0; } } pkt_start(); printf("wait %d seconds for profiling %s rates%s%s... ",((TICKS_PER_SECOND/10)+nInterval+nInterval/(100/nErrorPercentage))/TICKS_PER_SECOND, pchMediaType,NULL == pchModulePrefix? "":" from the module with prefix ",NULL == pchModulePrefix? "":pchModulePrefix); taskDelay(nInterval);/**//*统计时间*/ taskDelay(nInterval/(100/nErrorPercentage));/**//*考虑大概 的偏差*/ pkt_stat(); pkt_stop();} /**/ /*显示数据包RTP 头信息*/ NW_VOID pkt_show(NW_INT32 nCallerID,NW_INT32 nStreamId,NW_INT32 nPacketNum) ... { static NW_INT32 nCallerID2 = 0; static NW_INT32 nStreamId2 = 0; static NW_INT32 nPacketNum2 = 0; NW_INT32 nCaller = 0; NW_INT32 nChannel = 0; if (!g_bInitialized) ...{ printf("You gotta use pkt_prof to do initialization first!"); return; } pkt_stop(); if (0 != nCallerID) ...{ nCallerID2 = nCallerID; nStreamId2 = nStreamId; nPacketNum2 = nPacketNum; } if (nCallerID2 <CALLER_ID0 || nCallerID2 >= MAX_CALLERS) ...{ printf("Invalid caller ID %d ",nCallerID2); pkt_help(2); return; } if (nStreamId2 < 0 || nStreamId2 >= MAX_CHANNELS) ...{ printf("Invalid stream ID %d ",nStreamId2); pkt_help(2); return; } if (1 > nPacketNum2) ...{ printf("Invalid packet num %d ",nPacketNum2); pkt_help(2); return; } if (1 > g_tCaller[nCallerID2].nFuncLen) ...{ printf("Invalid func len %d ",g_tCaller[nCallerID2].nFuncLen); return; } for (nCaller = CALLER_ID0; nCaller < MAX_CALLERS; nCaller++) ...{ for (nChannel = 0; nChannel < MAX_CHANNELS; nChannel++) ...{ g_tCaller[nCaller].tPacket[nChannel].nPacketShown = 0; } } g_tCaller[nCallerID2].tPacket[nStreamId2].nPacketShown = nPacketNum2; pkt_start(); taskDelay(300*nPacketNum2/TICKS_PER_SECOND);/**//*300 为一秒中可能接收到的最大包数目*/ pkt_stop(); } #ifdef _PACKET_WRITE_FILE_ /**/ /*record*/ NW_BOOL pkt_confirmed( void ) ... { static NW_BOOL bFtpOpened = FALSE; NW_BYTE szLocalIP[16] = ...{0}; NW_CHAR ch = '0'; if (!bFtpOpened) ...{ printf("NOTE:Be 100%s sure whether host wftp server has been opened or not. ","%",szLocalIP); printf("Opened yet? Go,check and enter 'Y' or 'N' to make sure:"); ch = getchar(); while ('Y' != ch && 'N' != ch) ...{ ch = getchar(); } if('N' == ch) ...{ printf("Open WFTP server and enter 'Y' to continue or 'A' to exit:"); ch = getchar(); while ('Y' != ch && 'A' != ch ) ...{ ch = getchar(); } if('Y' != ch) ...{ return FALSE; } else ...{ printf("Warning:it'll cause a long delay in multi-pictures if WFTP server wasn't opened practically!"); } } bFtpOpened = TRUE; } return TRUE;} /**/ /*单点录制*/ NW_VOID pkt_rec(NW_INT32 nCallerID,NW_INT32 nStreamId,NW_INT32 nRecoredLen) ... { static NW_INT32 nCallerID2 = 0; static NW_INT32 nStreamId2 = 0; static NW_INT32 nRecoredLen2 = 0; NW_INT32 nCaller = 0; NW_INT32 nChannel = 0; NW_CHAR ch = '0'; if (!g_bInitialized) ...{ printf("You gotta use pkt_prof to do initialization first!"); return; } pkt_stop(); if (0 != nCallerID) ...{ nCallerID2 = nCallerID; nStreamId2 = nStreamId; nRecoredLen2 = nRecoredLen; } if (nCallerID2 < CALLER_ID0 || nCallerID2 >= MAX_CALLERS) ...{ printf("Invalid caller ID %d ",nCallerID2); pkt_help(5); return; } if (nStreamId2 < 0 || nStreamId2 >= MAX_CHANNELS) ...{ printf("Invalid stream ID %d ",nStreamId2); pkt_help(5); return; } if (1 > g_tCaller[nCallerID2].nFuncLen) ...{ printf("Invalid func len %d ",g_tCaller[nCallerID2].nFuncLen); return; } /**//*如果nRecoredLen 没有输入或0 则采取默认值*/ if (0 == nRecoredLen2) ...{ nRecoredLen2 = MAX_BUF_SIZE; } if (nRecoredLen2 > MAX_BUF_SIZE) ...{ pkt_help(4); return; } else ...{ s_nFileBufLen = nRecoredLen2; } if (!pkt_confirmed()) ...{ /**//*确认不成功*/ printf("Failed to confirm! "); return; } for (nCaller = CALLER_ID0; nCaller < MAX_CALLERS; nCaller++) ...{ for (nChannel = 0; nChannel < MAX_CHANNELS; nChannel++) ...{ g_tCaller[nCaller].tPacket[nChannel].bSaved = FALSE; g_tCaller[nCaller].tPacket[nChannel].bStart = FALSE; g_tCaller[nCaller].tPacket[nChannel].bReady = FALSE; g_tCaller[nCaller].tPacket[nChannel].nOffsetPrev = 0; g_tCaller[nCaller].tPacket[nChannel].nOffsetCurr = 0; } } memset(s_pFileBuf+g_tCaller[nCallerID2].tPacket[nStreamId2].nOffsetCurr,0,s_nFileBufLen*sizeof(NW_UINT8)); g_tCaller[nCallerID2].tPacket[nStreamId2].nFrameLen = 0; g_tCaller[nCallerID2].tPacket[nStreamId2].bFisrtPacket = FALSE; g_tCaller[nCallerID2].tPacket[nStreamId2].bSaved = TRUE; pkt_start();} /**/ /*多点录制: 为了同步多点的数据流, 所有 *同步录制的点共享MAX_BUF_SIZE 长度的内存 *空间。一次设定多点录制列表,之后可 *以使用pkt_rec2() 反复利用。该功能对调试 *音频重音很有用。*/ NW_VOID pkt_rec_sync(NW_INT32 nRecordedPoints) ... { TPacketInfo* ptPacket = NULL; static TRec tRecList[MAX_MULTI_RECORD_POINTS]; static NW_BOOL bInitialized = FALSE; static NW_INT32 nPoints = 0; NW_INT32 nPoint,nRecPoints = nRecordedPoints; NW_INT32 nRecoredLen = 0; NW_INT32 nCaller,nCallerID = 0; NW_INT32 nChannel,nChannelID = 0; NW_INT32 nChannelPrev,nChannelIDPrev = 0; if (!bInitialized) ...{ if (nRecPoints < 1 || nRecPoints > MAX_MULTI_RECORD_POINTS) ...{ printf("Invalid caller num %d! ",nRecPoints); pkt_help(6); return; } if (!pkt_confirmed()) ...{ /**//*确认不成功*/ printf("Failed to confirm! "); return; } memset(&tRecList[0],0,sizeof(TRec)*MAX_MULTI_RECORD_POINTS); bInitialized = TRUE; nPoints = 0; } if (bInitialized) ...{ if (nRecPoints < 0 || nRecPoints > MAX_MULTI_RECORD_POINTS) ...{ printf("Invalid caller num %d! ",nRecPoints); pkt_help(6); return; } pkt_stop(); if (nRecPoints > 0) ...{ nPoints = nRecPoints; } if (0 == nPoints) ...{ printf("recorded points overriden %d! ",nPoints); return; } for (nCaller = CALLER_ID0; nCaller < MAX_CALLERS; nCaller++) ...{ for (nChannel = 0; nChannel < MAX_CHANNELS; nChannel++) ...{ g_tCaller[nCaller].tPacket[nChannel].bSaved = FALSE; g_tCaller[nCaller].tPacket[nChannel].bStart = FALSE; g_tCaller[nCaller].tPacket[nChannel].bReady = FALSE; g_tCaller[nCaller].tPacket[nChannel].nOffsetPrev = 0; g_tCaller[nCaller].tPacket[nChannel].nOffsetCurr = 0; } } nRecoredLen = (MAX_BUF_SIZE/nPoints - 0x1) & ~0x3; s_nFileBufLen = nRecoredLen; for (nPoint =0; nPoint < nPoints; nPoint++) ...{ nCallerID = INVALID_VALUE; nChannelID = INVALID_VALUE; if (0 == nRecPoints) ...{ nCallerID = tRecList[nPoint].nCallerID; nChannelID = tRecList[nPoint].nChannelID; } else ...{ printf("Recorded point ID %d:Enter caller ID and channel ID:",nPoint); while (nCallerID <CALLER_ID0 || nCallerID >= MAX_CALLERS || nChannelID < CALLER_ID0 || nChannelID >= MAX_CHANNELS || (nPoint > 0 && nCallerID == tRecList[nPoint-1].nCallerID && nChannelID == tRecList[nPoint-1].nChannelID)) ...{ if ((nPoint > 0 && nCallerID == tRecList[nPoint-1].nCallerID && nChannelID == tRecList[nPoint-1].nChannelID)) ...{ printf("No repeat points allowed! Enter again:"); } scanf("%d,%d",&nCallerID,&nChannelID); } tRecList[nPoint].nCallerID = nCallerID; tRecList[nPoint].nChannelID = nChannelID; } ptPacket = &g_tCaller[nCallerID].tPacket[nChannelID]; ptPacket->nOffsetPrev = nPoint*nRecoredLen; ptPacket->nOffsetCurr = nPoint*nRecoredLen; ptPacket->bFisrtPacket = FALSE; ptPacket->nFrameLen = 0; ptPacket->bSaved = TRUE; memset(s_pFileBuf + ptPacket->nOffsetPrev,0,nRecoredLen*sizeof(NW_UINT8)); } pkt_start(); }} #endif NW_VOID pkt_stat( void ) ... { TCallerInfo* ptCaller = NULL; TPacketInfo* ptPacket = NULL; NW_INT32 nCaller = 0; NW_INT32 nChannel = 0; NW_BOOL bFound = 0; if (!g_bInitialized) ...{ printf("You gotta use pkt_prof to do initialization first!"); return; } if (1 > g_nCallers) ...{ printf("No stream coming! "); return; } printf("------------------------------------------------------------------------------- "); for (nCaller = CALLER_ID0; nCaller < MAX_CALLERS; nCaller++) ...{ ptCaller = &g_tCaller[nCaller]; if (1 > ptCaller->nFuncLen) ...{ continue; } bFound = FALSE; for (nChannel = 0; nChannel < MAX_CHANNELS; nChannel++) ...{ ptPacket = &g_tCaller[nCaller].tPacket[nChannel]; if (ptPacket->nInterval > 0) ...{ ptPacket->nInterval = 0; } if (ptPacket->nPacketRate > 0) ...{ printf("%-28s(%-4d) caller %-2d,%-4s id %-3d: %-3d %-s/s,%-3d %-7s ", ptCaller->pchFuncName,ptCaller->nLine,nCaller,STREAM_ID_DSP == ptPacket->eStreamIdType?"dsp": (STREAM_ID_CHAN == ptPacket->eStreamIdType? "chan":"call"),nChannel, ptPacket->nPacketRate,ptPacket->bFrame? "f":"p", ptPacket->nPackets,ptPacket->bFrame? "frames":"packets"); bFound = TRUE; } } if (bFound) ...{ printf(" "); } } printf("------------------------------------------------------------------------------- "); } NW_VOID pkt_check(NW_INT32 nCallerID,NW_INT32 nStreamId) ... { TPacketInfo* ptPacket = NULL; static NW_INT32 nCallerID2 = 0; static NW_INT32 nStreamId2 = 0; NW_INT32 nCaller = 0; NW_INT32 nChannel = 0; if (!g_bInitialized) ...{ printf("You gotta use pkt_prof to do initialization first!"); return; } if (0 != nCallerID) ...{ nCallerID2 = nCallerID; nStreamId2 = nStreamId; } if (nCallerID2 <CALLER_ID0 || nCallerID2 >= MAX_CALLERS) ...{ printf("Invalid caller ID %d ",nCallerID2); pkt_help(2); return; } if (nStreamId2 < 0 || nStreamId2 >= MAX_CHANNELS) ...{ printf("Invalid stream ID %d ",nStreamId2); pkt_help(2); return; } if (1 > g_tCaller[nCallerID2].nFuncLen) ...{ printf("Invalid func len %d ",g_tCaller[nCallerID2].nFuncLen); return; } ptPacket = &g_tCaller[nCallerID2].tPacket[nStreamId2]; printf("caller %-2d,%-4s id %-2d:nPackets %-d ",nCallerID2,STREAM_ID_DSP == ptPacket->eStreamIdType?"dsp": (STREAM_ID_CHAN == ptPacket->eStreamIdType? "chan":"call"),nChannel,ptPacket->nPackets); printf("caller %-2d,%-4s id %-2d:nPacketRate %-d ",nCallerID2,STREAM_ID_DSP == ptPacket->eStreamIdType?"dsp": (STREAM_ID_CHAN == ptPacket->eStreamIdType? "chan":"call"),nChannel,ptPacket->nPacketRate); printf("caller %-2d,%-4s id %-2d:nPrevPackets %-d ",nCallerID2,STREAM_ID_DSP == ptPacket->eStreamIdType?"dsp": (STREAM_ID_CHAN == ptPacket->eStreamIdType? "chan":"call"),nChannel,ptPacket->nPrevPackets); printf("caller %-2d,%-4s id %-2d:nPrevTicks %-d ",nCallerID2,STREAM_ID_DSP == ptPacket->eStreamIdType?"dsp": (STREAM_ID_CHAN == ptPacket->eStreamIdType? "chan":"call"),nChannel,ptPacket->nPrevTicks); printf("caller %-2d,%-4s id %-2d:nPacketShown %-d ",nCallerID2,STREAM_ID_DSP == ptPacket->eStreamIdType?"dsp": (STREAM_ID_CHAN == ptPacket->eStreamIdType? "chan":"call"),nChannel,ptPacket->nPacketShown); printf("caller %-2d,%-4s id %-2d:nInterval %-d ",nCallerID2,STREAM_ID_DSP == ptPacket->eStreamIdType?"dsp": (STREAM_ID_CHAN == ptPacket->eStreamIdType? "chan":"call"),nChannel,ptPacket->nInterval); printf("caller %-2d,%-4s id %-2d:bFrame %-d ",nCallerID2,STREAM_ID_DSP == ptPacket->eStreamIdType?"dsp": (STREAM_ID_CHAN == ptPacket->eStreamIdType? "chan":"call"),nChannel,ptPacket->bFrame); printf("caller %-2d,%-4s id %-2d:bSaved %-d ",nCallerID2,STREAM_ID_DSP == ptPacket->eStreamIdType?"dsp": (STREAM_ID_CHAN == ptPacket->eStreamIdType? "chan":"call"),nChannel,ptPacket->bSaved); } NW_VOID pkt_start( void ) ... { g_bActivated = TRUE;} NW_VOID pkt_stop( void ) ... { g_bActivated = FALSE;} NW_BOOL pkt_started( void ) ... { return g_bActivated;} NW_VOID pkt_reset( void ) ... { NW_INT32 nCaller = 0; NW_INT32 nChannel = 0; for (nCaller = CALLER_ID0; nCaller < MAX_CALLERS; nCaller++) ...{ for (nChannel = 0; nChannel < MAX_CHANNELS; nChannel++) ...{ g_tCaller[nCaller].tPacket[nChannel].bFrame = FALSE; #ifdef _PACKET_WRITE_FILE_ g_tCaller[nCaller].tPacket[nChannel].bSaved = FALSE; #endif g_tCaller[nCaller].tPacket[nChannel].eStreamIdType = STREAM_ID_INVALID; } } g_eStreamType = 0; g_bModulePrefixFiltered = FALSE; g_bActivated = FALSE; memset(&g_strModulePrefix[0],0,sizeof(NW_CHAR)*MAX_FUNC_NAME_LEN);} /**/ /*当出现异常时, 本模块可以诊断的手段*/ NW_VOID pkt_help(NW_INT32 nSelection) ... { /**//*NOTE : 打印是否对齐在UltraEdit 下看*/ switch (nSelection) ...{ case 0: ...{ printf("------------------------------------------------------------------------------ "); printf("pkt_help(0) 详细介绍pkt_help "); printf("pkt_help(1) 详细介绍pkt_prof "); printf("pkt_help(2) 详细介绍pkt_show "); printf("pkt_help(3) 详细介绍pkt_check "); printf("pkt_help(4) 详细介绍pkt_reset ");#ifdef _PACKET_WRITE_FILE_ printf("pkt_help(5) 详细介绍pkt_rec "); printf("pkt_help(6) 详细介绍pkt_rec_sync ");#endif printf("------------------------------------------------------------------------------ "); }break; case 1: ...{ printf("------------------------------------------------------------------------------ "); printf("NW_VOID pkt_prof(NW_CHAR* pchMediaType,NW_CHAR* pchModulePrefix) "); printf("1. 功能介绍: 打印所有或某监测点数据流通路径及速率 "); printf("2. 范例展示: pkt_prof 'video','DP' "); printf("3. 参数输入: "); printf(" pchMediaType: 媒体流类型, 如输入字符串audio / video 显示音视频 "); printf(" pchModulePrefix:模块的前缀, 如输入字符串COMM / DP表示通信层或DP "); printf("------------------------------------------------------------------------------ "); }break; case 2: ...{ printf("------------------------------------------------------------------------------ "); printf("NW_VOID pkt_show(NW_INT32 nCallerID,NW_INT32 nStreamId,NW_INT32 nPacketNum) "); printf("1. 功能介绍: 打印某监测点的一系列序列号 "); printf("2. 范例展示: pkt_show 2,1,10 "); printf("3. 参数输入: "); printf(" nCallerID: 监测点的函数调用ID, 调用pkt_prof 可以查看 "); printf(" nStreamId: 监测点的通道ID, 调用pkt_prof 可以查看 "); printf(" nPacketNum: 要求打印的数据包数目 "); printf("------------------------------------------------------------------------------ "); }break; case 3: ...{ printf("------------------------------------------------------------------------------ "); printf("NW_VOID pkt_check(NW_INT32 nCallerID,NW_INT32 nStreamId) "); printf("1. 功能介绍: 打印某监测点的详细统计信息 "); printf("2. 范例展示: pkt_check 2,1 "); printf("3. 参数输入: "); printf(" nCallerID: 监测点的函数调用ID, 调用pkt_prof 可以查看 "); printf(" nStreamId: 监测点的通道ID, 调用pkt_prof 可以查看 "); printf("------------------------------------------------------------------------------ "); }break; case 4: ...{ printf("------------------------------------------------------------------------------ "); printf("NW_VOID pkt_reset(void) "); printf("1. 功能介绍: 复位所有监测点状态 "); printf("2. 范例展示: pkt_reset "); printf("3. 参数输入: NONE "); printf("------------------------------------------------------------------------------ "); }break; #ifdef _PACKET_WRITE_FILE_ case 5: ...{ printf("------------------------------------------------------------------------------ "); printf("NW_VOID pkt_rec(NW_INT32 nCallerID,NW_INT32 nStreamId,NW_INT32 nRecoredLen)) "); printf("1. 功能介绍: 录制某监测点的数据流并传送到WFTP 用户目录 "); printf("2. 范例展示: pkt_rec 2,1 "); printf("3. 参数输入: "); printf(" nCallerID: 监测点的函数调用ID, 调用pkt_prof 可以查看 "); printf(" nStreamId: 监测点的通道ID, 调用pkt_prof 可以查看 "); printf(" nRecoredLen: 准备录制多少长度,不超过%d K ",MAX_BUF_SIZE/1024); printf("------------------------------------------------------------------------------ "); }break; case 6: ...{ printf("------------------------------------------------------------------------------ "); printf("NW_VOID pkt_rec_sync(NW_INT32 nRecordedPoints) "); printf("1. 功能介绍: 同时录制多个监测点的数据流 "); printf("2. 范例展示: pkt_rec_sync 2 "); printf("3. 参数输入: "); printf(" nRecordedPoints:同时录制多少个检测点, 最多支持%d 点 ",MAX_MULTI_RECORD_POINTS); printf("4. 注意事项: 该功能只对具备录制能力的监测点(rate:f/s) "); printf("------------------------------------------------------------------------------ "); }break; #endif default: ...{ /**//*递归显示*/ pkt_help(0); }break; }}