Skip to content

Commit be37d3a

Browse files
committed
Rework NAL filtering
1 parent 38eae73 commit be37d3a

File tree

1 file changed

+79
-49
lines changed

1 file changed

+79
-49
lines changed

alvr/server/cpp/alvr_server/ClientConnection.cpp

+79-49
Original file line numberDiff line numberDiff line change
@@ -8,65 +8,95 @@
88
#include "Utils.h"
99
#include "Settings.h"
1010

11-
static const uint8_t NAL_TYPE_SPS = 7;
11+
static const uint8_t H264_NAL_TYPE_SPS = 7;
1212
static const uint8_t H265_NAL_TYPE_VPS = 32;
1313

14-
ClientConnection::ClientConnection() {
15-
m_Statistics = std::make_shared<Statistics>();
14+
static const uint8_t H264_NAL_TYPE_AUD = 9;
15+
static const uint8_t H265_NAL_TYPE_AUD = 35;
16+
17+
ClientConnection::ClientConnection() {
18+
m_Statistics = std::make_shared<Statistics>();
1619
}
1720

18-
int findVPSSPS(const uint8_t *frameBuffer, int frameByteSize) {
19-
int zeroes = 0;
20-
int foundNals = 0;
21-
for (int i = 0; i < frameByteSize; i++) {
22-
if (frameBuffer[i] == 0) {
23-
zeroes++;
24-
} else if (frameBuffer[i] == 1) {
25-
if (zeroes >= 2) {
26-
foundNals++;
27-
if (Settings::Instance().m_codec == ALVR_CODEC_H264 && foundNals >= 3) {
28-
// Find end of SPS+PPS on H.264.
29-
return i - 3;
30-
} else if (Settings::Instance().m_codec == ALVR_CODEC_H265 && foundNals >= 4) {
31-
// Find end of VPS+SPS+PPS on H.264.
32-
return i - 3;
33-
}
34-
}
35-
zeroes = 0;
36-
} else {
37-
zeroes = 0;
38-
}
39-
}
40-
return -1;
21+
/*
22+
Extracts the (VPS + )SPS + PPS video configuration headers from H.264 or H.265 stream as a sequence of NALs.
23+
(VPS + )SPS + PPS have short size (8bytes + 28bytes in some environment), so we can
24+
assume SPS + PPS is contained in first fragment.
25+
*/
26+
void extractHeaders(uint8_t **buf, int *len, int nalNum) {
27+
static const char NAL_HEADER[] = {0x00, 0x00, 0x00, 0x01};
28+
29+
uint8_t *b = *buf;
30+
uint8_t *end = b + *len;
31+
32+
int headersLen = 0;
33+
int foundHeaders = -1; // Offset by 1 header to find the length until the next header
34+
while (b != end) {
35+
if (b[0] == 0 && memcmp(b, NAL_HEADER, sizeof(NAL_HEADER)) == 0) {
36+
foundHeaders++;
37+
if (foundHeaders == nalNum) {
38+
break;
39+
}
40+
b += sizeof(NAL_HEADER);
41+
headersLen += sizeof(NAL_HEADER);
42+
}
43+
44+
b++;
45+
headersLen++;
46+
}
47+
if (headersLen == 0 || foundHeaders != nalNum) {
48+
return;
49+
}
50+
InitializeDecoder((const unsigned char *)b, headersLen);
51+
52+
// move the cursor forward excluding config NALs
53+
*buf = b;
54+
*len -= headersLen;
55+
}
56+
57+
void processH264Nals(uint8_t **buf, int *len) {
58+
uint8_t *b = *buf;
59+
int l = *len;
60+
uint8_t nalType = b[4] & 0x1F;
61+
62+
if (nalType == H264_NAL_TYPE_AUD) {
63+
b += 6;
64+
l -= 6;
65+
nalType = b[4] & 0x1F;
66+
}
67+
if (nalType == H264_NAL_TYPE_SPS) {
68+
extractHeaders(buf, len, 2); // 2 headers SPS and PPS
69+
}
70+
*buf = b;
71+
*len = l;
72+
}
73+
74+
void processH265Nals(uint8_t **buf, int *len) {
75+
uint8_t *b = *buf;
76+
int l = *len;
77+
uint8_t nalType = (b[4] >> 1) & 0x3F;
78+
79+
if (nalType == H265_NAL_TYPE_AUD) {
80+
b += 7;
81+
l -= 7;
82+
nalType = (b[4] >> 1) & 0x3F;
83+
}
84+
if (nalType == H265_NAL_TYPE_VPS) {
85+
extractHeaders(buf, len, 3); // 3 headers VPS, SPS and PPS
86+
}
87+
*buf = b;
88+
*len = l;
4189
}
4290

4391
void ClientConnection::SendVideo(uint8_t *buf, int len, uint64_t targetTimestampNs) {
4492
// Report before the frame is packetized
4593
ReportEncoded(targetTimestampNs);
4694

47-
uint8_t NALType;
48-
if (Settings::Instance().m_codec == ALVR_CODEC_H264)
49-
NALType = buf[4] & 0x1F;
50-
else
51-
NALType = (buf[4] >> 1) & 0x3F;
52-
53-
if ((Settings::Instance().m_codec == ALVR_CODEC_H264 && NALType == NAL_TYPE_SPS) ||
54-
(Settings::Instance().m_codec == ALVR_CODEC_H265 && NALType == H265_NAL_TYPE_VPS)) {
55-
// This frame contains (VPS + )SPS + PPS + IDR on NVENC H.264 (H.265) stream.
56-
// (VPS + )SPS + PPS has short size (8bytes + 28bytes in some environment), so we can
57-
// assume SPS + PPS is contained in first fragment.
58-
59-
int end = findVPSSPS(buf, len);
60-
if (end == -1) {
61-
// Invalid frame.
62-
return;
63-
}
64-
65-
InitializeDecoder((const unsigned char *)buf, end);
66-
67-
// move the cursor forward excluding config NALs
68-
buf = &buf[end];
69-
len = len - end;
95+
int codec = Settings::Instance().m_codec;
96+
if (codec == ALVR_CODEC_H264) {
97+
processH264Nals(&buf, &len);
98+
} else if (codec == ALVR_CODEC_H265) {
99+
processH265Nals(&buf, &len);
70100
}
71101

72102
VideoSend(targetTimestampNs, buf, len);

0 commit comments

Comments
 (0)