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系统怎么玩王者安卓系统,... 亲爱的手机控们,你是否曾在某个午后,看着手中的iPhone,羡慕安卓用户能畅玩《王者荣耀》?别急,今...
安卓系统找手机app,高效找手... 手机不见了?别慌张,我来给你支个招!在这个智能时代,安卓系统里的手机找回应用可是帮了不少忙。接下来,...
is系统和安卓系统app差异,... 你有没有发现,无论是手机还是平板,现在市面上流行的操作系统主要有两种:iOS的is系统和安卓系统。这...
安卓 5.0的系统限制,揭秘新... 你有没有发现,自从你的安卓手机升级到了5.0系统,好像有些功能变得不那么好用了呢?别急,让我来给你细...
安卓系统如何使用tiktok,... 你有没有发现,现在手机上最火的短视频应用就是TikTok了?没错,就是那个让你刷到停不下来的短视频平...
安卓系统u盘更新,轻松实现系统... 你有没有发现,你的安卓系统U盘最近有点儿“蔫儿”了?别急,别急,让我来给你详细说说怎么给它来个焕然一...
系统很好的安卓手机,安卓手机巅... 你有没有发现,最近市面上那些安卓手机简直让人眼花缭乱?不过别急,今天我要给你安利一款特别好的安卓手机...
安卓系统测量长度软件,轻松掌控 你有没有想过,手机里的安卓系统竟然也能帮你测量长度?没错,就是那个我们每天不离手的安卓手机,现在竟然...
麒麟os系统与安卓系统下载,麒... 你有没有听说最近手机圈里又掀起了一股热潮?没错,就是麒麟OS系统与安卓系统的下载之争。这两大系统各有...
安卓10系统测试代码,基于安卓... 你有没有发现,最近你的安卓手机是不是有点不一样了?没错,那就是安卓10系统的魅力所在!今天,就让我带...
安卓14系统包下载,全面解析与... 你有没有听说?安卓14系统包下载已经悄然上线啦!没错,就是那个让无数安卓用户翘首以盼的新系统,现在终...
ipad安卓变苹果系统,揭秘i... 你有没有想过,你的iPad上突然冒出了苹果系统,而之前一直陪伴你的安卓系统呢?这可不是什么小把戏,而...
安卓属于华为系统吗,安卓之外的... 你有没有想过,安卓和华为系统之间的关系呢?是不是觉得它们就像是一对形影不离的好朋友,但实际上,它们之...
安卓系统版本怎么退,轻松退回旧... 手机用久了,是不是觉得安卓系统版本越来越高,更新换代的速度让你有点跟不上了?别急,今天就来手把手教你...
小米系统回退安卓6.0,体验纯... 你知道吗?最近小米手机界可是掀起了一阵小小的风波呢!那就是小米系统突然回退到了安卓6.0,这让不少米...
安卓os系统和鸿蒙系统对比,操... 你有没有想过,手机里的操作系统就像是我们生活的城市,各有各的特色和魅力呢?今天,就让我带你走进安卓O...
ns系统是安卓么,揭秘其是否为... 你有没有想过,那个你天天不离手的手机,里面运行的那个神秘的系统,它到底是不是安卓呢?别急,今天就来给...
安卓最新系统手表,智能手表的革... 你有没有发现,最近你的手腕上是不是也缺了一件神器?没错,说的就是安卓最新系统手表!这款小玩意儿可是科...
车载安卓盒子双系统,智能驾驶体... 你有没有想过,你的车载系统也能变得像智能手机一样酷炫呢?没错,就是那种可以同时运行安卓和Window...
哪家的安卓系统流畅,探索安卓新... 你有没有想过,手机里的安卓系统哪个最流畅呢?这可是个让人头疼的问题,因为市面上那么多品牌,每个品牌都...