myRtspClient通过简单修改JRTPLIB的官方例程作为其RTP传输层实现。因为JRTPLIB使用的是CMAKE编译工具,这就是为什么编译myRtspClient时需要预装CMAKE。

该部分所有代码均集中在myRtpSession.cpp中,接下来将对其进行分析。

一、获取RTP数据

此处GetMyRTPData获取数据的方式主要是轮询,即每隔USLEEP_UNIT个微秒轮询一次直到获取到一包数据或超时,超时时间为timeout_ms,单位是微秒。

GetMyRTPPacket的逻辑与之相同,但是会比前者多获取RTP消息头,对于myRtspClient的用户来说,这同样也就是RtspClient::GetMediaPacket和RtspClient::GetMediaData的区别(逻辑相同,GetMyRTPPacket的代码就不再此附上了)。

RtspClient::GetMediaPacket和RtspClient::GetMediaData最终获取RTP数据就是通过调用这两个函数完成的。

 uint8_t * MyRTPSession::GetMyRTPData(uint8_t * data_buf, size_t * size, unsigned long timeout_ms)
{
if(!data_buf) {
fprintf(stderr, "%s: Invalide argument('data_buf==NULL')", __func__);
return NULL;
} if(!size) {
fprintf(stderr, "%s: Invalide argument('size==NULL')", __func__);
return NULL;
} unsigned long UsleepTimes = (timeout_ms + USLEEP_UNIT - ) / USLEEP_UNIT; // floor the 'timeout_ms / USLEEP_UNIT' do {
#ifndef RTP_SUPPORT_THREAD
int status = Poll();
if(!IsError(status)) return NULL;
#endif BeginDataAccess(); // check incoming packets
if (!GotoFirstSourceWithData()) {
EndDataAccess();
usleep(USLEEP_UNIT);
UsleepTimes--;
continue;
// return NULL;
}
RTPPacket *pack; if(!(pack = GetNextPacket()))
{
EndDataAccess();
usleep(USLEEP_UNIT);
UsleepTimes--;
continue;
// return NULL;
} size_t PacketSize = ;
uint8_t * Packet = NULL;
Packet = pack->GetPayloadData();
PacketSize = pack->GetPayloadLength();
// printf("data length: %lu\n", PacketSize); *size = PacketSize;
memcpy(data_buf, Packet, PacketSize); // we don't longer need the packet, so
// we'll delete it
DeletePacket(pack);
EndDataAccess();
UsleepTimes = ; // Got the data. So not need to sleep any more.
} while(UsleepTimes > ); return data_buf;
}

二、会话建立、结束等接口

此处的MyRTP_SetUp的作用是建立会话,它会确定RTP/RTCP的UDP端口,建立通信socket。每当RTSP的SETUP命令设置成功后,都会调用此函数。
 int MyRTPSession::MyRTP_SetUp(MediaSession * media_session)
{
if(!media_session) {
fprintf(stderr, "%s: Invalid media session\n", __func__);
return RTP_ERROR;
}
if( == media_session->TimeRate) {
fprintf(stderr, "%s: Invalid MediaSession::TimeRate\n", __func__);
return RTP_ERROR;
}
if( == media_session->RTPPort) {
fprintf(stderr, "%s: Invalid MediaSession::RTPPort\n", __func__);
return RTP_ERROR;
} int status; // Now, we'll create a RTP session, set the destination
// and poll for incoming data. RTPUDPv4TransmissionParams transparams;
RTPSessionParams sessparams; // IMPORTANT: The local timestamp unit MUST be set, otherwise
// RTCP Sender Report info will be calculated wrong
// In this case, we'll be just use 8000 samples per second.
sessparams.SetOwnTimestampUnit(1.0/media_session->TimeRate); sessparams.SetAcceptOwnPackets(true);
transparams.SetPortbase(media_session->RTPPort);
status = Create(sessparams,&transparams);
return IsError(status);
}

客户端通过MyRTP_Teardown发起销毁会话,每当RTSP的TEARDOWN命令设置成功后,都会调用此函数。

 void MyRTPSession::MyRTP_Teardown(MediaSession * media_session, struct timeval * tval)
{
struct timeval Timeout; if(!tval) {
Timeout.tv_sec = ;
Timeout.tv_usec = ;
} else {
Timeout.tv_sec = tval->tv_sec;
Timeout.tv_usec = tval->tv_usec;
} media_session->RTPPort = ;
BYEDestroy(RTPTime(Timeout.tv_sec, Timeout.tv_usec), , );
}

