From 0fc81a53996993992dd86a96a26afd2aab0ac366 Mon Sep 17 00:00:00 2001 From: Sylvain BERTRAND Date: Fri, 25 Sep 2020 16:14:26 +0000 Subject: [PATCH] npv: backward discontinuity handling --- npv/config.h | 10 +++++++- npv/video/local/code.frag.c | 55 ++++++++++++++++++++++++++++++++++++++++---- npv/video/local/state.frag.c | 4 ++++ npv/video/namespace/main.c | 2 ++ npv/video/public/code.frag.c | 2 +- 5 files changed, 67 insertions(+), 6 deletions(-) diff --git a/npv/config.h b/npv/config.h index 2628bde..1830bf5 100644 --- a/npv/config.h +++ b/npv/config.h @@ -61,8 +61,16 @@ struct npv_x11_bind_t npv_x11_binds[] = { #define VOL_DELTA 0.1 /* from 0.0 to 1.0 */ #define SEEK_DELTA INT64_C(10) /* 10 seconds */ #define SEEK_DELTA_BIG (INT64_C(4) * INT64_C(60)) /* 4 minutes */ -/*----------------------------------------------------------------------------*/ +/*============================================================================*/ /* kinky internal settings, modify with care */ /* the count of decoded video frames in the array, it is "expensive" */ #define DEC_FRS_ARRAY_N_MAX 4 +/* + * video frames are presumed arriving inorder, but once a backward + * discontinuity is detected, in order to avoid a full and dead locked array of + * predecoded video frames, we must drop frames until we resynchronize. To + * decide if we found a resynchronzining frame, we define a time window based + * on the following value + */ +#define DISCONT_BACKWARD_RESYNC_MS 500 #endif diff --git a/npv/video/local/code.frag.c b/npv/video/local/code.frag.c index 758aaf2..44017cd 100644 --- a/npv/video/local/code.frag.c +++ b/npv/video/local/code.frag.c @@ -76,6 +76,8 @@ STATIC void init_once_local(void) } receive_fr_l = avutil_video_fr_ref_alloc(); is_swpchn_sem_fence_submitted_l = false; + drop_l.prev_now = AV_NOPTS_VALUE; + drop_l.until_resync = false; } #undef NONE STATIC void scaler_img_create(avutil_video_fr_ref_t *fr) @@ -332,18 +334,28 @@ STATIC void fr_drop(u16 fr) } #undef NO_FR #define NO_FR 0 -STATIC void frs_drop(avutil_video_fr_ref_t *selected_fr) +STATIC void frs_drop(s64 now, avutil_video_fr_ref_t *selected_fr) { u16 fr; + s64 lo; + s64 hi; + s64 resync; if (selected_fr == NO_FR) - return; - /* drop as many of as possible frames received before the selected one */ + goto exit; + /* backward discont detected */ + if (drop_l.prev_now != AV_NOPTS_VALUE && now < drop_l.prev_now) + drop_l.until_resync = true; + /*====================================================================*/ + /* + * since the frs are supposed inorder, first drop as many of as possible + * frs received before the selected one + */ fr = 0; loop { if (dec_frs_p.a[fr] == selected_fr) break; - /* keep the fr the scaler is related to */ + /* don't touch the scaler fr */ if (dec_frs_p.a[fr] != scaler_p.img.fr) { if (dec_frs_p.a[fr] == last_fr_sent_to_pe_l) last_fr_sent_to_pe_l = NO_FR; @@ -351,7 +363,42 @@ STATIC void frs_drop(avutil_video_fr_ref_t *selected_fr) } else ++fr; } + /*====================================================================*/ + /* + * here, we detected a backward discont, we are looking for a + * resynchronizing fr based on a time win. we must drop, inorder, + * frs which are out of the time win in order to avoid the dec frs a + * being full and locked + */ + if (!drop_l.until_resync) + goto exit; + resync = (DISCONT_BACKWARD_RESYNC_MS * st_p.tb.den) / (st_p.tb.num + * 1000); + lo = now - resync; + hi = now + resync; + fr = 0; + loop { + if (fr == dec_frs_p.n) + break; + /* don't touch the scaler fr or selected fr */ + if (dec_frs_p.a[fr] != scaler_p.img.fr + && dec_frs_p.a[fr] != selected_fr) { + if (dec_frs_p.a[fr]->pts < lo + || hi < dec_frs_p.a[fr]->pts) { + if (dec_frs_p.a[fr] == last_fr_sent_to_pe_l) + last_fr_sent_to_pe_l = NO_FR; + fr_drop(fr); /* do not advance */ + } else { /* found a resynchronizing fr */ + drop_l.until_resync = false; + break; + } + } else + ++fr; + } +exit: + drop_l.prev_now = now; } + #undef NO_FR #define NO_FR 0 STATIC void select_fr(s64 now, avutil_video_fr_ref_t **selected_fr, diff --git a/npv/video/local/state.frag.c b/npv/video/local/state.frag.c index ec8e788..89f57be 100644 --- a/npv/video/local/state.frag.c +++ b/npv/video/local/state.frag.c @@ -17,3 +17,7 @@ STATIC struct { } blit_l[npv_vk_swpchn_imgs_n_max]; STATIC avutil_video_fr_ref_t *last_fr_sent_to_pe_l; STATIC bool is_swpchn_sem_fence_submitted_l; +STATIC struct { + s64 prev_now; + bool until_resync; +} drop_l; diff --git a/npv/video/namespace/main.c b/npv/video/namespace/main.c index bf28b16..8f23c73 100644 --- a/npv/video/namespace/main.c +++ b/npv/video/namespace/main.c @@ -13,6 +13,7 @@ #define dec_a_grow npv_video_dec_a_grow #define dec_ctx_mutex_l npv_video_dec_ctx_mutex_l #define dec_l npv_video_dec_l +#define drop_l npv_video_drop_l #define fatal npv_video_fatal #define fatalff npv_video_fatalff #define fatalvk npv_video_fatalvk @@ -62,6 +63,7 @@ #undef dec_a_grow #undef dec_ctx_mutex_l #undef dec_l +#undef drop_l #undef fatal #undef fatalff #undef fatalvk diff --git a/npv/video/public/code.frag.c b/npv/video/public/code.frag.c index ee65471..5fb8dfd 100644 --- a/npv/video/public/code.frag.c +++ b/npv/video/public/code.frag.c @@ -217,7 +217,7 @@ STATIC void timer_evt(void) return; } select_fr(now, &fr, &fr_priv); - frs_drop(fr); + frs_drop(now, fr); dec_frs_unlock(); /* unlock ------------------------------------------------------------*/ if (fr == NO_FR) -- 2.11.4.GIT