移动端的UVC协议分析是基于github上开源项目UVCCamera的。
谷歌官方推荐使用该项目作为开发UVC相关APP的参考实现。
这个项目整合了libjpeg-turbo, libusb, libuvc和rapidjson等基础c开源库,封装了供Java层调用的native接口函数(jni),增加了logcat相关日志打印,然后封装成为libuvccamera的Java包。
同时,该项目也提供了8个例子供大家调试使用,每个例子都可以单独编译成独立APP。
以usbCameraTest8为例,其源文件结构如下:
可以看到,就一个MainActivity.java文件。
打开这个文件,可以看到,这是一个标准的Android APP的activity类,里面实现了onCreate(),onDestroy(),onStart(),onStop()等基本接口函数。
onCreate()
在onCreate函数中,定义了两个实例:
注意一下mOnDeviceConnectListener这个listener,它的实现如下:
private final OnDeviceConnectListener mOnDeviceConnectListener = new OnDeviceConnectListener() {
@Override
public void onAttach(final UsbDevice device) {
Toast.makeText(MainActivity.this, "USB_DEVICE_ATTACHED", Toast.LENGTH_SHORT).show();
}
@Override
public void onConnect(final UsbDevice device, final UsbControlBlock ctrlBlock, final boolean createNew) {
if (DEBUG) Log.v(TAG, "onConnect:");
mCameraHandler.open(ctrlBlock);
startPreview();
updateItems();
}
@Override
public void onDisconnect(final UsbDevice device, final UsbControlBlock ctrlBlock) {
if (DEBUG) Log.v(TAG, "onDisconnect:");
if (mCameraHandler != null) {
queueEvent(new Runnable() {
@Override
public void run() {
mCameraHandler.close();
}
}, 0);
setCameraButton(false);
updateItems();
}
}
@Override
public void onDettach(final UsbDevice device) {
Toast.makeText(MainActivity.this, "USB_DEVICE_DETACHED", Toast.LENGTH_SHORT).show();
}
@Override
public void onCancel(final UsbDevice device) {
setCameraButton(false);
}
};
在这个listener中,定义了USB摄像头与手机连接/断开等情况下,程序将如何执行,比如,当设备attach上后,会有一行提示语:“USB_DEVICE_ATTACHED”,当点击APP上的按钮去打开设备时,会调用onConnect()函数,调用UVCCameraHandler.open,同时启动预览。
onStart()
在onStart()中,注册了USBMonitor,从此刻起,系统开始监听USB口上的消息。
onStop()
关闭UVCCameraHandler,关闭相机控制相关按钮动作;
onDestroy()
释放UVCCameraHandler,关闭USBMonitor;
再回头看一下刚才在onCreate()中定义的那两个实例:
mUSBMonitor,mCameraHandler
它们的类USBMonitor和UVCCameraHandler分别位于:
USBMonitor用于监听手机USB口上的各种消息,并作出相应的动作,比如启动预览什么的。但是如果用户希望从APP上操作相机,比如拍照、录像或者设置相关相机参数,就需要调用UVCCameraHandler了。
UVCCameraHandler相关代码位于usbCameraCommon文件夹下,它继承了AbstractUVCCameraHandler这个类。在AbstractUVCCameraHandler这个类中,定义了一个名为CameraThread的类,在这个线程中,具体执行了拍照、录像、预览等相关函数;
到现在为止,可以看到,APP的MainActivity主要是调用USBCameraCommon中的UVCCameraHandler和AbstractUVCCameraHandler,而后者又进一步去调用libuvccamera文件夹下的UVCCamera.java。
可以看到,在libuvccamera目录里的文件如下:
UVCCamera.java是很薄的一层接口层,类似一个glue layer,向上对接UVCCameraHandler和APP,向下对接native层的c语言实现,显然,重头戏都在下面的c代码里,但是UVCCamera.java可以直观的展现手机APP可以操作相机的哪些功能,下面是native函数列表:
Get Method
Reset Method
Set Method
Camera Operation
USBMonitor.java的作用主要是用来监控USB口的事件(OnDeviceConnectListener : interface),获取相关usb设备信息(UsbControlBlock : class & UsbDeviceInfo : class)等。
上面基本就是java层代码的一个大概层次结构,接下来我们就进入底层的native函数,看看uvc到底是怎么运作的。
《============================================》
在UVCCamera.java中,声明了大量的native接口函数:
// #nativeCreate and #nativeDestroy are not static methods.
private final native long nativeCreate();
private final native void nativeDestroy(final long id_camera);
private final native int nativeConnect(long id_camera, int venderId, int productId, int fileDescriptor, int busNum, int devAddr, String usbfs);
private static final native int nativeRelease(final long id_camera);
private static final native int nativeSetStatusCallback(final long mNativePtr, final IStatusCallback callback);
private static final native int nativeSetButtonCallback(final long mNativePtr, final IButtonCallback callback);
private static final native int nativeSetPreviewSize(final long id_camera, final int width, final int height, final int min_fps, final int max_fps, final int mode, final float bandwidth);
private static final native String nativeGetSupportedSize(final long id_camera);
private static final native int nativeStartPreview(final long id_camera);
private static final native int nativeStopPreview(final long id_camera);
private static final native int nativeSetPreviewDisplay(final long id_camera, final Surface surface);
private static final native int nativeSetFrameCallback(final long mNativePtr, final IFrameCallback callback, final int pixelFormat);
private static final native int nativeSetCaptureDisplay(final long id_camera, final Surface surface);
private static final native long nativeGetCtrlSupports(final long id_camera);
private static final native long nativeGetProcSupports(final long id_camera);
private final native int nativeUpdateScanningModeLimit(final long id_camera);
private static final native int nativeSetScanningMode(final long id_camera, final int scanning_mode);
private static final native int nativeGetScanningMode(final long id_camera);
private final native int nativeUpdateExposureModeLimit(final long id_camera);
private static final native int nativeSetExposureMode(final long id_camera, final int exposureMode);
private static final native int nativeGetExposureMode(final long id_camera);
private final native int nativeUpdateExposurePriorityLimit(final long id_camera);
private static final native int nativeSetExposurePriority(final long id_camera, final int priority);
private static final native int nativeGetExposurePriority(final long id_camera);
private final native int nativeUpdateExposureLimit(final long id_camera);
private static final native int nativeSetExposure(final long id_camera, final int exposure);
private static final native int nativeGetExposure(final long id_camera);
private final native int nativeUpdateExposureRelLimit(final long id_camera);
private static final native int nativeSetExposureRel(final long id_camera, final int exposure_rel);
private static final native int nativeGetExposureRel(final long id_camera);
private final native int nativeUpdateAutoFocusLimit(final long id_camera);
private static final native int nativeSetAutoFocus(final long id_camera, final boolean autofocus);
private static final native int nativeGetAutoFocus(final long id_camera);
private final native int nativeUpdateFocusLimit(final long id_camera);
private static final native int nativeSetFocus(final long id_camera, final int focus);
private static final native int nativeGetFocus(final long id_camera);
private final native int nativeUpdateFocusRelLimit(final long id_camera);
private static final native int nativeSetFocusRel(final long id_camera, final int focus_rel);
private static final native int nativeGetFocusRel(final long id_camera);
private final native int nativeUpdateIrisLimit(final long id_camera);
private static final native int nativeSetIris(final long id_camera, final int iris);
private static final native int nativeGetIris(final long id_camera);
private final native int nativeUpdateIrisRelLimit(final long id_camera);
private static final native int nativeSetIrisRel(final long id_camera, final int iris_rel);
private static final native int nativeGetIrisRel(final long id_camera);
private final native int nativeUpdatePanLimit(final long id_camera);
private static final native int nativeSetPan(final long id_camera, final int pan);
private static final native int nativeGetPan(final long id_camera);
private final native int nativeUpdatePanRelLimit(final long id_camera);
private static final native int nativeSetPanRel(final long id_camera, final int pan_rel);
private static final native int nativeGetPanRel(final long id_camera);
private final native int nativeUpdateTiltLimit(final long id_camera);
private static final native int nativeSetTilt(final long id_camera, final int tilt);
private static final native int nativeGetTilt(final long id_camera);
private final native int nativeUpdateTiltRelLimit(final long id_camera);
private static final native int nativeSetTiltRel(final long id_camera, final int tilt_rel);
private static final native int nativeGetTiltRel(final long id_camera);
private final native int nativeUpdateRollLimit(final long id_camera);
private static final native int nativeSetRoll(final long id_camera, final int roll);
private static final native int nativeGetRoll(final long id_camera);
private final native int nativeUpdateRollRelLimit(final long id_camera);
private static final native int nativeSetRollRel(final long id_camera, final int roll_rel);
private static final native int nativeGetRollRel(final long id_camera);
private final native int nativeUpdateAutoWhiteBlanceLimit(final long id_camera);
private static final native int nativeSetAutoWhiteBlance(final long id_camera, final boolean autoWhiteBlance);
private static final native int nativeGetAutoWhiteBlance(final long id_camera);
private final native int nativeUpdateAutoWhiteBlanceCompoLimit(final long id_camera);
private static final native int nativeSetAutoWhiteBlanceCompo(final long id_camera, final boolean autoWhiteBlanceCompo);
private static final native int nativeGetAutoWhiteBlanceCompo(final long id_camera);
private final native int nativeUpdateWhiteBlanceLimit(final long id_camera);
private static final native int nativeSetWhiteBlance(final long id_camera, final int whiteBlance);
private static final native int nativeGetWhiteBlance(final long id_camera);
private final native int nativeUpdateWhiteBlanceCompoLimit(final long id_camera);
private static final native int nativeSetWhiteBlanceCompo(final long id_camera, final int whiteBlance_compo);
private static final native int nativeGetWhiteBlanceCompo(final long id_camera);
private final native int nativeUpdateBacklightCompLimit(final long id_camera);
private static final native int nativeSetBacklightComp(final long id_camera, final int backlight_comp);
private static final native int nativeGetBacklightComp(final long id_camera);
private final native int nativeUpdateBrightnessLimit(final long id_camera);
private static final native int nativeSetBrightness(final long id_camera, final int brightness);
private static final native int nativeGetBrightness(final long id_camera);
private final native int nativeUpdateContrastLimit(final long id_camera);
private static final native int nativeSetContrast(final long id_camera, final int contrast);
private static final native int nativeGetContrast(final long id_camera);
private final native int nativeUpdateAutoContrastLimit(final long id_camera);
private static final native int nativeSetAutoContrast(final long id_camera, final boolean autocontrast);
private static final native int nativeGetAutoContrast(final long id_camera);
private final native int nativeUpdateSharpnessLimit(final long id_camera);
private static final native int nativeSetSharpness(final long id_camera, final int sharpness);
private static final native int nativeGetSharpness(final long id_camera);
private final native int nativeUpdateGainLimit(final long id_camera);
private static final native int nativeSetGain(final long id_camera, final int gain);
private static final native int nativeGetGain(final long id_camera);
private final native int nativeUpdateGammaLimit(final long id_camera);
private static final native int nativeSetGamma(final long id_camera, final int gamma);
private static final native int nativeGetGamma(final long id_camera);
private final native int nativeUpdateSaturationLimit(final long id_camera);
private static final native int nativeSetSaturation(final long id_camera, final int saturation);
private static final native int nativeGetSaturation(final long id_camera);
private final native int nativeUpdateHueLimit(final long id_camera);
private static final native int nativeSetHue(final long id_camera, final int hue);
private static final native int nativeGetHue(final long id_camera);
private final native int nativeUpdateAutoHueLimit(final long id_camera);
private static final native int nativeSetAutoHue(final long id_camera, final boolean autohue);
private static final native int nativeGetAutoHue(final long id_camera);
private final native int nativeUpdatePowerlineFrequencyLimit(final long id_camera);
private static final native int nativeSetPowerlineFrequency(final long id_camera, final int frequency);
private static final native int nativeGetPowerlineFrequency(final long id_camera);
private final native int nativeUpdateZoomLimit(final long id_camera);
private static final native int nativeSetZoom(final long id_camera, final int zoom);
private static final native int nativeGetZoom(final long id_camera);
private final native int nativeUpdateZoomRelLimit(final long id_camera);
private static final native int nativeSetZoomRel(final long id_camera, final int zoom_rel);
private static final native int nativeGetZoomRel(final long id_camera);
private final native int nativeUpdateDigitalMultiplierLimit(final long id_camera);
private static final native int nativeSetDigitalMultiplier(final long id_camera, final int multiplier);
private static final native int nativeGetDigitalMultiplier(final long id_camera);
private final native int nativeUpdateDigitalMultiplierLimitLimit(final long id_camera);
private static final native int nativeSetDigitalMultiplierLimit(final long id_camera, final int multiplier_limit);
private static final native int nativeGetDigitalMultiplierLimit(final long id_camera);
private final native int nativeUpdateAnalogVideoStandardLimit(final long id_camera);
private static final native int nativeSetAnalogVideoStandard(final long id_camera, final int standard);
private static final native int nativeGetAnalogVideoStandard(final long id_camera);
private final native int nativeUpdateAnalogVideoLockStateLimit(final long id_camera);
private static final native int nativeSetAnalogVideoLoackState(final long id_camera, final int state);
private static final native int nativeGetAnalogVideoLoackState(final long id_camera);
private final native int nativeUpdatePrivacyLimit(final long id_camera);
private static final native int nativeSetPrivacy(final long id_camera, final boolean privacy);
private static final native int nativeGetPrivacy(final long id_camera);
这些native函数与libuvc库函数的对接位于UVCCamera/libuvccamera/src/main/jni/UVCCamera/serenegiant_usb_UVCCamera.cpp这个文件中。
我们以简单的nativeConnect函数为例,看看它的实现:
这个camera->connect定义在类UVCCamera中,进入UVCCamera.cpp文件,我们可以看到,其实现如下:
忍不住吐槽一句,这么知名的项目居然用日文注释,实在是不专业!
不过骂归骂,从这层函数开始,我们就开始真正调用libuvc库函数了。比如uvc_open()。接下来的故事,就可以参考本系列第二篇libuvc一文。