www.pudn.com > aa.rar > COverlayController.cpp


// 
// COverlayController.cpp 
// 
 
#include  
#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; 
}