参照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版本,区 ...
随机推荐
- 在 Visio 中录制宏
在“开发工具”选项卡上,单击“录制宏”.(如果您看不到“开发工具”选项卡,请参阅下面的“显示‘开发工具’选项卡”.) 在“宏名”框中,键入宏名称. 在“快捷键”框中,键入与 Ctrl 键一起使用可运行 ...
- MSSQL 当前会话设置隔离级别与查询
之前因为MySQL没有with(nolock)这种写法,于是想设置隔离级别,结果被坑. 直觉以为和MSSQL一样只要打set transaction isolation level xxx 就能搞定 ...
- PHP删除HTMl标签
/** * 取出html标签 * * @access public * @param string str * @return string * */ function deletehtml($str ...
- 输出多行字符的一个简单JAVA小程序
public class JAVA { public static void main(String[] args) { System.out.println("-------------- ...
- 理解ROS话题
首先需要打开一个终端在里面运行roscore: roscore 再打开一个终端,在里面运行一个turtlesim_node节点: rosrun turtlesim turtlesim_node 打开另 ...
- 基于JDK 8的Dubbo Admin
在使用Dubbo Admin的时候,一直报错,无法启动,因为Dubbo Admin使用的各种库相对是比较旧的,在JDK 8下,有些小问题 具体解决过程参考的以下链接 https://github.c ...
- Bluetooth 2.1+EDR是什么
目前应用最为广泛的是 Bluetooth 2.0+EDR标准,该标准在2004年已经推出,支持Bluetooth 2.0+EDR标准的产品也于2006年大量出现.虽然Bluetooth 2.0+EDR ...
- 投资新兴市场和细分市场 good
新兴市场对程序员来说,就是一种新的语言.一个新的平台.一套新的框架.新兴市场因为刚刚兴起,所以几乎所有人都在同一个起跑线,特别适合后进者.我认识从一个2011年开始学习iOS开发的同学,他能能力中等, ...
- qt4.8.4安装以及64位程序编译方法
本文将使用简单的几个步骤说明在vc2008和64位的操作系统下如何编译安装x64Qt软件 首先必须保证你所使用的系统是64bit的操作系统,本次我们使用的系统是windows7 professiona ...
- XML DOM 节点
来自:w3cschool菜鸟教程 在 DOM 中,XML 文档中的每个成分都是一个节点. DOM 节点 根据 DOM,XML 文档中的每个成分都是一个节点. DOM 是这样规定的: 整个文档是一个文档 ...