Android Camera开发讲解

概述

Android手机关于Camera的使用,一是拍照,二是摄像,由于Android提供了强大的组件功能,为此对于在Android手机系统上进行Camera的开发,我们可以使用两类方法:一是借助Intent和MediaStore调用系统Camera App程序来实现拍照和摄像功能,二是根据Camera API自写Camera程序。

基础知识

Android系统提供API来支持自定义相机拍照和系统拍照,以下是有关的类:

  • Camera

    该类提供基础API来使用设备上的相机,且该类可以为你的应用提供拍照和录像相关的API。

  • SurfaceView

    该类用于显示相机的预览数据。

  • MediaRecorder

    该类提供相机录像相关的API。

注意事项

在你的应用程序能够在Android设备上使用相机之前,你应该考虑几个问题,那就是你的App打算如何使用相机拍照或者录像?

  • Camera需求的声明:

    使用相机功能对于你的应用程序来说是否很重要并且你不希望你的应用程序被安装在没有相机的机器上?如果是这样,那么你需要把相机需求声明在配置文件里。

  • 调用系统拍照还是自定义相机:

    你的应用程序该如何使用相机?你是否仅仅需要拍摄一张照片或者一个视频,或者你的应用程序希望提供一种使用相机的新的方式?

  • 存储:

    是否你的应用生成的图片和视频仅对你的应用可见,还是其他应用程序例如相册或者其他的多媒体和社交App也可以使用它们?你是否希望你的应用程序被卸载后,这些照片和视频仍然可用,还是一起被删除?

权限申明

  • Camera Permission - 你的应用必须申请相机权限才可以使用设备相机。
<uses-permission android:name="android.permission.CAMERA" />

注意:如果你使用Intent调用系统相机,你的应用无需申请该权限。

  • Storage Permission - 如果你的应用需要保存照片或者视频到设备存储中,你必须在Manifest指定文件的写权限
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
  • Audio Recording Permission - 你必须申请录音权限才能使用相机来录像.
<uses-permission android:name="android.permission.RECORD_AUDIO" />
  • Location Permission - 当然如果你需要拍摄的照片记录地理位置,你同样需要申请如下权限
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

调用系统相机

你的应用可以通过发送一个Intent 到系统相机应用来实现抓取一张照片或者一段视频剪辑,然后将它们返回给你的应用。

使用camera intent调用系统相机流程如下:

(1)Compose a Camera Intent - 创建一个Intent请求用来拍照或者录像,有关的Intent类型如下:

  • MediaStore.ACTION_IMAGE_CAPTURE - 该Intent action 类型用于请求系统相机拍照。
  • MediaStore.ACTION_VIDEO_CAPTURE - 该Intent action 类型用于请求系统相机录像。

(2)Start the Camera Intent - 调用activity的startActivityForResult()方法来发送camera intent请求拍照或者录像,当发送camera intent 以后,当前应用会跳转到系统相机应用app界面,让用户可以拍照或者录像。

(3)Receive the Intent Result - 在你的应用中实现onActivityResult()回调方法去接收来自系统相机的拍摄结果。该方法在用户完成拍照或者录像以后由系统调用。

系统拍照

代码如下,按上面的三步走:

button1.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
                startActivityForResult(intent, CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE);
            }
        });

...

@Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        /**
         * 通过data取得数据
         */
        if (requestCode == CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE) {
            Bundle extras = data.getExtras();
            Bitmap bitmap = (Bitmap) extras.get("data");
            image.setImageBitmap(bitmap);
        }
    }

但是,现在手机像素这么高,万一图片特别大呢,会不会data过大而FC呢?放心,Android早就考虑到了,所以,data里面压根就不是完整的图片,它只是一张缩略图。所以,我们需要获取到拍摄的原图,就不能使用这种方法。但是我们可以这样做,我们可以指定MediaStore类的一个EXTRA_OUTPUT来指定拍摄图像保存的位置,相当于建立一个临时文件。在onActivityResult中,我们不使用data来获取图像,而是直接去读这个临时文件即可。如果自己代码指定了保存图片的uri,data里面就不会保存数据。

button1.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
                Uri fileUri = getOutputMediaFileUri(MEDIA_TYPE_IMAGE);
                intent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri);
                startActivityForResult(intent, CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE);
            }
        });
...

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        /**
         * 通过存储Uri取得数据
         */
        if (requestCode == CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE) {
            if (resultCode == RESULT_OK) {
                image.setImageURI(getOutputMediaFileUri(MEDIA_TYPE_IMAGE));
            }
        }
    }

这样我们就可以获取到完整的拍摄图片了。后面你可以让图像显示出来。

下面来看看保存多媒体文件:

拍照或者录像生成的多媒体文件需要保存到手机存储目录中(SD Card),所以在应用中必须有往手机中写文件的权限。一般可以有多种本地路径来保存多媒体文件,但是主要有如下两种常用的路径:

  • Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)

    该方法返回一个标准的外部存储路径去保存照片和视频。这个路径是公共的,所以其他应用也可以访问,修改,删除该路径下的照片和视频,如果你的应用被卸载了,媒体文件依然存在本地储存中。为了避免和其他多媒体文件混淆,你应该在公共目录下创建一个子目录来保存你自己应用中的多媒体数据。

  • Context.getExternalFilesDir(Environment.DIRECTORY_PICTURES)

    该方法返回一个标准的,唯独当前应用自己可见的路径去保存照片和视频。如果该应用被卸载,在该目录下的所有多媒体数据将会被移除。但是有一个好处就是其他应用无法去访问,修改,删除该路径下的文件。

如下示例代码演示如何创建一个路径用来保存照片和视频:

    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){
        File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "WatsonCamera");

        if (! mediaStorageDir.exists()){
            if (! mediaStorageDir.mkdirs()){
                return null;
            }
        }

        File mediaFile;
        if (type == MEDIA_TYPE_IMAGE){
            mediaFile = new File(mediaStorageDir.getPath() + File.separator + "IMG_watson.jpg");
        } else if(type == MEDIA_TYPE_VIDEO) {
            mediaFile = new File(mediaStorageDir.getPath() + File.separator + "VID_watson.mp4");
        } else {
            return null;
        }

        return mediaFile;
    }

系统录像

发送Intent录像携带的外部数据extra的信息如下:

  • MediaStore.EXTRA_OUTPUT

    该关键字和拍照使用的关键字一样,意思就是制定一个路径和文件名来构建一个Uri对象来保存录像结果。

  • MediaStore.EXTRA_VIDEO_QUALITY

    该关键字用于指定拍摄的录像质量,参数0表示低质量,参数1表示高质量。

  • MediaStore.EXTRA_DURATION_LIMIT

    该关键之用于指定拍摄的录像的时间限制,单位是秒。

  • MediaStore.EXTRA_SIZE_LIMIT

    该关键字用于指定拍摄的录像文件大小限制,单位值byte。

代码如下,按上面的三步走:

button2.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
                Uri fileUri = getOutputMediaFileUri(MEDIA_TYPE_VIDEO);
                intent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri);
                intent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 1);
                startActivityForResult(intent, CAPTURE_VIDEO_ACTIVITY_REQUEST_CODE);
            }
        });

...

@Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode == CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE) {
           if (resultCode == RESULT_OK) {
                image.setVisibility(View.VISIBLE);
                video.setVisibility(View.GONE);
                image.setImageURI(getOutputMediaFileUri(MEDIA_TYPE_IMAGE));
            }
        } else if (requestCode == CAPTURE_VIDEO_ACTIVITY_REQUEST_CODE) {
            if (resultCode == RESULT_OK) {
                video.setVisibility(View.VISIBLE);
                image.setVisibility(View.GONE);
                video.setVideoURI(getOutputMediaFileUri(MEDIA_TYPE_VIDEO));
                video.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
                    @Override
                    public void onPrepared(MediaPlayer mp) {
                        video.start();
                    }
                });
                video.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
                    @Override
                    public void onCompletion(MediaPlayer mp) {
                        if (null != video) {
                            video.stopPlayback();
                        }
                    }
                });
            }
        }
    }

自定义相机

