UVC Camera简单介绍

下面介绍UVC Camera工程的主要思路和调用过程。该工程主要驱动usb摄像头,进行打开,关闭,录像,拍照等一些操作,调用平台为android,通过外接usb camera进行调用。

(1)、工程主要依赖库有libuvccamera和usbCameraCommon两个库,其中libuvccamera库是底层库,包括c++实现部分,外加几个基本控制类,如USBMonitor和UVCCamera类等。

USBMonitor类负责管理usb设备类,从该类可以选出自己需要的usb camera设备。

UVCCamera则表示该类就是一个usb的摄像头,基本方法均调用native,通过jni方式直接调用c++实现。该类是一个桥接类,连接上层控制到底层实现的基本事件转发。

比如聚焦,亮度,缩放,白平衡,预览,打开,关闭等,均实际通过该类来实现。

CameraDialog则是以对话框的形式提供对USBMonitor的调用,如发现并找寻自己需要操作的设备,里面用到了DeviceFilter类,主要用来过滤设备,如果不过滤设备,则认为是所有usb设备,主要还是通过USBManager来获取设备,然后进行筛选,如:
 HashMap<String, UsbDevice> deviceList = mUsbManager.getDeviceList();
DeviceFilter类,这个是实际的筛选类,主要依据xml中的filter进行筛选,也就是说可以在xml中定义自己想要的设备的class,或者说不想要的设备的class,然后用xmlparser进行解析该xml文件,之后用此filter就可以过滤出实际想要的deviceList。

(2)usbCameraCommon库是上层封装库,主要用来操作调用摄像头,也就是USBMonitor和UVCCamera等。

上层调用比较主要的是AbstractUVCCameraHandler类,该类基本提供了对于UVCCamera的调用,然后同时开放api给Activity使用。

因为AbstractUVCCameraHandler类是一个Handler类,类定义是:

abstract class AbstractUVCCameraHandler extends Handler{...}

也就是说它主要负责消息发送接收,任何调用它的方法它都会转发给内部类,也就是其实内部主要维护的是一个Thread类,叫CameraThread,定义为:

static final class CameraThread extends Thread {...}

该CameraThread类为static类。任何发送给AbstractUVCCameraHandler的方法都会以消息的方式发送给CameraThread进行处理,当没有消息的时候,就什么也不做。以下可以看到转发过程:

	public void handleMessage(final Message msg) {
		final CameraThread thread = mWeakThread.get();
		if (thread == null) return;
		switch (msg.what) {
		case MSG_OPEN:
			thread.handleOpen((USBMonitor.UsbControlBlock)msg.obj);
			break;
		case MSG_CLOSE:
			thread.handleClose();
			break;
		case MSG_PREVIEW_START:
			thread.handleStartPreview(msg.obj);
			break;
		case MSG_PREVIEW_STOP:
			thread.handleStopPreview();
			break;
		case MSG_CAPTURE_STILL:
			thread.handleCaptureStill((String)msg.obj);
			break;
		case MSG_CAPTURE_START:
			thread.handleStartRecording();
			break;
		case MSG_CAPTURE_STOP:
			thread.handleStopRecording();
			break;
		case MSG_MEDIA_UPDATE:
			thread.handleUpdateMedia((String)msg.obj);
			break;
		case MSG_RELEASE:
			thread.handleRelease();
			break;
		default:
			throw new RuntimeException("unsupported message:what=" + msg.what);
		}
	}

然后CameraThread类内部持有UVCCamera类实例,所有调用CameraThread的方法又会发送给UVCCamera实例进行处理,举例如下:

开始预览的事件传递:

		public void handleStartPreview(final Object surface) {
			if (DEBUG) Log.v(TAG_THREAD, "handleStartPreview:");
			if ((mUVCCamera == null) || mIsPreviewing) return;
			try {
				mUVCCamera.setPreviewSize(mWidth, mHeight, 1, 31, mPreviewMode, mBandwidthFactor);
			} catch (final IllegalArgumentException e) {
				try {
					// fallback to YUV mode
					mUVCCamera.setPreviewSize(mWidth, mHeight, 1, 31, UVCCamera.DEFAULT_PREVIEW_MODE, mBandwidthFactor);
				} catch (final IllegalArgumentException e1) {
					callOnError(e1);
					return;
				}
			}
			if (surface instanceof SurfaceHolder) {
				mUVCCamera.setPreviewDisplay((SurfaceHolder)surface);
			} if (surface instanceof Surface) {
				mUVCCamera.setPreviewDisplay((Surface)surface);
			} else {
				mUVCCamera.setPreviewTexture((SurfaceTexture)surface);
			}
			mUVCCamera.startPreview();
			mUVCCamera.updateCameraParams();
			synchronized (mSync) {
				mIsPreviewing = true;
			}
			callOnStartPreview();
		}
