参照openRTSP写的一个RTSP client 加了一些注解
#include "liveMedia.hh"
#include "BasicUsageEnvironment.hh"
#include "GroupsockHelper.hh"
UsageEnvironment* env;
portNumBits tunnelOverHTTPPortNum = 0;
const char * url="rtsp://127.0.0.1:1935/vod/Extremists.m4v";
#if defined(__WIN32__) || defined(_WIN32)
#define snprintf _snprintf
#endif
int main(int argc,const char ** argv)
{
//创建BasicTaskScheduler对象
TaskScheduler* scheduler = BasicTaskScheduler::createNew();
//创建BisicUsageEnvironment对象
env = BasicUsageEnvironment::createNew(*scheduler);
//创建RTSPClient对象
RTSPClient * rtspClient= RTSPClient::createNew(*env);
//由RTSPClient对象向服务器发送OPTION消息并接受回应
char* optionsResponse=rtspClient->sendOptionsCmd(url);
delete [] optionsResponse;
//产生SDPDescription字符串(由RTSPClient对象向服务器发送DESCRIBE消息并接受回应,根据回应的信息产生SDPDescription字符串,其中包括视音频数据的协议和解码器类型)
char* sdpDescription =rtspClient->describeURL(url);
//创建MediaSession对象(根据SDPDescription在MediaSession中创建和初始化MediaSubSession子会话对象)
MediaSession* session = MediaSession::createNew(*env, sdpDescription);
delete[] sdpDescription;
MediaSubsessionIterator iter(*session);
MediaSubsession *subsession;
while ((subsession = iter.next()) != NULL) {
// Creates a "RTPSource" for this subsession. (Has no effect if it's
// already been created.) Returns True iff this succeeds.
if (!subsession->initiate()) {
*env << "Unable to create receiver for "" << subsession->mediumName()
<< "/" << subsession->codecName()
<< "" subsession: " << env->getResultMsg() << "\n";
} else {
*env << "Created receiver for "" << subsession->mediumName()
<< "/" << subsession->codecName()
<< "" subsession (client ports " << subsession->clientPortNum()
<< "-" << subsession->clientPortNum()+1 << ")\n";
if (subsession->rtpSource() != NULL) {
// Because we're saving the incoming data, rather than playing
// it in real time, allow an especially large time threshold
// (1 second) for reordering misordered incoming packets:
unsigned const thresh = 1000000; // 1 second
subsession->rtpSource()->setPacketReorderingThresholdTime(thresh);
// Set the RTP source's OS socket buffer size as appropriate - either if we were explicitly asked (using -B),
// or if the desired FileSink buffer size happens to be larger than the current OS socket buffer size.
// (The latter case is a heuristic, on the assumption that if the user asked for a large FileSink buffer size,
// then the input data rate may be large enough to justify increasing the OS socket buffer size also.)
int socketNum = subsession->rtpSource()->RTPgs()->socketNum();
unsigned curBufferSize = getReceiveBufferSize(*env, socketNum);
unsigned newBufferSize = setReceiveBufferTo(*env, socketNum, 100000);
}
}
}
//由RTSPClient对象向服务器发送SETUP消息并接受回应
iter.reset();
while ((subsession = iter.next()) != NULL) {
if (subsession->clientPortNum() == 0) continue; // port # was not set
if (!rtspClient->setupMediaSubsession(*subsession)) {
*env << "Failed to setup "" << subsession->mediumName()
<< "/" << subsession->codecName()
<< "" subsession: " << env->getResultMsg() << "\n";
} else {
*env << "Setup "" << subsession->mediumName()
<< "/" << subsession->codecName()
<< "" subsession (client ports " << subsession->clientPortNum()
<< "-" << subsession->clientPortNum()+1 << ")\n";
}
if (subsession->rtpSource() != NULL) {
// Because we're saving the incoming data, rather than playing
// it in real time, allow an especially large time threshold
// (1 second) for reordering misordered incoming packets:
unsigned const thresh = 1000000; // 1 second
subsession->rtpSource()->setPacketReorderingThresholdTime(thresh);
}
}
iter.reset();
while ((subsession = iter.next()) != NULL) {
if (subsession->readSource() == NULL) continue; // was not initiated
char outFileName[1000];
static unsigned streamCounter = 0;
snprintf(outFileName, sizeof outFileName, "%s-%s-%d",
subsession->mediumName(),
subsession->codecName(), ++streamCounter);
FileSink* fileSink;
if (strcmp(subsession->mediumName(), "audio") == 0 &&
(strcmp(subsession->codecName(), "AMR") == 0 ||
strcmp(subsession->codecName(), "AMR-WB") == 0)) {
// For AMR audio streams, we use a special sink that inserts AMR frame hdrs:
fileSink = AMRAudioFileSink::createNew(*env, outFileName);
} else if (strcmp(subsession->mediumName(), "video") == 0 &&
(strcmp(subsession->codecName(), "H264") == 0)) {
// For H.264 video stream, we use a special sink that insert start_codes:
unsigned int num=0;
SPropRecord * sps=parseSPropParameterSets(subsession->fmtp_spropparametersets(),num);
fileSink = H264VideoFileSink::createNew(*env, outFileName,100000);
struct timeval tv={0,0};
unsigned char start_code[4] = {0x00, 0x00, 0x00, 0x01};
fileSink->addData(start_code, 4, tv);
fileSink->addData(sps[0].sPropBytes,sps[0].sPropLength,tv);
fileSink->addData(start_code, 4, tv);
fileSink->addData(sps[1].sPropBytes,sps[1].sPropLength,tv);
delete[] sps;
} else {
// Normal case:
fileSink = FileSink::createNew(*env, outFileName);
}
subsession->sink = fileSink;
subsession->sink->startPlaying(*(subsession->readSource()),NULL,NULL);
}
rtspClient->playMediaSession(*session, 0.0f, 0.0f, (float)1.0);
env->taskScheduler().doEventLoop(); // does not return
return 0; // only to prevent compiler warning
}
参照openRTSP写的一个RTSP client 加了一些注解的更多相关文章
- C语言写了一个socket client端,适合windows和linux,用GCC编译运行通过
////////////////////////////////////////////////////////////////////////////////* gcc -Wall -o c1 c1 ...
- [jQuery插件]手写一个图片懒加载实现
教你做图片懒加载插件 那一年 那一年,我还年轻 刚接手一个ASP.NET MVC 的 web 项目, (C#/jQuery/Bootstrap) 并没有做 web 的经验,没有预留学习时间, (作为项 ...
- 用C3中的animation和transform写的一个模仿加载的时动画效果
用用C3中的animation和transform写的一个模仿加载的时动画效果! 不多说直接上代码; html标签部分 <div class="wrap"> <h ...
- 输入一个数字n 如果n为偶数则除以2,若为奇数则加1或者减1,直到n为1,求最少次数 写出一个函数
题目: 输入一个数字n 如果n为偶数则除以2,若为奇数则加1或者减1,直到n为1,求最少次数 写出一个函数 首先,这道题肯定可以用动态规划来解, n为整数时,n的解为 n/2 的解加1 n为奇数时 ...
- 用c#写的一个局域网聊天客户端 类似小飞鸽
用c#写的一个局域网聊天客户端 类似小飞鸽 摘自: http://www.cnblogs.com/yyl8781697/archive/2012/12/07/csharp-socket-udp.htm ...
- 搞了我一下午竟然是web.config少写了一个点
Safari手机版居然有个这么愚蠢的bug,浪费了我整个下午,使尽浑身解数,国内国外网站搜索解决方案,每一行代码读了又想想了又读如此不知道多少遍,想破脑袋也想不通到底哪里出了问题,结果竟然是web.c ...
- C# 写的一个生成随机汉语名字的小程序
最近因为要做数据库相关的测试,频繁使用到测试数据,手动添加太过于麻烦,而且复用性太差,因此干脆花了点时间写了一个生成随机姓名和相关数据的类,贴在这里,有需用的同志们可以参考一下.代码本身质量不好,也不 ...
- R入门-第一次写了一个完整的时间序列分析代码
纪念一下,在心心念念想从会计本科转为数据分析师快两年后,近期终于迈出了使用R的第一步,在参考他人的例子前提下,成功写了几行代码.用成本的角度来说,省去了部门去买昂贵的数据分析软件的金钱和时间,而对自己 ...
- 升级WebService图形服务,将K10.2和K10.3写到一个类库,所有服务放在一个类库
问题描述: 平时负责电子政务和图形调用部分,凡是牵涉到图形的都需要调用WebService服务,因此很多工程都需要添加web服务引用,现在WebForm的工程一个是10.2版本,一个是10.3版本,区 ...
随机推荐
- 前自加(++a)与后自加(a++)的差别
自加是自己加1的操作.比如a++ 是a+1 ,变量a变成了 a+1的值. 如果是简单的只做 a++:或者++a的语句,效果是一样的. 但是如果嵌入到复杂的语句中,比如 b = a++: 和 b = + ...
- Eclipse+EGit的配置注意点, 以及解决Github多个本地仓库之间的冲突
问题描述 不同本地仓库(e.g. Repo1, Repo2)之间同时修改一个文件时, 出现文件无法merge的情况. 具体表现为, 冲突(红色双向实心箭头)一直存在, 点pull没反应, 点push报 ...
- which 查看可执行文件的位置
我们经常在linux要查找某个文件,但不知道放在哪里了,可以使用下面的一些命令来搜索: which 查看可执行文件的位置. whereis 查看文件的位置. ...
- win10中的vmware桥接模式异常,不能设置同网段ip
今天发现centOS的桥接模式不正常了,配置 dhclient居然不成功,没有同个网段的ip,于是各种找原因. 突然灵光一现,前几天更新了win10,会不会神马驱动或者服务没安装? 找了一圈,我勒个去 ...
- Html 小插件5 百度搜索代码2
网页添加百度搜索框代码大全 ★ 用法:在下面选择合适的样式,复制代码到网页中相应位置粘贴即可. ★ 样式一(200×30)代码: <iframe id="baiduframe" ...
- 浅谈 android-query
介绍:android-query他是在GitHub上的一个开源轻量级的封装库,它集成了网络 .图片加载等模块,可以应用在android中的一些异步应用以及UI的操纵上,通过使用这个框架,使androi ...
- bootstrap 导航栏
非常好的一篇文章: http://webdesigntutsplus.s3.amazonaws.com/tuts/312_bs/My-Bootstrap-Site-NAVBAR/navbar-exam ...
- centos6.4-x86-64系统更新系统自带Apache Http Server
系统自带Apache Http Server 版本比较老,有漏洞.现在对Apache Http Server进行升级.总体思路:先删除老的,再安装新的.详细步骤如下: 1 删除老版本 1.1 删除老A ...
- 最长回文子串 | 勇幸|Thinking
最长回文子串 | 勇幸|Thinking 最长回文子串
- Android 开发佳站【转】
Android控件拖动 这里演示控件拖动的动画: 原理就是响应控件的Touch事件,在Touch事件中对移动进行处理,注意,一定要在布局文件中设置控件的 android:clickable=& ...