基于内存缓冲区的流媒体数据缓存排序(二)
2015-01-07 21:06
78 查看
C++ 实验
基于内存缓冲区的流媒体数据缓存排序(二)
要求:
①针对一个流媒体节目的单线程下载进行处理;②节目数据包无丢失、有乱序,假设乱序范围不超过10个数据包;
③将收到的数据包直接写入缓冲区,缓冲区长度无限定;
④排好序的数据如果超过一定长度,如30KB(可设定),则输出到文件;
实现要求
缓冲区类
定义基于动态内存分配的缓冲区类,包括如下数据成员:
•缓冲区,用于缓存数据(按偏移量写入,完成排序);
•记录缓冲区内收到的数据总量;
•缓冲区中数据在节目(文件)中的偏移量(缺了这项信息,无法写入文件);
•其他必要信息。
成员函数:
•构造函数、析构函数
•数据接收函数
•数据输出函数
测试程序
模拟网络流媒体的数据流到达:•设定数据来源多媒体文件(本地磁盘);
•从多媒体文件读取一块数据(长度不超多1500B),模拟网络数据包;
•模拟的网络数据包:包括节目ID、数据包偏移量、数据包长度;
•将数据包发送给排序缓存类。
•将文件的所有数据按上述方式读入并发送给排序缓存类
•最好用类实现(不要求)
提示:用随机数生成每个数据包的长度:256~1500 Bytes
</pre><pre name="code" class="cpp">/*StreamBuffer.h*/ #include <iostream> #include <cstdio> #include <cstdlib> #include <ctime> using namespace std; class StreamBuffer { public: StreamBuffer(); StreamBuffer(int iLen); int ReceiveData(unsigned int offset, unsigned int bytes, char *pData); //接收数据包。 int ContinueBytes(unsigned int &iDataOffset, char* &pData); //统计缓冲区中排好序的数据的信息。 int RemoveData(int iBytes); //释放缓冲区。 ~StreamBuffer(); private: char m_pData[30*1500]; //存数据的buffer,也可以用指针。 unsigned int m_PacketOffset[20]; //存传入数据包的偏移量。 unsigned int m_PacketBytes[20]; //存传入数据包的数据量(长度)。 char m_PacketData[20][1500]; //存传入数据包的数据。 int inPacketOffset; //写入缓冲区的数据的偏移量(标记下次位置)。 int m_iPacketsNum; //存储数据包的数组下标(每20个一循环)。 int outPackerOffset; // 缓冲区中排好序的数据块中第一个字节的偏移量数值. int m_iBufferLen; //缓冲区中排好序的数据的字节数(长度)。 };
/*StreamBuffer.cpp*/ #include <iostream> #include <cstdio> #include <cstdlib> #include <cmath> #include "StreamBuffer.h" using namespace std; StreamBuffer::StreamBuffer() { m_iBufferLen = 0; m_iPacketsNum = 0; <span style="white-space:pre"> </span>m_iBufferLen = 0; <span style="white-space:pre"> </span>outPackerOffset = 0; <span style="white-space:pre"> </span>inPacketOffset = 0; } StreamBuffer::StreamBuffer(int iLen) { m_iBufferLen = iLen; m_iPacketsNum = iLen; <span style="white-space:pre"> </span>m_iBufferLen = iLen; <span style="white-space:pre"> </span>outPackerOffset = iLen; } int StreamBuffer::ReceiveData(unsigned int offset, unsigned int bytes, char *pData) { int iBytes, i, j; cout << "bytes = " << bytes << endl; m_PacketOffset[m_iPacketsNum] = offset; //记录传入的每个数据包的偏移量。 m_PacketBytes[m_iPacketsNum] = bytes; //记录传入的每个数据包的长度。 // 存储每个数据包的数据。 for(iBytes = 0; iBytes < abs(bytes); iBytes++) { m_PacketData[m_iPacketsNum][iBytes] = *(pData++); } m_iPacketsNum++; //遍历每个数据包的偏移量信息,如果符合排序要求,就进行排序(即写入缓冲区)。 for(i = 0; i < m_iPacketsNum; i++) { if(m_PacketOffset[i] == abs(inPacketOffset)) { inPacketOffset += m_PacketBytes[i]; for(j = 0; j < abs(m_PacketBytes[i]); j++) { m_pData[m_iBufferLen++] = m_PacketData[i][j]; } i = 0; } } if(m_iPacketsNum == 20) //当接收了20个数据包后,清零,开始下一次的接收。 { m_iPacketsNum = 0; } return iBytes; } int StreamBuffer::ContinueBytes(unsigned int &iDataOffset, char* &pData) { //返回缓冲区中,排好序的数据的长度(单位字节数)。并通过引用参数返回如下信息 //iDataOffset: 排好序的数据块中第一个字节的偏移量数值 //pData:数据指针 int iContinueBytes = 0; pData = m_pData; iDataOffset = outPackerOffset; iContinueBytes = m_iBufferLen; return iContinueBytes; } int StreamBuffer::RemoveData(int iBytes) { //从缓冲区中把数据"删除",返回删除的字节数 int iBytesRemoved=0, i; outPackerOffset += iBytes; m_iBufferLen = 100; for(i = 0; i < 100; i++) { m_pData[i] = m_pData[iBytes+i]; } return iBytesRemoved; } StreamBuffer::~StreamBuffer() { if(NULL != m_pData) { delete []m_pData; } }
#include <iostream> #include <cstdio> #include <cstdlib> #include <ctime> #include "StreamBuffer.cpp" using namespace std; void GenDisOrder(int iSendOrder[],int iPacketNum); int main() { //该部分用于打开读写文件。 FILE* fpSrcFile = NULL; FILE* fpDstFile = NULL; char srcfileName[500] = "TestFile//song1.mp3"; char dstfileName[500] = "TestFile//result.mp3"; fpSrcFile = fopen(srcfileName, "rb"); if( fpSrcFile == NULL ) { cout<<"Cann't open file: "<<srcfileName<<endl; return 1; } fpDstFile = fopen(dstfileName, "wb"); if( fpDstFile == NULL ) { cout<<"Cann't create file: "<< dstfileName <<endl; return 2; } const int MTU = 1500; //最大传输单元,网络术语,表示一个数据包大最大尺寸,单位:字节 int iReadBytes = 0; int iWantReadBytes; int iContinueBytes; int iUseBytes; unsigned int iOutDataOffset; char *pOutData; StreamBuffer MyBuffer; //用排序类创建对象。 const int iMaxPacketNum = 20; //每次读入20个数据包,然后以乱序的形式发给排序模块(StreamBuffer类) int iSendOrder[iMaxPacketNum]; //记录下发数据包的顺序 unsigned int iPacketOffset[iMaxPacketNum]; //记录每个数据包中第一个字节数据的偏移量 unsigned int iPacketLen[iMaxPacketNum]; //记录每个数据包中的数据长度 char (*pDataBuf)[MTU]; //数据包缓冲区区。 int iPacketNum; int i; int iPackNo; srand(100);//用固定值初始化,会生成固定的随机数序列,方便测试程序,否则用srand( (unsigned)time( NULL ) ); pDataBuf = new char[iMaxPacketNum][MTU]; iWantReadBytes = 1024; do { iPacketNum = 0; for(i = 0; i < iMaxPacketNum; i++) //初始化数据包长度为0,表示没有读入数据 { iPacketLen[i] = 0; } do { iPacketOffset[iPacketNum] = ftell(fpSrcFile); //获取文件的偏移量。 iReadBytes = fread(pDataBuf[iPacketNum], 1, iWantReadBytes, fpSrcFile); iPacketLen[iPacketNum] = iReadBytes; //当前数据包读取成功,记录数据包长度,否则依旧是0 iWantReadBytes = (iPacketOffset[iPacketNum] + iPacketNum * iPacketNum) % 500 + 400; //下一个数据包读取长度 iPacketNum++; } while((iReadBytes > 0) && (iPacketNum < iMaxPacketNum)); //读入一组数据包,如果文件结束:iReadBytes<1 GenDisOrder(iSendOrder, iMaxPacketNum); //利用函数GenDisOrder对已经产生的20个数据包打乱顺序。 //把刚刚已经读入一组数据包,乱序下发给排序模块 for(i = 0; i < iMaxPacketNum; i++) //只要长度不为0,就发给排序模块 { iPackNo = iSendOrder[i]; if(iPacketLen[iPackNo] > 0)//有数据,给给排序模块 { MyBuffer.ReceiveData(iPacketOffset[iPackNo], iPacketLen[iPackNo], pDataBuf[iPackNo]); iContinueBytes = MyBuffer.ContinueBytes(iOutDataOffset, pOutData); iUseBytes = iContinueBytes - 100; //假设用了一部分 if( iContinueBytes > (20*1024)) //缓冲区数据只要大于20 KB就写入到文件中。 { fseek(fpDstFile, iOutDataOffset, SEEK_SET); fwrite(pOutData, iUseBytes, 1, fpDstFile); MyBuffer.RemoveData(iUseBytes); } } } } while(iReadBytes > 0);//文件还没读取完。 //输入结束,把缓冲区中剩余排好序的数据取出 iContinueBytes = MyBuffer.ContinueBytes(iOutDataOffset, pOutData); if(iContinueBytes > 0) { fseek(fpDstFile, iOutDataOffset, SEEK_SET); fwrite(pOutData, iContinueBytes, 1, fpDstFile); } fclose(fpDstFile); fclose(fpSrcFile); delete []pDataBuf; return 0; } void GenDisOrder(int iSendOrder[], int iPacketNum) { int i, j, k, n, temp; for(i = 0; i < iPacketNum; i++)//先产生顺序的序列:0,1,2,.....iPacketNum-1 { iSendOrder[i] = i; } if(iPacketNum < 5) { return; } n = rand() % (iPacketNum / 5) + 1; //置乱的次数,最多20%*2个数据包 for(i = 0; i < n; i++) { //交换j、k两个数据包的顺序 j = rand() % (iPacketNum / 2) + 1; k = rand() % (iPacketNum - j); temp = iSendOrder[j]; iSendOrder[j] = iSendOrder[k]; iSendOrder[k] = temp; } }
相关文章推荐
- 基于内存缓冲区的流媒体数据缓存排序(一)
- 基于live555的rtsp 客户端模块优化 标签: live555rtsp客户端 2014-11-14 09:24 980人阅读 评论(0) 收藏 举报 分类: 流媒体(16) 版权声明:本文
- delphi中基于内存流压缩和解压多个文件的经验
- 读书笔记-SQL Server 数据页缓冲区的内存瓶颈分析
- FMS3系列(三):创建基于FMS的流媒体播放程序,看山寨帮的山寨传奇
- Android 源码分析之基于NuPlayer的HLS流媒体协议
- 基于C++中常见内存错误的总结
- sybase 内存和缓冲区管理
- 基于mmap/munmap内存共享映射机制
- 缓冲区buffer,字节数组 bytep[] arraysample与内存流memory stream
- 基于DirectShow的流媒体解码和回放
- 最简单的基于Flash的流媒体示例:网页播放器(HTTP,RTMP,HLS)
- 基于8086CPU微处理器的汇编学习之内存空间的编辑
- 基于DSS的先侦听后推送式流媒体转发
- 基于allocator实现的内存共享
- Linux进程间通信-基于内存(共享内存)
- 【个人笔记重点,不作为参考】主题:详解基于node的前端项目编译时内存溢出问题
- javaCV开发详解之3:收流器实现,录制流媒体服务器的rtsp/rtmp视频文件(基于javaCV-FFMPEG)
- Infinispan's GridFileSystem--基于内存的网格文件系统
- 基于mini2440的Linux内存布局分析