700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > SurfaceView TextureView SurfaceTexture相关

SurfaceView TextureView SurfaceTexture相关

时间:2019-09-12 16:49:00

相关推荐

SurfaceView TextureView SurfaceTexture相关

首先我们知道View类如果需要更新视图,必须我们主动的去调用invalidate()或者postInvalidate()方法来再走一次onDraw()完成更新。但是呢,Android系统规定屏幕的刷新间隔为16ms,如果这个View在16ms内更新完毕了,就不会卡顿,但是如果逻辑操作太多,16ms内没有更新完毕,剩下的操作就会丢到下一个16ms里去完成,这样就会造成UI线程的阻塞,造成View的运动过程掉帧,自然就会卡顿了。

所以这些原因也就促使了SurfaceView的存在。比如一个Camera,它有可能相当频繁的有更新画面的需求。

(1)简单介绍

(A)SurfaceView

它继承自View,因此它本质上是一个View。但与普通View不同的是,它有自己的Surface。

一般的Activity包含的多个View会组成View hierachy的树形结构,只有最顶层的DecorView,也就是根结点视图,才是对WMS可见的。这个DecorView在WMS中有一个对应的WindowState。相应地,在SF中有对应的Layer。

这样的好处是对这个Surface的渲染可以放到单独线程去做,它不会影响主线程对事件的响应。但它也有缺点,因为这个Surface不在View hierachy中,它的显示也不受View的属性控制,所以不能进行平移,缩放等变换,也不能放在其它ViewGroup中,一些View中的特性也无法使用。

SurfaceView中采用了双缓冲机制,保证了UI界面的流畅性,同时 SurfaceView 不在主线程中绘制,而是另开辟一个线程去绘制,所以它不妨碍UI线程;View底层没有双缓冲机制,SurfaceView有;view主要适用于主动更新,而SurfaceView适用与被动的更新,如频繁的刷新;view会在主线程中去更新UI,而SurfaceView则在子线程中刷新;SurfaceView的内容不在应用窗口上,所以不能使用变换(平移、缩放、旋转等)。也难以放在ListView或者ScrollView中,不能使用UI控件的一些特性比如View.setAlpha();

(B)TextureView

与SurfaceView相比,TextureView并没有创建一个单独的Surface用来绘制,因此可以和其它普通View一样进行移动,旋转,缩放,动画等变化。另外,Textureview必须在硬件加速开启的窗口中;

从类图中可以看到,TextureView继承自View,它与其它的View一样在View hierachy中管理与绘制。TextureView重载了draw()方法,其中主要SurfaceTexture中收到的图像数据作为纹理更新到对应的HardwareLayer中。

SurfaceTexture.OnFrameAvailableListener用于通知TextureView内容流有新图像到来。TextureView.SurfaceTextureListener接口用于让TextureView的使用者知道SurfaceTexture已准备好,这样就可以把SurfaceTexture交给相应的内容源。

支持移动、旋转、缩放等动画,支持截图;必须在硬件加速的窗口中使用,占用内存比SurfaceView高,在5.0以前在主线程渲染,5.0以后有单独的渲染线程;

(C)SurfaceTexture

SurfaceTexture用来捕获视频流(stream)中的图像帧(image frame)的,视频流可以是相机预览或者视频解码数据。SurfaceTexture可以作为android.hardware.camera2、MediaCodec、MediaPlayer、和 VideoDecode这些类的目标视频数据输出对象。

SurfaceTexture和SurfaceView不同的是,它对图像流的处理并不直接显示,而是转为OpenGL的外部纹理,因此可用于图像流数据的二次处理(如Camera滤镜,桌面特效等)。比如Camera的预览数据,可以通过SurfaceTexture交给TextureView作为View heirachy中的一个硬件加速层来显示。首先,SurfaceTexture从图像流(来自Camera预览,视频解码,GL绘制场景等)中获得帧数据,当SurfaceTexture中有数据帧更新时,SurfaceTexture.OnFrameAvailableListener这个监听接口将会有回调,此时可以调用updateTexImage()方法从视频流数据中更新当前数据帧。并通过SurfaceTexture所绑定的OpenGL纹理对象来对其进行一些图像处理操作。

(2)API相关

(A)Surface

//android.view.SurfaceROTATION_0ROTATION_90ROTATION_180ROTATION_270Surface(SurfaceTexture surfaceTexture)CanvaslockCanvas(Rect inOutDirty)CanvaslockHardwareCanvas()voidunlockCanvasAndPost(Canvas canvas)

(B)SurfaceView

//android.view.View// ↳android.view.SurfaceViewvoiddraw(Canvas canvas)SurfaceHoldergetHolder()voidsetZOrderMediaOverlay(boolean isMediaOverlay)voidsetZOrderOnTop(boolean onTop)onMeasure(int widthMeasureSpec, int heightMeasureSpec)

(C)SurfaceHolder

