简体   繁体   English

使用 Windows Graphics Capture API 暂停/恢复屏幕录制

[英]Pausing / Resuming Screen recording with Windows Graphics Capture API

I am building a screen recording app in C# using Windows Graphics Capture API. I am using this script .我正在使用Windows Graphics Capture API 在 C# 构建一个屏幕录制应用程序。我正在使用这个脚本 I can select monitor and can record it to mp4 file.我可以 select 监控并可以将其录制到 mp4 文件。 I am trying to add Pause/Resume functionality.我正在尝试添加暂停/恢复功能。

Here is code of main Window that initiates Recording这是启动录音的主要代码 Window

try
{
    newFile = GetTempFile();
    using (var stream = new FileStream(newFile, FileMode.CreateNew).AsRandomAccessStream())
    using (_encoder = new Encoder(_device, item))
    {
        await _encoder.EncodeAsync(
            stream,
            width, height, bitrate,
            frameRate);
    }
}
catch (Exception ex)
{
  //
}

And here is the main function from Encoder class , which is used above这是上面使用的编码器 class的主要 function

private async Task EncodeInternalAsync(IRandomAccessStream stream, uint width, uint height, uint bitrateInBps, uint frameRate)
{
    if (!_isRecording)
    {
        _isRecording = true;

        _frameGenerator = new CaptureFrameWait(
            _device,
            _captureItem,
            _captureItem.Size);

        using (_frameGenerator)
        {
            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;
            var transcode = await _transcoder.PrepareMediaStreamSourceTranscodeAsync(_mediaStreamSource, stream, encodingProfile);

            await transcode.TranscodeAsync();
        }
    }
}

And finally this is the initializer function in CaptureFrameWait class最后这是CaptureFrameWait class 中的初始化器 function

private void InitializeCapture(SizeInt32 size)
{
    _framePool = Direct3D11CaptureFramePool.CreateFreeThreaded(
        _device,
        DirectXPixelFormat.B8G8R8A8UIntNormalized,
        1,
        size);
    _framePool.FrameArrived += OnFrameArrived;
    _session = _framePool.CreateCaptureSession(_item);
    _session.IsBorderRequired = false;
    _session.StartCapture();
}

How can we modify this to pause the recording?我们如何修改它以暂停录制? I have tried to dispose the _framepool and _session objects on Pause and initialize them again on Resume in CaptureFrameWait class, like shown below.我试图在暂停时处理_framepool_session对象,并在CaptureFrameWait class 中的恢复时再次初始化它们,如下所示。 It works fine, but sometimes TranscodeAsync function terminates during pause and ends recording.它工作正常,但有时 TranscodeAsync function 在暂停期间终止并结束录制。 How can we avoid that?我们怎样才能避免这种情况?

bool _paused = false;
public void PauseSession(bool status)
{
    if (status) {
        _paused = true;
        _framePool?.Dispose();
        _session?.Dispose();
    }
    else {
        InitializeCapture(_size);
        _paused = false;
    }
}

One solution is to get a deferral .一种解决方案是延期 Doc says:医生说:

The MediaStreamSource will then wait for you to supply the MediaStreamSample until you mark the deferral as complete.然后 MediaStreamSource 将等待您提供 MediaStreamSample,直到您将延迟标记为完成。

So for example, add two private members to the Encoder class and two methods:因此,例如,将两个私有成员添加到Encoder class 和两个方法:

private MediaStreamSourceSampleRequestedEventArgs _args;
private MediaStreamSourceSampleRequestDeferral _def;

public bool IsPaused { get; private set; }

public void Pause()
{
    IsPaused = true;
}

public void Resume()
{
    IsPaused = false;

    // complete the request we saved earlier
    OnMediaStreamSourceSampleRequested(_mediaStreamSource, _args);
}

And modify OnMediaStreamSourceSampleRequested methods like this (where I've put comments):并像这样修改OnMediaStreamSourceSampleRequested方法(我在其中发表评论):

private void OnMediaStreamSourceSampleRequested(MediaStreamSource sender, MediaStreamSourceSampleRequestedEventArgs args)
{
    if (_isRecording && !_closed)
    {
        // if paused get a deferral and save the current arguments.
        // OnMediaStreamSourceSampleRequested will not be called again until we complete the deferral
        if (IsPaused)
        {
            _def = args.Request.GetDeferral();
            _args = args;
            return;
        }

        try
        {
            using (var frame = _frameGenerator.WaitForNewFrame())
            {
                if (frame == null)
                {
                    args.Request.Sample = null;
                    DisposeInternal();
                    return;
                }

                var timeStamp = frame.SystemRelativeTime;

                var sample = MediaStreamSample.CreateFromDirect3D11Surface(frame.Surface, timeStamp);
                args.Request.Sample = sample;

                // when called again (manually by us) complete the work
                // and reset members
                if (_def != null)
                {
                    _def.Complete();
                    _def = null;
                    _args = null;
                }
            }
        }
        catch (Exception e)
        {
          ...
        }
    }
    else
    {
      ...
    }
}

Another solution is to simply freeze the frames timestamp, so add these members:另一种解决方案是简单地冻结帧时间戳,因此添加这些成员:

private TimeSpan _pausedTimestamp;
public bool IsPaused { get; private set; }

public void Pause()
{
    IsPaused = true;
}

public void Resume()
{
    IsPaused = false;
}

And modify OnMediaStreamSourceSampleRequested methods like this (where I've put comments):并像这样修改OnMediaStreamSourceSampleRequested方法(我在其中发表评论):

private void OnMediaStreamSourceSampleRequested(MediaStreamSource sender, MediaStreamSourceSampleRequestedEventArgs args)
{
    if (_isRecording && !_closed)
    {
        try
        {
            using (var frame = _frameGenerator.WaitForNewFrame())
            {
                if (frame == null)
                {
                    args.Request.Sample = null;
                    DisposeInternal();
                    return;
                }

                // if paused, "freeze" the timestamp
                TimeSpan timeStamp;
                if (IsPaused)
                {
                    timeStamp = _pausedTimestamp;
                }
                else
                {
                    timeStamp = frame.SystemRelativeTime;
                    _pausedTimestamp = timeStamp;
                }

                var sample = MediaStreamSample.CreateFromDirect3D11Surface(frame.Surface, timeStamp);
                args.Request.Sample = sample;
            }
        }
        catch (Exception e)
        {
          ...
        }
    }
    else
    {
      ...
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM