Android UVC驅動外接攝像頭
阿新 • • 發佈:2019-02-18
簡單記錄一下開發中遇到的手機驅動外接攝像頭,目前只能針對個別機型,像小米,魅族MX2,ZTE測試過是可行的,Lenovo,VIVO,華為由於關閉了外接裝置,並不支援外接攝像頭。攝像頭要支援UVC軟碟機。另外要注意,攝像頭預覽解析度要是手機/平板解析度和攝像頭支援的解析度交集,Demo中將檢視解析度的程式碼解開(程式碼改為true)可以檢視兩者支援的解析度。還是有很多問題的,距離商用還有一段距離,僅供參考,還請感興趣的大牛聯絡完善。
在平板測試過程中發現效能比較好的品牌平板表現良好,不過遇到一個棘手的問題就是HOME與BACk鍵交叉使用會導致影象不再顯示,手機顯示蠻好,平板表現比較次。
專案建立
本專案在EC下建立取名為UVCDemo,包名:com.serenegiant.uvccamera,我們先把底層庫引入:
如果會NDK的話請研究jni檔案:
資原始檔:
許可權如下:
- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
- <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
- <uses-permission android:name
="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" /> - <uses-permission android:name="android.permission.CAMERA"/>
上述許可權並不是都要有,由於肯定牽扯到聯網所以要有網路相關的許可權,根據需求增刪(本專案所用如下)
- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
- <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"
/> - <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
- <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
- <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
- <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
- <uses-permission android:name="android.permission.INTERNET" />
- <uses-permission android:name="android.permission.CAMERA"/>
- <!-- 遮蔽HOME鍵需要的許可權 -->
- <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
- <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
- <!-- 開機自啟動需要的許可權 -->
- <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
核心程式碼
原理是使用UVCCamera來控制、管理與外接裝置的連線,UVCCameraTextureView控制元件進行影象的預覽,USBMonitor進行驅動的連線和斷開 先在需要的地方新增控制元件:
- <com.serenegiant.usb.widget.UVCCameraTextureView
- android:id=“@+id/camera_view”
- android:layout_width=“match_parent”
- android:layout_height=“match_parent”
- android:layout_centerHorizontal=“true”
- android:layout_centerVertical=“true” />
我在CaptureActivity初始化:
- final View view = findViewById(R.id.camera_view);
- mUVCCameraView = (CameraViewInterface)view;
- mUVCCameraView.setAspectRatio(PREVIEW_WIDTH / (float)PREVIEW_HEIGHT);//TODO
- mUSBMonitor = new USBMonitor(this, mOnDeviceConnectListener);
- mHandler = CameraHandler.createHandler(this, mUVCCameraView);
我通過CameraHandler將事件分發出去,裡面包含了對外接攝像頭的所有操作,拍照啊、錄影啊、釋放資源啊等等
在使用“.so”庫的時候記得新增庫才能使用本地語言
- System.loadLibrary(“usb100”);
- System.loadLibrary(“uvc”);
- System.loadLibrary(“UVCCamera”);
預覽的呼叫等都是通過呼叫native的方法c++實現的
- /**
- * start preview
- */
- public void startPreview() {
- if (mCtrlBlock != null) {
- nativeStartPreview(mNativePtr);
- }
- }
- /**
- * stop preview
- */
- public void stopPreview() {
- setFrameCallback(null, 0);
- if (mCtrlBlock != null) {
- nativeStopPreview(mNativePtr);
- }
- }
驅動連線方面,我們自定義一個規則
- <?xml version=“1.0” encoding=“utf-8”?>
- <usb>
- <usb-device class=“239” subclass=“2” /> <!– all device of UVC –>
- </usb>
驅動列表是通過Android的USBManager獲取得到的
- /**
- * Returns a HashMap containing all USB devices currently attached.
- * USB device name is the key for the returned HashMap.
- * The result will be empty if no devices are attached, or if
- * USB host mode is inactive or unsupported.
- *
- * @return HashMap containing all connected USB devices.
- */
- public HashMap<String,UsbDevice> getDeviceList() {
- Bundle bundle = new Bundle();
- try {
- mService.getDeviceList(bundle);
- HashMap<String,UsbDevice> result = new HashMap<String,UsbDevice>();
- for (String name : bundle.keySet()) {
- result.put(name, (UsbDevice)bundle.get(name));
- }
- return result;
- } catch (RemoteException e) {
- Log.e(TAG, “RemoteException in getDeviceList”, e);
- return null;
- }
- }
專案原始碼
UVCCamera
- package com.serenegiant.usb;
- /*
- * UVCCamera
- * library and sample to access to UVC web camera on non-rooted Android device
- *
- * Copyright (c) 2014-2015 saki [email protected]
- *
- * File name: UVCCamera.java
- *
- * Licensed under the Apache License, Version 2.0 (the “License”);
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an “AS IS” BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * All files in the folder are under this Apache License, Version 2.0.
- * Files in the jni/libjpeg, jni/libusb, jin/libuvc, jni/rapidjson folder may have a different license, see the respective files.
- */
- import java.util.ArrayList;
- import java.util.List;
- import org.json.JSONArray;
- import org.json.JSONException;
- import org.json.JSONObject;
- import android.graphics.SurfaceTexture;
- import android.hardware.usb.UsbDevice;
- import android.text.TextUtils;
- import android.util.Log;
- import android.view.Surface;
- import android.view.SurfaceHolder;
- import com.serenegiant.usb.USBMonitor.UsbControlBlock;
- public class UVCCamera {
- private static final boolean DEBUG = false; // TODO set false when releasing
- private static final String TAG = UVCCamera.class.getSimpleName();
- private static final String DEFAULT_USBFS = “/dev/bus/usb”;
- public static final int DEFAULT_PREVIEW_WIDTH = 1600;//640
- public static final int DEFAULT_PREVIEW_HEIGHT = 1200;//480
- public static final int DEFAULT_PREVIEW_MODE = 0;
- public static final float DEFAULT_BANDWIDTH = 1.0f;
- public static final int FRAME_FORMAT_YUYV = 0;
- public static final int FRAME_FORMAT_MJPEG = 1;
- public static final int PIXEL_FORMAT_RAW = 0;
- public static final int PIXEL_FORMAT_YUV = 1;
- public static final int PIXEL_FORMAT_RGB565 = 2;
- public static final int PIXEL_FORMAT_RGBX = 3;
- public static final int PIXEL_FORMAT_YUV420SP = 4;
- public static final int PIXEL_FORMAT_NV21 = 5; // = YVU420SemiPlanar
- //——————————————————————————–
- public static final int CTRL_SCANNING = 0x00000001; // D0: Scanning Mode
- public static final int CTRL_AE = 0x00000002; // D1: Auto-Exposure Mode
- public static final int CTRL_AE_PRIORITY = 0x00000004; // D2: Auto-Exposure Priority
- public static final int CTRL_AE_ABS = 0x00000008; // D3: Exposure Time (Absolute)
- public static final int CTRL_AR_REL = 0x00000010; // D4: Exposure Time (Relative)
- public static final int CTRL_FOCUS_ABS = 0x00000020; // D5: Focus (Absolute)
- public static final int CTRL_FOCUS_REL = 0x00000040; // D6: Focus (Relative)
- public static final int CTRL_IRIS_ABS = 0x00000080; // D7: Iris (Absolute)
- public static final int CTRL_IRIS_REL = 0x00000100; // D8: Iris (Relative)
- public static final int CTRL_ZOOM_ABS = 0x00000200; // D9: Zoom (Absolute)
- public static final int CTRL_ZOOM_REL = 0x00000400; // D10: Zoom (Relative)
- public static final int CTRL_PANTILT_ABS = 0x00000800; // D11: PanTilt (Absolute)
- public static final int CTRL_PANTILT_REL = 0x00001000; // D12: PanTilt (Relative)
- public static final int CTRL_ROLL_ABS = 0x00002000; // D13: Roll (Absolute)
- public static final int CTRL_ROLL_REL = 0x00004000; // D14: Roll (Relative)
- public static final int CTRL_FOCUS_AUTO = 0x00020000; // D17: Focus, Auto
- public static final int CTRL_PRIVACY = 0x00040000; // D18: Privacy
- public static final int CTRL_FOCUS_SIMPLE = 0x00080000; // D19: Focus, Simple
- public static final int CTRL_WINDOW = 0x00100000; // D20: Window
- public static final int PU_BRIGHTNESS = 0x80000001; // D0: Brightness
- public static final int PU_CONTRAST = 0x80000002; // D1: Contrast
- public static final int PU_HUE = 0x80000004; // D2: Hue
- public static final int PU_SATURATION = 0x80000008; // D3: Saturation
- public static final int PU_SHARPNESS = 0x80000010; // D4: Sharpness
- public static final int PU_GAMMA = 0x80000020; // D5: Gamma
- public static final int PU_WB_TEMP = 0x80000040; // D6: White Balance Temperature
- public static final int PU_WB_COMPO = 0x80000080; // D7: White Balance Component
- public static final int PU_BACKLIGHT = 0x80000100; // D8: Backlight Compensation
- public static final int PU_GAIN = 0x80000200; // D9: Gain
- public static final int PU_POWER_LF = 0x80000400; // D10: Power Line Frequency
- public static final int PU_HUE_AUTO = 0x80000800; // D11: Hue, Auto
- public static final int PU_WB_TEMP_AUTO = 0x80001000; // D12: White Balance Temperature, Auto
- public static final int PU_WB_COMPO_AUTO = 0x80002000; // D13: White Balance Component, Auto
- public static final int PU_DIGITAL_MULT = 0x80004000; // D14: Digital Multiplier
- public static final int PU_DIGITAL_LIMIT = 0x80008000; // D15: Digital Multiplier Limit
- public static final int PU_AVIDEO_STD = 0x80010000; // D16: Analog Video Standard
- public static final int PU_AVIDEO_LOCK = 0x80020000; // D17: Analog Video Lock Status
- public static final int PU_CONTRAST_AUTO = 0x80040000; // D18: Contrast, Auto
- // uvc_status_class from libuvc.h
- public static final int STATUS_CLASS_CONTROL = 0x10;
- public static final int STATUS_CLASS_CONTROL_CAMERA = 0x11;
- public static final int STATUS_CLASS_CONTROL_PROCESSING = 0x12;
- // uvc_status_attribute from libuvc.h
- public static final int STATUS_ATTRIBUTE_VALUE_CHANGE = 0x00;
- public static final int STATUS_ATTRIBUTE_INFO_CHANGE = 0x01;
- public static final int STATUS_ATTRIBUTE_FAILURE_CHANGE = 0x02;
- public static final int STATUS_ATTRIBUTE_UNKNOWN = 0xff;
- private static boolean isLoaded;
- static {
- if (!isLoaded) {
- System.loadLibrary(“usb100”);
- System.loadLibrary(“uvc”);
- System.loadLibrary(“UVCCamera”);
- isLoaded = true;
- }
- }
- private UsbControlBlock mCtrlBlock;
- protected long mControlSupports; // カメラコントロールでサポートしている機能フラグ
- protected long mProcSupports; // プロセッシングユニットでサポートしている機能フラグ
- protected int mCurrentPreviewMode = 0;
- protected int mCurrentPreviewWidth = DEFAULT_PREVIEW_WIDTH, mCurrentPreviewHeight = DEFAULT_PREVIEW_HEIGHT;
- protected String mSupportedSize;
- // these fields from here are accessed from native code and do not change name and remove
- protected long mNativePtr;
- protected int mScanningModeMin, mScanningModeMax, mScanningModeDef;
- protected int mExposureModeMin, mExposureModeMax, mExposureModeDef;
- protected int mExposurePriorityMin, mExposurePriorityMax, mExposurePriorityDef;
- protected int mExposureMin, mExposureMax, mExposureDef;
- protected int mAutoFocusMin, mAutoFocusMax, mAutoFocusDef;
- protected int mFocusMin, mFocusMax, mFocusDef;
- protected int mFocusRelMin, mFocusRelMax, mFocusRelDef;
- protected int mFocusSimpleMin, mFocusSimpleMax, mFocusSimpleDef;
- protected int mIrisMin, mIrisMax, mIrisDef;
- protected int mIrisRelMin, mIrisRelMax, mIrisRelDef;
- protected int mPanMin, mPanMax, mPanDef;
- protected int mTiltMin, mTiltMax, mTiltDef;
- protected int mRollMin, mRollMax, mRollDef;
- protected int mPanRelMin, mPanRelMax, mPanRelDef;
- protected int mTiltRelMin, mTiltRelMax, mTiltRelDef;
- protected int mRollRelMin, mRollRelMax, mRollRelDef;
- protected int mPrivacyMin, mPrivacyMax, mPrivacyDef;
- protected int mAutoWhiteBlanceMin, mAutoWhiteBlanceMax, mAutoWhiteBlanceDef;
- protected int mAutoWhiteBlanceCompoMin, mAutoWhiteBlanceCompoMax, mAutoWhiteBlanceCompoDef;
- protected int mWhiteBlanceMin, mWhiteBlanceMax, mWhiteBlanceDef;
- protected int mWhiteBlanceCompoMin, mWhiteBlanceCompoMax, mWhiteBlanceCompoDef;
- protected int mWhiteBlanceRelMin, mWhiteBlanceRelMax, mWhiteBlanceRelDef;
- protected int mBacklightCompMin, mBacklightCompMax, mBacklightCompDef;
- protected int mBrightnessMin, mBrightnessMax, mBrightnessDef;
- protected int mContrastMin, mContrastMax, mContrastDef;
- protected int mSharpnessMin, mSharpnessMax, mSharpnessDef;
- protected int mGainMin, mGainMax, mGainDef;
- protected int mGammaMin, mGammaMax, mGammaDef;
- protected int mSaturationMin, mSaturationMax, mSaturationDef;
- protected int mHueMin, mHueMax, mHueDef;
- protected int mZoomMin, mZoomMax, mZoomDef;
- protected int mZoomRelMin, mZoomRelMax, mZoomRelDef;
- protected int mPowerlineFrequencyMin, mPowerlineFrequencyMax, mPowerlineFrequencyDef;
- protected int mMultiplierMin, mMultiplierMax, mMultiplierDef;
- protected int mMultiplierLimitMin, mMultiplierLimitMax, mMultiplierLimitDef;
- protected int mAnalogVideoStandardMin, mAnalogVideoStandardMax, mAnalogVideoStandardDef;
- protected int mAnalogVideoLockStateMin, mAnalogVideoLockStateMax, mAnalogVideoLockStateDef;
- // until here
- /**
- * the sonctructor of this class should be call within the thread that has a looper
- * (UI thread or a thread that called Looper.prepare)
- */
- public UVCCamera() {
- mNativePtr = nativeCreate();
- mSupportedSize = null;
- }
- /**
- * connect to a UVC camera
- * USB permission is necessary before this method is called
- * @param ctrlBlock
- */
- public void open(final UsbControlBlock ctrlBlock) {
- mCtrlBlock = ctrlBlock;
- nativeConnect(mNativePtr,
- mCtrlBlock.getVenderId(), mCtrlBlock.getProductId(),
- mCtrlBlock.getFileDescriptor(),
- getUSBFSName(mCtrlBlock));
- if (mNativePtr != 0 && TextUtils.isEmpty(mSupportedSize)) {
- mSupportedSize = nativeGetSupportedSize(mNativePtr);
- }
- nativeSetPreviewSize(mNativePtr, DEFAULT_PREVIEW_WIDTH, DEFAULT_PREVIEW_HEIGHT, DEFAULT_PREVIEW_MODE, DEFAULT_BANDWIDTH);
- }
- /**
- * set status callback
- * @param callback
- */
- public void setStatusCallback(final IStatusCallback callback) {
- if (mNativePtr != 0) {
- nativeSetStatusCallback(mNativePtr, callback);
- }
- }
- /**
- * set button callback
- * @param callback
- */
- public void setButtonCallback(final IButtonCallback callback) {
- if (mNativePtr != 0) {
- nativeSetButtonCallback(mNativePtr, callback);
- }
- }
- /**
- * close and release UVC camera
- */
- public void close() {
- stopPreview();
- if (mNativePtr != 0) {
- nativeRelease(mNativePtr);
- }
- mCtrlBlock = null;
- mControlSupports = mProcSupports = 0;
- mCurrentPreviewMode = -1;
- }
- public UsbDevice getDevice() {
- return mCtrlBlock != null ? mCtrlBlock.getDevice() : null;
- }
- public String getDeviceName(){
- return mCtrlBlock != null ? mCtrlBlock.getDeviceName() : null;
- }
- public UsbControlBlock getUsbControlBlock() {
- return mCtrlBlock;
- }
- public synchronized String getSupportedSize() {
- return !TextUtils.isEmpty(mSupportedSize) ? mSupportedSize : (mSupportedSize = nativeGetSupportedSize(mNativePtr));
- }
- public Size getPreviewSize() {
- Size result = null;
- final List<Size> list = getSupportedSizeList();
- for (final Size sz: list) {
- if ((sz.width == mCurrentPreviewWidth)
- || (sz.height == mCurrentPreviewHeight)) {
- result =sz;
- break;
- }
- }
- return result;
- }
- /**
-