参照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版本,区 ...
随机推荐
- linux查看与开启ssh
首先通过物理终端进入到linux上,手工检查ssh发现没运行/etc/init.d/sshd statussshd is stopped手工启动服务,发现报告权限错误./etc/init.d/sshd ...
- windows下设置/删除Tomcat的开机自启动
绿色版tomcat在配置好Java环境以后直接运行bin下面的startup.bat就能够正常启动,但是在客户这里很多时候都 需要tomcat开机自动启动.下面简单介绍一如何在windows下面开机自 ...
- 转场动画2-Pop动画
上一篇试讲push动画,这篇分解pop动画 里面关于矩阵有不懂得,参考CATransform3D 特效详解 上图(虚拟机下,图是渣渣 ) 代码直接上 // // PopTransition.h // ...
- .Net平台-MVP模式再探(二)
PS: 本文与 上一遍文章 没有什么必然的联系,可以说是对于MVP的一定的加深,或许在理解上比上一篇多有点难度. 正文 一.简单讲讲MVP是什么玩意儿 如果从层次关系来讲,MVP属于P ...
- nyoj 138 找球号(二)(哈希)
题目:nyoj——138 /*** 哈希求解...采用链表保存 插入时,可以去除重复 查找 找到该组,然后在改组的查找 当这个组不存在时或是没有找到时是 NO 其他是YES 1e6+1 时间最短 */ ...
- 9_Permanent Storage
9 // // ViewController.swift // Permanent Storage // // Created by ZC on 16/1/9. // Copyright © 2016 ...
- 注册表与盘符(转victor888文章 )
转自: http://blog.csdn.net/loulou_ff/article/details/3769479 写点东西,把这阶段的研究内容记录下来,同时也给研究相关内容的同志提供参考, ...
- [js - 算法可视化] 汉诺塔(Hanoi)演示程序
前段时间偶然看到有个日本人很早之前写了js的多种排序程序,使用js+html实现的排序动画,效果非常好. 受此启发,我决定写几个js的算法动画,第一个就用汉诺塔. 演示地址:http://tut.ap ...
- Checking Network Configuration requirements Failed
安装oracle执行检查,出现 Checking Network Configuration requirements ... Check complete. The overall result o ...
- ADF 项目创建流程
ADF 项目创建流程: 1.首先建好应用 2.创建model,UI 3.创建EO,VO,AO, VL 4.设置EO的属性 5.新建lov 6.设置VO的View Accessors,并设置Attrib ...