Android API Guides---Camera

Camera

Android框架,包括在设备上​​提供的各种相机和照相功能,让您拍摄的照片和视频应用程序的支持。本文讨论了一种快速,简单的方法,以图像和视频捕捉和概述了为用户创建自定义相机体验先进的方法。


注意事项


使您的应用程序在Android设备上使用相机之前,你应该考虑你的应用打算如何使用这个硬件功能的几个问题。


相机要求 - 就是利用对您不希望在没有摄像头的设备上安装应用程序应用程序,以便重要的一个摄像头?如果是的话,你应该在你的清单申报相机的要求。
快速的图片或自定义相机 - 您的应用程序将如何使用摄像头?你只是有兴趣抢购快速图片或视频剪辑,或将您的应用程序提供了使用相机的新方式?对于得到一个快速扣或夹子,可以考虑使用现有的相机应用。为了开发一个定制的摄像功能,检查了大楼一个相机应用部分。
存储 - 是你的应用程序生成旨在只有你的应用程序中显示或共享以便其他应用程序,如画廊或其他媒体和社交应用程序可以使用它们的图像或视频?你想要的图片和视频,即使您的应用程序卸载可用?退房保存媒体文件部分,看看如何实现这些选项。
基础


Android框架支持通过android.hardware.camera2 API或相机意图捕捉图像和视频。以下是相关的类:


android.hardware.camera2
这个包是用于控制装置的相机的主要API。它可以用来当你构建一个摄像头应用程序来拍摄照片或录像。
Camera
这个类是控制装置摄像头老过时的API。
SurfaceView
这个类用于呈现现场摄像机预览给用户。
MediaRecorder
此类用于从相机录制视频。
Intent
MediaStore.ACTION_IM​​AGE_CAPTURE或MediaStore.ACTION_VIDEO_CAPTURE的意图动作类型可以用来捕捉图像或视频而不直接使用Camera对象。
清单声明


在用相机的API应用程序开发开始之前,你应该确保你的清单有相应的声明,从而允许使用摄像头的硬件和其他相关功能。


相机许可 - 您的应用程序必须要求使用设备摄像头的权限。

<uses-permission android:name="android.permission.CAMERA" />
注意:如果您通过一个意图使用相机时,你的应用程序并不需要请求此权限。


拍照功能 - 您的应用程序还必须声明使用拍照功能,例如:

<uses-feature android:name="android.hardware.camera" />
对于相机功能的列表,请参阅清单功能参考。
加入拍照功能到你的清单使谷歌起到防止您的应用程序被安装到不包括相机或不支持您指定的相机功能的设备。有关使用基于特征的过滤与谷歌播放的更多信息,请参阅谷歌播放和基于特征的过滤。
必需的属性,并将其设置为false:如果您的应用程序可以使用正常工作的摄像机或摄像功能,但并不需要它,你应该包括Android在清单中指定此:

<uses-feature android:name="android.hardware.camera" android:required="false" />
存储权限 - 如果您的应用程序保存的图像或视频设备的外部存储(SD卡),还必须在清单中注明。

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
录音权限 - 对于录制视频拍摄有声,应用程序必须请求音频采集许可。

<uses-permission android:name="android.permission.RECORD_AUDIO" />
位置的权限 - 如果你的应用程序标签带有GPS位置信息的图片,你必须要求位置的权限:

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
有关获取用户位置的详细信息,请参阅位置策略。
使用现有的相机应用


一个快速的方法,使拍照或视频在您的应用程序没有很多额外的代码是使用一个Intent调用现有的Andr​​oid摄像头应用程序。照相机意图使捕捉到通过现有相机应用的图片或视频片段的请求,然后返回控制返回给应用程序。本节将向您展示如何使用这种技术捕捉图像或视频。


用于调用摄像头意图的过程遵循以下一般步骤:


撰写相机意图 - 创建一个请求图像或视频,使用这些意图类型之一的意图:
MediaStore.ACTION_IM​​AGE_CAPTURE - 意图动作类型从现有相机应用程序请求的图像。
MediaStore.ACTION_VIDEO_CAPTURE - 意图动作类型从现有相机应用程序请求的视频。
启动摄像头意图 - 用startActivityForResult()方法来执行相机意图。在启动的意图,相机应用程序的用户界面显示在设备屏幕上,用户可以拍摄照片或视频。
收到意向结果 - 在你的应用程序中设置的onActivityResult()方法来接收来自摄像头的意图回调和数据。当用户完成拍摄照片或视频(或取消操作)时,系统调用这个方法。
图像拍摄意图


捕获使用照相机图像的意图是快速的方法,使您的应用程序需要用最少的代码的图片。图像捕捉的意图可以包括以下额外信息:


MediaStore.EXTRA_OUTPUT - 此设置需要一个Uri对象指定的路径和文件名,你要保存的图片。此设置是可选的,但强烈建议。如果不指定此值,相机应用程序保存在默认名称的默认位置所要求的图片,在返回的意图的Intent.getData()字段中指定。
下面的例子演示了如何构建一个图像采集的意图并执行它。在这个例子中getOutputMediaFileUri()方法是指在保存媒体文件示出的代码示例。

private static final int CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE = 100;
private Uri fileUri;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    // create Intent to take a picture and return control to the calling application
    Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);

    fileUri = getOutputMediaFileUri(MEDIA_TYPE_IMAGE); // create a file to save the image
    intent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri); // set the image file name

    // start the image capture Intent
    startActivityForResult(intent, CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE);
}
当执行startActivityForResult()方法,用户看到相机应用接口。用户完成后拍照(或取消操作),用户界面​​返回到您的应用程序,你必须拦截的onActivityResult()方法来接收意向的结果,并继续你的应用程序的执行。有关如何接收完成意图的信息,请参阅接收相机意图的结果。
视频拍摄意图
用相机捕捉的意图视频的快捷方式,使您的应用程序,以便拍摄视频用最少的代码。视频捕捉的意图可以包括以下额外信息:
MediaStore.EXTRA_OUTPUT - 此设置需要一个开放的指定路径和文件名,你要保存的视频。此设置是可选的,但强烈建议。如果不指定此值,相机应用程序保存在使用默认名称的默认位置所要求的视频,在返回的意图Intent.getData()字段中指定。
MediaStore.EXTRA_VIDEO_QUALITY - 这个值可以是0为最高质量和更大的文件大小最低的质量和最小的文件大小或1。
MediaStore.EXTRA_DURATION_LIMIT - 将该值设置为限制长度,以秒为单位,被捕获的视频。
MediaStore.EXTRA_SIZE_LIMIT - 将该值设置为限制文件大小,以字节为单位,被捕获的视频。
下面的例子演示了如何构建一个视频捕捉的意图并执行它。在这个例子中getOutputMediaFileUri()方法是指在保存媒体文件示出的代码示例。

private static final int CAPTURE_VIDEO_ACTIVITY_REQUEST_CODE = 200;
private Uri fileUri;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    //create new Intent
    Intent intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);

    fileUri = getOutputMediaFileUri(MEDIA_TYPE_VIDEO);  // create a file to save the video
    intent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri);  // set the image file name

    intent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 1); // set the video image quality to high

    // start the Video Capture Intent
    startActivityForResult(intent, CAPTURE_VIDEO_ACTIVITY_REQUEST_CODE);
}
当执行startActivityForResult()方法中,用户可以看到修改后的摄像头应用程序接口。用户完成拍摄后的视频(或取消操作),用户界面​​返回到您的应用程序,你必须拦截的onActivityResult()方法来接收意向的结果,并继续你的应用程序的执行。有关如何接收完成意图的信息,请参阅下一节。


接收相机意图的结果


一旦你已经构建和执行的图像或视频摄像头的意图,你的应用程序必须被配置为接收意图的结果。本节将展示如何从相机意图拦截回调使应用程序可以做拍摄的图像或视频的进一步处理。


为了得到一个意图的结果,你必须覆盖的onActivityResult()在开始的意图的活动。下面的例子演示如何重写的onActivityResult()来捕获在前面的章节中显示的图像照相机意图或摄像机意图例子的结果。

private static final int CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE = 100;
private static final int CAPTURE_VIDEO_ACTIVITY_REQUEST_CODE = 200;

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (requestCode == CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE) {
        if (resultCode == RESULT_OK) {
            // Image captured and saved to fileUri specified in the Intent
            Toast.makeText(this, "Image saved to:\n" +
                     data.getData(), Toast.LENGTH_LONG).show();
        } else if (resultCode == RESULT_CANCELED) {
            // User cancelled the image capture
        } else {
            // Image capture failed, advise user
        }
    }

    if (requestCode == CAPTURE_VIDEO_ACTIVITY_REQUEST_CODE) {
        if (resultCode == RESULT_OK) {
            // Video captured and saved to fileUri specified in the Intent
            Toast.makeText(this, "Video saved to:\n" +
                     data.getData(), Toast.LENGTH_LONG).show();
        } else if (resultCode == RESULT_CANCELED) {
            // User cancelled the video capture
        } else {
            // Video capture failed, advise user
        }
    }
}
一旦您的活动获得成功的结果,所拍摄的图像或视频在您的应用程序访问指定的位置可用。


构建相机应用


有些开发人员可能需要定制自己的应用程序的外观或提供特殊功能,相机的用户界面。创建自定义相机活动要求比使用意图更多的代码,但它可以为使用者提供一个更引人注目的体验。


注:以下指南是上了年纪,不推荐使用相机API。对于新的或先进的相机应用,推荐更新的android.hardware.camera2 API。


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


