Android 拍攝 錄制

# 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 參數設置

# 拍攝 錄制流程圖

camera_flow.png

# 設置相機參數

預覽比例 保存比例 本機是否支持 該比例?
舉個栗子:預覽圖片希望是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();
}
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容