在开发类似视频聊天的应用时,我们经常需要获取摄像头的相关信息;而在进行视频聊天时,我们可能还希望有一些动态的能力。比如,在不中断视频聊天的情况下,切换一个摄像头、或者修改摄像头采集的分辨率或编码质量等等。OMCS提供了很多有用的特性以支持上述需求。

一.枚举摄像头

我们如何得知当前的计算机有哪些摄像头了?

OMCS提供了一个工具类OMCS.Tools.Camera,来帮助我们获取这些信息。Camera有个静态方法GetCameras,用于枚举当前计算机上的所有摄像头。

  /// <summary>
  /// 枚举当前计算机上的所有摄像头设备。
  /// </summary>
  public static List<CameraInformation> GetCameras()

CameraInformation封装了摄像头的基本信息,其类图如下所示:

我们可以将GetCameras方法返回的列表直接绑定到Combox控件,效果如下所示:

默认情况下,IMultimediaManager使用的摄像头的索引为0。如果索引为0的摄像头不可用,或者,用户指定使用其它的摄像头,则可以将指定摄像头的索引保存到配置文件。当客户端程序启动时,从配置文件中读取该索引值,并将其赋值给IMultimediaManager的CameraDeviceIndex属性。

二.获取摄像头支持的分辨率

当选定了一个摄像头,我们如何知道该摄像头支持哪些采集分辨率、支持最高的帧频是多少了?

Camera提供了另一个静态方法GetCameraCapability,来获取目标摄像头的能力信息。

  /// <summary>
  /// 获取目标摄像头的能力信息(分辨率、最大帧频)
  /// </summary>
  /// <param name="deviceIndex">目标摄像头的索引</param>
  public static List<CameraCapability> GetCameraCapability(int deviceIndex)

CameraCapability类封装了摄像头的能力信息,其类图如下所示:

我们可以将GetCameraCapability方法返回的列表直接绑定到Combox控件,效果如下所示:

三.动态切换摄像头

下面我们设想一种情况,假设我的电脑上装有两个可用的摄像头, 我正在使用索引为0的摄像头和我的朋友视频聊天,某个时刻,我想在不中断视频聊天的情况下,切换到索引为1的摄像头。这种需求就称为动态切换摄像头。

OMCS支持动态切换摄像头,并且操作相当简单:我们只需要将IMultimediaManager的CameraDeviceIndex属性赋值为要切换到的摄像头的索引即可。

切换会在OMCS内部自动进行,在很短的时间切换完成后,OMCS会将新摄像头采集的视频数据发送给各个guest。

四.动态修改摄像头的分辨率

还记得QQ视频聊天有这种能力,我们可以在视频聊天的时候,选择使用大窗口模式。这实际上就是使用摄像头更高的分辨率来采集视频,比如原始的采集分辨率为320*240,可切换到更高的640*480。

OMCS支持在不需要任何中断的情况下,修改正在使用的摄像头的采集分辨率。操作也是相当简单:我们只需要将IMultimediaManager的CameraVideoSize属性设置为目标分辨率大小即可。当然,如果设置的分辨率不被当前摄像头所支持,则将抛出NotSupportedException。另外要注意,在编码质量相同的情况下,视频的分辨率越高,所输出的码流就越大,所要求的带宽也越大。

为了避免设置不恰当的分辨率给CameraVideoSize属性,在赋值之前,我们可以通过OMCS.Tools.Camera的静态方法Support来判断目标摄像头是否支持指定的分辨率:

   /// <summary>
   /// 目标摄像头是否支持采集指定的分辨率。
   /// </summary>
   public static bool Support(int deviceIndex, Size videoSize)

五.动态调节编码质量

在客户端运行的任何时候,我们都可以通过设置IMultimediaManager的CameraEncodeQuality属性,来实时调整摄像头采集的视频的编码质量。编码质量越高(CameraEncodeQuality取值越小),对带宽的要求就越高;反之亦然。

当然,正如前面文章所介绍的,如果IMultimediaManager的AutoAdjustCameraEncodeQuality属性被设置为true,则CameraEncodeQuality将会被OMCS自动调节以优先保证语音的清晰连贯,手动对CameraEncodeQuality的设置就不起作用了。

如果我们将AutoAdjustCameraEncodeQuality设置为false,并且我们的应用自己能检测到网络状态的实时变化,那么,我们就可以根据当前的网络状态,来手动调整CameraEncodeQuality。

六.控制视频输出

设想这样一种情况:我在进行视频会议时,某个时间出于某种原因,我不想让与会者看到我的视频,一段时间后,我又希望恢复原样。

从节省带宽的角度,最好的方式就是在这段时间内不输出视频帧。OMCS能简单地实现这种控制:我们只需将IMultimediaManager的OutputVideo属性设置为false,即可关闭视频帧的输出。

七.广播时选择丢弃视频帧

下面要设想的场景稍微复杂一点:在视频会议时,我的视频会发送给与会的每个人,假设我与每个与会者之间都建立的是P2P通道,视频帧都经过P2P通道传送。现在的问题时,每个P2P通道的质量是不一样的,有的可能很快,有的可能很慢。我们假设到与会者A的通道非常慢,到其他与会者的通道质量都很好。那么,我们来分析一下在两种广播模式下,可能出现的情况。

1.同步广播模式

在同步广播模式下,只有当某个视频帧在所有的通道上都发送完毕时,才会去发送下一个视频帧。这样就会出现因为与A之间的通道缓慢,而导致其他与会者看到自己的视频出现卡或不连贯的情况。

2.异步广播模式

在异步广播模式下,视频帧在所有的通道上都是异步发送的,这样A通道的缓慢不会影响到其它的与会者。OMCS采用的就是这种模式。

但是,由于通道A的缓慢,生产视频帧的速度远大于通道A消费视频帧的速度,这就导致了需要使用更多的内存来缓存那些来不及发送的视频帧。就客户端进程看来,其所占用的内存会不断增加,就像内存泄漏一样。

如何解决这个问题了?OMCS给出的方案是可以选择在通道繁忙时丢弃帧。通过将IMultimediaManager的AllowDiscardFrameWhenBroadcast属性设置为true,便可启用这种方案。

AllowDiscardFrameWhenBroadcast被启用后,当一个新的视频帧要通过某个P2P通道发送给对应的与会者时,会先检测一下该P2P通道是否繁忙,如果繁忙,就取消该视频帧在这个通道上的发送。这样,就避免了内存无线增长的情况。但在这种方案下,那些通道比较慢的与会者,因为丢弃视频帧的原因,看到别人的视频可能就会出现马赛克、卡、不连续的现象。

