如何使用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应用的更多相关文章
- 简单的Windows Webcam应用:Barcode Reader
原文:简单的Windows Webcam应用:Barcode Reader 在Windows上用WinForm创建一个Webcam应用需要用到DirectShow.DirectShow没有提供C#的接 ...
- 用C#创建Windows服务(Windows Services)
用C#创建Windows服务(Windows Services) 学习: 第一步:创建服务框架 创建一个新的 Windows 服务项目,可以从Visual C# 工程中选取 Windows 服务(W ...
- 玩转Windows服务系列——创建Windows服务
创建Windows服务的项目 新建项目->C++语言->ATL->ATL项目->服务(EXE) 这样就创建了一个Windows服务项目. 生成的解决方案包含两个项目:Servi ...
- .Net创建windows服务入门
本文主要记录学习.net 如何创建windows服务. 1.创建一个Windows服务程序 2.新建安装程序 3.修改service文件 代码如下 protected override void On ...
- C# 创建Windows服务
创建windows服务项目 2 右键点击Service1.cs,查看代码, 用于编写操作逻辑代码 3 代码中OnStart用于执行服务事件,一般采用线程方式执行方法,便于隔一段事件执行一回 END ...
- 使用.net 创建windows service
最近公司项目需要,写了个windows 服务,windows 服务的内容可以在VS 中新建一个"windows服务项目", (1)服务中的主要代码: public partial ...
- 使用Topshelf创建Windows服务
概述 Topshelf是创建Windows服务的另一种方法,老外的一篇文章Create a .NET Windows Service in 5 steps with Topshelf通过5个步骤详细的 ...
- C#创建windows服务列表
转载自:http://www.cnblogs.com/sorex/archive/2012/05/16/2502001.html Windows Service这一块并不复杂,但是注意事项太多了,网上 ...
- [转]C#创建Windows服务与安装
本文档用于创建windows服务说明,使用vs2010系统平台 创建项目 1 创建windows服务项目 2 右键点击Service1.cs,查看代码, 用于编写操作逻辑代码 3 代码中OnStart ...
随机推荐
- HTML5物理游戏开发 - 越野山地自行车(三)粉碎自行车
自上一章公布到如今已时隔四月,实在对不住大家.让大家久等了~话说不是我不关注我的博客,而是事情一多起来写博客的时间就少了. 待到今日有空了,回头看了看自己曾经写的文章,猛得发现已经四个月不曾写文章了. ...
- 路由(Routing)
RabbitMQ系列教程之四:路由(Routing) (使用Net客户端) 在上一个教程中,我们构建了一个简单的日志系统,我们能够向许多消息接受者广播发送日志消息. 在本教程中,我们将为其添加一项功能 ...
- BZOJ 2021 Usaco2010 Jan Cheese Towers 动态规划
题目大意:全然背包.假设最顶端的物品重量≥k,那么以下的全部物品的重量变为原来的45 考虑一些物品装进背包,显然我要把全部重量大于≥k的物品中重量最小的那个放在最顶端.才干保证总重量最小 那么我们给物 ...
- 小强的HTML5移动开发之路(15)——HTML5中的音频
浏览器虽然发展很快,但是浏览器中的标准还是不完善,在HTML4+CSS2+JS的前段开发中让很多程序员头疼的就是浏览器的兼容性问题,音频播放也一样,直到现在,仍然不存在一项网页上播放视频和音频的标准. ...
- MSYS是一个小型的GNU环境,包括基本的bash,make等等,与Cygwin大致相当(双击“D:\MinGW\msys\1.0\msys.bat”,启动MinGW终端)
1 简介 MinGW,是Minimalist GNUfor Windows的缩写.它是一个可自由使用和自由发布的Windows特定头文件和使用GNU工具集导入库的集合,允许你在GNU/Linux和 ...
- mingw qt(可以去掉mingwm10.dll、libgcc_s_dw2-1.dll、libstdc++-6.dll的依赖,mingw默认都是动态链接gcc的库而TDM是静态链接gcc库,tdm版本更好用。用aspack压缩没有问题。qt本身不使用异常处理)good
原文地址:mingw qt作者:孙1东 不使用Qt SDK,使用mingw编译qt源代码所遇问题及解决方法: configure -fast -release -no-exceptions -no-r ...
- 数据库版本管理工具Flyway——基础篇
Flyway 默认规约 SQL 脚本文件默认位置是项目的源文件夹下的db/migration 目录. Java 代码默认位于db.migration 包. SQL 脚本文件及Java 代码类名必须遵循 ...
- 在WPF窗体中重绘
原文:在WPF窗体中重绘 写这篇主要是为了验证任何元素自身都具备绘图功能. 在默认Window中重写OnRender方法 protected override void OnRender(Draw ...
- UVALive 6531 Go up the ultras 单调栈+RMQ
题目链接:点击打开链接 题意: 给定n座山 以下n个数字表示n座山的高度 若这座山u合法,则要满足: 1.若u的左边存在比u高的山,设v是u左边距离u近期的且严格比u高的山,在[v,u]之间至少有一座 ...
- Cocos2d-X之LUA注意事项
「使用计时器」: 计时器函数原型:unsigned int scheduleScriptFunc(unsigned int handler, float interval, bool paused) ...