300字范文,内容丰富有趣,生活中的好帮手!
300字范文 > Android Camera API 2使用OpenGL ES 2.0和GLSurfaceView对预览进行实时二次处理(黑白滤镜)

Android Camera API 2使用OpenGL ES 2.0和GLSurfaceView对预览进行实时二次处理(黑白滤镜)

时间:2020-12-12 06:01:27

相关推荐

Android Camera API 2使用OpenGL ES 2.0和GLSurfaceView对预览进行实时二次处理(黑白滤镜)

这段时间有点忙,一直没时间写第三篇教程,其实代码很早之前就写好了。本系列教程会有三篇文章讲解Android平台滤镜的实现方式,希望在阅读本文之前先阅读前面两篇文档。

第一篇 Android Camera使用OpenGL ES 2.0和GLSurfaceView对预览进行实时二次处理(黑白滤镜)第二篇 Android Camera使用OpenGL ES 2.0和TextureView对预览进行实时二次处理(黑白滤镜)第三篇 Android Camera API 2使用OpenGL ES 2.0和GLSurfaceView对预览进行实时二次处理(黑白滤镜)

下面进入正题:第三篇

本文使用GLSurfaceView作为布局界面,并且仍将使用SurfaceTexture来获取预览图像,但是Camera V2的API跟Camera V1的差别还挺大的,所以需要熟悉一下,可以参考我之前的博客Android Camera2教程之打开相机、开启预览、实现PreviewCallback、拍照。这里我也再讲一下,下面开始讲解。

1, 使用Camera API 2开启相机

在onCreate方法中创建并启动Camera子线程,后面Camera开启、预览、拍照都放在这个子线程中。

public void startCameraThread() {mCameraThread = new HandlerThread("CameraThread");mCameraThread.start();mCameraHandler = new Handler(mCameraThread.getLooper());}

设置相机参数

public String setupCamera(int width, int height) {//获取摄像头管理者,它主要用来查询和打开可用的摄像头CameraManager cameraManager = (CameraManager) mActivity.getSystemService(Context.CAMERA_SERVICE);try {//遍历所有摄像头for (String id : cameraManager.getCameraIdList()) {//获取此ID对应摄像头的参数CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(id);//默认打开后置摄像头if (characteristics.get(CameraCharacteristics.LENS_FACING) == CameraCharacteristics.LENS_FACING_FRONT) {continue;}//获取StreamConfigurationMap,它是管理摄像头支持的所有输出格式和尺寸StreamConfigurationMap map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);//根据屏幕尺寸(通过参数传进来)匹配最合适的预览尺寸mPreviewSize = getOptimalSize(map.getOutputSizes(SurfaceTexture.class), width, height);mCameraId = id;}} catch (CameraAccessException e) {e.printStackTrace();}return mCameraId;}

开启相机

public boolean openCamera() {CameraManager cameraManager = (CameraManager) mActivity.getSystemService(Context.CAMERA_SERVICE);try {//开启相机,第一个参数指示打开哪个摄像头,第二个参数mStateCallback为相机的状态回调接口,第三个参数用来确定Callback在哪个线程执行,为null的话就在当前线程执行cameraManager.openCamera(mCameraId, mStateCallback, mCameraHandler);} catch (CameraAccessException e) {e.printStackTrace();return false;}return true;}//当相机成功打开后会回调onOpened方法,这里可以拿到CameraDevice对象,也就是具体的摄像头设备public CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() {@Overridepublic void onOpened(@NonNull CameraDevice camera) {mCameraDevice = camera;}}

2,添加GLSurfaceView作为布局界面、创建SurfaceTexture

现在Camera2已结打开了,下面开始初始化GLSurfaceView,伪代码如下,这个不细讲了,可以参考我之前的博客 Android初始化OpenGL ES,并且分析Renderer子线程原理

//实例化一个GLSurfaceViewmGLSurfaceView = new GLSurfaceView(this);//配置OpenGL ES,主要是版本设置和设置Renderer,Renderer用于执行OpenGL的绘制mGLSurfaceView.setEGLContextClientVersion(2);mGLSurfaceView.setRenderer(new GLSurfaceView.Renderer());//在屏幕上显示GLSurfaceView

我们在Renderer的onSurfaceCreated方法中创建一个OES纹理

public static int createOESTextureObject() {int[] tex = new int[1];GLES20.glGenTextures(1, tex, 0);GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, tex[0]);GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES,GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST);GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES,GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES,GL10.GL_TEXTURE_WRAP_S, GL10.GL_CLAMP_TO_EDGE);GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES,GL10.GL_TEXTURE_WRAP_T, GL10.GL_CLAMP_TO_EDGE);GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, 0);return tex[0];}

之后根据OES纹理Id创建SurfaceTexture,用来接收Camera2的预览数据。

public boolean initSurfaceTexture() {//根据OES纹理ID实例化SurfaceTexturemSurfaceTexture = new SurfaceTexture(mOESTextureId);//当SurfaceTexture接收到一帧数据时,请求OpenGL ES进行渲染mSurfaceTexture.setOnFrameAvailableListener(new SurfaceTexture.OnFrameAvailableListener() {@Overridepublic void onFrameAvailable(SurfaceTexture surfaceTexture) {mCameraV2GLSurfaceView.requestRender();}});return true;}

最后初始化OpenGL ES环境,主要有shader编写和编译,链接到program。这一套流程在第一篇文章中Android Camera使用OpenGL ES 2.0和GLSurfaceView对预览进行实时处理(黑白滤镜)讲过了,这里就不讲了。

3, 使用Camera2 API开启预览

public void startPreview() {//设置SurfaceTexture的默认尺寸mSurfaceTexture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());//根据mSurfaceTexture创建SurfaceSurface surface = new Surface(mSurfaceTexture);try {//创建preview捕获请求mCaptureRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);//将此请求输出目标设为我们创建的Surface对象,这个Surface对象也必须添加给createCaptureSession才行mCaptureRequestBuilder.addTarget(surface);//创建捕获会话,第一个参数是捕获数据的输出Surface列表,第二个参数是CameraCaptureSession的状态回调接口,当它创建好后会回调onConfigured方法,第三个参数用来确定Callback在哪个线程执行,为null的话就在当前线程执行mCameraDevice.createCaptureSession(Arrays.asList(surface), new CameraCaptureSession.StateCallback() {@Overridepublic void onConfigured(@NonNull CameraCaptureSession session) {try {//创建捕获请求mCaptureRequest = mCaptureRequestBuilder.build();mCameraCaptureSession = session;//设置重复捕获数据的请求,之后surface绑定的SurfaceTexture中就会一直有数据到达,然后就会回调SurfaceTexture.OnFrameAvailableListener接口mCameraCaptureSession.setRepeatingRequest(mCaptureRequest, null, mCameraHandler);} catch (CameraAccessException e) {e.printStackTrace();}}@Overridepublic void onConfigureFailed(@NonNull CameraCaptureSession session) {}}, mCameraHandler);} catch (CameraAccessException e) {e.printStackTrace();}}

4,绘制预览数据到屏幕上

在Renderer的onDrawFrame方法中,首先更新纹理数据

if (mSurfaceTexture != null) {//更新数据,其实也是消耗数据,将上一帧的数据处理或者抛弃掉,要不然SurfaceTexture是接收不到最新数据mSurfaceTexture.updateTexImage();mSurfaceTexture.getTransformMatrix(transformMatrix);}

然后OpenGL ES将此OES纹理数据绘制到屏幕上,这根前两篇讲的一样,就不复述了。

至此运行此程序Camera预览就会显示为黑白滤镜,如下图所示。

总结一下:首先使用Camera2 API开启相机,然后添加GLSurfaceView作为布局界面,之后创建一个外部纹理,根据此纹理ID创建一个SurfaceTexture。开启预览,Camera2将预览数据输出至此SurfaceTexture上。有数据到达时,会回调SurfaceTexture的OnFrameAvailableListener接口,在此接口中requestRender,通过OpenGL ES将此OES纹理绘制到屏幕上。

代码地址(顺手给个Star啊):点击查看源码

作者:lb377463323

出处:/lb377463323

原文链接:/lb377463323/article/details/78054892

转载请注明出处!

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