ortp协议 c语言,ortp库使用入门

我们知道, RTP(Real-timeTransportProtocol)是用于Internet上针对多媒体数据流的一种传输协议,做流媒体传输方面的应用离不开RTP协议的实现及使用,为了更加快速地在项目中应用RTP协议实现流媒体的传输,我们一般会选择使用一些RTP库,例如使用c++语言编写的JRTPLIB库,网上关于RTP协议以及JRTPLIB库的介绍已经很多了,在此我也不再赘述,文本主要介绍实现了RTP协议的另一种开源库——ORTP库,这个库是纯使用c语言编写,由于我们的项目是基于Linux下的c语言编程,故我们选择了ortp作为我们的第三方库,在此我也对该库进行一个简单地介绍,希望对其他ortp的初学者有所帮助。一、简介

ORTP是一个支持RTP以及RFC3550协议的库,有如下的特性:

(1)使用C语言编写,可以工作于windows, Linux, 以及 Unix平台

(2)实现了RFC3550协议,提供简单易用的API。支持多种配置,RFC3551为默认的配置。

(3)支持单线程下的多个RTP会话,支持自适应抖动处理。

(4)基于GPL版权声明。

关于ORTP的资料并不多,主要是其源码、帮助文档以及示例程序,关于示例程序说明如下:

rtprecv.c 和 rtpsend.c 展示了如何接收和发送单RTP数据流。

mrtprecv.c mrtpsend.c 展示了如何同时接收和发送多个RTP数据流。二、主要函数介绍

rtp_session_init

函数原型:void rtp_session_init (RtpSession * session, int mode)

函数功能:执行rtp会话的一些必要的初始化工作

参数含义:

session: rtp会话结构体,含有一些rtp会话的基本信息

mode:   传输模式,有以下几种,决定本会话的一些特性。

RTP_SESSION_RECVONLY:只进行rtp数据的接收

RTP_SESSION_SENDONLY:只进行rtp数据的发送

RTP_SESSION_SENDRECV:可以进行rtp数据的接收和发送

执行的操作:

1. 设置rtp包缓冲队列的最大长度

2. 根据传输模式设置标志变量的值

3. 随机产生×××C和同步源描述信息

4. 传入全局的av_profile,即使用默认的profile配置

5. 初始化rtp包缓冲区队列

6. 发送负载类型默认设置为0(pcmu音频),接收负载类型默认设置为-1(未定义)

7. 将session的其他成员的值均设置一个默认值。

rtp_session_set_scheduling_mode

函数原型:void rtp_session_set_scheduling_mode (RtpSession * session, int yesno)

函数功能: RtpScheduler管理多个session的调度和收发的控制,本函数设置是否使用该session调度管理功能。

参数含义:

session:rtp会话结构体

yesno:是否使用rtp session的系统调度功能

说明:

如果yesno为1,则表明使用系统的session调度管理功能,意味着可以使用以下功能:

1. 可以使用session_set_select在多个rtp会话之间进行选择,根据时间戳判定某个会话是否到达了收发的时间。

2. 可以使用rtp_session_set_blocking_mode()设置是否使用阻塞模式来进行rtp包的发送和接收。

如果yesno为0,则表明该会话不受系统管理和调度。

关于rtp session的管理和调度,由全局的变量RtpScheduler *__ortp_scheduler来负责,该变量必须通过ortp_scheduler_init()来进行初始化操作。

rtp_session_set_blocking_mode

函数原型:void rtp_session_set_blocking_mode (RtpSession * session, int yesno)

函数功能:设置是否使用阻塞模式,

参数含义:

session:rtp会话结构体

yesno: 是否使用阻塞模式

说明:

阻塞模式只有在scheduling mode被开启的情况下才能使用,本函数决定了rtp_session_recv_with_ts() 和 rtp_session_send_with_ts()两个函数的行为,如果启用了阻塞模式,则rtp_session_recv_with_ts()会一直阻塞直到接收RTP包的时间点到达(这个时间点由该函数参数中所定义的时间戳来决定),当接收完RTP数据包后,该函数才会返回。同样,rtp_session_send_with_ts()也会一直阻塞直到需要被发送的RTP包的时间点到达,发送结束后,函数才返回。

rtp_session_signal_connect

函数原型:int rtp_session_signal_connect (RtpSession * session, const char *signal,   RtpCallback cb, unsigned long user_data)

函数功能:本函数提供一种方式,用于通知应用程序各种可能发生的RTP事件(信号)。可能通过注册回调函数的形式来实现本功能。

参数含义:

session: rtp会话结构体

signal:信号的名称

cb:回调函数

user_data:传递给回调函数的数据

返回值:0表示成功,-EOPNOTSUPP表示信号名称不存在,-1表示回调函数绑定错误

说明:

信号的名称必须是以下字符串中的一种:

"***c_changed" : 数据流的同步源标识改变

"payload_type_changed" : 数据流的负载类型改变

"telephone-event_packet" : telephone-event RTP包(RFC2833)被接收

"telephone-event": telephone event 发生

"network_error" : 网络错误产生,传递给回调函数的是描述错误的字符串(const char *型)或者错误码(int型)

"timestamp_jump" : 接收到的数据包发生了时间戳的跳跃。

要取消事件(信号)的监听,可以使用下面这个函数

int rtp_session_signal_disconnect_by_callback ( RtpSession * session, const char * signal_name, RtpCallback cb )

rtp_session_set_local_addr

函数原型:int rtp_session_set_local_addr( RtpSession * session, const char * addr,int port)

函数功能:设置本地rtp数据监听地址

参数含义:

session: rtp会话结构体

addr:本地IP地址,例如127.0.0.1,如果为NULL,则系统分配0.0.0.0

port:监听端口,如果设置为-1,则系统为其自动分配端口

返回值: 0表示成功

说明:

如果是RTP_SESSION_SENDONLY(只发送)型会话,则不需要进行本设置,而必须设置rtp_session_set_remote_addr()来设置远程目的地址。

如果采用了系统自动分配监听端口,则可以通过int rtp_session_get_local_port(const RtpSession *session)来获取系统分配的监听端口号。

rtp_session_set_remote_addr

函数原型:int rtp_session_set_remote_addr (RtpSession * session, const char * addr, int port)

函数功能:设置RTP发送的目的地址

参数含义:

session: rtp会话结构体

addr:目的IP地址

port:目的地址的监听端口号

返回值: 0表示成功

rtp_session_set_send_payload_type

函数原型:int rtp_session_set_send_payload_type (RtpSession * session, int paytype)

函数功能:设置RTP发送数据的负载类型

参数含义:

session: rtp会话结构体

paytype:负载类型

返回值: 0表示成功,-1表示负载未定义

说明:

负载类型在payloadtype.h文件中有详细的定义,RTP接收端有着类似的负载类型设置函数,int rtp_session_set_recv_payload_type ( RtpSession * session, int paytype ),注意,发送的负载类型必须与接收的负载类型一致才能正常完成收发。

rtp_session_send_with_ts

函数原型:int rtp_session_send_with_ts (RtpSession * session, const char * buffer, int len,uint32_t userts)

函数功能:发送RTP数据包

参数含义:

session: rtp会话结构体

buffer:需要发送的RTP数据的缓冲区

len:需要发送的RTP数据的长度

userts: 本RTP数据包的时间戳

返回值: 成功发送到网络中的字节数

说明:

发送RTP数据需要自己管理时间戳的递增,每调用一次本函数,请根据实际情况对userts进行递增,具体递增的规则见RTP协议中的说明。

例如:如果发送的是采样率为90000Hz的视频数据包,每秒25帧,则时间戳的增量为:90000/25 = 3600

时间戳的起始值为随机值,建议设置为0 。

rtp_session_recv_with_ts

函数原型:int rtp_session_recv_with_ts (RtpSession * session, char * buffer,int len, uint32_t time, int * have_more)

函数功能:接收RTP数据包

参数含义:

session: rtp会话结构体

buffer:存放接收的RTP数据的缓冲区

len:期望接收的RTP数据的长度

time:   期望接收的RTP数据的时间戳

have_more:标识接收缓冲区是否还有数据没有传递完。当用户给出的缓冲区不够大时,为了标识缓冲区数据未取完,则have_more指向的数据为1,期望用户以同样的时间戳再次调用本函数;否则为0,标识取完。

rtp_session_destroy

【原型】: void rtp_session_destroy(RtpSession *session)

【功能】:摧毁rtp会话对象,释放资源

【参数】:session已经创建的RTP会话对象三、程序示例

下面,我简单地通过程序演示了怎么使用ortp进行rtp数据包的发送,接收端的程序待以后有时间再整理出来吧。

注:示例代码我已经整理出来了,见博文: 《ortp编程示例代码》

//

/// COPYRIGHT NOTICE

// Copyright (c) 2009, 华中科技大学ticktick Group

/// All rights reserved.

///

/// @file    ortpSend.c

/// @brief   ortpSend的测试

///

/// 本文件示例使用ortp库进行rtp数据包的发送

///

/// @version 1.0

/// @author  tickTick

/// @date    2010/07/07

/// @E-mail  lujun.hust@gmail.com

///

/// 修订说明:创建文件

//

#include 

#include 

#include 

#ifndef _WIN32

#include 

#include 

#include 

#endif

// 时间戳增量

#define TIME_STAMP_INC  160

#define BYTES_PER_COUNT 65535

// 时间戳

uint32_t g_user_ts;

/**  初始化

*

*   主要用于对ortp以及其它参数进行初始化

*   @param:  char * ipStr 目的端IP地址描述串

*   @param:  iint port 目的端RTP监听端口

*   @return:  RtpSession * 返回指向RtpSession对象的指针,如果为NULL,则初始化失败

*   @note:

*/

RtpSession * rtpInit(char * ipStr,int port)

{

// Rtp会话对象

RtpSession *session;

char ****c;

// 时间戳初始化

g_user_ts = 0;

// ortp的一些基本初始化操作

ortp_init();

ortp_scheduler_init();

// 创建新的rtp会话对象

session=rtp_session_new(RTP_SESSION_SENDONLY);

rtp_session_set_scheduling_mode(session,1);

rtp_session_set_blocking_mode(session,1);

// 设置远程RTP客户端的的IP和监听端口(即本rtp数据包的发送目的地址)

rtp_session_set_remote_addr(session,ipStr,port);

// 设置负载类型

rtp_session_set_payload_type(session,0);

// 获取同步源标识

***c=getenv("×××C");

if (***c!=NULL)

{

printf("using ×××C=%i.\n",atoi(***c));

rtp_session_set_***c(session,atoi(***c));

}

return session;

}

/**  发送rtp数据包

*

*   主要用于发送rtp数据包

*   @param:  RtpSession *session RTP会话对象的指针

*   @param:  const char *buffer 要发送的数据的缓冲区地址

*   @param: int len 要发送的数据长度

*   @return:  int 实际发送的数据包数目

*   @note:     如果要发送的数据包长度大于BYTES_PER_COUNT,本函数内部会进行分包处理

*/

int rtpSend(RtpSession *session,const char *buffer, int len)

{

int curOffset = 0;

int sendBytes = 0;

int clockslide=500;

// 发送包的个数

int sendCount = 0;

ortp_message("send data len %i\n ",len);

// 是否全部发送完毕

while(curOffset 

{

// 如果需要发送的数据长度小于等于阙值,则直接发送

if( len <= BYTES_PER_COUNT )

{

sendBytes = len;

}

else

{

// 如果当前偏移 + 阈值 小于等于 总长度,则发送阈值大小的数据

if( curOffset + BYTES_PER_COUNT <= len )

{

sendBytes = BYTES_PER_COUNT;

}

// 否则就发送剩余长度的数据

else

{

sendBytes = len - curOffset;

}

}

ortp_message("send data bytes %i\n ",sendBytes);

rtp_session_send_with_ts(session,(char *)(buffer+curOffset),sendBytes,g_user_ts);

// 累加

sendCount ++;

curOffset += sendBytes;

g_user_ts += TIME_STAMP_INC;

// 发送一定数据包后休眠一会

if (sendCount%10==0)

{

usleep(20000);

}

}

return 0;

}

/**  结束ortp的发送,释放资源

*

*   @param:  RtpSession *session RTP会话对象的指针

*   @return:  0表示成功

*   @note:

*/

int rtpExit(RtpSession *session)

{

g_user_ts = 0;

rtp_session_destroy(session);

ortp_exit();

ortp_global_stats_display();

return 0;

}

// 主函数,进行测试

int main()

{

// 待发送的数据缓冲区

char * pBuffer = "123445356234134234532523654323413453425236244123425234";

RtpSession * pRtpSession = NULL;

// 向(192.201.0.51,8000)目的地址发送rtp包

pRtpSession = rtpInit("192.201.0.51",8000);

if(pRtpSession==NULL)

{

printf("error rtpInit");

return 0;

}

// 循环发送

while(1)

{

if( rtpSend(pRtpSession,pBuffer,20) != 0)

{

printf("error rtpInit");

break;

}

usleep(10000);

printf("sleep");

}

// 退出

rtpExit(pRtpSession);

return 0;

}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
本季课程通过移植ORTP并调用ORTP函数来实现H.264裸流数据的网络传输,并且在Windows中安装VLC播放器,并在VLC中通过配置文件的方式来解析ORTP发送的裸流实现视频实时预览。本季课程的核心是ORTP协议的讲解,ORTP的移植、部署和调用,VLC软件的用法讲解和配置文件讲解,Wireshark网络抓包工具的用法讲解,实时视频流传输和解析的体验和编程实现。随着通信行业发展,网速越来越快,网络也从文本时代发展越过语音时代到了现在视频时代,“优酷、爱奇艺”、“微视频”、“直播”等的出现也是视频逐步成为主流媒体的证据和表现。航拍、视频监控、刷脸过关检测、汽车ADAS系统等应用也是视频在主流行业中的应用,因此视频的采集、编解码、传输、识别等技术变得越来越有价值,涌现出了“海康威视”、“大华股份”、“深圳英飞拓”等一批明星企业,名扬海内外,动辄市值几百亿。同时在芯片级,国产华为海思HI35XX系列视频编解码方案也逐步取代进口芯片(如TI、安霸)成为主流方案。视频行业技术含量高、难度大、学习周期长、发展变化快而资料少,因此行业比较缺人、工资较高。如海康威视,普通高校硕士研究生应届进入年薪普遍高于15-20万,在嵌入式linux领域也算高工资技术方向了。本项目是朱老师及其团队推出的一个嵌入式linux领域重量级企业级实战项目,选用华为海思HI3518E方案,结合OV9712/AR0130 Sensor实现图像采集和H.264编码压缩,并通过ethernet和WIFI,以socket实时流和RTSP等方式,实现720P/960P高清视频传输。本项目共分11季,从海思SDK开发环境搭建,到sample程序讲解、SDK中API函数解析,到H.264编解码、RTSP流媒体传输、MP4文件打包,到图像IQ调试、图像识别等视频领域高阶内容,可以说从零基础入手,对图像采集、编解码、网络传输、图像存储和识别做了全方位的详细讲解和代码分析,是目前市面上**一套系统讲解图像和视频技术的视频课程。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值