创建一个自定义的相机app基本遵循如下步骤:

  • 检测和访问相机:

    首先代码检测该设备相机是否存在,如果存在才能请求访问设备相机。

  • 创建一个预览来显示相机图像:

    在你的布局中使用SurfaceView控件,然后在代码中继承SurfaceHolder.Callback接口并且实现接口中的方法来显示来自相机的图像信息。

  • 设置相机基本参数:

    根据需求设置相机预览尺寸,图片大小,预览方向,图片方向等。

  • 设置拍照录像监听:

    当用户按下按钮时调用Camera.takePicture()或者MediaRecorder.start()来进行拍照或录像。

  • 文件保存:

    当拍照结束或者录像视频结束时,需要开启一个后台线程去保存图片或者视频文件。

  • 释放相机资源:

    Camera硬件是一个共享资源,所以你必须小心的编写你的应用代码来管理相机资源。一般在Activity的生命周期的onResume中开启相机,在onPause中释放相机。

注意: 当你不在使用相机资源时,记得调用Camera.release()方法来释放相机资源,否则其他应用甚至你自己的应用再次请求访问设备相机时会失败,并且crash。

检测相机硬件是否存在

一般情况,我们会在运行代码时检测该设备是否有相机硬件,如果有相机硬件,才进一步去访问相机,如下是检测相机硬件是否存在是代码示例:

/** Check if this device has a camera */
private boolean checkCameraHardware(Context context) {
    if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)){
        return true;
    } else {
        return false;
    }
}

Android 设备可以有多个相机硬件,现在一般手机都是前后两个camera,因此我们在Android2.3以后也可以使用Camera.getNumberOfCameras()方法来获得当前设备camera个数来判断相机硬件是否存在。

创建Camera预览

Camera预览布局文件:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <RelativeLayout
        android:id="@+id/record_navigation_bar"
        android:layout_width="match_parent"
        android:layout_height="48dp"
        android:background="#F8F8F8" >

        <ImageView
            android:id="@+id/record_act_back"
            android:layout_width="25dp"
            android:layout_height="31dp"
            android:layout_centerVertical="true"
            android:layout_marginLeft="10dp"
            android:layout_marginRight="10dp"
            android:src="@drawable/icon_ll_back" />
    </RelativeLayout>

    <SurfaceView
        android:id="@+id/camera_preview"
        android:layout_width="match_parent"
        android:layout_height="fill_parent"
        android:layout_above="@+id/record_bottom_bar"
        android:layout_below="@+id/record_navigation_bar" />

    <RelativeLayout
        android:id="@+id/record_bottom_bar"
        android:layout_width="match_parent"
        android:layout_height="60dp"
        android:layout_alignParentBottom="true"
        android:background="@drawable/recording_bottom_bar_bg_interview" >

        <Button
            android:id="@+id/btn_start_recording"
            android:layout_width="58dp"
            android:layout_height="58dp"
            android:layout_centerInParent="true"
            android:background="@drawable/recording_act_vedio_start" />

        <Button
            android:id="@+id/btn_change_module"
            android:layout_width="45dp"
            android:layout_height="35dp"
            android:layout_centerVertical="true"
            android:layout_marginLeft="30dp"
            android:background="@drawable/change_module_photo" />
    </RelativeLayout>

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="30dp"
        android:layout_alignParentRight="true"
        android:layout_below="@+id/record_navigation_bar"
        android:layout_marginRight="10dp"
        android:layout_marginTop="10dp"
        android:gravity="center_vertical" >

        <View
            android:id="@+id/record_video_tip"
            android:layout_width="15dp"
            android:layout_height="15dp"
            android:layout_marginRight="10dp"
            android:background="@drawable/record_video_tip" />

        <TextView
            android:id="@+id/record_video_time"
            android:layout_width="wrap_content"
            android:layout_height="30dp"
            android:layout_marginRight="10dp"
            android:gravity="center_vertical"
            android:text="00:00"
            android:textColor="@android:color/white"
            android:textSize="17sp" />
    </LinearLayout>

</RelativeLayout>

然后,我们创建一个Activity,用来展示Camera的预览,那么在这个Activity里面,我们需要做什么呢?两件事情:

  • 初始化相机
  • 将内容显示到SurfaceView

Android的Camera是独享的,如果多处调用,就会抛出异常,所以,我们需要将Camera的生命周期与SurfaceView的生命周期绑定:

  • surfaceCreated方法中初始化相机
  • surfaceDestroyed方法中释放相机

初始化相机非常简单:

private Camera getCamera() {
    Camera camera;
    try {
        camera = Camera.open();
    } catch (Exception e) {
        camera = null;
    }
    return camera;
}

注意: 在调用Camera.open()方法时总是要去捕获一个异常,以免打开相机设备失败导致整个应用crash。在Android2.3以及更高api上,你可以使用Camera.open(int)来打开指定的相机。以上代码示例总是默认打开后置camera,一般情况参数为0表示打开后置camera,参数为1表示打开前置camera。

释放相机也非常简单:

@Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        if (camera != null) {
            try {
                camera.setPreviewCallback(null);
                camera.stopPreview();
                camera.release();
                camera = null;
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

那么下面我们再来看如何把相机图像设置到SurfaceView中进行预览:

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        try {
            camera = getCamera();
            camera.setPreviewDisplay(holder); //camera关联到SurfaceView
            camera.setDisplayOrientation(90); //旋转90度
            camera.startPreview(); //开始预览
        } catch (Exception e) {
            finish();
        }
    }

是不是也非常简单,camera的一个方法已经帮我们自动关联了SurfaceView。

这里需要注意下这个方法camera.setDisplayOrientation(90),通过这个方法,我们可以调整摄像头的角度,不然默认是横屏,图像会显示的比较奇怪。当然,即使你设置了90,图像也有可能比较奇怪,这是因为你没有对图像进行正确的缩放,比例不对。

通过上面的设置,我们已经可以正常预览摄像头的图像内容了。

拍照

一旦你创建了camera preview并且加载到布局中可以实时显示预览画面了,此时就可以进行拍照了。为了配合拍照,我们需要做一些设定,设置拍照的参数。

Camera.Parameters params = mCamera.getParameters();
params.setPictureFormat(ImageFormat.JPEG);
params.setPreviewSize(800, 400);
params.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
mCamera.setParameters(params);
//自动聚焦
camera.autoFocus(new AutoFocusCallback() {
     public void onAutoFocus(boolean success, Camera camera) {
           if (success)
                System.out.println("聚焦成功 !");
           else
                System.out.println("聚焦失败 !");
        }
});

在代码中你应该实现一个监听回调来捕获用户拍照的行为。可以调用camera.takePciture()方法来进行拍照。

public final void takePicture(ShutterCallback shutter, PictureCallback raw, PictureCallback jpeg);

该方法接受三个参数,第一个参数ShutterCallback响应快门的接口,第二个参数PictureCallback接收raw格式的图片数据,第三个参数PictureCallback接收jpeg格式的图片数据。为了保存图片数据,你可以根据需要实现以上三个接口。此处我们暂且实现第三个PictureCallback接口回调。示例代码如下:

   //拍照
   if (camera != null) {
        camera.takePicture(null, null, mPictureCallback);
   }

   //第三个PictureCallback接口回调,通过data[]保持图片数据信息
    private Camera.PictureCallback mPictureCallback = new Camera.PictureCallback() {
        @Override
        public void onPictureTaken(byte[] data, Camera camera) {
            File pictureFile = MainActivity.getOutputMediaFile(MEDIA_TYPE_IMAGE);
            if (pictureFile == null){
                return;
            }
            try {
                FileOutputStream fos = new FileOutputStream(pictureFile);
                fos.write(data);
                fos.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
            Toast.makeText(RecordVedioAct.this, "图像已保存", Toast.LENGTH_SHORT).show();
            camera.startPreview(); //拍完继续预览
        }
    };

录像

Camera视频录像不仅涉及到Camera类还用到了MediaRecorder类。当你使用Camera录像时,你应该调用Camera.lock()和Camera.unlock()来管理camera硬件,允许MediaRecorder访问camera硬件。你应该在camera和MediaRecorder关联之前调用Camera.unlock()来解锁camera,允许MediaRecorder访问Camera,在释放MediaRecorder资源以后调用Camera.lock()来锁定camera以保证camera硬件资源的共享性。

注:在Android4.0以后,系统会自动管理camera.unlock()以及camera.lock(),无需用户自己管理。

启动录像流程需要一个指定调用顺序,如下是详细的步骤流程:

(1)Open Camera – 使用Camera.open()静态方法来获得camera对象实例。

(2)Connect Preview – 使用camera.setPreviewDiaplay(holder)方法将相机的预览画面显示在SurfaceView控件上。

(3)Start Preview – 使用camera.startPreview()方法开始启动预览画面。

(4)Start Recording Video – 必须完成以下步骤才能正常开始正常录音:

  • Unlock the Camera - 调用camera.unlock()方法解锁camera,使得MediaRecorder进程能访问Camera硬件。
  • Configure MediaRecorder - 在这一步,分别调用MediaRecorder类中如下方法来配置MediaRecorder:
/**配置MediaRecorder*/
recorder.setCamera(camera); //设置camera用于录像
recorder.setOutputFile(filePath); //设置输出文件路径
recorder.setAudioSource(MediaRecorder.AudioSource.MIC); //设置录像音频来源
recorder.setVideoSource(MediaRecorder.VideoSource.CAMERA); //设置录像视频来源
recorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4); //设置视频的输出格式
recorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264); //设置视频的编码格式
recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);  //设置音频的编码格式
/**输出格式和编码格式,对于Android2.2或者更高版本使用MediaRecorder.setProfile方法即可,使用方法CamcorderProfile.get()来获得一个配置信息*/
recorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH));
setPreviewDisplay(holder.getSurface()) //为MediaRecorder指定预览显示