OMCS使用技巧 -- 摄像头及其动态能力的更多相关文章

  1. 技巧:Linux 动态库与静态库制作及使用详解

    技巧:Linux 动态库与静态库制作及使用详解 标准库的三种连接方式及静态库制作与使用方法 Linux 应用开发通常要考虑三个问题,即:1)在 Linux 应用程序开发过程中遇到过标准库链接在不同 L ...

  2. [C# 开发技巧系列]如何动态设置屏幕分辨率

    首先,大家应该明确,现在没有可用的API来给我们动态地设置屏幕分辨率,我们要实现这个需求,我们只能在C#程序中调用Win32 API 函数来解决这个问题的,这里用C#代码调用Win32 API 就涉及 ...

  3. Android OpenCV集成摄像头图片动态识别车牌号

    最近两天开发一个使用OpenCV集成的一个识别车牌号的项目,困难重重,总结一下相关经验,以及开发注意事项: 一.开发环境: Android Studio 个人版本 3.1.4 NDK下载:14b CM ...

  4. JavaScript实例技巧精选(14)—动态变化背景颜色

    >>点击这里下载完整html源码<< 这是截图: 网页背景颜色随时间变化,核心代码如下: <SCRIPT LANGUAGE="JavaScript"& ...

  5. CDN加速小水管动态应用技巧

    不得不说现在大陆和HK的云主机都是小水管模式,由于硬件的快速发展在这种小水管的情况下很难发挥出用户硬件资源的能力,当然可以加水管但费用很高,更多时候会浪费带宽:这个时候我们想到CDN加速,这种资源的好 ...

  6. 监控摄像机常识:宽动态 (WDR)介绍和理解

    安装和使用监控摄像机经常会遇到强光问题. 因为我们不可能灵活选择摄像机的安装位置, 解决或者处理强光是一个无法避免的问题. 不管是由反光材质或者灯源造成此反光, 解决问题的方案来自于摄像机支持的一个特 ...

  7. YACEP相关技术工具服务技巧(上)

    这篇随笔的核心是介绍一下YACEP所用到的一些技术,工具,服务和技巧,鉴于篇幅原因,不可能面面俱到,只能点到为止,目录如下: 目录: 1. YACEP简介(上)             2. 技术篇( ...

  8. 动态调用WebService(C#) (非常实用)

    通常我们在程序中需要调用WebService时,都是通过“添加Web引用”,让VS.NET环境来为我们生成服务代理,然后调用对应的Web服务.这样是使工作简单了,但是却和提供Web服务的URL.方法名 ...

  9. 动态调用web服务

    通常我们在程序中需要调用WebService时,都是通过“添加Web引用”,让VS.NET环境来为我们生成服务代理,然后调用对应的Web服务.这样是使工作简单了,但是却和提供Web服务的URL.方法名 ...

随机推荐

  1. ArrayList、HashSet、HashTable、List、Dictionary的区别

    在C#中,数组由于是固定长度的,所以常常不能满足我们开发的需求. 由于这种限制不方便,所以出现了ArrayList. ArrayList.List<T> ArrayList是可变长数组,你 ...

  2. CoreJavaE10V1P3.2 第3章 Java的基本编程结构-3.2 注释

    3.2 注释 1. //形式注释 System.out.println("We will not use 'Hello, World!'"); // is this too cut ...

  3. 为jEasyUi的日期控件添加一个“清空”按钮----通过修改1.4的easyui.min.js

    为 jQuery EasyUI 1.4 的datebox或datetimebox添加一个清空按钮 使用场景:为用户指定了日期的格式,且日期可以为空 修改语言包easyui-lang-zh_CN.js ...

  4. CodeForces 708B Recover the String

    构造. 根据$a[0][0]$可以求得$0$的个数$p$,根据$a[1][1]$可以求得$1$的个数$q$. 如果找不到$p$或$q$,那么就无解. 每一个$0$放到序列中的任何一个位置,假设和前面的 ...

  5. PHP学习过程_Symfony_(4)_命令创建实体_以及实体关系

    //项目运行php app/console server:run//创建实体php app/console doctrine:generate:entitybundle名称:实体名称例如:Symfon ...

  6. 分布式存储 CentOS6.5虚拟机环境搭建FastDFS-5.0.5集群(转载-2)

    原文:http://www.cnblogs.com/PurpleDream/p/4510279.html 分布式存储 CentOS6.5虚拟机环境搭建FastDFS-5.0.5集群 前言:       ...

  7. vue跨组件通信的几种方法

    http://www.tuicool.com/articles/jyM32mA 在开发组件的时候,一定会遇到组件的通信,比如点击一个图标出现弹窗和蒙层,这三个分别是不同的组件.管理他们之间的状态就成了 ...

  8. spring @Scheduled 执行2次

    今天遇到定时任务Scheduled 执行2次的情况,做一个简单的记录. 网上有好多办法,我几乎都试了一遍,我的情况下面的办法可用. 1. autodeploy属性值设置为false,如果此项设为tru ...

  9. ACM-ICPC之路

    自从了解到了ACM,我就坚定了参加这个比赛的信心.虽然零基础开始,但是阻挡不了我的前进之路.从大一上学期的完成二十道题,到假期完成四十道题:从第一次校赛不了解退出循环方式只完成了一道题,到大一预选赛第 ...

  10. swift label不同颜色、不同字体

    let string = "点击注册按钮,即表示您已同意隐私条款和服务协议" let ranStr = "同意" let attrstring:NSMutabl ...