开始录像:
		public void handleStartRecording() {
			if (DEBUG) Log.v(TAG_THREAD, "handleStartRecording:");
			try {
				if ((mUVCCamera == null) || (mMuxer != null)) return;
				final MediaMuxerWrapper muxer = new MediaMuxerWrapper(".mp4");	// if you record audio only, ".m4a" is also OK.
				MediaVideoBufferEncoder videoEncoder = null;
				switch (mEncoderType) {
				case 1:	// for video capturing using MediaVideoEncoder
					new MediaVideoEncoder(muxer, getWidth(), getHeight(), mMediaEncoderListener);
					break;
				case 2:	// for video capturing using MediaVideoBufferEncoder
					videoEncoder = new MediaVideoBufferEncoder(muxer, getWidth(), getHeight(), mMediaEncoderListener);
					break;
				// case 0:	// for video capturing using MediaSurfaceEncoder
				default:
					new MediaSurfaceEncoder(muxer, getWidth(), getHeight(), mMediaEncoderListener);
					break;
				}
				if (true) {
					// for audio capturing
					new MediaAudioEncoder(muxer, mMediaEncoderListener);
				}
				muxer.prepare();
				muxer.startRecording();
				if (videoEncoder != null) {
					mUVCCamera.setFrameCallback(mIFrameCallback, UVCCamera.PIXEL_FORMAT_NV21);
				}
				synchronized (mSync) {
					mMuxer = muxer;
					mVideoEncoder = videoEncoder;
				}
				callOnStartRecording();
			} catch (final IOException e) {
				callOnError(e);
				Log.e(TAG, "startCapture:", e);
			}
		}
可以看到,实际都是通过mUVCCamera进行调用的。

而UVCCamera则直接调用native层进行处理。

所以事件的处理实际上是这个流程:

Activity-->UVCCameraHandler--->AbstractUVCCameraHandler--->CameraThread--->UVCCamera--->native。

为什么说Activity先发送给了UVCCameraHandler,需要看构造过程。

在Activity调用示例中引用了UVCCameraHandler,也就是说UVCCameraHandler是实际操作摄像头的类,AbstractUVCCameraHandler因为是abstract,无法实例化,同时UVCCameraHandler继承了AbstractUVCCameraHandler,类关系为:

public class UVCCameraHandler extends AbstractUVCCameraHandler {。。。}

所以Activity中实例化了UVCCameraHandler后,发送给UVCCameraHandler的事件都经过消息发送给了CameraThread。然后CameraThread又发送给了UVCCamera类。

如下为实例化过程:

在Activity中实例化UVCCameraHandler代码为:

		final View view = findViewById(R.id.camera_view);
		mUVCCameraView = (CameraViewInterface)view;
		mUSBMonitor = new USBMonitor(this, mOnDeviceConnectListener);
		mCameraHandler = UVCCameraHandler.createHandler(this, mUVCCameraView,
			USE_SURFACE_ENCODER ? 0 : 1, PREVIEW_WIDTH, PREVIEW_HEIGHT, PREVIEW_MODE);
这里多贴了几行,方便后面介绍。

先看这句,

mCameraHandler = UVCCameraHandler.createHandler(this, mUVCCameraView,
   USE_SURFACE_ENCODER ? 0 : 1, PREVIEW_WIDTH, PREVIEW_HEIGHT, PREVIEW_MODE);

等于:

	public static final UVCCameraHandler createHandler(
			final Activity parent, final CameraViewInterface cameraView,
			final int encoderType, final int width, final int height, final int format) {

		return createHandler(parent, cameraView, encoderType, width, height, format, UVCCamera.DEFAULT_BANDWIDTH);
	}
等于:
	public static final UVCCameraHandler createHandler(
			final Activity parent, final CameraViewInterface cameraView,
			final int encoderType, final int width, final int height, final int format, final float bandwidthFactor) {

		final CameraThread thread = new CameraThread(UVCCameraHandler.class, parent, cameraView, encoderType, width, height, format, bandwidthFactor);
		thread.start();
		return (UVCCameraHandler)thread.getHandler();
	}
,也就是说,在Activity中实例化UVCCameraHandler其实就是构造了一个CameraThread,并将CameraThread中引用的UVCCameraHandler返回了回去。也就是说UVCCameraHandler一旦实例化,则CameraThread线程也创建了。

