天天看點

這可能是介紹 Android UvcCamera 最詳細的文章了

裝置外接 usb 攝像頭,進行基本的預覽、拍照、錄像。相信有些同學在工作中有遇到類似的需求。

usb 攝像頭在 Android 裝置上,應用的确很廣泛,我之前公司做的是車載産品,衆所周知,現在汽車上是安裝了越來越多的攝像頭,通過攝像頭采集的實時資訊,能協助我們進行更加安全的駕駛。而這些攝像頭,除了比較常見的 mipi 攝像頭,很多也開始用的 usb 攝像頭。

除了車載産品,類似安防、醫療等各方面,和監控、視訊相關的很多領域,也都會用到 usb 攝像頭。

uvc camera?有 camera 不管你之前有沒用過,有沒遇到過,相信看完這篇文章,一定會帶給你不一樣的收獲。

這篇文章将從下面幾點展開講解:

一、什麼是 UVC?

二、UVCCamera 開源項目?

三、開源項目內建?

四、遇到的問題及解決?

一、什麼是 UVC?

UVC 全稱為 USB Video Class,直接翻譯過來的意思就是:USB 視訊類,它是一種專門為 USB 視訊捕獲裝置定義的協定标準。

這個标準是 Microsoft 與另外幾家裝置廠商聯合推出的為 USB 視訊捕獲裝置定義的協定标準,已經成為 USB org 标準之一。

現在的主流作業系統,都已提供 UVC 裝置驅動,是以符合 UVC 規格的硬體裝置在不需要安裝任何的驅動程式下即可在主機中正常使用。是的,目前 Android 系統已經支援 uvc 裝置。

小結:

講到這裡大家應該有這麼個概念了,uvc 是一種協定,不同的裝置可能會支援不同的協定。如果我們的 usb 攝像頭,需要在 Android 裝置上獲得支援的話,那這個攝像頭就得是支援 uvc 協定的攝像頭。

二、UVCCamera 開源項目?

GitHub - saki4510t/UVCCamera: library and sample to access to UVC web camera on non-rooted Android device

現在我們在網上搜尋 uvc camera 相關的文章,能查找到的 uvc camera 相關的項目,可以毫不誇張的說,基本都是基于上面這個開源項目來改的,這個開源項目的确比較牛逼,而且類封裝的很好,代碼邏輯比較清晰,使用起來也是非常的友善,而且關于攝像頭基本的預覽、拍照、錄像功能都實作了,是個比較完整的工程項目。

我們通過 git pull 先把代碼拉到本地,導入到 AndroidStudio 中,(不通過 git pull 也行,直接下載下傳代碼也是可以的。github 網站在國内不翻牆的話,可能有時通路不了,如何通路不了,大家也可以嘗試在 gitee 上去搜尋這個項目下載下傳)。

這可能是介紹 Android UvcCamera 最詳細的文章了

整個工程的目錄結構如下圖所示。當然導入的過程中,會遇到一些報錯的問題,其實主要是 gradle 版本的問題,導入報錯的問題,我們統一在這個文章後面再給大家做詳細的講解,包括遇到的問題以及是如何去解決這些問題的。

這可能是介紹 Android UvcCamera 最詳細的文章了

這個開源項目,除了 sdk 庫的源碼,作者還提供了 9 個 demo。這 9 個 demo 的具體功能介紹如下:

1)USBCameraTest0

顯示如何使用 SurfaceView 來啟動/停止預覽。

2)USBCameraTest

顯示如何啟動/停止預覽。這與 USBCameraTest0 幾乎相同,

但是使用自定義的 TextureView 來顯示相機圖像而不是使用 SurfaceView。

3)USBCameraTest2

示範如何使用 MediaCodec 編碼器将 UVC 相機(無音頻)的視訊記錄為.MP4 檔案。

此示例需要 API>=18,因為 MediaMuxer 僅支援 API>=18。

4)USBCameraTest3

示範如何将音頻(來自内部麥克風)的視訊(來自 UVC 相機)錄制為.MP4 檔案。

這也顯示了幾種捕捉靜止圖像的方式。此示例可能最适用于您的定制應用程式的基礎項目。

5)USBCameraTest4

顯示了通路 UVC 相機并将視訊圖像儲存到背景服務的方式。