检测并访问摄像头 - 创建代码以检查摄像头并请求访问的存在。
创建预览类 - 创建扩展SurfaceView并实现SurfaceHolder接口的摄像头预览类。该类预览来自摄像机的实时图像。
建立一个预览布局 - 一旦你的摄像头预览类,创建一个包含了预览和你想要的用户界面控件的视图布局。
设置为监听器捕获 - 连接监听器的界面来启动图像或视频捕获响应用户的操作,如按下一个按钮。
捕获和保存文件 - 设置捕获图片或视频并保存输出的代码。
松开相机 - 使用相机后,您的应用程序必须正确释放它的其他​​应用程序使用。
相机硬件是一个共享资源,必须精心管理,以便您的应用程序不与可能还需要使用它的其他应用程序冲突。以下各节讨论了如何检测相机的硬件,如何申请到一个摄像头,如何捕获图片或视频,以及如何当你的应用程序使用它做释放摄像头的访问。


注意:请记住通过调用Camera.release()当你的应用程序使用它做释放Camera对象!如果你的应用程序不能正确地释放相机,所有的后续尝试访问摄像机,包括那些由你自己的应用程序,将失败,并可能导致您或其他应用程序被关闭。


检测摄像头硬件


如果您的应用程序不使用舱单申报明确要求一个摄像头,你应该检查,看是否有摄像头在运行时可用。要执行此检查,使​​用PackageManager.hasSystemFeature()方法,如下面的示例代码:

/** Check if this device has a camera */
private boolean checkCameraHardware(Context context) {
    if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)){
        // this device has a camera
        return true;
    } else {
        // no camera on this device
        return false;
    }
}
Android设备可以有多个摄像头,例如背对着相机摄影和一个前置摄像头用于视频通话。的Android 2.3(API等级9),后来允许您检查摄像机使用Camera.getNumberOfCameras()方法的设备上可用的数量。


访问摄像头


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


要访问的主摄像头,使用Camera.open()方法,并且一定要捕捉任何异常,如下面的代码:

/** A safe way to get an instance of the Camera 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时,务必检查异常()。未检查异常,如果相机在使用或不存在会导致应用程序被系统关闭。


在运行Android 2.3(API等级9)或更高版本的设备,您可以访问使用Camera.open(int)的特定摄像机。上面的例子中的代码将访问第一,后置摄像头的设备上与多于一个照相机。


检查相机功能


一旦你获得访问摄像头,你可以得到有关使用Camera.getParameters()方法,并检查返回Camera.Parameters对象,用于支持的功能其功能的进一步信息。当使用API​​级别9或更高,使用Camera.getCameraInfo(),以确定是否一个照相机是在前面或该装置的后面,并且所述图像的方向。


创建预览类


为用户有效地拍摄照片或视频,他们必须能够看到设备摄像机看到的。一个摄像头预览类是可以显示实时图像数据从相机的到来,这样用户就可以框架和拍摄的照片或视频SurfaceView。


下面的示例代码演示了如何创建一个可以包含在一个视图布局基本的摄像头预览类。这类以捕获用于创建和销毁的观点,这是需要用于分配相机预览输入的回调事件实现SurfaceHolder.Callback。

/** A basic Camera preview class */
public class CameraPreview extends SurfaceView 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
        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());
        }
    }
}
如果要设置特定大小的摄像头预览,如意见指出在上面的surfaceChanged()方法来设置此。当设置预览大小,您必须使用值从getSupportedPreviewSizes()。不要在setPreviewSize()方法来设置任意值。


在布局中安置预览


一种相机预览类,如前一节中所示的例子中,必须放置在一个活动的布局与用于拍摄的图片或视频的其他用户界面控件一起。本节将展示如何构建用于预览的基本布局和活动。


下面布局代码提供了可用于显示相机预览一个非常基本的图。在本实施例中,的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>
在大多数设备,摄像头预览的默认方向为横向。此示例布局指定的水平(横向)的布局和下面的代码修复应用为横向的方向。对于渲染相机预览简单,你应该加入以下到您的清单应用程序的预览活动方向更改为横向。

<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等级8级)开始,您可以使用setDisplayOrientation()方法来设置预览图像的旋转。为了改变预览方向为用户重新定向预览类的surfaceChanged()方法中的电话,先停止Camera.stopPreview预览()与Camera.startPreview再次改变方向,然后开始预览( )。


在为您的相机查看活动,添加您预览类在上面的例子所示的FrameLayout元素。您的相机活动还必须确保它释放的相机,当它被暂停或关闭。下面的示例演示如何修改相机活动附上创建预览类显示预览类。

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()方法是指在访问摄像机中所示的示例性方法。


捕获图片


