Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2194425
  • 博文数量: 866
  • 博客积分: 14125
  • 博客等级: 上将
  • 技术积分: 10638
  • 用 户 组: 普通用户
  • 注册时间: 2007-07-27 16:53
个人简介

https://github.com/landuochong

文章分类

全部博文(866)

文章存档

2019年(3)

2018年(1)

2017年(10)

2015年(3)

2014年(8)

2013年(3)

2012年(70)

2011年(103)

2010年(360)

2009年(283)

2008年(22)

分类: 嵌入式

2011-07-29 11:02:00

转自:http://blog.csdn.net/wxzking/article/details/6384576

Android2.2及其以前的版本都不支持多cameraAndroid2.3中,camera的硬件接口中增加了对多camera的支持。由于某些原因,不能直接移植Android2.3,但又要支持多camera,所以只能参考Android2.3版本,在2.2上添加接口,支持多camera

接下来,我将从application层开始,贯穿framework,直到hardware层,逐层介绍如何去支持多camera

一、Application层支持多camera

1camera.java文件

首先是Packages/apps/camera/src/com/android/camera/camera.java文件,它是camera应用程序的主体。另外在Framework/base/core/java/android/hardware/下也有一个camera.java文件,它应该是frameworkapplication之间的接口文件。请不要将这两个文件混淆。在applicationcamera.java中,我添加如下的code

Import了一个新类,叫做CameraInfo,用它来存储camera的信息,其定义在文件Framework/base/core/java/android/hardware/camera.java中。

CODE:

import android.hardware.Camera.CameraInfo;

增加两个私有变量,CODE如下:

// multiple cameras support
private int mNumberOfCameras;
private int mCameraId;

mNumberOfCameras用来记录手机上camera的数量,可以通过函数CameraHolder.instance().getNumberOfCameras()来获得;mCameraId用来记录某个cameraIDcameraID可以从CameraInfo中获取。

当我们获取了camera的总数后,可以通过函数CameraHolder.instance().getCameraInfo(),逐个去获取每个camera的信息,选择自己想要的camera,然后通过函数CameraHolder.instance().setCameraId()去设置当前要用的camera

这里需要说明的是,在Android2.3中,只增加了getNumberOfCameras()getCameraInfo()这两个接口,同时修改了CameraHolder.instance().open()接口,该接口对应底层的connect()。我为了坚持Android2.2的所有接口不变的原则,只移植了这两个接口,没有修改connect(),但同时增加了另一个接口setCameraId()。通过setCameraId()告诉cameraHAL层,当前所要的camera,如果不调用该接口,系统就按照Android2.2原来的配置运行。好了,下面我们继续描述code

我修改了onCreate()函数,CODE如下:

@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);

setContentView(R.layout.camera);
mSurfaceView = (SurfaceView) findViewById(R.id.camera_preview);

mPreferences = PreferenceManager.getDefaultSharedPreferences(this);
CameraSettings.upgradePreferences(mPreferences);

mNumberOfCameras = CameraHolder.instance().getNumberOfCameras();
for(int I = 0; I < mNumberOfCameras; I++)

{

    CameraInfo info = CameraHolder.instance().getCameraInfo()[I];

    If(CameraInfo.CAMERA_FACING_FRONT == info.facing)

    {

        mCameraId = I;

        break;

    }

}

CameraHolder.instance().setCameraId(mCameraId);

mQuickCapture = getQuickCaptureSettings();

……

至此Packages/apps/camera/src/com/android/camera/camera.java文件修改完毕,接下来我们修改Packages/apps/camera/src/com/android/camera/CameraHolder.javacamera.java是通过调用CameraHolder.java的接口来实现功能的。

2CameraHolder.java文件

CameraHolder.java文件中,同样得import CameraInfo类。CODE如下:

import android.hardware.Camera.CameraInfo;

添加三个私有变量:

private int mNumberOfCameras;
private int mCameraId = -1;
private CameraInfo[] mInfo;

这三个变量的意义一目了然,不做多讲。

修改了CameraHolder()函数:

private CameraHolder() {
HandlerThread ht = new HandlerThread("CameraHolder");
ht.start();
mHandler = new MyHandler(ht.getLooper());
mNumberOfCameras = android.hardware.Camera.getNumberOfCameras();
mInfo = new CameraInfo[mNumberOfCameras];
for (int i = 0; i < mNumberOfCameras; i++) {
mInfo[i] = new CameraInfo();
android.hardware.Camera.getCameraInfo(i, mInfo[i]);
}
}

CameraHolder()中调用android.hardware.Camera.getNumberOfCameras()获取了camera的总数,赋值给mNumberOfCameras,同时创建了相应数目的CameraInfo数组,并通过函数android.hardware.Camera.getCameraInfo()camera的信息都存储在mInfo中。同时增加了下面三个接口函数:
public int getNumberOfCameras() {
return mNumberOfCameras;
}

public CameraInfo[] getCameraInfo() {
return mInfo;
}
public int setCameraId(int cameraId) {
return android.hardware.Camera.setCameraId(cameraId);
}

application中,修改上述两个文件即可。下面我们将描述framework中的修改。


下面我将在camera应用程序的preference菜单(也就是我们看到的第一个菜单,可以设置图像大小,场景等)中,添加select_camera项,其有两个成员,分别为:back_camerafront_camera,默认选中back_camera

       接下来,我将按照文件依次介绍如何修改菜单并支持camera切换。 

1.     camera_preferences.xml文件

其位于Packages/apps/camera/res/xml/camera_preferences.xml

camera_preferences.xml文件中,包含了camera应用程序所支持的所有preference菜单。首先需要在这个文件中添加如下code

 camera:defaultValue="@string/pref_camera_id_default"

 camera:title="@string/pref_camera_id_title"

 camera:entries="@array/pref_camera_id_entries"

 camera:entryValues="@array/pref_camera_id_entryvalues" />

该菜单项的名称为:pref_camera_id_title,其定义为:Select_camera;默认选中的是pref_camera_id_default,其定义为:back_camera菜单项包含的成员为:pref_camera_id_entries,其定义在文件arrays.xml中,为:pref_camera_id_entry_backpref_camera_id_entry_front,即Back_cameraFront_camera。菜单项成员对应的键值为pref_camera_id_entryvalues,其定义为:back_camerafront_camera

 

2.     strings.xml文件

          其位于Packages/apps/camera/ res/values/strings.xml

strings.xml文件中添加如下字符串的定义:

Select_camera

Back_camera

Front_camera

back_camera

 

3.     arrays.xml文件

其位于Packages/apps/camera/ res/values/ arrays.xml

arrays.xml文件中添加如下定义,其定义了菜单项成员及其键值。

  @string/pref_camera_id_entry_back

  @string/pref_camera_id_entry_front

 

  back_camera

  front_camera

 

 

4.       CameraSettings.java文件

其位于Packages/apps/camera/ src/com/android/camera/CameraSettings.java

首先定义:

public static final String KEY_CAMERA_ID = "pref_camera_id_key";

这个与文件camera_preferences.xml中的菜单项对应。

然后在函数:

private void initPreference(PreferenceGroup group)中添加如下的code

ListPreference cameraId = group.findPreference(KEY_CAMERA_ID); 

code的意思是在camera preference中去找键值为KEY_CAMERA_ID的菜单项。如果不存在则返回null,否则返回该菜单项。

函数public ListPreference findPreference(String key)的定义在文件

PreferenceGroup.java中。

紧接着,又添加code

if (cameraId != null) {

  filterUnsupportedOptions(group, cameraId,

  mParameters.getSupportedCameraId());}

函数mParameters.getSupportedCameraId()将获取camera 硬件支持的camera切换的项,其定义在文件Framework/base/core/java/android/hardware/camera.javacameraId相当于从camera_preferences.xml中获取的camera切换的项,它俩之间需要做个匹配,如果camera硬件支持的项不存在或者只有一项,则需要从group中去掉camera切换的菜单。

同时,添加如下两个函数:

    public static int getCameraId(Parameters parameters){      

        if(parameters.getCameraIdString().equals("front_camera"))

            return 1;

        else

            return 0;

    }

    public static void setCameraId(int cameraId, Parameters parameters){

        parameters.setCamId(cameraId);

}

通过它们可以获取或者设置cameraID

 

5.     Camera.java文件

其位于Packages/apps/camera/ src/com/android/camera/ Camera.java

在函数public void onCreate(Bundle icicle)中添加:

    mCameraId = 0;

    CameraInfo info = CameraHolder.instance().getCameraInfo()[mCameraId];

    CameraHolder.instance().setCameraId(mCameraId);

设置mCameraId0,即表示默认打开后置camera

将函数private void ensureCameraDevice()改为:

    private void ensureCameraDevice() throws CameraHardwareException {

        if (mCameraDevice == null) {

        CameraHolder.instance().setCameraId(mCameraId);

            mCameraDevice = CameraHolder.instance().open();

            mInitialParams = mCameraDevice.getParameters();

        }

    }

在打开cameraDevice前,调用CameraHolder.instance().setCameraId(mCameraId)设置当前需要打开的cameraID

在函数private void updateCameraParametersPreference()中添加:

String cameraId = mPreferences.getString(CameraSettings.KEY_CAMERA_ID,

                getString(R.string.pref_camera_id_default));       

if (isSupported(cameraId, mParameters.getSupportedCameraId())) {

    if (!mParameters.getCameraIdString().equals(cameraId)) {

         mParameters.setCameraIdString(cameraId);      

    }

}

该函数是用来更新菜单设置的,