這是最複雜的示例之一,因為這需要使用 AIDL 的 IPC。

6)USBCameraTest5

和 USBCameraTest3 幾乎相同,但使用 IFrameCallback 接口儲存視訊圖像,

而不是使用來自 MediaCodec 編碼器的輸入 Surface。

在大多數情況下,您不應使用 IFrameCallback 來儲存圖像,因為 IFrameCallback 比使用 Surface 要慢很多。

但是,如果您想擷取視訊幀資料并自行處理它們或将它們作為位元組緩沖區傳遞給其他外部庫,

則 IFrameCallback 将非常有用。

7)USBCameraTest6

這顯示了如何将視訊圖像分割為多個 Surface。你可以在這個應用程式中看到視訊圖像并排觀看。

這個例子還展示了如何使用 EGL 來渲染圖像。

如果您想在添加視覺效果/濾鏡效果後顯示視訊圖像,則此示例可能會對您有所幫助。

8)USBCameraTest7

這顯示了如何使用兩個攝像頭并顯示來自每個攝像頭的視訊圖像。這仍然是實驗性的,可能有一些問題。

9)usbCameraTest8

這顯示了如何設定/擷取 uvc 控件。目前這隻支援亮度和對比度。

提供的 demo,代碼邏輯都很清晰,大家可以根據自己的需求去看對應的 demo。這些 demo 包含了預覽、錄像、拍照這些基本的功能。關于調節亮度、對比度這點,可能是不同攝像頭的原因,我本地驗證了下,看實際上并沒有效果,如果有哪位同學後面試試到有效果的,歡迎給我留言,大家交流交流。

Demo7 我們可以看到是一個支援 2 個攝像頭的 Demo。有多攝像頭支援需求的,可以參考這個裡面的邏輯。記得之前做車載的時候,公司内部在高通 8953 上的一個預研項目,是挂了 6 個攝像頭,那會驅動的同僚也是花了不少的時間去點亮這些攝像頭,現在想想,如果采用 uvc 攝像頭,再參考這個開源項目,那應該很快就可以搞個簡單的 demo 出來。

三、開源項目 UVCCaemra 的編譯、內建?

UVCCamera 的核心代碼都在 libuvccamera 裡面了。

這可能是介紹 Android UvcCamera 最詳細的文章了

我們要在我們的項目工程中內建這個項目的話,需要 2 個東西,一個是 so 庫,一個可以調用的 java sdk 源碼。

從上面的截圖我們可以很清楚的看到,代碼裡面主要是包含了 jni 和 java 兩大部分的内容。編譯 jni,就可以得到我們需要的 so 庫,java 代碼可以打包成 aar,或者之間直接把整個代碼複制到我們的工程目錄下,作為庫引用也是可以的。

1) so 庫的編譯

現在 so 庫的編譯,已經非常的友善了,如下圖所示,我們在 as 的 Terminal 終端界面,切到 jni 目錄下,直接 ndk-build,就可以生成我們需要的 so 庫檔案了。

這可能是介紹 Android UvcCamera 最詳細的文章了

這裡有個地方我們得注意下,就是我們需要 Android 32 位還是 64 位的庫檔案,這個是在 Application.mk 裡面配的,上面的截圖我已經把 Application.mk 這個檔案的位置圈出來了。如果是 32 位,這裡邊 APP_ABI 的内容修改為 armeabi-v7a 即可,64 位則是 arm64-v8a,其它平台的類推。

2)打包 aar

我們項目要內建這個開源項目,那肯定得提供 java 代碼我們才能調用。我這裡采用的方式是,把 UVCCamera 的核心代碼(也就是不包含 8 個 demo)的内容,打包成 aar,然後在我自己的工程目錄中引用打包好的 aar.打包成 aar 在 AS 裡面操作也是非常簡單的。先貼下圖檔。

這可能是介紹 Android UvcCamera 最詳細的文章了
這可能是介紹 Android UvcCamera 最詳細的文章了

從上面的截圖,我們可以看到,需要打包的 module 有 2 個,分别是 libuvccamera 和 usbCameraCommon。按照截圖上的操作順序來,從 1 到 3。先是點選 as 界面右側的 Gradle,在騰出的界面中,輕按兩下執行 assembleRelease,執行完沒有啥報錯的話,在 module 的 build output 路徑下,就可以看到生成的 aar 檔案了。

