简单RTP发送类c++实现
我之前编译了jrtplib 3.9.1,并且在项目中使用,结果发现在用这个库时,程序体积有增加了300多K,感觉实在是有点笨重,我无法就是用来发送rtp包而已。想想还是自己重新实现一个简单的类用用拉倒了,所以有了下面的代码。
头文件:
- /*!
- @brief 简单rtp库
- @file easy_rtp.h
- */
- #ifndef _EASY_RTP_H
- #define _EASY_RTP_H
- #include <string>
- #include <stdint.h>
- #ifdef _WIN32
- #include <winsock2.h>
- #else
- #include <netinet/in.h>
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <arpa/inet.h>
- #include <errno.h>
- #ifndef INVALID_SOCKET
- #define INVALID_SOCKET (SOCKET)(~0)
- #endif
- #ifndef SOCKET_ERROR
- #define SOCKET_ERROR (-1)
- #endif
- #ifndef closesocket
- #define closesocket(x) close(x)
- #endif
- typedef int SOCKET;
- #endif
- // 默认最大包大小(MTU 1500 - IP头 20 - UDP头 8)
- #define DEFAULT_MAX_PACKET_SIZE 1472
- /*!
- @brief 简单rtp数据包装发送库
- */
- class EasyRtp
- {
- public:
- /*!
- @brief 构造
- @param destIp 目标ip地址
- @param port 目标端口
- @param localport 本地帮定端口,默认端口采用随机值
- */
- EasyRtp(const std::string& destIp, uint16_t port, uint16_t localPort = 0, int16_t maxpacketsize = DEFAULT_MAX_PACKET_SIZE);
- /*!
- @brief 构造
- @param destIp 目标ip地址
- @param port 目标端口
- @param localport 本地帮定端口,默认端口采用随机值
- */
- EasyRtp(uint32_t destIp, uint16_t port, uint16_t localPort = 0, int16_t maxpacketsize = DEFAULT_MAX_PACKET_SIZE);
- ~EasyRtp();
- public:
- /*!
- @brief 发送rtp包给目标
- @param buf 发送的缓冲
- @param len 发送的缓冲大小
- @param pt 负载类型
- @param mark 标记位
- @param timestampInc 时间戳增量
- @param 错误为-1
- */
- int32_t sendPacket(const char* buf, int32_t len, int8_t pt, bool mark, int32_t timestampInc);
- private:
- /// 简单rtp头12字节,不含扩展头,csrc列表等信息
- typedef struct
- {
- uint8_t ver; /// 版本号(2bit)
- bool p; /// 填充位,一直置0(1bit)
- bool x; /// 扩充头位,一直置0(1bit)
- uint8_t cc; /// csrc列表数量,一直置0(4bit)
- bool mark; /// 标记位(1bit)
- int8_t pt; /// 负载类型(7bit)
- uint16_t sn; /// 序列号(16bit)
- uint32_t ts; /// 时间戳(32bit)
- uint32_t ssrc; /// 来源标示(32bit)
- }RtpHeader;
- // 最大包大小
- int16_t _maxPacketSize;
- // 发送的缓冲
- char* _sbuf;
- // 序列号
- uint16_t _sn;
- // 时间戳
- uint32_t _ts;
- // 源标示
- uint32_t _ssrc;
- // 句柄
- SOCKET _socket;
- // 目标地址
- struct sockaddr_in _destTo;
- };
- #endif // _EASY_RTP_H
cpp源码:
- #include <stdio.h>
- #include <string.h>
- #include <stdexcept>
- #include "easy_rtp.h"
- #include "byte_write.h"
- #include "utils.h"
- // 默认的rtp版本
- #define RTP_VERSION 2
- // rtp头大小
- #define RTP_HEADER_SIZE 12
- EasyRtp::EasyRtp( const std::string& destIp, uint16_t port, uint16_t localPort /*= 0*/, int16_t maxpacketsize /*= 1500*/ )
- :_maxPacketSize(maxpacketsize),
- _sbuf(NULL),
- _sn(Utils::createRandam32()),
- _ts(Utils::createRandam32()),
- _ssrc(Utils::createRandam32())
- {
- if (maxpacketsize >= RTP_HEADER_SIZE)
- _sbuf = new char[maxpacketsize];
- else
- throw std::runtime_error("[EasyRtp] too small packet size, must more than 12 Byte");
- _socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
- if (_socket == INVALID_SOCKET)
- throw std::runtime_error("[EasyRtp] invalid socket");
- _destTo.sin_family = AF_INET;
- _destTo.sin_port = htons(port);
- _destTo.sin_addr.s_addr = inet_addr(destIp.c_str());
- if (localPort != 0)
- {
- struct sockaddr_in sockAddr;
- sockAddr.sin_family = AF_INET;
- sockAddr.sin_port = htons(localPort);
- sockAddr.sin_addr.s_addr = INADDR_ANY;
- if (bind(_socket, (const sockaddr*)&sockAddr, sizeof(sockAddr)) == SOCKET_ERROR)
- {
- #ifndef NPRINT
- #ifdef _WIN32
- printf("[EasyRtp] bind error: %d\n", WSAGetLastError());
- #else
- printf("[EasyRtp] bind error: %d\n", errno);
- #endif
- #endif
- closesocket(_socket);
- throw std::runtime_error("[EasyRtp] bind error");
- }
- }
- }
- EasyRtp::EasyRtp( uint32_t destIp, uint16_t port, uint16_t localPort /*= 0*/, int16_t maxpacketsize /*= DEFAULT_MAX_PACKET_SIZE*/ )
- :_maxPacketSize(maxpacketsize),
- _sbuf(NULL),
- _sn(Utils::createRandam32()),
- _ts(Utils::createRandam32()),
- _ssrc(Utils::createRandam32())
- {
- if (maxpacketsize >= RTP_HEADER_SIZE)
- _sbuf = new char[maxpacketsize];
- else
- throw std::runtime_error("[EasyRtp] too small packet size, must more than 12 Byte");
- _socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
- if (_socket == INVALID_SOCKET)
- throw std::runtime_error("[EasyRtp] invalid socket");
- _destTo.sin_family = AF_INET;
- _destTo.sin_port = htons(port);
- _destTo.sin_addr.s_addr = htonl(destIp);
- if (localPort != 0)
- {
- struct sockaddr_in sockAddr;
- sockAddr.sin_family = AF_INET;
- sockAddr.sin_port = htons(localPort);
- sockAddr.sin_addr.s_addr = INADDR_ANY;
- if (bind(_socket, (const sockaddr*)&sockAddr, sizeof(sockAddr)) == SOCKET_ERROR)
- {
- #ifndef NPRINT
- #ifdef _WIN32
- printf("[EasyRtp] bind error: %d\n", WSAGetLastError());
- #else
- printf("[EasyRtp] bind error: %d\n", errno);
- #endif
- #endif
- closesocket(_socket);
- throw std::runtime_error("[EasyRtp] bind error");
- }
- }
- }
- EasyRtp::~EasyRtp()
- {
- if (_socket != INVALID_SOCKET)
- closesocket(_socket);
- if (_sbuf != NULL)
- delete [] _sbuf;
- }
- int32_t EasyRtp::sendPacket( const char* buf, int32_t len, int8_t pt, bool mark, int32_t timestampInc )
- {
- if ((len + RTP_HEADER_SIZE) > _maxPacketSize)
- return -1;
- ++_sn;
- _ts += timestampInc;
- // 只设置版本号,其它的全是默认0
- _sbuf[0] = 0;
- _sbuf[0] |= RTP_VERSION << 6;
- _sbuf[1] = 0;
- _sbuf[1] |= mark << 7;
- _sbuf[1] |= pt;
- write_be_w(_sbuf + 2, _sn);
- write_be_dw(_sbuf + 4, _ts);
- write_be_dw(_sbuf + 8, _ssrc);
- // 保存数据
- memcpy(_sbuf + RTP_HEADER_SIZE, buf, len);
- int32_t ret = sendto(_socket, (const char*)_sbuf, len + RTP_HEADER_SIZE, 0, (const sockaddr*)&_destTo, sizeof(_destTo));
- #ifndef NPRINT
- if (ret < 0)
- {
- #ifdef _WIN32
- printf("[EasyRtp] sendto error: %d\n", WSAGetLastError());
- #else
- printf("[EasyRtp] sendto error: %d\n", errno);
- #endif
- }
- #endif
- return ret;
- }
注:
stdint.h是新c++标准中的头文件,定义了int32_t int8_t等typedef 类型。
简单RTP发送类c++实现的更多相关文章
- springboot开篇 (一)简单邮件发送
上篇终结篇为spring 发送邮件,这次将使用springboot 发送邮件,同时本篇将作为springboot入门篇. 新建一个工程..工程目录结构如下,此次使用idea进行开发.对于一个长期使用e ...
- H264 NALU 使用PS封装 RTP发送
最近由于项目平台需求,要将H264 NALU封装为PS再用RTP发送,PS封装按照ISO DEC-13818-1标准.一个PS包包含PS Header, PES Header, PS system h ...
- VC++ 一个简单的Log类
在软件开发中,为程序建立Log日志是很必要的,它可以记录程序运行的状态以及出错信息,方便维护和调试. 下面实现了一个简单的Log类,使用非常简单,仅供参考. // CLogHelper.h : hea ...
- 用qpython3写一个最简单的发送短信的程序
到目前为止并没有多少手机应用是用python开发的,不过qpython可以作为一个不错的玩具推荐给大家来玩. 写一个最简单的发送短信的程序,代码如下: #-*-coding:utf8;-*- #qpy ...
- php实现的IMEI限制的短信验证码发送类
php实现的IMEI限制的短信验证码发送类 <?php class Api_Sms{ const EXPIRE_SEC = 1800; // 过期时间间隔 const RESEND_SEC = ...
- C++ 最简单的日志类
最近搞一个 C++ 项目的二次开发,没玩过 C++,可谓步履维艰.自己写个简单的日志类都被各种坑折磨.终于搞定了. 参考了这篇博客,并且进一步简化:https://www.cnblogs.com/Ds ...
- python+selenium之自定义封装一个简单的Log类
python+selenium之自定义封装一个简单的Log类 一. 问题分析: 我们需要封装一个简单的日志类,主要有以下内容: 1. 生成的日志文件格式是 年月日时分秒.log 2. 生成的xxx.l ...
- C++定义一个简单的Computer类
/*定义一个简单的Computer类 有数据成员芯片(cpu).内存(ram).光驱(cdrom)等等, 有两个公有成员函数run.stop.cpu为CPU类的一个对象, ram为RAM类的一个对象, ...
- PHP 邮件发送类
mail.php <?php /** * 邮件发送类 * 支持发送纯文本邮件和HTML格式的邮件,可以多收件人,多抄送,多秘密抄送,带附件的邮件 * 需要的php扩展,sockets和Filei ...
随机推荐
- Python信息采集器使用轻量级关系型数据库SQLite
1,引言Python自带一个轻量级的关系型数据库SQLite.这一数据库使用SQL语言.SQLite作为后端数据库,可以搭配Python建网站,或者为python网络爬虫存储数据.SQLite还在其它 ...
- Entity Framewor中的 Migration
http://www.entityframeworktutorial.net/code-first/code-based-migration-in-code-first.aspx = Code bas ...
- INNO SETUP 获得命令行参数
原文 http://www.cnblogs.com/ahuo/archive/2009/07/30/1534998.html ); Result := CmdLine; ...
- linux上应用随机启动
这是个go项目,其他的可以参考. 首先要有个脚本比如demo #!/bin/bash # # etcd This shell script takes care of starting and sto ...
- Linux命令行之逗趣无极限
Linux命令行之逗趣无极限 . Linux"sl"命令行 尽管"sl"代表了"蒸汽机机头",但它是用来提醒那些命令行控们别把"l ...
- Linux下,查看网络配置(IP,Gateway,DNS)
查看IP [root@localhost ~]# ifconfigem1 Link encap:Ethernet HWaddr F0:1F:AF:D6:17:DD ...
- JIRA官方:JIRA亮点介绍
操作超级简单 简单不意味着要以牺牲功能作为代价.JIRA提供了友好.直观的可配置的Web界面,并支持大量的快捷键操作. 跟踪任何事务 跟踪问题.任务.需求,当然还有软件缺陷.定义你自己的事务类型来使之 ...
- linux之SQL语句简明教程---外部连接
之前我们看到的左连接 (left join),又称内部连接 (inner join).在这个情况下,要两个表格内都有同样的值,那一笔资料才会被选出.那如果我们想要列出一个表格中每一笔的资料,无论它的值 ...
- ReactNative setNativeProps
在封装原生组件的过程,如果我们希望在reactnative中触发原生的属性,但是又不需要暴露在reactnative的组件中. 那么我们就要用到setNativeProps这个方法,这个方法会直接触发 ...
- cmd命令大全/cmd命令提示符大全
刚接触电脑的时候是从DOS系统开始,DOS时代根本就没有Windows这样的视窗操作界面,只有一个黑漆漆的窗口,让你输入命令.所以学DOS系统操作,cmd命令提示符是不可或缺的.可以告诉大家,大多数的 ...