相信很多人都用过相机功能,也开发过简单调度相机功能,但是相机采集功能。是图像信号输入的重要来源。

SurfaceView和View的不同之处:

相机图像采样,需要维持一个比较稳定的帧数来维持图像实时性,需要频繁刷新,创建一个子线程来进行画面更新,会被占用主线程效率好很多,而且双缓冲机制可以在画面从前台刷新到后台时才占用主线程操作,所以选用SurfaceView作绘制是最好的。 而GLSurfaceView是SurfaceView的一个子类,专用于openGL绘制,其运行效率远高于SurfaceView是因为使用了GPU参与绘制。 这一节介绍Android摄像头采样,还是采用了SurfaceView来做采样 1.需要申请相机权限。

    <uses-permission android:name="android.permission.CAMERA" />
复制代码

2.打开摄像头,先检查摄像和前置摄像头,然后通过摄像头Id,来返回摄像头对象。

 fun openCamera(cameraId:Int):Camera?{if (!haveFeature(PackageManager.FEATURE_CAMERA)){Log.e(TAG,"no camera!")return null}if (cameraId == Camera.CameraInfo.CAMERA_FACING_FRONT && !haveFeature(PackageManager.FEATURE_CAMERA_FRONT)){Log.e(TAG,"no front camera!")return null}val camera = Camera.open(cameraId)if (camera == null){Log.e(TAG, "openCamera failed")return null}return camera}
复制代码

3.设置画面比例

