美文网首页
【安卓相关】安卓外置USB相机开发 ( UVC )

【安卓相关】安卓外置USB相机开发 ( UVC )

作者: norkm | 来源:发表于2021-01-16 10:13 被阅读0次

    近期在做物联网设备的开发,上位机是安卓一体机,有需要连接多个外置USB相机的录像和拍照的需要,记录一下,希望可以帮到有缘人。

    首先你的安卓设备需要支持UVC协议 ( 一种为USB视频捕获设备定义的协议标准 )

    如果需要使用多个摄像头的话,我这边的方案是使用 HUB 将多个USB摄像头连接起来,也就是这个。


    连接多个摄像头后,如何区分各个摄像头呢,每一个USB device 有一个pid或者vid 参数,也就是产品id和版本id 吧。

    android.hardware.usb.UsbDevice
    如图所示:

    image.png

    这个PID可以找摄像头厂家定制,或者找厂家给你烧录工具和烧录文件,自己去烧录,这样使用的时候按照PID进行安装。

    现在开始部署吧

    首先我使用的是这个库
    https://github.com/jiangdongguo/AndroidUSBCamera

    build.gradle

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

    saki4510t 构建的时候 如果出现 这个错误的话

    Could not resolve com.serenegiant:common:2.12.4

    可以改成 liuchaoya 这个试试

    maven { url 'https://gitee.com/liuchaoya/libcommon/raw/master/repository/' }
    



    接下来是 dependencies

    implementation 'com.github.jiangdongguo:AndroidUSBCamera:2.3.1'
    



    使用

    我这里写一个基于该库,使用uvc相机来录制视频的demo吧。

    布局文件

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context=".UVCCameraActivity">
        <com.serenegiant.usb.widget.UVCCameraTextureView
            android:id="@+id/textureView"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1"
            android:layout_gravity="center"/>
        <EditText
            android:id="@+id/cameraNumber"
            android:text="1"
            android:inputType="number"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"/>
        <Button
            android:onClick="StartAndStop"
            android:text="录制 / 停止"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"/>
    </LinearLayout>
    

    Activity

    
    import android.hardware.usb.UsbDevice;
    import android.os.Bundle;
    import android.os.Environment;
    import android.os.Looper;
    import android.support.v7.app.AppCompatActivity;
    import android.text.Editable;
    import android.text.TextUtils;
    import android.text.TextWatcher;
    import android.util.Log;
    import android.view.Surface;
    import android.view.View;
    import android.widget.EditText;
    import android.widget.Toast;
    
    import com.fenfeneco.recycle.util.AndroidDeviceSDK;
    import com.fenfeneco.recycle.util.UvcUtil;
    import com.jiangdg.usbcamera.UVCCameraHelper;
    import com.jiangdg.usbcamera.utils.FileUtils;
    import com.serenegiant.usb.common.AbstractUVCCameraHandler;
    import com.serenegiant.usb.encoder.RecordParams;
    import com.serenegiant.usb.widget.CameraViewInterface;
    import com.serenegiant.usb.widget.UVCCameraTextureView;
    
    import java.io.File;
    
    public class UVCCameraActivity extends AppCompatActivity{
        public static boolean isRequest;
        public static boolean isPreview;
        private UVCCameraHelper mCameraHelper;
        private UVCCameraTextureView uvcCameraTextureView;
        private final static String TAG = "UVC相机";
        private EditText cameraNumber;
    
        int nowCamera = 4;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_uvc_camera);
            AndroidDeviceSDK.hideStatus(this,false);
    
    
            cameraNumber = findViewById(R.id.cameraNumber);
            cameraNumber.addTextChangedListener(new TextWatcher() {
                @Override
                public void beforeTextChanged(CharSequence s, int start, int count, int after) {
    
                }
    
                @Override
                public void onTextChanged(CharSequence s, int start, int before, int count) {
    
                }
    
                @Override
                public void afterTextChanged(Editable s) {
                    if(!TextUtils.isEmpty(s)){
                        int number = Integer.parseInt(s.toString());
    
                        //  切换摄像头
                        mCameraHelper.closeCamera();
                        requestCamera(number);
                    }
                }
            });
    
    
            uvcCameraTextureView = findViewById(R.id.textureView);
            CameraViewInterface mUVCCameraView = (CameraViewInterface) uvcCameraTextureView;
            //  设置 UVC 预览界面回调
            mUVCCameraView.setCallback(new CameraViewInterface.Callback() {
                @Override
                public void onSurfaceCreated(CameraViewInterface view, Surface surface) {
                    Log.i(TAG,"画面创建");
                }
    
                @Override
                public void onSurfaceChanged(CameraViewInterface view, Surface surface, int width, int height) {
                    Log.i(TAG,"画面改变");
                }
    
                @Override
                public void onSurfaceDestroy(CameraViewInterface view, Surface surface) {
                    Log.i(TAG,"画面销毁");
                }
            });
            mCameraHelper = UVCCameraHelper.getInstance();
            mCameraHelper.setDefaultPreviewSize(640,480);
            // 设置默认帧格式,默认格式为 UVCCameraHelper.Frame_FORMAT_MPEG
            // 如果 Frame_FORMAT_MPEG 模式不能使用,可以尝试 YUYV
            // mCameraHelper.setDefaultFrameFormat(UVCCameraHelper.FRAME_FORMAT_YUYV);
            mCameraHelper.initUSBMonitor(this, mUVCCameraView, new UVCCameraHelper.OnMyDevConnectListener() {
                @Override
                public void onAttachDev(UsbDevice device) {
                    // 插拔的时候会触发
                    Log.i(TAG,"插拔扫描到的设备 (ID) :" + device.getProductId());
                }
    
                @Override
                public void onDettachDev(UsbDevice device) {
                    // 关闭相机
                    if (isRequest) {
                        isRequest = false;
                        mCameraHelper.closeCamera();
    
                        //  USB 相机被拔出
                        Log.i(TAG,"被拔出");
                    }
                }
    
                @Override
                public void onConnectDev(UsbDevice device, boolean isConnected) {
    
                    Log.i(TAG,"连接成功,结果:" + isConnected);
    
                    if (!isConnected) {
                        //  连接失败,检测连接参数
                        isPreview = false;
                    } else {
                        isPreview = true;
                        //  连接成功
                        // 等待 UVC 初始化成功
    
                    }
                }
    
                @Override
                public void onDisConnectDev(UsbDevice device) {
                    //  设备被断开
                    Log.i(TAG,"设备断开");
                }
            });
    
            mCameraHelper.registerUSB();
    
            //  寻找第一个可用的USB相机
            requestCamera(nowCamera);
        }
    
        private void requestCamera(int index){
            //  寻找第一个可用的USB相机
            for(int i = 0 ; i < mCameraHelper.getUsbDeviceList().size();i++){
                Log.i(TAG,"扫描到摄像头" + mCameraHelper.getUsbDeviceList().get(i).getProductId());
    
                if(mCameraHelper.getUsbDeviceList().get(i).getProductId() == UvcUtil.doorNumberToPid(index)){
                        Log.i(TAG,"找到了第一个相机");
    
                        mCameraHelper.requestPermission(i);
    
                        return;
                }
            }
        }
    
    
    
        //  开始或停止
        public void StartAndStop(View view){
            //  如果没有开始录制
            if (!mCameraHelper.isPushing()) {
    
                String videoPath = Environment.getExternalStorageDirectory() + File.separator + System.currentTimeMillis() + UVCCameraHelper.SUFFIX_MP4;
                
                // 录制的一些参数
                RecordParams params = new RecordParams();
                params.setRecordPath(videoPath);
                params.setRecordDuration(0);
                params.setVoiceClose(true);
    
                //  开始录制
                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) {
                            //  FileUtils.createfile(FileUtils.ROOT_PATH + "test666.h264");
                        }
                    }
    
                    @Override
                    public void onRecordResult(String videoPath) {
                        if(TextUtils.isEmpty(videoPath)) {
                            return;
                        }
                        Toast.makeText(UVCCameraActivity.this,"录制结束,视频地址" + videoPath,Toast.LENGTH_LONG ).show();
                    }
                });
                // 如果只想推送视频流
                // mCameraHelper.startPusher(listener);
                Toast.makeText(this, "开始录制", Toast.LENGTH_SHORT).show();
            } else {
                FileUtils.releaseFile();
                mCameraHelper.stopPusher();
                Toast.makeText(this, "停止录制", Toast.LENGTH_SHORT).show();
            }
        }
    
    }
    

    缺少 UvcUtil 这个类大家不用管,只是根据我自身业务写的一个序号和pid转换类。

    相关文章

      网友评论

          本文标题:【安卓相关】安卓外置USB相机开发 ( UVC )

          本文链接:https://www.haomeiwen.com/subject/zhnmaktx.html