最後就是把生成的 so 庫檔案,已經生成的 aar 檔案,都拷貝到我們自己工程的 libs 目錄下,導入到項目中使用即可。

3)将 UVCCamera sdk 內建到自己項目

通過上面的步驟,我們已經成功的編譯出了 so 庫檔案以及 aar 檔案。下圖顯示的就是我們把生成的檔案導入到我們自己的工程項目中。

這可能是介紹 Android UvcCamera 最詳細的文章了

四、demo 小改動:錄像的同時,擷取實時 yuv 流?

關于 uvcCamea 的文章,我之前也寫過一篇,這裡貼下位址,連同 demo 位址也一并給出,感興趣的同學也可以看看。

這個 demo,除了基本的預覽、拍照、錄像功能,我根據自己的需求,還添加了個傳回實時 yuv 流的接口。對有需求将實時流視訊流進行類似人臉識别、上傳背景之類的,相信能給你帶來幫助。

“一篇文章帶你了解 Android Usb 攝像頭”一篇文章帶你了解Android Usb攝像頭 - 簡書

demo 位址:https://github.com/yorkZJC/UvcCameraDemo

關于我自己的這個 demo,如果需要修改分辨率,統一在如下圖所示的 MyConstants.java 檔案中修改即可。

這可能是介紹 Android UvcCamera 最詳細的文章了

下面截圖展示的是 yuv 流回調的接口。

這可能是介紹 Android UvcCamera 最詳細的文章了

五、遇到的問題及解決?

1)sdk、ndk 配置?

第一步,我們需要把 sdk、nkd 先配置好,sdk 相信很多同學都會配,另外就是這裡需要用 ndk-build 來編譯 so 庫,是以 ndk 一定得配好,我本地的 ndk 版本是 r17,相信這個 ndk 的版本影響不是很大。

ndk 的配置,有 2 種方式,可以直接在 local.properties 檔案種修改,也可以在視圖界面,Project Structure 中選擇我們本地的 nkd 路徑來配置。下面截圖分别對應的是這 2 種不同的修改方式,采用其中任意一種即可。

這可能是介紹 Android UvcCamera 最詳細的文章了
這可能是介紹 Android UvcCamera 最詳細的文章了

2)導入 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

這可能是介紹 Android UvcCamera 最詳細的文章了

【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

這可能是介紹 Android UvcCamera 最詳細的文章了

【error3】

* What went wrong:

Execution failed for task ':libuvccamera:ndkBuild'.

> A problem occurred starting process 'command 'null/ndk-build.cmd''

這可能是介紹 Android UvcCamera 最詳細的文章了

【error4】

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.

【error5】

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 來追蹤記錄到。關于編譯報錯的,我們來看下我一共是修改了哪些内容。

這可能是介紹 Android UvcCamera 最詳細的文章了

上面截圖,我們看到一共是修改了 5 個地方。

i、工程根目錄下 build.gradle 的修改;

ii、libuvccamera/build.gradle 的修改;

3)拔出 usb 攝像頭,crash 異常導緻應用退出?

原生的庫檔案,有個 bug,就是在使用 usb 攝像頭的過程中,我們去把攝像頭拔掉,這時 so 庫有個 crash,到導緻我們的應用直接異常退出。

這個問題,網上的其它大神已經給出了解決方案,我這裡貼下修改的地方。我自己也是親自修改驗證了。

這可能是介紹 Android UvcCamera 最詳細的文章了
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 攝像頭識别不了?

有些同學可能還會遇到有些 usb 攝像頭識别不了的問題。這裡面有個前提,就是确認這個 usb 攝像頭,插到電腦上是能正常識别使用的,隻是插到我們的裝置上,識别不了。

遇到這種問題,可以抓個完整的 logcat 日志,然後在日志中全局搜尋 subclass,将搜尋到的 subclass 相關資訊,按照下面截圖的格式,在 xml 目錄下的 device_filter.xml 中配置下。

這可能是介紹 Android UvcCamera 最詳細的文章了

關于 uvcCamera 的内容,講到這裡就結束了。感謝大家的閱讀。也歡迎大家一起交流。

繼續閱讀