Use the IDR frame request packet on Gen 4 servers. This solves the issue of IDR frames breaking after 0xFFFFF frames (4.85 hours at 60 FPS)

This commit is contained in:
Cameron Gutman 2015-08-04 23:43:10 -07:00
parent b9597d696a
commit b79ee8ca46
3 changed files with 63 additions and 47 deletions

View File

@ -12,27 +12,28 @@ typedef struct _NVCTL_PACKET_HEADER {
static SOCKET ctlSock = INVALID_SOCKET;
static PLT_THREAD lossStatsThread;
static PLT_THREAD resyncThread;
static PLT_EVENT resyncEvent;
static PLT_THREAD invalidateRefFramesThread;
static PLT_EVENT invalidateRefFramesEvent;
static int lossCountSinceLastReport = 0;
static long currentFrame = 0;
#define IDX_START_A 0
#define IDX_REQUEST_IDR_FRAME 0
#define IDX_START_B 1
#define IDX_RESYNC 2
#define IDX_INVALIDATE_REF_FRAMES 2
#define IDX_LOSS_STATS 3
static const short packetTypesGen3[] = {
0x140b, // Start A
0x1410, // Start B
0x1404, // Resync
0x1404, // Invalidate reference frames
0x140c, // Loss Stats
0x1417, // Frame Stats (unused)
};
static const short packetTypesGen4[] = {
0x0606, // Start A
0x0606, // Request IDR frame
0x0609, // Start B
0x0604, // Resync
0x0604, // Invalidate reference frames
0x060a, // Loss Stats
0x0611, // Frame Stats (unused)
};
@ -40,20 +41,20 @@ static const short packetTypesGen4[] = {
static const char startAGen3[] = {0};
static const int startBGen3[] = {0, 0, 0, 0xa};
static const char startAGen4[] = {0, 0};
static const char requestIdrFrameGen4[] = {0, 0};
static const char startBGen4[] = {0};
static const short payloadLengthsGen3[] = {
sizeof(startAGen3), // Start A
sizeof(startBGen3), // Start B
24, // Resync
24, // Invalidate reference frames
32, // Loss Stats
64, // Frame Stats
};
static const short payloadLengthsGen4[] = {
sizeof(startAGen4), // Start A
sizeof(requestIdrFrameGen4), // Request IDR frame
sizeof(startBGen4), // Start B
24, // Resync
24, // Invalidate reference frames
32, // Loss Stats
64, // Frame Stats
};
@ -63,7 +64,7 @@ static const char* preconstructedPayloadsGen3[] = {
(char*)startBGen3
};
static const char* preconstructedPayloadsGen4[] = {
startAGen4,
requestIdrFrameGen4,
startBGen4
};
@ -75,7 +76,7 @@ static char **preconstructedPayloads;
/* Initializes the control stream */
int initializeControlStream(void) {
PltCreateEvent(&resyncEvent);
PltCreateEvent(&invalidateRefFramesEvent);
if (ServerMajorVersion == 3) {
packetTypes = (short*)packetTypesGen3;
@ -93,25 +94,24 @@ int initializeControlStream(void) {
/* Cleans up control stream */
void destroyControlStream(void) {
PltCloseEvent(&resyncEvent);
PltCloseEvent(&invalidateRefFramesEvent);
}
/* Resync on demand by the decoder */
void resyncOnDemand(void) {
// FIXME: Send ranges
PltSetEvent(&resyncEvent);
/* Request an IDR frame on demand by the decoder */
void requestIdrOnDemand(void) {
PltSetEvent(&invalidateRefFramesEvent);
}
/* Resync if the connection is too slow */
/* Invalidate reference frames if the decoder is too slow */
void connectionSinkTooSlow(int startFrame, int endFrame) {
// FIXME: Send ranges
PltSetEvent(&resyncEvent);
PltSetEvent(&invalidateRefFramesEvent);
}
/* Resync if we're losing frames */
/* Invalidate reference frames lost by the network */
void connectionDetectedFrameLoss(int startFrame, int endFrame) {
// FIXME: Send ranges
PltSetEvent(&resyncEvent);
PltSetEvent(&invalidateRefFramesEvent);
}
/* When we receive a frame, update the number of our current frame */
@ -236,35 +236,51 @@ static void lossStatsThreadFunc(void* context) {
free(lossStatsPayload);
}
static void resyncThreadFunc(void* context) {
long long payload[3];
static void requestIdrFrame(void) {
long long payload[3];
while (!PltIsThreadInterrupted(&resyncThread)) {
// Wait for a resync request
PltWaitForEvent(&resyncEvent);
if (ServerMajorVersion == 3) {
// Form the payload
payload[0] = 0;
payload[1] = 0xFFFFF;
payload[2] = 0;
// Form the payload
payload[0] = 0;
payload[1] = 0xFFFFF;
payload[2] = 0;
// Send the reference frame invalidation request and read the response
if (!sendMessageAndDiscardReply(packetTypes[IDX_INVALIDATE_REF_FRAMES],
payloadLengths[IDX_INVALIDATE_REF_FRAMES], payload)) {
Limelog("Request IDR Frame: Transaction failed: %d\n", (int) LastSocketError());
ListenerCallbacks.connectionTerminated(LastSocketError());
return;
}
}
else {
// Send IDR frame request and read the response
if (!sendMessageAndDiscardReply(packetTypes[IDX_REQUEST_IDR_FRAME],
payloadLengths[IDX_REQUEST_IDR_FRAME], preconstructedPayloads[IDX_REQUEST_IDR_FRAME])) {
Limelog("Request IDR Frame: Transaction failed: %d\n", (int) LastSocketError());
ListenerCallbacks.connectionTerminated(LastSocketError());
return;
}
}
// Done capturing the parameters
PltClearEvent(&resyncEvent);
Limelog("IDR frame request sent\n");
}
// Send the resync request and read the response
if (!sendMessageAndDiscardReply(packetTypes[IDX_RESYNC], payloadLengths[IDX_RESYNC], payload)) {
Limelog("Resync: Transaction failed: %d\n", (int)LastSocketError());
ListenerCallbacks.connectionTerminated(LastSocketError());
return;
}
Limelog("Resync complete\n");
}
static void invalidateRefFramesFunc(void* context) {
while (!PltIsThreadInterrupted(&invalidateRefFramesThread)) {
// Wait for a request to invalidate reference frames
PltWaitForEvent(&invalidateRefFramesEvent);
PltClearEvent(&invalidateRefFramesEvent);
// Send an IDR frame request
requestIdrFrame();
}
}
/* Stops the control stream */
int stopControlStream(void) {
PltInterruptThread(&lossStatsThread);
PltInterruptThread(&resyncThread);
PltInterruptThread(&invalidateRefFramesThread);
if (ctlSock != INVALID_SOCKET) {
closesocket(ctlSock);
@ -272,10 +288,10 @@ int stopControlStream(void) {
}
PltJoinThread(&lossStatsThread);
PltJoinThread(&resyncThread);
PltJoinThread(&invalidateRefFramesThread);
PltCloseThread(&lossStatsThread);
PltCloseThread(&resyncThread);
PltCloseThread(&invalidateRefFramesThread);
return 0;
}
@ -312,7 +328,7 @@ int startControlStream(void) {
return err;
}
err = PltCreateThread(resyncThreadFunc, NULL, &resyncThread);
err = PltCreateThread(invalidateRefFramesFunc, NULL, &invalidateRefFramesThread);
if (err != 0) {
return err;
}

View File

@ -26,7 +26,7 @@ int initializeControlStream(void);
int startControlStream(void);
int stopControlStream(void);
void destroyControlStream(void);
void resyncOnDemand(void);
void requestIdrOnDemand(void);
void connectionSinkTooSlow(int startFrame, int endFrame);
void connectionDetectedFrameLoss(int startFrame, int endFrame);
void connectionReceivedFrame(int frameIndex);

View File

@ -129,8 +129,8 @@ static void DecoderThreadProc(void* context) {
freeQueuedDecodeUnit(qdu);
if (ret == DR_NEED_IDR) {
Limelog("Request IDR frame on behalf of DR\n");
resyncOnDemand();
Limelog("Requesting IDR frame on behalf of DR\n");
requestIdrOnDemand();
}
}
}