Chinaunix首页 | 论坛 | 博客
  • 博客访问: 526253
  • 博文数量: 107
  • 博客积分: 927
  • 博客等级: 大尉
  • 技术积分: 865
  • 用 户 组: 普通用户
  • 注册时间: 2011-04-13 17:50
文章分类

全部博文(107)

文章存档

2014年(2)

2013年(13)

2012年(16)

2011年(76)

分类: Java

2011-11-30 12:03:42

俗话说:知己知彼,百战不殆,想要移植camera硬件,需要了解android中camera的框架思想和调用流程,才能事半功倍。

 

(1)       Android中camera编程思路:

     Camera类介绍:

常用接口,这些接口是camera编程时作为框架层回调时候使用:

 android <wbr>camera框架分析与移植

常用方法,这些方法作为camera应用编程时使用的API

   android <wbr>camera框架分析与移植

 

在应用层的编程上常用流程为:

预览: 

    mCamera = Camera.open();

Camera.Parameters p = mCamera.getParameters();

  p.setPreviewSize(w, h);

  mCamera.setParameters(p);
 

SurfaceView  mSurfaceView = (SurfaceView) findViewById(R.id.surface_camera);

  SurfaceHolder  holder = mSurfaceView.getHolder();

  holder.addCallback(this);

  mCamera.setPreviewDisplay(holder);

  mCamera.startPreview();

 

当我们打开摄像头应用的时候首先是预览的功能,预览就是将摄像头拍摄下的景物实时的呈现出来,在android应用中能够显示给用户交互的类都是继承自 view类,我们需要给camera预览显示时提供一个画布一样的东西,这里我们使用surfaceview类,为什么不直接使用view类呢?关于 view显示的框架我将在以后的博文中给大家分析,这里使用surfaceview类作为camera的显示,可以使camera框架层得到一个可以控制 显示框架的代理,使用这个代理可以将camera获取的帧数据发送到显示框架去合成显示,如果我们设置了预览回调:

android <wbr>camera框架分析与移植

也可以在回调中将每一帧的数据保存起来形成录像的功能


拍照:
    mCamera.( shutter, raw, jpeg)

拍照本身调用就需要设置回调函数,回调函数中可以设置几种回调方式,这几种都是拍照时框架层提供给应用层数据,有原始数据,有jpeg数据,这几种都是拍摄下来的数据的不同储存方式,供我们在应用层处理使用。

 

小结:在应用层上我们可以了解到什么?

预览和拍照都可以通过回调的方式获取框架层的数据,当然预览也可以不需要把框架层的数据获取,直接发给显示框架去显示。

 

(2)       现在我们要开始分析camera类代码了解调用细节:

 

 

Camera.java (frameworks\base\core\java\android\hardware)     

public static Camera open() {

        return new Camera(); //构造camera

    }

 

    Camera() {

        mShutterCallback = null;

        mRawImageCallback = null;

        mJpegCallback = null;

        mPreviewCallback = null;

        mPostviewCallback = null;

        mZoomCallback = null;

 

        Looper looper;

        if ((looper = Looper.myLooper()) != null) { //创建Handler,处理本地的通知事件

            mEventHandler = new EventHandler(this, looper);

        } else if ((looper = Looper.getMainLooper()) != null) {

            mEventHandler = new EventHandler(this, looper);

        } else {

            mEventHandler = null;

        }

 

        native_setup(new WeakReference(this)); //调用本地方法,完成初始化

    }

 

    private native final void native_setup(Object camera_this);

   

WeakReference 类的作用:如果想观察一个类什么时候被垃圾回收清除,我们使用WeakReference类来定义,当Camera类的引用为null是,可以通过WeakReferenceget方法获取此类的信息,了解此类是否被垃圾回收

 

EventHandler调用流程;

 

 

android <wbr>camera框架分析与移植

 

 

(1)        private native final void native_setup(Object camera_this);

(2)        private native final void native_setParameters(String params);

(3)        private native final String native_getParameters();

(4)        private native final void setPreviewDisplay(Surface surface);

(5)        public native final void startPreview();

 

camera中我们发现应用层代码调用中都调用了本地(native)方法

 

 

 

android <wbr>camera框架分析与移植



 

 

 

Camera在应用层做了重要的两件是,初始化一个EventHandler,等待本地消息通知,调用本地方法进入jni层代码空间,在这里jni的调用方向有两种:

