• Camera


    In this document

      1. Considerations
      2. The Basics
      3. Manifest Declarations
      4. Using Existing Camera Apps
        1. Image capture intent
        2. Video capture intent
        3. Receiving camera intent result
      5. Building a Camera App
        1. Detecting camera hardware
        2. Accessing cameras
        3. Checking camera features
        4. Creating a preview class
        5. Placing preview in a layout
        6. Capturing pictures
        7. Capturing videos
        8. Releasing the camera
      6. Saving Media Files

    Camera Features

      1. Checking feature availability
      2. Using camera features
      3. Metering and focus areas
      4. Face detection
      5. Time lapse video

    Considerations

    在你的应用使用Android设备上的相机之前,考虑下面的几点:

    Camera Requirement :相机功能是否很重要,以至于你不想让你的应用装到没有相机的设备上。如果是,在mainfest上声明。

    Quick Picture or Customized Camera:你是想简单的拍个照,还是自定义一个相机。

    Storage :你的应用生成的图片和录像,是可以共享给其他应用,还是私有?当应用被卸载的时候,图片和录像是否仍然保存下来?

    The Basics

    android拍照和录像有两种方式:一是通过使用 android.hardware.camera2 的API,二是使用Intent启动自带的相机程序。用到的类如下:

    android.hardware.camera2

    Camera 过时了

    SurfaceView

    MediaRecorder

    Intent 

    MediaStore.ACTION_IMAGE_CAPTURE or MediaStore.ACTION_VIDEO_CAPTURE,一个用来拍照一个用来录像。

    Manifest Declarations

    在进行开发之前,需要声明相应的权限。

    Camera Permission  使用相机必须声明下面的权限,如果是使用Intent来启动相机,则不用声明

    <uses-permission android:name="android.permission.CAMERA" />
    

    Camera Features  可以在GooglePlay用来过滤设备,下面的代码表示,只有有相机的设备,才可以安装该应用

    <uses-feature android:name="android.hardware.camera" android:required="false" />
    

    Storage Permission   保存图片和录像到SD Card需要下面的权限

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    

    Audio Recording Permission 录像权限

    <uses-permission android:name="android.permission.RECORD_AUDIO" />
    

    Location Permission  如果你想给图片加上GPS位置标签,需要下面的权限

    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    

    Using Existing Camera Apps

    通过Intent来启动相机,有如下的几步:

    1.Compose a Camera Intent  根据你的需求(拍照/录像)来创建不同的Intent

      MediaStore.ACTION_IMAGE_CAPTURE 拍照时传这个Action

      MediaStore.ACTION_VIDEO_CAPTURE 录像时传这个Action

    2.Start the Camera Intent  用startActivityForResult() 方法来启动相机程序。

    3.Receive the Intent Result 复写onActivityResult()方法,并在这个方法里面接收通过Intent传递过来的数据。当用户拍照/录像完毕或者取消,都会回调这个方法。

    Image capture intent

    使用Intent拍照,还可以在Intent里面传递一些其他的信息:

    MediaStore.EXTRA_OUTPUT  传递一个uri进去,这个uri包含了图片储存的位置和文件名。如果没有指定,图片会以默认的名字储存在默认的位置。

    下面给一个demo:

    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);
    }
    

    Video capture intent

    使用Intent录像,也可以传递一些额外信息:

    MediaStore.EXTRA_OUTPUT 不说了

    MediaStore.EXTRA_VIDEO_QUALITY 0~1, 0表示最低质量和最小大小,1表示最高质量和最大大小

    MediaStore.EXTRA_DURATION_LIMIT 限制录像的时间,单位为秒(s)

    MediaStore.EXTRA_SIZE_LIMIT 限制文件大小,单位是字节(byte)

    仍然给demo:

    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);
    }
    

    Receiving camera intent result

    下面的demo展示了如果拦截Camera Intent的回调,并处理数据。

    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:
    " +
                         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:
    " +
                         data.getData(), Toast.LENGTH_LONG).show();
            } else if (resultCode == RESULT_CANCELED) {
                // User cancelled the video capture
            } else {
                // Video capture failed, advise user
            }
        }
    }
    

    Building a Camera App

    如何自定义一个相机?下面的介绍都是以老的过时的Camera为例,对于最新的相机应用来说,推荐使用android.hardware.camera2

    大致的步骤如下:

    1.Detect and Access Camera 检查设备的相机是否可用,并请求使用

    2.Create a Preview Class 自定义一个View继承SurfaceView并实现SurfaceHolder接口,创建预览视图

    3.Build a Preview Layout 创建预览视图布局

    4.Setup Listeners for Capture 设置用于交互的监听器

    5.Capture and Save Files 获取数据并保存文件

    6.Release the Camera 释放资源,让别的应用使用

    当使用完Camera之后,调用Camera.release()来释放Camera对象,如果未释放,其他应用尝试访问的时候,可能会被shut down,包括你自己的应用。

    Detecting camera hardware

    如果你的应用没有在mainfest里面做特殊的声明,那么你就需要在运行时检查相机是否存在,如下代码:

    /** 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及以上可以使用 Camera.getNumberOfCameras()方法来获取可访问的摄像头个数。

    Accessing cameras

    确定设备上有相机之后,通过获取一个Camera的实例来获得使用权限,代码如下:

    /** 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()是否会出异常,否则会被 shut down by the system。

    android 2.3 (API Level 9)及以上,可以使用Camera.open(int)方法打开指定的摄像头。

    Checking camera features

    使用Camera.getParameters()方法,然后检查返回的对象Camera.Parameters 即可。API 9以及上 使用Camera.getCameraInfo()还可以知道摄像头是前置还是后置,图片的方向。

    Creating a preview class

    下面的demo创建了一个基本的视图预览类:

    /** 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()方法里面设置,setPreviewSize()方法可以实现设置视图大小功能,但是不能传递任意值,只能使用getSupportedPreviewSizes()获取的大小。

    Placing preview in a layout

    为预览视图写一个布局:

    <?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>
    

    使用FrameLayout是可以让你更方便的在预览视图上覆盖你想要的东西,如遮罩之类的。

    一般相机应用都使用横屏,你可以在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>
    

    如果不想要横屏,Android 2.2以及上提供了setDisplayOrientation()方法去控制视图的方向,要想实现视图旋转,在surfaceChanged()方法里面先Camera.stopPreview() 停止预览,设置方向,再Camera.startPreview()开启预览。

    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);
        }
    }
    

    Capturing pictures

    给拍照动作加上监听,监听的实现如下:

    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()),代码如下:

    // 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对象,Camera.release() 。

    Capturing videos

    录像需要Camera对象和MediaRecorder类协调使用。除了调用Camera.open() 和 Camera.release(),你还需要管理好Camera.lock() 和 Camera.unlock(),后两个方法是控制MediaRecorder访问相机硬件的。

    从Android 4.0开始,Camera.lock() 和 Camera.unlock()系统为你管理。

    录像不像拍照,调用有特定的顺序(不好简单翻译):

    1. Open Camera - Use the Camera.open() to get an instance of the camera object.
    2. Connect Preview - Prepare a live camera image preview by connecting a SurfaceView to the camera usingCamera.setPreviewDisplay().
    3. Start Preview - Call Camera.startPreview() to begin displaying the live camera images.
    4. Start Recording Video - The following steps must be completed in order to successfully record video:
      1. Unlock the Camera - Unlock the camera for use by MediaRecorder by calling Camera.unlock().
      2. Configure MediaRecorder - Call in the following MediaRecorder methods in this order. For more information, see the MediaRecorder reference documentation.
        1. setCamera() - Set the camera to be used for video capture, use your application's current instance ofCamera.
        2. setAudioSource() - Set the audio source, use MediaRecorder.AudioSource.CAMCORDER.
        3. setVideoSource() - Set the video source, use MediaRecorder.VideoSource.CAMERA.
        4. Set the video output format and encoding. For Android 2.2 (API Level 8) and higher, use theMediaRecorder.setProfile method, and get a profile instance using CamcorderProfile.get(). For versions of Android prior to 2.2, you must set the video output format and encoding parameters:
          1. setOutputFormat() - Set the output format, specify the default setting orMediaRecorder.OutputFormat.MPEG_4.
          2. setAudioEncoder() - Set the sound encoding type, specify the default setting orMediaRecorder.AudioEncoder.AMR_NB.
          3. setVideoEncoder() - Set the video encoding type, specify the default setting orMediaRecorder.VideoEncoder.MPEG_4_SP.
        5. setOutputFile() - Set the output file, use getOutputMediaFile(MEDIA_TYPE_VIDEO).toString()from the example method in the Saving Media Files section.
        6. setPreviewDisplay() - Specify the SurfaceView preview layout element for your application. Use the same object you specified for Connect Preview.

        Caution: You must call these MediaRecorder configuration methods in this order, otherwise your application will encounter errors and the recording will fail.

      3. Prepare MediaRecorder - Prepare the MediaRecorder with provided configuration settings by callingMediaRecorder.prepare().
      4. Start MediaRecorder - Start recording video by calling MediaRecorder.start().
    5. Stop Recording Video - Call the following methods in order, to successfully complete a video recording:
      1. Stop MediaRecorder - Stop recording video by calling MediaRecorder.stop().
      2. Reset MediaRecorder - Optionally, remove the configuration settings from the recorder by callingMediaRecorder.reset().
      3. Release MediaRecorder - Release the MediaRecorder by calling MediaRecorder.release().
      4. Lock the Camera - Lock the camera so that future MediaRecorder sessions can use it by callingCamera.lock(). Starting with Android 4.0 (API level 14), this call is not required unless theMediaRecorder.prepare() call fails.
    6. Stop the Preview - When your activity has finished using the camera, stop the preview usingCamera.stopPreview().
    7. Release Camera - Release the camera so that other applications can use it by calling Camera.release().

    在开始预览之前,将setRecordingHint(boolean)设置为true,可以减少启动录像的时间。

    Configuring MediaRecorder

    是用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;
    }
    

    配置完成之后,调用MediaRecorder.prepare()方法,会检查配置并让其生效。

    在android2.2之前,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);
    

    还有一些其他的配置可调整:

    Starting and stopping MediaRecorder

    使用MediaRecorder开始和停止录像,也有特定的顺序:

    1. Unlock the camera with Camera.unlock()
    2. Configure MediaRecorder as shown in the code example above
    3. Start recording using MediaRecorder.start()
    4. Record the video
    5. Stop recording using MediaRecorder.stop()
    6. Release the media recorder with MediaRecorder.release()
    7. Lock the camera using Camera.lock()

    下面给出demo(完成录像未释放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
                    }
                }
            }
        }
    );

    Releasing the camera

    释放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;
            }
        }
    }
    

    Saving Media Files

    保存文件,作为一个开发者,优先考虑下面两个路径(SD Card):

    Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)   公共的目录 Android 2.2 以及上可用,2.2之前有另外的方法Environment.getExternalStorageDirectory()

    Context.getExternalFilesDir(Environment.DIRECTORY_PICTURES) -  私有的目录,应用卸载时,目录会被删除。

    下面给出demo:

    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;
    }
    

    Camera Features

     绝大部分的相机特性都能通过Camera.Parameters设置,但是有几个需要特别处理:

    Checking feature availability

    不是所有的相机都支持所有的相机特性,另外设备支持的特性还有不同的等级和选项,所以检查设备是否支持相机的特性,以及支持到哪个等级是很重要的,示例代码如下:

    // 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...()is...Supported() 和 getMax...() 来检查特性是否被支持。

    如果你的应用必须需要某个特性才能使用,在mainfest里面加上限制。

    Using camera features

    使用某个特性很简单:

    // 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);
    

    On the software side, 特性需要花费几帧的时间才能开到效果。

    Metering and focus areas

    Android 4.0 开始支持,并没看懂这是做什么...

    // 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);
    

    录像预览视图的坐标系。

    Face detection

    人脸识别,Android 4.0 开始支持

    人脸识别运行的时候,setWhiteBalance(String)setFocusAreas(List) 和 setMeteringAreas(List) 都不会生效。

    使用人脸识别特性,需要下面几个步骤:

    • Check that face detection is supported on the device
    • Create a face detection listener
    • Add the face detection listener to your camera object
    • Start face detection after preview (and after every preview restart)

    检查是否支持人脸识别:

    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();
        }
    }
    

    创建识别人脸成功后的监听:

    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() );
            }
        }
    }
    

    监听设置如下:

    mCamera.setFaceDetectionListener(new MyFaceDetectionListener());
    

    使用人脸识别,需要在每次启动(或者重新启动)预览的时候:

    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方法里面启动人脸识别,因为这个时候视图预览不可用。

    Time lapse video

    Time lapse video allows users to create video clips that combine pictures taken a few seconds or minutes apart. 

    // 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
    
  • 相关阅读:
    C#操作Word打印
    判断文件名是否有效
    Windows系统下的程序开机自启
    Winform应用程序使用自定义的鼠标图片
    C# 操作网络适配器
    Runtime Error! R6025-pure virtual function call
    Winform中跨线程访问UI元素的方法
    C#自定义属性转换类---类型转换器
    获取计算机硬件信息
    获取程序集信息
  • 原文地址:https://www.cnblogs.com/aprz512/p/5092247.html
Copyright © 2020-2023  润新知