本文所有内容均为原创,转载请注明出处!

上一篇我们介绍了RTP协议的一些基本知识,下面我们介绍如何使用jrtplib这个库传输H264编码。

[cpp] view plain copy
  1. JRTP传输:
  2. 好了,下面是我写的使用JRTP进行发送H264数据包的例子,具体解释可以看注释。发送端也可以接收接收端发送过来的RTCP数据包。
  3. #define MAX_RTP_PKT_LENGTH 1360
  4. #define H264               96
  5. bool CheckError(int rtperr);
  6. class CRTPSender :
  7. public RTPSession
  8. {
  9. public:
  10. CRTPSender(void);
  11. ~CRTPSender(void);
  12. protected:
  13. void OnAPPPacket(RTCPAPPPacket *apppacket,const RTPTime &receivetime,const RTPAddress *senderaddress);
  14. void OnBYEPacket(RTPSourceData *srcdat);
  15. void OnBYETimeout(RTPSourceData *srcdat);
  16. public:
  17. void SendH264Nalu(unsigned char* m_h264Buf,int buflen);
  18. void SetParamsForSendingH264();
  19. };
  20. bool CheckError(int rtperr)
  21. {
  22. if (rtperr < 0)
  23. {
  24. std::cout<<"ERROR: "<<RTPGetErrorString(rtperr)<<std::endl;
  25. return false;
  26. }
  27. return true;
  28. }
  29. CRTPSender::CRTPSender(void)
  30. {
  31. }
  32. CRTPSender::~CRTPSender(void)
  33. {
  34. }
  35. void CRTPSender::OnAPPPacket(RTCPAPPPacket *apppacket,const RTPTime &receivetime,const RTPAddress *senderaddress)
  36. {//收到RTCP APP数据
  37. std::cout<<"Got RTCP packet from: "<<senderaddress<<std::endl;
  38. std::cout<<"Got RTCP subtype: "<<apppacket->GetSubType()<<std::endl;
  39. std::cout<<"Got RTCP data: "<<(char *)apppacket->GetAPPData()<<std::endl;
  40. return ;
  41. }
  42. void CRTPSender::SendH264Nalu(unsigned char* m_h264Buf,int buflen)
  43. {
  44. unsigned char *pSendbuf; //发送数据指针
  45. pSendbuf = m_h264Buf;
  46. //去除前导码0x000001 或者0x00000001
  47. //if( 0x01 == m_h264Buf[2] )
  48. //{
  49. //  pSendbuf = &m_h264Buf[3];
  50. //  buflen -= 3;
  51. //}
  52. //else
  53. //{
  54. //  pSendbuf = &m_h264Buf[4];
  55. //  buflen -= 4;
  56. //}
  57. char sendbuf[1430];   //发送的数据缓冲
  58. memset(sendbuf,0,1430);
  59. int status;
  60. printf("send packet length %d \n",buflen);
  61. if ( buflen <= MAX_RTP_PKT_LENGTH )
  62. {
  63. memcpy(sendbuf,pSendbuf,buflen);
  64. status = this->SendPacket((void *)sendbuf,buflen);
  65. CheckError(status);
  66. }
  67. else if(buflen > MAX_RTP_PKT_LENGTH)
  68. {
  69. //设置标志位Mark为0
  70. this->SetDefaultMark(false);
  71. //printf("buflen = %d\n",buflen);
  72. //得到该需要用多少长度为MAX_RTP_PKT_LENGTH字节的RTP包来发送
  73. int k=0,l=0;
  74. k = buflen / MAX_RTP_PKT_LENGTH;
  75. l = buflen % MAX_RTP_PKT_LENGTH;
  76. int t=0;//用指示当前发送的是第几个分片RTP包
  77. char nalHeader = pSendbuf[0]; // NALU 头ª¡¤
  78. while( t < k || ( t==k && l>0 ) )
  79. {
  80. if( (0 == t ) || ( t<k && 0!=t ) )//第一包到最后包的前一包
  81. {
  82. /*sendbuf[0] = (nalHeader & 0x60)|28;
  83. sendbuf[1] = (nalHeader & 0x1f);
  84. if ( 0 == t )
  85. {
  86. sendbuf[1] |= 0x80;
  87. }
  88. memcpy(sendbuf+2,&pSendbuf[t*MAX_RTP_PKT_LENGTH],MAX_RTP_PKT_LENGTH);
  89. status = this->SendPacket((void *)sendbuf,MAX_RTP_PKT_LENGTH+2);*/
  90. memcpy(sendbuf,&pSendbuf[t*MAX_RTP_PKT_LENGTH],MAX_RTP_PKT_LENGTH);
  91. status = this->SendPacket((void *)sendbuf,MAX_RTP_PKT_LENGTH);
  92. CheckError(status);
  93. t++;
  94. }
  95. //最后一包
  96. else if( ( k==t && l>0 ) || ( t== (k-1) && l==0 ))
  97. {
  98. //设置标志位Mark为1
  99. this->SetDefaultMark(true);
  100. int iSendLen;
  101. if ( l > 0)
  102. {
  103. iSendLen = buflen - t*MAX_RTP_PKT_LENGTH;
  104. }
  105. else
  106. iSendLen = MAX_RTP_PKT_LENGTH;
  107. //sendbuf[0] = (nalHeader & 0x60)|28;
  108. //sendbuf[1] = (nalHeader & 0x1f);
  109. //sendbuf[1] |= 0x40;
  110. //memcpy(sendbuf+2,&pSendbuf[t*MAX_RTP_PKT_LENGTH],iSendLen);
  111. //status = this->SendPacket((void *)sendbuf,iSendLen+2);
  112. memcpy(sendbuf,&pSendbuf[t*MAX_RTP_PKT_LENGTH],iSendLen);
  113. status = this->SendPacket((void *)sendbuf,iSendLen);
  114. CheckError(status);
  115. t++;
  116. }
  117. }
  118. }
  119. }
  120. void CRTPSender::SetParamsForSendingH264()
  121. {
  122. this->SetDefaultPayloadType(H264);//设置传输类型
  123. this->SetDefaultMark(true);      //设置位
  124. this->SetTimestampUnit(1.0/9000.0); //设置采样间隔
  125. this->SetDefaultTimestampIncrement(3600);//设置时间戳增加间隔
  126. }
  127. void CRTPSender::OnBYEPacket(RTPSourceData *srcdat)
  128. {
  129. }
  130. void CRTPSender::OnBYETimeout(RTPSourceData *srcdat)
  131. {
  132. }
  133. Main.cpp  在上一篇博客中的编码之后进行传输
  134. #define SSRC           100
  135. #define DEST_IP_STR   "192.168.1.252"
  136. #define DEST_PORT     1234
  137. #define BASE_PORT     2222
  138. int iNal   = 0;
  139. x264_nal_t* pNals = NULL;
  140. void SetRTPParams(CRTPSender& sess,uint32_t destip,uint16_t destport,uint16_t baseport)
  141. {
  142. int status;
  143. //RTP+RTCP库初始化SOCKET环境
  144. RTPUDPv4TransmissionParams transparams;
  145. RTPSessionParams sessparams;
  146. sessparams.SetOwnTimestampUnit(1.0/9000.0); //时间戳单位
  147. sessparams.SetAcceptOwnPackets(true);   //接收自己发送的数据包
  148. sessparams.SetUsePredefinedSSRC(true);  //设置使用预先定义的SSRC
  149. sessparams.SetPredefinedSSRC(SSRC);     //定义SSRC
  150. transparams.SetPortbase(baseport);
  151. status = sess.Create(sessparams,&transparams);
  152. CheckError(status);
  153. destip = ntohl(destip);
  154. RTPIPv4Address addr(destip,destport);
  155. status = sess.AddDestination(addr);
  156. CheckError(status);
  157. //为发送H264包设置参数
  158. //sess.SetParamsForSendingH264();
  159. }
  160. bool InitSocket()
  161. {
  162. int Error;
  163. WORD VersionRequested;
  164. WSADATA WsaData;
  165. VersionRequested=MAKEWORD(2,2);
  166. Error=WSAStartup(VersionRequested,&WsaData); //启动WinSock2
  167. if(Error!=0)
  168. {
  169. printf("Error:Start WinSock failed!\n");
  170. return false;
  171. }
  172. else
  173. {
  174. if(LOBYTE(WsaData.wVersion)!=2||HIBYTE(WsaData.wHighVersion)!=2)
  175. {
  176. printf("Error:The version is WinSock2!\n");
  177. WSACleanup();
  178. return false;
  179. }
  180. }
  181. return true;
  182. }
  183. void CloseSocket(CRTPSender sess)
  184. {
  185. //发送一个BYE包离开会话最多等待秒钟超时则不发送
  186. sess.BYEDestroy(RTPTime(3,0),0,0);
  187. WSACleanup();
  188. }
  189. int main(int argc, char** argv)
  190. {
  191. InitSocket();
  192. CRTPSender sender;
  193. string destip_str = "127.0.0.1";
  194. uint32_t dest_ip = inet_addr(destip_str.c_str());
  195. SetRTPParams(sender,dest_ip,DEST_PORT,BASE_PORT);
  196. sender.SetParamsForSendingH264();
  197. //…x264设置参数等步骤,具体参见上篇博客
  198. for(int i = 0; i < nFrames ; i++ )
  199. {
  200. //读取一帧
  201. read_frame_y4m(pPicIn,(hnd_t*)y4m_hnd,i);
  202. if( i ==0 )
  203. pPicIn->i_pts = i;
  204. else
  205. pPicIn->i_pts = i - 1;
  206. //编码
  207. int frame_size = x264_encoder_encode(pX264Handle,&pNals,&iNal,pPicIn,pPicOut);
  208. if(frame_size >0)
  209. {
  210. for (int i = 0; i < iNal; ++i)
  211. {//将编码数据写入文件t
  212. //fwrite(pNals[i].p_payload, 1, pNals[i].i_payload, pFile);
  213. //发送编码文件
  214. sender.SendH264Nalu(pNals[i].p_payload,pNals[i].i_payload);
  215. RTPTime::Wait(RTPTime(1,0));
  216. }
  217. }
  218. }
  219. CloseSocket(sender);
  220. //一些清理工作…
  221. }

使用jrtplib(RTP)传输H.264视频文件相关推荐

  1. 【FFmpeg编码实战】(2)将YUV420P图片集编码成H.264视频文件(方法二)

    [FFmpeg编码实战](2)将YUV420P图片集编码成H.264视频文件(方法二) 一.编码成 H.264 视频文件,运行结果 二.编码成 MPEG4 视频文件,运行结果 三.编码成 AV_COD ...

  2. 基于RTP的h.264视频传输系统(二)

    Live555 是一个为跨平台的C++开源项目,它实现了RTP/RTCP.RTSP.SIP等的支持.并且相对于其他的流媒体服务器是完全开源并且免费的. 废话不多说,下面开始. http://blog. ...

  3. h.264视频文件封装

    所谓封装格式就是将已经编码压缩好的视频轨和音频轨按照一定的格式放到一个文件中,也就是说仅仅是一个外壳,或者大家把它当成一个放视频轨和音频轨的文件夹也可以.说得通俗点,视频轨相当于饭,而音频轨相当于菜, ...

  4. 实现RTP协议的H.264视频传输系统

    1.  引言        随着信息产业的发展,人们对信息资源的要求已经逐渐由文字和图片过渡到音频和视频,并越来越强调获取资源的实时性和互动性.但人们又面临着另外一种不可避免的尴尬,就是在网络上看到生 ...

  5. 基于RTP协议的H.264视频传输系统:原理

    1.引言      随着信息产业的发展,人们对信息资源的要求已经逐渐由文字和图片过渡到音频和视频,并越来越强调获取资源的实时性和互动性.但人们又面临着另外一种不可避免的尴尬,就是在网络上看到生动清晰的 ...

  6. H.264 视频的 RTP 载荷格式

    本文是 IETF 的规范 RFC 6184 的一部分的翻译,该规范 地址.翻译这份文档,主要是为了编写一段用 RTP 传输 H.264 流的代码.本想在网上找一些文章完成任务了事的,但由于个人之前音视 ...

  7. RTP协议介绍以及C语言实现具有发送H.264视频功能的RTP服务器

    RTP封装H.264视频规范以及C语言实现 以前上学时间做嵌入式开发板Hi3516A的流媒体项目,现在又突然想起来,不想学过就忘了浪费了,所以又自己实现了一遍读取本地视频文件发送RTP视频流的程序,算 ...

  8. 基于RTP协议的H.264视频传输系统:实现

    实现的原理:基于RTP协议的H.264视频传输系统:原理 相关文章: [1]RTP协议分析 [2]jrtplib简介 [3]Qt调用jrtplib实现单播.多播和广播 [4]RTP 有效负载(载荷)类 ...

  9. H.264视频的RTP有效负载格式 (RFC-3984)

    RFC文档链接 本备忘录的状态 略 摘要 本备忘录描述了ITU-T建议的H.264视频编解码器和技术上相同的ISO/IEC国际标准14496-10视频编解码器的RTP有效载荷格式.RTP有效载荷格式允 ...

  10. H.264 RTPpayload 格式------ H.264 视频 RTP 负载格式

    H.264 RTPpayload 格式------ H.264 视频 RTP 负载格式 1. 网络抽象层单元类型 (NALU) NALU 头由一个字节组成, 它的语法如下: +------------ ...

