WebRTC源码分析之Video Capture

来源:互联网 发布:steam 知乎 编辑:程序博客网 时间:2024/05/01 16:18

Video Capture依赖于平台,这里针对Android平台进行分析.

1.  Video Capture的数据流:


Camera输出两路数据, 一路直接render并在SurfaceView上显示, 一路通过PreviewCallback回调传输给Video Channel.

WebRTC中video capture模块:


├── device_info_android.cc
├── device_info_android.h
├── java
│   └── src
│       └── org
│           └── webrtc
│               └── videoengine
│                   ├── VideoCaptureAndroid.java
│                   └── VideoCaptureDeviceInfoAndroid.java
├── video_capture_android.cc
└── video_capture_android.h


2.  如何获取Camera Information? 当一个设备有多个摄像头时怎么选择?

Android提供了一个Java类android.hardware.Camera,  通过它,我们能获得Android设备的摄像头的所有信息。如下摘自VideoCaptureDeviceInfoAndroid.java:

//首先获得摄像的数量for (int i = 0; i < Camera.getNumberOfCameras(); ++i) {        CameraInfo info = new CameraInfo();        Camera.getCameraInfo(i, info);        String uniqueName = deviceUniqueName(i, info);        JSONObject cameraDict = new JSONObject();        devices.put(cameraDict);        List<Size> supportedSizes;        List<int[]> supportedFpsRanges;        Camera camera = null;        try {          //只有打开摄像头后才能得到它的详细参数          camera = Camera.open(i);          Parameters parameters = camera.getParameters();          //分辨率          supportedSizes = parameters.getSupportedPreviewSizes();         //帧率          supportedFpsRanges = parameters.getSupportedPreviewFpsRange();          Log.d(TAG, uniqueName);        } catch (RuntimeException e) {          Log.e(TAG, "Failed to open " + uniqueName + ", skipping", e);          continue;        } finally {          if (camera != null) {            //别忘了释放摄像头资源            camera.release();          }        }}

顺便提一下, Android还提供了另一个Camera类android.graphics.Camera, 但其功能却完全不同。


3.  打开摄像头

主要做两件事, 1. 调用Camera.open(int id)打开对应的摄像头 2. 告诉摄像头要将它的图像显示在哪儿, 有两种方式:交给SurfaceView, 调用Camera.setPreviewDisplay;

或是交给OpenGL, 调用Camera.setPreviewTexture.

相应的代码在VideoCaptureAndroid.java中

值得注意的是:巧用MessageQueue(Looper)将所有Camera相关的操作交给一个Thread来处理,而利用Exchanger来同步的获得处理结果.

这里引用一张网上的图片来说明MessageQueue的工作原理:



该文件中的CameraThread就是一个很好的例子: 如何在自己创建的线程中使用Looper(Looper.prepare --> Looper.loop --> Looper.myLooper.quit), 如何交给该线程新的任务(Handler.post(new Runnable)).

Exchanger的作用: 以startCapture为例, 需要返回一个boolean值作为结果,但是打开摄像头的操作是在另一个线程(非调用者线程,即上面提到的CameraThread), 如何取得其执行完成后的结果呢? Exchanger 可以为两个线程之间交换对象, 那么就可以这样做:在startCapture结尾调用Exchanger.exchange来等待并取得打开摄像头任务的结果。

4.  JNI调用









0 0
原创粉丝点击