嵌入式流媒体音视频服务器EasyIPCamera中live555发送性能优化点

EasyIPCamera流媒体服务器

今年EasyDarwin团队在给国内某最大的金融安防公司做技术咨询的时候,开发了一款适用于嵌入式IPCamera、NVR的RTSP流媒体服务器:EasyIPCamera,EasyIPCamera的核心是基于live555进行封装的,外围增加对live555 RTSPServer的调用接口,更加方便海思等安防芯片进行RTSPServer服务的建立,EasyIPCamera在海思3156A芯片上的性能经过我们半年多的调试,目前已经可以稳定在4路1080P并发:

  • TCP/UDP 方式分别连接3路下,1080P 4M 定码率,音频格式G711(64K)G726(16K 24K 32K 40K)AAC(64K 96K 128K)都没问题;
  • TCP/UDP 方式分别连接4路下,1080P 4M 定码率,音频格式G711(64K)G726(16K 24K 32K 40K)AAC(64K 96K 128K)都没问题;

    EasyIPCamera嵌入式流媒体服务器

live555网络发送优化

在live555的RTP发送类MultiFramedRTPSink中的sendPacketIfNecessary()函数中,我们改造原有的live555发送过程,增加了live555在嵌入式arm中网络发送的速度,提升了嵌入式RTSPServer流媒体服务器的发送性能,具体代码:

void MultiFramedRTPSink::sendPacketIfNecessary() {
  if (fNumFramesUsedSoFar > 0) {
    // Send the packet:
#ifdef TEST_LOSS
    if ((our_random()%10) != 0) // simulate 10% packet loss #####
#endif
      if (!fRTPInterface.sendPacket(fOutBuf->packet(), fOutBuf->curPacketSize())) {
    // if failure handler has been specified, call it
    if (fOnSendErrorFunc != NULL) (*fOnSendErrorFunc)(fOnSendErrorData);
      }
    ++fPacketCount;
    fTotalOctetCount += fOutBuf->curPacketSize();
    fOctetCount += fOutBuf->curPacketSize()
      - rtpHeaderSize - fSpecialHeaderSize - fTotalFrameSpecificHeaderSizes;

    ++fSeqNo; // for next time
  }

  if (fOutBuf->haveOverflowData()
      && fOutBuf->totalBytesAvailable() > fOutBuf->totalBufferSize()/2) {
    // Efficiency hack: Reset the packet start pointer to just in front of
    // the overflow data (allowing for the RTP header and special headers),
    // so that we probably don't have to "memmove()" the overflow data
    // into place when building the next packet:
    unsigned newPacketStart = fOutBuf->curPacketSize()
      - (rtpHeaderSize + fSpecialHeaderSize + frameSpecificHeaderSize());
    fOutBuf->adjustPacketStart(newPacketStart);
  } else {
    // Normal case: Reset the packet start pointer back to the start:
    fOutBuf->resetPacketStart();
  }
  fOutBuf->resetOffset();
  fNumFramesUsedSoFar = 0;

  if (fNoFramesLeft) {
    // We're done:
    onSourceClosure();
  } else {
#if 0   //原有方法是重新计算一个Task时间,让live555下一次循环再将未发送完的包继续发送完成
    // We have more frames left to send.  Figure out when the next frame
    // is due to start playing, then make sure that we wait this long before
    // sending the next packet.
    struct timeval timeNow;
    gettimeofday(&timeNow, NULL);
    int secsDiff = fNextSendTime.tv_sec - timeNow.tv_sec;
    int64_t uSecondsToGo = secsDiff*1000000 + (fNextSendTime.tv_usec - timeNow.tv_usec);
    if (uSecondsToGo < 0 || secsDiff < 0) { // sanity check: Make sure that the time-to-delay is non-negative:
      uSecondsToGo = 0;
    }

    // Delay this amount of time:
    //nextTask() = envir().taskScheduler().scheduleDelayedTask(uSecondsToGo, (TaskFunc*)sendNext, this);
#else   //现有方法是不经过循环,直接将未发送的包全部发完再进行live555的eventLoop循环
    sendNext(this);
#endif
  }
}

获取更多信息

邮件:support@easydarwin.org

WEB:www.EasyDarwin.org

Copyright © EasyDarwin.org 2012-2016

EasyDarwin

posted @ 2016-09-02 14:33  Babosa  阅读(342)  评论(0编辑  收藏  举报