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