安卓使用系统相机拍照录视频

调用系统相机拍照和录制视频代码和踩的坑的总结。


前言

使用surfaceView+MediaRecorder进行视频拍摄和问题记录


1、问题记录

问题记录
1:无法手指缩小放大问题:
修改如下首先重新 onTouchEvent ,记录俩点之间距离和缩放比列,然后重新设置camera中Parameters里的zoom。

   private float startDis;
    private boolean isTouch;
    /**
     * 记录是拖拉照片模式还是放大缩小照片模式
     */

    private static final int MODE_INIT = 0;
    /**
     * 放大缩小照片模式
     */
    private static final int MODE_ZOOM = 1;
    private int mode = MODE_INIT;// 初始状态
    private Point point;

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction() & MotionEvent.ACTION_MASK) {
            case MotionEvent.ACTION_DOWN:
                mode = MODE_INIT;
                break;
            case MotionEvent.ACTION_POINTER_DOWN:
                if (event.getPointerCount() < 2)
                    return super.onTouchEvent(event);
                mode = MODE_ZOOM;
                startDis = spacing(event);//两点的距离
                break;
            case MotionEvent.ACTION_MOVE:
                if (mode == MODE_ZOOM) {
                    if (event.getPointerCount() < 2)
                        return super.onTouchEvent(event);
                    float endDis = spacing(event);//两点的距离
                    int scale = (int) ((endDis - startDis) / 10f);
                    if (scale >= 1 || scale <= -1) {
                        cameraUtils.setCameraZoom(scale);//设置zoom
                        startDis = endDis;
                    }
                }
                break;
            case MotionEvent.ACTION_UP:
                if (mode == MODE_INIT) {
                    point = new Point((int) event.getX(), (int) event.getY());
                    SensorManger.getIntance().lockFocus();
                    cameraUtils.focus();//重新聚焦
                }
                break;
        }
        return super.onTouchEvent(event);
    }

    /**
     * 两点的距离
     */
    private float spacing(MotionEvent event) {
        if (event == null) {
            return 0;
        }
        float x = event.getX(0) - event.getX(1);
        float y = event.getY(0) - event.getY(1);

        return (float) Math.sqrt(x * x + y * y);
    }
 Camera.Parameters parameters = camera.getParameters();
        int zoom = parameters.getZoom() + scale;
        if (zoom < 0) zoom = 0;
        if (zoom > parameters.getMaxZoom())
            zoom = parameters.getMaxZoom();
        parameters.setZoom(zoom);
        camera.setParameters(parameters);

2:部分手机拍摄导致崩溃 start failed:或拍摄后空文件
问题原因:1,MediaRecorder参数设置错误,有的手机不支持。2,参数配置顺序出错。

          //按以下顺序,亲测,都可以正常拍摄视频
           camera.unlock();
            mediaRecorder.setCamera(camera);
            mediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
            mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
            //mediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_LOW));
            mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
            mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT);

            mediaRecorder.setVideoEncodingBitRate(10*1024 * 1024);

            CamcorderProfile mProfile = CamcorderProfile.get(CamcorderProfile.QUALITY_720P);
            if (null!=mProfile){
                mediaRecorder.setVideoEncoder(mProfile.videoCodec);
                mediaRecorder.setVideoFrameRate(mProfile.videoFrameRate);
                Log.d("分辨率",mProfile.videoFrameWidth+"::"+ mProfile.videoFrameHeight);
                //设置录像的分辨率
                mediaRecorder.setVideoSize(mProfile.videoFrameWidth, mProfile.videoFrameHeight);
                mediaRecorder.setAudioEncodingBitRate((int) (mProfile.videoBitRate * 0.7));
             }
               File file = new File(path);
            if (!file.exists()) {
                file.mkdirs();
            }

            mediaRecorder.setOutputFile(name);
            Log.d("录制视频地址",name);

            // 发送广播,通知刷新图库的显示
            ContextFactory.getContext().sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE,
                    Uri.parse("file://" + name)));
            mediaRecorder.setPreviewDisplay(surfaceView.getHolder().getSurface());
            mediaRecorder.prepare();
            mediaRecorder.start();

3:拍摄后导致旋转

    /***不设置时,录制的视频总是倒着,翻屏导致视频上下翻滚*/
            Log.d("摄像头",backOrFtont+"::"+isBack);
            if (backOrFtont == Camera.CameraInfo.CAMERA_FACING_BACK){
                mediaRecorder.setOrientationHint(90);
            }else if (backOrFtont==Camera.CameraInfo.CAMERA_FACING_FRONT){
                mediaRecorder.setOrientationHint(270);
            }

2、工具类代码

代码如下(示例):

public class CameraUtils {
    private MediaRecorder mediaRecorder;
    private Camera camera;
    /*** 标识当前是前摄像头还是后摄像头  back:0  front:1*/
    private int backOrFtont = 0;
    private SurfaceHolder.Callback callback;
    private Context context;
    private SurfaceView surfaceView;
    /***录制视频的videoSize*/
    private int height, width;
    /***photo的height ,width*/
    private int heightPhoto, widthPhoto;

    public void create(SurfaceView surfaceView, Context context) {
        this.context = context;
        this.surfaceView = surfaceView;
        surfaceView.getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
        surfaceView.setKeepScreenOn(true);
        callback = new SurfaceHolder.Callback() {
            public void surfaceCreated(SurfaceHolder holder) {
                camera = Camera.open();
                getVideoSize();//获取拍摄尺寸
                mediaRecorder = new MediaRecorder();

            }

            public void surfaceChanged(SurfaceHolder holder, int format,
                                       int width, int height) {
                 doChange(holder);//切换摄像头
                 focus();//聚焦
            }

            @Override
            public void surfaceDestroyed(SurfaceHolder holder) {
                if (camera != null) {
                    camera.release();
                    camera = null;
                }
            }
        };
        surfaceView.getHolder().addCallback(callback);

    }

    private void doChange(SurfaceHolder holder) {
        try {
            camera.setPreviewDisplay(holder);
            camera.setDisplayOrientation(90);
            camera.startPreview();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    //缩放
    public void setCameraZoom(int scale) {
        Camera.Parameters parameters = camera.getParameters();
        int zoom = parameters.getZoom() + scale;
        if (zoom < 0) zoom = 0;
        if (zoom > parameters.getMaxZoom())
            zoom = parameters.getMaxZoom();
        parameters.setZoom(zoom);
        camera.setParameters(parameters);
    }
    /**
     * 切换摄像头
     */
    public void changeCamera() {
        int cameraCount = 0;
        Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
        cameraCount = Camera.getNumberOfCameras();
        for (int i = 0; i < cameraCount; i++) {
            Camera.getCameraInfo(i, cameraInfo);
            if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT && backOrFtont == 0) {
                camera.stopPreview();
                camera.release();
                camera = null;
                camera = Camera.open(i);
                try {
                    camera.setPreviewDisplay(surfaceView.getHolder());
                    camera.setDisplayOrientation(90);
                } catch (IOException e) {
                    e.printStackTrace();
                }
                backOrFtont = 1;
                camera.startPreview();
                break;
            } else if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_BACK && backOrFtont == 1) {
                camera.stopPreview();
                camera.release();
                camera = null;
                camera = Camera.open(i);
                try {
                    camera.setPreviewDisplay(surfaceView.getHolder());
                    camera.setDisplayOrientation(90);
                } catch (IOException e) {
                    e.printStackTrace();
                }
                camera.startPreview();
                backOrFtont = 0;
                break;
            }
        }

    }

    public void stopRecord() {
        if (mediaRecorder != null) {
            //设置后不会崩
            mediaRecorder.setOnErrorListener(null);
            mediaRecorder.setPreviewDisplay(null);
        }
        mediaRecorder.release();
        camera.release();
        mediaRecorder = null;
        camera = Camera.open();
        mediaRecorder = new MediaRecorder();
        doChange(surfaceView.getHolder());
    }
    public void remuse() {
       backOrFtont=0;
    }

    public void stop() {
        if (mediaRecorder != null && camera != null) {
            mediaRecorder.release();
            camera.release();
        }
    }

    public void destroy() {
        if (mediaRecorder != null && camera != null) {
            mediaRecorder.release();
            camera.release();
            mediaRecorder = null;
            camera = null;
        }

    }

    /**
     * @param path 保存的路径
     * @param name 录像视频名称(不包含后缀)
     * @param isBack
     */
    public void startRecord(String path, String name, boolean isBack) {

        try {
            camera.unlock();
            mediaRecorder.setCamera(camera);
            mediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
            mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
            //mediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_LOW));
            mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
            mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT);

            mediaRecorder.setVideoEncodingBitRate(10*1024 * 1024);

      /*  if (backOrFtont==0){
            mediaRecorder.setVideoSize(640,480);
            mediaRecorder.setVideoFrameRate(24);
        }else {*/
            CamcorderProfile mProfile = CamcorderProfile.get(CamcorderProfile.QUALITY_720P);
            if (null!=mProfile){
                mediaRecorder.setVideoEncoder(mProfile.videoCodec);
                mediaRecorder.setVideoFrameRate(mProfile.videoFrameRate);
                Log.d("分辨率",mProfile.videoFrameWidth+"::"+ mProfile.videoFrameHeight);
                //设置录像的分辨率
                mediaRecorder.setVideoSize(mProfile.videoFrameWidth, mProfile.videoFrameHeight);
                mediaRecorder.setAudioEncodingBitRate((int) (mProfile.videoBitRate * 0.7));

            }else {
               // mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
                //mediaRecorder.setVideoFrameRate(30);
               // mediaRecorder.setVideoSize(WIDTH_DEF, HEIGHT_DEF);

               // mediaRecorder.setVideoEncodingBitRate((int) (1920000 * 0.7));

                mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
                //mediaRecorder.setAudioEncodingBitRate(128000);
                //mediaRecorder.setAudioChannels(2);
                //mediaRecorder.setAudioSamplingRate(48000);


            }


            File file = new File(path);
            if (!file.exists()) {
                file.mkdirs();
            }

            mediaRecorder.setOutputFile(name);
            Log.d("录制视频地址",name);

            // 发送广播,通知刷新图库的显示
            ContextFactory.getContext().sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE,
                    Uri.parse("file://" + name)));
            mediaRecorder.setPreviewDisplay(surfaceView.getHolder().getSurface());
            /***不设置时,录制的视频总是倒着,翻屏导致视频上下翻滚*/
            Log.d("摄像头",backOrFtont+"::"+isBack);
            if (backOrFtont == Camera.CameraInfo.CAMERA_FACING_BACK){
                mediaRecorder.setOrientationHint(90);
            }else if (backOrFtont==Camera.CameraInfo.CAMERA_FACING_FRONT){
                mediaRecorder.setOrientationHint(270);
            }
            mediaRecorder.prepare();
            mediaRecorder.start();

        }catch (Exception e){
            e.printStackTrace();
            ToastUtils.showToast(AppManager.getAppManager().currentActivity(),"拍摄视频出错",false);
        }

    }


    /***
     * 获取SupportedVideoSizes 控制输出视频width在300到600之间(尽可能小)
     * 获取PictureSize的大小(控制在w:1000-2000之间)
     */
    public void getVideoSize() {
        Camera.Parameters parameters = camera.getParameters();
        List<Camera.Size> videoSize = parameters.getSupportedVideoSizes();
        for (int i = 0; i < videoSize.size(); i++) {
            int width1 = videoSize.get(i).width;
            int height1 = videoSize.get(i).height;
            if (width1 >= 600 && width1 <= 900) {
                if (height1 >= 700 && height1 <= 1000) {
                    width = width1;
                    height = height1;
                }
            }
            Log.d("路径", "getVideoSize:----w:-- " + videoSize.get(i).width + "---h:--" + videoSize.get(i).height);
        }
        parameters.setRecordingHint(true); //主要用于MediaRecord录像
        parameters.setPreviewFpsRange(30000, 30000);  //主要用于设置视频的帧数
        camera.setParameters(parameters);


        List<Camera.Size> photoSize = parameters.getSupportedPictureSizes();
        for (int i = 0; i < photoSize.size(); i++) {
            int width1 = photoSize.get(i).width;
            int height1 = photoSize.get(i).height;
            if (width1 >= 1400 && width1 <= 2000) {
                if (height1 >= 1400 && height1 <=2000) {
                    widthPhoto = width1;
                    heightPhoto = height1;
                }
            }
        }

    }

    /**
     * 聚焦
     */
    public void focus(){
        try {
            Camera.Parameters parameters=camera.getParameters();
            parameters.setPictureSize(widthPhoto,heightPhoto);
            parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
            camera.setParameters(parameters);
            camera.cancelAutoFocus();
        }catch (Exception e){
            e.printStackTrace();
        }

    }


    public void takePicture(String photoPath, String photoName) {
        Camera.Parameters parameters=camera.getParameters();
        parameters.setJpegQuality(100);
        camera.takePicture(null, null, new PictureCallBack(photoPath, photoName));
    }
    private Bitmap bitmap;
    /*** 拍照功能*/
    private class PictureCallBack implements Camera.PictureCallback {
        /*** 照片保存的路径和名称*/
        private String path;
        private String name;

        public PictureCallBack(String path, String name) {
            this.path = path;
            this.name = name;
        }

        @Override
        public void onPictureTaken(byte[] data, Camera camera) {
            bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
            if (backOrFtont == Camera.CameraInfo.CAMERA_FACING_BACK){
                bitmap = matrixBitmap(bitmap,90); //此方法将Bitmap 旋转90度
            }else if (backOrFtont == Camera.CameraInfo.CAMERA_FACING_FRONT){
                bitmap = matrixBitmap(bitmap,-90);
            }
            try {
                File filePic = new File(path + name);
                if (!filePic.exists()) {
                    filePic.getParentFile().mkdirs();
                    filePic.createNewFile();
                }
                FileOutputStream fos = new FileOutputStream(filePic);
                //Bitmap endBit = Bitmap.createScaledBitmap(mBitmap, 720, 1280, true); //创建新的图像大小
                bitmap.compress(Bitmap.CompressFormat.JPEG, 90, fos);
                fos.flush();
                fos.close();
                // 发送广播,通知刷新图库的显示
                ContextFactory.getContext().sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE,
                        Uri.parse("file://" + filePic)));
            } catch (Exception e) {
                e.printStackTrace();
            }
            camera.startPreview();

        }
    }
    /**
     * 对bitmap进行旋转
     *
     * @param bitmap
     * @param i
     * @return
     */
    public Bitmap matrixBitmap(Bitmap bitmap, int i) {
        Matrix matrix = new Matrix();
        matrix.postRotate(i);
        Bitmap bm = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
        return bm;
    }
    /**
     * 返回合适的照片尺寸参数
     *
     * @param cameraParameters
     * @param bl
     * @return
     */
    private Camera.Size findFitPicResolution(Camera.Parameters cameraParameters, float bl) throws Exception {
        List<Camera.Size> supportedPicResolutions = cameraParameters.getSupportedPictureSizes();

        Camera.Size resultSize = null;
        for (Camera.Size size : supportedPicResolutions) {
            if ((float) size.width / size.height == bl && size.width <= ALLOW_PIC_LEN && size.height <= ALLOW_PIC_LEN) {
                if (resultSize == null) {
                    resultSize = size;
                } else if (size.width > resultSize.width) {
                    resultSize = size;
                }
            }
        }
        if (resultSize == null) {
            return supportedPicResolutions.get(0);
        }
        return resultSize;
    }

    private boolean equalRate(int width, int height, float rate) {
        float r = (float) width / (float) height;
        if (Math.abs(r - rate) <= 0.2) {
            return true;
        } else {
            return false;
        }
    }
}
Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