ready_async_frame
2026-03-27
8
0
ready_async_frame函数用于移除在缓冲区队列中的所有“超时”的帧。
static bool ready_async_frame(obs_source_t *source, uint64_t sys_time)
- source :源对象,包含异步帧队列和时间戳信息
- sys_time :当前系统时间(纳秒)
- 返回值 :布尔值,表示是否有就绪的帧
ready_async_frame有2种模式,分为缓冲模式和非缓冲模式。通过async_unbuffered变量为区分。
非缓冲模式
对于非缓冲模式,只保留最新的一帧,丢弃所有旧帧,适用于实时源,如摄像头、屏幕捕获等,减少延迟,保证画面实时性
if (source->async_unbuffered) {
while (source->async_frames.num > 1) {
da_erase(source->async_frames, 0);
remove_async_frame(source, next_frame);
next_frame = source->async_frames.array[0];
}
source->last_frame_ts = next_frame->timestamp;
return true;
}
缓冲模式
这里有2个时间概念:
- 第一个时间为帧时间戳。这是从该obs_source创建之后相对于media-io的base_ts的一个ns时间戳,从该obs_source中输出的帧时间戳保证了其内在的连续性。
- 第二个为系统时间戳
时间戳有效性检查:
/* account for timestamp invalidation */
if (frame_out_of_bounds(source, frame_time)) {
#if DEBUG_ASYNC_FRAMES
blog(LOG_DEBUG, "timing jump");
#endif
source->last_frame_ts = next_frame->timestamp;
return true;
} else {
frame_offset = frame_time - source->last_frame_ts;
source->last_frame_ts += sys_offset;
}
frame_out_of_bounds超过了2秒,直接2秒跳帧加速播放
/* maximum timestamp variance in nanoseconds */
#define MAX_TS_VAR 2000000000ULL
static inline bool frame_out_of_bounds(const obs_source_t *source, uint64_t ts)
{
if (ts < source->last_frame_ts)
return ((source->last_frame_ts - ts) > MAX_TS_VAR);
else
return ((ts - source->last_frame_ts) > MAX_TS_VAR);
}
这2个时间戳肯定会有差异,所以同步是一个问题。
obs使用相对时间差来同步。
系统时间计算系统时间差,帧时间计算帧时间差。两者的时间差应相对同步。
//取缓冲区队列第一帧
struct obs_source_frame *next_frame = source->async_frames.array[0];
struct obs_source_frame *frame = NULL;
//两次调用的系统时间差
uint64_t sys_offset = sys_time - source->last_sys_timestamp;
//帧时间差
uint64_t frame_time = next_frame->timestamp;
uint64_t frame_offset = frame_time - source->last_frame_ts;
//通过帧时间差计算下一帧的时间差
source->last_frame_ts += sys_offset;
while (source->last_frame_ts > next_frame->timestamp)
{
//2ms
if ((source->last_frame_ts - next_frame->timestamp) < 2000000)
break;
if (frame)
da_erase(source->async_frames, 0);
remove_async_frame(source, frame);
if (source->async_frames.num == 1)
return true;
frame = next_frame;
next_frame = source->async_frames.array[1];
/* more timestamp checking and compensating */
if ((next_frame->timestamp - frame_time) > MAX_TS_VAR) {
#if DEBUG_ASYNC_FRAMES
blog(LOG_DEBUG, "timing jump");
#endif
source->last_frame_ts = next_frame->timestamp - frame_offset;
}
frame_time = next_frame->timestamp;
frame_offset = frame_time - source->last_frame_ts;
}
return frame != NULL;
obs_source_frame





