美文网首页
令live555从I帧开始发送

令live555从I帧开始发送

作者: 叶迎宪 | 来源:发表于2018-08-08 17:49 被阅读0次

用easyplayer播放live555的rtsp流,发现前面几帧总是会花一下。通过抓包发现,rtsp流不是从I帧开始发送的,因此导致前几帧没有参考帧,所以解码花屏。开始以为是我实现的DeviceSource::deliverFrame的问题,因为这个实现确实没有保证从I帧开始发送。但是deliverFrame改成从I帧开始发送以后,花屏问题依然存在,这又是为什么呢?

通过调试发现,DeviceSource::deliverFrame开始执行的时候,数据最后不会在RTPInterface::sendPacket发送出去,是因为目标地址还没有给出。DeviceSource::deliverFrame开始执行是因为触发了 RTSPServer::RTSPClientConnection
::handleCmd_DESCRIBE,这个里面会调用 ServerMediaSession::generateSDPDescription,最终调用到 ServerMediaSubsession::getAuxSDPLine。这个 ServerMediaSubsession::getAuxSDPLine 是在我的派生类中实现的,里面的代码跟示例代码是一模一样的

    if (fAuxSDPLine != NULL) return fAuxSDPLine;
    if (fDummySink == NULL)
    {
        fDummySink = rtpSink;
        fDummySink->startPlaying(*inputSource, afterPlayingDummy, this);
        checkForAuxSDPLine(this);
    }

这说明,在RTSP客户端发送DESCRIBE命令的时候,live555为了获取sdp信息(像h.264 SDP之中的sprop-parameter-sets,是要通过码流获取到sps、pps才知道的),先启动了rtpSink,从而就会从DeviceSource开始拉数据。

而rtpSink可以把数据发送给客户端,是在 RTSPServer::RTSPClientSession
::handleCmd_PLAY,这里调用到了 OnDemandServerMediaSubsession::startStream,这个又调用StreamState
::startPlaying,最后调用到 RTPInterface::addStreamSocket(TCP)或者 Groupsock::addDestination(UDP),把目标地址给设定了,从而让数据包可以最终发送到rtsp客户端。

RTPInterface::sendPacket的调用栈为
MultiFramedRTPSink::afterGettingFrame1
MultiFramedRTPSink::sendPacketIfNecessary
RTPInterface::sendPacket

如果要强制从I帧开始发送,从 RTPInterface::sendPacket 拦截是有点麻烦的,因为rtp、rtcp都会调用这个类,还得判断是rtp包还是rtcp包,是音频还是视频。
MultiFramedRTPSink::sendPacketIfNecessary这里拦截相对容易一些,这里只有rtp了,需要判断是音频还是视频,从fOutBuf->packet()取出rtp数据判断是I帧还是非I帧

相关文章

网友评论

      本文标题:令live555从I帧开始发送

      本文链接:https://www.haomeiwen.com/subject/dwvxbftx.html