解决UVCamera stopPreview阻塞崩溃以及无法识别摄像头等bug

UVCCamera是基于安卓的一个USB外接摄像头调用项目,该项目允许安卓设备在不需要root的情况下打开外接USB摄像头进行预览,获取视频帧.

最近在基于UVCCamera适配一款设备的时候出现了问题:该设备始终无法打开一款摄像头(项目必须要适配这款摄像头),作为对比,我的安卓手机就没有任何问题.作为一个负责任的开发人员,我只好硬着头皮肝下去.并最终解决了这个问题.

经过研究,发现UVCCamera项目确实有这些缺点:

  • 兼容性不是太好,经常出现不同的手机,或者不同摄像头上面表现不一致的问题;
  • 停止预览(stopPreview)时,偶尔会阻死,接口无法返回;
  • native层线程较多,比较杂乱.感觉并不需要这么多线程呀,这也是上一条阻死的原因;
  • 视频采集和显示具有强耦合,发现如果不设置surface,则不会启动预览线程,从而无法采集;
  • 视频格式转换时效率较低;

我在UVCCamera基础上,修改了上面的问题.修改方法如下:

  • 优化了libusb调用方法,提高了兼容性,在那个原先有故障的设备上测试通过,故障排除;
  • 解决了stopPreview阻死的问题;
  • native层使用轮询模式(之前是回调模式),一方面减少了线程数,一方面可以根据业务逻辑动态调节帧率;
  • 去掉采集对surface的依赖;
  • 使用libyuv进行格式转换,提高了效率.

目前项目处于内测阶段,先把apk附上.如果你也遇到usb摄像头无法正常工作,可以先装一下apk进行测试.apk可从github上下载最新的release版,下载地址:
https://github.com/tsinglink/uvccamera/releases

在这里插入图片描述

2022年1月10号更新
项目已经开源,地址:
https://github.com/tsinglink/uvccamera

  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 11
    评论
实现Android人脸识别需要用到Android系统自带的FaceDetector类。具体步骤如下: 1.获取摄像头对象。 2.设置预览界面,并启动预览。 3.在预览界面的SurfaceView上获取画布,并将预览界面的图像绘制到画布上。 4.通过FaceDetector类检测人脸,并获取人脸的坐标和数量。 5.根据人脸坐标在预览界面上绘制人脸框。 下面是一份简单的代码实现: ```java public class MainActivity extends AppCompatActivity implements SurfaceHolder.Callback, Camera.PreviewCallback { private SurfaceView mPreview; private SurfaceHolder mHolder; private Camera mCamera; private byte[] mBuffer; private FaceDetector mFaceDetector; private Face[] mFaces; private Paint mPaint; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mPreview = findViewById(R.id.preview); mHolder = mPreview.getHolder(); mHolder.addCallback(this); mFaceDetector = new FaceDetector(320, 240, 1); mPaint = new Paint(); mPaint.setColor(Color.RED); mPaint.setStyle(Paint.Style.STROKE); } @Override public void surfaceCreated(SurfaceHolder holder) { try { mCamera = Camera.open(); mCamera.setPreviewDisplay(holder); } catch (IOException e) { e.printStackTrace(); } } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { Camera.Parameters parameters = mCamera.getParameters(); Camera.Size size = parameters.getPreviewSize(); int bufferSize = size.width * size.height * ImageFormat.getBitsPerPixel(parameters.getPreviewFormat()) / 8; mBuffer = new byte[bufferSize]; mCamera.addCallbackBuffer(mBuffer); mCamera.setPreviewCallbackWithBuffer(this); mCamera.startPreview(); } @Override public void surfaceDestroyed(SurfaceHolder holder) { mCamera.setPreviewCallback(null); mCamera.stopPreview(); mCamera.release(); mCamera = null; } @Override public void onPreviewFrame(byte[] data, Camera camera) { Camera.Parameters parameters = camera.getParameters(); Camera.Size size = parameters.getPreviewSize(); YuvImage yuvImage = new YuvImage(data, parameters.getPreviewFormat(), size.width, size.height, null); ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); yuvImage.compressToJpeg(new Rect(0, 0, size.width, size.height), 100, outputStream); byte[] jpegData = outputStream.toByteArray(); Bitmap bmp = BitmapFactory.decodeByteArray(jpegData, 0, jpegData.length); mFaces = new Face[1]; mFaceDetector.findFaces(bmp, mFaces); Canvas canvas = mHolder.lockCanvas(); canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); if (mFaces.length > 0) { Face face = mFaces[0]; float left = face.rect.left; float top = face.rect.top; float right = face.rect.right; float bottom = face.rect.bottom; canvas.drawRect(left, top, right, bottom, mPaint); } mHolder.unlockCanvasAndPost(canvas); camera.addCallbackBuffer(mBuffer); } } ``` 在这个例子中,我们使用SurfaceView来预览摄像头采集到的图像,然后在画布上绘制人脸框。注意,这个例子只识别一张人脸。如果需要识别多张人脸,需要修改代码。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值