?? coverlaycontroller.cpp
字號:
//
// COverlayController.cpp
//
#include "streams.h"
#include "COverlayController.h"
#include "CPixelRGB32.h"
#include "CPixelRGB24.h"
#include "CPixelRGB565.h"
#include "CPixelRGB555.h"
#include "CPixelRGB8.h"
#include "CAutoFont.h"
//////////////////////////////////////////////////////////////////////////////
COverlayController::COverlayController()
{
mPixelConverter = 0;
mCanDoOverlay = FALSE;
mIsOverlayByCover = TRUE;
mOverlayCounter = 0;
mDoubleStartTime = 0;
mDoubleEndTime = -1;
mOverlayStartTime = 0;
mOverlayEndTime = -1; // Means to the end
mTitle = new char[1];
*mTitle = '\0';
mTitleDIBBits = 0;
mColorRed = 0;
mColorGreen = 128;
mColorBlue = 0;
memset(&mTitleSize, 0, sizeof(SIZE));
memset(&mStartPos, 0, sizeof(POINT));
memset(&mTitleFont, 0, sizeof(LOGFONT));
mIsFontChanged = FALSE;
mInputColorSpace = FT_NONE;
mImageWidth = 0;
mImageHeight = 0;
mImageWidthInBytes = 0;
mImageBitCount = 0;
mIsBottomUpImage = TRUE;
mDIBWidthInBytes = 0;
mInputFrameRate = 25;
}
COverlayController::~COverlayController()
{
ReleasePixelConverter();
ReleaseTitleBuffer();
ReleaseTitleDIB();
}
void COverlayController::ReleasePixelConverter(void)
{
if (mPixelConverter)
{
delete mPixelConverter;
mPixelConverter = 0;
}
}
void COverlayController::ReleaseTitleBuffer(void)
{
if (mTitle)
{
delete[] mTitle;
mTitle = 0;
}
}
void COverlayController::ReleaseTitleDIB(void)
{
if (mTitleDIBBits)
{
delete[] mTitleDIBBits;
mTitleDIBBits = 0;
}
}
// In order to create the pixel convertor used by overlay working properly,
// this method must be invoke
void COverlayController::SetInputColorSpace(RGB_FORMAT inColorSpace)
{
if (mInputColorSpace != inColorSpace)
{
ReleasePixelConverter();
mInputColorSpace = inColorSpace;
SideEffectColorSpaceChanged();
}
}
BOOL COverlayController::CreateTitleDIBBits(void)
{
HDC hdc = CreateCompatibleDC(NULL);
if (hdc)
{
HBITMAP hbm = ActualCreateTitleDIB(hdc);
DeleteDC(hdc);
if (hbm)
{
DeleteObject(hbm);
return TRUE;
}
}
return FALSE;
}
HBITMAP COverlayController::ActualCreateTitleDIB(HDC inDC)
{
// DIB info we used to create title pixel-mapping.
// The system default color policy is:
// Initial Whole Black, while output area White-background and Black-text.
struct {
BITMAPINFOHEADER bmiHeader;
DWORD rgbEntries[2];
} bmi =
{
{
sizeof(BITMAPINFOHEADER),
0,
0,
1,
1,
BI_RGB,
0,
0,
0
},
{
0x00000000,
0xFFFFFFFF
}
};
// We change the system default color policy.
// That is, we use Black-background and White-text.
// We do so especially for rotation font using.
// SetBkColor(hdc, RGB(0, 0, 0));
// SetTextColor(hdc, RGB(255, 255, 255));
// Set tile font here, so we can get the exact size of the title
CAutoFont autoFont;
if (mIsFontChanged)
{
// autoFont.CreateFont("Arial"); // Testing
autoFont.CreateFont(mTitleFont);
autoFont.SelectToDC(inDC);
}
GetTextExtentPoint32(inDC, mTitle, lstrlen(mTitle), &mTitleSize);
// Overridable to change title DIB size
if (!ValidateTitleDIBSize())
{
return NULL;
}
// Set proper DIB size here! Important!
bmi.bmiHeader.biHeight = mTitleSize.cy;
bmi.bmiHeader.biWidth = mTitleSize.cx;
HBITMAP hbm = CreateDIBitmap(inDC, &bmi.bmiHeader, 0, NULL, NULL, 0);
BOOL pass = (hbm != NULL);
// Draw title after selecting DIB into the DC
if (pass)
{
HGDIOBJ hobj = SelectObject(inDC, hbm);
pass = ExtTextOut(inDC, 0, 0, ETO_OPAQUE | ETO_CLIPPED, NULL,
mTitle, lstrlen(mTitle), NULL);
SelectObject(inDC, hobj);
}
// Get the title-drew DIB bits
if (pass)
{
ReleaseTitleDIB();
// Attention: To get bitmap data from the DIB object,
// the scan line must be a multiple of 4 (DWORD)!
// If the actual bitmap data is not exactly fit for DWORD,
// The rest of DWORD bits will be filled automatically.
// So we should expand to bytes and round up to a multiple of 4.
mDIBWidthInBytes = ((mTitleSize.cx + 31) >> 3) & ~3;
mTitleDIBBits = new BYTE[mDIBWidthInBytes * mTitleSize.cy];
memset(mTitleDIBBits, 0, mDIBWidthInBytes * mTitleSize.cy);
LONG lLines = GetDIBits(inDC, hbm, 0, mTitleSize.cy, (PVOID)mTitleDIBBits,
(BITMAPINFO *)&bmi, DIB_RGB_COLORS);
pass = (lLines != 0);
}
if (!pass && hbm)
{
DeleteObject(hbm);
hbm = NULL;
}
return hbm;
}
BOOL COverlayController::ValidateTitleDIBSize(void)
{
return TRUE;
}
void COverlayController::SideEffectColorSpaceChanged(void)
{
switch (mInputColorSpace)
{
case FT_RGB8:
mPixelConverter = new CPixelRGB8();
mPixelConverter->SetPixelSize(1);
break;
case FT_RGB555:
mPixelConverter = new CPixelRGB555();
mPixelConverter->SetPixelSize(2);
break;
case FT_RGB565:
mPixelConverter = new CPixelRGB565();
mPixelConverter->SetPixelSize(2);
break;
case FT_RGB24:
mPixelConverter = new CPixelRGB24();
mPixelConverter->SetPixelSize(3);
break;
case FT_RGB32:
mPixelConverter = new CPixelRGB32();
mPixelConverter->SetPixelSize(4);
break;
}
// Set the title color to the pixel converter
if (mPixelConverter)
{
mPixelConverter->SetTargetColor(mColorRed, mColorGreen, mColorBlue);
}
}
// Commonly we don't support rotation font
// Subclass can override this to support it
void COverlayController::SideEffectFontChanged(void)
{
mTitleFont.lfEscapement = 0;
mTitleFont.lfOrientation = 0;
}
void COverlayController::SetInputVideoInfo(const VIDEOINFOHEADER * inInfoHeader)
{
ASSERT(inInfoHeader);
mImageWidth = inInfoHeader->bmiHeader.biWidth;
mImageHeight = (DWORD)(abs(inInfoHeader->bmiHeader.biHeight));
mImageBitCount = inInfoHeader->bmiHeader.biBitCount;
if (inInfoHeader->AvgTimePerFrame > 0)
{
mInputFrameRate = 1.0 * UNITS / inInfoHeader->AvgTimePerFrame;
SideEffectProgressChanged();
}
// biWidth is the stride in pixels for 'normal formats'
// Expand to bytes and round up to a multiple of 4
if (mImageBitCount != 0 && 0 == (7 & mImageBitCount))
{
mImageWidthInBytes = (mImageWidth * (mImageBitCount / 8) + 3) & ~3;
}
else
{
mImageWidthInBytes = mImageWidth;
}
mIsBottomUpImage = mImageHeight > 0 ? TRUE : FALSE;
}
void COverlayController::SetEstimatedFrameRate(double inFrameRate)
{
mInputFrameRate = inFrameRate;
SideEffectProgressChanged();
}
void COverlayController::SetOverlayStyle(BOOL inUsingCover)
{
mIsOverlayByCover = inUsingCover;
}
void COverlayController::GetOverlayStyle(BOOL * outUsingCover)
{
*outUsingCover = mIsOverlayByCover;
}
void COverlayController::SetTitle(const char * inTitle, int inLength)
{
ReleaseTitleBuffer();
mTitle = new char[inLength + 1];
if (inTitle && mTitle)
{
strcpy(mTitle, inTitle);
}
}
void COverlayController::SetTitleColor(BYTE inR, BYTE inG, BYTE inB)
{
mColorRed = inR;
mColorGreen = inG;
mColorBlue = inB;
// Set the title color to the pixel converter
if (mPixelConverter)
{
mPixelConverter->SetTargetColor(mColorRed, mColorGreen, mColorBlue);
}
}
void COverlayController::SetTitleStartPosition(POINT inStartPos)
{
mStartPos.x = inStartPos.x;
mStartPos.y = inStartPos.y;
}
void COverlayController::SetTitleFont(LOGFONT inFont)
{
mTitleFont = inFont;
mIsFontChanged = TRUE;
// Do title font validation
SideEffectFontChanged();
}
void COverlayController::SetTitleDuration(double inStart, double inEnd)
{
mDoubleStartTime = inStart;
mDoubleEndTime = inEnd;
SideEffectProgressChanged();
}
void COverlayController::SideEffectProgressChanged(void)
{
mOverlayStartTime = long(mInputFrameRate * mDoubleStartTime);
mOverlayEndTime = -1;
if (mDoubleEndTime > 0)
{
mOverlayEndTime = long(mInputFrameRate * mDoubleEndTime);
}
}
// Commonly, invoker should get the title length first by passing NULL to outBuffer
int COverlayController::GetTitle(char * outBuffer)
{
int titleLength = 0;
if (mTitle)
{
titleLength = strlen(mTitle) + 1;
if (outBuffer)
{
strcpy(outBuffer, mTitle);
}
}
return titleLength;
}
void COverlayController::GetTitleColor(BYTE * outR, BYTE * outG, BYTE * outB)
{
*outR = mColorRed;
*outG = mColorGreen;
*outB = mColorBlue;
}
void COverlayController::GetTitleStartPosition(POINT * outStartPos)
{
outStartPos->x = mStartPos.x;
outStartPos->y = mStartPos.y;
}
void COverlayController::GetTitleFont(LOGFONT * outFont)
{
*outFont = mTitleFont;
}
void COverlayController::GetTitleDuration(double * outStart, double * outEnd)
{
*outStart = mDoubleStartTime;
*outEnd = mDoubleEndTime;
}
// This method must be invoked before all actual title overlay work.
// We can create title DIB map here!
BOOL COverlayController::StartTitleOverlay(void)
{
mCanDoOverlay = (mPixelConverter != 0);
if (mCanDoOverlay)
{
mCanDoOverlay = CreateTitleDIBBits();
}
return mCanDoOverlay;
}
BOOL COverlayController::StopTitleOverlay(void)
{
mCanDoOverlay = FALSE;
mOverlayCounter = 0;
return TRUE;
}
BOOL COverlayController::DoTitleOverlay(PBYTE inImage)
{
if (!mCanDoOverlay)
{
return FALSE;
}
BOOL pass = BeforeActualOverlay();
if (pass)
{
pass = ActualOverlay(inImage);
}
if (pass)
{
pass = AfterActualOverlay();
}
return pass;
}
// Do title duration checking here!
// Subclass can override this method to ignore tile duration feature
BOOL COverlayController::BeforeActualOverlay(void)
{
// Only keep the title duration here
if (mOverlayCounter >= mOverlayStartTime)
{
if (mOverlayEndTime == -1 || mOverlayCounter <= mOverlayEndTime)
{
return TRUE;
}
}
// If not reach the start time, count any way!
mOverlayCounter++;
return FALSE;
}
BOOL COverlayController::AfterActualOverlay(void)
{
mOverlayCounter++;
return TRUE;
}
BOOL COverlayController::ActualOverlay(PBYTE inImage)
{
// Now copy the data from the DIB section (which is usually bottom-up)
// but first check if it's too big
if (mImageWidth > mStartPos.x && mImageHeight > mStartPos.y &&
mTitleSize.cx > 0 && mTitleSize.cy > 0)
{
long actualOverlayWidth = min((mImageWidth - mStartPos.x), mTitleSize.cx);
long actualOverlayHeight = min((mImageHeight - mStartPos.y), mTitleSize.cy);
// Image may be bottom-up, may be top-down.
// Anyway retrieve the pointer which point to the top line
PBYTE pTopLine = NULL;
long strideInBytes = 0;
if (mIsBottomUpImage)
{
strideInBytes = -mImageWidthInBytes;
pTopLine = inImage + mImageWidthInBytes * (mImageHeight - 1);
}
else
{
strideInBytes = mImageWidthInBytes;
pTopLine = inImage;
}
PBYTE pStartPos = pTopLine + mStartPos.y * strideInBytes + mStartPos.x * mImageBitCount / 8;
for (DWORD dwY = 0; dwY < (DWORD)actualOverlayHeight; dwY++)
{
PBYTE pbTitle = mTitleDIBBits + mDIBWidthInBytes * ((DWORD)mTitleSize.cy - dwY - 1);
for (DWORD dwX = 0; dwX < (DWORD)actualOverlayWidth; dwX++)
{
// dwX & 7, value from 0 - 7
// 0x80 >> (dwX & 7), value from 10000000 to 00000001
// dwX >> 3, value add one every eight
// If the source bit is 0, the background. If 1, draw the text.
if ( !((0x80 >> (dwX & 7)) & pbTitle[dwX >> 3]) )
{
PBYTE pbPixel = mPixelConverter->NextNPixel(pStartPos, dwX);
if (mIsOverlayByCover)
{
mPixelConverter->ConvertByCover(pbPixel);
}
else
{
mPixelConverter->ConvertByReverse(pbPixel);
}
}
}
pStartPos += strideInBytes;
}
return TRUE;
}
return FALSE;
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -