【VS开发】【Live555-rtsp】在windows 使用vs2008编译live555
在windows 使用vs2008编译live555
liveMedia项目的源代码包括四个基本的库,各种测试代码以及 IVE555 Media Server。
四 个基本的库分别是 UsageEnvironment&TaskScheduler,groupsock,liveMedia,BasicUsageEnvironment。
UsageEnvironment 和TaskScheduler类用于事件的调度,实现异步读取事件的句柄的设置以及错误信息的输出。另外,还有一个HashTable类定义了一个通用的 hash表,其它代码要用到这个表。这些都是抽象类,在应用程序中基于这些类实现自己的子类。
groupsock类是对网络接口的封装, 用于收发数据包。正如名字本身,Groupsock主要是面向多播数据的收发的,它也同时支持单播数据的收发。Groupsock定义了两个构造函数
Groupsock(UsageEnvironment& env, struct in_addr const& groupAddr,
Port port, u_int8_t ttl);
Groupsock(UsageEnvironment& env, struct in_addr const& groupAddr,
struct in_addr const& sourceFilterAddr,
Port port);
前 者是用于SIM(source-independent multicast)组,后者用于SSM(source-specific multicast)组。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 Studio 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 Studio 9\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>devenv openRTSP.exe,这样就会把相关的调试环境搭建起来进行调试了。
liveMedia项目的源代码包括四个基本的库,各种测试代码以及IVE555 Media Server。
四个基本的库分别是 UsageEnvironment&TaskScheduler,groupsock,liveMedia,BasicUsageEnvironment。
UsageEnvironment 和TaskScheduler类用于事件的调度,实现异步读取事件的句柄的设置以及错误信息的输出。另外,还有一个HashTable类定义了一个通用的 hash表,其它代码要用到这个表。这些都是抽象类,在应用程序中基于这些类实现自己的子类。
groupsock类是对网络接口的封装, 用于收发数据包。正如名字本身,Groupsock主要是面向多播数据的收发的,它也同时支持单播数据的收发。Groupsock定义了两个构造函数
Groupsock(UsageEnvironment& env, struct in_addr const& groupAddr,
Port port, u_int8_t ttl);
Groupsock(UsageEnvironment& env, struct in_addr const& groupAddr,
struct in_addr const& sourceFilterAddr,
Port port);
前者是用于SIM(source-independent multicast)组,后者用于SSM(source-specific multicast)组。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 base class
virtual ~MediaSink();
virtual Boolean sourceIsCompatibleWithUs(MediaSource& source);
// called by startPlaying()
virtual Boolean continuePlaying() = 0;
// called by startPlaying()
static void onSourceClosure(void* clientData);
// should be called (on ourselves) by continuePlaying() when it
// 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: :DoGetNextFrame() 实现的,每一个Source module都有相应的实现。
Each 'source' module's implementation of "doGetNextFrame()" works by arranging for an 'after getting' function to be called (from an event handler) when new data becomes available for the caller.
注意,任何应用程序都要处理从'sources'到'sinks' 的数据流,但是并非每个这样的数据流都与从网络接口收发数据相对应。
比如,一个服务器应用程序发送RTP数据包的时候用到一个或多 个"RTPSink" modules。这些"RTPSink" modules以别的方式接收数据,通常是文件 "*Source" modules (e.g., to read data from a file), 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::DoGetNextFrame 在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消息给客户 端,客户端接收到该消息后释放资源,程序退出。
}
用live555中的库写了一个最简单的RTSPServer程序,仅用于学习目的。从下例的代码中,可以清析的明白RTSPServer的函数调用流程。
- #include <BasicUsageEnvironment.hh>
- #include "liveMedia.hh"
- static ServerMediaSession* createNewSMS(UsageEnvironment& env,charconst* fileName);
- int main()
- {
- TaskScheduler* scheduler;
- UsageEnvironment* env ;
- RTSPServer* rtspServer;
- ServerMediaSession* sms;
- //创建任务调用器
- scheduler = BasicTaskScheduler::createNew();
- //创建交互环境
- env = BasicUsageEnvironment::createNew(*scheduler);
- //创建RTSP服务器
- rtspServer = RTSPServer::createNew(*env,554); //使用554端口
- if(rtspServer == NULL)
- {
- rtspServer = RTSPServer::createNew(*env,8554); //554端口被占用,就使用8554端口
- }
- //打印服务器地址
- *env << "Play streams from this server using the URL\n\t"
- << rtspServer->rtspURLPrefix() << "<filename>.\n";
- //创建session
- sms = createNewSMS(*env, "test.mpg");
- rtspServer->addServerMediaSession(sms);
- //添加其它文件对应的session...
- //进行事件循环
- env->taskScheduler().doEventLoop(); // does not return
- return 0;
- }
- static ServerMediaSession* createNewSMS(UsageEnvironment& env,charconst* fileName)
- {
- char const* extension = strrchr(fileName,'.');
- ServerMediaSession* sms = NULL;
- Boolean reuseSource = False; //不重用source
- sms = ServerMediaSession::createNew(env, fileName); //创建一个session
- //
- //在session中添加subssesion
- //
- if(strcmp(extension, ".aac") == 0)
- {
- sms->addSubsession(ADTSAudioFileServerMediaSubsession::createNew(env, fileName, reuseSource));
- }
- else if(strcmp(extension, ".264") == 0)
- {
- sms->addSubsession(H264VideoFileServerMediaSubsession::createNew(env, fileName, reuseSource));
- }
- else if(strcmp(extension, ".mpg") == 0)
- {
- MPEG1or2FileServerDemux* demux
- = MPEG1or2FileServerDemux::createNew(env, fileName, reuseSource);
- sms->addSubsession(demux->newVideoServerMediaSubsession());
- sms->addSubsession(demux->newAudioServerMediaSubsession());
- }
- //添加其它媒体格式支持...
- return sms;
- }
1:编译好liive555库,在windows下
2:用测试例子建立个工程 将live555 头文件和lib路径加入工程属性中
3:在工程代码中写入代码:#pragma comment(lib,"libBasicUsageEnvironment.lib")
#pragma comment(lib,"libgroupsock.lib")
#pragma comment(lib,"libliveMedia.lib")
#pragma comment(lib,"libUsageEnvironment.lib")
4:测试工程无BUG 打开vlc 在打开网络串流中 输入: “rtsp://127.0.0.1/G:\VIDEO_AEDIO\mpg\test.mpg”
5:运行结果:
【VS开发】【Live555-rtsp】在windows 使用vs2008编译live555的更多相关文章
- JAVA 基础开发环境 vscode 搭建 Windows下VSCode编译运行简单java
JAVA 基础开发环境 vscode 搭建 来源 https://www.cnblogs.com/freewsf/p/7744728.html 对于使用 Visual Studio Code 的 Ja ...
- DevEco Device Tool 2.1 Beta1 的Hi3861在Windows平台的编译体验
DevEco Device Tool迎来了2.1 Beta1,其中的亮点之一是:支持Hi3861开发板的源码在Windows平台编译.带着浓厚的兴趣,第一时间做了一次体验. 首先在官网下载" ...
- live555 RTSP推送到Darwin出现404错误的解决
我们将Darwin部署到公网,接收live555 RTSP/RTP推送的时候,经常会出现在SETUP步骤Darwin返回404错误,经过查找原因,主要是Darwin对live555推送的sdp信息中的 ...
- 【转发】NPAPI开发详解,Windows版
NPAPI开发详解,Windows版 9 jiaofeng601, +479 9人支持,来自Meteor.猪爪.hanyuxinting更多 .是非黑白 .Yuan Xulei.hyolin.Andy ...
- 【搭建开发环境】在 Windows XP 中参与开源项目,搭建 git 和 cygwin 开发环境
引言 只有一台 Windows XP 家用机,却想在诸如 Git@OSC 之类的开源社区参与开发,本文提供一个入门级的开发环境搭建指引. 涉及工具:Eclipse,EGit,Cygwin. 欢迎来到 ...
- 【转】Windows下使用VS2008编译OpenCV 2.1 添加Intel TBB和Python支持
Windows下使用VS2008编译OpenCV2.1 添加Intel TBB和Python支持 步骤: 1.仔细阅读OpenCV官网上的InstallGuide:http://opencv.will ...
- .net 开发定时执行的windows服务
环境:win7+vs2010+Oracle11g+office2010(64位操作系统) 需求:开发定时执行的windows服务从数据库中查询数据下载到指定地址Excel中 一.添加新建项目——win ...
- 用C#开发较完整的Windows任务管理器
原文 用C#开发较完整的Windows任务管理器 这个代码没有什么技术含量,仅仅使用 WMI 和 API 实现了 Windows 任务管理器的部分功能. 但代码里面封装了一个 SystemInfo 的 ...
- Android ROM开发(一)——Windows下Cygwin和Android_Kitchen厨房的安装
Android ROM开发(一)--Windows下Cygwin和Android_Kitchen厨房的安装 很久没有碰到ROM开发了,在很久很久以前也是从ROM起步的,无奈还是一脚踏上了Android ...
随机推荐
- SQL Server查询表结构语句
--1:获取当前数据库中的所有用户表 www.2cto.com select Name from sysobjects where xtype='u' and status>=0 -- ...
- 09 saltstack生产实例--Haproxy+keepalived
1.如何理解haproxy+keepalived https://www.cnblogs.com/zs-wei/p/9213961.html HaProxy可以通过监听一个统一的端口对外提供能力,然后 ...
- Transformer的PyTorch实现--转载
转载自 https://blog.csdn.net/stupid_3/article/details/83184691
- js获取整个屏幕的尺寸
原文 首先获取屏幕宽度:window.screen.width; //整个屏幕的宽度. 然后获取屏幕高度:window.screen.height; //整个屏幕的高度. 获取可用工作区 ...
- MAC为Apache2服务器配置多个虚拟主机
Mac 下自带的 Apache 配置 2016年01月25日 00:25:03 阅读数:1292 参考: http://www.cnblogs.com/snandy/archive/2012/11/1 ...
- k8s-helm01-----helm基本使用
什么是helm Helm 是 Kubernetes 生态系统中的一个软件包管理工具. 基础概念: Helm:客户端,主要负责管理本地的 Charts.repositories 以及与tiller服务器 ...
- leetcode 日常清单
a:excellent几乎一次ac或只有点小bug很快解决:半年后再重刷: b:经过艰难的debug和磕磕绊绊或者看了小提示才刷出来: c:经过艰难的debug没做出来,看答案刷的: 艾宾浩斯遗忘曲线 ...
- 用key管理可复用元素
先看看不用key管理可复用元素的代码.Vue 会尽可能高效地渲染元素,通常会复用已有元素而不是从头开始渲染.这么做,除了使 Vue 变得非常快之外,还有一些有用的好处,那就是在切换input时不会清楚 ...
- C++中.cpp和.hpp的区别
原文地址:https://blog.csdn.net/qzx9059/article/details/89210571 c++中 cpp和hpp我们可以将所有东西都放在一个.cpp文件内,编译器会将这 ...
- mysql查询json字段
一张test表里存了一个content字段是json类型的,查询该content里manualNo这个字段 select JSON_EXTRACT (test .content, '$.manualN ...