mirror of
https://github.com/moonlight-stream/moonlight-common-c.git
synced 2026-04-18 06:10:06 +00:00
More fixes and work on video
This commit is contained in:
@@ -1,9 +1,223 @@
|
||||
#include "Platform.h"
|
||||
#include "Limelight.h"
|
||||
#include "LinkedBlockingQueue.h"
|
||||
#include "Video.h"
|
||||
|
||||
LENTRY *nalChainHead;
|
||||
PLENTRY nalChainHead;
|
||||
int nalChainDataLength;
|
||||
int decodingAvc;
|
||||
|
||||
LINKED_BLOCKING_QUEUE decodeUnitQueue;
|
||||
LINKED_BLOCKING_QUEUE decodeUnitQueue;
|
||||
|
||||
unsigned short lastSequenceNumber;
|
||||
|
||||
typedef struct _BUFFER_DESC {
|
||||
char* data;
|
||||
int offset;
|
||||
int length;
|
||||
} BUFFER_DESC, *PBUFFER_DESC;
|
||||
|
||||
void initializeVideoDepacketizer(void) {
|
||||
initializeLinkedBlockingQueue(&decodeUnitQueue, 15);
|
||||
}
|
||||
|
||||
static void clearAvcNalState(void) {
|
||||
PLENTRY lastEntry;
|
||||
|
||||
while (nalChainHead != NULL) {
|
||||
lastEntry = nalChainHead;
|
||||
nalChainHead = lastEntry->next;
|
||||
free(lastEntry->data);
|
||||
free(lastEntry);
|
||||
}
|
||||
|
||||
nalChainDataLength = 0;
|
||||
}
|
||||
|
||||
static int isSeqFrameStart(PBUFFER_DESC candidate) {
|
||||
return (candidate->length == 4 && candidate->data[candidate->offset + candidate->length - 1] == 1);
|
||||
}
|
||||
|
||||
static int isSeqAvcStart(PBUFFER_DESC candidate) {
|
||||
return (candidate->data[candidate->offset + candidate->length - 1] == 1);
|
||||
}
|
||||
|
||||
static int isSeqPadding(PBUFFER_DESC candidate) {
|
||||
return (candidate->data[candidate->offset + candidate->length - 1] == 0);
|
||||
}
|
||||
|
||||
static int getSpecialSeq(PBUFFER_DESC current, PBUFFER_DESC candidate) {
|
||||
if (current->length < 3) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (current->data[current->offset] == 0 &&
|
||||
current->data[current->offset + 1] == 0) {
|
||||
// Padding or frame start
|
||||
if (current->data[current->offset + 2] == 0) {
|
||||
if (current->length >= 4 && current->data[current->offset + 3] == 1) {
|
||||
// Frame start
|
||||
candidate->data = current->data;
|
||||
candidate->offset = current->offset;
|
||||
candidate->length = 4;
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
// Padding
|
||||
candidate->data = current->data;
|
||||
candidate->offset = current->offset;
|
||||
candidate->length = 3;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else if (current->data[current->offset + 2] == 1) {
|
||||
// NAL start
|
||||
candidate->data = current->data;
|
||||
candidate->offset = current->offset;
|
||||
candidate->length = 3;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void reassembleFrame(void) {
|
||||
if (nalChainHead != NULL) {
|
||||
PDECODE_UNIT du = (PDECODE_UNIT) malloc(sizeof(*du));
|
||||
if (du != NULL) {
|
||||
du->bufferList = nalChainHead;
|
||||
du->fullLength = nalChainDataLength;
|
||||
|
||||
nalChainHead = NULL;
|
||||
nalChainDataLength = 0;
|
||||
|
||||
if (!offerQueueItem(&decodeUnitQueue, du)) {
|
||||
nalChainHead = du->bufferList;
|
||||
nalChainDataLength = du->fullLength;
|
||||
free(du);
|
||||
|
||||
clearAvcNalState();
|
||||
|
||||
// FIXME: IDR frame!!!
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PDECODE_UNIT getNextDecodeUnit(void) {
|
||||
return (PDECODE_UNIT) waitForQueueElement(&decodeUnitQueue);
|
||||
}
|
||||
|
||||
void freeDecodeUnit(PDECODE_UNIT decodeUnit) {
|
||||
PLENTRY lastEntry;
|
||||
|
||||
while (decodeUnit->bufferList != NULL) {
|
||||
lastEntry = decodeUnit->bufferList;
|
||||
decodeUnit->bufferList = lastEntry->next;
|
||||
free(lastEntry->data);
|
||||
free(lastEntry);
|
||||
}
|
||||
|
||||
free(decodeUnit);
|
||||
}
|
||||
|
||||
void processRtpPayload(PNV_VIDEO_PACKET videoPacket, int length) {
|
||||
BUFFER_DESC currentPos, specialSeq;
|
||||
|
||||
currentPos.data = (char*) (videoPacket + 1);
|
||||
currentPos.offset = 0;
|
||||
currentPos.length = length;
|
||||
|
||||
if (currentPos.length == 968) {
|
||||
if (videoPacket->packetIndex < videoPacket->totalPackets) {
|
||||
currentPos.length = videoPacket->payloadLength;
|
||||
}
|
||||
else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
while (currentPos.length != 0) {
|
||||
int start = currentPos.offset;
|
||||
|
||||
if (getSpecialSeq(¤tPos, &specialSeq)) {
|
||||
if (isSeqAvcStart(&specialSeq)) {
|
||||
if (isSeqFrameStart(&specialSeq)) {
|
||||
decodingAvc = 1;
|
||||
|
||||
reassembleFrame();
|
||||
}
|
||||
|
||||
currentPos.length -= specialSeq.length;
|
||||
currentPos.offset += specialSeq.length;
|
||||
}
|
||||
else {
|
||||
if (decodingAvc && isSeqPadding(¤tPos)) {
|
||||
reassembleFrame();
|
||||
}
|
||||
|
||||
decodingAvc = 0;
|
||||
|
||||
currentPos.length--;
|
||||
currentPos.offset++;
|
||||
}
|
||||
}
|
||||
|
||||
while (currentPos.length != 0) {
|
||||
if (getSpecialSeq(¤tPos, &specialSeq)) {
|
||||
if (decodingAvc || isSeqPadding(&specialSeq)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
currentPos.offset++;
|
||||
currentPos.length--;
|
||||
}
|
||||
|
||||
if (decodingAvc) {
|
||||
PLENTRY entry = (PLENTRY) malloc(sizeof(*entry));
|
||||
if (entry != NULL) {
|
||||
entry->length = currentPos.offset - start;
|
||||
entry->data = (char*) malloc(entry->length);
|
||||
if (entry->data == NULL) {
|
||||
free(entry);
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(entry->data, ¤tPos.data[start], entry->length);
|
||||
|
||||
nalChainDataLength += entry->length;
|
||||
|
||||
if (nalChainHead == NULL) {
|
||||
nalChainHead = entry;
|
||||
}
|
||||
else {
|
||||
PLENTRY currentEntry = nalChainHead;
|
||||
|
||||
while (currentEntry->next != NULL) {
|
||||
currentEntry = currentEntry->next;
|
||||
}
|
||||
|
||||
currentEntry->next = entry;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void queueRtpPacket(PRTP_PACKET rtpPacket, int length) {
|
||||
if (lastSequenceNumber != 0 &&
|
||||
(unsigned short) (lastSequenceNumber + 1) != rtpPacket->sequenceNumber) {
|
||||
Limelog("Received OOS video data (expected %d, but got %d)\n", lastSequenceNumber + 1, rtpPacket->sequenceNumber);
|
||||
|
||||
clearAvcNalState();
|
||||
|
||||
// FIXME: IDR frame here!!!
|
||||
}
|
||||
|
||||
lastSequenceNumber = rtpPacket->sequenceNumber;
|
||||
|
||||
processRtpPayload((PNV_VIDEO_PACKET) (rtpPacket + 1), length - sizeof(*rtpPacket));
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user