mirror of
https://github.com/moonlight-stream/moonlight-common-c.git
synced 2025-07-04 00:36:37 +00:00
Add another predictive RFI detection technique
This commit is contained in:
parent
5e1be51b84
commit
9091238861
@ -105,10 +105,10 @@ static bool queuePacket(PRTP_VIDEO_QUEUE queue, PRTPV_QUEUE_ENTRY newEntry, PRTP
|
|||||||
}
|
}
|
||||||
else if (!isFecRecovery && isBefore16(packet->sequenceNumber, entry->packet->sequenceNumber)) {
|
else if (!isFecRecovery && isBefore16(packet->sequenceNumber, entry->packet->sequenceNumber)) {
|
||||||
// This packet was received after a higher sequence number packet, so note that we
|
// This packet was received after a higher sequence number packet, so note that we
|
||||||
// received an out of order packet to disable our fast RFI recovery logic.
|
// received an out of order packet to disable our predictive RFI recovery logic.
|
||||||
queue->lastOosSequenceNumber = packet->sequenceNumber;
|
queue->lastOosSequenceNumber = packet->sequenceNumber;
|
||||||
if (!queue->receivedOosData) {
|
if (!queue->receivedOosData) {
|
||||||
Limelog("Leaving fast RFI mode after OOS video data (%u < %u)\n",
|
Limelog("Leaving predictive RFI mode after OOS video data (%u < %u)\n",
|
||||||
packet->sequenceNumber, entry->packet->sequenceNumber);
|
packet->sequenceNumber, entry->packet->sequenceNumber);
|
||||||
queue->receivedOosData = true;
|
queue->receivedOosData = true;
|
||||||
}
|
}
|
||||||
@ -120,7 +120,7 @@ static bool queuePacket(PRTP_VIDEO_QUEUE queue, PRTPV_QUEUE_ENTRY newEntry, PRTP
|
|||||||
|
|
||||||
// This is just a fancy way of determining if 32767 packets have passed since our last OOS data
|
// This is just a fancy way of determining if 32767 packets have passed since our last OOS data
|
||||||
if (queue->receivedOosData && isBefore16(queue->bufferHighestSequenceNumber, queue->lastOosSequenceNumber)) {
|
if (queue->receivedOosData && isBefore16(queue->bufferHighestSequenceNumber, queue->lastOosSequenceNumber)) {
|
||||||
Limelog("Entering fast RFI mode after sequenced video data\n");
|
Limelog("Entering predictive RFI mode after sequenced video data\n");
|
||||||
queue->receivedOosData = false;
|
queue->receivedOosData = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -156,20 +156,27 @@ static int reconstructFrame(PRTP_VIDEO_QUEUE queue) {
|
|||||||
// We'll need an extra packet to run in FEC validation mode, because we will
|
// We'll need an extra packet to run in FEC validation mode, because we will
|
||||||
// be "dropping" one below and recovering it using parity. However, some frames
|
// be "dropping" one below and recovering it using parity. However, some frames
|
||||||
// are so large that FEC is disabled entirely, so don't wait for parity on those.
|
// are so large that FEC is disabled entirely, so don't wait for parity on those.
|
||||||
neededPackets += (queue->fecPercentage ? 1 : 0);
|
neededPackets += queue->fecPercentage ? 1 : 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (queue->pendingFecBlockList.count < neededPackets) {
|
if (queue->pendingFecBlockList.count < neededPackets) {
|
||||||
// If we've never seen OOS data and we've seen parity packets but not enough to recover the frame without
|
// If we've never received OOS data from this host, we can predict whether this frame will be recoverable
|
||||||
// additional data (which is unlikely to come, given that we've never seen OOS data from this host), we
|
// based on the packets we've received (or not) so far.
|
||||||
// will presume the frame is lost and tell the host immediately.
|
if (!queue->reportedLostFrame && !queue->receivedOosData) {
|
||||||
if (!queue->reportedLostFrame &&
|
if (queue->missingDataPackets > queue->bufferParityPackets) {
|
||||||
!queue->receivedOosData &&
|
// If the number of missing data shards exceeds the total number of possible parity shards,
|
||||||
queue->receivedParityPackets != 0 &&
|
// we will presume the frame is lost.
|
||||||
neededPackets - queue->pendingFecBlockList.count > U16(queue->bufferHighestSequenceNumber - queue->receivedParityHighestSequenceNumber)) {
|
|
||||||
notifyFrameLost(queue->currentFrameNumber);
|
notifyFrameLost(queue->currentFrameNumber);
|
||||||
queue->reportedLostFrame = true;
|
queue->reportedLostFrame = true;
|
||||||
}
|
}
|
||||||
|
else if (queue->receivedParityPackets != 0 &&
|
||||||
|
neededPackets - queue->pendingFecBlockList.count > U16(queue->bufferHighestSequenceNumber - queue->receivedParityHighestSequenceNumber)) {
|
||||||
|
// If we've seen some parity shards but not enough parity shards remain to recover this frame
|
||||||
|
// without additional data shards, we will presume the frame is lost.
|
||||||
|
notifyFrameLost(queue->currentFrameNumber);
|
||||||
|
queue->reportedLostFrame = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Not enough data to recover yet
|
// Not enough data to recover yet
|
||||||
return -1;
|
return -1;
|
||||||
@ -178,6 +185,7 @@ static int reconstructFrame(PRTP_VIDEO_QUEUE queue) {
|
|||||||
// If we make it here and reported a lost frame, we lied to the host. This can happen if we happen to get
|
// If we make it here and reported a lost frame, we lied to the host. This can happen if we happen to get
|
||||||
// unlucky and this particular frame happens to be the one with OOS data, but it should almost never happen.
|
// unlucky and this particular frame happens to be the one with OOS data, but it should almost never happen.
|
||||||
LC_ASSERT(!queue->reportedLostFrame);
|
LC_ASSERT(!queue->reportedLostFrame);
|
||||||
|
LC_ASSERT(queue->receivedParityPackets >= queue->missingDataPackets);
|
||||||
|
|
||||||
#ifdef FEC_VALIDATION_MODE
|
#ifdef FEC_VALIDATION_MODE
|
||||||
// If FEC is disabled or unsupported for this frame, we must bail early here.
|
// If FEC is disabled or unsupported for this frame, we must bail early here.
|
||||||
@ -187,6 +195,7 @@ static int reconstructFrame(PRTP_VIDEO_QUEUE queue) {
|
|||||||
if (queue->receivedBufferDataPackets == queue->bufferDataPackets) {
|
if (queue->receivedBufferDataPackets == queue->bufferDataPackets) {
|
||||||
#endif
|
#endif
|
||||||
// We've received a full frame with no need for FEC.
|
// We've received a full frame with no need for FEC.
|
||||||
|
LC_ASSERT(queue->missingDataPackets == 0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -590,7 +599,9 @@ int RtpvAddPacket(PRTP_VIDEO_QUEUE queue, PRTP_PACKET packet, int length, PRTPV_
|
|||||||
queue->nextContiguousSequenceNumber = queue->bufferLowestSequenceNumber;
|
queue->nextContiguousSequenceNumber = queue->bufferLowestSequenceNumber;
|
||||||
queue->receivedBufferDataPackets = 0;
|
queue->receivedBufferDataPackets = 0;
|
||||||
queue->receivedParityPackets = 0;
|
queue->receivedParityPackets = 0;
|
||||||
|
queue->receivedDataHighestSequenceNumber = 0;
|
||||||
queue->receivedParityHighestSequenceNumber = 0;
|
queue->receivedParityHighestSequenceNumber = 0;
|
||||||
|
queue->missingDataPackets = 0;
|
||||||
queue->reportedLostFrame = false;
|
queue->reportedLostFrame = false;
|
||||||
queue->bufferDataPackets = (nvPacket->fecInfo & 0xFFC00000) >> 22;
|
queue->bufferDataPackets = (nvPacket->fecInfo & 0xFFC00000) >> 22;
|
||||||
queue->fecPercentage = (nvPacket->fecInfo & 0xFF0) >> 4;
|
queue->fecPercentage = (nvPacket->fecInfo & 0xFF0) >> 4;
|
||||||
@ -624,6 +635,24 @@ int RtpvAddPacket(PRTP_VIDEO_QUEUE queue, PRTP_PACKET packet, int length, PRTPV_
|
|||||||
else {
|
else {
|
||||||
if (isBefore16(packet->sequenceNumber, queue->bufferFirstParitySequenceNumber)) {
|
if (isBefore16(packet->sequenceNumber, queue->bufferFirstParitySequenceNumber)) {
|
||||||
queue->receivedBufferDataPackets++;
|
queue->receivedBufferDataPackets++;
|
||||||
|
|
||||||
|
if (queue->receivedBufferDataPackets == 1) {
|
||||||
|
queue->missingDataPackets += U16(packet->sequenceNumber - queue->bufferLowestSequenceNumber);
|
||||||
|
queue->receivedDataHighestSequenceNumber = packet->sequenceNumber;
|
||||||
|
}
|
||||||
|
else if (isBefore16(queue->receivedDataHighestSequenceNumber, packet->sequenceNumber)) {
|
||||||
|
// If we receive a packet above the highest data sequence number,
|
||||||
|
// adjust our missing packets count based on that new sequence number.
|
||||||
|
queue->missingDataPackets += U16(packet->sequenceNumber - queue->receivedDataHighestSequenceNumber - 1);
|
||||||
|
queue->receivedDataHighestSequenceNumber = packet->sequenceNumber;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// If we receive a packet behind the highest data sequence number and
|
||||||
|
// queuePacket() accepted it, we must have received a missing packet.
|
||||||
|
queue->missingDataPackets--;
|
||||||
|
}
|
||||||
|
|
||||||
|
LC_ASSERT(queue->missingDataPackets < queue->bufferDataPackets);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
queue->receivedParityPackets++;
|
queue->receivedParityPackets++;
|
||||||
|
@ -31,8 +31,10 @@ typedef struct _RTP_VIDEO_QUEUE {
|
|||||||
uint32_t receivedBufferDataPackets;
|
uint32_t receivedBufferDataPackets;
|
||||||
uint32_t receivedParityPackets;
|
uint32_t receivedParityPackets;
|
||||||
uint32_t receivedParityHighestSequenceNumber;
|
uint32_t receivedParityHighestSequenceNumber;
|
||||||
|
uint32_t receivedDataHighestSequenceNumber;
|
||||||
uint32_t fecPercentage;
|
uint32_t fecPercentage;
|
||||||
uint32_t nextContiguousSequenceNumber;
|
uint32_t nextContiguousSequenceNumber;
|
||||||
|
uint32_t missingDataPackets; // # of holes behind receivedDataHighestSequenceNumber
|
||||||
bool reportedLostFrame;
|
bool reportedLostFrame;
|
||||||
|
|
||||||
uint32_t currentFrameNumber;
|
uint32_t currentFrameNumber;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user