Video-Asset mit Clips, am Sprite platzieren und abspielen #402

Closed
opened 2026-10-10 23:58:29 +02:00 by meleki · 1 comment
Owner

Wunsch vom 2026-10-10 im Chat:

alpha bräuchte ich nicht, und chrome reicht als ziel browser. mein ziel ist es erstmal einfach nur ein video asset zu erstellen. dort auch clips anzulegen wie bei sound. und diese dann wie ein sprite zu platzieren und abzuspielen

Ziel: ein Video-Asset anlegen, darin Clips wie bei Sound (#357), und ein Video oder einen Clip in der Szene platzieren und abspielen. Nur Chrome, kein Alpha.

Vorab gemessen (2026-10-10)

  • Chromium im CI-Image (game-maker-ci, Chromium 152, Debian): canPlayType liefert probably für H.264+AAC, VP9 und AV1, aber nichts für HEVC. Das ist das Format von iPhone-Videos, deshalb braucht es eine Umwandlung.
  • ffmpeg auf stein2: 5.1.9 mit libx264 und aac. Im Container web-php-fpm fehlt ffmpeg.
  • Tempo auf stein2: 10 s 1080p30 erzeugen (libx264 -preset veryfast -crf 23 -g 15) dauert 3,8 s, 10 s 1080p → 720p 2,5 s. Gemessen mit einem Testbild (testsrc2), echtes Material ist schwerer, die Zahlen sind also eine Untergrenze.
  • Range-Requests: Hochgeladene Dateien liefert nginx statisch aus data/ aus, Springen im Video geht damit von selbst.

Vorschlag

1. Upload und Umwandlung (Server)

  • Hochladen wie bei Sounds: rohe Bytes, bis 256 MB, in den Ordner des Kontos (#344). Angenommen wird, was ffmpeg lesen kann (MP4, MOV, WebM, MKV …).
  • ffmpeg wandelt in ein Zielformat um: MP4, H.264 + AAC, yuv420p, konstante Bildrate, Keyframe alle 15 Frames (damit Springen und Clip-Loops schnell sind), +faststart, Auflösung begrenzt.
  • Dazu ein Posterbild für den Picker und die Daten aus ffprobe: Dauer, Größe, fps, ob es Ton hat.
  • Das Umwandeln ist ein Job, kein Request: Upload → „wird umgewandelt“ → Client fragt nach → fertig oder Fehler.

2. Modell

  • Neuer Asset-Typ video: Datei, Breite, Höhe, Dauer, fps, Ton ja/nein, Loop und Volume.
  • Clips wie bei Sound: clips?: {id, name, props}[], Start und Ende. Clip-Ids teilen den Generator mit den Asset-Ids, ein Feld hält ein Video oder einen Clip.

3. Editor

  • Video-Tab: Vorschau mit Zeitleiste und einer Clip-Leiste darunter, so wie im Sound-Tab. Clips per Ziehen anlegen, Start und Ende im Inspector.
  • Picker mit Posterbild und Fortschritt der Umwandlung.

4. Platzieren und Abspielen

  • Ein Sprite trägt das Video über sein Feld Texture, so wie eine Textur oder einen Frame. Größe, Tint, Shader, Collider und Z-Reihenfolge gibt es damit ohne Zusatzarbeit.
  • Zur Laufzeit hat jede platzierte Instanz ihr eigenes <video> als Pixi-VideoSource. Es spielt ab Szenenstart und springt am Clip-Ende zum Clip-Start zurück, wenn Loop an ist.
  • Der Ton geht über MediaElementAudioSourceNode in den Audio-Graphen auf den Master-Bus. Chrome lässt Ton erst nach einem Klick zu. Im Editor ist Play dieser Klick, im Spiel-Link (#266) braucht es einen.

5. Tests

  • Unit: Modell, Clip-Regeln, Auflösen von Video oder Clip.
  • PHP: Store und Job, Annahme und Ablehnung.
  • e2e: kleines MP4 im Repo als Fixture (wenige KB), Upload → umgewandelt → Sprite zeigt laufende Frames.

Offen, Entscheidung des Users

  1. Wo ffmpeg läuft. Vorschlag: ein eigener kleiner Container game-maker-video mit ffmpeg und demselben data/-Mount, der einen Warteordner abarbeitet. Alternativen: ffmpeg ins Image web-php-fpm (einfacher, aber das Umwandeln hängt dann am PHP-Prozess), oder ein Dienst auf dem Host (ffmpeg ist dort schon da).
  2. Höchste Auflösung: Vorschlag 1280 (720p). Jedes Frame wird zur GPU hochgeladen, 1080p kostet spürbar mehr.
  3. Video am Sprite (Vorschlag) oder ein eigener platzierbarer Typ Video.

Nicht dabei (vorerst)

  • Alpha, Safari und Firefox
  • Graph-Nodes zum Steuern (Play, Pause, Seek, „Video ended“): eigenes Folge-Issue
  • Schnitt oder Export eines Videos, Untertitel
Wunsch vom 2026-10-10 im Chat: > alpha bräuchte ich nicht, und chrome reicht als ziel browser. mein ziel ist es erstmal einfach nur ein video asset zu erstellen. dort auch clips anzulegen wie bei sound. und diese dann wie ein sprite zu platzieren und abzuspielen Ziel: ein Video-Asset anlegen, darin Clips wie bei Sound (#357), und ein Video oder einen Clip in der Szene platzieren und abspielen. Nur Chrome, kein Alpha. ## Vorab gemessen (2026-10-10) - **Chromium im CI-Image** (`game-maker-ci`, Chromium 152, Debian): `canPlayType` liefert `probably` für H.264+AAC, VP9 und AV1, aber **nichts für HEVC**. Das ist das Format von iPhone-Videos, deshalb braucht es eine Umwandlung. - **ffmpeg auf stein2:** 5.1.9 mit `libx264` und `aac`. Im Container `web-php-fpm` fehlt ffmpeg. - **Tempo auf stein2:** 10 s 1080p30 erzeugen (`libx264 -preset veryfast -crf 23 -g 15`) dauert 3,8 s, 10 s 1080p → 720p 2,5 s. Gemessen mit einem Testbild (`testsrc2`), echtes Material ist schwerer, die Zahlen sind also eine Untergrenze. - **Range-Requests:** Hochgeladene Dateien liefert nginx statisch aus `data/` aus, Springen im Video geht damit von selbst. ## Vorschlag ### 1. Upload und Umwandlung (Server) - Hochladen wie bei Sounds: rohe Bytes, bis 256 MB, in den Ordner des Kontos (#344). Angenommen wird, was ffmpeg lesen kann (MP4, MOV, WebM, MKV …). - ffmpeg wandelt in **ein** Zielformat um: MP4, H.264 + AAC, `yuv420p`, konstante Bildrate, Keyframe alle 15 Frames (damit Springen und Clip-Loops schnell sind), `+faststart`, Auflösung begrenzt. - Dazu ein Posterbild für den Picker und die Daten aus `ffprobe`: Dauer, Größe, fps, ob es Ton hat. - **Das Umwandeln ist ein Job, kein Request:** Upload → „wird umgewandelt“ → Client fragt nach → fertig oder Fehler. ### 2. Modell - Neuer Asset-Typ `video`: Datei, Breite, Höhe, Dauer, fps, Ton ja/nein, Loop und Volume. - Clips wie bei Sound: `clips?: {id, name, props}[]`, Start und Ende. Clip-Ids teilen den Generator mit den Asset-Ids, ein Feld hält ein Video **oder** einen Clip. ### 3. Editor - Video-Tab: Vorschau mit Zeitleiste und einer Clip-Leiste darunter, so wie im Sound-Tab. Clips per Ziehen anlegen, Start und Ende im Inspector. - Picker mit Posterbild und Fortschritt der Umwandlung. ### 4. Platzieren und Abspielen - **Ein Sprite trägt das Video über sein Feld `Texture`**, so wie eine Textur oder einen Frame. Größe, Tint, Shader, Collider und Z-Reihenfolge gibt es damit ohne Zusatzarbeit. - Zur Laufzeit hat jede platzierte Instanz ihr eigenes `<video>` als Pixi-`VideoSource`. Es spielt ab Szenenstart und springt am Clip-Ende zum Clip-Start zurück, wenn Loop an ist. - Der Ton geht über `MediaElementAudioSourceNode` in den Audio-Graphen auf den Master-Bus. Chrome lässt Ton erst nach einem Klick zu. Im Editor ist Play dieser Klick, im Spiel-Link (#266) braucht es einen. ### 5. Tests - Unit: Modell, Clip-Regeln, Auflösen von Video oder Clip. - PHP: Store und Job, Annahme und Ablehnung. - e2e: kleines MP4 im Repo als Fixture (wenige KB), Upload → umgewandelt → Sprite zeigt laufende Frames. ## Offen, Entscheidung des Users 1. **Wo ffmpeg läuft.** Vorschlag: ein eigener kleiner Container `game-maker-video` mit ffmpeg und demselben `data/`-Mount, der einen Warteordner abarbeitet. Alternativen: ffmpeg ins Image `web-php-fpm` (einfacher, aber das Umwandeln hängt dann am PHP-Prozess), oder ein Dienst auf dem Host (ffmpeg ist dort schon da). 2. **Höchste Auflösung:** Vorschlag 1280 (720p). Jedes Frame wird zur GPU hochgeladen, 1080p kostet spürbar mehr. 3. **Video am Sprite** (Vorschlag) oder ein eigener platzierbarer Typ `Video`. ## Nicht dabei (vorerst) - Alpha, Safari und Firefox - Graph-Nodes zum Steuern (Play, Pause, Seek, „Video ended“): eigenes Folge-Issue - Schnitt oder Export eines Videos, Untertitel
admin added this to the Development project 2026-10-11 13:04:52 +02:00
admin moved this to Next in Development on 2026-10-11 13:05:11 +02:00
Author
Owner

Erledigt mit d48f174 und c815d2c, Wiki 8f4f4af (neue Seite Videos, dazu API, Architecture, Development).

Was es jetzt gibt

  • Upload und Umwandlung: Hochladen geht mit allem, was ffmpeg lesen kann. Der neue Container game-maker-video arbeitet die Warteschlange nacheinander ab und macht daraus MP4 mit H.264 + AAC: yuv420p, konstante Bildrate, ein Keyframe alle 15 Frames, +faststart, höchstens 1080p. Dazu kommen ein Posterbild und die Daten aus ffprobe. Der Picker zeigt „wird umgewandelt“ und danach das Posterbild.
  • Asset-Typ video mit Clips, so wie beim Sound. Im Video-Tab gibt es eine Vorschau, darunter den Clip-Streifen und die Spur.
  • Ein Sprite trägt ein Video oder einen Clip über Texture. Größe, Tint, Shader, Collider und Z-Reihenfolge funktionieren damit wie bei einem Bild. Auch die PREVIEW im Inspector spielt das Video ab.
  • Abspielen: Das Video läuft ab dem Start der Szene, auf Wunsch im Loop. In einer Partie geht der Ton über den Master-Bus, im Editor ist es stumm.

Entscheidungen des Users

  • ffmpeg in einem eigenen Container game-maker-video
  • bis 1080p
  • Video am Sprite statt eines eigenen Objekttyps

Selbst entschieden

  • Basis des Containers ist debian:12-slim mit php-cli und ffmpeg, also derselbe Stand wie im CI-Image (PHP 8.2, ffmpeg 5.1).
  • Ein Player pro Clip: Zwei Sprites mit demselben Clip zeigen dasselbe Bild. Für den Schnitt reicht das nicht, deshalb gibt es #404.
  • Ein Player, nach dem 2 s niemand fragt, wird verworfen. Wer ein Video trägt, muss deshalb jeden Frame danach fragen.

Funde nach dem ersten Stand

  • 413 bei einem Video mit 279 MB: Die API hatte für jede Route eine Grenze von 256 MB. Die Video-Route streamt den Upload jetzt direkt auf die Platte und erlaubt 2 GB. Gemessen über die echte Strecke (Brandmauer → nginx → PHP): 300 MB → 201 in 21 s, php-fpm dabei höchstens 13,7 MB RSS.
  • Absturz Cannot read properties of null (reading 'alphaMode'): Die PREVIEW hat nur nach Änderungen gezeichnet, der Player wurde verworfen und seine Textur zerstört. Behoben: PREVIEW und Shader-Vorschau zeichnen bei Video jeden Frame, und ein verworfener Player zerstört seine Textur nicht mehr.
  • Warnungen nach einem Fensterwechsel (a 'textureSource' was destroyed while still bound to a shader), c815d2c: Bei verdecktem Fenster zeichnet Chrome nicht, der Aufräum-Timer lief aber weiter. Jetzt wird bei verdeckter Seite nichts verworfen, und die Quelle wird nur entladen statt zerstört.
  • CI konnte im Video nicht springen, c815d2c: php -S kann keine Range-Requests. Das hat 4 Checks von e2e 66 im Lauf zu d48f174 rot gemacht. Behoben mit dem neuen Router tools/ci/router.php, der die Videos mit Range ausliefert.
  • CI-Image auf melektaus-atx neu gebaut (ffmpeg 5.1.9, Chromium 154, so wie auf stein2). Das alte Image liegt noch als game-maker-ci:pre-402 da. Chromium ist dabei auf beiden Runnern von 152 auf 154 gesprungen.

Tests

PHP videos.test.php (Worker-Image, echtes ffmpeg) → 68 Checks grün
Unit videos.test.ts / video-library.test.ts       → 20 / 3 Tests grün
e2e 66 (stein2 und atx)                           → ALL PASSED, 18 Checks
Gate (atx, vor d48f174)                           → CHECK EXIT 0, 294 Dateien, 4520 Tests
  • Gegenproben: Keyframe-Abstand 30 → der Keyframe-Check wird rot. Falsche Ende-Regel → genau die zwei Tests dazu werden rot. Altes Aufräumen → genau die zwei Tests zur verdeckten Seite werden rot.
  • CI: Gate zu d48f174 und ce933a4 grün. suite ist in beiden Läufen rot (Task 645 und 647). Bei d48f174 waren es 4 Checks von e2e 66. 3 davon hat der Range-Router behoben, 66f bleibt rot und sieht nur Lila statt des Clips. Mein Lauf auf melektaus-atx mit derselben GPU ist grün, der Fund steht in #406.

Nicht geprüft:

  • ein echter Fensterwechsel im Browser, das stellt nur der Unit-Test nach
  • für Check 66h (PREVIEW nach 4,5 s) keine Gegenprobe mit dem alten Code
  • Uploads deutlich über 300 MB. Bei 2 GB könnten fastcgi_read_timeout (60 s) oder das Timeout der Brandmauer (900 s) greifen.
  • die Umwandlung des 279-MB-Videos selbst habe ich nicht verfolgt

Folge-Issues

  • #404: Die Animation gibt die Zeit des Videos vor (bildgenau, Scrubben, ein Player pro Sprite)
  • #405: Export als Videodatei, Animation und Game-View-Aufnahme
  • Graph-Nodes zum Steuern (Play, Pause, Seek, „Video ended“): noch kein Issue angelegt
Erledigt mit d48f174 und c815d2c, Wiki 8f4f4af (neue Seite *Videos*, dazu *API*, *Architecture*, *Development*). ## Was es jetzt gibt - **Upload und Umwandlung:** Hochladen geht mit allem, was ffmpeg lesen kann. Der neue Container `game-maker-video` arbeitet die Warteschlange nacheinander ab und macht daraus MP4 mit H.264 + AAC: `yuv420p`, konstante Bildrate, ein Keyframe alle 15 Frames, `+faststart`, höchstens 1080p. Dazu kommen ein Posterbild und die Daten aus `ffprobe`. Der Picker zeigt „wird umgewandelt“ und danach das Posterbild. - **Asset-Typ `video` mit Clips**, so wie beim Sound. Im Video-Tab gibt es eine Vorschau, darunter den Clip-Streifen und die Spur. - **Ein Sprite trägt ein Video oder einen Clip über `Texture`.** Größe, Tint, Shader, Collider und Z-Reihenfolge funktionieren damit wie bei einem Bild. Auch die PREVIEW im Inspector spielt das Video ab. - **Abspielen:** Das Video läuft ab dem Start der Szene, auf Wunsch im Loop. In einer Partie geht der Ton über den Master-Bus, im Editor ist es stumm. ## Entscheidungen des Users - ffmpeg in einem eigenen Container `game-maker-video` - bis 1080p - Video am Sprite statt eines eigenen Objekttyps ## Selbst entschieden - **Basis des Containers ist `debian:12-slim`** mit `php-cli` und `ffmpeg`, also derselbe Stand wie im CI-Image (PHP 8.2, ffmpeg 5.1). - **Ein Player pro Clip:** Zwei Sprites mit demselben Clip zeigen dasselbe Bild. Für den Schnitt reicht das nicht, deshalb gibt es #404. - **Ein Player, nach dem 2 s niemand fragt, wird verworfen.** Wer ein Video trägt, muss deshalb jeden Frame danach fragen. ## Funde nach dem ersten Stand - **413 bei einem Video mit 279 MB:** Die API hatte für jede Route eine Grenze von 256 MB. Die Video-Route streamt den Upload jetzt direkt auf die Platte und erlaubt 2 GB. Gemessen über die echte Strecke (Brandmauer → nginx → PHP): 300 MB → 201 in 21 s, php-fpm dabei höchstens 13,7 MB RSS. - **Absturz `Cannot read properties of null (reading 'alphaMode')`:** Die PREVIEW hat nur nach Änderungen gezeichnet, der Player wurde verworfen und seine Textur zerstört. Behoben: PREVIEW und Shader-Vorschau zeichnen bei Video jeden Frame, und ein verworfener Player zerstört seine Textur nicht mehr. - **Warnungen nach einem Fensterwechsel** (`a 'textureSource' was destroyed while still bound to a shader`), c815d2c: Bei verdecktem Fenster zeichnet Chrome nicht, der Aufräum-Timer lief aber weiter. Jetzt wird bei verdeckter Seite nichts verworfen, und die Quelle wird nur entladen statt zerstört. - **CI konnte im Video nicht springen**, c815d2c: `php -S` kann keine `Range`-Requests. Das hat 4 Checks von e2e 66 im Lauf zu d48f174 rot gemacht. Behoben mit dem neuen Router `tools/ci/router.php`, der die Videos mit `Range` ausliefert. - **CI-Image auf `melektaus-atx` neu gebaut** (ffmpeg 5.1.9, Chromium 154, so wie auf stein2). Das alte Image liegt noch als `game-maker-ci:pre-402` da. Chromium ist dabei auf beiden Runnern von 152 auf 154 gesprungen. ## Tests ``` PHP videos.test.php (Worker-Image, echtes ffmpeg) → 68 Checks grün Unit videos.test.ts / video-library.test.ts → 20 / 3 Tests grün e2e 66 (stein2 und atx) → ALL PASSED, 18 Checks Gate (atx, vor d48f174) → CHECK EXIT 0, 294 Dateien, 4520 Tests ``` - Gegenproben: Keyframe-Abstand 30 → der Keyframe-Check wird rot. Falsche Ende-Regel → genau die zwei Tests dazu werden rot. Altes Aufräumen → genau die zwei Tests zur verdeckten Seite werden rot. - **CI:** Gate zu d48f174 und ce933a4 grün. `suite` ist in beiden Läufen rot (Task 645 und 647). Bei d48f174 waren es 4 Checks von e2e 66. 3 davon hat der Range-Router behoben, **66f bleibt rot** und sieht nur Lila statt des Clips. Mein Lauf auf `melektaus-atx` mit derselben GPU ist grün, der Fund steht in #406. **Nicht geprüft:** - ein echter Fensterwechsel im Browser, das stellt nur der Unit-Test nach - für Check 66h (PREVIEW nach 4,5 s) keine Gegenprobe mit dem alten Code - Uploads deutlich über 300 MB. Bei 2 GB könnten `fastcgi_read_timeout` (60 s) oder das Timeout der Brandmauer (900 s) greifen. - die Umwandlung des 279-MB-Videos selbst habe ich nicht verfolgt ## Folge-Issues - #404: Die Animation gibt die Zeit des Videos vor (bildgenau, Scrubben, ein Player pro Sprite) - #405: Export als Videodatei, Animation und Game-View-Aufnahme - Graph-Nodes zum Steuern (Play, Pause, Seek, „Video ended“): noch kein Issue angelegt
admin moved this to Done in Development on 2026-10-11 13:30:47 +02:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: meleki/feuerwerk#402