Android自定义Camera

Build A CAMERA(创建一个自定义的Camera)

一些开发人员需要一个(为应用程序定制或提供特殊功能)的相机用户界面(自定义相机)。创建一个定制的相机活动需要更多的代码,但它可以为你的用户提供更令人信服的体验。

为您的应用程序创建自定义相机接口的一般步骤如下:

1.        检测和访问摄像机-创建代码,以检查是否存在摄像头和允许访问。

2.        创建一个预览类,创建一个摄像机预览类继承SurfaceView实现SurfaceHolder接口。这类用于相机预览。

3.        建立一个预览布局,一旦你有相机预览类,创建一个视图布局,集成了你想要预览界面和用户界面控件。

4.        设置监听(为捕获),为像按钮一样的控件设置监听。

5.        捕获并保存文件-设置捕获图片或视频并保存到外部设备的代码。

6.        释放相机(重要)-在使用相机后,您的应用程序必须正确地释放它,供其他应用程序使用。

相机硬件是一个共享资源,必须小心管理,所以你的应用程序可能会与其他要使用它的其他应用程序发生冲突。

下面的章节将讨论如何检测相机的硬件,如何请求访问一个摄像头,如何捕捉照片或视频,以及如何释放相机:

记住:

当您的应用程序不在使用摄像头的时候,要通过Camera.release()方法释放相机对象。如果你的应用程序没有正确地释放相机,所有随后尝试访问相机的应用程序,包括那些你自己的应用程序,都将失败,可能会导致你或其他应用程序被关闭。

Camera.release():断开并释放相机的对象资源。只要不使用相机对象,就要释放。

1.        检测摄像机硬件

如果你的应用程序没有特别要求使用摄像头(在清单文件中声明Camera),你应该检查一下是否有一个摄像头在运行时可用。要执行此检查,使用PackageManager.hasSystemFeature()方法,如下面的代码示例所示:

/**Check if this device has a camera */

private boolean checkCameraHardware(Contextcontext) {

if(context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)){

// this device has a camera

return true;

}else {

// no camera on this device

return false;

}

}

安卓设备可以有多个摄像头,例如一个背对着相机的摄影和一个前置摄像头进行录像。Android 2.3(API Level 9)以及后面的版本允许你检查在设备上可使用的摄像头的个数。通过Camera.getNumberOfCameras()方法。

public static int getNumberOfCameras():返回此设备上可用的物理摄像头的数量。

2.        连接相机

如果你已经确定了你的应用程序运行的设备上有一个摄像头,你必须通过获取一个相机的实例来请求获得它(除非你使用的意图访问相机)。

为了访问私有摄像头,要使用Camera.open()
open(int)】方法,并且try catch所有异常,下面代码所示:

public static Cameraopen ():创建一个新的相机对象(连接第一个后置摄像头),如果设备没有一个后置摄像头,返回null。

/** A safe way to get an instance of theCamera object. */

public static Camera getCameraInstance(){

Camera c = null;

try {

c = Camera.open(); // attempt to get a Camera instance

}

catch (Exception e){

// Camera is not available (in use or does not exist)

}

return c; // returns null if camera is unavailable

}

记住:在使用Camera.open()方法的时候,要检查异常,如果不检查异常:当摄像头正被其他应用使用,或者不存在摄像头,会导致你的应用程序shut down。在Android2.3(API Level9)的设备上或更高的版本上,你可以使用通过Camera.open(int)方法连接特定的摄像头。上面的代码返回第一个,后置摄像头(该设备上的,即使有多个摄像头)。

public static Cameraopen (int cameraId):创建一个新的相机对象访问特定的硬件相机。如果这个摄像头被其他应用程序打开,将会抛出一个运行时异常。参数:between
0 and getNumberOfCameras()-1。

u  使用完摄像头后必须调用release()方法释放相机,否则这个摄像头仍然被锁定,是无法被其他应用程序访问的。

u  对于一个特定的摄像头硬件,你的应用程序应该在同一时间只有一个活动着的摄像头对象。

u  其他方法的回调被传递给了thread(线程)的event loop(事件轮询器, 消息循环,使线程随时处理事件,但不退出)叫做open()。如果这个线程没有event loop,回调会被传递给主线程的event loop。如果没有主线程的event loop,回调不会传递。

警告:在某些设备上,这种方法可能需要很长的时间才能完成。最好是从一个工作者线程调用这个方法(可能使用AsyncTask)以避免阻塞UI线程的主要应用。(此方法最好在子线程中调用)。

摄像头禁用?

public boolean getCameraDisabled (ComponentNameadmin);

