源代码已上传gitee
live555源代码中的liveMediaServer是将本地文件作为源文件搭建rtsp服务器,我想用live555封装一个第三方库,接收流数据搭建Rtsp服务器;预想接口如下:
class LiveRtspServer { public: 	/**     *@brief构造一个新的Live Rtsp服务器对象     *     *@param videoCodec要用于流式传输的视频编解码器     *@param audioCodec要用于流式传输的音频编解码器     *@param fps流的帧速率     *@param port用于流传输的端口     *@param suffix要添加到流URL的后缀     *@param username身份验证的用户名     *@param password身份验证的密码     */     LiveRtspServer(const std::string &videoCodec = "h264",                    const std::string &audioCodec = "none", unsigned fps = 60,                    unsigned port = 8554, const std::string &suffix = "",                    const std::string &username = "",                    const std::string &password = "");     /**     *@brief设置客户端上状态已更改的回调     *     *@param callback客户端状态更改时要调用的回调     */     void setOnClientStateChanged(clientConnectCallback callback){         clientConnectCallback_ = callback;     }     /**     *@brief启动服务器     */     void start();     /**     *@brief停止服务器     */     void stop();     /**     *@brief向客户端发送视频数据     *     *@param buf包含视频数据的缓冲区     *@param len视频数据的长度     *如果数据发送成功,@return true,否则为false     */     bool sendVideoData(const unsigned char *buf, int len);     /**     *@brief向客户端发送音频数据     *     *@param buf包含视频数据的缓冲区     *@param len视频数据的长度     *如果数据发送成功,@return true,否则为false     */     bool sendAudioData(const unsigned char *buf, int len);     /**     *@brief获取服务器的RTSP URL     *     *@param ipv6是否使用ipv6     *@return const char*RTSP URL     */     const char *RtspUrl(int ipv6 = 0); };  阅读LiveMediaServer源码可以发现建立Rtsp服务器的大致过程比较简单,创建一个继承RTSPServer的类,重写lookupServerMediaSession方法创建ServerMediaSession实例,并调用addServerMediaSession将实例添加到RTSPServer中,再通过创建对应不同数据格式的ServerMediaSubsession实例和ServerMediaSession的addSubsession方法,将ServerMediaSubsession实例添加到ServerMediaSession中,最终读取数据通过ServerMediaSubsession的createNewStreamSource创建的FramedSource实现;写的有点乱,回头做个流程图,整体来说过程比较简单;
 详细的源码分析可以查看live555学习笔记【3】—RTSP服务器(一);这里摘录其中RTSP链接建立过程:
所以我们照着这个流程走一遍即可;
liveMedia/include/ByteStreamFileSource.hh创建自己的liveMedia/include/ByteStreamFrameSource.hh,重写doGetNextFrame获取数据接口,并添加一个doPutFrames(const uint8_t *buffer,unsigned bufferSize)传递视频数据接口;将传递进的数据在doGetNextFrame中拷贝到fTo地址,设置fFrameSize;liveMedia/include/FileServerMediaSubsession.hh创建自己的liveMedia/include/StreamServerMediaSubsession.hh,以及对应的子类liveMedia/include/H265VideoStreamServerMediaSubsession.hh和liveMedia/include/H264VideoStreamServerMediaSubsession.hh,这两个子类调用createNewStreamSource方法创建第一步的ByteStreamFrameSource实例;mediaServer/DynamicRTSPServer.hh创建自己的liveRtspServer/include/StreamRTSPServer.hh,其中createNewSMS方法我们根据传入的视频编码格式创建我们自己的H264/H265VideoStreamServerMediaSubsession;ByteStreamFileSource中数据传入接口doPutFrames导出到我们自己的StreamRTSPServer中,在这里我通过1、2、3步创建自己的类中层层传递void onFrameSourceStateChanged(void* clientData, Boolean state)回调的方式,将在第2步里创建或析构ByteStreamFrameSource的实例指针传到StreamRTSPServer的std::vector fFrameSources 成员中,这样就可以将数据传入了;流程走通后,遇到有时候rtsp客户端无法连接到客户端问题,经层层跟踪发现,rtsp链接建立时也就是服务器对RTSP DESCRIBE响应,这一步服务器端要读取一帧IDR帧获取其中视频流信息的SPS/PPS/VPS信息,发送必要的媒体参数给客户端,LiveMediaServer中创建RTSP服务器时,每次链接建立都是从开始读取文件,必然能读取到IDR帧。而流式推送,如果编码参数GOP过大,长时间读取不到IDR帧,链接就会超时退出,因此需要将IDR帧保存,链接建立中第一次读取数据时保证读取到的是IDR帧;
ByteStreamFrameSource仍然保留了文件读取的BANK_SIZE限制,没有找到控制发送地方,没有完全看懂这部分代码,所以在获取数据是加了等待数据到达超时方式,感觉不太友好;live555源代码为单线程读取数据,多客户端连接会有性能瓶颈,如何修改多线程;抛砖引玉,希望路过大佬不吝指点一二。