0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

XAudio2とMediaFoundationを使ったWAV/MP3再生その2

Posted at

はじめに

その1ではXAudio2を使ってWAV再生を行いました。
しかし、このままではWAV以外を再生できません。
Media FoundationはMP3をサポートしており読み込むことができるので
XAudio2とMedia Foundationを使ってMP3の再生を行います。

XAudio2とMediaFoundationを使ったWAV/MP3再生その1
https://qiita.com/ryo_shiraishi6352/items/cc1b54b47a46a353c549

Media Foundationでサポートされるメディア形式
https://docs.microsoft.com/ja-jp/windows/win32/medfound/supported-media-formats-in-media-foundation

Media Foundationの初期化

Media Foundationを使用するために以下のヘッダファイルとlibファイルを使用します。

#include <mfapi.h>
#include <mfidl.h>
#include <mfreadwrite.h>

#pragma comment(lib, "Mf.lib")
#pragma comment(lib, "mfplat.lib")
#pragma comment(lib, "Mfreadwrite.lib")
#pragma comment(lib, "mfuuid.lib")

Media Foundationの初期化をするにはCOMの初期化、Media Foundationの初期化の順に行います。

CoInitializeEx(nullptr, COINIT_MULTITHREADED);

MFStartup(MF_VERSION, MFSTARTUP_NOSOCKET);

ソースリーダーの作成

ソースリーダーを作成します。

IMFSourceReader* pMFSourceReader{ nullptr };
MFCreateSourceReaderFromURL(path.c_str(), NULL, &pMFSourceReader);

メディアタイプの取得

メディアタイプを取得します。
まず、ソースリーダーにPCMで読み込むために
MF_MT_MAJOR_TYPEにMFMediaType_Audio、MF_MT_SUBTYPEにMFAudioFormat_PCM
を指定してからソースリーダからメディアタイプを取得します。

IMFMediaType* pMFMediaType{ nullptr };
MFCreateMediaType(&pMFMediaType);
pMFMediaType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio);
pMFMediaType->SetGUID(MF_MT_SUBTYPE, MFAudioFormat_PCM);
pMFSourceReader->SetCurrentMediaType(MF_SOURCE_READER_FIRST_AUDIO_STREAM, nullptr, pMFMediaType);

pMFMediaType->Release();
pMFMediaType = nullptr;
pMFSourceReader->GetCurrentMediaType(MF_SOURCE_READER_FIRST_AUDIO_STREAM, &pMFMediaType);

オーディオデータ形式の作成

メディアタイプからWAVEFORMATEXを生成します。

WAVEFORMATEX* waveFormat{ nullptr };
MFCreateWaveFormatExFromMFMediaType(pMFMediaType, &waveFormat, nullptr);

データの読み込み

ソースリーダーからサンプルを読み込んでvectorに格納していきます。

std::vector<BYTE> mediaData;
while (true)
{
    IMFSample* pMFSample{ nullptr };
    DWORD dwStreamFlags{ 0 };
    pMFSourceReader->ReadSample(MF_SOURCE_READER_FIRST_AUDIO_STREAM, 0, nullptr, &dwStreamFlags, nullptr, &pMFSample);

    if (dwStreamFlags & MF_SOURCE_READERF_ENDOFSTREAM)
    {
        break;
    }

    IMFMediaBuffer* pMFMediaBuffer{ nullptr };
    pMFSample->ConvertToContiguousBuffer(&pMFMediaBuffer);

    BYTE* pBuffer{ nullptr };
    DWORD cbCurrentLength{ 0 };
    pMFMediaBuffer->Lock(&pBuffer, nullptr, &cbCurrentLength);

    mediaData.resize(mediaData.size() + cbCurrentLength);
    memcpy(mediaData.data() + mediaData.size() - cbCurrentLength, pBuffer, cbCurrentLength);

    pMFMediaBuffer->Unlock();

    pMFMediaBuffer->Release();
    pMFSample->Release();
}

XAudio2で再生

XAudio2の初期化などはその1とほとんど同じなので省略します。
ソースボイスを生成して、データを与えます。

IXAudio2SourceVoice* pSourceVoice{ nullptr };
pXAudio2->CreateSourceVoice(&pSourceVoice, waveFormat);

XAUDIO2_BUFFER buffer{ 0 };
buffer.pAudioData = mediaData.data();
buffer.Flags = XAUDIO2_END_OF_STREAM;
buffer.AudioBytes = sizeof(BYTE) * static_cast<UINT32>(mediaData.size());
pSourceVoice->SubmitSourceBuffer(&buffer);

Media Foundationの終了

作られた順番に破棄していきます。

CoTaskMemFree(waveFormat);
pMFMediaType->Release();
pMFSourceReader->Release();
MFShutdown();

CoUninitialize();

終わりに

XAudio2とMedia Foundationを使ってMP3の再生を行いました。
Media FoundationはWAVもサポートしているのでコードを変更せずにWAVも再生できます。

今回のコードは以下のところにおいています。
https://github.com/ryo-shiraishi6352/Articles/blob/main/XAudio2MFPlay.h

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?