Android 有关Camera的应用

Camera

版本:Android 4.0r1

在本文中

需要考虑的问题

概述

Manifest声明

使用内置的摄像头应用程序

捕获图像的intent

捕获视频的intent

接收摄像头intent的结果

创建摄像头应用程序

检测摄像头硬件

访问摄像头

检查摄像头feature

创建预览类

将预览画面置入layout

捕获图像

捕获视频

释放摄像头

保存媒体文件

关键类

Camera

SurfaceView

MediaRecorder

Intent

参阅

Camera

MediaRecorder

数据存储

Android框架包含了对多种摄像头和摄像特性的支持,应用程序可以进行图片和视频的捕获。本文讨论了一种快速、简便的捕获图像和视频的方法,并简述了一种更高级的可为用户创建自定义摄像功能的方法。

需要考虑的问题

在让应用程序使用Android设备的摄像头之前,应该考虑一些期望如何使用此硬件的问题。

  • 摄像头需求——摄像头的使用对于应用程序是否确实如此重要,以至于在没有摄像头的设备上就不期望安装此应用了?如果确实如此,应该在manifest中声明摄像头需求
  • 快速拍照还是自定义摄像——应用程序如何使用摄像头?仅仅是对快速拍照和视频片段感兴趣,还是要提供一种使用摄像头的新方式?对于快速拍照和摄像而言,可以考虑使用内置的摄像头应用 。为了开发一种定制的摄像头功能,请查看创建摄像头应用 一节。
  • 存储——应用程序产生的图像和视频是否期望仅对自身可见,还是可以共享——以便相册或其它媒体应用也能够使用?当应用程序被卸载后,还期望图像和视频可用么?请查看保存媒体文件 一节来了解如何实现这些选项。

概述

通过  Camera API或摄像头意图  Intent ,Android框架为图像和视频捕获提供支持。下面列出了有关的类:
Camera
此类是控制摄像头的主要API。在创建摄像头应用程序时,此类用于拍摄照片或视频。
SurfaceView
此类用于向用户提供摄像头实时预览功能。
MediaRecorder
此类用于从摄像头录制视频。
Intent
动作类型为 MediaStore.ACTION_IMAGE_CAPTUREMediaStore.ACTION_VIDEO_CAPTURE的意图, 可在不直接使用 Camera对象的情况下捕获图像和视频。

Manifest声明

开始开发摄像头API的应用之前,应该确保已经在manifest中正确声明了对摄像头的使用及其它相关的feature。

  • Camera权限——应用程序必须对请求摄像头的使用权限。
    <uses-permission android:name =  "android.permission.CAMERA" />

    注意:如果是 通过意图 来使用摄像头的,应用程序就不必请求本权限。

  • Camera Feature——应用程序必须同时声明对camerafeature的使用,例如:
    <uses-feature android:name =  "android.hardware.camera" />

    关于摄像头feature的清单,参阅manifest Feature参考

    在manifest中加入camerafeature,将会使得AndroidMarket在没有摄像头或不支持指定feature的设备上禁止安装该应用程序。关于AndroidMarket基于feature过滤的使用详情,请参阅Android Market和基于Feature的过滤

    如果应用程序可能用到摄像头或摄像头feature,但却不是必需的,则应在manifest中指定包含android:required属性的feature,并将该属性设为false

    <uses-feature android:name =  "android.hardware.camera" android:required  = "false"  />
  • 存储权限——如果应用程序要把图像或视频保存到设备的外部存储上(SD卡),则还必须在>manifest中指定如下权限。

    <uses-permission android:name =  "android.permission.WRITE_EXTERNAL_STORAGE" />
  • 录音权限——要用音频捕获来录音,应用程序必须请求音频捕获权限。

    <uses-permission android:name =  "android.permission.RECORD_AUDIO" />
使用内置的摄像头应用程序

有一种快捷的方法可以让应用程序不用额外编写很多代码就能实现拍照或摄像,这就是用意图 Intent来调用内置的Android摄像头应用程序。摄像头intent会请求通过内置摄像应用来捕获图像或视频,并把控制权返回给应用程序。本节展示了如何用这种方法来捕获图像。

通常按以下步骤来提交一个摄像头intent:

  • 构建一个摄像头Intent——用以下意图类型之一,创建一个请求图像或视频的Intent
  • 启动摄像头Intent——用 startActivityForResult()方法执行摄像头intent。启动完毕后摄像头应用的用户界面就会显示在屏幕上,用户就可以拍照或摄像了。
  • 接收Intent结果——在应用程序中设置 onActivityResult()方法,用于接收从摄像头intent返回的数据。当用户拍摄完毕后(或者取消操作),系统会调用此方法。

捕获图像的intent

如果希望程序以最少的代码实现拍照功能,利用摄像头intent捕获图像是一条捷径。图像捕捉intent还可以包含以下附加信息:

  • MediaStore.EXTRA_OUTPUT——本设置需要一个Uri对象,用于指定存放图片的路径和文件名。本设置是可选项,但强烈建议使用。如果未指定本设置值,那么摄像应用将会把所请求的图片以默认文件名和路径进行保存,并将数据置入intent的Intent.getData()部分返回。

以下例子演示了如何构建并执行一个图像捕获intent。此例中的getOutputMediaFileUri() 方法引自保存媒体文件中的例程代码。

private static final intCAPTURE_IMAGE_ACTIVITY_REQUEST_CODE=100;

private Uri fileUri;

@Override

public void onCreate(Bundle savedInstanceState){

 super.onCreate(savedInstanceState);

  setContentView(R.layout.main);

  //创建拍照Intent并将控制权返回给调用的程序

  Intentintent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);

  fileUri =getOutputMediaFileUri(MEDIA_TYPE_IMAGE);

 //创建保存图片的文件

  intent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri);

 //设置图片文件名

  //启动图像捕获Intent

  startActivityForResult(intent,CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE);

}

startActivityForResult()方法执行完毕后,用户将看到内置摄像头应用程序的界面。用户拍照完毕(或取消操作)后,用户界面返回应用程序,这时必须截获onActivityResult() 方法来接收intent的返回结果并执行后续操作。关于如何接收完整的intent,请参阅接收摄像头Intent的结果

捕获视频的intent

如果希望程序以最少的代码实现摄像功能,利用摄像头intent捕获视频是一条捷径。视频捕捉intent可以包含以下附带信息:

  • MediaStore.EXTRA_OUTPUT——本设置需要一个Uri,用于指定保存视频的路径和文件名。本设置是可选项,但强烈建议使用。如果未指定本设置值,那么摄像应用将会把所请求的视频以默认文件名和路径进行保存,并将数据置入intent的Intent.getData() 部分返回。
  • MediaStore.EXTRA_VIDEO_QUALITY——本值用0表示最低品质及最小的文件尺寸,用1表示最高品质和较大的文件尺寸。
  • MediaStore.EXTRA_DURATION_LIMIT——本值用于限制所捕获视频的长度,以秒为单位。
  • MediaStore.EXTRA_SIZE_LIMIT——本值用于限制所捕获视频的文件尺寸,以字节为单位。

以下例子演示了如何构建并执行一个视频捕获intent。本例中的getOutputMediaFileUri()方法引自保存媒体文件中的例程代码。

private static final intCAPTURE_VIDEO_ACTIVITY_REQUEST_CODE =200;

private Uri fileUri;

@Override

public voidonCreate(BundlesavedInstanceState){

 super.onCreate(savedInstanceState);

  setContentView(R.layout.main);

 //创建新的Intent

  intent new Intent(MediaStore.ACTION_VIDEO_CAPTURE);

  fileUri =getOutputMediaFileUri(MEDIA_TYPE_VIDEO);

 //创建保存视频的文件

  intent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri);

 //设置视频文件名

  intent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY,1);

 //设置视频的品质为高

  //启动视频捕获Intent

  startActivityForResult(intent,CAPTURE_VIDEO_ACTIVITY_REQUEST_CODE);

}

