实时传输协议(RTP)和实时控制协议(RTCP)

RTP是一种提供端对端传输服务的实时传输协议,用来支持在单目标广播和多目标广播网络服务中传输实时数据,而实时数据的传输则由RTCP协议来监视和控制。

RTP定义在RFC

使用RTP协议的应用程序运行在RTP之上,而执行RTP的程序运行在UDP的上层,目的是为了使用UDP的端口号和检查和。如图16-12所示,RTP可以看成是传输层的子层。由多媒体应用程序生成的声音和电视数据块被封装在RTP信息包中,每个RTP信息包被封装在UDP消息段中,然后再封装在IP数据包中。

1889中。信息包的结构包含广泛用于多媒体的若干个域,包括声音点播(audio-on-demand)、影视点播(video ondemand)、因特网电话(Internettelephony)和电视会议(videoconferencing)。RTP的规格没有对声音和电视的压缩格式制定标准,它可以被用来传输普通格式的文件。例如,WAV或者GSM(Global System forMobilecommunications)格式的声音、MPEG-1和MPEG-2的电视,也可以用来传输专有格式存储的声音和电视文件。

 

TCP/IP模型

 

应用层(application)

传输层

RTP

 

UDP

 

IP

 

数据链路层(data link)

 

物理层(physical)

图16-12 RTP是传输层上的协议

从应用开发人员的角度来看,可把RTP执行程序看成是应用程序的一部分,因为开发人员必需把RTP集成到应用程序中。在发送端,开发人员必需把执行RTP协议的程序写入到创建RTP信息包的应用程序中,然后应用程序把RTP信息包发送到UDP的套接接口(socketinterface),如图16-13所示;同样,在接收端,RTP信息包通过UDP套接接口输入到应用程序,因此开发人员必需把执行RTP协议的程序写入到从RTP信息包中抽出媒体数据的应用程序。

TCP/IP模型

 

应用层(application)

 

RTP

 

套接接口

UDP

 

IP

 

数据链路层(data link)

 

物理层(physical)

 

图16-13 RTP和UDP之间的接口

现以用RTP传输声音为例来说明它的工作过程。假设音源的声音是64kb/s的PCM编码声音,并假设应用程序取20毫秒的编码数据为一个数据块(chunk),即在一个数据块中有160个字节的声音数据。应用程序需要为这块声音数据添加RTP标题生成RTP信息包,这个标题包括声音数据的类型、顺序号和时间戳。然后RTP信息包被送到UDP套接接口,在那里再被封装在UDP信息包中。在接收端,应用程序从套接接口处接收RTP信息包,并从RTP信息包中抽出声音数据块,然后使用RTP信息包的标题域中的信息正确地译码和播放声音。

如果应用程序不使用专有的方案来提供有效载荷类型(payloadtype)、顺序号或者时间戳,而是使用标准的RTP协议,应用程序就更容易与其他的网络应用程序配合运行,这是大家都希望的事情。例如,如果有两个不同的公司都在开发因特网电话软件,他们都把RTP合并到他们的产品中,这样就有希望:使用不同公司电话软件的用户之间能够进行通信。

这里需要强调的是,RTP本身不提供任何机制来确保把数据及时递送到接收端或者确保其他的服务质量,它也不担保在递送过程中不丢失信息包或者防止信息包的次序不被打乱。的确,RTP的封装只是在系统端才能看到,中间的路由器并不区分那个IP数据报是运载RTP信息包的。

RTP允许给每个媒体源分配一个单独的RTP信息包流,例如,摄像机或者麦克风。例如,有两个团体参与的电视会议,这就可能打开4个信息包流:两台摄像机传送电视流和两个麦克风传送声音流。然而,许多流行的编码技术,包括MPEG-1和MPEG-2在编码过程中都把声音和电视图像捆绑在一起以形成单一的数据流,一个方向就生成一个RTP信息包流。

RTP信息包没有被限制只可应用于单目标广播,它们也可以在一对多(one-to-many)的多目标广播树或者在多对多(many-to-many)的多目标广播树上传送。例如,多对多的多目标广播,在这种应用场合下,所有发送端通常都把他们的RTP信息包流发送到具有相同多目标广播地址的多目标广播树上。

16.6.2 RTP信息包标题域

RTP标题由4个信息包标题域和其他域组成:有效载荷类型(payload type)域,顺序号(sequencenumber)域,时间戳(timestamp)域和同步源标识符(Synchronization SourceIdentifier)域等。RTP信息包的标题域的结构如下图所示:

Payload

Type
(有效载荷类型)

Sequence Number

(顺序号)

Timestamp

(时间戳)

Synchronization Source Identifier
(同步源标识符)

Miscellaneous Fields
(其他)

 

1. 有效载荷类型

RTP信息包中的有效载荷域(Payload TypeField)的长度为7位,因此RTP可支持128种不同的有效载荷类型。对于声音流,这个域用来指示声音使用的编码类型,例如PCM、自适应增量调制或线性预测编码等等。如果发送端在会话或者广播的中途决定改变编码方法,发送端可通过这个域来通知接收端。表16-01列出了目前RTP所能支持的声音有效载荷类型。

表16-01目前RTP所能支持的声音有效载荷类型

有效载荷号

声音类型

采样率(kHz)

数据率(kb/s)

0

PCM mu-law

8

64

1

1016

8

4.8

2

G.721

8

32

3

GSM

8

32

6

DVI

16

64

7

LPC

8

2.4

9

G.722

8

48~64

14

MPEG Audio

90

-

15

G.728

8

16

对电视流,有效载荷类型可以用来指示电视编码的类型,例如motion JPEG,MPEG-1,MPEG-2或者H.231等等。发送端也可以在会话或者期间随时改变电视的编码方法。表16-02列出了目前RTP所能支持的某些电视有效载荷类型。

表16-02目前RTP所能支持的声音有效载荷类型

有效载荷号

电视格式

26

Motion JPEG

28

-

31

H.261

32

MPEG-1 video

33

MPEG-2 video

 

2. 顺序号

顺序号(Sequence NumberField)域的长度为16位。每发送一个RTP信息包顺序号就加1,接收端可以用它来检查信息包是否有丢失以及按顺序号处理信息包。例如,接收端的应用程序接收到一个RTP信息包流,这个RTP信息包在顺序号86和89之间有一个间隔,接收端就知道信息包87和88已经丢失,并且采取措施来处理丢失的数据。

3. 时间戳

时间戳(Timestamp)域的长度为32字节。它反映RTP数据信息包中第一个字节的采样时刻(时间)。接收端可以利用这个时间戳来去除由网络引起的信息包的抖动,并且在接收端为播放提供同步功能。

4. 同步源标识符

同步源标识符(SynchronizationSourceIdentifier,SSRC)域的长度为32位。它用来标识RTP信息包流的起源,在RTP会话或者期间的每个信息包流都有一个清楚的SSRC。SSRC不是发送端的IP地址,而是在新的信息包流开始时源端随机分配的一个号码。

16.6.3 实时传输控制协议

实时传输控制协议(Real-timeControl Protocol,RTCP)也定义在1996年提出的RFC1889中。多媒体网络应用把RTCP和RTP一起使用,尤其是在多目标广播中更具吸引力。当从一个或者多个发送端向多个接收端广播声音或者电视时,也就是在RTP会话期间,每个参与者周期性地向所有其他参与者发送RTCP控制信息包,如图16-14所示。RTCP用来监视服务质量和传送有关与会者的信息。对于RTP会话或者广播,通常使用单个多目标广播地址,属于这个会话的所有RTP和RTCP信息包都使用这个多目标广播地址,通过使用不同的端口号可把RTP信息包和RTCP信息包区分开来。

RTCP的主要功能是为应用程序提供会话质量或者广播性能质量的信息。每个RTCP信息包不封装声音数据或者电视数据,而是封装发送端和/或者接收端的统计报表。这些信息包括发送的信息包数目、丢失的信息包数目和信息包的抖动等情况,这些反馈信息对发送端、接收端或者网络管理员都是很有用的。RTCP规格没有指定应用程序应该使用这个反馈信息做什么,这完全取决于应用程序开发人员。例如,发送端可以根据反馈信息来修改传输速率,接收端可以根据反馈信息判断问题是本地的、区域性的还是全球性的,网络管理员也可以使用RTCP信息包中的信息来评估网络用于多目标广播的性能。

16.6.4 实时流放协议

实时流放协议(Real-Time StreamingProtocol,RTSP)是一个刚开始开发的协议,它的设想描述在RFC

播放的数据流被分成许多信息包,信息包的大小很适用于客户机和服务器之间的带宽。当客户机已经接收到足够多的信息包之后,用户软件就可开始播放一个信息包,同时对另一个信息包解压缩和接收第三个信息包。这样用户就不需要把整个媒体文件从服务器上下载之后就可立即播放。广播源可以是现场的数据流也可以是存储的数据流。

RTSP协议想要提供控制多种应用数据传送的功能,提供一种选择传送通道的方法,例如UDP, TCP,IP多目标广播通道,以及提供一种基于RTP协议的递送方法。正在设计的RTSP将工作在RTP的上层,用来控制和传送实时的内容。

RTSP能够与资源保留协议一起使用,用来设置和管理保留带宽的流式会话或者广播。

2326文件中。RTSP是应用级的实时流放协议,它主要目标是为单目标广播和多目标广播上的流式多媒体应用提供牢靠的播放性能,以及支持不同厂家提供的客户机和服务机之间的协同工作能力。

在windows使用vs2008编译live555

在windows使用vs2008编译live555
1.live555 源代码简介
liveMedia项目的源代码包括四个基本的库,各种测试代码以及IVE555 Media Server。

四个基本的库分别是UsageEnvironment&TaskScheduler,groupsock,liveMedia,BasicUsageEnvironment。

UsageEnvironment和TaskScheduler类用于事件的调度,实现异步读取事件的句柄的设置以及错误信息的输出。另外,还有一个HashTable类定义了一个通用的hash表,其它代码要用到这个表。这些都是抽象类,在应用程序中基于这些类实现自己的子类。

groupsock类是对网络接口的封装,用于收发数据包。正如名字本身,Groupsock主要是面向多播数据的收发的,它也同时支持单播数据的收发。Groupsock定义了两个构造函数

 Groupsock(UsageEnvironment& env, struct in_addrconst& groupAddr,
           Port port,u_int8_t ttl);
   Groupsock(UsageEnvironment& env, struct in_addrconst& groupAddr,
           structin_addr const& sourceFilterAddr,
           Portport);
前者是用于SIM(source-independent multicast)组,后者用于SSM(source-specificmulticast)组。groupsock库中的Helper例程提供了读写socket等函数,并且屏蔽了不同的操作系统之间的区别,这是在GroupsockHelper.cpp文件中实现的。

liveMedia库中有一系列类,基类是Medium,这些类针对不同的流媒体类型和编码。

各种测试代码在testProgram目录下,比如openRTSP等,这些代码有助于理解liveMedia的应用。

LIVE555 Media Server是一个纯粹的RTSP服务器。支持多种格式的媒体文件:

   * TS流文件,扩展名ts。
     * PS流文件,扩展名mpg。
     * MPEG-4视频基本流文件,扩展名m4e。
     * MP3文件,扩展名mp3。
     * WAV文件(PCM),扩展名wav。
     * AMR音频文件,扩展名.amr。
     * AAC文件,ADTS格式,扩展名aac。
2.在windows下编译live555
  (1).下载 live555,http://www.live555.com/
    (2). 编辑win32config,TOOLS32=C:\Program Files\Microsoft Visual Studio9.0\VC
       即保证这个路径是你的Vs2008路径。
    (3). 编辑"LINK_OPTS_0 =$(linkdebug) msvcirt.lib" in win32config to "LINK_OPTS_0 =$(linkdebug) msvcrt.lib",由于编译器所要LINK的运行库不一样了
    (4).修改groupsock/makefile.head,替换"INCLUDES = -Iinclude-I../UsageEnvironment/include" 为"INCLUDES = -Iinclude-I../UsageEnvironment/include -DNO_STRSTREAM".
    (5).运行genWindowsMakefiles.cmd 生成VS能够编译的*.mak文件
    (6).将以下内容保存为live/compile.bat
call "C:\Program Files\Microsoft Visual Studio9\VC\vcvarsall.bat"
cd liveMedia
nmake /B -f liveMedia.mak
cd ../groupsock
nmake /B -f groupsock.mak
cd ../UsageEnvironment
nmake /B -f UsageEnvironment.mak
cd ../BasicUsageEnvironment
nmake /B -f BasicUsageEnvironment.mak
cd ../testProgs
nmake /B -f testProgs.mak
cd ../mediaServer
nmake /B -f mediaServer.mak

有关这一点来说,建议把vs2008的编译环境加入到环境变量中,那么以后需用命令行编译程序都可行了,可以参考 http://blog.chinaunix.net/u3/94873/showart_1907792.html的前部分设置VS2008的环境设置。
    (7).在命令行下运行compile.bat,就会看到很多编译过程出现在CMD中了。

以上的编译并不是 DEBUG模式,要调试时,应先在win32config加入一行"NODEBUG=1"
进行编译后,可以在要调试的程序路径下输入如:C:\works\VCCode\video\live555-latest\live\testProgs>devenvopenRTSP.exe,这样就会把相关的调试环境搭建起来进行调试了。

字体大小:大

live555库的应用指南

Real Time Streaming Protocol或者RTSP(实时流媒体协议),是由 Real network和Netscape共同提出的如何有效地在IP网络上传输流媒体数据的应用层协议。RTSP提供一种可扩展的框架,使能够提供能控制的,按需传输实时数据,比如音频和视频文件。源数据可以包括现场数据的反馈和存贮的文件。rtsp对流媒体提供了诸如暂停,快进等控制,而它本身并不传输数据,rtsp作用相当于流媒体服务器的远程控制。传输数据可以通过传输层的tcp,udp协议,rtsp也提供了基于rtp传输机制的一些有效的方法。

   RTSP协议是一个非常类似HTTP协议的流控制协议。它们都使用纯文本来发送信息,而且rtsp协议的语法也和HTTP类似。Rtsp一开始这样设计,也是为了能够兼容使用以前写的HTTP协议分析代 码 。这是个好消息。

它们主要的区别是HTTP协议是没有状态的, http协议在发送一个命令后,连接会断开,而且命令之间没有依赖性。不同的是RTSP的命令需要知道现在正处于一个什么状态,也就是说rtsp的命令总是按照顺序来发送,某个命令总在另外一个命令之前要发送。Rtsp不管处于什么状态都不会去断掉连接。

HTTP 协议默 认使用80端口,而RTSP默认使用554端口。如果一些服务器因为某些安全的原因而封掉了这个端口,那代理和防火墙可能不让RTSP消息通过,需要管理员去放开554端口,而使得rtsp协议能通过。

基本类
在Mplayer中如果使用live选项进行编译,则需要安装live555库。live555实现RTP/RTSP功能。

使用环境(usageEnvironment):UsageEnvironment和TaskScheduler类用在调度不同事件。还有HashTable类定义,这些都是抽象基类。在使用过程中可以利用环境的特定功能。
groupsock:封装网络接口和socket。特别是还封装了multicast应用,这个multicast并不是Mbone意义的multicast,而是将多个写而不读socket组合处理,用来模拟multicast。
liveMedia:定义一个类栈,根类是Medium类-不同的流类型和编解码器。
BasicUsageEnvironment:定义一个usageEnvironment的实现,这个里面除了有一个TaskScheduler以外,都是一些说明性的东西。TaskSheduler里面是一些调度相关的函数,其中doEventLoop是主控函数,定义为纯虚函数。
testProgs:目录下是一个简单的实现,使用了BasicUsageEnvironment来展示如何使用这些库。
BasicTaskScheduler0:主要成员变量有fdelayQueue, fReadHandlers,fLastHandledSocketNum;这里主要的处理函数是scheduleDelayedTask,通过定时器触发一个时间,比如RTCP包的发送等。
BasicTaskScheduler:中又添加了fMaxNumSockets和fReadSet。其中freadHandlers类中定义一个链表,将所有的句柄,对应的处理函数 和处理函数参数作链接成一个链表,通过成员函数assignHandler管理。这里面主要的函数是turnOnBackgroundReadHandling,这个函数把句柄和处理函数注册到select中,这样可以完成数据包的等待及其处理操作。
MediaSession类中定义了一个mediaSubSession链表;MediaSubSession中又SessionId,服务端口号,rtp/rtcp ChannelId和MediaSink指针,等等一些参数信息。

H.264
1. 基类
Medium:定义媒体名字和环境信息,处理任务名,静态函数close和lookupByName和一些虚函数来指明该medium类型,是媒体帧的基类。
MediaSource类:实现基类中medium类型的虚函数,
FramedSoruce:定义了getNextFrame和doGetNextFrame纯虚函数是使用到的一些变量。
2. 相关类
H264VideoStreamFramer;H264VideoFileSink:H264VideoRTPSource:H264VideoRTPSinik
H.264利用NAL封装数据,通过RTP传输数据包。相关的处理在RTPSource/Sink中。

Mplayer
从RTSP或者SIP中渠道SDP描述,然后调用Live555中的mediaSession类创建Session。通过成员函数initializeWithSDP分析SDP描述。

OpenRTSP
1. Client
1. 创建TaskScheduler和UsageEnvironment实例;
2. 调用createClient创建media实例;

在openRTSP.c中,main完成配置以后,开始如下循环:
startPlayingStreams();
env->taskScheduler().doEventLoop(); // does notreturn
在BasicTaskScheduler0类中,定义为while(1) SingleStep();
SingleStep的处理是通过select监听一组句柄,这组句柄通过iter组成的链表串接起来,对每个句柄有处理函数,如果有句柄上有数据,那么调用对应的处理函数。

2. liev555mediaserver
创建过程:
1. 创建TaskScheduler:这里仅仅初始化一个fdset并且socket数目初始化为0。
2. 以TaskScheduler为参数创建UsageEnvironment对象。
3. 以前述environment和服务端口号(554/8554)以及用户认证对象为参数创建 RTSPServer对象,这里是用子类DynamicRTSPServer的创建函数创建。在createNew成员函数中建立socket,分配发送缓冲区,和创建RTSPServer对象。这里通过turnOnBackgroundReadHandling函数将要处理的句柄和处理函数关联起来。
4. 执行env->taskScheduler().doEventLoop();

从RFC2326中可以看出通常的交互流程是发送describe,然后发送setup,再play。所以以请求MPG多媒体URI为例分析如下:
C->M: DESCRIBE rtsp://foo/twister RTSP/1.0
CSeq: 1

M->C: RTSP/1.0 200 OK
CSeq: 1
Content-Type: application/sdp
Content-Length: 164

v=0
o=- 2890844256 2890842807 IN IP4 172.16.2.93
s=RTSP Session
i=An Example of RTSP Session Usage
a=control:rtsp://foo/twister
t=0 0
m=audio 0 RTP/AVP 0
a=control:rtsp://foo/twister/audio
m=video 0 RTP/AVP 26
a=control:rtsp://foo/twister/video

C->M: SETUP rtsp://foo/twister/audio RTSP/1.0
CSeq: 2
Transport: RTP/AVP;unicast;client_port=8000-8001

M->C: RTSP/1.0 200 OK
CSeq: 2
Transport: RTP/AVP;unicast;client_port=8000-8001;
server_port=9000-9001
Session: 12345678

C->M: SETUP rtsp://foo/twister/video RTSP/1.0
CSeq: 3
Transport: RTP/AVP;unicast;client_port=8002-8003
Session: 12345678

M->C: RTSP/1.0 200 OK
CSeq: 3
Transport: RTP/AVP;unicast;client_port=8002-8003;
server_port=9004-9005
Session: 12345678

C->M: PLAY rtsp://foo/twister RTSP/1.0
CSeq: 4
Range: npt=0-
Session: 12345678

M->C: RTSP/1.0 200 OK
CSeq: 4
Session: 12345678
RTP-Info: url=rtsp://foo/twister/video;
seq=9810092;rtptime=3450012

C->M: PAUSE rtsp://foo/twister/video RTSP/1.0
CSeq: 5
Session: 12345678

M->C: RTSP/1.0 460 Only aggregate operationallowed
CSeq: 5

C->M: PAUSE rtsp://foo/twister RTSP/1.0
CSeq: 6
Session: 12345678

M->C: RTSP/1.0 200 OK
CSeq: 6
Session: 12345678

C->M: SETUP rtsp://foo/twister RTSP/1.0
CSeq: 7
Transport: RTP/AVP;unicast;client_port=10000

M->C: RTSP/1.0 459 Aggregate operation notallowed
CSeq: 7

函数 handleCmd_DESCRIBE处理describe请求,生成含SDP信息响应消息,lookupServerMediaSession函数是虚函数,在创建RTSPServer对象时,用的是子类DynamicRTSPServer的创建函数,所以上述函数使用的是类DynamicRTSPServer中的定义。函数打开,并且分析流媒体文件。createNewSMS根据请求的文件后缀来调用对应的处理函数。如果是MPG,那么创建ServerMediaSession对象并添加到RTSPserver中,这个对象是可以通过Hash类定位的。然后创建一个Mpeg1or2FileServerDemux对象demux,然后将创建demux对象中的音频,视频子会话对象并且通过函数 addSubsession将他们添加到ServerMediaSession中链表中。响应函数会依次调用会话中注册的子会话的 sdpLines函数以取得SDP信息。sdpLines是一个纯虚函数,如果URI指定的MPG文件,那么sdpLines 函数在OnDemandServerMediaSubsession中定义实现。此时,对每个子会话那么会创建一个sink对象。对应MPG文件,在MPEG1or2DemuxedServerMediaSubsession类定义的createNewRTPSink会创建对象:
音频:MPEG1or2AudioRTPSink::AudioRTPSink::MultiFramedRTPSink::RTPSink::MediaSink::Media
视频:MPEG1or2VideoRTPSink::VideoRTPSink::MultiFramedRTPSink::RTPSink::MediaSink::Media
而SDP信息的获取在函数 setSDPLinesFromRTPSink中处理。(AudioRTPSink指定媒体类型,时间标签频率和载荷格式名“MPA”,视频名字是“MPV")
这里类结构 MPEG1or2DemuxedServerMediaSubsession::OnDemandServerMediaSubsession ::ServerMediaSubsession::Medium

函数 handleCmd_SETUP处理setup请求,

MPEG1or2Demux类是mpeg相关的一个主要类,创建该类时会分析媒体文件。该类定义中有个数组,OutputDescriptorfOutput[256];MPEG1or2Demux的构造函数中初始化。

在windows使用vs2008编译live555

1.live555 源代码简介
liveMedia项目的源代码包括四个基本的库,各种测试代码以及IVE555 Media Server。

四 个基本的库分别是UsageEnvironment&TaskScheduler,groupsock,liveMedia,BasicUsageEnvironment。

UsageEnvironment和TaskScheduler类用于事件的调度,实现异步读取事件的句柄的设置以及错误信息的输出。另外,还有一个HashTable类定义了一个通用的hash表,其它代码要用到这个表。这些都是抽象类,在应用程序中基于这些类实现自己的子类。

groupsock类是对网络接口的封装,用于收发数据包。正如名字本身,Groupsock主要是面向多播数据的收发的,它也同时支持单播数据的收发。Groupsock定义了两个构造函数
Groupsock(UsageEnvironment& env, struct in_addrconst& groupAddr,
Port port, u_int8_t ttl);
Groupsock(UsageEnvironment& env, struct in_addrconst& groupAddr,
struct in_addr const& sourceFilterAddr,
Port port);
前 者是用于SIM(source-independent multicast)组,后者用于SSM(source-specificmulticast)组。groupsock库中的Helper例程提供了读写socket等函数,并且屏蔽了不同的操作系统之间的区别,这是在GroupsockHelper.cpp文件中实现的。

liveMedia库中有一系列类,基类是Medium,这些类针对不同的流媒体 类型和编码。

各种测试代码在testProgram目录下,比如openRTSP等,这些代码有助于理解liveMedia的应用。

LIVE555 Media Server是一个纯粹的RTSP服务器。支持多种格式的媒体文件:

* TS流文件,扩展名ts。
* PS流文件,扩展名mpg。
* MPEG-4视频基本流文件,扩展名m4e。
* MP3文件,扩展名mp3。
* WAV文件(PCM),扩展名wav。
* AMR音频文件,扩展名.amr。
* AAC文件,ADTS格式,扩展名aac。
2.在windows下编译live555
(1).下载 live555,http://www.live555.com/
(2). 编辑 win32config,TOOLS32=C:\Program Files\Microsoft VisualStudio 9.0\VC
即保证这个路径是你的Vs2008 路径。
(3). 编辑"LINK_OPTS_0 = $(linkdebug) msvcirt.lib" in win32config to"LINK_OPTS_0 = $(linkdebug) msvcrt.lib",由于编译器所要LINK的运行库不一样了
(4). 修改groupsock/makefile.head,替换"INCLUDES = -Iinclude-I../UsageEnvironment/include" 为"INCLUDES = -Iinclude-I../UsageEnvironment/include -DNO_STRSTREAM".
(5). 运行genWindowsMakefiles.cmd 生成VS能够编译的*.mak文件
(6). 将以下内容保存为live/compile.bat
call "C:\Program Files\Microsoft Visual Studio9\VC\vcvarsall.bat"
cd liveMedia
nmake /B -f liveMedia.mak
cd ../groupsock
nmake /B -f groupsock.mak
cd ../UsageEnvironment
nmake /B -f UsageEnvironment.mak
cd ../BasicUsageEnvironment
nmake /B -f BasicUsageEnvironment.mak
cd ../testProgs
nmake /B -f testProgs.mak
cd ../mediaServer
nmake /B -f mediaServer.mak

有 关这一点来说,建议把vs2008的编译环境加入到环境变量中,那么以后需用命令行编译程序都可行了,可以参考 http://blog.chinaunix.net/u3/94873/showart_1907792.html的前部分设置VS2008的环境设置。
(7). 在命令行下运行compile.bat,就会看到很多编译过程出现在CMD中了。

以上的编译并不是 DEBUG模式,要调试时,应先在win32config加入一行"NODEBUG=1"
进行编译后,可以在要调试的程序路径下输入如:C:\works\VCCode\video\live555-latest\live\testProgs>devenvopenRTSP.exe,这样就会把相关的调试环境搭建起来进行调试了。

liveMedia项目的源代码包括四个基本的库,各种测试代码以及IVE555 Media Server。

四个基本的库分别是UsageEnvironment&TaskScheduler,groupsock,liveMedia,BasicUsageEnvironment。

UsageEnvironment和TaskScheduler类用于事件的调度,实现异步读取事件的句柄的设置以及错误信息的输出。另外,还有一个HashTable类定义了一个通用的hash表,其它代码要用到这个表。这些都是抽象类,在应用程序中基于这些类实现自己的子类。

groupsock类是对网络接口的封装,用于收发数据包。正如名字本身,Groupsock主要是面向多播数据的收发的,它也同时支持单播数据的收发。Groupsock定义了两个构造函数
Groupsock(UsageEnvironment& env, struct in_addrconst& groupAddr,
Port port, u_int8_t ttl);
Groupsock(UsageEnvironment& env, struct in_addrconst& groupAddr,
struct in_addr const& sourceFilterAddr,
Port port);
前者是用于SIM(source-independent multicast)组,后者用于SSM(source-specificmulticast)组。groupsock库中的Helper例程提供了读写socket等函数,并且屏蔽了不同的操作系统之间的区别,这是在GroupsockHelper.cpp文件中实现的。

liveMedia库中有一系列类,基类是Medium,这些类针对不同的流媒体 类型和编码。

各种测试代码在testProgram目录下,比如openRTSP等,这些代码有助于理解liveMedia的应用。

LIVE555 Media Server是一个纯粹的RTSP服务器。支持多种格式的媒体文件:

* TS流文件,扩展名ts。
* PS流文件,扩展名mpg。
* MPEG-4视频基本流文件,扩展名m4e。
* MP3文件,扩展名mp3。
* WAV文件(PCM),扩展名wav。
* AMR音频文件,扩展名.amr。
* AAC文件,ADTS格式,扩展名aac。

用live555开发应用程序
基于liveMedia的程序,需要通过继承UsageEnvironment抽象类和TaskScheduler抽象类,定义相应的类来处理事件调度,数据读写以及错误处理。live项目的源代码里有这些类的一个实现,这就是“BasicUsageEnvironment”库。BasicUsageEnvironment主要是针对简单的控制台应用程序,利用select实现事件获取和处理。这个库利用Unix或者Windows的控制台作为输入输出,处于应用程序原形或者调试的目的,可以用这个库用户可以开发传统的运行与控制台的应用。

通过使用自定义的“UsageEnvironment”和“TaskScheduler”抽象类的子类,这些应用程序就可以在特定的环境中运行,不需要做过多的修改。需要指出的是在图形环境(GUI toolkit)下,抽象类 TaskScheduler 的子类在实现doEventLoop()的时候应该与图形环境自己的事件处理框架集成。

先来熟悉在liveMedia库中Source,Sink以及Filter等概念。Sink就是消费数据的对象,比如把接收到的数据存储到文件,这个文件就是一个Sink。Source就是生产数据的对象,比如通过RTP读取数据。数据流经过多个'source'和'sink's,下面是一个示例:

'source1' -> 'source2' (a filter) ->'source3' (a filter) -> 'sink'

从其它 Source接收数据的source也叫做"filters"。Module是一个sink或者一个filter。

数据接收的终点是 Sink类,MediaSink是所有Sink类的基类。MediaSink的定义如下:

class MediaSink: public Medium {
public:
static Boolean lookupByName(UsageEnvironment& env,char const* sinkName,
MediaSink*& resultSink);

typedef void (afterPlayingFunc)(void* clientData);
Boolean startPlaying(MediaSource& source,
afterPlayingFunc* afterFunc,
void* afterClientData);
virtual void stopPlaying();

// Test for specific types of sink:
virtual Boolean isRTPSink() const;

FramedSource* source() const {return fSource;}

protected:
MediaSink(UsageEnvironment& env); // abstract baseclass
virtual ~MediaSink();

virtual BooleansourceIsCompatibleWithUs(MediaSource&source);
// called by startPlaying()
virtual Boolean continuePlaying() = 0;
// called by startPlaying()

static void onSourceClosure(void* clientData);
// should be called (on ourselves) by continuePlaying() whenit
// discovers that the source we're playing from has closed.

FramedSource* fSource;

private:
// redefined virtual functions:
virtual Boolean isSink() const;

private:
// The following fields are used when we're being played:
afterPlayingFunc* fAfterFunc;
void* fAfterClientData;
};

Sink 类实现对数据的处理是通过实现纯虚函数continuePlaying(),通常情况下continuePlaying调用fSource->getNextFrame来为Source设置数据缓冲区,处理数据的回调函数等,fSource是MediaSink的类型为FramedSource*的类成员;

基于liveMedia的应用程序的控制流程如下:

应用程序是事件驱动的,使用如 下方式的循环

while (1) {
通过查找读网络句柄的列表和延迟队列(delay queue)来发现需要完成的任务
完成这个任务
}

对于每个sink,在进入这个循环之 前,应用程序通常调用下面的方法来启动需要做的生成任务:

someSinkObject->startPlaying();

任何时候,一个Module需要获取数据都通过调用刚好在它之前的那个Module的FramedSource::getNextFrame()方法。这是通过纯虚函数FramedSource:oGetNextFrame() 实现的,每一个Source module都有相应的实现。

Each 'source' module's implementation of "doGetNextFrame()" worksby arranging for an 'after getting' function to be called (from anevent handler) when new data becomes available for thecaller.

注意,任何应用程序都要处理从'sources'到'sinks'的数据流,但是并非每个这样的数据流都与从网络接口收发数据相对应。
比如,一个服务器应用程序发送RTP数据包的时候用到一个或多 个"RTPSink" modules。这些"RTPSink"modules以别的方式接收数据,通常是文件 "*Source" modules (e.g., to read data from afile), and, as a side effect, transmit RTP packets.

一个简单的RTSP客户端程序
在另一个文章里,给出了这个简单的客户端的程序的代码,可以通过修改Makefile来裁剪liveMedia,使得这个客户端最小化。此客户端已经正常运行。

首先是OPTION
然 后是DESCRIBE
建立Media Session,调用的函数是MediaSession::createNew,在文件liveMedia/MediaSession.cpp中实现。
为这个Media Session建立RTPSource,这是通过调用MediaSubsession::initiate来实现的的,这个方法在liveMedia/MediaSession.cpp中实现。
在然 后是SETUP
最后是PLAY

rtp数据的句 柄:MultiFramedRTPSource::networkReadHandler在liveMedia/MultiFramedRTPSource.cpp中
rtcp数据处理的句 柄:RTCPInstance::incomingReportHandler在liveMedia/RTCP.cpp中

rtp数据处 理的句柄的设置:MultiFramedRTPSource: oGetNextFrame在liveMedia/MultiFramedRTPSource.cpp中,被FileSink::continuePlaying调用在FileSink.cpp中.

rtcp数据处理的句柄设置 fRTCPInstance = RTCPInstance::createNew在/liveMedia/MediaSession.cpp中调用,
createNew 调用了构造函数RTCPInstance::RTCPInstance,这个构造函数有如下调用
TaskScheduler::BackgroundHandlerProc* handler =(TaskScheduler::BackgroundHandlerProc*)&incomingReportHandler;

*********************************************************************************************************************
通过分析live库提供的例子程序OpenRTSP,可以清晰地了解客户端接收来自网络上媒体数据的过程。注意,RTP协议和RTCP协议接收的数据分别是视音频数据和发送/接收状况的相关信息,其中,RTP协议只负责接收数据,而RTCP协议除了接收服务器的消息之外,还要向服务器反馈。
A.       main函数流程
main(int argc,char *argv[])
{
1.         创建BasicTaskScheduler对象
2.         创建BisicUsageEnvironment对象
3.         分析argv参数,(最简单的用法是:openRTSP rtsp://172.16.24.240/mpeg4video.mp4)以便在下面设置一些相关参数
4.         创建RTSPClient对象
5.         由RTSPClient对象向服务器发送OPTION消息并接受回应
6.         产生SDPDescription字符串(由RTSPClient对象向服务器发送DESCRIBE消息并接受回应,根据回应的信息产生SDPDescription字符串,其中包括视音频数据的协议和解码器类型)
7.         创建MediaSession对象(根据SDPDescription在MediaSession中创建和初始化MediaSubSession子会话对象)
8.         while循环中配置所有子会话对象(为每个子会话创建RTPSource和RTCPInstance对象,并创建两个GroupSock对象,分别对应 RTPSource和RTCPInstance对象,把在每个GroupSock对象中创建的socket描述符置入BasicTaskScheduler::fReadSet中,RTPSource对象的创建的依据是SDPDescription,例如对于MPEG4文件来说,视音频RTPSource分别对应MPEG4ESVideoRTPSource和MPEG4GenericRTPSource对象。RTCPInstance对象在构造函数中完成将Socket描述符、处理接收RTCP数据的函数(RTCPInstance::incomingReportHandler)以及RTCPInstance本身三者绑定在一个HandlerDescriptor对象中,并置入BasicTaskScheduler::fReadHandler中。完成绑定后会向服务器发送一条消息。)
9.         由RTSPClient对象向服务器发送SETUP消息并接受回应。
10.       while循环中为每个子会话创建接收器(FileSink对象),在FileSink对象中根据子会话的codec等属性缺省产生记录视音频数据的文件 名,视音频文件名分别为:video-MP4V-ES-1和audio-MPEG4-GENERIC-2,无后缀名
11.       while循环中为每个子会话的视音频数据装配相应的接收函数,将每个子会话中的RTPSource中的GroupSock对象中的SOCKET描述符, 置入BasicTaskScheduler::fReadSet中,并将描述符、处理接收RTP数据的函数(MultiFramedRTPSource::networkReadHandler)以及RTPSource本身三者绑定在一个HandlerDescriptor对象中,并置入BasicTaskScheduler::fReadHandler中,并将FileSink的缓冲区和包含写入文件操作的一个函数指针配置给RTPSource对象,这个缓冲区将会在networkReadHandler中接收来自网络的视音频数据(分析和去掉RTP包头的工作由RTPSource完成),而这个函数指针在networkReadHandler中被调用以完成将缓冲区中的数据写入文件。
12.       由RTSPClient对象向服务器发送PLAY消息并接受回应。
13.       进入while循环,调用BasicTaskScheduler::SingleStep()函数接受数据,直到服务器发送TREADOWN消息给客户端,客户端接收到该消息后释放资源,程序退出。

}

浅谈vlc模块管理方式-插件

vlc中所有的模块均以动态库(插件)方式来管理,就连main模块也不例外。可以在windows下查看vlc安装目录下plugin目录,里面包含了所有的动态库。当vlc启动的时候,主模块采用动态加入的方式.

具体实现如下:

   If you have alook at include/modules_inner.h, you can see on line 97 that itdeclares a new function. This function's name is defined by__VLC_SYMBOL(vlc_entry). __VLC_SYMBOL is defined a few lines aboveas the concatenation of "vlc_entry" with MODULE_NAME (theCONCATENATE macro inserts the double underscore). MODULE_NAME isdefined by the compiler at compile time using a -D command lineflag except in the case of the main libvlc module (which is the oneyou're looking at) where it defines the name at line 31 ofsrc/libvlc.c. This file then includes src/libvlc.h which calls thevlc_module_begin() macro on line 1177. So we now have a validfunction called vlc_entry__main. When the main plugin isinitialized in the __module_LoadMain() in src/misc/modules.c, itgives that function as the second argument to theAllocateBuiltinModule() on line 327 which will then call thefunction on line 1212.

 上面一段是老外解释的,还是说的比较清楚了,后来我仔细看了下,自己也做了相关的试验。其实他的核心就是采用宏定义将该模块的入口函数导出,以让其他函数调用。同时入口函数里面初始化了于该模块相关的所有函数指针。

 主模块的库是libvlc。在modules_in.h中,通过宏定义,导出了vlc_entry__MODULE_NAME函数,MODULE_NAME的宏定义在libvlc.c的31行,(#define MODULE_NAMEmain)这样也就说明了该模块的入口函数是vlc_entry__main。在modules.c中存在函数__module_InitBank,该函数最后调用module_LoadMain,在module_LoadMain中,调用了AllocateBuiltinModule函数(AllocateBuiltinModule( p_this, vlc_entry__main);),此处明确指出了需要调用主模块的入口函数vlc_entry__main,哈哈,看到了吧,此处说明了main模块要载入了,果然在AllocateBuiltinModule函数中存在调用pf_entry( p_module)1212行,该调用实质是vlc_entry__main的调用,现在一切真像大白了。

   除了主模块的载入外,其他模块的载入和主模块有点不同。他们不是通过这样直接指定模块名字调用相应的函数指针的方式,而是采用在动态库中直接找到_vlc_entry*函数的地址,并调用该函数完成具体模块的初始化工作。具体的函数调用流程如下:

   1。通过__module_Need(modules.h)找到需要载入的模块;

   2。在上面函数中通过AllocatePlugin(Modules.h)函数来完成载入;

   3.在AllocatePlugin函数中,CallEntry实现具体的模块入口的调用,其实现原理就是通过在动态库文件中查找_vlc_entry*函数的地址(C语言风格的动态库)。

   4。回到最上层的__module_Need函数中,调用模块初始化的pf_activate来激活,最后当需要卸载时,调用pf_deactivate函数即可。

   以上就是vlc独特的管理模块的方式,只是一个大概的原理,具体里面还有很多数据结构还未仔细研究,不过可以看的出vlc这样做的好处能比较灵活的管理各种模块,并动态改变。虽然代码都有C写的,但是实现后的灵活度还是很高的。

TS流、ES流、PES流介绍分析

IP数据报有首部和数据两部分组成的,首部的前一部分是固定长度20字节,是所有IP数据报必须具有的。首部包括:总长度、标识、MF、DF、片偏移。

数字信号实际传送的是数据流,一般数据流包括以下三种:

ES流:也叫基本码流,包含视频、音频或数据的连续码流。
PES流:也叫打包的基本码流,是将基本的码流ES流根据需要分成长度不等的数据包,并加上包头就形成了打包的基本码流PES流。

TS流:也叫传输流,是由固定长度为188字节的包组成,含有独立时基的一个或多个节目,适用于误码较多的环境。liveMedia项目(http://www.live555.com/)的源代码包括四个基本的库,各种测试代码以及MediaServer。四个基本的库分别是: UsageEnvironment&TaskScheduler,groupsock, liveMedia和BasicUsageEnvironment。

UsageEnvironment和TaskScheduler类用于事件的调度,实现异步读取事件的句柄的设置以及错误信息的输出。另外,还有一个HashTable类定义了一个通用的hash表,其它代码要用到这个表。这些都是抽象类,在应用程序中基于这些类来实现自己的子类。

groupsock类是对网络接口的封装,用于收发数据包。正如名字本身,groupsock主要是面向多播数据的收发的,它也同时支持单播数据的收发。

liveMedia库中有一系列类,基类是Medium,这些类针对不同的流媒体类型和编码。

各种测试代码在testProgram目录下,比如openRTSP等,这些代码有助于理解liveMedia的应用。

Media Server是一个纯粹的RTSP服务器。支持多种格式的媒体文件:

* TS流文件,扩展名ts。
* PS流文件,扩展名mpg。
* MPEG-4视频基本流文件,扩展名m4e。
* MP3文件,扩展名mp3。
* WAV文件(PCM),扩展名wav。
* AMR音频文件,扩展名.amr。
* AAC文件,ADTS格式,扩展名aac。

用live555开发应用程序

基于liveMedia的程序,需要通过继承UsageEnvironment抽象类和TaskScheduler抽象类,定义相应的类来处理事件调度,数据读写以及错误处理。live项目的源代码里有这些类的一个基本实现,这就是“BasicUsageEnvironment”库。BasicUsageEnvironment主要是针对简单的控制台应用程序,利用select实现事件获取和处理。这个库利用Unix或者Windows的控制台作为输入输出,处于应用程序原形或者调试的目的,可以用这个库用户可以开发传统的运行与控制台的应用。
通过使用自定义的“UsageEnvironment”和“TaskScheduler”抽象类的子类,这些应用程序就可以在特定的环境中运行,不需要做过多的修改。需要指出的是在图形环境(GUI toolkit)下,抽象类 TaskScheduler 的子类在实现doEventLoop()的时候应该与图形环境自己的事件处理框架集成。

基本概念

先来熟悉在liveMedia库中Source,Sink以及Filter等概念。Sink就是消费数据的对象,比如把接收到的数据存储到文件,这个文件就是一个Sink。Source就是生产数据的对象,比如通过RTP读取数据。数据流经过多个'source'和'sink's,下面是一个示例:

'source1' -> 'source2' (a filter) ->'source3' (a filter) -> 'sink'

从其它Source接收数据的source也叫做"filters"。Module是一个sink或者一个filter。数据接收的终点是Sink类,MediaSink是所有Sink类的基类。Sink类实现对数据的处理是通过实现纯虚函数continuePlaying(),通常情况下continuePlaying调用fSource->getNextFrame来为Source设置数据缓冲区,处理数据的回调函数等,fSource是MediaSink的类型为FramedSource*的类成员。

基本控制流程

基于liveMedia的应用程序的控制流程如下:

应用程序是事件驱动的,使用如下方式的循环
while (1) {
通过查找读网络句柄的列表和延迟队列(delay queue)来发现需要完成的任务
完成这个任务
}
对于每个sink,在进入这个循环之前,应用程序通常调用下面的方法来启动需要做的生成任务:

 someSinkObject->startPlaying()。任何时候,一个Module需要获取数据都通过调用刚好在它之前的那个Module的FramedSource::getNextFrame()方法。这是通过纯虚函数FramedSource::doGetNextFrame() 实现的,每一个Source module都有相应的实现。

Each 'source' module's implementation of "doGetNextFrame()" worksby arranging for an 'after getting' function to be called (from anevent handler) when new data becomes available for thecaller.

Note that the flow of data from 'sources' to 'sinks' happens withineach application, and doesn't necessarily correspond to the sendingor receiving of network packets. For example, a server application(such as "testMP3Streamer") that sends RTP packets will do so usingone or more "RTPSink" modules. These "RTPSink" modules receive datafrom other, "*Source" modules (e.g., to read data from a file),and, as a side effect, transmit RTP packets.

live555代码解读之一: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.1.109/1.mpg)连接服务器时,select返回对应的scoket,进而根据前面保存的对应关系,可找到对应处理函数句柄,这里就是前面提到的incomingConnectionHandler了。在incomingConnectionHandler中创建了RTSPClientSession,开始对这个客户端的会话进行处理。

live555代码解读之二:DESCRIBE请求消息处理过程

RTSP服务器收到客户端的DESCRIBE请求后,根据请求URL(rtsp://192.168.1.109/1.mpg),找到对应的流媒体资源,返回响应消息。live555中的ServerMediaSession类用来处理会话中描述,它包含多个(音频或视频)的子会话描述(ServerMediaSubsession)。

上节我们谈到RTSP服务器收到客户端的连接请求,建立了RTSPClientSession类,处理单独的客户会话。在建立RTSPClientSession的过程中,将新建立的socket句柄(clientSocket)和RTSP请求处理函数句柄RTSPClientSession::incomingRequestHandler传给任务调度器,由任务调度器对两者进行一对一关联。当客户端发出RTSP请求后,服务器主循环中的select调用返回,根据socket句柄找到对应的incomingRequestHandler,开始消息处理。先进行消息的解析,如果发现请求是DESCRIBE则进入handleCmd_DESCRIBE函数。根据客户端请求URL的后缀(例如是1.mpg),调用成员函数DynamicRTSPServer::lookupServerMediaSession查找对应的流媒体信息ServerMediaSession。如果ServerMediaSession不存在,但是本地存在1.mpg文件,则创建一个新的ServerMediaSession。在创建ServerMediaSession过程中,根据文件后缀.mpg,创建媒体MPEG-1or2的解复用器(MPEG1or2FileServerDemux)。再由MPEG1or2FileServerDemux创建一个子会话描述MPEG1or2DemuxedServerMediaSubsession。最后由ServerMediaSession完成组装响应消息中的SDP信息(SDP组装过程见下面的描述),然后将响应消息发给客户端,完成一次消息交互。
SDP消息组装过程:
ServerMediaSession负责产生会话公共描述信息,子会话描述由MPEG1or2DemuxedServerMediaSubsession产生。MPEG1or2DemuxedServerMediaSubsession在其父类成员函数OnDemandServerMediaSubsession::sdpLines()中生成会话描述信息。在sdpLines()实现里面,创建一个虚构(dummy)的FramedSource(具体实现类为MPEG1or2AudioStreamFramer和MPEG1or2VideoStreamFramer)和RTPSink(具体实现类为MPEG1or2AudioRTPSink和MPEG1or2VideoRTPSink),最后调用setSDPLinesFromRTPSink(...)成员函数生成子会话描述。

以上涉及到的类以及继承关系:
Medium <- ServerMediaSession
Medium <- ServerMediaSubsession <-OnDemandServerMediaSubsession <-MPEG1or2DemuxedServerMediaSubsession
Medium <- MediaSource <- FramedSouse<- FramedFileSource <-ByteStreamFileSource
Medium <- MediaSource <- FramedSouse<- MPEG1or2DemuxedElementaryStream
Medium <- MPEG1or2FileServerDemux
Medium <- MPEG1or2Demux
Medium <- MediaSource <- FramedSouse<- MPEG1or2DemuxedElementaryStream
Medium <- MediaSource <- FramedSouse<- FramedFilter <-MPEGVideoStreamFramer <-MPEG1or2VideoStreamFramer
Medium <- MediaSink <- RTPSink<- MultiFramedRTPSink <- VideoRTPSink<- MPEG1or2VideoRTPSink

live555代码解读之三:SETUP 和PLAY请求消息处理过程

前面已经提到RTSPClientSession类,用于处理单独的客户会话。其类成员函数handleCmd_SETUP()处理客户端的SETUP请求。调用parseTransportHeader()对SETUP请求的传输头解析,调用子会话(这里具体实现类为OnDemandServerMediaSubsession)的getStreamParameters()函数获取流媒体发送传输参数。将这些参数组装成响应消息,返回给客户端。

获取发送传输参数的过程:调用子会话(具体实现类MPEG1or2DemuxedServerMediaSubsession)的createNewStreamSource(...)创建MPEG1or2VideoStreamFramer,选择发送传输参数,并调用子会话的createNewRTPSink(...)创建MPEG1or2VideoRTPSink。同时将这些信息保存在StreamState类对象中,用于记录流的状态。

客户端发送两个SETUP请求,分别用于建立音频和视频的RTP接收。

PLAY请求消息处理过程

RTSPClientSession类成员函数handleCmd_PLAY()处理客户端的播放请求。首先调用子会话的startStream(),内部调用MediaSink::startPlaying(...),然后是MultiFramedRTPSink::continuePlaying(),接着调用MultiFramedRTPSink::buildAndSendPacket(...)。buildAndSendPacke内部先设置RTP包头,内部再调用MultiFramedRTPSink::packFrame()填充编码帧数据。
packFrame内部通过 FramedSource::getNextFrame(),接着MPEGVideoStreamFramer::doGetNextFrame(),再接着经过MPEGVideoStreamFramer::continueReadProcessing(),FramedSource::afterGetting(...),  MultiFramedRTPSink::afterGettingFrame(...),  MultiFramedRTPSink::afterGettingFrame1(...)等一系列繁琐调用,最后到了 MultiFramedRTPSink::sendPacketIfNecessary(),这里才真正发送RTP数据包。然后是计算下一个数据包发送时间,把MultiFramedRTPSink::sendNext(...)函数句柄传给任务调度器,作为一个延时事件调度。在主循环中,当MultiFramedRTPSink::sendNext()被调度时,又开始调用MultiFramedRTPSink::buildAndSendPacket(...)开始新的发送数据过程,这样客户端可以源源不断的收到服务器传来的RTP包了。

发送RTP数据包的间隔计算方法:
Update the time at which the next packet should be sent, based onthe duration of the frame that we just packed into it.

涉及到一些类有:

MPEGVideoStreamFramer: A filter that breaks up an MPEG videoelementary stream into headers and frames

MPEG1or2VideoStreamFramer: A filter that breaks up an MPEG 1 or 2video elementary stream into frames for: Video_Sequence_Header,GOP_Header, Picture_Header

MPEG1or2DemuxedElementaryStream: A MPEG 1 or 2 Elementary Stream,demultiplexed from a Program Stream

MPEG1or2Demux: Demultiplexer for a MPEG 1 or 2 Program Stream

ByteStreamFileSource: A file source that is a plain byte stream(rather than frames)

MPEGProgramStreamParser: Class for parsing MPEG programstream

StreamParser: Abstract class for parsing a byte stream

StreamState:A class that represents the state of an ongoing stream

复合/分离的过程称为系统复接/分接,据传输媒体的质量不同,MPEG-2中定义了两种复合信息流:传送流(TS)和节目流(PS:ProgramStream)

RTSP点播消息流程

Real Time Streaming Protocol或者RTSP(实时流媒体协议),是由Real network 和Netscape共同提出的如何有效地在IP网络上传输流媒体数据的应用层协议。RTSP提供一种可扩展的框架,使能够提供可控制的,按需传输实时数据,比如音频和视频文件。源数据可以包括现场数据的反馈和存贮的文件。rtsp对流媒体提供了诸如暂停,快进等控制,而它本身并不传输数据,rtsp作用相当于流媒体服务器的远程控制。传输数据可以 

通过传输层的tcp,udp协议,rtsp也提供了基于rtp传输机制的一些有效的方法。

RTSP消息格式: 

RTSP的消息有两大类,一是请求消息(request),一是回应消息(response),两种消息的格式不同. 

请求消息: 

方法 URI RTSP版本 CR LF 

消息头 CR LF CR LF 

消息体 CR LF 

其中方法包括OPTION回应中所有的命令,URI是接受方的地址,例如 

:rtsp://192.168.20.136 

RTSP版本一般都是 RTSP/1.0.每行后面的CRLF表示回车换行,需要接受端有相应的解 

析,最后一个消息头需要有两个CR LF 

回应消息: 

RTSP版本 状态码 解释 CR LF 

消息头 CR LF CR LF 

消息体 CR LF 

其中RTSP版本一般都是RTSP/1.0,状态码是一个数值,200表示成功,解释是与状态码对应 

的文本解释. 

简单的rtsp交互过程: 

C表示rtsp客户端,S表示rtsp服务端 

1.C->S:OPTION request//询问S有哪些方法可用 

1.S->C:OPTION response//S回应信息中包括提供的所有可用方法 

2.C->S:DESCRIBE request//要求得到S提供的媒体初始化描述信息 

2.S->C:DESCRIBE response//S回应媒体初始化描述信息,主要是sdp 

3.C->S:SETUP request//设置会话的属性,以及传输模式,提醒S建立会 

话 

3.S->C:SETUP response//S建立会话,返回会话标识符,以及会话相关信息 

4.C->S:PLAY request //C请求播放 

4.S->C:PLAY response//S回应该请求的信息 

S->C:发送流媒体数据 

5.C->S:TEARDOWN request//C请求关闭会话 

5.S->C:TEARDOWN response//S回应该请求 

上述的过程是标准的、友好的rtsp流程,但实际的需求中并不一定按部就班来。 

其中第3和4步是必需的!第一步,只要服务器客户端约定好,有哪些方法可用,则option请求可以不要。第二步,如果我们有其他途径得到媒体初始化描述信息(比如http请求等等),则我们也不需要通过rtsp中的describe请求来完成。第五步,可以根据系统需求的设计来决定是否需要。 

rtsp中常用方法: 

1.OPTION 

目的是得到服务器提供的可用方法: 

OPTIONS rtsp://192.168.20.136:5000/xxx666RTSP/1.0 

CSeq: 1 //每个消息都有序号来标记,第一个包通常是option请求消息 

User-Agent: VLC media player (LIVE555 Streaming Mediav2005.11.10) 

服务器的回应信息包括提供的一些方法,例如: 

RTSP/1.0 200 OK 

Server: UServer 0.9.7_rc1 

Cseq: 1 //每个回应消息的cseq数值和请求消息的cseq相对应 

Public: OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE,SCALE, 

GET_PARAMETER //服务器提供的可用的方法 

2.DESCRIBE 

C向S发起DESCRIBE请求,为了得到会话描述信息(SDP): 

DESCRIBE rtsp://192.168.20.136:5000/xxx666RTSP/1.0 

CSeq: 2 

token: 

Accept: application/sdp 

User-Agent: VLC media player (LIVE555 Streaming Mediav2005.11.10) 

服务器回应一些对此会话的描述信息(sdp): 

RTSP/1.0 200 OK 

Server: UServer 0.9.7_rc1 

Cseq: 2 

x-prev-url: rtsp://192.168.20.136:5000 

x-next-url: rtsp://192.168.20.136:5000 

x-Accept-Retransmit: our-retransmit 

x-Accept-Dynamic-Rate: 1 

Cache-Control: must-revalidate 

Last-Modified: Fri, 10 Nov 2006 12:34:38GMT 

Date: Fri, 10 Nov 2006 12:34:38 GMT 

Expires: Fri, 10 Nov 2006 12:34:38 GMT 

Content-Base:rtsp://192.168.20.136:5000/xxx666/ 

Content-Length: 344 

Content-Type: application/sdp 

v=0 //以下都是sdp信息 

o=OnewaveUServerNG 1451516402 1025358037 IN IP4192.168.20.136 

s=/xxx666 

u=http:/// 

e=admin@ 

c=IN IP4 0.0.0.0 

t=0 0 

a=isma-compliance:1,1.0,1 

a=range:npt=0- 

m=video 0 RTP/AVP 96//m表示媒体描述,下面是对会话中视频通道的媒体描述 

a=rtpmap:96 MP4V-ES/90000 

a=fmtp:96 

profile-level-id=245;config=000001B0F5000001B509000001000000012000C888B0E0E0FA62D089028307 

a=control:trackID=0//trackID=0表示视频流用的是通道0 

3.SETUP 

客户端提醒服务器建立会话,并确定传输模式: 

SETUP rtsp://192.168.20.136:5000/xxx666/trackID=0RTSP/1.0 

CSeq: 3 

Transport:RTP/AVP/TCP;unicast;interleaved=0-1 

User-Agent: VLC media player (LIVE555 Streaming Mediav2005.11.10) 

//uri中带有trackID=0,表示对该通道进行设置。Transport参数设置了传输模式,包 

的结构。接下来的数据包头部第二个字节位置就是interleaved,它的值是每个通道都 

不同的,trackID=0的interleaved值有两个0或1,0表示rtp包,1表示rtcp包,接受端 

根据interleaved的值来区别是哪种数据包。 

服务器回应信息: 

RTSP/1.0 200 OK 

Server: UServer 0.9.7_rc1 

Cseq: 3 

Session: 6310936469860791894 //服务器回应的会话标识符 

Cache-Control: no-cache 

Transport:RTP/AVP/TCP;unicast;interleaved=0-1;ssrc=6B8B4567 

4.PLAY 

客户端发送播放请求: 

PLAY rtsp://192.168.20.136:5000/xxx666RTSP/1.0 

CSeq: 4 

Session: 6310936469860791894 

Range: npt=0.000- //设置播放时间的范围 

User-Agent: VLC media player (LIVE555 Streaming Mediav2005.11.10) 

服务器回应信息: 

RTSP/1.0 200 OK 

Server: UServer 0.9.7_rc1 

Cseq: 4 

Session: 6310936469860791894 

Range: npt=0.000000- 

RTP-Info:url=trackID=0;seq=17040;rtptime=1467265309 

//seq和rtptime都是rtp包中的信息 

5.TEARDOWN 

客户端发起关闭请求: 

TEARDOWN rtsp://192.168.20.136:5000/xxx666RTSP/1.0 

CSeq: 5 

Session: 6310936469860791894 

User-Agent: VLC media player (LIVE555 Streaming Mediav2005.11.10) 

服务器回应: 

RTSP/1.0 200 OK 

Server: UServer 0.9.7_rc1 

Cseq: 5 

Session: 6310936469860791894 

Connection: Close 

以上方法都是交互过程中最为常用的,其它还有一些重要的方法如 

get/set_parameter,pause,redirect等等 

ps: 

sdp的格式 

v=<version> 

o=<username><session id><version> <networktype> <address type><address> 

s=<sessionname> 

i=<sessiondescription> 

u=<URI> 

e=<emailaddress> 

p=<phonenumber> 

c=<network type><address type><connectionaddress> 

b=<modifier>:<bandwidth-value> 

t=<start time><stop time> 

r=<repeat interval><active duration><list of offsets fromstart-time> 

z=<adjustment time><offset> <adjustmenttime> <offset>.... 

k=<method> 

k=<method>:<encryptionkey> 

a=<attribute> 

a=<attribute>:<value> 

m=<media><port><transport> <fmtlist> 

v = (协议版本) 

o = (所有者/创建者和会话标识符) 

s = (会话名称) 

i = * (会话信息) 

u = * (URI 描述) 

e = * (Email 地址) 

p = * (电话号码) 

c = * (连接信息) 

b = * (带宽信息) 

z = * (时间区域调整) 

k = * (加密密钥) 

a = * (0 个或多个会话属性行) 

时间描述: 

t = (会话活动时间) 

r = * (0或多次重复次数) 

媒体描述: 

m = (媒体名称和传输地址) 

i = * (媒体标题) 

c = * (连接信息 — 如果包含在会话层则该字段可选) 

b = * (带宽信息) 

k = * (加密密钥) 

a = * (0 个或多个媒体属性行) 

参考文章:rfc2326(rtsp);rfc2327(sdp) 

RTSP点播消息流程实例(客户端:VLC, RTSP服务器:LIVE555 MediaServer) 

1)C(Client)-> M(MediaServer) 

OPTIONS rtsp://192.168.1.109/1.mpgRTSP/1.0 

CSeq: 1 

user-Agent: VLC media player(LIVE555 Streaming Mediav2007.02.20) 

1)M -> C 

RTSP/1.0 200 OK 

CSeq: 1 

Date: wed, Feb 20 2008 07:13:24 GMT 

Public: OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY,PAUSE 

2)C -> M 

DESCRIBE rtsp://192.168.1.109/1.mpgRTSP/1.0 

CSeq: 2 

Accept: application/sdp 

User-Agent: VLC media player(LIVE555 Streaming Mediav2007.02.20) 

2)M -> C 

RTSP/1.0 200 OK 

CSeq: 2 

Date: wed, Feb 20 2008 07:13:25 GMT 

Content-Base: rtsp://192.168.1.109/1.mpg/ 

Content-type: application/sdp 

Content-length: 447 

v=0 

o =- 2284269756 1 IN IP4 192.168.1.109 

s=MPEG-1 or 2 program Stream, streamed by the LIVE555 MediaServer 

i=1.mpg 

t=0 0 

a=tool:LIVE555 Streaming Media v2008.02.08 

a=type:broadcast 

a=control:* 

a=range:npt=0-66.181 

a=x-qt-text-nam:MPEG-1 or Program Stream, streamed by theLIVE555 Media Server 

a=x-qt-text-inf:1.mpg 

m=video 0 RTP/AVP 32 

c=IN IP4 0.0.0.0 

a=control:track1 

m=audio 0 RTP/AVP 14 

c=IN IP4 0.0.0.0 

a=control:track2 

3)C -> M 

SETUP rtsp://192.168.1.109/1.mpg/track1RTSP/1.0 

CSeq: 3 

Transport: RTP/AVP;unicast;client_port=1112-1113 

User-Agent: VLC media player(LIVE555 Streaming Mediav2007.02.20) 

3)M -> C 

RTSP/1.0 200 OK 

CSeq: 3 

Date: wed, Feb 20 2008 07:13:25 GMT 

Transport:RTP/AVP;unicast;destination=192.168.1.222;source=192.168.1.109;client_port=1112-1113;server_port=6970-6971 

Session: 3 

4)C -> M 

SETUP rtsp://192.168.1.109/1.mpg/track2RTSP/1.0 

CSeq: 4 

Transport: RTP/AVP;unicast;client_port=1114-1115 

Session: 3 

User-Agent: VLC media player(LIVE555 Streaming Mediav2007.02.20) 

4)M -> C 

RTSP/1.0 200 OK 

CSeq: 4 

Date: wed, Feb 20 2008 07:13:25 GMT 

Transport:RTP/AVP;unicast;destination=192.168.1.222;source=192.168.1.109;client_port=1114-1115;server_port=6972-6973 

Session: 3 

5)C -> M 

PLAY rtsp://192.168.1.109/1.mpg/ RTSP/1.0 

CSeq: 5 

Session: 3 

Range: npt=0.000- 

User-Agent: VLC media player(LIVE555 Streaming Mediav2007.02.20) 

5)M -> C 

RTSP/1.0 200 OK 

CSeq: 5 

Range: npt=0.000- 

Session: 3 

RTP-Info:url=rtsp://192.168.1.109/1.mpg/track1;seq=9200;rtptime=214793785,url=rtsp://192.168.1.109/1.mpg/track2;seq=12770;rtptime=31721

TS流与PS流的区别在于TS流的包结构是固定长度的,而PS流的包结构是可变长度。PS包与TS包在结构上的这种差异,导致了它们对传输误码具有不同的抵抗能力,因而应用的环境也有所不同。TS码流由于采用了固定长度的包结构,当传输误码破坏了某一TS包的同步信息时,接收机可在固定的位置检测它后面包中的同步信息,从而恢复同步,避免了信息丢失。而PS包由于长度是变化的,一旦某一PS包的同步信息丢失,接收机无法确定下一包的同步位置,就会造成失步,导致严重的信息丢失。因此,在信道环境较为恶劣,传输误码较高时,一般采用TS码流;而在信道环境较好,传输误码较低时,一般采用PS码流由于TS码流具有较强的抵抗传输误码的能力,因此目前在传输媒体中进行传输的MPEG-2码流基本上都采用了TS码流的包

格。

用live555开发流媒体播放器应用程序的方法

H264 流媒体 编码汇总相关推荐

  1. 流媒体-H264协议-编码-x264学习-相关概念x264编译及文件解析(一)

    流媒体-H264协议-编码-x264学习-相关概念x264编译及文件解析(一) 流媒体-H264协议-编码-x264学习-主要结构体(二) 流媒体-H264协议-编码-x264学习-主要函数(三) 流 ...

  2. 流媒体-H264协议-编码-x264学习-主要结构体(二)

    流媒体-H264协议-编码-x264学习-相关概念x264编译及文件解析(一) 流媒体-H264协议-编码-x264学习-主要结构体(二) 流媒体-H264协议-编码-x264学习-主要函数(三) 流 ...

  3. android 硬编码h264,windows 平台 ffmeg h264 硬编码

    本文讲述windows 平台下ffmpeg如何利用intel media SDK 进行 h264硬编码(测试版本为3.2.2). ffmeg硬编编码的流程与软件编码流程相同,唯一不同的地方在初始化en ...

  4. H264实时编码及NALU,RTP传输(续)

    对h.264压缩视频码流中i帧的提取(firstime) 2010-06-30 09:15 转载自 fandy586  http://hi.baidu.com/sdlyfdy 最终编辑 fandy58 ...

  5. FFMPEG H264/H265 编码延迟问题

    参考:http://blog.csdn.net/aoshilang2249/article/details/40397199?utm_source=tuicool&utm_medium=ref ...

  6. mp4v2再学习 -- H264视频编码成MP4文件

    一.H264视频编码成MP4文件 参看:H264视频编码成MP4文件 参看:mp4v2在VS2010下的编译与在项目中的使用 最近做项目需要将H264文件封装为mp4文件,从网上找到了MP4V2库,下 ...

  7. h264基本编码参数

    一  h264主要编码参数: 帧率,分辨率,YUV格式,qp,profile类型,vbr/cbr,gop,码率 1 帧率:表示每秒有多少个视频帧. 2 分辨率 3 YUV格式,标明YUV在数据流中的排 ...

  8. 海康PS转H264的编码思想(带图码流解释)

    海康PS转H264的编码思想(带图码流解释) 本人PS流解析成H264的其余文章: 01PS流格式 02封装时遇到的重点问题 03海康PS转H264的编码思想(带图码流解释) 1 海康的PS流发包的顺 ...

  9. H264视频编码成MP4文件

    http://blog.csdn.net/firehood_/article/details/8813587 版权声明:本文为博主原创文章,未经博主允许不得转载. 最近需要将H264视频编码成MP4格 ...

最新文章

  1. 【新星计划】MATLAB-冒号:符号详解
  2. 劲脆鸡米花、鸡排、黄金鸡块
  3. AtCoder - 2153 An Ordinary Game list模拟 || 博弈
  4. OS- -文件系统(三)
  5. 网络协议 3 - 从物理层到 MAC 层
  6. java设置小数位数_java设置小数点后位数
  7. 计算机及网络保密检查记录表,南京航空航天大学涉密计算机保密检查记录表.doc...
  8. Matlab常用函数表
  9. Siemens NX 1930中文版
  10. 弘辽科技:复购率太低怎么办呢?
  11. 第2章第29节:英文排版技巧:无衬线字体和手写字体的搭配 [PowerPoint精美幻灯片实战教程]
  12. 音频处理—SOX音效
  13. AxureRP和Markman新手入门心得
  14. matlab求解杜分方程,[转载]时间序列分析matlab简单函数
  15. ubuntu 关闭系统自动更新
  16. OPC OPCUA OPCDA
  17. psid mysql_sql-帮助将子查询转换为具有联接的查询
  18. 关于时间:UTC/GMT/xST/ xDT
  19. 082为什么不是c语言合理常量,082高级语言程序设计课件@北工大第2讲C语言的基本控制.pdf_人人文库网...
  20. LoRa模块(内置MCU),亿百特E22-400T30S,广播监听、定点传输、中继组网

热门文章

  1. 【转】Postman系列二:Postman中get接口实战讲解(接口测试介绍,接口测试流程,头域操作)
  2. 开源干货!.NET Core + Vue.js通用动态权限(RBAC)管理系统框架[DncZeus]开源
  3. mysql数据库字符集设置_查看和设置MySQL数据库字符集
  4. 人体轮廓_女性人体油画轮廓柔和生动,优美动人,你喜欢吗?
  5. number 限制最长数字_Java源码阅读-Number
  6. php linux 常用命令,Linux常用命令整理
  7. 【CodeForces - 1197C】Array Splitting(水题)
  8. 【 POJ - 3628 】Bookshelf 2(dfs 或 dp,0-1背包)
  9. 【HDU - 5627】Clarke and MST(最大生成树,与运算性质,最小生成树MST变形)
  10. 【CodeForces - 1042A】Benches (优先队列,思维模拟,maxmin问题)