mPreferences.getString(CameraSettings.KEY_CAMERA_ID,

getString(R.string.pref_camera_id_default))获取了键值KEY_CAMERA_ID对应的菜单项当前所选择的项。isSupported(cameraId, mParameters.getSupportedCameraId())用来判断该项是否是camera硬件所支持的项。如果是,使用

mParameters.getCameraIdString().equals(cameraId)来判断该项是否与保存的cameraID是否一致,如果不一致,则使用mParameters.setCameraIdString(cameraId)更新保存值。通过这个函数,当用户选择菜单时,它就会用菜单上的变化更新当前保存的值。

在函数private void onSharedPreferenceChanged()的末尾添加code

int cameraId = CameraSettings.getCameraId(mParameters);

if (mCameraId != cameraId) {

    switchCameraId(cameraId);

}

使用CameraSettings.getCameraId(mParameters)获取目前保存的cameraID,让它与mCameraId比较,如果不一致,则需要切换camera。函数switchCameraId()的定义如下:

private void switchCameraId(int cameraId) {

        if (mPausing || !isCameraIdle()) return;

    Log.v(TAG, "switch camera: new cameraID: " + cameraId + ", old cameraID: " + mCameraId);

        mCameraId = cameraId;

        CameraSettings.setCameraId(cameraId, mParameters);

  

        stopPreview();

        closeCamera();

 

        // Remove the messages in the event queue.

        mHandler.removeMessages(RESTART_PREVIEW);

 

        // Reset variables

        mJpegPictureCallbackTime = 0;

        mZoomValue = 0;

 

        // Reload the preferences.

        mPreferences = PreferenceManager.getDefaultSharedPreferences(this);

        CameraSettings.upgradePreferences(mPreferences);

       

        // Restart the preview.

        resetExposureCompensation();

        //if (!restartPreview()) return;

        restartPreview();

 

        initializeZoom();

 

        // Reload the UI.

        if (mFirstTimeInitialized) {

            initializeHeadUpDisplay();

        }

}


6.     CameraHeadUpDisplay.java文件

其位于Packages/apps/camera/ src/com/android/camera/ui/ CameraHeadUpDisplay.java

在函数getListPreferences中添加CameraSettings.KEY_CAMERA_ID,即如下所示:

ListPreference prefs[] = getListPreferences(group,

                CameraSettings.KEY_FOCUS_MODE,

                CameraSettings.KEY_EXPOSURE,

                CameraSettings.KEY_SCENE_MODE,

                CameraSettings.KEY_PICTURE_SIZE,

                CameraSettings.KEY_CAMERA_ID,

                CameraSettings.KEY_JPEG_QUALITY,

                CameraSettings.KEY_COLOR_EFFECT);

函数getListPreferences()定义在文件HeadUpDisplay.java中,其定义为:

protected static ListPreference[] getListPreferences(

            PreferenceGroup group, String ... prefKeys) {

        ArrayList list = new ArrayList();

        for (String key : prefKeys) {

            ListPreference pref = group.findPreference(key);

            if (pref != null && pref.getEntries().length > 0) {

                list.add(pref);

            }

        }

        return list.toArray(new ListPreference[list.size()]);

    }

这里的处理,就决定了哪些菜单项会被考虑去做显示。所以必须添加CameraSettings.KEY_CAMERA_ID进去,否则菜单项是不会被显示的。

 

7.     Camera.java文件

其位于Framework/base/core/java/android/hardware/camera.java

在这个文件中,主要是提供几个获取和设置cameraId的接口。首先定义:

private static final String KEY_CAMERA_ID = "cameraid";

 

public   void setCamId(int cameraId)

{

    if(0 == cameraId){

        set(KEY_CAMERA_ID, "back_camera");

        }

    else{

                set(KEY_CAMERA_ID, "front_camera");

    }

}

public  int getCamId()

{  

    if("back_camera" == get(KEY_CAMERA_ID)){

        return 0;

    }

    else{

        return 1;

    }

}

public   void setCameraIdString(String value)

{

    set(KEY_CAMERA_ID, value);

}

public  String getCameraIdString()

{  

    return get(KEY_CAMERA_ID);

}

public List getSupportedCameraId() {

    String str = get(KEY_CAMERA_ID + SUPPORTED_VALUES_SUFFIX);     

    return split(str);

}

这里需要说明的是,在camera HAL必须把硬件camera所支持的cameraID信息表示清楚,否则应用程序不能正确显示camera切换菜单。

 

8.     CameraParameters.cpp文件

其位于Framework/base/libs/camera/CameraParameters.cpp

在该文件中添加如下定义:

const char CameraParameters::KEY_CAMERA_ID[] = "cameraid";
const char CameraParameters::KEY_SUPPORTED_CAMERA_ID[] = "cameraid-values";

    同时,CameraParameters.h中添加:

static const char KEY_CAMERA_ID[];

static const char KEY_SUPPORTED_CAMERA_ID[];

 

阅读(1343) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~
评论热议
请登录后评论。

登录 注册