Add presentation timestamp to video frame metadata
This commit is contained in:
parent
eceb7d3a2b
commit
f4dad9ae8b
7 changed files with 27 additions and 4 deletions
|
|
@ -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)) {
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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) {
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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) {
|
||||||
|
|
|
||||||
|
|
@ -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]);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue