rtsp服务器逻辑
创始人
2024-09-25 02:51:02
0

定时器逻辑:比如H264文件是每隔40ms发送一帧数据。aac文件每隔23ms发送一个音频帧数据。

在sink的子类中有aac和h264的sink,在两个子类的构造函数中需要添加它们各自的触发时间。调用的函数时runEvery(),将这两个触发时间设置到了TimerManager中,在TimerManager中有一个map类型的结构体mEvent:记录着触发时间。

在sink中需要create一个TimeEvent事件,这个是事件是时间到了触发,用来触发回调。设置回调函数:mTimerEvent->setTimeoutCallback(cbTimeout);就是定时的发送数据。

在cbTimeout回调函数中就是发送数据:

void Sink::handleTimeout() {     MediaFrame* frame = mMediaSource->getFrameFromOutputQueue();     if (!frame) {         return;     }     this->sendFrame(frame);// 由具体子类实现发送逻辑      mMediaSource->putFrameToInputQueue(frame);//将使用过的frame插入输入队列,插入输入队列以后,加入一个子线程task,从文件中读取数据再次将输入写入到frame }

在TimerManager的构造函数中就是创建了一个定时器的文件描述符,将这个文件描述符添加到一个IO事件中,为这个IO事件添加一个回调函数,将这个IO事件添加到select模型中。这是一个定时器的管理者,用来定时触发读取事件。

设置的回调函数时readCallback,其中调用的是handleRead函数,一旦定时器触发,就会触发这个函数,函数中就是处理上述提到的TimerEvent,

当定时器触发会后,readCallback函数将从mEvent中移除已触发的事件,并调用modifyTimeOut函数重新设置下一个最近的定时事件。就相当于是处理完一个定时器事件之后重新设置新的时间戳的定时器。

void TimerManager::handleRead() {     Timer::Timestamp timestamp = Timer::getCurTime(); // 获取当前时间     if (!mTimers.empty() && !mEvents.empty()) { // 确保定时器和事件队列不为空         std::multimap::iterator it = mEvents.begin(); // 获取最早到期的定时器         Timer timer = it->second; // 获取定时器对象         int expire = timer.mTimestamp - timestamp; // 计算定时器到期剩余时间          if (timestamp > timer.mTimestamp || expire == 0) { // 如果当前时间超过定时器的到期时间             bool timerEventIsStop = timer.handleEvent(); // 处理定时器事件              mEvents.erase(it); // 从事件队列中移除已处理的定时器              if (timer.mRepeat) { // 如果是重复定时器                 if (timerEventIsStop) { // 如果定时器事件需要停止(例如,定时器任务完成后)                     mTimers.erase(timer.mTimerId); // 从定时器管理器中移除                 } else { // 否则,重新安排定时器                     timer.mTimestamp = timestamp + timer.mTimeInterval; // 设置下一个到期时间                     mEvents.insert(std::make_pair(timer.mTimestamp, timer)); // 将新的定时器事件插入到事件队列中                 }             } else { // 如果不是重复定时器                 mTimers.erase(timer.mTimerId); // 从定时器管理器中移除             }         }     }     modifyTimeout(); // 更新定时器的到期时间 } 

定时器到期后触发的发送器发送逻辑

1.调用getFrameOutputQueue()函数取出一帧数据

2.调用函数sendFrame(frame)进行发送

3.调用putFrameToInputQueue(frame)函数,将使用过的frame插入输入队列中,插入输入队列之后,加入一个子线程task,从文件中读取数据再次将输入写入到frame中。

Main函数的主流程:

1.先创建了一个调度器EventScheduler,在构造函数中创建了Poller和创建了一个定时器管理者。

在定时器管理者构造函数中就是上面所提到的。

在调度器类中最主要的就是一个循环功能:只要不退出一直调用以下函数:

while (!mQuit) {         handleTriggerEvents();         mPoller->handleEvent();     }

还有一些添加IO事件,移除IO事件,更新IO事件的函数;添加触发事件,移除触发事件的函数;添加定时器事件的函数。

2.创建了线程池,任务队列中的任务是从H264文件或者aac文件中读取数据,进行处理然后添加到mFrameOutputQueue队列中。

3.创建媒体会话管理者,在构造函数中啥也没干,这类中有几个函数,往MediaSessionManager中添加MediaSession,这里的MediaSession有一个名字叫做test,在MediaSession中有两路轨,一路是音频轨一路是视频轨,当然一个MediaSessionManager中肯定包含着很多的MediaSession。

4.设置RTSP服务器的IP地址和端口号

5.创建rtsp服务器,在构造函数中需要加MediaSessionManager,调度器和线程池以及IP和端口号传入当做参数。函数体中创建了socket文件描述符,为该文件描述符添加了IO事件并设置了回调函数。同时也设置了回调的关闭连接。“为该文件描述符添加了IO事件并设置了回调函数”这里设置的回调函数就是调用accept,然后创建一个rtsp连接,调用了RtspConnection构造函数,在这个类中主要处理的就是rtsp协议交互相关的东西。

比如有parseRequest函数用来解析客户端发送的RTSP请求,从请求中提取方法,URL,协议版本等信息。

handleReadBytes()函数:当有数据从客户端发送到服务器时,会调用此函数处理数据。判断是否是RTP over TCP,如果是调用handleRtpOverTcp()函数,否则解析RTSP请求并根据不同的RTSP方法执行相应的命令。

RTSP方法的处理:比如对OPTION请求,DESCRIBE请求,SETUP请求,PLAY请求的响应。

RTP和RTCP处理:通过UDP创建两者的实例,用于传输和接收流媒体数据,或者是通过TCP创建RTP实例等。

6.创建一个session也就是上面提到的MediaSession,在MediaSession构造函数中给每个MediaSession添加一个名字,在该服务器中就是test。我觉得这个类中关键的一个函数就是addSink(),这个函数的作用就是给指定的轨添加sink函数,在addSink()函数中有一个关键的操作就是给sink实例设置一个SessionCb,这里的回调函数才是真正将rtp数据包发送出去的函数。

其中还有addRtpInstance()函数以及remove函数,就是为轨道添加RTP实例,也是建立数据传输的媒介。

7.创建一个H264媒体资源,在构造函数中向线程池中添加4个任务,每个任务的处理过程是从mFrameInputQueue取第一帧数据frame,然后将H264文件中的数据拷贝到frame中,这里要检查并处理起始码,可能是00 00 01,也可能是00 00 00 01.然后再检查NALU类型,如果是0x09的话就跳过这帧处理下一帧,以上步骤如果成功的话将frame添加到mFrameOutputQueue中。

8.创建一个H264fileSink子类对象,需要将上面创建的H264媒体资源传给构造函数,在构造函数中设置了定时器的触发时间。这个子类中主要是重写了父类中的sendFrame()函数,在sendFrame函数中有两种发包的思路,一种是单NALU打包,一种是分片打包。在父类中还会调用父类的构造函数,在该构造函数中创建了一个定时器事件,同时设置了定时器事件的回调函数,表示定时器时间到后执行的函数。函数的逻辑就是时间到后发送帧数据。子类中的sendFrame函数中的关键函数在父类中:sendRtpPacket()函数,这个函数中就是调用了一个回调函数,那么是在哪里设置了这个回调函数呢?就是在接下来的addSink中设置的。

9.向session中添加sink实例,也就是调用了session中的addSink()函数,在MediaSession中有两个轨,我们就将H264的sink子类添加到TrackId0中,将aac的sink子类添加到TrackId1中。在addSink函数中就设置了sink中的回调函数。

那么整个流程是什么样的呢?首先我们设置了定时器,例如我们的H264文件的帧率是25帧的,那么就是一秒播放25帧,也就是40ms一帧数据。我们将这个数值设置到定时器管理者中,这个时候管理者到点就会触发回调函数也就是TimerManager::readCallback,也就是取出对应的定时器,执行定时器里面的事件。这里的定时器里面的事情是在sink构造函数中设置的 mTimerEvent->setTimeoutCallback(cbTimeout);就是触发真正的发送数据了。

那么数据是怎么发送出去的?上面我们提到cbTimeout回调函数,里面调用了handleTimeout()函数,然后由子类去实现发送逻辑this->sendFrame(frame),在子类中真正的发送逻辑还是在父类中实现的也就是sendRtpPacket(RtpPacket* packet)函数,在这个函数里还执行了一个回调函数,最终发送者是在MediaSession中,在MediaSession中调用了handleSendRtpPacket()函数才将数据最终发送出去。

这是一个基于北小菜RTSP服务器的个人理解,有不对的地方欢迎指正。

相关内容

热门资讯

安卓系统为什么不封闭,揭秘安卓... 你有没有想过,为什么安卓系统那么开放,却不像苹果iOS那样封闭呢?这背后可是有着不少有趣的故事和原因...
安卓系统更新包多大,解析不同版... 你有没有发现,每次安卓系统更新,手机里都会多出那么几个G的文件?这可真是让人好奇,安卓系统更新包究竟...
安卓手机安装双系统吗,安卓手机... 你有没有想过,你的安卓手机是不是也能像电脑一样,装上两个系统,一个用来工作,一个用来娱乐?没错,这就...
oppo会升级安卓系统,畅享最... 你知道吗?最近有个大消息在手机圈里炸开了锅,那就是OPPO要升级安卓系统啦!这可不是什么小打小闹的更...
安卓系统上安装windows,... 你有没有想过,在安卓手机上安装Windows系统?听起来是不是有点不可思议?但你知道吗,这竟然是可能...
安卓系统怎么进运行框,安卓系统... 你有没有想过,你的安卓手机里有一个超级实用的功能,那就是运行框!它就像是一个小助手,帮你快速找到正在...
安卓系统电视无图像设置,安卓电... 你家的安卓系统电视突然没图像了?别急,让我来给你支个招,让你轻松解决这个问题!一、检查电源和连接线首...
安卓机建议升级系统吗,提升性能 你有没有发现,你的安卓手机最近有点儿慢吞吞的?是不是在犹豫要不要升级系统呢?别急,让我来给你好好分析...
升级不了安卓系统升级,探寻升级... 你有没有遇到过这种情况?手机里的安卓系统突然告诉你,它需要升级,但你左等右等,就是升不上去。这可真是...
备用安卓系统手机推荐,盘点热门... 你有没有想过,如果你的手机突然罢工了,你会怎么办?别担心,今天我就要给你安利几款备用安卓系统手机,让...
旧安卓系统ipad无法更新系统... 你有没有遇到过这种情况?你的旧安卓系统iPad突然告诉你,它无法更新系统了!是不是瞬间感觉心里有点小...
运行安卓6系统命令大全,全面掌... 你有没有想过,你的安卓手机里隐藏着无数强大的功能,只等着你去发现和探索呢?今天,就让我带你走进安卓6...
安卓系统简笔画教程下载,轻松绘... 你有没有想过,用简单的线条就能把复杂的安卓系统画出来?没错,就是那种一看就懂,一画就上手的感觉!今天...
华为如何鸿蒙转安卓系统,轻松实... 你知道吗?最近华为的大动作可是让整个科技圈都沸腾了!他们竟然把鸿蒙系统转到了安卓系统上,这可真是让人...
安卓10系统的问题,安卓10系... 你有没有发现,自从你的手机升级到安卓10系统后,好像有点不对劲呢?别急,让我来给你细细道来,看看安卓...
安卓系统苹果搞笑视频,苹果搞笑... 你知道吗?在互联网的世界里,搞笑视频可是个永恒的热门话题。尤其是那些结合了安卓系统和苹果手机的搞笑片...
卡片机改造安卓系统,探索改造之... 你有没有想过,那些曾经陪伴我们记录美好时光的卡片机,现在竟然也能焕发第二春呢?没错,就是那些小巧便携...
装安卓系统倒车出不来,智能科技... 你有没有遇到过这样的事情:手机装了个安卓系统,结果倒车的时候出不来啦?这可不是闹着玩的,简直让人抓狂...
定制安卓系统哪家好点儿,哪家服... 你有没有想过,手机系统就像是个人的衣服,每个人都需要找到最适合自己的那一款?今天,咱们就来聊聊定制安...
台电用回安卓系统吗,开启智能新... 最近有个话题在科技圈里炒得挺热的,那就是台电是不是要用回安卓系统了?你有没有想过,这个小小的决定背后...