确定是否设备的摄像头已被禁用或被当前的管理员,如果指定,或所有管理员。

Admin:管理组件的名称。

3.        检查相机功能

一旦你获得一个摄像头,你可以得到进一步得到更多摄像头的信息,通过Camera.getParameters()方法可以得到摄像头的功能信息,检查返回的相机所支持功能的参数对象。使用API级别9或更高的时候,可以通过Camera.getCameraInfo()方法确定一个摄像头是否在设备的正面或背面,以及图像的方向。

publicCamera.Parameters getParameters ():返回此相机的当前设置。如果要修改返回的相机配置参数,就必须通过setParameters(Camera.Parameters)使新的相机参数生效。

public void setParameters (Camera.Parameters params):修改相机的设置。

Camera.Parameters params:相机参数。

2  Camera.Parameters params类(以后补充)

4.        创建预览类

为了使用户可以拍摄照片和视频,要使他们必须能够看到设备摄像头看到的场景。相机预览类是一个图形,可以实时显示来自摄像头的数据,所以用户可以组织和拍摄照片或视频。

下面的示例代码演示了如何创建一个基本的相机预览类,它包含了一个视图布局。这个类实现了SurfaceHolder.Callback接口。用于捕捉事件回调(创建和销毁界面),需要指定摄像预览输入。

/** A basic Camerapreview class */

public class CameraPreview extendsSurfaceView implements SurfaceHolder.Callback {

private SurfaceHolder mHolder;

private Camera mCamera;

public CameraPreview(Context context, Camera camera) {

super(context);

mCamera = camera;

//Install a SurfaceHolder.Callback so we get notified when the

// underlying surface is created and destroyed.

mHolder = getHolder();

mHolder.addCallback(this);

// deprecated setting, but required on Android versions prior to 3.0

//推荐设置。

mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

}

public void surfaceCreated(SurfaceHolder holder) {

//The Surface has been created, now tell the camera where to draw the preview.

try {

mCamera.setPreviewDisplay(holder);

mCamera.startPreview();

} catch (IOException e) {

Log.d(TAG, "Error setting camera preview: " + e.getMessage());

}

}

public void surfaceDestroyed(SurfaceHolder holder) {

//empty. Take care of releasing the Camera preview in your activity.

}

public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {

// If your preview can change or rotate, take care of those events here.

// Make sure to stop the preview before resizing or reformatting it.

if (mHolder.getSurface() == null){

// preview surface does not exist

return;

}

// stop preview before making changes

//在改变surface前要先停止预览。

try {

mCamera.stopPreview();

} catch (Exception e){

// ignore: tried to stop a non-existent preview

//停止一个不存在的预览。

}

// set preview size and make any resize, rotate or

// reformatting changes here设置预览大小和作任何调整大小,旋转或重新设置格式修改

// start preview with new settings

//开始预览新设置。

try {

mCamera.setPreviewDisplay(mHolder);

mCamera.startPreview();

} catch (Exception e){

Log.d(TAG, "Error starting camera preview: " + e.getMessage());

}

}

}

SurfaceHolder.Callback:

一个客户端可以实现这个接口从而接收到Surface的信息变化。

想让SurfaceHolder.CallBack生效,必须执行SurfaceHolder.addCallBack(SurfaceHolder.CallBack)方法。当使用一个SurfaceView,这个Surface只在surfaceCreated(SurfaceHolder)和surfaceDestroyed(SurfaceHolder)之间可获得。这个Callback在
SurfaceHolder.addCallback方法中设置。

abstract void surfaceChanged(SurfaceHolder holder, int format, int width, int height):
一旦Surface的结构变化(格式或者尺寸大小的变化)都会导致这个方法的调用。你应该此时更新Surface表面的图像。这个方法在surfaceCreated(SurfaceHolder)后至少调用一次。

Holder: 该SurfaceHolder的surface发生改变了。

Format: Surface的新的像素格式。

Width:Surface的新宽度。

Height:Surface的新高度。

abstract void surfaceCreated(SurfaceHolder holder):Surface第一次创建后立即调用。在这个方法中写希望渲染surface的代码。注意:只有一个线程可以在一个Surface上draw(),所以你不应该在Surface上draw(),如果此时该Surface在另一个线程中渲染。

Holder:该SurfaceHolder的surface正在被创建。

abstract void surfaceDestroyed(SurfaceHolder holder):Surface马上被销毁前调用。执行这个回调后,你不应该尝试去访问这个surface。在执行这个方法后,如果你有一个渲染线程直接访问这个surface,你必须确保这个线程不再接触这个Surface。