注意:在这一步,你必须调用MediaRecorder类中的以上全部方法来配置MediaRecorder,否则你的应用将无法正常录像并且报错。

由于录像默认设置了很多参数,无需用户太关心更细节的参数设置,但是如果需要在你的应用中修改这些默认参数设置,你可以使用如下方法来修改默认参数:


recorder.setAudioEncodingBitRate(); //设置音频编码的字节率
recorder.setVideoEncodingBitRate(); //设置视频编码的字节率
recorder.setOrientationHint(tureAngle); //设置MediaRecorder旋转角度
recorder.setAudioSamplingRate(); //设置音频采样率
recorder.setMaxDuration(5 * 60 * 1000); //设置最大录制时间
recorder.setVideoSize(640, 480); //设置视频尺寸大小,在setVideoSource()和setOutFormat()之后
recorder.setVideoFrameRate() //设置视频帧率,在setVideoSource()和setOutFormat()之后
recorder.setAudioChannels(); //设置音频的频道数目,参数一般1/2
  • Prepare MediaRecorder - 在配置完MediaRecorder参数之后调用mediaRecorder.prepare()方法来准备MediaRecorder。
  • Start MediaRecorder - 调用mediaRecorder.start()方法启动录像。

(5)Stop Recording Video – 当你结束录像时调用如下方法:

  • Stop MediaRecorder - 首先调用 mediaRecorder.stop()方法停止多媒体录像。
  • Reset MediaRecorder - 调用mediaRecorder.reset()方法重置多媒体状态,调用该方法之后之前的所有MediaRecorder configuration将被移除,你如果还想再次录像,需要再次配置多媒体参数。
  • Release MediaRecorder - 调用 mediaRecorder.release()方法释放多媒体资源。
  • Lock the Camera - 调用camera.lock()方法来给Camera硬件加锁。在Android4.0及以后无需调用该方法,除非在调用mediaRecorder.prepare()失败时,才需要再次调用该方法。

(6)Stop the Preview - 当你的Activity已经不再使用camera时,调用camera.stopPreview()方法来停止预览。

(7)Release Camera - 当不再使用Camera时,调用camera.release()方法来释放camera,以便其他应用可以使用camera资源。

注意: 当完成一段视频录像时,不要马上去释放camera资源或者停止当前预览,因为有可能用户会再次启动录像操作。本文中将camera释放操作放在surfaceDestroyed里面。

