1、testRTSPClient简介

testRTSPClient是个简单的客户端实例,这个实例对rtsp数据交互作了详细的描述,其中涉及到rtsp会话的两个概念Source和Sink.

Source是生产数据,Sink是消费数据.

testRTSPClient非常简洁,除了接收服务端发送过来的数据,什么都没干,所以我们很方便在这个基础上改造,做我们自己的项目.

2、testRTSPClient编译,运行

在linux下编译运行更方便,鉴于我的电脑太渣,虚拟机跑起来费劲,就转到windows下来折腾.

在windows下只需要加载这一个文件就可以编译,我们以mediaServer为服务端,以testRTSPClient为客户端。

当然也可以用支持rtsp协议的摄像机或其他实体设备作为服务端。

先启动mediaServer,然后在testRTSPClient项目的命令菜单里填入mediaServer 提示的IP, 再启动testRTSPClient即可。

3、testRTSPClient核心代码解读

1)看代码之前可以大致浏览一下总体的框架,这位博主画了个流程图http://blog.csdn.net/smilestone_322/article/details/17297817

void DummySink::afterGettingFrame(unsigned frameSize, unsigned numTruncatedBytes,
struct timeval presentationTime, unsigned /*durationInMicroseconds*/) {
// We've just received a frame of data. (Optionally) print out information about it:
#ifdef DEBUG_PRINT_EACH_RECEIVED_FRAME
if (fStreamId != NULL) envir() << "Stream \"" << fStreamId << "\"; ";
envir() << fSubsession.mediumName() << "/" << fSubsession.codecName() << ":\tReceived " << frameSize << " bytes";
if (numTruncatedBytes > 0) envir() << " (with " << numTruncatedBytes << " bytes truncated)";
char uSecsStr[6+1]; // used to output the 'microseconds' part of the presentation time
sprintf(uSecsStr, "%06u", (unsigned)presentationTime.tv_usec);
envir() << ".\tPresentation time: " << (unsigned)presentationTime.tv_sec << "." << uSecsStr;
if (fSubsession.rtpSource() != NULL && !fSubsession.rtpSource()->hasBeenSynchronizedUsingRTCP()) {
envir() << "!"; // mark the debugging output to indicate that this presentation time is not RTCP-synchronized
}
envir() << "\n";
#endif // Then continue, to request the next frame of data:
continuePlaying();
} Boolean DummySink::continuePlaying() {
if (fSource == NULL) return False; // sanity check (should not happen) // Request the next frame of data from our input source. "afterGettingFrame()" will get called later, when it arrives:
fSource->getNextFrame(fReceiveBuffer, DUMMY_SINK_RECEIVE_BUFFER_SIZE,
afterGettingFrame, this,
onSourceClosure, this);
return True;
}

2)有网友在testRTSPClient基础上,把接收的数据写成h264文件了http://blog.csdn.net/occupy8/article/details/36426821

