懒人模式:发现问题,澄清问题,解决问题
问题:程序使用TextureView显示camera的图像。camera的捕获帧率为60帧每秒(60fps),但是UI实际显示帧率只有大概30fps,而且视频有抖动(video jitters)。如果把TextureView换成如下代码生成的Surface对象,则帧率看起来正常。
sp<ISurfaceComposer> composer = ComposerService::getComposerService();
sp<ISurfaceComposerClient> session = composer->createScopedConnection();
sp<IBinder> dtoken(SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
DisplayInfo dinfo;
SurfaceComposerClient::getDisplayInfo(dtoken, &dinfo);
// create the native surface
sp<SurfaceControl> control = session()->createSurface(String8("cameraSurface"), dinfo.w, dinfo.h, HAL_PIXEL_FORMAT_YCBCR_420_888);
SurfaceComposerClient::openGlobalTransaction();
control->setLayer(0x40000000);
SurfaceComposerClient::closeGlobalTransaction();
sp<Surface> s = control->getSurface();
实际上,上面的代码Copy自BootAnimation.cpp,使用SourceInsight用关键字CreateSurface搜索出来的。通过穷搜代码,发现TextureView的背后也是BufferQueue, Surface是BufferQueueProducer的一个Wrapper。那么,问题来了:
a. TextureView是如何和BufferQueue绑定的?
b. TextureView是如何刷新它的View的?
下面通过代码一步一步跟踪并回答上面两个问题。
1. TextureView和SurfaceTexture关联,并且设置onFrameAvailableListener
public void setSurfaceTexture(SurfaceTexture surfaceTexture) {
...............
mSurface = surfaceTexture;
........................
/*
* If the view is visible and we already made a layer, update the
* listener in the new surface to use the existing listener in the view.
* Otherwise this will be called when the view becomes visible or the
* layer is created
*/
if (((mViewFlags & VISIBILITY_MASK) == VISIBLE) && mLayer != null) {
mSurface.setOnFrameAvailableListener(mUpdateListener, mAttachInfo.mHandler);
}
.................................
}
2. mUpdateListener是TextureView的一个变量,一旦收到onFrameAvailable调用,则调用updateLayer() 和invalidate()。写UI代码的人或许不熟悉updateLayer,但是invalidate一定很熟悉,就是通知UI主线程去用opengl合成不同的窗口区域啊。
private final SurfaceTexture.OnFrameAvailableListener mUpdateListener =
new SurfaceTexture.OnFrameAvailableListener() {
@Override
public void onFrameAvailable(SurfaceTexture surfaceTexture) {
updateLayer();