文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

UVCAndroid,安卓UVC相机通用开发库(支持多预览和多摄像头)

2023-08-17 08:19

关注

简介

UVCAndroid是一款用于安卓UVC相机的通用开发库。

GitHub源码地址https://github.com/shiyinghan/UVCAndroid

主要功能

主要功能包括:
(1) 支持USB Camera设备检测,画面实时预览;
(2) 支持抓拍jpg格式图片,可设置图片压缩质量;
(3) 支持录制mp4格式视频,可屏蔽音频,可设置视频和音频的录制参数;
(4) 支持获取camera支持的分辨率,和分辨率切换;
(5) 支持预览自动识别各种相机的分辨率;
(6) 支持旋转摄像头90度、180度、270度
(7) 支持调整对比度、亮度、色调、饱和度、白平衡等等一些相机控制参数;
(8) 支持多预览和多摄像头;
(9) 支持Android5.0+;

如何使用

1. 添加依赖到本地工程

第一步 添加mavenCentral仓库到工程gradle文件
Step 1. Add the mavenCentral repository to your build file
Add it in your root build.gradle at the end of repositories:

allprojects {    repositories {...mavenCentral()    }}

第二步 添加依赖到app Module的gradle文件

dependencies {    implementation 'com.herohan:UVCAndroid:1.0.5'}

2. 获取权限

Request permissions

 List needPermissions = new ArrayList<>();    needPermissions.add(Manifest.permission.CAMERA);    needPermissions.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);//拍照和录制视频时需要该权限    //needPermissions.add(Manifest.permission.MANAGE_EXTERNAL_STORAGE); //Android 11 使用该权限替代 WRITE_EXTERNAL_STORAGE    needPermissions.add(Manifest.permission.RECORD_AUDIO);//录制视频时需要音频时需要该权限//这里使用XXPermissions开源框架获取权限,你也可以使用系统原生的,或者其他开源框架获取权限    XXPermissions.with(this)            .permission(needPermissions)            .request((permissions, all) -> {                if(!all){                    return;                }//摄像头业务操作           });

3. 初始化UVC业务类,设置UVC摄像头状态回调,设置TextureView或者SurfaceView的Surface监听回调

Initialize CameraHelper,set UVC Camera state callback

 private ICameraHelper mCameraHelper; private AspectRatioSurfaceView mCameraViewMain; private ICameraHelper.StateCallback mStateListener;//UVC摄像头状态回调mStateListener = new ICameraHelper.StateCallback() {//插入UVC设备        @Override        public void onAttach(UsbDevice device) {        //设置为当前设备(如果没有权限,会显示授权对话框)            mCameraHelper.selectDevice(device);        }//打开UVC设备成功(也就是已经获取到UVC设备的权限)        @Override        public void onDeviceOpen(UsbDevice device, boolean isFirstOpen) {        //打开UVC摄像头            mCameraHelper.openCamera();        }//打开摄像头成功        @Override        public void onCameraOpen(UsbDevice device) {        //开始预览            mCameraHelper.startPreview();//获取预览使用的Size(包括帧格式、宽度、高度、FPS)            Size size = mCameraHelper.getPreviewSize();            if (size != null) {                int width = size.width;                int height = size.height;                //需要自适应摄像头分辨率的话,设置新的宽高比                mCameraViewMain.setAspectRatio(width, height);            }//添加预览Surface            mCameraHelper.addSurface(mCameraViewMain.getHolder().getSurface(), false);        }//关闭摄像头成功        @Override        public void onCameraClose(UsbDevice device) {            if (mCameraHelper != null) {            //移除预览Surface                mCameraHelper.removeSurface(mCameraViewMain.getHolder().getSurface());            }        }//关闭UVC设备成功        @Override        public void onDeviceClose(UsbDevice device) {        }//断开UVC设备        @Override        public void onDetach(UsbDevice device) {        }//用户没有授予访问UVC设备的权限        @Override        public void onCancel(UsbDevice device) {        }    };        //设置SurfaceView的Surface监听回调    mCameraViewMain.getHolder().addCallback(new SurfaceHolder.Callback() {        //创建了新的Surface            @Override            public void surfaceCreated(@NonNull SurfaceHolder holder) {                if (mCameraHelper != null) {                //添加预览Surface                    mCameraHelper.addSurface(holder.getSurface(), false);                }            }//Surface发生了改变            @Override            public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, int height) {            }//销毁了原来的Surface            @Override            public void surfaceDestroyed(@NonNull SurfaceHolder holder) {                if (mCameraHelper != null) {                //移除预览Surface                    mCameraHelper.removeSurface(holder.getSurface());                }            }        });        mCameraHelper = new CameraHelper();//设置UVC摄像头状态回调        mCameraHelper.setStateCallback(mStateListener);

4. 释放UVC业务类(包含取消UVC摄像头状态回调,停止Camera预览,关闭Camera等操作)

Release CameraHelper(including canceling UVC Camera state callback, stopping Camera preview, etc.)

 mCameraHelper.release();

5. 图片抓拍

Image Capture

//设置视图片抓拍全局参数(非必须,可以不设置,使用默认值)mCameraHelper.setImageCaptureConfig(                mCameraHelper.getImageCaptureConfig().setCaptureMode(ImageCapture.CAPTURE_MODE_MAXIMIZE_QUALITY));//        mCameraHelper.setImageCaptureConfig(//                mCameraHelper.getImageCaptureConfig().setJpegCompressionQuality(90));//设置需要保存图片文件 File file = FileUtils.getCaptureFile(this, Environment.DIRECTORY_DCIM, ".jpg");    ImageCapture.OutputFileOptions options =             new ImageCapture.OutputFileOptions.Builder(file).build();//                ContentValues contentValues = new ContentValues();//                contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, "NEW_IMAGE");//                contentValues.put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg");////                ImageCapture.OutputFileOptions options = new ImageCapture.OutputFileOptions.Builder(//                        getContentResolver(),//                        MediaStore.Images.Media.EXTERNAL_CONTENT_URI,//                        contentValues).build();//                ByteArrayOutputStream outputStream = new ByteArrayOutputStream();//                ImageCapture.OutputFileOptions options = new ImageCapture.OutputFileOptions.Builder(outputStream).build();//进行图片抓拍    mCameraHelper.takePicture(options, new ImageCapture.OnImageCaptureCallback() {    //图片抓拍成功       @Override        public void onImageSaved(@NonNull ImageCapture.OutputFileResults outputFileResults) {            Toast.makeText(TakePictureActivity.this,                    "save \"" + UriHelper.getPath(TakePictureActivity.this, outputFileResults.getSavedUri()) + "\"",                    Toast.LENGTH_SHORT).show();        }//图片抓拍出现错误        @Override        public void onError(int imageCaptureError, @NonNull String message, @Nullable Throwable cause) {            Toast.makeText(TakePictureActivity.this, message, Toast.LENGTH_SHORT).show();        }    });

6. 录制视频

Video Capture

//设置视频录制全局参数(非必须,可以不设置,使用默认值)mCameraHelper.setVideoCaptureConfig(    mCameraHelper.getVideoCaptureConfig()              .setAudioCaptureEnable(true) // true:有音频;false:没有音频(默认为true)              .setBitRate((int) (1024 * 1024 * 25 * 0.25))              .setVideoFrameRate(25)              .setIFrameInterval(1));//设置需要保存视频文件File file = FileUtils.getCaptureFile(this, Environment.DIRECTORY_MOVIES, ".mp4");    VideoCapture.OutputFileOptions options =            new VideoCapture.OutputFileOptions.Builder(file).build();//        ContentValues contentValues = new ContentValues();//        contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, "NEW_VIDEO");//        contentValues.put(MediaStore.MediaColumns.MIME_TYPE, "video/mp4");////        VideoCapture.OutputFileOptions options = new VideoCapture.OutputFileOptions.Builder(//                getContentResolver(),//                MediaStore.Video.Media.EXTERNAL_CONTENT_URI,//                contentValues).build();//开始录制    mCameraHelper.startRecording(options, new VideoCapture.OnVideoCaptureCallback() {        @Override        public void onStart() {        }//视频录制成功        @Override        public void onVideoSaved(@NonNull VideoCapture.OutputFileResults outputFileResults) {            Toast.makeText(                    RecordVideoActivity.this,                    "save \"" + UriHelper.getPath(RecordVideoActivity.this, outputFileResults.getSavedUri()) + "\"",                    Toast.LENGTH_SHORT).show();        }//视频录制出现错误        @Override        public void onError(int videoCaptureError, @NonNull String message, @Nullable Throwable cause) {            Toast.makeText(RecordVideoActivity.this, message, Toast.LENGTH_LONG).show();        }    });

7. 改变摄像机预览参数(包括帧格式、宽度、高度、FPS)

Set camera preview parameters (including frame format, width, height, FPS)

//停止相机预览mCameraHelper.stopPreview();//设置摄像机预览参数mCameraHelper.setPreviewSize(size);//开始相机预览mCameraHelper.startPreview();//需要自适应摄像头分辨率的话,设置新的宽高比mCameraViewMain.setAspectRatio(mPreviewWidth, mPreviewHeight);

8. 调整对比度、亮度、色调、饱和度、白平衡等等一些相机控制参数

Adjust contrast, brightness, hue, saturation, white balance, and other camera controls

//获取UVCControl对象,通过该对象调整相机控制参数UVCControl control = mCameraHelper.getUVCControl();//根据监听器设置各种相机控制参数private void setAllControlChangeListener(UVCControl controls) {        // Brightness        isbBrightness.setOnSeekChangeListener(                (MyOnSeekChangeListener) seekParams -> controls.setBrightness(seekParams.progress));        // Contrast        isbContrast.setOnSeekChangeListener(                (MyOnSeekChangeListener) seekParams -> controls.setContrast(seekParams.progress));        // Contrast Auto        cbContrastAuto.setOnCheckedChangeListener((buttonView, isChecked) -> {            controls.setContrastAuto(isChecked);        });        // Hue        isbHue.setOnSeekChangeListener(                (MyOnSeekChangeListener) seekParams -> controls.setHue(seekParams.progress));        // Hue Auto        cbHueAuto.setOnCheckedChangeListener((buttonView, isChecked) -> {            controls.setHueAuto(isChecked);        });        // Saturation        isbSaturation.setOnSeekChangeListener(                (MyOnSeekChangeListener) seekParams -> controls.setSaturation(seekParams.progress));        // Sharpness        isbSharpness.setOnSeekChangeListener(                (MyOnSeekChangeListener) seekParams -> controls.setSharpness(seekParams.progress));        // Gamma        isbGamma.setOnSeekChangeListener(                (MyOnSeekChangeListener) seekParams -> controls.setGamma(seekParams.progress));        // White Balance        isbWhiteBalance.setOnSeekChangeListener(                (MyOnSeekChangeListener) seekParams -> controls.setWhiteBalance(seekParams.progress));        // White Balance Auto        cbWhiteBalanceAuto.setOnCheckedChangeListener((buttonView, isChecked) -> {            controls.setWhiteBalanceAuto(isChecked);        });        // Backlight Compensation        isbBacklightComp.setOnSeekChangeListener(                (MyOnSeekChangeListener) seekParams -> controls.setBacklightComp(seekParams.progress));        // Gain        isbGain.setOnSeekChangeListener(                (MyOnSeekChangeListener) seekParams -> controls.setGain(seekParams.progress));        // Exposure Time        isbExposureTime.setOnSeekChangeListener(                (MyOnSeekChangeListener) seekParams -> controls.setExposureTimeAbsolute(seekParams.progress));        // Exposure Time Auto        cbExposureTimeAuto.setOnCheckedChangeListener((buttonView, isChecked) -> {            controls.setExposureTimeAuto(isChecked);        });        // Iris        isbIris.setOnSeekChangeListener(                (MyOnSeekChangeListener) seekParams -> controls.setIrisAbsolute(seekParams.progress));        // Focus        isbFocus.setOnSeekChangeListener(                (MyOnSeekChangeListener) seekParams -> controls.setFocusAbsolute(seekParams.progress));        // Focus Auto        cbFocusAuto.setOnCheckedChangeListener((buttonView, isChecked) -> {            controls.setFocusAuto(isChecked);        });        // Zoom        isbZoom.setOnSeekChangeListener(                (MyOnSeekChangeListener) seekParams -> controls.setZoomAbsolute(seekParams.progress));        // Pan        isbPan.setOnSeekChangeListener(                (MyOnSeekChangeListener) seekParams -> controls.setPanAbsolute(seekParams.progress));        // Tilt        isbTilt.setOnSeekChangeListener(                (MyOnSeekChangeListener) seekParams -> controls.setTiltAbsolute(seekParams.progress));        // Roll        isbRoll.setOnSeekChangeListener(                (MyOnSeekChangeListener) seekParams -> controls.setRollAbsolute(seekParams.progress));        // Power Line Frequency        rgPowerLineFrequency.setOnCheckedChangeListener((group, checkedId) -> {            int value = 0;            if (checkedId == R.id.rbPowerLineFrequencyDisable) {                value = 0;            } else if (checkedId == R.id.rbPowerLineFrequency50Hz) {                value = 1;            } else if (checkedId == R.id.rbPowerLineFrequency60Hz) {                value = 2;            } else if (checkedId == R.id.rbPowerLineFrequencyAuto) {                value = 3;            }            controls.setPowerlineFrequency(value);        });    }// 重置所有相机控制参数为初试值private void resetAllControlParams(UVCControl control) {        // Brightness        control.resetBrightness();        // Contrast        control.resetContrast();        // Contrast Auto        control.resetContrastAuto();        // Hue        control.resetHue();        // Hue Auto        control.resetHueAuto();        // Saturation        control.resetSaturation();        // Sharpness        control.resetSharpness();        // Gamma        control.resetGamma();        // White Balance        control.resetWhiteBalance();        // White Balance Auto        control.resetWhiteBalanceAuto();        // Backlight Compensation        control.resetBacklightComp();        // Gain        control.resetGain();        // Exposure Time        control.resetExposureTimeAbsolute();        // Auto-Exposure Mode        control.resetAutoExposureMode();        // Iris        control.resetIrisAbsolute();        // Focus        control.resetFocusAbsolute();        // Focus Auto        control.resetFocusAuto();        // Zoom        control.resetZoomAbsolute();        // Pan        control.resetPanAbsolute();        // Tilt        control.resetTiltAbsolute();        // Roll        control.resetRollAbsolute();        // Power Line Frequency        control.resetPowerlineFrequency();    }

