Поделиться через


Обработка аудиокадров с помощью MediaFrameReader

В этой статье показано, как использовать MediaFrameReader с MediaCapture для получения звуковых данных из источника кадра мультимедиа. Сведения об использовании MediaFrameReader для получения данных изображения, таких как цвет, инфракрасная камера или камера глубины, см. в разделе "Обработка кадров мультимедиа" с помощью MediaFrameReader. В этой статье представлен общий обзор шаблона использования средства чтения кадров и рассматриваются некоторые дополнительные функции класса MediaFrameReader , такие как использование MediaFrameSourceGroup для получения кадров из нескольких источников одновременно.

Примечание.

Функции, рассмотренные в этой статье, доступны только начиная с Windows 10 версии 1803.

Примечание.

Существует пример универсального приложения Для Windows, демонстрирующий использование MediaFrameReader для отображения кадров из разных источников кадров, включая цвет, глубину и инфракрасные камеры. Дополнительные сведения см. в примере кадров камеры.

Настройка проекта

Процесс приобретения аудиокадров в значительной степени совпадает с получением других типов медиакадров. Как и в любом приложении, использующего MediaCapture, необходимо объявить, что приложение использует возможность веб-камеры, прежде чем пытаться получить доступ к любому устройству камеры. Если ваше приложение будет записывать с звукового устройства, вы также должны объявить возможность устройства микрофона.

Добавление возможностей в манифест приложения

  1. В Microsoft Visual Studio в Обозреватель решений откройте конструктор манифеста приложения, дважды щелкнув элемент package.appxmanifest.
  2. Перейдите на вкладку Возможности.
  3. Установите флажок для веб-камеры и флажок для микрофона.
  4. Чтобы получить доступ к библиотеке изображений и видео, установите флажки для библиотеки изображений и поле для библиотеки видео.

Выбор источников кадров и групп источников кадров

Первым шагом в записи аудиокадров является инициализация MediaFrameSource , представляющая источник звуковых данных, например микрофон или другое устройство захвата звука. Для этого необходимо создать новый экземпляр объекта MediaCapture. В этом примере единственным параметром инициализации для MediaCapture является настройка StreamingCaptureMode, указывающая, что мы хотим передавать звук с устройства записи.

После вызова MediaCapture.InitializeAsync можно получить список доступных источников кадров мультимедиа с помощью свойства FrameSources. В этом примере используется запрос Linq для выбора всех источников кадров, где MediaFrameSourceInfo, описывающий источник кадров, имеет MediaStreamType audio, указывающий, что источник мультимедиа создает звуковые данные.

Если запрос возвращает один или несколько источников кадров, можно проверить свойство CurrentFormat , чтобы узнать, поддерживает ли источник нужный формат звука в этом примере с плавающей запятой. Проверьте audioEncodingProperties, чтобы убедиться, что нужное кодирование звука поддерживается источником.

mediaCapture = new MediaCapture();
MediaCaptureInitializationSettings settings = new MediaCaptureInitializationSettings()
{
    StreamingCaptureMode = StreamingCaptureMode.Audio,
};
await mediaCapture.InitializeAsync(settings);

var audioFrameSources = mediaCapture.FrameSources.Where(x => x.Value.Info.MediaStreamType == MediaStreamType.Audio);

if (audioFrameSources.Count() == 0)
{
    Debug.WriteLine("No audio frame source was found.");
    return;
}

MediaFrameSource frameSource = audioFrameSources.FirstOrDefault().Value;

MediaFrameFormat format = frameSource.CurrentFormat;
if (format.Subtype != MediaEncodingSubtypes.Float)
{
    return;
}

if (format.AudioEncodingProperties.ChannelCount != 1
    || format.AudioEncodingProperties.SampleRate != 48000)
{
    return;
}

Создание и запуск MediaFrameReader

Получите новый экземпляр MediaFrameReader, вызвав MediaCapture.CreateFrameReaderAsync, передав объект MediaFrameSource, выбранный на предыдущем шаге. По умолчанию аудиокадры получаются в буферизованном режиме, что делает его менее вероятным, что кадры будут удалены, хотя это все равно может произойти, если вы не обрабатываете аудиокадры достаточно быстро и заполняете буфер памяти системы.

Зарегистрируйте обработчик события MediaFrameReader.FrameArrived , который вызывается системой при наличии нового кадра звуковых данных. Вызов StartAsync, чтобы начать приобретение аудиокадров. Если средство чтения кадров не запускается, значение состояния, возвращаемое из вызова, будет иметь значение, отличное от успешного выполнения.

mediaFrameReader = await mediaCapture.CreateFrameReaderAsync(frameSource);

// Optionally set acquisition mode. Buffered is the default mode for audio.
mediaFrameReader.AcquisitionMode = MediaFrameReaderAcquisitionMode.Buffered;

