package com.jiangdg.uvc; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.ImageFormat; import android.graphics.Rect; import android.graphics.SurfaceTexture; import android.graphics.YuvImage; import android.hardware.usb.UsbDevice; import android.opengl.GLES11Ext; import android.os.Handler; import android.os.Vibrator; import android.view.Surface; import com.elvishew.xlog.XLog; import com.jiangdg.usb.USBMonitor; import com.jiangdg.utils.HandlerThreadHandler; import com.wmdigit.camera.listener.OnImageAnalyzeListener; import com.wmdigit.common.model.SimpleUsbDevice; import com.wmdigit.common.utils.NV21ToBitmap; import com.wmdigit.common.utils.YuvToRgbConverter; import com.wmdigit.data.mmkv.repository.CameraLocalRepository; import java.io.ByteArrayOutputStream; import java.nio.ByteBuffer; /** * @author dizi */ public class USBCameraHelper { private static final String TAG = USBCameraHelper.class.getSimpleName(); private static USBCameraHelper instance; private final Object mSync = new Object(); private final Object mSyncFrame = new Object(); private Context mContext; private USBMonitor mUSBMonitor; private UVCCamera mUVCCamera; private Vibrator mVibraotor = null; private SurfaceTexture mSurfaceTexture; private Surface mPreviewSurface; private NV21ToBitmap nv21ToBitmap; private Handler mWorkerHandler; private long mWorkerThreadID = -1; private volatile byte[] frame; private long latestAttachTimestamp = 0L; private long latestDetachTimestamp = 0L; // private OnCameraOpenListener onCameraOpenListener; boolean isFirstFrame = false; /** * 图片分析回调 */ private OnImageAnalyzeListener onImageAnalyzeListener; public void setOnImageAnalyzeListener(OnImageAnalyzeListener onImageAnalyzeListener) { this.onImageAnalyzeListener = onImageAnalyzeListener; } private IFrameCallback iFrameCallback = new IFrameCallback() { int count = 0; int frameInterval = 3; @Override public void onFrame(ByteBuffer buffer) { synchronized (mSyncFrame) { count ++; int len = buffer.capacity(); if (frame != null){ frame = null; } frame = new byte[len]; buffer.get(frame); if (count % frameInterval == 0){ count = 0; if (onImageAnalyzeListener != null){ // onImageAnalyzeListener.onAnalyzed(encodeYuvToJpeg(frame, 640, 480, ImageFormat.NV21)); onImageAnalyzeListener.onAnalyzed(nv21ToBitmap.nv21ToBitmap(frame, 640, 480)); // onImageAnalyzeListener.onAnalyzed(BitmapFactory.decodeByteArray(frame, 0, frame.length)); } } } } }; private Bitmap encodeYuvToJpeg(byte[] yuvData, int width, int height, int format){ try { // 将YUV数据转换为Bitmap YuvImage yuvImage = new YuvImage(yuvData, format, width, height, null); ByteArrayOutputStream out = new ByteArrayOutputStream(); yuvImage.compressToJpeg(new Rect(0, 0, width, height), 75, out); byte[] imageBytes = out.toByteArray(); return BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.length); // // 使用OpenCV进一步压缩 // Mat mat = Imgcodecs.imdecode(new MatOfByte(imageBytes), Imgcodecs.IMREAD_UNCHANGED); // MatOfByte mob = new MatOfByte(); // Imgcodecs.imencode(".jpg", mat, mob); // return mob.toArray(); } catch (Exception e) { XLog.e(e); return null; } } public static USBCameraHelper getInstance(Context context) { if (instance == null) { synchronized (USBCameraHelper.class) { if (instance == null) { instance = new USBCameraHelper(context); } } } return instance; } public USBCameraHelper(Context context) { mContext = context; if (mWorkerHandler == null) { mWorkerHandler = HandlerThreadHandler.createHandler(TAG); mWorkerThreadID = mWorkerHandler.getLooper().getThread().getId(); } nv21ToBitmap = new NV21ToBitmap(mContext); mUSBMonitor = new USBMonitor(mContext, mOnDeviceConnectListener); } private final Object mSyncUsb = new Object(); private boolean isAttach = false; private final USBMonitor.OnDeviceConnectListener mOnDeviceConnectListener = new USBMonitor.OnDeviceConnectListener() { @Override public void onAttach(final UsbDevice device) { System.out.println("onAttach==>"); synchronized (mSyncUsb) { XLog.i("getDeviceName" + device.getDeviceName() + "getProductId" + device.getProductId() + "getVendorId" + device.getVendorId() + "getDeviceClass" + device.getDeviceClass() + "getProductName" + device.getProductName()); if (mUSBMonitor != null) { if (device.getDeviceClass() == 239 && !isAttach) { SimpleUsbDevice simpleUsbDevice = CameraLocalRepository.getInstance().getCamera(); if (simpleUsbDevice.getVid() != 0 && simpleUsbDevice.getPid() != 0) { if(device.getProductId() == simpleUsbDevice.getPid() && device.getVendorId() == simpleUsbDevice.getVid()){ isAttach = true; mUSBMonitor.requestPermission(device); } }else{ isAttach = true; mUSBMonitor.requestPermission(device); } } } } } @Override public void onConnect(final UsbDevice device, final USBMonitor.UsbControlBlock ctrlBlock, final boolean createNew) { releaseCamera(); XLog.d("onConnect===>"); queueEvent(() -> { try { final UVCCamera camera = new UVCCamera(); camera.open(ctrlBlock); try { // camera.setPreviewSize(640, 480, UVCCamera.PIXEL_FORMAT_YUV420SP); camera.setPreviewSize(640, 480, UVCCamera.FRAME_FORMAT_YUYV); } catch (final IllegalArgumentException e) { // fallback to YUV mode try { camera.setPreviewSize(640, 480,UVCCamera.PIXEL_FORMAT_YUV420SP); } catch (final IllegalArgumentException e1) { camera.destroy(); return; } } camera.setFrameCallback(iFrameCallback, UVCCamera.PIXEL_FORMAT_YUV420SP); if (mSurfaceTexture == null) { mSurfaceTexture = new SurfaceTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES); } if (mPreviewSurface == null) { mPreviewSurface = new Surface(mSurfaceTexture); } camera.setPreviewDisplay(mPreviewSurface); camera.startPreview(); isFirstFrame = true; synchronized (mSync) { mUVCCamera = camera; } } catch (Exception e) { XLog.e(e.toString()); } }, 900); } @Override public void onDisconnect(final UsbDevice device, final USBMonitor.UsbControlBlock ctrlBlock) { synchronized (mSyncUsb) { long time = System.currentTimeMillis(); if (time - latestDetachTimestamp < 100) { return; } isAttach = false; latestDetachTimestamp = time; XLog.d(String.format("相机vid:%s断开连接", device.getVendorId())); releaseCamera(); } } @Override public void onDetach(final UsbDevice device) { System.out.println("onDetach=>"); } @Override public void onCancel(final UsbDevice device) { System.out.println("onCancel=>"); } }; /** * Release the USB camera device. */ private synchronized void releaseCamera() { synchronized (mSync) { if (mUVCCamera != null) { try { mUVCCamera.stopPreview(); mUVCCamera.setStatusCallback(null); mUVCCamera.setButtonCallback(null); mUVCCamera.close(); mUVCCamera.destroy(); if (mPreviewSurface != null) { mPreviewSurface.release(); mPreviewSurface = null; } if (mSurfaceTexture != null) { mSurfaceTexture.release(); mSurfaceTexture = null; } XLog.d("uvc相机释放完成"); } catch (final Exception e) { XLog.d(e.toString()); } mUVCCamera = null; } } } public synchronized Bitmap captureStillImage() { Bitmap[] bitmap = new Bitmap[1]; // synchronized (mSyncFrame) { try { if (frame == null || frame.length <= 0) { System.out.println("抓取图片失败"); bitmap[0] = null; } else { System.out.println("抓取图片成功"); byte[] tempFrame = frame; bitmap[0] = BitmapFactory.decodeByteArray(tempFrame, 0, tempFrame.length); frame = null; } } catch (Exception e) { XLog.e(e.toString()); } // } return bitmap[0]; } protected final synchronized void queueEvent(final Runnable task, final long delayMillis) { if ((task == null) || (mWorkerHandler == 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) { } } public synchronized void open() { mUSBMonitor.register(); synchronized (mSync) { if (mUVCCamera != null) { mUVCCamera.startPreview(); } } } public synchronized void close() { synchronized (mSync) { if (mUVCCamera != null) { mUVCCamera.stopPreview(); } if (mUSBMonitor != null) { mUSBMonitor.unregister(); } } } public synchronized void destroy() { synchronized (mSync) { releaseCamera(); if (mUSBMonitor != null) { mUSBMonitor.destroy(); mUSBMonitor = null; } nv21ToBitmap.destroy(); instance = null; } } public boolean checkCameraOpened() { if (mUVCCamera == null) { return false; } return true; } }