可以看到CameraThread中确实引用了UVCCameraHandler:

	static final class CameraThread extends Thread {
		private static final String TAG_THREAD = "CameraThread";
		private final Object mSync = new Object();
		private final Class<? extends AbstractUVCCameraHandler> mHandlerClass;
		private final WeakReference<Activity> mWeakParent;
		private final WeakReference<CameraViewInterface> mWeakCameraView;
		private final int mEncoderType;
		private final Set<CameraCallback> mCallbacks = new CopyOnWriteArraySet<CameraCallback>();
		private int mWidth, mHeight, mPreviewMode;
		private float mBandwidthFactor;
		private boolean mIsPreviewing;
		private boolean mIsRecording;
		/**
		 * shutter sound
		 */
		private SoundPool mSoundPool;
		private int mSoundId;
		private AbstractUVCCameraHandler mHandler;
		/**
		 * for accessing UVC camera
		 */
		private UVCCamera mUVCCamera;
		/**
		 * muxer for audio/video recording
		 */
		private MediaMuxerWrapper mMuxer;
		private MediaVideoBufferEncoder mVideoEncoder;

		/**
		 *
		 * @param clazz Class extends AbstractUVCCameraHandler
		 * @param parent parent Activity
		 * @param cameraView for still capturing
		 * @param encoderType 0: use MediaSurfaceEncoder, 1: use MediaVideoEncoder, 2: use MediaVideoBufferEncoder
		 * @param width
		 * @param height
		 * @param format either FRAME_FORMAT_YUYV(0) or FRAME_FORMAT_MJPEG(1)
		 * @param bandwidthFactor
		 */
		CameraThread(final Class<? extends AbstractUVCCameraHandler> clazz,
			final Activity parent, final CameraViewInterface cameraView,
			final int encoderType, final int width, final int height, final int format,
			final float bandwidthFactor) {

			super("CameraThread");
			mHandlerClass = clazz;
			mEncoderType = encoderType;
			mWidth = width;
			mHeight = height;
			mPreviewMode = format;
			mBandwidthFactor = bandwidthFactor;
			mWeakParent = new WeakReference<Activity>(parent);
			mWeakCameraView = new WeakReference<CameraViewInterface>(cameraView);
			loadShutterSound(parent);
		}
。。。。。
}
其中mHandlerClass就是UVCCameraHandler。

(3),在上面Activity中的调用中,初始化代码为:

		final View view = findViewById(R.id.camera_view);
		mUVCCameraView = (CameraViewInterface)view;
		mUSBMonitor = new USBMonitor(this, mOnDeviceConnectListener);
		mCameraHandler = UVCCameraHandler.createHandler(this, mUVCCameraView,
			USE_SURFACE_ENCODER ? 0 : 1, PREVIEW_WIDTH, PREVIEW_HEIGHT, PREVIEW_MODE);

其中mUSBMonitor类负责扫描设备并发现目标usb camera设备,然后mUVCCameraView负责预览页面,并将该预览页面传给UVCCameraHandler并传给CameraThread,见弱引用变量:

private final WeakReference<CameraViewInterface> mWeakCameraView;

也就是CameraThread完成了承上启下的作用,负责对上提供api调用,对下进行实际操作。

既有页面遇见,声音播放,操作控制UVCCamera,进行录像等各功能。

(4),native层

native层由java类UVCCamera发起调用,调用传递为jni-->UVCCamera-->UVCCamear.cpp--->UVCPreview.cpp

类,UVCCamear.cpp部分方法见下图:

 

 举例,如startPreview,stopPreview俩方法则又调用了UVCPreview 的方法,因为UVCCamear.cpp有引用UVCPreview.cpp指针:

UVCPreview *mPreview;

见下图:

int UVCCamera::startPreview() {
	ENTER();

	int result = EXIT_FAILURE;
	if (mDeviceHandle) {
		return mPreview->startPreview();
	}
	RETURN(result, int);
}

int UVCCamera::stopPreview() {
	ENTER();
	if (LIKELY(mPreview)) {
		mPreview->stopPreview();
	}
	RETURN(0, int);
}
UVCPreview.cpp的startPreview,stopPreview方法内容为:
int UVCPreview::startPreview() {
	ENTER();

	int result = EXIT_FAILURE;
	if (!isRunning()) {
		mIsRunning = true;
		pthread_mutex_lock(&preview_mutex);
		{
			if (LIKELY(mPreviewWindow)) {
				result = pthread_create(&preview_thread, NULL, preview_thread_func, (void *)this);
			}
		}
		pthread_mutex_unlock(&preview_mutex);
		if (UNLIKELY(result != EXIT_SUCCESS)) {
			LOGW("UVCCamera::window does not exist/already running/could not create thread etc.");
			mIsRunning = false;
			pthread_mutex_lock(&preview_mutex);
			{
				pthread_cond_signal(&preview_sync);
			}
			pthread_mutex_unlock(&preview_mutex);
		}
	}
	RETURN(result, int);
}

