先來一段從網(wǎng)上找到的理論知識(shí),對(duì)UVC協(xié)議有初步的印象
UVC協(xié)議:USB Video Class,USB視頻類,是一種為USB視頻捕獲設(shè)備定義的協(xié)議標(biāo)準(zhǔn)。
Android 平臺(tái)支持使用即插即用的 USB 攝像頭(即網(wǎng)絡(luò)攝像頭),但前提是這些攝像頭采用標(biāo)準(zhǔn)的?Android Camera2 API?和攝像頭?HIDL?接口。網(wǎng)絡(luò)攝像頭通常支持?USB 視頻類 (UVC)?驅(qū)動(dòng)程序,并且在 Linux 上,系統(tǒng)采用標(biāo)準(zhǔn)的?Video4Linux (V4L)?驅(qū)動(dòng)程序控制 UVC 攝像頭。
本文主要展示具體的實(shí)現(xiàn),并不研究UVC協(xié)議以及底層實(shí)現(xiàn),只展示Android外界usb攝像頭的預(yù)覽功能的流程。文末附demo
本文的實(shí)現(xiàn)基于github開源庫:傳送門
1.項(xiàng)目中集成libuvccamera模塊(代碼可從github下載,或者是文末demo中附帶)
implementation project(':libuvccamera')
2.布局文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<com.serenegiant.widget.AspectRatioSurfaceView
android:id="@+id/surfaceView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
3.MainActivity
public class MainActivity extends AppCompatActivity {
private static final String TAG = MainActivity.class.getSimpleName();
private static final boolean DEBUG = true;
private ActivityMainBinding binding;
private UsbDevice mUsbDevice;
/**
* CameraHelper是管理Camera服務(wù)的客戶端
* (功能包括:選擇設(shè)備,打開設(shè)備,連接設(shè)備,關(guān)聯(lián)預(yù)覽用的CameraView,拍照,錄像,斷開連接等操作)
* 其中通過addSurface,關(guān)聯(lián)預(yù)覽用的Surface比較關(guān)鍵,分為三種情況:
* a. 連接設(shè)備成功時(shí),執(zhí)行addSurface
* b. 旋轉(zhuǎn)屏幕,成功進(jìn)入OnResume時(shí),CameraView生成Surface,并執(zhí)行回調(diào)onSurfaceCreated方法,在方法中執(zhí)行addSurface
*/
private ICameraHelper mCameraHelper;
private final ICameraHelper.StateCallback mStateCallback = new MyCameraHelperCallback();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityMainBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
}
@Override
public void onStart() {
super.onStart();
resetCameraHelper();
}
private void resetCameraHelper() {
clearCameraHelper();
initCameraHelper();
}
public void initCameraHelper() {
mCameraHelper = new CameraHelper();
mCameraHelper.setStateCallback(mStateCallback);
}
/**
* 程序結(jié)束或者UVC設(shè)備斷開連接時(shí),釋放CameraHelper
*/
private void clearCameraHelper() {
if (mCameraHelper != null) {
mCameraHelper.releaseAll();
mCameraHelper = null;
}
}
private class MyCameraHelperCallback implements ICameraHelper.StateCallback {
@Override
public void onAttach(UsbDevice device) {
if (DEBUG) Log.v(TAG, "onAttach:device=" + device.getDeviceName());
mCameraHelper.selectDevice(device);
}
/**
* 獲取USB設(shè)備權(quán)限之后,才開始連接USB攝像頭
*/
@Override
public void onDeviceOpen(UsbDevice device, boolean createNew) {
if (DEBUG) Log.v(TAG, "onDeviceOpen:device=" + device.getDeviceName());
if (mCameraHelper != null) {
mCameraHelper.openCamera();
}
}
@Override
public void onCameraOpen(UsbDevice device) {
if (DEBUG) Log.v(TAG, "onCameraOpen:");
mCameraHelper.startPreview();
// 和攝像頭成功建立連接之后,就可以獲取攝像頭當(dāng)前預(yù)覽的實(shí)際分辨率
Size size = mCameraHelper.getPreviewSize();
if (size != null) {
// 設(shè)置TextureView的寬高比,使之符合攝像頭的真實(shí)比例
binding.surfaceView.setAspectRatio(size.width, size.height);
}
if (mCameraHelper != null && binding.surfaceView != null && binding.surfaceView.getHolder() != null && binding.surfaceView.getHolder().getSurface() != null) {
mCameraHelper.addSurface(binding.surfaceView.getHolder().getSurface(), false);
}
}
@Override
public void onCameraClose(UsbDevice device) {
if (DEBUG) Log.v(TAG, "onCameraClose:");
if (mCameraHelper != null && binding.surfaceView != null && binding.surfaceView.getHolder() != null && binding.surfaceView.getHolder().getSurface() != null) {
mCameraHelper.removeSurface(binding.surfaceView.getHolder().getSurface());
}
}
@Override
public void onDeviceClose(UsbDevice device) {
if (DEBUG) Log.v(TAG, "onDeviceClose:");
}
@Override
public void onDetach(UsbDevice device) {
if (DEBUG) Log.v(TAG, "onDetach:device=" + device.getDeviceName());
if (device.equals(mUsbDevice)) {
mUsbDevice = null;
}
}
@Override
public void onCancel(UsbDevice device) {
if (DEBUG) Log.v(TAG, "onCancel:device=" + device.getDeviceName());
if (device.equals(mUsbDevice)) {
mUsbDevice = null;
}
}
@Override
public void onError(UsbDevice device, CameraException e) {
if (DEBUG) Log.v(TAG, "onError:" + e);
if (device.equals(mUsbDevice)) {
mUsbDevice = null;
}
}
}
}
至此,就實(shí)現(xiàn)了對(duì)usb攝像頭的簡單的預(yù)覽功能文章來源:http://www.zghlxwxcb.cn/news/detail-620834.html
demo源碼?文章來源地址http://www.zghlxwxcb.cn/news/detail-620834.html
到了這里,關(guān)于Android 外接基于UVC協(xié)議的攝像頭并實(shí)現(xiàn)預(yù)覽的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!