下述代碼是關於UVC camera處理的封裝類,具體依賴的aar請參考https://github.com/saki4510t/UVCCamera。
借用該類,在接入UVC 攝像頭設備時可以很方便的進行使用,只需要在對應的Activity中,先初始化該類,綁定一個SurfaceView,便於展示攝像視頻數據,再在onStart生命週期回調中調用onStart方法、onStop生命週期回調中調用onStop方法、在onDestroy生命週期回調中調用release即可。
public class UVCCameraManager {
private static final String TAG = UVCCameraManager.class.getSimpleName();
private final USBMonitor mUSBMonitor;
private UVCCamera mUVCCamera;
private SurfaceView mUVCCameraView;
private Surface mPreviewSurface;
private final Object mSync = new Object();
private boolean isActive, isPreview;
private final HandlerThreadHandler mWorkerHandler;
private final Handler mUIHandler = new Handler(Looper.getMainLooper());
private long mWorkerThreadID;
public UVCCameraManager(@NonNull Context context, @NonNull SurfaceView surfaceView) {
mUSBMonitor = new USBMonitor(context, mConnectListener);
mWorkerHandler = HandlerThreadHandler.createHandler(TAG);
mWorkerThreadID = mWorkerHandler.getLooper().getThread().getId();
mUVCCameraView = surfaceView;
mUVCCameraView.getHolder().addCallback(mSurfaceViewCallback);
}
public void onStart() {
L.d(TAG, "onStart:");
synchronized (mSync) {
mUSBMonitor.register();
}
}
public void onStop() {
L.d(TAG, "onStop:");
synchronized (mSync) {
mUSBMonitor.unregister();
}
}
public void release() {
synchronized (mSync) {
isActive = isPreview = false;
if (mUVCCamera != null) {
mUVCCamera.destroy();
mUVCCamera = null;
}
mUSBMonitor.destroy();
}
try {
mWorkerHandler.getLooper().quit();
} catch (Exception e) {
e.printStackTrace();
}
}
private synchronized void queueEvent(final Runnable task, final long delayMillis) {
if (task == null) return;
try {
mWorkerHandler.removeCallbacks(task);
if (delayMillis > 0) {
mWorkerHandler.postDelayed(task, delayMillis);
} else if (mWorkerThreadID == Thread.currentThread().getId()) {
task.run();
} else {
mWorkerHandler.post(task);
}
} catch (final Exception e) {
// ignore
}
}
private final USBMonitor.OnDeviceConnectListener mConnectListener = new USBMonitor.OnDeviceConnectListener() {
@Override
public void onAttach(UsbDevice usbDevice) {
L.d(TAG, "onAttach");
if (usbDevice != null) {
mUSBMonitor.requestPermission(usbDevice);
} else {
L.d(TAG, "usbDevice is null");
}
}
@Override
public void onDettach(UsbDevice usbDevice) {
L.d(TAG, "onDettach");
}
@Override
public void onConnect(UsbDevice usbDevice, USBMonitor.UsbControlBlock ctrlBlock, boolean createNew) {
L.d(TAG, "onConnect:");
synchronized (mSync) {
if (mUVCCamera != null) {
mUVCCamera.destroy();
}
isActive = isPreview = false;
}
queueEvent(() -> {
synchronized (mSync) {
final UVCCamera camera = new UVCCamera();
camera.open(ctrlBlock);
L.d(TAG, "supportedSize:" + camera.getSupportedSize());
try {
camera.setPreviewSize(UVCCamera.DEFAULT_PREVIEW_WIDTH, UVCCamera.DEFAULT_PREVIEW_HEIGHT, UVCCamera.FRAME_FORMAT_MJPEG);
} catch (IllegalArgumentException e) {
try {
// fallback to YUV mode
camera.setPreviewSize(UVCCamera.DEFAULT_PREVIEW_WIDTH, UVCCamera.DEFAULT_PREVIEW_HEIGHT, UVCCamera.DEFAULT_PREVIEW_MODE);
} catch (IllegalArgumentException ex) {
camera.destroy();
return;
}
}
mPreviewSurface = mUVCCameraView.getHolder().getSurface();
if (mPreviewSurface != null) {
isActive = true;
camera.setPreviewDisplay(mPreviewSurface);
//第一次在這裏會黑屏???
//isPreview = camera.startPreview()>=0;
//L.d(TAG,"startPreview:"+isPreview);
}
synchronized (mSync) {
mUVCCamera = camera;
}
}
}, 0);
mUIHandler.post(() -> {
mUVCCameraView.setVisibility(View.VISIBLE);
mUVCCameraView.bringToFront();
});
}
@Override
public void onDisconnect(UsbDevice usbDevice, USBMonitor.UsbControlBlock usbControlBlock) {
L.d(TAG, "onDisconnect:");
// XXX you should check whether the comming device equal to camera device that currently using
queueEvent(() -> {
synchronized (mSync) {
if (mUVCCamera != null) {
mUVCCamera.close();
if (mPreviewSurface != null) {
mPreviewSurface.release();
mPreviewSurface = null;
}
isActive = isPreview = false;
}
}
}, 0);
mUIHandler.post(() -> mUVCCameraView.setVisibility(View.GONE));
}
@Override
public void onCancel(UsbDevice usbDevice) {
L.d(TAG, "onCancel:");
}
};
private final SurfaceHolder.Callback mSurfaceViewCallback = new SurfaceHolder.Callback() {
@Override
public void surfaceCreated(final SurfaceHolder holder) {
L.d(TAG, "surfaceCreated:");
}
@Override
public void surfaceChanged(final SurfaceHolder holder, final int format, final int width, final int height) {
if ((width == 0) || (height == 0)) return;
L.d(TAG, "surfaceChanged:");
mPreviewSurface = holder.getSurface();
synchronized (mSync) {
if (isActive && !isPreview && (mUVCCamera != null)) {
mUVCCamera.setPreviewDisplay(mPreviewSurface);
mUVCCamera.startPreview();
isPreview = true;
L.d(TAG, "startPreview:" + isPreview);
} else {
L.d(TAG, "isActive:" + isActive + ",isPreview:" + isPreview + ",mUVCCamera:" + mUVCCamera);
}
}
}
@Override
public void surfaceDestroyed(final SurfaceHolder holder) {
L.d(TAG, "surfaceDestroyed:");
synchronized (mSync) {
if (mUVCCamera != null) {
mUVCCamera.stopPreview();
}
isPreview = false;
}
mPreviewSurface = null;
}
};
}