网络数据包片段拼合(连续h264片段拼接成完整h264 slice)(三)循环体移到外部调用,便于调用者控制

6 篇文章 0 订阅

继上一篇的优化改进,将主控制权交给外部调用者。

代码:

/***
***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

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值