最近在开发即时通讯这个模块的时候使用到了自定义的相机,需求与微信一样,要求相机能长按和轻点,当时在网上找自定义相机的资源,很少,所以,我在这里把我的一些开发经验贴出来,供大家学习。
大致完成的功能如下:
- 长按拍摄视频,轻点拍照
- 前后摄像头的切换
- 闪光的的开启,关闭,自动
- 图片的压缩
- 自动聚焦,手动聚焦
效果图如下:
相关代码如下:
package com.ses.im.app.chat.newcamera; import android.app.Activity; import android.content.Context; import android.content.Intent; import android.graphics.PointF; import android.graphics.SurfaceTexture; import android.hardware.Camera; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v7.app.AppCompatActivity; import android.view.Surface; import android.view.TextureView; import android.view.View; import android.widget.ImageView; import android.widget.RelativeLayout; import android.widget.TextView; import com.ses.im.app.chat.R; import java.io.File; import java.util.concurrent.TimeUnit; import rx.Observable; import rx.Subscriber; import rx.Subscription; import rx.android.schedulers.AndroidSchedulers; import rx.schedulers.Schedulers; /** * * 拍摄界面 */ public class CameraActivity extends AppCompatActivity implements View.OnClickListener { /** * 获取相册 */ public static final int REQUEST_PHOTO = 1; /** * 获取视频 */ public static final int REQUEST_VIDEO = 2; /** * 最小录制时间 */ private static final int MIN_RECORD_TIME = 1 * 1000; /** * 最长录制时间 */ private static final int MAX_RECORD_TIME = 15 * 1000; /** * 刷新进度的间隔时间 */ private static final int PLUSH_PROGRESS = 100; private Context mContext; /** * TextureView */ private TextureView mTextureView; /** * 带手势识别 */ private CameraView mCameraView; /** * 录制按钮 */ private CameraProgressBar mProgressbar; /** * 顶部像机设置 */ private RelativeLayout rl_camera; /** * 关闭,选择,前后置 */ private ImageView iv_close, iv_facing; private RelativeLayout iv_choice; private RelativeLayout cancel; /** * 闪光 */ private TextView tv_flash; /** * camera manager */ private CameraManager cameraManager; /** * player manager */ private MediaPlayerManager playerManager; /** * true代表视频录制,否则拍照 */ private boolean isSupportRecord; /** * 视频录制地址 */ private String recorderPath; /** * 图片地址 */ private String photoPath; /** * 录制视频的时间,毫秒 */ private int recordSecond; /** * 获取照片订阅, 进度订阅 */ private Subscription takePhotoSubscription, progressSubscription; /** * 是否正在录制 */ private boolean isRecording; /** * 是否为点了拍摄状态(没有拍照预览的状态) */ private boolean isPhotoTakingState; public static void lanuchForPhoto(Activity context) { Intent intent = new Intent(context, CameraActivity.class); context.startActivityForResult(intent, REQUEST_PHOTO); } @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); mContext = this; setContentView(R.layout.activity_camera); initView(); initDatas(); } private void initView() { mTextureView = (TextureView) findViewById(R.id.mTextureView); mCameraView = (CameraView) findViewById(R.id.mCameraView); mProgressbar = (CameraProgressBar) findViewById(R.id.mProgressbar); rl_camera = (RelativeLayout) findViewById(R.id.rl_camera); iv_close = (ImageView) findViewById(R.id.iv_close); iv_close.setOnClickListener(this); iv_choice = (RelativeLayout) findViewById(R.id.iv_choice); iv_choice.setOnClickListener(this); iv_close.setOnClickListener(this); iv_facing = (ImageView) findViewById(R.id.iv_facing); iv_facing.setOnClickListener(this); iv_close.setOnClickListener(this); tv_flash = (TextView) findViewById(R.id.tv_flash); tv_flash.setOnClickListener(this); cancel= (RelativeLayout) findViewById(R.id.cancel); cancel.setOnClickListener(this); } protected void initDatas() { cameraManager = CameraManager.getInstance(getApplication()); playerManager = MediaPlayerManager.getInstance(getApplication()); cameraManager.setCameraType(isSupportRecord ? 1 : 0); tv_flash.setVisibility(cameraManager.isSupportFlashCamera() ? View.VISIBLE : View.GONE); setCameraFlashState(); iv_facing.setVisibility(cameraManager.isSupportFrontCamera() ? View.VISIBLE : View.GONE); rl_camera.setVisibility(cameraManager.isSupportFlashCamera() || cameraManager.isSupportFrontCamera() ? View.VISIBLE : View.GONE); final int max = MAX_RECORD_TIME / PLUSH_PROGRESS; mProgressbar.setMaxProgress(max); /** * 拍照,拍摄按钮监听 */ mProgressbar.setOnProgressTouchListener(new CameraProgressBar.OnProgressTouchListener() { @Override public void onClick(CameraProgressBar progressBar) { cameraManager.takePhoto(callback); isSupportRecord = false; } @Override public void onLongClick(CameraProgressBar progressBar) { isSupportRecord = true; cameraManager.setCameraType(1); rl_camera.setVisibility(View.GONE); recorderPath = FileUtils.getUploadVideoFile(mContext); cameraManager.startMediaRecord1(recorderPath); isRecording = true; progressSubscription = Observable.interval(100, TimeUnit.MILLISECONDS, AndroidSchedulers.mainThread()).take(max).subscribe(new Subscriber() { @Override public void onCompleted() { stopRecorder(true); } @Override public void onError(Throwable e) { } @Override public void onNext(Long aLong) { mProgressbar.setProgress(mProgressbar.getProgress() + 1); } }); } @Override public void onZoom(boolean zoom) { cameraManager.handleZoom(zoom); } @Override public void onLongClickUp(CameraProgressBar progressBar) { // isSupportRecord = false; cameraManager.setCameraType(0); stopRecorder(true); if (progressSubscription != null) { progressSubscription.unsubscribe(); } } @Override public void onPointerDown(float rawX, float rawY) { if (mTextureView != null) { mCameraView.setFoucsPoint(new PointF(rawX, rawY)); } } }); /** *点击预览图聚焦 */ mCameraView.setOnViewTouchListener(new CameraView.OnViewTouchListener() { @Override public void handleFocus(float x, float y) { cameraManager.handleFocusMetering(x, y); } @Override public void handleZoom(boolean zoom) { cameraManager.handleZoom(zoom); } }); } /** * 设置闪光状态 */ private void setCameraFlashState() { int flashState = cameraManager.getCameraFlash(); switch (flashState) { case 0: //自动 tv_flash.setSelected(true); tv_flash.setText("自动"); break; case 1://open tv_flash.setSelected(true); tv_flash.setText("开启"); break; case 2: //close tv_flash.setSelected(false); tv_flash.setText("关闭"); break; } } /** * 是否显示录制按钮 * @param isShow */ private void setTakeButtonShow(boolean isShow) { if (isShow) { mProgressbar.setVisibility(View.VISIBLE); rl_camera.setVisibility(cameraManager.isSupportFlashCamera() || cameraManager.isSupportFrontCamera() ? View.VISIBLE : View.GONE); } else { mProgressbar.setVisibility(View.GONE); rl_camera.setVisibility(View.GONE); } } /** * 停止拍摄 */ private void stopRecorder(boolean play) { isRecording = false; cameraManager.stopMediaRecord(); recordSecond = mProgressbar.getProgress() * PLUSH_PROGRESS;//录制多少毫秒 mProgressbar.reset(); if (recordSecond < MIN_RECORD_TIME) {//小于最小录制时间作废 if (recorderPath != null) { FileUtils.delteFiles(new File(recorderPath)); recorderPath = null; recordSecond = 0; } setTakeButtonShow(true); } else if (play && mTextureView != null && mTextureView.isAvailable()){ setTakeButtonShow(false); mProgressbar.setVisibility(View.GONE); iv_choice.setVisibility(View.VISIBLE); cancel.setVisibility(View.VISIBLE); iv_close.setVisibility(View.GONE); cameraManager.closeCamera(); playerManager.playMedia(new Surface(mTextureView.getSurfaceTexture()), recorderPath); } } @Override protected void onResume() { super.onResume(); if (mTextureView.isAvailable()) { if (recorderPath != null) {//优先播放视频 iv_choice.setVisibility(View.VISIBLE); setTakeButtonShow(false); playerManager.playMedia(new Surface(mTextureView.getSurfaceTexture()), recorderPath); } else { iv_choice.setVisibility(View.GONE); setTakeButtonShow(true); cameraManager.openCamera(mTextureView.getSurfaceTexture(), mTextureView.getWidth(), mTextureView.getHeight()); } } else { mTextureView.setSurfaceTextureListener(listener); } } @Override protected void onPause() { if (progressSubscription != null) { progressSubscription.unsubscribe(); } if (takePhotoSubscription != null) { takePhotoSubscription.unsubscribe(); } if (isRecording) { stopRecorder(false); } cameraManager.closeCamera(); playerManager.stopMedia(); super.onPause(); } @Override protected void onDestroy() { mCameraView.removeOnZoomListener(); super.onDestroy(); } @Override public void onClick(View v) { int i = v.getId(); if (i == R.id.iv_close) { // if (recorderPath != null) {//有拍摄好的正在播放,重新拍摄 // FileUtils.delteFiles(new File(recorderPath)); // recorderPath = null; // recordSecond = 0; // playerManager.stopMedia(); // setTakeButtonShow(true); // iv_choice.setVisibility(View.GONE); // cameraManager.openCamera(mTextureView.getSurfaceTexture(), mTextureView.getWidth(), mTextureView.getHeight()); // } else if (isPhotoTakingState) { // isPhotoTakingState = false; // iv_choice.setVisibility(View.GONE); // setTakeButtonShow(true); // cameraManager.restartPreview(); // } else { finish(); // } } else if (i == R.id.iv_choice) {//拿到图片或视频路径 Intent intent=new Intent(); if(isSupportRecord){ intent.putExtra("videopath", recorderPath); setResult(3, intent); finish(); }else{ intent.putExtra("videopath", photoPath); setResult(3, intent); finish(); } } else if (i == R.id.tv_flash) { cameraManager.changeCameraFlash(mTextureView.getSurfaceTexture(), mTextureView.getWidth(), mTextureView.getHeight()); setCameraFlashState(); } else if (i == R.id.iv_facing) { cameraManager.changeCameraFacing(mTextureView.getSurfaceTexture(), mTextureView.getWidth(), mTextureView.getHeight()); }else if(i == R.id.cancel){ if (recorderPath != null) {//有拍摄好的正在播放,重新拍摄 FileUtils.delteFiles(new File(recorderPath)); recorderPath = null; recordSecond = 0; playerManager.stopMedia(); setTakeButtonShow(true); iv_choice.setVisibility(View.GONE); cancel.setVisibility(View.GONE); iv_close.setVisibility(View.VISIBLE); cameraManager.openCamera(mTextureView.getSurfaceTexture(), mTextureView.getWidth(), mTextureView.getHeight()); } else if (isPhotoTakingState) { isPhotoTakingState = false; iv_choice.setVisibility(View.GONE); cancel.setVisibility(View.GONE); iv_close.setVisibility(View.VISIBLE); setTakeButtonShow(true); cameraManager.restartPreview(); } } } /** * camera回调监听 */ private TextureView.SurfaceTextureListener listener = new TextureView.SurfaceTextureListener() { @Override public void onSurfaceTextureAvailable(SurfaceTexture texture, int width, int height) { if (recorderPath != null) { iv_choice.setVisibility(View.VISIBLE); setTakeButtonShow(false); playerManager.playMedia(new Surface(texture), recorderPath); } else { setTakeButtonShow(true); iv_choice.setVisibility(View.GONE); cameraManager.openCamera(texture, width, height); } } @Override public void onSurfaceTextureSizeChanged(SurfaceTexture texture, int width, int height) { } @Override public boolean onSurfaceTextureDestroyed(SurfaceTexture texture) { return true; } @Override public void onSurfaceTextureUpdated(SurfaceTexture texture) { } }; private Camera.PictureCallback callback = new Camera.PictureCallback() { @Override public void onPictureTaken(final byte[] data, Camera camera) { setTakeButtonShow(false); takePhotoSubscription = Observable.create(new Observable.OnSubscribe () { @Override public void call(Subscriber super Boolean> subscriber) { if (!subscriber.isUnsubscribed()) { photoPath = FileUtils.getUploadPhotoFile(mContext); isPhotoTakingState = FileUtils.savePhoto(photoPath, data, cameraManager.isCameraFrontFacing()); subscriber.onNext(isPhotoTakingState); } } }).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Subscriber () { @Override public void onCompleted() { } @Override public void onError(Throwable e) { } @Override public void onNext(Boolean aBoolean) { if (aBoolean != null && aBoolean) { iv_choice.setVisibility(View.VISIBLE); cancel.setVisibility(View.VISIBLE); iv_close.setVisibility(View.GONE); } else { setTakeButtonShow(true); } } }); } }; }
相机管理类:
package com.ses.im.app.chat.newcamera; import android.app.Application; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.SurfaceTexture; import android.hardware.Camera; import android.media.CamcorderProfile; import android.media.MediaRecorder; import android.util.Log; import android.widget.Toast; import com.ses.im.app.chat.util.AppConfig; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; /** * * 相机管理类 */ public final class CameraManager { private Application context; /** * camera */ private Camera mCamera; private Camera.Parameters mParameters; /** * 视频录制 */ private MediaRecorder mMediaRecorder; /** * 相机闪光状态 */ private int cameraFlash; /** * 前后置状态 */ private int cameraFacing = Camera.CameraInfo.CAMERA_FACING_BACK; /** * 是否支持前置摄像,是否支持闪光 */ private boolean isSupportFrontCamera, isSupportFlashCamera; /** * 录制视频的相关参数 */ private CamcorderProfile mProfile; /** * 0为拍照, 1为录像 */ private int cameraType; private CameraManager(Application context) { this.context = context; isSupportFrontCamera = CameraUtils.isSupportFrontCamera(); isSupportFlashCamera = CameraUtils.isSupportFlashCamera(context); if (isSupportFrontCamera) { cameraFacing = CameraUtils.getCameraFacing(context, Camera.CameraInfo.CAMERA_FACING_BACK); } if (isSupportFlashCamera) { cameraFlash = CameraUtils.getCameraFlash(context); } } private static CameraManager INSTANCE; public static CameraManager getInstance(Application context) { if (INSTANCE == null) { synchronized (CameraManager.class) { if (INSTANCE == null) { INSTANCE = new CameraManager(context); } } } return INSTANCE; } /** * 打开camera */ public void openCamera(SurfaceTexture surfaceTexture, int width, int height) { if (mCamera == null) { mCamera = Camera.open(cameraFacing);//打开当前选中的摄像头 mProfile = CamcorderProfile.get(cameraFacing, CamcorderProfile.QUALITY_HIGH); try { mCamera.setDisplayOrientation(90);//默认竖直拍照 mCamera.setPreviewTexture(surfaceTexture); initCameraParameters(cameraFacing, width, height); mCamera.startPreview(); } catch (Exception e) { LogUtils.i(e); if (mCamera != null) { mCamera.release(); mCamera = null; } } } } /** * 开启预览,前提是camera初始化了 */ public void restartPreview() { if (mCamera == null) return; try { Camera.Parameters parameters = mCamera.getParameters(); int zoom = parameters.getZoom(); if (zoom > 0) { parameters.setZoom(0); mCamera.setParameters(parameters); } mCamera.startPreview(); } catch (Exception e) { LogUtils.i(e); if (mCamera != null) { mCamera.release(); mCamera = null; } } } private void initCameraParameters(int cameraId, int width, int height) { Camera.Parameters parameters = mCamera.getParameters(); if (cameraId == Camera.CameraInfo.CAMERA_FACING_BACK) { ListfocusModes = parameters.getSupportedFocusModes(); if (focusModes != null) { if (cameraType == 0) { if (focusModes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) { parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE); } } else { if (focusModes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO)) { parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO); } } } } parameters.setRotation(90);//设置旋转代码, switch (cameraFlash) { case 0: parameters.setFlashMode(Camera.Parameters.FLASH_MODE_AUTO); break; case 1: parameters.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH); break; case 2: parameters.setFlashMode(Camera.Parameters.FLASH_MODE_OFF); break; } List pictureSizes = parameters.getSupportedPictureSizes(); List previewSizes = parameters.getSupportedPreviewSizes(); if (!isEmpty(pictureSizes) && !isEmpty(previewSizes)) { /** for (Camera.Size size : pictureSizes) { LogUtils.i("pictureSize " + size.width + " " + size.height); } for (Camera.Size size : pictureSizes) { LogUtils.i("previewSize " + size.width + " " + size.height); }*/ Camera.Size optimalPicSize = getOptimalCameraSize(pictureSizes, width, height); Camera.Size optimalPreSize = getOptimalCameraSize(previewSizes, width, height); // Camera.Size optimalPicSize = getOptimalSize(pictureSizes, width, height); // Camera.Size optimalPreSize = getOptimalSize(previewSizes, width, height); LogUtils.i("TextureSize "+width+" "+height+" optimalSize pic " + optimalPicSize.width + " " + optimalPicSize.height + " pre " + optimalPreSize.width + " " + optimalPreSize.height); parameters.setPictureSize(optimalPicSize.width, optimalPicSize.height); parameters.setPreviewSize(optimalPreSize.width, optimalPreSize.height); mProfile.videoFrameWidth = optimalPreSize.width; mProfile.videoFrameHeight = optimalPreSize.height; mProfile.videoBitRate = 5000000;//此参数主要决定视频拍出大小 } mCamera.setParameters(parameters); } /** * 释放摄像头 */ public void closeCamera() { this.cameraType = 0; if (mCamera != null) { try { mCamera.stopPreview(); mCamera.release(); mCamera = null; } catch (Exception e) { LogUtils.i(e); if (mCamera != null) { mCamera.release(); mCamera = null; } } } } /** * 集合不为空 * * @param list * @param * @return */ private boolean isEmpty(List list) { return list == null || list.isEmpty(); } /** * * @param sizes 相机support参数 * @param w * @param h * @return 最佳Camera size */ private Camera.Size getOptimalCameraSize(List sizes, int w, int h){ sortCameraSize(sizes); int position = binarySearch(sizes, w*h); return sizes.get(position); } /** * * @param sizes * @param targetNum 要比较的数 * @return */ private int binarySearch(List sizes,int targetNum){ int targetIndex; int left = 0,right; int length = sizes.size(); for (right = length-1;left != right;){ int midIndex = (right + left)/2; int mid = right - left; Camera.Size size = sizes.get(midIndex); int midValue = size.width * size.height; if (targetNum == midValue){ return midIndex; } if (targetNum > midValue){ left = midIndex; }else { right = midIndex; } if (mid <= 1){ break; } } Camera.Size rightSize = sizes.get(right); Camera.Size leftSize = sizes.get(left); int rightNum = rightSize.width * rightSize.height; int leftNum = leftSize.width * leftSize.height; targetIndex = Math.abs((rightNum - leftNum)/2) > Math.abs(rightNum - targetNum) ? right : left; return targetIndex; } /** * 排序 * @param previewSizes */ private void sortCameraSize(List previewSizes){ Collections.sort(previewSizes, new Comparator () { @Override public int compare(Camera.Size size1, Camera.Size size2) { int compareHeight = size1.height - size2.height; if (compareHeight == 0){ return (size1.width == size2.width ? 0 :(size1.width > size2.width ? 1:-1)); } return compareHeight; } }); } /** * 获取最佳预览相机Size参数 * * @return */ private Camera.Size getOptimalSize(List sizes, int w, int h) { Camera.Size optimalSize = null; float targetRadio = h / (float) w; float optimalDif = Float.MAX_VALUE; //最匹配的比例 int optimalMaxDif = Integer.MAX_VALUE;//最优的最大值差距 for (Camera.Size size : sizes) { float newOptimal = size.width / (float) size.height; float newDiff = Math.abs(newOptimal - targetRadio); if (newDiff < optimalDif) { //更好的尺寸 optimalDif = newDiff; optimalSize = size; optimalMaxDif = Math.abs(h - size.width); } else if (newDiff == optimalDif) {//更好的尺寸 int newOptimalMaxDif = Math.abs(h - size.width); if (newOptimalMaxDif < optimalMaxDif) { optimalDif = newDiff; optimalSize = size; optimalMaxDif = newOptimalMaxDif; } } } return optimalSize; } /** * 缩放 * @param isZoomIn */ public void handleZoom(boolean isZoomIn) { if (mCamera == null) return; Camera.Parameters params = mCamera.getParameters(); if (params == null) return; if (params.isZoomSupported()) { int maxZoom = params.getMaxZoom(); int zoom = params.getZoom(); if (isZoomIn && zoom < maxZoom) { zoom++; } else if (zoom > 0) { zoom--; } params.setZoom(zoom); mCamera.setParameters(params); } else { LogUtils.i("zoom not supported"); } } /** * 更换前后置摄像 */ public void changeCameraFacing(SurfaceTexture surfaceTexture, int width, int height) { if(isSupportFrontCamera) { Camera.CameraInfo cameraInfo = new Camera.CameraInfo(); int cameraCount = Camera.getNumberOfCameras();//得到摄像头的个数 for(int i = 0; i < cameraCount; i++) { Camera.getCameraInfo(i, cameraInfo);//得到每一个摄像头的信息 if(cameraFacing == Camera.CameraInfo.CAMERA_FACING_FRONT) { //现在是后置,变更为前置 if(cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {//代表摄像头的方位为前置 closeCamera(); cameraFacing = Camera.CameraInfo.CAMERA_FACING_BACK; CameraUtils.setCameraFacing(context, cameraFacing); openCamera(surfaceTexture, width, height); break; } } else {//现在是前置, 变更为后置 if(cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_BACK) {//代表摄像头的方位 closeCamera(); cameraFacing = Camera.CameraInfo.CAMERA_FACING_FRONT; CameraUtils.setCameraFacing(context, cameraFacing); openCamera(surfaceTexture, width, height); break; } } } } else { //不支持摄像机 Toast.makeText(context, "您的手机不支持前置摄像", Toast.LENGTH_SHORT).show(); } } /** * 改变闪光状态 */ public void changeCameraFlash(SurfaceTexture surfaceTexture, int width, int height) { if (!isSupportFlashCamera) { Toast.makeText(context, "您的手机不支闪光", Toast.LENGTH_SHORT).show(); return; } if(mCamera != null) { Camera.Parameters parameters = mCamera.getParameters(); if(parameters != null) { int newState = cameraFlash; switch (cameraFlash) { case 0: //自动 parameters.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH); newState = 1; break; case 1://open parameters.setFlashMode(Camera.Parameters.FLASH_MODE_OFF); newState = 2; break; case 2: //close parameters.setFlashMode(Camera.Parameters.FLASH_MODE_AUTO); newState = 0; break; } cameraFlash = newState; CameraUtils.setCameraFlash(context, newState); mCamera.setParameters(parameters); } } } /** * 拍照 */ public void takePhoto(Camera.PictureCallback callback) { if (mCamera != null) { try { mCamera.takePicture(null, null, callback); } catch(Exception e) { Toast.makeText(context, "拍摄失败", Toast.LENGTH_SHORT).show(); } } } /** * 开始录制视频 */ // public void startMediaRecord(String savePath) { // if (mCamera == null || mProfile == null) return; // mCamera.unlock(); // if (mMediaRecorder == null) { // mMediaRecorder = new MediaRecorder(); // } // if (isCameraFrontFacing()) { // mMediaRecorder.setOrientationHint(270); // Log.i("wujie","front"); // }else // { // Log.i("wujie","back"); // mMediaRecorder.setOrientationHint(90); // } // mMediaRecorder.reset(); // mMediaRecorder.setCamera(mCamera); // mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA); // mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.DEFAULT); // mMediaRecorder.setProfile(mProfile); // mMediaRecorder.setOutputFile(savePath); // try { // mMediaRecorder.prepare(); // mMediaRecorder.start(); // } catch (Exception e) { // e.printStackTrace(); // // } // } /** * 开始录制视频 */ public void startMediaRecord1(String savePath) { if (mCamera == null) { return; } if (mMediaRecorder == null) { mMediaRecorder = new MediaRecorder(); } else { mMediaRecorder.reset(); } if (isCameraFrontFacing()) { mMediaRecorder.setOrientationHint(270); Log.i("wujie","front"); }else { Log.i("wujie","back"); mMediaRecorder.setOrientationHint(90); } mParameters = mCamera.getParameters(); mCamera.unlock(); mMediaRecorder.setCamera(mCamera); mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA); mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); // 设置录像参数 mMediaRecorder.setProfile(CamcorderProfile.get(AppConfig.VIDEOSIZE)); try { mMediaRecorder.setOutputFile(savePath); mMediaRecorder.prepare(); mMediaRecorder.start(); } catch (Exception e) { } } /** * 停止录制 */ public void stopMediaRecord() { this.cameraType = 0; stopRecorder(); releaseMediaRecorder(); } private void releaseMediaRecorder() { if (mMediaRecorder != null) { try { mMediaRecorder.reset(); mMediaRecorder.release(); mMediaRecorder = null; mCamera.lock(); } catch (Exception e) { e.printStackTrace(); LogUtils.i(e); } } } private void stopRecorder() { if (mMediaRecorder != null) { try { mMediaRecorder.stop(); } catch (Exception e) { e.printStackTrace(); LogUtils.i(e); } } } public boolean isSupportFrontCamera() { return isSupportFrontCamera; } public boolean isSupportFlashCamera() { return isSupportFlashCamera; } public boolean isCameraFrontFacing() { return cameraFacing == Camera.CameraInfo.CAMERA_FACING_FRONT; } /** * 设置对焦类型 * @param cameraType */ public void setCameraType(int cameraType) { this.cameraType = cameraType; if (mCamera != null) {//拍摄视频时 if (cameraFacing == Camera.CameraInfo.CAMERA_FACING_BACK) { Camera.Parameters parameters = mCamera.getParameters(); List focusModes = parameters.getSupportedFocusModes(); if (focusModes != null) { if (cameraType == 0) { if (focusModes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) { parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE); } } else { if (focusModes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO)) { parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO); } } } } } } public int getCameraFlash() { return cameraFlash; } /** * 对焦 * @param x * @param y */ public void handleFocusMetering(float x, float y) { if(mCamera!=null){ Camera.Parameters params = mCamera.getParameters(); Camera.Size previewSize = params.getPreviewSize(); Rect focusRect = calculateTapArea(x, y, 1f, previewSize); Rect meteringRect = calculateTapArea(x, y, 1.5f, previewSize); mCamera.cancelAutoFocus(); if (params.getMaxNumFocusAreas() > 0) { List focusAreas = new ArrayList<>(); focusAreas.add(new Camera.Area(focusRect, 1000)); params.setFocusAreas(focusAreas); } else { LogUtils.i("focus areas not supported"); } if (params.getMaxNumMeteringAreas() > 0) { List meteringAreas = new ArrayList<>(); meteringAreas.add(new Camera.Area(meteringRect, 1000)); params.setMeteringAreas(meteringAreas); } else { LogUtils.i("metering areas not supported"); } final String currentFocusMode = params.getFocusMode(); params.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO); mCamera.setParameters(params); mCamera.autoFocus(new Camera.AutoFocusCallback() { @Override public void onAutoFocus(boolean success, Camera camera) { Camera.Parameters params = camera.getParameters(); params.setFocusMode(currentFocusMode); camera.setParameters(params); } }); } } private Rect calculateTapArea(float x, float y, float coefficient, Camera.Size previewSize) { float focusAreaSize = 300; int areaSize = Float.valueOf(focusAreaSize * coefficient).intValue(); int centerX = (int) (x / previewSize.width - 1000); int centerY = (int) (y / previewSize.height - 1000); int left = clamp(centerX - areaSize / 2, -1000, 1000); int top = clamp(centerY - areaSize / 2, -1000, 1000); RectF rectF = new RectF(left, top, left + areaSize, top + areaSize); return new Rect(Math.round(rectF.left), Math.round(rectF.top), Math.round(rectF.right), Math.round(rectF.bottom)); } private int clamp(int x, int min, int max) { if (x > max) { return max; } if (x < min) { return min; } return x; } }
自定义拍摄,拍照按钮:
package com.ses.im.app.chat.newcamera; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.RectF; import android.os.Bundle; import android.os.Parcelable; import android.support.v4.view.GestureDetectorCompat; import android.support.v4.view.MotionEventCompat; import android.util.AttributeSet; import android.view.GestureDetector; import android.view.MotionEvent; import android.view.View; import android.view.ViewConfiguration; import com.ses.im.app.chat.R; /** * 自定义拍照,拍摄按钮 */ public class CameraProgressBar extends View { /** * 默认缩小值 */ public static final float DEF_SCALE = 0.75F; /** * 默认缩小值 */ private float scale = DEF_SCALE; /** * 内圆颜色 */ private int innerColor = Color.GRAY; /** * 背景颜色 */ private int backgroundColor = Color.WHITE; /** * 外圆颜色 */ private int outerColor = Color.parseColor("#e9e9e9"); /** * 进度颜色 */ private int progressColor = Color.parseColor("#0ebffa"); /** * 进度宽 */ private int progressWidth = 15; /** * 内圆宽度 */ private int innerRadio = 10; /** * 进度 */ private int progress; /** * 最大进度 */ private int maxProgress = 100; /** * paint */ private Paint backgroundPaint, progressPaint, innerPaint; /** * 圆的中心坐标点, 进度百分比 */ private float sweepAngle; /** * 手识识别 */ private GestureDetectorCompat mDetector; /** * 是否为长按录制 */ private boolean isLongClick; /** * 是否产生滑动 */ private boolean isBeingDrag; /** * 滑动单位 */ private int mTouchSlop; /** * 记录上一次Y轴坐标点 */ private float mLastY; /** * 是否长按放大 */ private boolean isLongScale; public CameraProgressBar(Context context) { super(context); init(context, null); } public CameraProgressBar(Context context, AttributeSet attrs) { super(context, attrs); init(context, attrs); } public CameraProgressBar(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(context, attrs); } private void init(Context context, AttributeSet attrs) { mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); if (attrs != null) { TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CameraProgressBar); innerColor = a.getColor(R.styleable.CameraProgressBar_innerColor, innerColor); outerColor = a.getColor(R.styleable.CameraProgressBar_outerColor, outerColor); progressColor = a.getColor(R.styleable.CameraProgressBar_progressColor, progressColor); innerRadio = a.getDimensionPixelOffset(R.styleable.CameraProgressBar_innerRadio, innerRadio); progressWidth = a.getDimensionPixelOffset(R.styleable.CameraProgressBar_progressWidth, progressWidth); progress = a.getInt(R.styleable.CameraProgressBar_progresscamera, progress); scale = a.getFloat(R.styleable.CameraProgressBar_scale, scale); isLongScale = a.getBoolean(R.styleable.CameraProgressBar_isLongScale, isLongScale); maxProgress = a.getInt(R.styleable.CameraProgressBar_maxProgress, maxProgress); a.recycle(); } backgroundPaint = new Paint(); backgroundPaint.setAntiAlias(true); backgroundPaint.setColor(backgroundColor); progressPaint = new Paint(); progressPaint.setAntiAlias(true); progressPaint.setStrokeWidth(progressWidth); progressPaint.setStyle(Paint.Style.STROKE); innerPaint = new Paint(); innerPaint.setAntiAlias(true); innerPaint.setStrokeWidth(innerRadio); innerPaint.setStyle(Paint.Style.STROKE); sweepAngle = ((float) progress / maxProgress) * 360; mDetector = new GestureDetectorCompat(context, new GestureDetector.SimpleOnGestureListener() { @Override public boolean onSingleTapConfirmed(MotionEvent e) { isLongClick = false; if (CameraProgressBar.this.listener != null) { CameraProgressBar.this.listener.onClick(CameraProgressBar.this); } return super.onSingleTapConfirmed(e); } @Override public void onLongPress(MotionEvent e) { isLongClick = true; postInvalidate(); mLastY = e.getY(); if (CameraProgressBar.this.listener != null) { CameraProgressBar.this.listener.onLongClick(CameraProgressBar.this); } } }); mDetector.setIsLongpressEnabled(true); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int width = MeasureSpec.getSize(widthMeasureSpec); int height = MeasureSpec.getSize(heightMeasureSpec); if (width > height) { setMeasuredDimension(height, height); } else { setMeasuredDimension(width, width); } } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); int width = getWidth(); float circle = width / 2.0f; if (/*isLongScale && */!isLongClick) { canvas.scale(scale, scale, circle, circle); } //画内圆 float backgroundRadio = circle - progressWidth - innerRadio; canvas.drawCircle(circle, circle, backgroundRadio, backgroundPaint); //画内外环 float halfInnerWidth = innerRadio / 2.0f + progressWidth; RectF innerRectF = new RectF(halfInnerWidth, halfInnerWidth, width - halfInnerWidth, width - halfInnerWidth); canvas.drawArc(innerRectF, -90, 360, true, innerPaint); progressPaint.setColor(outerColor); float halfOuterWidth = progressWidth / 2.0f; RectF outerRectF = new RectF(halfOuterWidth, halfOuterWidth, getWidth() - halfOuterWidth, getWidth() - halfOuterWidth); canvas.drawArc(outerRectF, -90, 360, true, progressPaint); progressPaint.setColor(progressColor); canvas.drawArc(outerRectF, -90, sweepAngle, false, progressPaint); } @Override public boolean onTouchEvent(MotionEvent event) { if (!isLongScale) { return super.onTouchEvent(event); } this.mDetector.onTouchEvent(event); switch(MotionEventCompat.getActionMasked(event)) { case MotionEvent.ACTION_DOWN: isLongClick = false; isBeingDrag = false; break; case MotionEvent.ACTION_MOVE: if (isLongClick) { float y = event.getY(); if (isBeingDrag) { boolean isUpScroll = y < mLastY; mLastY = y; if (this.listener != null) { this.listener.onZoom(isUpScroll); } } else { isBeingDrag = Math.abs(y - mLastY) > mTouchSlop; } } break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: isBeingDrag = false; if (isLongClick) { isLongClick = false; postInvalidate(); if (this.listener != null) { this.listener.onLongClickUp(this); } } break; case MotionEvent.ACTION_POINTER_DOWN: if (isLongClick) { if (this.listener != null) { this.listener.onPointerDown(event.getRawX(), event.getRawY()); } } break; } return true; } @Override protected Parcelable onSaveInstanceState() { Bundle bundle = new Bundle(); Parcelable superData = super.onSaveInstanceState(); bundle.putParcelable("superData", superData); bundle.putInt("progress", progress); bundle.putInt("maxProgress", maxProgress); return bundle; } @Override protected void onRestoreInstanceState(Parcelable state) { Bundle bundle = (Bundle) state; Parcelable superData = bundle.getParcelable("superData"); progress = bundle.getInt("progress"); maxProgress = bundle.getInt("maxProgress"); super.onRestoreInstanceState(superData); } /** * 设置进度 * @param progress */ public void setProgress(int progress) { if (progress <= 0) progress = 0; if (progress >= maxProgress) progress = maxProgress; if (progress == this.progress) return; this.progress = progress; this.sweepAngle = ((float) progress / maxProgress) * 360; postInvalidate(); } /** * 还原到初始状态 */ public void reset() { isLongClick = false; this.progress = 0; this.sweepAngle = 0; postInvalidate(); } public int getProgress() { return progress; } public void setLongScale(boolean longScale) { isLongScale = longScale; } public void setMaxProgress(int maxProgress) { this.maxProgress = maxProgress; } private OnProgressTouchListener listener; public void setOnProgressTouchListener(OnProgressTouchListener listener) { this.listener = listener; } /** * 进度触摸监听 */ public interface OnProgressTouchListener { /** * 单击 * @param progressBar */ void onClick(CameraProgressBar progressBar); /** * 长按 * @param progressBar */ void onLongClick(CameraProgressBar progressBar); /** * 移动 * @param zoom true放大 */ void onZoom(boolean zoom); /** * 长按抬起 * @param progressBar */ void onLongClickUp(CameraProgressBar progressBar); /** * 触摸对焦 * @param rawX * @param rawY */ void onPointerDown(float rawX, float rawY); } }
预览试图页:
package com.ses.im.app.chat.newcamera; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.PointF; import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; import android.graphics.RectF; import android.support.v4.view.MotionEventCompat; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; import android.view.ViewParent; import java.util.concurrent.TimeUnit; import rx.Observable; import rx.Subscriber; import rx.Subscription; /** * 相机预览页 */ public class CameraView extends View { /** * 动画时长 */ private static final int ANIM_MILS = 600; /** * 动画每多久刷新一次 */ private static final int ANIM_UPDATE = 30; /** * focus paint */ private Paint paint, clearPaint; private int paintColor = Color.GREEN; /** * 进度订阅 */ private Subscription subscription; /** * focus rectf */ private RectF rectF = new RectF(); /** * focus size */ private int focusSize = 120; private int lineSize = focusSize / 4; /** * 上一次两指距离 */ private float oldDist = 1f; /** * 画笔宽 */ private float paintWidth = 6.0f; /** * s */ private float scale; public CameraView(Context context) { super(context); init(); } public CameraView(Context context, AttributeSet attrs) { super(context, attrs); init(); } public CameraView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } private void init() { paint = new Paint(); paint.setColor(paintColor); paint.setStyle(Paint.Style.STROKE); paint.setStrokeWidth(paintWidth); clearPaint = new Paint(); clearPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); } @Override public boolean onTouchEvent(MotionEvent event) { int action = MotionEventCompat.getActionMasked(event); if (event.getPointerCount() == 1 && action == MotionEvent.ACTION_DOWN) { float x = event.getX(); float y = event.getY(); setFoucsPoint(x, y); if (listener != null) { listener.handleFocus(x, y); } } else if (event.getPointerCount() >= 2){ switch (event.getAction() & MotionEvent.ACTION_MASK) { case MotionEvent.ACTION_POINTER_DOWN: oldDist = getFingerSpacing(event); break; case MotionEvent.ACTION_MOVE: float newDist = getFingerSpacing(event); if (newDist > oldDist) { if (this.listener != null) { this.listener.handleZoom(true); } } else if (newDist < oldDist) { if (this.listener != null) { this.listener.handleZoom(false); } } oldDist = newDist; break; } } return true; } /** * 计算两点触控距离 * @param event * @return */ private float getFingerSpacing(MotionEvent event) { float x = event.getX(0) - event.getX(1); float y = event.getY(0) - event.getY(1); return (float) Math.sqrt(x * x + y * y); } /** * 设置坐标点(坐标为rawX, rawY) */ public void setFoucsPoint(PointF pointF) { PointF transPointF = transPointF(pointF, this); setFoucsPoint(transPointF.x, transPointF.y); } /** * 设置当前触摸点 * @param x * @param y */ private void setFoucsPoint(float x, float y) { if (subscription != null) { subscription.unsubscribe(); } rectF.set(x - focusSize, y - focusSize, x + focusSize, y + focusSize); final int count = ANIM_MILS / ANIM_UPDATE; subscription = Observable.interval(ANIM_UPDATE, TimeUnit.MILLISECONDS).take(count).subscribe(new Subscriber() { @Override public void onCompleted() { scale = 0; postInvalidate(); } @Override public void onError(Throwable e) { scale = 0; postInvalidate(); } @Override public void onNext(Long aLong) { float current = aLong== null ? 0 : aLong.longValue(); scale = 1 - current / count; if (scale <= 0.5f) { scale = 0.5f; } postInvalidate(); } }); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); if (scale != 0) { float centerX = rectF.centerX(); float centerY = rectF.centerY(); canvas.scale(scale, scale, centerX, centerY); canvas.drawRect(rectF, paint); canvas.drawLine(rectF.left, centerY, rectF.left + lineSize, centerY, paint); canvas.drawLine(rectF.right, centerY, rectF.right - lineSize, centerY, paint); canvas.drawLine(centerX, rectF.top, centerX, rectF.top + lineSize, paint); canvas.drawLine(centerX, rectF.bottom, centerX, rectF.bottom - lineSize, paint); } } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); if (subscription != null) { subscription.unsubscribe(); } } /** * 根据raw坐标转换成屏幕中所在的坐标 * @param pointF * @return */ private PointF transPointF(PointF pointF, View view) { pointF.x -= view.getX(); pointF.y -= view.getY(); ViewParent parent = view.getParent(); if (parent instanceof View) { return transPointF(pointF, (View) parent); } else { return pointF; } } private OnViewTouchListener listener; public void setOnViewTouchListener(OnViewTouchListener listener) { this.listener = listener; } public void removeOnZoomListener() { this.listener = null; } public interface OnViewTouchListener { /** * 对焦 * @param x * @param y */ void handleFocus(float x, float y); /** * 缩放 * @param zoom true放大反之 */ void handleZoom(boolean zoom); } }
视频管理类:
package com.ses.im.app.chat.newcamera; import android.app.Application; import android.media.MediaPlayer; import android.view.Surface; /** * Created by you on 2016/10/24. * 由于拍摄跟播放都关联TextureView,停止播放时要释放mediaplayer */ public class MediaPlayerManager { private Application app; private MediaPlayer mPlayer; private MediaPlayerManager(Application app) { this.app = app; } private static MediaPlayerManager INSTANCE; public static MediaPlayerManager getInstance(Application app) { if (INSTANCE == null) { synchronized (CameraManager.class) { if (INSTANCE == null) { INSTANCE = new MediaPlayerManager(app); } } } return INSTANCE; } /** * 播放Media */ public void playMedia(Surface surface, String mediaPath) { try { if (mPlayer == null) { mPlayer = new MediaPlayer(); mPlayer.setDataSource(mediaPath); } else { if (mPlayer.isPlaying()) { mPlayer.stop(); } mPlayer.reset(); mPlayer.setDataSource(mediaPath); } mPlayer.setSurface(surface); mPlayer.setLooping(true); mPlayer.prepareAsync(); mPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { @Override public void onPrepared(MediaPlayer mp) { mp.start(); } }); } catch (Exception e) { LogUtils.i(e); } } /** * 停止播放Media */ public void stopMedia() { try { if (mPlayer != null) { if (mPlayer.isPlaying()) { mPlayer.stop(); } mPlayer.release(); mPlayer = null; } } catch (Exception e) { LogUtils.i(e); } } }
由于本人上传的demo被csdn弄丢了,想要做微信相机的可以参考陈嘉桐的demo
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。