diff --git a/app/src/app_base.h b/app/src/app_base.h index 1f7b86c67..6c21f68db 100644 --- a/app/src/app_base.h +++ b/app/src/app_base.h @@ -507,6 +507,7 @@ struct st_app_context { bool enable_hdr_split; bool tx_copy_once; bool app_thread; + bool enable_timing_parser; bool ptp_systime_sync; int ptp_sync_cnt; diff --git a/app/src/args.c b/app/src/args.c index e72566335..b515ac5ef 100644 --- a/app/src/args.c +++ b/app/src/args.c @@ -61,7 +61,7 @@ enum st_args_cmd { ST_ARG_TEST_TIME, ST_ARG_PTP_UNICAST_ADDR, ST_ARG_CNI_THREAD, - ST_ARG_RX_EBU, + ST_ARG_RX_TIMING_PARSER, ST_ARG_USER_LCORES, ST_ARG_SCH_DATA_QUOTA, ST_ARG_SCH_SESSION_QUOTA, @@ -182,7 +182,7 @@ static struct option st_app_args_options[] = { {"test_time", required_argument, 0, ST_ARG_TEST_TIME}, {"ptp_unicast", no_argument, 0, ST_ARG_PTP_UNICAST_ADDR}, {"cni_thread", no_argument, 0, ST_ARG_CNI_THREAD}, - {"ebu", no_argument, 0, ST_ARG_RX_EBU}, + {"rx_timing_parser", no_argument, 0, ST_ARG_RX_TIMING_PARSER}, {"lcores", required_argument, 0, ST_ARG_USER_LCORES}, {"sch_data_quota", required_argument, 0, ST_ARG_SCH_DATA_QUOTA}, {"sch_session_quota", required_argument, 0, ST_ARG_SCH_SESSION_QUOTA}, @@ -528,8 +528,9 @@ int st_app_parse_args(struct st_app_context* ctx, struct mtl_init_params* p, int case ST_ARG_TEST_TIME: ctx->test_time_s = atoi(optarg); break; - case ST_ARG_RX_EBU: - p->flags |= MTL_FLAG_RX_VIDEO_EBU; + case ST_ARG_RX_TIMING_PARSER: + ctx->enable_timing_parser = true; + p->flags |= MTL_FLAG_ENABLE_HW_TIMESTAMP; break; case ST_ARG_RX_MONO_POOL: p->flags |= MTL_FLAG_RX_MONO_POOL; diff --git a/app/src/rx_audio_app.c b/app/src/rx_audio_app.c index 1d1e5fd35..a99af42d4 100644 --- a/app/src/rx_audio_app.c +++ b/app/src/rx_audio_app.c @@ -281,6 +281,7 @@ static int app_rx_audio_init(struct st_app_context* ctx, st_json_audio_session_t ops.framebuff_cnt = s->framebuff_cnt; ops.rtp_ring_size = ctx->rx_audio_rtp_ring_size ? ctx->rx_audio_rtp_ring_size : 16; if (audio && audio->enable_rtcp) ops.flags |= ST30_RX_FLAG_ENABLE_RTCP; + if (ctx->enable_timing_parser) ops.flags |= ST30_RX_FLAG_ENABLE_TIMING_PARSER; st_pthread_mutex_init(&s->st30_wake_mutex, NULL); st_pthread_cond_init(&s->st30_wake_cond, NULL); diff --git a/app/src/rx_st20p_app.c b/app/src/rx_st20p_app.c index 546c4210c..ca9fb330b 100644 --- a/app/src/rx_st20p_app.c +++ b/app/src/rx_st20p_app.c @@ -240,6 +240,7 @@ static int app_rx_st20p_init(struct st_app_context* ctx, /* always try to enable DMA offload */ ops.flags = ST20P_RX_FLAG_DMA_OFFLOAD; if (st20p && st20p->enable_rtcp) ops.flags |= ST20P_RX_FLAG_ENABLE_RTCP; + if (ctx->enable_timing_parser) ops.flags |= ST20P_RX_FLAG_ENABLE_TIMING_PARSER; st_pthread_mutex_init(&s->st20p_wake_mutex, NULL); st_pthread_cond_init(&s->st20p_wake_cond, NULL); diff --git a/app/src/rx_video_app.c b/app/src/rx_video_app.c index 6bee129ba..c8ba34858 100644 --- a/app/src/rx_video_app.c +++ b/app/src/rx_video_app.c @@ -565,6 +565,7 @@ static int app_rx_video_init(struct st_app_context* ctx, st_json_video_session_t ops_rtcp.nack_interval_us = 250; ops.rtcp = &ops_rtcp; } + if (ctx->enable_timing_parser) ops.flags |= ST20_RX_FLAG_ENABLE_TIMING_PARSER; st_pthread_mutex_init(&s->st20_wake_mutex, NULL); st_pthread_cond_init(&s->st20_wake_cond, NULL); diff --git a/doc/run.md b/doc/run.md index 909c56758..93dfaf31d 100644 --- a/doc/run.md +++ b/doc/run.md @@ -313,7 +313,7 @@ If it failed to run the sample, please help to collect the system setup status b --log_file : set log file for mtl log. If you're initiating multiple RxTxApp processes simultaneously, please ensure each process has a unique filename path. Default the log is writing to stderr. --arp_timeout_s : set the arp timeout in seconds if using unicast address. Default timeout value is 60 seconds. ---ebu : debug option, enable timing check for video rx streams. +--rx_timing_parser : debug option, enable timing check for video rx streams. --pcapng_dump : debug option, dump n packets from rx video streams to pcapng files. --rx_video_file_frames : debug option, dump the received video frames to a yuv file, n is dump file size in frame unit. --rx_video_fb_cnt : debug option, the frame buffer count. diff --git a/include/mtl_api.h b/include/mtl_api.h index c69aabb51..d4d6dc0c5 100644 --- a/include/mtl_api.h +++ b/include/mtl_api.h @@ -384,9 +384,10 @@ enum st21_tx_pacing_way { #define MTL_FLAG_CNI_THREAD (MTL_BIT64(32)) /** * Flag bit in flags of struct mtl_init_params, debug usage only. - * Enable video rx ebu check + * Enable HW offload timestamp for all RX packets target the compliance analyze. Only can + * work for PF on E810 now. */ -#define MTL_FLAG_RX_VIDEO_EBU (MTL_BIT64(33)) +#define MTL_FLAG_ENABLE_HW_TIMESTAMP (MTL_BIT64(33)) /** * Flag bit in flags of struct mtl_init_params, debug usage only. * Enable NIC promiscuous mode for RX diff --git a/include/st20_api.h b/include/st20_api.h index ad188cf98..7f371a947 100644 --- a/include/st20_api.h +++ b/include/st20_api.h @@ -190,6 +190,11 @@ extern "C" { * Always disable MIGRATE for this session. */ #define ST20_RX_FLAG_DISABLE_MIGRATE (MTL_BIT32(20)) +/** + * Flag bit in flags of struct st20_rx_ops. + * Enable the timing analyze + */ +#define ST20_RX_FLAG_ENABLE_TIMING_PARSER (MTL_BIT32(21)) /** * Flag bit in flags of struct st22_rx_ops, for non MTL_PMD_DPDK_USER. diff --git a/include/st30_api.h b/include/st30_api.h index b7ab58a9e..eb87e299d 100644 --- a/include/st30_api.h +++ b/include/st30_api.h @@ -72,6 +72,11 @@ typedef struct st_rx_audio_session_handle_impl* st30_rx_handle; * If enable the rtcp. */ #define ST30_RX_FLAG_ENABLE_RTCP (MTL_BIT32(1)) +/** + * Flag bit in flags of struct st30_rx_ops. + * Enable the timing analyze + */ +#define ST30_RX_FLAG_ENABLE_TIMING_PARSER (MTL_BIT32(16)) /** default time in the fifo between packet builder and pacing */ #define ST30_TX_FIFO_DEFAULT_TIME_MS (10) diff --git a/include/st_pipeline_api.h b/include/st_pipeline_api.h index 5461d10c8..49b16b2ee 100644 --- a/include/st_pipeline_api.h +++ b/include/st_pipeline_api.h @@ -540,6 +540,11 @@ enum st22_quality_mode { * Always disable MIGRATE for this session. */ #define ST20P_RX_FLAG_DISABLE_MIGRATE (MTL_BIT32(20)) +/** + * Flag bit in flags of struct st20p_rx_ops. + * Enable the timing analyze + */ +#define ST20P_RX_FLAG_ENABLE_TIMING_PARSER (MTL_BIT32(21)) /** The structure info for st plugin encode session create request. */ struct st22_encoder_create_req { diff --git a/lib/src/dev/mt_dev.c b/lib/src/dev/mt_dev.c index 14a4e55e7..ce48c2464 100644 --- a/lib/src/dev/mt_dev.c +++ b/lib/src/dev/mt_dev.c @@ -1763,7 +1763,7 @@ int mt_dev_create(struct mtl_main_impl* impl) { #if RTE_VERSION >= RTE_VERSION_NUM(21, 11, 0, 0) /* DPDK 21.11 support start time sync before rte_eth_dev_start */ - if ((mt_user_ptp_service(impl) || mt_user_ebu_active(impl)) && + if ((mt_user_ptp_service(impl) || mt_user_hw_timestamp(impl)) && (port_type == MT_PORT_PF)) { ret = dev_start_timesync(inf); if (ret >= 0) inf->feature |= MT_IF_FEATURE_TIMESYNC; @@ -1798,7 +1798,7 @@ int mt_dev_create(struct mtl_main_impl* impl) { } } /* try to start time sync after rte_eth_dev_start */ - if ((mt_user_ptp_service(impl) || mt_user_ebu_active(impl)) && + if ((mt_user_ptp_service(impl) || mt_user_hw_timestamp(impl)) && (port_type == MT_PORT_PF) && !(inf->feature & MT_IF_FEATURE_TIMESYNC)) { ret = dev_start_timesync(inf); if (ret >= 0) inf->feature |= MT_IF_FEATURE_TIMESYNC; @@ -2192,7 +2192,7 @@ int mt_dev_if_init(struct mtl_main_impl* impl) { } #endif - if (mt_user_ebu_active(impl) && + if (mt_user_hw_timestamp(impl) && #if RTE_VERSION >= RTE_VERSION_NUM(22, 3, 0, 0) (dev_info->rx_offload_capa & RTE_ETH_RX_OFFLOAD_TIMESTAMP) #else diff --git a/lib/src/mt_main.h b/lib/src/mt_main.h index 1d775580d..b9a27ffa0 100644 --- a/lib/src/mt_main.h +++ b/lib/src/mt_main.h @@ -1397,9 +1397,9 @@ static inline bool mt_user_quota_active(struct mtl_main_impl* impl) { return false; } -/* if user enable ebu feature */ -static inline bool mt_user_ebu_active(struct mtl_main_impl* impl) { - if (mt_get_user_params(impl)->flags & MTL_FLAG_RX_VIDEO_EBU) +/* if user enable hw offload timestamp */ +static inline bool mt_user_hw_timestamp(struct mtl_main_impl* impl) { + if (mt_get_user_params(impl)->flags & MTL_FLAG_ENABLE_HW_TIMESTAMP) return true; else return false; @@ -1582,6 +1582,14 @@ static inline bool mt_if_has_timesync(struct mtl_main_impl* impl, enum mtl_port return false; } +static inline bool mt_if_has_offload_timestamp(struct mtl_main_impl* impl, + enum mtl_port port) { + if (mt_if(impl, port)->feature & MT_IF_FEATURE_RX_OFFLOAD_TIMESTAMP) + return true; + else + return false; +} + static inline bool mt_if_has_offload_ipv4_cksum(struct mtl_main_impl* impl, enum mtl_port port) { if (mt_if(impl, port)->feature & MT_IF_FEATURE_TX_OFFLOAD_IPV4_CKSUM) @@ -1838,8 +1846,8 @@ struct rte_mbuf* mt_pcapng_copy(struct mtl_main_impl* impl, enum mtl_port port, enum rte_pcapng_direction direction); #endif -uint64_t mt_mbuf_hw_time_stamp(struct mtl_main_impl* impl, struct rte_mbuf* mbuf, - enum mtl_port port); +uint64_t mt_mbuf_time_stamp(struct mtl_main_impl* impl, struct rte_mbuf* mbuf, + enum mtl_port port); static inline uint64_t mt_get_ptp_time(struct mtl_main_impl* impl, enum mtl_port port) { return mt_if(impl, port)->ptp_get_time_fn(impl, port); diff --git a/lib/src/mt_ptp.c b/lib/src/mt_ptp.c index d32fe5e6b..f117b3bec 100644 --- a/lib/src/mt_ptp.c +++ b/lib/src/mt_ptp.c @@ -19,7 +19,7 @@ #define MT_PTP_CHECK_RX_TIME_STAMP (0) #define MT_PTP_PRINT_ERR_RESULT (0) -#define MT_PTP_EBU_SYNC_MS (10) +#define MT_PTP_TP_SYNC_MS (10) #define MT_PTP_DEFAULT_KP 5e-10 /* to be tuned */ #define MT_PTP_DEFAULT_KI 1e-10 /* to be tuned */ @@ -1070,7 +1070,7 @@ static void ptp_sync_from_user_handler(void* param) { struct mt_ptp_impl* ptp = param; ptp_sync_from_user(ptp->impl, ptp); - rte_eal_alarm_set(MT_PTP_EBU_SYNC_MS * 1000, ptp_sync_from_user_handler, ptp); + rte_eal_alarm_set(MT_PTP_TP_SYNC_MS * 1000, ptp_sync_from_user_handler, ptp); } #ifdef WINDOWSENV @@ -1233,11 +1233,11 @@ static int ptp_init(struct mtl_main_impl* impl, struct mt_ptp_impl* ptp, ptp_coefficient_result_reset(ptp); if (!mt_user_ptp_service(impl)) { - if (mt_user_ebu_active(impl)) { + if (mt_if_has_offload_timestamp(impl, port)) { ptp->no_timesync = true; - info("%s(%d), ptp running for ebu without time sync\n", __func__, port); + info("%s(%d), ptp sync from user for hw offload timestamp\n", __func__, port); ptp_sync_from_user(impl, ptp); - rte_eal_alarm_set(MT_PTP_EBU_SYNC_MS * 1000, ptp_sync_from_user_handler, ptp); + rte_eal_alarm_set(MT_PTP_TP_SYNC_MS * 1000, ptp_sync_from_user_handler, ptp); ptp->connected = true; ptp->locked = true; ptp->active = true; @@ -1397,7 +1397,6 @@ int mt_ptp_parse(struct mt_ptp_impl* ptp, struct mt_ptp_header* hdr, bool vlan, static int ptp_stat(void* priv) { struct mt_ptp_impl* ptp = priv; - struct mtl_main_impl* impl = ptp->impl; enum mtl_port port = ptp->port; char date_time[64]; struct timespec spec; @@ -1411,19 +1410,7 @@ static int ptp_stat(void* priv) { strftime(date_time, sizeof(date_time), "%Y-%m-%d %H:%M:%S", &t); notice("PTP(%d): time %" PRIu64 ", %s\n", port, ns, date_time); - if (!ptp->active) { - if (mt_user_ebu_active(impl)) { - notice("PTP(%d): raw ptp %" PRIu64 "\n", port, ptp_get_raw_time(ptp)); - if (ptp->stat_delta_cnt) { - notice("PTP(%d): delta avr %" PRId64 ", min %" PRId64 ", max %" PRId64 - ", cnt %d, expect %d\n", - port, ptp->stat_delta_sum / ptp->stat_delta_cnt, ptp->stat_delta_min, - ptp->stat_delta_max, ptp->stat_delta_cnt, ptp->expect_result_avg); - } - ptp_stat_clear(ptp); - } - return 0; - } + if (!ptp->active) return 0; if (ptp->stat_delta_cnt) { if (ptp->phc2sys_active) { @@ -1514,8 +1501,8 @@ uint64_t mt_get_raw_ptp_time(struct mtl_main_impl* impl, enum mtl_port port) { return ptp_get_raw_time(mt_get_ptp(impl, port)); } -uint64_t mt_mbuf_hw_time_stamp(struct mtl_main_impl* impl, struct rte_mbuf* mbuf, - enum mtl_port port) { +static uint64_t mbuf_hw_time_stamp(struct mtl_main_impl* impl, struct rte_mbuf* mbuf, + enum mtl_port port) { struct mt_ptp_impl* ptp = mt_get_ptp(impl, port); uint64_t time_stamp = *RTE_MBUF_DYNFIELD(mbuf, impl->dynfield_offset, rte_mbuf_timestamp_t*); @@ -1523,6 +1510,14 @@ uint64_t mt_mbuf_hw_time_stamp(struct mtl_main_impl* impl, struct rte_mbuf* mbuf return ptp_correct_ts(ptp, time_stamp); } +uint64_t mt_mbuf_time_stamp(struct mtl_main_impl* impl, struct rte_mbuf* mbuf, + enum mtl_port port) { + if (mt_if_has_offload_timestamp(impl, port)) + return mbuf_hw_time_stamp(impl, mbuf, port); + else + return mtl_ptp_read_time(impl); +} + int mt_ptp_wait_stable(struct mtl_main_impl* impl, enum mtl_port port, int timeout_ms) { struct mt_ptp_impl* ptp = mt_get_ptp(impl, port); uint64_t start_ts = mt_get_tsc(impl); diff --git a/lib/src/mt_ptp.h b/lib/src/mt_ptp.h index b9707aa40..d985b5d81 100644 --- a/lib/src/mt_ptp.h +++ b/lib/src/mt_ptp.h @@ -114,6 +114,10 @@ int mt_ptp_parse(struct mt_ptp_impl* ptp, struct mt_ptp_header* hdr, bool vlan, enum mt_ptp_l_mode mode, uint16_t timesync, struct mt_ipv4_udp* ipv4_hdr); +static inline bool mt_ptp_is_active(struct mtl_main_impl* impl, enum mtl_port port) { + return mt_get_ptp(impl, port)->active; +} + static inline bool mt_ptp_is_locked(struct mtl_main_impl* impl, enum mtl_port port) { return mt_get_ptp(impl, port)->locked; } diff --git a/lib/src/st2110/meson.build b/lib/src/st2110/meson.build index 6c9c8575e..b8c94f614 100644 --- a/lib/src/st2110/meson.build +++ b/lib/src/st2110/meson.build @@ -17,7 +17,7 @@ sources += files( 'st_avx512_vbmi.c', 'st_convert.c', 'st_fmt.c', - 'st_rx_ebu.c', + 'st_rx_timing_parser.c', ) subdir('pipeline') diff --git a/lib/src/st2110/pipeline/st20_pipeline_rx.c b/lib/src/st2110/pipeline/st20_pipeline_rx.c index 742caa6d6..d0f8a4992 100644 --- a/lib/src/st2110/pipeline/st20_pipeline_rx.c +++ b/lib/src/st2110/pipeline/st20_pipeline_rx.c @@ -393,6 +393,8 @@ static int rx_st20p_create_transport(struct mtl_main_impl* impl, struct st20p_rx if (ops->flags & ST20P_RX_FLAG_HDR_SPLIT) ops_rx.flags |= ST20_RX_FLAG_HDR_SPLIT; if (ops->flags & ST20P_RX_FLAG_DISABLE_MIGRATE) ops_rx.flags |= ST20_RX_FLAG_DISABLE_MIGRATE; + if (ops->flags & ST20P_RX_FLAG_ENABLE_TIMING_PARSER) + ops_rx.flags |= ST20_RX_FLAG_ENABLE_TIMING_PARSER; if (ops->flags & ST20P_RX_FLAG_PKT_CONVERT) { uint64_t pkt_cvt_output_cap = ST_FMT_CAP_YUV422PLANAR10LE | ST_FMT_CAP_Y210 | ST_FMT_CAP_UYVY; diff --git a/lib/src/st2110/st_header.h b/lib/src/st2110/st_header.h index eb3c6e03a..99bfd22ca 100644 --- a/lib/src/st2110/st_header.h +++ b/lib/src/st2110/st_header.h @@ -501,14 +501,14 @@ struct st_rx_session_priv { enum mtl_session_port s_port; }; -enum st_rv_ebu_compliant { - ST_RV_EBU_COMPLIANT_FAILED = 0, - ST_RV_EBU_COMPLIANT_WIDE, - ST_RV_EBU_COMPLIANT_NARROW, - ST_RV_EBU_COMPLIANT_MAX, +enum st_rx_tp_compliant { + ST_RX_TP_COMPLIANT_FAILED = 0, + ST_RX_TP_COMPLIANT_WIDE, + ST_RX_TP_COMPLIANT_NARROW, + ST_RX_TP_COMPLIANT_MAX, }; -struct st_rv_ebu_slot { +struct st_rv_tp_slot { /* epoch of current slot */ uint64_t cur_epochs; /* result(packet) cnt in current slot */ @@ -546,12 +546,12 @@ struct st_rv_ebu_slot { int64_t ipt_sum; float ipt_avg; - enum st_rv_ebu_compliant compliant; + enum st_rx_tp_compliant compliant; }; -struct st_rv_ebu_stat { +struct st_rv_tp_stat { /* for the status */ - struct st_rv_ebu_slot slot; + struct st_rv_tp_slot slot; uint32_t stat_frame_cnt; int32_t stat_fpt_min; @@ -566,10 +566,10 @@ struct st_rv_ebu_stat { int32_t stat_rtp_ts_delta_min; int32_t stat_rtp_ts_delta_max; float stat_rtp_ts_delta_sum; - uint32_t stat_compliant_result[ST_RV_EBU_COMPLIANT_MAX]; + uint32_t stat_compliant_result[ST_RX_TP_COMPLIANT_MAX]; }; -struct st_rx_video_ebu { +struct st_rx_video_tp { /* in ns for of 2 consecutive packets, T-Frame / N-Packets */ double trs; /* in ns, tr offset time of each frame */ @@ -581,12 +581,12 @@ struct st_rx_video_ebu { uint32_t vrx_full_wide_pass; int32_t rtp_offset_max_pass; - /* ebu timing info for each slot */ - struct st_rv_ebu_slot slots[ST_VIDEO_RX_REC_NUM_OFO]; + /* timing info for each slot */ + struct st_rv_tp_slot slots[ST_VIDEO_RX_REC_NUM_OFO]; uint32_t pre_rtp_tmstamp; /* for the status */ - struct st_rv_ebu_stat stat; + struct st_rv_tp_stat stat; }; struct st_rx_video_session_impl { @@ -695,9 +695,9 @@ struct st_rx_video_session_impl { int (*pkt_handler)(struct st_rx_video_session_impl* s, struct rte_mbuf* mbuf, enum mtl_session_port s_port, bool ctrl_thread); - /* if enable the ebu parser for the st2110-21 timing */ - bool enable_ebu; - struct st_rx_video_ebu* ebu; + /* if enable the parser for the st2110-21 timing */ + bool enable_timing_parser; + struct st_rx_video_tp* tp; /* status */ int stat_pkts_idx_dropped; @@ -882,42 +882,36 @@ struct st_audio_transmitter_impl { int inflight_cnt[MTL_PORT_MAX]; /* for stats */ }; -struct st_rx_audio_ebu_info { - double frame_time; /* time of the frame in nanoseconds */ - double frame_time_sampling; /* time of the frame in sampling */ - int dropped_results; /* number of results to drop at the beginning */ - - /* Pass Criteria */ - int32_t dpvr_max_pass_narrow; - int32_t dpvr_max_pass_wide; - float dpvr_avg_pass_wide; - int32_t tsdf_max_pass; +struct st_ra_tp_slot { + uint32_t pkt_cnt; + int32_t dpvr_min; + int32_t dpvr_max; + int64_t dpvr_sum; + enum st_rx_tp_compliant compliant; }; -struct st_rx_audio_ebu_stat { - uint32_t pkt_num; - bool compliant; +struct st_ra_tp_stat { + uint32_t stat_compliant_result[ST_RX_TP_COMPLIANT_MAX]; + struct st_ra_tp_slot slot; + int32_t dpvr_first; +}; +struct st_rx_audio_tp { + /* time of the frame in nanoseconds */ + double frame_time; + /* time of the frame in sampling */ + double frame_time_sampling; + /* Pass Criteria*/ /* Delta Packet vs RTP */ - int64_t dpvr_max; - int64_t dpvr_min; - uint32_t dpvr_cnt; - uint64_t dpvr_sum; - float dpvr_avg; - int64_t dpvr_first; - + int32_t dpvr_max_pass_narrow; /* in us */ + int32_t dpvr_max_pass_wide; /* in us */ /* Maximum Timestamped Delay Factor */ - int64_t tsdf_max; -}; + int32_t tsdf_max_pass; /* in us */ -struct st_rx_audio_ebu_result { - int ebu_result_num; - int dpvr_pass_narrow; - int dpvr_pass_wide; - int dpvr_fail; - int tsdf_pass; - int tsdf_fail; - int compliance; + /* timing info for each frame */ + struct st_ra_tp_slot slot; + /* for the status */ + struct st_ra_tp_stat stat; }; struct st_rx_audio_session_impl { @@ -928,6 +922,7 @@ struct st_rx_audio_session_impl { struct st_rx_session_priv priv[MTL_SESSION_PORT_MAX]; struct st_rx_audio_session_handle_impl* st30_handle; bool time_measure; + bool enable_timing_parser; enum mtl_port port_maps[MTL_SESSION_PORT_MAX]; struct mt_rxq_entry* rxq[MTL_SESSION_PORT_MAX]; @@ -955,6 +950,8 @@ struct st_rx_audio_session_impl { struct mt_rtcp_rx* rtcp_rx[MTL_SESSION_PORT_MAX]; + struct st_rx_audio_tp* tp; + /* status */ int st30_stat_pkts_dropped; int st30_stat_pkts_wrong_pt_dropped; @@ -966,10 +963,6 @@ struct st_rx_audio_session_impl { int st30_stat_pkts_rtp_ring_full; uint64_t st30_stat_last_time; uint32_t stat_max_notify_frame_us; - - struct st_rx_audio_ebu_info ebu_info; - struct st_rx_audio_ebu_stat ebu; - struct st_rx_audio_ebu_result ebu_result; }; struct st_rx_audio_sessions_mgr { diff --git a/lib/src/st2110/st_pkt.h b/lib/src/st2110/st_pkt.h index f6af33dbf..44b35412e 100644 --- a/lib/src/st2110/st_pkt.h +++ b/lib/src/st2110/st_pkt.h @@ -13,21 +13,21 @@ #define ST_RARTP_PAYLOAD_TYPE_PCM_AUDIO (111) #define ST_RANCRTP_PAYLOAD_TYPE_ANCILLARY (113) -#define ST_EBU_CINST_DRAIN_FACTOR (1.1f) /* Drain factor */ +#define ST_TP_CINST_DRAIN_FACTOR (1.1f) /* Drain factor */ -#define ST_EBU_LATENCY_MAX_US (1000) /* Latency in us */ -#define ST_EBU_LATENCY_MAX_NS (1000 * ST_EBU_LATENCY_MAX_US) /* Latency in ns */ +#define ST_TP_LATENCY_MAX_US (1000) /* Latency in us */ +#define ST_TP_LATENCY_MAX_NS (1000 * ST_TP_LATENCY_MAX_US) /* Latency in ns */ -#define ST_EBU_RTP_OFFSET_MIN (-1) /* MIN RTP Offset */ +#define ST_TP_RTP_OFFSET_MIN (-1) /* MIN RTP Offset */ -#define ST_EBU_RTP_WRAP_AROUND (0x100000000) +#define ST_TP_RTP_WRAP_AROUND (0x100000000) -#define ST_EBU_PASS_NARROW "PASSED NARROW" -#define ST_EBU_PASS_WIDE "FAILED with WIDE" +#define ST_TP_PASS_NARROW "PASSED NARROW" +#define ST_TP_PASS_WIDE "FAILED with WIDE" /* Extend WA WIDE as no hw rx time */ -#define ST_EBU_PASS_WIDE_WA "FAILED with WIDE WA error" -#define ST_EBU_PASS "PASSED" -#define ST_EBU_FAIL "FAILED" +#define ST_TP_PASS_WIDE_WA "FAILED with WIDE WA error" +#define ST_TP_PASS "PASSED" +#define ST_TP_FAIL "FAILED" /* total size: 54 */ struct st_rfc3550_hdr { diff --git a/lib/src/st2110/st_rx_audio_session.c b/lib/src/st2110/st_rx_audio_session.c index 08a1536e3..0d0001b88 100644 --- a/lib/src/st2110/st_rx_audio_session.c +++ b/lib/src/st2110/st_rx_audio_session.c @@ -9,183 +9,13 @@ #include "../datapath/mt_queue.h" #include "../mt_log.h" #include "../mt_stat.h" - -static inline double ra_ebu_pass_rate(struct st_rx_audio_ebu_result* ebu_result, - int pass) { - return (double)pass * 100 / ebu_result->ebu_result_num; -} +#include "st_rx_timing_parser.h" static inline uint16_t rx_audio_queue_id(struct st_rx_audio_session_impl* s, enum mtl_session_port s_port) { return mt_rxq_queue_id(s->rxq[s_port]); } -static void rx_audio_session_ebu_result(struct st_rx_audio_session_impl* s) { - int idx = s->idx; - struct st_rx_audio_ebu_info* ebu_info = &s->ebu_info; - struct st_rx_audio_ebu_result* ebu_result = &s->ebu_result; - - ebu_result->ebu_result_num -= ebu_info->dropped_results; - if (ebu_result->ebu_result_num < 0) { - err("%s, ebu result not enough\n", __func__); - return; - } - - critical("st30(%d), [ --- Total %d --- Compliance Rate %.2f%% ]\n", idx, - ebu_result->ebu_result_num, - ra_ebu_pass_rate(ebu_result, ebu_result->compliance)); - critical( - "st30(%d), [ Delta Packet vs RTP Pass Rate]\t| Narrow %.2f%% | Wide %.2f%% | Fail " - "%.2f%% |\n", - idx, ra_ebu_pass_rate(ebu_result, ebu_result->dpvr_pass_narrow), - ra_ebu_pass_rate(ebu_result, ebu_result->dpvr_pass_wide), - ra_ebu_pass_rate(ebu_result, ebu_result->dpvr_fail)); - critical( - "st30(%d), [ Maximum Timestamped Delay Factor Pass Rate]\t| Pass %.2f%% | Fail " - "%.2f%% |\n", - idx, ra_ebu_pass_rate(ebu_result, ebu_result->tsdf_pass), - ra_ebu_pass_rate(ebu_result, ebu_result->tsdf_fail)); -} - -static void ra_ebu_clear_result(struct st_rx_audio_ebu_stat* ebu) { - memset(ebu, 0, sizeof(*ebu)); - - ebu->dpvr_max = INT_MIN; - ebu->dpvr_min = INT_MAX; - ebu->tsdf_max = INT_MIN; - - ebu->compliant = true; -} - -static inline float ra_ebu_calculate_avg(uint32_t cnt, int64_t sum) { - return cnt ? ((float)sum / cnt) : -1.0f; -} - -static char* ra_ebu_dpvr_result(struct st_rx_audio_session_impl* s) { - struct st_rx_audio_ebu_stat* ebu = &s->ebu; - struct st_rx_audio_ebu_info* ebu_info = &s->ebu_info; - struct st_rx_audio_ebu_result* ebu_result = &s->ebu_result; - - if (ebu->dpvr_max >= 0 && ebu->dpvr_max < ebu_info->dpvr_max_pass_narrow) { - ebu_result->dpvr_pass_narrow++; - return ST_EBU_PASS_NARROW; - } - - if (ebu->dpvr_max >= 0 && ebu->dpvr_max < ebu_info->dpvr_max_pass_wide && - ebu->dpvr_avg >= 0 && ebu->dpvr_avg < ebu_info->dpvr_avg_pass_wide) { - ebu_result->dpvr_pass_wide++; - return ST_EBU_PASS_WIDE; - } - - ebu_result->dpvr_fail++; - ebu->compliant = false; - return ST_EBU_FAIL; -} - -static char* ra_ebu_tsdf_result(struct st_rx_audio_session_impl* s) { - struct st_rx_audio_ebu_stat* ebu = &s->ebu; - struct st_rx_audio_ebu_info* ebu_info = &s->ebu_info; - struct st_rx_audio_ebu_result* ebu_result = &s->ebu_result; - - if (ebu->tsdf_max < ebu_info->tsdf_max_pass) { - ebu_result->tsdf_pass++; - return ST_EBU_PASS; - } - ebu_result->tsdf_fail++; - ebu->compliant = false; - return ST_EBU_FAIL; -} - -static void ra_ebu_result(struct st_rx_audio_session_impl* s) { - struct st_rx_audio_ebu_stat* ebu = &s->ebu; - struct st_rx_audio_ebu_result* ebu_result = &s->ebu_result; - int idx = s->idx; - - /* Maximum Timestamped Delay Factor */ - int64_t tsdf = (ebu->dpvr_max - ebu->dpvr_first) - (ebu->dpvr_min - ebu->dpvr_first); - ebu->tsdf_max = RTE_MAX(tsdf, ebu->tsdf_max); - ebu->dpvr_first = 0; - - ebu->dpvr_avg = ra_ebu_calculate_avg(ebu->dpvr_cnt, ebu->dpvr_sum); - /* print every 5 results */ - if (ebu_result->ebu_result_num % 5 == 0) { - info("%s(%d), Delta Packet vs RTP AVG %.2f (us) MIN %" PRId64 " (us) MAX %" PRId64 - " (us) test %s!\n", - __func__, idx, ebu->dpvr_avg, ebu->dpvr_min, ebu->dpvr_max, - ra_ebu_dpvr_result(s)); - info("%s(%d), Maximum Timestamped Delay Factor %" PRIu64 " (us) test %s!\n\n", - __func__, idx, ebu->tsdf_max, ra_ebu_tsdf_result(s)); - } else { - ra_ebu_dpvr_result(s); - ra_ebu_tsdf_result(s); - } - - if (ebu->compliant) ebu_result->compliance++; -} - -static void ra_ebu_on_packet(struct st_rx_audio_session_impl* s, uint32_t rtp_tmstamp, - uint64_t pkt_tmstamp) { - struct st_rx_audio_ebu_stat* ebu = &s->ebu; - struct st_rx_audio_ebu_info* ebu_info = &s->ebu_info; - struct st_rx_audio_ebu_result* ebu_result = &s->ebu_result; - - uint64_t epochs = (double)pkt_tmstamp / ebu_info->frame_time; - uint64_t epoch_tmstamp = (double)epochs * ebu_info->frame_time; - double fpt_delta = (double)pkt_tmstamp - epoch_tmstamp; - uint64_t tmstamp64 = epochs * ebu_info->frame_time_sampling; - uint32_t tmstamp32 = tmstamp64; - double diff_rtp_ts = (double)rtp_tmstamp - tmstamp32; - double diff_rtp_ts_ns = - diff_rtp_ts * ebu_info->frame_time / ebu_info->frame_time_sampling; - double latency = fpt_delta - diff_rtp_ts_ns; - double dpvr = latency / 1000; - - ebu->pkt_num++; - - if (ebu->pkt_num % 1000 == 0) { - ebu_result->ebu_result_num++; - /* every second (for 1ms/packet) */ - if (ebu_result->ebu_result_num > ebu_info->dropped_results) ra_ebu_result(s); - ra_ebu_clear_result(ebu); - } - - /* calculate Delta Packet vs RTP */ - ebu->dpvr_sum += dpvr; - ebu->dpvr_min = RTE_MIN(dpvr, ebu->dpvr_min); - ebu->dpvr_max = RTE_MAX(dpvr, ebu->dpvr_max); - ebu->dpvr_cnt++; - - if (!ebu->dpvr_first) ebu->dpvr_first = dpvr; -} - -static int ra_ebu_init(struct st_rx_audio_session_impl* s) { - int idx = s->idx; - struct st_rx_audio_ebu_info* ebu_info = &s->ebu_info; - struct st30_rx_ops* ops = &s->ops; - - ra_ebu_clear_result(&s->ebu); - - int sampling = (ops->sampling == ST30_SAMPLING_48K) ? 48 : 96; - ebu_info->frame_time = (double)1000000000.0 * 1 / 1000; /* 1ms, in ns */ - ebu_info->frame_time_sampling = (double)(sampling * 1000) * 1 / 1000; - - ebu_info->dpvr_max_pass_narrow = 3 * ebu_info->frame_time / 1000; /* in us */ - ebu_info->dpvr_max_pass_wide = 20 * ebu_info->frame_time / 1000; /* in us */ - ebu_info->dpvr_avg_pass_wide = 2.5 * ebu_info->frame_time / 1000; /* in us */ - ebu_info->tsdf_max_pass = 17 * ebu_info->frame_time / 1000; /* in us */ - - ebu_info->dropped_results = 10; /* we drop first 10 results */ - - info("%s[%02d], Delta Packet vs RTP Pass Criteria(narrow) min %d (us) max %d (us)\n", - __func__, idx, 0, ebu_info->dpvr_max_pass_narrow); - info("%s[%02d], Delta Packet vs RTP Pass Criteria(wide) max %d (us) avg %.2f (us)\n", - __func__, idx, ebu_info->dpvr_max_pass_wide, ebu_info->dpvr_avg_pass_wide); - info("%s[%02d], Maximum Timestamped Delay Factor Pass Criteria %d (us)\n", __func__, - idx, ebu_info->tsdf_max_pass); - - return 0; -} - /* call rx_audio_session_put always if get successfully */ static inline struct st_rx_audio_session_impl* rx_audio_session_get( struct st_rx_audio_sessions_mgr* mgr, int idx) { @@ -382,8 +212,6 @@ static int rx_audio_session_handle_frame_pkt(struct mtl_main_impl* impl, struct rte_mbuf* mbuf, enum mtl_session_port s_port) { struct st30_rx_ops* ops = &s->ops; - enum mtl_port port = mt_port_logic2phy(s->port_maps, s_port); - struct mt_interface* inf = mt_if(impl, port); size_t hdr_offset = sizeof(struct st_rfc3550_audio_hdr) - sizeof(struct st_rfc3550_rtp_hdr); struct st_rfc3550_rtp_hdr* rtp = @@ -437,6 +265,7 @@ static int rx_audio_session_handle_frame_pkt(struct mtl_main_impl* impl, s->st30_stat_pkts_dropped++; return -EIO; } + if (s->enable_timing_parser) ra_tp_slot_init(&s->tp->slot); } uint32_t offset = s->st30_pkt_idx * s->pkt_len; if ((offset + s->pkt_len) > s->st30_frame_size) { @@ -450,8 +279,9 @@ static int rx_audio_session_handle_frame_pkt(struct mtl_main_impl* impl, s->st30_stat_pkts_received++; s->st30_pkt_idx++; - if (mt_user_ebu_active(impl) && inf->feature & MT_IF_FEATURE_RX_OFFLOAD_TIMESTAMP) { - ra_ebu_on_packet(s, tmstamp, mt_mbuf_hw_time_stamp(impl, mbuf, port)); + if (s->enable_timing_parser) { + enum mtl_port port = mt_port_logic2phy(s->port_maps, s_port); + ra_tp_on_packet(s, &s->tp->slot, tmstamp, mt_mbuf_time_stamp(impl, mbuf, port)); } // notify frame done @@ -459,6 +289,8 @@ static int rx_audio_session_handle_frame_pkt(struct mtl_main_impl* impl, struct st30_rx_frame_meta* meta = &s->meta; uint64_t tsc_start = 0; + if (s->enable_timing_parser) ra_tp_slot_parse_result(s, &s->tp->slot); + meta->tfmt = ST10_TIMESTAMP_FMT_MEDIA_CLK; meta->timestamp = tmstamp; meta->fmt = ops->fmt; @@ -490,15 +322,14 @@ static int rx_audio_session_handle_rtp_pkt(struct mtl_main_impl* impl, struct rte_mbuf* mbuf, enum mtl_session_port s_port) { struct st30_rx_ops* ops = &s->ops; - enum mtl_port port = mt_port_logic2phy(s->port_maps, s_port); - struct mt_interface* inf = mt_if(impl, port); size_t hdr_offset = sizeof(struct st_rfc3550_audio_hdr) - sizeof(struct st_rfc3550_rtp_hdr); struct st_rfc3550_rtp_hdr* rtp = rte_pktmbuf_mtod_offset(mbuf, struct st_rfc3550_rtp_hdr*, hdr_offset); + MTL_MAY_UNUSED(impl); + MTL_MAY_UNUSED(s_port); uint16_t seq_id = ntohs(rtp->seq_number); - uint32_t tmstamp = ntohl(rtp->tmstamp); uint8_t payload_type = rtp->payload_type; if (payload_type != ops->payload_type) { @@ -540,10 +371,6 @@ static int rx_audio_session_handle_rtp_pkt(struct mtl_main_impl* impl, ops->notify_rtp_ready(ops->priv); s->st30_stat_pkts_received++; - if (mt_user_ebu_active(impl) && inf->feature & MT_IF_FEATURE_RX_OFFLOAD_TIMESTAMP) { - ra_ebu_on_packet(s, tmstamp, mt_mbuf_hw_time_stamp(impl, mbuf, port)); - } - return 0; } @@ -783,10 +610,15 @@ static int rx_audio_session_attach(struct mtl_main_impl* impl, rte_atomic32_set(&s->st30_stat_frames_received, 0); s->st30_stat_last_time = mt_get_monotonic_time(); - if (mt_user_ebu_active(impl)) { - ret = ra_ebu_init(s); + if (s->ops.flags & ST30_RX_FLAG_ENABLE_TIMING_PARSER) { + info("%s(%d), enable the timing analyze\n", __func__, idx); + s->enable_timing_parser = true; + } + + if (s->enable_timing_parser) { + ret = ra_tp_init(impl, s); if (ret < 0) { - err("%s(%d), ra_ebu_init fail %d\n", __func__, idx, ret); + err("%s(%d), ra_tp_init fail %d\n", __func__, idx, ret); return -EIO; } } @@ -861,14 +693,17 @@ static void rx_audio_session_stat(struct st_rx_audio_sessions_mgr* mgr, s->stat_max_notify_frame_us); s->stat_max_notify_frame_us = 0; } + + if (s->enable_timing_parser) ra_tp_stat(s); } static int rx_audio_session_detach(struct mtl_main_impl* impl, struct st_rx_audio_sessions_mgr* mgr, struct st_rx_audio_session_impl* s) { s->attached = false; - if (mt_user_ebu_active(impl)) rx_audio_session_ebu_result(s); rx_audio_session_stat(mgr, s); + + ra_tp_uinit(s); rx_audio_session_uinit_mcast(impl, s); rx_audio_session_uinit_sw(s); rx_audio_session_uinit_hw(s); diff --git a/lib/src/st2110/st_rx_ebu.c b/lib/src/st2110/st_rx_ebu.c deleted file mode 100644 index 55367c0f2..000000000 --- a/lib/src/st2110/st_rx_ebu.c +++ /dev/null @@ -1,298 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2023 Intel Corporation - */ - -#include "st_rx_ebu.h" - -#include "../mt_log.h" - -static inline float rv_ebu_calculate_avg(uint32_t cnt, int64_t sum) { - return cnt ? ((float)sum / cnt) : -1.0f; -} - -void rv_ebu_on_packet(struct st_rx_video_session_impl* s, struct st_rv_ebu_slot* slot, - uint32_t rtp_tmstamp, uint64_t pkt_time, int pkt_idx) { - struct st_rx_video_ebu* ebu = s->ebu; - uint64_t epoch_tmstamp; - double tvd, packet_delta_ns, trs = ebu->trs; - - if (!slot->cur_epochs) { /* the first packet */ - uint64_t epochs = (double)pkt_time / s->frame_time; - uint64_t epoch_tmstamp = (double)epochs * s->frame_time; - - slot->cur_epochs = epochs; - slot->rtp_tmstamp = rtp_tmstamp; - slot->first_pkt_time = pkt_time; - slot->fpt_to_epoch = pkt_time - epoch_tmstamp; - - uint64_t tmstamp64 = epochs * s->frame_time_sampling; - uint32_t tmstamp32 = tmstamp64; - double diff_rtp_ts = (double)rtp_tmstamp - tmstamp32; - double diff_rtp_ts_ns = diff_rtp_ts * s->frame_time / s->frame_time_sampling; - slot->latency = slot->fpt_to_epoch - diff_rtp_ts_ns; - slot->rtp_offset = diff_rtp_ts; - if (ebu->pre_rtp_tmstamp) { - slot->rtp_ts_delta = rtp_tmstamp - ebu->pre_rtp_tmstamp; - } - ebu->pre_rtp_tmstamp = rtp_tmstamp; - } - - epoch_tmstamp = (uint64_t)(slot->cur_epochs * s->frame_time); - tvd = epoch_tmstamp + ebu->tr_offset; - - /* Calculate vrx */ - packet_delta_ns = (double)pkt_time - tvd; - int32_t drained = (packet_delta_ns + trs) / trs; - int32_t vrx_cur = slot->vrx_prev + 1 - (drained - slot->vrx_drained_prev); - slot->vrx_sum += vrx_cur; - slot->vrx_min = RTE_MIN(vrx_cur, slot->vrx_min); - slot->vrx_max = RTE_MAX(vrx_cur, slot->vrx_max); - slot->vrx_prev = vrx_cur; - slot->vrx_drained_prev = drained; - - /* Calculate C-inst */ - int exp_cin_pkts = - ((pkt_time - slot->first_pkt_time) / trs) * ST_EBU_CINST_DRAIN_FACTOR; - int cinst = RTE_MAX(0, pkt_idx - exp_cin_pkts); - slot->cinst_sum += cinst; - slot->cinst_min = RTE_MIN(cinst, slot->cinst_min); - slot->cinst_max = RTE_MAX(cinst, slot->cinst_max); - - /* calculate Inter-packet time */ - if (slot->prev_pkt_time) { - double ipt = (double)pkt_time - slot->prev_pkt_time; - - slot->ipt_sum += ipt; - slot->ipt_min = RTE_MIN(ipt, slot->ipt_min); - slot->ipt_max = RTE_MAX(ipt, slot->ipt_max); - } - slot->prev_pkt_time = pkt_time; - - slot->pkt_cnt++; -} - -static enum st_rv_ebu_compliant rv_ebu_compliant(struct st_rx_video_session_impl* s, - struct st_rx_video_ebu* ebu, - struct st_rv_ebu_slot* slot) { - /* fpt check */ - if (slot->fpt_to_epoch > ebu->tr_offset) return ST_RV_EBU_COMPLIANT_FAILED; - /* rtp ts delta check */ - int32_t sampling = s->frame_time_sampling; - if ((slot->rtp_ts_delta < sampling) || (slot->rtp_ts_delta > (sampling + 1))) - return ST_RV_EBU_COMPLIANT_FAILED; - /* rtp offset check */ - if ((slot->rtp_offset < ST_EBU_RTP_OFFSET_MIN) || - (slot->rtp_offset > ebu->rtp_offset_max_pass)) - return ST_RV_EBU_COMPLIANT_FAILED; - /* latency check */ - if ((slot->latency < 0) || (slot->latency > ST_EBU_LATENCY_MAX_NS)) - return ST_RV_EBU_COMPLIANT_FAILED; - /* vrx check */ - if ((slot->vrx_min < 0) || (slot->vrx_max > ebu->vrx_full_wide_pass)) - return ST_RV_EBU_COMPLIANT_FAILED; - /* narrow or wide */ - if (slot->cinst_max > ebu->c_max_wide_pass) return ST_RV_EBU_COMPLIANT_FAILED; - if (slot->cinst_max > ebu->c_max_narrow_pass) return ST_RV_EBU_COMPLIANT_WIDE; - if (slot->vrx_max > ebu->vrx_full_narrow_pass) return ST_RV_EBU_COMPLIANT_WIDE; - return ST_RV_EBU_COMPLIANT_NARROW; -} - -void rv_ebu_slot_parse_result(struct st_rx_video_session_impl* s, - struct st_rv_ebu_slot* slot) { - struct st_rx_video_ebu* ebu = s->ebu; - float cinst_avg = rv_ebu_calculate_avg(slot->pkt_cnt, slot->cinst_sum); - float vrx_avg = rv_ebu_calculate_avg(slot->pkt_cnt, slot->vrx_sum); - float ipt_avg = rv_ebu_calculate_avg(slot->pkt_cnt, slot->ipt_sum); - - slot->cinst_avg = cinst_avg; - slot->vrx_avg = vrx_avg; - slot->ipt_avg = ipt_avg; - dbg("%s(%d), Cinst AVG %.2f MIN %d MAX %d test %s!\n", __func__, s->idx, cinst_avg, - slot->cinst_min, slot->cinst_max, rv_ebu_cinst_result(ebu, slot)); - dbg("%s(%d), VRX AVG %.2f MIN %d MAX %d test %s!\n", __func__, s->idx, vrx_avg, - slot->vrx_min, slot->vrx_max, rv_ebu_vrx_result(ebu, slot)); - dbg("%s(%d), Inter-packet time(ns) AVG %.2f MIN %d MAX %d!\n", __func__, s->idx, - ipt_avg, slot->ipt_min, slot->ipt_max); - - /* parse ebu compliant for current frame */ - enum st_rv_ebu_compliant compliant = rv_ebu_compliant(s, ebu, slot); - slot->compliant = compliant; - - /* update stat */ - struct st_rv_ebu_stat* stat = &ebu->stat; - struct st_rv_ebu_slot* stat_slot = &stat->slot; - - stat->stat_compliant_result[compliant]++; - - stat_slot->vrx_sum += slot->vrx_sum; - stat_slot->vrx_min = RTE_MIN(stat_slot->vrx_min, slot->vrx_min); - stat_slot->vrx_max = RTE_MAX(stat_slot->vrx_min, slot->vrx_max); - stat_slot->cinst_sum += slot->cinst_sum; - stat_slot->cinst_min = RTE_MIN(stat_slot->cinst_min, slot->cinst_min); - stat_slot->cinst_max = RTE_MAX(stat_slot->cinst_max, slot->cinst_max); - stat_slot->ipt_sum += slot->ipt_sum; - stat_slot->ipt_min = RTE_MIN(stat_slot->ipt_min, slot->ipt_min); - stat_slot->ipt_max = RTE_MAX(stat_slot->ipt_min, slot->ipt_max); - stat_slot->pkt_cnt += slot->pkt_cnt; - - stat->stat_fpt_min = RTE_MIN(stat->stat_fpt_min, slot->fpt_to_epoch); - stat->stat_fpt_max = RTE_MAX(stat->stat_fpt_max, slot->fpt_to_epoch); - stat->stat_fpt_sum += slot->fpt_to_epoch; - stat->stat_latency_min = RTE_MIN(stat->stat_latency_min, slot->latency); - stat->stat_latency_max = RTE_MAX(stat->stat_latency_max, slot->latency); - stat->stat_latency_sum += slot->latency; - stat->stat_rtp_offset_min = RTE_MIN(stat->stat_rtp_offset_min, slot->rtp_offset); - stat->stat_rtp_offset_max = RTE_MAX(stat->stat_rtp_offset_max, slot->rtp_offset); - stat->stat_rtp_offset_sum += slot->rtp_offset; - if (slot->rtp_ts_delta) { - stat->stat_rtp_ts_delta_min = - RTE_MIN(stat->stat_rtp_ts_delta_min, slot->rtp_ts_delta); - stat->stat_rtp_ts_delta_max = - RTE_MAX(stat->stat_rtp_ts_delta_max, slot->rtp_ts_delta); - stat->stat_rtp_ts_delta_sum += slot->rtp_ts_delta; - } - stat->stat_frame_cnt++; -} - -static void rv_ebu_stat_init(struct st_rx_video_ebu* ebu) { - struct st_rv_ebu_stat* stat = &ebu->stat; - - memset(stat, 0, sizeof(*stat)); - rv_ebu_slot_init(&stat->slot); - stat->stat_fpt_min = INT_MAX; - stat->stat_fpt_max = INT_MIN; - stat->stat_latency_min = INT_MAX; - stat->stat_latency_max = INT_MIN; - stat->stat_rtp_offset_min = INT_MAX; - stat->stat_rtp_offset_max = INT_MIN; - stat->stat_rtp_ts_delta_min = INT_MAX; - stat->stat_rtp_ts_delta_max = INT_MIN; -} - -void rv_ebu_stat(struct st_rx_video_session_impl* s) { - int idx = s->idx; - struct st_rx_video_ebu* ebu = s->ebu; - struct st_rv_ebu_stat* stat = &ebu->stat; - struct st_rv_ebu_slot* stat_slot = &stat->slot; - - info("%s(%d), COMPLIANT NARROW %d WIDE %d FAILED %d!\n", __func__, idx, - stat->stat_compliant_result[ST_RV_EBU_COMPLIANT_NARROW], - stat->stat_compliant_result[ST_RV_EBU_COMPLIANT_WIDE], - stat->stat_compliant_result[ST_RV_EBU_COMPLIANT_FAILED]); - float cinst_avg = rv_ebu_calculate_avg(stat_slot->pkt_cnt, stat_slot->cinst_sum); - float vrx_avg = rv_ebu_calculate_avg(stat_slot->pkt_cnt, stat_slot->vrx_sum); - float ipt_avg = rv_ebu_calculate_avg(stat_slot->pkt_cnt, stat_slot->ipt_sum); - info("%s(%d), Cinst AVG %.2f MIN %d MAX %d!\n", __func__, idx, cinst_avg, - stat_slot->cinst_min, stat_slot->cinst_max); - info("%s(%d), VRX AVG %.2f MIN %d MAX %d!\n", __func__, idx, vrx_avg, - stat_slot->vrx_min, stat_slot->vrx_max); - info("%s(%d), Inter-packet time(ns) AVG %.2f MIN %d MAX %d!\n", __func__, idx, ipt_avg, - stat_slot->ipt_min, stat_slot->ipt_max); - float fpt_avg = rv_ebu_calculate_avg(stat->stat_frame_cnt, stat->stat_fpt_sum); - info("%s(%d), FPT AVG %.2f MIN %d MAX %d DIFF %d!\n", __func__, idx, fpt_avg, - stat->stat_fpt_min, stat->stat_fpt_max, stat->stat_fpt_max - stat->stat_fpt_min); - float latency_avg = rv_ebu_calculate_avg(stat->stat_frame_cnt, stat->stat_latency_sum); - info("%s(%d), LATENCY AVG %.2f MIN %d MAX %d!\n", __func__, idx, latency_avg, - stat->stat_latency_min, stat->stat_latency_max); - float rtp_offset_avg = - rv_ebu_calculate_avg(stat->stat_frame_cnt, stat->stat_rtp_offset_sum); - info("%s(%d), RTP OFFSET AVG %.2f MIN %d MAX %d!\n", __func__, idx, rtp_offset_avg, - stat->stat_rtp_offset_min, stat->stat_rtp_offset_max); - float rtp_ts_delta_avg = - rv_ebu_calculate_avg(stat->stat_frame_cnt, stat->stat_rtp_ts_delta_sum); - info("%s(%d), RTP TS DELTA AVG %.2f MIN %d MAX %d!\n", __func__, idx, rtp_ts_delta_avg, - stat->stat_rtp_ts_delta_min, stat->stat_rtp_ts_delta_max); - rv_ebu_stat_init(ebu); -} - -void rv_ebu_slot_init(struct st_rv_ebu_slot* slot) { - memset(slot, 0, sizeof(*slot)); - - slot->cinst_max = INT_MIN; - slot->cinst_min = INT_MAX; - slot->vrx_max = INT_MIN; - slot->vrx_min = INT_MAX; - slot->ipt_max = INT_MIN; - slot->ipt_min = INT_MAX; -} - -int rv_ebu_uinit(struct st_rx_video_session_impl* s) { - if (s->ebu) { - mt_rte_free(s->ebu); - s->ebu = NULL; - } - - return 0; -} - -int rv_ebu_init(struct mtl_main_impl* impl, struct st_rx_video_session_impl* s) { - enum mtl_port port = mt_port_logic2phy(s->port_maps, MTL_SESSION_PORT_P); - int soc_id = mt_socket_id(impl, port); - int idx = s->idx, ret; - struct st_rx_video_ebu* ebu; - struct st20_rx_ops* ops = &s->ops; - double frame_time = s->frame_time; - double frame_time_s; - struct st_fps_timing fps_tm; - - ret = st_get_fps_timing(ops->fps, &fps_tm); - if (ret < 0) { - err("%s(%d), invalid fps %d\n", __func__, idx, ops->fps); - return ret; - } - frame_time_s = (double)fps_tm.den / fps_tm.mul; - - int st20_total_pkts = s->detector.pkt_per_frame; - info("%s(%d), st20_total_pkts %d\n", __func__, idx, st20_total_pkts); - if (!st20_total_pkts) { - err("%s(%d), can not get total packets number\n", __func__, idx); - return -EINVAL; - } - - ebu = mt_rte_zmalloc_socket(sizeof(*ebu), soc_id); - if (!ebu) { - err("%s(%d), ebu malloc fail\n", __func__, idx); - return -ENOMEM; - } - s->ebu = ebu; - - rv_ebu_stat_init(ebu); - - double reactive = 1080.0 / 1125.0; - if (ops->interlaced && ops->height <= 576) { - reactive = (ops->height == 480) ? 487.0 / 525.0 : 576.0 / 625.0; - } - - ebu->trs = frame_time * reactive / st20_total_pkts; - if (!ops->interlaced) { - ebu->tr_offset = - ops->height >= 1080 ? frame_time * (43.0 / 1125.0) : frame_time * (28.0 / 750.0); - } else { - if (ops->height == 480) { - ebu->tr_offset = frame_time * (20.0 / 525.0) * 2; - } else if (ops->height == 576) { - ebu->tr_offset = frame_time * (26.0 / 625.0) * 2; - } else { - ebu->tr_offset = frame_time * (22.0 / 1125.0) * 2; - } - } - - ebu->c_max_narrow_pass = - RTE_MAX(4, (double)st20_total_pkts / (43200 * reactive * frame_time_s)); - ebu->c_max_wide_pass = RTE_MAX(16, (double)st20_total_pkts / (21600 * frame_time_s)); - ebu->vrx_full_narrow_pass = RTE_MAX(8, st20_total_pkts / (27000 * frame_time_s)); - ebu->vrx_full_wide_pass = RTE_MAX(720, st20_total_pkts / (300 * frame_time_s)); - ebu->rtp_offset_max_pass = - ceil((ebu->tr_offset / NS_PER_S) * fps_tm.sampling_clock_rate) + 1; - - rv_ebu_stat_init(ebu); - - info("%s[%02d], trs %f tr offset %f sampling %f\n", __func__, idx, ebu->trs, - ebu->tr_offset, s->frame_time_sampling); - info( - "%s[%02d], cmax_narrow %d cmax_wide %d vrx_full_narrow %d vrx_full_wide %d " - "rtp_offset_max %d\n", - __func__, idx, ebu->c_max_narrow_pass, ebu->c_max_wide_pass, - ebu->vrx_full_narrow_pass, ebu->vrx_full_wide_pass, ebu->rtp_offset_max_pass); - return 0; -} \ No newline at end of file diff --git a/lib/src/st2110/st_rx_ebu.h b/lib/src/st2110/st_rx_ebu.h deleted file mode 100644 index 182fa32e2..000000000 --- a/lib/src/st2110/st_rx_ebu.h +++ /dev/null @@ -1,23 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2023 Intel Corporation - */ - -#ifndef _ST_LIB_RX_EBU_HEAD_H_ -#define _ST_LIB_RX_EBU_HEAD_H_ - -#include "st_main.h" - -int rv_ebu_init(struct mtl_main_impl* impl, struct st_rx_video_session_impl* s); -int rv_ebu_uinit(struct st_rx_video_session_impl* s); - -void rv_ebu_slot_init(struct st_rv_ebu_slot* slot); - -void rv_ebu_on_packet(struct st_rx_video_session_impl* s, struct st_rv_ebu_slot* slot, - uint32_t rtp_tmstamp, uint64_t pkt_time, int pkt_idx); - -void rv_ebu_slot_parse_result(struct st_rx_video_session_impl* s, - struct st_rv_ebu_slot* slot); - -void rv_ebu_stat(struct st_rx_video_session_impl* s); - -#endif \ No newline at end of file diff --git a/lib/src/st2110/st_rx_timing_parser.c b/lib/src/st2110/st_rx_timing_parser.c new file mode 100644 index 000000000..3c2592f4f --- /dev/null +++ b/lib/src/st2110/st_rx_timing_parser.c @@ -0,0 +1,431 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Intel Corporation + */ + +#include "st_rx_timing_parser.h" + +#include "../mt_log.h" + +static inline float rv_tp_calculate_avg(uint32_t cnt, int64_t sum) { + return cnt ? ((float)sum / cnt) : -1.0f; +} + +void rv_tp_on_packet(struct st_rx_video_session_impl* s, struct st_rv_tp_slot* slot, + uint32_t rtp_tmstamp, uint64_t pkt_time, int pkt_idx) { + struct st_rx_video_tp* tp = s->tp; + uint64_t epoch_tmstamp; + double tvd, packet_delta_ns, trs = tp->trs; + + if (!slot->cur_epochs) { /* the first packet */ + uint64_t epochs = (double)pkt_time / s->frame_time; + uint64_t epoch_tmstamp = (double)epochs * s->frame_time; + + slot->cur_epochs = epochs; + slot->rtp_tmstamp = rtp_tmstamp; + slot->first_pkt_time = pkt_time; + slot->fpt_to_epoch = pkt_time - epoch_tmstamp; + + uint64_t tmstamp64 = epochs * s->frame_time_sampling; + uint32_t tmstamp32 = tmstamp64; + double diff_rtp_ts = (double)rtp_tmstamp - tmstamp32; + double diff_rtp_ts_ns = diff_rtp_ts * s->frame_time / s->frame_time_sampling; + slot->latency = slot->fpt_to_epoch - diff_rtp_ts_ns; + slot->rtp_offset = diff_rtp_ts; + if (tp->pre_rtp_tmstamp) { + slot->rtp_ts_delta = rtp_tmstamp - tp->pre_rtp_tmstamp; + } + tp->pre_rtp_tmstamp = rtp_tmstamp; + } + + epoch_tmstamp = (uint64_t)(slot->cur_epochs * s->frame_time); + tvd = epoch_tmstamp + tp->tr_offset; + + /* Calculate vrx */ + packet_delta_ns = (double)pkt_time - tvd; + int32_t drained = (packet_delta_ns + trs) / trs; + int32_t vrx_cur = slot->vrx_prev + 1 - (drained - slot->vrx_drained_prev); + slot->vrx_sum += vrx_cur; + slot->vrx_min = RTE_MIN(vrx_cur, slot->vrx_min); + slot->vrx_max = RTE_MAX(vrx_cur, slot->vrx_max); + slot->vrx_prev = vrx_cur; + slot->vrx_drained_prev = drained; + + /* Calculate C-inst */ + int exp_cin_pkts = ((pkt_time - slot->first_pkt_time) / trs) * ST_TP_CINST_DRAIN_FACTOR; + int cinst = RTE_MAX(0, pkt_idx - exp_cin_pkts); + slot->cinst_sum += cinst; + slot->cinst_min = RTE_MIN(cinst, slot->cinst_min); + slot->cinst_max = RTE_MAX(cinst, slot->cinst_max); + + /* calculate Inter-packet time */ + if (slot->prev_pkt_time) { + double ipt = (double)pkt_time - slot->prev_pkt_time; + + slot->ipt_sum += ipt; + slot->ipt_min = RTE_MIN(ipt, slot->ipt_min); + slot->ipt_max = RTE_MAX(ipt, slot->ipt_max); + } + slot->prev_pkt_time = pkt_time; + + slot->pkt_cnt++; +} + +static enum st_rx_tp_compliant rv_tp_compliant(struct st_rx_video_session_impl* s, + struct st_rx_video_tp* tp, + struct st_rv_tp_slot* slot) { + /* fpt check */ + if (slot->fpt_to_epoch > tp->tr_offset) return ST_RX_TP_COMPLIANT_FAILED; + /* rtp ts delta check */ + int32_t sampling = s->frame_time_sampling; + if ((slot->rtp_ts_delta < sampling) || (slot->rtp_ts_delta > (sampling + 1))) + return ST_RX_TP_COMPLIANT_FAILED; + /* rtp offset check */ + if ((slot->rtp_offset < ST_TP_RTP_OFFSET_MIN) || + (slot->rtp_offset > tp->rtp_offset_max_pass)) + return ST_RX_TP_COMPLIANT_FAILED; + /* latency check */ + if ((slot->latency < 0) || (slot->latency > ST_TP_LATENCY_MAX_NS)) + return ST_RX_TP_COMPLIANT_FAILED; + /* vrx check */ + if ((slot->vrx_min < 0) || (slot->vrx_max > tp->vrx_full_wide_pass)) + return ST_RX_TP_COMPLIANT_FAILED; + /* narrow or wide */ + if (slot->cinst_max > tp->c_max_wide_pass) return ST_RX_TP_COMPLIANT_FAILED; + if (slot->cinst_max > tp->c_max_narrow_pass) return ST_RX_TP_COMPLIANT_WIDE; + if (slot->vrx_max > tp->vrx_full_narrow_pass) return ST_RX_TP_COMPLIANT_WIDE; + return ST_RX_TP_COMPLIANT_NARROW; +} + +void rv_tp_slot_parse_result(struct st_rx_video_session_impl* s, + struct st_rv_tp_slot* slot) { + struct st_rx_video_tp* tp = s->tp; + float cinst_avg = rv_tp_calculate_avg(slot->pkt_cnt, slot->cinst_sum); + float vrx_avg = rv_tp_calculate_avg(slot->pkt_cnt, slot->vrx_sum); + float ipt_avg = rv_tp_calculate_avg(slot->pkt_cnt, slot->ipt_sum); + + slot->cinst_avg = cinst_avg; + slot->vrx_avg = vrx_avg; + slot->ipt_avg = ipt_avg; + dbg("%s(%d), Cinst AVG %.2f MIN %d MAX %d test %s!\n", __func__, s->idx, cinst_avg, + slot->cinst_min, slot->cinst_max, rv_tp_cinst_result(tp, slot)); + dbg("%s(%d), VRX AVG %.2f MIN %d MAX %d test %s!\n", __func__, s->idx, vrx_avg, + slot->vrx_min, slot->vrx_max, rv_tp_vrx_result(tp, slot)); + dbg("%s(%d), Inter-packet time(ns) AVG %.2f MIN %d MAX %d!\n", __func__, s->idx, + ipt_avg, slot->ipt_min, slot->ipt_max); + + /* parse tp compliant for current frame */ + enum st_rx_tp_compliant compliant = rv_tp_compliant(s, tp, slot); + slot->compliant = compliant; + + /* update stat */ + struct st_rv_tp_stat* stat = &tp->stat; + struct st_rv_tp_slot* stat_slot = &stat->slot; + + stat->stat_compliant_result[compliant]++; + + stat_slot->vrx_sum += slot->vrx_sum; + stat_slot->vrx_min = RTE_MIN(stat_slot->vrx_min, slot->vrx_min); + stat_slot->vrx_max = RTE_MAX(stat_slot->vrx_min, slot->vrx_max); + stat_slot->cinst_sum += slot->cinst_sum; + stat_slot->cinst_min = RTE_MIN(stat_slot->cinst_min, slot->cinst_min); + stat_slot->cinst_max = RTE_MAX(stat_slot->cinst_max, slot->cinst_max); + stat_slot->ipt_sum += slot->ipt_sum; + stat_slot->ipt_min = RTE_MIN(stat_slot->ipt_min, slot->ipt_min); + stat_slot->ipt_max = RTE_MAX(stat_slot->ipt_min, slot->ipt_max); + stat_slot->pkt_cnt += slot->pkt_cnt; + + stat->stat_fpt_min = RTE_MIN(stat->stat_fpt_min, slot->fpt_to_epoch); + stat->stat_fpt_max = RTE_MAX(stat->stat_fpt_max, slot->fpt_to_epoch); + stat->stat_fpt_sum += slot->fpt_to_epoch; + stat->stat_latency_min = RTE_MIN(stat->stat_latency_min, slot->latency); + stat->stat_latency_max = RTE_MAX(stat->stat_latency_max, slot->latency); + stat->stat_latency_sum += slot->latency; + stat->stat_rtp_offset_min = RTE_MIN(stat->stat_rtp_offset_min, slot->rtp_offset); + stat->stat_rtp_offset_max = RTE_MAX(stat->stat_rtp_offset_max, slot->rtp_offset); + stat->stat_rtp_offset_sum += slot->rtp_offset; + if (slot->rtp_ts_delta) { + stat->stat_rtp_ts_delta_min = + RTE_MIN(stat->stat_rtp_ts_delta_min, slot->rtp_ts_delta); + stat->stat_rtp_ts_delta_max = + RTE_MAX(stat->stat_rtp_ts_delta_max, slot->rtp_ts_delta); + stat->stat_rtp_ts_delta_sum += slot->rtp_ts_delta; + } + stat->stat_frame_cnt++; +} + +static void rv_tp_stat_init(struct st_rx_video_tp* tp) { + struct st_rv_tp_stat* stat = &tp->stat; + + memset(stat, 0, sizeof(*stat)); + rv_tp_slot_init(&stat->slot); + stat->stat_fpt_min = INT_MAX; + stat->stat_fpt_max = INT_MIN; + stat->stat_latency_min = INT_MAX; + stat->stat_latency_max = INT_MIN; + stat->stat_rtp_offset_min = INT_MAX; + stat->stat_rtp_offset_max = INT_MIN; + stat->stat_rtp_ts_delta_min = INT_MAX; + stat->stat_rtp_ts_delta_max = INT_MIN; +} + +void rv_tp_stat(struct st_rx_video_session_impl* s) { + int idx = s->idx; + struct st_rx_video_tp* tp = s->tp; + if (!tp) return; + + struct st_rv_tp_stat* stat = &tp->stat; + struct st_rv_tp_slot* stat_slot = &stat->slot; + + info("%s(%d), COMPLIANT NARROW %d WIDE %d FAILED %d!\n", __func__, idx, + stat->stat_compliant_result[ST_RX_TP_COMPLIANT_NARROW], + stat->stat_compliant_result[ST_RX_TP_COMPLIANT_WIDE], + stat->stat_compliant_result[ST_RX_TP_COMPLIANT_FAILED]); + float cinst_avg = rv_tp_calculate_avg(stat_slot->pkt_cnt, stat_slot->cinst_sum); + float vrx_avg = rv_tp_calculate_avg(stat_slot->pkt_cnt, stat_slot->vrx_sum); + float ipt_avg = rv_tp_calculate_avg(stat_slot->pkt_cnt, stat_slot->ipt_sum); + info("%s(%d), Cinst AVG %.2f MIN %d MAX %d!\n", __func__, idx, cinst_avg, + stat_slot->cinst_min, stat_slot->cinst_max); + info("%s(%d), VRX AVG %.2f MIN %d MAX %d!\n", __func__, idx, vrx_avg, + stat_slot->vrx_min, stat_slot->vrx_max); + info("%s(%d), Inter-packet time(ns) AVG %.2f MIN %d MAX %d!\n", __func__, idx, ipt_avg, + stat_slot->ipt_min, stat_slot->ipt_max); + float fpt_avg = rv_tp_calculate_avg(stat->stat_frame_cnt, stat->stat_fpt_sum); + info("%s(%d), FPT AVG %.2f MIN %d MAX %d DIFF %d!\n", __func__, idx, fpt_avg, + stat->stat_fpt_min, stat->stat_fpt_max, stat->stat_fpt_max - stat->stat_fpt_min); + float latency_avg = rv_tp_calculate_avg(stat->stat_frame_cnt, stat->stat_latency_sum); + info("%s(%d), LATENCY AVG %.2f MIN %d MAX %d!\n", __func__, idx, latency_avg, + stat->stat_latency_min, stat->stat_latency_max); + float rtp_offset_avg = + rv_tp_calculate_avg(stat->stat_frame_cnt, stat->stat_rtp_offset_sum); + info("%s(%d), RTP OFFSET AVG %.2f MIN %d MAX %d!\n", __func__, idx, rtp_offset_avg, + stat->stat_rtp_offset_min, stat->stat_rtp_offset_max); + float rtp_ts_delta_avg = + rv_tp_calculate_avg(stat->stat_frame_cnt, stat->stat_rtp_ts_delta_sum); + info("%s(%d), RTP TS DELTA AVG %.2f MIN %d MAX %d!\n", __func__, idx, rtp_ts_delta_avg, + stat->stat_rtp_ts_delta_min, stat->stat_rtp_ts_delta_max); + rv_tp_stat_init(tp); +} + +void rv_tp_slot_init(struct st_rv_tp_slot* slot) { + memset(slot, 0, sizeof(*slot)); + + slot->cinst_max = INT_MIN; + slot->cinst_min = INT_MAX; + slot->vrx_max = INT_MIN; + slot->vrx_min = INT_MAX; + slot->ipt_max = INT_MIN; + slot->ipt_min = INT_MAX; +} + +int rv_tp_uinit(struct st_rx_video_session_impl* s) { + if (s->tp) { + mt_rte_free(s->tp); + s->tp = NULL; + } + + return 0; +} + +int rv_tp_init(struct mtl_main_impl* impl, struct st_rx_video_session_impl* s) { + enum mtl_port port = mt_port_logic2phy(s->port_maps, MTL_SESSION_PORT_P); + int soc_id = mt_socket_id(impl, port); + int idx = s->idx, ret; + struct st_rx_video_tp* tp; + struct st20_rx_ops* ops = &s->ops; + double frame_time = s->frame_time; + double frame_time_s; + struct st_fps_timing fps_tm; + + ret = st_get_fps_timing(ops->fps, &fps_tm); + if (ret < 0) { + err("%s(%d), invalid fps %d\n", __func__, idx, ops->fps); + return ret; + } + frame_time_s = (double)fps_tm.den / fps_tm.mul; + + int st20_total_pkts = s->detector.pkt_per_frame; + info("%s(%d), st20_total_pkts %d\n", __func__, idx, st20_total_pkts); + if (!st20_total_pkts) { + err("%s(%d), can not get total packets number\n", __func__, idx); + return -EINVAL; + } + + tp = mt_rte_zmalloc_socket(sizeof(*tp), soc_id); + if (!tp) { + err("%s(%d), tp malloc fail\n", __func__, idx); + return -ENOMEM; + } + s->tp = tp; + + rv_tp_stat_init(tp); + + double reactive = 1080.0 / 1125.0; + if (ops->interlaced && ops->height <= 576) { + reactive = (ops->height == 480) ? 487.0 / 525.0 : 576.0 / 625.0; + } + + tp->trs = frame_time * reactive / st20_total_pkts; + if (!ops->interlaced) { + tp->tr_offset = + ops->height >= 1080 ? frame_time * (43.0 / 1125.0) : frame_time * (28.0 / 750.0); + } else { + if (ops->height == 480) { + tp->tr_offset = frame_time * (20.0 / 525.0) * 2; + } else if (ops->height == 576) { + tp->tr_offset = frame_time * (26.0 / 625.0) * 2; + } else { + tp->tr_offset = frame_time * (22.0 / 1125.0) * 2; + } + } + + tp->c_max_narrow_pass = + RTE_MAX(4, (double)st20_total_pkts / (43200 * reactive * frame_time_s)); + tp->c_max_wide_pass = RTE_MAX(16, (double)st20_total_pkts / (21600 * frame_time_s)); + tp->vrx_full_narrow_pass = RTE_MAX(8, st20_total_pkts / (27000 * frame_time_s)); + tp->vrx_full_wide_pass = RTE_MAX(720, st20_total_pkts / (300 * frame_time_s)); + tp->rtp_offset_max_pass = + ceil((tp->tr_offset / NS_PER_S) * fps_tm.sampling_clock_rate) + 1; + + rv_tp_stat_init(tp); + + info("%s[%02d], trs %f tr offset %f sampling %f\n", __func__, idx, tp->trs, + tp->tr_offset, s->frame_time_sampling); + info( + "%s[%02d], cmax_narrow %d cmax_wide %d vrx_full_narrow %d vrx_full_wide %d " + "rtp_offset_max %d\n", + __func__, idx, tp->c_max_narrow_pass, tp->c_max_wide_pass, tp->vrx_full_narrow_pass, + tp->vrx_full_wide_pass, tp->rtp_offset_max_pass); + return 0; +} + +static void ra_tp_stat_init(struct st_rx_audio_tp* tp) { + struct st_ra_tp_stat* stat = &tp->stat; + + memset(stat, 0, sizeof(*stat)); + ra_tp_slot_init(&stat->slot); +} + +static enum st_rx_tp_compliant ra_tp_slot_compliant(struct st_rx_audio_tp* tp, + struct st_ra_tp_slot* slot) { + /* dpvr check */ + if ((slot->dpvr_min < 0) || (slot->dpvr_max > tp->dpvr_max_pass_wide)) + return ST_RX_TP_COMPLIANT_FAILED; + if (slot->dpvr_max > tp->dpvr_max_pass_narrow) return ST_RX_TP_COMPLIANT_WIDE; + return ST_RX_TP_COMPLIANT_NARROW; +} + +void ra_tp_slot_parse_result(struct st_rx_audio_session_impl* s, + struct st_ra_tp_slot* slot) { + struct st_rx_audio_tp* tp = s->tp; + + /* parse tp compliant for current frame */ + enum st_rx_tp_compliant compliant = ra_tp_slot_compliant(tp, slot); + slot->compliant = compliant; + + /* update stat */ + struct st_ra_tp_stat* stat = &tp->stat; + struct st_ra_tp_slot* stat_slot = &stat->slot; + + stat->stat_compliant_result[compliant]++; + + stat_slot->dpvr_sum += slot->dpvr_sum; + stat_slot->dpvr_min = RTE_MIN(stat_slot->dpvr_min, slot->dpvr_min); + stat_slot->dpvr_max = RTE_MAX(stat_slot->dpvr_min, slot->dpvr_max); + + stat_slot->pkt_cnt += slot->pkt_cnt; +} + +void ra_tp_on_packet(struct st_rx_audio_session_impl* s, struct st_ra_tp_slot* slot, + uint32_t rtp_tmstamp, uint64_t pkt_time) { + struct st_rx_audio_tp* tp = s->tp; + + uint64_t epochs = (double)pkt_time / tp->frame_time; + uint64_t epoch_tmstamp = (double)epochs * tp->frame_time; + double fpt_delta = (double)pkt_time - epoch_tmstamp; + uint64_t tmstamp64 = epochs * tp->frame_time_sampling; + uint32_t tmstamp32 = tmstamp64; + double diff_rtp_ts = (double)rtp_tmstamp - tmstamp32; + double diff_rtp_ts_ns = diff_rtp_ts * tp->frame_time / tp->frame_time_sampling; + double latency = fpt_delta - diff_rtp_ts_ns; + double dpvr = latency / 1000; + + slot->pkt_cnt++; + + /* calculate Delta Packet vs RTP */ + slot->dpvr_min = RTE_MIN(dpvr, slot->dpvr_min); + slot->dpvr_max = RTE_MAX(dpvr, slot->dpvr_max); + slot->dpvr_sum += dpvr; + + struct st_ra_tp_stat* stat = &tp->stat; + if (!stat->dpvr_first) stat->dpvr_first = dpvr; +} + +int ra_tp_init(struct mtl_main_impl* impl, struct st_rx_audio_session_impl* s) { + enum mtl_port port = mt_port_logic2phy(s->port_maps, MTL_SESSION_PORT_P); + int soc_id = mt_socket_id(impl, port); + int idx = s->idx; + struct st_rx_audio_tp* tp; + struct st30_rx_ops* ops = &s->ops; + + tp = mt_rte_zmalloc_socket(sizeof(*tp), soc_id); + if (!tp) { + err("%s(%d), tp malloc fail\n", __func__, idx); + return -ENOMEM; + } + s->tp = tp; + + int sampling = (ops->sampling == ST30_SAMPLING_48K) ? 48 : 96; + tp->frame_time = (double)1000000000.0 * 1 / 1000; /* 1ms, in ns */ + tp->frame_time_sampling = (double)(sampling * 1000) * 1 / 1000; + + tp->dpvr_max_pass_narrow = 3 * tp->frame_time / 1000; /* in us */ + tp->dpvr_max_pass_wide = 20 * tp->frame_time / 1000; /* in us */ + tp->tsdf_max_pass = 17 * tp->frame_time / 1000; /* in us */ + + ra_tp_stat_init(tp); + + info("%s(%d), Delta Packet vs RTP Pass Criteria in us, narrow %d wide %d\n", __func__, + idx, tp->dpvr_max_pass_narrow, tp->dpvr_max_pass_wide); + info("%s(%d), Maximum Timestamped Delay Factor Pass Criteria %d (us)\n", __func__, idx, + tp->tsdf_max_pass); + + return 0; +} + +int ra_tp_uinit(struct st_rx_audio_session_impl* s) { + if (s->tp) { + mt_rte_free(s->tp); + s->tp = NULL; + } + + return 0; +} + +void ra_tp_stat(struct st_rx_audio_session_impl* s) { + int idx = s->idx; + struct st_rx_audio_tp* tp = s->tp; + struct st_ra_tp_stat* stat = &tp->stat; + struct st_ra_tp_slot* stat_slot = &stat->slot; + + info("%s(%d), COMPLIANT NARROW %d WIDE %d FAILED %d!\n", __func__, idx, + stat->stat_compliant_result[ST_RX_TP_COMPLIANT_NARROW], + stat->stat_compliant_result[ST_RX_TP_COMPLIANT_WIDE], + stat->stat_compliant_result[ST_RX_TP_COMPLIANT_FAILED]); + float dpvr_avg = rv_tp_calculate_avg(stat_slot->pkt_cnt, stat_slot->dpvr_sum); + info("%s(%d), dpvr AVG %.2f MIN %d MAX %d, pkt_cnt %u\n", __func__, idx, dpvr_avg, + stat_slot->dpvr_min, stat_slot->dpvr_max, stat_slot->pkt_cnt); + + /* Maximum Timestamped Delay Factor */ + int32_t tsdf = + (stat_slot->dpvr_max - stat->dpvr_first) - (stat_slot->dpvr_min - stat->dpvr_first); + info("%s(%d), tsdf %d\n", __func__, idx, tsdf); + + ra_tp_stat_init(tp); +} + +void ra_tp_slot_init(struct st_ra_tp_slot* slot) { + memset(slot, 0, sizeof(*slot)); + + slot->dpvr_max = INT_MIN; + slot->dpvr_min = INT_MAX; +} diff --git a/lib/src/st2110/st_rx_timing_parser.h b/lib/src/st2110/st_rx_timing_parser.h new file mode 100644 index 000000000..c8badf389 --- /dev/null +++ b/lib/src/st2110/st_rx_timing_parser.h @@ -0,0 +1,36 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Intel Corporation + */ + +#ifndef _ST_LIB_RX_TP_HEAD_H_ +#define _ST_LIB_RX_TP_HEAD_H_ + +#include "st_main.h" + +int rv_tp_init(struct mtl_main_impl* impl, struct st_rx_video_session_impl* s); +int rv_tp_uinit(struct st_rx_video_session_impl* s); + +void rv_tp_slot_init(struct st_rv_tp_slot* slot); + +void rv_tp_on_packet(struct st_rx_video_session_impl* s, struct st_rv_tp_slot* slot, + uint32_t rtp_tmstamp, uint64_t pkt_time, int pkt_idx); + +void rv_tp_slot_parse_result(struct st_rx_video_session_impl* s, + struct st_rv_tp_slot* slot); + +void rv_tp_stat(struct st_rx_video_session_impl* s); + +int ra_tp_init(struct mtl_main_impl* impl, struct st_rx_audio_session_impl* s); +int ra_tp_uinit(struct st_rx_audio_session_impl* s); + +void ra_tp_on_packet(struct st_rx_audio_session_impl* s, struct st_ra_tp_slot* slot, + uint32_t rtp_tmstamp, uint64_t pkt_time); + +void ra_tp_slot_parse_result(struct st_rx_audio_session_impl* s, + struct st_ra_tp_slot* slot); + +void ra_tp_stat(struct st_rx_audio_session_impl* s); + +void ra_tp_slot_init(struct st_ra_tp_slot* slot); + +#endif \ No newline at end of file diff --git a/lib/src/st2110/st_rx_video_session.c b/lib/src/st2110/st_rx_video_session.c index a5a94e2ce..8710c8c8b 100644 --- a/lib/src/st2110/st_rx_video_session.c +++ b/lib/src/st2110/st_rx_video_session.c @@ -12,7 +12,7 @@ #include "../mt_rtcp.h" #include "../mt_stat.h" #include "st_fmt.h" -#include "st_rx_ebu.h" +#include "st_rx_timing_parser.h" static int rv_init_pkt_handler(struct st_rx_video_session_impl* s); static int rvs_mgr_update(struct st_rx_video_sessions_mgr* mgr); @@ -712,10 +712,10 @@ static void rv_frame_notify(struct st_rx_video_session_impl* s, struct st20_rx_ops* ops = &s->ops; struct st20_rx_frame_meta* meta = &slot->meta; - if (s->ebu) { - /* todo: share the ebu data to st20_rx_frame_meta */ - struct st_rv_ebu_slot* ebu_slot = &s->ebu->slots[slot->idx]; - rv_ebu_slot_parse_result(s, ebu_slot); + if (s->enable_timing_parser) { + /* todo: share the timing data to st20_rx_frame_meta */ + struct st_rv_tp_slot* tp_slot = &s->tp->slots[slot->idx]; + rv_tp_slot_parse_result(s, tp_slot); } dbg("%s(%d), start\n", __func__, s->idx); @@ -991,7 +991,7 @@ static struct st_rx_video_slot_impl* rv_slot_by_tmstamp( slot->pkts_recv_per_port[MTL_SESSION_PORT_R] = 0; s->slot_idx = slot_idx; - if (s->ebu) rv_ebu_slot_init(&s->ebu->slots[slot_idx]); + if (s->enable_timing_parser) rv_tp_slot_init(&s->tp->slots[slot_idx]); struct st_frame_trans* frame_info = rv_get_frame(s); if (!frame_info) { @@ -1280,7 +1280,7 @@ static int rv_dump_pcapng(struct mtl_main_impl* impl, struct st_rx_video_session #if RTE_VERSION < RTE_VERSION_NUM(23, 11, 0, 0) /* dpdk 23.11 uses internal time */ struct mt_interface* inf = mt_if(impl, port); if (inf->feature & MT_IF_FEATURE_RX_OFFLOAD_TIMESTAMP) - timestamp_ns = mt_mbuf_hw_time_stamp(impl, mbuf[i], port); + timestamp_ns = mt_mbuf_time_stamp(impl, mbuf[i], port); else timestamp_cycle = rte_get_tsc_cycles(); #endif @@ -1520,20 +1520,16 @@ static int rv_handle_frame_pkt(struct st_rx_video_session_impl* s, struct rte_mb bool need_copy = true; struct mtl_dma_lender_dev* dma_dev = s->dma_dev; - /* if ebu */ - if (s->ebu) { + /* if enable_timing_parser */ + if (s->enable_timing_parser) { struct mtl_main_impl* impl = rv_get_impl(s); enum mtl_port port = mt_port_logic2phy(s->port_maps, s_port); - struct mt_interface* inf = mt_if(impl, port); - if (mt_ptp_is_connected(impl, port)) { - uint64_t pkt_ns; - if (inf->feature & MT_IF_FEATURE_RX_OFFLOAD_TIMESTAMP) - pkt_ns = mt_mbuf_hw_time_stamp(impl, mbuf, port); - else - pkt_ns = mt_ptp_internal_time(impl, port); - struct st_rv_ebu_slot* ebu_slot = &s->ebu->slots[slot->idx]; - rv_ebu_on_packet(s, ebu_slot, tmstamp, pkt_ns, pkt_idx); - } + + uint64_t pkt_ns = mt_mbuf_time_stamp(impl, mbuf, port); + struct st_rv_tp_slot* tp_slot = &s->tp->slots[slot->idx]; + dbg("%s(%d,%d), tmstamp %u pkt_ns %" PRIu64 " pkt_idx %d\n", __func__, s->idx, s_port, + tmstamp, pkt_ns, pkt_idx); + rv_tp_on_packet(s, tp_slot, tmstamp, pkt_ns, pkt_idx); } if (s->st20_uframe_size) { @@ -2246,7 +2242,7 @@ static int rv_uinit_st22(struct st_rx_video_session_impl* s) { } static int rv_uinit_sw(struct mtl_main_impl* impl, struct st_rx_video_session_impl* s) { - rv_ebu_uinit(s); + rv_tp_uinit(s); rv_uinit_pkt_lcore(impl, s); rv_free_dma(impl, s); rv_uinit_slot(s); @@ -2360,8 +2356,8 @@ static int rv_init_sw(struct mtl_main_impl* impl, struct st_rx_video_sessions_mg s->slot_max = ST_VIDEO_RX_REC_NUM_OFO; } - if (s->enable_ebu) { - ret = rv_ebu_init(impl, s); + if (s->enable_timing_parser) { + ret = rv_tp_init(impl, s); if (ret < 0) { err("%s(%d), ebu init fail %d\n", __func__, idx, ret); rv_uinit_sw(impl, s); @@ -2995,10 +2991,10 @@ static int rv_attach(struct mtl_main_impl* impl, struct st_rx_video_sessions_mgr s->dma_busy_score = 0; s->st22_expect_frame_size = 0; s->burst_loss_cnt = 0; - if (mt_user_ebu_active(impl)) - s->enable_ebu = true; - else - s->enable_ebu = false; + if (s->ops.flags & ST20_RX_FLAG_ENABLE_TIMING_PARSER) { + info("%s(%d), enable the timing analyze\n", __func__, idx); + s->enable_timing_parser = true; + } ret = rv_init_hw(impl, s); if (ret < 0) { @@ -3007,7 +3003,7 @@ static int rv_attach(struct mtl_main_impl* impl, struct st_rx_video_sessions_mgr } if (st20_is_frame_type(ops->type) && (!st22_ops) && - ((ops->flags & ST20_RX_FLAG_AUTO_DETECT) || s->enable_ebu)) { + ((ops->flags & ST20_RX_FLAG_AUTO_DETECT) || s->enable_timing_parser)) { /* init sw after detected */ ret = rv_detector_init(s); if (ret < 0) { @@ -3345,7 +3341,7 @@ static void rv_stat(struct st_rx_video_sessions_mgr* mgr, s->stat_st22_boxes); s->stat_st22_boxes = 0; } - if (s->ebu) rv_ebu_stat(s); + if (s->enable_timing_parser) rv_tp_stat(s); } static int rvs_ctl_tasklet_start(void* priv) { diff --git a/lib/src/st2110/st_rx_video_session.h b/lib/src/st2110/st_rx_video_session.h index 9ee5a47c3..4b0e1b788 100644 --- a/lib/src/st2110/st_rx_video_session.h +++ b/lib/src/st2110/st_rx_video_session.h @@ -11,8 +11,8 @@ #define ST_RX_VIDEO_DMA_MIN_SIZE (1024) -#define ST_RV_EBU_TSC_SYNC_MS (100) /* sync tsc with ptp period(ms) */ -#define ST_RV_EBU_TSC_SYNC_NS (ST_RV_EBU_TSC_SYNC_MS * 1000 * 1000) +#define ST_RV_TP_TSC_SYNC_MS (100) /* sync tsc with ptp period(ms) */ +#define ST_RV_TP_TSC_SYNC_NS (ST_RV_TP_TSC_SYNC_MS * 1000 * 1000) #define ST_RX_VIDEO_PREFIX "RV_" diff --git a/tests/script/README.md b/tests/script/README.md index 192982011..780d6cf2c 100644 --- a/tests/script/README.md +++ b/tests/script/README.md @@ -39,10 +39,10 @@ Use the random IP for json config file, run: ./loop_test.sh ``` -Run below cmd for the software ebu test with loop mode. +Run below cmd for the software timing parser test with loop mode. ```bash -./loop_ebu_test.sh +./loop_TP_test.sh ``` ## 3. AFXDP loop test diff --git a/tests/script/loop_ebu_test.sh b/tests/script/loop_ebu_test.sh index 797d0e0e2..47bc2dab9 100755 --- a/tests/script/loop_ebu_test.sh +++ b/tests/script/loop_ebu_test.sh @@ -32,7 +32,7 @@ echo "Total ${#TEST_JSON_LIST[@]} cases, each with ${TEST_TIME_SEC}s" for ((loop=0; loop