From 921b59c467ac78ef2a770ad1bb3e61fbef51bd09 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Mon, 17 Jan 2022 14:12:11 -0600 Subject: [PATCH] Add API to wake a waiting thread in LiWaitForNextVideoFrame() --- src/Limelight.h | 1 + src/LinkedBlockingQueue.c | 16 +++++++++++++++- src/LinkedBlockingQueue.h | 3 +++ src/VideoDepacketizer.c | 4 ++++ 4 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/Limelight.h b/src/Limelight.h index b3cd6e8..f24454e 100644 --- a/src/Limelight.h +++ b/src/Limelight.h @@ -651,6 +651,7 @@ typedef void* VIDEO_FRAME_HANDLE; bool LiWaitForNextVideoFrame(VIDEO_FRAME_HANDLE* frameHandle, PDECODE_UNIT* decodeUnit); bool LiPollNextVideoFrame(VIDEO_FRAME_HANDLE* frameHandle, PDECODE_UNIT* decodeUnit); bool LiPeekNextVideoFrame(PDECODE_UNIT* decodeUnit); +void LiWakeWaitForVideoFrame(void); void LiCompleteVideoFrame(VIDEO_FRAME_HANDLE handle, int drStatus); #ifdef __cplusplus diff --git a/src/LinkedBlockingQueue.c b/src/LinkedBlockingQueue.c index 1551425..5d7f9a7 100644 --- a/src/LinkedBlockingQueue.c +++ b/src/LinkedBlockingQueue.c @@ -71,6 +71,13 @@ void LbqSignalQueueDrain(PLINKED_BLOCKING_QUEUE queueHead) { PltSignalConditionVariable(&queueHead->cond); } +void LbqSignalQueueUserWake(PLINKED_BLOCKING_QUEUE queueHead) { + PltLockMutex(&queueHead->mutex); + queueHead->pendingUserWake = true; + PltUnlockMutex(&queueHead->mutex); + PltSignalConditionVariable(&queueHead->cond); +} + int LbqGetItemCount(PLINKED_BLOCKING_QUEUE queueHead) { return queueHead->currentSize; } @@ -196,7 +203,7 @@ int LbqWaitForQueueElement(PLINKED_BLOCKING_QUEUE queueHead, void** data) { PltLockMutex(&queueHead->mutex); // Wait for a waking condition: either data available or rundown - while (queueHead->head == NULL && !queueHead->draining && !queueHead->shutdown) { + while (queueHead->head == NULL && !queueHead->draining && !queueHead->shutdown && !queueHead->pendingUserWake) { PltWaitForConditionVariable(&queueHead->cond, &queueHead->mutex); } @@ -206,6 +213,13 @@ int LbqWaitForQueueElement(PLINKED_BLOCKING_QUEUE queueHead, void** data) { return LBQ_INTERRUPTED; } + // If this is a user requested wake, process it now + if (queueHead->pendingUserWake) { + queueHead->pendingUserWake = false; + PltUnlockMutex(&queueHead->mutex); + return LBQ_USER_WAKE; + } + // If we're draining, only abort if we have no data available if (queueHead->draining && queueHead->head == NULL) { PltUnlockMutex(&queueHead->mutex); diff --git a/src/LinkedBlockingQueue.h b/src/LinkedBlockingQueue.h index 5f58802..426f43d 100644 --- a/src/LinkedBlockingQueue.h +++ b/src/LinkedBlockingQueue.h @@ -7,6 +7,7 @@ #define LBQ_INTERRUPTED 1 #define LBQ_BOUND_EXCEEDED 2 #define LBQ_NO_ELEMENT 3 +#define LBQ_USER_WAKE 4 typedef struct _LINKED_BLOCKING_QUEUE_ENTRY { struct _LINKED_BLOCKING_QUEUE_ENTRY* flink; @@ -24,6 +25,7 @@ typedef struct _LINKED_BLOCKING_QUEUE { int lifetimeSize; bool shutdown; bool draining; + bool pendingUserWake; } LINKED_BLOCKING_QUEUE, *PLINKED_BLOCKING_QUEUE; int LbqInitializeLinkedBlockingQueue(PLINKED_BLOCKING_QUEUE queueHead, int sizeBound); @@ -35,4 +37,5 @@ PLINKED_BLOCKING_QUEUE_ENTRY LbqDestroyLinkedBlockingQueue(PLINKED_BLOCKING_QUEU PLINKED_BLOCKING_QUEUE_ENTRY LbqFlushQueueItems(PLINKED_BLOCKING_QUEUE queueHead); void LbqSignalQueueShutdown(PLINKED_BLOCKING_QUEUE queueHead); void LbqSignalQueueDrain(PLINKED_BLOCKING_QUEUE queueHead); +void LbqSignalQueueUserWake(PLINKED_BLOCKING_QUEUE queueHead); int LbqGetItemCount(PLINKED_BLOCKING_QUEUE queueHead); diff --git a/src/VideoDepacketizer.c b/src/VideoDepacketizer.c index 36727cf..8087084 100644 --- a/src/VideoDepacketizer.c +++ b/src/VideoDepacketizer.c @@ -221,6 +221,10 @@ bool LiPeekNextVideoFrame(PDECODE_UNIT* decodeUnit) { return true; } +void LiWakeWaitForVideoFrame(void) { + LbqSignalQueueUserWake(&decodeUnitQueue); +} + // Cleanup a decode unit by freeing the buffer chain and the holder void LiCompleteVideoFrame(VIDEO_FRAME_HANDLE handle, int drStatus) { PQUEUED_DECODE_UNIT qdu = handle;