一、说明

RTP 现在的问题是要解决的流媒体的实时传输的问题的最佳方法。和JRTPLIB 是一个用C++语言实现的RTP库。包含UDP通讯。刚使用JRTPLIB,对JRTPLIB的理解还不够深,当做使用时,积累的一些经验写个笔记吧。

二、RTP协议

实时传送协议(Real-time
Transport Protocol或简写RTP,也能够写成RTTP)是一个网络传输协议,RTP协议具体说明了在互联网上传递音频和视频的标准数据包格式。它一開始被设计为一个多播协议。但后来被用在非常多单播应用中。

RTP协议经常使用于流媒体系统(配合RTCP协议或者RTSP协议)。由于RTP自身具有Time
stamp所以在ffmpeg 中被用做一种formate。

RTP协议的具体介绍,请參考这篇文章http://www.360doc.com/content/11/1009/15/496343_154624612.shtml

三、RTPSession类

这里不介绍jrtplib的编译安装。这个非常easy,网上非常多地方都有解说。

jrtplib的使用中,主要是环绕这个类来实现的,因此大家有必要去查看源代码,看这类的实现。为了方便使用,我在这做了RTPSession的继承封装。以下直接贴代码了。

RTPSessionUtils.h

#include "rtpsession.h"
#include "rtppacket.h"
#include "rtpudpv4transmitter.h"
#include "rtpipv4address.h"
#include "rtpsessionparams.h"
#include "rtperrors.h"
#ifndef WIN32
#include <netinet/in.h>
#include <arpa/inet.h>
#else
#include <winsock2.h>
#endif // WIN32
#include "rtpsourcedata.h"
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <string> //jrtplib应用需链接的lib
#pragma comment(lib,"ws2_32.lib")
#pragma comment(lib, "jrtplib_d.lib")
#pragma comment(lib,"jthread_d.lib") namespace jrtplib
{
class RTPSessionUtils : public RTPSession
{
typedef RTPSession base_type;
public:
RTPSessionUtils();
~RTPSessionUtils(); int AddDestination(const std::string& ip, uint16_t port);
int DeleteDestination(const std::string& ip, uint16_t port);
int CreateDefault(uint16_t port);
protected:
void OnNewSource(RTPSourceData *dat);
void OnBYEPacket(RTPSourceData *dat);
void OnRemoveSource(RTPSourceData *dat);
void OnRTPPacket(RTPPacket *pack,const RTPTime &receivetime,
const RTPAddress *senderaddress);
void OnRTCPCompoundPacket(RTCPCompoundPacket *pack,const RTPTime &receivetime,
const RTPAddress *senderaddress);
void OnPollThreadStep();
private:
int GetAddrFromSource(RTPSourceData *dat, uint32_t& ip, uint16_t& port);
};
} //整形的ip转成字符串ip
static std::string IPToString(const unsigned int iIP)
{
struct in_addr inaddr;
inaddr.s_addr = htonl(iIP);
return std::string(inet_ntoa(inaddr));
} //字符串ip转成整形ip
static unsigned int IPToInt(const std::string& sIP)
{
return inet_addr(sIP.c_str());
}

RTPSessionUtils.cpp

#include "RTPSessionUtils.h"

