用 Golang 开发 Android(安卓)应用(六)—— Camera 使用
用 Golang 开发 Android 应用 -- Camera 使用
- 计划按以下的内容更新
- Android 中的 Camera
- Demo 代码说明
- Camera2
计划按以下的内容更新
- 基本环境配置
- 简单 UI
- Storage 使用
- Sensor 使用
- Audio(openAL) 使用
- Camera 使用
- OpenCV 使用
Android 中的 Camera
在 Android 中,最初的 Camera 连前置摄像头(以下简称前摄,后摄同理)都没支持,而是各厂商自行实现的,曾逆向过一个 Camera 应用,里面有太多的反射调用,并不是它们写得不好,而是现实中太多实现方式了,各种不同的类。总之要靠一些复杂、怪异的判断来决定当前要用什么方式来调用前摄。
后来虽然官方加入了前摄的支持,但NDK都没有提供 Camera 的方式,要在 NDK 中使用用摄像头就需要通过参考 Android 的源码,找到调用方法。
直到 Android 7.0 上 Camera 2 的出现,NDK 才开始有官方接口提供,这个我们可以从 NDK 的 include\camera 头文件看到。
这一篇还是基于 Camera 2 之前的版本,也如上面说的原因,在 Android 4.4 的仿真上这个 Camera Demo 是能正常运行的。
理论上它能在的如下几个 Android 版本上跑(仅限 armeabi ):
libnative_camera_r6.0.0.so
libnative_camera_r5.1.0.so
libnative_camera_r4.4.0.so
libnative_camera_r4.3.0.so
Demo 代码说明
为了便于理解,先说一下 Camera 的帧数据的格式,目前我碰到的都是 yuv420sp 格式,所以这个 Demo 只处理了这一种格式的数据。 代码中 YuvRender 就是用来处理这种格式的,它是一个 Render 对象。
type Render interface {// Init render, userdata is ignoreInit()Draw(pixels interface{})Release()// SetProperty// wW, wH is windows/client width, height// iW, iH is image width, height// x, y, w, h is draw image to rect// op is ROTATION?? | FLIPHOR | FLIPVERSetProperty(wW, wH int, iW, iH int, x, y, w, h int, op int)// 验证 pixels 是否符合指定 width、heightValidate(width, height int, pixels interface{}) bool}
主要是用来绘制和检查数据是否有效。
如果出现其它格式的数据,同样实现一个 Render 。
并在这里加上对它的支持:
switch cam.imgFormat {case "yuv420sp":cam.irender = &render.YuvRender{}case "????": // 新加的格式cam.irender = ???? default:log.Println("not support format:", cam.imgFormat)return}
如果 Demo 不能正常跑,一方面看 cameraInit 是否成功, 另外就是看一下数据格式。
func cameraInit(id int, usercb func(w, h int, img []byte) bool) *cameraObj {cam := &cameraObj{}cb := func(buffer []byte) bool {// init doneif atomic.CompareAndSwapInt32(&cam.camStat, NONE, READY) {return true}wh := cam.previewSizes[cam.previewIndex]if cam.camStat == RESIZING && cam.irender.Validate(wh[0], wh[1], buffer) {cam.ResetProperty()atomic.CompareAndSwapInt32(&cam.camStat, RESIZING, READY)}...runtime.Gosched()return true}cam.Camera = camera.Connect(id, cb)if cam.Camera == 0 {log.Println("Cammera connect fail")return nil}...// 第一个为默认分辨率// 因 camera 还未初始化完,需就异步执行go func() {runtime.LockOSThread()for cam.camStat == NONE {time.Sleep(time.Millisecond * 100)}cam.setPreviewSize(0)}()return cam}
cam.Camera = camera.Connect(id, cb)
这就是“打开”摄像头的函数,它的参数有一个回调,用于传回帧数据的。这个回调之所以做了一些判断逻辑,主要是因为象改分辨率这种操作,和回调传回的数据之间是异步的,也就是说调用修改分辨率之后,可能还会有一两帧数据是之前分辨率的数据,所以要用cam.irender.Validate(...)
确认一下,这个数据是否符合新分辨率要求的数据。只有符合最新分辨率的的数据第一次收到时才去修改 render 的 property ,否则会花屏或崩溃。还有就是传入的 buffer 可能是和之前是同一个内存块,这意味着这个 buffer 的数据可能会被新的帧数据填充,因此我们不能直接拿着 buffer 来用,如果需要处理数据要做一次 copy 到自己分配的内存里,考虑到这个数据 buffer 较大,最好也只做一次 copy ,否则执行效率是个大问题。
另外之所以调用runtime.Gosched()
是为了主动进行一次 goroutine 调度,以避免回调占用太多CPU导致其它 goroutine 没有机会运行(虽然对现在的多核手机来说似乎没意义了)。
...cam.SetFlashMode(camera.FLASH_MODE_TORCH)...cam.SetFlashMode(camera.FLASH_MODE_OFF)...cam.ApplyProperties()
这是开关闪光灯的地方 FLASH_MODE_TORCH
这个模式是开灯,闪光灯常亮。记得加个定时器自动关了,烧了闪光灯本人不负任何责任。调用cam.ApplyProperties()
之后,所做的各种 property 修改才真正有效。正确用法是依次设置不同的 property ,最后调用 cam.ApplyProperties()
使所做设置有效。
Camera2
关于 Camera 就写这些了,毕竟它已被 Android 给淘汰了。Camera2 估计要一段时间才能写个 Demo 出来,暂时没计划。该收收心积极点找工作了。
当然这个计划还有一篇关于 OpenCV 的,将用它结合Camera 实现一个人脸检测(非识别),争取这两天完成。
更多相关文章
- Android性能调优工具TraceView介绍
- android shape的使用
- Android(安卓)开发笔记 —— AndroidStudio 中使用 android-seri
- 应用界面主题Theme使用方法
- Android调Ajax和动态添加JS中的token(Android(安卓)和JS完全交互
- 应用界面主题Theme使用方法
- Android:shape的使用详解(1)
- 有关Android调用服务全解析
- Android的文件系统