startActivityForResult()方法执行完毕后,用户将看到一个改动过的摄像程序界面。用户摄像完毕(或取消操作)后,用户界面返回应用程序,这时必须截获onActivityResult()方法来接收intent的返回结果并执行后续操作。关于如何接收完整的intent,请参阅下一节。

接收摄像头的结果

一旦已构建并运行了图像或视频的摄像头intent,应用程序就必须进行设置,以接收intent返回的结果。本节展示了如何截获摄像头intent的回调方法,以便应用程序对捕获到的图片及视频进行进一步的处理。

要接收intent的返回结果,必须覆盖启动intent的activity中的 onActivityResult()方法。以下例子演示了如何覆盖onActivityResult()来获取上述章节例程中的 图像捕获intent或 视频捕获intent的结果。

private static final intCAPTURE_IMAGE_ACTIVITY_REQUEST_CODE =100;

private static final intCAPTURE_VIDEO_ACTIVITY_REQUEST_CODE =200;

@Override protected voidonActivityResult(intrequestCode,intresultCode,Intentdata){

   if(requestCode==CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE) {

      if (resultCode==RESULT_OK) {

          //捕获的图像保存到Intent指定的fileUri

          Toast..makeText(this,"Imagesaved to:n"+

       data.getData(),Toast.LENGTH_LONG).show();

    }

       elseif (resultCode==RESULT_CANCELED) {

       //用户取消了图像捕获

   else {

   //图像捕获失败,提示用户

    }

  }

  if(requestCode==CAPTURE_VIDEO_ACTIVITY_REQUEST_CODE) {

     if (resultCode==RESULT_OK) {

     //捕获的视频保存到Intent指定的fileUri

     Toast.makeText(this,"Videosaved to:n" +

       data.getData();

      Toast.LENGTH_LONG).show();

        }

      else  if (resultCode == RESULT_CANCELED){

      //用户取消了视频捕获

    }

   else {

   //视频捕获失败,提示用户

    }

  }

}

一旦activity接收到成功的结果,就说明捕获到的图像或视频已保存到指定位置了,应用程序就可对其进行访问。

创建摄像头应用程序

有些开发人员可能需要自定义外观的摄像头用户界面,或者需要提供特殊的功能。相比 使用intent而言,创建定制的摄像activity需要编写更多的代码,不过也能向用户提供更吸引人的使用感受。

通常按照以下步骤创建一个定制的摄像界面:

  • 检测并访问摄像头——创建代码以检查摄像头存在与否并请求访问。
  • 创建预览类——创建继承自 SurfaceView 并实现 SurfaceHolder 接口的摄像预览类。此类能预览摄像的实时图像。
  • 建立预览Preview Layout——一旦有了摄像预览类,即可创建一个viewlayout,用于把预览画面与设计好的用户界面控件融合在一起。
  • 为捕获设置侦听器Listener——将用户界面控件连接到listener,使其能响应用户操作开始捕获图像或视频,比如按下按钮。
  • 捕获并保存文件——建立捕获图片或视频并保存到输出文件的代码。
  • 释放摄像头——摄像头使用完毕后,应用程序必须正确地将其释放,便于其它程序的使用。

摄像头硬件是一个共享资源,必须对其进行精心管理,因此需要使用它的应用程序之间不能发生冲突。下一节将会讨论如何检测摄像头硬件、如何请求访问摄像头、使用完毕如何释放。

警告:应用程序用完摄像头后,请记得调用 Camera.release() 释放 Camera对象!如果某应用程序未能正确释放摄像头,所有后续访问摄像头的尝试(包括此应用程序自身)都将会失败,并可能导致程序被强行关闭。

检测摄像头硬件

如果应用程序未利用manifest声明对摄像头需求进行特别指明,则应该在运行时检查一下摄像头是否可用。可用PackageManager.hasSystemFeature() 方法来进行这种检查,代码示例如下:

private   boolean checkCameraHardware(Context  context) {

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

      //摄像头存在

      returntrue;

    }

   else {

      //摄像头不存在

      return  false;

   }

}

Android设备可能拥有多个摄像头,比如后置摄像头用于拍照、前置摄像头用于摄像。Android 2.3 (API Level9)以上版本允许利用 Camera.getNumberOfCameras()方法来检查设备可用摄像头的数量。

访问摄像头

如果在运行程序的设备上已经检测到了摄像头,则必须通过获取一个 Camera的实例来请求对其访问(除非使用了 用于访问摄像头的intent)。

可用Camera.open()方法来访问主摄像头,并确保捕获全部的异常,示例代码如下:

public  static Camera getCameraInstance(){

Camera c=null;

   try {

       c=Camera.open();//试图获取Camera实例

    }

    catch(Exceptione){

      //摄像头不可用(正被占用或不存在)

    }

    returnc;//不可用则返回null

}

警告:每次使用 Camera.open()时都要检查异常。如果摄像头被占用或者不存在,未检查异常将会导致应用程序被系统强行关闭。

在运行Android   2.3 (API   Level  9)以上版本的设备上,可以用 Camera.open(int)访问指定的摄像头。在拥有多于一个摄像头的设备上,以上示例代码将会访问第一个也即朝后的那个摄像头。

检查摄像头feature

一旦获得了摄像头的访问权,就可以通过 Camera.getParameters()方法来获取更多信息,检查返回的Camera.Parameters对象可查看摄像头所支持的feature。如果正在使用API  Level   9以上版本,可用Camera.getCameraInfo()来确定摄像头朝前还是朝后以及图像的方向。

创建预览类

为了方便拍照或摄像,用户必须能看到摄像头所拍摄的画面。摄像头预览类就是一种能够显示摄像头实时数据的SurfaceView,用户可以调整并捕获图片和视频。

以下示例代码演示了如何创建一个基本的摄像头预览类,它可被嵌入一个 View布局中。为了截获view创建和销毁时的回调事件,此类实现了SurfaceHolder.Callback,这在指定摄像头预览的输入时需要用到。

public   class  CameraPreview extends SurfaceView implements SurfaceHolder.Callback{

    private SurfaceHolder mHolder;

    private Camera   mCamera;

    public CameraPreview   Context  context,Camera  camera {

      super (context);

       mCamera =camera;

      //安装一个SurfaceHolder.Callback,

      //这样创建和销毁底层surface时能够获得通知。

       mHolder = getHolder();

       mHolder.addCallback(this);

      //已过期的设置,但版本低于3.0的Android还需要用到。

       mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

    }

    public void  surfaceCreated(SurfaceHolder  holder) {

      //surface已被创建,现在把预览画面的位置通知摄像头

      try {

          mCamera.setPreviewDisplay(holder);

          mCamera.startPreview();

      }catch  (IOException  e) {

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

      }

    }

    public  void  surfaceDestroyed(SurfaceHolderholder){

      //空代码。注意在activity中释放摄像头预览对象

    }

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

      //如果预览无法更改或旋转,注意此处的事件

      //确保在缩放或重排时停止预览

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

        // 预览surface不存在

        return;

       }

      //更改时停止预览

      try{

          mCamera.stopPreview();

      }catch(Exception  e){

        // 忽略:试图停止不存在的预览

      }

      //在此进行缩放、旋转和重新组织格式

      //以新的设置启动预览

      try{

          mCamera.setPreviewDisplay(mHolder);

          mCamera.startPreview();

      }catch(Exception   e){

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

      }

    }

}

将预览画面置入layout

上节例程所述的摄像预览类必须被放入一个activity的layout中,连同其它用户界面控件一起,实现拍照或摄像功能。本节展示了如何为预览创建一个简单的layout和activity。

以下layout代码提供了一个非常简单的view,用于显示一个摄像预览画面。在此例中,FrameLayout元素用于容纳摄像预览类。利用此类layout,可以把附加的图片信息或控件叠加到实时预览画面上。

<?xmlversion="1.0"encoding="utf-8"?> 

<LinearLayoutxmlns: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>

在大多数设备上,缺省的摄像预览方向是横向的。此例中的layout指定了横向(landscape)布局,下面的代码还把应用程序的方向也改为了横向。为了简化摄像预览画面的刷新,应该在manifest中增加如下内容,把应用程序的预览activity也改为横向显示。

