我之前编译了jrtplib 3.9.1,并且在项目中使用,结果发现在用这个库时,程序体积有增加了300多K,感觉实在是有点笨重,我无法就是用来发送rtp包而已。想想还是自己重新实现一个简单的类用用拉倒了,所以有了下面的代码。

头文件:

  1. /*!
  2. @brief 简单rtp库
  3. @file easy_rtp.h
  4. */
  5. #ifndef _EASY_RTP_H
  6. #define _EASY_RTP_H
  7. #include <string>
  8. #include <stdint.h>
  9. #ifdef _WIN32
  10. #include <winsock2.h>
  11. #else
  12. #include <netinet/in.h>
  13. #include <sys/types.h>
  14. #include <sys/socket.h>
  15. #include <arpa/inet.h>
  16. #include <errno.h>
  17. #ifndef INVALID_SOCKET
  18. #define INVALID_SOCKET  (SOCKET)(~0)
  19. #endif
  20. #ifndef SOCKET_ERROR
  21. #define SOCKET_ERROR    (-1)
  22. #endif
  23. #ifndef closesocket
  24. #define closesocket(x)  close(x)
  25. #endif
  26. typedef int SOCKET;
  27. #endif
  28. // 默认最大包大小(MTU 1500 - IP头 20 - UDP头 8)
  29. #define DEFAULT_MAX_PACKET_SIZE 1472
  30. /*!
  31. @brief 简单rtp数据包装发送库
  32. */
  33. class EasyRtp
  34. {
  35. public:
  36. /*!
  37. @brief 构造
  38. @param destIp 目标ip地址
  39. @param port 目标端口
  40. @param localport 本地帮定端口,默认端口采用随机值
  41. */
  42. EasyRtp(const std::string& destIp, uint16_t port, uint16_t localPort = 0, int16_t maxpacketsize = DEFAULT_MAX_PACKET_SIZE);
  43. /*!
  44. @brief 构造
  45. @param destIp 目标ip地址
  46. @param port 目标端口
  47. @param localport 本地帮定端口,默认端口采用随机值
  48. */
  49. EasyRtp(uint32_t destIp, uint16_t port, uint16_t localPort = 0, int16_t maxpacketsize = DEFAULT_MAX_PACKET_SIZE);
  50. ~EasyRtp();
  51. public:
  52. /*!
  53. @brief 发送rtp包给目标
  54. @param buf 发送的缓冲
  55. @param len 发送的缓冲大小
  56. @param pt 负载类型
  57. @param mark 标记位
  58. @param timestampInc 时间戳增量
  59. @param 错误为-1
  60. */
  61. int32_t sendPacket(const char* buf, int32_t len, int8_t pt, bool mark, int32_t timestampInc);
  62. private:
  63. /// 简单rtp头12字节,不含扩展头,csrc列表等信息
  64. typedef struct
  65. {
  66. uint8_t ver;                /// 版本号(2bit)
  67. bool p;                     /// 填充位,一直置0(1bit)
  68. bool x;                     /// 扩充头位,一直置0(1bit)
  69. uint8_t cc;                 /// csrc列表数量,一直置0(4bit)
  70. bool mark;                  /// 标记位(1bit)
  71. int8_t pt;                  /// 负载类型(7bit)
  72. uint16_t sn;                /// 序列号(16bit)
  73. uint32_t ts;                /// 时间戳(32bit)
  74. uint32_t ssrc;              /// 来源标示(32bit)
  75. }RtpHeader;
  76. // 最大包大小
  77. int16_t _maxPacketSize;
  78. // 发送的缓冲
  79. char* _sbuf;
  80. // 序列号
  81. uint16_t _sn;
  82. // 时间戳
  83. uint32_t _ts;
  84. // 源标示
  85. uint32_t _ssrc;
  86. // 句柄
  87. SOCKET _socket;
  88. // 目标地址
  89. struct sockaddr_in _destTo;
  90. };
  91. #endif  // _EASY_RTP_H

cpp源码:

  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <stdexcept>
  4. #include "easy_rtp.h"
  5. #include "byte_write.h"
  6. #include "utils.h"
  7. // 默认的rtp版本
  8. #define RTP_VERSION         2
  9. // rtp头大小
  10. #define RTP_HEADER_SIZE     12
  11. EasyRtp::EasyRtp( const std::string& destIp, uint16_t port, uint16_t localPort /*= 0*/, int16_t maxpacketsize /*= 1500*/ )
  12. :_maxPacketSize(maxpacketsize),
  13. _sbuf(NULL),
  14. _sn(Utils::createRandam32()),
  15. _ts(Utils::createRandam32()),
  16. _ssrc(Utils::createRandam32())
  17. {
  18. if (maxpacketsize >= RTP_HEADER_SIZE)
  19. _sbuf = new char[maxpacketsize];
  20. else
  21. throw std::runtime_error("[EasyRtp] too small packet size, must more than 12 Byte");
  22. _socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
  23. if (_socket == INVALID_SOCKET)
  24. throw std::runtime_error("[EasyRtp] invalid socket");
  25. _destTo.sin_family = AF_INET;
  26. _destTo.sin_port = htons(port);
  27. _destTo.sin_addr.s_addr = inet_addr(destIp.c_str());
  28. if (localPort != 0)
  29. {
  30. struct sockaddr_in sockAddr;
  31. sockAddr.sin_family = AF_INET;
  32. sockAddr.sin_port = htons(localPort);
  33. sockAddr.sin_addr.s_addr = INADDR_ANY;
  34. if (bind(_socket, (const sockaddr*)&sockAddr, sizeof(sockAddr)) == SOCKET_ERROR)
  35. {
  36. #ifndef NPRINT
  37. #ifdef _WIN32
  38. printf("[EasyRtp] bind error: %d\n", WSAGetLastError());
  39. #else
  40. printf("[EasyRtp] bind error: %d\n", errno);
  41. #endif
  42. #endif
  43. closesocket(_socket);
  44. throw std::runtime_error("[EasyRtp] bind error");
  45. }
  46. }
  47. }
  48. EasyRtp::EasyRtp( uint32_t destIp, uint16_t port, uint16_t localPort /*= 0*/, int16_t maxpacketsize /*= DEFAULT_MAX_PACKET_SIZE*/ )
  49. :_maxPacketSize(maxpacketsize),
  50. _sbuf(NULL),
  51. _sn(Utils::createRandam32()),
  52. _ts(Utils::createRandam32()),
  53. _ssrc(Utils::createRandam32())
  54. {
  55. if (maxpacketsize >= RTP_HEADER_SIZE)
  56. _sbuf = new char[maxpacketsize];
  57. else
  58. throw std::runtime_error("[EasyRtp] too small packet size, must more than 12 Byte");
  59. _socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
  60. if (_socket == INVALID_SOCKET)
  61. throw std::runtime_error("[EasyRtp] invalid socket");
  62. _destTo.sin_family = AF_INET;
  63. _destTo.sin_port = htons(port);
  64. _destTo.sin_addr.s_addr = htonl(destIp);
  65. if (localPort != 0)
  66. {
  67. struct sockaddr_in sockAddr;
  68. sockAddr.sin_family = AF_INET;
  69. sockAddr.sin_port = htons(localPort);
  70. sockAddr.sin_addr.s_addr = INADDR_ANY;
  71. if (bind(_socket, (const sockaddr*)&sockAddr, sizeof(sockAddr)) == SOCKET_ERROR)
  72. {
  73. #ifndef NPRINT
  74. #ifdef _WIN32
  75. printf("[EasyRtp] bind error: %d\n", WSAGetLastError());
  76. #else
  77. printf("[EasyRtp] bind error: %d\n", errno);
  78. #endif
  79. #endif
  80. closesocket(_socket);
  81. throw std::runtime_error("[EasyRtp] bind error");
  82. }
  83. }
  84. }
  85. EasyRtp::~EasyRtp()
  86. {
  87. if (_socket != INVALID_SOCKET)
  88. closesocket(_socket);
  89. if (_sbuf != NULL)
  90. delete [] _sbuf;
  91. }
  92. int32_t EasyRtp::sendPacket( const char* buf, int32_t len, int8_t pt, bool mark, int32_t timestampInc )
  93. {
  94. if ((len + RTP_HEADER_SIZE) > _maxPacketSize)
  95. return -1;
  96. ++_sn;
  97. _ts += timestampInc;
  98. // 只设置版本号,其它的全是默认0
  99. _sbuf[0] = 0;
  100. _sbuf[0] |= RTP_VERSION << 6;
  101. _sbuf[1] = 0;
  102. _sbuf[1] |= mark << 7;
  103. _sbuf[1] |= pt;
  104. write_be_w(_sbuf + 2, _sn);
  105. write_be_dw(_sbuf + 4, _ts);
  106. write_be_dw(_sbuf + 8, _ssrc);
  107. // 保存数据
  108. memcpy(_sbuf + RTP_HEADER_SIZE, buf, len);
  109. int32_t ret = sendto(_socket, (const char*)_sbuf, len + RTP_HEADER_SIZE, 0, (const sockaddr*)&_destTo, sizeof(_destTo));
  110. #ifndef NPRINT
  111. if (ret < 0)
  112. {
  113. #ifdef _WIN32
  114. printf("[EasyRtp] sendto error: %d\n", WSAGetLastError());
  115. #else
  116. printf("[EasyRtp] sendto error: %d\n", errno);
  117. #endif
  118. }
  119. #endif
  120. return ret;
  121. }

注:

stdint.h是新c++标准中的头文件,定义了int32_t int8_t等typedef 类型。

