自己开发的相机APP代码java部分

CameraActivity.java

package com.example.android.camera2basic;import android.Manifest;
import android.annotation.SuppressLint;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.provider.Settings;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.view.Menu;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;public class CameraActivity extends AppCompatActivity {private Button btn1,btn2,btn3,btn4;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_camera);btn1 = (Button) findViewById(R.id.button1);btn2 = (Button) findViewById(R.id.button2);/* btn3 = (Button) findViewById(R.id.button3);btn4 = (Button) findViewById(R.id.button4);*/checkPermission();btn1.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {// if (null == savedInstanceState) {getSupportFragmentManager().beginTransaction().replace(R.id.container, Camera2BasicFragment.newInstance()).commit();// }}});btn2.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {getSupportFragmentManager().beginTransaction().replace(R.id.container, CameraFragment.intent()).commit();}});//分辨率切换/*   btn3.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {getSupportFragmentManager().beginTransaction().replace(R.id.container, Camera2BasicFragment2.newInstance()).commit();}});//录像功能btn4.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {getSupportFragmentManager().beginTransaction().replace(R.id.container, Camera2VideoFragment.newInstance()).commit();}});*/}//读取相册的图片权限设置private void checkPermission() {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {String[] permissions = new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.CAMERA};for (String permission : permissions) {if (ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) {ActivityCompat.requestPermissions(this, permissions, 200);return;}}}}@Overridepublic void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[]grantResults) {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && requestCode == 200) {for (int i = 0; i < permissions.length; i++) {if (grantResults[i] != PackageManager.PERMISSION_GRANTED) {Toast.makeText(this, "请在设置中打开摄像头和存储权限", Toast.LENGTH_SHORT).show();Intent intent = new Intent();intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);Uri uri = Uri.fromParts("package", getPackageName(), null);intent.setData(uri);startActivityForResult(intent, 200);return;}}}}}

Camera2BasicFragment.java

/** Copyright 2017 The Android Open Source Project** Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at**       http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/package com.example.android.camera2basic;import android.Manifest;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ImageFormat;
import android.graphics.Matrix;
import android.graphics.Paint;
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.media.ThumbnailUtils;
import android.os.Bundle;
import android.os.CountDownTimer;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
import android.os.SystemClock;
import android.provider.MediaStore;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.Fragment;
import android.support.v4.content.ContextCompat;
import android.util.Log;
import android.util.Range;
import android.util.Size;
import android.util.SparseIntArray;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.Surface;
import android.view.TextureView;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.Chronometer;
import android.widget.ImageView;
import android.widget.PopupMenu;
import android.widget.TableLayout;
import android.widget.TextView;
import android.widget.Toast;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;/* 拍照预览流程图UI控件分辨率:protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {预览分辨率:texture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());图片分辨率:mImageReader = ImageReader.newInstance(largest.getWidth(), largest.getHeight(),ImageFormat.JPEG, 2);TextureView设置预览方向:mTextureView.setTransform(matrix); 其他预览控件,不是这个方法。
图片方向:captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, getOrientation(rotation));屏幕旋转:private void configureTransform(int viewWidth, int viewHeight)1-> public void onViewCreated(final View view, Bundle savedInstanceState) {2-> mTextureView = (AutoFitTextureView) view.findViewById(R.id.texture);//获取mTextureView
1-> public void onResume() {2-> startBackgroundThread();  //为相机开启了一个后台线程,这个进程用于后台执行保存图片等相关的工作3-> mBackgroundThread = new HandlerThread("bruceCameraBackground");3-> mBackgroundThread.start();3-> mBackgroundHandler = new Handler(mBackgroundThread.getLooper());2-> if (mTextureView.isAvailable()) {openCamera(mTextureView.getWidth(), mTextureView.getHeight());  //mTextureView已经创建,SurfaceTexture已经有效,则直接openCamera,用于屏幕熄灭等情况,这时onSurfaceTextureAvailable不会回调。2-> else {mTextureView.setSurfaceTextureListener(mSurfaceTextureListener);     //SurfaceTexture处于无效状态中,则通过SurfaceTextureListener确保surface准备好。3-> public void onSurfaceTextureAvailable(SurfaceTexture texture, int width, int height) {4-> openCamera(width, height);     //SurfaceTexture有效即可openCamera5-> requestCameraPermission();//请求权限5-> setUpCameraOutputs(width, height);//包括对相机设备的选择,ImageReader的初始化和参数、回调设置。设置显示的转化矩阵,即将预览的图片调整至显示图层的大小。6-> for (String cameraId : manager.getCameraIdList()) {//获取摄像头可用列表6-> CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId);获取相机的特性6-> Integer facing = characteristics.get(CameraCharacteristics.LENS_FACING);// 不使用前置摄像头6-> mImageReader = ImageReader.newInstance(largest.getWidth(), largest.getHeight(),ImageFormat.JPEG, 2);//设置ImageReader接收的图片格式,以及允许接收的最大图片数目6-> mImageReader.setOnImageAvailableListener(mOnImageAvailableListener, mBackgroundHandler);//设置图片存储的监听,但在创建会话,调用capture后才能有数据7-> public void onImageAvailable(ImageReader reader) {//图片有效回调8-> reader.acquireNextImage()//获取图片image8-> mBackgroundHandler.post(new ImageSaver(reader.acquireNextImage(), mFile));///通知ImageSaver线程保存图片9-> private static class ImageSaver implements Runnable {//保存图片线程 10-> public void run() {11-> output = new FileOutputStream(mFile);output.write(bytes);//保存图片到文件6-> int displayRotation = activity.getWindowManager().getDefaultDisplay().getRotation();//获取显示方向6-> mSensorOrientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);//获取sensor方向6-> mPreviewSize = chooseOptimalSize(map.getOutputSizes(SurfaceTexture.class),//获取最优的预览分辨率6-> mTextureView.setAspectRatio(mPreviewSize.getWidth(), mPreviewSize.getHeight());//设置TextureView预览分辨率6-> mCameraId = cameraId;//获取当前ID5-> configureTransform(width, height);//配置transformation,主要是矩阵旋转相关5-> CameraManager manager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE);5-> manager.openCamera(mCameraId, mStateCallback, mBackgroundHandler);//打开相机---------------------6-> private final CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() {//打开相机设备状态回调---------------------7-> public void onError(@NonNull CameraDevice cameraDevice, int error) {//打开错误  7-> public void onDisconnected(@NonNull CameraDevice cameraDevice) {//断开相机7-> public void onOpened(@NonNull CameraDevice cameraDevice) {//打开成功8-> mCameraDevice = cameraDevice;//从onOpened参数获取mCameraDevice8-> createCameraPreviewSession();//创建会话9-> SurfaceTexture texture = mTextureView.getSurfaceTexture();//获取SurfaceTexture9-> texture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());//设置TextureView大小 9-> Surface surface = new Surface(texture);//创建Surface来预览9-> mPreviewRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);//创建TEMPLATE_PREVIEW预览CaptureRequest.Builder9-> mPreviewRequestBuilder.addTarget(surface);//CaptureRequest.Builder中添加Surface9-> mCameraDevice.createCaptureSession(Arrays.asList(surface, mImageReader.getSurface()),new CameraCaptureSession.StateCallback() {//创建会话---------------------10-> public void onConfigureFailed(//创建会话失败10-> public void onConfigured(@NonNull CameraCaptureSession cameraCaptureSession) {//创建会话成功11-> mCaptureSession = cameraCaptureSession;//从onConfigured参数获取mCaptureSession11-> mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE,CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);//设置AF自动对焦模式11-> mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE,CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);//设置AE模式11-> mPreviewRequest = mPreviewRequestBuilder.build();//转换为CaptureRequest11-> mCaptureSession.setRepeatingRequest(mPreviewRequest,mCaptureCallback, mBackgroundHandler);//设置预览,和拍照是同一个回调mCaptureCallback---------------------12-> private CameraCaptureSession.CaptureCallback mCaptureCallback = new CameraCaptureSession.CaptureCallback() {//预览回调---------------------13-> public void onCaptureProgressed(@NonNull CameraCaptureSession session,@NonNull CaptureRequest request,@NonNull CaptureResult partialResult) {//预览过程中13-> public void onCaptureCompleted(@NonNull CameraCaptureSession session,@NonNull CaptureRequest request,@NonNull TotalCaptureResult result) {//预览完成,和拍照是同一个回调mCaptureCallback14-> process(result); //从onCaptureCompleted参数获取CaptureResult15-> case STATE_PREVIEW: {//预览状态,则什么都不做15-> case STATE_WAITING_LOCK: {//等待焦点被锁时,由设置拍照流时设置的STATE_WAITING_LOCK16->captureStillPicture();//进行拍照17-> final CaptureRequest.Builder captureBuilder =  mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);//设置TEMPLATE_STILL_CAPTURE拍照CaptureRequest.Builder17-> captureBuilder.addTarget(mImageReader.getSurface());//添加拍照mImageReader为Surface17-> captureBuilder.set(CaptureRequest.CONTROL_AF_MODE,CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);//设置AF17-> captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, getOrientation(rotation));//设置图片方向17-> mCaptureSession.stopRepeating();//停止预览 17-> mCaptureSession.abortCaptures();//中断Capture17-> mCaptureSession.capture(captureBuilder.build(), CaptureCallback, null);//重新Capture进行拍照,这时mImageReader的回调会执行并保存图片---------------------18-> CameraCaptureSession.CaptureCallback CaptureCallback  = new CameraCaptureSession.CaptureCallback() { //拍照流程执行完成回调---------------------19-> public void onCaptureCompleted(@NonNull CameraCaptureSession session,20-> showToast("Saved: " + mFile);//提示拍照图片已经保存20-> unlockFocus();//释放焦点锁,重新开启预览。21-> mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,CameraMetadata.CONTROL_AF_TRIGGER_CANCEL);//重新设置AE/AF21-> mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback,mBackgroundHandler);//重新设置AE/AF,通过mPreviewRequestBuilder.build()只发送一次请求,而不是mPreviewRequest。21-> mState = STATE_PREVIEW;//设置预览状态,通知mCaptureCallback回到预览状态21-> mCaptureSession.setRepeatingRequest(mPreviewRequest, mCaptureCallback,mBackgroundHandler);//重新进入预览,使用mPreviewRequest
3-> public void onSurfaceTextureSizeChanged(SurfaceTexture texture, int width, int height) { 4-> configureTransform(width, height);
3-> public boolean onSurfaceTextureDestroyed(SurfaceTexture texture) {3-> public void onSurfaceTextureUpdated(SurfaceTexture texture) { 4-> //镜像模式获取bitmap
1-> public void onClick(View view) {2-> takePicture();//拍照3-> lockFocus() {//拍照过程中锁住焦点4-> mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_START); //通知camera锁住对焦4-> mState = STATE_WAITING_LOCK;//设置状态,通知mCaptureCallback等待锁定4-> mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback,mBackgroundHandler);//通知camera锁住对焦和状态只发送一次请求,是同一个回调mCaptureCallback,只是等待焦点被锁,切换为STATE_WAITING_LOCK再真正进行拍照---------------------*/
public class Camera2BasicFragment extends Fragmentimplements View.OnClickListener, ActivityCompat.OnRequestPermissionsResultCallback, Chronometer.OnChronometerTickListener {/*** Conversion from screen rotation to JPEG orientation.*/private static final SparseIntArray ORIENTATIONS = new SparseIntArray();private static final int REQUEST_CAMERA_PERMISSION = 1;private static final int REQUEST_VIDEO_PERMISSIONS = 1;private static final String FRAGMENT_DIALOG = "dialog";private Button mButtonVideo;private Button mButtonPz;//拍照private TextView mButtonFz;//翻转private TextView mButtonFbl;//分辨率private TextView mButtonSy;//水印private TextView mButtonLx;//录像private TextView mButtonCkx;//参考线private TextView mButtonMdz;//慢动作private Chronometer mchronometer;//录制时长显示private TextView mBntTime;//延迟拍照private TextView mButtonYc;//延迟private int yc_flag=0;//延迟flagprivate static TextView mButtonSgd;//闪光灯private static int sgd_flag=0;private static TableLayout tableLine;private static int line_flag=0;//参考线private static ImageView mimage_thumbnail;//缩略图private static Bitmap bitMap;private static Handler handler = new Handler() {@Overridepublic void handleMessage(Message msg) {if (msg.what == 1) {mimage_thumbnail.setImageBitmap(bitMap);}else if (msg.what==2){if(line_flag==0){line_flag=1;tableLine.setVisibility(View.VISIBLE);//参考线显示状态}else {line_flag=0;tableLine.setVisibility(View.GONE);//隐藏状态,且不占空间}}else if(msg.what==3){if(sgd_flag==0){sgd_flag=1;mButtonSgd.setText("闪关灯: 开");}else {sgd_flag=0;mButtonSgd.setText("闪关灯: 关");}}}};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 SparseIntArray DEFAULT_ORIENTATIONS = new SparseIntArray();private static final SparseIntArray INVERSE_ORIENTATIONS = new SparseIntArray();static {DEFAULT_ORIENTATIONS.append(Surface.ROTATION_0, 90);DEFAULT_ORIENTATIONS.append(Surface.ROTATION_90, 0);DEFAULT_ORIENTATIONS.append(Surface.ROTATION_180, 270);DEFAULT_ORIENTATIONS.append(Surface.ROTATION_270, 180);}static {INVERSE_ORIENTATIONS.append(Surface.ROTATION_0, 270);INVERSE_ORIENTATIONS.append(Surface.ROTATION_90, 180);INVERSE_ORIENTATIONS.append(Surface.ROTATION_180, 90);INVERSE_ORIENTATIONS.append(Surface.ROTATION_270, 0);}private static final String[] VIDEO_PERMISSIONS = {Manifest.permission.CAMERA,Manifest.permission.RECORD_AUDIO,};/*** Tag for the {@link Log}.*/private static final String TAG = "Fragment_TextureView";/*** Camera state: Showing camera preview.*/private static final int STATE_PREVIEW = 0;//预览状态/*** Camera state: Waiting for the focus to be locked.等待自动对焦的焦点被锁状态*/private static final int STATE_WAITING_LOCK = 1;/*** Camera state: Waiting for the exposure to be precapture state.等待曝光为预捕获状态*/private static final int STATE_WAITING_PRECAPTURE = 2;/*** Camera state: Waiting for the exposure state to be something other than precapture.等待曝光不是预捕获状态*/private static final int STATE_WAITING_NON_PRECAPTURE = 3;/*** Camera state: Picture was taken.  拍照状态,APP开始获取图片数据流进行保存*/private static final int STATE_PICTURE_TAKEN = 4;/*** Max preview width that is guaranteed by Camera2 API*/private static final int MAX_PREVIEW_WIDTH = 1920;/*** Max preview height that is guaranteed by Camera2 API*/private static final int MAX_PREVIEW_HEIGHT = 1080;/*** {@link TextureView.SurfaceTextureListener} handles several lifecycle events on a* {@link TextureView}.*/private final TextureView.SurfaceTextureListener mSurfaceTextureListener= new TextureView.SurfaceTextureListener() {//TextureView回调@Overridepublic void onSurfaceTextureAvailable(SurfaceTexture texture, int width, int height) {openCamera(width, height);//SurfaceTexture有效即可openCamera}@Overridepublic void onSurfaceTextureSizeChanged(SurfaceTexture texture, int width, int height) {configureTransform(width, height);// 当屏幕旋转时,预览方向改变时, 执行转换操作. 默认情况下TextureView通过此方法设置预览方向}@Overridepublic boolean onSurfaceTextureDestroyed(SurfaceTexture texture) {return true;}@Overridepublic void onSurfaceTextureUpdated(SurfaceTexture texture) {//可获取bitmap}};/*** ID of the current {@link CameraDevice}.正在使用的相机id*/private String mCameraId;private int flag_Fz=0;private int flag=0;private int flag_Lx = 0;//录像private  int text_flag=0;//水印private int video_flag1=0;//慢动作private int width_T=3968;private int height_T=2976;private boolean mIsRecordingVideo;private int camera_flag=0;/*** An {@link AutoFitTextureView} for camera preview.预览使用的自定义TextureView控件*/private AutoFitTextureView mTextureView;private TextView text1;/*** A {@link CameraCaptureSession } for camera preview.预览用的获取会话*/private CameraCaptureSession mCaptureSession;/*** A reference to the opened {@link CameraDevice}.正在使用的相机*/private CameraDevice mCameraDevice;/*** The {@link Size} of camera preview.预览数据的尺寸*/private Size mPreviewSize;/*** {@link CameraDevice.StateCallback} is called when {@link CameraDevice} changes its state.相机状态改变的回调函数*/private final CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() {//打开相机设备状态回调@Overridepublic void onOpened(@NonNull CameraDevice cameraDevice) {//打开成功// This method is called when the camera is opened.  We start camera preview here.mCameraOpenCloseLock.release();//释放访问许可mCameraDevice = cameraDevice;//从onOpened参数获取mCameraDevicecreateCameraPreviewSession();//创建会话}@Overridepublic void onDisconnected(@NonNull CameraDevice cameraDevice) {//断开相机mCameraOpenCloseLock.release();cameraDevice.close();mCameraDevice = null;}@Overridepublic void onError(@NonNull CameraDevice cameraDevice, int error) {//打开错误mCameraOpenCloseLock.release();cameraDevice.close();mCameraDevice = null;Activity activity = getActivity();if (null != activity) {activity.finish();}}};/*** An additional thread for running tasks that shouldn't block the UI.处理拍照等工作的子线程*/private HandlerThread mBackgroundThread;/*** A {@link Handler} for running tasks in the background.*/private Handler mBackgroundHandler;/*** An {@link ImageReader} that handles still image capture.*/private ImageReader mImageReader;/*** This is the output file for our picture.*/private File mFile;/*** This a callback object for the {@link ImageReader}. "onImageAvailable" will be called when a* still image is ready to be saved.ImageReader的回调函数, 其中的onImageAvailable会在照片准备好可以被保存时调用*/private final ImageReader.OnImageAvailableListener mOnImageAvailableListener= new ImageReader.OnImageAvailableListener() {@Overridepublic void onImageAvailable(ImageReader reader) {//图片有效回调mBackgroundHandler.post(new ImageSaver(reader.acquireNextImage(), mFile,flag_Fz,text_flag));//通知ImageSaver线程保存图片,//reader.acquireNextImage()获取图片image}};/*** {@link CaptureRequest.Builder} for the camera preview预览请求构建器, 用来构建"预览请求"(下面定义的)通过pipeline发送到Camera device*/private CaptureRequest.Builder mPreviewRequestBuilder;/*** {@link CaptureRequest} generated by {@link #mPreviewRequestBuilder}预览请求, 由上面的构建器构建出来*/private CaptureRequest mPreviewRequest;/*** The current state of camera state for taking pictures.用于拍照的相机状态的当前状态** @see #mCaptureCallback*/private int mState = STATE_PREVIEW;//默认状态为预览状态/*** A {@link Semaphore} to prevent the app from exiting before closing the camera.信号量控制器, 防止相机没有关闭时退出本应用*/private Semaphore mCameraOpenCloseLock = new Semaphore(1);/*** Whether the current camera device supports Flash or not.当前摄像头设备是否支持Flash*/private boolean mFlashSupported;/*** Orientation of the camera sensor*/private int mSensorOrientation;/*** A {@link CameraCaptureSession.CaptureCallback} that handles events related to JPEG capture.处理与JPEG捕获相关的事件*/private CameraCaptureSession.CaptureCallback mCaptureCallback= new CameraCaptureSession.CaptureCallback() {//预览回调private void process(CaptureResult result) {switch (mState) {case STATE_PREVIEW: {//预览状态,则什么都不做// We have nothing to do when the camera preview is working normally.break;}case STATE_WAITING_LOCK: {//等待自动对焦的焦点被锁时,由设置拍照流时设置的STATE_WAITING_LOCKInteger afState = result.get(CaptureResult.CONTROL_AF_STATE);//获取当前 AF 算法状态if (afState == null) {//某些设备完成锁定后CONTROL_AF_STATE可能为nullcaptureStillPicture();//进行拍照} else if (CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED == afState ||    /*AF 算法认为已对焦。镜头未移动。*/CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED == afState || flag==0) { /*AF 算法认为无法对焦。镜头未移动。*/// CONTROL_AE_STATE can be null on some devicesInteger aeState = result.get(CaptureResult.CONTROL_AE_STATE);//获取当前 AF 算法状态if (aeState == null ||aeState == CaptureResult.CONTROL_AE_STATE_CONVERGED) {//AE 已经为当前场景找到了理想曝光值,且曝光参数不会变化。mState = STATE_PICTURE_TAKEN;//设置拍照状态,APP开始获取图片数据流进行保存captureStillPicture();} else {runPrecaptureSequence();//如果没有找到理想曝光值,则运行捕获静止图像的预捕获序列操作。}}break;}case STATE_WAITING_PRECAPTURE: {//等待曝光为预捕获状态// CONTROL_AE_STATE can be null on some devices某些设备CONTROL_AE_STATE可能为nullInteger aeState = result.get(CaptureResult.CONTROL_AE_STATE);//获取当前 AE 算法状态if (aeState == null ||  //某些设备CONTROL_AE_STATE可能为nullaeState == CaptureResult.CONTROL_AE_STATE_PRECAPTURE ||   /*HAL 正在处理预拍序列。*/aeState == CaptureRequest.CONTROL_AE_STATE_FLASH_REQUIRED) {/*HAL 已聚焦曝光,但认为需要启动闪光灯才能保证照片亮度充足。*/mState = STATE_WAITING_NON_PRECAPTURE;//设置等待曝光不是预捕获状态}break;}case STATE_WAITING_NON_PRECAPTURE: {// CONTROL_AE_STATE can be null on some devices 某些设备CONTROL_AE_STATE可能为nullInteger aeState = result.get(CaptureResult.CONTROL_AE_STATE);//获取当前 AE 算法状态if (aeState == null || aeState != CaptureResult.CONTROL_AE_STATE_PRECAPTURE) {/*HAL 正在处理预拍序列。*/mState = STATE_PICTURE_TAKEN;//设置拍照状态,APP开始获取图片数据流进行保存captureStillPicture();}break;}}}@Overridepublic void onCaptureProgressed(@NonNull CameraCaptureSession session,@NonNull CaptureRequest request,@NonNull CaptureResult partialResult) {//预览过程中process(partialResult);}@Overridepublic void onCaptureCompleted(@NonNull CameraCaptureSession session,@NonNull CaptureRequest request,@NonNull TotalCaptureResult result) {//预览完成process(result);//从onCaptureCompleted参数获取CaptureResult}};/*** Shows a {@link Toast} on the UI thread.** @param text The message to show*/private void showToast(final String text) {final Activity activity = getActivity();if (activity != null) {activity.runOnUiThread(new Runnable() {@Overridepublic void run() {Thread.currentThread().setName("bruce线程");Toast.makeText(activity, text, Toast.LENGTH_SHORT).show();}});}}/*** Given {@code choices} of {@code Size}s supported by a camera, choose the smallest one that* is at least as large as the respective texture view size, and that is at most as large as the* respective max size, and whose aspect ratio matches with the specified value. If such size* doesn't exist, choose the largest one that is at most as large as the respective max size,* and whose aspect ratio matches with the specified value.* * @param choices           The list of sizes that the camera supports for the intended output*                          class 相机支持的尺寸list* @param textureViewWidth  The width of the texture view relative to sensor coordinate* @param textureViewHeight The height of the texture view relative to sensor coordinate* @param maxWidth          The maximum width that can be chosen 能够选择的最大宽度* @param maxHeight         The maximum height that can be chosen 能够选择的醉倒高度* @param aspectRatio       The aspect ratio 图像的比例(pictureSize, 只有当pictureSize和textureSize保持一致, 才不会失真)* @return The optimal {@code Size}, or an arbitrary one if none were big enough 返回最合适的预览尺寸*/private static Size chooseOptimalSize(Size[] choices, int textureViewWidth,int textureViewHeight, int maxWidth, int maxHeight, Size aspectRatio) {// Collect the supported resolutions that are at least as big as the preview Surface// 存放小于等于限定尺寸, 大于等于texture控件尺寸的SizeList<Size> bigEnough = new ArrayList<>();// Collect the supported resolutions that are smaller than the preview Surface// 存放小于限定尺寸, 小于texture控件尺寸的SizeList<Size> 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);}}}// Pick the smallest of those big enough. If there is no one big enough, pick the// largest of those not big enough.// 1. 若存在bigEnough数据, 则返回最大里面最小的// 2. 若不存bigEnough数据, 但是存在notBigEnough数据, 则返回在最小里面最大的// 3. 上述两种数据都没有时, 返回空, 并在日志上显示错误信息if (bigEnough.size() > 0) {return Collections.min(bigEnough, new CompareSizesByArea());} else if (notBigEnough.size() > 0) {return Collections.max(notBigEnough, new CompareSizesByArea());} else {Log.e(TAG, "Couldn't find any suitable preview size");return choices[0];}}public static Camera2BasicFragment newInstance() {return new Camera2BasicFragment();}@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {return inflater.inflate(R.layout.fragment_camera2_basic, container, false);}@Overridepublic void onViewCreated(final View view, Bundle savedInstanceState) {/*view.findViewById(R.id.picture).setOnClickListener(this);//翻转view.findViewById(R.id.picture2).setOnClickListener(this);view.findViewById(R.id.info).setOnClickListener(this);mTextureView = (AutoFitTextureView) view.findViewById(R.id.texture);//获取mTextureViewtext1= (TextView)view.findViewById(R.id.text11);view.findViewById(R.id.picture3).setOnClickListener(this);//录像view.findViewById(R.id.btn_video).setOnClickListener(this);//分辨率view.findViewById(R.id.btn_check).setOnClickListener(this);*/
////录制时长mchronometer = (Chronometer) view.findViewById(R.id.chronometer);mchronometer.setOnChronometerTickListener(this);//翻转mButtonFz = (TextView) view.findViewById(R.id.picture2);mButtonFz.setOnClickListener(this);//拍照mButtonPz = (Button) view.findViewById(R.id.picture);mButtonPz.setOnClickListener(this);//view.findViewById(R.id.info).setOnClickListener(this);mTextureView = (AutoFitTextureView) view.findViewById(R.id.texture);//获取mTextureView//水印text1= (TextView)view.findViewById(R.id.text11);mButtonSy=(TextView) view.findViewById(R.id.picture3);mButtonSy.setOnClickListener(this);//录像mButtonLx=(TextView) view.findViewById(R.id.btn_video);mButtonLx.setOnClickListener(this);mButtonVideo = (Button) view.findViewById(R.id.video1);mButtonVideo.setOnClickListener(this);//分辨率mButtonFbl = (TextView) view.findViewById(R.id.btn_check);mButtonFbl.setOnClickListener(this);//缩略图mimage_thumbnail = (ImageView)view.findViewById(R.id.image_thumbnail);ImageXJ image = new ImageXJ();// 获取相册里最新的图片显示mimage_thumbnail.setImageBitmap(image.getLatestThumbBitmap());mimage_thumbnail.setOnClickListener(this);//参考线mButtonCkx=(TextView)view.findViewById(R.id.btn_line);mButtonCkx.setOnClickListener(this);tableLine = (TableLayout)view.findViewById(R.id.line_table);//闪光灯mButtonSgd = (TextView)view.findViewById(R.id.btn_sgd);mButtonSgd.setOnClickListener(this);//慢动作mButtonMdz = (TextView)view.findViewById((R.id.btn_video_mdz));mButtonMdz.setOnClickListener(this);//延迟拍照10smBntTime = (TextView)view.findViewById(R.id.btn_time);mButtonYc = (TextView)view.findViewById(R.id.btn_yc);mButtonYc.setOnClickListener(this);}@Overridepublic void onActivityCreated(Bundle savedInstanceState) {super.onActivityCreated(savedInstanceState);mFile = new File(getActivity().getExternalFilesDir(null), "pic.jpg");}@Overridepublic void onResume() {super.onResume();startBackgroundThread();//为相机开启了一个后台线程,这个进程用于后台执行相关的工作// When the screen is turned off and turned back on, the SurfaceTexture is already// available, and "onSurfaceTextureAvailable" will not be called. In that case, we can open// a camera and start preview from here (otherwise, we wait until the surface is ready in// the SurfaceTextureListener).if (mTextureView.isAvailable()) {//mTextureView已经创建,SurfaceTexture已经有效,则直接openCamera,用于屏幕熄灭等情况,这时onSurfaceTextureAvailable不会回调。openCamera(mTextureView.getWidth(), mTextureView.getHeight());} else {//SurfaceTexture处于无效状态中,则通过SurfaceTextureListener确保surface准备好。mTextureView.setSurfaceTextureListener(mSurfaceTextureListener);//设置mTextureView回调}}@Overridepublic void onPause() {closeCamera();stopBackgroundThread();super.onPause();}private void requestCameraPermission() {if (shouldShowRequestPermissionRationale(Manifest.permission.CAMERA)) {new ConfirmationDialog().show(getChildFragmentManager(), FRAGMENT_DIALOG);} else {requestPermissions(new String[]{Manifest.permission.CAMERA}, REQUEST_CAMERA_PERMISSION);}}@Overridepublic void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,@NonNull int[] grantResults) {if (requestCode == REQUEST_CAMERA_PERMISSION) {if (grantResults.length != 1 || grantResults[0] != PackageManager.PERMISSION_GRANTED) {ErrorDialog.newInstance(getString(R.string.request_permission)).show(getChildFragmentManager(), FRAGMENT_DIALOG);}} else {super.onRequestPermissionsResult(requestCode, permissions, grantResults);}}/*** Sets up member variables related to camera.** @param width  The width of available size for camera preview 预览有效宽度* @param height The height of available size for camera preview 预览有效高度*/@SuppressWarnings("SuspiciousNameCombination")private void setUpCameraOutputs(int width, int height) {包括对相机设备的选择,ImageReader的初始化和参数、回调设置。设置显示的转化矩阵,即将预览的图片调整至显示图层的大小。Activity activity = getActivity();CameraManager manager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE);try {for (String cameraId : manager.getCameraIdList()) {//获取摄像头可用列表CameraCharacteristics characteristics= manager.getCameraCharacteristics(cameraId);获取相机的特性// We don't use a front facing camera in this sample.// 如果该摄像头是前置摄像头, 则看下一个摄像头(本应用不使用前置摄像头)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;}
/*min_duration:33331760, stall:0],
[w:3968, h:2976, format:YUV_420_888(35), min_duration:50000000, stall:0],
[w:2976, h:2976, format:YUV_420_888(35), min_duration:50000000, stall:0],
[w:3840, h:2160, format:YUV_420_888(35), min_duration:33331760, stall:0],[w:2448, h:2448, format:YUV_420_888(35), min_duration:50000000, stall:0],[w:2592, h:1952, format:YUV_420_888(35), min_duration:33331760, stall:0],[w:2048, h:1536, format:YUV_420_888(35), min_duration:33331760, stall:0],[w:1920, h:1080, format:YUV_420_888(35), min_duration:33331760, stall:0],[w:1440, h:1080, format:YUV_420_888(35), min_duration:33331760, stall:0],[w:1536, h:864, format:YUV_420_888(35), min_duration:33331760, stall:0],[w:1280, h:960, format:YUV_420_888(35), min_duration:33331760, stall:0],[w:1280, h:720, format:YUV_420_888(35), min_duration:33331760, stall:0],[w:960, h:720, format:YUV_420_888(35), min_duration:33331760, stall:0],[w:960, h:540, format:YUV_420_888(35), min_duration:33331760, stall:0],[w:720, h:720, format:YUV_420_888(35), */// For still image captures, we use the largest available size.对于静态图像捕捉,我们使用最大的可用尺寸Size largest = Collections.max(Arrays.asList(map.getOutputSizes(ImageFormat.JPEG)),new CompareSizesByArea());//   mImageReader = ImageReader.newInstance(largest.getWidth(), largest.getHeight(),//     ImageFormat.JPEG, /*maxImages*/2);//设置ImageReader接收的图片格式,以及允许接收的最大图片数目mImageReader = ImageReader.newInstance(width_T, height_T,ImageFormat.JPEG,2);/*   w:480 h:640       *//* w:1280 h:720 *//* w:1920 h:1080 *//* w:3968 h:2976 */mImageReader.setOnImageAvailableListener(mOnImageAvailableListener, mBackgroundHandler);//设置图片存储的监听,但在创建会话,调用capture后才能有数据// Find out if we need to swap dimension to get the preview size relative to sensor// coordinate.看看我们是否需要交换尺寸,以获得相对于传感器坐标的预览大小。int displayRotation = activity.getWindowManager().getDefaultDisplay().getRotation();//获取屏幕显示方向//noinspection ConstantConditionsmSensorOrientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);//获取sensor方向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();activity.getWindowManager().getDefaultDisplay().getSize(displaySize);//Android获取屏幕分辨率displaySizeint 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;}// Danger, W.R.! Attempting to use too large a preview size could  exceed the camera// bus' bandwidth limitation, resulting in gorgeous previews but the storage of// garbage capture data.// mPreviewSize = chooseOptimalSize(map.getOutputSizes(SurfaceTexture.class),//    rotatedPreviewWidth, rotatedPreviewHeight, maxPreviewWidth,//   maxPreviewHeight, largest);//获取最优的预览分辨率mPreviewSize = chooseOptimalSize(map.getOutputSizes(SurfaceTexture.class),rotatedPreviewWidth, rotatedPreviewHeight, width_T,height_T, largest);// mPreviewSize = new  Size(width_T,height_T);// We fit the aspect ratio of TextureView to the size of preview we picked.int orientation = getResources().getConfiguration().orientation;if (orientation == Configuration.ORIENTATION_LANDSCAPE) {// 如果方向是横向(landscape)mTextureView.setAspectRatio(mPreviewSize.getWidth(), mPreviewSize.getHeight());;//设置TextureView预览分辨率。} else {// 方向不是横向(即竖向)mTextureView.setAspectRatio(mPreviewSize.getHeight(), mPreviewSize.getWidth());}// Check if the flash is supported.检查是否支持flash。Boolean available = characteristics.get(CameraCharacteristics.FLASH_INFO_AVAILABLE);mFlashSupported = available == null ? false : available;if(flag_Fz==0)mCameraId = cameraId;//获取当前IDelsemCameraId = "1";return;}} catch (CameraAccessException e) {e.printStackTrace();} catch (NullPointerException e) {// Currently an NPE is thrown when the Camera2API is used but not supported on the// device this code runs.ErrorDialog.newInstance(getString(R.string.camera_error)).show(getChildFragmentManager(), FRAGMENT_DIALOG);}}//录像请求权限private boolean hasPermissionsGranted(String[] permissions) {for (String permission : permissions) {if (ActivityCompat.checkSelfPermission(getActivity(), permission)!= PackageManager.PERMISSION_GRANTED) {return false;}}return true;}private boolean shouldShowRequestPermissionRationale(String[] permissions) {for (String permission : permissions) {if (shouldShowRequestPermissionRationale(permission)) {return true;}}return false;}/*** Requests permissions needed for recording video.*/private void requestVideoPermissions() {if (shouldShowRequestPermissionRationale(VIDEO_PERMISSIONS)) {new Camera2VideoFragment.ConfirmationDialog().show(getChildFragmentManager(), FRAGMENT_DIALOG);} else {requestPermissions(VIDEO_PERMISSIONS, REQUEST_VIDEO_PERMISSIONS);}}private static Size chooseVideoSize(Size[] choices) {for (Size size : choices) {if (size.getWidth() == size.getHeight() * 4 / 3 && size.getWidth() <= 1080) {return size;}}Log.e(TAG, "Couldn't find any suitable video size");return choices[choices.length - 1];}private static Size chooseOptimalSize(Size[] choices, int width, int height, Size aspectRatio) {// Collect the supported resolutions that are at least as big as the preview SurfaceList<Size> bigEnough = new ArrayList<>();int w = aspectRatio.getWidth();int h = aspectRatio.getHeight();for (Size option : choices) {if (option.getHeight() == option.getWidth() * h / w &&option.getWidth() >= width && option.getHeight() >= height) {bigEnough.add(option);}}// Pick the smallest of those, assuming we found anyif (bigEnough.size() > 0) {return Collections.min(bigEnough, new Camera2VideoFragment.CompareSizesByArea());} else {Log.e(TAG, "Couldn't find any suitable preview size");return choices[0];}}
录像  end/*** Opens the camera specified by {@link Camera2BasicFragment#mCameraId}.*/private void openCamera(int width, int height) {if(camera_flag==0) {if (ContextCompat.checkSelfPermission(getActivity(), Manifest.permission.CAMERA)!= PackageManager.PERMISSION_GRANTED) {requestCameraPermission();//请求权限return;}}else {//录像请求权限if (!hasPermissionsGranted(VIDEO_PERMISSIONS)) {requestVideoPermissions();return;}}setUpCameraOutputs(width, height);configureTransform(width, height);//TextureView通过此方法设置预览方向Activity activity = getActivity();CameraManager manager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE);try {if (!mCameraOpenCloseLock.tryAcquire(2500, TimeUnit.MILLISECONDS)) {throw new RuntimeException("Time out waiting to lock camera opening.");}manager.openCamera(mCameraId, mStateCallback, mBackgroundHandler);} catch (CameraAccessException e) {e.printStackTrace();} catch (InterruptedException e) {throw new RuntimeException("Interrupted while trying to lock camera opening.", e);}}/*** Closes the current {@link CameraDevice}.*/private void closeCamera() {try {mCameraOpenCloseLock.acquire();if (null != mCaptureSession) {mCaptureSession.close();mCaptureSession = null;}if (null != mCameraDevice) {mCameraDevice.close();mCameraDevice = null;}if (null != mImageReader) {mImageReader.close();mImageReader = null;}} catch (InterruptedException e) {throw new RuntimeException("Interrupted while trying to lock camera closing.", e);} finally {mCameraOpenCloseLock.release();}}/*** Starts a background thread and its {@link Handler}.*/private void startBackgroundThread() {mBackgroundThread = new HandlerThread("bruceCameraBackground");mBackgroundThread.start();mBackgroundHandler = new Handler(mBackgroundThread.getLooper());}/*** Stops the background thread and its {@link Handler}.*/private void stopBackgroundThread() {mBackgroundThread.quitSafely();try {mBackgroundThread.join();mBackgroundThread = null;mBackgroundHandler = null;} catch (InterruptedException e) {e.printStackTrace();}}/*** Creates a new {@link CameraCaptureSession} for camera preview.*/private void createCameraPreviewSession() {try {SurfaceTexture texture = mTextureView.getSurfaceTexture();//通过mTextureView获取SurfaceTexture。assert texture != null;// We configure the size of default buffer to be the size of camera preview we want.我们将默认缓冲区的大小配置为我们想要的相机预览的大小texture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());//设置SurfaceTexture大小// texture.setDefaultBufferSize(1000, 1280);// This is the output Surface we need to start preview.Surface surface = new Surface(texture);//通过SurfaceTexture创建Surface来预览。// We set up a CaptureRequest.Builder with the output Surface.mPreviewRequestBuilder= mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);//创建TEMPLATE_PREVIEW预览模板CaptureRequest.BuildermPreviewRequestBuilder.addTarget(surface);//CaptureRequest.Builder中添加Surface,即mTextureView获取创建的Surface// Here, we create a CameraCaptureSession for camera preview.mCameraDevice.createCaptureSession(Arrays.asList(surface, mImageReader.getSurface()),new CameraCaptureSession.StateCallback() {//创建会话@Overridepublic void onConfigured(@NonNull CameraCaptureSession cameraCaptureSession) {//创建会话成功// The camera is already closedif (null == mCameraDevice) {return;}// When the session is ready, we start displaying the preview.mCaptureSession = cameraCaptureSession;//从onConfigured参数获取mCaptureSessiontry {// Auto focus should be continuous for camera preview.mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE,CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);//设置快速连续对焦,用于快门零延迟静像拍摄。mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE,CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);//设置快速连续对焦,用于快门零延迟静像拍摄。// Flash is automatically enabled when necessary.setAutoFlash(mPreviewRequestBuilder);// Finally, we start displaying the camera preview.mPreviewRequest = mPreviewRequestBuilder.build();//转换为CaptureRequestmCaptureSession.setRepeatingRequest(mPreviewRequest,mCaptureCallback, mBackgroundHandler);//设置预览,setRepeatingRequest不断的重复mPreviewRequest请求捕捉画面,常用于预览或者连拍场景。} catch (CameraAccessException e) {e.printStackTrace();}}@Overridepublic void onConfigureFailed(//创建会话失败@NonNull CameraCaptureSession cameraCaptureSession) {showToast("Failed");}}, null);} catch (CameraAccessException e) {e.printStackTrace();}}/*** Configures the necessary {@link Matrix} transformation to `mTextureView`.* This method should be called after the camera preview size is determined in* setUpCameraOutputs and also the size of `mTextureView` is fixed.* 屏幕方向发生改变时调用转换数据方法,* @param viewWidth  The width of `mTextureView`* @param viewHeight The height of `mTextureView`TextureView通过此方法设置预览方向*/private void configureTransform(int viewWidth, int viewHeight) {//配置transformation,主要是矩阵旋转相关Activity activity = getActivity();if (null == mTextureView || null == mPreviewSize || null == activity) {return;}int rotation = activity.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);//设置mTextureView的transformation}/*** Initiate a still image capture.*/private void takePicture() {//拍照lockFocus();}/*** Lock the focus as the first step for a still image capture.*/private void lockFocus() {//拍照过程中锁住焦点if(sgd_flag==1){//开启闪光灯mPreviewRequestBuilder.set(CaptureRequest.FLASH_MODE,CaptureRequest.FLASH_MODE_TORCH);}else {mPreviewRequestBuilder.set(CaptureRequest.FLASH_MODE,CaptureRequest.FLASH_MODE_OFF);}try {// This is how to tell the camera to lock focus.通知camera锁住对焦mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,//触发 AF 扫描CameraMetadata.CONTROL_AF_TRIGGER_START);//触发 AF 扫描的启动操作。扫描效果取决于模式和状态。// Tell #mCaptureCallback to wait for the lock.通知mCaptureCallback等待锁定mState = STATE_WAITING_LOCK;//设置等待自动对焦的焦点被锁状态,通知mCaptureCallback等待锁定mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback,mBackgroundHandler);//通知camera锁住对焦和状态通过mPreviewRequestBuilder.build()只发送一次请求,而不是mPreviewRequest。是同一个回调mCaptureCallback,发送一次请求只是等待自动对焦的焦点被锁,切换为STATE_WAITING_LOCK再真正进行拍照} catch (CameraAccessException e) {e.printStackTrace();}}/*** Run the precapture sequence for capturing a still image. This method should be called when* we get a response in {@link #mCaptureCallback} from {@link #lockFocus()}.运行捕获静止图像的预捕获序列。*/private void runPrecaptureSequence() {try {// This is how to tell the camera to trigger.mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER,//用于在拍摄高品质图像之前启动测光序列的控件。CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START);//启动预拍序列。HAL 应使用后续请求进行衡量并达到理想的曝光/白平衡,以便接下来拍摄高分辨率的照片。// Tell #mCaptureCallback to wait for the precapture sequence to be set.mState = STATE_WAITING_PRECAPTURE;//设置等待曝光为预捕获状态mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback,mBackgroundHandler);} catch (CameraAccessException e) {e.printStackTrace();}}/*** Capture a still picture. This method should be called when we get a response in* {@link #mCaptureCallback} from both {@link #lockFocus()}.*/private void captureStillPicture() {//进行拍照try {final Activity activity = getActivity();if (null == activity || null == mCameraDevice) {return;}// This is the CaptureRequest.Builder that we use to take a picture.final CaptureRequest.Builder captureBuilder =mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);//设置TEMPLATE_STILL_CAPTURE拍照模板CaptureRequest.BuildercaptureBuilder.addTarget(mImageReader.getSurface());//添加拍照mImageReader为Surface// Use the same AE and AF modes as the preview.//设置AF和AEcaptureBuilder.set(CaptureRequest.CONTROL_AF_MODE,CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);//设置快速连续对焦,用于快门零延迟静像拍摄。setAutoFlash(captureBuilder);// Orientationint rotation = activity.getWindowManager().getDefaultDisplay().getRotation();/*  captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, getOrientation(rotation));//设置图片方向*/captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, getOrientation(rotation));//设置图片方向CameraCaptureSession.CaptureCallback CaptureCallback= new CameraCaptureSession.CaptureCallback() {//拍照流程执行完成回调@Overridepublic void onCaptureCompleted(@NonNull CameraCaptureSession session,@NonNull CaptureRequest request,@NonNull TotalCaptureResult result) {showToast("图片已经保存到/sdcard/DCIM/Camera/");//提示拍照图片已经保存Log.d(TAG, "/sdcard/DCIM/Camera/");//关闭闪光灯// mPreviewRequestBuilder.set(CaptureRequest.FLASH_MODE,//  CaptureRequest.FLASH_MODE_OFF);unlockFocus();//释放焦点锁,重新开启预览。}};mCaptureSession.stopRepeating();//停止预览,停止任何一个正常进行的重复请求。mCaptureSession.abortCaptures();//中断Capture,尽可能快的取消当前队列中或正在处理中的所有捕捉请求。mCaptureSession.capture(captureBuilder.build(), CaptureCallback, null);//重新Capture进行拍照,这时mImageReader的回调会执行并保存图片} catch (CameraAccessException e) {e.printStackTrace();}}/*** Retrieves the JPEG orientation from the specified screen rotation.** @param rotation The screen rotation.* @return The JPEG orientation (one of 0, 90, 270, and 360)*/private int getOrientation(int rotation) {// Sensor orientation is 90 for most devices, or 270 for some devices (eg. Nexus 5X)// We have to take that into account and rotate JPEG properly.// For devices with orientation of 90, we simply return our mapping from ORIENTATIONS.// For devices with orientation of 270, we need to rotate the JPEG 180 degrees./* return (ORIENTATIONS.get(rotation) + mSensorOrientation + 270) % 360;*/return (ORIENTATIONS.get(rotation) + mSensorOrientation + 270)%360 ;}/*** Unlock the focus. This method should be called when still image capture sequence is* finished.*/private void unlockFocus() {try {// Reset the auto-focus triggermPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,CameraMetadata.CONTROL_AF_TRIGGER_CANCEL);//取消当前 AF 扫描(如有),并将算法重置为默认值。setAutoFlash(mPreviewRequestBuilder);mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback,mBackgroundHandler);//通过mPreviewRequestBuilder.build()只发送一次请求,而不是mPreviewRequest。// After this, the camera will go back to the normal state of preview.mState = STATE_PREVIEW;//设置预览状态,通知mCaptureCallback回到预览状态mCaptureSession.setRepeatingRequest(mPreviewRequest, mCaptureCallback,mBackgroundHandler);//重新进入预览,使用mPreviewRequest} catch (CameraAccessException e) {e.printStackTrace();}}@SuppressLint("ResourceType")@Overridepublic void onClick(View view) {switch (view.getId()) {//点击拍照case R.id.picture: {if(yc_flag==1){final short mDelayTime=10*1000;final short TIME_INTERVAL=1000;new CountDownTimer(mDelayTime,TIME_INTERVAL){@Overridepublic void onTick(long millisUntilFinished){mBntTime.setVisibility(View.VISIBLE);mBntTime.setText(""+(millisUntilFinished/TIME_INTERVAL)+"s");}@Overridepublic void onFinish() {mBntTime.setVisibility(View.GONE);takePicture();//拍照}}.start();}else {takePicture();//拍照}break;}case R.id.btn_yc:{if(yc_flag==0){Toast.makeText(getActivity(),"开启定时模式",Toast.LENGTH_SHORT).show();yc_flag = 1;//开启延迟模式}else {yc_flag = 0;//关闭延迟模式}break;}case R.id.info: {Activity activity = getActivity();if (null != activity) {new AlertDialog.Builder(activity).setMessage(R.string.intro_message).setPositiveButton(android.R.string.ok, null).show();}break;}//前后翻转摄像头case R.id.picture2:{//关闭相机closeCamera();if(flag_Fz==0){flag_Fz=1;}elseflag_Fz=0;//打开相机onResume();Toast.makeText(getActivity(),"翻转摄像头",Toast.LENGTH_SHORT).show();Log.d("翻转","mCameraId="+mCameraId);break;}//水印的添加和关闭case R.id.picture3:{closeCamera();if(text_flag==0){/* text1.setText("水印");*/text1.setVisibility(View.VISIBLE);//text1显示状态text_flag=1;}else {text1.setVisibility(View.GONE);//text1隐藏状态,且不占空间text_flag=0;}onResume();if(text_flag==1){Toast.makeText(getActivity(),"开启水印", Toast.LENGTH_SHORT).show();}else {Toast.makeText(getActivity(),"关闭水印", Toast.LENGTH_SHORT).show();}break;}//录像case R.id.btn_video:{closeCamera();if(flag_Lx==0){mButtonLx.setText("拍照");camera_flag =1 ;flag_Lx=1;mButtonVideo.setVisibility(View.VISIBLE);mButtonVideo.setText("录制");mchronometer.setVisibility(View.VISIBLE);text1.setVisibility(View.GONE);mButtonSy.setVisibility(View.GONE);mButtonFz.setVisibility(View.GONE);mButtonFbl.setVisibility(View.GONE);mButtonPz.setVisibility(View.GONE);mButtonMdz.setVisibility(View.GONE);mButtonYc.setVisibility(View.GONE);}else {mButtonLx.setText("录像");flag_Lx=0;camera_flag =0;mButtonVideo.setVisibility(View.GONE);mchronometer.setVisibility(View.GONE);text1.setVisibility(View.GONE);mButtonSy.setVisibility(View.VISIBLE);mButtonFz.setVisibility(View.VISIBLE);mButtonFbl.setVisibility(View.VISIBLE);mButtonPz.setVisibility(View.VISIBLE);mButtonMdz.setVisibility(View.VISIBLE);mButtonYc.setVisibility(View.VISIBLE);}/* getActivity().getSupportFragmentManager().beginTransaction().replace(R.id.container, new Camera2VideoFragment(), null).addToBackStack(null).commit();*/onResume();break;}//慢动作case R.id.btn_video_mdz:{{closeCamera();if(flag_Lx==0){mButtonLx.setText("拍照");video_flag1=1;camera_flag =1 ;flag_Lx=1;mButtonVideo.setVisibility(View.VISIBLE);mButtonVideo.setText("录制");mButtonMdz.setVisibility(View.GONE);text1.setVisibility(View.GONE);mButtonSy.setVisibility(View.GONE);mButtonFz.setVisibility(View.GONE);mButtonFbl.setVisibility(View.GONE);mButtonPz.setVisibility(View.GONE);mButtonYc.setVisibility(View.GONE);}else {video_flag1=0;mButtonLx.setText("录像");flag_Lx=0;camera_flag =0;mButtonVideo.setVisibility(View.GONE);text1.setVisibility(View.GONE);mButtonMdz.setVisibility(View.VISIBLE);mButtonSy.setVisibility(View.VISIBLE);mButtonFz.setVisibility(View.VISIBLE);mButtonFbl.setVisibility(View.VISIBLE);mButtonPz.setVisibility(View.VISIBLE);mButtonYc.setVisibility(View.VISIBLE);}/* getActivity().getSupportFragmentManager().beginTransaction().replace(R.id.container, new Camera2VideoFragment(), null).addToBackStack(null).commit();*/onResume();Toast.makeText(getActivity(),"慢动作模式",Toast.LENGTH_SHORT).show();break;}}//开始录像和停止case R.id.video1:{if (mIsRecordingVideo) {stopRecordingVideo();mchronometer.setBase(SystemClock.elapsedRealtime());// 复位} else {startRecordingVideo();mchronometer.setBase(SystemClock.elapsedRealtime());// 复位mchronometer.start();//开始时长显示}break;}//分辨率case R.id.btn_check:{PopupMenu popup = new PopupMenu(getActivity(),view);popup.getMenuInflater().inflate(R.layout.menu_btn, popup.getMenu());popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {@Overridepublic boolean onMenuItemClick(MenuItem item) {switch (item.getItemId()){case R.id.check11:Toast.makeText(getActivity(),"分辨率 w:480 h:640",Toast.LENGTH_SHORT).show();closeCamera();width_T=480;height_T=640;onResume();break;case R.id.check22:Toast.makeText(getActivity(),"分辨率 w:1280 h:720",Toast.LENGTH_SHORT).show();closeCamera();width_T=1280;height_T=720;onResume();break;case R.id.check33:Toast.makeText(getActivity(),"分辨率 w:3968 h:2976",Toast.LENGTH_SHORT).show();closeCamera();width_T =3968;height_T=2976;onResume();break;}return true;}});popup.show();/*  getActivity().getSupportFragmentManager().beginTransaction().replace(R.id.container, new Camera2BasicFragment2(), null).addToBackStack(null).commit();*/break;}case R.id.image_thumbnail:{//进入本机相册Intent intent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);startActivity(intent);}break;//参考线case R.id.btn_line:{Message msg1 = new Message();msg1.what = 2;handler.sendMessage(msg1);}break;//闪光灯case R.id.btn_sgd:{Message msg2 = new Message();msg2.what = 3;handler.sendMessage(msg2);}break;}}private void setAutoFlash(CaptureRequest.Builder requestBuilder) {if (mFlashSupported) {requestBuilder.set(CaptureRequest.CONTROL_AE_MODE,CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);//标准自动曝光,闪光灯听从 HAL 指令开启,以进行预拍摄和静像拍摄。}}private byte[] getJpegData(Image image) {ByteBuffer buffer = image.getPlanes()[0].getBuffer();byte[] bytes = new byte[buffer.remaining()];buffer.get(bytes);return bytes;}@Overridepublic void onChronometerTick(Chronometer chronometer) {}/*** Saves a JPEG {@link Image} into the specified {@link File}.*/private static class ImageSaver implements Runnable {//保存图片线程 /*** The JPEG image*/private final Image mImage;/*** The file we save the image into.*/private final File mFile;private int mflag;private  int text_flag;ImageSaver(Image image, File file,int flag,int text_flag) {mImage = image;mFile = file;this.mflag = flag;this.text_flag =text_flag;}@Overridepublic void run() {Thread.currentThread().setName("bruce线程5");ByteBuffer buffer = mImage.getPlanes()[0].getBuffer();byte[] bytes = new byte[buffer.remaining()];buffer.get(bytes);Canvas canvas = new Canvas();FileOutputStream output = null;String str=null;Date date=null;SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss");//获取当前时间,进一步转化为字符串date =new Date();str=format.format(date);String fileName = "/sdcard/DCIM/Camera/IMG_"+str+"pci.jpg";try {output = new FileOutputStream(fileName);//启用前置摄像头时的保存if(mflag==1){Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);Matrix m = new Matrix();m.postScale(1, -1); // 镜像水平翻转bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), m, true);Log.d(TAG, "run: ------------------flag"+mflag);bitmap.compress(Bitmap.CompressFormat.JPEG, 100, output);}//后置摄像头加水印if(text_flag==1) {Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);// 加水印Bitmap createBitmap = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.RGB_565);canvas = new Canvas(createBitmap);canvas.drawBitmap(bitmap, 0, 0, null);Paint paint = new Paint();paint.setStyle(Paint.Style.FILL);paint.setColor(Color.parseColor("#70E1DFE0"));paint.setDither(true);paint.setAntiAlias(true);paint.setTextSize(300);canvas.drawText("水印测试", 20, 2420, paint);createBitmap.compress(Bitmap.CompressFormat.JPEG, 100, output);Log.d(TAG, "run: ------------------flag" + mflag);}//将数据存放到缩略图要使用的bitMap里Bitmap bitmap1 = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);Bitmap bitmap2= ThumbnailUtils.extractThumbnail(bitmap1, 200, 200);bitMap = bitmap2;output.write(bytes);//保存图片到文件} catch (IOException e) {e.printStackTrace();} finally {mImage.close();if (null != output) {try {output.close();} catch (IOException e) {e.printStackTrace();}}}//处理完成后给handler发送消息 进行缩略图显示Message msg = new Message();msg.what = 1;handler.sendMessage(msg);}}/*** Compares two {@code Size}s based on their areas.*/static class CompareSizesByArea implements Comparator<Size> {@Overridepublic int compare(Size lhs, Size rhs) {// We cast here to ensure the multiplications won't overflowreturn Long.signum((long) lhs.getWidth() * lhs.getHeight() -(long) rhs.getWidth() * rhs.getHeight());}}/*** Shows an error message dialog.*/public static class ErrorDialog extends DialogFragment {private static final String ARG_MESSAGE = "message";public static ErrorDialog newInstance(String message) {ErrorDialog dialog = new ErrorDialog();Bundle args = new Bundle();args.putString(ARG_MESSAGE, message);dialog.setArguments(args);return dialog;}@NonNull@Overridepublic Dialog onCreateDialog(Bundle savedInstanceState) {final Activity activity = getActivity();return new AlertDialog.Builder(activity).setMessage(getArguments().getString(ARG_MESSAGE)).setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialogInterface, int i) {activity.finish();}}).create();}}/*** Shows OK/Cancel confirmation dialog about camera permission.*/public static class ConfirmationDialog extends DialogFragment {@NonNull@Overridepublic Dialog onCreateDialog(Bundle savedInstanceState) {final Fragment parent = getParentFragment();return new AlertDialog.Builder(getActivity()).setMessage(R.string.request_permission).setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {parent.requestPermissions(new String[]{Manifest.permission.CAMERA},REQUEST_CAMERA_PERMISSION);}}).setNegativeButton(android.R.string.cancel,new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {Activity activity = parent.getActivity();if (activity != null) {activity.finish();}}}).create();}}
///录像private MediaRecorder mMediaRecorder = new MediaRecorder();private String mNextVideoAbsolutePath;private Size mVideoSize;private CaptureRequest.Builder mPreviewBuilder;private CameraCaptureSession mPreviewSession;private void updatePreview(){if (null == mCameraDevice) {return;}try {setUpCaptureRequestBuilder(mPreviewBuilder);HandlerThread thread = new HandlerThread("CameraPreview");thread.start();mPreviewSession.setRepeatingRequest(mPreviewBuilder.build(), null, mBackgroundHandler);} catch (CameraAccessException e) {e.printStackTrace();}}private void setUpCaptureRequestBuilder(CaptureRequest.Builder builder) {builder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);}private void setUpMediaRecorder() throws IOException {final Activity activity = getActivity();if (null == activity) {return;}mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);if (mNextVideoAbsolutePath == null || mNextVideoAbsolutePath.isEmpty()) {mNextVideoAbsolutePath = getVideoFilePath(getActivity());}mMediaRecorder.setOutputFile(mNextVideoAbsolutePath);mMediaRecorder.setVideoEncodingBitRate(10000000);if(video_flag1==1)//慢动作{mMediaRecorder.setCaptureRate(120);}mMediaRecorder.setVideoFrameRate(30);mMediaRecorder.setVideoSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();switch (mSensorOrientation) {case SENSOR_ORIENTATION_DEFAULT_DEGREES:mMediaRecorder.setOrientationHint(DEFAULT_ORIENTATIONS.get(rotation));break;case SENSOR_ORIENTATION_INVERSE_DEGREES:mMediaRecorder.setOrientationHint(INVERSE_ORIENTATIONS.get(rotation));break;}mMediaRecorder.prepare();}private String getVideoFilePath(Context context) {final File dir = context.getExternalFilesDir(null);return (dir == null ? "" : (dir.getAbsolutePath() + "/"))+ System.currentTimeMillis() + ".mp4";}private 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<Surface> surfaces = new ArrayList<>();// Set up Surface for the camera previewSurface previewSurface = new Surface(texture);surfaces.add(previewSurface);mPreviewBuilder.addTarget(previewSurface);// Set up Surface for the MediaRecorderSurface recorderSurface = mMediaRecorder.getSurface();surfaces.add(recorderSurface);mPreviewBuilder.addTarget(recorderSurface);// Start a capture session// Once the session starts, we can update the UI and start recordingmCameraDevice.createCaptureSession(surfaces, new CameraCaptureSession.StateCallback() {@Overridepublic void onConfigured(@NonNull CameraCaptureSession cameraCaptureSession) {mPreviewSession = cameraCaptureSession;updatePreview();getActivity().runOnUiThread(new Runnable() {@Overridepublic void run() {// UImButtonVideo.setText(R.string.stop);mIsRecordingVideo = true;// Start recordingmMediaRecorder.start();}});}@Overridepublic void onConfigureFailed(@NonNull CameraCaptureSession cameraCaptureSession) {Activity activity = getActivity();if (null != activity) {Toast.makeText(activity, "Failed", Toast.LENGTH_SHORT).show();}}}, mBackgroundHandler);} catch (CameraAccessException | IOException e) {e.printStackTrace();}}private void closePreviewSession() {if (mPreviewSession != null) {mPreviewSession.close();mPreviewSession = null;}}private void stopRecordingVideo() {// UImIsRecordingVideo = false;mButtonVideo.setText(R.string.record);// Stop recordingmchronometer.stop();//停止时长显示mMediaRecorder.stop();mMediaRecorder.reset();Activity activity = getActivity();if (null != activity) {Toast.makeText(activity, "Video saved: " + mNextVideoAbsolutePath,Toast.LENGTH_SHORT).show();Log.d(TAG, "Video saved: " + mNextVideoAbsolutePath);}mNextVideoAbsolutePath = null;createCameraPreviewSession();}}

相机图片
ImageXJ.java

package com.example.android.camera2basic;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.os.Environment;
import android.provider.MediaStore;
import android.util.Log;import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class ImageXJ {private  final String TAG = "ImageUtils";private  Context sContext = MyApp.getInstance();private  final String GALLERY_PATH = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM) + File.separator + "Camera";private  final String[] STORE_IMAGES = {MediaStore.Images.Thumbnails._ID,};private  final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyyMMdd_HHmmss");public  Bitmap rotateBitmap(Bitmap source, int degree, boolean flipHorizontal, boolean recycle) {if (degree == 0 && !flipHorizontal) {return source;}Matrix matrix = new Matrix();matrix.postRotate(degree);if (flipHorizontal) {matrix.postScale(-1, 1);}Log.d(TAG, "source width: " + source.getWidth() + ", height: " + source.getHeight());Log.d(TAG, "rotateBitmap: degree: " + degree);Bitmap rotateBitmap = Bitmap.createBitmap(source, 0, 0, source.getWidth(), source.getHeight(), matrix, false);Log.d(TAG, "rotate width: " + rotateBitmap.getWidth() + ", height: " + rotateBitmap.getHeight());if (recycle) {source.recycle();}return rotateBitmap;}public  void saveImage(byte[] jpeg) {String fileName = DATE_FORMAT.format(new Date(System.currentTimeMillis())) + ".jpg";File outFile = new File(GALLERY_PATH, fileName);Log.d(TAG, "saveImage. filepath: " + outFile.getAbsolutePath());FileOutputStream os = null;try {os = new FileOutputStream(outFile);os.write(jpeg);os.flush();os.close();insertToDB(outFile.getAbsolutePath());} catch (IOException e) {e.printStackTrace();} finally {if (os != null) {try {os.close();} catch (IOException e) {e.printStackTrace();}}}}public  void saveBitmap(Bitmap bitmap) {String fileName = DATE_FORMAT.format(new Date(System.currentTimeMillis())) + ".jpg";File outFile = new File(GALLERY_PATH, fileName);Log.d(TAG, "saveImage. filepath: " + outFile.getAbsolutePath());FileOutputStream os = null;try {os = new FileOutputStream(outFile);boolean success = bitmap.compress(Bitmap.CompressFormat.JPEG, 100, os);Log.d(TAG, "saveBitmap: " + success);if (success) {insertToDB(outFile.getAbsolutePath());}} catch (IOException e) {e.printStackTrace();} finally {if (os != null) {try {os.close();} catch (IOException e) {e.printStackTrace();}}}}public  void insertToDB(String picturePath) {ContentValues values = new ContentValues();ContentResolver resolver = sContext.getContentResolver();values.put(MediaStore.Images.ImageColumns.DATA, picturePath);values.put(MediaStore.Images.ImageColumns.TITLE, picturePath.substring(picturePath.lastIndexOf("/") + 1));values.put(MediaStore.Images.ImageColumns.DATE_TAKEN, System.currentTimeMillis());values.put(MediaStore.Images.ImageColumns.MIME_TYPE, "image/jpeg");resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);}public  Bitmap getLatestThumbBitmap() {Bitmap bitmap = null;// 按照时间顺序降序查询Cursor cursor = MediaStore.Images.Media.query(sContext.getContentResolver(), MediaStore.Images.Media.EXTERNAL_CONTENT_URI, STORE_IMAGES, null, null, MediaStore.Files.FileColumns.DATE_MODIFIED + " DESC");boolean first = cursor.moveToFirst();if (first) {long id = cursor.getLong(0);bitmap = MediaStore.Images.Thumbnails.getThumbnail(sContext.getContentResolver(), id, MediaStore.Images.Thumbnails.MICRO_KIND, null);Log.d(TAG, "bitmap width: " + bitmap.getWidth());Log.d(TAG, "bitmap height: " + bitmap.getHeight());}cursor.close();return bitmap;}
}

AutoFitTextureView.java

/** Copyright 2014 The Android Open Source Project** Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at**       http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/package com.example.android.camera2basic;import android.content.Context;
import android.util.AttributeSet;
import android.view.TextureView;/*** A {@link TextureView} that can be adjusted to a specified aspect ratio.*/
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);}/*** Sets the aspect ratio for this view. The size of the view will be measured based on the ratio* calculated from the parameters. Note that the actual sizes of parameters don't matter, that* is, calling setAspectRatio(2, 3) and setAspectRatio(4, 6) make the same result.** @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();}@Overrideprotected 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);}}}}

相机demo的java部分相关推荐

  1. Android 自定义相机Demo 入门学习

    Android 自定义相机Demo 本文是参考网上一些自定义相机示例,再结合自己对相机的功能需求写的,基本上包含了很多基本功能,比如相机对焦.闪光灯,以及在手机预览界面上绘制自己想要绘制的图案. 话不 ...

  2. 一个demo学会java

    全栈工程师开发手册 (作者:栾鹏) 快捷链接: java开发大全 这篇demo较长,包含了java基本的内容,若不是出于校验自己java基础能力的朋友,建议按照上面的链接分章节学习.本demo包含了j ...

  3. 阿里大于 DEMO(java)

    SDK下载地址(需要先登录阿里大于):https://www.alidayu.com/center/application/sdk 阿里大于文档中心(接入.返回码等文档):https://doc.al ...

  4. 短信平台API接口demo示例-JAVA/Message/Send

    DEMO:Message/Send 原文链接 支持JDK版本:1.5以上 依赖的jar包:httpclient-4.5.3.jar.httpcore-4.4.14.jar.commons-loggin ...

  5. 短信平台API接口demo示例-JAVA/Message/MultiXSend

    DEMO:Message/MultiXSend 原文链接 支持JDK版本:1.5以上 依赖的jar包:httpclient-4.5.3.jar.httpcore-4.4.14.jar.commons- ...

  6. Android使用相机demo

    private void saveFullImage(String str) {Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); ...

  7. Android 自定义相机Demo源码

    本文转载自: https://www.cnblogs.com/linjzong/p/4201266.html 作者:linjzong 转载请注明该声明. Github源码:https://github ...

  8. JFormDesigner教程(02)demo演示 java swing插件

    目录 0 前言 1 demo演示 0 前言 在上一篇博客中,讲了如何下载JFormDesigner: https://gitee.com/YFwinston/java-swing/tree/main ...

  9. Camera2 Android相机Demo

    基于Camera2 API V1.0 主要功能 前置.后置摄像头一件切换 保存图片 闪光灯的控制 想学习的可以看看源码,挺简单的. 源码地址:github地址 本demo是基于这篇博客改的:Andro ...

最新文章

  1. 图灵奖得主Joseph Sifakis:物联网自主系统设计的边界与风险(附视频)
  2. 二进制与加减乘除的物理层实现
  3. 南京林业大学计算机专升本,2018江苏专转本学校之:南京林业大学
  4. 如何获取 sql server 最新补丁
  5. 你能体会那种写 Python 时不用 import 的幸福吗?
  6. 利用Bing翻译API简单的实现一个翻译工具
  7. leetcode刷题 15.三数之和
  8. [蓝桥杯][算法提高VIP]聪明的美食家-dp
  9. Python 开发者 2017 应该关注的 7 个类库
  10. Android modem 开发(17)---VoLTE Call
  11. android ijkplayer c层分析-prepare过程与读取线程(续1-解码粗略分析)
  12. 习题4-8 高空坠球(20 分)
  13. Pandas学习——空值填充
  14. android 4.4.2截屏方法,Android截屏截图的几种方法总结
  15. 关于在窗体之间传值的问题 C# winform
  16. VC6.0快捷键一览表
  17. Qt for WinRT
  18. STM32f103微妙延迟函数
  19. c语言建立线性表输入,c语言 建立线性表 链式
  20. Unity 翻书效果

热门文章

  1. iOS 14的UIMenu和ContextMenu中的新增功能
  2. Java解惑系列(三): 让人疑惑的0xff
  3. acer电脑新装系统指南
  4. json学习(pythonj)
  5. 二〇一七互联网八大猜想
  6. 单引号和双引号的区别
  7. OA的下一站在哪?蓝凌给出了答案——生态OA
  8. 【新书推荐】【2019.06】我们为什么会说脏话?(了解爆粗口的神奇趣味科学,看说脏话如何在情感和身体上影响我们。)...
  9. Java DB loadBalance设计
  10. 人力资源管理计划—RACI表的建立步骤