std.video — Video-Metadaten

Das std.video-Paket liest Video-Container-Metadaten (Auflösung, Dauer, FPS, Codec) aus AVI- und MP4/ISOBMFF-Dateien. AVI-Dateien mit MJPEG-Codec unterstützen zusätzlich Frame-Extraktion und Dekodierung.

Es gibt kein vollständiges Videodecoding (keine Softdecoder für H.264/H.265/AV1) — die Units sind auf Metadaten-Extraktion und MJPEG-Einzelbilder ausgelegt.

Units-Übersicht · Lyx-Sprache


Units

Unit Code Beschreibung
std.video.core VID-00 VidMeta-Struct, Format- und Codec-Konstanten, Container-Erkennung
std.video.avi VID-01 AVI-Reader: Metadaten, Frame-Zählung, MJPEG-Frame-Extraktion
std.video.mp4 VID-02 MP4/ISOBMFF-Reader: Box-Traversierung, Video-Track-Metadaten, Codec-Erkennung

VidMeta-Struct

VidMeta ist ein 64-Byte-Puffer im Heap. Alle Felder sind int64 (8 Bytes). Die Funktionen AviMeta, AviMetaFile, Mp4Meta und Mp4MetaFile schreiben direkt in diesen Puffer:

Konstante Offset Inhalt
VID_OFF_WIDTH 0 Videobreite in Pixeln
VID_OFF_HEIGHT 8 Videohöhe in Pixeln
VID_OFF_DURATION_MS 16 Gesamtdauer in Millisekunden
VID_OFF_FPS_NUM 24 FPS-Zähler (Frames per Second, Zähler)
VID_OFF_FPS_DEN 32 FPS-Nenner
VID_OFF_FRAME_COUNT 40 Gesamtzahl der Frames
VID_OFF_FORMAT 48 Container-Format (VID_FMT_*)
VID_OFF_CODEC 56 Codec (VID_CODEC_*)
VID_SIZE 64 Gesamtgröße des Structs

FPS wird als Bruch dargestellt: FPS = VID_OFF_FPS_NUM / VID_OFF_FPS_DEN. Bei MP4 sind beide Felder nicht aus dem moov-Box ableitbar und werden auf 0/1 gesetzt.


Konstanten

Container-Formate

Konstante Wert Format Erkennungsmerkmal
VID_FMT_UNKNOWN 0 Unbekannt
VID_FMT_AVI 1 AVI RIFF + AVI ab Offset 8
VID_FMT_MP4 2 MP4/ISOBMFF ftyp ab Offset 4

Codecs

Konstante Wert Codec Typische Verwendung
VID_CODEC_UNKNOWN 0 Unbekannt
VID_CODEC_MJPEG 1 Motion JPEG Überwachungskameras, Screencasts
VID_CODEC_H264 2 H.264 / AVC Standard-Web- und Kameravideo
VID_CODEC_H265 3 H.265 / HEVC 4K, effizientere Kompression
VID_CODEC_AV1 4 AV1 Streaming, lizenzfrei
VID_CODEC_MP4V 5 MPEG-4 Part 2 Ältere Kameras, DivX/Xvid
VID_CODEC_VP8 6 VP8 WebM, ältere Browser
VID_CODEC_VP9 7 VP9 YouTube, Chrome

Quickstart

import std.video.core;
import std.video.mp4;
import std.alloc;
import std.io;

fn main(): int64 {
    var vid: int64 := alloc(VID_SIZE);

    var ok: int64 := Mp4MetaFile("film.mp4"c as int64, 0, vid);
    if (ok == 0) { PrintLn("Fehler"); return 1; }

    var w:   int64 := peek64(vid + VID_OFF_WIDTH);
    var h:   int64 := peek64(vid + VID_OFF_HEIGHT);
    var dur: int64 := peek64(vid + VID_OFF_DURATION_MS);
    var cod: int64 := peek64(vid + VID_OFF_CODEC);

    PrintLn(IntToStr(w) + "x" + IntToStr(h) + "  " + IntToStr(dur / 1000) + "s");

    if (cod == VID_CODEC_H264) { PrintLn("Codec: H.264"); }
    if (cod == VID_CODEC_H265) { PrintLn("Codec: H.265"); }
    if (cod == VID_CODEC_AV1)  { PrintLn("Codec: AV1");  }

    free(vid, VID_SIZE);
    return 0;
}


std.video.core — Container-Erkennung

// Mindestens 12 Bytes erforderlich.
// Gibt VID_FMT_* zurück.
var fmt: int64 := VidDetectFormat(buf, len);
if (fmt == VID_FMT_AVI) { AviMeta(buf, len, vid); }
if (fmt == VID_FMT_MP4) { Mp4Meta(buf, len, vid); }


std.video.avi — AVI-Reader

Metadaten

import std.video.avi;

// Aus Speicher-Puffer
var ok: int64 := AviMeta(buf, len, vid);    // 1 = Erfolg, 0 = Fehler

// Aus Datei (liest automatisch in Puffer)
// plen: Zeiger auf int64 → erhält Dateigröße; oder 0
var ok: int64 := AviMetaFile("clip.avi"c as int64, 0, vid);

AVI liefert alle Felder einschließlich FPS (aus strh.dwRate/dwScale) und Frame-Zählung (aus avih.dwTotalFrames).

Frame-Extraktion

// Anzahl '00dc'-Chunks (Video-Stream 0) in der movi-Liste
var count: int64 := AviGetFrameCount(buf, len);

// Zeiger auf Frame-Daten (innerhalb von buf), Größe in pFrameLen
// frameIdx: 0-basiert
var pFrameLen: int64 := alloc(8);
var framePtr: int64 := AviGetFrameOffset(buf, len, 0, pFrameLen);
var frameLen: int64 := peek64(pFrameLen);

MJPEG-Frame dekodieren

AviExtractMjpegFrame kombiniert Frame-Suche und JPEG-Dekodierung in einem Schritt. Nur bei VID_CODEC_MJPEG sinnvoll:

import std.video.avi;
import std.image.core;

fn ExtractFrame(buf: int64, len: int64, frameIdx: int64): int64 {
    var img: int64 := GrfImageAlloc(0, 0);   // Größe wird vom Decoder gesetzt
    var ok: int64 := AviExtractMjpegFrame(buf, len, frameIdx, img);
    if (ok == 0) { GrfImageFree(img); return 0; }
    return img;   // GrfImage mit RGBA-Pixeln; Aufrufer muss GrfImageFree aufrufen
}


std.video.mp4 — MP4/ISOBMFF-Reader

import std.video.mp4;

// Aus Speicher-Puffer (erfordert 'ftyp'-Box ab Offset 4)
var ok: int64 := Mp4Meta(buf, len, vid);

// Aus Datei
var ok: int64 := Mp4MetaFile("film.mp4"c as int64, 0, vid);

Der Reader traversiert moov → mvhd (Dauer, Timescale), moov → trak → tkhd (Auflösung), mdia → hdlr ('vide'-Track), minf → stbl → stsd (Codec-Erkennung).

Einschränkungen MP4: FPS und Frame-Zählung sind aus dem moov-Box allein nicht zuverlässig ermittelbar und werden auf VID_OFF_FPS_NUM=0, VID_OFF_FPS_DEN=1, VID_OFF_FRAME_COUNT=0 gesetzt. Dauer und Auflösung sind immer verfügbar.

Codec-Erkennung (MP4)

Aus der stsd-Box (minf → stbl → stsd):

4CC Codec
avc1, avc3 H.264
hvc1, hev1 H.265
av01 AV1
mp4v MPEG-4 Part 2
vp08 VP8
vp09 VP9

Codec-Erkennung (AVI)

Aus dem strh.fccHandler-Feld des Video-Streams:

FCC Codec
MJPG, mjpg MJPEG
H264, avc1, X264 H.264
MP4V, XVID, DIVX, DIV3 MPEG-4 Part 2
hvc1, HVC1 H.265

Quelldateien

Datei Inhalt
std/video/core.lyx VID-00: VidMeta-Struct-Offsets, Format- und Codec-Konstanten, VidDetectFormat
std/video/avi.lyx VID-01: RIFF/AVI-Parser, avih/strh-Auswertung, Frame-Extraktion, MJPEG-Dekodierung
std/video/mp4.lyx VID-02: ISOBMFF-Box-Traversierung, mvhd/tkhd/hdlr/stsd-Auswertung

Letzte Aktualisierung: 2026-06-15