参照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版本,区 ...
随机推荐
- 【ActionBar的使用】
在AS工程中使用ActionBar 简单实用: 1.功能清单文件中指定主题标签属性Theme.Holo或其子类 <application android :theme="@androi ...
- LINQ中的Aggregate用法总结
Aggregate这个语法可以做一些复杂的聚合运算,例如累计求和,累计求乘积.它接受2个参数,一般第一个参数是称为累积数(默认情况下等于第一个值),而第二个代表了下一个值.第一次计算之后,计算的结果会 ...
- SimpleXML 使用详细例子
要处理XML 文件,有两种传统的处理思路:SAX 和DOM.SAX 基于事件触发机制, 对XML 文件进行一次扫描,完成要进行的处理:DOM 则将整个XML 文件构造为一棵DOM 树,通过对DOM 树 ...
- Hadoop学习笔记01——Hadoop分布式文件系统
Hadoop有一个称为HDFS的分布式系统,全称为Hadoop Distributed Filesystem. HDFS有块(block)的概念,默认为64MB,HDFS上的文件被划分为块大小的多个分 ...
- linux服务器在运行210天左右宕机
减小字体 增大字体 作者:错新网 来源:www.cuoxin.com 发布时间:2014-2-25 19:21:32 错新网讯 最近几天,一批linux线上的服务器接连宕机,当时以为是硬件问题 ...
- 8_Times_Tables
8 // // ViewController.swift // Times Tables // // Created by ZC on 16/1/9. // Copyright © 2016年 ZC. ...
- Oracle数据库时间修改
http://blog.csdn.net/tianlesoftware/article/details/6163859
- 分享一个MD5加密工具类
来自:http://blog.csdn.net/zranye/article/details/8234480 Es:http://blog.csdn.net/longxibendi/article/d ...
- 利用 Android Studio 和 Gradle 打包多版本APK
在项目开发过程中,经常会有需要打包不同版本的 APK 的需求. 比如 debug版,release版,dev版等等. 有时候不同的版本中使用到的不同的服务端api域名也不相同. 比如 debug_ap ...
- mysql 批量删除分区
alter table titles drop partition p01; use zabbix; mysql> source drop_par.sql [oracle@oadb mysql] ...