//android.view.SurfaceHolderSurfaceHolder.Callbackabstract voidsurfaceChanged(SurfaceHolder holder, int format, int width, int height)abstract voidsurfaceCreated(SurfaceHolder holder)abstract voidsurfaceDestroyed(SurfaceHolder holder)abstract voidaddCallback(SurfaceHolder.Callback callback)abstract SurfacegetSurface()abstract CanvaslockCanvas()default CanvaslockHardwareCanvas()abstract voidremoveCallback(SurfaceHolder.Callback callback)abstract voidsetFixedSize(int width, int height)abstract voidsetFormat(int format)abstract voidsetKeepScreenOn(boolean screenOn)abstract voidsetSizeFromLayout()abstract voidunlockCanvasAndPost(Canvas canvas)

(D)TextureView

//android.view.View// ↳android.view.TextureViewTextureView.SurfaceTextureListenerabstract voidonSurfaceTextureAvailable(SurfaceTexture surface, int width, int height)abstract booleanonSurfaceTextureDestroyed(SurfaceTexture surface)abstract voidonSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height)abstract voidonSurfaceTextureUpdated(SurfaceTexture surface)final voiddraw(Canvas canvas)BitmapgetBitmap(int width, int height)BitmapgetBitmap()BitmapgetBitmap(Bitmap bitmap)SurfaceTexturegetSurfaceTexture()voidsetSurfaceTexture(SurfaceTexture surfaceTexture)TextureView.SurfaceTextureListenergetSurfaceTextureListener()voidsetSurfaceTextureListener(TextureView.SurfaceTextureListener listener)MatrixgetTransform(Matrix transform)voidsetTransform(Matrix transform)CanvaslockCanvas()voidunlockCanvasAndPost(Canvas canvas)final voidonDraw(Canvas canvas)voidonSizeChanged(int w, int h, int oldw, int oldh)voidonVisibilityChanged(View changedView, int visibility)

(E)SurfaceTexture

//android.graphics.SurfaceTextureSurfaceTexture.OnFrameAvailableListenerabstract voidonFrameAvailable(SurfaceTexture surfaceTexture)longgetTimestamp()voidgetTransformMatrix(float[] mtx)voidsetDefaultBufferSize(int width, int height)voidsetOnFrameAvailableListener(SurfaceTexture.OnFrameAvailableListener listener)voidupdateTexImage()voidreleaseTexImage()

(3)Demo

(A)自定义PreviewSurfaceView

