RTP library fixes and improvements.
- Fixes marker bit bug in H264 output over RTP-based protocols - Fixes RTCP packets going over the wrong channel in TCP-based RTSP - Fixes RTSP RTCP packets having wrong timestamps - Fixes payload padding parser bug in H264, H265, VP8 and VP9 RTP-based inputs. - Cleans up WebRTC's needless use of thisPacket.getTime() to use thisTime instead
This commit is contained in:
		
							parent
							
								
									132e59db51
								
							
						
					
					
						commit
						a1232d56af
					
				
					 5 changed files with 43 additions and 25 deletions
				
			
		
							
								
								
									
										34
									
								
								lib/rtp.cpp
									
										
									
									
									
								
							
							
						
						
									
										34
									
								
								lib/rtp.cpp
									
										
									
									
									
								
							| 
						 | 
					@ -22,6 +22,11 @@ namespace RTP{
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  unsigned int Packet::getPayloadSize() const{
 | 
					  unsigned int Packet::getPayloadSize() const{
 | 
				
			||||||
 | 
					    // If there is more padding than content, ignore the packet
 | 
				
			||||||
 | 
					    if (getHsize() + (getPadding() ? data[maxDataLen - 1] : 0) >= maxDataLen){
 | 
				
			||||||
 | 
					      WARN_MSG("Packet has more padding than payload; ignoring packet");
 | 
				
			||||||
 | 
					      return 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    return maxDataLen - getHsize() - (getPadding() ? data[maxDataLen - 1] : 0);
 | 
					    return maxDataLen - getHsize() - (getPadding() ? data[maxDataLen - 1] : 0);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -273,7 +278,6 @@ namespace RTP{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void Packet::sendH264(void *socket, void callBack(void *, const char *, size_t, uint8_t),
 | 
					  void Packet::sendH264(void *socket, void callBack(void *, const char *, size_t, uint8_t),
 | 
				
			||||||
                        const char *payload, uint32_t payloadlen, uint32_t channel, bool lastOfAccesUnit){
 | 
					                        const char *payload, uint32_t payloadlen, uint32_t channel, bool lastOfAccesUnit){
 | 
				
			||||||
    if ((payload[0] & 0x1F) == 12){return;}
 | 
					 | 
				
			||||||
    /// \todo This function probably belongs in DMS somewhere.
 | 
					    /// \todo This function probably belongs in DMS somewhere.
 | 
				
			||||||
    if (payloadlen + getHsize() + 2 <= maxDataLen){
 | 
					    if (payloadlen + getHsize() + 2 <= maxDataLen){
 | 
				
			||||||
      data[1] &= 0x7F; // setting the RTP marker bit to 0
 | 
					      data[1] &= 0x7F; // setting the RTP marker bit to 0
 | 
				
			||||||
| 
						 | 
					@ -446,12 +450,22 @@ namespace RTP{
 | 
				
			||||||
                        unsigned int payloadlen, unsigned int channel, std::string codec){
 | 
					                        unsigned int payloadlen, unsigned int channel, std::string codec){
 | 
				
			||||||
    if (codec == "H264"){
 | 
					    if (codec == "H264"){
 | 
				
			||||||
      unsigned long sent = 0;
 | 
					      unsigned long sent = 0;
 | 
				
			||||||
 | 
					      const char * lastPtr = 0;
 | 
				
			||||||
 | 
					      size_t lastLen = 0;
 | 
				
			||||||
      while (sent < payloadlen){
 | 
					      while (sent < payloadlen){
 | 
				
			||||||
        unsigned long nalSize = ntohl(*((unsigned long *)(payload + sent)));
 | 
					        unsigned long nalSize = ntohl(*((unsigned long *)(payload + sent)));
 | 
				
			||||||
        sendH264(socket, callBack, payload + sent + 4, nalSize, channel,
 | 
					        // Since we skip filler data, we need to delay sending by one NAL unit to reliably
 | 
				
			||||||
                 (sent + nalSize + 4) >= payloadlen ? true : false);
 | 
					        // detect the end of the access unit.
 | 
				
			||||||
 | 
					        if ((payload[sent + 4] & 0x1F) != 12){
 | 
				
			||||||
 | 
					          // If we have a pointer stored, we know it's not the last one, so send it as non-last.
 | 
				
			||||||
 | 
					          if (lastPtr){sendH264(socket, callBack, lastPtr, lastLen, channel, false);}
 | 
				
			||||||
 | 
					          lastPtr = payload + sent + 4;
 | 
				
			||||||
 | 
					          lastLen = nalSize;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        sent += nalSize + 4;
 | 
					        sent += nalSize + 4;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					      // Still a pointer stored? That means it was the last one. Mark it as such and send.
 | 
				
			||||||
 | 
					      if (lastPtr){sendH264(socket, callBack, lastPtr, lastLen, channel, true);}
 | 
				
			||||||
      return;
 | 
					      return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (codec == "VP8"){
 | 
					    if (codec == "VP8"){
 | 
				
			||||||
| 
						 | 
					@ -512,7 +526,7 @@ namespace RTP{
 | 
				
			||||||
    increaseSequence();
 | 
					    increaseSequence();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void Packet::sendRTCP_SR(void *socket, void callBack(void *, const char *, size_t, uint8_t)){
 | 
					  void Packet::sendRTCP_SR(void *socket, uint8_t channel, void callBack(void *, const char *, size_t, uint8_t)){
 | 
				
			||||||
    char *rtcpData = (char *)malloc(32);
 | 
					    char *rtcpData = (char *)malloc(32);
 | 
				
			||||||
    if (!rtcpData){
 | 
					    if (!rtcpData){
 | 
				
			||||||
      FAIL_MSG("Could not allocate 32 bytes. Something is seriously messed up.");
 | 
					      FAIL_MSG("Could not allocate 32 bytes. Something is seriously messed up.");
 | 
				
			||||||
| 
						 | 
					@ -529,7 +543,7 @@ namespace RTP{
 | 
				
			||||||
    //*((int *)(rtcpData+16) ) = htonl(getTimeStamp());//rtpts
 | 
					    //*((int *)(rtcpData+16) ) = htonl(getTimeStamp());//rtpts
 | 
				
			||||||
    Bit::htobl(rtcpData + 20, sentPackets); // packet
 | 
					    Bit::htobl(rtcpData + 20, sentPackets); // packet
 | 
				
			||||||
    Bit::htobl(rtcpData + 24, sentBytes);   // octet
 | 
					    Bit::htobl(rtcpData + 24, sentBytes);   // octet
 | 
				
			||||||
    callBack(socket, (char *)rtcpData, 28, 0);
 | 
					    callBack(socket, (char *)rtcpData, 28, channel);
 | 
				
			||||||
    free(rtcpData);
 | 
					    free(rtcpData);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -867,6 +881,10 @@ namespace RTP{
 | 
				
			||||||
  /// Adds an RTP packet to the converter, outputting DTSC packets and/or updating init data,
 | 
					  /// Adds an RTP packet to the converter, outputting DTSC packets and/or updating init data,
 | 
				
			||||||
  /// as-needed.
 | 
					  /// as-needed.
 | 
				
			||||||
  void toDTSC::addRTP(const RTP::Packet &pkt){
 | 
					  void toDTSC::addRTP(const RTP::Packet &pkt){
 | 
				
			||||||
 | 
					    if (pkt.getPayloadType() >= 72 && pkt.getPayloadType() <= 76){
 | 
				
			||||||
 | 
					      INFO_MSG("RTCP packet, ignoring for decoding");
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    if (codec.empty()){
 | 
					    if (codec.empty()){
 | 
				
			||||||
      MEDIUM_MSG("Unknown codec - ignoring RTP packet.");
 | 
					      MEDIUM_MSG("Unknown codec - ignoring RTP packet.");
 | 
				
			||||||
      return;
 | 
					      return;
 | 
				
			||||||
| 
						 | 
					@ -908,17 +926,17 @@ namespace RTP{
 | 
				
			||||||
    // From here on, there is codec-specific parsing. We call handler functions for each codec,
 | 
					    // From here on, there is codec-specific parsing. We call handler functions for each codec,
 | 
				
			||||||
    // except for the trivial codecs.
 | 
					    // except for the trivial codecs.
 | 
				
			||||||
    if (codec == "H264"){
 | 
					    if (codec == "H264"){
 | 
				
			||||||
      return handleH264(msTime, pl, plSize, missed, (pkt.getPadding() == 1) ? true : false);
 | 
					      return handleH264(msTime, pl, plSize, missed, false);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (codec == "AAC"){return handleAAC(msTime, pl, plSize);}
 | 
					    if (codec == "AAC"){return handleAAC(msTime, pl, plSize);}
 | 
				
			||||||
    if (codec == "MP2" || codec == "MP3"){return handleMP2(msTime, pl, plSize);}
 | 
					    if (codec == "MP2" || codec == "MP3"){return handleMP2(msTime, pl, plSize);}
 | 
				
			||||||
    if (codec == "HEVC"){return handleHEVC(msTime, pl, plSize, missed);}
 | 
					    if (codec == "HEVC"){return handleHEVC(msTime, pl, plSize, missed);}
 | 
				
			||||||
    if (codec == "MPEG2"){return handleMPEG2(msTime, pl, plSize);}
 | 
					    if (codec == "MPEG2"){return handleMPEG2(msTime, pl, plSize);}
 | 
				
			||||||
    if (codec == "VP8"){
 | 
					    if (codec == "VP8"){
 | 
				
			||||||
      return handleVP8(msTime, pl, plSize, missed, (pkt.getPadding() == 1) ? true : false);
 | 
					      return handleVP8(msTime, pl, plSize, missed, false);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (codec == "VP9"){
 | 
					    if (codec == "VP9"){
 | 
				
			||||||
      return handleVP8(msTime, pl, plSize, missed, (pkt.getPadding() == 1) ? true : false);
 | 
					      return handleVP8(msTime, pl, plSize, missed, false);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    // Trivial codecs just fill a packet with raw data and continue. Easy peasy, lemon squeezy.
 | 
					    // Trivial codecs just fill a packet with raw data and continue. Easy peasy, lemon squeezy.
 | 
				
			||||||
    if (codec == "ALAW" || codec == "opus" || codec == "PCM" || codec == "ULAW"){
 | 
					    if (codec == "ALAW" || codec == "opus" || codec == "PCM" || codec == "ULAW"){
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -105,7 +105,7 @@ namespace RTP{
 | 
				
			||||||
                   const char *payload, unsigned int payloadlen, unsigned int channel);
 | 
					                   const char *payload, unsigned int payloadlen, unsigned int channel);
 | 
				
			||||||
    void sendData(void *socket, void callBack(void *, const char *, size_t, uint8_t), const char *payload,
 | 
					    void sendData(void *socket, void callBack(void *, const char *, size_t, uint8_t), const char *payload,
 | 
				
			||||||
                  unsigned int payloadlen, unsigned int channel, std::string codec);
 | 
					                  unsigned int payloadlen, unsigned int channel, std::string codec);
 | 
				
			||||||
    void sendRTCP_SR(void *socket, void callBack(void *, const char *, size_t, uint8_t));
 | 
					    void sendRTCP_SR(void *socket, uint8_t channel, void callBack(void *, const char *, size_t, uint8_t));
 | 
				
			||||||
    void sendRTCP_RR(SDP::Track &sTrk, void callBack(void *, const char *, size_t, uint8_t));
 | 
					    void sendRTCP_RR(SDP::Track &sTrk, void callBack(void *, const char *, size_t, uint8_t));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Packet();
 | 
					    Packet();
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -148,19 +148,9 @@ namespace Mist{
 | 
				
			||||||
    if (sdpState.tracks[thisIdx].channel == -1){// UDP connection
 | 
					    if (sdpState.tracks[thisIdx].channel == -1){// UDP connection
 | 
				
			||||||
      socket = &sdpState.tracks[thisIdx].data;
 | 
					      socket = &sdpState.tracks[thisIdx].data;
 | 
				
			||||||
      callBack = sendUDP;
 | 
					      callBack = sendUDP;
 | 
				
			||||||
      if (Util::bootSecs() != sdpState.tracks[thisIdx].rtcpSent){
 | 
					 | 
				
			||||||
        sdpState.tracks[thisIdx].pack.setTimestamp(timestamp * SDP::getMultiplier(&M, thisIdx));
 | 
					 | 
				
			||||||
        sdpState.tracks[thisIdx].rtcpSent = Util::bootSecs();
 | 
					 | 
				
			||||||
        sdpState.tracks[thisIdx].pack.sendRTCP_SR(&sdpState.tracks[thisIdx].rtcp, sendUDP);
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }else{
 | 
					    }else{
 | 
				
			||||||
      socket = &myConn;
 | 
					      socket = &myConn;
 | 
				
			||||||
      callBack = sendTCP;
 | 
					      callBack = sendTCP;
 | 
				
			||||||
      if (Util::bootSecs() != sdpState.tracks[thisIdx].rtcpSent){
 | 
					 | 
				
			||||||
        sdpState.tracks[thisIdx].pack.setTimestamp(timestamp * SDP::getMultiplier(&M, thisIdx));
 | 
					 | 
				
			||||||
        sdpState.tracks[thisIdx].rtcpSent = Util::bootSecs();
 | 
					 | 
				
			||||||
        sdpState.tracks[thisIdx].pack.sendRTCP_SR(socket, sendTCP);
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    uint64_t offset = thisPacket.getInt("offset");
 | 
					    uint64_t offset = thisPacket.getInt("offset");
 | 
				
			||||||
| 
						 | 
					@ -168,6 +158,16 @@ namespace Mist{
 | 
				
			||||||
    sdpState.tracks[thisIdx].pack.sendData(socket, callBack, dataPointer, dataLen,
 | 
					    sdpState.tracks[thisIdx].pack.sendData(socket, callBack, dataPointer, dataLen,
 | 
				
			||||||
                                           sdpState.tracks[thisIdx].channel, meta.getCodec(thisIdx));
 | 
					                                           sdpState.tracks[thisIdx].channel, meta.getCodec(thisIdx));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (Util::bootSecs() != sdpState.tracks[thisIdx].rtcpSent){
 | 
				
			||||||
 | 
					      if (sdpState.tracks[thisIdx].channel == -1){// UDP connection
 | 
				
			||||||
 | 
					        sdpState.tracks[thisIdx].pack.sendRTCP_SR(&sdpState.tracks[thisIdx].rtcp, 0, callBack);
 | 
				
			||||||
 | 
					      }else{
 | 
				
			||||||
 | 
					        sdpState.tracks[thisIdx].pack.sendRTCP_SR(socket, sdpState.tracks[thisIdx].channel, callBack);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      sdpState.tracks[thisIdx].rtcpSent = Util::bootSecs();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    static uint64_t lastAnnounce = Util::bootSecs();
 | 
					    static uint64_t lastAnnounce = Util::bootSecs();
 | 
				
			||||||
    if (reqUrl.size() && lastAnnounce + 5 < Util::bootSecs()){
 | 
					    if (reqUrl.size() && lastAnnounce + 5 < Util::bootSecs()){
 | 
				
			||||||
      INFO_MSG("Sending announce");
 | 
					      INFO_MSG("Sending announce");
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -170,7 +170,7 @@ namespace Mist{
 | 
				
			||||||
      if (Util::bootSecs() != sdpState.tracks[thisIdx].rtcpSent){
 | 
					      if (Util::bootSecs() != sdpState.tracks[thisIdx].rtcpSent){
 | 
				
			||||||
        sdpState.tracks[thisIdx].pack.setTimestamp(timestamp * SDP::getMultiplier(&M, thisIdx));
 | 
					        sdpState.tracks[thisIdx].pack.setTimestamp(timestamp * SDP::getMultiplier(&M, thisIdx));
 | 
				
			||||||
        sdpState.tracks[thisIdx].rtcpSent = Util::bootSecs();
 | 
					        sdpState.tracks[thisIdx].rtcpSent = Util::bootSecs();
 | 
				
			||||||
        sdpState.tracks[thisIdx].pack.sendRTCP_SR(&sdpState.tracks[thisIdx].rtcp, sendUDP);
 | 
					        sdpState.tracks[thisIdx].pack.sendRTCP_SR(&sdpState.tracks[thisIdx].rtcp, sdpState.tracks[thisIdx].channel, sendUDP);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }else{
 | 
					    }else{
 | 
				
			||||||
      FAIL_MSG("RTP SDP output does not support TCP. No data will be sent to the target address");
 | 
					      FAIL_MSG("RTP SDP output does not support TCP. No data will be sent to the target address");
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1712,8 +1712,8 @@ namespace Mist{
 | 
				
			||||||
      onIdle();
 | 
					      onIdle();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (M.getLive() && stayLive && lastTimeSync + 666 < thisPacket.getTime()){
 | 
					    if (M.getLive() && stayLive && lastTimeSync + 666 < thisTime){
 | 
				
			||||||
      lastTimeSync = thisPacket.getTime();
 | 
					      lastTimeSync = thisTime;
 | 
				
			||||||
      if (liveSeek()){return;}
 | 
					      if (liveSeek()){return;}
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1760,9 +1760,9 @@ namespace Mist{
 | 
				
			||||||
    // This checks if we have a whole integer multiplier, and if so,
 | 
					    // This checks if we have a whole integer multiplier, and if so,
 | 
				
			||||||
    // ensures only integer math is used to prevent rounding errors
 | 
					    // ensures only integer math is used to prevent rounding errors
 | 
				
			||||||
    if (mult == (uint64_t)mult){
 | 
					    if (mult == (uint64_t)mult){
 | 
				
			||||||
      rtcTrack.rtpPacketizer.setTimestamp(thisPacket.getTime() * (uint64_t)mult);
 | 
					      rtcTrack.rtpPacketizer.setTimestamp(thisTime * (uint64_t)mult);
 | 
				
			||||||
    }else{
 | 
					    }else{
 | 
				
			||||||
      rtcTrack.rtpPacketizer.setTimestamp(thisPacket.getTime() * mult);
 | 
					      rtcTrack.rtpPacketizer.setTimestamp(thisTime * mult);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bool isKeyFrame = thisPacket.getFlag("keyframe");
 | 
					    bool isKeyFrame = thisPacket.getFlag("keyframe");
 | 
				
			||||||
| 
						 | 
					@ -1798,7 +1798,7 @@ namespace Mist{
 | 
				
			||||||
    //If this track hasn't sent yet, actually sent
 | 
					    //If this track hasn't sent yet, actually sent
 | 
				
			||||||
    if (mustSendSR.count(thisIdx)){
 | 
					    if (mustSendSR.count(thisIdx)){
 | 
				
			||||||
      mustSendSR.erase(thisIdx);
 | 
					      mustSendSR.erase(thisIdx);
 | 
				
			||||||
      rtcTrack.rtpPacketizer.sendRTCP_SR((void *)&udp, onRTPPacketizerHasRTCPDataCallback);
 | 
					      rtcTrack.rtpPacketizer.sendRTCP_SR((void *)&udp, 0, onRTPPacketizerHasRTCPDataCallback);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue