最近项目用的网络摄像头,从网络层获取到连续的h264片段数据,于是写了一个将连续输入数据按 指定字符串分割成一个slice数据的 class, 稍作改动,也可以用来处理 文本文件中查找 替换等等功能,或者从一个h264文件中分离出单独的h264帧

linux 环境 ubunt 上已测试,编译:g++ *.cpp -lpthread

用到了回调,但是没有处理C++成员函数作为回调问题,后续改良

2.0 (连续h264片段拼接成完整h264帧)(二)支持c++调用  (纠正下,是拼接或分离出h264slice)

https://blog.csdn.net/u012459903/article/details/85263959

3.0(连续h264片段拼接成完整h264帧)(三)循环体移到外部调用,便于调用者控制 (纠正下,是拼接或分离出h264slice)

https://blog.csdn.net/u012459903/article/details/85263959

4.0 c++ 回调(还可继续修改为c++风格常见的虚函数)

https://blog.csdn.net/u012459903/article/details/86623018

代码:

/***
***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)
#define DEBUG(fmt, args...)     do {printf("[%s,%s,%d]",__FILE__,__FUNCTION__,__LINE__);printf(fmt,##args);} while(0)
class CDataLinkup
{public:CDataLinkup(int maxframelen,int fixreadlen);~CDataLinkup();void setDataInputCallback(int (*input)(uint8_t *buf,int buflen));void setDataOutputCallback(int (*output)(uint8_t *buf,int buflen));void setDataMark(uint8_t *mark, int marklen);void start();void stop();void setStopCallback(int(*stopcallback)(void*pram));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:int (*fun_getInputData)(uint8_t *buf,int buflen);int (*fun_putOutData)(uint8_t *buf,int buflen);int (*fun_stopcalled)(void*pram);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);}
}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 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,%d\n",mBufferlen,mBuffaddlen);}memset(mBuffer,0,mBufferlen);memset(mBuffadd,0,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 :%d\n",marklen);}memcpy(mMark,mark,marklen);mMarklen = marklen;
}void CDataLinkup::setDataInputCallback(int (*input)(uint8_t *buf,int buflen))
{fun_getInputData = input;
}void CDataLinkup::setDataOutputCallback(int (*output)(uint8_t *buf,int buflen))
{fun_putOutData = output;
}
void CDataLinkup::setStopCallback(int (*stopcallback)(void*pram))
{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, NULL, ThreadBody, this);if (iRet != 0){printf("[%d %s]pthread_create   failed (%d)\n",__LINE__, __FUNCTION__, iRet);}else{pthread_detach(pid);}
}void CDataLinkup::stop()
{//加锁等待完全退出才返回mbrun = false;
}void CDataLinkup::initBuffer(int *mNaluOld,int* mNaluNew,int *readOffsetOld,int*readOffsetCur)
{int naulflag =0;int datalen =0;while(naulflag<=0){int ret = getData(datalen);if(ret >=0){datalen +=ret;naulflag = findHead(mBuffer, 0, 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<fixreadlen?remainlen:fixreadlen;int ret = 0;if(copylen < fixreadlen){ret = fun_getInputData(mBuffadd,fixreadlen);if(ret < fixreadlen){mbrun = false;DEBUG("getinput %d fixreadlen %d\n",ret,fixreadlen);return 0;}//DEBUG("full !\n");memcpy(mBuffer+offset,mBuffadd,copylen);mBuffadddatalen = fixreadlen - copylen;}else {  //DEBUG("offset %d \n",offset);ret = fun_getInputData(mBuffer+offset,fixreadlen);if(ret < fixreadlen){mbrun = false;DEBUG("getinput %d fixreadlen %d\n",ret,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",__LINE__,__FUNCTION__,readOffsetOld);if(!bFull){readdata =  getData(readOffsetOld);if(readdata == 0){mbrun = false;DEBUG("getdata erro\n");break;}readOffsetCur += readdata;}// 从帧缓冲中找 h264 NALU 开始标记if (bFull) {   // 已经溢出,数据不连续, 跨断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]);mNaluNew = findHead(checkbak, 0, checkbaklen);if(mNaluNew >0 ){mNaluNew+=mBufferlen-mMarklen-1;fun_putOutData(framebuffer+mNaluOld,mNaluNew-mNaluOld);DEBUG("specific\n");mNaluOld = mNaluNew;}{   mNaluNew = findHead(framebuffer, 0, readOffsetOld);while(!mNaluNew){readdata =  getData(readOffsetOld);if(readdata == 0){mbrun = false;DEBUG("getdata erro\n");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,0,olddatalen+mNaluNew);if(ptemp == NULL){//printf("wang %d %s malloc fialed len :%d \n",__LINE__,__FUNCTION__,olddatalen+mNaluNew);return NULL;}memcpy(ptemp,framebuffer+mNaluOld,olddatalen);memcpy(ptemp+olddatalen,framebuffer,mNaluNew);fun_putOutData(ptemp,olddatalen+mNaluNew);free(ptemp);bFull = false;mNaluOld = mNaluNew;}else {//TRACK("readOffsetOld %d readOffsetcur %d\n",readOffsetOld,readOffsetCur);mNaluNew = findHead(framebuffer, readOffsetOld-(mMarklen-1), readOffsetCur - readOffsetOld);if (mNaluNew > 0) {// //找到一完整帧,输出int framelen = mNaluNew - mNaluOld;fun_putOutData(framebuffer+mNaluOld,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(framebuffer,mBuffadddatalen);//break;}else{readdata =  getData(readOffsetOld);if(readdata == 0){mbrun = false;DEBUG("getdata erro\n");break;}readOffsetCur += readdata;}readOffsetOld = readOffsetCur;// 避免出现跨端区的NALL漏检memcpy(checkbak,framebuffer+mBufferlen-(mMarklen-1),mMarklen-1);}else{readOffsetOld = readOffsetCur;}}}free(checkbak);if(fun_stopcalled){fun_stopcalled(NULL);}}#if 1
FILE*fpin = NULL;
FILE*fpout = NULL;
uint8_t count  =0;
int maxlen =0;
int datainput(uint8_t * buf,int buflen)
{int ret = fread(buf,1,buflen,fpin);//DEBUG("input  %d\n",ret);return ret;
}int dataoutput(uint8_t * buf,int buflen)
{count ++;if(buflen >maxlen){maxlen = buflen;}fwrite(&count,1,1,fpout);int ret = fwrite(buf,1,buflen,fpout);DEBUG("output  %d buflen %d\n",ret,buflen);return ret;
}
int fileclose(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,0x0,0x01};CDataLinkup *datalink = new CDataLinkup(200*1024,1024*80);datalink->setDataInputCallback(datainput);datalink->setDataOutputCallback(dataoutput);datalink->setDataMark(mark,sizeof(mark));datalink->setStopCallback(fileclose);datalink->start();//while(1);//主线程退出, 如果直接return则会导致调用eixt把整个进程结束pthread_exit(NULL);
}
#endif

网络数据包片段拼合(连续h264片段拼接成完整h264帧)--纠正下,是h264 slice,不是图像帧相关推荐

  1. Packet Chasing:通过缓存侧信道监视网络数据包

    摘要 本文介绍了一种对网络的攻击–Packet Chasing,这种攻击不需要访问网络,无论接收数据包的进程的特权级别如何,都能发挥作用.一个间谍进程可以很容易地探测和发现网络驱动程序使用的每个缓冲区 ...

  2. linux接收网络数据并存存储,linux网络数据包数据结构 Socket Buffer

    Linux网络核心数据结构是套接字缓存(socket buffer),简称skb.它代表一个要发送或处理的报文,并贯穿于整个协议栈.1.套接字缓存skb由两部分组成:(1)报文数据:它保存了实际在网络 ...

  3. tcpdump 网络数据包分析工具

    简介 用简单的话来定义tcpdump,就是:dump the traffic on a network,根据使用者的定义对网络上的数据包进行截获的包分析工具. tcpdump可以将网络中传送的数据包的 ...

  4. 【php毕业设计】基于php+mysql+apache的网络数据包分析工具设计与实现(毕业论文+程序源码)——网络数据包分析工具

    基于php+mysql+apache的网络数据包分析工具设计与实现(毕业论文+程序源码) 大家好,今天给大家介绍基于php+mysql+apache的网络数据包分析工具设计与实现,文章末尾附有本毕业设 ...

  5. 常用网络数据包丢失的分析与处理

    网络管理维护过程中,经常会遇到数据包丢失的情况.用Ping命令进行连接测试,会发现Ping包的延迟远远超过正常值,甚至无法到达,同时伴随着网络服务应用的障碍,比如打开网站的速度太慢,严重时甚至无法打开 ...

  6. Jpcap JAVA捕捉并分析网络数据包

    读书时候,曾经做过一个sniffer软件.主要的开发语言是JAVA.主要的作用有很多,但是我个人测试的效果估计要比臭名远扬的绿坝要好了.主要的设计不是用于控制人家上网,这个软件业做技术统计,主要是用来 ...

  7. 网络数据包分析软件Wireshark简介

    Wireshark是被广泛使用的免费开源的网络协议分析软件(network protocol analyzer)或网络数据包分析软件,它可以让你在微观层面上查看网络上发生的事情,它的功能是截取网络数据 ...

  8. 一个最简单的通过WireShark破解SSL加密网络数据包的方法

    原文地址: http://article.yeeyan.org/view/530101/444688 一般来说,我们用WireShark来抓取包进行分析是没有多大问题的.但这里有个问题是,如果你碰到的 ...

  9. Linux内核中网络数据包的接收-第一部分 概念和框架

    与网络数据包的发送不同,网络收包是异步的的.由于你不确定谁会在什么时候突然发一个网络包给你.因此这个网络收包逻辑事实上包括两件事: 1.数据包到来后的通知 2.收到通知并从数据包中获取数据这两件事发生 ...

最新文章

  1. java final
  2. Leetcode 8. 字符串转换整数 (atoi) (每日一题 20210615)
  3. python参数顺序 元组 字典_python学习之元组列表字典操作
  4. qt窗口左上角坐标变动函数使用中的误区
  5. 数据结构二叉树遍历求后序
  6. mysql 5.7.17 64位_Windows(x86,64bit)升级MySQL 5.7.17免安装版的详细教程
  7. verilog系统任务之$random
  8. 4分钟看尽Top编程语言15年沉浮:C#默Java泪,Python终上位!
  9. 使PNG图片在IE6下透明(非背景图片)
  10. z-index无效解决
  11. Ajax学习笔记-错误的处理-7
  12. 数据分析职位需求分析报告-数据来源于Boss直聘网站
  13. 【终极】文件夹隐藏方法,彻底隐藏文件夹的方法!显示隐藏的文件也看不到
  14. 学生信息管理系统可行性研究报告
  15. _itemmod_extract_enchant随机附魔提取
  16. 51单片机控制双步进电机的魔法师思想
  17. IAR for 430 如何建一个简易工程
  18. java 修改Excel表 在指定位置插入行列
  19. 瑞典皇工学院计算机,瑞典规模最大的理工院校,皇家理工学院
  20. Python版 孤勇者 | 画图+演奏+音乐可视化

热门文章

  1. 同一个Maven项目移机出错解决办法
  2. Unity学习笔记:监听函数有什么卵用?(似乎就是从一件事过渡到另一件事?)
  3. 人机融合很难,恰当的人机分离更难
  4. 几种常用RAID的特性
  5. MVP??你配吗??
  6. logrotate测试_logrotate 日志管理
  7. (附源码)springboot员工管理系统 毕业设计 021430
  8. 王佩丰excel学习笔记(二):第三——六讲
  9. Tableau 消费客户分析(二)分群规模和消费
  10. Windows 10任务栏中托盘区(通知区域)图标怎么缩略成^