Microsoft DirectX 8.0 |
ここには、マルチメディア ストリーミング インターフェイスを実装するサンプル コードを記載する。ビデオ ストリーミングのサンプル コードは、ファイルを読み取り、それをプライマリ Microsoft® DirectDraw® サーフェスにレンダリングする方法を示す。このコードでは簡潔さのため、エラー チェックが省略されている。
2 番目のサンプル コードは、オーディオ ストリーミング インターフェイスを使ってオーディオ データをストリームする方法を示す。
以下の項で構成される。
このサンプル コードでは、ファイルを読み取り、それをプライマリ DirectDraw サーフェスにレンダリングする。
#include <stdio.h> #include "ddraw.h" // DirectDraw インターフェイス #include "mmstream.h" // マルチメディア ストリーム インターフェイス #include "amstream.h" // DirectShow マルチメディア ストリーム インターフェイス #include "ddstream.h" // DirectDraw マルチメディア ストリーム インターフェイス void RenderStreamToSurface(IDirectDrawSurface *pSurface, IMultiMediaStream *pMMStream) { IMediaStream *pPrimaryVidStream; IDirectDrawMediaStream *pDDStream; IDirectDrawStreamSample *pSample; RECT rect; DDSURFACEDESC ddsd; pMMStream->GetMediaStream(MSPID_PrimaryVideo, &pPrimaryVidStream); pPrimaryVidStream->QueryInterface(IID_IDirectDrawMediaStream, (void **)&pDDStream); ddsd.dwSize = sizeof(ddsd); pDDStream->GetFormat(&ddsd, NULL, NULL, NULL); rect.top = rect.left = 0; rect.bottom = ddsd.dwHeight; rect.right = ddsd.dwWidth; pDDStream->CreateSample(pSurface, &rect, 0, &pSample); pMMStream->SetState(STREAMSTATE_RUN); while (pSample->Update(0, NULL, NULL, NULL) == S_OK); pMMStream->SetState(STREAMSTATE_STOP); pSample->Release(); pDDStream->Release(); pPrimaryVidStream->Release(); } void RenderFileToMMStream(const char * szFileName, IMultiMediaStream **ppMMStream, IDirectDraw *pDD) { IAMMultiMediaStream *pAMStream; CoCreateInstance(CLSID_AMMultiMediaStream, NULL, CLSCTX_INPROC_SERVER, IID_IAMMultiMediaStream, (void **)&pAMStream); WCHAR wPath[MAX_PATH]; // ワイド (32 ビット) 文字列名 MultiByteToWideChar(CP_ACP, 0, szFileName, -1, wPath, sizeof(wPath)/sizeof(wPath[0])); pAMStream->Initialize(STREAMTYPE_READ, AMMSF_NOGRAPHTHREAD, NULL); pAMStream->AddMediaStream(pDD, &MSPID_PrimaryVideo, 0, NULL); pAMStream->AddMediaStream(NULL, &MSPID_PrimaryAudio, AMMSF_ADDDEFAULTRENDERER, NULL); pAMStream->OpenFile(wPath, 0); *ppMMStream = pAMStream; } int _CRTAPI1 main(int argc, char *argv[]) { if (argc < 2) { printf("Usage : showstrm movie.ext\n"); exit(0);} DDSURFACEDESC ddsd; IDirectDraw *pDD; IDirectDrawSurface *pPrimarySurface; IMultiMediaStream *pMMStream; CoInitialize(NULL); DirectDrawCreate(NULL, &pDD, NULL); pDD->SetCooperativeLevel(GetDesktopWindow(), DDSCL_NORMAL); ddsd.dwSize = sizeof(ddsd); ddsd.dwFlags = DDSD_CAPS; ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; pDD->CreateSurface(&ddsd, &pPrimarySurface, NULL); RenderFileToMMStream(argv[1], &pMMStream, pDD); RenderStreamToSurface(pPrimarySurface, pMMStream); pMMStream->Release(); pPrimarySurface->Release(); pDD->Release(); CoUninitialize(); return 0; }
次のサンプル コードは、IAudioMediaStream、IAudioStreamSample、IMemoryData、および IAudioData の 4 つのインターフェイスを使ってオーディオ データをストリームする方法を示す。
#include <windows.h> #include <mmsystem.h> #include <amstream.h> /******************************************************************** 簡単なウェーブ プレーヤー処理 ********************************************************************/ class CWaveBuffer; class CWaveBuffer { public: CWaveBuffer(); ~CWaveBuffer(); BOOL Init(HWAVEOUT hWave, int Size); void Done(); BOOL Write(PBYTE pData, int nBytes, int& BytesWritten); void Flush(); private: WAVEHDR m_Hdr; HWAVEOUT m_hWave; int m_nBytes; }; class CWaveOut { public: CWaveOut(LPCWAVEFORMATEX Format, int nBuffers, int BufferSize); ~CWaveOut(); void Write(PBYTE Data, int nBytes); void Flush(); void Wait(); void Reset(); private: const HANDLE m_hSem; const int m_nBuffers; int m_CurrentBuffer; BOOL m_NoBuffer; CWaveBuffer *m_Hdrs; HWAVEOUT m_hWave; }; /* CWaveBuffer */ CWaveBuffer::CWaveBuffer() { } BOOL CWaveBuffer::Init(HWAVEOUT hWave, int Size) { m_hWave = hWave; m_nBytes = 0; /* バッファを割り当て、ヘッダーを初期化する。 */ m_Hdr.lpData = (LPSTR)LocalAlloc(LMEM_FIXED, Size); if (m_Hdr.lpData == NULL) { return FALSE; } m_Hdr.dwBufferLength = Size; m_Hdr.dwBytesRecorded = 0; m_Hdr.dwUser = 0; m_Hdr.dwFlags = 0; m_Hdr.dwLoops = 0; m_Hdr.lpNext = 0; m_Hdr.reserved = 0; /* 準備をする。 */ waveOutPrepareHeader(hWave, &m_Hdr, sizeof(WAVEHDR)); return TRUE; } CWaveBuffer::~CWaveBuffer() { if (m_Hdr.lpData) { waveOutUnprepareHeader(m_hWave, &m_Hdr, sizeof(WAVEHDR)); LocalFree(m_Hdr.lpData); } } void CWaveBuffer::Flush() { // ASSERT(m_nBytes != 0); m_nBytes = 0; waveOutWrite(m_hWave, &m_Hdr, sizeof(WAVEHDR)); } BOOL CWaveBuffer::Write(PBYTE pData, int nBytes, int& BytesWritten) { // ASSERT((DWORD)m_nBytes != m_Hdr.dwBufferLength); BytesWritten = min((int)m_Hdr.dwBufferLength - m_nBytes, nBytes); CopyMemory((PVOID)(m_Hdr.lpData + m_nBytes), (PVOID)pData, BytesWritten); m_nBytes += BytesWritten; if (m_nBytes == (int)m_Hdr.dwBufferLength) { /* 書き込む。 */ m_nBytes = 0; waveOutWrite(m_hWave, &m_Hdr, sizeof(WAVEHDR)); return TRUE; } return FALSE; } void CALLBACK WaveCallback(HWAVEOUT hWave, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2) { if (uMsg == WOM_DONE) { ReleaseSemaphore((HANDLE)dwUser, 1, NULL); } } /* CWaveOut */ CWaveOut::CWaveOut(LPCWAVEFORMATEX Format, int nBuffers, int BufferSize) : m_nBuffers(nBuffers), m_CurrentBuffer(0), m_NoBuffer(TRUE), m_hSem(CreateSemaphore(NULL, nBuffers, nBuffers, NULL)), m_Hdrs(new CWaveBuffer[nBuffers]), m_hWave(NULL) { /* ウェーブ デバイスを作成する。 */ waveOutOpen(&m_hWave, WAVE_MAPPER, Format, (DWORD)WaveCallback, (DWORD)m_hSem, CALLBACK_FUNCTION); /* ウェーブ バッファを初期化する。 */ for (int i = 0; i < nBuffers; i++) { m_Hdrs[i].Init(m_hWave, BufferSize); } } CWaveOut::~CWaveOut() { /* まず、バッファをリセットする。 */ waveOutReset(m_hWave); /* バッファを解放する。 */ delete [] m_Hdrs; /* ウェーブ デバイスを閉じる。 */ waveOutClose(m_hWave); /* セマフォを解放する。 */ CloseHandle(m_hSem); } void CWaveOut::Flush() { if (!m_NoBuffer) { m_Hdrs[m_CurrentBuffer].Flush(); m_NoBuffer = TRUE; m_CurrentBuffer = (m_CurrentBuffer + 1) % m_nBuffers; } } void CWaveOut::Reset() { waveOutReset(m_hWave); } void CWaveOut::Write(PBYTE pData, int nBytes) { while (nBytes != 0) { /* 必要ならバッファを取得する。 */ if (m_NoBuffer) { WaitForSingleObject(m_hSem, INFINITE); m_NoBuffer = FALSE; } /* バッファに書き込む。 */ int nWritten; if (m_Hdrs[m_CurrentBuffer].Write(pData, nBytes, nWritten)) { m_NoBuffer = TRUE; m_CurrentBuffer = (m_CurrentBuffer + 1) % m_nBuffers; nBytes -= nWritten; pData += nWritten; } else { // ASSERT(nWritten == nBytes); break; } } } void CWaveOut::Wait() { /* 残っているバッファをすべて送る。 */ Flush(); /* バッファが戻るまで待つ。 */ for (int i = 0; i < m_nBuffers; i++) { WaitForSingleObject(m_hSem, INFINITE); } LONG lPrevCount; ReleaseSemaphore(m_hSem, m_nBuffers, &lPrevCount); } /************************************************************ ウェーブ プレーヤー処理はここまで ************************************************************/ HRESULT RenderStreamToDevice(IMultiMediaStream *pMMStream) { WAVEFORMATEX wfx; #define DATA_SIZE 5000 PBYTE pBuffer = (PBYTE)LocalAlloc(LMEM_FIXED, DATA_SIZE); IMediaStream *pStream; IAudioStreamSample *pSample; IAudioMediaStream *pAudioStream; IAudioData *pAudioData; pMMStream->GetMediaStream(MSPID_PrimaryAudio, &pStream); pStream->QueryInterface(IID_IAudioMediaStream, (void **)&pAudioStream); pAudioStream->GetFormat(&wfx); CoCreateInstance(CLSID_AMAudioData, NULL, CLSCTX_INPROC_SERVER, IID_IAudioData, (void **)&pAudioData); pAudioData->SetBuffer(DATA_SIZE, pBuffer, 0); pAudioData->SetFormat(&wfx); pAudioStream->CreateSample(pAudioData, 0, &pSample); HANDLE hEvent = CreateEvent(FALSE, NULL, NULL, FALSE); CWaveOut WaveOut(&wfx, 4, 2048); int iTimes; for (iTimes = 0; iTimes < 3; iTimes++) { DWORD dwStart = timeGetTime(); for (; ; ) { HRESULT hr = pSample->Update(0, hEvent, NULL, 0); if (FAILED(hr) || MS_S_ENDOFSTREAM == hr) { break; } WaitForSingleObject(hEvent, INFINITE); DWORD dwTimeDiff = timeGetTime() - dwStart; // 10 秒以内に限定する if (dwTimeDiff > 10000) { break; } DWORD dwLength; pAudioData->GetInfo(NULL, NULL, &dwLength); WaveOut.Write(pBuffer, dwLength); } pMMStream->Seek(0); } pAudioData->Release(); pSample->Release(); pStream->Release(); pAudioStream->Release(); LocalFree((HLOCAL)pBuffer); return S_OK; } HRESULT RenderFileToMMStream( WCHAR * pszFileName, IMultiMediaStream **ppMMStream) { IAMMultiMediaStream *pAMStream; CoCreateInstance(CLSID_AMMultiMediaStream, NULL, CLSCTX_INPROC_SERVER, IID_IAMMultiMediaStream, (void **)&pAMStream); pAMStream->Initialize(STREAMTYPE_READ, AMMSF_NOGRAPHTHREAD, NULL); pAMStream->AddMediaStream(NULL, &MSPID_PrimaryAudio, 0, NULL); pAMStream->OpenFile(pszFileName, AMMSF_RUN); *ppMMStream = pAMStream; return S_OK; } int _CRTAPI1 main(int argc, char *argv[]) { IMultiMediaStream *pMMStream; CoInitialize(NULL); WCHAR wszName[1000]; MultiByteToWideChar(CP_ACP, 0, argv[1], -1, wszName, sizeof(wszName) / sizeof(wszName[0])); RenderFileToMMStream(wszName, &pMMStream); RenderStreamToDevice(pMMStream); pMMStream->Release(); CoUninitialize(); return 0; }