首页 > 其他分享 >LIVE555再学习 -- testRTSPClient 实例

LIVE555再学习 -- testRTSPClient 实例

时间:2023-04-03 20:06:31浏览次数:53  
标签:recvBuf LIVE555 .. lib -- 0x00 live555 testRTSPClient


上一篇文章简单看了一遍 testRTSPClient  的源码,接下来举几个应用实例加深一下。

首先什么都不做修改,先执行一遍,看一下。

一、执行 testRTSPClient  

LIVE555再学习 -- testRTSPClient 实例_#pragma

LIVE555再学习 -- testRTSPClient 实例_ide_02

特么,上面的东西我没看明白。。。 a=、b=、c=等等这是什么?

还有我看别人分析的好像用到什么网络抓包工具,我不知道是什么工具,可能是 Wireshark ,我也不晓得怎么用。

参看: live555源代码分析

二、核心代码

再就是做移植的时候主要更改的地方

LIVE555再学习 -- testRTSPClient 实例_sed_03

上述函数中会返回每帧数据长度 frameSize,fReceiveBuffer 是缓存指针;
DUMMY_SINK_RECEIVE_BUFFER_SIZE宏值默认是100000,若是高清视频超过1080p需要设置为300000。
一般为了取流我们必须在此触发个回调函数将frameSize,fReceiveBuffer以参数化形式送出。
fSubsession为媒体信息,主要提供通道名称、RTP负载类型、RTP时间戳、序列等信息,很重要的信息,可用于区分音、视频。
DummySink为数据池,用于处理摄像机发送过来的视频流。

三、实例(1)

参看:live555 使用testRTSPClient 接收h264记录

接收 h264 文件记录

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();  
}

先理解关键知识点,不知道有没有误导,H264 的帧是以 NAL 单元的单位来传送的,一个 NAL 单元包含一帧(I帧 或 P帧 或 B帧),这三种类型的帧可以百度。所谓的 NAL 单元就是去掉 SPS、PPS 的视频帧, I 帧是关键帧,所有的解析都需要靠它,两个 I 帧之间被称为视频序列,I 帧头部需要加入 SPS 和 PPS,这两个之间需要 0x00000001 来分割, 0x00 0x00 0x00 0x01 + SPS的 Base64 解码形式 + 0x00 0x00 0x00 0x01 + PPS 的解码形式 + 0x00 0x00 0x00 0x01 视频帧(IDR帧) 这样组成的一个 buffer,FFMPEG 的 H264 解码器才能成功解码。

四、实例(2)

参看:【rtsp录制器】testRTSPClient+mp4v2录制mp4(h264+aac)


实现效果为: 
修改 testRTSPClient 来接收音视频流,并通过mp4v2 将音视频流录制为mp4(audio:aac,video:h264)

live555 和 MP4v2 我们之前都讲过的,这就简单了。


参看:mp4v2再学习 -- H264视频编码成MP4文件

参看:LIVE555再学习 -- Windows 下编译

因为我用的是vs2017,直接下载参看博客提供的工程会出现错误。


1>------ 已启动生成: 项目: testRTSPClient, 配置: Debug Win32 ------
1>TRACKER :
1>C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\Platforms\Win32\Microsoft.Cpp.Win32.Targets(153,5):
 error MSB6006: “CL.exe”已退出,代码为 5。
1>已完成生成项目“testRTSPClient.vcxproj”的操作 - 失败。
========== 生成: 成功 0 个,失败 1 个,最新 0 个,跳过 0 个 ==========

而且需要的库文件也不是vs2017生成的,容易产生版本不兼容。

得了还是自己从新做一遍。

(1)新建项目

打开 VS;

文件->新建->项目->Win32控制台应用程序->选择空项目,点击完成。

注意,选择的位置最好不要有 空格或者汉字。

LIVE555再学习 -- testRTSPClient 实例_sed_04

LIVE555再学习 -- testRTSPClient 实例_ide_05

LIVE555再学习 -- testRTSPClient 实例_ide_06

(2)拷贝文件

将 live555 四个库文件的include 和 lib 拷贝到一起。将MP4v2的include和lib拷贝到一起。

然后将参看博客工程里的 testRTSPClient 文件夹下的 .cpp 和 .h 文件拷贝到新建项目下。 

其中源码部分也要注意要和存放位置一致

LIVE555再学习 -- testRTSPClient 实例_sed_07

LIVE555再学习 -- testRTSPClient 实例_#pragma_08

LIVE555再学习 -- testRTSPClient 实例_sed_09

根据实际需要修改你的位置

LIVE555再学习 -- testRTSPClient 实例_sed_10

 

LIVE555再学习 -- testRTSPClient 实例_ide_11

然后将 .h 添加到头文件刷选器下,将.cpp添加到源文件刷选器下

LIVE555再学习 -- testRTSPClient 实例_sed_12

(3)配置属性

打开属性面板

