【发布时间】:2020-06-14 19:05:31
【问题描述】:
我正在尝试在使用 MediaFrameReader 时录制相机视频。对于我的应用程序,我需要 MediaFrameReader 实例来单独处理每个帧。我曾尝试另外应用 LowLagMediaRecording 来简单地将相机流保存到文件中,但似乎您不能同时使用这两种方法。这意味着我只能在可以访问 Frame_Arrived 方法中的每个帧的地方使用 MediaFrameReader。
我尝试了几种方法,并找到了两个使用 MediaComposition 类创建 MediaClip 对象的可行解决方案。您可以将每一帧保存为 JPEG 文件,然后将所有图像最终渲染为视频文件。这个过程非常缓慢,因为您经常需要访问硬盘驱动器。或者,您可以从帧的 Direct3DSurface 创建 MediaStreamSample 对象。通过这种方式,您可以将数据保存在 RAM 中(首先保存在 GPU RAM 中,如果已满,则保存在 RAM 中)而不是理论上更快的硬盘驱动器。问题是调用 MediaComposition 类的 RenderToFileAsync 方法需要所有 MediaClip 都已添加到内部列表中。这会导致在已经很短的录制时间之后超出 RAM。在收集了大约 5 分钟的数据后,windows 已经创建了一个 70GB 的交换文件,这无视了选择此路径的原因。
我还尝试了第三方库 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);
}
}
【问题讨论】:
-
在 uwp 平台内将 SoftwareBitmap 转换为视频文件的唯一方法。但是
MediaComposition经常用来修剪视频,它无法处理实时帧。我很困惑为什么你只需要使用 MediaFrameReader 来捕获视频。? -
您好,感谢您的回复。我需要调用
MediaFrameReader来执行多项任务,例如获取每个帧的时间戳。
标签: c# uwp video-capture mediacapture