Android 移動開發 拍攝照片 錄製視頻頁面 分兩大塊 若是業務不是很複雜 對拍攝錄製要求沒有定製化 ps: 4:3 16:9 照片質量 720P 1080P 不須要實現本身的拍照邏輯 只要藉助 Android 原生的 相機 實現拍照錄像便可 若是實現定製化開發 ps:照片尺寸 質量 連拍?等 則須要自行開發java
Android 6.0 以上 相機權限 錄製權限 須要自行申請 這裏再也不講明方法android
<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);
}
}
複製代碼
預覽比例 保存比例 本機是否支持 該比例? 舉個栗子:預覽圖片但願是4:3 拍照保存也是4:3 手機的屏幕倒是 16:9 或者 18:9 如何設置?bash
/** * 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);
}
}
複製代碼
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();
}
複製代碼
@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();
}
複製代碼