File npv/TODO changed (mode: 100644) (index 1e32934..90608f3) |
1 |
1 |
not ordered: |
not ordered: |
2 |
|
- some live streams can have the audio and video unsynced up to 10 seconds with |
|
3 |
|
missing tons of video frames. |
|
4 |
|
To support those rare and horrible streams, what seems to be a reasonable |
|
5 |
|
work around: |
|
6 |
|
- always presume monotonic decoding of frames, monotonic as presentation |
|
7 |
|
order, not pts monotonic. |
|
8 |
|
- once the array of frames reached a specified limit, do buffer the |
|
9 |
|
video demuxed packets. |
|
10 |
|
- it would means that outside of transient discontinuity handling, |
|
11 |
|
usually based on the audio, only the "too old" frames would be dropped. |
|
|
2 |
|
- try to workaround as much as possible the nasty live streams out there. |
12 |
3 |
- "buffering" indicator (no)? subtitles (mmmmh...)? |
- "buffering" indicator (no)? subtitles (mmmmh...)? |
13 |
4 |
- use vulkan shaders (no glsl or hlsl), compute or not, in order to perform |
- use vulkan shaders (no glsl or hlsl), compute or not, in order to perform |
14 |
5 |
some yuvX pixel formats to srgb format conversions. do NOT use the vulkan |
some yuvX pixel formats to srgb format conversions. do NOT use the vulkan |
File npv/config.h changed (mode: 100644) (index 54fc3c1..090af26) |
... |
... |
struct npv_x11_bind_t npv_x11_binds[] = { |
72 |
72 |
#define SEEK_DELTA_BIG (INT64_C(4) * INT64_C(60)) /* 4 minutes */ |
#define SEEK_DELTA_BIG (INT64_C(4) * INT64_C(60)) /* 4 minutes */ |
73 |
73 |
/*============================================================================*/ |
/*============================================================================*/ |
74 |
74 |
/* kinky internal settings, modify with care */ |
/* kinky internal settings, modify with care */ |
75 |
|
/* the count of decoded video frames in the array, it is "expensive" */ |
|
|
75 |
|
/* |
|
76 |
|
* The targeted count of decoded video frames in the array (while not |
|
77 |
|
* resyncing). Decoded frames are "memory expensive". |
|
78 |
|
*/ |
76 |
79 |
#define DEC_FRS_ARRAY_N_MAX 4 |
#define DEC_FRS_ARRAY_N_MAX 4 |
77 |
80 |
/* |
/* |
78 |
81 |
* video frames are presumed arriving inorder, but once a backward |
* video frames are presumed arriving inorder, but once a backward |
79 |
|
* discontinuity is detected, in order to avoid a full and dead locked array of |
|
80 |
|
* predecoded video frames, we must drop frames until we resynchronize. To |
|
81 |
|
* decide if we found a resynchronzining frame, we define a time window based |
|
82 |
|
* on the following value |
|
|
82 |
|
* discontinuity is detected, in order to avoid a full/dead locked array of |
|
83 |
|
* predecoded video frames, we unlock the size of array of decoded frames until |
|
84 |
|
* we "resynchronize". To decide if we found a resynchronizing frame, we define |
|
85 |
|
* a time window based on the following value. |
83 |
86 |
*/ |
*/ |
84 |
87 |
#define DISCONT_BACKWARD_RESYNC_MS 500 |
#define DISCONT_BACKWARD_RESYNC_MS 500 |
85 |
88 |
#endif |
#endif |
File npv/pipeline/local/code.frag.c changed (mode: 100644) (index bef6d57..aac6b3d) |
... |
... |
STATIC bool have_enough_predecoded_video_frs(void) |
153 |
153 |
npv_video_dec_frs_lock(); |
npv_video_dec_frs_lock(); |
154 |
154 |
if (npv_video_dec_frs_p.eof_receive) { |
if (npv_video_dec_frs_p.eof_receive) { |
155 |
155 |
r = true; |
r = true; |
156 |
|
} else if (npv_video_dec_frs_p.n < DEC_FRS_ARRAY_N_MAX) { |
|
|
156 |
|
} else if (npv_video_dec_frs_p.discont_backward.resyncing) |
|
157 |
|
/* |
|
158 |
|
* We are looking for a "resyncing" fr, and to secure we |
|
159 |
|
* receive one, we must decode more frs or the dec frs a |
|
160 |
|
* may endup full and dead locked. |
|
161 |
|
*/ |
157 |
162 |
r = false; |
r = false; |
158 |
|
} else /* >= 4 */ |
|
|
163 |
|
else if (npv_video_dec_frs_p.n < DEC_FRS_ARRAY_N_MAX) { |
|
164 |
|
r = false; |
|
165 |
|
} else /* >= DEC_FRS_ARRAY_N_MAX && ! RESYNCING */ |
159 |
166 |
r = true; |
r = true; |
160 |
167 |
npv_video_dec_frs_unlock(); |
npv_video_dec_frs_unlock(); |
161 |
168 |
return r; |
return r; |
File npv/video/local/code.frag.c changed (mode: 100644) (index d6f7e54..20a1a18) |
... |
... |
STATIC void init_once_local(void) |
76 |
76 |
} |
} |
77 |
77 |
receive_fr_l = avutil_video_fr_ref_alloc(); |
receive_fr_l = avutil_video_fr_ref_alloc(); |
78 |
78 |
is_swpchn_sem_fence_submitted_l = false; |
is_swpchn_sem_fence_submitted_l = false; |
79 |
|
drop_l.prev_now = AV_NOPTS_VALUE; |
|
80 |
|
drop_l.until_resync = false; |
|
81 |
79 |
} |
} |
82 |
80 |
#undef NONE |
#undef NONE |
83 |
81 |
STATIC void scaler_img_create(avutil_video_fr_ref_t *fr) |
STATIC void scaler_img_create(avutil_video_fr_ref_t *fr) |
|
... |
... |
STATIC void fr_drop(u16 fr) |
336 |
334 |
STATIC void frs_drop(s64 now, avutil_video_fr_ref_t *selected_fr) |
STATIC void frs_drop(s64 now, avutil_video_fr_ref_t *selected_fr) |
337 |
335 |
{ |
{ |
338 |
336 |
u16 fr; |
u16 fr; |
339 |
|
s64 lo; |
|
340 |
|
s64 hi; |
|
341 |
|
s64 resync; |
|
342 |
337 |
|
|
343 |
338 |
if (selected_fr == NO_FR) |
if (selected_fr == NO_FR) |
344 |
|
goto exit; |
|
345 |
|
/* backward discont detected */ |
|
346 |
|
if (drop_l.prev_now != AV_NOPTS_VALUE && now < drop_l.prev_now) |
|
347 |
|
drop_l.until_resync = true; |
|
348 |
|
/*====================================================================*/ |
|
|
339 |
|
return; |
|
340 |
|
#ifdef NPV_DEBUG |
|
341 |
|
if (npv_debug_p) |
|
342 |
|
npv_perr("DEBUG:%s:selected_fr.pts=%ld\n", __func__, selected_fr->pts); |
|
343 |
|
#endif |
349 |
344 |
/* |
/* |
350 |
345 |
* since the frs are supposed inorder, first drop as many of as possible |
* since the frs are supposed inorder, first drop as many of as possible |
351 |
346 |
* frs received before the selected one |
* frs received before the selected one |
|
... |
... |
STATIC void frs_drop(s64 now, avutil_video_fr_ref_t *selected_fr) |
362 |
357 |
} else |
} else |
363 |
358 |
++fr; |
++fr; |
364 |
359 |
} |
} |
365 |
|
/*====================================================================*/ |
|
366 |
|
/* |
|
367 |
|
* here, we detected a backward discont, we are looking for a |
|
368 |
|
* resynchronizing fr based on a time win. we must drop, inorder, |
|
369 |
|
* frs which are out of the time win in order to avoid the dec frs a |
|
370 |
|
* being full and locked |
|
371 |
|
*/ |
|
372 |
|
if (!drop_l.until_resync) |
|
373 |
|
goto exit; |
|
374 |
|
resync = (DISCONT_BACKWARD_RESYNC_MS * st_p.tb.den) / (st_p.tb.num |
|
375 |
|
* 1000); |
|
376 |
|
lo = now - resync; |
|
377 |
|
hi = now + resync; |
|
378 |
|
fr = 0; |
|
379 |
|
loop { |
|
380 |
|
if (fr == dec_frs_p.n) |
|
381 |
|
break; |
|
382 |
|
/* don't touch the scaler fr or selected fr */ |
|
383 |
|
if (dec_frs_p.a[fr] != scaler_p.img.fr |
|
384 |
|
&& dec_frs_p.a[fr] != selected_fr) { |
|
385 |
|
if (dec_frs_p.a[fr]->pts < lo |
|
386 |
|
|| hi < dec_frs_p.a[fr]->pts) { |
|
387 |
|
if (dec_frs_p.a[fr] == last_fr_sent_to_pe_l) |
|
388 |
|
last_fr_sent_to_pe_l = NO_FR; |
|
389 |
|
fr_drop(fr); /* do not advance */ |
|
390 |
|
} else { /* found a resynchronizing fr */ |
|
391 |
|
drop_l.until_resync = false; |
|
392 |
|
break; |
|
393 |
|
} |
|
394 |
|
} else |
|
395 |
|
++fr; |
|
396 |
|
} |
|
397 |
|
exit: |
|
398 |
|
drop_l.prev_now = now; |
|
399 |
360 |
} |
} |
400 |
|
|
|
401 |
361 |
#undef NO_FR |
#undef NO_FR |
402 |
362 |
#define NO_FR 0 |
#define NO_FR 0 |
403 |
363 |
STATIC void select_fr(s64 now, avutil_video_fr_ref_t **selected_fr, |
STATIC void select_fr(s64 now, avutil_video_fr_ref_t **selected_fr, |
|
... |
... |
STATIC void timer_ack(void) |
763 |
723 |
if (r == -1) |
if (r == -1) |
764 |
724 |
warning("unable to read the number of timer expirations\n"); |
warning("unable to read the number of timer expirations\n"); |
765 |
725 |
} |
} |
|
726 |
|
/*NSPC*/ |
|
727 |
|
STATIC void discont_backward(s64 now) |
|
728 |
|
{ |
|
729 |
|
s64 lo; |
|
730 |
|
s64 hi; |
|
731 |
|
s64 resync; |
|
732 |
|
u16 fr; |
|
733 |
|
/* |
|
734 |
|
* Backward discont detected, we will look for a fr reasonably in sync: |
|
735 |
|
* we will named this "resyncing". |
|
736 |
|
* The issue is the dec frs a may not receive any new fr from the |
|
737 |
|
* pipeline which would refuse to add more in order to avoid filling |
|
738 |
|
* up memory. |
|
739 |
|
* Then, we choose to "take the risk" once a backward discontinuity is |
|
740 |
|
* detected, namely let the pipeline increase its hard limit and |
|
741 |
|
* potentially fill up huge amount of memory. |
|
742 |
|
* This was done to handle some live streams which drops many seconds |
|
743 |
|
* of frs and do some backward discontinuity at the same time. |
|
744 |
|
* If in normal usage this actually fills up too often the memory, |
|
745 |
|
* a tighter strategy would have to be implemented with the shrinking |
|
746 |
|
* of the dec frs a. |
|
747 |
|
*/ |
|
748 |
|
if (dec_frs_p.discont_backward.prev_now != AV_NOPTS_VALUE |
|
749 |
|
&& now < dec_frs_p.discont_backward.prev_now) |
|
750 |
|
dec_frs_p.discont_backward.resyncing = true; |
|
751 |
|
if (dec_frs_p.discont_backward.resyncing) |
|
752 |
|
goto exit; |
|
753 |
|
#ifdef NPV_DEBUG |
|
754 |
|
if (npv_debug_p) |
|
755 |
|
npv_perr("DEBUG:%s:running resyncing code\n", __func__); |
|
756 |
|
#endif |
|
757 |
|
resync = (DISCONT_BACKWARD_RESYNC_MS * st_p.tb.den) / (st_p.tb.num |
|
758 |
|
* 1000); |
|
759 |
|
lo = now - resync; |
|
760 |
|
hi = now + resync; |
|
761 |
|
fr = 0; |
|
762 |
|
loop { |
|
763 |
|
if (fr == dec_frs_p.n) |
|
764 |
|
break; |
|
765 |
|
if (lo <= dec_frs_p.a[fr]->pts && dec_frs_p.a[fr]->pts <= hi) { |
|
766 |
|
/* |
|
767 |
|
* We have a fr reasonably in sync in the dec frs a, |
|
768 |
|
* let's end this. |
|
769 |
|
*/ |
|
770 |
|
dec_frs_p.discont_backward.resyncing = false; |
|
771 |
|
break; |
|
772 |
|
} |
|
773 |
|
++fr; |
|
774 |
|
} |
|
775 |
|
exit: |
|
776 |
|
dec_frs_p.discont_backward.prev_now = now; |
|
777 |
|
} |