【问题标题】:UWP: How to record Screen and save as mp4 file?UWP:如何录制屏幕并保存为 mp4 文件?
【发布时间】:2018-10-30 18:06:18
【问题描述】:

我已经知道如何使用此处的示例捕获屏幕并将其输出回预览器:Microsoft Screen Capture Documentation

就目前而言,这很好。

我无法弄清楚,也找不到任何文档是获取这些帧并将它们写入视频文件。

理想情况下,我想将它们直接流式传输到 mp4 或类似文件中,然后我可以稍后使用 MediaComposition 系统进行编辑。

我找到了 VideoFrame.CreateWithDirect3D11Surface,但我不知道如何将视频帧添加到现有视频文件中。该文档告诉您如何创建视频帧以及属性如何工作,但它没有告诉您如何在视频文件中使用视频帧,我也找不到任何关于如何在没有相机的情况下创建视频文件或其他捕获设备。

还有一些来自文档 GitHub 的参考资料,其中有人问同样的问题,他们说 MediaStreamSample 是关键,但也没有任何代码可以保存文件。 (Here's the issue)

人们会认为使用此 api 记录屏幕并将这些帧转储到原始视频文件中很容易,然后您可以使用 MediaComposition api 导入和编辑。

请帮忙!

【问题讨论】:

  • 我遇到了同样的问题。一件事是,如果您尝试存储那些 Direct3DSurfaces,您将无法做到这一点。
  • 好的,但我不知道如何在它们进入时将它们全部转储到磁盘的视频文件流中。有什么建议吗?
  • 你提到的问题有MediaStreamSample的一些代码的答案。你试过吗?虽然我自己没有。
  • 我试过了。它不完整,实际上并没有向您展示如何使用示例来创建文件。因此我的问题。

标签: uwp video-capture


【解决方案1】:

假设您正在使用 Microsoft 的屏幕捕获示例。以下是您需要做的:

此处提供完整的源代码(代码确实需要重构,但它可以工作?‍♂️):https://gitlab.com/colinkiama/screenrecordertest/-/tree/master/screenRecorderTest

代码是使用屏幕截图示例和 SimpleRecorder 源代码的一部分:https://github.com/robmikh/SimpleRecorder/tree/master/SimpleRecorder

  1. 使用有关输入的详细信息创建 MediaStreamSource
private void CreateMediaObjects()
 {
            // Describe our input: uncompressed BGRA8 buffers
            var videoProperties = VideoEncodingProperties.CreateUncompressed(MediaEncodingSubtypes.Bgra8, _sourceWidth, _sourceHeight);
            _videoDescriptor = new VideoStreamDescriptor(videoProperties);


            // Create our MediaStreamSource
            _mediaStreamSource = new MediaStreamSource(_videoDescriptor);
            _mediaStreamSource.BufferTime = TimeSpan.FromSeconds(0);
            _mediaStreamSource.Starting += OnMediaStreamSourceStarting;
            _mediaStreamSource.SampleRequested += OnMediaStreamSourceSampleRequested;

            // Create our transcoder
            _transcoder = new MediaTranscoder();
            _transcoder.HardwareAccelerationEnabled = true;

        }

  1. 设置编码,开始抓屏,开始转码(注:流是指从StorageFile对象打开的流)
private async Task EncodeInternalAsync(IRandomAccessStream stream, uint width, uint height, uint bitrateInBps, uint frameRate)
        {
            if (!_isRecording)
            {
                _isRecording = true;

                var encodingProfile = new MediaEncodingProfile();
                encodingProfile.Container.Subtype = "MPEG4";
                encodingProfile.Video.Subtype = "H264";
                encodingProfile.Video.Width = width;
                encodingProfile.Video.Height = height;
                encodingProfile.Video.Bitrate = bitrateInBps;
                encodingProfile.Video.FrameRate.Numerator = frameRate;
                encodingProfile.Video.FrameRate.Denominator = 1;
                encodingProfile.Video.PixelAspectRatio.Numerator = 1;
                encodingProfile.Video.PixelAspectRatio.Denominator = 1;

                StartFrameCapture();

                var transcode = await _transcoder.PrepareMediaStreamSourceTranscodeAsync(_mediaStreamSource, stream, encodingProfile);
                await transcode.TranscodeAsync();
            }
        }
  1. 对于从屏幕捕获到达的每一帧,创建一个 MediaStream 示例
using (var frame = _framePool.TryGetNextFrame())
                {
                    MediaStreamSample sampleToUseLater = MediaStreamSample.CreateFromDirect3D11Surface(frame.Surface, frame.SystemRelativeTime);

                    lock (doubleBufferingPool)
                    {
                        while (doubleBufferingPool.Count >= 2)
                        {
                            // Stops too many samples from being saved
                            doubleBufferingPool.Dequeue();
                        }

                        doubleBufferingPool.Enqueue(sampleToUseLater);
                    }
                }
  1. 设置流的实际开始时间:
 private void OnMediaStreamSourceStarting(MediaStreamSource sender, MediaStreamSourceStartingEventArgs args)
        {

            while (doubleBufferingPool.Count == 0)
            {

            }
            var sample = doubleBufferingPool.Dequeue();
            TimeSpan timeStamp = sample.Timestamp;
            args.Request.SetActualStartPosition(timeStamp);
        }
  1. 向 MediaStreamSource 提供样本
private void OnMediaStreamSourceSampleRequested(MediaStreamSource sender, MediaStreamSourceSampleRequestedEventArgs args)
        {
            if (_isRecording && !_closed)
            {
                while (doubleBufferingPool.Count == 0)
                {

                }

                lock (doubleBufferingPool)
                {
                    args.Request.Sample = doubleBufferingPool.Dequeue();
                }
            }
            else
            {
                args.Request.Sample = null;
                StopCapture();
            }
        }

如果您向 MediaStreamSource 提供空样本,它将停止要求更多样本。

然后可以从您打开流的文件中查看视频。

【讨论】:

    猜你喜欢
    • 2010-12-10
    • 1970-01-01
    • 1970-01-01
    • 2016-10-28
    • 1970-01-01
    • 1970-01-01
    • 2015-12-18
    • 1970-01-01
    相关资源
    最近更新 更多