public abstract void addCallback (SurfaceHolder.Callback callback):为该holder添加一个Callback回调,这个holder可以关联多个Callback.

如果你想为你的相机预览界面设置特定的大小,就在surfacechanged()方法中设置。设置预览大小的时候,你必须使用从getsupportedpreviewsizes()方法中获取的值。不要在setpreviewsize()设定任意的值。

public List<Camera.Size> getSupportedPreviewSizes ():获取所支持预览的大小。返回一个相机所支持的场景模式的集合,返回null表示不支持场景模式设置。

Camera.Size

相机尺寸

总结:

属性:public int height 图片的高度

Public int width 图片的宽度

构造方法:

Camera.Size(int w, int h)

public void setPreviewSize (int width, int height):设置预览图片的尺寸。如果预览已经开始(启动了),应用程序应该在更改预览大小之前先停止预览。宽度和高度的边是基于摄像机的方向。也就是说,预览大小是在它被显示方向旋转之前的大小。因此,应用程序需要考虑的显示方向,同时设置预览大小。(这两个一起设置的时候要注意)例如,假设相机支持320x480 480x320的预览图片。应用程序需要一个3:2的预览比例。如果显示方向设置为0或180,预览大小应设置为480x320。如果显示方向设置为90或270,预览大小应设置为320x480。在设置图片大小和缩略图大小时,还应考虑显示方向。

Width: 图片的宽度,以像素为单位。

Height: 图片的宽度,以像素为单位。

public final void setDisplayOrientation (int degrees):设置顺时针旋转的预览显示的度数。这影响到预览框和snapshot后显示的图片。这个方法对垂直模式的应用有效。请注意:前置摄像头的预览显示在旋转之前水平翻转了,即

图像是反映沿摄像头传感器的中心垂直轴。所以用户可以看到自己像镜子一样。

 这个方法不允许在摄像头预览的时候调用(setDisplayOrientation)

如果你想让相机的图像显示在同一个方向上显示,可以使用以下代码:

public static void setCameraDisplayOrientation(Activity activity,

int cameraId, android.hardware.Camera camera) {

android.hardware.Camera.CameraInfo info =

new android.hardware.Camera.CameraInfo();

android.hardware.Camera.getCameraInfo(cameraId, info);

int rotation = activity.getWindowManager().getDefaultDisplay()

.getRotation();

int degrees = 0;

switch (rotation) {

case Surface.ROTATION_0: degrees = 0; break;

case Surface.ROTATION_90: degrees = 90; break;

case Surface.ROTATION_180: degrees = 180; break;

case Surface.ROTATION_270: degrees = 270; break;

}

int result;

if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {

result = (info.orientation + degrees) % 360;

result = (360 - result) % 360;  // compensate the mirror

} else {  // back-facing

result = (info.orientation - degrees + 360) % 360;

}

camera.setDisplayOrientation(result);

}

从API14开始,这种方法可以在预览时主动被调用。

int degrees:图片将顺时针旋转的角度。有效值分别为0、90、180和270。起始位置为0(景观)

public final void setPreviewDisplay (SurfaceHolder holder):用于设置实时预览的界面。

不论是surface还是surface texture 必须能够预览,并且预览界面可以用来拍照。同一个surface界面可以重新设定而不会损害surface。设置一个预览界面会重置所有预览界面的结构,通过setPreviewTexture(SurfaceTexture)方法实现。

当这个方法调用的时候,SurfaceHolder必须已经包含了一个surface。如果你使用SurfaceView,在调用setPreviewDisplay()或starting preview()之前,你必须先注册一个SurfaceHolder.Callback接口和调用addCallback(SurfaceHolder.Callback)方法,并且等待surfaceCreated(SurfaceHolder)的执行。

这个方法必须在startPreview()方法之前调用。唯一的例外是,在调用startPreview()方法之前,如果没有设置预览界面,(或者预览界面设置为空),这个方法会调用一次(传入一个非空参数)来设置预览界面。预览界面正在运行的时候,预览界面无法做改动。

Camera布局:

例如前面举的一个例子(相机预览类)。需要一个布局,来进行拍照和录像。本节将向您展示如何构建预览的基本布局和Activity。下面的布局代码提供了一个非常基本的视图,可以用来显示一个摄像头预览。在这个例子中,FrameLayout元素是相机预览类的容器。这个布局用来在相机预览图像上叠加额外的图片信息和控件。

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

android:orientation="horizontal"

android:layout_width="fill_parent"

android:layout_height="fill_parent"

>

<FrameLayout

android:id="@+id/camera_preview"

android:layout_width="fill_parent"

android:layout_height="fill_parent"

android:layout_weight="1"

/>

<Button

android:id="@+id/button_capture"

android:text="Capture"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_gravity="center"

/>

</LinearLayout>

在大多数设备,相机预览的默认方向是垂直的。此示例布局指定一个横向(纵向)的布局,下面的代码应用程序landscape的方向性。要使摄像头的预览方向为垂直方向,你应该在清单文件中增加以下代码。

<activity android:name=".CameraActivity"

android:label="@string/app_name"

android:screenOrientation="landscape">

<!-- configure this activity to use landscape orientation -->

<intent-filter>

<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />

</intent-filter>

</activity>

注意:一个摄像头预览模式不必一定是垂直模式。在Android 2.2(API Level 8开始),你可以使用setDisplayOrientation()方法设置预览图像旋转。要想改变预览方向。在预览类的surfaceChanged()方法中,首先要通过Camera.stopPreview()方法停止预览。然后通过Camera.startPreview()方法重启预览。把你自定义的预览类添加到上面FrameLayout元素中。你的相机Activity必须确定当Activity执行pause(暂停)和shut
down(关闭)的时候,它已经释放了camera。

public class CameraActivity extends Activity {

private Camera mCamera;

private CameraPreview mPreview;

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

// Create an instance of Camera

mCamera = getCameraInstance();

// Create our Preview view and set it as the content of our activity.

mPreview = new CameraPreview(this, mCamera);

FrameLayout preview = (FrameLayout) findViewById(R.id.camera_preview);

preview.addView(mPreview);

}

}

在上面的例子中的getCameraInstance()方法指的是在Accessing cameras中。

捕获图片:

一旦你已经建立了一个预览类和一个视图布局来显示它,你准备开始用您的应用程序捕捉图像。在您的应用程序代码中,您必须为用户界面控件设置侦听器来回应用户的拍照操作。要获取一张图片,使用Camera.takePicture()方法类获取图片。该方法需要三个参数,从而接收来自摄像机的数据。为了接收以JPEG格式的数据,你必须实现Camera.PictureCallback接口,来接收图片信息和把信息写到文件中去。以下的代码展示了实现了一个 Camera.PictureCallback接口来保存图片(从相机中获取的)。

