設(shè)備外接usb攝像頭,進行基本的預(yù)覽、拍照哲嘲、錄像贪薪。相信有些同學(xué)在工作中有遇到類似的需求。
usb攝像頭在Android設(shè)備上眠副,應(yīng)用的確很廣泛画切,我之前公司做的是車載產(chǎn)品,眾所周知囱怕,現(xiàn)在汽車上是安裝了越來越多的攝像頭霍弹,通過攝像頭采集的實時信息,能協(xié)助我們進行更加安全的駕駛光涂。而這些攝像頭庞萍,除了比較常見的mipi攝像頭拧烦,很多也開始用的usb攝像頭忘闻。
除了車載產(chǎn)品,類似安防恋博、醫(yī)療等各方面齐佳,和監(jiān)控、視頻相關(guān)的很多領(lǐng)域债沮,也都會用到usb攝像頭炼吴。
uvc camera?有camera不管你之前有沒用過疫衩,有沒遇到過硅蹦,相信看完這篇文章,一定會帶給你不一樣的收獲闷煤。
這篇文章將從下面幾點展開講解:
一童芹、什么是UVC?
二、UVCCamera開源項目鲤拿?
三假褪、開源項目集成?
四近顷、遇到的問題及解決生音?
一、什么是UVC?
UVC全稱為USB Video Class窒升,直接翻譯過來的意思就是:USB視頻類缀遍,它是一種專門為USB視頻捕獲設(shè)備定義的協(xié)議標(biāo)準(zhǔn)。
這個標(biāo)準(zhǔn)是Microsoft與另外幾家設(shè)備廠商聯(lián)合推出的為USB視頻捕獲設(shè)備定義的協(xié)議標(biāo)準(zhǔn)饱须,已經(jīng)成為USB org標(biāo)準(zhǔn)之一域醇。
現(xiàn)在的主流操作系統(tǒng),都已提供UVC設(shè)備驅(qū)動,因此符合UVC規(guī)格的硬件設(shè)備在不需要安裝任何的驅(qū)動程序下即可在主機中正常使用歹苦。是的青伤,目前Android系統(tǒng)已經(jīng)支持uvc設(shè)備。
小結(jié):
講到這里大家應(yīng)該有這么個概念了殴瘦,uvc是一種協(xié)議狠角,不同的設(shè)備可能會支持不同的協(xié)議。如果我們的usb攝像頭蚪腋,需要在Android設(shè)備上獲得支持的話丰歌,那這個攝像頭就得是支持uvc協(xié)議的攝像頭。
二屉凯、UVCCamera開源項目立帖?
https://github.com/saki4510t/UVCCamera
現(xiàn)在我們在網(wǎng)上搜索uvc camera相關(guān)的文章,能查找到的uvc camera相關(guān)的項目悠砚,可以毫不夸張的說晓勇,基本都是基于上面這個開源項目來改的,這個開源項目的確比較牛逼灌旧,而且類封裝的很好绑咱,代碼邏輯比較清晰,使用起來也是非常的方便枢泰,而且關(guān)于攝像頭基本的預(yù)覽描融、拍照、錄像功能都實現(xiàn)了衡蚂,是個比較完整的工程項目窿克。
我們通過git pull先把代碼拉到本地,導(dǎo)入到AndroidStudio中毛甲,(不通過git pull 也行年叮,直接下載代碼也是可以的。github 網(wǎng)站在國內(nèi)不翻墻的話丽啡,可能有時訪問不了谋右,如何訪問不了,大家也可以嘗試在gitee上去搜索這個項目下載)补箍。整個工程的目錄結(jié)構(gòu)如下圖所示改执。當(dāng)然導(dǎo)入的過程中,會遇到一些報錯的問題坑雅,其實主要是gradle版本的問題辈挂,導(dǎo)入報錯的問題,我們統(tǒng)一在這個文章后面再給大家做詳細(xì)的講解裹粤,包括遇到的問題以及是如何去解決這些問題的终蒂。
這個開源項目,除了sdk庫的源碼,作者還提供了8個demo拇泣。這8個demo的具體功能介紹如下:
1)USBCameraTest0
顯示如何使用SurfaceView來啟動/停止預(yù)覽噪叙。
2)USBCameraTest
顯示如何啟動/停止預(yù)覽。這與USBCameraTest0幾乎相同霉翔,
但是使用自定義的TextureView來顯示相機圖像而不是使用SurfaceView睁蕾。
3)USBCameraTest2
演示如何使用MediaCodec編碼器將UVC相機(無音頻)的視頻記錄為.MP4文件。
此示例需要API>=18债朵,因為MediaMuxer僅支持API>=18子眶。
4)USBCameraTest3
演示如何將音頻(來自內(nèi)部麥克風(fēng))的視頻(來自UVC相機)錄制為.MP4文件。
這也顯示了幾種捕捉靜止圖像的方式序芦。此示例可能最適用于您的定制應(yīng)用程序的基礎(chǔ)項目臭杰。
5)USBCameraTest4
顯示了訪問UVC相機并將視頻圖像保存到后臺服務(wù)的方式。
這是最復(fù)雜的示例之一谚中,因為這需要使用AIDL的IPC渴杆。
6)USBCameraTest5
和USBCameraTest3幾乎相同,但使用IFrameCallback接口保存視頻圖像藏杖,
而不是使用來自MediaCodec編碼器的輸入Surface将塑。
在大多數(shù)情況下,您不應(yīng)使用IFrameCallback來保存圖像蝌麸,因為IFrameCallback比使用Surface要慢很多。
但是艾疟,如果您想獲取視頻幀數(shù)據(jù)并自行處理它們或?qū)⑺鼈冏鳛樽止?jié)緩沖區(qū)傳遞給其他外部庫来吩,
則IFrameCallback將非常有用。
7)USBCameraTest6
這顯示了如何將視頻圖像分割為多個Surface蔽莱。你可以在這個應(yīng)用程序中看到視頻圖像并排觀看弟疆。
這個例子還展示了如何使用EGL來渲染圖像。
如果您想在添加視覺效果/濾鏡效果后顯示視頻圖像盗冷,則此示例可能會對您有所幫助怠苔。
8)USBCameraTest7
這顯示了如何使用兩個攝像頭并顯示來自每個攝像頭的視頻圖像。這仍然是實驗性的仪糖,可能有一些問題柑司。
9)usbCameraTest8
這顯示了如何設(shè)置/獲取uvc控件。目前這只支持亮度和對比度锅劝。
提供的demo攒驰,代碼邏輯都很清晰,大家可以根據(jù)自己的需求去看對應(yīng)的demo故爵。這些demo包含了預(yù)覽玻粪、錄像、拍照這些基本的功能。關(guān)于調(diào)節(jié)亮度劲室、對比度這點伦仍,可能是不同攝像頭的原因,我本地驗證了下很洋,看實際上并沒有效果呢铆,如果有哪位同學(xué)后面試試到有效果的,歡迎給我留言蹲缠,大家交流交流棺克。
Demo7我們可以看到是一個支持2個攝像頭的Demo。有多攝像頭支持需求的线定,可以參考這個里面的邏輯娜谊。記得之前做車載的時候,公司內(nèi)部在高通8953上的一個預(yù)研項目斤讥,是掛了6個攝像頭纱皆,那會驅(qū)動的同事也是花了不少的時間去點亮這些攝像頭,現(xiàn)在想想芭商,如果采用uvc攝像頭派草,再參考這個開源項目,那應(yīng)該很快就可以搞個簡單的demo出來铛楣。
三近迁、開源項目UVCCaemra的編譯、集成簸州?
UVCCamera的核心代碼都在libuvccamera里面了鉴竭。我們要在我們的項目工程中集成這個項目的話,需要2個東西岸浑,一個是so庫搏存,一個可以調(diào)用的java sdk源碼。
從上面的截圖我們可以很清楚的看到矢洲,代碼里面主要是包含了jni和java兩大部分的內(nèi)容璧眠。編譯jni,就可以得到我們需要的so庫读虏,java代碼可以打包成aar责静,或者之間直接把整個代碼復(fù)制到我們的工程目錄下,作為庫引用也是可以的掘譬。
1) so庫的編譯
現(xiàn)在so庫的編譯泰演,已經(jīng)非常的方便了,如下圖所示葱轩,我們在as的Terminal終端界面睦焕,切到j(luò)ni目錄下藐握,直接ndk-build,就可以生成我們需要的so庫文件了垃喊。
這里有個地方我們得注意下猾普,就是我們需要Android 32位還是64位的庫文件,這個是在Application.mk里面配的本谜,上面的截圖我已經(jīng)把Application.mk這個文件的位置圈出來了初家。如果是32位,這里邊APP_ABI的內(nèi)容修改為armeabi-v7a即可乌助,64位則是arm64-v8a溜在,其它平臺的類推。
2)打包aar
我們項目要集成這個開源項目他托,那肯定得提供java代碼我們才能調(diào)用掖肋。我這里采用的方式是,把UVCCamera的核心代碼(也就是不包含8個demo)的內(nèi)容赏参,打包成aar志笼,然后在我自己的工程目錄中引用打包好的aar.
打包成aar在AS里面操作也是非常簡單的。先貼下圖片把篓。
從上面的截圖纫溃,我們可以看到,需要打包的module有2個韧掩,分別是libuvccamera和usbCameraCommon紊浩。按照截圖上的操作順序來,從1到3揍很。先是點擊as界面右側(cè)的Gradle,在騰出的界面中郎楼,雙擊執(zhí)行assembleRelease,執(zhí)行完沒有啥報錯的話,在module的build output路徑下窒悔,就可以看到生成的aar文件了敌买。
最后就是把生成的so庫文件芙粱,已經(jīng)生成的aar文件,都拷貝到我們自己工程的libs目錄下,導(dǎo)入到項目中使用即可。
3)將UVCCamera sdk集成到自己項目
通過上面的步驟,我們已經(jīng)成功的編譯出了so庫文件以及aar文件立轧。下圖顯示的就是我們把生成的文件導(dǎo)入到我們自己的工程項目中胜卤。
四败富、demo小改動:錄像的同時,獲取實時yuv流?
關(guān)于uvcCamea的文章姻僧,我之前也寫過一篇规丽,這里貼下地址蒲牧,連同demo地址也一并給出,感興趣的同學(xué)也可以看看嘁捷。
這個demo造成,除了基本的預(yù)覽、拍照雄嚣、錄像功能晒屎,我根據(jù)自己的需求,還添加了個返回實時yuv流的接口缓升。對有需求將實時流視頻流進行類似人臉識別鼓鲁、上傳后臺之類的,相信能給你帶來幫助港谊。
“一篇文章帶你了解Android Usb攝像頭”
http://www.reibang.com/p/35124f098c24
demo地址:
https://github.com/yorkZJC/UvcCameraDemo
關(guān)于我自己的這個demo骇吭,如果需要修改分辨率,統(tǒng)一在如下圖所示的MyConstants.java文件中修改即可歧寺。
五、遇到的問題及解決斜筐?
1)sdk龙致、ndk配置?
第一步顷链,我們需要把sdk目代、nkd先配置好,sdk相信很多同學(xué)都會配嗤练,另外就是這里需要用ndk-build來編譯so庫榛了,所以ndk一定得配好,我本地的ndk版本是r17煞抬,相信這個ndk的版本影響不是很大霜大。
ndk的配置,有2種方式革答,可以直接在local.properties文件種修改僧诚,也可以在視圖界面,Project Structure中選擇我們本地的nkd路徑來配置蝗碎。下面截圖分別對應(yīng)的是這2種不同的修改方式,采用其中任意一種即可旗扑。
2)導(dǎo)入Android Studio蹦骑,gradle版本配置?
下面是我遇到的一些問題臀防,按照我的修改操作來眠菇,相信大家都能成功運行起來边败。
【error 1】
Caused by: org.apache.http.conn.HttpHostConnectException: Connect to maven.google.com:443
[maven.google.com/142.250.204.46] failed: Connection timed out: connect
【error2】
ERROR: The minSdk version should not be declared in the android manifest file. You can move the version from the manifest to the defaultConfig in the build.gradle file.
Remove minSdkVersion and sync project
Affected Modules: libuvccamera
【error3】
* What went wrong:
Execution failed for task ':libuvccamera:ndkBuild'.
> A problem occurred starting process 'command 'null/ndk-build.cmd''
Android NDK: The armeabi ABI is no longer supported. Use armeabi-v7a.
Android NDK: NDK Application 'local' targets unknown ABI(s): armeabi mips
D:/APPS/sdk/android-ndk-r17b/build//../build/core/setup-app.mk:79: *** Android NDK: Aborting . Stop.
2021-06-11 10:08:11.386 3105-3105/? E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.serenegiant.usbcameratest0, PID: 3105
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.serenegiant.usbcameratest0/com.serenegiant.usbcameratest0.MainActivity}: java.lang.IllegalStateException: You need to use a Theme.AppCompat theme (or descendant) with this activity.
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3432)
我是通過git pull拉代碼到本地的,所以本地的每筆修改都可以通過git 來追蹤記錄到捎废。關(guān)于編譯報錯的笑窜,我們來看下我一共是修改了哪些內(nèi)容。
上面截圖登疗,我們看到一共是修改了5個地方排截。
i、工程根目錄下build.gradle的修改辐益;
ii断傲、libuvccamera/build.gradle的修改;
3)拔出usb攝像頭智政,crash異常導(dǎo)致應(yīng)用退出认罩?
原生的庫文件,有個bug续捂,就是在使用usb攝像頭的過程中垦垂,我們?nèi)グ褦z像頭拔掉,這時so庫有個crash牙瓢,到導(dǎo)致我們的應(yīng)用直接異常退出劫拗。
這個問題,網(wǎng)上的其它大神已經(jīng)給出了解決方案一罩,我這里貼下修改的地方杨幼。我自己也是親自修改驗證了。
diff --git a/libuvccamera/src/main/jni/libusb/libusb/os/android_usbfs.c b/libuvccamera/src/main/jni/libusb/libusb/os/android_usbfs.c
index 8626595..c4842c4 100644
--- a/libuvccamera/src/main/jni/libusb/libusb/os/android_usbfs.c
+++ b/libuvccamera/src/main/jni/libusb/libusb/os/android_usbfs.c
@@ -2726,6 +2726,12 @@ static int handle_iso_completion(struct libusb_device_handle *handle, // XXX add
usbi_mutex_lock(&itransfer->lock);
for (i = 0; i < num_urbs; i++) {
+ //+Add by york.zhou on 2021.05.19,fix issue app crash on remove usb device
+ if (tpriv->iso_urbs == NULL){
+ break;
+ }
+ //-Add by york.zhou on 2021.05.19,fix issue app crash on remove usb device
+
if (urb == tpriv->iso_urbs[i]) {
urb_idx = i + 1;
break;
diff --git a/libuvccamera/src/main/jni/libuvc/src/stream.c b/libuvccamera/src/main/jni/libuvc/src/stream.c
index 8a1e90a..b7cedcc 100644
--- a/libuvccamera/src/main/jni/libuvc/src/stream.c
+++ b/libuvccamera/src/main/jni/libuvc/src/stream.c
@@ -641,7 +641,8 @@ static void _uvc_delete_transfer(struct libusb_transfer *transfer) {
libusb_cancel_transfer(strmh->transfers[i]); // XXX 20141112追加
UVC_DEBUG("Freeing transfer %d (%p)", i, transfer);
free(transfer->buffer);
- libusb_free_transfer(transfer);
+ //+Add york.zhou 2021.05-19,fix remove usb devices,app crash
+ //libusb_free_transfer(transfer);
strmh->transfers[i] = NULL;
break;
}
4)有些usb攝像頭識別不了聂渊?
有些同學(xué)可能還會遇到有些usb攝像頭識別不了的問題差购。這里面有個前提,就是確認(rèn)這個usb攝像頭汉嗽,插到電腦上是能正常識別使用的欲逃,只是插到我們的設(shè)備上,識別不了饼暑。
遇到這種問題稳析,可以抓個完整的logcat日志弓叛,然后在日志中全局搜索subclass,將搜索到的subclass相關(guān)信息,按照下面截圖的格式陈惰,在xml 目錄下的device_filter.xml中配置下。
關(guān)于uvcCamera的內(nèi)容毕籽,講到這里就結(jié)束了抬闯。感謝大家的閱讀。也歡迎大家一起交流溶握。