Как исправить утечку памяти в 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. Память выглядит следующим образом: каждый тик вверх — это нажатие кнопки;

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

Не могли бы вы рассказать больше о том, как проверить утечку памяти?

Nico Zhu - MSFT 19.06.2019 08:50

@NicoZhu-MSFT Конечно; Я добавил некоторую информацию, чтобы повторить проблему в основной части вопроса.

Stephen Starkie 19.06.2019 10:59

Интересно, что мой настольный ПК с тем же кодом и USB-камерой (которая также показывает проблему на Surface Pro 4) не показывает проблему — мой настольный ПК — Win 10 v1809 (17763.504)

Stephen Starkie 19.06.2019 11:11

Хорошо, я понял, я проверю это, если проблема действительно существует, я сообщу соответствующей команде

Nico Zhu - MSFT 19.06.2019 11:42

Пожалуйста, проверьте эту проблему отчет, которая размещена на Github.

Nico Zhu - MSFT 19.06.2019 12:46

@NicoZhu-MSFT: спасибо, мы уже видели это; но я не думаю, что видеокарта (которая кажется там решением) действительно является проблемой здесь, учитывая, что это происходит на Surface Pro 4, на котором мы не можем заменить видеокарту (и это происходит на моем рабочем столе с встроенная карта) Это также происходит только в последней версии Win10: v1903. v1809 вроде нормально. Мы вернули Surface Pro, и утечка исчезла.

Stephen Starkie 19.06.2019 14:58

Хорошо, я обсужу с командой.

Nico Zhu - MSFT 20.06.2019 04:01

Давайте продолжить обсуждение в чате.

Nico Zhu - MSFT 20.06.2019 08:21

Спасибо за сообщение об этой проблеме, наша команда инженеров исследует эту проблему, я обновлю ее здесь, как только появятся какие-либо обновления.

Amy Peng - MSFT 20.06.2019 10:14
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
9
251
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

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

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

...
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);
...
            }
        }
...
    }
}

Другие вопросы по теме