一旦你已经建立了一个预览类,并在其中显示该视图的布局,你就可以开始你的应用程序捕获图像。在您的应用程序代码,您必须设置监听器为用户界面控件通过拍照为响应用户操作。


为了检索一个图象,使用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()方法捕捉图像。下面的示例代码显示了如何调用从按钮View.OnClickListener此方法。

// 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);
        }
    }
);
注意:mPicture构件在下面的例子中是指上述示例代码。


注意:请记住通过调用Camera.release()当你的应用程序使用它做释放Camera对象!有关如何释放摄像头的信息,请参阅释放摄像头。


捕捉视频


使用Android框架视频捕获要求Camera对象,并与MediaRecorder类协调的精心管理。用摄像头录制视频时,必须管理Camera.lock()和Camera.unlock()调用允许MediaRecorder相机硬件访问,除了Camera.open()和Camera.release()调用。


注:与Android 4.0(API等级14),该Camera.lock()和Camera.unlock开始()调用都为你自动管理。


不同于拍照与设备的摄像头,捕获视频需要一个非常特殊的来电订购。您必须遵守执行特定的顺序,以成功为准备和捕捉视频与您的应用程序,详见下文。


打开相机 - 使用Camera.open()让相机对象的实例。
连接预览 - 通过使用Camera.setPreviewDisplay一个SurfaceView连接到相机准备现场摄像机图像预览()。
开始预览 - 呼叫Camera.startPreview()开始显示实时摄像机图像。
开始录制视频 - 下面的步骤必须以成功地录制视频完成:
解锁相机 - 通过调用Camera.unlock由MediaRecorder解锁使用相机()。
配置MediaRecorder - 在这个顺序如下MediaRecorder方法调用。欲了解更多信息,请参阅MediaRecorder参考文档。
setCamera() - 设置用于视频拍摄相机,用你的应用程序的当前摄像头的实例。
setAudioSource() - 设置音频信号源,使用MediaRecorder.AudioSource.CAMCORDER。
setVideoSource() - 设置视频信号源,使用MediaRecorder.VideoSource.CAMERA。
设置视频的输出格式和编码。对于Android 2.2的(API级别8)和更高,使用MediaRecorder.setProfile方法,并得到使用CamcorderProfile.get配置文件实例()。对于之前的Andr​​oid 2.2版本,您必须设置视频输出格式和编码参数:
setOutputFormat() - 设置输出格式,指定默认设置或MediaRecorder.OutputFormat.MPEG_4。
setAudioEncoder() - 设置声音编码类型,指定默认设置或MediaRecorder.AudioEncoder.AMR_NB。
setVideoEncoder() - 设置视频编码类型,指定默认设置或MediaRecorder.VideoEncoder.MPEG_4_SP。
setOutputFile() - 设置输出文件,从保存媒体文件部分的示例方法使用getOutputMediaFile(MEDIA_TYPE_VIDEO)的ToString()。
setPreviewDisplay() - 为应用程序指定的SurfaceView预览布局元素。使用您预览连接指定的同一个对象。
注意:您必须调用按以下顺序进行MediaRecorder配置方法,否则你的应用程序将遇到错误,记录将失败。


准备MediaRecorder - 通过调用MediaRecorder.prepare准备与提供的配置设置MediaRecorder()。
开始MediaRecorder - 开始通过调用MediaRecorder.start录像()。
停止录制视频 - 呼叫为了下面的方法,成功地完成视频录制:
停止MediaRecorder - 停止通过调用MediaRecorder.stop录像()。
复位MediaRecorder - 或者,通过调用MediaRecorder.reset删除记录的配置设置()。
发布MediaRecorder - 通过调用MediaRecorder.release松开MediaRecorder()。
锁定相机 - 锁定相机,使未来MediaRecorder会话可以通过调用Camera.lock使用它()。采用Android 4.0(API级别14)开始,除非MediaRecorder.prepare()调用失败,则不需要此调用。
停止预览 - 当你的活动已使用相机结束后,停止使用预览Camera.stopPreview()。
松开相机 - 松开相机,使其他应用程序可以通过调用Camera.release使用它()。
注:可以使用MediaRecorder不首先创建一个摄像头预览和跳过此过程的前几个步骤。然而,由于用户通常喜欢在开始录制前,看到一个预览,这个过程是不是这里讨论。


提示:如果您的应用程序通常用于录制视频,setRecordingHint(布尔),以真正开始预览之前设置。此设置可以帮助减少需要开始录制的时间。


配置MediaRecorder


当使用MediaRecorder类来录制视频,你必须在一个特定的顺序执行的配置步骤,然后调用MediaRecorder.prepare()方法来检查和落实的配置。下面的示例代码演示了如何正确配置,并准备视频录制MediaRecorder类。