解决方案资源管理器->右键单击项目->属性

LIVE555再学习 -- testRTSPClient 实例_ide_13

头文件配置

配置属性->C/C++->常规->附加包含目录,输入

 ..\MP4Encoder\include;..\live555\BasicUsageEnvironment\include;..\live555\groupsock\include;..\live555\liveMedia\include;..\live555\UsageEnvironment\include

LIVE555再学习 -- testRTSPClient 实例_#pragma_14

导入库配置

配置属性->链接器->常规->附加库目录,输入 ..\MP4Encoder\lib

LIVE555再学习 -- testRTSPClient 实例_sed_15

配置属性->链接器->输入->附加依赖项,输入 libmp4v2.lib;

live555 四个库,用程序包含了,这里就不用再添加了。

#pragma comment (lib, "Ws2_32.lib")  
#pragma comment(lib,"../live555/lib/BasicUsageEnvironment.lib")
#pragma comment(lib,"../live555/lib/liveMedia.lib")
#pragma comment(lib,"../live555/lib/groupsock.lib")
#pragma comment(lib,"../live555/lib/UsageEnvironment.lib")

LIVE555再学习 -- testRTSPClient 实例_#pragma_16


此刻再编译testRTSPClient,OK 编译成功,生成 testRTSPClient.exe。

LIVE555再学习 -- testRTSPClient 实例_ide_17

(4)测试

打开live555服务器

LIVE555再学习 -- testRTSPClient 实例_#pragma_18

执行 testRTSPClient.exe rtsp://192.168.2.xx/Titanic.mkv

LIVE555再学习 -- testRTSPClient 实例_#pragma_19

最后生成 lsh.mp4,将其和 Titanic.mkv 对比。可发现比 Titanic.mkv 小了十几 KB。

LIVE555再学习 -- testRTSPClient 实例_ide_20

使用 VLC 播放 lsh.mp4 ,没有声音. 

LIVE555再学习 -- testRTSPClient 实例_ide_21

(5)项目工程

下载:testRTSPClient+mp4v2录制mp4工程文件

(6)总结

这个工程,源码部分,还好理解。核心源码

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: " << (int)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
	}
#ifdef DEBUG_PRINT_NPT
	envir() << "\tNPT: " << fSubsession.getNormalPlayTime(presentationTime);
#endif
	envir() << "\n";
#endif

	//----------------------------------------------------------------------------------
	static int count = 1;
	//
	if(count++ == 6000){
		m_mp4Encoder->CloseMp4Encoder();
		MessageBoxA(NULL,"end","end",MB_OK);
	}
	//
	if ( 0==strcmp(fSubsession.mediumName(),"video") )     
	{
		m_recvBuf[0] = 0x00;
		m_recvBuf[1] = 0x00;
		m_recvBuf[2] = 0x00;
		m_recvBuf[3] = 0x01;
		//
		if(m_isInitSpsPps)
		{
			m_isInitSpsPps = false;
			unsigned int num=0;  
			SPropRecord * sps=parseSPropParameterSets(fSubsession.fmtp_spropparametersets(),num);
			//
			for(int i=0;i<2;i++){
				memcpy(&m_recvBuf[4], sps[i].sPropBytes, sps[i].sPropLength);
				m_mp4Encoder->Mp4VEncode(m_recvBuf,sps[i].sPropLength+4);
			}
			delete[] sps;  
		}
		//
		memcpy(&m_recvBuf[4], fReceiveBuffer, frameSize);
		m_mp4Encoder->Mp4VEncode(m_recvBuf,frameSize+4);
	}
	if ( 0==strcmp(fSubsession.mediumName(),"audio") )
	{
		memcpy(m_recvBuf,fReceiveBuffer,frameSize);
		m_mp4Encoder->Mp4AEncode(m_recvBuf,frameSize);
	}
	//----------------------------------------------------------------------------------
	// Then continue, to request the next frame of data:
	continuePlaying();
}

MP4v2部分的源码,我就不晓得了。跟我之前参看的 mp4v2再学习 -- H264视频编码成MP4文件 不太一样

然后,我又想一般我们都是 sensor 输出数据然后通过 RTSP 传输 VLC 播放,是这样的一套。

这个 testRTSPClient RTSP的客户端肯定是不对的。应该是 RTSP的服务器测。

所以,接下来我们讲下一个源码分析之 testH264VideoStreamer,官网介绍如下:

testH264VideoStreamer repeatedly reads from a H.264 Elementary Stream video file (named "test.264"), and streams it using RTP multicast. This program also has a built-in RTSP server.

  • Apple's "QuickTime Player" can be used to receive and play this audio stream. To use this, have the player open the session's "rtsp://" URL (which the program prints out as it starts streaming).
  • The Open Source "VLC" and "MPlayer" media players can also be used.


翻译一下:

