mirror of
https://github.com/moonlight-stream/moonlight-common-c.git
synced 2025-08-18 01:15:46 +00:00
Update video code for GFE 2.1.1
This commit is contained in:
parent
1e4c65e7bb
commit
806f5f184a
@ -1,20 +1,24 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#define FLAG_CONTAINS_PIC_DATA 0x1
|
||||||
#define FLAG_EOF 0x2
|
#define FLAG_EOF 0x2
|
||||||
#define FLAG_SOF 0x4
|
#define FLAG_SOF 0x4
|
||||||
|
|
||||||
typedef struct _NV_VIDEO_PACKET {
|
typedef struct _NV_VIDEO_PACKET {
|
||||||
int frameIndex;
|
|
||||||
int packetIndex;
|
|
||||||
int totalPackets;
|
|
||||||
int flags;
|
|
||||||
int payloadLength;
|
|
||||||
int streamPacketIndex;
|
int streamPacketIndex;
|
||||||
char reserved2[32];
|
int frameIndex;
|
||||||
|
char flags;
|
||||||
|
char reserved[3];
|
||||||
|
int reserved2;
|
||||||
} NV_VIDEO_PACKET, *PNV_VIDEO_PACKET;
|
} NV_VIDEO_PACKET, *PNV_VIDEO_PACKET;
|
||||||
|
|
||||||
|
#define FLAG_EXTENSION 0x10
|
||||||
|
|
||||||
|
#define FIXED_RTP_HEADER_SIZE 12
|
||||||
|
#define MAX_RTP_HEADER_SIZE 16
|
||||||
|
|
||||||
typedef struct _RTP_PACKET {
|
typedef struct _RTP_PACKET {
|
||||||
char flags;
|
char header;
|
||||||
char packetType;
|
char packetType;
|
||||||
unsigned short sequenceNumber;
|
unsigned short sequenceNumber;
|
||||||
char reserved[8];
|
char reserved[8];
|
||||||
|
@ -5,17 +5,18 @@
|
|||||||
|
|
||||||
static PLENTRY nalChainHead;
|
static PLENTRY nalChainHead;
|
||||||
static int nalChainDataLength;
|
static int nalChainDataLength;
|
||||||
static int decodingAvc;
|
|
||||||
|
|
||||||
static int nextFrameNumber = 1;
|
static int nextFrameNumber = 1;
|
||||||
static int nextPacketNumber;
|
static int nextPacketNumber;
|
||||||
static int startFrameNumber = 1;
|
static int startFrameNumber = 1;
|
||||||
static int waitingForNextSuccessfulFrame;
|
static int waitingForNextSuccessfulFrame;
|
||||||
|
static int waitingForIdrFrame = 1;
|
||||||
static int gotNextFrameStart;
|
static int gotNextFrameStart;
|
||||||
static int lastPacketInStream = 0;
|
static int lastPacketInStream = 0;
|
||||||
|
static int decodingFrame = 0;
|
||||||
|
|
||||||
static LINKED_BLOCKING_QUEUE decodeUnitQueue;
|
static LINKED_BLOCKING_QUEUE decodeUnitQueue;
|
||||||
static int packetSize;
|
static unsigned int nominalPacketDataLength;
|
||||||
|
|
||||||
static unsigned short lastSequenceNumber;
|
static unsigned short lastSequenceNumber;
|
||||||
|
|
||||||
@ -27,10 +28,10 @@ typedef struct _BUFFER_DESC {
|
|||||||
|
|
||||||
void initializeVideoDepacketizer(int pktSize) {
|
void initializeVideoDepacketizer(int pktSize) {
|
||||||
LbqInitializeLinkedBlockingQueue(&decodeUnitQueue, 15);
|
LbqInitializeLinkedBlockingQueue(&decodeUnitQueue, 15);
|
||||||
packetSize = pktSize;
|
nominalPacketDataLength = pktSize - sizeof(NV_VIDEO_PACKET);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void clearAvcNalState(void) {
|
static void cleanupAvcFrameState(void) {
|
||||||
PLENTRY lastEntry;
|
PLENTRY lastEntry;
|
||||||
|
|
||||||
while (nalChainHead != NULL) {
|
while (nalChainHead != NULL) {
|
||||||
@ -43,6 +44,11 @@ static void clearAvcNalState(void) {
|
|||||||
nalChainDataLength = 0;
|
nalChainDataLength = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void dropAvcFrameState(void) {
|
||||||
|
waitingForIdrFrame = 1;
|
||||||
|
cleanupAvcFrameState();
|
||||||
|
}
|
||||||
|
|
||||||
void destroyVideoDepacketizer(void) {
|
void destroyVideoDepacketizer(void) {
|
||||||
PLINKED_BLOCKING_QUEUE_ENTRY entry, nextEntry;
|
PLINKED_BLOCKING_QUEUE_ENTRY entry, nextEntry;
|
||||||
|
|
||||||
@ -54,7 +60,7 @@ void destroyVideoDepacketizer(void) {
|
|||||||
entry = nextEntry;
|
entry = nextEntry;
|
||||||
}
|
}
|
||||||
|
|
||||||
clearAvcNalState();
|
cleanupAvcFrameState();
|
||||||
}
|
}
|
||||||
|
|
||||||
static int isSeqFrameStart(PBUFFER_DESC candidate) {
|
static int isSeqFrameStart(PBUFFER_DESC candidate) {
|
||||||
@ -105,7 +111,7 @@ static int getSpecialSeq(PBUFFER_DESC current, PBUFFER_DESC candidate) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void reassembleFrame(int frameNumber) {
|
static void reassembleAvcFrame(int frameNumber) {
|
||||||
if (nalChainHead != NULL) {
|
if (nalChainHead != NULL) {
|
||||||
PDECODE_UNIT du = (PDECODE_UNIT) malloc(sizeof(*du));
|
PDECODE_UNIT du = (PDECODE_UNIT) malloc(sizeof(*du));
|
||||||
if (du != NULL) {
|
if (du != NULL) {
|
||||||
@ -122,10 +128,12 @@ static void reassembleFrame(int frameNumber) {
|
|||||||
nalChainDataLength = du->fullLength;
|
nalChainDataLength = du->fullLength;
|
||||||
free(du);
|
free(du);
|
||||||
|
|
||||||
clearAvcNalState();
|
|
||||||
|
|
||||||
// FIXME: Get proper lower bound
|
// FIXME: Get proper lower bound
|
||||||
connectionSinkTooSlow(0, frameNumber);
|
connectionSinkTooSlow(0, frameNumber);
|
||||||
|
|
||||||
|
// Clear frame state and wait for an IDR
|
||||||
|
dropAvcFrameState();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Notify the control connection
|
// Notify the control connection
|
||||||
@ -157,7 +165,7 @@ void freeDecodeUnit(PDECODE_UNIT decodeUnit) {
|
|||||||
free(decodeUnit);
|
free(decodeUnit);
|
||||||
}
|
}
|
||||||
|
|
||||||
void queueFragment(char *data, int offset, int length) {
|
static void queueFragment(char *data, int offset, int length) {
|
||||||
PLENTRY entry = (PLENTRY) malloc(sizeof(*entry));
|
PLENTRY entry = (PLENTRY) malloc(sizeof(*entry));
|
||||||
if (entry != NULL) {
|
if (entry != NULL) {
|
||||||
entry->next = NULL;
|
entry->next = NULL;
|
||||||
@ -187,42 +195,60 @@ void queueFragment(char *data, int offset, int length) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void processRtpPayloadSlow(PNV_VIDEO_PACKET videoPacket, PBUFFER_DESC currentPos) {
|
static void processRtpPayloadSlow(PNV_VIDEO_PACKET videoPacket, PBUFFER_DESC currentPos) {
|
||||||
BUFFER_DESC specialSeq;
|
BUFFER_DESC specialSeq;
|
||||||
|
int decodingAvc = 0;
|
||||||
|
|
||||||
while (currentPos->length != 0) {
|
while (currentPos->length != 0) {
|
||||||
int start = currentPos->offset;
|
int start = currentPos->offset;
|
||||||
|
|
||||||
if (getSpecialSeq(currentPos, &specialSeq)) {
|
if (getSpecialSeq(currentPos, &specialSeq)) {
|
||||||
if (isSeqAvcStart(&specialSeq)) {
|
if (isSeqAvcStart(&specialSeq)) {
|
||||||
|
// Now we're decoding AVC
|
||||||
decodingAvc = 1;
|
decodingAvc = 1;
|
||||||
|
|
||||||
if (isSeqFrameStart(&specialSeq)) {
|
if (isSeqFrameStart(&specialSeq)) {
|
||||||
reassembleFrame(videoPacket->frameIndex);
|
// Now we're working on a frame
|
||||||
|
decodingFrame = 1;
|
||||||
|
|
||||||
|
// Reassemble any pending frame
|
||||||
|
reassembleAvcFrame(videoPacket->frameIndex);
|
||||||
|
|
||||||
|
if (specialSeq.data[specialSeq.offset + specialSeq.length] == 0x65) {
|
||||||
|
// This is the NALU code for I-frame data
|
||||||
|
waitingForIdrFrame = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Skip the start sequence
|
||||||
currentPos->length -= specialSeq.length;
|
currentPos->length -= specialSeq.length;
|
||||||
currentPos->offset += specialSeq.length;
|
currentPos->offset += specialSeq.length;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
// Check if this is padding after a full AVC frame
|
||||||
if (decodingAvc && isSeqPadding(currentPos)) {
|
if (decodingAvc && isSeqPadding(currentPos)) {
|
||||||
reassembleFrame(videoPacket->frameIndex);
|
reassembleAvcFrame(videoPacket->frameIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Not decoding AVC
|
||||||
decodingAvc = 0;
|
decodingAvc = 0;
|
||||||
|
|
||||||
|
// Just skip this byte
|
||||||
currentPos->length--;
|
currentPos->length--;
|
||||||
currentPos->offset++;
|
currentPos->offset++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Move to the next special sequence
|
||||||
while (currentPos->length != 0) {
|
while (currentPos->length != 0) {
|
||||||
|
// Check if this should end the current NAL
|
||||||
if (getSpecialSeq(currentPos, &specialSeq)) {
|
if (getSpecialSeq(currentPos, &specialSeq)) {
|
||||||
if (decodingAvc || !isSeqPadding(&specialSeq)) {
|
if (decodingAvc || !isSeqPadding(&specialSeq)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This byte is part of the NAL data
|
||||||
currentPos->offset++;
|
currentPos->offset++;
|
||||||
currentPos->length--;
|
currentPos->length--;
|
||||||
}
|
}
|
||||||
@ -233,156 +259,189 @@ void processRtpPayloadSlow(PNV_VIDEO_PACKET videoPacket, PBUFFER_DESC currentPos
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void processRtpPayloadFast(PNV_VIDEO_PACKET videoPacket, BUFFER_DESC location) {
|
static int isFirstPacket(char flags) {
|
||||||
|
// Clear the picture data flag
|
||||||
|
flags &= ~FLAG_CONTAINS_PIC_DATA;
|
||||||
|
|
||||||
|
// Check if it's just the start or both start and end of a frame
|
||||||
|
return (flags == (FLAG_SOF | FLAG_EOF) ||
|
||||||
|
flags == FLAG_SOF);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void processRtpPayloadFast(PNV_VIDEO_PACKET videoPacket, BUFFER_DESC location) {
|
||||||
queueFragment(location.data, location.offset, location.length);
|
queueFragment(location.data, location.offset, location.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int isBeforeSigned(int numA, int numB, int ambiguousCase) {
|
||||||
|
// This should be the common case for most callers
|
||||||
|
if (numA == numB) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If numA and numB have the same signs,
|
||||||
|
// we can just do a regular comparison.
|
||||||
|
if ((numA < 0 && numB < 0) || (numA >= 0 && numB >= 0)) {
|
||||||
|
return numA < numB;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// The sign switch is ambiguous
|
||||||
|
return ambiguousCase;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void processRtpPayload(PNV_VIDEO_PACKET videoPacket, int length) {
|
void processRtpPayload(PNV_VIDEO_PACKET videoPacket, int length) {
|
||||||
BUFFER_DESC currentPos, specialSeq;
|
BUFFER_DESC currentPos, specialSeq;
|
||||||
int isFirstPacket;
|
|
||||||
int streamPacketIndex;
|
// Mask the top 8 bits from the SPI
|
||||||
|
videoPacket->streamPacketIndex >>= 8;
|
||||||
|
videoPacket->streamPacketIndex &= 0xFFFFFF;
|
||||||
|
|
||||||
currentPos.data = (char*) (videoPacket + 1);
|
currentPos.data = (char*) (videoPacket + 1);
|
||||||
currentPos.offset = 0;
|
currentPos.offset = 0;
|
||||||
currentPos.length = length - sizeof(*videoPacket);
|
currentPos.length = length - sizeof(*videoPacket);
|
||||||
|
|
||||||
if (currentPos.length < packetSize - sizeof(NV_VIDEO_PACKET)) {
|
int frameIndex = videoPacket->frameIndex;
|
||||||
processRtpPayloadSlow(videoPacket, ¤tPos);
|
char flags = videoPacket->flags;
|
||||||
|
int firstPacket = isFirstPacket(flags);
|
||||||
|
|
||||||
|
// Drop duplicates or re-ordered packets
|
||||||
|
int streamPacketIndex = videoPacket->streamPacketIndex;
|
||||||
|
if (isBeforeSigned((short) streamPacketIndex, (short) (lastPacketInStream + 1), 0)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We can use FEC to correct single packet errors
|
// Drop packets from a previously completed frame
|
||||||
// on single packet frames because we just get a
|
if (isBeforeSigned(frameIndex, nextFrameNumber, 0)) {
|
||||||
// duplicate of the original packet
|
|
||||||
if (videoPacket->totalPackets == 1 &&
|
|
||||||
videoPacket->packetIndex == 1 &&
|
|
||||||
nextPacketNumber == 0 &&
|
|
||||||
videoPacket->frameIndex == nextFrameNumber) {
|
|
||||||
Limelog("Using FEC for error correction\n");
|
|
||||||
nextPacketNumber = 1;
|
|
||||||
}
|
|
||||||
// Discard the rest of the FEC data until we know how to use it
|
|
||||||
else if (videoPacket->packetIndex >= videoPacket->totalPackets) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that this is the next frame
|
// Look for a frame start before receiving a frame end
|
||||||
isFirstPacket = (videoPacket->flags & FLAG_SOF) != 0;
|
if (firstPacket && decodingFrame)
|
||||||
if (videoPacket->frameIndex > nextFrameNumber) {
|
{
|
||||||
// Nope, but we can still work with it if it's
|
Limelog("Network dropped end of a frame\n");
|
||||||
// the start of the next frame
|
nextFrameNumber = frameIndex;
|
||||||
if (isFirstPacket) {
|
|
||||||
Limelog("Got start of frame %d when expecting %d of frame %d\n",
|
|
||||||
videoPacket->frameIndex, nextPacketNumber, nextFrameNumber);
|
|
||||||
|
|
||||||
nextFrameNumber = videoPacket->frameIndex;
|
// Unexpected start of next frame before terminating the last
|
||||||
nextPacketNumber = 0;
|
waitingForNextSuccessfulFrame = 1;
|
||||||
clearAvcNalState();
|
waitingForIdrFrame = 1;
|
||||||
|
|
||||||
|
// Clear the old state and wait for an IDR
|
||||||
|
dropAvcFrameState();
|
||||||
|
}
|
||||||
|
// Look for a non-frame start before a frame start
|
||||||
|
else if (!firstPacket && !decodingFrame) {
|
||||||
|
// Check if this looks like a real frame
|
||||||
|
if (flags == FLAG_CONTAINS_PIC_DATA ||
|
||||||
|
flags == FLAG_EOF ||
|
||||||
|
currentPos.length < nominalPacketDataLength)
|
||||||
|
{
|
||||||
|
Limelog("Network dropped beginning of a frame");
|
||||||
|
nextFrameNumber = frameIndex + 1;
|
||||||
|
|
||||||
// Tell the encoder when we're done decoding this frame
|
|
||||||
// that we lost some previous frames
|
|
||||||
waitingForNextSuccessfulFrame = 1;
|
waitingForNextSuccessfulFrame = 1;
|
||||||
gotNextFrameStart = 0;
|
|
||||||
|
dropAvcFrameState();
|
||||||
|
decodingFrame = 0;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Limelog("Got packet %d of frame %d when expecting packet %d of frame %d\n",
|
// FEC data
|
||||||
videoPacket->packetIndex, videoPacket->frameIndex,
|
|
||||||
nextPacketNumber, nextFrameNumber);
|
|
||||||
|
|
||||||
// We dropped the start of this frame too
|
|
||||||
waitingForNextSuccessfulFrame = 1;
|
|
||||||
gotNextFrameStart = 0;
|
|
||||||
|
|
||||||
// Try to pickup on the next frame
|
|
||||||
nextFrameNumber = videoPacket->frameIndex + 1;
|
|
||||||
nextPacketNumber = 0;
|
|
||||||
clearAvcNalState();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (videoPacket->frameIndex < nextFrameNumber) {
|
// Check sequencing of this frame to ensure we didn't
|
||||||
Limelog("Frame %d is behind our current frame number %d\n",
|
// miss one in between
|
||||||
videoPacket->frameIndex, nextFrameNumber);
|
else if (firstPacket) {
|
||||||
return;
|
// Make sure this is the next consecutive frame
|
||||||
|
if (isBeforeSigned(nextFrameNumber, frameIndex, 1)) {
|
||||||
|
Limelog("Network dropped an entire frame");
|
||||||
|
nextFrameNumber = frameIndex;
|
||||||
|
|
||||||
|
// Wait until an IDR frame comes
|
||||||
|
waitingForNextSuccessfulFrame = 1;
|
||||||
|
dropAvcFrameState();
|
||||||
|
}
|
||||||
|
else if (nextFrameNumber != frameIndex) {
|
||||||
|
// Duplicate packet or FEC dup
|
||||||
|
decodingFrame = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We're now decoding a frame
|
||||||
|
decodingFrame = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We know it's the right frame, now check the packet number
|
// If it's not the first packet of a frame
|
||||||
if (videoPacket->packetIndex != nextPacketNumber) {
|
// we need to drop it if the stream packet index
|
||||||
Limelog("Frame %d: expected packet %d but got %d\n",
|
// doesn't match
|
||||||
videoPacket->frameIndex, nextPacketNumber, videoPacket->packetIndex);
|
if (!firstPacket && decodingFrame) {
|
||||||
|
if (streamPacketIndex != (int) (lastPacketInStream + 1)) {
|
||||||
|
Limelog("Network dropped middle of a frame");
|
||||||
|
nextFrameNumber = frameIndex + 1;
|
||||||
|
|
||||||
// At this point, we're guaranteed that it's not FEC data that we lost
|
waitingForNextSuccessfulFrame = 1;
|
||||||
waitingForNextSuccessfulFrame = 1;
|
|
||||||
gotNextFrameStart = 0;
|
|
||||||
|
|
||||||
// Skip this frame
|
dropAvcFrameState();
|
||||||
nextFrameNumber++;
|
decodingFrame = 0;
|
||||||
nextPacketNumber = 0;
|
|
||||||
clearAvcNalState();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (waitingForNextSuccessfulFrame) {
|
return;
|
||||||
if (!gotNextFrameStart) {
|
|
||||||
if (!isFirstPacket) {
|
|
||||||
// We're waiting for the next frame, but this one is a fragment of a frame
|
|
||||||
// so we must discard it and wait for the next one
|
|
||||||
Limelog("Expected start of frame %d\n", videoPacket->frameIndex);
|
|
||||||
|
|
||||||
nextFrameNumber = videoPacket->frameIndex;
|
|
||||||
nextPacketNumber = 0;
|
|
||||||
clearAvcNalState();
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
gotNextFrameStart = 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
streamPacketIndex = videoPacket->streamPacketIndex;
|
// Notify the server of any packet losses
|
||||||
if (streamPacketIndex != (int) (lastPacketInStream + 1)) {
|
if (streamPacketIndex != (int) (lastPacketInStream + 1)) {
|
||||||
// Packets were lost so report this to the server
|
// Packets were lost so report this to the server
|
||||||
connectionLostPackets(lastPacketInStream, streamPacketIndex);
|
connectionLostPackets(lastPacketInStream, streamPacketIndex);
|
||||||
}
|
}
|
||||||
lastPacketInStream = streamPacketIndex;
|
lastPacketInStream = streamPacketIndex;
|
||||||
|
|
||||||
nextPacketNumber++;
|
if (isFirstPacket &&
|
||||||
|
getSpecialSeq(¤tPos, &specialSeq) &&
|
||||||
// Remove extra padding
|
isSeqFrameStart(&specialSeq) &&
|
||||||
currentPos.length = videoPacket->payloadLength;
|
specialSeq.data[specialSeq.offset + specialSeq.length] == 0x67)
|
||||||
|
{
|
||||||
/*if (isFirstPacket) {
|
// SPS and PPS prefix is padded between NALs, so we must decode it with the slow path
|
||||||
if (getSpecialSeq(¤tPos, &specialSeq) &&
|
processRtpPayloadSlow(videoPacket, ¤tPos);
|
||||||
isSeqFrameStart(&specialSeq) &&
|
}
|
||||||
specialSeq.data[specialSeq.offset+specialSeq.length] == 0x67) {
|
else
|
||||||
// SPS and PPS prefix is padded between NALs, so we must decode it with the slow path
|
{
|
||||||
clearAvcNalState();
|
processRtpPayloadFast(videoPacket, currentPos);
|
||||||
processRtpPayloadSlow(videoPacket, ¤tPos);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
|
|
||||||
processRtpPayloadFast(videoPacket, currentPos);
|
|
||||||
|
|
||||||
// We can't use the EOF flag here because real frames can be split across
|
|
||||||
// multiple "frames" when packetized to fit under the bandwidth ceiling
|
|
||||||
if (videoPacket->packetIndex + 1 >= videoPacket->totalPackets) {
|
|
||||||
nextFrameNumber++;
|
|
||||||
nextPacketNumber = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (videoPacket->flags & FLAG_EOF) {
|
if (flags & FLAG_EOF) {
|
||||||
reassembleFrame(videoPacket->frameIndex);
|
// Move on to the next frame
|
||||||
|
decodingFrame = 0;
|
||||||
|
nextFrameNumber = frameIndex + 1;
|
||||||
|
|
||||||
|
// If waiting for next successful frame and we got here
|
||||||
|
// 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, nextFrameNumber - 1);
|
connectionDetectedFrameLoss(startFrameNumber, nextFrameNumber - 1);
|
||||||
waitingForNextSuccessfulFrame = 0;
|
waitingForNextSuccessfulFrame = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If we need an IDR frame first, then drop this frame
|
||||||
|
if (waitingForIdrFrame) {
|
||||||
|
Limelog("Waiting for IDR frame");
|
||||||
|
|
||||||
|
dropAvcFrameState();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
reassembleAvcFrame(frameIndex);
|
||||||
|
|
||||||
startFrameNumber = nextFrameNumber;
|
startFrameNumber = nextFrameNumber;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void queueRtpPacket(PRTP_PACKET rtpPacket, int length) {
|
void queueRtpPacket(PRTP_PACKET rtpPacket, int length) {
|
||||||
processRtpPayload((PNV_VIDEO_PACKET) (rtpPacket + 1), length - sizeof(*rtpPacket));
|
int dataOffset;
|
||||||
|
|
||||||
|
dataOffset = sizeof(*rtpPacket);
|
||||||
|
if (rtpPacket->header & FLAG_EXTENSION) {
|
||||||
|
dataOffset += 4; // 2 additional fields
|
||||||
|
}
|
||||||
|
|
||||||
|
processRtpPayload((PNV_VIDEO_PACKET)(((char*)rtpPacket) + dataOffset), length - dataOffset);
|
||||||
}
|
}
|
||||||
|
@ -63,7 +63,7 @@ static void ReceiveThreadProc(void* context) {
|
|||||||
int bufferSize;
|
int bufferSize;
|
||||||
char* buffer;
|
char* buffer;
|
||||||
|
|
||||||
bufferSize = configuration.packetSize + sizeof(RTP_PACKET);
|
bufferSize = configuration.packetSize + MAX_RTP_HEADER_SIZE;
|
||||||
buffer = (char*)malloc(bufferSize);
|
buffer = (char*)malloc(bufferSize);
|
||||||
if (buffer == NULL) {
|
if (buffer == NULL) {
|
||||||
Limelog("Receive thread terminating\n");
|
Limelog("Receive thread terminating\n");
|
||||||
|
Loading…
x
Reference in New Issue
Block a user