private boolean prepareVideoRecorder(){

    mCamera = getCameraInstance();
    mMediaRecorder = new MediaRecorder();

    // Step 1: Unlock and set camera to MediaRecorder
    mCamera.unlock();
    mMediaRecorder.setCamera(mCamera);

    // Step 2: Set sources
    mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
    mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);

    // Step 3: Set a CamcorderProfile (requires API Level 8 or higher)
    mMediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH));

    // Step 4: Set output file
    mMediaRecorder.setOutputFile(getOutputMediaFile(MEDIA_TYPE_VIDEO).toString());

    // Step 5: Set the preview output
    mMediaRecorder.setPreviewDisplay(mPreview.getHolder().getSurface());

    // Step 6: Prepare configured MediaRecorder
    try {
        mMediaRecorder.prepare();
    } catch (IllegalStateException e) {
        Log.d(TAG, "IllegalStateException preparing MediaRecorder: " + e.getMessage());
        releaseMediaRecorder();
        return false;
    } catch (IOException e) {
        Log.d(TAG, "IOException preparing MediaRecorder: " + e.getMessage());
        releaseMediaRecorder();
        return false;
    }
    return true;
}
在此之前的Android 2.2(API等级8),你必须直接设置,而不是使用CamcorderProfile输出格式和编码格式的参数。这种方法被证明在下面的代码:

// Step 3: Set output format and encoding (for versions prior to API Level 8)
    mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
    mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT);
    mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.DEFAULT);
对于MediaRecorder下面的视频录像给定参数的默认设置,但是,您可能需要调整您的应用这些设置:
  • setVideoEncodingBitRate()
  • setVideoSize()
  • setVideoFrameRate()
  • setAudioEncodingBitRate()
  • setAudioChannels()
  • setAudioSamplingRate()

当启动和停止使用MediaRecorder类视频录制,您必须按照特定的顺序,如下所示。
解锁与Camera.unlock相机()
配置MediaRecorder中所示的代码示例以上
开始使用MediaRecorder.start记录()
录制视频
停止使用MediaRecorder.stop记录()
释放与MediaRecorder.release媒体记录器()
锁定使用Camera.lock相机()
下面的示例代码演示了如何把一个按钮,正常启动和使用相机和MediaRecorder类停止视频录制。
注意:当完成视频录制,不要松开相机,否则您的预览将被停止。

private boolean isRecording = false;

// 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) {
            if (isRecording) {
                // stop recording and release camera
                mMediaRecorder.stop();  // stop the recording
                releaseMediaRecorder(); // release the MediaRecorder object
                mCamera.lock();         // take camera access back from MediaRecorder

                // inform the user that recording has stopped
                setCaptureButtonText("Capture");
                isRecording = false;
            } else {
                // initialize video camera
                if (prepareVideoRecorder()) {
                    // Camera is available and unlocked, MediaRecorder is prepared,
                    // now you can start recording
                    mMediaRecorder.start();

                    // inform the user that recording has started
                    setCaptureButtonText("Stop");
                    isRecording = true;
                } else {
                    // prepare didn't work, release the camera
                    releaseMediaRecorder();
                    // inform user
                }
            }
        }
    }
);
注:在上面的例子中,准备视频记录器()方法是指在配置MediaRecorder所示的例子的代码。此方法需要锁定的摄像头,配置和准备MediaRecorder实例的照顾。
松开相机
摄像机是通过在设备上的应用程序共享的资源。应用程序可以让相机的一个实例后,利用摄像头,当你的应用程序停止使用它,你必须特别小心松开相机对象,只要你的应用程序暂停(Activity.onPause())。如果你的应用程序不能正确地释放相机,所有的后续尝试访问摄像机,包括那些由你自己的应用程序,将失败,并可能导致您或其他应用程序被关闭。
为了释放摄像机对象的一个实例,可使用Camera.release()方法,如在下面的例子中的代码。

public class CameraActivity extends Activity {
    private Camera mCamera;
    private SurfaceView mPreview;
    private MediaRecorder mMediaRecorder;

    ...

    @Override
    protected void onPause() {
        super.onPause();
        releaseMediaRecorder();       // if you are using MediaRecorder, release it first
        releaseCamera();              // release the camera immediately on pause event
    }

    private void releaseMediaRecorder(){
        if (mMediaRecorder != null) {
            mMediaRecorder.reset();   // clear recorder configuration
            mMediaRecorder.release(); // release the recorder object
            mMediaRecorder = null;
            mCamera.lock();           // lock camera for later use
        }
    }

    private void releaseCamera(){
        if (mCamera != null){
            mCamera.release();        // release the camera for other applications
            mCamera = null;
        }
    }
}
注意:如果您的应用程序不能正确地释放相机,所有的后续尝试访问摄像机,包括那些由你自己的应用程序,将失败,并可能导致您或其他应用程序被关闭。


保存媒体文件


用户如图片和视频创建的媒体文件保存到设备的外部存储目录(SD卡),以节省系统空间,并允许用户访问这些文件,而他们的设备。有许多可能的目录位置保存在设备上的媒体文件,但只有两个,你应该考虑作为一个开发人员的标准位置:


Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) - 这个方法返回的标准,共享和保存图片和视频推荐位置。该目录是共享(公共),以便其他应用程序可以很容易地发现,读取,修改和删除保存在此位置的文件。如果您的应用程序被用户卸载,保存到这个位置的媒体文件不会被删除。为了避免与用户现有的图片和视频的干扰,你应该把这个目录中创建一个子目录的应用程序的媒体文件,如下面的代码示例所示。这种方法是在Android 2.2的(API级别8)用,在早期版本的API等效调用,请参阅保存共享文件。
Context.getExternalFilesDir(Environment.DIRECTORY_PICTURES) - 这个方法返回保存图片,哪些是与应用程序相关联的视频标准位置。如果你的应用被卸载时,保存在此位置的任何文件将被删除。安全不是强制执行文件中的位置和其他应用程序可以读取,修改和删除它们。
下面的示例代码演示了如何创建可以与一个Intent或建筑物中的摄像头应用程序的一部分调用设备的摄像头时使用媒体文件文件或URI位置。

public static final int MEDIA_TYPE_IMAGE = 1;
public static final int MEDIA_TYPE_VIDEO = 2;

/** Create a file Uri for saving an image or video */
private static Uri getOutputMediaFileUri(int type){
      return Uri.fromFile(getOutputMediaFile(type));
}

/** Create a File for saving an image or video */
private static File getOutputMediaFile(int type){
    // To be safe, you should check that the SDCard is mounted
    // using Environment.getExternalStorageState() before doing this.

    File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(
              Environment.DIRECTORY_PICTURES), "MyCameraApp");
    // This location works best if you want the created images to be shared
    // between applications and persist after your app has been uninstalled.

    // Create the storage directory if it does not exist
    if (! mediaStorageDir.exists()){
        if (! mediaStorageDir.mkdirs()){
            Log.d("MyCameraApp", "failed to create directory");
            return null;
        }
    }

    // Create a media file name
    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
    File mediaFile;
    if (type == MEDIA_TYPE_IMAGE){
        mediaFile = new File(mediaStorageDir.getPath() + File.separator +
        "IMG_"+ timeStamp + ".jpg");
    } else if(type == MEDIA_TYPE_VIDEO) {
        mediaFile = new File(mediaStorageDir.getPath() + File.separator +
        "VID_"+ timeStamp + ".mp4");
    } else {
        return null;
    }

    return mediaFile;
}
注:Environment.getExternalStoragePublicDirectory()是Android 2.2的(API 8级)或更高版本可用。如果你的目标与早期版​​本的Andr​​oid设备,可以使用Environment.getExternalStorageDirectory()代替。欲了解更多信息,请参见保存共享文件。


有关保存在Android设备上的文件的详细信息,请参阅数据存储。


拍照功能


Android支持广泛的相机功能,你可以用你的相机应用程序来控制,比如图片格式,闪光模式,对焦设置,多阵列。本节列出了常见的拍照功能,并简要讨论如何使用它们。大多数拍照功能可以访问和使用通过Camera.Parameters对象设置。然而,也有需要比在Camera.Parameters简单的设置更几个重要特征。这些特征包括在以下部分:


测光和重点领域
人脸检测
时间流逝视频
有关如何使用通过Camera.Parameters控制功能,查看使用相机功能部分的一般信息。有关如何使用通过摄像头的参数控制对象的特点,按照链接的功能列表下方的API参考文档更详细的信息。


表1.常见的拍照功能由它们被引入了Android API级别来分类的。
功能API级别说明
人脸检测识别14的画面中的人脸,并用它们对焦,测光和白平衡
在图像内的计量区14指定一个或多个区域,用于计算白平衡
焦点区14设置的一个或多个区域的图像中要用于焦点
白平衡锁定14停止或启动自动白平衡调整
曝光锁定14停止或启动自动曝光调整
视频快照14拍照而拍摄视频(帧抓取)
与延迟设定时间推移视频录制11帧录制视频经过时间
多个相机9支持多于一个照相机的装置上,其中包括面向前和面向背相机
对焦距离9的报告,似乎是对焦相机和物体之间的距离
放大8集图像放大
曝光补偿8增加或减少曝光水平
GPS数据5包含或省略与图像的地理位置数据
白平衡5设置白平衡模式,从而影响到拍摄的图像中的颜色值
对焦模式5设置相机的对​​焦方式对被摄物体,如自动,固定,微距或无穷
场景模式5应用预设模式为特定类型的摄影的情况下,如夜间,海滩,雪景或烛光场景
JPEG质量5设置为JPEG图像压缩级别,从而增加或减少图像输出文件的质量和大小
闪光模式5打开闪光灯开启,关闭,或使用自动设置
色彩效果5应用颜色效果来拍摄的图像,如黑白,棕褐色调或负。
防5捆扎带减少在颜色渐变的效果,由于JPEG压缩
图片格式1指定的图片文件格式
图片大小1指定保存的图片的像素尺寸
注意:这些功能不会因硬件差异和软件实现支持的所有设备。有关检查的在您的应用程序运行在设备上功能的可用性信息,请参见检查功能的可用性。


检查功能的可用性


首先要明白什么时候列明在Android设备上使用摄像功能是,并非所有的摄像头功能都支持的所有设备。此外,支持特定功能的设备可以将它们支持不同级别或具有不同的选择。因此,当你开发一个摄像头应用程序的决策过程的一部分,是决定你要支持到什么级别什么相机功能。作出该决定后,你应该包括检查,看看你的相机应用程序代码计划,如果硬件设备支持这些功能和优雅的失败,如果一个功能不可用。


你可以得到一个摄像头的参数对象的实例,并检查相关的方法检查相机功能的库存状况。下面的代码示例显示了如何获得Camera.Parameters对象,并检查摄像头支持自动对焦功能:

// get Camera parameters
Camera.Parameters params = mCamera.getParameters();

List<String> focusModes = params.getSupportedFocusModes();
if (focusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO)) {
  // Autofocus mode is supported
}
您可以使用相机的大部分功能上面显示的技术。该Camera.Parameters对象提供了一个getSupported ...(),是...支持()或GetMax的...()方法来判断是否(以及在多大程度上)功能的支持。


如果应用程序需要为了正常运行一定的拍照功能,您可以要求他们通过增加的应用程序清单。在声明中使用特定的拍照功能,如闪光灯和自动对焦,谷歌播放被安装在不支持这些功能的设备限制了您的应用程序。有关可在应用清单中声明的​​拍照功能列表,请参阅清单功能参考。


使用相机功能


大多数相机功能被激活,使用Camera.Parameters对象控制。通过先获取Camera对象的实例,调用getParameters()方法,改变了返回的参数对象,然后将它设置回相机对象,如下面的代码示例演示获取该对象:

// get Camera parameters
Camera.Parameters params = mCamera.getParameters();
// set the focus mode
params.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
// set Camera parameters
mCamera.setParameters(params);
这种技术适用于几乎所有的拍照功能,而且大多数参数可以在任何时候,你已经获得了摄像机对象的实例后更改。变更参数通常可见于在应用程序的相机预览立即给用户。在软件方面,参数的修改可能需要几帧实际生效的摄像头硬件处理新的指令,然后发送更新的图像数据。


要点:某些相机功能,不能随意更改。特别是,改变摄像头预览的大小和方向,您需要先停止预览,改变预览大小,然后重新启动预览。采用Android 4.0(API等级14)预览方向出发而不需要重新启动预览改变。


其他摄像功能需要更多的代码才能实现,其中包括:


测光和重点领域
人脸检测
时间流逝视频
如何实现这些功能的快速大纲在下面的章节提供。


测光和重点领域


在某些情况下拍摄,自动对焦和测光可能不会产生预期的效果。采用Android 4.0开始(API等级14),你的相机应用程序可以提供额外的控制,让您的应用程序或用户的图像中的指定区域捕捉用于确定焦点或轻级别的设置,并通过这些值的摄像头硬件使用图像或视频。


计量和重点工作非常相似的其他的拍照功能,在你控制他们通过在Camera.Parameters方法方面反对。下面的代码演示了相机的一个实例设置两个光测光方面:

// Create an instance of Camera
mCamera = getCameraInstance();

// set Camera parameters
Camera.Parameters params = mCamera.getParameters();

if (params.getMaxNumMeteringAreas() > 0){ // check that metering areas are supported
    List<Camera.Area> meteringAreas = new ArrayList<Camera.Area>();

    Rect areaRect1 = new Rect(-100, -100, 100, 100);    // specify an area in center of image
    meteringAreas.add(new Camera.Area(areaRect1, 600)); // set weight to 60%
    Rect areaRect2 = new Rect(800, -1000, 1000, -800);  // specify an area in upper right of image
    meteringAreas.add(new Camera.Area(areaRect2, 400)); // set weight to 40%
    params.setMeteringAreas(meteringAreas);
}

mCamera.setParameters(params);
该Camera.Area对象包含两个数据参数:一个矩形对象指定的摄像机视场之内的区域和权重值,它告诉相机什么水平的重要性这一领域应测光给予或聚焦计算。

在一个Camera.Area对象的矩形字段描述映射到一个2000×2000单元格具有矩形形状。坐标-1000,-1000表示的顶部,在摄像机图像的左上角和坐标1000,1000代表的底部,在摄像机图像的右下角,如下面的插图。


