OPhone Camera 介绍
在手机中通过android.hardware.Camera类来控制摄像头设备,通过Camera类可以与摄像头服务取得(断开)链接、可以设置摄像头的各种属性、开始(结束)图像预览、拍照或则录像。要使用Camera只有通过调用Camera的open() 函数来得到一个Camera对象。另外OPhone系统还提供了一些接口来控制Camera的状态:
- android.hardware.Camera.AutoFocusCallback :当摄像头自动对焦的时候调用,该接口具有一个函数 voidonAutoFocus(boolean success, Camera camera);当自动对焦成功的时候success参数的值为true,否则为false。
- android.hardware.Camera.ErrorCallback :当摄像头出错的时候调用,该接口具有一个函数 void onError(int error, Camera camera); 参数error为错误类型,其取值为Camera类中的常量CAMERA_ERROR_UNKNOWN或CAMERA_ERROR_SERVER_DIED;前者表明错误类型不明确,后者表明服务已关闭,在这种情况下必须释放当前的Camera对象然后重新初始化一个。
- android.hardware.Camera.PreviewCallback :在图像预览时候调用,该接口具有一个函数void onPreviewFrame(byte[] data, Camera camera); 参数data为每帧图像的数据流。
- android.hardware.Camera.ShutterCallback :当摄像头快门关闭的时候调用,该接口具有一个函数void onShutter(); 可以在该函数中通知用户快门已关闭,例如播放一个声音。
- android.hardware.Camera.PictureCallback :当拍摄照片的时候调用,该接口具有一个函数void onPictureTaken(byte[] data, Camera camera); 参数data为拍摄照片的数据流。
当取得照片的数据流后可以通过BitmapFactory的 decodeByteArray() 函数来解析图片。
另外还可以通过Camera对象的getParameters()函数得到一个android.hardware.Camera.Parameters对象,Parameters提供了一些接口来设置Camera的属性:
- setPictureFormat(int pixel_format):设置图片的格式,其取值为PixelFormat.YCbCr_420_SP、PixelFormat.RGB_565或则PixelFormat.JPEG。
- setPreviewFormat(int pixel_format):设置图片预览的格式,取值同上。
- setPictureSize(int width, int height):设置图片的高度和宽度,单位为像素。
- setPreviewSize(int width, int height):设置图片预览的高度和宽度,取值同上。
- setPreviewFrameRate(int fps):设置图片预览的帧速。
在设置好Camera的参数后,可以通过函数void startPreview()开始预览图像、void stopPreview()结束预览,通过autoFocus(AutoFocusCallback cb)来自动对焦,最后可以通过takePicture(ShutterCallback shutter, PictureCallback raw, PictureCallback jpeg)函数来拍照。该函数有三个参数,分别为快门回调接口、原生图像数据接口和压缩格式图片数据接口。如果数据格式不存在的话数据流为空,如果不需要实现这些接口则这些参数取值可以为null。
以上就是关于OPhone Camera的基础知识和相关的API介绍,下面来具体看看如何在程序中拍照并使用照片。
OPhone Camera 实战这个示例将显示预览图像,在图像上点击则触发拍照操作,拍照成功后显示所拍的照片,然后点击Start菜单可以继续拍照。
首先通过OPhone开发工具(ODT)创建一个OPhone项目,填写基本信息后ODT会自动创建一个\src\org\goodev\camera\CameraActivity.java文件和res\layout\main.xml文件。
把main.xml文件内容修改为如下:
SurfaceView 用来预览图像,ImageView 用来显示所拍的照片。这里也需读者会问,为什么要使用SurfaceView 来预览图像?使用其他的View不可以吗?要回答这个问题,需要了解下SurfaceView 的作用,关于SurfaceView 的详细介绍已超出了本教程的范围,我们会在后续教程中来详细介绍SurfaceView ,这里只做简要介绍。
在通常情况下,OPhone程序中的View都是在同一个GUI线程中绘制的,该线程也是接收用户交互事件的线程(例如:按钮点击事件)。从另外的线程修改GUI元素是不可以的,如果要迅速的更新UI显示该如何办?显然在主线程中还需要处理其他事件,不适合做这件事情,所以OPhone提供了SurfaceView 来满足这种需求。一个SurfaceView 包装一个Surface对象(通过SurfaceHolder操作该对象)而不是Canvas对象,这就是关键所在,Surface可以在其他线程中绘制,这对于周期性更新和要求高帧率的场景来说是很有用的,特别是在游戏开发中。Surface中包含了当前UI的原生数据(raw data),在不同的软件和硬件条件下对这些数据的处理是不一样的,这就可以通过一些设置来加速图形的绘制,可以通过SurfaceHolder的setType函数来设置,目前接收如下的参数:
- SURFACE_TYPE_NORMAL:用RAM缓存原生数据的普通Surface
- SURFACE_TYPE_HARDWARE:适用于DMA(Direct memory access )引擎和硬件加速的Surface
- SURFACE_TYPE_GPU:适用于GPU加速的Surface
- SURFACE_TYPE_PUSH_BUFFERS:表明该Surface不包含原生数据,Surface用到的数据由其他对象提供,在Camera图像预览中就使用该类型的Surface,有Camera负责提供给预览Surface数据,这样图像预览会比较流畅。如果在这里设置了上面三种类型则可以发现不会出现预览图像,在和Camera底层的预览机制实现有关,如果对预览有特殊要求的可以现实PreviewCallback接口来自己处理。
关于SurfaceView先简单介绍到这里,下面来继续看看如何在代码中实现。
修改CameraActivity类使其实现如下接口:
在CameraActivity的onCreate函数中初始化相关资源:
上面的代码首先设置窗口为全屏幕无标题的窗口,然后取得SurfaceView和ImageView对象并设置mSurfaceView的OnClickListener和mSurfaceHolder 的回调函数,最后设置mSurfaceHolder的类型为SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS。
当surface创建后初始化Camera对象,代码如下:
当surface摧毁的时候释放Camera对象,代码如下:
当surface状态改变的时候,重置Camera的状态,代码如下:
当在surface上点击的时候拍照,代码如下:
在mPictureCallback中读取所拍的照片并显示:
最后不要忘记使用Camera是需要权限的,在AndroidManifest.xml文件中添加如下设置:
总结:通过以上示例程序可以看出在OPhone中使用设备的Camera是相当简单的,现在你就可以通过Camera来实现各种新奇的应用了,是否已经想跃跃欲试了?那就开始吧!
附录:CameraActivity完整代码public void back_deal() { AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setIcon(R.drawable.epoint2); builder.setMessage("请选择需要返回的界面"); builder.setTitle(getString(R.string.prjname)); builder.setPositiveButton("主界面", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { Intent intent = new Intent(QWT_ManagerReportView.this, MainView.class); startActivity(intent); finish(); } }); builder.setNegativeButton("取消", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { dialog.cancel(); } }); builder.setNeutralButton("商户查询", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { setResult(1); finish(); } }); builder.create().show(); }
public static void showBackDialog(Context con, String backpage,// 指定返回页面的名称 OnClickListener listener1, OnClickListener listener2, OnClickListener listener3) { AlertDialog.Builder builder = new AlertDialog.Builder(con); builder.setIcon(R.drawable.epoint2); builder.setMessage("请选择需要返回的界面"); builder.setTitle(con.getString(R.string.prjname)); builder.setPositiveButton("主界面", listener1); builder.setNegativeButton("取消", listener2); builder.setNeutralButton(backpage, listener3); builder.create().show(); }
AlertHelp.showBackDialog(this, "商户查询", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { Intent intent = new Intent(QWT_ManagerReportView.this, MainView.class); startActivity(intent); finish(); } }, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { finish(); } }, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { setResult(1); finish(); } });
1、基本数据类型
JNI定义了一系列基本数据类型和引用数据类型与java相对应。
Java Language Type Native Type Description boolean jboolean
unsigned 8 bits
byte jbyte signed 8 bits short jchar unsigned 16 bits int jint signed 32 bits long jlong signed 64 bits float jfloat 32 bits double jdouble 64 bits观察能够发现,JNI基本数据类型只是比Java基本数据类型前多了个'j'而已。
2、引用数据类型
jobject (all objects)
jclass (java.lang.Class instances)
jstring (java.lang.String instances)
jarray (arrays)
jobjectArray (object[])
jbooleanArray (boolean[])
jcharArray (char[])
jshortArray (short[])
jintArray (int[])
jlongArray (long[])
jfloatArray (float[])
jdoubleArray (double[])
jthrowable java.lang.throwable
跟java一样,jobject是所有引用类型的父亲。看看是不是很容易理解?呵呵,关于jthrowable,JNI也是有线程概念的。
3、 The jvalue Type
Jvalue 是基本数据类型和引用数据类型的集合,它的定义如下:
typedef union jvalue{
jboolean z;
jbyte b;
jchar c;
jshort s;
jint i;
jlong j;
jfloat f;
jdouble d;
jobject l;
)jvalue;