c++实现rtsp点播客户端

c++实现rtsp点播客户端

  • RTSP协议简介
  • LIVE555的testRTSPClient.cpp简介
  • RTSP视频流的处理

RTSP协议简介

     简单来说,RTSP协议是一种基于命令形式的协议,对于服务端S和客户端C,两者的命令交互过程为:

  1. 第一步:查询服务器端可用方法
    1.C->S:OPTION request //询问S有哪些方法可用
    1.S->C:OPTION response //S回应信息的public头字段中包括提供的所有可用方法
  2. 第二步:得到媒体描述信息
    2.C->S:DESCRIBE request //要求得到S提供的媒体描述信息
    2.S->C:DESCRIBE response //S回应媒体描述信息,一般是sdp信息
  3. 第三步:建立RTSP会话
    3.C->S:SETUP request //通过Transport头字段列出可接受的传输选项,请求S建立会话
    3.S->C:SETUP response //S建立会话,通过Transport头字段返回选择的具体转输选 项,并返回建立的Session ID;
  4. 第四步:请求开始传送数据
    4.C->S:PLAY request //C请求S开始发送数据
    4.S->C:PLAY response //S回应该请求的信息
  5. 第五步: 数据传送播放中
    S->C:发送流媒体数据 // 通过RTP协议传送数据
  6. 第六步:关闭会话,退出
    6.C->S:TEARDOWN request //C请求关闭会话
    6.S->C:TEARDOWN response //S回应该请求

LIVE555的testRTSPClient.cpp简介

     由于网上已有详细介绍,不再重复,可转至
live555 RTSP客户端源码分析学习。

RTSP视频流的处理

     数据流的接收都在DummySink::afterGettingFrame函数里,

void DummySink::afterGettingFrame(unsigned frameSize, unsigned numTruncatedBytes,
struct timeval presentationTime, unsigned /*durationInMicroseconds*/) 

     这个函数自带的第一个参数就是当前的数据流的大小,数据流指针为DummySink的成员变量u_int8_t* fReceiveBuffer,这个变量作为参数在continuePlaying()函数中被调用,进行了数据的填充,填充完毕后,调用回调函数,也就是上面的afterGettingFrame来进行通知,那么我们只需要在这个函数中处理fReceiveBuffer即可。

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

	//当时做的是用的公司内部的解码器,暂时找不到合适的解码器,就直接把rtsp流写到文件中
	//如果是使用解码器,那么需要创建一个解码线程,在里面处理解码,然后把解码数据显示到窗口上
	static bool bFirstFrame = true;
	if(!strcmp(fSubsession.mediumName(), "video"))
	{
		unsigned char chStart[4] = {0x00, 0x00, 0x00, 0x01};
		if(bFirstFrame)
		{
			unsigned int numSPropRecords;
			SPropRecord *sps = parseSPropParameterSets(fSubsession.fmtp_spropparametersets(), numSPropRecords);
			FILE *fp = fopen("test.264", "a+b");
			if(fp)
			{
				fwrite(chStart, 4, 1, fp);
				fwrite(sps[0].sPropBytes, sps[0].sPropLength, 1, fp);
				fwrite(chStart, 4, 1, fp);
				fwrite(sps[1].sPropBytes, sps[1].sPropLength, 1, fp);
				fclose(fp);
			}
			delete [] sps;
			bFirstFrame = false;
		}
		char *pBuf = (char *)fReceiveBuffer;
		FILE *fp = fopen("test.264", "a+b");
		if(fp)
		{
			fwrite(chStart, 4, 1, fp);
			fwrite(fReceiveBuffer, frameSize, 1, fp);
			fclose(fp);
		}
	}
	// Then continue, to request the next frame of data:
	continuePlaying();
}

     此处简单处理,我们直接将RTSP流转换为H264格式的视频文件,写到本地,可以直接使用VLC等播放器进行播放。当然,如果是要显示到自己的窗口上,那么需要用到解码器,将rtsp流转为RGB或者YUV数据,然后绘制到窗口上,实时显示的性能主要受到解码器的影响。(这种方式可以直接参考调用VLC库实现,几行代码就能达到一样的效果,但是性能方面,拉流速度慢于live555,所以大部分公司都是使用自己的解码库,或者在其他开源库上封装的解码库,来实现这一部分流程)
     注意:整个RTSP的播放都是在非主线程上进行处理的,因为需要让当前线程进入循环等待状态来与服务端保持一个通信,接收来自服务端的数据,然后,如果需要解码,则另外创建一个线程,解码完成后的数据,通过SendMessage抛送到UI线程的窗口上去绘制。

附上代码连接:https://download.csdn.net/download/bajianxiaofendui/10714639

你可能感兴趣的:(视频与图片)