Skip to content

Instantly share code, notes, and snippets.

@zhuker
Created August 8, 2025 16:39
Show Gist options
  • Select an option

  • Save zhuker/a1ec1afba79cc31a93a9c2e71a8013a4 to your computer and use it in GitHub Desktop.

Select an option

Save zhuker/a1ec1afba79cc31a93a9c2e71a8013a4 to your computer and use it in GitHub Desktop.
simple h264 nal unit parser
#include <iostream>
#include <vector>
#include <cstdint>
#include <cstring>
bool isStartCode3(const uint8_t* p)
{
return p[0] == 0x00 && p[1] == 0x00 && p[2] == 0x01;
}
bool isStartCode4(const uint8_t* p)
{
return p[0] == 0x00 && p[1] == 0x00 && p[2] == 0x00 && p[3] == 0x01;
}
struct Nal
{
const uint8_t* buffer;
size_t size;
size_t startCodeLength;
};
// Returns a vector of pointers to NAL units (without start codes)
std::vector<Nal> parseNALUnits(const uint8_t* buffer, size_t size)
{
std::vector<Nal> nalUnits;
size_t i = 0;
while (i + 3 < size)
{
size_t start = 0, end = 0;
size_t startCodeLength = 0;
// Find the start code
if (isStartCode4(buffer + i))
{
start = i + 4;
startCodeLength = 4;
}
else if (isStartCode3(buffer + i))
{
start = i + 3;
startCodeLength = 3;
}
else
{
++i;
continue;
}
// Find the next start code
i = start;
while (i + 3 < size && !isStartCode3(buffer + i) && !isStartCode4(buffer + i))
{
++i;
}
end = i;
if (i + 3 >= size)
{
end = size;
}
Nal nal{buffer + start - startCodeLength, end - start + startCodeLength, startCodeLength};
nalUnits.emplace_back(nal);
}
return nalUnits;
}
static const char* nalUnitTypeString(uint8_t nalType)
{
switch (nalType)
{
case 1: return "non-IDR";
case 2: return "Coded slice data partition A";
case 3: return "Coded slice data partition B";
case 4: return "Coded slice data partition C";
case 5: return "IDR";
case 6: return "SEI";
case 7: return "SPS";
case 8: return "PPS";
default: return "Unknown";
}
}
int main(void) {
FILE* f = fopen("video.h264", "rb");
struct stat fileInfo{};
ASSERT_EQ(0, stat("video.h264", &fileInfo));
void* data = mmap(nullptr, fileInfo.st_size, PROT_READ, MAP_SHARED | MAP_NORESERVE, fileno(f), 0);
ASSERT_NE(MAP_FAILED, data);
auto nalUnits = parseNALUnits(static_cast<const uint8_t*>(data), fileInfo.st_size);
for (const auto& nal_unit : nalUnits)
{
printf("%lu\n", nal_unit.size);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment