在android的模拟器上面调用系统的摄像机会出现异常的现象,会自动退出,这可能和模拟器有关,模拟器无法使用系统的硬件,就像重力感应和方向感应系统一样都无法使用,甚至是GPS

导航系统也无法使用,好像有个第三方的组织,已经模拟出来模拟器上使用重力感应。但是我没有真正的看到,下面的这几段是一本书上面写的android上面使用模拟器的例子。

这个示例将显示预览图像,在图像上点击则触发拍照操作,拍照成功后显示所拍的照片,然后点击Start菜单可以继续拍照。

首先通过OPhone开发工具(ODT)创建一个OPhone项目,填写基本信息后ODT会自动创建一个\src\org\goodev\camera\CameraActivity.java文件和res\layout\main.xml文件。

把main.xml文件内容修改为如下:

view plaincopy to clipboardprint?
1.    <?xml version="1.0" encoding="utf-8"?>  
2.    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
3.        android:orientation="vertical"  
4.        android:layout_width="fill_parent"  
5.        android:layout_height="fill_parent"  
6.        >  
7.        <SurfaceView android:id="@+id/camera"  
8.            android:layout_width="fill_parent"  
9.            android:layout_height="fill_parent"/>  
10.     <ImageView android:id="@+id/image"  
11.         android:layout_width="fill_parent"  
12.         android:layout_height="fill_parent"/>  
13. </LinearLayout>  
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <SurfaceView android:id="@+id/camera" android:layout_width="fill_parent" android:layout_height="fill_parent"/> <ImageView android:id="@+id/image" android:layout_width="fill_parent" android:layout_height="fill_parent"/> </LinearLayout>

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类使其实现如下接口:

view plaincopy to clipboardprint?
1.    android.view.SurfaceHolder.Callback   
2.    android.view.View.OnClickListener

原创 android 之摄像头 

用google查了一下camera方面的资料,前几页的检索内容居然一模一样的,真是浪费时间,严重鄙视一下。

既然要用到硬件肯定要牵涉到权限,

在         中加入camera的权限:

<uses-permission android:name="android.permission.CAMERA"></uses-permission>
<uses-feature android:name="android.hardware.camera" />
 <uses-feature android:name="android.hardware.camera.autofocus" />调用camera最简单的办法是调用系统的功能,然后通过onActivityResult方法获得图像数据。
不是太习惯用android的xml配置文件,但是为了代码简单,先加一个layout.xml
<?xml version="1.0" encoding="utf-8"?>
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:orientation="vertical" android:layout_width="fill_parent"
     android:layout_height="fill_parent">
     <TextView android:text="Camera Demo" android:id="@+id/TextView01"
         android:layout_width="fill_parent" android:layout_height="wrap_content"></TextView>
     <RelativeLayout android:id="@+id/FrameLayout01" android:layout_weight="1"
         android:layout_width="fill_parent" android:layout_height="fill_parent"></RelativeLayout>
     <Button android:text="test" android:id="@+id/Button01"
         android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center"></Button>
 </LinearLayout>系统camera的uri为:
android.media.action.IMAGE_CAPTURE
final int TAKE_PICTURE = 1;
 ImageView iv;private void test1(){
      iv = new ImageView(this);
      ((FrameLayout)findViewById(R.id.FrameLayout01)).addView(iv);
      Button buttonClick = (Button)findViewById(R.id.Button01);
      buttonClick.setOnClickListener(new OnClickListener(){
             @Override
             public void onClick(View arg0) {
                 startActivityForResult(new Intent("android.media.action.IMAGE_CAPTURE"), TAKE_PICTURE);
             }
             
         });}
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
         if (requestCode == TAKE_PICTURE) {
             if (resultCode == RESULT_OK) {
                 Bitmap b = (Bitmap) data.getExtras().get("data");
                 iv.setImageBitmap(b);
             }
         }
 }

系统功能很简单,呵呵,不过不能满足俺小小的控制欲,看看camera类能干些什么。

首先扫描了一下camera,感觉camera主要是用到几个接口:

1.需要SurfaceHolder类来显示图像,并获取SurfaceHolder类传递给Camera,Camera以后通过该Holder对图像进行处理。

所以程序中需要SurfaceView子类,并实现SurfaceHolder.Callback 接口:

   public void surfaceChanged(SurfaceHolder holder, int format, int width,int height)

   public void surfaceCreated(SurfaceHolder holder)

   public void surfaceDestroyed(SurfaceHolder holder)

如:public class Preview extends SurfaceView implements SurfaceHolder.Callback

2.拍摄相片主要用到如下方法:

public final void takePicture(ShutterCallback shutter, PictureCallback raw, PictureCallback jpeg)

方法中的参数是几个回调接口:

①ShutterCallback

   void onShutter();

拍照时调用该接口,用于按下拍摄按钮后播放声音等操作 

②PictureCallback

   void onPictureTaken(byte[] data, Camera camera);

拍照时调用该接口,data为拍摄照片数据,camera为Camera类自身

takePicture方法中有两个PictureCallback,看参数名好像一个是原始数据,一个是jpeg数据。

3.还有一个预览方式

PreviewCallback

   void onPreviewFrame(byte[] data, Camera camera);

该接口可以获取摄像头每一帧的图像数据

此外此外还有几个辅助方法:

startPreview()
stopPreview()
previewEnabled()

4.其它方法:

①自动对焦 AutoFocusCallback

void onAutoFocus(boolean success, Camera camera); 
摄像头自动对焦,success表示自动对焦是否成功
② ErrorCallback
   void onError(int error, Camera camera)
摄像头发生错误是调用该接口,
CAMERA_ERROR_UNKNOWN
CAMERA_ERROR_SERVER_DIED 表示媒体服务已经当掉,需要释放Camera重新启动
③setParameters(Parameters params)
设置摄像头参数
先来做一个最简单的测试:
用来表现图像的SurfaceView子类,Android的例子里面有一个,直接拿过来用用:
class camerView extends SurfaceView implements SurfaceHolder.Callback{
     SurfaceHolder mHolder;
     Camera mCamera;
     
     public camerView(Context context) {
         super(context);
         
         mHolder = this.getHolder();
         mHolder.addCallback(this);
         mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
     }

     public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
         Camera.Parameters parameters = mCamera.getParameters();
         parameters.setPreviewSize(width, height);
         mCamera.setParameters(parameters);
         mCamera.startPreview();
     }

     public void surfaceCreated(SurfaceHolder holder) {
         mCamera = Camera.open();
         try {
            mCamera.setPreviewDisplay(holder);
         } catch (IOException exception) {
             mCamera.release();
             mCamera = null;
         }
     }

     public void surfaceDestroyed(SurfaceHolder holder) {
         mCamera.stopPreview();
         mCamera.release();
         mCamera = null;
     }
     
     public void draw(Canvas canvas){
         super.draw(canvas);
         Log.d("===>", "draw");
     }
 }内容比较简单,Camera的管理都跟camerView 的几个接口绑在一块。
下来把View加到Active中去,同时用用
private void test2(){
     cv = new camerView(this);
     RelativeLayout relay = (RelativeLayout)findViewById(R.id.FrameLayout01);
     relay.addView(cv);
     
     buttonClick = (Button)findViewById(R.id.Button01);
     buttonClick.setOnClickListener(new OnClickListener(){
         public void onClick(View arg0) {
             cv.mCamera.takePicture(
                     new ShutterCallback(){
                         public void onShutter() {
                             Log.d("===>", "onShutter");
                         }},
                     new PictureCallback(){
                         public void onPictureTaken(byte[] data, Camera camera) {
                             Log.d("===>", "raw:" + (data == null ? "null" : data.length));
                         }},//raw
                     new PictureCallback(){
                         public void onPictureTaken(byte[] data, Camera camera) {
                             Log.d("===>", "postview:" + (data == null ? "null" : data.length));
                         }}, //postview
                     new PictureCallback(){
                         public void onPictureTaken(byte[] data, Camera camera) {
                             Log.d("===>", "jpeg:" + (data == null ? "null" : data.length));
                         }} // jpeg
                 );
         }
   });
 } 这样所有的代码就完成了,在模拟器上点击test按钮,在log中可以看到:
===>onShutter
===>raw:null
===>jpeg:18474