1):java调用C/C++代码,将用户功能性的代码放到jni层处理

2):C/C++代码调用java层代码,将框架层的消息传递给应用层处理

 

(2) Camera jni层代码:

android_hardware_Camera.cpp (frameworks\base\core\jni)      

 

int register_android_hardware_Camera(JNIEnv *env)

{

    field fields_to_find[] = {

        { "android/hardware/Camera", "mNativeContext",   "I", &fields.context },

        { "android/view/Surface",    "mSurface",         "I", &fields.surface }

    };

 

 

//初始化fields_t结构体contextsurface

    if (find_fields(env, fields_to_find, NELEM(fields_to_find)) < 0)        return -1;

 

    jclass clazz = env->FindClass("android/hardware/Camera");

//初始化fields_t结构体post_event

    fields.post_event = env->GetStaticMethodID(clazz, "postEventFromNative",

                                               "(Ljava/lang/Object;IIILjava/lang/Object;)V");

    if (fields.post_event == NULL) {

        LOGE("Can't find android/hardware/Camera.postEventFromNative");

        return -1;

    }

 

 

    // Register native functions 注册本地函数列表

    return AndroidRuntime::registerNativeMethods(env, "android/hardware/Camera",

                                              camMethods, NELEM(camMethods));

}

 

int register_android_hardware_Camera方法是首先调用的方法,作用是将java层的变量域和方法域存在jni层,jni层调用java层的成员变量和成员方法都要依赖域:

struct fields_t {

    jfieldID    context;// mNativeContext

    jfieldID    surface;// mSurface

    jmethodID   post_event;// postEventFromNative

};

 

 

AndroidRuntime::registerNativeMethods 方法主要是将本地函数注册给虚拟机,java层可以通过虚拟机调用这些方法

static JNINativeMethod camMethods[] = {

  { "native_setup",

    "(Ljava/lang/Object;)V",

    (void*)android_hardware_Camera_native_setup },

  { "native_release",

    "()V",

    (void*)android_hardware_Camera_release },

  { "setPreviewDisplay",

    "(Landroid/view/Surface;)V",

    (void *)android_hardware_Camera_setPreviewDisplay },

  { "startPreview",

    "()V",

    (void *)android_hardware_Camera_startPreview },

  { "stopPreview",

    "()V",

    (void *)android_hardware_Camera_stopPreview },

  { "previewEnabled",

    "()Z",

    (void *)android_hardware_Camera_previewEnabled },

  { "setHasPreviewCallback",

    "(ZZ)V",

    (void *)android_hardware_Camera_setHasPreviewCallback },

  { "addCallbackBuffer",

    "([B)V",

    (void *)android_hardware_Camera_addCallbackBuffer },

  { "native_autoFocus",

    "()V",

    (void *)android_hardware_Camera_autoFocus },

  { "native_cancelAutoFocus",

    "()V",

    (void *)android_hardware_Camera_cancelAutoFocus },

  { "native_takePicture",

    "()V",

    (void *)android_hardware_Camera_takePicture },

  { "native_setParameters",

    "(Ljava/lang/String;)V",

    (void *)android_hardware_Camera_setParameters },

  { "native_getParameters",

    "()Ljava/lang/String;",

    (void *)android_hardware_Camera_getParameters },

  { "reconnect",

    "()V",

    (void*)android_hardware_Camera_reconnect },

  { "lock",

    "()V",

    (void*)android_hardware_Camera_lock },

  { "unlock",

    "()V",

    (void*)android_hardware_Camera_unlock },

  { "startSmoothZoom",

    "(I)V",

    (void *)android_hardware_Camera_startSmoothZoom },

  { "stopSmoothZoom",

    "()V",

    (void *)android_hardware_Camera_stopSmoothZoom },

};

 

JNINativeMethod列出java层方法和c/c++层方法的映射表:

 

 

android <wbr>camera框架分析与移植

 

 

1android_hardware_Camera_native_setup方法

 

这个方法主要作用是建立如图的联系:

 

android <wbr>camera框架分析与移植

 sp camera = Camera::connect();//初始化三组proxy/stub联系

    sp context = new JNICameraContext(env, weak_this, clazz, camera);

    context->incStrong(thiz);

    camera->setListener(context);//初始化mListener

    env->SetIntField(thiz, fields.context, (int)context.get());

 

  

随后产生server和HAL之间的联系:

 

android <wbr>camera框架分析与移植

void CameraService::Client::dataCallback(int32_t msgType, const sp& dataPtr, void* user)

{

    LOGV("dataCallback(%d)", msgType);

 

    sp client = getClientFromCookie(user);

    if (client == 0) {

        return;

    }

 

    sp c = client->mCameraClient;

    if (dataPtr == NULL) {

        LOGE("Null data returned in data callback");

        if (c != NULL) {

            c->notifyCallback(CAMERA_MSG_ERROR, UNKNOWN_ERROR, 0);

            c->dataCallback(msgType, NULL);

        }

        return;

    }

       CAMERA_MSG_SHUTTER

 

    switch (msgType) {

        case CAMERA_MSG_PREVIEW_FRAME:

            client->handlePreviewData(dataPtr);//处理预览数据函数

            break;

        case CAMERA_MSG_POSTVIEW_FRAME:

            client->handlePostview(dataPtr);

            break;

        case CAMERA_MSG_RAW_IMAGE: //处理未压缩照片函数

            client->handleRawPicture(dataPtr);

            break;

        case CAMERA_MSG_COMPRESSED_IMAGE: //处理压缩处理的照片函数

            client->handleCompressedPicture(dataPtr);

            break;

        default:

            if (c != NULL) {

                c->dataCallback(msgType, dataPtr);

            }

            break;

    }

 

#if DEBUG_CLIENT_REFERENCES

    if (client->getStrongCount() == 1) {

        LOGE("++++++++++++++++ (DATA CALLBACK) THIS WILL CAUSE A LOCKUP!");

        client->printRefs();

    }

#endif

}

 

Linux中使用V4L2最为摄像头驱动,V4L2在用户空间通过各种ioctl调用进行控制,并且可以使用mmap进行内存映射

 android <wbr>camera框架分析与移植

 

ioctl函数命令参数如下:

 .vidioc_querycap  = vidioc_querycap,  //查询驱动功能 
 .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,  //获取当前驱动支持的视频格式 
 .vidioc_g_fmt_vid_cap  = vidioc_g_fmt_vid_cap,  //读取当前驱动的频捕获格式 
 .vidioc_s_fmt_vid_cap  = vidioc_s_fmt_vid_cap,   //设置当前驱动的频捕获格式 
 .vidioc_try_fmt_vid_cap  = vidioc_try_fmt_vid_cap,  //验证当前驱动的显示格式 
 .vidioc_reqbufs   = vidioc_reqbufs,   //分配内存 
 .vidioc_querybuf  = vidioc_querybuf,  //把VIDIOC_REQBUFS中分配的数据缓存转换成物理地址 
 .vidioc_qbuf   = vidioc_qbuf,  //把数据从缓存中读取出来 
 .vidioc_dqbuf   = vidioc_dqbuf,   //把数据放回缓存队列 
 .vidioc_streamon  = vidioc_streamon,  //开始视频显示函数 
 .vidioc_streamoff  = vidioc_streamoff,   //结束视频显示函数 

 .vidioc_cropcap   = vidioc_cropcap,   //查询驱动的修剪能力 
 .vidioc_g_crop   = vidioc_g_crop,     //读取视频信号的矩形边框
 .vidioc_s_crop   = vidioc_s_crop,     //设置视频信号的矩形边框  .vidioc_querystd  = vidioc_querystd,   //检查当前视频设备支持的标准,例如PAL或NTSC。 
 .vidioc_default   = vidioc_default,

 

 android <wbr>camera框架分析与移植

 

HAL首先:初始化的时候进行camera基础参数的设置,然后调用mmap系统调用将camera驱动层的数据队列映射到用户空间,

其次:当预览方法被调用的时候启动预览线程,循环的检测队列中是否有帧数据,如果帧数据存在,读取帧数据,由于读取的数据为YUV格式的数据,所有要将YUV数据转换成RGB的送给显示框架显示,也可以将转换过的数据送给视频编码模块,编码成功后储存变成录像的功能,

最后:当用户使用拍照的功能的时候,拍照线程被调用(非循环),检测队列中的帧数据,将帧数据从队列中取出,拍照的数据一定需要传到JAVA层,所有可以将数据转换成JPEG格式再上传,也可以转换成RGB的数据上传给java层

所有上传的数据处理都要经过dataCallback,除非实现了overlay

阅读(4608) | 评论(0) | 转发(0) |
0

上一篇:My Android Camera Notes

下一篇:Android Camera框架

给主人留下些什么吧!~~