PC端RTP(基于C++的一个开源协议库jrtplib)

jrtplib

可选:基于c的ortp和gstreamer,基于c++的live555和jrtplib

ortp:http://www.linphone.org/index.php/eng/code_review/ortp

jrtplib主页:https://research.edm.uhasselt.be/jori/page/Main/HomePage.html

jrtplib:https://github.com/j0r1/JRTPLIB

需要配套线程的库jthread,jthread负责线程调用函数和mutex

jthread协议的作用:https://blog.csdn.net/caoshangpa/article/details/51151942

jthread:https://github.com/j0r1/JThread

cmake:https://cmake.org/download/

【一】jthread编译

1.运行cmake

2.选择源目录和编译目录

3.点击configure,选择自己的编译器

4.出现如下界面,点击generate即可

5.管理员身份用vs打开目录文件夹的工程文件,直接编译,生成分别对用debug(jthread_d.lib)和release(jthread.lib)的两个lib文件。

 

【二】jrtplip编译

1-4.前四个步骤和jthread编译的国程基本相同,只是在cmake的时候要添加下面这个这个参数

5.如果用vs直接编译,会报缺少文件的错误,我们将jthread-1.3.3\src里的jmutex.h和jthread.h复制到jrtplib\src中,并且将src文件夹下所有头文件中引入jmutex.h和jthread.h的地方改为include "jmutex.h"、include "jthread.h",编译生成jrtplib.lib和jrtplib_d.lib。

【三】示例

1.库的配置:将jthread.lib和jrtplib.lib放到vs的lib下可以直接使用,也可放到项目中。

  将jrtplib\src下的所有头文件放到vs的inlude里,或者放到项目中。

2.项目配置:打开一个示例项目,如exemple1,或者用下面我更改过的代码。

/*
   Here's a small IPv4 example: it asks for a portbase and a destination and
   starts sending packets to that destination.
*/

#include "rtpsession.h"
#include "rtpudpv4transmitter.h"
#include "rtpipv4address.h"
#include "rtpsessionparams.h"
#include "rtperrors.h"
#include "rtplibraryversion.h"
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <string>

using namespace jrtplib;

//这个函数在RTP通信出错时报所出现的错误

void checkerror(int rtperr)
{
	if (rtperr < 0)
	{
		std::cout << "ERROR: " << RTPGetErrorString(rtperr) << std::endl;
		exit(-1);
	}
}

//主程序入口

int main(void)
{
// 加载套接字,判断RTP_SOCKETTYPE_WINSOCK是否定义,若已定义,使用2.2版本的Socket库
#ifdef RTP_SOCKETTYPE_WINSOCK
	WSADATA dat;
	WSAStartup(MAKEWORD(2, 2), &dat);
#endif 

	RTPSession sess;
	uint16_t portbase, destport;
	uint32_t destip;
	std::string ipstr;
	int status, i, num;
//设置portbase,ip,端口,包数
	portbase = 6666;//这个数大于零即可
	ipstr = "127.0.0.1";
	destport = 6666;
	num = 10;
//ip转长整型
	destip = inet_addr(ipstr.c_str());
//若destip无效就报错
	if (destip == INADDR_NONE)
	{
		std::cerr << "Bad IP address specified" << std::endl;
		return -1;
	}

//将网络顺序转主机顺序
	destip = ntohl(destip);

//开始创建RTP
	RTPUDPv4TransmissionParams transparams;
	RTPSessionParams sessparams;

	sessparams.SetOwnTimestampUnit(1.0 / 10.0);//设置时间戳保证RTCP计算

	sessparams.SetAcceptOwnPackets(true);//设置是否接收自定义的数据包
	transparams.SetPortbase(portbase);//设置监听端口
	status = sess.Create(sessparams, &transparams);//创建会话
	checkerror(status);//检查是否出错

	RTPIPv4Address addr(destip, destport);

	status = sess.AddDestination(addr);//设置RTP接收端
	checkerror(status);

	for (i = 1; i <= num; i++)
	{
		printf("\nSending packet %d/%d\n", i, num);

		//发送数据:第一个参数是发送的数据,二个是数据长度,往后是rtp负载类型,标识,时戳量
		status = sess.SendPacket((void *)"1234567890", 10, 0, false, 10);
		checkerror(status);

		sess.BeginDataAccess();//接收数据包

		// 检查输入数据包,递归寻找第一个有RTP数据的流
		if (sess.GotoFirstSourceWithData())
		{
			do
			{
				RTPPacket *pack;

				while ((pack = sess.GetNextPacket()) != NULL)//获得下一个RTP数据包
				{
					//如果收到就报告收到
					printf("Got packet !\n");

					// 报告之后就删掉
					sess.DeletePacket(pack);
				}
			} while (sess.GotoNextSourceWithData());//跳到下一个RTP流,到尾部就返回false。
		}

		sess.EndDataAccess();//数据包接收结束

#ifndef RTP_SUPPORT_THREAD
		status = sess.Poll();
		checkerror(status);
#endif // RTP_SUPPORT_THREAD

		RTPTime::Wait(RTPTime(1, 0));
	}

	sess.BYEDestroy(RTPTime(10, 0), 0, 0);
//卸载套接字
#ifdef RTP_SOCKETTYPE_WINSOCK
	WSACleanup();
#endif // RTP_SOCKETTYPE_WINSOCK
	return 0;
}

 

3.添加那对用的.lib和所有.h文件,编译,如果报inet_addr函数的错可以在前面加上#define _WINSOCK_DEPRECATED_NO_WARNINGS,如果还是有问题,就在“预处理器” 里加上“_CRT_SECURE_NO_WARNINGS”,以及在c/c++的常规里,将SDL检查改为否;如果报msvc的错,就在链接器命令行中添加/NODEFAULTLIB:"libcmt.lib"。

至此,环境搭建成功。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
解析 RTP 流需要对 RTP 协议进行解析,因此需要一定的协议知识。下面是一个简单的示例代码,可以解析 RTP 数据包并输出其有效载荷: ```java import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.util.Arrays; public class RTPParser { private DatagramSocket socket; public RTPParser(String address, int port) throws Exception { // 创建 DatagramSocket 对象 socket = new DatagramSocket(port, InetAddress.getByName(address)); } public void start() throws Exception { byte[] buffer = new byte[2048]; DatagramPacket packet = new DatagramPacket(buffer, buffer.length); // 循环读取 RTP 数据包 while (true) { socket.receive(packet); // 解析 RTP 数据包 int version = (buffer[0] & 0xC0) >> 6; int padding = (buffer[0] & 0x20) >> 5; int extension = (buffer[0] & 0x10) >> 4; int csrcCount = buffer[0] & 0x0F; int marker = (buffer[1] & 0x80) >> 7; int payloadType = buffer[1] & 0x7F; int sequenceNumber = (buffer[2] & 0xFF) << 8 | buffer[3] & 0xFF; int timestamp = (buffer[4] & 0xFF) << 24 | (buffer[5] & 0xFF) << 16 | (buffer[6] & 0xFF) << 8 | buffer[7] & 0xFF; int ssrc = (buffer[8] & 0xFF) << 24 | (buffer[9] & 0xFF) << 16 | (buffer[10] & 0xFF) << 8 | buffer[11] & 0xFF; int headerLength = 12 + 4 * csrcCount; // 输出 RTP 数据包有效载荷 byte[] payload = Arrays.copyOfRange(buffer, headerLength, packet.getLength()); System.out.println("Payload: " + Arrays.toString(payload)); } } public void stop() { // 关闭 DatagramSocket socket.close(); } } ``` 需要注意的是,RTP 数据包包含一个 RTP 头部和有效载荷,因此在解析 RTP 数据包时需要过滤掉 RTP 头部。此外,RTP 流是一种实时传输协议,因此在读取数据时需要使用循环来持续读取数据。此外,由于 RTP 数据包可能会使用多种编码格式,因此需要根据实际情况来处理有效载荷。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值