Memproses bingkai audio dengan MediaFrameReader

Artikel ini memperlihatkan kepada Anda cara menggunakan MediaFrameReader dengan MediaCapture untuk mendapatkan data audio dari sumber bingkai media. Untuk mempelajari tentang menggunakan MediaFrameReader untuk mendapatkan data gambar, seperti dari warna, inframerah, atau kamera kedalaman, lihat Memproses bingkai media dengan MediaFrameReader. Artikel tersebut memberikan gambaran umum tentang pola penggunaan pembaca bingkai dan membahas beberapa fitur tambahan kelas MediaFrameReader , seperti menggunakan MediaFrameSourceGroup untuk mengambil bingkai dari beberapa sumber secara bersamaan.

Catatan

Fitur yang dibahas dalam artikel ini hanya tersedia dimulai dengan Windows 10, versi 1803.

Catatan

Ada sampel aplikasi Universal Windows yang menunjukkan penggunaan MediaFrameReader untuk menampilkan bingkai dari sumber bingkai yang berbeda, termasuk warna, kedalaman, dan camreas inframerah. Untuk informasi selengkapnya, lihat Sampel bingkai kamera.

Menyiapkan proyek Anda

Proses untuk memperoleh bingkai audio sebagian besar sama dengan memperoleh jenis bingkai media lainnya. Seperti halnya aplikasi apa pun yang menggunakan MediaCapture, Anda harus menyatakan bahwa aplikasi Anda menggunakan kemampuan webcam sebelum mencoba mengakses perangkat kamera apa pun. Jika aplikasi Anda akan mengambil dari perangkat audio, Anda juga harus mendeklarasikan kemampuan perangkat mikrofon .

Menambahkan kemampuan ke manifes aplikasi

  1. Di Microsoft Visual Studio, di Penjelajah Solusi, buka perancang untuk manifes aplikasi dengan mengklik dua kali item package.appxmanifest .
  2. Pilih tab Kemampuan.
  3. Centang kotak untuk Webcam dan kotak untuk Mikrofon.
  4. Untuk akses ke pustaka Gambar dan Video, centang kotak untuk Pustaka Gambar dan kotak untuk Pustaka Video.

Pilih sumber bingkai dan grup sumber bingkai

Langkah pertama dalam menangkap bingkai audio adalah menginisialisasi MediaFrameSource yang mewakili sumber data audio, seperti mikrofon atau perangkat pengambilan audio lainnya. Untuk melakukan ini, Anda harus membuat instans baru objek MediaCapture . Untuk contoh ini, satu-satunya pengaturan inisialisasi untuk MediaCapture adalah mengatur StreamingCaptureMode untuk menunjukkan bahwa kita ingin mengalirkan audio dari perangkat pengambilan.

Setelah memanggil MediaCapture.InitializeAsync, Anda bisa mendapatkan daftar sumber bingkai media yang dapat diakses dengan properti FrameSources . Contoh ini menggunakan kueri Linq untuk memilih semua sumber bingkai di mana MediaFrameSourceInfo yang menjelaskan sumber bingkai memiliki MediaStreamTypeof Audio, yang menunjukkan bahwa sumber media menghasilkan data audio.

Jika kueri mengembalikan satu atau beberapa sumber bingkai, Anda dapat memeriksa properti CurrentFormat untuk melihat apakah sumber mendukung format audio yang Anda inginkan - dalam contoh ini, mengambangkan data audio. Periksa AudioEncodingProperties untuk memastikan pengodean audio yang Anda inginkan didukung oleh sumbernya.

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

Membuat dan Memulai MediaFrameReader

Dapatkan instans baru MediaFrameReader dengan memanggil MediaCapture.CreateFrameReaderAsync, melewati objek MediaFrameSource yang Anda pilih di langkah sebelumnya. Secara default, bingkai audio diperoleh dalam mode buffer, sehingga kecil kemungkinan bingkai akan dihilangkan, meskipun ini masih dapat terjadi jika Anda tidak memproses bingkai audio cukup cepat dan mengisi buffer memori yang dialokasikan sistem.

Daftarkan handler untuk peristiwa MediaFrameReader.FrameArrived , yang dinaikkan oleh sistem saat bingkai data audio baru tersedia. Panggil StartAsync untuk memulai akuisisi bingkai audio. Jika pembaca bingkai gagal memulai, nilai status yang dikembalikan dari panggilan akan memiliki nilai selain Berhasil.

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

Di penanganan aktivitas FrameArrived , panggil TryAcquireLatestFrame pada objek MediaFrameReader yang diteruskan sebagai pengirim ke handler untuk mencoba mengambil referensi ke bingkai media terbaru. Perhatikan bahwa objek ini bisa null, jadi Anda harus selalu memeriksa sebelum menggunakan objek . Kesalahan ketik bingkai media yang dibungkus dalam MediaFrameReference yang dikembalikan dari TryAcquireLatestFrame tergantung pada jenis sumber bingkai atau sumber apa yang Anda konfigurasikan untuk diperoleh pembaca bingkai. Karena pembaca bingkai dalam contoh ini disiapkan untuk memperoleh bingkai audio, ia mendapatkan bingkai yang mendasar menggunakan properti AudioMediaFrame .

Metode pembantu ProcessAudioFrame ini dalam contoh di bawah ini menunjukkan cara mendapatkan AudioFrame yang menyediakan informasi seperti tanda waktu bingkai dan apakah itu dihentikan dari objek AudioMediaFrame . Untuk membaca atau memproses data sampel audio, Anda harus mendapatkan objek AudioBuffer dari objek AudioMediaFrame , membuat IMemoryBufferReference, lalu memanggil metode COM IMemoryBufferByteAccess::GetBuffer untuk mengambil data. Lihat catatan di bawah daftar kode untuk informasi selengkapnya tentang mengakses buffer asli.

Format data tergantung pada sumber bingkai. Dalam contoh ini, saat memilih sumber bingkai media, kami secara eksplisit memastikan bahwa sumber bingkai yang dipilih menggunakan satu saluran data float. Kode contoh lainnya menunjukkan cara menentukan durasi dan jumlah sampel untuk data audio dalam bingkai.

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;

    }
}

Catatan

Untuk melakukan operasi pada data audio, Anda harus mengakses buffer memori asli. Untuk melakukan ini, Anda harus menggunakan antarmuka IMemoryBufferByteAccess COM dengan menyertakan daftar kode di bawah ini. Operasi pada buffer asli harus dilakukan dalam metode yang menggunakan kata kunci yang tidak aman . Anda juga perlu mencentang kotak untuk mengizinkan kode tidak aman di tab Build dari dialog Proyek -> Properti .

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

Informasi tambahan tentang menggunakan MediaFrameReader dengan data audio

Anda dapat mengambil AudioDeviceController yang terkait dengan sumber bingkai audio dengan mengakses properti MediaFrameSource.Controller . Objek ini dapat digunakan untuk mendapatkan atau mengatur properti aliran perangkat tangkapan atau untuk mengontrol tingkat pengambilan. Contoh berikut membisukan perangkat audio sehingga bingkai terus diperoleh oleh pembaca bingkai, tetapi semua sampel memiliki nilai 0.

audioDeviceController.Muted = true;

Anda dapat menggunakan objek AudioFrame untuk meneruskan data audio yang diambil oleh sumber bingkai media ke dalam AudioGraph. Teruskan bingkai ke metode AddFrame dari AudioFrameInputNode. Untuk informasi selengkapnya tentang menggunakan grafik audio untuk menangkap, memproses, dan mencampur sinyal audio, lihat Grafik audio.