Skip to content

Media Metadata Inspector — C++ source

Inspect audio, video and image files at the byte level — MP4 boxes, ID3 tags, WAV chunks, GIF headers — parsed by our own readers, entirely in your browser.

This is the C++ implementation — the same logic the interactive tool runs, in a shareable, citable form.

// Media Metadata Inspector — read container metadata straight from the bytes.
//
// Language: C++ (C++20), standard library only
// CosmoDev polyglot showcase port of the `media-metadata-inspector` tool.
// Ported from src/lib/media-meta.ts — display source, part of CosmoDev's
// polyglot tool pages.
//
// Sniffs the container signature (MP4 "ftyp" box, "ID3", RIFF/WAVE, GIF8,
// WebM EBML magic), then walks that container for duration, dimensions, and
// ID3 tags. Deterministic; probe() returns kind="unknown" for inputs too
// short for a signature — never throws.

#include <algorithm>
#include <cstdint>
#include <cstring>
#include <optional>
#include <string>
#include <string_view>
#include <vector>

enum class Kind { mp4, mp3, wav, gif, webm, unknown };

struct MediaMeta {
  Kind kind = Kind::unknown;
  std::optional<double> durationSec;
  std::optional<double> width, height;
  std::optional<std::string> title, artist, album;
};

namespace {

uint16_t u16be(const uint8_t* b, size_t o) {
  return static_cast<uint16_t>((b[o] << 8) | b[o + 1]);
}
uint16_t u16le(const uint8_t* b, size_t o) {
  return static_cast<uint16_t>(b[o] | (b[o + 1] << 8));
}
uint32_t u32be(const uint8_t* b, size_t o) {
  return (static_cast<uint32_t>(b[o]) << 24) | (static_cast<uint32_t>(b[o + 1]) << 16) |
         (static_cast<uint32_t>(b[o + 2]) << 8) | b[o + 3];
}
uint32_t u32le(const uint8_t* b, size_t o) {
  return uint32_t(b[o]) | (uint32_t(b[o + 1]) << 8) | (uint32_t(b[o + 2]) << 16) |
         (uint32_t(b[o + 3]) << 24);
}
std::string ascii(const uint8_t* b, size_t start, size_t len) {
  return {reinterpret_cast<const char*>(b + start), len};
}

struct Box { std::string type; size_t start, end; };

// MP4 box walk: payload ranges for every box of the wanted types.
// 64-bit sizes (size==1) are unsupported — stop safely, like the TS lib.
std::vector<Box> findBoxes(const uint8_t* b, size_t pos, size_t end,
                           std::initializer_list<std::string_view> wanted) {
  std::vector<Box> found;
  while (pos + 8 <= end) {
    uint32_t size = u32be(b, pos);
    if (size == 1) return found;
    if (size == 0) size = static_cast<uint32_t>(end - pos);  // extends to end
    if (size < 8 || pos + size > end) return found;
    std::string type = ascii(b, pos + 4, 4);
    for (auto w : wanted)
      if (type == w) found.push_back({type, pos + 8, pos + size});
    pos += size;
  }
  return found;
}

void probeMp4(const uint8_t* b, size_t len, MediaMeta& m) {
  m.kind = Kind::mp4;
  for (const auto& moov : findBoxes(b, 0, len, {"moov"})) {
    for (const auto& mvhd : findBoxes(b, moov.start, moov.end, {"mvhd"})) {
      uint8_t version = b[mvhd.start];
      if (version == 0 && mvhd.end - mvhd.start >= 20) {
        uint32_t timescale = u32be(b, mvhd.start + 12);
        uint32_t duration = u32be(b, mvhd.start + 16);
        if (timescale > 0) m.durationSec = double(duration) / timescale;
      } else if (version == 1 && mvhd.end - mvhd.start >= 32) {
        uint32_t timescale = u32be(b, mvhd.start + 20);
        // 64-bit duration as two 32-bit halves — no __int128 needed.
        double duration = double(u32be(b, mvhd.start + 24)) * 4294967296.0 +
                          double(u32be(b, mvhd.start + 28));
        if (timescale > 0) m.durationSec = duration / timescale;
      }
    }
    for (const auto& trak : findBoxes(b, moov.start, moov.end, {"trak"})) {
      auto tkhds = findBoxes(b, trak.start, trak.end, {"tkhd"});
      if (!tkhds.empty() && b[tkhds[0].start] == 0 &&
          tkhds[0].end - tkhds[0].start >= 84) {
        // Width/height ride in the high 16 bits of fixed-point 16.16 values.
        m.width = double(u32be(b, tkhds[0].start + 76)) / 65536.0;
        m.height = double(u32be(b, tkhds[0].start + 80)) / 65536.0;
      }
      if (m.width) break;  // first track is enough
    }
  }
}

uint32_t syncsafe(const uint8_t* b, size_t o) {
  return (uint32_t(b[o]) << 21) | (uint32_t(b[o + 1]) << 14) |
         (uint32_t(b[o + 2]) << 7) | b[o + 3];
}

// ID3 text frames: byte 0 is the encoding (0 latin1, 1 utf-16 BOM,
// 2 utf-16BE, 3 utf-8). This port decodes UTF-8 and latin-1; UTF-16 is
// handled in the TS reference — here we keep the null-terminated slice.
std::string id3Text(const uint8_t* b, size_t start, size_t len) {
  if (len <= 1) return "";
  uint8_t enc = b[start];
  const char* text = reinterpret_cast<const char*>(b + start + 1);
  size_t n = len - 1;
  if (const char* nul = static_cast<const char*>(memchr(text, 0, n)))
    n = size_t(nul - text);
  if (enc == 3) return std::string(text, n);  // UTF-8 passthrough
  std::string out;                             // latin-1 → UTF-8
  out.reserve(n);
  for (size_t i = 0; i < n; i++) {
    uint8_t c = static_cast<uint8_t>(text[i]);
    if (c < 0x80) out += char(c);
    else out += {char(0xC0 | (c >> 6)), char(0x80 | (c & 0x3F))};
  }
  return out;
}

void probeId3(const uint8_t* b, size_t len, MediaMeta& m) {
  m.kind = Kind::mp3;
  uint32_t tagSize = syncsafe(b, 6);
  size_t end = std::min<size_t>(10 + tagSize, len);
  size_t pos = 10;
  while (pos + 10 <= end) {
    std::string id = ascii(b, pos, 4);
    if (id[0] == 0) break;  // padding
    uint32_t frameSize = syncsafe(b, pos + 4);  // v2.4 syncsafe; v2.3 differs
    if (frameSize == 0 || pos + 10 + frameSize > end) break;
    std::string text = id3Text(b, pos + 10, frameSize);
    if (id == "TIT2" && !text.empty()) m.title = text;
    if (id == "TPE1" && !text.empty()) m.artist = text;
    if (id == "TALB" && !text.empty()) m.album = text;
    pos += 10 + frameSize;
  }
}

}  // namespace

