jncultural/camera/src/main/java/com/cjt2325/cameralibrary/CameraInterface.java

781 lines
27 KiB
Java
Raw Normal View History

2020-05-27 13:32:22 +08:00
package com.cjt2325.cameralibrary;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.ImageFormat;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.YuvImage;
import android.hardware.Camera;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.media.MediaRecorder;
import android.os.Build;
import android.os.Environment;
import android.util.Log;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.widget.ImageView;
import com.cjt2325.cameralibrary.listener.ErrorListener;
import com.cjt2325.cameralibrary.util.AngleUtil;
import com.cjt2325.cameralibrary.util.CameraParamUtil;
import com.cjt2325.cameralibrary.util.CheckPermission;
import com.cjt2325.cameralibrary.util.DeviceUtil;
import com.cjt2325.cameralibrary.util.FileUtil;
import com.cjt2325.cameralibrary.util.ScreenUtils;
import com.sucstepsoft.cm_utils.utils.LogUtils;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import static android.graphics.Bitmap.createBitmap;
/**
* =====================================
* : 陈嘉桐
* 1.1.4
* 创建日期2017/4/25
* camera操作单例
* =====================================
*/
@SuppressWarnings("deprecation")
public class CameraInterface implements Camera.PreviewCallback {
private static final String TAG = "CJT";
private volatile static CameraInterface mCameraInterface;
public static void destroyCameraInterface() {
if (mCameraInterface != null) {
mCameraInterface = null;
}
}
private Camera mCamera;
private Camera.Parameters mParams;
private boolean isPreviewing = false;
private int SELECTED_CAMERA = -1;
private int CAMERA_POST_POSITION = -1;
private int CAMERA_FRONT_POSITION = -1;
private SurfaceHolder mHolder = null;
private float screenProp = -1.0f;
private boolean isRecorder = false;
private MediaRecorder mediaRecorder;
private String videoFileName;
private String saveVideoPath;
private String videoFileAbsPath;
private Bitmap videoFirstFrame = null;
private ErrorListener errorLisenter;
private ImageView mSwitchView;
private ImageView mFlashLamp;
private int preview_width;
private int preview_height;
private int angle = 0;
private int cameraAngle = 90;//摄像头角度 默认为90度
private int rotation = 0;
private byte[] firstFrame_data;
public static final int TYPE_RECORDER = 0x090;
public static final int TYPE_CAPTURE = 0x091;
private int nowScaleRate = 0;
private int recordScleRate = 0;
//视频质量
private int mediaQuality = JCameraView.MEDIA_QUALITY_MIDDLE;
private SensorManager sm = null;
//获取CameraInterface单例
public static synchronized CameraInterface getInstance() {
if (mCameraInterface == null)
synchronized (CameraInterface.class) {
if (mCameraInterface == null)
mCameraInterface = new CameraInterface();
}
return mCameraInterface;
}
public void setSwitchView(ImageView mSwitchView, ImageView mFlashLamp) {
this.mSwitchView = mSwitchView;
this.mFlashLamp = mFlashLamp;
if (mSwitchView != null) {
cameraAngle = CameraParamUtil.getInstance().getCameraDisplayOrientation(mSwitchView.getContext(),
SELECTED_CAMERA);
}
}
private SensorEventListener sensorEventListener = new SensorEventListener() {
public void onSensorChanged(SensorEvent event) {
if (Sensor.TYPE_ACCELEROMETER != event.sensor.getType()) {
return;
}
float[] values = event.values;
angle = AngleUtil.getSensorAngle(values[0], values[1]);
rotationAnimation();
}
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
};
//切换摄像头icon跟随手机角度进行旋转
private void rotationAnimation() {
if (mSwitchView == null) {
return;
}
if (rotation != angle) {
int start_rotaion = 0;
int end_rotation = 0;
switch (rotation) {
case 0:
start_rotaion = 0;
switch (angle) {
case 90:
end_rotation = -90;
break;
case 270:
end_rotation = 90;
break;
}
break;
case 90:
start_rotaion = -90;
switch (angle) {
case 0:
end_rotation = 0;
break;
case 180:
end_rotation = -180;
break;
}
break;
case 180:
start_rotaion = 180;
switch (angle) {
case 90:
end_rotation = 270;
break;
case 270:
end_rotation = 90;
break;
}
break;
case 270:
start_rotaion = 90;
switch (angle) {
case 0:
end_rotation = 0;
break;
case 180:
end_rotation = 180;
break;
}
break;
}
ObjectAnimator animC = ObjectAnimator.ofFloat(mSwitchView, "rotation", start_rotaion, end_rotation);
ObjectAnimator animF = ObjectAnimator.ofFloat(mFlashLamp, "rotation", start_rotaion, end_rotation);
AnimatorSet set = new AnimatorSet();
set.playTogether(animC, animF);
set.setDuration(500);
set.start();
rotation = angle;
}
}
@SuppressWarnings("ResultOfMethodCallIgnored")
void setSaveVideoPath(String saveVideoPath) {
this.saveVideoPath = saveVideoPath;
File file = new File(saveVideoPath);
if (!file.exists()) {
file.mkdirs();
}
}
public void setZoom(float zoom, int type) {
if (mCamera == null) {
return;
}
if (mParams == null) {
mParams = mCamera.getParameters();
}
if (!mParams.isZoomSupported() || !mParams.isSmoothZoomSupported()) {
return;
}
switch (type) {
case TYPE_RECORDER:
//如果不是录制视频中,上滑不会缩放
if (!isRecorder) {
return;
}
if (zoom >= 0) {
//每移动50个像素缩放一个级别
int scaleRate = (int) (zoom / 40);
if (scaleRate <= mParams.getMaxZoom() && scaleRate >= nowScaleRate && recordScleRate != scaleRate) {
mParams.setZoom(scaleRate);
mCamera.setParameters(mParams);
recordScleRate = scaleRate;
}
}
break;
case TYPE_CAPTURE:
if (isRecorder) {
return;
}
//每移动50个像素缩放一个级别
int scaleRate = (int) (zoom / 50);
if (scaleRate < mParams.getMaxZoom()) {
nowScaleRate += scaleRate;
if (nowScaleRate < 0) {
nowScaleRate = 0;
} else if (nowScaleRate > mParams.getMaxZoom()) {
nowScaleRate = mParams.getMaxZoom();
}
mParams.setZoom(nowScaleRate);
mCamera.setParameters(mParams);
}
LogUtils.i("setZoom = " + nowScaleRate);
break;
}
}
void setMediaQuality(int quality) {
this.mediaQuality = quality;
}
@Override
public void onPreviewFrame(byte[] data, Camera camera) {
firstFrame_data = data;
}
public void setFlashMode(String flashMode) {
if (mCamera == null)
return;
Camera.Parameters params = mCamera.getParameters();
params.setFlashMode(flashMode);
mCamera.setParameters(params);
}
public interface CameraOpenOverCallback {
void cameraHasOpened();
}
private CameraInterface() {
findAvailableCameras();
SELECTED_CAMERA = CAMERA_POST_POSITION;
saveVideoPath = "";
}
/**
* open Camera
*/
void doOpenCamera(CameraOpenOverCallback callback) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
if (!CheckPermission.isCameraUseable(SELECTED_CAMERA) && this.errorLisenter != null) {
this.errorLisenter.onError();
return;
}
}
if (mCamera == null) {
openCamera(SELECTED_CAMERA);
}
callback.cameraHasOpened();
}
private void setFlashModel() {
mParams = mCamera.getParameters();
mParams.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH); //设置camera参数为Torch模式
mCamera.setParameters(mParams);
}
private synchronized void openCamera(int id) {
try {
this.mCamera = Camera.open(id);
} catch (Exception var3) {
var3.printStackTrace();
if (this.errorLisenter != null) {
this.errorLisenter.onError();
}
}
if (Build.VERSION.SDK_INT > 17 && this.mCamera != null) {
try {
this.mCamera.enableShutterSound(false);
} catch (Exception e) {
e.printStackTrace();
Log.e("CJT", "enable shutter sound faild");
}
}
}
public synchronized void switchCamera(SurfaceHolder holder, float screenProp) {
if (SELECTED_CAMERA == CAMERA_POST_POSITION) {
SELECTED_CAMERA = CAMERA_FRONT_POSITION;
} else {
SELECTED_CAMERA = CAMERA_POST_POSITION;
}
doDestroyCamera();
LogUtils.i("open start");
openCamera(SELECTED_CAMERA);
// mCamera = Camera.open();
if (Build.VERSION.SDK_INT > 17 && this.mCamera != null) {
try {
this.mCamera.enableShutterSound(false);
} catch (Exception e) {
e.printStackTrace();
}
}
LogUtils.i("open end");
doStartPreview(holder, screenProp);
}
/**
* doStartPreview
*/
public void doStartPreview(SurfaceHolder holder, float screenProp) {
if (isPreviewing) {
LogUtils.i("doStartPreview isPreviewing");
}
if (this.screenProp < 0) {
this.screenProp = screenProp;
}
if (holder == null) {
return;
}
this.mHolder = holder;
if (mCamera != null) {
try {
mParams = mCamera.getParameters();
Camera.Size previewSize = CameraParamUtil.getInstance().getPreviewSize(mParams
.getSupportedPreviewSizes(), 1000, screenProp);
Camera.Size pictureSize = CameraParamUtil.getInstance().getPictureSize(mParams
.getSupportedPictureSizes(), 1200, 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(),
Camera.Parameters.FOCUS_MODE_AUTO)) {
mParams.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
}
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 (IOException e) {
e.printStackTrace();
}
}
}
/**
* 停止预览
*/
public void doStopPreview() {
if (null != mCamera) {
try {
mCamera.setPreviewCallback(null);
mCamera.stopPreview();
//这句要在stopPreview后执行不然会卡顿或者花屏
mCamera.setPreviewDisplay(null);
isPreviewing = false;
Log.i(TAG, "=== Stop Preview ===");
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 销毁Camera
*/
void doDestroyCamera() {
errorLisenter = null;
if (null != mCamera) {
try {
mCamera.setPreviewCallback(null);
mSwitchView = null;
mFlashLamp = null;
mCamera.stopPreview();
//这句要在stopPreview后执行不然会卡顿或者花屏
mCamera.setPreviewDisplay(null);
mHolder = null;
isPreviewing = false;
mCamera.release();
mCamera = null;
// destroyCameraInterface();
Log.i(TAG, "=== Destroy Camera ===");
} catch (IOException e) {
e.printStackTrace();
}
} else {
Log.i(TAG, "=== Camera Null===");
}
}
/**
* 拍照
*/
private int nowAngle;
public void takePicture(final TakePictureCallback callback) {
if (mCamera == null) {
return;
}
switch (cameraAngle) {
case 90:
nowAngle = Math.abs(angle + cameraAngle) % 360;
break;
case 270:
nowAngle = Math.abs(cameraAngle - angle);
break;
}
//
Log.i("CJT", angle + " = " + cameraAngle + " = " + nowAngle);
mCamera.takePicture(null, null, new Camera.PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
Matrix matrix = new Matrix();
if (SELECTED_CAMERA == CAMERA_POST_POSITION) {
matrix.setRotate(nowAngle);
} else if (SELECTED_CAMERA == CAMERA_FRONT_POSITION) {
matrix.setRotate(360 - nowAngle);
matrix.postScale(-1, 1);
}
bitmap = createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
if (callback != null) {
if (nowAngle == 90 || nowAngle == 270) {
callback.captureResult(bitmap, true);
} else {
callback.captureResult(bitmap, false);
}
}
}
});
}
//启动录像
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);
2020-06-08 10:09:08 +08:00
mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_2_TS);
2020-05-27 13:32:22 +08:00
mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
Camera.Size videoSize;
if (mParams.getSupportedVideoSizes() == null) {
videoSize = CameraParamUtil.getInstance().getPreviewSize(mParams.getSupportedPreviewSizes(), 600,
screenProp);
} else {
videoSize = CameraParamUtil.getInstance().getPreviewSize(mParams.getSupportedVideoSizes(), 600,
screenProp);
}
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.setPreviewDisplay(surface);
videoFileName = "video_" + System.currentTimeMillis() + ".mp4";
if (saveVideoPath.equals("")) {
saveVideoPath = Environment.getExternalStorageDirectory().getPath();
}
videoFileAbsPath = saveVideoPath + File.separator + 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 = saveVideoPath + File.separator + videoFileName;
callback.recordResult(fileName, videoFirstFrame);
}
}
private void findAvailableCameras() {
Camera.CameraInfo info = new Camera.CameraInfo();
int cameraNum = Camera.getNumberOfCameras();
for (int i = 0; i < cameraNum; i++) {
Camera.getCameraInfo(i, info);
switch (info.facing) {
case Camera.CameraInfo.CAMERA_FACING_FRONT:
CAMERA_FRONT_POSITION = info.facing;
break;
case Camera.CameraInfo.CAMERA_FACING_BACK:
CAMERA_POST_POSITION = info.facing;
break;
}
}
}
int handlerTime = 0;
public void handleFocus(final Context context, final float x, final float y, final FocusCallback callback) {
if (mCamera == null) {
return;
}
final Camera.Parameters params = mCamera.getParameters();
Rect focusRect = calculateTapArea(x, y, 1f, context);
mCamera.cancelAutoFocus();
if (params.getMaxNumFocusAreas() > 0) {
List<Camera.Area> focusAreas = new ArrayList<>();
focusAreas.add(new Camera.Area(focusRect, 800));
params.setFocusAreas(focusAreas);
} else {
Log.i(TAG, "focus areas not supported");
callback.focusSuccess();
return;
}
final String currentFocusMode = params.getFocusMode();
try {
params.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
mCamera.setParameters(params);
mCamera.autoFocus(new Camera.AutoFocusCallback() {
@Override
public void onAutoFocus(boolean success, Camera camera) {
if (success || handlerTime > 10) {
Camera.Parameters params = camera.getParameters();
params.setFocusMode(currentFocusMode);
camera.setParameters(params);
handlerTime = 0;
callback.focusSuccess();
} else {
handlerTime++;
handleFocus(context, x, y, callback);
}
}
});
} catch (Exception e) {
Log.e(TAG, "autoFocus failer");
}
}
private static Rect calculateTapArea(float x, float y, float coefficient, Context context) {
float focusAreaSize = 300;
int areaSize = Float.valueOf(focusAreaSize * coefficient).intValue();
int centerX = (int) (x / ScreenUtils.getScreenWidth(context) * 2000 - 1000);
int centerY = (int) (y / ScreenUtils.getScreenHeight(context) * 2000 - 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 static int clamp(int x, int min, int max) {
if (x > max) {
return max;
}
if (x < min) {
return min;
}
return x;
}
void setErrorLinsenter(ErrorListener errorLisenter) {
this.errorLisenter = errorLisenter;
}
public interface StopRecordCallback {
void recordResult(String url, Bitmap firstFrame);
}
interface ErrorCallback {
void onError();
}
public interface TakePictureCallback {
void captureResult(Bitmap bitmap, boolean isVertical);
}
public interface FocusCallback {
void focusSuccess();
}
void registerSensorManager(Context context) {
if (sm == null) {
sm = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
}
sm.registerListener(sensorEventListener, sm.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), SensorManager
.SENSOR_DELAY_NORMAL);
}
void unregisterSensorManager(Context context) {
if (sm == null) {
sm = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
}
sm.unregisterListener(sensorEventListener);
}
void isPreview(boolean res) {
this.isPreviewing = res;
}
}