<activityandroid:name=".CameraActivity" 

         android:label="@string/app_name" 

         android:screenOrientation="landscape"> 

   <!-- configure this activity to uselandscape orientation--> 

   <intent-filter> 

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

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

    </intent-filter> 

</activity>

注意:摄像预览画面并不是一定要横向显示。自Android2.2 (API Level 8)开始,可以利用setDisplayOrientation()方法来旋转预览画面。为了让预览方向跟随手机方向的变化而改变,可以在预览类的surfaceChanged()方法中实现,先用Camera.stopPreview()停止预览,改变方向后再用Camera.startPreview()开启预览。

在摄像view的activity中,请把预览类添加到上述的FrameLayout元素中。当摄像头暂停使用或者关闭时,摄像activity还必须确保将其释放。以下例子展示了如何修改摄像activity,加入创建预览类所述的预览类。

publicclassCameraActivityextendsActivity

    privateCameramCamera; 

    privateCameraPreviewmPreview; 

    @Override 

    publicvoidonCreate(BundlesavedInstanceState){ 

       super.onCreate(savedInstanceState); 

      setContentView(R.layout.main); 

 

       //创建Camera实例 

       mCamera =getCameraInstance(); 

 

       //创建Preview view并将其设为activity中的内容

       mPreview =newCameraPreview(this,mCamera); 

       FrameLayoutpreview=(FrameLayout)findViewById(id.camera_preview); 

      preview.addView(mPreview); 

   

}

注意:上例中的getCameraInstance()方法引用了访问摄像头中的方法示例。

 

捕获图像

一旦创建了预览类和显示它的viewlayout,就可以开始在程序中捕获图片了。必须在程序代码中为用户界面控件设置listener,使其可响应用户操作进行拍照。

可以通过Camera.takePicture()方法来获取图片,此方法用到三个参数并从摄像头接收数据。如果要以JPEG的格式接收数据,必须实现Camera.PictureCallback接口,以接收图片数据并写入文件。以下代码展示了Camera.PictureCallback接口的简单例子,实现了从摄像头接收图片并保存。

privatePictureCallbackmPicture=newPictureCallback(){ 

 

    @Override 

    publicvoidonPictureTaken(byte[]data,Cameracamera){ 

 

       FilepictureFile=getOutputMediaFile(MEDIA_TYPE_IMAGE); 

       if(pictureFile==null){ 

          Log.d(TAG,"Errorcreating media file, check storage permissions:"

             e.getMessage()); 

          return

      

 

       try

          FileOutputStreamfos=newFileOutputStream(pictureFile); 

          fos.write(data); 

          fos.close(); 

       }catch(FileNotFoundExceptione){ 

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

       }catch(IOExceptione){ 

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

      

   

};

通过调用Camera.takePicture()方法,触发器捕获了一张图片。以下例程展示了如何在按钮View.OnClickListener的中调用此方法。

// Capture按钮中加入listener 

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

   captureButton.setOnClickListener( 

       newView.OnClickListener(){ 

       @Override 

       publicvoidonClick(Viewv){ 

          //从摄像头获取图片

          mCamera.takePicture(null,null,mPicture); 

      

   

);

注意:下文例程中的mPicture成员将会引用上述代码。

警告:当应用程序使用完摄像头之后,请记得调用Camera.release()释放Camera对象!关于如何释放摄像头的详情,请参阅释放摄像头

 

捕获视频

Android框架的视频捕捉需要对Camera对象进行仔细的管理,还要与MediaRecorder类一起协同工作。使用Camera录制视频时,必须管理好Camera.lock()Camera.unlock()的调用,使得MediaRecorder能够顺利访问摄像头硬件,并且还要进行Camera.open()Camera.release()调用。

注意:自Android 4.0 (API level14)开始,Camera.lock()Camera.unlock()调用由系统自动管理。

与用摄像头拍照不同,视频捕获必需十分精确地按顺序进行调用。必须按照特定的顺序来执行,应用程序才能成功地准备并捕获视频,详细步骤如下。

 

配置MediaRecorder

在使用MediaRecorder类进行录像时,必须先按照特定顺序进行配置,然后调用MediaRecorder.prepare()方法检查并执行这些配置。以下例程演示了如何为录像正确配置并准备MediaRecorder类。

privatebooleanprepareVideoRecorder(){ 

 

    mCamera=getCameraInstance(); 

    mMediaRecorder=newMediaRecorder(); 

 

    // 1步:解锁并将摄像头指向MediaRecorder

   mCamera.unlock(); 

   mMediaRecorder.setCamera(mCamera); 

 

    // 2步:指定源

   mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER); 

   mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA); 

 

    // 3步:指定CamcorderProfile(需要API Level8以上版本)

   mMediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH)); 

 

    // 4步:指定输出文件

   mMediaRecorder.setOutputFile(getOutputMediaFile(MEDIA_TYPE_VIDEO).toString()); 

 

    // 5步:指定预览输出

   mMediaRecorder.setPreviewDisplay(mPreview.getHolder().getSurface()); 

 

    // 6步:根据以上配置准备MediaRecorder 

    try

      mMediaRecorder.prepare(); 

   }catch(IllegalStateExceptione){ 

       Log.d(TAG,"IllegalStateExceptionpreparing MediaRecorder: "+e.getMessage()); 

      releaseMediaRecorder(); 

       returnfalse

   }catch(IOExceptione){ 

       Log.d(TAG,"IOExceptionpreparing MediaRecorder: "+e.getMessage()); 

      releaseMediaRecorder(); 

       returnfalse

   

    returntrue

}

