继上一篇的优化改进,将主控制权交给外部调用者。
代码:
/***
***20181221 canok
*** brief : Combine data fragments into complete frames
*** input : Continuous data flow, support fix length data input;
*** output: complete frames
**/
#include<stdio.h>
#include<stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <pthread.h>
typedef unsigned char uint8_t; //无符号8位数
#define ERRO_INFO(fmt, args...) do {printf("[%s,%s,%d]",__FILE__,__FUNCTION__,__LINE__);printf(fmt,##args);} while(0)
#if 0
#define DEBUG(fmt, args...) do {printf("[%s,%s,%d]",__FILE__,__FUNCTION__,__LINE__);printf(fmt,##args);} while(0)
#else
#define DEBUG(fmt, args...)
#endif
typedef int (*FUN_GETINPUTDATA)(void *pclass,uint8_t *buf,int buflen);
typedef int (*FUN_PUTOUTDATA)(void *pclass,uint8_t *buf,int buflen);
#define DATALINK_IN_BACK(classtype,callfun) static int intput (void* pclass ,uint8_t *buf,int buflen)\
{ \
classtype *pCall = (classtype *)pclass; \
if(pCall) \
{ \
return pCall->callfun(buf,buflen); \
} \
}
#define DATALINK_OUT_BACK(classtype,callfun) static int output (void* pclass ,uint8_t *buf,int buflen)\
{ \
classtype *pCall = (classtype *)pclass; \
if(pCall) \
{ \
return pCall->callfun(buf,buflen); \
} \
}
#define MAX(a,b) (a)>(b)?(a):(b)
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 ClearBuffer();
int pushData(int buflen);
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,int len);
private:
FUN_GETINPUTDATA fun_getInputData;
FUN_PUTOUTDATA fun_putOutData;
void *pclassInput;
void *pclassOut;
uint8_t *mBuffer;
uint8_t *mMark;
uint8_t *mBuffInputadd;
uint8_t *mBuffOutadd;
int mBufferlen;
int mMarklen;
int mBuffaddlen;
int mBuffadddatalen;
int mBuffOutlen;
int mNalu;
int readOffset;
bool bFirst ;
bool bFull ;//是否溢出
int checkbaklen ;
uint8_t *checkbak;
};
inline bool CDataLinkup::checkHead(uint8_t *buffer, int offset)
{
if(NULL == mMark)
{
ERRO_INFO("erro !please setMark firstly\n");
return 0;
}
return !memcmp(buffer+offset,mMark,mMarklen);
}
inline int CDataLinkup::findHead(uint8_t *buffer, int offset, int len)
{
int i;
if (len < mMarklen) {
DEBUG("too short len %d \n",len);
return 0;
}
int maxoffset = offset+len;
//DEBUG("len %d %d\n",len,maxoffset);
for (i = offset; i <= maxoffset - mMarklen; i++) {
if (checkHead(buffer, i)){
return i;
}
}
return 0;
}
CDataLinkup::CDataLinkup(int maxframelen,int maxreadlen)
{
fun_getInputData = NULL;
fun_putOutData = NULL;
mBufferlen = maxframelen*8;//最长帧内容倍数
mMarklen = 0;
mBuffaddlen = maxreadlen;
mBuffOutlen = maxframelen;
mMark = NULL;
mBuffer = (uint8_t*)malloc(mBufferlen);
mBuffInputadd = (uint8_t*)malloc(mBuffaddlen);
mBuffOutadd = (uint8_t*)malloc(mBuffOutlen);
if(NULL == mBuffer || NULL == mBuffInputadd || NULL == mBuffOutadd)
{
ERRO_INFO("erro to malloc! mBufferlen %d,mBuffaddlen,%d, mBuffOutlen %d \n",mBufferlen,mBuffaddlen,mBuffOutlen);
}
memset(mBuffer,0,mBufferlen);
memset(mBuffInputadd,0,mBuffaddlen);
memset(mBuffOutadd,0,mBuffOutlen);
}
CDataLinkup::~CDataLinkup()
{
if(mBuffer)
{
free(mBuffer);
}
if(mBuffInputadd)
{
free(mBuffInputadd);
}
if(mMark)
{
free(mMark);
}
if(mBuffOutadd)
{
free(mBuffOutadd);
}
}
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 :%d\n",marklen);
}
memcpy(mMark,mark,marklen);
mMarklen = marklen;
checkbaklen = 2 * (mMarklen-1);
checkbak = (uint8_t*)malloc(checkbaklen);
if(checkbak == mMark)
{
ERRO_INFO("malloc erro marklen :%d\n",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;
}
//调用输入接口读取指定长度数据到mBuffer缓冲区
//如果缓冲区已经溢出,溢出部分数据会被存储在mBuffInputadd 特定位置,且mBuffadddatalen被设置
int CDataLinkup::getData(int offset,int len)
{
int remainlen = mBufferlen- offset;
int copylen = remainlen<len?remainlen:len;
int ret = 0;
if(copylen < len)
{
if(len>mBuffaddlen)
{
ERRO_INFO("input too large !lost data len:%d,mBuffaddlen:%d \n ",len,mBuffaddlen);
}
ret = fun_getInputData(pclassInput,mBuffInputadd,len);
if(ret < len)
{
//mbrun = false;
DEBUG("getinput %d len %d\n",ret,len);
return 0;
}
//DEBUG("full !\n");
memcpy(mBuffer+offset,mBuffInputadd,copylen);
mBuffadddatalen = len - copylen;
}
else
{
//DEBUG("offset %d \n",offset);
ret = fun_getInputData(pclassInput,mBuffer+offset,len);
if(ret < len)
{
//mbrun = false;
DEBUG("getinput %d len %d\n",ret,len);
return 0;
}
mBuffadddatalen = 0;
}
return copylen;
}
void CDataLinkup::ClearBuffer()
{
mNalu =0;
mNalu =0;
readOffset =0;
bFirst = true;
bFull = false;//是否溢出
}
int CDataLinkup::pushData(int buflen)
{
uint8_t *framebuffer = mBuffer;
int ret = getData(readOffset,buflen);
if(ret == 0)
{
DEBUG("getData erro!\n");
return -1;
}
if (bFirst)
{
int naulflag = findHead(mBuffer,MAX(readOffset-(mMarklen-1),0), ret);
if(naulflag>0)
{
bFirst = false;
mNalu= naulflag;
}
readOffset +=ret;
}
else
{
if(!bFull)
{
int naulflag = findHead(framebuffer, readOffset-(mMarklen-1), ret);
if (naulflag > 0)
{
// //找到一完整帧,输出
int framelen = naulflag - mNalu;
fun_putOutData(pclassOut,framebuffer+mNalu,framelen);
mNalu = naulflag;
}
if(mBuffadddatalen>0)
{// 溢出
bFull = true;
//溢出的数据拷贝回来
memcpy(framebuffer,mBuffInputadd+ret,mBuffadddatalen);
readOffset= mBuffadddatalen;
// 避免出现跨端区的NALL漏检
memcpy(checkbak,framebuffer+mBufferlen-(mMarklen-1),mMarklen-1);
}
else
{
readOffset += ret;
}
}
else
{// 上次溢出,数据不连续, 跨断
memcpy(checkbak+mMarklen-1,framebuffer,mMarklen-1);
//uint8_t temp[4]={0x0,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]);
int naulflag = findHead(checkbak, 0, checkbaklen);
if(naulflag >0 )
{
naulflag+=mBufferlen-mMarklen-1;
fun_putOutData(pclassOut,framebuffer+mNalu,naulflag-mNalu);
DEBUG("specific\n");
mNalu = naulflag;
}
naulflag = findHead(framebuffer, 0, readOffset+ret);
if(naulflag>0)
{
int olddatalen = mBufferlen - mNalu;
// //找到一完整帧,输出
if(naulflag+olddatalen>mBuffOutlen)
{
ERRO_INFO("maxframlen too short mBuffOutlen %d\n",mBuffOutlen);
}
memcpy(mBuffOutadd,framebuffer+mNalu,olddatalen);
memcpy(mBuffOutadd+olddatalen,framebuffer,naulflag);
fun_putOutData(pclassOut,mBuffOutadd,olddatalen+naulflag);
bFull = false;
mNalu = naulflag;
}
readOffset += ret;
}
}
return ret;
}
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* work();
DATALINK_IN_BACK(CTest,readdata);
DATALINK_OUT_BACK(CTest,putdata);
/*
static int intput (void* pclass ,uint8_t *buf,int buflen)
{
CTest *pCall= (CTest *)pclass;
//DEBUG("pclass %p\n",pclass);
if(pCall)
{
return pCall->readdata(buf,buflen);
}
}
static int output (void* pclass ,uint8_t *buf,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 ,uint8_t *buf,int buflen)
{
CTest *pCall= (CTest *)pclass;
//DEBUG("pclass %p\n",pclass);
if(pCall)
{
return pCall->readdata(buf,buflen);
}
return 0;
}
int CTest::output(void* pclass ,uint8_t *buf,int buflen)
{
CTest *pCall= (CTest *)pclass;
if(pCall)
{
return pCall->putdata(buf,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::work()
{
uint8_t mark[3]={0x0,0x0,0x01};
datalink = new CDataLinkup(200*1024,1024*80);
datalink->setDataInputCallback(this,intput);
datalink->setDataOutputCallback(this,output);
datalink->setDataMark(mark,sizeof(mark));
datalink->ClearBuffer();
while(datalink->pushData(1046) != -1);
delete datalink;
datalink = NULL;
return this;
}
int CTest::readdata(uint8_t * buf,int buflen)
{
int ret = fread(buf,1,buflen,mfpin);
DEBUG("input %d\n",ret);
return ret;
}
int CTest::putdata(uint8_t * buf,int buflen)
{
int ret = fwrite(buf,1,buflen,mfpout);
DEBUG("output %d buflen %d\n",ret,buflen);
return ret;
}
#if 1//for c++
int main(int argc, const char* argv[])
{
if(argc != 3){
printf("usage :input file, output file!\n");
return -1;
}
CTest *pTest = new CTest(argv[1],argv[2]);
pTest->work();
pthread_exit(NULL);
//一定要在pthread_exit之后,保证回调里面调用时这个pTest对象还存在
delete pTest;
}
#endif