Freigeben über


Verarbeiten von Audioframes mit „MediaFrameReader“

In diesem Artikel erfahren Sie, wie Sie einen MediaFrameReader mit MediaCapture verwenden, um Audiodaten aus einer Medienframequelle abzurufen. Informationen zur Verwendung eines MediaFrameReader zum Abrufen von Bilddaten, z. B. von einer Farb-, Infrarot- oder Tiefenkamera, finden Sie unter Verarbeiten von Medienframes mit MediaFrameReader. Dieser Artikel bietet eine allgemeine Übersicht über das Verwendungsmuster für Frameleser und erläutert einige zusätzliche Features der MediaFrameReader-Klasse , z. B. die Verwendung von MediaFrameSourceGroup zum gleichzeitigen Abrufen von Frames aus mehreren Quellen.

Hinweis

Die in diesem Artikel beschriebenen Features sind nur ab Windows 10 Version 1803 verfügbar.

Hinweis

Es gibt ein Beispiel für universelle Windows-Apps, in dem die Verwendung von MediaFrameReader zum Anzeigen von Frames aus unterschiedlichen Framequellen demonstriert wird, unter anderem Farb-, Tiefen- und Infrarotkameras. Weitere Informationen finden Sie unter Beispiel für Kameraframes.

Einrichten Ihres Projekts

Der Prozess zum Abrufen von Audioframes entspricht weitgehend dem Abrufen anderer Arten von Medienframes. Wie bei allen Apps, die MediaCapture verwenden, müssen Sie deklarieren, dass Ihre App die Webcam-Funktion verwendet. Erst dann können Sie auf Kamerageräte zugreifen. Wenn Ihre App von einem Audiogerät aufzeichnet, müssen Sie auch die microphone-Gerätefunktion deklarieren.

Hinzufügen von Funktionen zum App-Manifest

  1. Öffnen Sie in Microsoft Visual Studio im Projektmappen-Explorer den Designer für das Anwendungsmanifest, indem Sie auf das Element package.appxmanifest doppelklicken.
  2. Wählen Sie die Registerkarte Funktionen aus.
  3. Aktivieren Sie das Kontrollkästchen für Webcam und das Kontrollkästchen für Mikrofon.
  4. Für den Zugriff auf die Bibliothek „Bilder und Videos“ aktivieren Sie die Kontrollkästchen für Bildbibliothek und Videobibliothek.

Auswählen von Framequellen und Framequellgruppen

Der erste Schritt beim Erfassen von Audioframes besteht darin, eine MediaFrameSource zu initialisieren, die die Quelle der Audiodaten darstellt, z. B. ein Mikrofon oder ein anderes Audioaufnahmegerät. Dazu müssen Sie eine neue instance des MediaCapture-Objekts erstellen. In diesem Beispiel ist die einzige Initialisierungseinstellung für MediaCapture das Festlegen von StreamingCaptureMode , um anzugeben, dass audio vom Aufnahmegerät gestreamt werden soll.

Nachdem Sie MediaCapture.InitializeAsync aufgerufen haben, können Sie die Liste der zugänglichen Medienframequellen mit der FrameSources-Eigenschaft abrufen. In diesem Beispiel wird eine Linq-Abfrage verwendet, um alle Framequellen auszuwählen, bei denen mediaFrameSourceInfo , das die Framequelle beschreibt, einen MediaStreamType von Audio aufweist, was angibt, dass die Medienquelle Audiodaten erzeugt.

Wenn die Abfrage eine oder mehrere Framequellen zurückgibt, können Sie die CurrentFormat-Eigenschaft überprüfen, um festzustellen, ob die Quelle das gewünschte Audioformat unterstützt – in diesem Beispiel float-Audiodaten. Überprüfen Sie die AudioEncodingProperties , um sicherzustellen, dass die gewünschte Audiocodierung von der Quelle unterstützt wird.

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

Erstellen und Starten des MediaFrameReader

Rufen Sie eine neue instance von MediaFrameReader ab, indem Sie MediaCapture.CreateFrameReaderAsync aufrufen und das MediaFrameSource-Objekt übergeben, das Sie im vorherigen Schritt ausgewählt haben. Standardmäßig werden Audioframes im gepufferten Modus abgerufen, sodass es weniger wahrscheinlich ist, dass Frames gelöscht werden, obwohl dies immer noch vorkommen kann, wenn Sie Audioframes nicht schnell genug verarbeiten und den bereitgestellten Speicherpuffer des Systems auffüllen.

Registrieren Sie einen Handler für das MediaFrameReader.FrameArrived-Ereignis , das vom System ausgelöst wird, wenn ein neuer Frame mit Audiodaten verfügbar ist. Rufen Sie StartAsync auf, um mit dem Abrufen von Audioframes zu beginnen. Wenn der Frameleser nicht gestartet werden kann, weist der vom Aufruf zurückgegebene wert status einen anderen Wert als Success auf.

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

Rufen Sie im FrameArrived-EreignishandlerTryAcquireLatestFrame für das MediaFrameReader-Objekt auf, das als Absender an den Handler übergeben wird, um zu versuchen, einen Verweis auf den neuesten Medienframe abzurufen. Beachten Sie, dass dieses Objekt NULL sein kann, sodass Sie immer überprüfen sollten, bevor Sie das -Objekt verwenden. Die Typisierungen von Medienframes, die in mediaFrameReference umschlossen sind, die von TryAcquireLatestFrame zurückgegeben werden, hängen davon ab, welche Framequelle bzw. welche Quellen Sie für den Frameleser konfiguriert haben. Da der Framereader in diesem Beispiel für das Abrufen von Audioframes eingerichtet wurde, ruft er den zugrunde liegenden Frame mithilfe der AudioMediaFrame-Eigenschaft ab.

Diese ProcessAudioFrame-Hilfsmethode im folgenden Beispiel zeigt, wie Sie einen AudioFrame abrufen, der Informationen wie den Zeitstempel des Frames bereitstellt und ob er vom AudioMediaFrame-Objekt getrennt ist. Zum Lesen oder Verarbeiten der Audiobeispieldaten müssen Sie das AudioBuffer-Objekt aus dem AudioMediaFrame-Objekt abrufen, eine IMemoryBufferReference erstellen und dann die COM-Methode IMemoryBufferByteAccess::GetBuffer aufrufen, um die Daten abzurufen. Weitere Informationen zum Zugriff auf native Puffer finden Sie im Hinweis unter der Codeauflistung.

Das Format der Daten hängt von der Framequelle ab. In diesem Beispiel haben wir beim Auswählen einer Medienframequelle explizit sichergestellt, dass die ausgewählte Framequelle einen einzelnen Kanal mit Floatdaten verwendet. Der rest des Beispielcodes zeigt, wie Sie die Dauer und die Anzahl der Stichproben für die Audiodaten im Frame bestimmen.

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;

    }
}

Hinweis

Um die Audiodaten zu verarbeiten, müssen Sie auf einen nativen Speicherpuffer zugreifen. Dazu müssen Sie die IMemoryBufferByteAccess-COM-Schnittstelle verwenden, indem Sie die folgende Codeliste einschließen. Vorgänge für den nativen Puffer müssen in einer Methode ausgeführt werden, die die unsichere Schlüsselwort (keyword) verwendet. Sie müssen auch das Kontrollkästchen aktivieren, um unsicheren Code auf der Registerkarte Erstellen des Dialogfelds Projekt –> Eigenschaften zuzulassen.

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

Zusätzliche Informationen zur Verwendung von MediaFrameReader mit Audiodaten

Sie können den audioDeviceController abrufen, der der Audioframequelle zugeordnet ist, indem Sie auf die MediaFrameSource.Controller-Eigenschaft zugreifen. Dieses Objekt kann verwendet werden, um die Streameigenschaften des Aufnahmegeräts abzurufen oder festzulegen oder um die Erfassungsebene zu steuern. Im folgenden Beispiel wird das Audiogerät stummgeschaltet, sodass Frames weiterhin vom Framereader abgerufen werden, aber alle Beispiele den Wert 0 haben.

audioDeviceController.Muted = true;

Sie können ein AudioFrame-Objekt verwenden, um von einer Medienframequelle erfasste Audiodaten an einen AudioGraph zu übergeben. Übergeben Sie den Frame an die AddFrame-Methode eines AudioFrameInputNode-Elements. Weitere Informationen zur Verwendung von Audiographen zum Erfassen, Verarbeiten und Mischen von Audiosignalen finden Sie unter Audiographen.