使用 Android-Camera2 API 访问 USB 摄像头

ale*_*apa 9 java android android-camera2

我有一个 UVC 摄像头,想要从我的 Android Pie (Android 9) 代码中访问和抓取帧。

这是我用来枚举连接到 Android 手机的摄像头的代码:

    @Override
    public void onResume()
    {
        CameraManager manager =
                (CameraManager)getSystemService(CAMERA_SERVICE);
        try {
            for (String cameraId : manager.getCameraIdList()) {
                CameraCharacteristics chars
                        = manager.getCameraCharacteristics(cameraId);
                // Do something with the characteristics
                int deviceLevel = chars.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL);
                Log.d(TAG, " **** device ["+cameraId+"] level:"+deviceLevel);
            }
        } catch(CameraAccessException e){
            e.printStackTrace();
        }
    }
Run Code Online (Sandbox Code Playgroud)

我在 Android 9/Pie (Pixel 3) 上跳来跳去,这显示了连接的 USB 摄像头。但是只列出了两个设备,手机的前置和后置摄像头。

这是我的清单文件 (AndroidManifest.xml) 中的功能和权限列表:

<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-feature android:name="android.hardware.usb.host" />
Run Code Online (Sandbox Code Playgroud)

我在互联网上找不到任何示例代码如何实现这一点,即访问在 Android 9 及更高版本上使用的 USB 摄像头。

我缺少什么让我的代码枚举 USB 摄像头?我见过一些适用于 Android 的 3rd 方 UVC 库,但我不想使用它们,而是想使用原生 Android 代码。

小智 17

我花了太长时间试图让它发挥作用,所以我想我应该与读到这篇文章的人分享我的发现。之前的海报已经提到了其中的大部分内容,但希望我可以添加一些有价值的内容。

  1. Android有Camera2 API,它似乎支持外部摄像头。据说您可以获取每个连接的相机的特征并寻找一个LENS_FACING_EXTERNAL

  2. 实际上,这似乎还不适用于许多手机。我在三部三星手机(S9、A31、A51)和一部 Google Pixel 2 XL 上进行了尝试。这给了我 Android 10 和 11 的混合版本。这些手机都不支持外部摄像头。

  3. 有些应用程序(例如USB Camera)仍然可以使其正常工作。我相信他们正在使用像UVCCamera这样的库。这基本上是一个完整的 UVC(USB 视频类)实现 + USB 主机,这最终允许您捕获视频。

  4. 我自己决定不使用 UVCCamera 的原因是它没有“Android Blessing”,并且在不同设备上或在 Android 升级期间,事情可能会以奇怪的方式出现问题。我自己没有能力支持这一点。

  5. 您可以轻松下载并构建Camera2Video示例 ( ./gradlew assembleRelease -x test),因为这为您提供了一个现成的应用程序,可以显示所有检测到的摄像机。您需要一个 USB OTG 适配器才能将网络摄像头插入手机,但只需几美元即可购买。

就目前的情况来看,Android 上对外部 USB 摄像头的支持有点令人悲伤。似乎没有官方支持的方式来使用可在大多数设备上使用的外部 USB 摄像头。

这里有一些示例代码,如果您愿意的话,可以让您尝试枚举自己手机上的摄像头。这只是从我自己的实验代码中提取的一些片段,因此错误处理/正确性很差。然而,据我所知,它仍然是您需要了解的最重要的代码片段。

public class CameraUtils {
    final Context context;
    final CameraManager cameraManager;
    
    public CameraUtils(Context context) {      
        this.context = context;  
        this.cameraManager = (CameraManager)context.getSystemService(Context.CAMERA_SERVICE);
    }
    
    /** 
    * Get the IDs of all available cameras.
    */
    public String[] getCameraIds() {
        return this.cameraManager.getCameraIdList();
    }
        
    /**
    * Get the "lens facing" for a particular camera ID returned by `getCameraIds()`.
    */
    public bool getLensFacing(String cameraId) {        
        CameraCharacteristics characteristics = this.cameraManager.getCameraCharacteristics(cameraId);
        
        // This will return one of CameraMetadata.LENS_FACING_FRONT,
        // CameraMetadata.LENS_FACING_BACK or CameraMetadata.LENS_FACING_EXTERNAL.
        return characteristics.get(CameraCharacteristics.LENS_FACING);
    }
    
    /**
    * Return true if this kernel supports external cameras, false otherwise.
    */
    public bool supportsExternalCameras() {
        return this.context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_EXTERNAL);        
    }
}
Run Code Online (Sandbox Code Playgroud)

PS 我已尽力确保此信息正确。如果我有什么不对的地方,请随时纠正我!关于如何在 Android 上使用外部 USB 摄像头的文档充其量也很少。


ese*_*sov 10

您可以使用常量FEATURE_CAMERA_EXTERNAL调用PackageManager.hasSystemFeature来检查您的设备是否支持外部摄像头。Pixel 3 不支持此功能。

事实上,有多个库和应用程序提供 USB 摄像头支持。但他们不使用 android API 并自己实现一切。最常见的方法似乎是使用Video for linux内核模块(如果内核是用这个模块编译的)。它还需要访问/dev/video设备的权限,这在非 root 设备上通常不是这种情况。但实现相当简单。例如android-webcam使用这种方法。

另一种方法是使用USB 主机 api并自己实现所有协议。这不需要 root 访问权限,但实现要复杂得多。你可以检查这个库是这样的。


ale*_*apa 7

我想我找到了自己问题的答案。我购买了三星 Galaxy S10e,没有任何修改的完全相同的代码将 USB 摄像头作为列表中的第一个返回。即这条线Log.d(TAG, " **** device ["+cameraId+"] level:"+deviceLevel);打印 3 次,一次用于 USB 摄像头,两次用于内部摄像头。

我最好的猜测是,大多数在 2018 年 10 月发布 Android 9 之后设计和制造的手机都启用了此功能。大约在那个时间或之前发布然后后来收到 Android 9 (Pie) 更新的手机不太可能具有此功能。

  • 所以 **Samsung Galaxy S10e** `packageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA_EXTERNAL)` 返回 `true` 而在 **Samsung Galaxy S10** 上它返回 `false`? (3认同)