開發遊戲時常需播放片頭動畫。媒體播放控件雖簡單但功能受限;VFW 等多媒體庫又過於複雜。微軟提供的 DirectX Media SDK(含 DirectShow)結合 DirectX 高效能,支援多種格式(甚至 MPEG-2),是最佳選擇。
#include <ddraw.h>
#include <mmstream.h>
#include <amstream.h>
#include <ddstream.h>
核心介面:IMultiMediaStream(最高層多媒體串流物件,可包含音訊、視訊等多種串流)。
DDSURFACEDESC ddsd;
IDirectDraw *pDD;
IDirectDrawSurface *pPrimarySurface;
IMultiMediaStream *pMMStream;
HRESULT Init() {
pDD = NULL; pPrimarySurface = NULL; pMMStream = NULL;
ZeroMemory(&ddsd, sizeof(ddsd));
CoInitialize(NULL); // COM 初始化
return InitDDraw();
}
void Uninit() {
if (pMMStream) pMMStream->Release();
if (pPrimarySurface) pPrimarySurface->Release();
if (pDD) pDD->Release();
CoUninitialize();
}
HRESULT InitDDraw() {
HRESULT r;
if (FAILED(r = DirectDrawCreate(NULL, &pDD, NULL))) return r;
if (FAILED(r = pDD->SetCooperativeLevel(hWnd, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN))) return r;
if (FAILED(r = pDD->SetDisplayMode(640, 480, 16))) return r; // 解析度設定
ddsd.dwSize = sizeof(ddsd);
ddsd.dwFlags = DDSD_CAPS;
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
if (FAILED(pDD->CreateSurface(&ddsd, &pPrimarySurface, NULL))) return r;
return S_OK;
}
HRESULT LoadFromFile(const char *szFileName, IMultiMediaStream **ppMMStream, IDirectDraw *pDD) {
HRESULT r;
IAMMultiMediaStream *pAMStream;
if (FAILED(r = CoCreateInstance(CLSID_AMMultiMediaStream, NULL, CLSCTX_INPROC_SERVER,
IID_IAMMultiMediaStream, (void **)&pAMStream))) return r;
WCHAR wPath[MAX_PATH];
MultiByteToWideChar(CP_ACP, 0, szFileName, -1, wPath, MAX_PATH);
if (FAILED(r = pAMStream->Initialize(STREAMTYPE_READ, AMMSF_NOGRAPHTHREAD, NULL))) return r;
if (FAILED(r = pAMStream->AddMediaStream(pDD, &MSPID_PrimaryVideo, 0, NULL))) return r;
if (FAILED(r = pAMStream->AddMediaStream(NULL, &MSPID_PrimaryAudio, AMMSF_ADDDEFAULTRENDERER, NULL))) return r;
if (FAILED(r = pAMStream->OpenFile(wPath, 0))) return r;
*ppMMStream = pAMStream;
return S_OK;
}
關鍵點:IAMMultiMediaStream 功能強大,此處用於建立視訊/音訊串流並從檔案開啟。
HRESULT Play(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 = 100; rect.left = 150;
rect.bottom = ddsd.dwHeight + 100;
rect.right = ddsd.dwWidth + 150;
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();
}
播放核心:取得視訊串流 → 查詢 DirectDraw 串流介面 → 取得格式建立樣本 → 關聯表面 → 設定狀態為 RUN → 迴圈更新樣本 → 停止釋放。
完整範例碼可至 作者網站 下載。歡迎指正交流!