9.旋转摄像头90度、180度、270度,设置摄像头预览镜像

Rotate the camera 90 degrees, 180 degrees, and 270 degrees , set the camera preview mirror

//旋转摄像头private void rotateBy(int angle) {        mPreviewRotation += angle;        mPreviewRotation %= 360;        if (mPreviewRotation < 0) {            mPreviewRotation += 360;        }        if (mCameraHelper != null) {            mCameraHelper.setPreviewConfig(                    mCameraHelper.getPreviewConfig().setRotation(mPreviewRotation));        }    }//设置水平镜像显示    private void flipHorizontally() {        if (mCameraHelper != null) {            mCameraHelper.setPreviewConfig(                    mCameraHelper.getPreviewConfig().setMirror(MirrorMode.MIRROR_HORIZONTAL));        }    }//设置垂直镜像显示    private void flipVertically() {        if (mCameraHelper != null) {            mCameraHelper.setPreviewConfig(                    mCameraHelper.getPreviewConfig().setMirror(MirrorMode.MIRROR_VERTICAL));        }    }

10.设置多个预览

Set multiple previews

mCameraHelper.addSurface(svCameraViewMain.getHolder().getSurface(), false);mCameraHelper.addSurface(svCameraViewSecond.getHolder().getSurface(), false);mCameraHelper.addSurface(svCameraViewThird.getHolder().getSurface(), false);mCameraHelper.addSurface(svCameraViewFourth.getHolder().getSurface(), false);

11.设置多个摄像头(USB2.0受带宽所限,有可能无法同时连接多个摄像头)

Setting multiple Cameras