最新文章

  1. 一个关于异步的纠结问题
  2. JS和Jquery获取和修改label的值
  3. mysql数学函数有什么_mysql数学函数有哪些?
  4. VMware vSphere Storage Appliance (VSA) 5.1 群集部署
  5. Hive insert into小文件问题
  6. 发现TP5一个神奇的问题
  7. python3.x编程模板总结
  8. hopfield tsp matlab,TSP问题—Hopfield神经网络算法
  9. excel文件损坏修复绝招_ps文件损坏有修复的软件!超强开挂辅助神器
  10. 欧拉-拉格朗日方程(Euler -Lagrange equation)
  11. 华为5G专利收费标准曝光!原来卖专利真的很挣钱
  12. 143个相见恨晚的排行榜网站,总有一个用得着!
  13. FPGA:vivado2018.1编程界面字体大小与颜色修改
  14. C++编译错误总结及其英文翻译————墨白
  15. Godot官网新闻翻译 - 2015年
  16. 图像处理之相似图片识别(直方图应用篇)
  17. 健身与不健身五年后的差别?你可不能轻易忽视!
  18. 从数字化视角看飞书产品
  19. 终于等到你,最强 IDE Visual Studio 2017 正式版发布
  20. 蓝牙卡复制html,车库蓝牙卡能复制吗

热门文章

  1. WAMP(Windows+Apache+Mysql+PHP)环境搭建
  2. (转载) MTK之NVRAM研究[三]
  3. 【10g中db_recovery_file_dest和log_archive_dest参数的关系】
  4. EXP-00003解决
  5. centos普通用户和root用户之间相互切换
  6. Java 递归求后一个数是前两个数之和
  7. docker容器跨宿主机通信
  8. 《Haskell函数式编程入门》—— 第1章,第1.6节本章小结
  9. 分布式系统下数据一致性
  10. linux Apache2.4安装提示APR not found的解决办法