/*** 获取最大的图片大小*/fun getLargePictureSize(camera: Camera?): Camera.Size? {if (camera != null) {//获取可选比例val sizes = camera.parameters.supportedPictureSizesvar temp: Camera.Size = sizes[0]for (i in 1 until sizes.size) {val scale = sizes[i].height.toFloat() / sizes[i].widthif (temp.width < sizes[i].width && scale < 0.6f && scale > 0.5f)temp = sizes[i]}return temp}return null}/*** 获取最大的预览大小*/fun getLargePreviewSize(camera: Camera?): Camera.Size? {if (camera != null) {//获取可选比例val sizes = camera.parameters.supportedPreviewSizesvar temp: Camera.Size = sizes[0]for (i in 1 until sizes.size) {if (temp.width < sizes[i].width)temp = sizes[i]}return temp}return null}/*** 相机采样参数大小*/fun setOptimalSize(camera:Camera,aspectRatio:Float,maxWidth:Int,maxHeight:Int){val parameters= camera.parameters//使用自动对焦if (parameters.supportedFocusModes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {parameters.focusMode = Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE}val size = getLargePreviewSize(camera)size?.let {//设置相机预览大小parameters.setPreviewSize(it.width,it.height)Log.d(TAG, "input max: (" + maxWidth + ", " + maxHeight + "), output size: ("+ it.width + ", " + it.height + ")")}val pictureSize = getLargePictureSize(camera)pictureSize?.let {//图片参数parameters.setPictureSize(it.width,it.height)Log.d(TAG, "picture max: (" + maxWidth + ", " + maxHeight + "), output size: ("+ it.width + ", " + it.height + ")")}camera.parameters = parameters}
复制代码

3.设置相机图像角度

fun setDisplayOritation(activity: Activity, camera: Camera, cameraId: Int) {//获取window的角度val rotation = activity.windowManager.defaultDisplay.rotationvar degress = 0when (rotation) {Surface.ROTATION_0 -> degress = 0Surface.ROTATION_90 -> degress = 90Surface.ROTATION_180 -> degress = 180Surface.ROTATION_270 -> degress = 270}val info = Camera.CameraInfo()Camera.getCameraInfo(cameraId, info)var result: Int//前置摄像头if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {result = (info.orientation + degress) % 360result = (360 - result) % 360  // compensate the mirror} else {//后置摄像头result = (info.orientation - degress + 360) % 360 // back-facing}Log.d(TAG, "window rotation: $degress, camera oritation: $result")camera.setDisplayOrientation(result)}
复制代码

4.设置完摄像头参数后,需要设置一个SurfaceHolder.CallBack。 有三个必须的方法

   //创建时调用override fun surfaceCreated(holder: SurfaceHolder?) { }//当surface发生任何结构性的变化时(格式或者大小),该方法就会被立即调用。override fun surfaceChanged(holder: SurfaceHolder?, format: Int, width: Int, height: Int) { }//被移除时调用override fun surfaceDestroyed(holder: SurfaceHolder?) {}
复制代码

这里创建相机的调用surfaceCreated,之后会立刻调用一次surfaceChanged 这里在surfaceChanged上调用openGL的init操作

 fun initOpenGL(surface: Surface, width: Int, height: Int){//新开一个之后一个线程的线程池mExecutor.execute {//获取纹理idval textureId = OpenGLJniLib.magicBaseInit(surface,width,height,BaseApplication.context.assets)if (textureId < 0){Log.e(TAG, "surfaceCreated init OpenGL ES failed!")return@execute}//需要使用surfaceTexture来做纹理装载mSurfaceTexture = SurfaceTexture(textureId)//添加纹理变化回调mSurfaceTexture?.setOnFrameAvailableListener { drawOpenGL() }try {//把摄像头采样关联到纹理mCamera?.setPreviewTexture(mSurfaceTexture)//开始摄像头采样doStartPreview()}catch (e:IOException){Log.e(TAG,e.localizedMessage)releaseOpenGL()}}}
复制代码

5.开始预览,并开始自动对焦。

    fun doStartPreview(){mCamera?.startPreview()cameraFocus(width/2.0f,height/2.0f)}
复制代码

6.opengl绘制,先要强制更新纹理图像,再更新获取纹理矩阵,然后让opengl绘制

    fun drawOpenGL(){mExecutor.execute {mSurfaceTexture?.updateTexImage()mSurfaceTexture?.getTransformMatrix(mMatrix)OpenGLJniLib.magicBaseDraw(mMatrix)}}
复制代码

7.在destroySurfaceView的是否释放资源

    fun releaseOpenGL(){mExecutor.execute {mSurfaceTexture?.release()mSurfaceTexture=nullOpenGLJniLib.magicBaseRelease()}}
复制代码

介绍了Camera采样配置和,surfaceTexture纹理获取了和加载,下一节,将会介绍native层的opengl绘制代码。

近来在写一个有趣的项目,大家熟知摄像头绘制和opengl的人应该有看过MagicCamera这个Android opengl2.0的开源工程,但是已经很多年没人维护了,这边正在将其重构为opengl3.0的的版本。命名为MagicCamera3以供大家学习,现在还在重构当中,致敬作者,也希望可以有机会和作者多交流,如果有认识的可以告知我一声,谢谢。 开源地址:MagicCamera3,这节的用例在CameraActivity中

[OpenGL]未来视觉1-Android摄像头采集基础相关推荐

  1. [OpenGL]未来视觉5-滤镜

    1.灵魂出窍 效果说明,上一帧的透明度不断减少,叠加在现在这帧的上面,并有放大扩散效果. soulout.gif void MagicSoulOutFilter::onDrawArraysPre() ...

  2. android系统相机实时数据采集流程,Android 摄像头采集与数据处理

    android Camera2使用 前言:由于有关camera2使用和对数据处理的比较少所以笔者也有着乐于助人心所以有了后面的内容.咋们废话不多说先把流程和目的说下.首先是获取到相关摄像头id.然后打 ...

  3. Android 手机采集摄像头视频 socket 视频传输实时传播

    这里搜集了两种实现Android 手机采集摄像头视频 socket 视频传输实时传播的方法,两种都可以使用. 第一种如下: 1.通过客户端socket请求,服务端接受到请求后,获取socket的输出流 ...

  4. android视频采集

    视频画面的采集主要是使用各个平台提供的摄像头API来实现的, 在为摄像头设置了合适的参数之后,将摄像头实时采集的视频帧渲染到 屏幕上提供给用户预览,然后将该视频帧编码到一个视频文件中,其使 用的编码格 ...

  5. Android视频开发基础

    Android视频开发基础 版权声明:本文为[viclee]原创,如需转载请注明出处~ https://blog.csdn.net/goodlixueyong/article/details/6205 ...

  6. 音视频开发(19)---Android视频开发基础(一)

    Android视频开发基础(一) 版权声明:本文为[viclee]原创,如需转载请注明出处~ https://blog.csdn.net/goodlixueyong/article/details/6 ...

  7. Android视频开发基础(二)

    Android视频开发基础(二) https://blog.csdn.net/goodlixueyong/article/details/62447452 前一篇文章详细介绍了视频的一些基本概念,这些 ...

  8. android摄像头方向与屏方向,Android开发中关于摄像头方向的理解

    安卓开发中经常有需要使用摄像头的应用场景,对于初次接触的同学摄像头的方向是一个比较难弄清楚的概念,开发时很容易处理不当,本文将详述该部分内容帮助理解. 一.摄像头捕获的图像 先看一个简单的场景,打开手 ...

  9. android opengl录制水印视频,Android 仿抖音之使用OpenGL实现抖音视频录制

    前言 在之前写了仿抖音的第一步,就是使用OpenGL显示摄像头数据,今天这篇就是在之前的基础上来录制视频,并且对之前的代码的结构进行了简单的整理,然后进行了仿抖音的视频录制. 工程结构整理 在仿抖音的 ...

最新文章

  1. 几何画板论坛_伯中班主任论坛丨用爱守护生命的成长
  2. How to setup SLF4J and LOGBack in a web app - fast--转载
  3. java 隐藏了什么_JAVA程序中封装与隐藏是什么意思
  4. 外链引入css有哪些方式_外链怎么发才会快速收录?
  5. MTK 驱动(49)---TP测试规范
  6. 千万别惹程序员之经典的SQL注入式***
  7. jQuery1.9.1源码分析--Deferred对象和Promise对象
  8. bzoj4567: [Scoi2016]背单词
  9. 线性内插和双线性内插
  10. 新的开始——参加培训
  11. 开启和关闭Windows远程管理(WinRM)
  12. 如何在WordPress菜单中显示图标[WordPress插件]
  13. 自然语言处理从零到入门 BERT
  14. python项目案例开发pdf-python项目开发案例锦集 pdf|消费金融公司概念股
  15. 用牛顿迭代法求方程。
  16. android沉浸状态栏和顶部状态栏背景色的设置
  17. 关于服务器的使用——深度学习菜鸡入门(1)
  18. TEXT must be immediately followed by END_TAG and not START_TAG (position: START_TAG seen ...<depende
  19. Python学习手册--第六部分(类)
  20. TD-问题解答(四)

热门文章

  1. WiFi CC3200模块 加速IOT物联网发展
  2. vi vim 插入 删除 修改 文本
  3. 三维地形可视化开源项目TerraVision
  4. mysql常用命令行操作(二):表和库的操作、引擎、聚合函数
  5. Vue中data和computed的区别
  6. 容器数据卷网络基本配置
  7. 洛谷P2327 [SCOI2005] 扫雷
  8. MongoDB的学习--聚合
  9. 深入理解Linux内核-内存寻址
  10. C# 实现基于ffmpeg加虹软的人脸识别