职场小白迷上优美句子:
还是电影 《无问西东》中的台词,这句有点感人:
沈光耀的妈妈对沈光耀说:"当初你离家千里,来到这个地方读书,你父亲和我都没有反对过,因为,是我们想你,能享受到人生的乐趣,比如读万卷书行万里路,比如同你喜欢的女孩子结婚生子。注意不是给我增添子孙,而是你自己,能够享受为人父母的乐趣,你一生所要追求的功名利禄,没有什么是你的祖上没经历过的,那些只不过是人生的幻光。我怕,你还没想好怎么过这一生,你的命就没了啊!"
这个是效果图:
推荐一个写的很不错的博客 作者: 新根 - - - Android Camera2 API和拍照与录像过程
另外一个后来发现的:https://blog.csdn.net/qq_21898059/article/details/50986290
------------------------------ Main2Activity ----------------------------
package com.example.phonecamera2demo;
import android.content.pm.ActivityInfo;
import android.os.Bundle;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.Toast;
public class Main2Activity extends AppCompatActivity implements View.OnClickListener {
private AutoFitTextureView mTextureview;
private Button mTakePictureBtn;//拍照
private Button mVideoRecodeBtn;//开始录像
private LinearLayout mVerticalLinear;
private Button mTakePictureBtn2;//拍照 横,竖屏状态分别设置了一个拍照,录像的按钮
private Button mVideoRecodeBtn2;//开始录像
private LinearLayout mHorizontalLinear;
private Button mVHScreenBtn;
private CameraController mCameraController;
private boolean mIsRecordingVideo; //开始停止录像
public static String BASE_PATH = Environment.getExternalStorageDirectory() + "/AAA";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);// 去掉标题栏
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);// 设置全屏
setContentView(R.layout.activity_main2);
}
@Override
protected void onResume() {
super.onResume();
//获取相机管理类的实例
mCameraController = CameraController.getmInstance(this);
mCameraController.setFolderPath(BASE_PATH);
initView();
//判断当前横竖屏状态
if (getRequestedOrientation() == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) {
mVHScreenBtn.setText("切换为竖屏");
} else {
mVHScreenBtn.setText("切换为横屏");
}
}
private void initView() {
mTextureview = (AutoFitTextureView) findViewById(R.id.textureview);
mTakePictureBtn = (Button) findViewById(R.id.take_picture_btn);
mTakePictureBtn.setOnClickListener(this);
mVideoRecodeBtn = (Button) findViewById(R.id.video_recode_btn);
mVideoRecodeBtn.setOnClickListener(this);
mVerticalLinear = (LinearLayout) findViewById(R.id.vertical_linear);
mTakePictureBtn2 = (Button) findViewById(R.id.take_picture_btn2);
mTakePictureBtn2.setOnClickListener(this);
mVideoRecodeBtn2 = (Button) findViewById(R.id.video_recode_btn2);
mVideoRecodeBtn2.setOnClickListener(this);
mHorizontalLinear = (LinearLayout) findViewById(R.id.horizontal_linear);
mVHScreenBtn = (Button) findViewById(R.id.v_h_screen_btn);
mVHScreenBtn.setOnClickListener(this);
//判断当前屏幕方向
if (getRequestedOrientation() == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) {
//竖屏时
mHorizontalLinear.setVisibility(View.VISIBLE);
mVerticalLinear.setVisibility(View.GONE);
} else {
//横屏时
mVerticalLinear.setVisibility(View.VISIBLE);
mHorizontalLinear.setVisibility(View.GONE);
}
mCameraController.InitCamera(mTextureview);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
default:
break;
case R.id.take_picture_btn:
mCameraController.takePicture();
break;
case R.id.video_recode_btn:
if (mIsRecordingVideo) {
mIsRecordingVideo = !mIsRecordingVideo;
mCameraController.stopRecordingVideo();
mVideoRecodeBtn.setText("开始录像");
mVideoRecodeBtn2.setText("开始录像");
Toast.makeText(this, "录像结束", Toast.LENGTH_SHORT).show();
} else {
mVideoRecodeBtn.setText("停止录像");
mVideoRecodeBtn2.setText("停止录像");
mIsRecordingVideo = !mIsRecordingVideo;
mCameraController.startRecordingVideo();
Toast.makeText(this, "录像开始", Toast.LENGTH_SHORT).show();
}
break;
case R.id.take_picture_btn2:
mCameraController.takePicture();
break;
case R.id.video_recode_btn2:
if (mIsRecordingVideo) {
mIsRecordingVideo = !mIsRecordingVideo;
mCameraController.stopRecordingVideo();
mVideoRecodeBtn.setText("开始录像");
mVideoRecodeBtn2.setText("开始录像");
Toast.makeText(this, "录像结束", Toast.LENGTH_SHORT).show();
} else {
mVideoRecodeBtn.setText("停止录像");
mVideoRecodeBtn2.setText("停止录像");
mIsRecordingVideo = !mIsRecordingVideo;
mCameraController.startRecordingVideo();
Toast.makeText(this, "录像开始", Toast.LENGTH_SHORT).show();
}
break;
case R.id.v_h_screen_btn:
//判断当前屏幕方向
if (getRequestedOrientation() == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) {
//切换竖屏
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
Toast.makeText(Main2Activity.this, "竖屏了", Toast.LENGTH_SHORT).show();
} else {
//切换横屏
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
Toast.makeText(Main2Activity.this, "横屏了", Toast.LENGTH_SHORT).show();
}
break;
}
}
}
------------------------- activity_main2.xml ---------------------------
------------------------ AutoFitTextureView ----------------------
package com.example.zhuoshicarreco.camera;
import android.content.Context;
import android.util.AttributeSet;
import android.view.TextureView;
public class AutoFitTextureView extends TextureView {
private int mRatioWidth = 0;
private int mRatioHeight = 0;
public AutoFitTextureView(Context context) {
this(context, null);
}
public AutoFitTextureView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public AutoFitTextureView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
/**
* @param width Relative horizontal size
* @param height Relative vertical size
*/
public void setAspectRatio(int width, int height) {
if (width < 0 || height < 0) {
throw new IllegalArgumentException("Size cannot be negative.");
}
mRatioWidth = width;
mRatioHeight = height;
requestLayout();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
if (0 == mRatioWidth || 0 == mRatioHeight) {
setMeasuredDimension(width, height);
} else {
if (width < height * mRatioWidth / mRatioHeight) {
setMeasuredDimension(width, width * mRatioHeight / mRatioWidth);
} else {
setMeasuredDimension(height * mRatioWidth / mRatioHeight, height);
}
}
}
}
------------------------ CameraController--------------------------
package com.example.vehicleIllegalInspection.camera;
import android.Manifest;
import android.app.Activity;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.graphics.ImageFormat;
import android.graphics.Matrix;
import android.graphics.Point;
import android.graphics.RectF;
import android.graphics.SurfaceTexture;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.CameraMetadata;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.CaptureResult;
import android.hardware.camera2.TotalCaptureResult;
import android.hardware.camera2.params.StreamConfigurationMap;
import android.media.Image;
import android.media.ImageReader;
import android.media.MediaRecorder;
import android.os.Handler;
import android.os.HandlerThread;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.Size;
import android.util.SparseIntArray;
import android.view.Surface;
import android.view.TextureView;
import android.widget.Toast;
import com.example.vehicleIllegalInspection.mvp.ui.activity.MainActivity;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
public class CameraController {
private static final String TAG = "CameraController";
private static Activity mActivity;
private String mFolderPath; //保存视频,图片的文件夹路径
private ImageReader mImageReader;
private HandlerThread mBackgroundThread;
private Handler mBackgroundHandler;
private AutoFitTextureView mTextureView;
private Semaphore mCameraOpenCloseLock = new Semaphore(1);//一个信号量以防止应用程序在关闭相机之前退出。
private String mCameraId;//当前相机的ID。
private CameraDevice mCameraDevice;
private Size mPreviewSize;
private CaptureRequest.Builder mPreviewRequestBuilder;
private CameraCaptureSession mCaptureSession;
private CaptureRequest mPreviewRequest;
private File mFile;//拍照储存文件
private Integer mSensorOrientation;
private CameraCaptureSession mPreviewSession;
private CaptureRequest.Builder mPreviewBuilder;
private static final int MAX_PREVIEW_WIDTH = 1920;//Camera2 API保证的最大预览宽度
private static final int MAX_PREVIEW_HEIGHT = 1080;//Camera2 API保证的最大预览高度
private boolean mFlashSupported;
private int mState = STATE_PREVIEW;
private static final SparseIntArray ORIENTATIONS = new SparseIntArray();
static {
ORIENTATIONS.append(Surface.ROTATION_0, 90);
ORIENTATIONS.append(Surface.ROTATION_90, 0);
ORIENTATIONS.append(Surface.ROTATION_180, 270);
ORIENTATIONS.append(Surface.ROTATION_270, 180);
}
private static final int SENSOR_ORIENTATION_DEFAULT_DEGREES = 90;
private static final int SENSOR_ORIENTATION_INVERSE_DEGREES = 270;
private static final int STATE_PREVIEW = 0;//相机状态:显示相机预览。
private static final int STATE_WAITING_LOCK = 1;//相机状态:等待焦点被锁定。
private static final int STATE_WAITING_PRECAPTURE = 2;//等待曝光被Precapture状态。
private static final int STATE_WAITING_NON_PRECAPTURE = 3;//相机状态:等待曝光的状态是不是Precapture。
private static final int STATE_PICTURE_TAKEN = 4;//相机状态:拍照。
private MediaRecorder mMediaRecorder;
private String mNextVideoAbsolutePath;
private CameraController() {
}
private static class ClassHolder {
static CameraController mInstance = new CameraController();
}
public static CameraController getmInstance(Activity activity) {
mActivity = activity;
return ClassHolder.mInstance;
}
public void InitCamera(AutoFitTextureView textureView) {
this.mTextureView = textureView;
startBackgroundThread();
if (mTextureView.isAvailable()) {
openCamera(mTextureView.getWidth(), mTextureView.getHeight());
} else {
mTextureView.setSurfaceTextureListener(mSurfaceTextureListener);
}
}
/**
* 设置需要保存文件的文件夹路径
* @param path
*/
public void setFolderPath(String path) {
this.mFolderPath = path;
File mFolder = new File(path);
if (!mFolder.exists()) {
mFolder.mkdirs();
Log.d(TAG, "文件夹不存在去创建");
} else {
Log.d(TAG, "文件夹已创建");
}
}
public String getFolderPath() {
return mFolderPath;
}
/**
* 拍照
*/
public void takePicture() {
lockFocus();
}
/**
* 开始录像
*/
public void startRecordingVideo() {
if (null == mCameraDevice || !mTextureView.isAvailable() || null == mPreviewSize) {
return;
}
try {
closePreviewSession();
setUpMediaRecorder();
SurfaceTexture texture = mTextureView.getSurfaceTexture();
assert texture != null;
texture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
mPreviewBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_RECORD);
List surfaces = new ArrayList<>();
//为相机预览设置曲面
Surface previewSurface = new Surface(texture);
surfaces.add(previewSurface);
mPreviewBuilder.addTarget(previewSurface);
//设置MediaRecorder的表面
Surface recorderSurface = mMediaRecorder.getSurface();
surfaces.add(recorderSurface);
mPreviewBuilder.addTarget(recorderSurface);
// 启动捕获会话
// 一旦会话开始,我们就可以更新UI并开始录制
mCameraDevice.createCaptureSession(surfaces, new CameraCaptureSession.StateCallback() {
@Override
public void onConfigured(@NonNull CameraCaptureSession cameraCaptureSession) {
mPreviewSession = cameraCaptureSession;
updatePreview();
mActivity.runOnUiThread(new Runnable() {
@Override
public void run() {
//开启录像
mMediaRecorder.start();
}
});
}
@Override
public void onConfigureFailed(@NonNull CameraCaptureSession cameraCaptureSession) {
}
}, mBackgroundHandler);
} catch (CameraAccessException | IOException e) {
e.printStackTrace();
}
}
/**
* 停止录像
*/
public void stopRecordingVideo() {
mMediaRecorder.stop();
mMediaRecorder.reset();
mNextVideoAbsolutePath = null;
startPreview();
}
private void closePreviewSession() {
if (mPreviewSession != null) {
mPreviewSession.close();
mPreviewSession = null;
}
}
private void setUpMediaRecorder() throws IOException {
mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); //设置用于录制的音源
mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);//开始捕捉和编码数据到setOutputFile(指定的文件)
mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4); //设置在录制过程中产生的输出文件的格式
if (mNextVideoAbsolutePath == null || mNextVideoAbsolutePath.isEmpty()) {
mNextVideoAbsolutePath = getVideoFilePath();
}
mMediaRecorder.setOutputFile(mNextVideoAbsolutePath);//设置输出文件的路径
mMediaRecorder.setVideoEncodingBitRate(10000000);//设置录制的视频编码比特率
mMediaRecorder.setVideoFrameRate(25);//设置要捕获的视频帧速率
mMediaRecorder.setVideoSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());//设置要捕获的视频的宽度和高度
mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);//设置视频编码器,用于录制
mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);//设置audio的编码格式
int rotation = mActivity.getWindowManager().getDefaultDisplay().getRotation();
Log.d(TAG, "setUpMediaRecorder: "+rotation);
switch (mSensorOrientation) {
case SENSOR_ORIENTATION_DEFAULT_DEGREES:
mMediaRecorder.setOrientationHint(ORIENTATIONS.get(rotation));
break;
case SENSOR_ORIENTATION_INVERSE_DEGREES:
mMediaRecorder.setOrientationHint(ORIENTATIONS.get(rotation));
break;
}
mMediaRecorder.prepare();
}
private String getVideoFilePath() {
return getFolderPath() + "/" + System.currentTimeMillis() + ".mp4";
}
private void updatePreview() {
if (null == mCameraDevice) {
return;
}
try {
mPreviewBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);
HandlerThread thread = new HandlerThread("CameraPreview");
thread.start();
mPreviewSession.setRepeatingRequest(mPreviewBuilder.build(), null, mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
private void lockFocus() {
//创建文件
mFile = new File(getFolderPath() + "/" + getNowDate() + ".jpg");
try {
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,
CameraMetadata.CONTROL_AF_TRIGGER_START);
mState = STATE_WAITING_LOCK;
mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback,
mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
/**
* 获取当前时间,用来给文件夹命名
*/
private String getNowDate() {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return simpleDateFormat.format(new Date());
}
private TextureView.SurfaceTextureListener mSurfaceTextureListener
= new TextureView.SurfaceTextureListener() {
@Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
openCamera(width, height);
}
@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
}
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
return false;
}
@Override
public void onSurfaceTextureUpdated(SurfaceTexture surface) {
}
};
private void startBackgroundThread() {
mBackgroundThread = new HandlerThread("CameraBackground");
mBackgroundThread.start();
mBackgroundHandler = new Handler(mBackgroundThread.getLooper());
}
/**
* 开启相机
*/
private void openCamera(int width, int height) {
//设置相机输出
setUpCameraOutputs(width, height);
//配置变换
configureTransform(width, height);
CameraManager manager = (CameraManager) mActivity.getSystemService(Context.CAMERA_SERVICE);
try {
if (!mCameraOpenCloseLock.tryAcquire(2500, TimeUnit.MILLISECONDS)) {
throw new RuntimeException("Time out waiting to lock camera opening.");
}
if (ActivityCompat.checkSelfPermission(mActivity, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
return;
}
//打开相机预览
manager.openCamera(mCameraId, mStateCallback, mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
} catch (InterruptedException e) {
throw new RuntimeException("Interrupted while trying to lock camera opening.", e);
}
}
/**
* CameraDevice状态更改时被调用。
*/
private final CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() {
@Override
public void onOpened(@NonNull CameraDevice cameraDevice) {
// 打开相机时调用此方法。 在这里开始相机预览。
mCameraOpenCloseLock.release();
mCameraDevice = cameraDevice;
//创建CameraPreviewSession
startPreview();
}
@Override
public void onDisconnected(@NonNull CameraDevice cameraDevice) {
mCameraOpenCloseLock.release();
cameraDevice.close();
mCameraDevice = null;
}
@Override
public void onError(@NonNull CameraDevice cameraDevice, int error) {
mCameraOpenCloseLock.release();
cameraDevice.close();
mCameraDevice = null;
mActivity.finish();
}
};
/**
* 为相机预览创建新的CameraCaptureSession
*/
private void startPreview() {
try {
SurfaceTexture texture = mTextureView.getSurfaceTexture();
assert texture != null;
// 将默认缓冲区的大小配置为我们想要的相机预览的大小。 设置分辨率
texture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
// 预览的输出Surface。
Surface surface = new Surface(texture);
//设置了一个具有输出Surface的CaptureRequest.Builder。
mPreviewRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
mPreviewRequestBuilder.addTarget(surface);
//创建一个CameraCaptureSession来进行相机预览。
mCameraDevice.createCaptureSession(Arrays.asList(surface, mImageReader.getSurface()),
new CameraCaptureSession.StateCallback() {
@Override
public void onConfigured(@NonNull CameraCaptureSession cameraCaptureSession) {
// 相机已经关闭
if (null == mCameraDevice) {
return;
}
// 会话准备好后,我们开始显示预览
mCaptureSession = cameraCaptureSession;
// 自动对焦应
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE,
CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
// 最终开启相机预览并添加事件
mPreviewRequest = mPreviewRequestBuilder.build();
try {
mCaptureSession.setRepeatingRequest(mPreviewRequest,
mCaptureCallback, mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
@Override
public void onConfigureFailed(
@NonNull CameraCaptureSession cameraCaptureSession) {
}
}, null
);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
/**
* 处理与JPEG捕获有关的事件
*/
private CameraCaptureSession.CaptureCallback mCaptureCallback
= new CameraCaptureSession.CaptureCallback() {
//处理
private void process(CaptureResult result) {
switch (mState) {
case STATE_PREVIEW: {
//预览状态
break;
}
case STATE_WAITING_LOCK: {
//等待对焦
Integer afState = result.get(CaptureResult.CONTROL_AF_STATE);
if (afState == null) {
captureStillPicture();
} else if (CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED == afState ||
CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED == afState) {
// 某些设备上的控制状态可以为空
Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);
if (aeState == null || aeState == CaptureResult.CONTROL_AE_STATE_CONVERGED) {
mState = STATE_PICTURE_TAKEN;
captureStillPicture();
} else {
runPrecaptureSequence();
}
}
break;
}
case STATE_WAITING_PRECAPTURE: {
//某些设备上的控制状态可以为空
Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);
if (aeState == null ||
aeState == CaptureResult.CONTROL_AE_STATE_PRECAPTURE ||
aeState == CaptureRequest.CONTROL_AE_STATE_FLASH_REQUIRED) {
mState = STATE_WAITING_NON_PRECAPTURE;
}
break;
}
case STATE_WAITING_NON_PRECAPTURE: {
// CONTROL_AE_STATE can be null on some devices
Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);
if (aeState == null || aeState != CaptureResult.CONTROL_AE_STATE_PRECAPTURE) {
mState = STATE_PICTURE_TAKEN;
captureStillPicture();
}
break;
}
}
}
@Override
public void onCaptureProgressed(@NonNull CameraCaptureSession session,
@NonNull CaptureRequest request,
@NonNull CaptureResult partialResult) {
process(partialResult);
}
@Override
public void onCaptureCompleted(@NonNull CameraCaptureSession session,
@NonNull CaptureRequest request,
@NonNull TotalCaptureResult result) {
process(result);
}
};
/**
* 拍摄静态图片。
*/
private void captureStillPicture() {
try {
if (null == mCameraDevice) {
return;
}
// 这是用来拍摄照片的CaptureRequest.Builder。
final CaptureRequest.Builder captureBuilder =
mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
captureBuilder.addTarget(mImageReader.getSurface());
// 使用相同的AE和AF模式作为预览。
captureBuilder.set(CaptureRequest.CONTROL_AF_MODE,
CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
setAutoFlash(captureBuilder);
// 方向
int rotation = mActivity.getWindowManager().getDefaultDisplay().getRotation();
captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, getOrientation(rotation));
CameraCaptureSession.CaptureCallback CaptureCallback
= new CameraCaptureSession.CaptureCallback() {
@Override
public void onCaptureCompleted(@NonNull CameraCaptureSession session,
@NonNull CaptureRequest request,
@NonNull TotalCaptureResult result) {
showToast("图片地址: " + mFile);
Log.d(TAG, mFile.toString());
unlockFocus();
}
};
//停止连续取景
mCaptureSession.stopRepeating();
//捕获图片
mCaptureSession.capture(captureBuilder.build(), CaptureCallback, null);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
private void showToast(final String text) {
mActivity.runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(mActivity, text, Toast.LENGTH_SHORT).show();
}
});
}
private int getOrientation(int rotation) {
return (ORIENTATIONS.get(rotation) + mSensorOrientation + 270) % 360;
}
private void setAutoFlash(CaptureRequest.Builder requestBuilder) {
if (mFlashSupported) {
requestBuilder.set(CaptureRequest.CONTROL_AE_MODE,
CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
}
}
/**
* 解锁焦点
*/
private void unlockFocus() {
try {
// 重置自动对焦
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,
CameraMetadata.CONTROL_AF_TRIGGER_CANCEL);
setAutoFlash(mPreviewRequestBuilder);
mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback,
mBackgroundHandler);
// 将相机恢复正常的预览状态。
mState = STATE_PREVIEW;
// 打开连续取景模式
mCaptureSession.setRepeatingRequest(mPreviewRequest, mCaptureCallback,
mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
/**
* 运行捕获静止图像的预捕获序列。 当我们从{@link #()}的{@link #mCaptureCallback}中得到响应时,应该调用此方法。
*/
private void runPrecaptureSequence() {
try {
// 这是如何告诉相机触发的。
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER,
CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START);
// 告诉 mCaptureCallback 等待preapture序列被设置.
mState = STATE_WAITING_PRECAPTURE;
mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback,
mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
private ImageReader.OnImageAvailableListener mOnImageAvailableListener
= new ImageReader.OnImageAvailableListener() {
@Override
public void onImageAvailable(ImageReader reader) {
//等图片可以得到的时候获取图片并保存
mBackgroundHandler.post(new ImageSaver(reader.acquireNextImage(), mFile));
}
};
/**
* 设置与相机相关的成员变量。
*
* @param width 相机预览的可用尺寸宽度
* @param height 相机预览的可用尺寸的高度
*/
private void setUpCameraOutputs(int width, int height) {
CameraManager manager = (CameraManager) mActivity.getSystemService(Context.CAMERA_SERVICE);
//获取摄像头列表
try {
for (String cameraId : manager.getCameraIdList()) {
CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId);
//不使用前置摄像
Integer facing = characteristics.get(CameraCharacteristics.LENS_FACING);
if (facing != null && facing == CameraCharacteristics.LENS_FACING_FRONT) {
continue;//不结束循环,只跳出本次循环
}
StreamConfigurationMap map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
if (map == null) {
continue;
}
//对于静态图像拍照, 使用最大的可用尺寸
Size largest = Collections.max(
Arrays.asList(map.getOutputSizes(ImageFormat.JPEG)),
new CompareSizesByArea()
);
mImageReader = ImageReader.newInstance(largest.getWidth(), largest.getHeight(), ImageFormat.JPEG, 2);
mImageReader.setOnImageAvailableListener(mOnImageAvailableListener, mBackgroundHandler);
//获取手机旋转的角度以调整图片的方向
int displayRotation = mActivity.getWindowManager().getDefaultDisplay().getRotation();
mSensorOrientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
boolean swappedDimensions = false;
switch (displayRotation) {
case Surface.ROTATION_0:
case Surface.ROTATION_180:
//横屏
if (mSensorOrientation == 90 || mSensorOrientation == 270) {
swappedDimensions = true;
}
break;
case Surface.ROTATION_90:
case Surface.ROTATION_270:
//竖屏
if (mSensorOrientation == 0 || mSensorOrientation == 180) {
swappedDimensions = true;
}
break;
default:
Log.e(TAG, "Display rotation is invalid: " + displayRotation);
}
Point displaySize = new Point();
mActivity.getWindowManager().getDefaultDisplay().getSize(displaySize);
int rotatedPreviewWidth = width;
int rotatedPreviewHeight = height;
int maxPreviewWidth = displaySize.x;
int maxPreviewHeight = displaySize.y;
if (swappedDimensions) {
rotatedPreviewWidth = height;
rotatedPreviewHeight = width;
maxPreviewWidth = displaySize.y;
maxPreviewHeight = displaySize.x;
}
if (maxPreviewWidth > MAX_PREVIEW_WIDTH) {
maxPreviewWidth = MAX_PREVIEW_WIDTH;
}
if (maxPreviewHeight > MAX_PREVIEW_HEIGHT) {
maxPreviewHeight = MAX_PREVIEW_HEIGHT;
}
DisplayMetrics displayMetrics = new DisplayMetrics();
mActivity.getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
int widthPixels = displayMetrics.widthPixels;
int heightPixels = displayMetrics.heightPixels;
Log.d(TAG, "widthPixels: " + widthPixels + "____heightPixels:" + heightPixels);
//尝试使用太大的预览大小可能会超出摄像头的带宽限制
mPreviewSize = chooseOptimalSize(map.getOutputSizes(SurfaceTexture.class),
rotatedPreviewWidth, rotatedPreviewHeight, maxPreviewWidth,
maxPreviewHeight, largest);
//我们将TextureView的宽高比与我们选择的预览大小相匹配。这样设置不会拉伸,但是不能全屏展示
int orientation = mActivity.getResources().getConfiguration().orientation;
if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
//横屏
mTextureView.setAspectRatio(
mPreviewSize.getWidth(),mPreviewSize.getHeight());
Log.d(TAG, "横屏: "+"width:"+mPreviewSize.getWidth()+"____height:"+mPreviewSize.getHeight());
} else {
// 竖屏
mTextureView.setAspectRatio(
widthPixels, heightPixels);
Log.d(TAG, "竖屏: "+"____height:"+mPreviewSize.getHeight()+"width:"+mPreviewSize.getWidth());
}
mMediaRecorder = new MediaRecorder();
mCameraId = cameraId;
return;
}
} catch (CameraAccessException e) {
}
}
/**
* 根据他们的区域比较两个Size
*/
static class CompareSizesByArea implements Comparator {
@Override
public int compare(Size lhs, Size rhs) {
// 我们在这里投放,以确保乘法不会溢出
return Long.signum((long) lhs.getWidth() * lhs.getHeight() -
(long) rhs.getWidth() * rhs.getHeight());
}
}
private static Size chooseOptimalSize(Size[] choices, int textureViewWidth,
int textureViewHeight, int maxWidth, int maxHeight, Size aspectRatio) {
// 收集支持的分辨率,这些分辨率至少与预览图面一样大
List bigEnough = new ArrayList<>();
// 收集小于预览表面的支持分辨率
List notBigEnough = new ArrayList<>();
int w = aspectRatio.getWidth();
int h = aspectRatio.getHeight();
for (Size option : choices) {
if (option.getWidth() <= maxWidth && option.getHeight() <= maxHeight &&
option.getHeight() == option.getWidth() * h / w) {
if (option.getWidth() >= textureViewWidth &&
option.getHeight() >= textureViewHeight) {
bigEnough.add(option);
} else {
notBigEnough.add(option);
}
}
}
//挑一个足够大的最小的。如果没有一个足够大的,就挑一个不够大的。
if (bigEnough.size() > 0) {
return Collections.min(bigEnough, new CompareSizesByArea());
} else if (notBigEnough.size() > 0) {
return Collections.max(notBigEnough, new CompareSizesByArea());
} else {
Log.d(TAG, "Couldn't find any suitable preview size");
return choices[0];
}
}
private void configureTransform(int viewWidth, int viewHeight) {
if (null == mTextureView || null == mPreviewSize) {
return;
}
int rotation = mActivity.getWindowManager().getDefaultDisplay().getRotation();
Matrix matrix = new Matrix();
RectF viewRect = new RectF(0, 0, viewWidth, viewHeight);
RectF bufferRect = new RectF(0, 0, mPreviewSize.getHeight(), mPreviewSize.getWidth());
float centerX = viewRect.centerX();
float centerY = viewRect.centerY();
if (Surface.ROTATION_90 == rotation || Surface.ROTATION_270 == rotation) {
bufferRect.offset(centerX - bufferRect.centerX(), centerY - bufferRect.centerY());
matrix.setRectToRect(viewRect, bufferRect, Matrix.ScaleToFit.FILL);
float scale = Math.max(
(float) viewHeight / mPreviewSize.getHeight(),
(float) viewWidth / mPreviewSize.getWidth());
matrix.postScale(scale, scale, centerX, centerY);
matrix.postRotate(90 * (rotation - 2), centerX, centerY);
} else if (Surface.ROTATION_180 == rotation) {
matrix.postRotate(180, centerX, centerY);
}
mTextureView.setTransform(matrix);
}
/**
* 将JPG保存到指定的文件中。
*/
private static class ImageSaver implements Runnable {
/**
* JPEG图像
*/
private final Image mImage;
/**
* 保存图像的文件
*/
private final File mFile;
public ImageSaver(Image image, File file) {
mImage = image;
mFile = file;
}
@Override
public void run() {
ByteBuffer buffer = mImage.getPlanes()[0].getBuffer();
byte[] bytes = new byte[buffer.remaining()];
buffer.get(bytes);
FileOutputStream output = null;
try {
output = new FileOutputStream(mFile);
output.write(bytes);
} catch (IOException e) {
e.printStackTrace();
} finally {
mImage.close();
if (null != output) {
try {
output.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
}