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", ×tampNs)) {
// use media timestamp if client did not request a specific render timestamp
if (buffer->meta()->findInt64("timeUs", ×tampNs)) {
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最终流向下面几个地方:
并且衍生了另外一个变量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) {
}
}