String TAG =
"CameraPreview";
private static finalSparseIntArray ORIENTATIONS =
newSparseIntArray();
//从屏幕旋转转换为JPEG方向 private static final intMAX_PREVIEW_WIDTH =
1920;
//Camera2 API 保证的最大预览宽高 private static final intMAX_PREVIEW_HEIGHT =
1080;
private static final intSTATE_PREVIEW =
0;
//显示相机预览 private static final intSTATE_WAITING_LOCK =
1;
//焦点锁定中 private static final intSTATE_WAITING_PRE_CAPTURE =
2;
//拍照中 private static final intSTATE_WAITING_NON_PRE_CAPTURE =
3;
//其它状态 private static final intSTATE_PICTURE_TAKEN =
4;
//拍照完毕 private intmState = STATE_PREVIEW;
private intmRatioWidth =
0, mRatioHeight =
0;
private intmSensorOrientation;
private booleanmFlashSupported;
privateSemaphore mCameraOpenCloseLock =
newSemaphore(
1);
//使用信号量 Semaphore 进行多线程任务调度 privateActivity activity;
privateFile mFile;
privateHandlerThread mBackgroundThread;
privateHandler mBackgroundHandler;
privateSize mPreviewSize;
privateString mCameraId;
privateCameraDevice mCameraDevice;
privateCaptureRequest.Builder mPreviewRequestBuilder;
privateCaptureRequest mPreviewRequest;
privateCameraCaptureSession mCaptureSession;
privateImageReader mImageReader;
staticORIENTATIONS.append(Surface.ROTATION_0,
{
90ORIENTATIONS.append(Surface.ROTATION_90,
);
0ORIENTATIONS.append(Surface.ROTATION_180,
);
270ORIENTATIONS.append(Surface.ROTATION_270,
);
180}
);
public CameraPreview(Context context) {
this(context,
null}
);
public CameraPreview(Context context, AttributeSet attrs) {
this(context, attrs,
0}
);
public CameraPreview(Context context, AttributeSet attrs,
intdefStyleAttr) {
supermFile =
(context, attrs, defStyleAttr);
newFile(getContext().getExternalFilesDir(
null),
"pic.jpg"}
);
@Override protected void onMeasure(
intwidthMeasureSpec,
intheightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
intwidth = MeasureSpec.getSize(widthMeasureSpec);
intheight = MeasureSpec.getSize(heightMeasureSpec);
if(
0== mRatioWidth ||
0}
setMeasuredDimension(width, height);
== mRatioHeight) {
else{
if}
setMeasuredDimension(width, width * mRatioHeight / mRatioWidth);
(width < height * mRatioWidth / mRatioHeight) {
else}
}
}
setMeasuredDimension(height * mRatioWidth / mRatioHeight, height);
{
public void onResume(Activity activity) {
thisstartBackgroundThread();
.activity = activity;
//当Activity或Fragment OnResume()时,可以冲洗打开一个相机并开始预览,否则,这个Surface已经准备就绪 if(
thisopenCamera(
.isAvailable()) {
this.getWidth(),
this}
.getHeight());
else{
this}
}
.setSurfaceTextureListener(mSurfaceTextureListener);
public void onPause}
stopBackgroundThread();
closeCamera();
() {
public void setOutPutDir(File file) {
this}
.mFile = file;
public void setAspectRatio(
intwidth,
intheight) {
if(width <
0|| height <
0) {
throw newIllegalArgumentException(
"Size can't be negative"}
requestLayout();
mRatioHeight = height;
mRatioWidth = width;
}
);
public void setAutoFlash(CaptureRequest.Builder requestBuilder) {
if}
}
CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
requestBuilder.set(CaptureRequest.CONTROL_AE_MODE,
(mFlashSupported) {
public void takePicture}
lockFocus();
() {
private void startBackgroundThreadmBackgroundThread =
() {
newHandlerThread(
"CameraBackground"mBackgroundHandler =
mBackgroundThread.start();
);
new}
Handler(mBackgroundThread.getLooper());
private void stopBackgroundThreadmBackgroundThread.quitSafely();
() {
trymBackgroundThread =
mBackgroundThread.join();
{
nullmBackgroundHandler =
;
null}
;
catch}
}
e.printStackTrace();
(InterruptedException e) {
/** * 处理生命周期内的回调事件 */ private finalTextureView.SurfaceTextureListener mSurfaceTextureListener =
newTextureView.SurfaceTextureListener() {
@Override public void onSurfaceTextureAvailable(SurfaceTexture texture,
intwidth,
int}
openCamera(width, height);
height) {
@Override public void onSurfaceTextureSizeChanged(SurfaceTexture texture,
intwidth,
int}
configureTransform(width, height);
height) {
@Override public boolean onSurfaceTextureDestroyed(SurfaceTexture texture) {
return true}
;
@Override public void onSurfaceTextureUpdated};
}
(SurfaceTexture texture) {
/** * 相机状态改变回调 */ private finalCameraDevice.StateCallback mStateCallback =
newCameraDevice.StateCallback() {
@Override public void onOpenedLog.d(TAG,
mCameraOpenCloseLock.release();
(@NonNull CameraDevice cameraDevice) {
"相机已打开"}
createCameraPreviewSession();
mCameraDevice = cameraDevice;
);
@Override public void onDisconnectedmCameraDevice =
cameraDevice.close();
mCameraOpenCloseLock.release();
(@NonNull CameraDevice cameraDevice) {
null}
;
@Override public void onError(@NonNull CameraDevice cameraDevice,
intmCameraDevice =
cameraDevice.close();
mCameraOpenCloseLock.release();
error) {
null;
if(
null};
}
}
activity.finish();
!= activity) {
/** * 处理与照片捕获相关的事件 */ privateCameraCaptureSession.CaptureCallback mCaptureCallback =
newCameraCaptureSession.CaptureCallback() {
private void process(CaptureResult result) {
switch(mState) {
caseSTATE_PREVIEW: {
break}
;
caseInteger afState = result.get(CaptureResult.CONTROL_AF_STATE);
STATE_WAITING_LOCK: {
if(afState ==
null}
captureStillPicture();
) {
else ifInteger aeState = result.get(CaptureResult.CONTROL_AE_STATE);
CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED == afState) {
(CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED == afState ||
if(aeState ==
null}
captureStillPicture();
mState = STATE_PICTURE_TAKEN;
|| aeState == CaptureResult.CONTROL_AE_STATE_CONVERGED) {
else}
}
runPreCaptureSequence();
{
break}
;
caseInteger aeState = result.get(CaptureResult.CONTROL_AE_STATE);
STATE_WAITING_PRE_CAPTURE: {
if(aeState ==
null}
mState = STATE_WAITING_NON_PRE_CAPTURE;
aeState == CaptureRequest.CONTROL_AE_STATE_FLASH_REQUIRED) {
aeState == CaptureResult.CONTROL_AE_STATE_PRECAPTURE ||
||
break}
;
caseInteger aeState = result.get(CaptureResult.CONTROL_AE_STATE);
STATE_WAITING_NON_PRE_CAPTURE: {
if(aeState ==
null}
captureStillPicture();
mState = STATE_PICTURE_TAKEN;
|| aeState != CaptureResult.CONTROL_AE_STATE_PRECAPTURE) {
break}
}
}
;
@Override public void onCaptureProgressed}
process(partialResult);
@NonNull CaptureResult partialResult) {
@NonNull CaptureRequest request,
(@NonNull CameraCaptureSession session,
@Override public void onCaptureCompleted};
}
process(result);
@NonNull TotalCaptureResult result) {
@NonNull CaptureRequest request,
(@NonNull CameraCaptureSession session,
/** * 在确定相机预览大小后应调用此方法 * * @param viewWidth 宽 * @param viewHeight 高 */ private void configureTransform(
intviewWidth,
intviewHeight) {
if(
null== mPreviewSize ||
null== activity) {
return}
;
intMatrix matrix =
rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
newRectF viewRect =
Matrix();
newRectF(
0,
0RectF bufferRect =
, viewWidth, viewHeight);
newRectF(
0,
0, mPreviewSize.getHeight(), mPreviewSize.getWidth());
floatcenterX = viewRect.centerX();
floatcenterY = viewRect.centerY();
ifmatrix.setRectToRect(viewRect, bufferRect, Matrix.ScaleToFit.FILL);
bufferRect.offset(centerX - bufferRect.centerX(), centerY - bufferRect.centerY());
(Surface.ROTATION_90 == rotation || Surface.ROTATION_270 == rotation) {
float(
scale = Math.max(
float(
) viewHeight / mPreviewSize.getHeight(),
floatmatrix.postRotate(
matrix.postScale(scale, scale, centerX, centerY);
) viewWidth / mPreviewSize.getWidth());
90* (rotation -
2}
), centerX, centerY);
else ifmatrix.postRotate(
(Surface.ROTATION_180 == rotation) {
180}
, centerX, centerY);
this}
.setTransform(matrix);
/** * 根据mCameraId打开相机 */ private void openCamera(
intwidth,
intCameraManager manager = (CameraManager) getContext().getSystemService(Context.CAMERA_SERVICE);
configureTransform(width, height);
setUpCameraOutputs(width, height);
height) {
try{
if(!mCameraOpenCloseLock.tryAcquire(
2500, TimeUnit.MILLISECONDS)) {
throw newRuntimeException(
"Time out waiting to lock camera opening."}
);
if(ActivityCompat.checkSelfPermission(activity, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
// TODO: Consider calling // ActivityCompat#requestPermissions // here to request the missing permissions, and then overriding // public void onRequestPermissionsResult(int requestCode, String[] permissions, // int[] grantResults) // to handle the case where the user grants the permission. See the documentation // for ActivityCompat#requestPermissions for more details. return}
manager.openCamera(mCameraId, mStateCallback, mBackgroundHandler);
}
;
catch}
e.printStackTrace();
(CameraAccessException e) {
catch(InterruptedException e) {
throw newRuntimeException(
"Interrupted while trying to lock camera opening."}
}
, e);
/** * 关闭相机 */ private void closeCamera() {
trymCameraOpenCloseLock.acquire();
{
if(
nullmCaptureSession =
mCaptureSession.close();
!= mCaptureSession) {
null}
;
if(
nullmCameraDevice =
mCameraDevice.close();
!= mCameraDevice) {
null}
;
if(
nullmImageReader =
mImageReader.close();
!= mImageReader) {
null}
}
;
catch(InterruptedException e) {
throw newRuntimeException(
"Interrupted while trying to lock camera closing."}
, e);
finally}
}
mCameraOpenCloseLock.release();
{
/** * 设置相机相关的属性或变量 * * @param width 相机预览的可用尺寸的宽度 * @param height 相机预览的可用尺寸的高度 */ @SuppressWarnings(
"SuspiciousNameCombination")
private void setUpCameraOutputs(
intwidth,
intCameraManager manager = (CameraManager) getContext().getSystemService(Context.CAMERA_SERVICE);
height) {
try{
forCameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId);
(String cameraId : manager.getCameraIdList()) {
// 在这个例子中不使用前置摄像头Integer facing = characteristics.get(CameraCharacteristics.LENS_FACING);
if(facing !=
null&& facing == CameraCharacteristics.LENS_FACING_FRONT) {
continueStreamConfigurationMap map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
}
;
if(map ==
null) {
continueSize largest = Collections.max(Arrays.asList(map.getOutputSizes(ImageFormat.JPEG)),
}
;
newImageFormat.JPEG,
mImageReader = ImageReader.newInstance(largest.getWidth(), largest.getHeight(),
CompareSizesByArea());
/*maxImages*/2mOnImageAvailableListener, mBackgroundHandler);
mImageReader.setOnImageAvailableListener(
);
intdisplayRotation = activity.getWindowManager().getDefaultDisplay().getRotation();
// noinspection ConstantConditionsmSensorOrientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
booleanswappedDimensions =
false;
switch(displayRotation) {
caseSurface.ROTATION_0:
caseSurface.ROTATION_180:
if(mSensorOrientation ==
90|| mSensorOrientation ==
270swappedDimensions =
) {
true}
;
break;
caseSurface.ROTATION_90:
caseSurface.ROTATION_270:
if(mSensorOrientation ==
0|| mSensorOrientation ==
180swappedDimensions =
) {
true}
;
break;
defaultLog.e(TAG,
:
"Display rotation is invalid: "Point displaySize =
}
+ displayRotation);
newactivity.getWindowManager().getDefaultDisplay().getSize(displaySize);
Point();
introtatedPreviewWidth = width;
introtatedPreviewHeight = height;
intmaxPreviewWidth = displaySize.x;
intmaxPreviewHeight = displaySize.y;
if}
maxPreviewHeight = displaySize.x;
maxPreviewWidth = displaySize.y;
rotatedPreviewHeight = width;
rotatedPreviewWidth = height;
(swappedDimensions) {
if}
maxPreviewWidth = MAX_PREVIEW_WIDTH;
(maxPreviewWidth > MAX_PREVIEW_WIDTH) {
ifmaxPreviewHeight, largest);
rotatedPreviewWidth, rotatedPreviewHeight, maxPreviewWidth,
mPreviewSize = chooseOptimalSize(map.getOutputSizes(SurfaceTexture.class),
}
maxPreviewHeight = MAX_PREVIEW_HEIGHT;
(maxPreviewHeight > MAX_PREVIEW_HEIGHT) {
intorientation = getResources().getConfiguration().orientation;
if}
setAspectRatio(mPreviewSize.getWidth(), mPreviewSize.getHeight());
(orientation == Configuration.ORIENTATION_LANDSCAPE) {
elsemFlashSupported = available ==
Boolean available = characteristics.get(CameraCharacteristics.FLASH_INFO_AVAILABLE);
}
setAspectRatio(mPreviewSize.getHeight(), mPreviewSize.getWidth());
{
nullfalsemCameraId = cameraId;
: available;
return}
}
;
catch}
e.printStackTrace();
(CameraAccessException e) {
catchLog.e(TAG,
(NullPointerException e) {
"设备不支持Camera2"}
}
);
/** * 获取一个合适的相机预览尺寸 * * @param choices 支持的预览尺寸列表 * @param textureViewWidth 相对宽度 * @param textureViewHeight 相对高度 * @param maxWidth 可以选择的最大宽度 * @param maxHeight 可以选择的最大高度 * @param aspectRatio 宽高比 * @return 最佳预览尺寸 */ private staticSize
chooseOptimalSize(Size[] choices,
inttextureViewWidth,
inttextureViewHeight,
intmaxWidth,
intList
maxHeight, Size aspectRatio) {
newList
ArrayList<>();
newArrayList<>();
intw = aspectRatio.getWidth();
inth = aspectRatio.getHeight();
for(Size option : choices) {
ifoption.getHeight() == option.getWidth() * h / w) {
(option.getWidth() <= maxWidth && option.getHeight() <= maxHeight &&
if}
bigEnough.add(option);
option.getHeight() >= textureViewHeight) {
(option.getWidth() >= textureViewWidth &&
else}
}
}
notBigEnough.add(option);
{
if(bigEnough.size() >
0) {
returnCollections.min(bigEnough,
new}
CompareSizesByArea());
else if(notBigEnough.size() >
0) {
returnCollections.max(notBigEnough,
new}
CompareSizesByArea());
elseLog.e(TAG,
{
"Couldn't find any suitable preview size");
returnchoices[
0}
}
];
/** * 为相机预览创建新的CameraCaptureSession */ private void createCameraPreviewSession() {
trySurfaceTexture texture =
{
this.getSurfaceTexture();
asserttexture !=
null;
// 将默认缓冲区的大小配置为想要的相机预览的大小Surface surface =
texture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
newmPreviewRequestBuilder.addTarget(surface);
mPreviewRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
Surface(texture);
// 我们创建一个 CameraCaptureSession 来进行相机预览mCameraDevice.createCaptureSession(Arrays.asList(surface, mImageReader.getSurface()),
newCameraCaptureSession.StateCallback() {
@Override public void onConfigured(@NonNull CameraCaptureSession cameraCaptureSession) {
if(
null== mCameraDevice) {
return}
;
// 会话准备好后,我们开始显示预览mCaptureSession = cameraCaptureSession;
try}
mCaptureSession.setRepeatingRequest(mPreviewRequest, mCaptureCallback, mBackgroundHandler);
mPreviewRequest = mPreviewRequestBuilder.build();
setAutoFlash(mPreviewRequestBuilder);
CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE,
{
catch}
}
e.printStackTrace();
(CameraAccessException e) {
@Override public void onConfigureFailed},
}
(@NonNull CameraCaptureSession cameraCaptureSession) {
null}
);
catch}
}
e.printStackTrace();
(CameraAccessException e) {
/** * 从指定的屏幕旋转中检索照片方向 * * @param rotation 屏幕方向 * @return 照片方向(0,90,270,360) */ private int getOrientation(
introtation) {
return(ORIENTATIONS.get(rotation) + mSensorOrientation +
270) %
360}
;
/** * 锁定焦点 */ private void lockFocus() {
try{
// 如何通知相机锁定焦点mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_START);
// 通知mCaptureCallback等待锁定}
mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback, mBackgroundHandler);
mState = STATE_WAITING_LOCK;
catch}
}
e.printStackTrace();
(CameraAccessException e) {
/** * 解锁焦点 */ private void unlockFocus() {
try}
mBackgroundHandler);
mCaptureSession.setRepeatingRequest(mPreviewRequest, mCaptureCallback,
mState = STATE_PREVIEW;
mBackgroundHandler);
mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback,
setAutoFlash(mPreviewRequestBuilder);
CameraMetadata.CONTROL_AF_TRIGGER_CANCEL);
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,
{
catch}
}
e.printStackTrace();
(CameraAccessException e) {
/** * 拍摄静态图片 */ private void captureStillPicture() {
try{
if(
null== activity ||
null== mCameraDevice) {
return}
;
finalsetAutoFlash(captureBuilder);
CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
captureBuilder.set(CaptureRequest.CONTROL_AF_MODE,
captureBuilder.addTarget(mImageReader.getSurface());
mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
CaptureRequest.Builder captureBuilder =
// 方向 int=
CameraCaptureSession.CaptureCallback captureCallback
captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, getOrientation(rotation));
rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
newCameraCaptureSession.CaptureCallback() {
@Override public void onCaptureCompletedToast.makeText(getContext(),
@NonNull TotalCaptureResult result) {
@NonNull CaptureRequest request,
(@NonNull CameraCaptureSession session,
"Saved: "mCaptureSession.capture(captureBuilder.build(), captureCallback,
mCaptureSession.abortCaptures();
mCaptureSession.stopRepeating();
};
}
unlockFocus();
Log.d(TAG, mFile.toString());
+ mFile, Toast.LENGTH_SHORT).show();
null}
);
catch}
}
e.printStackTrace();
(CameraAccessException e) {
/** * 运行preCapture序列来捕获静止图像 */ private void runPreCaptureSequence() {
try{
// 设置拍照参数请求}
mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback, mBackgroundHandler);
mState = STATE_WAITING_PRE_CAPTURE;
CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START);
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER,
catch}
}
e.printStackTrace();
(CameraAccessException e) {
/** * 比较两者大小 */ private static class CompareSizesByArea implements Comparator<Size> { @Override public int compare(Size lhs, Size rhs) {
returnLong.signum((
long(
) lhs.getWidth() * lhs.getHeight() -
long}
}
) rhs.getWidth() * rhs.getHeight());
/** * ImageReader的回调对象 */ private final=
ImageReader.OnImageAvailableListener mOnImageAvailableListener
newImageReader.OnImageAvailableListener() {
@Override public void onImageAvailablemBackgroundHandler.post(
(ImageReader reader) {
new};
}
ImageSaver(reader.acquireNextImage(), mFile));
/** * 将捕获到的图像保存到指定的文件中 */ private static class ImageSaver implements Runnable { private finalImage mImage;
private final}
mFile = file;
mImage = image;
ImageSaver(Image image, File file) {
File mFile;
@Override public void runByteBuffer buffer = mImage.getPlanes()[
() {
0].getBuffer();
byte[] bytes =
new byteFileOutputStream output =
buffer.get(bytes);
[buffer.remaining()];
null;
tryoutput =
{
new}
output.write(bytes);
FileOutputStream(mFile);
catch}
e.printStackTrace();
(IOException e) {
finallymImage.close();
{
if(
null!= output) {
try}
output.close();
{
catch}
}
}
}
}
}
e.printStackTrace();
(IOException e) {
来源: http://blog.csdn.net/klxh2009/article/details/78326424