# Android 拍摄 录制

Android 移动开发 拍摄照片 录制视频页面 分两大块 如果业务不是很复杂 对拍摄录制要求没有定制化 ps: 4:3 16:9 照片质量 720P 1080P 不需要实现自己的拍照逻辑 只要借助 Android 原生的 相机 实现拍照录像即可 如果实现定制化开发 ps:照片尺寸 质量 连拍?等 则需要自行开发

# 申请必要的权限

Android 6.0 以上 相机权限 录制权限 需要自行申请 这里不再讲明方法

<uses-feature android:name="android.hardware.camera" />
	  <uses-feature android:name="android.hardware.camera.autofocus" />
	  <uses-permission android:name="android.permission.CAMERA" />
      <uses-permission android:name="android.permission.RECORD_AUDIO" />
	  <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
	  <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
复制代码

# 调用系统相机->拍摄照片

try {
					//检测相机 权限
                    CameraPermissionsUtils.checkCameraPermissions();
					//设置拍摄照片保存位置
                    File file = getStorgeFile();
                    imgSavePath = file.getPath();
				
                    Intent intentFromCapture = new Intent(
                            MediaStore.ACTION_IMAGE_CAPTURE);

					 //添加这一句表示对目标应用临时授权该Uri所代表的文件
                    intentFromCapture.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
                  
                    intentFromCapture.putExtra(MediaStore.EXTRA_OUTPUT,getUriForFile(getActivity(), file));
                    startActivityForResult(intentFromCapture,
                            FLAG_CAMERA);
           } catch (Exception e) {
              ToastUtils.shortToastMessage(BaseApplication.getContext(), "请检查下您是否禁用了照相权限!");
			  //执行申请 权限 代码 ...
           }

		@Override
	    public void onActivityResult(int requestCode, int resultCode, Intent data) {
	        super.onActivityResult(requestCode, resultCode, data);
	        if (resultCode == RESULT_OK) {
	            switch (requestCode) {
	                //相机拍摄
	                case FLAG_CAMERA:
	                    File file = new File(imgSavePath);
						//裁剪 拍摄的照片
	                    cropImageUri(getUriForFile(getActivity(), file), 800, 800, FLAG_CLIP, FLAG_CAMERA);
	                    break;
	            }
	        }
	    }
复制代码

# 调用系统相机->录制视频

static final int REQUEST_VIDEO_CAPTURE = 1;

	private void dispatchTakeVideoIntent() {
	    Intent takeVideoIntent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
	    if (takeVideoIntent.resolveActivity(getPackageManager()) != null) {
	        startActivityForResult(takeVideoIntent, REQUEST_VIDEO_CAPTURE);
	    }
	}
	
	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
	    if (requestCode == REQUEST_VIDEO_CAPTURE && resultCode == RESULT_OK) {
	        Uri videoUri = intent.getData();
	        videoView.setVideoURI(videoUri);
	    }
	}
复制代码

# 自定义拍摄 录制

  • 设置Camera 参数
  • 初始化 SurfaceView
  • MediaRecorder 参数设置

# 拍摄 录制流程图



# 设置相机参数

预览比例 保存比例 本机是否支持 该比例? 举个栗子:预览图片希望是4:3 拍照保存也是4:3 手机的屏幕却是 16:9 或者 18:9 如何设置?

  • 按屏幕宽设置 预览View的高
  • 按照比例设置 预览View的宽高 screenHeight = screenWith/3*4
  • 按照预览的比例去轮询 相机支持的参数 设置宽高比
