Keep a video's loading out of recordings and first frames (#417)
A Start recording right after Play composition still began with empty frames. The composition's clock waited for its video, but the recording went on and took every frame while the video loaded. A clip that starts later in the video also slipped through, because its player already had one picture while it still sought to the clip's start. - The view now counts every video sprite it leaves out as missing, not only one without any first picture. - GameRecorder takes no frame while the game view misses a video, for at most VIDEO_WAIT_MS (3 s) at a time. The recorded time stands and the sound of that time is dropped, so it stays in sync. - RecordingClock.start forgets a hold from before the first frame. Without that, the first real frames all got the time 0. - A followed player starts at 1x until the first speed reading. Before, it paused and sought every frame for about 100 ms, so the first pictures after a wait stuck and then jumped. A step faster than 4x and a time running backwards do not count as a start. - Test hooks: __gm.gameVideo(id) reads the game view's own player, TakeInfo.lastFrameAt shows when the last frame was taken. Tests: - Unit recording (clock after an early hold), video-follow (2 new, 1 adapted): 449 green in tests/core/recording, tests/viewport and tests/core/composition* - e2e 68e (a clip from 0.8 s shows that picture first and then plays), 68f (a recording that already runs takes no frame while the composition's video loads) - 68e is red without the start at 1x, 68f without the hold - README: 2038 editor checks Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
6e6b6a4d9a
commit
b2b4cbad28
10 files changed
+213
-25
No files matched your search
@@ -71,6 +71,14 @@ describe('RecordingClock', () => {
|
||||
clock.resume(8000);
|
||||
expect(clock.at(8000)).toBe(2000);
|
||||
});
|
||||
|
||||
it('leaves a hold before the first frame out of the time, not off it', () => {
|
||||
const clock = new RecordingClock();
|
||||
clock.pause(0);
|
||||
clock.resume(2000);
|
||||
clock.start(2000);
|
||||
expect(clock.at(2500)).toBe(500);
|
||||
});
|
||||
});
|
||||
|
||||
describe('FrameGate', () => {
|
||||
|
||||
@@ -23,11 +23,27 @@ describe('the speed of the asked time', () => {
|
||||
[0.083, 83],
|
||||
] as const)
|
||||
reading = readSpeed(reading, time, now);
|
||||
expect(reading.speed).toBe(0);
|
||||
expect(reading.samples[0]).toEqual({ time: 0, at: 0 });
|
||||
reading = readSpeed(reading, 0.1, SPEED_WINDOW_MS);
|
||||
expect(reading.speed).toBeCloseTo(1, 5);
|
||||
});
|
||||
|
||||
it('counts a start from standing as 1x until the window has its reading', () => {
|
||||
let reading = readSpeed(null, 0.8, 0);
|
||||
reading = readSpeed(reading, 0.8, 16);
|
||||
expect(reading.speed).toBe(0);
|
||||
// The first step of 1/60 s after the wait: held and sought instead, the first pictures stuck.
|
||||
reading = readSpeed(reading, 0.8 + 1 / 60, 33);
|
||||
expect(reading.speed).toBe(1);
|
||||
// Two steps in one frame are still a start.
|
||||
expect(readSpeed(readSpeed(null, 0.8, 0), 0.8 + 2 / 60, 16).speed).toBe(1);
|
||||
});
|
||||
|
||||
it('does not count a jump faster than a video plays, or a time running back, as a start', () => {
|
||||
expect(readSpeed(readSpeed(null, 0.8, 0), 0.9, 16).speed).toBe(0);
|
||||
expect(readSpeed(readSpeed(null, 0.8, 0), 0.8 - 1 / 60, 16).speed).toBe(0);
|
||||
});
|
||||
|
||||
it('reads steps of 1/60 s on uneven frames as 1x within 5 % once the window has grown', () => {
|
||||
let reading = readSpeed(null, 0, 0);
|
||||
const read: number[] = [];
|
||||
|
||||
Reference in new issue
Block a user