网络数据包片段拼合(连续h264片段拼接成完整h264帧)(二支持c+
上一篇的改进,支持c++,主要是对 C++ 类成员函数作为外部回调的处理。 关于这个c++ 类成员函数作为回调函数,还是有点意思的,有其他博文介绍的好几种方法,后续再论。 代码: /*** ***20181221 canok *** brief : Combine data fragments into complete frames *** input : Continuous data flow,support fix length data input; *** output: complete frames **/ #include #include #include #include #include #include typedef unsigned char uint8_t; //无符号8位数 #define ERRO_INFO(fmt,args...) do {printf("[%s,%s,%d]",__FILE__,__FUNCTION__,__LINE__);printf(fmt,##args);} while(0) #define DEBUG(fmt,args...) do {printf("[%s,##args);} while(0) typedef int (*FUN_GETINPUTDATA)(void *pclass,uint8_t *buf,int buflen); typedef int (*FUN_PUTOUTDATA)(void *pclass,int buflen); typedef int (*FUN_STOPCALLED)(void *pclass,void*pram); #define DATALINK_IN_BACK(classtype,callfun) static int intput (void* pclass,int buflen) { classtype *pCall = (classtype *)pclass; if(pCall) { return pCall->callfun(buf,buflen); } } #define DATALINK_OUT_BACK(classtype,callfun) static int output (void* pclass,buflen); } } #define DATALINK_STOP_BACK(classtype,callfun) static int stop (void* pclass,void *pram) { classtype *pCall = (classtype *)pclass; if(pCall) { return pCall->callfun(buf,buflen); } } class CDataLinkup { public: CDataLinkup(int maxframelen,int fixreadlen); ~CDataLinkup(); void setDataInputCallback(void *pclass,FUN_GETINPUTDATA input); void setDataOutputCallback(void *pclass,FUN_PUTOUTDATA output); void setDataMark(uint8_t *mark,int marklen); void start(); void stop(); void setStopCallback(void *pclass,FUN_STOPCALLED stopcallback); void *workThread(void *pParam); private: inline bool checkHead(uint8_t *buffer,int offset); inline int findHead(uint8_t *buffer,int offset,int len); void initBuffer(int *mNaluOld,int* mNaluNew,int *readOffsetOld,int*readOffsetCur); int getData(int offset); private: FUN_GETINPUTDATA fun_getInputData; FUN_PUTOUTDATA fun_putOutData; FUN_STOPCALLED fun_stopcalled; void *pclassInput; void *pclassOut; void *pclassStop; uint8_t *mBuffer; uint8_t *mMark; uint8_t *mBuffadd; int mBufferlen; int mMarklen; int mBuffaddlen; int mBuffadddatalen; int mfixreadlen;//每次输入数据长度 bool mbrun; }; static void *ThreadBody(void *pdat) { CDataLinkup *pDatalink = (CDataLinkup *)pdat; if(pDatalink) { pDatalink->workThread(NULL); } return NULL; } inline bool CDataLinkup::checkHead(uint8_t *buffer,int offset) { if(NULL == mMark) { ERRO_INFO("erro !please setMark firstlyn"); return 0; } return !memcmp(buffer+offset,mMark,mMarklen); } inline int CDataLinkup::findHead(uint8_t *buffer,int len) { int i; if (len < mMarklen) { DEBUG("too short len %d n",len); return 0; } int maxoffset = offset+len; //DEBUG("len %d %dn",len,maxoffset); for (i = offset; i <= maxoffset - mMarklen; i++) { if (checkHead(buffer,i)){ return i; } } return 0; } CDataLinkup::CDataLinkup(int maxframelen,int fixreadlen) { fun_getInputData = NULL; fun_putOutData = NULL; fun_stopcalled = NULL; mbrun = false; mBufferlen = maxframelen*8;//最长帧内容倍数 mMarklen = 0; mBuffaddlen = fixreadlen; mfixreadlen = fixreadlen; mMark = NULL; mBuffer = (uint8_t*)malloc(mBufferlen); mBuffadd = (uint8_t*)malloc(mBuffaddlen); if(NULL == mBuffer || NULL == mBuffadd) { ERRO_INFO("erro to malloc! mBufferlen %d,mBuffaddlen,%dn",mBufferlen,mBuffaddlen); } memset(mBuffer,mBufferlen); memset(mBuffadd,mBuffaddlen); } CDataLinkup::~CDataLinkup() { if(mBuffer) { free(mBuffer); } } void CDataLinkup::setDataMark(uint8_t *mark,int marklen) { if(NULL==mark) { ERRO_INFO("parm erro n"); return ; } if(mMark) { free(mMark); } mMark = (uint8_t*)malloc(marklen); if(NULL == mMark) { ERRO_INFO("malloc erro marklen :%dn",marklen); } memcpy(mMark,mark,marklen); mMarklen = marklen; }; void CDataLinkup::setDataInputCallback(void *pclass,FUN_GETINPUTDATA input) { pclassInput = pclass; fun_getInputData = input; } void CDataLinkup::setDataOutputCallback(void *pclass,FUN_PUTOUTDATA output) { pclassOut = pclass; fun_putOutData = output; } void CDataLinkup::setStopCallback(void *pclass,FUN_STOPCALLED stopcallback) { pclassStop = pclass; fun_stopcalled = stopcallback; } void CDataLinkup::start() { if(fun_getInputData == NULL || fun_putOutData == NULL || mMark == NULL) { DEBUG("erro to start,please check init!"); return ; } mbrun = true; int iRet; pthread_t pid; //iRet = pthread_create(&pid,NULL,(void* (*)(void*))&CDataLinkup::workThread,0); iRet = pthread_create(&pid,ThreadBody,this); if (iRet != 0) { printf("[%d %s]pthread_create failed (%d)n",__LINE__,iRet); } else { pthread_detach(pid); } } void CDataLinkup::stop() {//加锁等待完全退出才返回 mbrun = false; } void CDataLinkup::initBuffer(int *mNaluOld,int*readOffsetCur) { int naulflag =0; int datalen =0; while(naulflag<=0) { int ret = getData(datalen); if(ret > 0) { datalen +=ret; naulflag = findHead(mBuffer,datalen); } else { break; } } *mNaluOld= naulflag; *readOffsetOld = datalen; *readOffsetCur = *readOffsetOld; DEBUG("init %d %d n",*readOffsetCur,*readOffsetOld); } //调用输入接口读取固定长度数据到mBuffer缓冲区 //如果缓冲区已经溢出,溢出部分数据会被存储在mBuffadd 特定位置,且mBuffadddatalen被设置 int CDataLinkup::getData(int offset) { int fixreadlen = mfixreadlen; int remainlen = mBufferlen- offset; int copylen = remainlen int ret = 0; if(copylen < fixreadlen) { ret = fun_getInputData(pclassInput,mBuffadd,fixreadlen); if(ret < fixreadlen) { mbrun = false; DEBUG("getinput %d fixreadlen %dn",ret,fixreadlen); return 0; } //DEBUG("full !n"); memcpy(mBuffer+offset,copylen); mBuffadddatalen = fixreadlen - copylen; } else { //DEBUG("offset %d n",offset); ret = fun_getInputData(pclassInput,mBuffer+offset,fixreadlen); return 0; } mBuffadddatalen = 0; } return copylen; } void *CDataLinkup::workThread(void *pParam) { int mNaluOld = 0; int mNaluNew =0; int readOffsetOld = 0; int readOffsetCur =0; bool bFirst = true; bool bFull = false;//是否溢出 int checkbaklen = 2 * (mMarklen-1); uint8_t *checkbak = (uint8_t*)malloc(checkbaklen); uint8_t *framebuffer = mBuffer; int readdata = 0; if(framebuffer == NULL) { ERRO_INFO("erro,mBuffer NULL n"); return NULL; } while(mbrun) { //usleep(100);// if (bFirst) { initBuffer(&mNaluOld,&mNaluNew,&readOffsetOld,&readOffsetCur); bFirst =false; } //printf("wang %d %s readOffsetOld %d n",readOffsetOld); if(!bFull) { readdata = getData(readOffsetOld); if(readdata == 0) { mbrun = false; DEBUG("getdata erron"); break; } readOffsetCur += readdata; } // 从帧缓冲中找 h264 NALU 开始标记 if (bFull) { // 已经溢出,数据不连续,跨断 memcpy(checkbak+mMarklen-1,framebuffer,mMarklen-1); //uint8_t temp[4]={0x0,0x0,0x01}; //memcpy(checkbak,temp,checkbaklen); //printf("%#x %#x %#x %#x n",checkbak[0],checkbak[1],checkbak[2],checkbak[3]); //printf("%#x %#x %#x n",mMark[0],mMark[1],mMark[2]); mNaluNew = findHead(checkbak,checkbaklen); if(mNaluNew >0 ) { mNaluNew+=mBufferlen-mMarklen-1; fun_putOutData(pclassOut,framebuffer+mNaluOld,mNaluNew-mNaluOld); DEBUG("specificn"); mNaluOld = mNaluNew; } { mNaluNew = findHead(framebuffer,readOffsetOld); while(!mNaluNew) { readdata = getData(readOffsetOld); if(readdata == 0) { mbrun = false; DEBUG("getdata erron"); break; } readOffsetCur += readdata; mNaluNew = findHead(framebuffer,readOffsetOld-(mMarklen-1),readOffsetCur - readOffsetOld); readOffsetOld = readOffsetCur; } } int olddatalen = mBufferlen - mNaluOld; // //找到一完整帧,输出 uint8_t *ptemp =(uint8_t*)malloc(olddatalen+mNaluNew); memset(ptemp,olddatalen+mNaluNew); if(ptemp == NULL) { //printf("wang %d %s malloc fialed len :%d n",olddatalen+mNaluNew); return NULL; } memcpy(ptemp,olddatalen); memcpy(ptemp+olddatalen,mNaluNew); fun_putOutData(pclassOut,ptemp,olddatalen+mNaluNew); free(ptemp); bFull = false; mNaluOld = mNaluNew; } else { //TRACK("readOffsetOld %d readOffsetcur %dn",readOffsetOld,readOffsetCur); mNaluNew = findHead(framebuffer,readOffsetCur - readOffsetOld); if (mNaluNew > 0) { // //找到一完整帧,输出 int framelen = mNaluNew - mNaluOld; fun_putOutData(pclassOut,framelen); mNaluOld = mNaluNew; } if(readOffsetCur >= mBufferlen) { // 已经溢出,需要拿新的数据 readOffsetCur = 0; readOffsetOld = 0; bFull = true; if(mBuffadddatalen>0) {//溢出的数据拷贝回来 memcpy(framebuffer,mBuffadd+(mfixreadlen-mBuffadddatalen),mBuffadddatalen); readOffsetCur = mBuffadddatalen; //fun_putOutData(pclassOut,mBuffadddatalen); //break; } else { readdata = getData(readOffsetOld); if(readdata == 0) { mbrun = false; DEBUG("getdata erron"); break; } readOffsetCur += readdata; } readOffsetOld = readOffsetCur; // 避免出现跨端区的NALL漏检 memcpy(checkbak,framebuffer+mBufferlen-(mMarklen-1),mMarklen-1); } else { readOffsetOld = readOffsetCur; } } } free(checkbak); if(fun_stopcalled) { fun_stopcalled(pclassStop,NULL); } return NULL; } class CTest { public : CTest(const char*fin,const char*fout); ~CTest(); int readdata(uint8_t * buf,int buflen); int putdata(uint8_t * buf,int buflen); void* init(); DATALINK_IN_BACK(CTest,readdata); DATALINK_OUT_BACK(CTest,putdata); /* static int intput (void* pclass,int buflen) { CTest *pCall= (CTest *)pclass; //DEBUG("pclass %pn",pclass); if(pCall) { return pCall->readdata(buf,buflen); } } static int output (void* pclass,int buflen) { CTest *pCall= (CTest *)pclass; if(pCall) { return pCall->putdata(buf,buflen); } }*/ private: FILE *mfpin; FILE *mfpout; CDataLinkup *datalink; }; /* int CTest::intput (void* pclass,buflen); } return 0; } int CTest::output(void* pclass,buflen); } }*/ CTest::CTest(const char*fin,const char*fout) { mfpin= fopen(fin,"rb"); mfpout = fopen(fout,"w+"); if(mfpin == NULL || mfpout == NULL) { ERRO_INFO("fopen erro n"); } } CTest::~CTest() { if(mfpin) { fclose(mfpin); } if(mfpout) { fclose(mfpout); } } void* CTest::init() { uint8_t mark[3]={0x0,0x01}; datalink = new CDataLinkup(200*1024,1024*80); datalink->setDataInputCallback(this,intput); datalink->setDataOutputCallback(this,output); datalink->setDataMark(mark,sizeof(mark)); datalink->start(); return this; } int CTest::readdata(uint8_t * buf,int buflen) { int ret = fread(buf,1,buflen,mfpin); DEBUG("input %dn",ret); return ret; } int CTest::putdata(uint8_t * buf,int buflen) { int ret = fwrite(buf,mfpout); DEBUG("output %d buflen %dn",buflen); return ret; } #if 0 //for c FILE*fpin = NULL; FILE*fpout = NULL; uint8_t count =0; int maxlen =0; int datainput(void * pclass,uint8_t * buf,fpin); //DEBUG("input %dn",ret); return ret; } int dataoutput(void * pclass,int buflen) { count ++; if(buflen >maxlen) { maxlen = buflen; } fwrite(&count,fpout); int ret = fwrite(buf,fpout); DEBUG("output %d buflen %dn",buflen); return ret; } int fileclose(void * pclass,void *pram) { DEBUG("over maxlen %d n",maxlen); fclose(fpin); fclose(fpout); } int main(int argc,const char* argv[]) { if(argc != 3){ printf("usage :input file,output file!n"); return -1; } fpin = fopen(argv[1],"rb"); fpout = fopen(argv[2],"w+"); if(fpin == NULL || fpout == NULL){ printf("fopen erro n"); return -1; } uint8_t mark[3]={0x0,0x01}; CDataLinkup *datalink = new CDataLinkup(200*1024,1024*80); datalink->setDataInputCallback(NULL,datainput); datalink->setDataOutputCallback(NULL,dataoutput); datalink->setDataMark(mark,sizeof(mark)); datalink->setStopCallback(NULL,fileclose); datalink->start(); //while(1); //主线程退出,如果直接return则会导致调用eixt把整个进程结束 pthread_exit(NULL); } #endif #if 1//for c++ int main(int argc,output file!n"); return -1; } CTest *pTest = new CTest(argv[1],argv[2]); pTest->init(); pthread_exit(NULL); //一定要在pthread_exit之后,保证回调里面调用时这个pTest对象还存在 delete pTest; } #endif (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |