RTP GB28181 udp 转发桥

目的

通往外网只有一个节点可以通,这个时候我们需要一个转发桥, 做一个udp 转发桥是非常简单的,简单而有用,我们使用asio c++ 来编程序

原理

使用asio 异步接收并且发送,在接收到以后,立刻在桥上转发,转发到外网地址。这里做演示,程序里面使用的是127.0.0.1.

代码

#define ASIO_STANDALONE
#include 
#include 
#include 
#include "asio.hpp"

using asio::ip::udp;
static const asio::ip::udp::endpoint s_end_point(asio::ip::address::from_string("127.0.0.1"), 6000);

class TicToc
{
public:
	TicToc()
	{
		tic();
	}

	void tic()
	{
		start = std::chrono::system_clock::now();
	}

	double toc()
	{
		end = std::chrono::system_clock::now();
		std::chrono::duration<double> elapsed_seconds = end - start;
		start = end;
		return elapsed_seconds.count() ;
	}

private:
	std::chrono::time_point<std::chrono::system_clock> start, end;
};

class server
{
private:
	TicToc v_tock;
public:
	server(asio::io_context& io_context, short port)
		: socket_(io_context, udp::endpoint(udp::v4(), port))
	{
		do_receive();
	}
	int64_t v_i = 0;
	uint64_t v_recvbytes = 0;
	void do_receive()
	{
		
		socket_.async_receive_from(
			asio::buffer(data_, max_length), sender_endpoint_,
			[this](std::error_code ec, std::size_t bytes_recvd)
		{
			if (!ec && bytes_recvd > 0)
			{
				if (v_i == 0)
					v_tock.tic();
				v_recvbytes += bytes_recvd;
				if (v_i++ > 100) //每一百个包统计一次
				{
					double res = v_tock.toc();
					float m = v_recvbytes / res /1000.0f;
					std::cout<<"time:"<<res<<" bytes:"<< v_recvbytes<<" recv byte every second:" << m <<"KB"<< std::endl;
					v_i = 0;
					v_recvbytes = 0;
				}
				do_send(bytes_recvd);
			}
			else
			{
				do_receive();
			}
		});
	}

	void do_send(std::size_t length)
	{
		socket_.async_send_to(
			asio::buffer(data_, length), s_end_point,
			[this](std::error_code /*ec*/, std::size_t /*bytes_sent*/)
		{
			do_receive();
		});
	}

private:
	udp::socket socket_;
	udp::endpoint sender_endpoint_;
	udp::endpoint sender_to;
	enum { max_length = 1500 };
	char data_[max_length];
};

int main(int argc, char* argv[])
{
	try
	{
		/*if (argc != 2)
		{
			std::cerr << "Usage: async_udp_echo_server \n";
			return 1;
		}*/

		asio::io_context io_context;

		server s(io_context, 5000);

		io_context.run();
	}
	catch (std::exception& e)
	{
		std::cerr << "Exception: " << e.what() << "\n";
	}

	return 0;
}

实验

写一个RTP发送程序,使用摄像头,摄像头转发到RTP地址的端口5000上,然后使用桥转接到外网IP地址,这里为了演示使用本机内网地址127.0.0.1,我们再使用vlc来从转发桥那里接收数据
RTP GB28181 udp 转发桥_第1张图片
RTP GB28181 udp 转发桥_第2张图片
我在程序里面使用了计数,每100个rtp包接收一次,大概每秒钟300Kbit-400Kbit左右,打开vlc接收数据
RTP GB28181 udp 转发桥_第3张图片
如图所示,vlc 正常接收到rtp程序数据以后正常播放。

这个程序的好处是无论是rtp还是gb28181 的ps流都可以正常转发。

扩展和迭代

后面再做tcp 转发,tcp的转发显然比udp 要复杂很多,,为这个程序还要制定一个http restful,里面还需要增加ssrc 等rtp包数据获取,http协议等待接收告诉服务程序需要转发哪一个rtp包, 等待下一篇吧

你可能感兴趣的:(音视频和c++,java,物联网,c++,udp,网络协议,网络)