原文地址: http://developer.android.com/intl/zh-cn/guide/topics/media/camera.html#considerations
Android框架提供了对各种相机以及设备提供的相机功能的支持,让你可以在你的应用中获取照片和视频。本文档讨论了一种简单快速的获取照片和视频的方法,并描述了一种可以让你为你的客户创建自定义相机的先进方法。
在允许你的应用程序使用相机之前,你应该考虑你的应用程序要用相机来干什么:
android.hardware.camera2这个package是操作相机的主要API。当你开发相机应用时可以用它来获取照片和视频。
Camera这个类已经过期。
SurfaceView这个类是用来向用户提供实时预览的。
MediaRecorder这个类可以从相机中记录视频。
Intent你可以通过MediaStore.ACTION_IMAGE_CAPTURE和MediaStore.ACTION_VIDEO_CAPTURE获取照片和视频而不需要直接使用相机对象。
<uses-permission android:name="android.permission.CAMERA" />
Note:如果你是通过Intent使用相机,那可以不请求该权限
<uses-feature android:name="android.hardware.camera" />所有的相机功能,请看下面的Camera Feature。
<uses-feature android:name="android.hardware.camera" android:required="false" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />更多关于获取用户位置的内容请看这里(http://developer.android.com/guide/topics/location/strategies.html)
一种无需额外的代码就可以让你的应用程序可以拍照和拍视频的方法是使用Intent去启动Android设备现在的相机应用。Camera Intent通过Android自带的相机应用发出捕获照片或剪辑视频的请求,然后把控制交还你的应用程序。这一部分将会让你看到如何使用这种技术。
调用Camera Intent需要遵循以下步骤:
1. Compose a Camera Intent 你可以使用以下其中一个来创建你的Intent
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()方法,从该方法中取出Intent返回的结果,然后继续执行你的其他操作。更多关于如何取出返回数据的信息,请看下面的 Receiving camera intent result .
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); }
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 } } }
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; } }
/** 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 }Caution:当使用Camera.open()时需要经常的检测异常。当camera正在被使用或者不存在时,如果你没有检测异常,系统会导致你的程序崩溃。
/** 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()方法中对应的备注那里修改。设置预览界面大小的时候,你必须用getSupportedPreviewSized()放回的值修改。不要在setPreviewSize()方法中设定随意的值。
一个预览类,例如上面的简单预览类,必须和其他控制拍照或拍视频的控件一起放到Activity的布局中。本节我们将会为你展示如何为预览类创建一个基础的布局和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>在很多设备中,相机预览界面的默认方向是横向的。示例布局中指定了水平(横向)布局并且下面的代码使得应用程序的界面固定为横屏。为了时预览界面的绘制变得简单,你应该在manifest中加入以下代码,使应用程序中的Preview Activity的方向改为横向。
<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>Note:相机预览界面不一定要是横向的。从Android 2.2(API Level 8)开始,你可以使用setDisplayOrientation()方法旋转预览图片。为了在用户改变手机方向的同时改变预览界面的方向,可以在预览类的surfaceChanged()方法中,首先调用Camera.stopPreview()停止预览界面,改变方向,然后调用Camera.startPreview()重启预览界面。
在相机界面所属的Activity中把预览类加入到上面布局中的FrameLayout。同时,当不在使用相机时,确保在Activity中释放相机。下面的示例将为你展示如何在Activity中关联前面创建的预览类。
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); } }Note:上面示例中的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()); } } };
下面的示例展示了如何在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); } } );(这句是我加的:三个参数是 ShutterCallbackRawCallback,PictureCallback,分别是响应快门,raw数据,JPEG数据)
Note:上面示例的mPicture是再上一个示例的PictureCallback
Caution:在应用程序拍完照后记得要调用Camera.release()方法释放Camera对象。更多信息请看Releasing the camera。
Note:从Android 4.0(API level 14)开始,Camera.lock()和Camera.unlock()方法是自动管理的。
不像拍照片,捕获视频需要特别的调用顺序。你必须遵循一个特定的执行顺序,使得你的应用程序可以成功地准备并捕获视频,下面是详细说明:
b.Configure MediaRecorder 按下面的顺序调用MediaRecorder的方法
1. setCamera() 设置相机用于捕获视频,参数为你当前取得的Camera实例
2. setAudioSource() 设置音频来源,参数为MediaRecorder.AudioSource.CAMCORDER
3. setVideoSource() 设置视频来源,参数为MediaRecorder.VideoSource.CAMERA
4. 设置视频的输出格式和编码。在Android 2.2(API Level 8)版本及以上的版本中,可以使用MediaRecorder.setProfile()方法,你可以通过CamcorderProfile.get()方法取得Profile的一个实例。在2.2以下的版本,你必须设置输出格式和编码参数:
i. setOutputFormat() 设置输出格式,可以指定为默认设置或MediaRecorder.OutputFormat.MPEG_4
ii. setAudioEncoder() 设置声音编码类型,可以指定为默认设置或MediaRecorder.AudioEncoder.AMR_NB
iii. setVideoEncoder() 设置视频的编码类型,可以指定为默认设置或MediaRecorder.VideoEncoder.MPEG_4_SP
5. setOutputFile() 设置输出文件,你可以使用Saving Media Files小节示例中的getOutputMediaFile(MEDIA_TYPE_VIDEO).toString()方法
6.setPreviewDisplay() 在应用程序中指定SurfaceView预览布局元素,使用上面Connect Preview中的同一个对象。
Caution:你必须按顺序调用MediaRecorder的这些配置方法,否则你的程序会出错并且捕获视频失败。
c. Prepare MediaRecorder 调用MediaRecorder.prepare()方法提交上面的配置设定
d. Start MediaRecorder 调用MediaRecorder.start()方法开始录制视频。
b. Reset MediaRecorder (这一步是可选的)调用MediaRecorder.reset()方法移除之前的配置设定
c. Release MediaRecorder 调用MediaRecorder.release()释放MediaRecorder
d. Lock the Camera 锁定相机以便MediaRecorder将来可以通过Camera.lock()方法继续使用相机。从Android 4.0(API level 14)开始,调用MediaRecorder.prepare()失败时才需要调用该方法。
Tip:如果你的应用程序通常是用来拍摄视频的,你可以在启动预览前调用setRecordingHint(true)。这个设定可以减少开始录制前的等待时间。
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 level 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);
Note:完成录制后先别释放camera,否则你的预览界面会停止
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 } } } } );Note:上面示例中的prepareVideoRecorder()方法可以在Configuring MediaRecorder示例中找到,这个方法锁定camera,配置并准备MediaRecorder实例。
你可以调用Camera.release()释放Camera对象的实例,下面是示例:
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; } } }Caution: 如果你没有释放相机,所有后来试图访问相机的应用程序,包括你的应用程序,都会失败,甚至会引起程序的奔溃。
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; }Note:Environment.getExternalStoragePublicDirectory()在Android 2.2(API Level 8)及以上版本可用,如果你应用的目标设备是更早期的版本,你可以使用Environment.getExternalStorageDirectory()代替。更多详细信息请看Saving Shared Files。
更多在Android设备上存储文件的信息请看Data Storage.
Feature | API Level | Description |
Face Detection | 14 | Identify human faces within a picture and use them for focus, metering and white balance |
Metering Areas | 14 | Specify one or more areas within an image for calculating white balance |
Focus Areas | 14 | Set one or more areas within an image to use for focus |
White Balance Lock | 14 | Stop or start automatic white balance adjustments |
Exposure Lock | 14 | Stop or start automatic exposure adjustments |
Video Snapshot | 14 | Take a picture while shooting video (frame grab) |
Time Lapse Video | 11 | Record frames with set delays to record a time lapse video |
Multiple Cameras | 9 | Support for more than one camera on a device, including front-facing and back-facing cameras |
Focus Distance | 9 | Reports distances between the camera and objects that appear to be in focus |
Zoom | 8 | Set image magnification |
Exposure Compensation | 8 | Increase or decrease the light exposure level |
GPS Data | 5 | Include or omit geographic location data with the image |
White Balance | 5 | Set the white balance mode, which affects color values in the captured image |
Focus Mode | 5 | Set how the camera focuses on a subject such as automatic, fixed, macro or infinity |
Scene Mode | 5 | Apply a preset mode for specific types of photography situations such as night, beach, snow or candlelight scenes |
JPEG Quality | 5 | Set the compression level for a JPEG image, which increases or decreases image output file quality and size |
Flash Mode | 5 | Turn flash on, off, or use automatic setting |
Color Effects | 5 | Apply a color effect to the captured image such as black and white, sepia tone or negative. |
Anti-Banding | 5 | Reduces the effect of banding in color gradients due to JPEG compression |
Picture Format | 1 | Specify the file format for the picture |
Picture Size | 1 | Specify the pixel dimensions of the saved picture |
Note:由于硬件的不同和软件的实现等原因,并不是所有的设备都支持这些功能的。更多关于检测相机功能可用性的信息请看下面的Checking feature availability。
你可以通过取得Camera Parameter对象的一个实例并调用相关函数来检测相机功能的可用性。下面的示例代码将为你展示如何取得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对象提供了getSupportedXXX(),isXXXSupported()以及getMaxXXX()等方法判断相机是否支持某个功能。
如果应用程序为了正常运行而必须用到某些相机功能,你可以在manifest中请求这些功能。当你声明这些特定的功能,如闪光灯和自动对焦,Google Play会限制你的应用程序,使得程序不会被安装在不能提供这些功能的设备上。更多可以在manifest中声明的功能,请查看Features Reference.
// 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);这种技巧对几乎所有的相机功能都适用,并且在取得Camera对象的实例后,你可以在任意的时刻修改Parameter。修改Parameter后用户一般可以马上在预览界面看到变化。在软件层次,Parameter的修改需要经过若干个框架直到Camera硬件执行新的指令并发送新的图片数据才能生效。
Important:一些相机功能不能随意改变。特别是改变预览界面的大小或方向时,你得先停止预览界面,然后改变大小,最后重新开启预览界面。从Android 4.0(API Level 14)开始,改变预览界面的方向不需要重启。
其他的功能需要更多的代码才能实现,包括:
测光和对焦区域的工作和其他相机功能非常相似,你可以通过Camera.Parameters对象的方法控制它们。下面将为你展示如何通过Camera对象的一个实例设置两个测光区域。
// 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对象包含两个数据参数:一个Rect对象指定Camera画面内的一个区域和一个权重值,这些参数会告诉相机这个区域应该给予什么级别的测光和焦点计算。
Camera.Area对象把画面映射为2000X2000个单元格的矩形区域。坐标点<-1000,-1000>代表画面左上角的顶点,坐标点<1000,1000>代表画面右下角的顶点,如下图所示:
红色线是Camera.Area的坐标系,蓝色框显示值为(333,333,667,667)的Rect对象的位置和形状。
坐标系的边界总是与预览界面中可见图片的边界相契合且不会大规模的缩放。类似地,使用Camera.setDisplayOrientation()旋转预览界面时不会重新映射坐标系。
Note:当人脸识别功能启动后,setWhiteBalance(String),setFocusAreas(List)和setMeteringAreas(List)不会产生效果。
使用人脸识别功能的一般步骤:
为了接收通知并响应人脸的识别,你必须为人脸识别事件添加监听器。也就是你必须创建一个实现了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(); } }每次启动(或重新启动)预览界面时,都必须启动人脸识别功能。如果你使用的是上面Creating a preview class的预览类,你可以把上面的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()); } }Note:记住在调用startPreview()方法后一定要调用startFaceDetection()方法。请不要尝试在main Activity的onCreate()方法中启动人脸识别功能,因为这个时候预览界面还没有启动。
(Time lapse video这个不知道怎么翻译,大部分翻译为延时拍摄,但实际使用中,是你拍了很久才会生成1秒的视频,最后结果相当于把一段视频以几倍速播放)
延时拍摄允许用户把图片合并成一段几秒或几分钟的视频。这个功能需要MediaRecorder记录图片的一个时间序列。
为了使用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完整的配置过程请看Configuring MediaRecorder。配置完成后,你可以像拍摄普通视频那样开始拍摄。更多关于MediaRecorder的配置和使用信息,请看Capturing videos.