private PictureCallback mPicture = new PictureCallback() {

@Override

public void onPictureTaken(byte[] data, Camera camera) {

File pictureFile = getOutputMediaFile(MEDIA_TYPE_IMAGE);

if (pictureFile == null){

Log.d(TAG, "Error creating media file, check storage permissions: " +

e.getMessage());

return;

}

try {

FileOutputStream fos = new FileOutputStream(pictureFile);

fos.write(data);

fos.close();

} catch (FileNotFoundException e) {

Log.d(TAG, "File not found: " + e.getMessage());

} catch (IOException e) {

Log.d(TAG, "Error accessing file: " + e.getMessage());

}

}

触发调用摄像头捕获图像的方法 Camera.takePicture() 。下面的代码展示了如何在Button的View.OnClickListener方法中调用 Camera.takePicture() 方法。

// Add a listener to the Capture button

Button captureButton = (Button) findViewById(id.button_capture);

captureButton.setOnClickListener(

new View.OnClickListener() {

@Override

public void onClick(View v) {

// get an image from the camera

mCamera.takePicture(null, null, mPicture);

}

}

);

注意:在应用程序使用完摄像头后要及时通过Camera.release()方法释放摄像头。

捕获录像

使用Android框架的视频采集需要对相机对象和MediaRecorder类两者进行精心的协调管理。当使用摄像头录像,你必须管理Camera.lock()和Camera.unlock()方法让MediaRecorder可以访问相机硬件。除了 Camera.open() 和 Camera.release()需要调用之外。

public final void lock ():重新锁上的摄像头,以防止其他进程访问它。相机对象默认是锁定的,除非调用unlock()方法。通常用reconnect()代替。自从API级别14,相机会自动锁定在应用程序的start()中。应用程序可以使用相机,当启动后(start)。记录启动或停止后无需再调用此方法。如果你不录制视频,你可能不需要这种方法。

public final void unlock ():打开相机允许另一个进程访问它。通常,相机被锁定在的活动着的摄像机对象,直到release()被调用。允许进程间快速切换,你可以调用这个方法来暂时释放相机,让另一个应用来使用;一旦其他进程完成后你可以调用reconnect()方法取回相机。

这个方法必须在setCamera(Camera)方法之前调用。执行start()方法之后就不能调用了。

如果你不录制视频,你可能不需要这种方法。

注意:从安卓4.0(API Level 14)之后,Camera.lock()和Camera.unlock()由你自己管理。

不像使用摄像头来拍照,录像需要一个非常特别的调用顺序。你必须遵循一个特定的执行顺序,为了使您的应用程序成功地准备和捕捉视频。正如下面所说。

时间: 2024-10-24 14:07:50

Android自定义Camera的相关文章

Android 自定义Camera 随笔

  一.权限 <uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-feature android:name="android.hardware.camera" android:requ

Android 实例讲解自定义Camera拍照和预览以及前后置摄像头切换

上一篇博文讲解了怎么去调用本地图片和调用系统拍照图片(http://blog.csdn.net/a123demi/article/details/40003695)的功能. 而本博文将通过实例实现自定义Camera的功效.具体功能如下: 1.实现自定义Camera拍照: 2.实现前后置摄像头的切换: 3.实现Camera拍照后图片缩小显示以及正常预览: 4.实现Camera拍照后图片保存: 在具体实现代码之前,我们先来了解一下Android api对实现自定义Camera的介绍. 根据api的介

android 自定义照相机Camera黑屏 (转至 http://blog.csdn.net/chuchu521/article/details/8089058)

对于一些手机,像HTC,当自定义Camera时,调用Camera.Parameters的 parameters.setPreviewSize(width, height)方法时,如果width和height为奇数情况下,则会出现黑屏现象,解决办法可参考SDK提供的ApiDemos中关于Camera的 例子: List<Size> sizes = parameters.getSupportedPreviewSizes(); Size optimalSize = getOptimalPreview

Android自定义照相机 预览拍照 切换前后置摄像头

Android提供了Camera来控制拍照,步骤如下:(1)调用Camera的open()方法打开相机.(2)调用Camera的getParameters()获取拍照参数,该方法返回一个Cmera.Parameters对象.(3)调用Camera.Parameters对象对照相的参数进行设置.(4)调用Camera的setParameters(),并将Camera.Parameters对象作为参数传入,这样就可以对拍照进行参数控制,Android2.3.3以后不用设置.(5)调用Camerade

Android 自定义Gallery浏览图片

之前写的<Android ImageSwitcher和Gallery的使用>一文中提到我在教室一下午为实现那个效果找各种资料.期间在网上找了一个个人觉得比较不错的效果,现在贴图上来: 其实这个效果使用的知识点就是图像的获取.创建.缩放.旋转.Matrix类.Canvas类等,另外就是自定义的Gallery控件. 相信大家都期待马上上代码了吧,嘻嘻.(注释比较多,相信大家都能看懂.) main.xml: <?xml version="1.0" encoding=&quo

Android自定义相机超详细讲解

Android自定义相机超详细讲解 转载请标明出处: http://blog.csdn.net/vinicolor/article/details/49642861: 由于网上关于Android自定义相机的文章写得不是太详细,Google官方的文档又说得不太容易理解,所以今天我来详细讲解一下Android自定义相机. 这篇文章主要写给一些刚刚接触Android的那些看官方API困难以及不太了解Android机制的同学们,所以熟练开发者可以绕道了. 最近在使用Camera类的时候发现居然被弃用了,

Android自定义照相机注意事项

1.设置预览方向myCamera.setDisplayOrientation(90) 2.设置照片方向parameters.setRotation(90); 3.设置预览显示和照片的分辨率 // 设置照片分辨率 List<Camera.Size> previewSizeList = parameters .getSupportedPreviewSizes(); int previewWidth = 0; int previewHeight = 0; for (int i = 0; i <

Android 自定义ViewGroup手把手教你实现ArcMenu

转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/37567907 逛eoe发现这样的UI效果,感觉很不错,后来知道github上有这么个开源项目~~~~当然本篇不是教你如何使用这个开源项目,而是教你如何自己通过自定义ViewGroup写这样的效果,自定义ViewGroup也是我的痛楚,嘿嘿,希望以此可以抛砖引玉~~ 效果图: 1.实现思路 通过效果图,会有几个问题: a.动画效果如何实现 可以看出动画是从顶点外外发射的,可能有人

Android自定义照相机实现(拍照、保存到SD卡,利用Bundle在Acitivity交换数据)

Android自定义照相机实现 近期小巫在学校有一个创新项目,也不是最近,是一个拖了很久的项目,之前一直没有去搞,最近因为要中期检查,搞得我跟小组成员一阵忙活,其实开发一款照相机软件并不太难,下面就是通过自定义的方式来实现手机照相的功能. 创建一个项目:FingerTakePicture 首先来搞一下界面: <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools=&qu