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 文件开启相关权限
项目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 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
4、需要注意
(1)mCameraHelper.requestPermission(int index) 是打开usb设备,有的usb不是摄像头设备,需要对usb设备名称进行过滤,可控制需要打开特定的usb摄像头, 可以热插拔显示
(2)app关闭或后台运行 isPreview 需要重置为 false 不然再次进入app 预览无画面因为startPreview 未执行
(3)设备重启后第一次打开app, 预览画面可能没有,但实际是可以录制的,重新进入app就可以了