如果是Android 2.2 (API Level 8)之前的版本,则必须直接指定输出格式和编码格式,而不是使用CamcorderProfile。以下代码演示了这种方式:

    // 3步:设置输出格式和编码格式(针对低于API Level 8版本)

   mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4); 

   mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT); 

   mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.DEFAULT);

MediaRecorder中以下有关视频录制的参数都给出了缺省值,当然也可以在应用程序中修改这些设置:

开始和停止MediaRecorder

使用MediaRecorder类开始和停止视频录制时,必须遵循以下特定顺序。

以下例程演示了如何触发按钮并用camera和MediaRecorder类正确地开始和停止视频录制。

注意:视频录制完毕后请不要释放camera,否则预览将会停止。

privatebooleanisRecording=false

 

// Capture按钮加入listener

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

captureButton.setOnClickListener( 

    newView.OnClickListener(){ 

       @Override 

       publicvoidonClick(Viewv){ 

          if(isRecording){ 

              // 停止录像并释放camera 

             mMediaRecorder.stop(); //停止录像

             releaseMediaRecorder();//释放MediaRecorder对象

             mCamera.lock();      //将控制权从MediaRecorder 交回camera

 

              // 通知用户录像已停止

             setCaptureButtonText("Capture"); 

              isRecording=false

          }else

              // 初始化视频camera 

              if(prepareVideoRecorder()){ 

                 //Camera已可用并解锁,MediaRecorder已就绪,

                 //现在可以开始录像

                mMediaRecorder.start(); 

 

                 //通知用户录像已开始

                setCaptureButtonText("Stop"); 

                 isRecording=true

             }else

                 //准备未能完成,释放camera 

                releaseMediaRecorder(); 

                 //通知用户

             

          

      

   

);

注意:在上例中,prepareVideoRecorder()方法引用了配置MediaRecorder.中的示例代码。此方法实现了锁定camera、配置和准备MediaRecorder实例。

 

释放摄像头

摄像头是设备上所有应用程序共享使用的资源。应用程序可以在获得Camera实例后使用摄像头,停止使用后请务必注意释放摄像头对象,应用程序暂停时(Activity.onPause())也是如此。如果某应用程序未能正确地释放摄像头,则所有后续访问摄像头的尝试(包括该应用程序自身)都将会失败,并可能导致应用程序被强行关闭。

Camera.release()方法可以释放Camera对象的实例,代码示例如下。

publicclassCameraActivityextendsActivity

    privateCameramCamera; 

    privateSurfaceViewmPreview; 

    privateMediaRecordermMediaRecorder; 

    ...

@Override

   protected  void  onPause(){

      super.onPause(); 

      releaseMediaRecorder();//如果正在使用MediaRecorder,首先需要释放它。

       releaseCamera();      //在暂停事件中立即释放摄像头

   

 

    privatevoidreleaseMediaRecorder(){ 

       if(mMediaRecorder!=null){ 

          mMediaRecorder.reset(); // 清除recorder配置

          mMediaRecorder.release();//释放recorder对象

          mMediaRecorder =null

          mCamera.lock();        // 为后续使用锁定摄像头

      

   

 

    privatevoidreleaseCamera(){ 

       if(mCamera!=null){ 

          mCamera.release();      //为其它应用释放摄像头

          mCamera =null

      

   

}

警告:如果某应用程序未能正确释放摄像头,所有后续访问摄像头的尝试(包括该应用程序自身)都将会失败,并可能会导致应用程序被强行关闭。

 

诸如图片和视频这些由用户创建的媒体文件,应该保存到设备外部存储的目录中(SD卡)去,以节省系统空间,并使用户离开设备时也能访问这些文件。设备上有很多可用于存储媒体文件的目录,但作为开发人员只应考虑两个标准的位置:

·      Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)——本方法返回标准的、共享的、系统建议的存放位置,用于存放图片和视频文件。本目录是共享的(public),因此其它应用程序可以很容易地查找、读取、修改、删除存于此处的文件。即使应用程序被用户卸载,存于此处的媒体文件也不会被删除。为了避免与已有的图片和视频相冲突,应该在此目录下为自己的媒体文件创建一个子目录,如下代码所示。本方法自Android2.2 (API Level 8)起启用,更早API版本的也有类似的调用,请参阅保存共享文件

·      Context.getExternalFilesDir(Environment.DIRECTORY_PICTURES)——本方法返回一个标准的、用于存放图片和视频的位置,该存放位置与应用程序相关联。如果应用程序被卸载,则存于此处的文件将会被删除。对存于此处的文件不会增加访问权限控制,其它应用程序也可以读取、修改、删除文件。

以下例程演示了如何为媒体文件创建一个FileUri存放位置,通过Intent调用摄像头时可以使用该文件,创建摄像应用时也可以使用它。

publicstaticfinalintMEDIA_TYPE_IMAGE=1

publicstaticfinalintMEDIA_TYPE_VIDEO=2

 

privatestaticUrigetOutputMediaFileUri(inttype){ 

     returnUri.fromFile(getOutputMediaFile(type)); 

 

privatestaticUrigetOutputMediaFile(inttype){ 

    // 安全起见,在使用前应该

    // Environment.getExternalStorageState()检查SD卡是否已装入

 

    File mediaStorageDir=newFile(Environment.getExternalStoragePublicDirectory( 

            Environment.DIRECTORY_PICTURES),"MyCameraApp"); 

// 如果期望图片在应用程序卸载后还存在、且能被其它应用程序共享,

// 则此保存位置最合适

 

    // 如果不存在的话,则创建存储目录

    if(!mediaStorageDir.exists()){ 

       if(!mediaStorageDir.mkdirs()){ 

          Log.d("MyCameraApp","failedto createdirectory"); 

          returnnull

      

   

    // 创建媒体文件名

    String timeStamp=newSimpleDateFormat("yyyyMMdd_HHmmss").format(newDate()); 

    FilemediaFile; 

    if(type==MEDIA_TYPE_IMAGE){ 

       mediaFile =newFile(mediaStorageDir.getPath()+File.separator+ 

       "IMG_"+timeStamp+".jpg"); 

   }elseif(type==MEDIA_TYPE_VIDEO){ 

       mediaFile =newFile(mediaStorageDir.getPath()+File.separator+ 

       "VID_"+timeStamp+".mp4"); 

   }else

       returnnull

   

    returnmediaFile; 

}

注意:Environment.getExternalStoragePublicDirectory()自Android2.2 (API Level 8)版本启用。如果目标设备使用较早期版本的Android,请用Environment.getExternalStorageDirectory()代替。详情请参阅保存共享文件

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值