testH264VideoStreamer 重复从 H.264 基本流视频文件(名为“test.264”)中读取,并使用 RTP 多播进行流式传输。 该程序还具有内置的 RTSP 服务器。
Apple 的“QuickTime 播放器”可用于接收和播放此音频流。 要使用它,让玩家打开会话的“rtsp://”URL(程序在开始流式传输时打印出来)。
开源“VLC”和“MPlayer”媒体播放器也可以使用。


标签:recvBuf,LIVE555,..,lib,--,0x00,live555,testRTSPClient
From: https://blog.51cto.com/u_15979522/6167163

相关文章

  • LIVE555再学习 -- testH264VideoStreamer 源码分析
    上一篇文章我们已经讲了一部分:testH264VideoStreamer重复从H.264基本流视频文件(名为“test.264”)中读取,并使用RTP多播进行流式传输。 该程序还具有内置的RTSP服务器。Apple的“QuickTime播放器”可用于接收和播放此音频流。要使用它,让玩家打开会话的“rtsp://”URL(程序在......
  • LIVE555再学习 -- testRTSPClient 源码分析
    现在开讲 testRTSPClient。在官网这这样一段介绍,参看:RTSPclient翻译下来就是:testRTSPClient是一个命令行程序,显示如何打开和接收由RTSPURL指定的媒体流,即以rtsp://开头的URL在这个演示应用中,接收到的音频/视频数据什么也没有。但是,您可以在自己的应用程序中使用和调整此代码(......
  • LIVE555再学习 -- Windows 下编译
    然后开始下载编译,其中包含,Windows、Linux和交叉编译三种形式。首先来讲Windows下编译参看:Live555研究之一源代码编译一、下载源码下载:Indexof/liveMedia/public参看:LIVE555StreamingMedia选择下载live555-latest.tar.gz二、文件介绍我的开发环境为win1064位+VS2017将上面......
  • RTSP再学习 -- RTSP协议分析(转载)
    最近一直在看RTSP,但是RTSP协议是个啥?还没有搞清楚。首先流媒体百度百科上有这样一段,从基本的名字上或多或少可以理解一下这些传输协议的区别。这很重要!!传输协议1、RSVP:资源预留协议2、RTP:实时传输协议3、RTCP:实时传输控制协议4、MMS:微软流媒体服务协议5、RTSP:实时流传输协议6、MIM......
  • mysql多实例配置
    实现在一台服务器上开两个数据库服务。配置:[mysqld_multi]user=rootmysqld=/usr/local/mysql/bin/mysqld_safemysqladmin=/usr/local/mysql/bin/mysqladmin[mysqld1]datadir=/dir1port=3307pid-file=/dir1/mysqld1.pidlog-error=/dir1/mysqld1.errsocket=/dir1/mysqld1.sock[mysqld......
  • MQTT再学习 -- 安装MQTT客户端及测试
    上一篇文章我们已经讲了MQTT服务器的搭建,参看:MQTT再学习--搭建MQTT服务器及测试接下来我们看一下MQTT客户端。一、客户端下载首先,客户端也有多种,我们需要面临选择了。参看:基于mqtt的消息推送(三)客户端实现现有客户端sdk分析,基本分为两大类:一类移植自C类库,如Mosquitto,一类是用o......
  • FFmpeg再学习 -- FFmpeg+SDL+MFC实现图形界面视频播放器
    继续看雷霄骅的课程资料-基于FFmpeg+SDL的视频播放器的制作最后一篇,主要是想学一下MFC创建和配置。一、创建MFC工程文件->新建->项目->VisualC++->MFC应用程序应用程序类型,选择基于对话框生成效果如下:二、设置控件找到“工具箱”,就可以将相应的控件拖拽至应用程序对话框......
  • 图像和流媒体 -- Sapera 安装遇到的问题
    一、下载安装包参看:GenieNanoM1930-NIR点击软件及例程下载二、安装遇到的问题(1)Installationdirectorymustbeonalocalharddrive解决方法:clsicacls%temp%/reset/T/Q/Cpause以上文件复制到txt中将后缀名修改为bat以管理员执行即可。windows自身权限的的问题。(2)安......
  • Problem B. Harvest of Apples 组合数求和(莫队没怎么看懂)
    ProblemB.HarvestofApplesTimeLimit:4000/2000MS(Java/Others)    MemoryLimit:262144/262144K(Java/Others)TotalSubmission(s):3775    AcceptedSubmission(s):1450 ProblemDescriptionTherearenapplesonatree,numberedfrom1ton.Count......
  • MQTT再学习 -- 漫谈MQTT协议
    MQTT服务器搭建我们已经完成了,现在回过头来看协议。参看:MQTT官网参看:MQTT_V3.1_Protocol_Specific参看:MQTT协议中文版参看:MQTT协议中文版上面这几篇文章,已经说明了一切。下面着重讲一下MQTT的消息格式和主要特征。一、什么是MQTT首先你要知道什么是MQTT。额,这个很重要。官网是......