首页 > 解决方案 > 在 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);
            }

        }

标签: c#uwpvideo-capturemediacapture

解决方案


我正在尝试在使用 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

谢谢。


推荐阅读