private ICameraHelper mCameraHelperLeft;    private ICameraHelper mCameraHelperRight;    private AspectRatioSurfaceView svCameraViewLeft;    private AspectRatioSurfaceView svCameraViewRight;private UsbDevice mUsbDeviceLeft;    private UsbDevice mUsbDeviceRight;private final ICameraHelper.StateCallback mStateListenerLeft = new ICameraHelper.StateCallback() {@Override        public void onAttach(UsbDevice device) {            synchronized (mSync) {                if (mUsbDeviceLeft == null && !device.equals(mUsbDeviceRight)) {                    selectDeviceLeft(device);                }            }        }        @Override        public void onDeviceOpen(UsbDevice device, boolean isFirstOpen) {            if (device.equals(mUsbDeviceLeft)) {                UVCParam param = new UVCParam();                param.setQuirks(UVCCamera.UVC_QUIRK_FIX_BANDWIDTH);                mCameraHelperLeft.openCamera(param);            }        }        @Override        public void onCameraOpen(UsbDevice device) {            if (device.equals(mUsbDeviceLeft)) {                mCameraHelperLeft.startPreview();                Size size = mCameraHelperLeft.getPreviewSize();                if (size != null) {                    int width = size.width;                    int height = size.height;                    //auto aspect ratio                    svCameraViewLeft.setAspectRatio(width, height);                }                mCameraHelperLeft.addSurface(svCameraViewLeft.getHolder().getSurface(), false);                mIsCameraLeftConnected = true;            }        }        @Override        public void onCameraClose(UsbDevice device) {            if (device.equals(mUsbDeviceLeft)) {                if (mCameraHelperLeft != null) {                   mCameraHelperLeft.removeSurface(svCameraViewLeft.getHolder().getSurface());                }                mIsCameraLeftConnected = false;            }        }        @Override        public void onDeviceClose(UsbDevice device) {        }        @Override        public void onDetach(UsbDevice device) {            if (device.equals(mUsbDeviceLeft)) {                mUsbDeviceLeft = null;            }        }        @Override        public void onCancel(UsbDevice device) {            if (device.equals(mUsbDeviceLeft)) {                mUsbDeviceLeft = null;            }        }};private final ICameraHelper.StateCallback mStateListenerRight = new ICameraHelper.StateCallback() {@Override        public void onAttach(UsbDevice device) {            synchronized (mSync) {                if (mUsbDeviceRight == null && !device.equals(mUsbDeviceLeft)) {                    selectDeviceRight(device);                }            }        }        @Override        public void onDeviceOpen(UsbDevice device, boolean isFirstOpen) {            if (device.equals(mUsbDeviceRight)) {                UVCParam param = new UVCParam();                param.setQuirks(UVCCamera.UVC_QUIRK_FIX_BANDWIDTH);                mCameraHelperRight.openCamera(param);            }        }        @Override        public void onCameraOpen(UsbDevice device) {            if (device.equals(mUsbDeviceRight)) {                mCameraHelperRight.startPreview();                Size size = mCameraHelperRight.getPreviewSize();                if (size != null) {                    int width = size.width;                    int height = size.height;                    //auto aspect ratio                    svCameraViewRight.setAspectRatio(width, height);                }                mCameraHelperRight.addSurface(svCameraViewRight.getHolder().getSurface(), false);                mIsCameraRightConnected = true;            }        }        @Override        public void onCameraClose(UsbDevice device) {            if (device.equals(mUsbDeviceRight)) {                if (mCameraHelperRight != null) {                    mCameraHelperRight.removeSurface(svCameraViewRight.getHolder().getSurface());                }                mIsCameraRightConnected = false;            }        }        @Override        public void onDeviceClose(UsbDevice device) {        }        @Override        public void onDetach(UsbDevice device) {            if (device.equals(mUsbDeviceRight)) {                mUsbDeviceRight = null;            }        }        @Override        public void onCancel(UsbDevice device) {            if (device.equals(mUsbDeviceRight)) {                mUsbDeviceRight = null;            }        }};svCameraViewLeft.getHolder().addCallback(new SurfaceHolder.Callback() {            @Override            public void surfaceCreated(@NonNull SurfaceHolder holder) {                if (mCameraHelperLeft != null) {                    mCameraHelperLeft.addSurface(holder.getSurface(), false);                }            }            @Override            public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, int height) {            }            @Override            public void surfaceDestroyed(@NonNull SurfaceHolder holder) {                if (mCameraHelperLeft != null) {                    mCameraHelperLeft.removeSurface(holder.getSurface());                }            }        });svCameraViewRight.setAspectRatio(DEFAULT_WIDTH, DEFAULT_HEIGHT);        svCameraViewRight.getHolder().addCallback(new SurfaceHolder.Callback() {            @Override            public void surfaceCreated(@NonNull SurfaceHolder holder) {                if (mCameraHelperRight != null) {                    mCameraHelperRight.addSurface(holder.getSurface(), false);                }            }            @Override            public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, int height) {            }            @Override            public void surfaceDestroyed(@NonNull SurfaceHolder holder) {                if (mCameraHelperRight != null) {                    mCameraHelperRight.removeSurface(holder.getSurface());                }            }        });mCameraHelperLeft = new CameraHelper();mCameraHelperLeft.setStateCallback(mStateListenerLeft);mCameraHelperRight = new CameraHelper();mCameraHelperRight.setStateCallback(mStateListenerRight);

其他API

方法说明
getDeviceList()获取当前检测到的所有UVC设备
getSupportedFormatList()获取当前摄像头支持的Format列表
getSupportedSizeList()获取当前摄像头支持的Size列表
getPreviewSize()获取当前摄像头正在使用的预览Size
setButtonCallback()设置按钮事件回调
setFrameCallback()设置实时预览图像数据回调(请在StateCallback的onDeviceOpen或者onCameraOpen回调函数里面调用,使用方法可以参考demo里面的SetFrameCallbackActivity),支持格式 UVCCamera.PIXEL_FORMAT_YUV;PIXEL_FORMAT_NV12;PIXEL_FORMAT_NV21;PIXEL_FORMAT_RGB565;PIXEL_FORMAT_RGBX等格式
openCamera(Size size)用指定格式打开当前摄像头
closeCamera()关闭当前摄像头
isRecording()是否正在录像
isCameraOpened()是否已经打开当前摄像头

下载演示APK

Download demo APK
在这里插入图片描述
app-debug.apk

在这里插入图片描述
demo-debug.apk

参考

saki4510t/UVCCamera

来源地址:https://blog.csdn.net/hanshiying007/article/details/124118486

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