rtsp服务器源码(rtsp 服务)
本文目录一览:
- 1、如何在win2008中搭建rtsp流媒体服务器?
- 2、linux怎么架设RTSP流媒体服务器
- 3、基于RTP\RTSP数据传输中的丢包现象...
- 4、怎么实现最小的RTSP服务器
- 5、什么是RTSP
- 6、如何实现最小的RTSP服务器
如何在win2008中搭建rtsp流媒体服务器?
用Helix Server做流媒体服务器,搭建过程先参考下,如果不成功,后期我会在csdn上写篇博客,到时候把链接发给你。我搭过很多流媒体服务器,这个就是专门支持rtsp协议的,视频格式为rmvb或rm,音频格式为ra,就是用helix server做流媒体服务器,helix producer plus做视音频编码器,realplayer做客户端播放器,这三个组合起来使用,配置通畅就好了,那么都和你说了用哪些软件了,其实网上都能搜到相关软件的使用说明了,不懂的再问我吧!
linux怎么架设RTSP流媒体服务器
Linux下利用gnump3d架设流媒体服务器
库文件被安装到:/usr/lib/perl5/5.8.6/gnump3d目录
man被安装到:
/usr/man/man1/gnump3d.1
/usr/man/man1/gnump3d-index.1
/usr/man/man1/gnump3d-top.1
/usr/man/man1/gnump3d.conf.1
3、配置
gnump3d的配置文件被存放在/etc/gnump3d/gnump3d.conf ,我们可以对配置文件进行修改。
gnump3d的themes被存放在/usr/share/gnump3d/目录中,所以要想换theme,可以在 gnump3d.conf中指定。
媒体文件存放在目录gnump3d.conf中,是/home/mp3 ,您也可以改为您媒体文件的目录,或者在/home中建一个mp3目录,把所有的媒体文件拷过去。
4、运行gnump3d流媒体服务器
[root@localhost gnump3d-2.9.5]# gnump3d
或
[root@localhost gnump3d-2.9.5]# gnump3d2
5、访问gnump3d流媒体服务器
访问地址是: ,您也可以让局域网的其它电脑来访问,当然要把localhost改为您的机器的IP地址,举例来说,如果您的流媒体服务器所在电脑的IP是192.168.1.6 ,那么,局域网访问地址应该是:
对属性的配置页面:
6、汉化theme让界面变成中文
基于RTP\RTSP数据传输中的丢包现象...
如果是udp的话 发送方丢包可能性不大,可能是路由设备或者客户端接收逻辑垃圾 导致客户端丢码。但是rtp提供了tcp方式传输,如果你tcp方式发现也丢得话,那估计就是发送逻辑的问题。一般都是send的时候返回错误而没有判断造成的。建议使用多线程发送,将网络和其他逻辑分开,网络部分最好使用异步。我做过rtsp服务器,主要就是io线程不能干其他的,这样就能确保数据即时发送出去。当然如果tcp的话带宽限制你发送不了那么快可以适当的从数据源这里就丢一些非关键帧b或者p。这样就能有稍微好点的实时性。
最后一句话,开发rtsp之前要计算好带宽,连接数,码流大小这些数据。
怎么实现最小的RTSP服务器
亲 很高兴为你解答 以下答案有道友提供
//////rtsp.c//////
#include stdio.h
#include stdlib.h
#include string.h
#include memory.h
#include errno.h
#include netdb.h
#include time.h
#include sys/types.h
#include netinet/in.h
#include sys/socket.h
#include arpa/inet.h
#include unistd.h //close()
#include "h264.h"
//#define DEST_PORT 8888
typedef struct
{
int startcodeprefix_len; //, 4 for parameter sets and first slice in picture, 3 for everything else (suggested)
unsigned len; //, Length of the NAL unit (Excluding the start code, which does not belong to the NALU)
unsigned max_size; //, Nal Unit Buffer size
int forbidden_bit; //, should be always FALSE
int nal_reference_idc; //, NALU_PRIORITY_xxxx
int nal_unit_type; //, NALU_TYPE_xxxx
char *buf; //, contains the first byte followed by the EBSP
unsigned short lost_packets; //, true, if packet loss is detected
} NALU_t;
FILE *bits = NULL; //, the bit stream file
static int FindStartCode2 (unsigned char *Buf);//查找开始字符0x000001
static int FindStartCode3 (unsigned char *Buf);//查找开始字符0x00000001
//static bool flag = true;
static int info2=0, info3=0;
RTP_FIXED_HEADER *rtp_hdr;
NALU_HEADER *nalu_hdr;
FU_INDICATOR *fu_ind;
FU_HEADER *fu_hdr;
/**
int sock_init(int sockfd,struct sockaddr_in addr,int SERVER_PORT)
{
sockfd=socket(AF_INET,SOCK_DGRAM,0);
if(sockfd0)
{
fprintf(stderr,"Socket Error:%s\n",strerror(errno));
exit(1);
}
printf("sockfd is %d\n",sockfd);
bzero(addr,sizeof(struct sockaddr_in));
addr.sin_family=AF_INET;
addr.sin_addr.s_addr=htonl(INADDR_ANY);
addr.sin_port=htons(SERVER_PORT);
if(bind(sockfd,(struct sockaddr *)addr,sizeof(struct sockaddr_in))0)
{
fprintf(stderr,"Bind Error:%s\n",strerror(errno));
exit(1);
}
printf("init successfel,,\nport is %dsockfd is %d\n",SERVER_PORT,sockfd);
return 0;
}
*/
char* sock_recv(int sockfd,struct sockaddr *addr_client,int *addrlen)
{
//int *tem_len = addrlen;
socklen_t len;
printf("sock_recv sockfd is %d\n",sockfd);
char *recv_buffer = malloc (sizeof (char));
//printf("sock_recv sockfd is88888888888888 %d\n",sockfd);
int n;
n=recvfrom(sockfd,recv_buffer,256,0,addr_client,len);
//printf("recv number is %d\n",n);
if(0)
{
printf("recvfrom error,\n");
exit (1);
}
if(-1==n)
{
perror("recv error:");
}
else
{
addrlen=(int *)len;
printf("sock recv success,,\n");
/** char IPdotdec[20]; //存放点分十进制IP地址
struct in_addr s =
inet_ntop(AF_INET, (void *)s, IPdotdec, 16);
printf("addr_client.data=%s\n",IPdotdec);
*/ printf("addr_len=%ld\n",addrlen);
}
return recv_buffer;
}
//为NALU_t结构体分配内存空间
NALU_t *AllocNALU(int buffersize)
{
NALU_t *n;
if ((n = (NALU_t*)calloc (1, sizeof (NALU_t))) == NULL)
{
printf("AllocNALU: n");
exit(0);
}
n-max_size=buffersize;
if ((n-buf = (char*)calloc (buffersize, sizeof (char))) == NULL)
{
free (n);
printf ("AllocNALU: n-buf");
exit(0);
}
return n;
}
//释放
void FreeNALU(NALU_t *n)
{
if (n)
{
if (n-buf)
{
free(n-buf);
n-buf=NULL;
}
free (n);
}
}
void OpenBitstreamFile (char *fn)
{
if (NULL == (bits=fopen(fn, "rb")))
{
printf("open file error\n");
exit(0);
}
printf("test264 open successful,\n");
}
//这个函数输入为一个NAL结构体,主要功能为得到一个完整的NALU并保存在NALU_t的buf中,获取他的长度,填充F,IDC,TYPE位。
//并且返回两个开始字符之间间隔的字节数,即包含有前缀的NALU的长度
int GetAnnexbNALU (NALU_t *nalu)
{
int pos = 0;
int StartCodeFound, rewind;
unsigned char *Buf;
if ((Buf = (unsigned char*)calloc (nalu-max_size , sizeof(char))) == NULL)
printf ("GetAnnexbNALU: Could not allocate Buf memory\n");
nalu-startcodeprefix_len=3;//初始化码流序列的开始字符为3个字节
if (3 ,= fread (Buf, 1, 3, bits))//从码流中读3个字节
{
free(Buf);
return 0;
}
info2 = FindStartCode2 (Buf);//判断是否为0x000001
if(info2 ,= 1)
{
//如果不是,再读一个字节
if(1 ,= fread(Buf+3, 1, 1, bits))//读一个字节
{
free(Buf);
return 0;
}
info3 = FindStartCode3 (Buf);//判断是否为0x00000001
if (info3 ,= 1)//如果不是,返回-1
{
free(Buf);
return -1;
}
else
{
//如果是0x00000001,得到开始前缀为4个字节
pos = 4;
nalu-startcodeprefix_len = 4;
}
}
else
{
//如果是0x000001,得到开始前缀为3个字节
nalu-startcodeprefix_len = 3;
pos = 3;
}
//查找下一个开始字符的标志位
StartCodeFound = 0;
info2 = 0;
info3 = 0;
while (,StartCodeFound)
{
if (feof (bits))//判断是否到了文件尾
{
nalu-len = (pos-1)-nalu-startcodeprefix_len;
memcpy (nalu-buf, Buf[nalu-startcodeprefix_len], nalu-len);
nalu-forbidden_bit = nalu-buf[0] 0x80; //1 bit
nalu-nal_reference_idc = nalu-buf[0] 0x60; // 2 bit
nalu-nal_unit_type = (nalu-buf[0]) 0x1f;// 5 bit
free(Buf);
return pos-1;
}
Buf[pos++] = fgetc (bits);//读一个字节到BUF中
info3 = FindStartCode3(Buf[pos-4]);//判断是否为0x00000001
if(info3 ,= 1)
info2 = FindStartCode2(Buf[pos-3]);//判断是否为0x000001
StartCodeFound = (info2 == 1 || info3 == 1);
}
// Here, we have found another start code (and read length of startcode bytes more than we should
// have. Hence, go back in the file
rewind = (info3 == 1)? -4 : -3;
if (0 ,= fseek (bits, rewind, SEEK_CUR))//把文件指针指向前一个NALU的末尾
{
free(Buf);
printf("GetAnnexbNALU: Cannot fseek in the bit stream file");
}
// Here the Start code, the complete NALU, and the next start code is in the Buf.
// The size of Buf is pos, pos+rewind are the number of bytes excluding the next
// start code, and (pos+rewind)-startcodeprefix_len is the size of the NALU excluding the start code
// 不管有没有再次读到 头 ,其主要 关心的还是 nalu-len
nalu-len = (pos+rewind)-nalu-startcodeprefix_len;
memcpy (nalu-buf, Buf[nalu-startcodeprefix_len], nalu-len);//拷贝一个完整NALU,不拷贝起始前缀0x000001或0x00000001
nalu-forbidden_bit = nalu-buf[0] 0x80; //1 bit
nalu-nal_reference_idc = nalu-buf[0] 0x60; // 2 bit
nalu-nal_unit_type = (nalu-buf[0]) 0x1f;// 5 bit
free(Buf);
return (pos+rewind);//返回两个开始字符之间间隔的字节数,即包含有前缀的NALU的长度
}
//输出NALU长度和TYPE
void dump(NALU_t *n)
{
if (,n)return;
//printf("a new nal:");
printf(" len: %d ", n-len);
printf("nal_unit_type: %x\n", n-nal_unit_type);。
什么是RTSP
实时流协议RTSP(RealTimeStreamingProtocol)是由RealNetworks和Netscape共同提出的,该
协议定义了一对多应用程序如何有效地通过IP网络传送多媒体数据。RTSP在体系结构上位于RTP
和RTCP之上,它使用TCP或RTP完成数据传输。HTTP与RTSP相比,HTTP传送HTML,而RTP传送的
是多媒体数据。HTTP请求由客户机发出,服务器作出响应;使用RTSP时,客户机和服务器都可
以发出请求,即RTSP可以是双向的。
6.3 RTSP协议
实时流协议(RTSP)是应用级协议,控制实时数据的发送。RTSP提供了一个可扩展框架,使
实时数据,如音频与视频,的受控、点播成为可能。数据源包括现场数据与存储在剪辑中数据
。该协议目的在于控制多个数据发送连接,为选择发送通道,如UDP、组播UDP与TCP,提供途径
,并为选择基于RTP上发送机制提供方法。
6.3.1 简介
6.3.1.1 目的
实时流协议(RTSP)建立并控制一个或几个时间同步的连续流媒体。尽管连续媒体流与控制
流交*是可能的,通常它本身并不发送连续流。换言之,RTSP充当多媒体服务器的网络远程控
制。RTSP连接没有绑定到传输层连接,如TCP。在RTSP连接期间,RTSP用户可打开或关闭多个对
服务器的可*传输连接以发出RTSP 请求。此外,可使用无连接传输协议,如UDP。RTSP流控制
的流可能用到RTP,但RTSP操作并不依赖用于携带连续媒体的传输机制。实时流协议在语法和操
作上与HTTP/1.1类似,因此HTTP的扩展机制大都可加入RTSP。协议支持的操作如下:
从媒体服务器上检索媒体:
用户可通过HTTP或其它方法提交一个演示描述。如演示是组播,演示式就包含用于连续媒体
的的组播地址和端口。如演示仅通过单播发送给用户,用户为了安全应提供目的地址。
媒体服务器邀请进入会议:
媒体服务器可被邀请参加正进行的会议,或回放媒体,或记录其中一部分,或全部。这种模
式在分布式教育应用上很有用,会议中几方可轮流按远程控制按钮。
将媒体加到现成讲座中:
如服务器告诉用户可获得附加媒体内容,对现场讲座显得尤其有用。如HTTP/1.1中类似,RTSP
请求可由代理、通道与缓存处理。
6.3.1.2 协议特点
RTSP 特性如下:
可扩展性:
新方法和参数很容易加入RTSP。
易解析:
RTSP可由标准 HTTP或MIME解吸器解析。
安全:
RTSP使用网页安全机制。
独立于传输:
RTSP可使用不可*数据报协议(UDP)、可*数据报协议(RDP),如要实现应用级可*,可
使用可*流协议。
多服务器支持:
每个流可放在不同服务器上,用户端自动同不同服务器建立几个并发控制连接,媒体同步在
传输层执行。
记录设备控制:
协议可控制记录和回放设备。
流控与会议开始分离:
仅要求会议初始化协议提供,或可用来创建唯一会议标识号。特殊情况下, SIP或H.323
可用来邀请服务器入会。
适合专业应用:
通过SMPTE 时标,RTSP支持帧级精度,允许远程数字编辑
演示描述中立:
协议没强加特殊演示或元文件,可传送所用格式类型;然而,演示描述至少必须包含一个RTSP
URI。
代理与防火墙友好:
协议可由应用和传输层防火墙处理。防火墙需要理解SETUP方法,为UDP媒体流打开一个"缺
口"。
HTTP友好:
此处,RTSP明智的采用HTTP观念,使现在结构都可重用。结构包括Internet 内容选择平台
(PICS)。由于在大多数情况下控制连续媒体需要服务器状态, RTSP不仅仅向HTTP 添加方法
。 适当的服务器控制:
如用户启动一个流,他必须也可以停止一个流。
传输协调;
实际处理连续媒体流前,用户 可协调传输方法。
性能协调:
如基本特征无效,必须有一些清理机制让用户决定那种方法没生效。这允许用户提出适合的
用户界面。
6.3.1.3扩展RTSP
由于不是所有媒体服务器有着相同的功能,媒体服务器有必要支持不同请求集。RTSP 可以
如下三种方式扩展,这里以改变大小排序:
以新参数扩展。如用户需要拒绝通知,而方法扩展不支持,相应标记就加入要求的段中。
加入新方法。如信息接收者不理解请求,返回501错误代码(还未实现),发送者不应再次
尝试这种方法。用户可使用OPTIONS方法查询服务器支持的方法。服务器使用公共响应头列出支
持的方法。
定义新版本协议,允许改变所有部分。(除了协议版本号位置)
6.3.1.4操作模式
每个演示和媒体流可用RTSP URL识别。演示组成的整个演示与媒体属性由演示描述文件定义
。使用HTTP或其它途径用户可获得这个文件,它没有必要保存在媒体服务器上。
为了说明,假设演示描述描述了多个演示,其中每个演示维持了一个公共时间轴。为简化说
明,且不失一般性,假定演示描述的确包含这样一个演示。演示可包含多个媒体流。除媒体参
数外,网络目标地址和端口也需要决定。下面区分几种操作模式:
单播:
以用户选择的端口号将媒体发送到RTSP请求源。
组播,服务器选择地址:
媒体服务器选择组播地址和端口,这是现场直播或准点播常用的方式。
组播,用户选择地址:
如服务器加入正在进行的组播会议,组播地址、端口和密匙由会议描述给出。
6.3.1.5 RTSP状态
RTSP控制通过单独协议发送的流,与控制通道无关。例如,RTSP控制可通过TCP连接,而数
据流通过UDP。因此,即使媒体服务器没有收到请求,数据也会继续发送。在连接生命期,单个
媒体流可通过不同TCP连接顺序发出请求来控制。所以,服务器需要维持能联系流与RTSP请求的
连接状态。RTSP中很多方法与状态无关,但下列方法在定义服务器流资源的分配与应用上起着
重要的作用:
SETUP:
让服务器给流分配资源,启动RTSP连接。
PLAY与RECORD:
启动SETUP 分配流的数据传输。
PAUSE:
临时停止流,而不释放服务器资源。
TEARDOWN:
释放流的资源,RTSP连接停止。
标识状态的RTSP方法使用连接头段识别RTSP连接,为响应SETUP请求,服务器连
接产生连接标识。
6.3.1.6 与其他协议关系
RTSP在功能上与HTTP有重叠,与HTTP相互作用体现在与流内容的初始接触是通过网页的。目
前的协议规范目的在于允许在网页服务器与实现RTSP媒体服务器之间存在不同传递点。例如,
演示描述可通过HTTP和RTSP检索,这降低了浏览器的往返传递,也允许独立RTSP 服务器与用户
不全依*HTTP。
但是,RTSP与HTTP 的本质差别在于数据发送以不同协议进行。HTTP是不对称协议,用户发
出请求,服务器作出响应。RTSP中,媒体用户和服务器都可发出请求,且其请求都是无状态的
;在请求确认后很长时间内,仍可设置参数,控制媒体流。重用HTTP功能至少在两个方面有好
处,即安全和代理。要求非常接近,在缓存、代理和授权上采用HTTP功能是有价值的。
当大多数实时媒体使用RTP作为传输协议时,RTSP没有绑定到RTP。RTSP假设存在演示描述格
式可表示包含几个媒体流的演示的静态与临时属性。
6.3.2 协议参数
6.3.3 RTSP 信息
RTSP是基于文本的协议,采用ISO 10646 字符集,使用UTF-8编码方案。行以CRLF中断,但
接收者本身可将CR和LF解释成行终止符。基于文本的协议使以自描述方式增加可选参数更容易
。由于参数的数量和命令的频率出现较低,处理效率没引起注意。如仔细研究,文本协议很容
易以脚本语言(如:Tcl、Visual Basic与Perl)实现研究原型。
10646字符集避免敏感字符集切换,但对应用来说不可见。RTCP也采用这种编码方案。带有
重要意义位的ISO 8859-1字符表示如100001x 10xxxxxx.。RTSP信息可通过任何低层传输协议
携带。
请求包括方法、方法作用于其上的对象和进一步描述方法的参数。方法也可设计为在服务器
端只需要少量或不需要状态维护。当信息体包含在信息中,信息体长度有如下因素决定:
不管实体头段是否出现在信息中,不包括信息体的的响应信息总以头段后第一和空行结束。
如出现内容长度头段,其值以字节计,表示信息体长度。如未出现头段,其值为零。
服务器关闭连接。
注意:RTSP目前并不支持HTTP/1.1"块"传输编码,需要有内容长度头。假如返回适度演示描
述长度,即使动态产生,使块传输编码没有必要,服务器也应该能决定其长度。如有实体,即
使必须有内容长度,且长度没显式给出,规则可确保行为合理。
从用户到服务器端的请求信息在第一行内包括源采用的方法、源标识和所用协议版本。RTSP
定义了附加状态代码,而没有定义任何HTTP代码。
6.3.4 实体
如不受请求方法或响应状态编码限制,请求和响应信息可传输实体,实体由实体头文件和试
题体组成,有些响应仅包括实体头。在此,根据谁发送实体、谁接收实体,发送者和接收者可
分别指用户和服务器。
实体头定义实体体可选元信息,如没有实体体,指请求标识的资源。扩展头机制允许定义附
加实体头段,而不用改变协议,但这些段不能假定接收者能识别。不可识别头段应被接收者忽
略,而让代理转发。
6.3.5 连接
RTSP请求可以几种不同方式传送:
1、持久传输连接,用于多个请求/响应传输。
2、每个请求/响应传输一个连接。
3、无连接模式。
传输连接类型由RTSP URI来定义。对 "rtsp" 方案,需要持续连接;而"rtspu"方案,调用
RTSP 请求发送,而不用建立连接。
不象HTTP,RTSP允许媒体服务器给媒体用户发送请求。然而,这仅在持久连接时才支持,否
则媒体服务器没有可*途径到达用户,这也是请求通过防火墙从媒体服务器传到用户的唯一途
径。
6.3.6 方法定义
方法记号表示资源上执行的方法,它区分大小写。新方法可在将来定义,但不能以$开头。
某些防火墙设计与其他环境可能要求服务器插入RTSP方法和流数据。由于插入将使客户端和
服务器操作复杂,并强加附加开销,除非有必要,应避免这样做。插入二进制数据仅在RTSP通
过TCP传输时才可使用。流数据(如RTP包)用一个ASCII美圆符号封装,后跟一个一字节通道标
识,其后是封装二进制数据的长度,两字节整数。
如何实现最小的RTSP服务器
RTSPServer类用于构建一个RTSP服务器,该类同时在其内部定义了一个RTSPClientSession类,用于处理单独的客户会话。
首先创建RTSP服务器(具体实现类是DynamicRTSPServer),在创建过程中,先建立Socket(ourSocket)在TCP的554 端口进行监听,然后把连接处理函数句柄(RTSPServer::incomingConnectionHandler)和socket句柄传给任务调度器(taskScheduler)。
任务调度器把socket句柄放入后面select调用中用到的socket句柄集(fReadSet)中,同时将socket句柄和 incomingConnectionHandler句柄关联起来。 接着,主程序开始进入任务调度器的主循环(doEventLoop),在主循环中调用系统函数select阻塞,等待网络连接。
当RTSP客户端输入( rtsp://192.168.0.1/1.mpg)连接服务器时,select返回对应的scoket,进而根据前面保存的对应关系,可找到对应处理函数句柄,这里就是前面提到的incomingConnectionHandler了。在 incomingConnectionHandler中创建了RTSPClientSession,开始对这个客户端的会话进行处理。