客户端通过OnBYEPacket被动销毁会话,当服务器向客户端发送BYE的RTP数据包时(比如当一段媒体流播放完的时候),该函数就会被调用。其中DestroiedClbk是myRtspClient提供给用户的回调接口。用户可以通过调用RtspClient::SetAudioByeFromServerClbk/RtspClient::SetVideoByeFromServerClbk来设置该函数。(逻辑相同,OnRemoveSource的代码就不再此附上了)。

 void MyRTPSession::OnBYEPacket(RTPSourceData *dat)
{
if (dat->IsOwnSSRC())
return; uint32_t ip;
uint16_t port; if (dat->GetRTPDataAddress() != )
{
const RTPIPv4Address *addr = (const RTPIPv4Address *)(dat->GetRTPDataAddress());
ip = addr->GetIP();
port = addr->GetPort();
}
else if (dat->GetRTCPDataAddress() != )
{
const RTPIPv4Address *addr = (const RTPIPv4Address *)(dat->GetRTCPDataAddress());
ip = addr->GetIP();
port = addr->GetPort()-;
}
else
return; RTPIPv4Address dest(ip,port);
DeleteDestination(dest); struct in_addr inaddr;
inaddr.s_addr = htonl(ip);
std::cout << "Deleting destination " << std::string(inet_ntoa(inaddr)) << ":" << port << std::endl;
if(DestroiedClbk) {
DestroiedClbk();
}
}

每当新加入一个RTP数据源,OnNewSource就会被调用

 void MyRTPSession::OnNewSource(RTPSourceData *dat)
{
if (dat->IsOwnSSRC())
return; uint32_t ip;
uint16_t port; if (dat->GetRTPDataAddress() != )
{
const RTPIPv4Address *addr = (const RTPIPv4Address *)(dat->GetRTPDataAddress());
ip = addr->GetIP();
port = addr->GetPort();
}
else if (dat->GetRTCPDataAddress() != )
{
const RTPIPv4Address *addr = (const RTPIPv4Address *)(dat->GetRTCPDataAddress());
ip = addr->GetIP();
port = addr->GetPort()-;
}
else
return; RTPIPv4Address dest(ip,port);
AddDestination(dest); struct in_addr inaddr;
inaddr.s_addr = htonl(ip);
std::cout << "Adding destination " << std::string(inet_ntoa(inaddr)) << ":" << port << std::endl;
}

上一篇                回目录

一个基于JRTPLIB的轻量级RTSP客户端(myRTSPClient)——实现篇:(十)使用JRTPLIB传输RTP数据的更多相关文章

  1. 一个基于JRTPLIB的轻量级RTSP客户端(myRTSPClient)——实现篇:(八)RTP音视频传输解析层之MPA传输格式

    一.MPEG RTP音频传输 相较H264的RTP传输格式,MPEGE音频传输格式则简单许多. 每一包MPEG音频RTP包都前缀一个4字节的Header,如下图(RFC2550) “MBZ”必须为0( ...

  2. 一个基于JRTPLIB的轻量级RTSP客户端(myRTSPClient)——实现篇:(七)RTP音视频传输解析层之H264传输格式

    一.H264传输封包格式的2个概念 (1)组包模式(Packetization Modes) RFC3984中定义了3种组包模式:单NALU模式(Single Nal Unit Mode).非交错模式 ...

  3. 一个基于JRTPLIB的轻量级RTSP客户端(myRTSPClient)——实现篇:(六)RTP音视频传输解析层之音视频数据传输格式

    一.差异 本地音视频数据格式和用来传输的音视频数据格式存在些许差异,由于音视频数据流到达客户端时,需要考虑数据流的数据边界.分包.组包顺序等问题,所以传输中的音视频数据往往会多一些字节. 举个例子,有 ...

  4. 一个基于JRTPLIB的轻量级RTSP客户端(myRTSPClient)——实现篇:(五)用户接口层之提取媒体流数据

    当RTSP客户端向RTSP服务端发送完PLAY命令后,RTSP服务端就会另外开启UDP端口(SDP协商定义的端口)发送RTP媒体流数据包.这些数据包之间会间隔一段时间(毫秒级)陆续被发送到RTSP客户 ...

  5. 一个基于JRTPLIB的轻量级RTSP客户端(myRTSPClient)——实现篇:(四)用户接口层之处理SDP报文

    当RTSP客户端向RTSP服务端发送DESCRIBE命令时,服务端理应当回复一条SDP报文. 该SDP报文中包含RTSP服务端的基本信息.所能提供的音视频媒体类型以及相应的负载能力,以下是一段SDP示 ...

  6. 一个基于JRTPLIB的轻量级RTSP客户端(myRTSPClient)——实现篇:(一)概览

    myRTSPClient主要可以分成3个部分: 1. RTSPClient用户接口层: 2. RTP 音视频传输解析层: 3. RTP传输层. "RTSPClient用户接口层": ...

  7. 一个基于JRTPLIB的轻量级RTSP客户端(myRTSPClient)——实现篇:(九)以g711-mulaw为例添加新的编码格式解析支持

    一.myRtspClient音频解析架构 AudioTypeBase是处理解析各种编码的音频数据的接口类.处理MPA数据的MPEG_Audio类和处理g711-mulaw的PCMU_Audio类均从A ...

  8. 一个基于JRTPLIB的轻量级RTSP客户端(myRTSPClient)——解码篇:(一)用ffmpeg解码视频

    一.概述 myRTSPClient(RTSPClient)获取音视频数据之后,接下来的工作便是将音视频数据交给解码器去解码(ffmpeg),ffmpeg解码之后于是便有了呈现在终端用户(USER)面前 ...

  9. 一个基于JRTPLIB的轻量级RTSP客户端(myRTSPClient)——实现篇:(二)用户接口层之RtspClient类及其构造函数

    RtspClient类是myRTSPClient函数库所有特性集中实现的地方. 主要为用户提供: 1. RTSP协议通信接口函数,如DoOPTIONS(): 2. RTSP账号.密码设置函数,如Set ...

随机推荐

  1. day_5.14 py 飞机大战Demo

    飞机未完,继续做 2018-5-14 21:05:45 明天继续       循环里面的坑; 删除列表元素后循环了打印的不一样,主要是比如相邻的删除了,33,44 删除33 循环一次后44跑到33位置 ...

  2. eclipse下配置Spring环境

    工具: jdk1.8 win10 spring5.0 1.准备工作:下载Spring开发应用的插件,api 1.spring插件包:springsource-tool-suite-3.9.4.RELE ...

  3. Flask web开发之路九

    flask_scripts介绍 项目结构如下: flask_script_demo.py文件: from flask import Flask app = Flask(__name__) @app.r ...

  4. ABP之事件总线(1)

    什么是事件总线呢?官方的文档说,它是一个单例对象,由其他的类共同拥有,可以用来触发和处理事件.这个东西确实比较陌生,为什么要使用事件总线,或者说事件总线的优势是什么???首先我们可以明确的是,事件总线 ...

  5. 2018ACM-ICPC南京区域赛---AJGIDKM

    含[最小球覆盖][最大流isap]模板. 题面pdf https://codeforc.es/gym/101981/attachments/download/7891/20182019-acmicpc ...

  6. 使用Kdenlive为视频加入马赛克特效

    Kdenlive(KDE Non-Linear Video Editor)是一种基于MLT框架.KDE和Qt的自由开源的非线性影片编辑器.其底层包含了FFmpeg,所以可以支持FFmpeg中的所有视频 ...

  7. [No0000172]Android Studio设置HTTP代理(可用)

    android SDK下载:http://www.androiddevtools.cn . 禁止第一次启动 到AS安装目录,打开bin目录,编辑idea.properties, 在文件末尾添加: di ...

  8. CentOS-6.9安装配置JDK-7

    CentOS-6.9安装配置JDK-7 安装说明 系统环境:centos-6.9安装方式:rpm安装 软件:jdk-7u79-linux-x64.rpm下载地址:http://download.ora ...

  9. 2012年蓝桥杯省赛A组c++第4题(电视台答题比赛)

    /* 某电视台举办了低碳生活大奖赛.题目的计分规则相当奇怪: 每位选手需要回答10个问题(其编号为1到10),越后面越有难度. 答对的,当前分数翻倍:答错了则扣掉与题号相同的分数(选手必须回答问题,不 ...

  10. [security] security engine things

    1. luarock luarock 之于 lua,就好比 pip 之于 python https://luarocks.org/ 2.  lua的库 [root@base package]# ls ...