如下代码演示在button的点击事件中去启动和停止视频录像操作:

   /**录像*/
   if (isRecording) {
      stopRecord();
   } else {
      startRecord();
   }

    // 开始录像
    private void startRecord() {
        if (prepareVideoRecorder()) {
            mediaRecorder.start();
            //修改状态
            isRecording = true;
            Toast.makeText(RecordVedioAct.this, "开始录像", Toast.LENGTH_SHORT).show();
            btn_start_recording.setBackgroundResource(R.drawable.recording_act_vedio_stop);
            start_time = 0;
            timer = new Timer();
            timer.scheduleAtFixedRate(new TimerTask() {
                @Override
                public void run() {
                    start_time++;
                    handler.sendEmptyMessage(0);
                }
            }, 0, 1000);
        } else {
            mediaRecorder.release();
            camera.lock();
        }
    }

    // 停止录像
    private void stopRecord() {
        mediaRecorder.stop();
        mediaRecorder.reset();
        mediaRecorder.release();
        camera.lock();
        //修改状态
        isRecording = false;
        btn_start_recording.setBackgroundResource(R.drawable.recording_act_vedio_start);
        timer.cancel();
        record_video_tip.setVisibility(View.VISIBLE);
        Toast.makeText(RecordVedioAct.this, "录像已保存", Toast.LENGTH_SHORT).show();
    }

    private boolean prepareVideoRecorder(){
        mediaRecorder = new MediaRecorder();
        camera.unlock();
        mediaRecorder.setCamera(camera);
        mediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
        mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
        mediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH));
        mediaRecorder.setOutputFile(MainActivity.getOutputMediaFile(MEDIA_TYPE_VIDEO).toString());
        mediaRecorder.setPreviewDisplay(myHolder.getSurface());
        try {
            mediaRecorder.prepare();
        } catch (Exception e) {
            mediaRecorder.release();
            camera.lock();
            return false;
        }
        return true;
    }

获取相机的属性参数

一旦你成功访问相机设备,你可以使用camera.getParameters()方法来获取相机参数信息,可以根据返回值 Camera.Parameters 类来查看当前camera支持哪些参数设置等。当使用API 9或者更高时,你可以使用Camera.getCameraInfo()静态方法来获取前后camera的信息,如camera数据流的方向和是否能禁止拍照快门声音标记。示例代码如下:

public static Camera.CameraInfo getCameraInfo(int cameraId) {
        Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
        Camera.getCameraInfo(cameraId, cameraInfo);
        return cameraInfo;
    }

CameraInfo类:

    public static class CameraInfo {
        public static final int CAMERA_FACING_BACK = 0; //后置camera
        public static final int CAMERA_FACING_FRONT = 1; //前置camera
        public boolean canDisableShutterSound; //是否能禁止拍照快门声音
        public int facing;
        public int orientation; //camera数据流的方向
    }
}

相机特征描述

Android支持一组相机功能来控制你的相机应用,比如:生成的照片格式,闪光灯模式,对焦设置等等。这里罗列出通用的相机功能并且显示怎么使用它们来辅助我们拍照。有关相机更多的参数设置,可以直接阅读Camera.Parameters类。下表罗列出通用的相机参数:

时间: 2024-10-15 06:13:06

Android Camera开发讲解的相关文章

Android Camera开发之基础知识篇

概述 Android框架支持设备的相机拍照和录像功能,你的应用可以直接调用系统的Camera应用来拍照或者录像(比如微信拍照),当然也可以利用Android系统提供的API开发一个Camera应用来实现相机拍照和录像功能(比如市面上流行的360相机).此篇文章主要记录相机开发有关的基础知识,以及带着自己的理解翻译Camera官方文档,如有翻译不恰当支出,还请指出改正.当然我会开一个有关相机开发的一个系列,该系列主要内容包括如下: 相机基本预览拍照功能. 实现相机的Flash,Hdr,滤镜,前后摄

玩转Android Camera开发(一):Surfaceview预览Camera,基础拍照功能完整demo

杂家前文是在2012年的除夕之夜仓促完成,后来很多人指出了一些问题,琐事缠身一直没有进行升级.后来随着我自己的使用,越来越发现不出个升级版的demo是不行了.有时候就连我自己用这个demo测一些性能.功能点,用着都不顺手.当初代码是在linux下写的,弄到windows里下全是乱码.还要自己改几分钟才能改好.另外,很多人说不能正常预览,原因是我在布局里把Surfaceview的尺寸写死了.再有就是initCamera()的时候设参数失败,直接黑屏退出,原因也是我把预览尺寸和照片尺寸写死了.再有就

玩转Android Camera开发(五):基于Google自带算法实时检测人脸并绘制人脸框(网络首发,附完整demo)

本文主要介绍使用Google自带的FaceDetectionListener进行人脸检测,并将检测到的人脸用矩形框绘制出来.本文代码基于PlayCameraV1.0.0,在Camera的open和preview流程上进行了改动.原先是放在单独线程里,这次我又把它放到Surfaceview的生命周期里进行打开和开预览. 首先要反省下,去年就推出了静态图片的人脸检测demo,当时许诺一周内推出Camera预览实时检测并绘制的demo,结果拖到现在才整.哎,屌丝一天又一天,蹉跎啊.在demo制作过程中

玩转Android Camera开发(四):预览界面四周暗中间亮,只拍摄矩形区域图片(附完整源码)

杂家前文曾写过一篇关于只拍摄特定区域图片的demo,只是比较简陋,在坐标的换算上不是很严谨,而且没有完成预览界面四周暗中间亮的效果,深以为憾,今天把这个补齐了. 在上代码之前首先交代下,这里面存在着换算的两种模式.第一种,是以屏幕上的矩形区域为基准进行换算.举个例子,屏幕中间一个 矩形框为100dip*100dip.这里一定要使用dip为单位,否则在不同的手机上屏幕呈现的矩形框大小不一样.先将这个dip换算成px,然后根据屏幕的宽和高的像素计算出矩形区域,传给Surfaceview上铺的一层Vi

浅析Android Camera开发中的三个尺寸和三种变形 (贡献一个自适配Picturesize和Previewsize的工具类)

转至 (http://blog.csdn.net/yanzi1225627/article/details/17652643) 经常听人问Camera开发中,各种变形问题,今天有空就在此梳理总结下. 三个尺寸: 1.Surfaceview的尺寸 Surfaceview是用来预览Camera的,当它全屏时就是Screen的大小. 2.Picturesize的尺寸 这是拍照后的PictureSize尺寸. 3.Previewsize的尺寸 这是预览时帧数据的尺寸. 三种变形: 1.预览画面的物体长宽

玩转Android Camera开发(二):使用TextureView和SurfaceTexture预览Camera 基础拍照demo

Google自Android4.0出了TextureView.为什么推出呢?就是为了弥补Surfaceview的不足.另外一方面也是为了平衡GlSurfaceView.当然这是本人揣度的. 关于TextureView.Surfaceview.SurfaceTexture.GLSurfaceView的关系,待咱家推出GLSurfaceview预览Camera后再专门分析. 本文主要介绍使用TextureView预览Camera. 事实上关于怎样用TextureView预览Camera,官网已经给出

玩转Android Camera开发(四):预览界面四周暗中间亮,仅仅拍摄矩形区域图片(附完整源代码)

杂家前文曾写过一篇关于仅仅拍摄特定区域图片的demo.仅仅是比較简陋.在坐标的换算上不是非常严谨,并且没有完毕预览界面四周暗中间亮的效果,深以为憾.今天把这个补齐了. 在上代码之前首先交代下,这里面存在着换算的两种模式.第一种,是以屏幕上的矩形区域为基准进行换算.举个样例.屏幕中间一个 矩形框为100dip*100dip.这里一定要使用dip为单位,否则在不同的手机上屏幕呈现的矩形框大小不一样. 先将这个dip换算成px.然后依据屏幕的宽和高的像素计算出矩形区域,传给Surfaceview上铺的

玩转Android Camera开发(三):国内首发---使用GLSurfaceView预览Camera 基础拍照demo

GLSurfaceView是OpenGL中的一个类,也是能够预览Camera的,并且在预览Camera上有其独到之处. 独到之处在哪?当使用Surfaceview无能为力.痛不欲生时就仅仅有使用GLSurfaceView了.它能够真正做到让Camera的数据和显示分离,所以搞明确了这个,像Camera仅仅开预览不显示这都是小菜,妥妥的. Android4.0的自带Camera源代码是用SurfaceView预览的.但到了4.2就换成了GLSurfaceView来预览. 现在到了4.4又用了自家的

【转】玩转Android Camera开发(三):国内首发---使用GLSurfaceView预览Camera 基础拍照demo

http://blog.csdn.net/yanzi1225627/article/details/33339965 GLSurfaceView是OpenGL中的一个类,也是可以预览Camera的,而且在预览Camera上有其独到之处.独到之处在哪?当使用Surfaceview无能为力.痛不欲生时就只有使用GLSurfaceView了,它能够真正做到让Camera的数据和显示分离,所以搞明白了这个,像Camera只开预览不显示这都是小菜,妥妥的.Android4.0的自带Camera源码是用Su