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
Reference in a new issue