Bound video display cadence independently of capture timestamp gaps

This commit is contained in:
evgeny committed 2026-10-19 18:22:47 +02:00
1 parent 642fc34bcc
commit 9bffe49e62
2 files changed
+24 -7

No files matched your search

+18 -6
View File
@@ -33,16 +33,18 @@ static void report(struct call_video_playout *p, int64_t now) {
DEBUG_DEBUG(DEBUG_CATEGORY_CALL,
"video playout call=%llu interval_us=%lld shown=%u speed_ppm=%u drop_order=%u "
"cadence_us=%lld..%lld gap_pts_us=%lld gap_rx_us=%lld gap_dispatch_us=%lld "
"av_us=%lld..%lld dispatch_max_us=%lld data_shift_us=%lld audio_wait=%u clock_wait=%u",
"av_us=%lld..%lld dispatch_max_us=%lld data_shift_us=%lld audio_wait=%u clock_wait=%u source_gaps=%u source_gap_max_us=%lld",
(unsigned long long)p->call_id, (long long)(now - p->report_us), p->shown, p->speed_ppm, p->order,
(long long)(p->interval_min == INT64_MAX ? 0 : p->interval_min), (long long)p->interval_max,
(long long)p->gap_pts, (long long)p->gap_received, (long long)p->gap_dispatch,
(long long)(p->shown ? p->av_min : 0), (long long)(p->shown ? p->av_max : 0),
(long long)p->dispatch_max, (long long)p->data_shift, p->audio_wait, p->clock_wait);
(long long)p->dispatch_max, (long long)p->data_shift, p->audio_wait, p->clock_wait,
p->source_gaps, (long long)p->source_gap_max);
p->report_us = now; p->shown = p->order = p->audio_wait = p->clock_wait = 0;
p->interval_min = p->av_min = INT64_MAX; p->av_max = INT64_MIN;
p->interval_max = p->dispatch_max = p->data_shift = 0;
p->gap_pts = p->gap_received = p->gap_dispatch = 0;
p->source_gaps = 0; p->source_gap_max = 0;
}
enum call_video_playout_action call_video_playout_poll(struct call_video_playout *p,
@@ -60,10 +62,11 @@ enum call_video_playout_action call_video_playout_poll(struct call_video_playout
if (!audio_valid) { p->anchored = 0; p->clock_wait++; return CALL_VIDEO_PLAYOUT_WAIT; }
// Ожидание новых данных уже прошло в реальном времени: повторно добавлять этот интервал нельзя.
if (!f) { p->anchored = 0; return CALL_VIDEO_PLAYOUT_WAIT; }
if (f->pts_us <= p->last_pts || f->received_us < 0 || f->received_us > now) {
DEBUG_WARN(DEBUG_CATEGORY_CALL, "video playout invalid/order call=%llu pts=%lld last=%lld received=%lld now=%lld",
if (f->pts_us <= p->last_pts || f->received_us < 0 || f->received_us > now
|| f->interval_us < 16666 || f->interval_us > 1000000) {
DEBUG_WARN(DEBUG_CATEGORY_CALL, "video playout invalid/order call=%llu pts=%lld last=%lld received=%lld now=%lld interval_us=%u",
(unsigned long long)p->call_id, (long long)f->pts_us, (long long)p->last_pts,
(long long)f->received_us, (long long)now);
(long long)f->received_us, (long long)now, f->interval_us);
p->order++; return CALL_VIDEO_PLAYOUT_DROP_ORDER;
}
// Аудио задаёт базовый темп; долг видео снимается с постоянной 0.5с, максимум 1.6x.
@@ -73,7 +76,9 @@ enum call_video_playout_action call_video_playout_poll(struct call_video_playout
int64_t speed = base + correction;
p->speed_ppm = speed < VIDEO_MAX_SPEED_PPM ? (uint32_t)speed : VIDEO_MAX_SPEED_PPM;
int64_t delta = p->last_pts >= 0 ? f->pts_us - p->last_pts : 0;
int64_t step = delta / p->speed_ppm * 1000000 + delta % p->speed_ppm * 1000000 / p->speed_ppm;
// PTS-разрыв захвата уже прошёл; готовую голову нельзя снова удерживать delta/speed.
int64_t cadence = delta < f->interval_us ? delta : f->interval_us;
int64_t step = cadence * 1000000 / p->speed_ppm;
int64_t deadline = p->anchored ? p->last_deadline + step : now;
p->deadline_us = deadline;
if (av > VIDEO_AHEAD_US) {
@@ -81,6 +86,13 @@ enum call_video_playout_action call_video_playout_poll(struct call_video_playout
return CALL_VIDEO_PLAYOUT_WAIT;
}
if (deadline > now) return CALL_VIDEO_PLAYOUT_WAIT;
if (delta > (int64_t)f->interval_us * 3) {
if (!p->source_gaps) DEBUG_WARN(DEBUG_CATEGORY_CALL,
"video source gap call=%llu pts_delta_us=%lld interval_us=%u av_us=%lld display_step_us=%lld; no extra gap wait",
(unsigned long long)p->call_id, (long long)delta, f->interval_us, (long long)av, (long long)step);
p->source_gaps++;
if (delta > p->source_gap_max) p->source_gap_max = delta;
}
p->last_pts = f->pts_us; p->last_deadline = now; p->anchored = 1;
{
if (now - deadline > p->dispatch_max) p->dispatch_max = now - deadline;
+6 -1
View File
@@ -12,7 +12,10 @@
extern "C" {
#endif
struct call_video_playout_frame { int64_t pts_us, received_us; };
struct call_video_playout_frame {
int64_t pts_us, received_us;
uint32_t interval_us; // 1000000/format.fps: предел интервала показа, пауза capture не растягивает его.
};
enum call_video_playout_action {
CALL_VIDEO_PLAYOUT_WAIT, CALL_VIDEO_PLAYOUT_SHOW, CALL_VIDEO_PLAYOUT_DROP_ORDER
};
@@ -24,6 +27,8 @@ struct call_video_playout {
int64_t last_show_pts, last_received, gap_pts, gap_received, gap_dispatch;
uint32_t speed_ppm; // Темп аудио + коррекция отставания, максимум 1.6x.
unsigned shown, order, audio_wait, clock_wait;
unsigned source_gaps;
int64_t source_gap_max; // Большие разрывы capture PTS, уже прошедшие до показа.
};
int64_t call_video_playout_now_us(void);