【V】native_window_set_buffers_timestamp介绍

603 阅读1分钟

native_window_set_buffers_timestamp用来设置surface上屏时间的,其原型如下:

static inline int native_window_set_buffers_timestamp(struct ANativeWindow* window, int64_t timestamp)

函数功能就是surface本次queue出去的buffer在timestamp后第一个vsync内进行显示。

视频播放会用native_window_set_buffers_timestamp接口来保证音画同步:

void ACodec::BaseState::onOutputBufferDrained(const sp<AMessage> &msg) {
    ...
    int64_t timestampNs = 0;
    if (!msg->findInt64("timestampNs", &timestampNs)) {
        // use media timestamp if client did not request a specific render timestamp
        if (buffer->meta()->findInt64("timeUs", &timestampNs)) {
            ALOGV("using buffer PTS of %lld", (long long)timestampNs);
            timestampNs *= 1000;
        }
    }

    status_t err;
    err = native_window_set_buffers_timestamp(mCodec->mNativeWindow.get(), timestampNs);
    ...
}

EGL的eglPresentationTimeANDROID的功能也是通过native_window_set_buffers_timestamp实现的:

EGLBoolean eglPresentationTimeANDROIDImpl(EGLDisplay dpy, EGLSurface surface,
                                          EGLnsecsANDROID time) {
    const egl_display_t* dp = validate_display(dpy);
    if (!dp) {
        return EGL_FALSE;
    }

    SurfaceRef _s(dp, surface);
    if (!_s.get()) {
        setError(EGL_BAD_SURFACE, EGL_FALSE);
        return EGL_FALSE;
    }

    egl_surface_t const* const s = get_surface(surface);
    native_window_set_buffers_timestamp(s->getNativeWindow(), time);

    return EGL_TRUE;
}

分析上面参数timestamp的流向,时序图如下:

通过上面分析,可知timestamp最终流向下面几个地方:

image.png

并且衍生了另外一个变量isAutoTimestamp,如果isAutoTimestamp为true,表示最上层设置了timestamp。如果为false,表示最上层没有设置timestamp,timestamp的值是系统根据apply调用时间自动生成的。

再分析sf对timestamp的处理:

sf在处理transaction时,如果该transction是否设置isAutoTimestamp,如果没有设置isAutoTimestamp,而且timestamp大于下一个vsync信号的时间戳,说明这个transaction不应该处理,需要等到后面在处理,从而实现在设置surface上屏时间:

TransactionHandler::TransactionReadiness SurfaceFlinger::transactionReadyTimelineCheck(
        const TransactionHandler::TransactionFlushState& flushState) {
    const auto& transaction = *flushState.transaction;
    
    const TimePoint desiredPresentTime = TimePoint::fromNs(transaction.desiredPresentTime);
    const TimePoint expectedPresentTime = mScheduler->expectedPresentTimeForPacesetter();
 
    if (!transaction.isAutoTimestamp && desiredPresentTime >= expectedPresentTime &&
        desiredPresentTime < expectedPresentTime + 1s) {
    }
 }