obs_source_frame
+ -

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;

0 篇笔记 写笔记

作者信息
我爱内核
Windows驱动开发,网站开发
好好学习,天天向上。
取消
感谢您的支持,我会继续努力的!
扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

您的支持,是我们前进的动力!