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; }