Android平台之不预览获取照相机预览数据帧及精确时间截
在android平台上要获取预览数据帧是一件极其容易的事儿,但要获取每帧数据对应的时间截并不那么容易,网络上关于这方面的资料也比较少。之所以要获取时间截,是因为某些情况下需要加入精确时间轴才能解决问题,如果自己给获取到的时间截打上时间截,则必定引入很多误差,文档主要以理论为主,我想作为一名合格的程序员,有了一个想法,则一定会有办法去编码实现的。
因为项目需要,查找了大量的资料,发现网络上关于获取预览数据的资料都是通过实现PreviewCallback接口来获取。这种方法能获取到照相机的预览数据,但是系统不提供时间截服务,自己打上时间截,可能会导致预览数据帧发生时间截偏移。具体分析来说,如果你实现了PreviewCallback接口,调用setPreviewDisplay使用一个SurfaceHolder来显示预览数据,并且在onPreviewFrame回调函数中获取到了帧数据,但是你不能获取该帧产生时的时间截。你需要为他手工编码打上时间截,或许你就是以程序运行到那行代码时刻的时间截,但在帧生成到调用回调onPreviewFrame,再到运行该行代码,已经消耗了一些时间,如果你的预览频率设置不当的话,会使得消耗是时间是你设定的预览帧间隔的几倍,这样误差可能就导致了错误的时间截。
使用PreviewCallback和SurfaceView来获取预览数据的方法,还有很大的问题就是你必须把预览得到的数据显示出来,才能在onPreviewFrame回调函数中获取到数据。官方API是这么解释的,但这一点在2.3及以前版本的android中并不一定成立,因为我已经在2.3,2.2的系统中测试关闭输出,仍然能在onPreviewFrame中获取数据,但同样的方法在4.0以上的系统中则不可以。获取你可能会问,为什么要关闭预览输出?这个问题可能会有各种答案,但很明显的是它可以明显减少系统资源的消耗,从而可以使得照相机Camera能够以更大的预览频率输出。那么,怎么样才能使得高版本的android在不显示预览的情况下也能获得预览数据呢?这种情况下,一个叫SurfaceTexture的类登场了。
SurfaceTexture是直接继承自Object类, 最低版本api 11,关于SurfaceTexture的介绍,官方是这么介绍的——"A Surface created from a SurfaceTexture can be used as an output destination for the android.hardware.camera2, MediaCodec, MediaPlayer, and Allocation APIs."和"A SurfaceTexture may also be used in place of a SurfaceHolder when specifying the output destination of the older Camera API. Doing so will cause all the frames from the image stream to be sent to the SurfaceTexture object rather than to the device's display."。也就是说SurfaceTexture可以作为视频或图像流的输出载体。说明一下,因为android5.0的推出,要废弃Camera类,使用Camera2来替代,所以说"older Camera API"。总之,如果你使用SurfaceTexure来作为Camera的输出载体(调用Camera的setPreviewTexture即可把生成的SurfaceTexture对象设置了输出载体),那么就可以把SurfaceTexture作为预览数据缓存地方,而不用再屏幕上显示出来,显然你要为设置一个足够大的缓存区域。有了SurfaceTexture,那么接下来的工作就变得容易多了,下面说说本文提到的另一个重点就是获取到精确的时间截。
查阅SurfaceTexture类API就会发现它还提供了一个getTimeStamp()函数,官方介绍"Retrieve the timestamp associated with the texture image set by the most recent call to updateTexImage.",也就是说它可以获得SurfaceTexture最新数据帧的时间截,但在这之前需要调用updateTexImage()更新数据,另外getTimeStamp返回值的单位是纳秒。而updateTexImage()的调用对SurfaceTexture有要求,必须把SurfaceTexture设置为 GL_TEXTURE_EXTERNAL_OES texture 类型。可以这样编写代码:
surfaceTexture = new SurfaceTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES);
使用SurfaceTexture获取预览数据也是要实现PreviewCallback,方法同前文提到的PreviewCallback获取预览数据,不同的是在startPreview之前,不再调用setPreviewDisplay,而是使用Camera的setPreviewTexture。
int version = android.os.Build.VERSION.SDK_INT;
if (version >= OSSURPORTFORSURFACETEXTURE) {
try {
camera.setPreviewTexture(surfaceTexture);
int buffersize = WIDTH_COLLECT * HEIGHT_COLLECT
* ImageFormat.getBitsPerPixel(ImageFormat.NV21) / 8;
previewBuffer = new byte[buffersize];
camera.addCallbackBuffer(previewBuffer);
camera.setPreviewCallbackWithBuffer(this);
camera.startPreview();
isView = true;
} catch (IOException e) {
camera.release();
camera = null;
e.printStackTrace();
}
} else {
......
}
另外还要主要的就是要记得onPreviewFrame回调函数中添加addCallbackBuffer调用,不然缓存不会自动更新,就不能获取到后续的数据帧;要获取精确时间截(这里说精确,是因为这个时间截是系统在数据发送到SurfaceTexture时设置的,非常接近预览数据生成的时间,要远比手工在onPreviewFrame中打上数据的时间截准确),还要调用updateTexImage()。可以像下面这样编写程序:
long timestampx;
if (osversion >= OSSURPORTFORSURFACETEXTURE) {
surfaceTexture.updateTexImage();
timestampx = surfaceTexture.getTimestamp()/1000000;
camera.addCallbackBuffer(previewBuffer);
}
上述代码是写在onPreviewFrame回调函数中的,有一个值得注意的地方是不要在onPreviewFrame中做耗时的工作,因为那么极可能会导致丢掉一些预览数据帧。
通过上面的方法,已经可以在不显示预览的情况下获取到数据帧,并打上极为精确的生成时间截,这对于需要精确计算时间的程序来说是非常有用的。当然是用SurfaceTexture也可以将预览图像显示出来,你可以开一个线程专门来做这件事,而不是在onPreviewFrame中完成。下面提供一段显示预览图像的参考代码:
try {
YuvImage image = new YuvImage(data, ImageFormat.NV21,
WIDTH_COLLECT, HEIGHT_COLLECT, null);
if (image != null) {
ByteArrayOutputStream stream = new ByteArrayOutputStream();
image.compressToJpeg(new Rect(0, 0, WIDTH_COLLECT,
HEIGHT_COLLECT), 100, stream);
Bitmap bm = BitmapFactory.decodeByteArray(
stream.toByteArray(), 0, stream.size());
stream.close();
Canvas canvas = previewHolder.lockCanvas();
canvas.drawBitmap(bm, 0, 0, null);
previewHolder.unlockCanvasAndPost(canvas);
}
} catch (Exception e) {
// TODO: handle exception
}
previewHolder就是要显示预览数据的SurfaceView的SurfaceHolder,当然你要可以加上synchronized同步机制。
Demo就没有上传了,如果有什么问题可以直接留言讨论。虽然写得比较水,欢迎复制粘贴,转载请带上原文地址:http://www.cnblogs.com/HackingProgramer/p/4062119.html
Android平台之不预览获取照相机预览数据帧及精确时间截的更多相关文章
- 基于ANDROID平台,U3D对蓝牙手柄键值的获取
对于ANDROID平台,物理蓝牙手柄已被封装,上层应用不可见,也就是说对于上层应用,不区分蓝牙手柄还是其它手柄: 完成蓝牙手柄和ANDROID手机的蓝牙连接后,即可以UNITY3D中获取其键值: 在U ...
- android平台获取手机IMSI,IMEI ,序列号,和 手机号的方法
1)获取运营商sim卡imsi号, String IMSI =android.os.SystemProperties.get( android.telephony.TelephonyPropertie ...
- Android平台的Swift—Kotlin
WeTest 导读 Kotlin 已经出来较长一段时间了,有些同学已经对Kotlin进行了深入的学习,甚至已经运用到了自己的项目当中,但是还有较多同学可能只是听过Kotlin或简单了解过,这篇文章的目 ...
- Android平台上最好的几款免费的代码编辑器
使用正确的开发工具能够快速有效地完成源代码的编写和测试,使编程事半功倍.在网络信息高速发展的今天,移动设备的方便快捷已经深入人心,越来越多的程序员会选择在任何感觉舒适的地方使用移动设备查看或者编辑源代 ...
- Android平台Camera实时滤镜实现方法探讨(三)--通过Shader实现YUV转换RBG
http://blog.csdn.net/oshunz/article/details/50055057 文章例如该链接通过将YUV分成三个纹理,在shader中取出并且经过公式变换,转换成RGB.我 ...
- Android平台的开发环境的发展演变
因为之前学习java语言的时候安装过了eclipse,所以想在eclipse上搭建android平台,在参照知乎上大神们的意见,发现了AS强大的代码提示.实时预览和搜索匹配等出色功能,最后还是选择在A ...
- 【转】Android平台下利用zxing实现二维码开发
http://www.cnblogs.com/dolphin0520/p/3355728.html 现在走在大街小巷都能看到二维码,而且最近由于项目需要,所以研究了下二维码开发的东西,开源的二维码扫描 ...
- Android平台下利用zxing实现二维码开发
Android平台下利用zxing实现二维码开发 现在走在大街小巷都能看到二维码,而且最近由于项目需要,所以研究了下二维码开发的东西,开源的二维码扫描库主要有zxing和zbar,zbar在iPos平 ...
- Android平台介绍
一.Android平台介绍 什么是智能手机 具有独立的操作系统,独立的运行空间,可以由用户自行安装软件.游戏.导航等第三方应用程序,并可以通过移动通讯网络来实现无线网络接入的手机类型总称. 智能手机操 ...
随机推荐
- FeatureClass Copy
http://edndoc.esri.com/arcobjects/9.2/NET/c45379b5-fbf2-405c-9a36-ea6690f295b2.htm Method What is tr ...
- 《VIM-Adventures攻略》前言
本文已转至http://cn.abnerchou.me/2014/03/02/bfdaadb0/ 自从有了计算机,人们就想向其灌输自己的想法. 要想对其输入,自然离不开文本编辑器. 公告:<VI ...
- CentOS6.5切换 语言(附带6.5官方下载地址)
1 在终端中输入命令[sudo vim /etc/sysconfig/i18n]来编辑i18n文件, 2 把“zh_CN.UTF-8”修改为“en_US.UTF-8”, 3 保存修改并退出,如果提示这 ...
- apache 启动不了
netstat -ano|findstr "443" 发现443端口被占 记录下443端口对应的PID 进入任务管理器,查看进程,发现为一个叫做vmware-hostd.exe的进 ...
- Linux企业级项目实践之网络爬虫(9)——通过URL抓取网页内容
基本URL包含模式(或称协议).服务器名称(或IP地址).路径和文件名,如"协议://授权/路径?查询".完整的.带有授权部分的普通统一资源标志符语法看上去如下:协议://用户名: ...
- 法爱格2014 春夏新款欧美纯色修身高腰无袖吊带V领 拼接性感 连衣裙 黑色 M【图片 价格 品牌 报价】-京东
法爱格2014 春夏新款欧美纯色修身高腰无袖吊带V领 拼接性感 连衣裙 黑色 M[图片 价格 品牌 报价]-京东 法爱格2014 春夏新款欧美纯色修身高腰无袖吊带V领 拼接性感 连衣裙 黑色 M
- PyInstaller打包Python脚本为exe
1.PyInstaller-3.1.1 百度云链接 http://pan.baidu.com/s/1jHYWin8 密码 oapl 2.安装最新版本的 pywin32-217.win32-py2 ...
- git 拆库 切库 切分 子目录建库
如果git库目录是这样的: git根目录 project_a/ project_b/ ... 并且想为project_a单独创建一个代码库 # 拉一个新分支 git co -b project_a_r ...
- 在sae配置django项目
1:使用sae开发必须有sae帐号,自己注册吧: 2:在sae上新建立一个python项目: 3:建立完成之后新建一个版本,即版本1: 4:获取svn的地址在eclipse中check下来: 5:注意 ...
- MongoDB 操作手冊CRUD插入
插入操作 插入记录 1.插入一条记录 db.testData.insert({num:1,name:'a'}); 结果 WriteResult({ "nInserted" : 1 ...