原文:如何使用C#创建Windows Webcam应用

最近想用C#写一个camera的应用。搜索了Google和StackOverflow,发现大部分的sample用了WIA或者DirectShow。WIA和DirectShow都没有直接提供C#接口,所以实现起来也比较复杂。试着运行了几个WIA的工程,在Windows10上还不起作用。发现微软提供了一个MediaCapture类,包含了丰富的C#接口,可用于音频,视频。要用这个类,就需要创建一个UWP工程。这里分享下如何使用MediaCapture的C#接口来获取camera的每一帧数据。

微软示例

微软在GitHub上放了大量的UWP示例,里面包含了各种camera的接口使用方法。

在Android中要获取camera的每一帧数据,可以通过onPreviewCallback的回调函数实现。参考CameraFrames这个示例,也可以实现类似的功能。

如何创建Windows Webcam应用

1. 在package.appxmanifest中获取webcam权限:

2. 创建image element用于绘制webcam的预览界面:

3. 通过Image Element初始化FrameRenderer :

_frameRenderer = new FrameRenderer(PreviewImage);

4. 初始化MediaCapture对象:

// Create a new media capture object.
_mediaCapture = new MediaCapture(); var settings = new MediaCaptureInitializationSettings()
{
// Select the source we will be reading from.
SourceGroup = groupModel.SourceGroup, // This media capture has exclusive control of the source.
SharingMode = MediaCaptureSharingMode.ExclusiveControl, // Set to CPU to ensure frames always contain CPU SoftwareBitmap images,
// instead of preferring GPU D3DSurface images.
MemoryPreference = MediaCaptureMemoryPreference.Cpu, // Capture only video. Audio device will not be initialized.
StreamingCaptureMode = StreamingCaptureMode.Video,
}; try
{
// Initialize MediaCapture with the specified group.
// This can raise an exception if the source no longer exists,
// or if the source could not be initialized.
await _mediaCapture.InitializeAsync(settings);
_logger.Log($"Successfully initialized MediaCapture for {groupModel.DisplayName}");
}
catch (Exception exception)
{
_logger.Log(exception.Message);
DisposeMediaCapture();
}

5. 使用DeviceWatcher 列出所有设备:

var deviceSelector = MediaFrameSourceGroup.GetDeviceSelector();
_watcher = DeviceInformation.CreateWatcher(deviceSelector);
_watcher.Added += Watcher_Added;
_watcher.Removed += Watcher_Removed;
_watcher.Updated += Watcher_Updated;
_watcher.Start(); private async void Watcher_Added(DeviceWatcher sender, DeviceInformation args)
{
await AddDeviceAsync(args.Id);
} private async Task AddDeviceAsync(string id)
{
var group = await MediaFrameSourceGroup.FromIdAsync(id);
if (group != null)
{
await _dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
_sourceCollection.Add(new FrameSourceGroupModel(group));
});
}
}

6. 针对用户的选择更新设备源:

_mediaCapture.FrameSources.TryGetValue(info.SourceInfo.Id, out _source);

7. 通过MediaFrameReader 注册回调函数:

if (_source != null)
{
_reader = await _mediaCapture.CreateFrameReaderAsync(_source);
_reader.FrameArrived += Reader_FrameArrived;
}

8. 启动webcam:

MediaFrameReaderStartStatus result = await _reader.StartAsync();

9. 读取并绘制每一帧数据:

private void Reader_FrameArrived(MediaFrameReader sender, MediaFrameArrivedEventArgs args)
{
// TryAcquireLatestFrame will return the latest frame that has not yet been acquired.
// This can return null if there is no such frame, or if the reader is not in the
// "Started" state. The latter can occur if a FrameArrived event was in flight
// when the reader was stopped.
using (var frame = sender.TryAcquireLatestFrame())
{
_frameRenderer.ProcessFrame(frame);
}
} public void ProcessFrame(MediaFrameReference frame)
{
var softwareBitmap = FrameRenderer.ConvertToDisplayableImage(frame?.VideoMediaFrame); if (softwareBitmap != null)
{
// Swap the processed frame to _backBuffer and trigger UI thread to render it
softwareBitmap = Interlocked.Exchange(ref _backBuffer, softwareBitmap); // UI thread always reset _backBuffer before using it. Unused bitmap should be disposed.
softwareBitmap?.Dispose(); // Changes to xaml ImageElement must happen in UI thread through Dispatcher
var task = _imageElement.Dispatcher.RunAsync(CoreDispatcherPriority.Normal,
async () =>
{
// Don't let two copies of this task run at the same time.
if (_taskRunning)
{
return;
}
_taskRunning = true; // Keep draining frames from the backbuffer until the backbuffer is empty.
SoftwareBitmap latestBitmap;
while ((latestBitmap = Interlocked.Exchange(ref _backBuffer, null)) != null)
{
var imageSource = (SoftwareBitmapSource)_imageElement.Source;
await imageSource.SetBitmapAsync(latestBitmap);
latestBitmap.Dispose();
} _taskRunning = false;
});
}
}

参考

Basic photo, video, and audio capture with MediaCapture

源码

https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/CameraFrames

如何使用C#创建Windows Webcam应用的更多相关文章

  1. 简单的Windows Webcam应用:Barcode Reader

    原文:简单的Windows Webcam应用:Barcode Reader 在Windows上用WinForm创建一个Webcam应用需要用到DirectShow.DirectShow没有提供C#的接 ...

  2. 用C#创建Windows服务(Windows Services)

    用C#创建Windows服务(Windows Services) 学习:  第一步:创建服务框架 创建一个新的 Windows 服务项目,可以从Visual C# 工程中选取 Windows 服务(W ...

  3. 玩转Windows服务系列——创建Windows服务

    创建Windows服务的项目 新建项目->C++语言->ATL->ATL项目->服务(EXE) 这样就创建了一个Windows服务项目. 生成的解决方案包含两个项目:Servi ...

  4. .Net创建windows服务入门

    本文主要记录学习.net 如何创建windows服务. 1.创建一个Windows服务程序 2.新建安装程序 3.修改service文件 代码如下 protected override void On ...

  5. C# 创建Windows服务

    创建windows服务项目   2 右键点击Service1.cs,查看代码, 用于编写操作逻辑代码 3 代码中OnStart用于执行服务事件,一般采用线程方式执行方法,便于隔一段事件执行一回 END ...

  6. 使用.net 创建windows service

    最近公司项目需要,写了个windows 服务,windows 服务的内容可以在VS 中新建一个"windows服务项目", (1)服务中的主要代码: public partial ...

  7. 使用Topshelf创建Windows服务

    概述 Topshelf是创建Windows服务的另一种方法,老外的一篇文章Create a .NET Windows Service in 5 steps with Topshelf通过5个步骤详细的 ...

  8. C#创建windows服务列表

    转载自:http://www.cnblogs.com/sorex/archive/2012/05/16/2502001.html Windows Service这一块并不复杂,但是注意事项太多了,网上 ...

  9. [转]C#创建Windows服务与安装

    本文档用于创建windows服务说明,使用vs2010系统平台 创建项目 1 创建windows服务项目 2 右键点击Service1.cs,查看代码, 用于编写操作逻辑代码 3 代码中OnStart ...

随机推荐

  1. iOS 一个简单的单例

    比如我有一个Singleton的类(DemoStatusManage),他有一个实例方法currentStatus会返回一个1-100的随机数. @interface DemoStatusManage ...

  2. WPF入门(四)->线形区域Path内容填充之渐变色(LinearGradientBrush)

    原文:WPF入门(四)->线形区域Path内容填充之渐变色(LinearGradientBrush) 前面我们介绍到,Path对象表示一个用直线或者曲线连接的图形,我们可以使用Path.Data ...

  3. 【9102】&&【a102】求a/b的高精度值

    Time Limit: 10 second Memory Limit: 2 MB 问题描述 计算a/b的精度值,设a,b以一般整数输入,计算结果精确到小数后20位(结果四舍五入). Input 文件输 ...

  4. 【BZOJ 1016】[JSOI2008]最小生成树计数(搜索+克鲁斯卡尔)

    [题目链接]:http://www.lydsy.com/JudgeOnline/problem.php?id=1016 [题意] [题解] /* 两个最小生成树T和T'; 它们各个边权的边的数目肯定是 ...

  5. Swift异常处理:throw和rethrow

    Swift异常处理体现了函数式语言的特性.因此我们能够传一个会抛出异常的函数闭包(高阶函数)作为參数传到还有一个函数中(父函数),父函数能够在子函数抛出异常时直接向上抛出异常,这时用rethrowke ...

  6. Enhancing network controls in mandatory access control computing environments

    A Mandatory Access Control (MAC) aware firewall includes an extended rule set for MAC attributes, su ...

  7. C#实现拼图游戏

    C#实现<拼图游戏> (下) 原理篇   前言:在 http://www.cnblogs.com/labixiaohei/p/6698887.html 程序设计 之 C#实现<拼图游 ...

  8. quartz结合多线程处理后台业务

    最近项目中有播放视频的需求,技术选型采用UMS播放器,免费版只能播放FLV格式的视频文件,因此需要对用户上传的视频进行格式转换,转换工具为FormatFactory,功能还是比较强大的.但是面临的一个 ...

  9. handsontable前端excel学习笔记

    暂时没有好的中文资料,大概找了三遍随便看看,之后重点研究其github 1.Handsontable 学习笔记-Methods 2. Handsontable通用方法 3.handsontable的核 ...

  10. jQuery.noop

    一个空函数 当你仅仅想要传递一个空函数的时候,就用他吧.这对一些插件作者很有用,当插件提供了一个可选的回调函数接口,那么如果调用的时候没有传递这个回调函数,就用jQuery.noop来代替执行.