Smooth video presentation phase across render latency changes
This commit is contained in:
1 parent
6f542bfae9
commit
d0232e4c6e
3 files changed
+37
-3
No files matched your search
@@ -122,7 +122,11 @@ enum call_video_playout_action call_video_playout_poll(struct call_video_playout
|
||||
int64_t step = (int64_t)f->interval_us * 1000000 / p->speed_ppm;
|
||||
if (p->head_pts != f->pts_us) {
|
||||
p->head_pts = f->pts_us;
|
||||
p->head_due_us = p->anchored ? p->last_show_us + step - p->lead_us : now;
|
||||
p->head_show_us = p->anchored ? p->last_deadline + step : now;
|
||||
// После опоздания сохраняем все кадры, но не устраиваем мгновенный burst.
|
||||
int64_t earliest = p->last_show_us + (int64_t)f->interval_us * 1000000 / VIDEO_MAX_SPEED_PPM;
|
||||
if (p->anchored && p->head_show_us < earliest) p->head_show_us = earliest;
|
||||
p->head_due_us = p->head_show_us - (p->anchored ? p->lead_us : 0);
|
||||
}
|
||||
int64_t deadline = p->head_due_us;
|
||||
p->deadline_us = deadline;
|
||||
@@ -151,7 +155,15 @@ void call_video_playout_presented(struct call_video_playout *p, int64_t pts, int
|
||||
int64_t av = p->pending_av, lead = now - p->selected_us;
|
||||
// GUI freeze не становится постоянным опережением dispatch для последующих кадров.
|
||||
if (lead <= f->interval_us / 2) p->lead_us = (p->lead_us * 7 + lead) / 8;
|
||||
p->awaiting = 0; p->anchored = 1; p->last_deadline = now; p->head_pts = -1;
|
||||
int64_t error = now - p->head_show_us;
|
||||
if (!p->anchored || error > f->interval_us / 2 || error < -(int64_t)f->interval_us / 2) p->last_deadline = now;
|
||||
else {
|
||||
int64_t correction = error / 8;
|
||||
if (correction > 1000) correction = 1000;
|
||||
if (correction < -1000) correction = -1000;
|
||||
p->last_deadline = p->head_show_us + correction;
|
||||
}
|
||||
p->awaiting = 0; p->anchored = 1; p->head_pts = -1;
|
||||
{
|
||||
if (av < p->av_min) p->av_min = av;
|
||||
if (av > p->av_max) p->av_max = av;
|
||||
|
||||
@@ -34,6 +34,7 @@ struct call_video_playout {
|
||||
struct call_video_playout_frame pending; // Единственный выбранный кадр до подтверждения потребителем.
|
||||
int awaiting;
|
||||
int64_t selected_us, pending_av, head_pts, head_due_us, lead_us, rate_us;
|
||||
int64_t head_show_us; // Плановая презентация головы; GUI ACK корректирует фазу плавно.
|
||||
unsigned queued, reserve; // reserve — будущие кадры сверх головы, включая необходимый pipeline backend.
|
||||
// NULL пишет DEBUG напрямую; timer устанавливает неблокирующий callback с копированием события.
|
||||
void (*log_event)(void *, const struct call_video_playout_event *);
|
||||
|
||||
@@ -108,6 +108,27 @@ static void slowing_with_queue(void) {
|
||||
DEBUG_INFO(DEBUG_CATEGORY_CALL, "PASS queue governor: speed_ppm=%u -> %u as total frames fall 8 -> 2", fast, p.speed_ppm);
|
||||
}
|
||||
|
||||
static void render_latency_change(void) {
|
||||
struct call_video_playout p; call_video_playout_init(&p, 13);
|
||||
struct call_video_playout_frame f = {origin, origin, 33333};
|
||||
struct call_clock_snapshot audio = {.valid = 1, .rate_ppm = 1000000};
|
||||
int64_t now = origin;
|
||||
for (unsigned i = 0; i < 240; ++i) {
|
||||
f.pts_us = origin + i * 33333ll; audio.pts_us = f.pts_us + 100000;
|
||||
int action = call_video_playout_poll(&p, &f, now, &audio, 2, 1);
|
||||
if (action == CALL_VIDEO_PLAYOUT_WAIT) {
|
||||
now = p.deadline_us;
|
||||
CHECK(call_video_playout_poll(&p, &f, now, &audio, 2, 1) == CALL_VIDEO_PLAYOUT_SHOW);
|
||||
} else CHECK(action == CALL_VIDEO_PLAYOUT_SHOW);
|
||||
now += i < 120 ? 3000 : 9000;
|
||||
call_video_playout_presented(&p, f.pts_us, now);
|
||||
++now;
|
||||
}
|
||||
int64_t phase = p.last_show_us - (origin + 239 * 33333ll);
|
||||
CHECK(phase >= 0 && phase < 15000);
|
||||
DEBUG_INFO(DEBUG_CATEGORY_CALL, "PASS render latency 3->9ms: phase_us=%lld; no accumulated per-frame GUI delay", (long long)phase);
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
debug_config_init(); debug_set_level(DEBUG_LEVEL_INFO);
|
||||
const unsigned pauses[] = {50, 100, 200, 500};
|
||||
@@ -116,5 +137,5 @@ int main(void) {
|
||||
simulate(pauses[i], cpu, 1000, 0);
|
||||
simulate(pauses[i], cpu, 15625, 1);
|
||||
}
|
||||
presentation_deadline(); queued_capture_gap(); slowing_with_queue(); return 0;
|
||||
presentation_deadline(); queued_capture_gap(); slowing_with_queue(); render_latency_change(); return 0;
|
||||
}
|
||||
Reference in new issue
Block a user