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就可以了

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