├── .gitignore ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── test │ │ └── lgh │ │ └── com │ │ └── uvccameraproject │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── lgh │ │ │ └── test │ │ │ ├── ImageActivity.java │ │ │ ├── MyApplication.java │ │ │ └── UVCCameraActivity.java │ └── res │ │ ├── layout │ │ ├── activity_image.xml │ │ ├── activity_main.xml │ │ └── activity_uvc_camera.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_round.png │ │ └── ic_take_picture.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_round.png │ │ └── ic_take_picture.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ └── values │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── test │ └── lgh │ └── com │ └── uvccameraproject │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle └── uvccamerasdk ├── .gitignore ├── build.gradle ├── libs ├── armeabi-v7a │ ├── libUVCCamera.so │ ├── libjpeg-turbo1500.so │ ├── libusb100.so │ └── libuvc.so └── armeabi │ ├── libUVCCamera.so │ ├── libjpeg-turbo1500.so │ ├── libusb100.so │ └── libuvc.so ├── proguard-rules.pro └── src ├── androidTest └── java │ └── com │ └── lgh │ └── uvccamera │ └── ExampleInstrumentedTest.java ├── main ├── AndroidManifest.xml ├── java │ └── com │ │ ├── lgh │ │ └── uvccamera │ │ │ ├── IUVCCamera.java │ │ │ ├── UVCCameraProxy.java │ │ │ ├── bean │ │ │ └── PicturePath.java │ │ │ ├── callback │ │ │ ├── ConnectCallback.java │ │ │ ├── PhotographCallback.java │ │ │ ├── PictureCallback.java │ │ │ └── PreviewCallback.java │ │ │ ├── config │ │ │ └── CameraConfig.java │ │ │ ├── usb │ │ │ ├── IMonitor.java │ │ │ ├── UsbController.java │ │ │ └── UsbMonitor.java │ │ │ └── utils │ │ │ ├── FileUtil.java │ │ │ ├── ImageUtil.java │ │ │ ├── LogUtil.java │ │ │ └── RxUtil.java │ │ └── serenegiant │ │ └── usb │ │ ├── IButtonCallback.java │ │ ├── IFrameCallback.java │ │ ├── IStatusCallback.java │ │ ├── Size.java │ │ └── UVCCamera.java └── res │ └── values │ └── strings.xml └── test └── java └── com └── lgh └── uvccamera └── ExampleUnitTest.java /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | .externalNativeBuild 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AndroidUVCCamera 2 | 最近在做一个外接USB相机的项目,github上搜了下,有很多开源的库,这些库底层基本用的都是同一套东西,但上层业务比较繁琐,使用起来很不方便,并且也不太符合项目的业务需求,所以重新封装了一下,本库只需几个简单的API即可完成预览、拍照功能,无需关注复杂的USB插拔处理逻辑。[文档地址: 3 | 最好用的Android UVC Camera库](https://blog.csdn.net/u011630465/article/details/86511258) 4 | #### 1.添加依赖 5 | Step 1. Add the JitPack repository to your build file.Add it in your root build.gradle at the end of repositories: 6 | ```java 7 | allprojects { 8 | repositories { 9 | ... 10 | maven { url 'https://jitpack.io' } 11 | } 12 | } 13 | ``` 14 | Step 2. Add the dependency 15 | ```java 16 | dependencies { 17 | implementation 'com.github.Liuguihong:AndroidUVCCamera:1.0.0' 18 | } 19 | ``` 20 | #### 2.创建UVCCameraProxy对象 21 | ```javascript 22 | UVCCameraProxy mUVCCamera = new UVCCameraProxy(this); 23 | ``` 24 | #### 3.添加配置(可选) 25 | ```javascript 26 | mUVCCamera.getConfig() 27 | .isDebug(true) // 是否调试 28 | .setPicturePath(PicturePath.APPCACHE) // 图片保存路径,保存在app缓存还是sd卡 29 | .setDirName("uvccamera") // 图片保存目录名称 30 | .setProductId(0) // 产品id,用于过滤设备,不需要可不设置 31 | .setVendorId(0); // 供应商id,用于过滤设备,不需要可不设置 32 | ``` 33 | #### 4.设置预览View 34 | 支持TextureView和SurfaceView,在其生命周期里封装了注册/注销USB插拔广播、释放相机资源等逻辑,并且自动过滤USB设备,只响应USB相机插拔。 35 | ```javascript 36 | mUVCCamera.setPreviewTexture(mTextureView); // TextureView 37 | // mUVCCamera.setPreviewSurface(mSurfaceView); // SurfaceView 38 | ``` 39 | #### 5.设置USB监听回调,并在回调里处理相关逻辑 40 | ```javascript 41 | mUVCCamera.setConnectCallback(new ConnectCallback() { 42 | @Override 43 | public void onAttached(UsbDevice usbDevice) { 44 | mUVCCamera.requestPermission(usbDevice); // USB设备授权 45 | } 46 | 47 | @Override 48 | public void onGranted(UsbDevice usbDevice, boolean granted) { 49 | if (granted) { 50 | mUVCCamera.connectDevice(usbDevice); // 连接USB设备 51 | } 52 | } 53 | 54 | @Override 55 | public void onConnected(UsbDevice usbDevice) { 56 | mUVCCamera.openCamera(); // 打开相机 57 | } 58 | 59 | @Override 60 | public void onCameraOpened() { 61 | mUVCCamera.setPreviewSize(640, 480); // 设置预览尺寸 62 | mUVCCamera.startPreview(); // 开始预览 63 | } 64 | 65 | @Override 66 | public void onDetached(UsbDevice usbDevice) { 67 | mUVCCamera.closeCamera(); // 关闭相机 68 | } 69 | }); 70 | ``` 71 | #### 6.设置拍照按钮点击回调(可选) 72 | ```javascript 73 | mUVCCamera.setPhotographCallback(new PhotographCallback() { 74 | @Override 75 | public void onPhotographClick() { 76 | mUVCCamera.takePicture(); 77 | } 78 | }); 79 | ``` 80 | #### 7.设置预览回调(可选) 81 | ```javascript 82 | mUVCCamera.setPreviewCallback(new PreviewCallback() { 83 | @Override 84 | public void onPreviewFrame(byte[] yuv) { 85 | 86 | } 87 | }); 88 | ``` 89 | #### 8.设置拍照成功图片回调(可选) 90 | ```javascript 91 | mUVCCamera.setPictureTakenCallback(new PictureCallback() { 92 | @Override 93 | public void onPictureTaken(String path) { 94 | 95 | } 96 | }); 97 | ``` 98 | #### 9.拍照 99 | ```javascript 100 | mUVCCamera.takePicture(); 101 | // mUVCCamera.takePicture("test.jpg"); // 自定义图片名称,不设置则根据UUID自动保存 102 | ``` 103 | #### 10.其他API 104 | |方法|说明| 105 | |:-------------|:-------------| 106 | |registerReceiver()|注册USB插拔监听广播| 107 | |unregisterReceiver()|注销USB插拔监听广播| 108 | |checkDevice()|查找USB相机设备,会在onAttached里回调| 109 | |requestPermission(UsbDevice usbDevice)|USB设备授权,要连接USB设备必须先授权| 110 | |connectDevice(UsbDevice usbDevice)|连接USB设备| 111 | |closeDevice()|关闭USB设备| 112 | |openCamera()|打开相机| 113 | |closeCamera()|关闭相机| 114 | |setPreviewSurface(SurfaceView surfaceView)|设置预览View为SurfaceView| 115 | |setPreviewTexture(TextureView textureView)|设置预览View为TextureView| 116 | |setPreviewDisplay(Surface surface)|设置预览View,自定义| 117 | |setPreviewRotation(float rotation)|设置相机预览旋转角度,暂时只支持TextureView| 118 | |setPreviewSize(int width, int height)|设置预览尺寸| 119 | |getPreviewSize()|获取相机预览尺寸| 120 | |getSupportedPreviewSizes()|获取相机支持的预览尺寸| 121 | |startPreview()|开始预览| 122 | |stopPreview()|停止预览| 123 | |takePicture()|拍照| 124 | |takePicture(String pictureName)|拍照| 125 | |isCameraOpen()|是否已经打开相机| 126 | |getConfig()|获取配置信息| 127 | |clearCache()|删除图片缓存目录| 128 | #### 参考 129 | [https://github.com/saki4510t/UVCCamera](https://github.com/saki4510t/UVCCamera) 130 | 131 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 27 5 | buildToolsVersion "27.0.1" 6 | 7 | defaultConfig { 8 | applicationId "com.lgh.test" 9 | minSdkVersion 18 10 | targetSdkVersion 27 11 | versionCode 1 12 | versionName "1.0" 13 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 14 | } 15 | 16 | buildTypes { 17 | release { 18 | minifyEnabled false 19 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 20 | } 21 | } 22 | } 23 | 24 | dependencies { 25 | compile fileTree(include: ['*.jar'], dir: 'libs') 26 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { 27 | exclude group: 'com.android.support', module: 'support-annotations' 28 | }) 29 | testCompile 'junit:junit:4.12' 30 | compile 'com.android.support:appcompat-v7:27.+' 31 | compile 'com.android.support.constraint:constraint-layout:1.0.2' 32 | 33 | compile project(':uvccamerasdk') 34 | compile 'com.bulong.rudeness:rudeness:latest.release@aar' 35 | } 36 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in E:\sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | 19 | # Uncomment this to preserve the line number information for 20 | # debugging stack traces. 21 | #-keepattributes SourceFile,LineNumberTable 22 | 23 | # If you keep the line number information, uncomment this to 24 | # hide the original source file name. 25 | #-renamesourcefileattribute SourceFile 26 | -------------------------------------------------------------------------------- /app/src/androidTest/java/test/lgh/com/uvccameraproject/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package test.lgh.com.uvccameraproject; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumentation test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() throws Exception { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("test.lgh.com.uvccameraproject", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /app/src/main/java/com/lgh/test/ImageActivity.java: -------------------------------------------------------------------------------- 1 | package com.lgh.test; 2 | 3 | import android.net.Uri; 4 | import android.os.Bundle; 5 | import android.support.v7.app.AppCompatActivity; 6 | import android.text.TextUtils; 7 | import android.widget.ImageView; 8 | 9 | public class ImageActivity extends AppCompatActivity { 10 | 11 | @Override 12 | protected void onCreate(Bundle savedInstanceState) { 13 | super.onCreate(savedInstanceState); 14 | setContentView(R.layout.activity_image); 15 | String path = getIntent().getStringExtra("path"); 16 | if (!TextUtils.isEmpty(path)) { 17 | ((ImageView) findViewById(R.id.image)).setImageURI(Uri.parse(path)); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /app/src/main/java/com/lgh/test/MyApplication.java: -------------------------------------------------------------------------------- 1 | package com.lgh.test; 2 | 3 | import android.app.Application; 4 | 5 | import com.bulong.rudeness.RudenessScreenHelper; 6 | 7 | public class MyApplication extends Application { 8 | @Override 9 | public void onCreate() { 10 | super.onCreate(); 11 | new RudenessScreenHelper(this, 1920).activate(); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /app/src/main/java/com/lgh/test/UVCCameraActivity.java: -------------------------------------------------------------------------------- 1 | package com.lgh.test; 2 | 3 | import android.content.Intent; 4 | import android.hardware.usb.UsbDevice; 5 | import android.net.Uri; 6 | import android.os.Bundle; 7 | import android.support.v7.app.AppCompatActivity; 8 | import android.util.Log; 9 | import android.view.TextureView; 10 | import android.view.View; 11 | import android.widget.AdapterView; 12 | import android.widget.ArrayAdapter; 13 | import android.widget.ImageView; 14 | import android.widget.Spinner; 15 | 16 | import com.lgh.uvccamera.UVCCameraProxy; 17 | import com.lgh.uvccamera.bean.PicturePath; 18 | import com.lgh.uvccamera.callback.ConnectCallback; 19 | import com.lgh.uvccamera.callback.PhotographCallback; 20 | import com.lgh.uvccamera.callback.PictureCallback; 21 | import com.lgh.uvccamera.callback.PreviewCallback; 22 | import com.serenegiant.usb.Size; 23 | 24 | import java.util.ArrayList; 25 | import java.util.List; 26 | 27 | public class UVCCameraActivity extends AppCompatActivity { 28 | private static final String TAG = "MainActivity"; 29 | private TextureView mTextureView; 30 | // private SurfaceView mSurfaceView; 31 | private ImageView mImageView1; 32 | private Spinner mSpinner; 33 | private UVCCameraProxy mUVCCamera; 34 | private boolean isFirst = true; 35 | private String path1; 36 | 37 | @Override 38 | protected void onCreate(Bundle savedInstanceState) { 39 | super.onCreate(savedInstanceState); 40 | setContentView(R.layout.activity_uvc_camera); 41 | initView(); 42 | initUVCCamera(); 43 | } 44 | 45 | private void initView() { 46 | mTextureView = findViewById(R.id.textureView); 47 | // mSurfaceView = findViewById(R.id.surfaceView); 48 | // mSurfaceView.setZOrderOnTop(true); 49 | mImageView1 = findViewById(R.id.imag1); 50 | mSpinner = findViewById(R.id.spinner); 51 | mSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { 52 | @Override 53 | public void onItemSelected(AdapterView parent, View view, final int position, long id) { 54 | if (isFirst) { 55 | isFirst = false; 56 | return; 57 | } 58 | Log.i(TAG, "position-->" + position); 59 | mUVCCamera.stopPreview(); 60 | List list = mUVCCamera.getSupportedPreviewSizes(); 61 | if (!list.isEmpty()) { 62 | mUVCCamera.setPreviewSize(list.get(position).width, list.get(position).height); 63 | mUVCCamera.startPreview(); 64 | } 65 | } 66 | 67 | @Override 68 | public void onNothingSelected(AdapterView parent) { 69 | 70 | } 71 | }); 72 | } 73 | 74 | private void initUVCCamera() { 75 | mUVCCamera = new UVCCameraProxy(this); 76 | // 已有默认配置,不需要可以不设置 77 | mUVCCamera.getConfig() 78 | .isDebug(true) 79 | .setPicturePath(PicturePath.APPCACHE) 80 | .setDirName("uvccamera") 81 | .setProductId(0) 82 | .setVendorId(0); 83 | mUVCCamera.setPreviewTexture(mTextureView); 84 | // mUVCCamera.setPreviewSurface(mSurfaceView); 85 | // mUVCCamera.registerReceiver(); 86 | 87 | mUVCCamera.setConnectCallback(new ConnectCallback() { 88 | @Override 89 | public void onAttached(UsbDevice usbDevice) { 90 | mUVCCamera.requestPermission(usbDevice); 91 | } 92 | 93 | @Override 94 | public void onGranted(UsbDevice usbDevice, boolean granted) { 95 | if (granted) { 96 | mUVCCamera.connectDevice(usbDevice); 97 | } 98 | } 99 | 100 | @Override 101 | public void onConnected(UsbDevice usbDevice) { 102 | mUVCCamera.openCamera(); 103 | } 104 | 105 | @Override 106 | public void onCameraOpened() { 107 | showAllPreviewSizes(); 108 | mUVCCamera.setPreviewSize(640, 480); 109 | mUVCCamera.startPreview(); 110 | } 111 | 112 | @Override 113 | public void onDetached(UsbDevice usbDevice) { 114 | mUVCCamera.closeCamera(); 115 | } 116 | }); 117 | 118 | mUVCCamera.setPhotographCallback(new PhotographCallback() { 119 | @Override 120 | public void onPhotographClick() { 121 | mUVCCamera.takePicture(); 122 | // mUVCCamera.takePicture("test.jpg"); 123 | } 124 | }); 125 | 126 | mUVCCamera.setPreviewCallback(new PreviewCallback() { 127 | @Override 128 | public void onPreviewFrame(byte[] yuv) { 129 | 130 | } 131 | }); 132 | 133 | mUVCCamera.setPictureTakenCallback(new PictureCallback() { 134 | @Override 135 | public void onPictureTaken(String path) { 136 | path1 = path; 137 | mImageView1.setImageURI(null); 138 | mImageView1.setImageURI(Uri.parse(path)); 139 | } 140 | }); 141 | } 142 | 143 | public void onClick(View v) { 144 | switch (v.getId()) { 145 | case R.id.btn1: 146 | mUVCCamera.startPreview(); 147 | break; 148 | 149 | case R.id.btn2: 150 | mUVCCamera.stopPreview(); 151 | break; 152 | 153 | case R.id.btn3: 154 | mUVCCamera.clearCache(); 155 | break; 156 | 157 | case R.id.btn4: 158 | mUVCCamera.setPreviewRotation(180); 159 | break; 160 | 161 | case R.id.take_picture: 162 | // mUVCCamera.takePicture(); 163 | mUVCCamera.takePicture("test.jpg"); 164 | break; 165 | 166 | case R.id.imag1: 167 | Log.i(TAG, "path1-->" + path1); 168 | jump2ImageActivity(path1); 169 | break; 170 | } 171 | } 172 | 173 | @Override 174 | protected void onDestroy() { 175 | super.onDestroy(); 176 | // mUVCCamera.unregisterReceiver(); 177 | } 178 | 179 | private void jump2ImageActivity(String path) { 180 | Intent intent = new Intent(this, ImageActivity.class); 181 | intent.putExtra("path", path); 182 | startActivity(intent); 183 | } 184 | 185 | private void showAllPreviewSizes() { 186 | isFirst = true; 187 | List previewList = mUVCCamera.getSupportedPreviewSizes(); 188 | List previewStrs = new ArrayList<>(); 189 | for (Size size : previewList) { 190 | previewStrs.add(size.width + " * " + size.height); 191 | } 192 | ArrayAdapter adapter = new ArrayAdapter(UVCCameraActivity.this, android.R.layout.simple_spinner_item, previewStrs); 193 | adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); 194 | mSpinner.setAdapter(adapter); 195 | } 196 | 197 | } 198 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_image.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_uvc_camera.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 25 | 26 | 31 | 32 | 37 | 38 | 39 | 49 | 50 | 55 | 56 |