原文:如何使用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

最新文章

  1. C#开发微信门户及应用(18)-微信企业号的通讯录管理开发之成员管理
  2. 单独使用jdbc编程问题总结(一)
  3. js中时间戳转化成时间格式
  4. 最新原创:Power8伴随云计算横空出世
  5. oracle批量update 转
  6. java.io.stream
  7. SecureCRT 的安装和注册
  8. 课题练习——找从1到N出现的1的个数
  9. UVa 674 Coin Change【记忆化搜索】
  10. ios 调试
  11. Hadoop HDFS的常用命令
  12. tomcat7.0 的配置
  13. Git 基本使用配置
  14. uniq 命令
  15. js原生之scrollTop、offsetHeight和offsetTop等属性用法详解
  16. 浅谈C10K问题
  17. Openstack oslo.config【一】
  18. 免花生壳 TCP测试 DTU测试 GPRS测试TCP服务器
  19. iOS 出现内存泄漏的几种原因
  20. C#6.0语言规范(二) 词法结构

热门文章

  1. MVVM初步搭建应用
  2. 【rlz000】字串找数
  3. 【b604】2K进制数
  4. solr 7.x 配置ikanalyzer
  5. HDU 3605Escape(缩点+网络流之最大流)
  6. 单点登录原理与简单实现--good
  7. 【43.75%】【codeforces 688E】The Values You Can Make
  8. git 修改仓库地址
  9. Unity3d报告奇怪的错误CompareBaseObjectsInternal can only be called from the main thread.
  10. c语言学习笔记(12)——补码