在 Windows 平台上開發多媒體應用時,字幕疊加是常見需求。本文將深入探討如何使用 Visual C++ 結合 GDI(Graphics Device Interface)實現具有卡拉OK 效果的動態字幕疊加,包含逐字填充、節奏同步、勾邊顯示等核心功能,並提供完整的類設計與優化方案。
GDI 是 Windows 圖形繪製的核心 API 集合,提供豐富的繪圖功能。主要函數分類包括:
GetDC、CreateDC、DeleteDCLineTo、Polyline)、填充(Ellipse、FillRect)SetBkColor)、透明模式(SetBkMode)、文字色(SetTextColor)TextOut、GetTextExtentPoint32BitBlt、StretchBlt、SetPixelBeginPath/EndPath、StrokeAndFillPath、SelectClipRgn、SelectClipPathMFC 將這些 API 封裝為 CDC、CFont、CPen、CBrush、CBitmap、CRgn 等類,簡化了物件導向開發。繪圖流程通常為:取得 DC → 設定映射模式 → 執行繪圖 → 釋放 DC。
利用 GDI 路徑功能可輕鬆實現字符輪廓提取與填充:
CClientDC* pDC = new CClientDC(mTargetWnd);
pDC->BeginPath();
pDC->TextOut(x, y, szSubtitleLine);
pDC->EndPath();
pDC->StrokeAndFillPath(); // 同時勾邊與填充
勾邊顏色由當前畫筆(CPen)決定,填充顏色由當前畫刷(CBrush)決定。
根據歌詞時間軸,為每個字分配開始填充時間點與持續時間。例如「真的好想你」五字,分別分配 1500ms、300ms、1600ms、500ms、1000ms。播放時以固定頻率(如 25fps,40ms 間隔)計算當前「流時間」,換算出已演唱字符寬度 sungLength,作為左右區域分界線。
將字幕行分為「已唱」(藍底白邊實心)與「未唱」(黑邊空心)兩區域:
CRgn sungRgn, singingRgn;
sungRgn.CreateRectRgn(xStart, yStart, xStart + sungLength, yStart + height);
singingRgn.CreateRectRgn(xStart + sungLength, yStart, xStart + totalWidth, yStart + height);
繪製流程:
StrokeAndFillPath → SelectClipPath(RGN_AND) 取交集StrokePath → SelectClipPath(RGN_AND)此法可精確處理分界線落在單字內部的情況。
mSubtitleArray:逐字存儲的 CString 陣列mDurationArray:對應字符填充耗時(毫秒)mFromToArray:記錄每字起始/結束時間、寬高等屬性mClientDC:目標視窗 DC 指標mSungRegion/mSingingRegion:雙裁剪區域DrawSubtitle(DWORD streamTime)LocateChar 依流時間定位當前字符索引 currentChar 及字內相對時間 timeInCharsungLength:前幾字總寬 + 當前字按比例填充寬度SelectClipRgn + SelectClipPath(RGN_AND) 組合裁剪LocateChar遍歷 mFromToArray,找出 from ≤ streamTime < to 的字符,回傳索引與字內偏移時間。
直接在視窗 DC 繪圖會造成明顯閃爍。解決方案:建立相容記憶體 DC(CDC memDC),配合相容位圖(CreateCompatibleBitmap),在記憶體 DC 完成所有繪圖後,一次 BitBlt 複製到視窗 DC。
CDC memDC;
memDC.CreateCompatibleDC(mClientDC);
HBITMAP membmp = CreateCompatibleBitmap(mClientDC->GetSafeHdc(), w, h);
HBITMAP oldbmp = (HBITMAP)memDC.SelectObject(membmp);
// ... 在 memDC 上執行完整 DrawSubtitle 邏輯 ...
mClientDC->BitBlt(0, 0, w, h, &memDC, 0, 0, SRCCOPY);
// 清理資源
memDC.SelectObject(oldbmp);
DeleteObject(membmp);
memDC.DeleteDC();
此法顯著提升幀率穩定性,適合即時卡拉OK 播放場景。
本文示範了基於 GDI 路徑、區域裁剪、雙緩衝的卡拉OK 字幕疊加完整實現。實際專案可進一步擴展:
完整原始碼可作為多媒體應用開發的參考基礎。