天天看点

基于live555制作RtspClientDLL库支持能力代码思路软件实现

本文为博主原创文章,未经博主允许不得转载。(合作洽谈请联系QQ:1010316426)

基于live555制作RtspClientDLL库

  • 支持能力
  • 代码思路
    • 制作C++包装类
      • 包装调度器和RTSPClient
      • 包装媒体资源
      • A/V流数据处理
    • 事件调度及触发
      • 请求失败
      • 码流中断
      • 模拟心跳
  • 软件实现

去年笔者开发制作了基于live555的RtspClientDLL库v1.0,今年6月底7月初进行了v2.0升级,增加了事件、统一了视音频流处理逻辑。写出来与读者分享。

支持能力

1.基于live555的基础组件能力,将其包装成C++类或C的API并导出成DLL库,可供其他模块使用。

2.导出的C-API要求能定制端口和传输协议,并能在内部交互发生异常/出错时告知调用方代码。

3.视频支持H264/H265,音频支持的比较多,笔者只处理了G711A/G711U/AAC,MP2L2/G722.1/G729/G723等没有处理。

4.支持安防行业主流的海康/大华/宇视/华三/三星等的IPC/NVR/编码器等编码类视频设备。

代码思路

制作C++包装类

通过阅读示例testRTSPClient.cpp,熟悉基本的用法。尤其是基础类RTSPClient、事件函数、接收到A/V流数据的处理、事件调度等。利用C++语言提供的封装思想,将这些资源及其调度者分门别类进行封装。

包装调度器和RTSPClient

为了简化实现,笔者给每一个连接都绑定了一个env和schedule,并将RtspClient与它们都包装在一起,类关系如下:(为了突出重点,笔者将大部分辅助代码都删去)

class CRtspStream
{
public:
	TaskScheduler * m_scheduler;
	UsageEnvironment * m_env;
	MyRTSPClient* m_pRtspClient;
};
           

其中MyRTSPClient就是笔者封装的RTSPClient,它是从live555继承而来。m_scheduler和m_env则使用live555提供的两个工具类。

//CRtspStream.cpp:
	m_scheduler = BasicTaskScheduler::createNew();
	m_env = BasicUsageEnvironment::createNew(*m_scheduler);

//MyRTSPClient:
class MyRTSPClient : public RTSPClient {
    ....
}
           

包装媒体资源

媒体资源使用示例testRTSPClient.cpp中的class StreamClientState不做更改。这个类能够在每个流的全生命周期过程中保存期其运行状态。

class StreamClientState {
public:
	StreamClientState();
	~StreamClientState();

public:
	MediaSubsessionIterator* iter;
	MediaSession* session;
	MediaSession* playSession;
	MediaSubsession* subsession;
	TaskToken streamTimerTask;
	double duration;
};
           

XXXsession的是与stream会话有关的;streamTimerTask是一个live555中的任务句柄,在后面事件处理有用到;duration则与录像有关。

A/V流数据处理

视音频流处理分为两部分,第1部分是缓存,第2部分是分派。

缓存是在类class DummySink中实现。fReceiveBuffer就是缓存地址,每当要接收流时就将此地址传进去以获得数据的一份拷贝。

分派是通过我们上面提到的MyRTSPClient实现的。当fReceiveBuffer获取到数据后,在MyRTSPClient::afterGettingFrame()中根据数据的类型进行分派处理。具体代码如下:

//Sink类:
class DummySink: public MediaSink {
private:
  uint8_t* fReceiveBuffer;
public:
    RTSPClient* m_pRtspClient;
};

//数据分派处理
void MyRTSPClient::afterGettingFrame(MediaSubsession& fSubsession, u_int8_t* fReceiveBuffer, unsigned frameSize, unsigned numTruncatedBytes, struct timeval presentationTime, unsigned durationInMicroseconds)
{
	std::string mediumName(fSubsession.mediumName());
	std::string codecName(fSubsession.codecName());

	if (mediumName == RTSP_MEDIUM_NAME_VIDEO)
	{
		if (codecName == RTSP_CODEC_NAME_H264)
		{
			//process_h264(...);
		}
		else if (codecName == RTSP_CODEC_NAME_MP4VES && fSubsession.fmtp_config() != NULL)
		{
			//printf("mp4v-es \n");
		}
		else if (codecName == RTSP_CODEC_NAME_H265)
		{
			//process_h265(...);
		}
		else {}
	}
	else if (mediumName == RTSP_MEDIUM_NAME_AUDIO)
	{
		if (codecName == RTSP_CODEC_NAME_AAC)
		{
			//process_aac(...);
		}
		else if (codecName == RTSP_CODEC_NAME_PCMA)
		{
			//process_pcma(...);
		}
		else if (codecName == RTSP_CODEC_NAME_PCMU)
		{
			//process_pcmu(...);
		}
		else {}
	}
}
           

事件调度及触发

事件调度使用了live555提供的taskschedule。事件触发包括两方面,一方面是当请求发生错误时获取错误信息并通知DLL主调代码,另一方面要监测流是否中断、并维持“模拟心跳”。

请求失败

请求失败主要地发生在会话建立阶段,也就是rtsp的Option/Describe/Setup/Play等阶段是否发生交互性错误及业务性错误。

先看交互性错误。交互性错误主要是通过live555的RTSPClient的接口来捕获的,它的接口如下所示。我们可以看到,命令的执行结果通过回调得到,在回调函数中通过resultCode和resultString就知道是否发生错误及发生了何种错误。错误码的说明在图中的黄色框中可以知道。

基于live555制作RtspClientDLL库支持能力代码思路软件实现

再说说业务性错误。笔者这里说的业务性错误主要指媒体内容,也就是SDP中的media部分是不是我们所期望需要的。

因为笔者发现,现在比较新的高端的IPC都会具有智能分析能力,另外厂家也会通过RTSP提供一些私有化的能力,所以前阵子我们测试的厂家IPC除了在SDP中包含video/audio之外,还会包含一些其他的媒体内容在rtsp的rtp码流通道里面。这些是我们不需要的,因此就要在SETUP的responseHandler中剔除出业务上不需要的内容。

这部分内容请读者根据自己的产品情况酌情理解。在这里笔者就不展开写了。

码流中断

周期地检查码流数据可以作为流保活的手段之一。

通过给taskScheduler添加一个DelayTask,利用live555的事件调度来模拟Timer,达到周期检查码流是否终端的目的。但是因为TaskSchedule的原理是单次触发的,所以在每次执行这个task后还要再次将task重新插入到Schedule队列中,这样才是一个真正的“Timer”。

实际代码类似如下这样:

基于live555制作RtspClientDLL库支持能力代码思路软件实现

模拟心跳

模拟心跳实际上是“信令-媒体双信道”思想的产物。这种策略在GB28181服务器中、尤其是信令和媒体做分布式、集群化部署等类似的场景中必须要使用。

模拟心跳和码流中断检测的思路相同。实现方法是通过周期性发送Option命令来探测信令信道是否断开。代码就是上图中的client->checkOptionTask。

软件实现

代码就不在这里贴了。想深入学习研究的读者可以先研读live555的示例 testRTSPClient.cpp,自行揣摩、体会设计思路,来实现一个适合自己需求的RtspClientDLL库。

基于live555制作RtspClientDLL库支持能力代码思路软件实现

近期事情比较杂也比较多,断断续续抽时间写了将近不到两周才写完。耗的时间比较长。

下篇博客跟读者分享下拉取rtsp并推rtmp的实现方法。