简单RTP发送类c++实现的更多相关文章

  1. springboot开篇 (一)简单邮件发送

    上篇终结篇为spring 发送邮件,这次将使用springboot 发送邮件,同时本篇将作为springboot入门篇. 新建一个工程..工程目录结构如下,此次使用idea进行开发.对于一个长期使用e ...

  2. H264 NALU 使用PS封装 RTP发送

    最近由于项目平台需求,要将H264 NALU封装为PS再用RTP发送,PS封装按照ISO DEC-13818-1标准.一个PS包包含PS Header, PES Header, PS system h ...

  3. VC++ 一个简单的Log类

    在软件开发中,为程序建立Log日志是很必要的,它可以记录程序运行的状态以及出错信息,方便维护和调试. 下面实现了一个简单的Log类,使用非常简单,仅供参考. // CLogHelper.h : hea ...

  4. 用qpython3写一个最简单的发送短信的程序

    到目前为止并没有多少手机应用是用python开发的,不过qpython可以作为一个不错的玩具推荐给大家来玩. 写一个最简单的发送短信的程序,代码如下: #-*-coding:utf8;-*- #qpy ...

  5. php实现的IMEI限制的短信验证码发送类

    php实现的IMEI限制的短信验证码发送类 <?php class Api_Sms{ const EXPIRE_SEC = 1800; // 过期时间间隔 const RESEND_SEC = ...

  6. C++ 最简单的日志类

    最近搞一个 C++ 项目的二次开发,没玩过 C++,可谓步履维艰.自己写个简单的日志类都被各种坑折磨.终于搞定了. 参考了这篇博客,并且进一步简化:https://www.cnblogs.com/Ds ...

  7. python+selenium之自定义封装一个简单的Log类

    python+selenium之自定义封装一个简单的Log类 一. 问题分析: 我们需要封装一个简单的日志类,主要有以下内容: 1. 生成的日志文件格式是 年月日时分秒.log 2. 生成的xxx.l ...

  8. C++定义一个简单的Computer类

    /*定义一个简单的Computer类 有数据成员芯片(cpu).内存(ram).光驱(cdrom)等等, 有两个公有成员函数run.stop.cpu为CPU类的一个对象, ram为RAM类的一个对象, ...

  9. PHP 邮件发送类

    mail.php <?php /** * 邮件发送类 * 支持发送纯文本邮件和HTML格式的邮件,可以多收件人,多抄送,多秘密抄送,带附件的邮件 * 需要的php扩展,sockets和Filei ...

随机推荐

  1. 期末考试--nyoj-757

    期末考试 时间限制:1000 ms  |  内存限制:65535 KB 难度:2 描述 马上就要考试了,小T有许多作业要做,而且每个老师都给出来了作业要交的期限,如果在规定的期限内没 交作业就会扣期末 ...

  2. java学习:AWT组件和事件处理的笔记(1)--文本框上的ActionEvent事件

    学习处理事件时,必须很好的掌握事件源,监视器,处理事件的接口    1.事件源        能够产生java认可事件的对象都可称为事件源,也就是说事件源必须是对象    2.监视器        监 ...

  3. Nand flash 的发展和eMMC

    讨论到eMMC的发展历程,必须要从介绍Flash的历史开始 Flash分为两种规格:NOR Flash和NAND Flash,两者均为非易失性闪存模块. 1988年,Intel首次发出NOR flas ...

  4. 忽然有一种感觉:云存储必须从系统级定制,所以必须对Linux相当熟悉。Windows下开发软件的模式已经过时了

    看了诸多招聘帖子以后的感觉- 工作内容: .存储相关产品的设计.开发和维护. .Linux系统应用程序研发. .主流Linux内核文件系统研发. .自动化测试框架和工具的研发. 职位要求: .计算机相 ...

  5. cf459C Pashmak and Buses

    C. Pashmak and Buses time limit per test 1 second memory limit per test 256 megabytes input standard ...

  6. C语言运算符的优先级

    熟悉C语言的同学都知道,C语言众多的运算符及繁琐难记的优先级总是搞得我们这些C初学者头大.那么本文就 对C语言中所有的运算符进行汇总,并对其优先级进行一定的介绍. 这里虽然对所有C运算符的优先级进行了 ...

  7. PIE(二分) 分类: 二分查找 2015-06-07 15:46 9人阅读 评论(0) 收藏

    Pie Time Limit: 5000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Submissio ...

  8. Curly braces in Python in 2012? - Stack Overflow

    Curly braces in Python in 2012? - Stack Overflow Curly braces in Python in 2012? [closed]

  9. poj3233之经典矩阵乘法

    Matrix Power Series Time Limit: 3000MS   Memory Limit: 131072K Total Submissions: 12346   Accepted:  ...

  10. SNMP协议具体解释

    简单网络管理协议(SNMP)是TCP/IP协议簇的一个应用层协议.在1988年被制定,并被Internet体系结构委员会(IAB)採纳作为一个短期的网络管理解决方式:因为SNMP的简单性,在Inter ...