Share via


Elaborare frame audio con MediaFrameReader

Questo articolo illustra come usare MediaFrameReader con MediaCapture per ottenere dati audio da un'origine di fotogrammi multimediali. Per informazioni sull'uso di un MediaFrameReader per ottenere dati di immagine, ad esempio da una fotocamera a colori, infrarossi o profondità, vedere Elaborare fotogrammi multimediali con MediaFrameReader. Questo articolo offre una panoramica generale del modello di utilizzo del lettore di fotogrammi e illustra alcune funzionalità aggiuntive della classe MediaFrameReader, ad esempio l'uso di MediaFrameSourceGroup per recuperare fotogrammi da più origini contemporaneamente.

Nota

Le funzionalità descritte in questo articolo sono disponibili solo a partire da Windows 10 versione 1803.

Nota

È disponibile un esempio di app di Universal Windows che illustra l'uso di MediaFrameReader per visualizzare fotogrammi da origini di fotogrammi diverse, tra cui camera a colori, profondità e infrarossi. Per altre informazioni, vedere l'esempio Camera frames.

Impostazione del progetto

Il processo di acquisizione di fotogrammi audio è in gran parte uguale all'acquisizione di altri tipi di fotogrammi multimediali. Come per qualsiasi app che usa MediaCapture, si deve dichiarare che l'app usa la funzionalità webcam prima di tentare di accedere a qualsiasi dispositivo fotocamera. Se l'app acquisisce da un dispositivo audio, devi anche dichiarare la funzionalità del dispositivo microfono.

Aggiungere funzionalità al manifesto dell'app

  1. In Esplora soluzioni in Microsoft Visual Studio aprire la finestra di progettazione per il manifesto dell'applicazione facendo doppio clic sull'elemento package.appxmanifest.
  2. Fare clic sulla scheda Funzionalità.
  3. Selezionare la casella Webcam e la casella microfono.
  4. Per accedere alla raccolta immagini e video, selezionare le caselle Pictures Library e la casella Videos Library.

Selezionare le origini dei fotogrammi e i gruppi di origine dei frame

Il primo passaggio nell'acquisizione di fotogrammi audio consiste nell'inizializzare un oggetto MediaFrameSource che rappresenta l'origine dei dati audio, ad esempio un microfono o un altro dispositivo di acquisizione audio. A tale scopo, è necessario creare una nuova istanza dell'oggetto MediaCapture. Per questo esempio, l'unica impostazione di inizializzazione per MediaCapture è l'impostazione di StreamingCaptureMode per indicare che si vuole trasmettere l'audio dal dispositivo di acquisizione.

Dopo aver chiamato MediaCapture.InitializeAsync, è possibile ottenere l'elenco delle origini dei fotogrammi multimediali accessibili con la proprietà FrameSources. In questo esempio viene utilizzata una query Linq per selezionare tutte le origini dei fotogrammi in cui MediaFrameSourceInfo che descrive l'origine fotogramma ha un MediaStreamType di Audio, a indicare che l'origine multimediale produce dati audio.

Se la query restituisce una o più origini frame, è possibile controllare la proprietà CurrentFormat per verificare se l'origine supporta il formato audio desiderato, in questo esempio i dati audio float. Controllare AudioEncodingProperties per assicurarsi che la codifica audio desiderata sia supportata dall'origine.

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

Creare e avviare MediaFrameReader

Ottenere una nuova istanza di MediaFrameReader chiamando MediaCapture.CreateFrameReaderAsync, passando l'oggetto MediaFrameSource selezionato nel passaggio precedente. Per impostazione predefinita, i fotogrammi audio vengono ottenuti in modalità memorizzata nel buffer, rendendo meno probabile che i fotogrammi vengano eliminati, anche se ciò può verificarsi ancora se non si elaborano fotogrammi audio abbastanza veloci e riempiono il buffer di memoria allocato del sistema.

Registrare un gestore per l'evento MediaFrameReader.FrameArrived, generato dal sistema quando è disponibile un nuovo frame di dati audio. Chiama StartAsync per avviare l'acquisizione di fotogrammi audio. Se l'avvio del lettore di fotogrammi non riesce, il valore di stato restituito dalla chiamata avrà un valore diverso da Success.

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

Nel gestore eventi FrameArrived, chiamare TryAcquireLatestFrame sull'oggetto MediaFrameReader passato come mittente al gestore per tentare di recuperare un riferimento al fotogramma multimediale più recente. Si noti che questo oggetto può essere Null, quindi è consigliabile controllare sempre prima di usare l'oggetto. Gli errori di digitazione del frame multimediale racchiusi in MediaFrameReference restituiti da TryAcquireLatestFrame dipendono dal tipo di origine o dalle origini dei fotogrammi configurati per l'acquisizione. Poiché il lettore di fotogrammi in questo esempio è stato configurato per acquisire fotogrammi audio, ottiene il fotogramma sottostante usando la proprietà AudioMediaFrame.

Questo metodo helper ProcessAudioFrame helper nell'esempio seguente mostra come ottenere un AudioFrame che fornisce informazioni come il timestamp del frame e se è discontinuo dall'oggetto AudioMediaFrame. Per leggere o elaborare i dati di esempio audio, è necessario ottenere l'oggetto AudioBuffer dall'oggetto AudioMediaFrame, creare un IMemoryBufferReference e quindi chiamare il metodo COM IMemoryBufferByteAccess::GetBuffer per recuperare i dati. Per altre informazioni sull'accesso ai buffer nativi, vedere la nota seguente.

Il formato dei dati dipende dall'origine del frame. In questo esempio, quando si seleziona un'origine fotogramma multimediale, è stato specificato in modo esplicito che l'origine fotogramma selezionata ha usato un singolo canale di dati float. Il resto del codice di esempio mostra come determinare la durata e il conteggio dei campioni per i dati audio nel frame.

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;

    }
}

Nota

Per operare sui dati audio, è necessario accedere a un buffer di memoria nativo. A tale scopo, è necessario usare l'interfaccia COM IMemoryBufferByteAccess includendo l'elenco di codice riportato di seguito. Le operazioni sul buffer nativo devono essere eseguite in un metodo che usa la parola chiave unsafe. È anche necessario selezionare la casella per consentire il codice non sicuro nella scheda Compilazione della finestra di dialogo Progetto:> Proprietà.

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

Altre informazioni sull'uso di MediaFrameReader con dati audio

È possibile recuperare l'oggetto AudioDeviceController associato all'origine dei fotogrammi audio accedendo alla proprietà MediaFrameSource.Controller. Questo oggetto può essere usato per ottenere o impostare le proprietà del flusso del dispositivo di acquisizione o per controllare il livello di acquisizione. Nell'esempio seguente il dispositivo audio viene disattivato in modo che i fotogrammi continuino a essere acquisiti dal lettore di fotogrammi, ma tutti gli esempi hanno il valore 0.

audioDeviceController.Muted = true;

È possibile utilizzare un oggetto AudioFrame per passare i dati audio acquisiti da un'origine di fotogrammi multimediali in un oggetto AudioGraph. Passare il fotogramma al metodo AddFrame di un AudioFrameInputNode. Per maggiori informazioni sull'uso di grafici audio per acquisire, elaborare e combinare segnali audio, vedere Grafici audio.