diff --git a/Development.md b/Development.md index f58a8df..6f49b55 100644 --- a/Development.md +++ b/Development.md @@ -21,7 +21,7 @@ php tests/php/releases.test.php # the release stor php tests/php/files.test.php # uploaded files in a folder per account (#344), the same way php tests/php/videos.test.php # the video store, its queue and the worker (#402), with the # real ffmpeg: the CI image and feuerwerk-video have it -node tools/seed-e2e.mjs && node tools/e2e.mjs # 2080 editor checks, screenshots in /tmp/gm-e2e-*.png +node tools/seed-e2e.mjs && node tools/e2e.mjs # 2083 editor checks, screenshots in /tmp/gm-e2e-*.png GM_STEPS=20 node tools/e2e.mjs # or 1-12, or 6,20 — a subset while working on one step ./e2e.sh start [GM_STEPS] # the same run detached, see below ./e2e.sh status # live progress, or the last run's result diff --git a/Videos.md b/Videos.md index 884d92f..2bf7a05 100644 --- a/Videos.md +++ b/Videos.md @@ -179,7 +179,7 @@ Two action nodes record what the game view shows, with what the master plays (#4 | Node | | |---|---| -| **Start recording** | **name** (empty: `Recording 2026-10-11 16:42:05`, when it started), **resolution** (*Game view*, *720p*, *1080p*, *1440p*, *4K*), **fps** (*60*, *30*), **Sound**, **Convert**, **Import after conversion** (all three on, as in **Start recording…** below) | +| **Start recording** | **name** (empty: `Recording 2026-10-11 16:42:05`, when it started), **resolution** (*Game view*, *720p*, *1080p*, *1440p*, *4K*), **fps** (*60*, *30*), **Sound**, **Convert**, **Import after conversion** (all three on, as in **Start recording…** below), **Real time** (on; off, see [Not in real time](#not-in-real-time)) | | **Stop recording** | ends it and saves it | - **The picture** is the camera's, nothing of what lies over it: no notice, no fullscreen button, @@ -235,7 +235,8 @@ Two action nodes record what the game view shows, with what the master plays (#4 helps. Its first second is left out of both: a short stall while it starts is no stutter. The line at the end comes after the run, so in the editor it is in the console panel. 4K at 60 fps is too much for most computers: reading each frame back from the GPU takes longer than a frame. - The converted MP4 has a constant frame rate again. + The converted MP4 has a constant frame rate again. A recording with **Real time** off has every + frame instead. How it is made: H.264 from Chrome's `VideoEncoder` (VP9 where there is no H.264), hardware where the computer has it, 10 Mbit/s at 1080p60, a keyframe every 2 s. The file is Matroska, written by @@ -253,6 +254,42 @@ side is `src/viewport/GameRecorder.ts`, and `src/viewport/PictureReader.ts` read back through pixel buffers with a fence. The encoders, the sound and the file are `src/viewport/RecordingTake.ts`, which the editor recording below shares. +### Not in real time + +With **Real time** off (#423) the game moves on by exactly one frame of the recording at a time, +1/60 or 1/30 s, however long the computer takes for it, and only once the frame before is taken. +So the file has every frame, 4K at 60 fps too. The game view runs slower meanwhile, and the notice +line says how far it has got, such as `Recording "Trailer" not in real time: 4.2 s of video, 2.6x +real time`. + +- **The sound is made apart**, in an offline audio context: while it records, what the run plays + (sounds, instruments, patterns, songs, the audio items of a composition) goes there instead of + to the speakers, through the same mix, buses, sound FX and limiter. It is made up to each next + frame before the game goes on, so it lies on the picture whatever the frames took. You hear none + of it meanwhile. A sound that was playing before the recording started goes on at the speakers + and is not in it. A composition playing then moves into it, at the place its picture is. +- **Videos are shown frame by frame:** a driven video, which every video of a composition item + is, holds at each picture asked for, and the frame waits until that picture is there. Its sound + is decoded from the video's file and played in step, through its bus. A free video plays on in + real time, so it does not fit such a recording: set its Video clock to *Driven*. +- **Input** still reaches the game, but the game runs slower than your hands. Such a recording is + for compositions and scenes that play by themselves. +- **At most ten minutes:** the offline context holds all of its sound in memory, 230 MB for ten + minutes. A recording that gets there stops and says so in the log. +- **When it is saved**, the log says how long it took, such as `Recording "Trailer" took 35.2 s + for 13.8 s of video, 2.6x real time, and has every frame`. The start line ends with + `not in real time`. +- Only the node records so. **Start recording…** in the main menu records the editor in real time. + +The run moves on by a frame of the recording rather than by the frame the screen drew +(`SteadyPace` in `src/core/recording/recording.ts`). The run's sound goes through an +`AudioSwitch` (`src/runtime/audioSwitch.ts`), which diverts it to the library of a `SteadySound` +(`src/viewport/SteadySound.ts`) while such a recording lasts: a `SoundLibrary` on an +`OfflineAudioContext`, suspended at each next frame. A driven video sought while held hands over +its picture before `seeked`, so the frame callback is asked for as the seek begins. And a seek +right onto where a picture begins showed that picture or the one before, as its time came out in +microseconds, so such a video is sought half a millisecond further. + ## Recording the editor **Start recording…** in the main menu (top left) records the whole editor, for a tutorial or a bug