Skip to content

Commit 25499a6

Browse files
Fix: use media-clock ticks for RL RTP timestamp offset
The RL pacing warm-up compensation was computed in nanoseconds and subtracted from the TAI time before converting to media-clock ticks. This caused rounding errors for fractional frame rates like 1080i59, where the ns-domain subtraction could land on a tick boundary and produce repeated or skipped RTP timestamps. Convert the offset to media-clock ticks directly. Also document the truncation-toward-zero requirement for callers that derive TAI timestamps from rational frame periods (see issue #1321).
1 parent 16c4818 commit 25499a6

File tree

3 files changed

+32
-15
lines changed

3 files changed

+32
-15
lines changed

include/st_api.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,18 @@ enum st_fps st_name_to_fps(const char* name);
368368
/**
369369
* Helper function to convert ST10_TIMESTAMP_FMT_TAI to ST10_TIMESTAMP_FMT_MEDIA_CLK.
370370
*
371+
* The conversion quantises the continuous TAI time to a discrete media-clock tick
372+
* by computing: tick = round(tai_ns * sampling_rate / 1e9). Because the media
373+
* clock is discrete, a difference of just 1 ns in the input can change the output
374+
* by one tick when the value lies exactly on a tick boundary.
375+
*
376+
* Callers that derive tai_ns from a frame number and frame period (which is a
377+
* rational number, e.g. 1001/60000 s for 59.94 fps) must use truncation toward
378+
* zero — **not** rounding — when converting the rational time to nanoseconds,
379+
* i.e. tai_ns = (uint64_t)(frame_number * period_num / period_den).
380+
* Using roundl() or similar can push the value past a tick boundary, producing
381+
* repeated or skipped RTP timestamps.
382+
*
371383
* @param tai_ns
372384
* time in nanoseconds since the TAI epoch.
373385
* @param sampling_rate

lib/src/st2110/st_header.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -173,8 +173,8 @@ struct st_tx_video_pacing {
173173
/* in ns, idle time at the end of frame, frame_time - tr_offset - (trs * pkts) */
174174
double frame_idle_time;
175175
double reactive;
176-
float pad_interval; /* padding pkt interval(pkts level) for RL pacing */
177-
uint64_t rl_rtp_offset_ns; /* RL-only RTP timestamp shift (ns), compensates warm-up */
176+
float pad_interval; /* padding pkt interval(pkts level) for RL pacing */
177+
uint32_t rl_rtp_offset_ticks; /* RL-only RTP timestamp shift (media-clk ticks) */
178178

179179
uint64_t cur_epochs; /* epoch of current frame */
180180
/* timestamp for rtp header */

lib/src/st2110/st_tx_video_session.c

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
#include "st_video_transmitter.h"
1616

1717
#define MTL_LATENCY_COMPENSATION_PACKET_SHIFT 5
18+
#define MTL_LATENCY_COMPENSATION_PACKET_SHIFT_MIN_TICK \
19+
1 /* at least shift 1 tick for RL pacing */
1820

1921
#ifdef MTL_SIMULATE_PACKET_DROPS
2022
static inline void tv_simulate_packet_loss(struct st_tx_video_session_impl* s,
@@ -523,7 +525,7 @@ static int tv_init_pacing(struct mtl_main_impl* impl,
523525
dbg("%s[%02d], max_onward_epochs %u\n", __func__, idx, pacing->max_onward_epochs);
524526
/* default VRX compensate as rl accuracy, update later in tv_train_pacing */
525527
pacing->pad_interval = s->st20_total_pkts;
526-
pacing->rl_rtp_offset_ns = 0; /* set later for RL pacing */
528+
pacing->rl_rtp_offset_ticks = 0; /* set later for RL pacing */
527529

528530
int num_port = s->ops.num_port;
529531
int ret;
@@ -560,8 +562,10 @@ static int tv_init_pacing(struct mtl_main_impl* impl,
560562

561563
/* RL pacing: shift RTP timestamp back by few packets to compensate warm-up pad */
562564
if (s->pacing_way[MTL_SESSION_PORT_P] == ST21_TX_PACING_WAY_RL) {
563-
pacing->rl_rtp_offset_ns =
564-
(uint64_t)(MTL_LATENCY_COMPENSATION_PACKET_SHIFT * pacing->trs);
565+
pacing->rl_rtp_offset_ticks =
566+
RTE_MAX(MTL_LATENCY_COMPENSATION_PACKET_SHIFT_MIN_TICK,
567+
st10_tai_to_media_clk(MTL_LATENCY_COMPENSATION_PACKET_SHIFT * pacing->trs,
568+
s->fps_tm.sampling_clock_rate));
565569
}
566570

567571
/* calculate vrx pkts */
@@ -602,10 +606,10 @@ static int tv_init_pacing(struct mtl_main_impl* impl,
602606
}
603607
info(
604608
"%s[%02d], trs %f trOffset %f vrx %u warm_pkts %u frame time %fms fps %f "
605-
"rl_rtp_adj %" PRIu64 "ns\n",
609+
"rl_rtp_adj %u ticks\n",
606610
__func__, idx, pacing->trs, pacing->tr_offset, pacing->vrx, pacing->warm_pkts,
607611
pacing->frame_time / NS_PER_MS, st_frame_rate(s->ops.fps),
608-
pacing->rl_rtp_offset_ns);
612+
pacing->rl_rtp_offset_ticks);
609613
/* resolve pacing tasklet */
610614
for (int i = 0; i < num_port; i++) {
611615
ret = st_video_resolve_pacing_tasklet(s, i);
@@ -746,9 +750,10 @@ static void tv_update_rtp_time_stamp(struct st_tx_video_session_impl* s,
746750
} else {
747751
tai_for_rtp_ts = pacing->ptp_time_cursor;
748752
}
749-
tai_for_rtp_ts += delta_ns - pacing->rl_rtp_offset_ns;
753+
tai_for_rtp_ts += delta_ns;
750754
pacing->rtp_time_stamp =
751-
st10_tai_to_media_clk(tai_for_rtp_ts, s->fps_tm.sampling_clock_rate);
755+
st10_tai_to_media_clk(tai_for_rtp_ts, s->fps_tm.sampling_clock_rate) -
756+
pacing->rl_rtp_offset_ticks;
752757
}
753758
dbg("%s(%d), rtp time stamp %u\n", __func__, s->idx, pacing->rtp_time_stamp);
754759
}
@@ -1366,10 +1371,10 @@ static int tv_build_rtp(struct mtl_main_impl* impl, struct st_tx_video_session_i
13661371
} else {
13671372
tai_for_rtp_ts = s->pacing.ptp_time_cursor;
13681373
}
1369-
tai_for_rtp_ts += (uint64_t)s->ops.rtp_timestamp_delta_us * NS_PER_US -
1370-
s->pacing.rl_rtp_offset_ns;
1374+
tai_for_rtp_ts += (uint64_t)s->ops.rtp_timestamp_delta_us * NS_PER_US;
13711375
s->pacing.rtp_time_stamp =
1372-
st10_tai_to_media_clk(tai_for_rtp_ts, s->fps_tm.sampling_clock_rate);
1376+
st10_tai_to_media_clk(tai_for_rtp_ts, s->fps_tm.sampling_clock_rate) -
1377+
s->pacing.rl_rtp_offset_ticks;
13731378
}
13741379
dbg("%s(%d), rtp time stamp %u\n", __func__, s->idx, s->pacing.rtp_time_stamp);
13751380
}
@@ -1439,10 +1444,10 @@ static int tv_build_rtp_chain(struct mtl_main_impl* impl,
14391444
} else {
14401445
tai_for_rtp_ts = s->pacing.ptp_time_cursor;
14411446
}
1442-
tai_for_rtp_ts += (uint64_t)s->ops.rtp_timestamp_delta_us * NS_PER_US -
1443-
s->pacing.rl_rtp_offset_ns;
1447+
tai_for_rtp_ts += (uint64_t)s->ops.rtp_timestamp_delta_us * NS_PER_US;
14441448
s->pacing.rtp_time_stamp =
1445-
st10_tai_to_media_clk(tai_for_rtp_ts, s->fps_tm.sampling_clock_rate);
1449+
st10_tai_to_media_clk(tai_for_rtp_ts, s->fps_tm.sampling_clock_rate) -
1450+
s->pacing.rl_rtp_offset_ticks;
14461451
}
14471452
dbg("%s(%d), rtp time stamp %u\n", __func__, s->idx, s->pacing.rtp_time_stamp);
14481453
}

0 commit comments

Comments
 (0)