import android.content.Context;import android.content.res.Configuration;import android.graphics.Point;import android.util.AttributeSet;import android.view.Display;import android.view.SurfaceView;import android.view.WindowManager;public class PreviewSurfaceView extends SurfaceView {private static final double ASPECT_TOLERANCE = 0.03;private double mAspectRatio = 0.0;private int mPreviewWidth = 0;private int mPreviewHeight = 0;public PreviewSurfaceView(Context context, AttributeSet attrs) {super(context, attrs);}public void setAspectRatio(double aspectRatio) {if (mAspectRatio != aspectRatio) {mAspectRatio = aspectRatio;requestLayout();}}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {int previewWidth = MeasureSpec.getSize(widthMeasureSpec);int previewHeight = MeasureSpec.getSize(heightMeasureSpec);boolean widthLonger = previewWidth > previewHeight;int longSide = (widthLonger ? previewWidth : previewHeight);int shortSide = (widthLonger ? previewHeight : previewWidth);if (mAspectRatio > 0) {double fullScreenRatio = findFullscreenRatio(getContext());if (Math.abs((mAspectRatio - fullScreenRatio)) <= ASPECT_TOLERANCE) {// full screen preview caseif (longSide < shortSide * mAspectRatio) {longSide = Math.round((float) (shortSide * mAspectRatio) / 2) * 2;} else {shortSide = Math.round((float) (longSide / mAspectRatio) / 2) * 2;}} else {// standard (4:3) preview caseif (longSide > shortSide * mAspectRatio) {longSide = Math.round((float) (shortSide * mAspectRatio) / 2) * 2;} else {shortSide = Math.round((float) (longSide / mAspectRatio) / 2) * 2;}}}if (widthLonger) {previewWidth = longSide;previewHeight = shortSide;} else {previewWidth = shortSide;previewHeight = longSide;}boolean originalPreviewIsLandscape = (mPreviewWidth > mPreviewHeight);boolean configurationIsLandscape =(getContext().getResources().getConfiguration().orientation ==Configuration.ORIENTATION_LANDSCAPE);// if configuration is changed, swap to view's configuration// if (originalPreviewIsLandscape != configurationIsLandscape) {// int originalPreviewWidth = previewWidth;// previewWidth = previewHeight;// previewHeight = originalPreviewWidth;// }setMeasuredDimension(previewWidth, previewHeight);}protected boolean isFullScreenPreview(double aspectRatio) {double fullScreenRatio = findFullscreenRatio(getContext());if (Math.abs((aspectRatio - fullScreenRatio)) <= ASPECT_TOLERANCE) {return true;} else {return false;}}private static double findFullscreenRatio(Context context) {WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);Display display = wm.getDefaultDisplay();Point point = new Point();display.getRealSize(point);double fullscreen;if (point.x > point.y) {fullscreen = (double) point.x / point.y;} else {fullscreen = (double) point.y / point.x;}return fullscreen;}}

(B)自定义PreviewTextureView

import android.content.Context;import android.graphics.Point;import android.util.AttributeSet;import android.view.Display;import android.view.TextureView;import android.view.WindowManager;public class PreviewTextureView extends TextureView {private static final double ASPECT_TOLERANCE = 0.03;private double mAspectRatio = 0.0;public PreviewTextureView(Context context) {this(context, null);}public PreviewTextureView(Context context, AttributeSet attrs) {this(context, attrs, 0);}public PreviewTextureView(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);}public void setAspectRatio(double aspectRatio) {if (mAspectRatio != aspectRatio) {mAspectRatio = aspectRatio;requestLayout();}}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {int previewWidth = MeasureSpec.getSize(widthMeasureSpec);int previewHeight = MeasureSpec.getSize(heightMeasureSpec);boolean widthLonger = previewWidth > previewHeight;int longSide = (widthLonger ? previewWidth : previewHeight);int shortSide = (widthLonger ? previewHeight : previewWidth);if (mAspectRatio > 0) {double fullScreenRatio = findFullscreenRatio(getContext());if (Math.abs((mAspectRatio - fullScreenRatio)) <= ASPECT_TOLERANCE) {// full screen preview caseif (longSide < shortSide * mAspectRatio) {longSide = Math.round((float) (shortSide * mAspectRatio) / 2) * 2;} else {shortSide = Math.round((float) (longSide / mAspectRatio) / 2) * 2;}} else {// standard (4:3) preview caseif (longSide > shortSide * mAspectRatio) {longSide = Math.round((float) (shortSide * mAspectRatio) / 2) * 2;} else {shortSide = Math.round((float) (longSide / mAspectRatio) / 2) * 2;}}}if (widthLonger) {previewWidth = longSide;previewHeight = shortSide;} else {previewWidth = shortSide;previewHeight = longSide;}setMeasuredDimension(previewWidth, previewHeight);}private static double findFullscreenRatio(Context context) {WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);Display display = wm.getDefaultDisplay();Point point = new Point();display.getRealSize(point);double fullscreen;if (point.x > point.y) {fullscreen = (double) point.x / point.y;} else {fullscreen = (double) point.y / point.x;}return fullscreen;}}

(C)SurfaceView Demo

<RelativeLayout xmlns:android="/apk/res/android"xmlns:tools="/tools"android:layout_width="match_parent"android:layout_height="match_parent" ><SurfaceViewandroid:id="@+id/surfaceView"android:layout_width="match_parent"android:layout_height="match_parent"/></RelativeLayout>

private void getScreenParams() {DisplayMetrics dm = new DisplayMetrics();// 获取屏幕信息getWindowManager().getDefaultDisplay().getMetrics(dm);screenWidth = dm.widthPixels;screenHeight = dm.heightPixels;}protected void initView() {surfaceHolder = surfaceview.getHolder();surfaceHolder.setKeepScreenOn(true);surfaceHolder.addCallback(new SurfaceViewCallback());// 调整surfaceView的大小ViewGroup.LayoutParams params = surfaceview.getLayoutParams();params.width = screenWidth;params.height = screenHeight;surfaceview.setLayoutParams(params);}private class SurfaceViewCallback implements SurfaceHolder.Callback {@Overridepublic void surfaceChanged(SurfaceHolder holder, int format, int width,int height) {mCamera.setPreviewDisplay(holder);mCamera.startPreview();}@Overridepublic void surfaceCreated(SurfaceHolder holder) {}@Overridepublic void surfaceDestroyed(SurfaceHolder holder) {}}

(D)TextureView Demo

public class LiveCameraActivity extends Activity implements TextureView.SurfaceTextureListener {private Camera mCamera;private TextureView mTextureView;protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);mTextureView = new TextureView(this);mTextureView.setSurfaceTextureListener(this);setContentView(mTextureView);}public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {mCamera = Camera.open();try {mCamera.setPreviewTexture(surface);mCamera.startPreview();} catch (IOException ioe) {// Something bad happened}}public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {}public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {mCamera.stopPreview();mCamera.release();return true;}public void onSurfaceTextureUpdated(SurfaceTexture surface) {}}

(4)总结

SurfaceView是一个有自己独立Surface的View, 它的渲染可以放在单独线程而不是主线程中, 其缺点是不能做变形和动画;SurfaceTexture可以用作非直接输出的内容流,这样就提供二次处理的机会。与SurfaceView直接输出相比,这样会有若干帧的延迟;TextureView是一个可以把内容流作为外部纹理输出在上面的View, 它本身需要是一个硬件加速层;

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。