void DummySink::afterGettingFrame(void* clientData, unsigned frameSize, unsigned numTruncatedBytes,
struct timeval presentationTime, unsigned durationInMicroseconds) {
DummySink* sink = (DummySink*)clientData;
sink->afterGettingFrame(frameSize, numTruncatedBytes, presentationTime, durationInMicroseconds);
} // If you don't want to see debugging output for each received frame, then comment out the following line:
#define DEBUG_PRINT_EACH_RECEIVED_FRAME 1 void DummySink::afterGettingFrame(unsigned frameSize, unsigned numTruncatedBytes,
struct timeval presentationTime, unsigned /*durationInMicroseconds*/) {
// We've just received a frame of data. (Optionally) print out information about it:
#ifdef DEBUG_PRINT_EACH_RECEIVED_FRAME
if (fStreamId != NULL) envir() << "Stream \"" << fStreamId << "\"; ";
envir() << fSubsession.mediumName() << "/" << fSubsession.codecName() << ":\tReceived " << frameSize << " bytes";
if (numTruncatedBytes > 0) envir() << " (with " << numTruncatedBytes << " bytes truncated)";
char uSecsStr[6+1]; // used to output the 'microseconds' part of the presentation time
sprintf(uSecsStr, "%06u", (unsigned)presentationTime.tv_usec);
envir() << ".\tPresentation time: " << (unsigned)presentationTime.tv_sec << "." << uSecsStr;
if (fSubsession.rtpSource() != NULL && !fSubsession.rtpSource()->hasBeenSynchronizedUsingRTCP()) {
envir() << "!"; // mark the debugging output to indicate that this presentation time is not RTCP-synchronized
}
envir() << "\n";
#endif //todo one frame
//save to file
if(!strcmp(fSubsession.mediumName(), "video"))
{
if(firstFrame)
{
unsigned int num;
SPropRecord *sps = parseSPropParameterSets(fSubsession.fmtp_spropparametersets(), num);
// For H.264 video stream, we use a special sink that insert start_codes:
struct timeval tv= {0,0};
unsigned char start_code[4] = {0x00, 0x00, 0x00, 0x01};
FILE *fp = fopen("test.264", "a+b");
if(fp)
{
fwrite(start_code, 4, 1, fp);
fwrite(sps[0].sPropBytes, sps[0].sPropLength, 1, fp);
fwrite(start_code, 4, 1, fp);
fwrite(sps[1].sPropBytes, sps[1].sPropLength, 1, fp);
fclose(fp);
fp = NULL;
}
delete [] sps;
firstFrame = False;
} char *pbuf = (char *)fReceiveBuffer;
char head[4] = {0x00, 0x00, 0x00, 0x01};
FILE *fp = fopen("test.264", "a+b");
if(fp)
{
fwrite(head, 4, 1, fp);
fwrite(fReceiveBuffer, frameSize, 1, fp);
fclose(fp);
fp = NULL;
}
} // Then continue, to request the next frame of data:
continuePlaying();
} Boolean DummySink::continuePlaying() {
if (fSource == NULL) return False; // sanity check (should not happen) // Request the next frame of data from our input source. "afterGettingFrame()" will get called later, when it arrives:
fSource->getNextFrame(fReceiveBuffer, DUMMY_SINK_RECEIVE_BUFFER_SIZE,
afterGettingFrame, this,
onSourceClosure, this);
return True;
}

testRTSPClient接收的fReceiveBuffer缓存没有起始码,start_code[4] = {0x00, 0x00, 0x00, 0x01}; 写成文件或者播放都需要自行加上。

3)testRTSPClient这个实例还支持多路录放,网上搜到有人已经实现了,搬过来.

http://blog.chinaunix.net/uid-15063109-id-4482932.html

                                                    ——缺什么补什么

live555库中的testRTSPClient实例的更多相关文章

  1. RTSP客户端接收存储数据(live555库中的testRTSPClient实例)

    1.testRTSPClient简介 testRTSPClient是个简单的客户端实例,这个实例对rtsp数据交互作了详细的描述,其中涉及到rtsp会话的两个概念Source和Sink. Source ...

  2. live555库中的testH264VideoStreamer实例

    1.h264文件的推送 testH264VideoStreamer.cpp文件的开头就定义了 char const* inputFileName = "test.264"; 后面接 ...

  3. live555库中的openRTSP实例

    一.openRTSP编译运行 a)windows下编译运行 还是以mediaServer作为服务端,openRTSP作为客户端 b)Linux下编译运行 转自http://kuafu80.blog.1 ...

  4. RTSP客户端接收存储数据(live555库中的openRTSP实例)

    一.openRTSP编译运行 a)windows下编译运行 还是以mediaServer作为服务端,openRTSP作为客户端 b)Linux下编译运行 转自http://kuafu80.blog.1 ...

  5. RTSP服务端转发服务(live555库中的testH264VideoStreamer.cpp和testOnDemandRTSPServer.cpp实例)

    1.h264文件的推送 testH264VideoStreamer.cpp文件的开头就定义了 char const* inputFileName = "test.264"; 后面接 ...

  6. 宣布在 Azure 镜像库中正式推出 Windows Server 2012 R2 并降低 Windows Azure 的实例定价

    我们今天将宣布两条消息,为使用基础结构服务的客户提供更多选择和成本节约:在镜像库中推出 Windows Server 2012 R2 以及降低 Memory Intensive 计算实例定价. 虚拟机 ...

  7. NSClassFromString 实例话静态库中的类

    Class myClass = NSClassFromString("StaticLibyClassName"); StaticLibyClassName是从静态库中实例化一个Cl ...

  8. Solr的原理及在项目中的使用实例.

    前面已经讲过 如果安装及配置Solr服务器了, 那么现在我们就来正式在代码中使用Solr.1,这里Solr主要是怎么使用的呢?  当我们在前台页面搜索商品名称关键词时, 我们这时是在Solr库中去查找 ...

  9. linux静态与动态库创建及使用实例

    一,gcc基础语法: 基本语法结构:(由以下四部分组成) gcc -o 可执行文件名 依赖文件集(*.c/*.o) 依赖库文件及其头文件集(由-I或-L与-l指明) gcc 依赖文件集(*.c/*.o ...

随机推荐

  1. 转: linux内核版本本地版本号的检查——setlocalversion

    转载:http://blog.csdn.net/adaptiver/article/details/7225980 1.   引子 编译2.6.35.7 kernel版本的时候发现,"2.6 ...

  2. 通过javascript在网页端解压zip文件并查看压缩包内容

    WEB前端解压ZIP压缩包 web前端解压zip文件有什么用: 只考虑标准浏览器的话, 服务器只要传输压缩包到客户端, 节约了带宽, 而且节约了传输时间, 听起来好像很厉害的说:     如果前端的代 ...

  3. hdu 4612 强连通

    题意:有一些联通的地方,如果2点间只有一条路径,这样的边叫做桥,现在让你添加一个桥,使最后的桥最少,问最少的桥使多少? 先求一次强连通分量,然后图就分成了几个块,将这几个块看做点,求出总共有多少条重建 ...

  4. 让Chrome支持Ajax/$http方式读取本地文件

    在开发中经常写些小demo调试一下插件什么的 数据源又经常手动构造分离为一个单独的文件.用ajax或$http去访问时总是拒绝访问.这个时候可以给Chrome的快捷图标加启动参数,让浏览器允许js访问 ...

  5. 【POJ 2528】Mayor’s posters(线段树+离散化)

    题目 给定每张海报的覆盖区间,按顺序覆盖后,最后有几张海报没有被其他海报完全覆盖.离散化处理完区间端点,排序后再给相差大于1的相邻端点之间再加一个点,再排序.线段树,tree[i]表示节点i对应区间是 ...

  6. BZOJ 4385: [POI2015]Wilcze doły

    4385: [POI2015]Wilcze doły Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 648  Solved: 263[Submit][ ...

  7. js-JavaScript高级程序设计学习笔记2

    第四章 变量.作用域和内存问题 1.ES变量包含两种不同数据类型的值--基本类型值(5种基本数据类型)和引用类型值(保存在内存中的对象,所有引用类型值都是Object的实例) 2.只能给引用类型值动态 ...

  8. 【poj3522】 Slim Span

    http://poj.org/problem?id=3522 (题目链接) 题意 求最小生成树的最大边与最小边差最小. Solution 排序后滑动窗口维护 代码 // poj3522 #includ ...

  9. jQuery—选择器

    摘抄自<锋利的jQuery> 一.基本选择器 $("#one").css("background","#bbffaa"); 选取 ...

  10. 数据结构2 静态区间第K大/第K小

    给定数组$A[1...N]$, 区间$[L,R]$中第$K$大/小的数的指将$A[L...R]$中的数从大到小/从小到大排序后的第$K$个. "静态"指的是不带修改. 这个问题有多 ...