android_camera框架结构

wayaonline 贡献于2016-07-26

作者 微软用户  创建于2009-09-02 07:03:00   修改者lijun  修改于2011-05-03 07:31:00字数19452

文档摘要: Android 的 Camera 包含取景器(viewfinder)和拍摄照片的功能。目前Android发布版的Camera程序虽然功能比较简单,但是其程序的架构分成客户端和服务器两个部分,它们建立在Android的进程间通讯Binder的结构上。
关键词:

 Android的Camera架构介绍 1.1 Camera概述  Android 的 Camera 包含取景器(viewfinder)和拍摄照片的功能。目前Android发布版的Camera程序虽然功能比较简单,但是其程序的架构分成客户端和服务器两个部分,它们建立在Android的进程间通讯Binder的结构上。      以开源的Android为例,Camera的代码主要在以下的目录中:  Camera的JAVA程序的路径:  packages/apps/Camera/src/com/android/camera/  在其中Camera.java是主要实现的文件    frameworks/base/core/java/android/hardware/Camera.java  这个类是和JNI中定义的类是一个,有些方法通过JNI的方式调用本地代码得到,有些方法自己实现。    Camera的JAVA本地调用部分(JNI):  frameworks/base/core/jni/android_hardware_Camera.cpp    这部分内容编译成为目标是libandroid_runtime.so。    主要的头文件在以下的目录中:  frameworks/base/include/ui/    Camera底层库在以下的目录中:  frameworks/base/libs/ui/  这部分的内容被编译成库libui.so。    Camera服务部分:  frameworks/base/camera/libcameraservice/  这部分内容被编译成库libcameraservice.so。        为了实现一个具体功能的Camera,在最底层还需要一个硬件相关的Camer库(例如通过调用video for linux驱动程序和Jpeg编码程序实现)。这个库将被Camera的服务库libcameraservice.so调用。 1.2 Camera的接口与架构 Camera的整体框架图 Camera的各个库之间的结构可以用下图的表示:     在Camera系统的各个库中,libui.so位于核心的位置,它对上层的提供的接口主要是Camera类,类libandroid_runtime.so通过调用Camera类提供对JAVA的接口,并且实现了android.hardware.camera类。      libcameraservice.so是Camera的服务器程序,它通过继承libui.so的类实现服务器的功能,并且与libui.so中的另外一部分内容则通过进程间通讯(即Binder机制)的方式进行通讯。  libandroid_runtime.so和libui.so两个库是公用的,其中除了Camera还有其他方面的功能。        Camera部分的头文件在frameworks/base/include/ui/目录中,这个目录是和libmedia.so库源文件的目录frameworks/base/libs/ui/相对应的。        Camera主要的头文件有以下几个:              ICameraClient.h              Camera.h              ICamera.h              ICameraService.h              CameraHardwareInterface.h    在这些头文件Camera.h提供了对上层的接口,而其他的几个头文件都是提供一些接口类(即包含了纯虚函数的类),这些接口类必须被实现类继承才能够使用。  整个Camera在运行的时候,可以大致上分成Client和Server两个部分,它们分别在两个进程中运行,它们之间使用Binder机制实现进程间通讯。这样在客户端调用接口,功能则在服务器中实现,但是在客户端中调用就好像直接调用服务器中的功能,进程间通讯的部分对上层程序不可见。  从框架结构上来看,ICameraService.h、ICameraClient.h和ICamera.h三个类定义了 camera的接口和架构,ICameraService.cpp和Camera.cpp两个文件用于Camera架构的实现,Camera的具体功能在下层调用硬件相关的接口来实现。 从Camera的整体结构上,类Camera是整个系统核心,ICamera类提供了Camera主要功能的接口,在客户端方面调用,CameraService是Camera服务,它通过调用实际的Camera硬件接口来实现功能。事实上,图中红色虚线框的部分都是Camera程序的框架部分,它主要利用了Android的系统的Binder机制来完成通讯。蓝色的部分通过调用Camera硬件相关的接口完成具体的Camera服务功能,其它的部分是为上层的JAVA程序提供JNI接口。在整体结构上,左边可以视为一个客户端,右边是一个可以视为服务器,二者通过Android的 Binder来实现进程间的通讯。 头文件ICameraClient.h  ICameraClient.h用于描述一个Camera客户端的接口,定义如下所示:  class ICameraClient: public IInterface  {  public:      DECLARE_META_INTERFACE(CameraClient);      virtual void shutterCallback() = 0;      virtual void rawCallback(const sp& picture) = 0;      virtual void jpegCallback(const sp& picture) = 0;      virtual void frameCallback(const sp& frame) = 0;      virtual void errorCallback(status_t error) = 0;      virtual void autoFocusCallback(bool focused) = 0;  };    class BnCameraClient: public BnInterface  {  public:      virtual status_t onTransact( uint32_t code,                                  const Parcel& data,  Parcel* reply,                                  uint32_t flags = 0);  };      在定义中,ICameraClient 类继承IInterface,并定义了一个Camera客户端的接口,BnCameraClient 继承了BnInterface,这是为基于Android的基础类Binder机制实现在进程通讯而构建的。根据BnInterface类模版的定义BnInterface类相当于双继承了BnInterface和ICameraClient。        IcameraClient这个类的主要接口是几个回调函数shutterCallback、rawCallback和jpegCallback等,它们在相应动作发生的时候被调用。作为Camera的“客户端”,需要自己实现几个回调函数,让服务器程序去“间接地”调用它们。   头文件Camera.h            Camera.h是Camera对外的接口头文件,它被实现Camera JNI的文件android_hardware_Camera.cpp所调用。Camera.h最主要是定义了一个Camera类:  class Camera : public BnCameraClient, public IBinder:: DeathRecipient  {  public:      static  sp  connect();                          ~Camera();              void        disconnect();               status_t    getStatus() { retu rn mStatus; }              status_t    setPreviewDisplay(const sp& surface);              status_t    startPreview();              void        stopPreview();              status_t    autoFocus();              status_t    takePicture();              status_t    setParameters(const String8& params);              String8     getParameters() const;              void        setShutterCallback(shutter_callback cb, void *cookie);              void        setRawCallback(frame_callback cb, void *cookie);              void        setJpegCallback(frame_callback cb, void *cookie);              void        setFrameCallback(frame_callback cb, void *cookie);              void        setErrorCallback(error_callback cb, void *cookie);        void        setAutoFocusCallback(autofocus_callback cb, void *cookie);      // ICameraClient interface      virtual void        shutterCallback();      virtual void        rawCallback(const sp& picture);      virtual void        jpegCallback(const sp& picture);      virtual void        frameCallback(const sp& frame);      virtual void        errorCallback(status_t error);      virtual void        autoFocusCallback(bool focused);  //……  }            从接口中可以看出Camera类刚好实现了一个Camera的基本操作,例如播放(startPreview)、停止(stopPreview)、 暂停(takePicture)等。在Camera类中connect()是一个静态函数,它用于得到一个Camera的实例。在这个类中,具有设置回调 函数的几个函数:setShutterCallback、setRawCallback和setJpegCallback等,这几个函数是为了提供给上层 使用,上层利用这几个设置回调函数,这些回调函数在相应的回调函数中调用,例如使用setShutterCallback设置的回调函数指针被 shutterCallback所调用。          在定义中,ICameraClient 类双继承了IInterface和IBinder:: DeathRecipient,并定义了一个Camera客户端的接口,BnCameraClient 继承了BnInterface,这是为基于Android的基础类Binder机制实现在进程通讯而构建的。 事实上,根据BnInterface类模版的定义BnInterface类相当于双继承了 BnInterface和ICameraClient。这是Android一种常用的定义方式。          继承了DeathNotifier类之后,这样当这个类作为IBinder使用的时候,当这个Binder即将Died的时候被调用其中的binderDied函数。继承这个类基本上实现了一个回调函数的功能。      头文件ICamera.h        ICamera.h描述的内容是一个实现Camera功能的接口,其定义如下所示:  class ICamera: public IInterface  {  public:      DECLARE_META_INTERFACE(Camera);       virtual void       disconnect() = 0;      virtual status_t  setPreviewDisplay(const sp& surface) = 0;      virtual void       setHasFrameCallback(bool installed) = 0;      virtual status_t  startPreview() = 0;      virtual void       stopPreview() = 0;      virtual status_t  autoFocus() = 0;      virtual status_t  takePicture() = 0;      virtual status_t  setParameters(const String8& params) = 0;      virtual String8   getParameters() const = 0;  };  class BnCamera: public BnInterface  {  public:      virtual status_t    onTransact( uint32_t code,                                      const Parcel& data,                                      Parcel* reply,                                      uint32_t flags = 0);  };        ICamera.h描述的内容是一个实现Camera功能的接口,其定义如下所示:  在camera类中,主要定义Camera的功能接口,这个类必须被继承才能够使用。值得注意的是,这些接口和Camera类的接口有些类似,但是它们并没有直接的关系。事实上,在Camera类的各种实现中,一般都会通过调用ICamera类的实现类来完成。   头文件ICameraService .h  ICameraService.h用于描述一个Camera的服务,定义方式如下所示:  class ICameraService : public IInterface  {  public:      DECLARE_META_INTERFACE(CameraService);      virtual sp     connect(const sp& cameraClient) = 0;  };  class BnCameraService: public BnInterface  {  public:      virtual status_t    onTransact( uint32_t code,                                      const Parcel& data,                                      Parcel* reply,                                      uint32_t flags = 0);  };    由于具有纯虚函数, ICameraService 以及BnCameraService必须被继承实现才能够使用,在ICameraService 只定义了一个connect()接口,它的返回值的类型是sp,这个ICamera 是提供实现功能的接口。注意,ICameraService只有连接函数connect(),没有断开函数,断开的功能由ICamera接口来提供。  头文件CameraHardwareInterface.h        CameraHardwareInterface.h定义的是一个Camera底层的接口,这个类的实现者是最终实现Camera的。        CameraHardwareInterface 定以Camera硬件的接口,如下所示:  class CameraHardwareInterface : public virtual RefBase {  public:      virtual ~CameraHardwareInterface() { }      virtual sp         getPreviewHeap() const = 0;      virtual status_t   startPreview(preview_callback cb, void* user) = 0;      virtual void        stopPreview() = 0;      virtual status_t   autoFocus(autofocus_callback,                                    void* user) = 0;      virtual status_t   takePicture(shutter_callback,                                      raw_callback,                                      jpeg_callback,                                      void* user) = 0;      virtual status_t   cancelPicture(bool cancel_shutter,                                        bool cancel_raw,                                        bool cancel_jpeg) = 0;      virtual status_t   setParameters(const CameraParameters& params) = 0;      virtual CameraParameters  getParameters() const = 0;      virtual void release() = 0;      virtual status_t dump(int fd, const Vector& args) const = 0;  };        使用C语言的方式导出符号:  extern "C" sp openCameraHardware();       在程序的其他地方,使用openCameraHardware()就可以得到一个 CameraHardwareInterface,然后调用 CameraHardwareInterface的接口完成Camera的功能。 1.3 Camera的主要实现分析 JAVA程序部分    在packages/apps/Camera/src/com/android/camera/目录的Camera.java文件中,包含了对Camera的调用  在Camera.java中包含对包的引用:  import android.hardware.Camera.PictureCallback;  import android.hardware.Camera.Size;        在这里定义的Camera类继承了活动Activity类,在它的内部,包含了一个 android.hardware.Camera  public class Camera extends Activity implements View.OnClickListener, SurfaceHolder.Callback {         android.hardware.Camera mCameraDevice;  }        对Camera功能的一些调用如下所示:  mCameraDevice.takePicture(mShutterCallback, mRawPictureCallback, mJpegPictureCallback);  mCameraDevice.startPreview();  mCameraDevice.stopPreview();        startPreview、stopPreview 和takePicture等接口就是通过JAVA本地调用(JNI)来实现的。    frameworks/base/core/java/android/hardware/目录中的Camera.java文件提供了一个JAVA类:Camera。    public class Camera {  }      在这个类当中,大部分代码使用JNI调用下层得到,例如:      public void setParameters(Parameters params) {          Log.e(TAG, "setParameters()");          //params.dump();          native_setParameters(params.flatten());      }        再者,例如以下代码:      public final void setPreviewDisplay(SurfaceHolder holder) {          setPreviewDisplay(holder.getSurface());      }        private native final void setPreviewDisplay(Surface surface);      两个setPreviewDisplay参数不同,后一个是本地方法,参数为Surface类型,前一个通过调用后一个实现,但自己的参数以SurfaceHolder为类型。       Camera的JAVA本地调用部分         Camera的JAVA本地调用(JNI)部分在frameworks/base/core/jni/目录的android_hardware_Camera.cpp中的文件中实现。      android_hardware_Camera.cpp之中定义了一个JNINativeMethod(JAVA本地调用方法)类型的数组gMethods,如下所示:  static JNINativeMethod camMethods[] = {  {"native_setup","(Ljava/lang/Object;)V",(void*)android_hardware_Camera_native_setup },    {"native_release","()V",(void*)android_hardware_Camera_release },    {"setPreviewDisplay","(Landr oid/view/Surface;)V",(void *)android_hardware_Camera_setPreviewDisplay },    {"startPreview","()V",(void *)android_hardware_Camera_startPreview },    {"stopPreview", "()V", (void *)android_hardware_Camera_stopPreview },    {"setHasPreviewCallback","(Z)V",(void *)android_hardware_Camera_setHasPreviewCallback },    {"native_autoFocus","()V",(void *)android_hardware_Camera_autoFocus },    {"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 }  };      JNINativeMethod的第一个成员是一个字符串,表示了JAVA本地调用方法的名称,这个名称是在JAVA程序中调用的名称;第二个成员也是一个字符串,表示JAVA本地调用方法的参数和返回值;第三个成员是JAVA本地调用方法对应的C语言函数。        register_android_hardware_Camera 函数将gMethods注册为的类"android/media/Camera",其主要的实现如下所示。  int register_android_hardware_Camera(JNIEnv *env)  {      // Register native functions      return AndroidRuntime::registerNativeMethods(env, "android/hardware/Camera",                                                camMethods, NELEM(camMethods));  }      "android/hardware/Camera"对应JAVA的类android.hardware.Camera。 Camera本地库libui.so      frameworks/base/libs/ui/中的Camera.cpp文件用于实现Camera.h提供的接口,其中一个重要的片段如下所示:  const sp& Camera::getCameraService()  {      Mutex::Autolock _l(mLock);      if (mCameraService.get() == 0) {          sp sm = defaultServiceManager();          sp binder;          do {              binder = sm->getService(String16("media.camera"));              if (binder != 0)                  break;              LOGW("CameraService not published, waiting...");              usleep(500000); // 0.5 s          } while(true);          if (mDeathNotifier == NULL) {              mDeathNotifier = new DeathNotifier();          }          binder->linkToDeath(mDeathNotifier);          mCameraService = interface_cast(binder);      }      LOGE_IF(mCameraService==0, "no CameraService!?");      return mCameraService;  }         其中最重要的一点是binder = sm->getService(String16("media.camera"));;这个调用用来得到一个名称为"media.camera" 的服务,这个调用返回值的类型为IBinder,根据实现将其转换成类型ICameraService使用。         一个函数 connect的实现 如下所示:  sp Camera::connect()  {      sp c = new Camera();      const sp& cs = getCameraService();      if (cs != 0) {          c->mCamera = cs->connect(c);      }      if (c->mCamera != 0) {          c->mCamera->asBinder()->linkToDeath(c);          c->mStatus = NO_ERROR;      }      return c;  }        connect通过调用getCameraService得到一个 ICameraService,再通过 ICameraService的cs->connect(c)得到一个 ICamera类型的指针。 调用connect将得到一个 Camera的指针,正常情况下Camera的成员 mCamera已经初始化完成。         一个具体的函数startPreview 如下所示:  status_t Camera::startPreview()  {      return mCamera->startPreview();  }      这些操作可以直接对 mCamera来进行,它是ICamera类型的指针。       其他一些函数的实现也与setDataSource类似。       libmedia.so中的其他一些文件与头文件的名称相同,它们是:  frameworks/base/libs/ui/ICameraClient.cpp  frameworks/base/libs/ui/ICamera.cpp  frameworks/base/libs/ui/ICameraService.cpp         在此处,BnCameraClient和BnCameraService类虽然实现了onTransact()函数,但是由于还有纯虚函数没有实现,因此这个类都是不能实例化的。         ICameraClient.cpp中的BnCameraClient在别的地方也没有实现;而ICameraService.cpp中的BnCameraService类在别的地方被继承并实现,继承者实现了Camera服务的具体功能。   Camera服务libcameraservice.so          frameworks/base/camera/libcameraservice/ 用于实现一个Camera的服务,这个服务是继承ICameraService的具体实现。        在这里的Android.mk文件中,使用宏USE_CAMERA_STUB决定是否使用真的Camera,如果宏为真,则使用 CameraHardwareStub.cpp和FakeCamera.cpp构造一个假的Camera,如果为假则使用 CameraService.cpp构造一个实际上的Camera服务。         CameraService.cpp是继承BnCameraService 的实现,在这个类的内部又定义了类Client,CameraService::Client继承了BnCamera。在运作的过程中 CameraService::connect()函数用于得到一个CameraService::Client,在使用过程中,主要是通过调用这个类的 接口来实现完成Camera的功能,由于CameraService::Client本身继承了BnCamera类,而BnCamera类是继承了 ICamera,因此这个类是可以被当成ICamera来使用的。        CameraService和CameraService::Client两个类的结果如下所示:  class CameraService : public BnCameraService  {       class Client : public BnCamera {};      wp                  mClient;  }         在CameraService中的一个静态函数instantiate()用于初始化一个Camera服务,寒暑如下所示:  void CameraService::instantiate() {      defaultServiceManager()->addService( String16("media.camera"), new CameraService());  }        事实上,CameraService::instantiate()这个函数注册了一个名称为"media.camera"的服务,这个服务和Camera.cpp中调用的名称相对应。        Camera整个运作机制是:在Camera.cpp中可以调用ICameraService的接口,这时实际上调用的是 BpCameraService,而BpCameraService又通过Binder机制和BnCameraService实现两个进程的通讯。而 BpCameraService的实现就是这里的CameraService。因此,Camera.cpp虽然是在另外一个进程中运行,但是调用 ICameraService的接口就像直接调用一样,从connect()中可以得到一个ICamera类型的指针,真个指针的实现实际上是 CameraService::Client。        而这些Camera功能的具体实现,就是CameraService::Client所实现的了,其构造函数如下所示:  CameraService::Client::Client(const sp& cameraService,          const sp& cameraClient) :      mCameraService(cameraService), mCameraClient(cameraClient), mHardware(0)  {      mHardware = openCameraHardware();      mHasFrameCallback = false;  }        构造函数中,调用openCameraHardware()得到一个CameraHardwareInterface类型的指针,并作为其成员mHardware。以后对实际的Camera的操作都通过对这个指针进行。这是一个简单的直接调用关系。        事实上,真正的Camera功能己通过实现CameraHardwareInterface类来完成。在这个库当中 CameraHardwareStub.h和CameraHardwareStub.cpp两个文件定义了一个桩模块的接口,在没有Camera硬件的情 况下使用,例如在仿真器的情况下使用的文件就是CameraHardwareStub.cpp和它依赖的文件FakeCamera.cpp。        CameraHardwareStub类的结构如下所示:  class CameraHardwareStub : public CameraHardwareInterface {      class PreviewThread : public Thread {      };  };        在类CameraHardwareStub当中,包含一个线程类PreviewThread,这个线程用于处理PreView,即负责刷新取景器的内 容。实际的Camera硬件接口通常可以通过对v4l2 捕获驱动的调用来实现,同时还需要一个JPEG编码程序将从驱动中取出的数据编码成JPEG文件。 1.4 代码分析 Android应用程序编程语言是JAVA,而linux的很多服务程序,包括一些libraries都是用c 或者c++写的,应用程序使用什么样的机制去调用这些系统函数的呢?Java的虚拟机可以通过 System.loadLibrary 来加载本地库,也可以通过JNI函数 RegisterNatives来注册与类相关联的本地方法。在Android中对于一些底层平台相关的native函数大多采用注册关联的方式来调用。 系统启动后两个重要的process: 1:App_main process: 进程通过AndroidRuntime调用register_jni_procs向JNI注册模块的native函数供JVM调用。 2:Mediaserver proces:进程注册了以下几个server: AudioFlinger, MediaPlayerServer;CameraService. Android Camera Application调用native 函数流程: 首先Android Runtime调用register_android_hardware_Camera注册Camera相关的navtive函数到JNI。然后调用android_hardware_Camera_native_setup为Application创建一个client 通过openCameraHardware打开设备,并连接到CameraServer。Application 开启preview的过程与Application建立到CameraService之间连接相似。这个过程如下图: 从上面可以看出在JAVA VM 与native之间存在一个非常重要的连接层JNI即JAVA Native Interface。Android1.0平台提供了Camera相关的native接口,如果这些接口不够的话,通过这种机制我们可以方便的进行扩展,但是我们自己扩展的接口是与我们的硬件平台相关的,并不是Android官方支持的。网上有人说Android1.0不支持JNI,Android无法执行本地JNI调用,但从Android源码来看是乎不存在这种情况,至少是支持注册与类相关联的本地方法。 Android Architecture JAVA process 与Native process之间的通信 Native process姑且认为是以c,c++语言编写服务程序(是独立的一个进程)。JAVA process是通常说的Android Application。还是Camera模块为例。我们要建立Camera Object,与CameraService Object之间的通信。 JAVA Application调用native_setup在CameraService中创建了一个Camera客户端,客户端通过getCameraService取得CameraSevice中的IBinder对象,为JAVA Application 与CamerService之间建立了一个接口ICameraService,通过这个接口我们调用BpCameraService::connect 实际上通过前面取得的IBinder对象将调用CameraService::onTransact函数在这个函数中再调用BnCameraSrvice::onTransact至此JAVA Application与CameraService之间的消息管道建立完毕。 上图中,Camera.jar Camera.cpp,ICamera, ICameraService的对象都属于java application process,当两个object之间的通信建立完毕,java application通过ICamera接口向CameraService中Camera Client发送消息。 在Native层,不同进程间两个对象需要传递消息需要继承IBinder接口,如果一个对象只需要发起连接可以继承IBinder的扩展接口BpInterface,如果需要接受连接请求可以继承BnInterface接口,比如在ICamera.cpp中有两个接口BpCamera与BnCamera,BpCamera用于发送消息,BnCamera由CameraService继承,最近消息响应通过BnCamera调用CameraService::client对象处理消息。 AudioRecord,AudioFinger,MediaPlayer其底层接口实现方式与Camera类似 camera学习(一)--参数设置 fsl的camera hal层没有实现上层到下层的设置参数的接口,所以需要自己实现。好在从应用到hal层的参数已经弄好,否则工作量就更大了。 参数设置在hal层调用的函数是status_t CameraHal::setParameters(const CameraParameters& params)。在这个函数里实现对每个参数的设置。参数设置主要通过 CameraParameters这个类实现的。通过观察这个类发现,里面有个get()函数,可以分别得到各个参数。如       const char *white_balance = params.get(CameraParameters::KEY_WHITE_BALANCE);这个可以得到目前白平衡的参数即返回值。然后根据返回值判断是哪种情况,如     if (strcmp(white_balance,  CameraParameters::WHITE_BALANCE_AUTO) == 0) {   //判断为自动白平衡         LOGV("white_balance to ioctl is auto !\n");         ctl.id = V4L2_CID_AUTO_WHITE_BALANCE;    //自动白平衡命令,ctl为v4l2_control结构,该结构很有用         ctl.value = 1;         if (ioctl(camera_device, VIDIOC_S_CTRL, &ctl) < 0){   //通过 VIDIOC_S_CTRL把ctl结构体传下去             LOGE("set control failed\n");                 //return -1;         }     }else if(strcmp(white_balance,  CameraParameters::WHITE_BALANCE_INCANDESCENT) == 0){  //白炽灯模式         LOGV("white_balance to ioctl is incandescent !\n");         ctl.id = V4L2_CID_DO_WHITE_BALANCE;   //其它白平衡情况都用该命令         ctl.value = 2;  //根据用户自己定义的白平衡模式数目排列         if (ioctl(camera_device, VIDIOC_S_CTRL, &ctl) < 0){  //同样通过 VIDIOC_S_CTRL把ctl结构体传下去,然后在根据value值分情况讨论             LOGE("set control failed\n");                 //return -1;         }     } 传到驱动的mxc_v4l2_capture.c文件的mxc_v4l_ioctl中,mxc_v4l_ioctl调用mxc_v4l_do_ioctl,mxc_v4l_do_ioctl对命令的解释如下     /*!      * V4l2 VIDIOC_S_CTRL ioctl      */     case VIDIOC_S_CTRL: {         pr_debug("   case VIDIOC_S_CTRL\n");         retval = mxc_v4l2_s_ctrl(cam, arg);         break;     } 这样就到了mxc_v4l2_s_ctrl。在mxc_v4l2_s_ctrl通过对ctl.id分情况调用 switch (c->id) {     ......     case V4L2_CID_AUTO_WHITE_BALANCE:         ipu_csi_enable_mclk_if(CSI_MCLK_I2C, cam->csi, true, true);         ret = vidioc_int_s_ctrl(cam->sensor, c);  //该函数是v4l2对应ov7670驱动中的s_ctl         ipu_csi_enable_mclk_if(CSI_MCLK_I2C, cam->csi, false, false);         break;     case V4L2_CID_DO_WHITE_BALANCE:         ipu_csi_enable_mclk_if(CSI_MCLK_I2C, cam->csi, true, true);         ret = vidioc_int_s_ctrl(cam->sensor, c);         ipu_csi_enable_mclk_if(CSI_MCLK_I2C, cam->csi, false, false);         break;      ...... 其中vidioc_int_s_ctrl()是v4l2对应ov7670驱动中的 ioctl_s_ctrl,具体代码怎么对应由于篇幅原因就不贴出来。 根据ctl结构体的id分情况去实现即可。     switch (vc->id) {     .....     case V4L2_CID_AUTO_WHITE_BALANCE:         retval = ov7670_autowhitebalance(vc->value);         break;     case V4L2_CID_DO_WHITE_BALANCE:         retval = ov7670_dowhitebalance(vc->value);         break;     ...... 下面是whitebalance函数的实现 static int ov7670_autowhitebalance(int value) {     unsigned char v = 0;     int ret;     printk("0v7670_autowhitebalance called\n");     ret = ov7670_read(ov7670_data.i2c_client, REG_COM8, &v);     if (value)         v |= COM8_AWB;  //自动白平衡     msleep(10);  /* FIXME */     ret += ov7670_write(ov7670_data.i2c_client, 0x01, 0x56);     ret += ov7670_write(ov7670_data.i2c_client, 0x02, 0x44);     ret += ov7670_write(ov7670_data.i2c_client, REG_COM8, v);     return ret;    } static int ov7670_dowhitebalance(int value) {     unsigned char v = 0;     int ret;     printk("0v7670_dowhitebalance called value:%d\n",value);     ret = ov7670_read(ov7670_data.i2c_client, REG_COM8, &v);     if (value)         v &= ~COM8_AWB;  //关闭自动白平衡     msleep(10);  /* FIXME */     ret += ov7670_write(ov7670_data.i2c_client, REG_COM8, v);     if(value == 2) //INCANDESCENCE  //这个值就是ctl的value值     {         ret += ov7670_write(ov7670_data.i2c_client, 0x01, 0x8c);         ret += ov7670_write(ov7670_data.i2c_client, 0x02, 0x59);     }else if(value == 3)  //FLUORESCENT     {         ret += ov7670_write(ov7670_data.i2c_client, 0x01, 0x7e);         ret += ov7670_write(ov7670_data.i2c_client, 0x02, 0x49);             }else if(value == 4)  //DAYLIGHT     {         ret += ov7670_write(ov7670_data.i2c_client, 0x01, 0x52);         ret += ov7670_write(ov7670_data.i2c_client, 0x02, 0x66);     }     return ret;    } 其中函数中ox01、0x02分别是蓝红通道的增益的寄存器。 上面是白平衡从hal层最终到sensor的参数设置过程。其它如色彩效果、取景模式等都是同样的过程。 取景模式根据具体的情况如夜间模式等设定具体的寄存器即可 色彩效果主要通过设置uv的值实现的 解决camera的两个小问题 由于刚开始接触camera,对里面的好多名词都很陌生。记得第一遍读完datasheet,完全是一头污水,印象最深的就是它要设置的寄存器特别多。        今天晚上特地再研究一下datasheet和它的补充介绍,感觉那个补充介绍比较好,说明的比较清楚,同时这次是我对照代码,研究它相应的寄存器。这次感觉好多了。顺便还解决了两个小问题。       1、我们camera原来的图像向下有偏移;       2、外界亮度不够的时候,camera就会很黑; 解决方法:       1、对于图像偏移,它的的寄存器0x19是用来设置图像的Vertical Frame (Row) Start,调此寄存器即可。       2、它的寄存器0x55是brightness级别。修改此寄存器的值即可。注意0x00和0x80表示不用亮度调整。 超级终端打印: 启动时 Linux video capture interface: v2.00 ^^^^ in mxc_v4l2_probe^^^ ++++ ov3640.c:ov3640_probe ++++ ++++ ov3640.c:ioctl_s_power() ++++ ++++ ov3640.c:ioctl_dev_init ++++ ++++ Setting mclk to 24 MHz++++ ++++ ov3640.c : ov3640_init_mode ++++ ++++ ov3640_write_reg:write reg :reg 点击时 意外停止(没有camera 连接) ^^^^In MVC: mxc_v4l_open^^^^ ^^^^In MVC: mxc_v4l_open:vidioc_int_g_ifparm^^^^ ++++ ov3640.c:ioctl_g_ifparm() ++++ ^^^^In MVC: mxc_v4l_open:vidioc_int_init^^^^ ++++ ov3640.c:ioctl_g_parm() ++++ ++++ ov3640.c:ioctl_s_parm ++++ ++++ ov3640.c : ov3640_init_mode ++++ ++++ ov3640_write_reg:write reg :reg=3012,val=80++++ ov3640_write_reg:write reg error:reg=3012,val=80 mxc_v4l2_s_param: vidioc_int_s_parm returned an error -1 mxc_v4l_close: release resource 点击时(有camera连接) 设置时 mxc_ipu mxc_ipu: Channel already disabled 9 mxc_ipu mxc_ipu: Channel already uninitialized 9 ^^^^^^^In MVC: mxc_v4l_open ++++ ov3640.c: ioctl_s_parm ++++ ++++ ov3640.c: ov3640_init_mode ++++ IPU:In prp_enc_enabling_tasks In prp_enc_setup YUV420 mxc_ipu mxc_ipu: IPU Error - IPU_INT_STAT_10 = 0x02000000

下载文档到电脑,查找使用更方便

文档的实际排版效果,会与网站的显示效果略有不同!!

需要 10 金币 [ 分享文档获得金币 ] 0 人已下载

下载文档