?? winutil.cpp
字號:
}
ASSERT(!m_bRealizing);
// Should we realise our palette again
if ((Message == WM_QUERYNEWPALETTE || hwnd != m_hwnd)) {
// It seems that even if we're invisible that we can get asked
// to realize our palette and this can cause really ugly side-effects
// Seems like there's another bug but this masks it a least for the
// shutting down case.
if (!IsWindowVisible(m_hwnd)) {
DbgLog((LOG_TRACE, 1, TEXT("Realizing when invisible!")));
return (LRESULT) 0;
}
// Avoid recursion with multiple graphs in the same app
#ifdef DEBUG
m_bRealizing = TRUE;
#endif
DoRealisePalette(Message != WM_QUERYNEWPALETTE);
#ifdef DEBUG
m_bRealizing = FALSE;
#endif
// Should we redraw the window with the new palette
if (Message == WM_PALETTECHANGED) {
InvalidateRect(m_hwnd,NULL,FALSE);
}
}
return (LRESULT) 1;
}
// Determine if the window exists.
bool CBaseWindow::WindowExists()
{
return !!IsWindow(m_hwnd);
}
// Return the default window rectangle
RECT CBaseWindow::GetDefaultRect()
{
RECT DefaultRect = {0,0,DEFWIDTH,DEFHEIGHT};
ASSERT(m_hwnd);
// ASSERT(m_hdc);
return DefaultRect;
}
// Return the current window width
LONG CBaseWindow::GetWindowWidth()
{
ASSERT(m_hwnd);
// ASSERT(m_hdc);
return m_Width;
}
// Return the current window height
LONG CBaseWindow::GetWindowHeight()
{
ASSERT(m_hwnd);
// ASSERT(m_hdc);
return m_Height;
}
// Return the window handle
HWND CBaseWindow::GetWindowHWND()
{
ASSERT(m_hwnd);
// ASSERT(m_hdc);
return m_hwnd;
}
// Return the window drawing device context
HDC CBaseWindow::GetWindowHDC()
{
ASSERT(m_hwnd);
ASSERT(m_hdc);
return m_hdc;
}
// Return the offscreen window drawing device context
HDC CBaseWindow::GetMemoryHDC()
{
ASSERT(m_hwnd);
ASSERT(m_MemoryDC);
return m_MemoryDC;
}
#ifdef DEBUG
HPALETTE CBaseWindow::GetPalette()
{
// The palette lock should always be held when accessing
// m_hPalette.
ASSERT(CritCheckIn(&m_PaletteLock));
return m_hPalette;
}
#endif // DEBUG
// This is available to clients who want to change the window visiblity. It's
// little more than an indirection to the Win32 ShowWindow although these is
// some benefit in going through here as this function may change sometime
HRESULT CBaseWindow::DoShowWindow(LONG ShowCmd)
{
ShowWindow(m_hwnd,ShowCmd);
return NOERROR;
}
// Generate a WM_PAINT message for the video window
void CBaseWindow::PaintWindow(BOOL bErase)
{
InvalidateRect(m_hwnd,NULL,bErase);
}
// Allow an application to have us set the video window in the foreground. We
// have this because it is difficult for one thread to do do this to a window
// owned by another thread. Rather than expose the message we use to execute
// the inter thread send message we provide the interface function. All we do
// is to SendMessage to the video window renderer thread with a WM_SHOWSTAGE
void CBaseWindow::DoSetWindowForeground(BOOL bFocus)
{
SendMessage(m_hwnd,m_ShowStageMessage,(WPARAM) bFocus,(LPARAM) 0);
}
// Constructor initialises the owning object pointer. Since we are a worker
// class for the main window object we have relatively few state variables to
// look after. We are given device context handles to use later on as well as
// the source and destination rectangles (but reset them here just in case)
CDrawImage::CDrawImage(CBaseWindow *pBaseWindow) :
m_pBaseWindow(pBaseWindow),
m_hdc(NULL),
m_MemoryDC(NULL),
m_bStretch(FALSE),
m_pMediaType(NULL),
m_bUsingImageAllocator(FALSE)
{
ASSERT(pBaseWindow);
ResetPaletteVersion();
SetRectEmpty(&m_TargetRect);
SetRectEmpty(&m_SourceRect);
m_perfidRenderTime = MSR_REGISTER(TEXT("Single Blt time"));
}
// Overlay the image time stamps on the picture. Access to this method is
// serialised by the caller. We display the sample start and end times on
// top of the video using TextOut on the device context we are handed. If
// there isn't enough room in the window for the times we don't show them
void CDrawImage::DisplaySampleTimes(IMediaSample *pSample)
{
#ifdef DEBUG
//
// Only allow the "annoying" time messages if the users has turned the
// logging "way up"
//
BOOL bAccept = DbgCheckModuleLevel(LOG_TRACE, 5);
if (bAccept == FALSE) {
return;
}
#endif
TCHAR szTimes[TIMELENGTH]; // Time stamp strings
ASSERT(pSample); // Quick sanity check
RECT ClientRect; // Client window size
SIZE Size; // Size of text output
// Get the time stamps and window size
pSample->GetTime((REFERENCE_TIME*)&m_StartSample, (REFERENCE_TIME*)&m_EndSample);
HWND hwnd = m_pBaseWindow->GetWindowHWND();
EXECUTE_ASSERT(GetClientRect(hwnd,&ClientRect));
// Format the sample time stamps
wsprintf(szTimes,TEXT("%08d : %08d"),
m_StartSample.Millisecs(),
m_EndSample.Millisecs());
ASSERT(lstrlen(szTimes) < TIMELENGTH);
// Put the times in the middle at the bottom of the window
GetTextExtentPoint32(m_hdc,szTimes,lstrlen(szTimes),&Size);
INT XPos = ((ClientRect.right - ClientRect.left) - Size.cx) / 2;
INT YPos = ((ClientRect.bottom - ClientRect.top) - Size.cy) * 4 / 5;
// Check the window is big enough to have sample times displayed
if ((XPos > 0) && (YPos > 0)) {
TextOut(m_hdc,XPos,YPos,szTimes,lstrlen(szTimes));
}
}
// This is called when the drawing code sees that the image has a down level
// palette cookie. We simply call the SetDIBColorTable Windows API with the
// palette that is found after the BITMAPINFOHEADER - we return no errors
void CDrawImage::UpdateColourTable(HDC hdc,BITMAPINFOHEADER *pbmi)
{
ASSERT(pbmi->biClrUsed);
RGBQUAD *pColourTable = (RGBQUAD *)(pbmi+1);
// Set the new palette in the device context
UINT uiReturn = SetDIBColorTable(hdc,(UINT) 0,
pbmi->biClrUsed,
pColourTable);
// Should always succeed but check in debug builds
ASSERT(uiReturn == pbmi->biClrUsed);
}
// No source rectangle scaling is done by the base class
RECT CDrawImage::ScaleSourceRect(const RECT *pSource)
{
ASSERT(pSource);
return *pSource;
}
// This is called when the funky output pin uses our allocator. The samples we
// allocate are special because the memory is shared between us and GDI thus
// removing one copy when we ask for the image to be rendered. The source type
// information is in the main renderer m_mtIn field which is initialised when
// the media type is agreed in SetMediaType, the media type may be changed on
// the fly if, for example, the source filter needs to change the palette
void CDrawImage::FastRender(IMediaSample *pMediaSample)
{
BITMAPINFOHEADER *pbmi; // Image format data
DIBDATA *pDibData; // Stores DIB information
BYTE *pImage; // Pointer to image data
HBITMAP hOldBitmap; // Store the old bitmap
CImageSample *pSample; // Pointer to C++ object
ASSERT(m_pMediaType);
// From the untyped source format block get the VIDEOINFO and subsequently
// the BITMAPINFOHEADER structure. We can cast the IMediaSample interface
// to a CImageSample object so we can retrieve it's DIBSECTION details
pbmi = HEADER(m_pMediaType->Format());
pSample = (CImageSample *) pMediaSample;
pDibData = pSample->GetDIBData();
hOldBitmap = (HBITMAP) SelectObject(m_MemoryDC,pDibData->hBitmap);
// Get a pointer to the real image data
HRESULT hr = pMediaSample->GetPointer(&pImage);
if (FAILED(hr)) {
return;
}
// Do we need to update the colour table, we increment our palette cookie
// each time we get a dynamic format change. The sample palette cookie is
// stored in the DIBDATA structure so we try to keep the fields in sync
// By the time we get to draw the images the format change will be done
// so all we do is ask the renderer for what it's palette version is
if (pDibData->PaletteVersion < GetPaletteVersion()) {
ASSERT(pbmi->biBitCount <= iPALETTE);
UpdateColourTable(m_MemoryDC,pbmi);
pDibData->PaletteVersion = GetPaletteVersion();
}
// This allows derived classes to change the source rectangle that we do
// the drawing with. For example a renderer may ask a codec to stretch
// the video from 320x240 to 640x480, in which case the source we see in
// here will still be 320x240, although the source we want to draw with
// should be scaled up to 640x480. The base class implementation of this
// method does nothing but return the same rectangle as we are passed in
RECT SourceRect = ScaleSourceRect(&m_SourceRect);
// Is the window the same size as the video
if (m_bStretch == FALSE) {
// Put the image straight into the window
BitBlt(
(HDC) m_hdc, // Target device HDC
m_TargetRect.left, // X sink position
m_TargetRect.top, // Y sink position
m_TargetRect.right - m_TargetRect.left, // Destination width
m_TargetRect.bottom - m_TargetRect.top, // Destination height
m_MemoryDC, // Source device context
SourceRect.left, // X source position
SourceRect.top, // Y source position
SRCCOPY); // Simple copy
} else {
// Stretch the image when copying to the window
StretchBlt(
(HDC) m_hdc, // Target device HDC
m_TargetRect.left, // X sink position
m_TargetRect.top, // Y sink position
m_TargetRect.right - m_TargetRect.left, // Destination width
m_TargetRect.bottom - m_TargetRect.top, // Destination height
m_MemoryDC, // Source device HDC
SourceRect.left, // X source position
SourceRect.top, // Y source position
SourceRect.right - SourceRect.left, // Source width
SourceRect.bottom - SourceRect.top, // Source height
SRCCOPY); // Simple copy
}
// This displays the sample times over the top of the image. This used to
// draw the times into the offscreen device context however that actually
// writes the text into the image data buffer which may not be writable
#ifdef DEBUG
DisplaySampleTimes(pMediaSample);
#endif
// Put the old bitmap back into the device context so we don't leak
SelectObject(m_MemoryDC,hOldBitmap);
}
// This is called when there is a sample ready to be drawn, unfortunately the
// output pin was being rotten and didn't choose our super excellent shared
// memory DIB allocator so we have to do this slow render using boring old GDI
// SetDIBitsToDevice and StretchDIBits. The down side of using these GDI
// functions is that the image data has to be copied across from our address
// space into theirs before going to the screen (although in reality the cost
// is small because all they do is to map the buffer into their address space)
void CDrawImage::SlowRender(IMediaSample *pMediaSample)
{
// Get the BITMAPINFOHEADER for the connection
ASSERT(m_pMediaType);
BITMAPINFOHEADER *pbmi = HEADER(m_pMediaType->Format());
BYTE *pImage;
// Get the image data buffer
HRESULT hr = pMediaSample->GetPointer(&pImage);
if (FAILED(hr)) {
return;
}
// This allows derived classes to change the source rectangle that we do
// the drawing with. For example a renderer may ask a codec to stretch
// the video from 320x240 to 640x480, in which case the source we see in
// here will still be 320x240, although the source we want to draw with
// should be scaled up to 640x480. The base class implementation of this
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -