Add presentation timestamp to video frame metadata

This commit is contained in:
Cameron Gutman
2019-11-10 18:07:11 -08:00
parent eceb7d3a2b
commit f4dad9ae8b
7 changed files with 27 additions and 4 deletions
+3 -1
View File
@@ -218,8 +218,10 @@ static void ReceiveThreadProc(void* context) {
continue; continue;
} }
// RTP sequence number must be in host order for the RTP queue // Convert fields to host byte-order
rtp->sequenceNumber = htons(rtp->sequenceNumber); rtp->sequenceNumber = htons(rtp->sequenceNumber);
rtp->timestamp = htonl(rtp->timestamp);
rtp->ssrc = htonl(rtp->ssrc);
queueStatus = RtpqAddPacket(&rtpReorderQueue, (PRTP_PACKET)packet, &packet->q.rentry); queueStatus = RtpqAddPacket(&rtpReorderQueue, (PRTP_PACKET)packet, &packet->q.rentry);
if (RTPQ_HANDLE_NOW(queueStatus)) { if (RTPQ_HANDLE_NOW(queueStatus)) {
+5
View File
@@ -122,6 +122,11 @@ typedef struct _DECODE_UNIT {
// shares the same epoch as this value. // shares the same epoch as this value.
unsigned long long receiveTimeMs; unsigned long long receiveTimeMs;
// Presentation time in milliseconds with the epoch at the first captured frame.
// This can be used to aid frame pacing or to drop old frames that were queued too
// long prior to display.
unsigned int presentationTimeMs;
// Length of the entire buffer chain in bytes // Length of the entire buffer chain in bytes
int fullLength; int fullLength;
+5
View File
@@ -47,6 +47,9 @@ static int queuePacket(PRTP_FEC_QUEUE queue, PRTPFEC_QUEUE_ENTRY newEntry, int h
newEntry->prev = NULL; newEntry->prev = NULL;
newEntry->next = NULL; newEntry->next = NULL;
// 90 KHz video clock
newEntry->presentationTimeMs = packet->timestamp / 90;
if (queue->bufferHead == NULL) { if (queue->bufferHead == NULL) {
LC_ASSERT(queue->bufferSize == 0); LC_ASSERT(queue->bufferSize == 0);
queue->bufferHead = queue->bufferTail = newEntry; queue->bufferHead = queue->bufferTail = newEntry;
@@ -158,6 +161,8 @@ cleanup_packets:
PRTP_PACKET rtpPacket = (PRTP_PACKET) packets[i]; PRTP_PACKET rtpPacket = (PRTP_PACKET) packets[i];
rtpPacket->sequenceNumber = U16(i + queue->bufferLowestSequenceNumber); rtpPacket->sequenceNumber = U16(i + queue->bufferLowestSequenceNumber);
rtpPacket->header = queue->bufferHead->packet->header; rtpPacket->header = queue->bufferHead->packet->header;
rtpPacket->timestamp = queue->bufferHead->packet->timestamp;
rtpPacket->ssrc = queue->bufferHead->packet->ssrc;
int dataOffset = sizeof(*rtpPacket); int dataOffset = sizeof(*rtpPacket);
if (rtpPacket->header & FLAG_EXTENSION) { if (rtpPacket->header & FLAG_EXTENSION) {
+1
View File
@@ -7,6 +7,7 @@ typedef struct _RTPFEC_QUEUE_ENTRY {
int length; int length;
int isParity; int isParity;
unsigned long long receiveTimeMs; unsigned long long receiveTimeMs;
unsigned int presentationTimeMs;
struct _RTPFEC_QUEUE_ENTRY* next; struct _RTPFEC_QUEUE_ENTRY* next;
struct _RTPFEC_QUEUE_ENTRY* prev; struct _RTPFEC_QUEUE_ENTRY* prev;
+2 -1
View File
@@ -33,7 +33,8 @@ typedef struct _RTP_PACKET {
char header; char header;
char packetType; char packetType;
unsigned short sequenceNumber; unsigned short sequenceNumber;
char reserved[8]; unsigned int timestamp;
unsigned int ssrc;
} RTP_PACKET, *PRTP_PACKET; } RTP_PACKET, *PRTP_PACKET;
#pragma pack(pop) #pragma pack(pop)
+8 -1
View File
@@ -15,6 +15,7 @@ static unsigned int lastPacketInStream;
static int decodingFrame; static int decodingFrame;
static int strictIdrFrameWait; static int strictIdrFrameWait;
static unsigned long long firstPacketReceiveTime; static unsigned long long firstPacketReceiveTime;
static unsigned int firstPacketPresentationTime;
static int dropStatePending; static int dropStatePending;
static int idrFrameProcessed; static int idrFrameProcessed;
@@ -47,6 +48,7 @@ void initializeVideoDepacketizer(int pktSize) {
lastPacketInStream = UINT32_MAX; lastPacketInStream = UINT32_MAX;
decodingFrame = 0; decodingFrame = 0;
firstPacketReceiveTime = 0; firstPacketReceiveTime = 0;
firstPacketPresentationTime = 0;
dropStatePending = 0; dropStatePending = 0;
idrFrameProcessed = 0; idrFrameProcessed = 0;
strictIdrFrameWait = !isReferenceFrameInvalidationEnabled(); strictIdrFrameWait = !isReferenceFrameInvalidationEnabled();
@@ -261,6 +263,7 @@ static void reassembleFrame(int frameNumber) {
qdu->decodeUnit.fullLength = nalChainDataLength; qdu->decodeUnit.fullLength = nalChainDataLength;
qdu->decodeUnit.frameNumber = frameNumber; qdu->decodeUnit.frameNumber = frameNumber;
qdu->decodeUnit.receiveTimeMs = firstPacketReceiveTime; qdu->decodeUnit.receiveTimeMs = firstPacketReceiveTime;
qdu->decodeUnit.presentationTimeMs = firstPacketPresentationTime;
// IDR frames will have leading CSD buffers // IDR frames will have leading CSD buffers
if (nalChainHead->bufferType != BUFFER_TYPE_PICDATA) { if (nalChainHead->bufferType != BUFFER_TYPE_PICDATA) {
@@ -497,7 +500,9 @@ static int isFirstPacket(char flags) {
// Process an RTP Payload // Process an RTP Payload
// The caller will free *existingEntry unless we NULL it // The caller will free *existingEntry unless we NULL it
void processRtpPayload(PNV_VIDEO_PACKET videoPacket, int length, unsigned long long receiveTimeMs, PLENTRY_INTERNAL* existingEntry) { void processRtpPayload(PNV_VIDEO_PACKET videoPacket, int length,
unsigned long long receiveTimeMs, unsigned int presentationTimeMs,
PLENTRY_INTERNAL* existingEntry) {
BUFFER_DESC currentPos; BUFFER_DESC currentPos;
int frameIndex; int frameIndex;
char flags; char flags;
@@ -563,6 +568,7 @@ void processRtpPayload(PNV_VIDEO_PACKET videoPacket, int length, unsigned long l
// We're now decoding a frame // We're now decoding a frame
decodingFrame = 1; decodingFrame = 1;
firstPacketReceiveTime = receiveTimeMs; firstPacketReceiveTime = receiveTimeMs;
firstPacketPresentationTime = presentationTimeMs;
} }
lastPacketInStream = streamPacketIndex; lastPacketInStream = streamPacketIndex;
@@ -694,6 +700,7 @@ void queueRtpPacket(PRTPFEC_QUEUE_ENTRY queueEntryPtr) {
processRtpPayload((PNV_VIDEO_PACKET)(((char*)queueEntry.packet) + dataOffset), processRtpPayload((PNV_VIDEO_PACKET)(((char*)queueEntry.packet) + dataOffset),
queueEntry.length - dataOffset, queueEntry.length - dataOffset,
queueEntry.receiveTimeMs, queueEntry.receiveTimeMs,
queueEntry.presentationTimeMs,
&existingEntry); &existingEntry);
if (existingEntry != NULL) { if (existingEntry != NULL) {
+3 -1
View File
@@ -116,9 +116,11 @@ static void ReceiveThreadProc(void* context) {
// as quickly, since we're now just keeping the NAT session open. // as quickly, since we're now just keeping the NAT session open.
receivedDataFromPeer = 1; receivedDataFromPeer = 1;
// RTP sequence number must be in host order for the RTP queue // Convert fields to host byte-order
packet = (PRTP_PACKET)&buffer[0]; packet = (PRTP_PACKET)&buffer[0];
packet->sequenceNumber = htons(packet->sequenceNumber); packet->sequenceNumber = htons(packet->sequenceNumber);
packet->timestamp = htonl(packet->timestamp);
packet->ssrc = htonl(packet->ssrc);
queueStatus = RtpfAddPacket(&rtpQueue, packet, err, (PRTPFEC_QUEUE_ENTRY)&buffer[receiveSize]); queueStatus = RtpfAddPacket(&rtpQueue, packet, err, (PRTPFEC_QUEUE_ENTRY)&buffer[receiveSize]);