用 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 实现一个人脸检测(非识别),争取这两天完成。

更多相关文章

  1. Android性能调优工具TraceView介绍
  2. android shape的使用
  3. Android(安卓)开发笔记 —— AndroidStudio 中使用 android-seri
  4. 应用界面主题Theme使用方法
  5. Android调Ajax和动态添加JS中的token(Android(安卓)和JS完全交互
  6. 应用界面主题Theme使用方法
  7. Android:shape的使用详解(1)
  8. 有关Android调用服务全解析
  9. Android的文件系统

随机推荐

  1. android 5.0多用户支持
  2. Android中做一个无标题窗口
  3. Android不依赖Activity的全局悬浮窗实现
  4. 使用eclipse打开android_sdk自带的例子
  5. android之照相、相冊裁剪功能的实现过程
  6. Android(安卓)实现全屏显示的几种方法整
  7. Android(安卓)Theme的设置
  8. android中调试之日志
  9. android sdk setup时出现:Failed to fetc
  10. Android(安卓)XML解析