Skip to content

Commit

Permalink
Allow seeking MVD to file position percentage.
Browse files Browse the repository at this point in the history
  • Loading branch information
skullernet committed Nov 1, 2022
1 parent d871bba commit 35697a3
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 31 deletions.
7 changes: 4 additions & 3 deletions doc/server.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -908,12 +908,13 @@ mvdplay [-hl:n:r:] <[/]filename> [...]::
-r | --replace=<channel>::: replace existing _channel_ playlist with
new entries, don't create a new channel

mvdseek [+-]<timespec> [channel]::
mvdseek [+-]<timespec|percent>[%] [channel]::
Seeks the given amount of time during MVD playback on the specified
_channel_. Prepend with ‘+’ to seek forward relative to current position,
prepend with ‘-’ to seek backward relative to current position. Without
prefix, seeks to an absolute position within the MVD file, counted from the
last map change. See below for _timespec_ syntax description. Initial
prefix, seeks to an absolute frame position within the MVD file, counted
from the last map change. See below for _timespec_ syntax description.
With ‘%’ suffix, seeks to specified file position percentage. Initial
forward seek may be slow, so be patient. For multi-map recordings, it is
not possible to return to the previous map by seeking. Seeking during demo
recording is not yet supported.
Expand Down
85 changes: 57 additions & 28 deletions src/server/mvd/client.c
Original file line number Diff line number Diff line change
Expand Up @@ -619,7 +619,7 @@ static void demo_emit_snapshot(mvd_t *mvd)
mvd->last_snapshot = mvd->framenum;
}

static mvd_snap_t *demo_find_snapshot(mvd_t *mvd, int framenum)
static mvd_snap_t *demo_find_snapshot(mvd_t *mvd, int64_t dest, bool byte_seek)
{
int l = 0;
int r = mvd->numsnapshots - 1;
Expand All @@ -630,9 +630,10 @@ static mvd_snap_t *demo_find_snapshot(mvd_t *mvd, int framenum)
do {
int m = (l + r) / 2;
mvd_snap_t *snap = mvd->snapshots[m];
if (snap->framenum < framenum)
int64_t pos = byte_seek ? snap->filepos : snap->framenum;
if (pos < dest)
l = m + 1;
else if (snap->framenum > framenum)
else if (pos > dest)
r = m - 1;
else
return snap;
Expand Down Expand Up @@ -2151,13 +2152,14 @@ static void MVD_Seek_f(void)
mvd_t *mvd;
gtv_t *gtv;
mvd_snap_t *snap;
int i, j, ret, index, frames, dest;
int i, j, ret, index, frames;
int64_t dest;
char *from, *to;
edict_t *ent;
bool gamestate;
bool gamestate, back_seek, byte_seek;

if (Cmd_Argc() < 2) {
Com_Printf("Usage: %s [+-]<timespec> [chanid]\n", Cmd_Argv(0));
Com_Printf("Usage: %s [+-]<timespec|percent>[%%] [chanid]\n", Cmd_Argv(0));
return;
}

Expand All @@ -2180,27 +2182,50 @@ static void MVD_Seek_f(void)

to = Cmd_Argv(1);

if (*to == '-' || *to == '+') {
// relative to current frame
if (!Com_ParseTimespec(to + 1, &frames)) {
Com_Printf("Invalid relative timespec.\n");
if (strchr(to, '%')) {
char *suf;
float percent = strtof(to, &suf);
if (strcmp(suf, "%") || !isfinite(percent)) {
Com_Printf("[%s] Invalid percentage.\n", mvd->name);
return;
}
if (*to == '-')
frames = -frames;
dest = mvd->framenum + frames;
} else {
// relative to first frame
if (!Com_ParseTimespec(to, &dest)) {
Com_Printf("Invalid absolute timespec.\n");

if (!gtv->demosize) {
Com_Printf("[%s] Unknown file size, can't seek.\n", mvd->name);
return;
}
frames = dest - mvd->framenum;
}

if (!frames)
// already there
return;
clamp(percent, 0, 100);
dest = gtv->demoofs + gtv->demosize * percent / 100;

byte_seek = true;
back_seek = dest < FS_Tell(gtv->demoplayback);
} else {
if (*to == '-' || *to == '+') {
// relative to current frame
if (!Com_ParseTimespec(to + 1, &frames)) {
Com_Printf("Invalid relative timespec.\n");
return;
}
if (*to == '-')
frames = -frames;
dest = mvd->framenum + frames;
} else {
// relative to first frame
if (!Com_ParseTimespec(to, &i)) {
Com_Printf("Invalid absolute timespec.\n");
return;
}
dest = i;
frames = i - mvd->framenum;
}

if (!frames)
return; // already there

byte_seek = false;
back_seek = frames < 0;
}

if (setjmp(mvd_jmpbuf))
return;
Expand All @@ -2211,11 +2236,11 @@ static void MVD_Seek_f(void)
// clear dirty configstrings
memset(mvd->dcs, 0, sizeof(mvd->dcs));

Com_DPrintf("[%d] seeking to %d\n", mvd->framenum, dest);
Com_DPrintf("[%d] seeking to %"PRId64"\n", mvd->framenum, dest);

// seek to the previous most recent snapshot
if (frames < 0 || mvd->last_snapshot > mvd->framenum) {
snap = demo_find_snapshot(mvd, dest);
if (back_seek || mvd->last_snapshot > mvd->framenum) {
snap = demo_find_snapshot(mvd, dest, byte_seek);

if (snap) {
Com_DPrintf("found snap at %d\n", snap->framenum);
Expand Down Expand Up @@ -2248,14 +2273,18 @@ static void MVD_Seek_f(void)

MVD_ParseMessage(mvd);
mvd->framenum = snap->framenum;
} else if (frames < 0) {
} else if (back_seek) {
Com_Printf("[%s] Couldn't seek backwards without snapshots!\n", mvd->name);
goto done;
}
}

// skip forward to destination frame
while (mvd->framenum < dest) {
// skip forward to destination frame/position
while (1) {
int64_t pos = byte_seek ? FS_Tell(gtv->demoplayback) : mvd->framenum;
if (pos >= dest)
break;

ret = demo_read_message(gtv->demoplayback);
if (ret <= 0) {
demo_finish(gtv, ret);
Expand Down

0 comments on commit 35697a3

Please sign in to comment.