Android camera2 api 在 Android5.0 的时候发布的,貌似。
比起之前的 camera, 使用上复杂了很多。
- 这里给出最简单的实现。
import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.ImageFormat;
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.CaptureFailure;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.TotalCaptureResult;
import android.media.Image;
import android.media.ImageReader;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import com.apkfuns.logutils.LogUtils;
import com.permissionx.guolindev.PermissionX;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import static android.hardware.camera2.CameraDevice.TEMPLATE_PREVIEW;
public class MainActivity extends AppCompatActivity {
private CameraManager mCameraManager;
private static final boolean DETAIL = false;
private static final boolean DEBUG = BuildConfig.DEBUG && DETAIL;
private SurfaceView mFullSurfaceView;
private HandlerThread mEyeThread;
private Handler mBgHandler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mFullSurfaceView = findViewById(R.id.full_surface);
mEyeThread = new HandlerThread("eyeThread") {
@Override
protected void onLooperPrepared() {
super.onLooperPrepared();
LogUtils.i("ok");
}
};
mEyeThread.start();
mBgHandler = new Handler(mEyeThread.getLooper());
}
@Override
protected void onStart() {
super.onStart();
PermissionX.init(this)
.permissions(Manifest.permission.CAMERA)
.onForwardToSettings((scope, deniedList) -> {
LogUtils.d("%s, %s", scope, deniedList);
}).onExplainRequestReason((scope, deniedList, beforeRequest) -> {
LogUtils.d("%s, %s, %s", scope, deniedList, beforeRequest);
}).request((allGranted, grantedList, deniedList) -> {
LogUtils.d("permission request result: %s, %s, %s", allGranted, grantedList, deniedList);
if (!allGranted) {
return;
}
onPermissionPrepared();
});
}
private void onPermissionPrepared() {
LogUtils.d("view: %s,%s", mFullSurfaceView.getWidth(), mFullSurfaceView.getHeight());
mCameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
LogUtils.d(mCameraManager);
try {
String[] cameraIdList = mCameraManager.getCameraIdList();
LogUtils.d("cameraIdList: %s", Arrays.toString(cameraIdList));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
Set<Set<String>> concurrentCameraIds = mCameraManager.getConcurrentCameraIds();
LogUtils.i("concurrentCameraIds: %s", concurrentCameraIds);
}
for (String cameraId : cameraIdList) {
CameraCharacteristics characteristics = mCameraManager.getCameraCharacteristics(cameraId);
Integer facing = characteristics.get(CameraCharacteristics.LENS_FACING);
if (DEBUG) {
List<CameraCharacteristics.Key<?>> keys = characteristics.getKeys();
keys.forEach(key -> {
Object value = characteristics.get(key);
LogUtils.d("info in characteristics of ID(%s):{%s -> %s}", cameraId, key, value);
});
}
if (facing == CameraCharacteristics.LENS_FACING_BACK) {
// ok set default facing is back, not front
ImageReader imageReader = ImageReader.newInstance(100, 100, ImageFormat.JPEG, 2);
imageReader.setOnImageAvailableListener(reader -> {
LogUtils.d("onImageAvailable: ...");
LogUtils.d("onImageAvailable: ...#");
Image image = reader.acquireLatestImage();
LogUtils.d("... %s", image.getTimestamp());
}, mBgHandler);
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
!= PackageManager.PERMISSION_GRANTED) {
return;
}
mCameraManager.openCamera(cameraId, new CameraDevice.StateCallback() {
@Override
public void onOpened(@NonNull CameraDevice camera) {
LogUtils.d("opened: %s, %s", camera.getId(), camera.getClass());
mFullSurfaceView.getHolder().addCallback(new SurfaceHolder.Callback() {
@Override
public void surfaceCreated(@NonNull SurfaceHolder holder) {
try {
ArrayList<Surface> outputs = new ArrayList<>();
Collections.addAll(outputs, holder.getSurface());
camera.createCaptureSession(outputs, new CameraCaptureSession.StateCallback() {
@Override
public void onConfigured(@NonNull CameraCaptureSession session) {
LogUtils.d(session);
try {
CaptureRequest.Builder builder = camera.createCaptureRequest(TEMPLATE_PREVIEW);
builder.set(CaptureRequest.CONTROL_AF_MODE,
CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
builder.addTarget(holder.getSurface());
CaptureRequest captureRequest = builder.build();
session.setRepeatingRequest(captureRequest, new CameraCaptureSession.CaptureCallback() {
@Override
public void onCaptureStarted(@NonNull CameraCaptureSession session,
@NonNull CaptureRequest request, long timestamp, long frameNumber) {
super.onCaptureStarted(session, request, timestamp, frameNumber);
LogUtils.d("onCaptureStarted:");
}
@Override
public void onCaptureCompleted(@NonNull CameraCaptureSession session,
@NonNull CaptureRequest request, @NonNull TotalCaptureResult result) {
super.onCaptureCompleted(session, request, result);
LogUtils.d("onCaptureCompleted");
}
@Override
public void onCaptureFailed(@NonNull CameraCaptureSession session,
@NonNull CaptureRequest request, @NonNull CaptureFailure failure) {
super.onCaptureFailed(session, request, failure);
LogUtils.w("onCaptureFailed: %s --- %s", failure, failure.getReason());
}
}, mBgHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
LogUtils.e(e);
}
}
@Override
public void onConfigureFailed(@NonNull CameraCaptureSession session) {
LogUtils.d(session);
}
}, mBgHandler);
} catch (CameraAccessException e) {
LogUtils.e(e);
}
}
@Override
public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, int height) {
LogUtils.d("changed..");
}
@Override
public void surfaceDestroyed(@NonNull SurfaceHolder holder) {
LogUtils.w("destroyed..");
}
});
}
@Override
public void onDisconnected(@NonNull CameraDevice camera) {
LogUtils.d(camera.getId());
}
@Override
public void onError(@NonNull CameraDevice camera, int error) {
LogUtils.e("error: %s, %d", camera.getId(), error);
}
}, mBgHandler);
}
}
} catch (CameraAccessException ex) {
LogUtils.e(ex);
}
}
@Override
protected void onDestroy() {
super.onDestroy();
mBgHandler.removeCallbacksAndMessages(null);
mEyeThread.quitSafely();
}
}
里面用到了两个第三方库,一个是打日志的,一个是动态权限的。分别是:
implementation 'com.permissionx.guolindev:permissionx:1.4.0'
implementation 'com.apkfuns.logutils:library:1.7.5'
布局文件很简单,就是一个 <Surfaview>
<SurfaceView
android:id="@+id/full_surface"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
然后,因为只是最简单的实现,所以是有很多需要优化的地方,比如资源释放等。
以上代码就是完整的实现了。有需要的可以参考。
如果复制过去不能运行,也可以下载源码。我上传在 csdn 上面了(不需要积分的)。
下载地址:Camera2easy.zip
实现效果如图: