mirror of
https://github.com/obsproject/obs-studio.git
synced 2024-07-14 23:34:08 +00:00
libobs: Improve timing of unbuffered deinterlacing
There are devices like the GV-USB2 that produce frames with smmoth timestamps at an uneven pace, which causes OBS to stutter because the unbuffered path is designed to aggressively operate on the latest frame. We can make the unbuffered path work by making two adjustments: - Don't discard the current frame until it has elapsed. - Don't skip frames in the queue until they have elapsed. The buffered path still has problems with deinterlacing GV-USB2 output, but the unbuffered path is better anyway. Testing: GV-USB2, Unbuffered: Stuttering is gone! GV-USB2, Buffered: No regression (still broken). SC-512N1-L/DVI, Unbuffered: No regression (still works). SC-512N1-L/DVI, Buffered: No regression (still works).
This commit is contained in:
parent
cdb7cd80f6
commit
3ea98b8b0d
|
@ -34,8 +34,28 @@ static bool ready_deinterlace_frames(obs_source_t *source, uint64_t sys_time)
|
|||
next_frame = source->async_frames.array[0];
|
||||
}
|
||||
|
||||
if (source->async_frames.num == 2)
|
||||
source->async_frames.array[0]->prev_frame = true;
|
||||
if (source->async_frames.num == 2) {
|
||||
bool prev_frame = true;
|
||||
if (source->async_unbuffered &&
|
||||
source->deinterlace_offset) {
|
||||
const uint64_t timestamp =
|
||||
source->async_frames.array[0]->timestamp;
|
||||
const uint64_t after_timestamp =
|
||||
source->async_frames.array[1]->timestamp;
|
||||
const uint64_t duration =
|
||||
after_timestamp - timestamp;
|
||||
const uint64_t frame_end =
|
||||
timestamp + source->deinterlace_offset +
|
||||
duration;
|
||||
if (sys_time < frame_end) {
|
||||
// Don't skip ahead prematurely.
|
||||
prev_frame = false;
|
||||
source->deinterlace_frame_ts =
|
||||
timestamp - duration;
|
||||
}
|
||||
}
|
||||
source->async_frames.array[0]->prev_frame = prev_frame;
|
||||
}
|
||||
source->deinterlace_offset = 0;
|
||||
source->last_frame_ts = next_frame->timestamp;
|
||||
return true;
|
||||
|
@ -122,12 +142,30 @@ static inline uint64_t uint64_diff(uint64_t ts1, uint64_t ts2)
|
|||
return (ts1 < ts2) ? (ts2 - ts1) : (ts1 - ts2);
|
||||
}
|
||||
|
||||
#define TWOX_TOLERANCE 1000000
|
||||
#define TS_JUMP_THRESHOLD 70000000ULL
|
||||
|
||||
static inline void deinterlace_get_closest_frames(obs_source_t *s,
|
||||
uint64_t sys_time)
|
||||
{
|
||||
const struct video_output_info *info;
|
||||
uint64_t half_interval;
|
||||
|
||||
if (s->async_unbuffered && s->deinterlace_offset) {
|
||||
// Want to keep frame if it has not elapsed.
|
||||
const uint64_t frame_end =
|
||||
s->deinterlace_frame_ts + s->deinterlace_offset +
|
||||
((uint64_t)s->deinterlace_half_duration * 2) -
|
||||
TWOX_TOLERANCE;
|
||||
if (sys_time < frame_end) {
|
||||
// Process new frames if we think time jumped.
|
||||
const uint64_t diff = frame_end - sys_time;
|
||||
if (diff < TS_JUMP_THRESHOLD) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!s->async_frames.num)
|
||||
return;
|
||||
|
||||
|
@ -303,8 +341,6 @@ static inline gs_effect_t *get_effect(enum obs_deinterlace_mode mode)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
#define TWOX_TOLERANCE 1000000
|
||||
|
||||
void deinterlace_render(obs_source_t *s)
|
||||
{
|
||||
gs_effect_t *effect = s->deinterlace_effect;
|
||||
|
|
Loading…
Reference in a new issue