namespace jrtplib{
RTPSessionUtils::RTPSessionUtils()
{
#ifdef WIN32
WSADATA dat;
WSAStartup(MAKEWORD(2,2),&dat);
#endif // WIN32
} RTPSessionUtils::~RTPSessionUtils()
{
#ifdef WIN32
WSACleanup();
#endif // WIN32
} int RTPSessionUtils::CreateDefault(uint16_t port)
{
RTPUDPv4TransmissionParams transparams;
RTPSessionParams sessparams;
sessparams.SetOwnTimestampUnit(1.0/10.0);//必须设置
transparams.SetPortbase(port);//port必须是偶数
return base_type::Create(sessparams, &transparams); base_type::SetDefaultPayloadType(0);
base_type::SetDefaultTimestampIncrement(0);
base_type::SetDefaultMark(false);
} int RTPSessionUtils::AddDestination(const std::string& ip, uint16_t port)
{
return base_type::AddDestination(RTPIPv4Address(ntohl(inet_addr(ip.c_str())), port));
} int RTPSessionUtils::DeleteDestination(const std::string& ip, uint16_t port)
{
return base_type::DeleteDestination(RTPIPv4Address(ntohl(inet_addr(ip.c_str())), port));
} int RTPSessionUtils::GetAddrFromSource(RTPSourceData *dat, uint32_t& ip, uint16_t& port)
{
if (dat->IsOwnSSRC())
return -1; if (dat->GetRTPDataAddress() != 0)
{
const RTPIPv4Address *addr = (const RTPIPv4Address *)(dat->GetRTPDataAddress());
ip = addr->GetIP();
port = addr->GetPort();
}
else if (dat->GetRTCPDataAddress() != 0)
{
const RTPIPv4Address *addr = (const RTPIPv4Address *)(dat->GetRTCPDataAddress());
ip = addr->GetIP();
port = addr->GetPort()-1;
} return 0;
} void RTPSessionUtils::OnNewSource(RTPSourceData *dat)
{
uint32_t ip;
uint16_t port; if (GetAddrFromSource(dat, ip, port))
return; RTPIPv4Address dest(ip,port);
base_type::AddDestination(dest); std::cout << "OnNewSource Adding destination " << IPToString(ip) << ":" << port << std::endl;
} void RTPSessionUtils::OnRemoveSource(RTPSourceData *dat)
{
if (dat->ReceivedBYE())
return; uint32_t ip;
uint16_t port; if (GetAddrFromSource(dat, ip, port))
return; RTPIPv4Address dest(ip,port);
base_type::DeleteDestination(dest); std::cout << "OnRemoveSource Deleting destination " << IPToString(ip) << ":" << port << std::endl;
} void RTPSessionUtils::OnBYEPacket(RTPSourceData *dat)
{
uint32_t ip;
uint16_t port; if (GetAddrFromSource(dat, ip, port))
return; RTPIPv4Address dest(ip,port);
base_type::DeleteDestination(dest); std::cout << "OnBYEPacket Deleting destination " << IPToString(ip) << ":" << port << std::endl;
} //仅仅要有rtp包就会触发
void RTPSessionUtils::OnRTPPacket(RTPPacket *pack,const RTPTime &receivetime,
const RTPAddress *senderaddress)
{
std::cout << "OnRTPPacket: data:" << pack->GetPayloadData() << std::endl;
} //收到rtcp包触发
void RTPSessionUtils::OnRTCPCompoundPacket(RTCPCompoundPacket *pack,const RTPTime &receivetime,
const RTPAddress *senderaddress)
{
std::cout << "OnRTCPCompoundPacket: data:" << pack->GetCompoundPacketData() << std::endl;
} //隔段时间就会触发,也能够用于收包回调函数
//void RTPSessionUtils::OnPollThreadStep()
//{
// BeginDataAccess(); // // check incoming packets
// if (GotoFirstSourceWithData())
// {
// do
// {
// RTPPacket *pack;
// RTPSourceData *srcdat; // srcdat = GetCurrentSourceInfo(); // while ((pack = GetNextPacket()) != NULL)
// {
// std::cout << "Got packet " << pack->GetExtendedSequenceNumber() << " from SSRC " << srcdat->GetSSRC() << std::endl;
// DeletePacket(pack);
// }
// } while (GotoNextSourceWithData());
// } // EndDataAccess();
//}
}

server.cpp

#include <iostream>
#include "RTPSessionUtils.h"
using namespace jrtplib;
void main()
{
int status;
RTPSessionUtils sess;
status = sess.CreateDefault(8888);
if(status)
{
std::cout << "RTP error:" << RTPGetErrorString(status) << std::endl;
return;
} while (1)
{
std::string buf;
std::cout << "Input send data:" ;
std::cin >> buf; sess.SendPacket((void*)buf.c_str(), buf.length(), 0, false, 0);
if(status)
{
std::cout << "RTP error:" << RTPGetErrorString(status) << std::endl;
continue;
}
} system("pause");
}

client.cpp

#include <iostream>
#include "RTPSessionUtils.h"
using namespace jrtplib; void main()
{
int status;
RTPSessionUtils sess;
status = sess.CreateDefault(6666);
if(status)
{
std::cout << "RTP error:" << RTPGetErrorString(status) << std::endl;
return;
}
status = sess.AddDestination("127.0.0.1", 8888);
if(status)
{
std::cout << "RTP error:" << RTPGetErrorString(status) << std::endl;
return;
} while (1)
{
std::string buf;
std::cout << "Input send data:" ;
std::cin >> buf; sess.SendPacket((void*)buf.c_str(), buf.length(), 0, false, 0);
if(status)
{
std::cout << "RTP error:" << RTPGetErrorString(status) << std::endl;
continue;
}
} system("pause");
}

