Как исправить утечку памяти в GetPreviewFrameAsync

У меня есть код, основанный на этом образце; https://github.com/microsoft/Windows-universal-samples/tree/master/Samples/CameraGetPreviewFrame. Каждый раз, когда линия;

await _mediaCapture.GetPreviewFrameAsync(_currentVideoFrame);

хит мы, кажется, утечка памяти. Что я не убираю? Я также пытался каждый раз создавать рамку шаблона и удалять и обнулять ее в каждом цикле - похоже, это тоже не работает.

Я вернулся к исходному образцу от Microsoft, и, похоже, он тоже протекает. Вот мой код;

await Task.Run(async () =>
{
    try
    {
        var videoEncodingProperties = 
            _mediaCapture.VideoDeviceController.GetMediaStreamProperties
                (MediaStreamType.VideoPreview) as VideoEncodingProperties;

        Debug.Assert(videoEncodingProperties != null, nameof(videoEncodingProperties) + " != null");

        _currentVideoFrame = new VideoFrame(BitmapPixelFormat.Gray8,
            (int) videoEncodingProperties.Width,
            (int) videoEncodingProperties.Height);

        TimeSpan? lastFrameTime = null;

        while (_mediaCapture.CameraStreamState == CameraStreamState.Streaming)
        {
            token.ThrowIfCancellationRequested();

            await _mediaCapture.GetPreviewFrameAsync(_currentVideoFrame);

            if (!lastFrameTime.HasValue ||
                lastFrameTime != _currentVideoFrame.RelativeTime)
            {
                await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync
                    (CoreDispatcherPriority.Normal,
                    () =>
                    {
                        try
                        {
                            Debug.Assert(_currentVideoFrame != null,
                                        $"{nameof(_currentVideoFrame)} != null");

                            var bitmap = _currentVideoFrame.SoftwareBitmap.AsBitmap();

                            float focalLength = _cameraOptions == CameraOptions.Front ? AppSettings.FrontCameraFocalLength : AppSettings.RearCameraFocalLength;

                            _frameProcessor.ProcessFrame(bitmap, focalLength);
                        }
                        catch (Exception ex)
                        {
                            Debug.WriteLine($"Exception: {ex}");
                        }
                    });

                lastFrameTime = _currentVideoFrame.RelativeTime;
            }
        }
    }
    catch (Exception ex)
    {
        Debug.WriteLine($"Exception: {ex}");
    }
},
token);

Это должно просто получать кадры и передавать их через вызов _frameProcessor.ProcessFrame(), но даже когда это ничего не делает (и я вырезал все, кроме GetPreviewFrameAsync), происходит утечка.

Чтобы повторить проблему, загрузите образец с; https://github.com/microsoft/Windows-universal-samples/tree/master/Samples/CameraGetPreviewFrame. Запустите образец в отладчике с помощью инструментов диагностики (Отладка->Windows->Показать инструменты диагностики) удаленно на Surface Pro 4 (i5-6300U @2,4 ГГц) под управлением Windows 10 v 1903 (18362.175). Установите флажок «Показать кадр» и наблюдайте за памятью при нажатии кнопки GetPreviewFrameAsync. Память выглядит следующим образом: каждый тик вверх — это нажатие кнопки;

Утечка памяти


person Stephen Starkie    schedule 18.06.2019    source источник
comment
Не могли бы вы рассказать больше о том, как проверить утечку памяти?   -  person Nico Zhu - MSFT    schedule 19.06.2019
comment
@NicoZhu-MSFT Конечно; Я добавил некоторую информацию, чтобы повторить проблему в основной части вопроса.   -  person Stephen Starkie    schedule 19.06.2019
comment
Интересно, что мой настольный ПК с тем же кодом и USB-камерой (которая также показывает проблему на Surface Pro 4) не показывает проблему — мой настольный ПК — Win 10 v1809 (17763.504)   -  person Stephen Starkie    schedule 19.06.2019
comment
Хорошо, я понял, я проверю это, если проблема действительно существует, я сообщу соответствующей команде   -  person Nico Zhu - MSFT    schedule 19.06.2019
comment
Пожалуйста, проверьте эту проблему сообщите об этом хосте в Github.   -  person Nico Zhu - MSFT    schedule 19.06.2019
comment
@NicoZhu-MSFT: спасибо, мы уже видели это; но я не думаю, что видеокарта (которая кажется там решением) действительно является проблемой здесь, учитывая, что это происходит на Surface Pro 4, на котором мы не можем заменить видеокарту (и это происходит на моем рабочем столе с встроенная карта) Это также происходит только в последней версии Win10: v1903. v1809 вроде нормально. Мы вернули Surface Pro, и утечка исчезла.   -  person Stephen Starkie    schedule 19.06.2019
comment
Хорошо, я обсужу с командой.   -  person Nico Zhu - MSFT    schedule 20.06.2019
comment
Давайте продолжим это обсуждение в чате.   -  person Nico Zhu - MSFT    schedule 20.06.2019
comment
Спасибо за сообщение об этой проблеме, наша команда инженеров исследует эту проблему, я обновлю ее здесь, как только появятся какие-либо обновления.   -  person Amy Peng - MSFT    schedule 20.06.2019


Ответы (1)


Использование MediaFrameReader API работает эта ошибка присутствует в нашем коде и, возможно, немного более отзывчива. Теперь Microsoft добавила примечание в документацию по GetPreviewFrameAsync. page, чтобы указать на это.

Это работает для нас;

...
private MediaFrameReader _mediaFrameReader;
...

private async Task InitializeCameraAsync()
{
    if (_mediaCapture == null)
    {
         _mediaCapture = new MediaCapture();
         var frameSourceGroups = await MediaFrameSourceGroup.FindAllAsync();
         var selectedGroup = frameSourceGroups.FirstOrDefault(x => x.Id.Equals(_camera.UwpDeviceInfo.Id));

         try
         {
             var mediaInitSettings = new MediaCaptureInitializationSettings
             {
                 SourceGroup = selectedGroup,
                 VideoDeviceId = _camera.UwpDeviceInfo.Id,
                 AudioDeviceId = string.Empty,
                 StreamingCaptureMode = StreamingCaptureMode.Video,
                 MemoryPreference = MediaCaptureMemoryPreference.Cpu
             };

             await _mediaCapture.InitializeAsync(mediaInitSettings);

             _isInitialized = true;
         }
         catch (UnauthorizedAccessException)
         {
...
         }
         catch (Exception ex)
         {
...
         }
...

         // Set-up for frameProcessing
         var sourceInfo = selectedGroup?.SourceInfos.FirstOrDefault(info =>
             info.SourceKind == MediaFrameSourceKind.Color);
...                   
         var colorFrameSource = _mediaCapture.FrameSources[sourceInfo.Id];
         var preferredFormat = colorFrameSource.SupportedFormats
             .OrderByDescending(x => x.VideoFormat.Width)
             .FirstOrDefault(x => x.VideoFormat.Width <= 1920 &&
                  x.Subtype.Equals(MediaEncodingSubtypes.Nv12, StringComparison.OrdinalIgnoreCase));

         await colorFrameSource.SetFormatAsync(preferredFormat);

         _mediaFrameReader = await _mediaCapture.CreateFrameReaderAsync(colorFrameSource);
     }
...
}

...

private void _mediaFrameReader_FrameArrived(MediaFrameReader sender, MediaFrameArrivedEventArgs args)
{
...
        var mediaFrameReference = sender.TryAcquireLatestFrame();
        var videoMediaFrame = mediaFrameReference?.VideoMediaFrame;
        var softwareBitmap = videoMediaFrame?.SoftwareBitmap;

        if (softwareBitmap != null && _frameProcessor != null)
        {
            if (_mediaCapture.CameraStreamState == CameraStreamState.Streaming)
            {
...
                _frameProcessor.ProcessFrame(SoftwareBitmap.Convert(softwareBitmap, 
                        BitmapPixelFormat.Gray8).AsBitmap(), _camera);
...
            }
        }
...
    }
}
person Stephen Starkie    schedule 02.07.2019