很奇怪的是 camerView中的 ===>draw没有输出,说明View不进行绘制,那么摄像图像是怎么出来的呢?

源代码中是调用本地方法,懒得去看C代码,不想钻得太深,娱乐而已。

上网查了一半天也没有搞明白,感觉是通过SurfaceHolder获得View的Canvas对象,直接进行绘制,Holder中没有View的引用,当然不会再去调用View的draw方法了。

最后在网上搜到文章一篇,对这个原因有一点说明,Copy之,以防后面忘记:

在通常情况下,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 接口来自己处理

如果想在图像上叠加一些文字等透明信息的时候,总不能也像j2me一样地处理吧。

后面看到一篇文章介绍,直接将一个View叠加到Camera上就可以了,开始还不相信,后面实在找不到其它办法,试一试看看:

在test2()中加入

TextView tv = new TextView(this);
     tv.setText("test");
     
     RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
     lp.addRule(RelativeLayout.CENTER_IN_PARENT);
     relay.addView(tv, lp);

果然可以。呵呵,分了一下神,再回来看看Camera。

既然jpeg数据有输出,看看jpeg是什么内容,

new PictureCallback(){
  public void onPictureTaken(byte[] data, Camera camera) {
       Log.d("===>", "jpeg:" + (data == null ? "null" : data.length));
   }} // jpeg在jpeg的回调接口中添加内容
Log.d("===>", "jpeg:" + (data == null ? "null" : data.length));
 cv.setVisibility(View.INVISIBLE);
 ImageView iv = new ImageView(test.this);
 Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);  
 iv.setImageBitmap(bitmap);
 relay.addView(iv);

其中的test是类名,另外需要把relay改成final变量:

final RelativeLayout relay = (RelativeLayout)findViewById(R.id.FrameLayout01);

呵呵,又看到那幅熟悉的图片了,帅。

raw数据没有输出,网上也有人提问,外网被屏蔽了看不到详细的信息,那就此处不表下次再说了。

看看能不能设置一下参数就可以有输出了,在好奇的驱使下,又试了一下设置参数。

从log中可以看到Parameters预设的参数:

picture-format=jpeg
 picture-preview=yuv422sp


很可惜,设置为其它的参数系统都报错,玩不转,郁闷,看来要在摄像头这一块抱太多的遗憾了。

算了,看看Camera最后一点功能吧,获取帧数据:

mCamera.setPreviewCallback(new PreviewCallback(){
     public void onPreviewFrame(byte[] data, Camera camera) {
         Log.d("===>", "onPreviewFrame");
     }
 });

其中的data是yuv格式的,需要对其解码:

static public void decodeYUV420SP(byte[] rgbBuf, byte[] yuv420sp, int width, int height) {
     final int frameSize = width * height;
         if (rgbBuf == null)
             throw new NullPointerException("buffer 'rgbBuf' is null");
         if (rgbBuf.length < frameSize * 3)
             throw new IllegalArgumentException("buffer 'rgbBuf' size "
              + rgbBuf.length + " < minimum " + frameSize * 3);

         if (yuv420sp == null)
             throw new NullPointerException("buffer 'yuv420sp' is null");

          if (yuv420sp.length < frameSize * 3 / 2)
             throw new IllegalArgumentException("buffer 'yuv420sp' size " + yuv420sp.length
               + " < minimum " + frameSize * 3 / 2);

      int i = 0, y = 0;
      int uvp = 0, u = 0, v = 0;
      int y1192 = 0, r = 0, g = 0, b = 0;

      for (int j = 0, yp = 0; j < height; j++) {
           uvp = frameSize + (j >> 1) * width;
           u = 0;
           v = 0;
          for (i = 0; i < width; i++, yp++) {
               y = (0xff & ((int) yuv420sp[yp])) - 16;
              if (y < 0) y = 0;
              if ((i & 1) == 0) {
                   v = (0xff & yuv420sp[uvp++]) - 128;
                   u = (0xff & yuv420sp[uvp++]) - 128;
               }

               y1192 = 1192 * y;
               r = (y1192 + 1634 * v);
               g = (y1192 - 833 * v - 400 * u);
               b = (y1192 + 2066 * u);

              if (r < 0) r = 0; else if (r > 262143) r = 262143;
              if (g < 0) g = 0; else if (g > 262143) g = 262143;
              if (b < 0) b = 0; else if (b > 262143) b = 262143;

               rgbBuf[yp * 3] = (byte)(r >> 10);
               rgbBuf[yp * 3 + 1] = (byte)(g >> 10);
               rgbBuf[yp * 3 + 2] = (byte)(b >> 10);
           }
       }
     }


摄像头这一块android虽然给了一个接口,但是实现还是各个厂家自己实现的,所以不同的机型处理方式还不一致,

android camera 源码分析(基于应用) 

这里主要是针对Ophone进行介绍的,当然 结合了android的源码(以下出现均为android2.2源码)。 

首先在Ophone中也是通过android.hardware.Camera类来控制摄像头设备的,要使用只有通过 android.hardware.Camera.open()来打开。 try { mCameraDevice = android.hardware.Ca

mera.open(); } 
catch (RuntimeException e) { Log.e(TAG, "fail to connect Camera", e); 
throw new CameraHardwareException(e); }

另外Ophone还提供了一些接口来给予回调,控制Camera的状态,

分别是: 1.android.hardware.Camera.ErrorCallback:摄像头出错的时候调用,这个接口具有一个void onError(int error,Camera camera)函数;其中,

前者表示数据类型,取值是Camera类中的常量CAMERA_ERROR_UNKNOWN或者是 CAMERA_ERROR_SERVICE_DIED;

前者是不明错误,后者是表示服务已经关闭,

在这种情况下需要释放当前的Camera对象,然后再初始化一个。 

private static final class ErrorCallback implements android.hardware.Camera.ErrorCallback { public void onError(int error, android.hardware.Camera camera) { if (error == android.hardware.Camera.CAMERA_ERROR_SERVER_DIED) { mMediaServerDied = true; Log.v(TAG, "media server died"); } } }

2.android.hardware.camera.PreviewCallback:在图像预览时调用,这个接口有一个void onPreviewFrame(byte[] data,Camera camera);参数data为每帧图像的数据流。我们可以根据实际需要来实现这个接口。

3.android.hardware.Camera.ShutterCallback:在图像预览的时候调用,这个接口具有一个void onShutter();可以在改函数中通知用户快门已经关闭,例如播放一个声音。 private final class ShutterCallback implements android.hardware.Camera.ShutterCallback { public void onShutter() { mShutterCallbackTime = System.currentTimeMillis(); mShutterLag = mShutterCallbackTime - mCaptureStartTime; Log.v(TAG, "mShutterLag = " + mShutterLag + "ms"); clearFocusState(); } } 
4.android.hardware.Camera.PictureCallback:当拍摄相片的时候调用,该接口具有一个void onPictureTaken(byte[] data,Camera camera)函数;参数和预览的一样。在android中主要有三个类实现了这个接口,分别是PostViewPictureCallback、 RawPictureCallback、JepgPictureCallback。我们可以根据需要定义自己需要的类。 
5.android.hardware.Camera.AutoFocusCallback:当自动对焦时候调用,该接口具有一个void onAutoFocus(boolean focused,Camera camera)函数; 
private final class AutoFocusCallback implements android.hardware.Camera.AutoFocusCallback { public void onAutoFocus(boolean focused, android.hardware.Camera camera) { mFocusCallbackTime = System.currentTimeMillis(); 
mAutoFocusTime = mFocusCallbackTime - mFocusStartTime; Log.v(TAG, "mAutoFocusTime = " + mAutoFocusTime + "ms"); 
if (mFocusState == FOCUSING_SNAP_ON_FINISH) { // Take the picture no matter focus succeeds or fails. No need // to play the AF sound if we're about to play the shutter // sound. if (focused) { mFocusState = FOCUS_SUCCESS; } 
else { mFocusState = FOCUS_FAIL; } mImageCapture.onSnap(); } 
else if (mFocusState == FOCUSING)
{ // User is half-pressing the focus key. Play the focus tone. // Do not take the picture now. ToneGenerator tg = mFocusToneGenerator; if (tg != null) 
{ tg.startTone(ToneGenerator.TONE_PROP_BEEP2); } 
if (focused) { mFocusState = FOCUS_SUCCESS; } 
else { mFocusState = FOCUS_FAIL; } } 
else if (mFocusState == FOCUS_NOT_STARTED)
{ // User has released the focus key before focus completes. // Do nothing. } updateFocusIndicator(); } } 
6.还提供了放大缩小的监听器android.hardware.Camera.OnZoomChangeListener。
private final class ZoomListener implements android.hardware.Camera.OnZoomChangeListener { public void onZoomChange(int value, boolean stopped, android.hardware.Camera camera) { Log.v(TAG, "Zoom changed: value=" + value + ". stopped=" + stopped); mZoomValue = value; // Keep mParameters up to date. We do not getParameter again in // takePicture.
If we do not do this, wrong zoom value will be set. mParameters.setZoom(value); 
// We only care if the zoom is stopped. mZooming is set to true when 
// we start smooth zoom.
if (stopped && mZoomState != ZOOM_STOPPED)
{ if (value != mTargetZoomValue) { mCameraDevice.startSmoothZoom(mTargetZoomValue); mZoomState = ZOOM_START; } 
else { mZoomState = ZOOM_STOPPED; } } } }

当取得照片的数据流后可以通过BitmapFactory的decodeByteArray()函数来解析图片。 

另外还可以通过Camera对象的getParameters()函数来得到一个android.hardware.Camera.Parameters 对象,Parameters提供了一些接口来设置Camera的属性:

1.setPictureFormat(int pixel_format):设置图片的格式,其取值为PixelFormat YCbCr_420_SP、PixelFormatRGB_565或者PixelFormatJPEG。 

2.setPreviewFormat(int pixel_format):设置图片的预览格式,取值如上。

3.setPictureSize(int width,int height):设置图片的高度和宽度,单位为像素。

4.setPreviewSize(int width,int height):设置预览的高度和宽度,取值如上。

5.setPreviewFrameRate(int fps):设置图片预览的帧速。 在设置好Camera的参数后,可以通过函数void startPreview()开始预览图像、void stopPreview()结束预览,通过autoFocus(AutoFocusCallback cb)来自动对焦,最后可以通过takePicture(ShutterCallback shutter, PictureCallback raw, PictureCallback jpeg)函数来拍照。

该函数有三个参数,分别为快门回调接口、原生图像数据接口和压缩格式图片数据接口。

如果数据格式不存在的话数据流为空,如果不需要实现这些接口则这些参数取值可以为null。

Android平台硬件调试之Camera篇 

之前一段时间有幸在高通android平台上调试2款camera sensor,一款是OV的5M YUV sensor,支持jpeg out,同时也支持AF,调试比较比较简单,因为别的项目已经在使用了,只是把相关的驱动移植过来就好;另一款是Samsung的一款比较新的3M YUV FF sensor,在最新项目中要使用的,本文以调试该sensor为例,从底层驱动的角度分享一下高通android平台下调试camera的经验,而对于高通平台camera部分的架构以及原理不做过多的介绍。
    一、准备工作
    从项目中看,在硬件(板子)ready前,软件部分是要准备好的。单独从底层驱动来看,软件部分可以分为2个部分,一个是高通平台相关的,再一个就是 sensor部分的,通常的做法就是把sensor相关的设定移植到高通平台的框架之中。这样就需要先拿到sensor的spec以及厂商提供的 sensor register setting file。Spec的用途是清楚高通平台和sensor通讯(读写寄存器)的时序以及相关参数设定;而厂商提供的setting file则是在使用camera各个功能(preview、snapshot...)时候需要写入到sensor中的.
    本项目中,高通平台为MSM7X27,camera为Samsung 5CA。从spec中知道,该sensor的I2C ID为0x78,I2C的通信采用双字节方式,另外也弄清楚了读写sensor寄存器的规则,从调试角度看这些基本上够用了。另外厂商提供的 setting file,其实就是寄存器列表,告诉我们再什么时候将哪些寄存器写入什么值,通常是一个寄存器地址再加上一个寄存器的值,不过Samsung提供的是PC 上调试使用的文本,需要自己转换成c语言中的二维数组。从文件中看,寄存器数据可以分为几个部分:初始化、IQ设定(tuning相关)、clk设定、 preview设定、snapshot设定,基本上有这几个就够了,其他的比如调节亮度啦、设定特殊效果啦、设置白平衡啦等等都可以自己通过spec来完成。
    Sensor部分的东西搞定后,接下来就是修改高通camera部分的驱动了,主要有:
Kernal部分:
1、检查Sensor的电源配置,并修改软件中的设定。本项目中使用2.8/1.8/1.5共3个电源。
2、检查并修改sensor reset设置。注意reset的时间设定,务必和spec中一致,否则会导致sensor无法工作。
3、修改I2C驱动,使用双字节读写的接口,并完成读取sensor ID的接口。这个用来检验I2C通讯是否OK
4、导入寄存器设定,分别在初始化、preview、snapshot等几个部分写入对应的寄存器值。
注意:reset以及写寄存器部分一定要按照spec的规定加入一些delay,否则会导致sensor工作异常

User空间部分:
这个部分主要是根据硬件的规格来配置VFE,如sensor输出数据的格式,接口方式、分辨率大小、同步信号模式等,比较简单,但一定要检查仔细,任何一个地方不对都会导致调试失败。
    到这里为止,软件部分的准备已经告一段落了。

sensor sample还没到位)
    首先,测试点的准备。
    调试前就需要想好,如果sensor无法工作,要怎么去debug,这就需要去测量一些信号,比如power、reset、I2C、M/P CLK、H/V同步信号、数据信号等,要确保这些信号都可以测量到。
    其次要选择软件的调试环境,这里选择在ADB环境中执行高通的mm-qcamera-test程序来调试,相关的trace都可以打印出来。
    这样就万事俱备,只欠sensor了。

sensor终于拿到了)
    将sensor接到板子上,开机后,ADB中运行调试程序,preview画面并没有出来,失败,有点小失望,本来觉得可以一气呵成的,但毕竟这是一个全新的sensor,任何一个地方没有想到位做到位都会导致失败。那就找原因吧。
    1、首先从trace得知,I2C已经读到了sensor的ID:0x05CA,这可以说明I2C通讯是没有问题的
    2、接着检查Sensor的电源配置,测量了供给sensor的3个电源,都是OK的。
    3、测量MCLK,这个是提供给sensor使用的,正常(24MHZ)
    4、测量PCLK,这个是sensor输出的,正常(58MHZ,高通上限为96MHZ),和寄存器中配置的一致。
    5、测量H/V同步信号,这个是sensor输出的,正常。和FPS和分辨率一致。
    6、测量数据信号,这个是sensor输出的,正常。(数据信号,示波器上可以看到)
    这样看来,sensor已经在正常工作了,但为何preview画面没有出来呢?继续检查高通这边的设定。
    从trace看,高通的VFE已经reset并且start了,但一直接没有输出preview数据,这就奇怪了,sensor明明已经输出了,为什么 VFE接收后并没有把数据吐出来呢,难道这个sensor输出的数据VFE无法识别?为了验证这个问题,我在另一块板子上测量了OV sensor输出数据的波形,主要是M/P clk、H/V同步信号,然后再拿来对比,不过并没有发现异常,只是H/V同步信号有所不同,主要高低的占空比不太一致,会不会是这样信号的问题呢?为了进一步验证,我同时测量了H/V 信号和数据信号,这时发现OV sensor输出的数据信号是包在V帧同步信号的低电平中;而Samsung 5CA输出的数据信号是包在V帧同步信号的高电平中,会不会是因为V信号极性设置不对导致VFE没有读取到sensor输出的数据呢?重新检查了一下高通 VFE的设定,果然有一个参数是用来设定V信号极性的,这个参数默认是Active Low的,我这边并没有去修改它。接着把这个参数修改为Active High,重新build、download后,开机运行,Ok了,preview画面可以正常显示了。到这里为止sensor的硬件调试可以算作完成了,后续的其他功能也可以慢慢完善了。
    Note:V同步即帧同步信号,代表一帧数据的开始,VFE会根据该信号来读取一帧数据。
              H同步即行同步信号,代表一行数据的开始,VFE会根据该信号来读取一行数据。H信号一定是包在V同步中的。