1. Overview
Recently, I am working on some projects about face recognition, and I need to use the preview function of Android cameras. After checking the relevant information online, I found that in Android 5.0 and later versions, the original Camera API has been replaced by the Camera2 API.
The new Camera2 has been transformed on the basis of Camera, greatly improving the photography function of the Android system. It implements the working process during camera preview through the following classes and methods:
•CameraManager: Camera Manager, mainly used to detect system cameras, turn on system cameras, etc.;
•CameraDevice: used to describe the system camera, which can be used to turn off the camera, create camera conversations, send photo requests, etc.;
•CameraCharacteristics: used to describe various features supported by the camera;
•CameraCaptureSession: When the program needs to preview and take photos, it needs to be implemented first through CameraCaptureSession. The session is previewed by calling the method setRepeatingRequest();
•CameraRequest: represents a capture request, used to describe various parameter settings for capturing pictures;
•: Responsible for generating the CameraRequest object.
2. Camera preview
The following is a source code to explain how to use Camera2 to implement the preview function of the camera.
2.1 Camera permission settings
<uses-permission android:name="" />
2.2 App Layout
•activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:andro xmlns:tools="/tools" android: android:layout_width="match_parent" android:layout_height="match_parent" android:background="#000" tools:context=".MainActivity"> </FrameLayout> •fragment_camera.xml <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:andro xmlns:tools="/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".CameraFragment"> <. android: android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerVertical="true" android:layout_centerHorizontal="true" /> </RelativeLayout>
2.3 Camera Custom View
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); } 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) { (widthMeasureSpec, heightMeasureSpec); int width = (widthMeasureSpec); int height = (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); } } } }
2.4 Dynamically apply for camera permissions
public class MainActivity extends AppCompatActivity { private static final int REQUEST_PERMISSION = 1; @Override protected void onCreate(Bundle savedInstanceState) { (savedInstanceState); setContentView(.activity_main); if (hasPermission()) { if (null == savedInstanceState) { setFragment(); } } else { requestPermission(); } } @Override public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) { if (requestCode == REQUEST_PERMISSION) { if ( == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { setFragment(); } else { requestPermission(); } } else { (requestCode, permissions, grantResults); } } // Permission judgment. When the system version is greater than 23, it is necessary to determine whether to obtain permissions. private boolean hasPermission() { if (.SDK_INT >= Build.VERSION_CODES.M) { return checkSelfPermission() == PackageManager.PERMISSION_GRANTED; } else { return true; } } // Request camera permissions private void requestPermission() { if (.SDK_INT >= Build.VERSION_CODES.M) { if (shouldShowRequestPermissionRationale()) { (, "Camera permission are required for this demo", Toast.LENGTH_LONG).show(); } requestPermissions(new String[]{}, REQUEST_PERMISSION); } } // Start the camera Fragment private void setFragment() { getSupportFragmentManager() .beginTransaction() .replace(, ()) .commitNowAllowingStateLoss(); } }
2.5 Turn on camera preview
First, in onResume(), we need to enable a HandlerThread, and then use the thread's Looper object to build a Handler for camera callbacks.
@Override public void 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 (()) { openCamera((), ()); } else { (mSurfaceTextureListener); } } private void startBackgroundThread() { mBackgroundThread = new HandlerThread("CameraBackground"); (); mBackgroundHandler = new Handler(()); }
At the same time, there is a corresponding HandlerThread closing method in onPause().
When the screen is turned off and re-opens, SurfaceTexture is ready, and the onSurfaceTextureAvailable callback will not be triggered. Therefore, we judge that if mTextureView is available, turn on the camera directly, otherwise wait for the SurfaceTexture callback to be ready before turning on the camera.
private void openCamera(int width, int height) { if ((getActivity(), ) != PackageManager.PERMISSION_GRANTED) { return; } setUpCameraOutputs(width, height); configureTransform(width, height); Activity activity = getActivity(); CameraManager manager = (CameraManager) (Context.CAMERA_SERVICE); try { if (!(2500, )) { throw new RuntimeException("Time out waiting to lock camera opening."); } (mCameraId, mStateCallback, mBackgroundHandler); } catch (CameraAccessException e) { (); } catch (InterruptedException e) { throw new RuntimeException("Interrupted while trying to lock camera opening.", e); } }
When turning on the camera, we first determine whether we have camera permissions, and then call the setUpCameraOutputs function to set the camera parameters (including specifying the camera, camera preview direction, and preview size settings, etc.). Next, call the configureTransform function to adjust the size and direction of the preview picture, and finally obtain the CameraManager object to turn on the camera. Because the camera may be accessed by other processes at the same time, it is necessary to add a lock when turning on the camera.
private final mStateCallback = new () { @Override public void onOpened(@NonNull CameraDevice cameraDevice) { (); mCameraDevice = cameraDevice; createCameraPreviewSession(); } @Override public void onDisconnected(@NonNull CameraDevice cameraDevice) { (); (); mCameraDevice = null; } @Override public void onError(@NonNull CameraDevice cameraDevice, int error) { (); (); mCameraDevice = null; Activity activity = getActivity(); if (null != activity) { (); } } };
When the camera is turned on, the camera's state change callback function mStateCallback will also be specified. If the camera is turned on successfully, the camera preview session will begin to be created.
private void createCameraPreviewSession() { try { // Get the texture instance SurfaceTexture texture = (); assert texture != null; // Set TextureView buffer size ((), ()); // Get the preview data for Surface Surface surface = new Surface(texture); // Build a request for camera preview mPreviewRequestBuilder = (CameraDevice.TEMPLATE_PREVIEW); // Set surface as the display interface for preview data (surface); // Create a camera capture session for preview ((surface), new () { @Override public void onConfigured(@NonNull CameraCaptureSession cameraCaptureSession) { // If the camera is turned off, return if (null == mCameraDevice) { return; } // Turn on preview if the session is ready mCaptureSession = cameraCaptureSession; try { // Autofocus (CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE); mPreviewRequest = (); // Set requests to capture data repeatedly, and the preview interface keeps displaying the screen (mPreviewRequest, null, mBackgroundHandler); } catch (CameraAccessException e) { (); } } @Override public void onConfigureFailed( @NonNull CameraCaptureSession cameraCaptureSession) { showToast("Failed"); } }, null ); } catch (CameraAccessException e) { (); } }
The above is the main process of implementing camera preview by the Camera2 API.
3. Demo source code
Github:Camera2Preview
4. Reference
• /googlesamples/android-Camera2Basic
Summarize
The above is the preview function of Android Camera2 introduced to you by the editor. I hope it will be helpful to you. If you have any questions, please leave me a message and the editor will reply to you in time. Thank you very much for your support for my website!