科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航

至顶网软件频道基础软件VC实现卡拉OK字幕叠加

VC实现卡拉OK字幕叠加

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

本文介绍了卡拉OK字幕叠加的一般原理以及VC上使用GDI的一种简单实现。

作者:陆其明 来源:VCHelp 2007年10月21日

关键字:

  • 评论
  • 分享微博
  • 分享邮件
四. 性能优化

  我们在演示中发现,频繁地直接在窗口DC中画图会带来一定的闪烁感。对此,我们可以进行一下优化,即首先创建一个与目标窗口DC兼容的内存DC,在这个内存DC中画好字幕后,再将字幕位图从内存DC拷贝到目标窗口DC中去。

  我们可以参考CSubtitleController类的DrawSubtitle2函数的实现:

BOOL CSubtitleController::DrawSubtitle2(DWORD inStreamTime)
{
ASSERT(mClientDC);

RECT bounds;
mTargetWnd->GetClientRect(&bounds);
int wndWidth = bounds.right - bounds.left;
int wndHeight = bounds.bottom - bounds.top;

CDC memDC;
// 创建与目标窗口DC兼容的内存DC
memDC.CreateCompatibleDC(mClientDC);
// 创建与目标窗口DC兼容的位图
HBITMAP membmp = CreateCompatibleBitmap(mClientDC->GetSafeHdc(),wndWidth,wndHeight);
// 将位图选入内存DC
HBITMAP oldbmp = (HBITMAP) memDC.SelectObject(membmp);
FillRect(memDC.GetSafeHdc(), &bounds, (HBRUSH)GetStockObject(LTGRAY_BRUSH));

/*----------------- 以下字幕操作都在内存DC中进行 ----------------*/
DWORD timeInChar = 0;
LONG sungLength = 0;
int currentChar = LocateChar(inStreamTime, timeInChar);
if (currentChar != -1)
{
sungLength = mFromToArray[currentChar].size.cx * timeInChar;
sungLength = sungLength / mFromToArray[currentChar].duration;
for (int i = 0; i < currentChar; i++)
{
sungLength += mFromToArray[i].size.cx;
}
}
else
{
sungLength = mTotalWidth;
}

CFont * pOldFont = (CFont *) memDC.SelectObject(&mTextFont);
memDC.SetBkMode(TRANSPARENT);

mSungRegion.CreateRectRgn(mStartPoint.x, mStartPoint.y,
mStartPoint.x + sungLength, mStartPoint.y + mFromToArray[0].size.cy);
mSingingRegion.CreateRectRgn(mStartPoint.x + sungLength, mStartPoint.y,
mStartPoint.x + mTotalWidth, mStartPoint.y + mFromToArray[0].size.cy);

// Draw the first part which has been sung
int ret = memDC.SelectClipRgn(&mSungRegion, RGN_COPY);
memDC.SetPolyFillMode(WINDING);
HPEN pOldPen = (HPEN) memDC.SelectObject(mSungBoundaryPen);
HBRUSH pOldBrush = (HBRUSH) memDC.SelectObject(mSungTextBrush);
memDC.BeginPath();
memDC.TextOut(mStartPoint.x, mStartPoint.y, mSubtitleLine);
memDC.EndPath();
memDC.StrokeAndFillPath();
memDC.SelectClipPath(RGN_AND);
memDC.SelectObject(pOldPen);
memDC.SelectObject(pOldBrush);

// Draw the second part which is waiting for being sung
pOldPen = (HPEN) memDC.SelectObject(mSingingBoundaryPen);
pOldBrush = (HBRUSH) memDC.SelectObject(mSingingTextBrush);
memDC.SelectClipRgn(&mSingingRegion, RGN_COPY);
memDC.BeginPath();
memDC.TextOut(mStartPoint.x, mStartPoint.y, mSubtitleLine);
memDC.EndPath();
memDC.StrokePath();
memDC.SelectClipPath(RGN_AND);
memDC.SelectObject(pOldBrush);
memDC.SelectObject(pOldPen);
mSungRegion.DeleteObject();
mSingingRegion.DeleteObject();

memDC.SelectObject(pOldFont);
// 将内存DC中的位图拷贝到目标窗口DC中
mClientDC->BitBlt(0, 0, wndWidth, wndHeight, &memDC, 0, 0, SRCCOPY);
// 删除内存DC及使用的资源
memDC.SelectObject(oldbmp);
DeleteObject(membmp);
memDC.DeleteDC();

return (currentChar != -1);
}

  五. 结束语

  本文介绍了卡拉OK字幕叠加的一般原理以及VC上使用GDI的一种简单实现,并且提供了完整的示例源代码,希望能够对读者朋友们有所启示。

  下载本文源代码  

查看本文来源

    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

    如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

    重磅专题
    往期文章
    最新文章