精华内容
下载资源
问答
  • MTK USB camera patch

    2018-12-11 18:14:23
    MTK实现UVC camera的patch,可以实现Preview ,拍照,录像。支持USB摄像头,可以下载USB摄像头APP验证,此Patch针对MTK平台,官网释放
  • usb camera trial_1.4.8

    2015-06-27 21:54:23
    手机连接USB摄像头USB camera
  • usbcamera.apk

    2015-03-14 10:04:43
    这是一个Android应用程序连接到智能手机或平板设备的USB摄像头,显示和记录视频。赶快来下载吧!
  • Android USB Camera .zip

    2019-12-24 14:35:57
    这个demo不是调用系统本身的摄像头,而是调用USB外接摄像头的,请根据需要下载.该demo能够拍照,录制视频以及调整分辨率
  • Android usb Camera源码

    热门讨论 2014-05-27 14:56:24
    这个资源是网站下载的一份Android usb摄像头的源码!我在我的Exynos4412开发板上面测试OK!不过只能预览!而且我强制把ImageProc.c里面的设备文件指向我USB摄像头的设备文件! 编译环境:ubuntu+ndk_build+eclipse ...
  • usb2.0 camera 摄像头驱动是一款万能的摄像头驱动程序,几乎支持市面上所有的摄像头型号,支持win7、win8和64位操作系统。usb2.0 camera驱动使用说明64位系统必须运行UniversalThemePatcher-x64.exe。需要管理员权限...
  • AndroidUSBCamera.zip

    2019-12-09 16:21:47
    根据项目需求安卓板卡调用usb摄像头,调分辨率,拍照保存图片的实现,av摄像头也可以调用起来,在github找的项目,经过修改实现摄像头拍照等功能,亲测有效!
  • USBCamera.zip

    2020-04-13 09:30:10
    1.支持USB Camera设备检测,画面实时预览 2.支持jpg格式图片抓拍 仅提供了基础的功能,大家需要的功能可以根据需求进行自行添加
  • usb camera (uvc) on android

    2015-09-10 20:00:54
    UVC device on android
  • AndroidUSBCamera 使用步骤

    千次阅读 热门讨论 2020-03-10 11:12:21
    1、git下载:https://github.com/jiangdongguo/AndroidUSBCamera 2、下载后解压,将模块 libusbcamera、libutils集成到自已的项目中,直接拷贝到项目根目录下,相关配置 settings.gradle 后添加 , ':libusbcamera'...

    1、git下载:https://github.com/jiangdongguo/AndroidUSBCamera

    2、下载后解压,将模块 libusbcamera、libutils集成到自已的项目中,直接拷贝到项目根目录下,相关配置

    settings.gradle 后添加   , ':libusbcamera', ':libutils'

    app build.gradle 文件   implementation project(':libusbcamera')

    project build.gradle 文件   

    allprojects {
        repositories {
            jcenter()
            google()
            maven { url 'https://jitpack.io' }
            maven { url 'https://raw.githubusercontent.com/saki4510t/libcommon/master/repository/' }
    
        }
    }

    AndroidManifest.xml 文件开启相关权限

        <uses-permission android:name="android.permission.RECORD_AUDIO"/>
        <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
        <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    
        <uses-feature android:name="android.hardware.usb.host"/>

    项目ndk 要设置上 最后项目async

    3、MainActivity

    public class MainActivity extends AppCompatActivity implements CameraViewInterface.Callback {
    
        private final String TAG = MainActivity.class.getSimpleName();
    
        public View mTextureView;
        private UVCCameraHelper mCameraHelper;
        private CameraViewInterface mUVCCameraView;
    
        private boolean isRequest = false;
        private boolean isPreview = false;
        private boolean isRecording = false;
        private UVCCameraHelper.OnMyDevConnectListener listener = new UVCCameraHelper.OnMyDevConnectListener() {
    
            @Override
            public void onAttachDev(UsbDevice device) {
                // request open permission
                Log.d(TAG, "camera: usb 设备 " + device.getProductName() + " 新连接");
                if (mCameraHelper == null || mCameraHelper.getUsbDeviceCount() == 0) {
                    showShortMsg("未检测到USB摄像头设备");
                    return;
                }
                List<UsbDevice> devList = mCameraHelper.getUsbDeviceList();
                /*
                 * usb连接时,判断是不是这个摄像头,是就打开,实现了热插拔,插拔一次,
                 * 设备的id就加一,所以地址就改变,机器重启id初始化,getProductName()获得的是摄像头 
                 * 名称 
                 * */
                if (!isRequest)
                    for (int i = 0; i < devList.size(); i++) {
                        UsbDevice _device = devList.get(i);
                        if (_device.getProductName().indexOf("camera") > -1) {
                            isRequest = true;
                            mCameraHelper.requestPermission(i);//打开usb摄像头
                        }
                    }
            }
    
            @Override
            public void onDettachDev(UsbDevice device) {
                // close camera
                Log.d(TAG, "camera: usb 设备 " + device.getProductName() + " 已拔出");
                if (isRequest) {
                    isRequest = false;
                    mCameraHelper.closeCamera();
                    showShortMsg(device.getProductName() + " 已拨出");
                }
            }
    
            @Override
            public void onConnectDev(UsbDevice device, boolean isConnected) {
                Log.d(TAG, "camera: usb 设备 " + device.getProductName() + " 连接失败");
                if (!isConnected) {
                    showShortMsg("连接失败,请检查分辨率参数是否正确");
                    isPreview = false;
                } else {
                    isPreview = true;
                    showShortMsg("usb 设备正在连接");
                    // need to wait UVCCamera initialize over
                    Log.d(TAG, "camera is connected");
                }
            }
    
            @Override
            public void onDisConnectDev(UsbDevice device) {
                Log.d(TAG, "camera: usb disconnecting");
                showShortMsg("usb设备连接断开");
            }
        };
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            mContext = this;
            // step.1 initialize UVCCameraHelper
            mTextureView = findViewById(R.id.camera_view);
            mUVCCameraView = (CameraViewInterface) mTextureView;
            mUVCCameraView.setCallback(this);
            mCameraHelper = UVCCameraHelper.getInstance();
            mCameraHelper.setDefaultFrameFormat(UVCCameraHelper.FRAME_FORMAT_YUYV);
            /*
             * 初始化分辨率,一定是设备支持的分辨率,否则摄像不能正常使用
             * */
            mCameraHelper.setDefaultPreviewSize(640, 480);
            mCameraHelper.initUSBMonitor(this, mUVCCameraView, listener);
            mCameraHelper.setOnPreviewFrameListener(new AbstractUVCCameraHandler.OnPreViewResultListener() {
                int printNum = 0;
    
                @Override
                public void onPreviewResult(byte[] nv21Yuv) {
                    printNum++;
                    if (printNum == 300) {
                        printNum = 0;
                        Log.d(TAG, "onPreviewResult: " + nv21Yuv.length + "摄像头预览");
                    }
    
                }
            });
        }
    
        //录像
        private void cameraRecording(Boolean isStartRecording, String Name) {
            isRecording = isStartRecording;
            if (mCameraHelper == null || !mCameraHelper.isCameraOpened() || !isPreview) {
                showShortMsg("摄像头异常,请重新更换插口并重启app");
                return;
            }
            String OrderRecordStr = prefs.getString(Config.ORDER_RECORDING, "");
            Log.d(TAG, "OrderRecorde1=" + OrderRecordStr);
            if (!mCameraHelper.isPushing() && isStartRecording) {
                //文件地址自已设置
                String videoPath = Config.VIDEO_DIRECTORY + "/ " + Name;
                OrderRecordStr = OrderRecordStr + "&" + Name;
                prefs.edit().putString(Config.ORDER_RECORDING, OrderRecordStr).apply();
                RecordParams params = new RecordParams();
                params.setRecordPath(videoPath);
                params.setRecordDuration(0);                        // auto divide saved,default 0 means not divided
                params.setVoiceClose(true);    // is close voice
                params.setSupportOverlay(true); // overlay only support armeabi-v7a & arm64-v8a
                mCameraHelper.startPusher(params, new AbstractUVCCameraHandler.OnEncodeResultListener() {
                    @Override
                    public void onEncodeResult(byte[] data, int offset, int length, long timestamp, int type) {
                        // type = 1,h264 video stream
                        if (type == 1) {
                            FileUtils.putFileStream(data, offset, length);
                        }
                        // type = 0,aac audio stream
                        if (type == 0) {
    
                        }
                    }
    
                    @Override
                    public void onRecordResult(String videoPath) {
                        if (TextUtils.isEmpty(videoPath)) {
                            return;
                        }
                        new Handler(getMainLooper()).post(() -> Toast.makeText(MainActivity.this, "save videoPath:" + videoPath, Toast.LENGTH_SHORT).show());
                    }
                });
                // if you only want to push stream,please call like this
                // mCameraHelper.startPusher(listener);
                showShortMsg("开始录制视频");
            } else if (mCameraHelper.isPushing() && !isStartRecording) {
                FileUtils.releaseFile();
                mCameraHelper.stopPusher();
                showShortMsg("停止录制视频");
                String[] OrderRecordArr = OrderRecordStr.split("&");
                if (OrderRecordArr.length > 5) {
                    String order = OrderRecordArr[1];
                    String filePath = Config.VIDEO_DIRECTORY + "/ " + order + ".mp4";
                    deleteFile(filePath);
                    String _OrderRecordStr = "";
                    for (int i = 0; i < OrderRecordArr.length; i++) {
                        if (OrderRecordArr[i] != order && OrderRecordArr[i].length() > 0)
                            _OrderRecordStr = _OrderRecordStr + "&" + OrderRecordArr[i];
                    }
                    prefs.edit().putString(Config.ORDER_RECORDING, _OrderRecordStr).apply();
                    Log.d(TAG, "OrderRecorde=" + prefs.getString(Config.ORDER_RECORDING, ""));
                }
            }
        }
    
        //删除文件
        public boolean deleteFile(String filePath) {
            File file = new File(filePath);
            if (file.isFile() && file.exists()) return file.delete();
            else if (file.isFile() && !file.exists()) return true;
            return false;
        }
        @Override
        public void onResume() {
            super.onResume();
            // 恢复Camera预览
            if (mUVCCameraView != null) mUVCCameraView.onResume();
        }
    
        @Override
        protected void onStart() {
            super.onStart();
            // step.2 register USB event broadcast
            if (mCameraHelper != null) {
                mCameraHelper.registerUSB();
            }
        }
    
        @Override
        protected void onStop() {
            super.onStop();
            // step.3 unregister USB event broadcast
            if (mCameraHelper != null) {
                mCameraHelper.unregisterUSB();
            }
        }
    
        @Override
        protected void onPause() {
            super.onPause();
            
            if (mUVCCameraView != null) mUVCCameraView.onPause();
        }
    
        private void showShortMsg(String msg) {
            Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
        }
    
        @Override
        public USBMonitor getUSBMonitor() {
            return mCameraHelper.getUSBMonitor();
        }
    
        @Override
        public void onDialogResult(boolean canceled) {
    
        }
    
        public boolean isCameraOpened() {
            return mCameraHelper.isCameraOpened();
        }
    
        @Override
        public void onSurfaceCreated(CameraViewInterface view, Surface surface) {
            isPreview = false;
            new Thread(new Runnable() {
                @Override
                public void run() {
                    // wait for camera created
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    Log.d(TAG, "camera: surface start preview " + isPreview + "  " + isCameraOpened());
                    if (!isPreview && isCameraOpened()) {
                        mCameraHelper.startPreview(mUVCCameraView);
                        isPreview = true;
                        Log.d(TAG, "camera: surface start preview");
                    }
                }
            }).start();
        }
    
        @Override
        public void onSurfaceChanged(CameraViewInterface view, Surface surface, int width, int height) {
    
        }
    
        @Override
        public void onSurfaceDestroy(CameraViewInterface view, Surface surface) {
            if (isPreview && isCameraOpened()) {
                mCameraHelper.stopPreview();
                Log.d(TAG, "surface:" + "is destroy");
            }
            isPreview = false;
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            FileUtils.releaseFile();
            // step.4 release uvc camera resources
            if (mCameraHelper != null) {
                mCameraHelper.release();
                Log.d(TAG, "camera is release");
            }
            isPreview = false;
            isRequest = false;
        }
    
    }

    activity_main.xml      

    <com.serenegiant.usb.widget.UVCCameraTextureView
        android:id="@+id/camera_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center"/>

    4、需要注意

    (1)mCameraHelper.requestPermission(int index) 是打开usb设备,有的usb不是摄像头设备,需要对usb设备名称进行过滤,可控制需要打开特定的usb摄像头, 可以热插拔显示

    (2)app关闭或后台运行  isPreview 需要重置为 false 不然再次进入app 预览无画面因为startPreview 未执行

    (3)设备重启后第一次打开app, 预览画面可能没有,但实际是可以录制的,重新进入app就可以了

    展开全文
  • Android-USB-OTG-Camera

    2021-05-10 17:58:45
    AndroidUSBCamera是基于开发的,USB Camera(UVC设备)的项目和视频数据采集的使用都经过高度打包,它可以通过一些简单的API帮助开发人员轻松使用USB Camera设备。 通过使用AndroidUSBCamera,您可以简单地检测并...
  • usb_camera

    2013-12-05 18:57:18
    用于在友善之臂嵌入式板子上跑的usb camera应用程序,从usb camera取出数据然后保存为图片文件并显示在LCD屏幕上
  • Camera-168驱动是一类摄影头驱动,为解决用户摄像头不能正常使用的驱动问题,支持多种型号,具体可参考以下详解,有需要的朋友欢迎下载体验!驱动介绍Camera-168驱动如果不能正常安装,请先删除原来的安装文件或者...
  • AndroidUSBCamera  AndroidUSBCamera is developed based on the saki4510t/UVCCamera, the project of USB Camera (UVC equipment) and the use of video data acquisition are highly packaged, and it can help...
  • Android USB Camera(1) : 调试记录

    万次阅读 热门讨论 2016-11-07 19:00:26
    1. 前言 ...UVC全称是usb video class,一种usb视频规范。所有遵循uvc协议的摄像头都不需要安装额外的驱动,只需要一个通用驱动即可。Linux内核已经集成了uvc驱动,代码路径是kernel-3.10/drivers/med

    1. 前言

    前段时间调试了一个uvc摄像头,这里做下记录。硬件平台为mt6735,软件平台为android 5.0

    2. 底层配置

    UVC全称是usb video class,一种usb视频规范。所有遵循uvc协议的摄像头都不需要安装额外的驱动,只需要一个通用驱动即可。Linux内核已经集成了uvc驱动,代码路径是kernel-3.10/drivers/media/usb/uvc/

    2.1 打开配置

    Linux内核需要打开以下配置来支持uvc设备

    CONFIG_MEDIA_SUPPORT=y
    CONFIG_MEDIA_CAMERA_SUPPORT=y
    CONFIG_VIDEO_DEV=y
    CONFIG_VIDEO_V4L2=y
    CONFIG_VIDEOBUF2_CORE=y
    CONFIG_VIDEOBUF2_MEMOPS=y
    CONFIG_VIDEOBUF2_VMALLOC=y
    CONFIG_MEDIA_USB_SUPPORT=y
    CONFIG_USB_VIDEO_CLASS=y

    MTK平台还需要额外打开otg配置

    CONFIG_USB_MTK_OTG=y 
    CONFIG_USB_MTK_HDRC=y 
    CONFIG_USB_MTK_HDRC_HCD=y

    插入摄像头,如果生成了/dev/video0设备节点,则证明uvc摄像头已经加载成功了。成功生成驱动节点后还需要为它添加权限

    2.2 添加权限

    在uevent.rc中加入

    /dev/video0               0666   root       root

    在system_app.te中加入

    allow system_app video_device:chr_file { read write open getattr };

    2.3 Debug

    如果没有出现/dev/video0节点,需要先判断是否枚举成功。在shell终端cat相关的节点查询

    cat /sys/kernel/debug/usb/devices

    如果该摄像头枚举成功,则能找到对应的设备信息

    T:  Bus=01 Lev=00 Prnt=00 Port=00 Cnt=00 Dev#=1 Spd=480 MxCh=1
    D:  Ver=2.00 Cls=00(>ifc) Sub=00 Prot=00 MxPS=64 #Cfgs=1
    P:  Vendor=18EC ProdID=3399 Rev=0.00
    S:  Manufacturer=ARKMICRO
    S:  Product=USB PC CAMERA

    如果枚举成功则需要判断当前的usb摄像头是不是遵循uvc协议的摄像头。将usb摄像头插到PC上(ubuntu操作系统),通过”lsusb”命令查找是否有视频类接口信息

    lsusb -d 18ec:3399 -v | grep "14 Video"

    如果该摄像头遵循UVC协议,则会输出以下类似信息

    bFunctionClass 14 Video
    bInterfaceClass 14 Video
    bInterfaceClass 14 Video
    bInterfaceClass 14 Video

    其中18ec:3399是摄像头的vid和pid,而14 video代表uvc规范

    2.4 几个比较有用的调试命令

    打开/关闭linux uvc driver log

    echo 0xffff > /sys/module/uvcvideo/parameters/trace //打开
    echo 0 > /sys/module/uvcvideo/parameters/trace //关闭

    获取详细的usb设备描述符

    lsusb -d 18ec:3399 –v

    3. 上层应用

    v4l2 - Video for Linux 2,是Linux内核中关于视频设备的内核驱动框架,为上层的访问底层的视频设备提供了统一的接口。同时是针对uvc免驱usb设备的编程框架,主要用于采集usb摄像头等。

    MTK标准的Camera并没有采用v4l2框架,所以需要在jni层实现基本的v4l2视频采集流程。

    3.1 操作流程

    在v4l2编程中,一般使用ioctl函数来对设备进行操作:

    extern int ioctl (int __fd, unsigned long int __request, …) __THROW;

    __fd:设备的ID,例如用open函数打开/dev/video0后返回的cameraFd;
    __request:具体的命令标志符。
    在进行V4L2开发中,一般会用到以下的命令标志符:
    VIDIOC_REQBUFS:分配内存
    VIDIOC_QUERYBUF:把VIDIOC_REQBUFS中分配的数据缓存转换成物理地址
    VIDIOC_QUERYCAP:查询驱动功能
    VIDIOC_ENUM_FMT:获取当前驱动支持的视频格式
    VIDIOC_S_FMT:设置当前驱动的视频格式
    VIDIOC_G_FMT:读取当前驱动的视频格式
    VIDIOC_TRY_FMT:验证当前驱动的视频格式
    VIDIOC_CROPCAP:查询驱动的修剪能力
    VIDIOC_S_CROP:设置视频信号的边框
    VIDIOC_G_CROP:读取视频信号的边框
    VIDIOC_QBUF:把数据放回缓存队列
    VIDIOC_DQBUF:把数据从缓存中读取出来
    VIDIOC_STREAMON:开始视频采集
    VIDIOC_STREAMOFF:结束视频采集
    VIDIOC_QUERYSTD:检查当前视频设备支持的标准,例如PAL或NTSC。
    这些IO调用,有些是必须的,有些是可选择的。

    在网上有开源的应用simplewebcam,它已经实现了基本的v4l2视频采集流程。大概看下它是怎么做的

    操作流程

    v4l2

    3.2 具体代码实现

    (1) 打开设备驱动节点

    int opendevice(int i)
    {
        struct stat st;
    
        sprintf(dev_name,"/dev/video%d",i);
    
        if (-1 == stat (dev_name, &st)) {
            LOGE("Cannot identify '%s': %d, %s", dev_name, errno, strerror (errno));
            return ERROR_LOCAL;
        }
    
        if (!S_ISCHR (st.st_mode)) {
            LOGE("%s is no device", dev_name);
            return ERROR_LOCAL;
        }
    
        fd = open (dev_name, O_RDWR);
    
        if (-1 == fd) {
            LOGE("Cannot open '%s': %d, %s", dev_name, errno, strerror (errno));
            return ERROR_LOCAL;
        }
        return SUCCESS_LOCAL;
    }

    (2) 查询驱动功能

    int initdevice(void) 
    {
        struct v4l2_capability cap;
        struct v4l2_format fmt;
        unsigned int min;
    
        if (-1 == xioctl (fd, VIDIOC_QUERYCAP, &cap)) {
            if (EINVAL == errno) {
                LOGE("%s is no V4L2 device", dev_name);
                return ERROR_LOCAL;
            } else {
                return errnoexit ("VIDIOC_QUERYCAP");
            }
        }
    
        if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {
            LOGE("%s is no video capture device", dev_name);
            return ERROR_LOCAL;
        }
    
        if (!(cap.capabilities & V4L2_CAP_STREAMING)) {
            LOGE("%s does not support streaming i/o", dev_name);
            return ERROR_LOCAL;
        }
    
        ......
    
    }

    (3) 设置视频格式

    int initdevice(void) 
    {
        struct v4l2_capability cap;
        struct v4l2_format fmt;
    
        ......
    
        CLEAR (fmt);
        fmt.type                = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        fmt.fmt.pix.width       = IMG_WIDTH; 
        fmt.fmt.pix.height      = IMG_HEIGHT;
        fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG;
    
        if (-1 == xioctl (fd, VIDIOC_S_FMT, &fmt))
            return errnoexit ("VIDIOC_S_FMT");
    
        ......
    }

    (4) 申请帧缓存并映射到用户空间

    int initmmap(void)
    {
        struct v4l2_requestbuffers req;
    
        CLEAR (req);
        req.count               = 4;
        req.type                = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        req.memory              = V4L2_MEMORY_MMAP;
    
        if (-1 == xioctl (fd, VIDIOC_REQBUFS, &req)) {
            if (EINVAL == errno) {
                LOGE("%s does not support memory mapping", dev_name);
                return ERROR_LOCAL;
            } else {
                return errnoexit ("VIDIOC_REQBUFS");
            }
        }
    
        if (req.count < 2) {
            LOGE("Insufficient buffer memory on %s", dev_name);
            return ERROR_LOCAL;
        }
    
        buffers = calloc (req.count, sizeof (*buffers));
    
        if (!buffers) {
            LOGE("Out of memory");
            return ERROR_LOCAL;
        }
    
        for (n_buffers = 0; n_buffers < req.count; ++n_buffers) {
            struct v4l2_buffer buf;
    
            CLEAR (buf);
            buf.type        = V4L2_BUF_TYPE_VIDEO_CAPTURE;
            buf.memory      = V4L2_MEMORY_MMAP;
            buf.index       = n_buffers;
    
            if (-1 == xioctl (fd, VIDIOC_QUERYBUF, &buf))
                return errnoexit ("VIDIOC_QUERYBUF");
    
            buffers[n_buffers].length = buf.length;
            buffers[n_buffers].start =
            mmap (NULL ,
                buf.length,
                PROT_READ | PROT_WRITE,
                MAP_SHARED,
                fd, buf.m.offset);
    
            if (MAP_FAILED == buffers[n_buffers].start)
                return errnoexit ("mmap");
        }
    
        return SUCCESS_LOCAL;
    }

    (5) 将帧缓存加入缓存队列并启动视频采集

    int startcapturing(void)
    {
        unsigned int i;
        struct v4l2_buffer buf;
        enum v4l2_buf_type type;
    
        for (i = 0; i < n_buffers; ++i) {
            CLEAR (buf);
            buf.type        = V4L2_BUF_TYPE_VIDEO_CAPTURE;
            buf.memory      = V4L2_MEMORY_MMAP;
            buf.index       = i;
    
            if (-1 == xioctl (fd, VIDIOC_QBUF, &buf))
                return errnoexit ("VIDIOC_QBUF");
        }
    
        type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        if (-1 == xioctl (fd, VIDIOC_STREAMON, &type))
            return errnoexit ("VIDIOC_STREAMON");
    
        return SUCCESS_LOCAL;
    }

    (6) 从缓存队列中取出一帧

    int readframeonce(void)
    {
        for (;;) {
            fd_set fds;
            struct timeval tv;
            int r;
    
            FD_ZERO (&fds);
            FD_SET (fd, &fds);
    
            tv.tv_sec = 2;
            tv.tv_usec = 0;
    
            r = select (fd + 1, &fds, NULL, NULL, &tv);
    
            if (-1 == r) {
                if (EINTR == errno)
                    continue;
    
                return errnoexit ("select");
            }
    
            if (0 == r) {
                LOGE("select timeout");
                return ERROR_LOCAL;
    
            }
    
            if (readframe ()==1)
                break;
    
        }
    
        return realImageSize;
    
    }
    int readframe(void)
    {
        struct v4l2_buffer buf;
        unsigned int i;
    
        CLEAR (buf);
    
        buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        buf.memory = V4L2_MEMORY_MMAP;
    
        if (-1 == xioctl (fd, VIDIOC_DQBUF, &buf)) {
            switch (errno) {
                case EAGAIN:
                    return 0;
                case EIO:
                default:
                    return errnoexit ("VIDIOC_DQBUF");
            }
        }
    
        assert (buf.index < n_buffers);
    
        convert2JPEG(buffers[buf.index].start, buf.bytesused);
    
        if (-1 == xioctl (fd, VIDIOC_QBUF, &buf))
            return errnoexit ("VIDIOC_QBUF");
    
        return 1;
    }

    4. 解码mjpeg格式

    我所使用的usb摄像头是mjpeg格式,而从网上下载的simplewebcam应用只支持yuyv格式,所以需要重写解码模块。

    4.1 jni层 - 插入huffman表

    安卓自带的libjpeg解码库只能解码jpeg格式。而mjpeg格式需要在v4l2读出的帧中找到SOF0(Start Of Frame 0),插入huffman表后就可以用libjpeg库解码成rgb。

    static int convert2JPEG(const void *p, int size)
    {
        char *mjpgBuf = NULL;
    
        if (pImageBuf == NULL) {
            return errnoexit("pImageBuf isn't initialized in JNI");
        }
    
        /* Clear pImageBuf and realImageSize */
        memset(pImageBuf, 0, (IMG_WIDTH*IMG_HEIGHT)*2);
        realImageSize = 0;
    
        /* insert dht data to p, and then save them to pImageBuf */
        realImageSize = insert_huffman(p, size, pImageBuf);
    
        return SUCCESS_LOCAL;
    }
    
    static int insert_huffman(const void *in_buf, int buf_size, void *out_buf) 
    {
        int pos = 0;
        int size_start = 0;   
        char *pcur = (char *)in_buf;    
        char *pdeb = (char *)in_buf;   
        char *plimit = (char *)in_buf + buf_size;    
        char *jpeg_buf = (char *)out_buf;    
    
        /* find the SOF0(Start Of Frame 0) of JPEG */    
        while ( (((pcur[0] << 8) | pcur[1]) != 0xffc0) && (pcur < plimit) ){ 
            pcur++;
        }
    
        LOGD("pcur: 0x%x, plimit: 0x%x", pcur, plimit);
    
        /* SOF0 of JPEG exist */
        if (pcur < plimit){
            if (jpeg_buf != NULL)
            {
                /* insert huffman table after SOF0 */
                size_start = pcur - pdeb;
                memcpy(jpeg_buf, in_buf, size_start);
                pos += size_start;
                memcpy(jpeg_buf + pos, dht_data, sizeof(dht_data));
                pos += sizeof(dht_data);
                memcpy(jpeg_buf + pos, pcur, buf_size - size_start);
                pos += buf_size - size_start;
                return pos;
            }
        } else{
            LOGE("SOF0 does not exist");
        }
        return 0;
    }
    
    const static unsigned char dht_data[] = {
        0xff, 0xc4, 0x01, 0xa2, 0x00, 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01,
        0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02,
        0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x01, 0x00, 0x03,
        0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
        0x0a, 0x0b, 0x10, 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03, 0x05,
        0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7d, 0x01, 0x02, 0x03, 0x00, 0x04,
        0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, 0x22,
        0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, 0x23, 0x42, 0xb1, 0xc1, 0x15,
        0x52, 0xd1, 0xf0, 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, 0x17,
        0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x34, 0x35, 0x36,
        0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a,
        0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66,
        0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a,
        0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95,
        0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8,
        0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2,
        0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5,
        0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
        0xe8, 0xe9, 0xea, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9,
        0xfa, 0x11, 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, 0x07, 0x05,
        0x04, 0x04, 0x00, 0x01, 0x02, 0x77, 0x00, 0x01, 0x02, 0x03, 0x11, 0x04,
        0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, 0x13, 0x22,
        0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33,
        0x52, 0xf0, 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25,
        0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36,
        0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a,
        0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66,
        0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a,
        0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94,
        0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
        0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba,
        0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
        0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
        0xe8, 0xe9, 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa
    };

    第28-31行,找到SOF0所在的位置,并让pcur指向它
    第39-47行,在SOF0所在的位置之后插入huffman表,也就是dht_data数组。可被libjpeg解码的图像最终保存在pImageBuf中

    4.2 jave层 - 解码并显示

    jni层把图像保存在pImageBuf,这个buffer对应java层的mImageBuffer。Jave层获取到图像之后调用BitmapFactory.decodeByteArray进行解码,并通过Canvas显示图像

    @Override
    public void run() {
        while (true && cameraExists) {
    
            ......
    
            imageSize = processCamera();
            if(imageSize == -1 || imageSize == 0)
                continue;
    
            bmp = BitmapFactory.decodeByteArray(mImageBuffer.array(), mImageBuffer.arrayOffset(), imageSize);
            if(bmp == null)
                continue;
    
            Canvas canvas = getHolder().lockCanvas();
            if (canvas != null)
            {
                // draw camera bmp on canvas
                canvas.drawBitmap(bmp,null,rect,null);
                getHolder().unlockCanvasAndPost(canvas);
            }
        }
    }

    5. 总结

    底层配置,只需要使能otg功能并把uvc相关的配置宏打开,插入设备后生成了/dev/videoX设备节点则说明usb摄像头枚举并初始化成功了

    上层应用,采用网上的开源应用simplewebcam,这个应用只支持yuyv格式,所以需要重写解码模块。需要在数据帧中手动插入huffman表之后,才能用android的libjpeg库来解码mjpeg格式

    另外,在调试过程中出现了”uvcvideo: Non-zero status (-71) in video completion handler”这样的log,那是因为mt6735平台的usb host controller对iso端点的支持不太好,经常出现丢包现象,这个问题需要打上mtk提供的patch才能解决问题

    展开全文
  • Linux下USB Camera的使用

    千次阅读 2020-06-02 10:35:29
    Linux下USB Camera的使用查看摄像头usb信息查看video设备文件查看camera信息查看系统能否识别出camera通过luvcview查看安装luvcview查看视频opencv c++读取usb camera数据参考 支持yuv协议的camera通过usb连接上电脑...

    支持yuv协议的camera通过usb连接上电脑,可进行如下操作:

    查看摄像头usb信息

    lsusb
    

    Bus 001 Device 007: ID 0c45:130c Microdia
    Bus 001 Device 005: ID 0c45:310a Microdia

    查看video设备文件

    进入/dev/下查看是否有video设备文件

    cd /dev
    ls | grep video
    

    将会输出类似如下信息:
    video0
    video1

    查看camera信息

    udevadm info --query=all --name=/dev/video0
    

    将会输出如下信息:
    在这里插入图片描述

    查看系统能否识别出camera

    dmesg | grep Cam
    dmesg | grep video
    

    将会输出如下信息:
    在这里插入图片描述

    通过luvcview查看

    安装luvcview

    https://launchpad.net/ubuntu/trusty/+package/luvcview下载amd64的luvcview_0.2.6-6_amd64.deb安装包

    sudo dpkg -i luvcview_0.2.6-6_amd64.deb
    

    查看视频

    luvcview -d /dev/video0 -f yuv -s 640x480
    

    opencv c++读取usb camera数据

    https://github.com/lxuejiao/USBCamera

    参考

    https://blog.csdn.net/liwf616/article/details/8784361
    https://launchpad.net/ubuntu/trusty/+package/luvcview

    展开全文
  • AndroidUSBCamera基于[saki4510t/UVCCamera](https://github.com/saki4510t/UVCCamera)开发,该项目对USB Camera(UVC设备)的使用和视频数据采集进行了高度封装,能够帮助开发者通过几个简单的API实现USB Camera设备...

        AndroidUSBCamera基于[saki4510t/UVCCamera](https://github.com/saki4510t/UVCCamera)开发,该项目对USB Camera(UVC设备)的使用和视频数据采集进行了高度封装,能够帮助开发者通过几个简单的API实现USB Camera设备的检测、连接、预览和音视频数据采集,最重要的是手机无需root,只需支持otg功能即可驱动。主要功能包括:  

    (1)支持USB Camera设备检测,画面实时预览;  
    (2)支持本地录制mp4格式视频,支持实时获取音视频数据流;  
    (3)支持jpg格式图片抓拍;  
    (4)支持获取camera支持的分辨率,和分辨率切换;  
    (5)支持屏蔽声音,重启Camera; 
    (6)支持相机自动对焦;  

    (7)支持调整对比度和亮度

    (8) 支持480P、720P、1080P and higher

    (9) 支持Android5.0,6.0,7.0,8.0,9.0


    如何使用AndroidUSBCamera项目 


    1. 添加依赖到本地工程
      
    第一步 添加JitPack仓库到工程gradle  
    Step 1. Add the JitPack repository to your build file
    Add it in your root build.gradle at the end of repositories:

     

    allprojects {
    repositories {
    ...
    maven { url 'http://raw.github.com/saki4510t/libcommon/master/repository/' }
    maven { url 'https://jitpack.io' }
    }
    }


    第二步 添加依赖到app Module的gradle   
    Step 2. Add the dependency  

     

     

     

    dependencies {
    compile 'com.github.jiangdongguo:AndroidUSBCamera:1.3.8'
    } 
    

     

    注:最新版为2,3,0

     

     2. 初始化引擎,注册USB设备事件监听器  
      Init AndroidUSBCamera engine,register the USB device event listener  
      

       private USBCameraManager.OnMyDevConnectListener listener = new USBCameraManager.OnMyDevConnectListener() {
            // 插入USB设备
            @Override
            public void onAttachDev(UsbDevice device) {
                if(mUSBManager == null || mUSBManager.getUsbDeviceCount() == 0){
                    showShortMsg("未检测到USB摄像头设备");
                    return;
                }
                // 请求打开摄像头
                if(! isRequest){
                    isRequest = true;
                    if(mUSBManager != null){
                        mUSBManager.requestPermission(0);
                    }
                }
            }
    
    
            // 拔出USB设备
            @Override
            public void onDettachDev(UsbDevice device) {
                if(isRequest){
                    // 关闭摄像头
                    isRequest = false;
                    mUSBManager.closeCamera();
                    showShortMsg(device.getDeviceName()+"已拨出");
                }
            }
    
    
            // 连接USB设备成功
            @Override
            public void onConnectDev(UsbDevice device,boolean isConnected) {
                if(! isConnected) {
                    showShortMsg("连接失败,请检查分辨率参数是否正确");
                    isPreview = false;
                }else{
                    isPreview = true;
                }
            }
    
    
            // 与USB设备断开连接
            @Override
            public void onDisConnectDev(UsbDevice device) {
                showShortMsg("连接失败");
            }
        };
        
        mUVCCameraView = (CameraViewInterface) mTextureView;
        mUVCCameraView.setCallback(new CameraViewInterface.Callback() {
            @Override
            public void onSurfaceCreated(CameraViewInterface view, Surface surface) {
                if(!isPreview && mUSBManager.isCameraOpened()) {
                     mUSBManager.startPreview(mUVCCameraView, new AbstractUVCCameraHandler.OnPreViewResultListener() {
                     @Override
                     public void onPreviewResult(boolean result) {
    
    
                     }
                  });
                  isPreview = true;
                  }
             }
                @Override
                public void onSurfaceChanged(CameraViewInterface view, Surface surface, int width, int height) {
    
    
                }
    
    
                @Override
                public void onSurfaceDestroy(CameraViewInterface view, Surface surface) {
                    if(isPreview && mUSBManager.isCameraOpened()) {
                        mUSBManager.stopPreview();
                        isPreview = false;
                    }
                }
            });
            // 初始化引擎
            mUSBManager = USBCameraManager.getInstance();
            mUSBManager.initUSBMonitor(this,listener);
            mUSBManager.createUVCCamera(mUVCCameraView);


    3. 注册USB设备广播事件监听器,开始Camera预览  
      Register the USB device broadcast event listener and start the Camera Preview

     

     

     

    // 注册USB事件广播监听器
    if(mUSBManager != null){
          mUSBManager.registerUSB();
    }
    // 恢复Camera预览
     if(mUVCCameraView != null){
          mUVCCameraView.onResume();
     }

     


    4. 注销USB设备广播事件监听器,停止Camera预览  
      Unregister the USB device broadcast event listener and stop the Camera Preview

     

     

     

     

    // 注销USB事件广播监听器
     if(mUSBManager != null){
             mUSBManager.unregisterUSB();
      }
     // 暂停Camera预览
     if(mUVCCameraView != null){
             mUVCCameraView.onPause();
     }

     


     5. 图片抓拍
      Picture capturing

     

     

     

     

    if(mUSBManager == null || ! mUSBManager.isCameraOpened()){
              showShortMsg("抓拍异常,摄像头未开启");
              return;
     }
     mUSBManager.capturePicture(picPath, new AbstractUVCCameraHandler.OnCaptureListener() {
              @Override
              public void onCaptureResult(String path) {
                   showShortMsg("保存路径:"+path);
              }
     });

     


    6. 本地录制(可实时获取音视频数据流)
       recoring mp4,and get media real-stream  
       

     

     

     

    if(mUSBManager == null || ! mUSBManager.isCameraOpened()){
               showShortMsg("录制异常,摄像头未开启");
               return;
     }
    if(! mUSBManager.isRecording()){
                        String videoPath = USBCameraManager.ROOT_PATH+System.currentTimeMillis();
                        FileUtils.createfile(FileUtils.ROOT_PATH+"test666.h264");
                        RecordParams params = new RecordParams();
                        params.setRecordPath(videoPath);
                        params.setRecordDuration(0);    // 设置为0,不分割保存
                        params.setVoiceClose(false);    // 不屏蔽声音
                        mUSBManager.startRecording(params, new AbstractUVCCameraHandler.OnEncodeResultListener() {
                            @Override
                            public void onEncodeResult(byte[] data, int offset, int length, long timestamp, int type) {
                                // type = 0,aac格式音频流
                                // type = 1,h264格式视频流
                                if(type == 1){
                                    FileUtils.putFileStream(data,offset,length);
                                }
                            }
    
    
                            @Override
                            public void onRecordResult(String videoPath) {
                                showShortMsg(videoPath);
                            }
                        });
    // 停止录制
    mUSBManager.stopRecording();


    7. 切换分辨率
      update Resulotion  
        

     

    mUSBManager.updateResolution(this, mUVCCameraView, 320, 240, new USBCameraManager.OnPreviewListener() {
                 @Override
                 public void onPreviewResult(boolean isSuccess) {
                        if(! isSuccess) {
                                showShortMsg("预览失败,不支持该分辨率");
                            }else {
                                showShortMsg("以切换到分辨率为320x240");
                            }
                        }
          });  
     // 获取Camera支持得分辨率  
     List<Size> list = mUSBManager.getSupportedPreviewSizes();
     // Camera自动对焦  
     mUSBManager.startCameraFoucs();


    8. 释放引擎资源
      release resource  

     

    // 释放资源
    if(mUSBManager != null){
           mUSBManager.release();
     }

    9. 添加权限
      add permissions  
       

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.RECORD_AUDIO" />


    USBCameraManager  API (Other)

     

    (1) void requestPermission(int index):请求授予开启USB摄像头权限;
    (2) int getUsbDeviceCount():返回查询到的可用USB Camera数目;
    (3) boolean isRecording():判断是否正在录制视频;
    (4) boolean isCameraOpened():判断USB摄像头是否正常打开;
    (5) void release():释放资源
    (6) USBMonitor getUSBMonitor():返回USBMonitor实例;
    (7) mUSBManager.setModelValue(USBCameraManager.MODE_CONTRAST,contrast++); 调整对比度
    (8) mUSBManager.setModelValue(USBCameraManager.MODE_BRIGHTNESS,brightness++);调整亮度

     

     

     

     

     

    注:在使用Android Studio移植UVCCamera时,很多朋友可能会遇到"open(“/dev/bus/usb/001/002”, O_RDWR, 0),报错,Permission denied"问题,这是由于Android Studio使用的ndk版本所致,建议使用ndk-r14即可。解决方法:local.properties-->指定ndk.dir版本。(注:这里使用的是离线方式)

     

    最新版为2.3.0,更新时间为2019年6月17日,使用方法请移步Github项目

     

     

    GitHub源码地址:https://github.com/jiangdongguo/AndroidUSBCamera(如果对您有用,欢迎star&fork以表支持~谢谢^_^!)

     

    Download APK

     In order to display the functions, I develop a simple released apk,which is based on version 2.3.1,and the build version is 28.0.3.Here is my configs and if you have any questions please issues to me ,I will follow it do my best.

    ext {
        javaSourceCompatibility = JavaVersion.VERSION_1_8
        javaTargetCompatibility = JavaVersion.VERSION_1_8
        compileSdkVersion = 28
        buildToolsVersion = '28.0.3'
        minSdkVersion = 21
        targetSdkVersion = 28
        commonLibVersion= '2.12.4'
    }
    

    下载APP:  安装密码 12345678

    displaying:

     

     

    展开全文
  • 我采用的是<a href="https://github.com/jiangdongguo/AndroidUSBCamera">https://github.com/jiangdongguo/AndroidUSBCamera</a>这位博主的项目源码,编译成功后在安卓9手机上可以运行,但在安卓10及...
  • linux usb-camera 应用

    2018-05-14 10:16:56
    linux usb-camera 应用开发,内附详细说明,值得下载喔!
  • [USBCamera]驱动安装与使用

    千次阅读 2015-07-11 00:15:51
    试用过程:直接插上笔记本的USB接口,Win7弹出自动查找驱动的对话框,但未能进行自动安装,但给出了驱动的下载地址,于是下载和安装了驱动,驱动压缩包名字为DRV_VC0305_VA6241_50hz。解压缩后并未找到Win7的文件夹...
  • 转 自: https://blog.csdn.net/AndrExpert/article/details/78324181 Android直播开发之旅(10):AndroidUSBCamera,UVCCamera开发通用库...
  • pccamera驱动适合绝大多少的摄像头,但某些品牌摄像头特有的功能无法使用。不过对于一些杂牌厂商出产的摄像头也可以在本站按具体型号搜索。pccamera驱动相关介绍本...pccamera驱动安装方法操作pda手机,欢迎下载体验
  • [ROS] 安装 USB Camera 驱动并调用

    千次阅读 2019-05-18 07:47:00
    在 ROS 系统中,想要使用 USB 摄像头需要安装相应的驱动程序。这里以常用的 usb_cam 为例来说明如何安装给 ROS 安装 USB 摄像头。 0、安装环境: Ubuntu版本:14.04 LTS ROS版本:indigo (1.11.13) 1、进入ROS工作...
  • Android USB 摄像头 Camera

    2017-10-31 10:52:59
    android 调用 USB 摄像头, 运到预览画面黑屏,参考https://bitbucket.org/neuralassembly/simplewebcam/src 对源码进行了 优化处理
  • 另外有个UsbWebCamera的app,直接无视权限就能启用otg usb cam。可惜没找到源码。 ——————-Opencv Mat 与Java Bitmap转换——————— Mat src = new Mat() ; Utils .bitmapToMat (bmp, src) ; ...
  • ubuntu16.04 安装usb-camera

    2021-03-12 15:38:28
    ubutun16.04 安装usb-camera E: Unable to locate package ros-kinetic-usb-cam 1 sudo sh -c 'echo "deb http://packages.ros.org/ros/ubuntu $(lsb_release -sc) main" > /etc/apt/sources.list.d/ros-latest....
  • AndroidUSBCamera是基于开发的,USB Camera(UVC设备)的项目和视频数据采集的使用都经过高度打包,它可以通过一些简单的API帮助开发人员轻松使用USB Camera设备。 通过使用AndroidUSBCamera,您可以简单地检测并...
  • deltavision usb camera   一 Tengine安装  下载Tengine代码: https://github.com/OAID/Tengine  安装文档:doc/install.md  1. 依赖库 caffe依赖库 sudo apt install libprotobu...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 7,780
精华内容 3,112
关键字:

usbcamera下载