int UVCPreview::stopPreview() {
	ENTER();
	bool b = isRunning();
	if (LIKELY(b)) {
		mIsRunning = false;
		pthread_cond_signal(&preview_sync);
		pthread_cond_signal(&capture_sync);
		if (pthread_join(capture_thread, NULL) != EXIT_SUCCESS) {
			LOGW("UVCPreview::terminate capture thread: pthread_join failed");
		}
		if (pthread_join(preview_thread, NULL) != EXIT_SUCCESS) {
			LOGW("UVCPreview::terminate preview thread: pthread_join failed");
		}
		clearDisplay();
	}
	clearPreviewFrame();
	clearCaptureFrame();
	pthread_mutex_lock(&preview_mutex);
	if (mPreviewWindow) {
		ANativeWindow_release(mPreviewWindow);
		mPreviewWindow = NULL;
	}
	pthread_mutex_unlock(&preview_mutex);
	pthread_mutex_lock(&capture_mutex);
	if (mCaptureWindow) {
		ANativeWindow_release(mCaptureWindow);
		mCaptureWindow = NULL;
	}
	pthread_mutex_unlock(&capture_mutex);
	RETURN(0, int);
}
(5),UVCCameraTextureView类,该类是显示摄像头预览页面的类,非常重要,
public class UVCCameraTextureView extends AspectRatioTextureView   
	implements TextureView.SurfaceTextureListener, CameraViewInterface {
...}
因为时间关系,暂略。。。
 
 

 

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: UVCCamera 是一款非常实用的摄像头驱动程序和API。它是为 Android 设备设计的,可以用于访问和控制 USB 摄像头。 使用 UVCCamera 的第一步是在 Android 设备上下载并安装相应的驱动程序。然后,将摄像头连接到设备上的 USB 端口。一旦连接成功,我们就可以开始使用 UVCCamera 进行录像和拍照。 UVCCamera 具有丰富的功能。它支持多个摄像头同时连接,并可以实时预览摄像头的画面。此外,我们可以对摄像头的参数进行调整,如亮度、对比度、饱和度等,以获得更好的图像效果。 使用 UVCCamera 进行录像非常简单。首先,我们需要创建一个用于保存录像的文件。然后,通过调用 startRecording() 方法,即可开始录制。录像过程中,我们可以实时预览录像的画面,并可以随时停止录制。 除了录制,UVCCamera 还支持拍照功能。我们可以通过调用 takePicture() 方法,即可拍摄一张照片,并保存到指定的文件中。 在使用 UVCCamera 进行开发时,我们可以通过编写自定义的回调函数,来处理摄像头的各种事件。例如,我们可以监听摄像头的连接和断开事件,并在事件发生时进行相应的处理。 总之,UVCCamera 是一款功能强大且易于使用的摄像头驱动程序和API。无论是进行录像还是拍照,都可以通过简单的调用实现。它为 Android 设备提供了更多的摄像头功能,并为我们的应用程序提供了更多的可能性。 ### 回答2: UVCCamera是一款Android平台上常用的摄像头操作库,它提供了方便、灵活的摄像头连接和使用功能。下面是一个简要的教程介绍: 1. 导入依赖:首先,在你的Android项目中的build.gradle文件中添加UVCCamera的依赖项。 2. 设置权限:在AndroidManifest.xml文件中添加以下权限: <uses-feature android:name="android.hardware.usb.host" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.RECORD_AUDIO" /> 3. 初始化CameraHelper:在你的Activity类中创建一个CameraHelper对象来管理摄像头连接和调用功能: mCameraHelper = new CameraHelper(this); 4. 连接摄像头:使用CameraHelper的openCamera方法来连接摄像头: mCameraHelper.openCamera(new CameraHelper.OnCameraConnectListener() { @Override public void onCameraConnectError(Exception e) { // 连接错误处理 } @Override public void onCameraConnected() { // 摄像头连接成功处理 } @Override public void onCameraDisconnect() { // 摄像头断开连接处理 } }); 5. 预览画面:当摄像头连接成功后,可以使用CameraHelper的setPreviewTexture方法来设置预览画面的显示。你可以选择SurfaceView、TextureView或者自定义的View来显示预览画面。 6. 拍照或录制视频:通过CameraHelper的captureStill()方法来拍照,通过CameraHelper的startRecording()和stopRecording()方法来录制视频。 7. 释放资源:在不再使用摄像头时,要记得释放资源,可以在Activity的onDestroy()方法中调用CameraHelper的release()方法来释放资源。 除了上述基本功能,UVCCamera还提供了一些其他的功能和设置选项,比如设置分辨率、曝光、对焦、闪光灯等。 希望通过这个简要的教程,你能够对UVCCamera的基本使用有一个初步的了解。如果你有更多的需求和问题,可以查阅官方文档或者在相关的开发社区进行进一步的学习和讨论。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值