MediaMeta probe(const uint8_t* bytes, size_t len) {
  MediaMeta m;
  if (len < 12) return m;  // too short for ANY signature

  if (ascii(bytes, 4, 4) == "ftyp") {
    probeMp4(bytes, len, m);
  } else if (memcmp(bytes, "ID3", 3) == 0) {
    probeId3(bytes, len, m);
  } else if (memcmp(bytes, "RIFF", 4) == 0 && memcmp(bytes + 8, "WAVE", 4) == 0) {
    m.kind = Kind::wav;
    // PCM: byteRate at offset 28 (little-endian) → duration = data bytes / rate.
    uint32_t byteRate = u32le(bytes, 28);
    if (byteRate > 0 && len > 44) m.durationSec = double(len - 44) / byteRate;
  } else if (memcmp(bytes, "GIF8", 4) == 0) {
    m.kind = Kind::gif;
    m.width = u16le(bytes, 6);   // logical screen descriptor
    m.height = u16le(bytes, 8);
  } else if (memcmp(bytes, "\x1A\x45\xDF\xA3", 4) == 0) {
    m.kind = Kind::webm;
    // Duration lives in a float SecsInfo element — the TS lib scans for it;
    // this port flags the kind and leaves duration unset (documented gap).
  }
  return m;
}

Also available in 9 other languages

Every CosmoDev tool ships its pure logic in TypeScript (web) and Go (CLI), with authored implementations in a dozen-plus languages — the same contract, ported. Compare all languages side by side →