c# - 在 UWP C# 中从没有 MediaComposition 的 SoftwareBitmap 或 Direct3DSurface 创建视频文件
问题描述
我正在尝试在使用 MediaFrameReader 时录制相机视频。对于我的应用程序,我需要 MediaFrameReader 实例来单独处理每个帧。我曾尝试另外应用 LowLagMediaRecording 来简单地将相机流保存到文件中,但似乎您不能同时使用这两种方法。这意味着我只能在可以访问 Frame_Arrived 方法中的每个帧的地方使用 MediaFrameReader。
我尝试了几种方法,并找到了两个使用 MediaComposition 类创建 MediaClip 对象的工作解决方案。您可以将每一帧保存为 JPEG 文件,然后将所有图像最终渲染为视频文件。这个过程非常缓慢,因为您经常需要访问硬盘驱动器。或者,您可以从帧的 Direct3DSurface 创建 MediaStreamSample 对象。通过这种方式,您可以将数据保存在 RAM 中(首先保存在 GPU RAM 中,如果已满,则保存在 RAM 中)而不是理论上更快的硬盘驱动器。问题是调用 MediaComposition 类的 RenderToFileAsync 方法需要所有 MediaClip 都已添加到内部列表中。这会导致在已经很短的录制时间之后超出 RAM。在收集了大约 5 分钟的数据后,
我还尝试了第三方库 OpenCvSharp 将处理后的帧保存为视频。我以前在 python 中做过,没有任何问题。但是,在 UWP 中,如果没有 StorageFile 对象,我将无法与文件系统进行交互。因此,当我尝试将渲染的视频保存到文件系统时,我从 OpenCvSharp 得到的只是 UnauthorizedAccessException。
因此,总结一下:我需要一种在数据仍在进入时将相机帧的数据渲染为视频的方法,这样我就可以在处理完每一帧后处理每一帧,就像 python OpenCV 实现一样. 我非常感谢每一个提示。以下是我的部分代码,可以更好地理解上下文:
private void ColorFrameArrived(MediaFrameReader sender, MediaFrameArrivedEventArgs args)
{
MediaFrameReference colorFrame = sender.TryAcquireLatestFrame();
if (colorFrame != null)
{
if (currentMode == StreamingMode)
{
colorRenderer.Draw(colorFrame, true);
}
if (currentMode == RecordingMode)
{
MediaStreamSample sample = MediaStreamSample.CreateFromDirect3D11Surface(colorFrame.VideoMediaFrame.Direct3DSurface, new TimeSpan(0, 0, 0, 0, 33));
ColorComposition.Clips.Add(MediaClip.CreateFromSurface(sample.Direct3D11Surface, new TimeSpan(0, 0, 0, 0, 33)));
}
}
}
private async Task CreateVideo(MediaComposition composition, string outputFileName)
{
try
{
await mediaFrameReaderColor.StopAsync();
mediaFrameReaderColor.FrameArrived -= ColorFrameArrived;
mediaFrameReaderColor.Dispose();
StorageFolder folder = await documentsFolder.GetFolderAsync(directory);
StorageFile vid = await folder.CreateFileAsync(outputFileName + ".mp4", CreationCollisionOption.GenerateUniqueName);
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
await composition.RenderToFileAsync(vid, MediaTrimmingPreference.Precise);
stopwatch.Stop();
Debug.WriteLine("Video rendered: " + stopwatch.ElapsedMilliseconds);
composition.Clips.Clear();
composition = null;
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
}
解决方案
我正在尝试在使用 MediaFrameReader 时录制相机视频。对于我的应用程序,我需要 MediaFrameReader 实例来单独处理每个帧。
请创建自定义视频效果并将其添加到 MediaCapture 对象以实现您的要求。使用自定义视频效果将允许我们在不使用 MediaFrameReader 的情况下处理 MediaCapture 对象的上下文中的帧,这样您提到的 MediaFrameReader 的所有限制都会消失。
此外,它还有许多内置效果,可以让我们分析相机帧,更多信息请查看以下文章:
#MediaCapture.AddVideoEffectAsync
https://docs.microsoft.com/en-us/uwp/api/windows.media.capture.mediacapture.addvideoeffectasync。
#自定义视频效果
https://docs.microsoft.com/en-us/windows/uwp/audio-video-camera/custom-video-effects。
#用于分析相机帧的效果
https://docs.microsoft.com/en-us/windows/uwp/audio-video-camera/scene-analysis-for-media-capture。
谢谢。
推荐阅读
- r - 有没有办法使用重复循环的最后一个值来制作数据框?
- mysql - MySQL内存没有被释放
- vscode-debugger - 本地调试 CluedIn 集成的最佳方法
- css - 如何在 CSS 中删除播放按钮和徽标 img 下的边框?
- javascript - 在元素外部单击时切换元素并移除其可见性 - JavaScript
- reactjs - 如何访问 ReduxSlice 中的状态
- kubernetes - 如何从 HTTP 请求绑定掌舵图中的值?
- r - 有没有办法从 R 中的现有列名生成年份列?
- reactjs - 自动导入类名 Reactjs
- python - @提及随机用户 discord.py