/**
	     * doStartPreview
	     * @param holder
	     * @param screenProp H/W
	     */
	    public void doStartPreview(SurfaceHolder holder, float screenProp) {
	        if (isPreviewing) {
	            LogUtil.i("doStartPreview isPreviewing");
	        }
	        if (this.screenProp < 0) {
	            this.screenProp = screenProp;
	        }
	        if (holder == null) {
	            return;
	        }
	        this.mHolder = holder;
	        if (mCamera != null) {
	            try {
	                mParams = mCamera.getParameters();
	
	                mParams.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
	                //闪关灯配置
	                //自动模式,当光线较暗时自动打开闪光灯;
	                mParams.setFlashMode(Camera.Parameters.FLASH_MODE_AUTO);
	                //对焦模式
	                //自动模式
	                mParams.setFocusMode(Camera.Parameters.FOCUS_MODE_MACRO);
	
	              
	                mParams = mCamera.getParameters();
	                Camera.Size previewSize = CameraParamUtil.getInstance().getPreviewSize(mParams
	                        .getSupportedPreviewSizes(), DisplayUtils.getScreenMetrics(BaseApp.getContext()).x, screenProp);
	                Camera.Size pictureSize = CameraParamUtil.getInstance().getPictureSize(mParams
	                        .getSupportedPictureSizes(), DisplayUtils.getScreenMetrics(BaseApp.getContext()).x, screenProp);
	                mParams.setPreviewSize(previewSize.width, previewSize.height);
	                preview_width = previewSize.width;
	                preview_height = previewSize.height;
	                mParams.setPictureSize(pictureSize.width, pictureSize.height);

					//设置聚焦方式
	                if (CameraParamUtil.getInstance().isSupportedFocusMode(
	                        mParams.getSupportedFocusModes(), android.hardware.Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {
	                    mParams.setFocusMode(android.hardware.Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
	                }
					// 设置图片保存
	                if (CameraParamUtil.getInstance().isSupportedPictureFormats(mParams.getSupportedPictureFormats(),
	                        ImageFormat.JPEG)) {
	                    mParams.setPictureFormat(ImageFormat.JPEG);
	                    mParams.setJpegQuality(100);
	                }
	
	                mCamera.setParameters(mParams);
	                mParams = mCamera.getParameters();
	                mCamera.setPreviewDisplay(holder);  //SurfaceView
	                mCamera.setDisplayOrientation(cameraAngle);//浏览角度
	                mCamera.setPreviewCallback(this); //每一帧回调
	                mCamera.startPreview();//启动浏览
	                isPreviewing = true;
	                Log.i(TAG, "=== Start Preview ===");
	            } catch (Exception e) {
	                e.printStackTrace();
	            }
		        }
		   	}

- 按照比例 查询最优 尺寸
			
	     public Camera.Size getPreviewSize(List<Camera.Size> list, int th, float rate) {
	        Collections.sort(list, sizeComparator);
	        int i = 0;
	        for (Camera.Size s : list) {
	            if ((s.width > th) && equalRate(s, rate)) {
	                Log.i(TAG, "MakeSure Preview :w = " + s.width + " h = " + s.height);
	                break;
	            }
	            i++;
	        }
	        if (i == list.size()) {
	            return getBestSize(list, rate);
	        } else {
	            return list.get(i);
	        }
	    }
		
		//排序
		private class CameraSizeComparator implements Comparator<Camera.Size> {
       				 public int compare(Camera.Size lhs, Camera.Size rhs) {
	            if (lhs.width == rhs.width) {
	                return 0;
	            } else if (lhs.width > rhs.width) {
	                return 1;
	            } else {
	                return -1;
	            }
	        }
    	}

		//换算 比例差别 
		//如果差别 上下不超过 0.2 则为最佳尺寸	
		private boolean equalRate(Camera.Size s, float rate) {
		        float r = (float) (s.width) / (float) (s.height);
		        return Math.abs(r - rate) <= 0.2;
		 }
复制代码

# 拍照方法 很简单这里不再描述

/**
     * Equivalent to <pre>takePicture(Shutter, raw, null, jpeg)</pre>.
     *
     * @see #takePicture(ShutterCallback, PictureCallback, PictureCallback, PictureCallback)
     */
    public final void takePicture(ShutterCallback shutter, PictureCallback raw,
            PictureCallback jpeg) {
        takePicture(shutter, raw, null, jpeg);
    }
复制代码

# 录制

# 设置录制参数:

//启动录像
    public void startRecord(Surface surface, float screenProp, ErrorCallback callback) {
        mCamera.setPreviewCallback(null);
        final int nowAngle = (angle + 90) % 360;
        //获取第一帧图片
        Camera.Parameters parameters = mCamera.getParameters();
        int width = parameters.getPreviewSize().width;
        int height = parameters.getPreviewSize().height;
        YuvImage yuv = new YuvImage(firstFrame_data, parameters.getPreviewFormat(), width, height, null);
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        yuv.compressToJpeg(new Rect(0, 0, width, height), 50, out);
        byte[] bytes = out.toByteArray();
        videoFirstFrame = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
        Matrix matrix = new Matrix();
        if (SELECTED_CAMERA == CAMERA_POST_POSITION) {
            matrix.setRotate(nowAngle);
        } else if (SELECTED_CAMERA == CAMERA_FRONT_POSITION) {
            matrix.setRotate(270);
        }
        videoFirstFrame = createBitmap(videoFirstFrame, 0, 0, videoFirstFrame.getWidth(), videoFirstFrame
                .getHeight(), matrix, true);

        if (isRecorder) {
            return;
        }
        if (mCamera == null) {
            openCamera(SELECTED_CAMERA);
        }
        if (mediaRecorder == null) {
            mediaRecorder = new MediaRecorder();
        }
        if (mParams == null) {
            mParams = mCamera.getParameters();
        }
        List<String> focusModes = mParams.getSupportedFocusModes();
        if (focusModes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO)) {
            mParams.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
        }
        mCamera.setParameters(mParams);
        mCamera.unlock();
        mediaRecorder.reset();
        mediaRecorder.setCamera(mCamera);
        mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA); //视频采集来源

        mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);

        mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4); //输出格式
        mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264); //编码格式
        mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC); //音频模式

		//设置视频输出 尺寸比例
        Camera.Size videoSize;
        if (mParams.getSupportedVideoSizes() == null) {
            videoSize = CameraParamUtil.getInstance().getPreviewSize(mParams.getSupportedPreviewSizes(),
                    DisplayUtils.getScreenMetrics(BaseApp.getContext()).x, screenProp);
        } else {
            //            videoSize = CameraParamUtil.getInstance().getPreviewSize(mParams.getSupportedVideoSizes(), 600,
            //                    screenProp);
            videoSize = CamParaUtil.getInstance().getOptimalSize(mParams.getSupportedVideoSizes(),
                    DisplayUtils.getScreenMetrics(BaseApp.getContext()).x, DisplayUtils.getScreenMetrics(BaseApp.getContext()).y);
        }
        Log.i(TAG, "setVideoSize    width = " + videoSize.width + "height = " + videoSize.height);
        if (videoSize.width == videoSize.height) {
            mediaRecorder.setVideoSize(preview_width, preview_height);
        } else {
            mediaRecorder.setVideoSize(videoSize.width, videoSize.height);
        }

        //        if (SELECTED_CAMERA == CAMERA_FRONT_POSITION) {
        //            mediaRecorder.setOrientationHint(270);
        //        } else {
        //            mediaRecorder.setOrientationHint(nowAngle);
                    mediaRecorder.setOrientationHint(90);
        //        }
        if (SELECTED_CAMERA == CAMERA_FRONT_POSITION) {
            //手机预览倒立的处理
            if (cameraAngle == 270) {
                //横屏
                if (nowAngle == 0) {
                    mediaRecorder.setOrientationHint(180);
                } else if (nowAngle == 270) {
                    mediaRecorder.setOrientationHint(270);
                } else {
                    mediaRecorder.setOrientationHint(90);
                }
            } else {
                if (nowAngle == 90) {
                    mediaRecorder.setOrientationHint(270);
                } else if (nowAngle == 270) {
                    mediaRecorder.setOrientationHint(90);
                } else {
                    mediaRecorder.setOrientationHint(nowAngle);
                }
            }
        } else {
            mediaRecorder.setOrientationHint(nowAngle);
        }


        //        if (DeviceUtil.isHuaWeiRongyao()) {
        //            mediaRecorder.setVideoEncodingBitRate(4 * 100000);
        //        } else {
        //            mediaRecorder.setVideoEncodingBitRate(mediaQuality);
        //        }
		
		//设置帧率
        mediaRecorder.setVideoFrameRate(24);
		//设置比特率
        mediaRecorder.setVideoEncodingBitRate(mediaQuality);
        mediaRecorder.setPreviewDisplay(surface);
		
		//文件保存文位置 设置
        videoFileName = "video_" + System.currentTimeMillis() + ".mp4";
        if (saveVideoPath.equals("")) {
            saveVideoPath = Environment.getExternalStorageDirectory().getPath();
        }
        //        videoFileAbsPath = saveVideoPath + File.separator + videoFileName;
        videoFileAbsPath = FileUtil.initPath() + videoFileName;
        mediaRecorder.setOutputFile(videoFileAbsPath);

        try {
            mediaRecorder.prepare();
            mediaRecorder.start();
            isRecorder = true;
        } catch (IllegalStateException e) {
            e.printStackTrace();
            Log.i("CJT", "startRecord IllegalStateException");
            if (this.errorLisenter != null) {
                this.errorLisenter.onError();
            }
        } catch (IOException e) {
            e.printStackTrace();
            Log.i("CJT", "startRecord IOException");
            if (this.errorLisenter != null) {
                this.errorLisenter.onError();
            }
        } catch (RuntimeException e) {
            Log.i("CJT", "startRecord RuntimeException");
        }
    }

	 //停止录像
    public void stopRecord(boolean isShort, StopRecordCallback callback) {
        if (!isRecorder) {
            return;
        }
        if (mediaRecorder != null) {
            mediaRecorder.setOnErrorListener(null);
            mediaRecorder.setOnInfoListener(null);
            mediaRecorder.setPreviewDisplay(null);
            try {
                mediaRecorder.stop();
            } catch (RuntimeException e) {
                e.printStackTrace();
                mediaRecorder = null;
                mediaRecorder = new MediaRecorder();
            } finally {
                if (mediaRecorder != null) {
                    mediaRecorder.release();
                }
                mediaRecorder = null;
                isRecorder = false;
            }
            if (isShort) {
                if (FileUtil.deleteFile(videoFileAbsPath)) {
                    callback.recordResult(null, null);
                }
                return;
            }
            doStopPreview();
            String fileName = FileUtil.initPath() + videoFileName;
            callback.recordResult(fileName, videoFirstFrame);
        }
    }
复制代码

# surfceView 设置

mSurfaceView = (SurfaceView) findViewById(R.id.surface_view);
    mHolder = mSurfaceView.getHolder();
    mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    mHolder.addCallback(this);

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
		//开启相机
        new Thread() {
            @Override
            public void run() {
                CameraInterface.getInstance().doOpenCamera(CameraShootActivity.this);
            }
        }.start();
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
		//释放相机
        LogUtil.i("JCameraView SurfaceDestroyed");
        CameraInterface.getInstance().doDestroyCamera();
    }
复制代码

# Activity 生命周期

@Override
    protected void onResume() {
        super.onResume();
        CameraInterface.getInstance().registerSensorManager(this);
        if (screenProp > 1.4) {
            isSwitchRecording = true;
            CameraInterface.getInstance().doStopPreview();
            //如果当前屏占比 大于1.8 不是 16:9 采用 16:9设置 小于16:9 采用原先屏占比
            CameraInterface.getInstance().doStartPreview(mSurfaceView.getHolder(), DisplayUtils.getScreenRate(this) > 1.8
                    ? 16f / 9f : DisplayUtils.getScreenRate(this));
            screenProp = DisplayUtils.getScreenRate(this) > 1.8
                    ? 16f / 9f : DisplayUtils.getScreenRate(this);
            measureVideoSize();
        } else {
            isSwitchRecording = false;
            CameraInterface.getInstance().doStopPreview();
            screenProp = 4f / 3f;
            CameraInterface.getInstance().doStartPreview(mSurfaceView.getHolder(), 4f / 3f);
            measureCameraSize();
        }
    }
	
	 @Override
    protected void onPause() {
        super.onPause();
        CameraInterface.getInstance().isPreview(false);
        CameraInterface.getInstance().unregisterSensorManager(this);
        CameraInterface.getInstance().doStopPreview();
    }
复制代码