mediaFrameReader.FrameArrived += MediaFrameReader_AudioFrameArrived;

var status = await mediaFrameReader.StartAsync();

if (status != MediaFrameReaderStartStatus.Success)
{
    Debug.WriteLine("The MediaFrameReader couldn't start.");
}

В обработчике событий FrameArrived вызовите TryAcquireLatestFrame в объекте MediaFrameReader, переданном обработчику, чтобы попытаться получить ссылку на последний кадр мультимедиа. Обратите внимание, что этот объект может иметь значение NULL, поэтому перед использованием объекта всегда следует проверять его. Тип кадра мультимедиа, упакованный в MediaFrameReference , возвращаемый из TryAcquireLatestFrame , зависит от типа источника кадров или источников, которые вы настроили средство чтения кадров для получения. Так как средство чтения кадров в этом примере было настроено для получения аудиокадров, он получает базовый кадр с помощью свойства AudioMediaFrame.

Этот вспомогательный метод ProcessAudioFrame в приведенном ниже примере показывает, как получить аудиофрейм, предоставляющий такие сведения, как метка времени кадра и не является ли она прекращенной из объекта AudioMediaFrame. Чтобы прочитать или обработать данные образца звука, необходимо получить объект AudioBuffer из объекта AudioMediaFrame, создать IMemoryBufferReferEnce, а затем вызвать метод COM IMemoryBufferByteAccess::GetBuffer для получения данных. Дополнительные сведения о доступе к собственным буферам см. в описании кода ниже.

Формат данных зависит от источника кадров. В этом примере при выборе источника кадра мультимедиа мы явно убедились, что выбранный источник кадров использовал один канал с плавающей запятой. В остальной части примера кода показано, как определить длительность и количество выборок для звуковых данных в кадре.

private void MediaFrameReader_AudioFrameArrived(MediaFrameReader sender, MediaFrameArrivedEventArgs args)
{
    using (MediaFrameReference reference = sender.TryAcquireLatestFrame())
    {
        if (reference != null)
        {
            ProcessAudioFrame(reference.AudioMediaFrame);
        }
    }
}
unsafe private void ProcessAudioFrame(AudioMediaFrame audioMediaFrame)
{

    using (AudioFrame audioFrame = audioMediaFrame.GetAudioFrame())
    using (AudioBuffer buffer = audioFrame.LockBuffer(AudioBufferAccessMode.Read))
    using (IMemoryBufferReference reference = buffer.CreateReference())
    {
        byte* dataInBytes;
        uint capacityInBytes;
        float* dataInFloat;


        ((IMemoryBufferByteAccess)reference).GetBuffer(out dataInBytes, out capacityInBytes);
        
        // The requested format was float
        dataInFloat = (float*)dataInBytes;

        // Get the number of samples by multiplying the duration by sampling rate: 
        // duration [s] x sampling rate [samples/s] = # samples 

        // Duration can be gotten off the frame reference OR the audioFrame
        TimeSpan duration = audioMediaFrame.FrameReference.Duration;

        // frameDurMs is in milliseconds, while SampleRate is given per second.
        uint frameDurMs = (uint)duration.TotalMilliseconds;
        uint sampleRate = audioMediaFrame.AudioEncodingProperties.SampleRate;
        uint sampleCount = (frameDurMs * sampleRate) / 1000;

    }
}

Примечание.

Для работы с звуковыми данными необходимо получить доступ к собственному буферу памяти. Для этого необходимо использовать COM-интерфейс IMemoryBufferByteAccess , включив приведенный ниже код. Операции с собственным буфером должны выполняться в методе, использующего небезопасное ключевое слово. Кроме того, необходимо установить флажок, чтобы разрешить небезопасный код на вкладке "Сборка " диалогового окна "Проект —> свойства ".

[ComImport]
[Guid("5B0D3235-4DBA-4D44-865E-8F1D0E4FD04D")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
unsafe interface IMemoryBufferByteAccess
{
    void GetBuffer(out byte* buffer, out uint capacity);
}

Дополнительные сведения об использовании MediaFrameReader с звуковыми данными

Вы можете получить AudioDeviceController, связанный с источником аудиокадров, путем доступа к свойству MediaFrameSource.Controller. Этот объект можно использовать для получения или задания свойств потока устройства захвата или управления уровнем захвата. В следующем примере отключает звуковое устройство, чтобы кадры продолжали получаться средством чтения кадров, но все образцы имеют значение 0.

audioDeviceController.Muted = true;

Объект AudioFrame можно использовать для передачи звуковых данных, захваченных источником кадра мультимедиа, в AudioGraph. Передайте кадр в метод AddFrame объекта AudioFrameInputNode. Дополнительные сведения об использовании звуковых графов для записи, обработки и смешивания звуковых сигналов см. в разделе "Звуковые графы".