jrtplib使用注意事项的更多相关文章

  1. jQuery UI resizable使用注意事项、实时等比例拉伸及你不知道的技巧

    这篇文章总结的是我在使用resizable插件的过程中,遇到的问题及变通应用的奇思妙想. 一.resizable使用注意事项 以下是我在jsfiddle上写的测试demo:http://jsfiddl ...

  2. Windows Server 2012 NIC Teaming介绍及注意事项

    Windows Server 2012 NIC Teaming介绍及注意事项 转载自:http://www.it165.net/os/html/201303/4799.html Windows Ser ...

  3. TODO:Golang指针使用注意事项

    TODO:Golang指针使用注意事项 先来看简单的例子1: 输出: 1 1 例子2: 输出: 1 3 例子1是使用值传递,Add方法不会做任何改变:例子2是使用指针传递,会改变地址,从而改变地址. ...

  4. app开发外包注意事项,2017最新资讯

    我们见过很多创业者,栽在这app外包上.很多创业者对于app外包这件事情不是特别重视,以为将事情交给app外包公司就完事了,实际上不是的.无论是从选择app外包公司还是签订合同.售后维护等各方面都有许 ...

  5. favicon.ioc使用以及注意事项

    1.效果 2.使用引入方法 2.1 注意事项:(把图标命名为favicon.ico,并且放在根目录下,同时使用Link标签,多重保险) 浏览器默认使用根目录下的favicon.ico 图标(如果你并没 ...

  6. ORACLE分区表梳理系列(二)- 分区表日常维护及注意事项(红字需要留意)

    版权声明:本文发布于http://www.cnblogs.com/yumiko/,版权由Yumiko_sunny所有,欢迎转载.转载时,请在文章明显位置注明原文链接.若在未经作者同意的情况下,将本文内 ...

  7. 【原】Masonry+UIScrollView的使用注意事项

    [原]Masonry+UIScrollView的使用注意事项 本文转载请注明出处 —— polobymulberry-博客园 1.问题描述 我想实现的使用在一个UIScrollView依次添加三个UI ...

  8. 《连载 | 物联网框架ServerSuperIO教程》- 5.轮询通讯模式开发及注意事项。附:网友制作的类库说明(CHM)

    1.C#跨平台物联网通讯框架ServerSuperIO(SSIO)介绍 <连载 | 物联网框架ServerSuperIO教程>1.4种通讯模式机制. <连载 | 物联网框架Serve ...

  9. 《连载 | 物联网框架ServerSuperIO教程》- 6.并发通讯模式开发及注意事项

    1.C#跨平台物联网通讯框架ServerSuperIO(SSIO)介绍 <连载 | 物联网框架ServerSuperIO教程>1.4种通讯模式机制. <连载 | 物联网框架Serve ...

随机推荐

  1. Hibernate(六)——多对多关联映射

    前面几篇文章已经较讲解了三大种关联映射,多对多映射就非常简单了,不过出于对关联映射完整性的考虑,本文还是会简要介绍下多对多关联映射. 1.单向多对多关联映射 情景:一个用户可以有多个角色,比如数据录入 ...

  2. ZeroClipboard插件:兼容各浏览器网页复制功能

    常规利用JS编写的网页复制功能只对IE有效,无法做到兼容其它浏览器,代码如下: function copyToClipBoard(){ var clipBoardContent="" ...

  3. Java 反射机制[Method反射]

    Java 反射机制[Method反射] 接着上一篇Java 反射机制[Field反射],通过调用Person类的setName方法将obj的name字段的Value设置为"callPerso ...

  4. Android开发:TextView添加超链接的简便方法

    TextView中加入超链接的方式很多,但下面的方式应该的最简便合理的 strings.xml中定义字串 <string name="blog"><a href= ...

  5. 谈论高并发(三十)解析java.util.concurrent各种组件(十二) 认识CyclicBarrier栅栏

    这次谈话CyclicBarrier栅栏,如可以从它的名字可以看出,它是可重复使用. 它的功能和CountDownLatch类别似,也让一组线程等待,然后开始往下跑起来.但也有在两者之间有一些差别 1. ...

  6. 类是公共,它应该被命名为.java文件声明

    当类的设置public时间,,public只要类的文件名必须是相同的,..这种错误可能发生在不同的

  7. linux zombie process相关学习

    1. zombie process是什么? zombie process是那些在系统中已经死掉的process, 通过ps -A | grep defunct可以查看系统中有多少zombie proc ...

  8. XHTML学习笔记

    1.每个网页都是在XML声明和DTD之后以一个<html>标记开始,以一个</html>标记结束 这两个标记表明在它们之间的所有文本都是HTML格式,他告诉浏览器如何理解该文档 ...

  9. SpringMVC与Mybatis框架整合遇到的坑(转)

    最近在做springmvc与mybatis的项目,遇到一些比较坑的问题.花了许多时间却发现其实解决的办法很简单.这里主要是讲我自己在整合这两个框架的时候遇到的一些问题做一个整理.希望遇到和我同样问题的 ...

  10. poj3254(状压dp)

    题目连接:http://poj.org/problem?id=3254 题意:一个矩阵里有很多格子,每个格子有两种状态,可以放牧和不可以放牧,可以放牧用1表示,否则用0表示,在这块牧场放牛,要求两个相 ...