图1.红线示出了用于一个相机预览内指定Camera.Area的坐标系。蓝色框显示与矩形的摄像头区域的位置和形状值333333667667。


这个坐标系的边界总是对应于图像中的相机预览可见的外边缘,并且不收缩或与缩放级别扩大。同样,图像预览的旋转使用Camera.setDisplayOrientation()不重新映射的坐标系。


人脸检测


的图片,包括人,面通常是图像的最重要的部分,并且应该被用于拍摄图像时确定两个聚焦和白平衡。而Android 4.0(API等级14)框架提供了识别人脸和计算使用脸部识别技术的图像设置的API。


注:当人脸检测功能运行时,setWhiteBalance(字符串),setFocusAreas(列表)和setMeteringAreas(列表)没有任何效果。


在相机应用程序中使用人脸检测功能需要几个基本步骤:


检查脸部检测设备支持的
创建人脸检测监听器
人脸检测监听器添加到您的相机对象
启动人脸检测后预览(每预览重启后)
人脸检测功能不支持的所有设备。您可以检查此功能是通过调用getMaxNumDetectedFaces支持()。这个检查的一个例子显示在下面的startFaceDetection()样品的方法。


在被通知秩序,并在检测到面部的回复,您的摄像头应用程序必须设置人脸检测事件的监听器。为了做到这一点,必须创建一个实现Camera.FaceDetectionListener界面显示在下面的示例代码监听器类。

class MyFaceDetectionListener implements Camera.FaceDetectionListener {

    @Override
    public void onFaceDetection(Face[] faces, Camera camera) {
        if (faces.length > 0){
            Log.d("FaceDetection", "face detected: "+ faces.length +
                    " Face 1 Location X: " + faces[0].rect.centerX() +
                    "Y: " + faces[0].rect.centerY() );
        }
    }
}
创建这个类之后,然后将其设置到应用程序的Camera对象,如下面的示例代码:

mCamera.setFaceDetectionListener(new MyFaceDetectionListener());
您的应用程序每次启动时必须启动人脸检测功能(或重新启动)的摄像头预览。创建启动人脸检测,所以你可以把它根据需要,如下面的示例代码的方法。

public void startFaceDetection(){
    // Try starting Face Detection
    Camera.Parameters params = mCamera.getParameters();

    // start face detection only *after* preview has started
    if (params.getMaxNumDetectedFaces() > 0){
        // camera supports face detection, so can start it:
        mCamera.startFaceDetection();
    }
}
你必须每次启动时启动人脸检测(或重新启动)的摄像头预览。如果您在创建预览类显示预览类中,添加在预览类的startFaceDetection()方法既surfaceCreated()和surfaceChanged()方法,如下面的示例代码。

public void surfaceCreated(SurfaceHolder holder) {
    try {
        mCamera.setPreviewDisplay(holder);
        mCamera.startPreview();

        startFaceDetection(); // start face detection feature

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

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

    if (mHolder.getSurface() == null){
        // preview surface does not exist
        Log.d(TAG, "mHolder.getSurface() == null");
        return;
    }

    try {
        mCamera.stopPreview();

    } catch (Exception e){
        // ignore: tried to stop a non-existent preview
        Log.d(TAG, "Error stopping camera preview: " + e.getMessage());
    }

    try {
        mCamera.setPreviewDisplay(mHolder);
        mCamera.startPreview();

        startFaceDetection(); // re-start face detection feature

    } catch (Exception e){
        // ignore: tried to stop a non-existent preview
        Log.d(TAG, "Error starting camera preview: " + e.getMessage());
    }
}
注意:请记住调用startPreview后调用此方法()。不要尝试启动人脸检测在相机应用程序的主活动的onCreate()方法,为预览不可用在您的应用程序这一点是执行。


时间流逝视频


视频经过时间允许用户创建,结合采取了数秒或数分钟除了图片视频剪辑。此功能使用MediaRecorder来记录影像的时间间隔序列。


要录制MediaRecorder时间推移视频,您必须配置记录对象,如果您正在录制一个正常的视频,每秒捕获的帧设置为较低的数量和使用的时间间隔质量设置之一,如图所示的代码示例 下面。

// Step 3: Set a CamcorderProfile (requires API Level 8 or higher)
mMediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_TIME_LAPSE_HIGH));
...
// Step 5.5: Set the video capture rate to a low number
mMediaRecorder.setCaptureRate(0.1); // capture a frame every 10 seconds
这些设置必须为MediaRecorder较大的配置过程的一部分来完成。对于一个完整的配置代码示例,请参阅配置MediaRecorder。一旦配置完成后,你就开始录像,如果你是录制正常的视频剪辑。有关配置和运行MediaRecorder的更多信息,请参见捕获视频。

你可能感兴趣的:(java,android,api,sdk,Camera)