联咏科技MS300二维码识别在android平台上实现流程一
整体思想是这样的:
preview的时候侦测二维码,如果侦测到,提示客户图像中有二维码
capture的时候将二维码解析出来
无论preview侦测还是capture解析,都是通过callback机制将数据传回到上层,供app读取使用。
下面我就该流程从上向下进行梳理分析:
一,app层:
camera应用的Camera.java。
一共使用了2个新方法,定义一个callback类,callback类中有2个callback方法,分别供preview和capture使用。
1,2个新方法:
mCameraDevice.setCustomSpecialCallback(mCustomSpecialCallback);//只有设置了该callback,然后callback中的方法才会自动被调用
mCameraDevice.doNovatekSpcial(1);
这2个方法从名字上可以大概看出其含义,setCustomSpecialCallback用来设置callback方法的,doNovatekSpcial用来打开或者关闭二维码识别的功能的。
mCameraDevice是android.hardware.Camera类,所以往下的话,应该要找frameworks中的camera类的定义的改变。
2,callback类定义:
private class NovatekSpcialCallback
implements android.hardware.Camera.NovatekSpcialCallback {//从这里可以看出,该callback实现的是frameworks层的接口类android.hardware.Camera.NovatekSpcialCallback
public void onCustomSpecial1(//供preview使用,如果侦测到,第一个字节返回1
byte [] CustomData, android.hardware.Camera camera) {
String value = new String((byte[])CustomData);
Log.i(TAG, " novatek callback1 3 "+ value);
}
public void onCustomSpecial2(//供capture使用,将二维码的数据返回到上层
byte [] CustomData, android.hardware.Camera camera) {
String value = new String((byte[])CustomData);
Log.i(TAG, " novatek callback2 3 "+ value);
}
}
二,frameworks实现
我们还是按照app分析过的思路继续往下分析。
路径:
frameworks/base/core/java/android/hardware/Camera.java
我们在该类中有添加app调用的2个方法和app引用到的接口类NovatekSpcialCallback。
1,两个方法:
1)public native final void doNovatekSpcial(int ena);
我们发现该方法前面有native的标记,这个代表该方法是本地实现的方法,也就是通过jni接口在native层实现
2)public final void setCustomSpecialCallback(NovatekSpcialCallback cb) {
mCustomSpecialCallback = cb;
}
该方法简单,app层调用该方法的时候,将app实现的callback传递给frameworks层。
2,NovatekSpcialCallback,定义如下:
public interface NovatekSpcialCallback
{
void onCustomSpecial1(byte[] data, Camera camera);
void onCustomSpecial2(byte[] data, Camera camera);
}
该接口就是app要实现的接口。
3,系统怎么调用callback?
private static final int CAMERA_MSG_CUSTOMSPECIAL1 = 0x4000;
private static final int CAMERA_MSG_CUSTOMSPECIAL2 = 0x8000;
private class EventHandler extends Handler
{
......
public void handleMessage(Message msg) {
switch(msg.what) {
......
case CAMERA_MSG_CUSTOMSPECIAL1:
if (mCustomSpecialCallback != null) {
String value = new String((byte[])msg.obj);//数据从msg中取出
//Log.i(TAG, " novatek callback1 1"+value);
mCustomSpecialCallback.onCustomSpecial1((byte[])msg.obj, mCamera);
}
else {
String value = new String((byte[])msg.obj);
//Log.i(TAG, " novatek callback1 2"+ value);
//Log.i(TAG, " novatek callback1 2");
}
return;
case CAMERA_MSG_CUSTOMSPECIAL2:
if (mCustomSpecialCallback != null) {
//Log.i(TAG, "novatek callback2 1");
mCustomSpecialCallback.onCustomSpecial2((byte[])msg.obj, mCamera);
}
else {
String value = new String((byte[])msg.obj);
//Log.i(TAG, "novatek callback2 2"+ value);
//Log.i(TAG, "novatek callback2 2");
}
return;
......
}
}
}
我们从handleMessage中看到了callback的调用,只要handle接受到处理的消息,那将会执行对应消息的处理部分。所以我们可以肯定在camera的service中有给该handle发送消息的地方。
路径:frameworks/base/services/camera/libcameraservice/CameraService.cpp
我们在status_t CameraService::Client::startPreviewMode() {
......
enableMsgType(CAMERA_MSG_PREVIEW_FRAME |
CAMERA_MSG_CUSTOMSPECIAL1 |
CAMERA_MSG_SMILE | CAMERA_MSG_EIS | CAMERA_MSG_MAV);
......
}
status_t CameraService::Client::takePicture() {
......
enableMsgType(CAMERA_MSG_SHUTTER |
CAMERA_MSG_POSTVIEW_FRAME |
CAMERA_MSG_RAW_IMAGE |
CAMERA_MSG_COMPRESSED_IMAGE |
CAMERA_MSG_COMPRESSED_END |
CAMERA_MSG_CUSTOMSPECIAL2 |
CAMERA_MSG_PANORAMA);
......
}
我们在preview中使能设置消息1,在capture中使能设置消息2。这样就会在preview和capture时notify到之前分析的那边,然后sendmsg,接受到msg后,就执行handlemessage中对应处理部分。
三,jni层
我们在frameworks分析中知道doNovatekSpcial(int ena)是一个本地方法。
路径:frameworks/base/core/jni/android_hardware_Camera.cpp
static void android_hardware_Camera_doNovatekSpcial(JNIEnv *env, jobject thiz, jint value)
{
// LOGV("doNovatekSpcial");
sp<Camera> camera = get_native_camera(env, thiz, NULL);
if (camera == 0) return;
if (camera->sendCommand(CAMERA_CMD_DO_NOVATEKSPEC, value, 0) != NO_ERROR) {
jniThrowException(env, "java/lang/RuntimeException", "doNovatekSpcial failed");
}
}
{ "doNovatekSpcial",
"(I)V",
(void *)android_hardware_Camera_doNovatekSpcial },
我们在本地方法中发现,它想hal层发送了一个CAMERA_CMD_DO_NOVATEKSPEC命令,打开或者关闭二维码识别的功能有后面的value决定。