mirror of
https://github.com/moonlight-stream/moonlight-common-c.git
synced 2026-06-22 00:31:09 +00:00
Rework RFI to work reliably with HEVC
This commit is contained in:
+56
-9
@@ -11,6 +11,7 @@ static unsigned int nextFrameNumber;
|
|||||||
static unsigned int startFrameNumber;
|
static unsigned int startFrameNumber;
|
||||||
static bool waitingForNextSuccessfulFrame;
|
static bool waitingForNextSuccessfulFrame;
|
||||||
static bool waitingForIdrFrame;
|
static bool waitingForIdrFrame;
|
||||||
|
static bool waitingForRefInvalFrame;
|
||||||
static unsigned int lastPacketInStream;
|
static unsigned int lastPacketInStream;
|
||||||
static bool decodingFrame;
|
static bool decodingFrame;
|
||||||
static bool strictIdrFrameWait;
|
static bool strictIdrFrameWait;
|
||||||
@@ -58,6 +59,7 @@ void initializeVideoDepacketizer(int pktSize) {
|
|||||||
startFrameNumber = 0;
|
startFrameNumber = 0;
|
||||||
waitingForNextSuccessfulFrame = false;
|
waitingForNextSuccessfulFrame = false;
|
||||||
waitingForIdrFrame = true;
|
waitingForIdrFrame = true;
|
||||||
|
waitingForRefInvalFrame = false;
|
||||||
lastPacketInStream = UINT32_MAX;
|
lastPacketInStream = UINT32_MAX;
|
||||||
decodingFrame = false;
|
decodingFrame = false;
|
||||||
firstPacketReceiveTime = 0;
|
firstPacketReceiveTime = 0;
|
||||||
@@ -90,11 +92,14 @@ static void dropFrameState(void) {
|
|||||||
// We're dropping frame state now
|
// We're dropping frame state now
|
||||||
dropStatePending = false;
|
dropStatePending = false;
|
||||||
|
|
||||||
// We'll need an IDR frame now if we're in strict mode
|
if (strictIdrFrameWait || !idrFrameProcessed || waitingForIdrFrame) {
|
||||||
// or if we've never seen one before
|
// We'll need an IDR frame now if we're in non-RFI mode, if we've never
|
||||||
if (strictIdrFrameWait || !idrFrameProcessed) {
|
// received an IDR frame, or if we explicitly need an IDR frame.
|
||||||
waitingForIdrFrame = true;
|
waitingForIdrFrame = true;
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
waitingForRefInvalFrame = true;
|
||||||
|
}
|
||||||
|
|
||||||
// Count the number of consecutive frames dropped
|
// Count the number of consecutive frames dropped
|
||||||
consecutiveFrameDrops++;
|
consecutiveFrameDrops++;
|
||||||
@@ -558,6 +563,7 @@ static void processRtpPayloadSlow(PBUFFER_DESC currentPos, PLENTRY_INTERNAL* exi
|
|||||||
if (isSeqReferenceFrameStart(currentPos)) {
|
if (isSeqReferenceFrameStart(currentPos)) {
|
||||||
// No longer waiting for an IDR frame
|
// No longer waiting for an IDR frame
|
||||||
waitingForIdrFrame = false;
|
waitingForIdrFrame = false;
|
||||||
|
waitingForRefInvalFrame = false;
|
||||||
|
|
||||||
// Cancel any pending IDR frame request
|
// Cancel any pending IDR frame request
|
||||||
waitingForNextSuccessfulFrame = false;
|
waitingForNextSuccessfulFrame = false;
|
||||||
@@ -701,6 +707,35 @@ static void processRtpPayload(PNV_VIDEO_PACKET videoPacket, int length,
|
|||||||
|
|
||||||
// If this is the first packet, skip the frame header (if one exists)
|
// If this is the first packet, skip the frame header (if one exists)
|
||||||
if (firstPacket) {
|
if (firstPacket) {
|
||||||
|
// Parse the frame type from the header
|
||||||
|
if (APP_VERSION_AT_LEAST(7, 1, 415)) {
|
||||||
|
switch (currentPos.data[currentPos.offset + 3]) {
|
||||||
|
case 1: // Normal P-frame
|
||||||
|
break;
|
||||||
|
case 2: // IDR frame
|
||||||
|
case 4: // Intra-refresh
|
||||||
|
case 5: // P-frame with reference frames invalidated
|
||||||
|
if (waitingForRefInvalFrame) {
|
||||||
|
Limelog("Next post-invalidation frame is: %d (%s-frame)\n",
|
||||||
|
frameIndex,
|
||||||
|
currentPos.data[currentPos.offset + 3] == 5 ? "P" : "I");
|
||||||
|
waitingForRefInvalFrame = false;
|
||||||
|
waitingForNextSuccessfulFrame = false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 104: // Sunshine hardcoded header
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Limelog("Unrecognized frame type: %d", currentPos.data[currentPos.offset + 3]);
|
||||||
|
LC_ASSERT(false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Hope for the best with older servers
|
||||||
|
waitingForRefInvalFrame = false;
|
||||||
|
}
|
||||||
|
|
||||||
if (APP_VERSION_AT_LEAST(7, 1, 446)) {
|
if (APP_VERSION_AT_LEAST(7, 1, 446)) {
|
||||||
// >= 7.1.446 uses 2 different header lengths based on the first byte:
|
// >= 7.1.446 uses 2 different header lengths based on the first byte:
|
||||||
// 0x01 indicates an 8 byte header
|
// 0x01 indicates an 8 byte header
|
||||||
@@ -793,22 +828,34 @@ static void processRtpPayload(PNV_VIDEO_PACKET videoPacket, int length,
|
|||||||
decodingFrame = false;
|
decodingFrame = false;
|
||||||
nextFrameNumber = frameIndex + 1;
|
nextFrameNumber = frameIndex + 1;
|
||||||
|
|
||||||
|
// If we can't submit this frame due to a discontinuity in the bitstream,
|
||||||
|
// inform the host (if needed) and drop the data.
|
||||||
|
if (waitingForIdrFrame || waitingForRefInvalFrame) {
|
||||||
|
// IDR wait takes priority over RFI wait (and an IDR frame will satisfy both)
|
||||||
|
if (waitingForIdrFrame) {
|
||||||
|
Limelog("Waiting for IDR frame\n");
|
||||||
|
|
||||||
// If waiting for next successful frame and we got here
|
// If waiting for next successful frame and we got here
|
||||||
// with an end flag, we can send a message to the server
|
// with an end flag, we can send a message to the server
|
||||||
if (waitingForNextSuccessfulFrame) {
|
if (waitingForNextSuccessfulFrame) {
|
||||||
// This is the next successful frame after a loss event
|
// This is the next successful frame after a loss event
|
||||||
connectionDetectedFrameLoss(startFrameNumber, frameIndex - 1);
|
connectionDetectedFrameLoss(startFrameNumber, frameIndex);
|
||||||
waitingForNextSuccessfulFrame = false;
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// If we need an RFI frame first, then drop this frame
|
||||||
|
// and update the reference frame invalidation window.
|
||||||
|
Limelog("Waiting for RFI frame\n");
|
||||||
|
connectionDetectedFrameLoss(startFrameNumber, frameIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we need an IDR frame first, then drop this frame
|
waitingForNextSuccessfulFrame = false;
|
||||||
if (waitingForIdrFrame) {
|
|
||||||
Limelog("Waiting for IDR frame\n");
|
|
||||||
|
|
||||||
dropFrameState();
|
dropFrameState();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LC_ASSERT(!waitingForNextSuccessfulFrame);
|
||||||
|
|
||||||
// Carry out any pending state drops. We can't just do this
|
// Carry out any pending state drops. We can't just do this
|
||||||
// arbitrarily in the middle of processing a frame because
|
// arbitrarily in the middle of processing a frame because
|
||||||
// may cause the depacketizer state to become corrupted. For
|
// may cause the depacketizer state to become corrupted. For
|
||||||
|
|||||||
Reference in New Issue
Block a user