?? winutil.cpp
字號:
// method does nothing but return the same rectangle as we are passed in
RECT SourceRect = ScaleSourceRect(&m_SourceRect);
LONG lAdjustedSourceTop = SourceRect.top;
// if the origin of bitmap is bottom-left, adjust soruce_rect_top
// to be the bottom-left corner instead of the top-left.
if (pbmi->biHeight > 0) {
lAdjustedSourceTop = pbmi->biHeight - SourceRect.bottom;
}
// Is the window the same size as the video
if (m_bStretch == FALSE) {
// Put the image straight into the window
SetDIBitsToDevice(
(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
SourceRect.left, // X source position
lAdjustedSourceTop, // Adjusted Y source position
(UINT) 0, // Start scan line
pbmi->biHeight, // Scan lines present
pImage, // Image data
(BITMAPINFO *) pbmi, // DIB header
DIB_RGB_COLORS); // Type of palette
} else {
// Stretch the image when copying to the window
StretchDIBits(
(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
SourceRect.left, // X source position
lAdjustedSourceTop, // Adjusted Y source position
SourceRect.right - SourceRect.left, // Source width
SourceRect.bottom - SourceRect.top, // Source height
pImage, // Image data
(BITMAPINFO *) pbmi, // DIB header
DIB_RGB_COLORS, // Type of palette
SRCCOPY); // Simple image copy
}
// This shows the sample reference times over the top of the image which
// looks a little flickery. I tried using GdiSetBatchLimit and GdiFlush to
// control the screen updates but it doesn't quite work as expected and
// only partially reduces the flicker. I also tried using a memory context
// and combining the two in that before doing a final BitBlt operation to
// the screen, unfortunately this has considerable performance penalties
// and also means that this code is not executed when compiled retail
#ifdef DEBUG
DisplaySampleTimes(pMediaSample);
#endif
}
// This is called with an IMediaSample interface on the image to be drawn. We
// decide on the drawing mechanism based on who's allocator we are using. We
// may be called when the window wants an image painted by WM_PAINT messages
// We can't realise the palette here because we have the renderer lock, any
// call to realise may cause an interthread send message to the window thread
// which may in turn be waiting to get the renderer lock before servicing it
BOOL CDrawImage::DrawImage(IMediaSample *pMediaSample)
{
ASSERT(m_hdc);
ASSERT(m_MemoryDC);
NotifyStartDraw();
// If the output pin used our allocator then the samples passed are in
// fact CVideoSample objects that contain CreateDIBSection data that we
// use to do faster image rendering, they may optionally also contain a
// DirectDraw surface pointer in which case we do not do the drawing
if (m_bUsingImageAllocator == FALSE) {
SlowRender(pMediaSample);
EXECUTE_ASSERT(GdiFlush());
NotifyEndDraw();
return TRUE;
}
// This is a DIBSECTION buffer
FastRender(pMediaSample);
EXECUTE_ASSERT(GdiFlush());
NotifyEndDraw();
return TRUE;
}
BOOL CDrawImage::DrawVideoImageHere(
HDC hdc,
IMediaSample *pMediaSample,
LPRECT lprcSrc,
LPRECT lprcDst
)
{
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 FALSE;
}
RECT SourceRect;
RECT TargetRect;
if (lprcSrc) {
SourceRect = *lprcSrc;
}
else SourceRect = ScaleSourceRect(&m_SourceRect);
if (lprcDst) {
TargetRect = *lprcDst;
}
else TargetRect = m_TargetRect;
LONG lAdjustedSourceTop = SourceRect.top;
// if the origin of bitmap is bottom-left, adjust soruce_rect_top
// to be the bottom-left corner instead of the top-left.
if (pbmi->biHeight > 0) {
lAdjustedSourceTop = pbmi->biHeight - SourceRect.bottom;
}
// Stretch the image when copying to the DC
BOOL bRet = (0 != StretchDIBits(hdc,
TargetRect.left,
TargetRect.top,
TargetRect.right - TargetRect.left,
TargetRect.bottom - TargetRect.top,
SourceRect.left,
lAdjustedSourceTop,
SourceRect.right - SourceRect.left,
SourceRect.bottom - SourceRect.top,
pImage,
(BITMAPINFO *)pbmi,
DIB_RGB_COLORS,
SRCCOPY));
return bRet;
}
// This is called by the owning window object after it has created the window
// and it's drawing contexts. We are constructed with the base window we'll
// be drawing into so when given the notification we retrive the device HDCs
// to draw with. We cannot call these in our constructor as they are virtual
void CDrawImage::SetDrawContext()
{
m_MemoryDC = m_pBaseWindow->GetMemoryHDC();
m_hdc = m_pBaseWindow->GetWindowHDC();
}
// This is called to set the target rectangle in the video window, it will be
// called whenever a WM_SIZE message is retrieved from the message queue. We
// simply store the rectangle and use it later when we do the drawing calls
void CDrawImage::SetTargetRect(RECT *pTargetRect)
{
ASSERT(pTargetRect);
m_TargetRect = *pTargetRect;
SetStretchMode();
}
// Return the current target rectangle
void CDrawImage::GetTargetRect(RECT *pTargetRect)
{
ASSERT(pTargetRect);
*pTargetRect = m_TargetRect;
}
// This is called when we want to change the section of the image to draw. We
// use this information in the drawing operation calls later on. We must also
// see if the source and destination rectangles have the same dimensions. If
// not we must stretch during the drawing rather than a direct pixel copy
void CDrawImage::SetSourceRect(RECT *pSourceRect)
{
ASSERT(pSourceRect);
m_SourceRect = *pSourceRect;
SetStretchMode();
}
// Return the current source rectangle
void CDrawImage::GetSourceRect(RECT *pSourceRect)
{
ASSERT(pSourceRect);
*pSourceRect = m_SourceRect;
}
// This is called when either the source or destination rectanges change so we
// can update the stretch flag. If the rectangles don't match we stretch the
// video during the drawing otherwise we call the fast pixel copy functions
// NOTE the source and/or the destination rectangle may be completely empty
void CDrawImage::SetStretchMode()
{
// Calculate the overall rectangle dimensions
LONG SourceWidth = m_SourceRect.right - m_SourceRect.left;
LONG SinkWidth = m_TargetRect.right - m_TargetRect.left;
LONG SourceHeight = m_SourceRect.bottom - m_SourceRect.top;
LONG SinkHeight = m_TargetRect.bottom - m_TargetRect.top;
m_bStretch = TRUE;
if (SourceWidth == SinkWidth) {
if (SourceHeight == SinkHeight) {
m_bStretch = FALSE;
}
}
}
// Tell us whose allocator we are using. This should be called with TRUE if
// the filter agrees to use an allocator based around the CImageAllocator
// SDK base class - whose image buffers are made through CreateDIBSection.
// Otherwise this should be called with FALSE and we will draw the images
// using SetDIBitsToDevice and StretchDIBitsToDevice. None of these calls
// can handle buffers which have non zero strides (like DirectDraw uses)
void CDrawImage::NotifyAllocator(BOOL bUsingImageAllocator)
{
m_bUsingImageAllocator = bUsingImageAllocator;
}
// Are we using the image DIBSECTION allocator
BOOL CDrawImage::UsingImageAllocator()
{
return m_bUsingImageAllocator;
}
// We need the media type of the connection so that we can get the BITMAPINFO
// from it. We use that in the calls to draw the image such as StretchDIBits
// and also when updating the colour table held in shared memory DIBSECTIONs
void CDrawImage::NotifyMediaType(CMediaType *pMediaType)
{
m_pMediaType = pMediaType;
}
// We store in this object a cookie maintaining the current palette version.
// Each time a palettised format is changed we increment this value so that
// when we come to draw the images we look at the colour table value they
// have and if less than the current we know to update it. This version is
// only needed and indeed used when working with shared memory DIBSECTIONs
LONG CDrawImage::GetPaletteVersion()
{
return m_PaletteVersion;
}
// Resets the current palette version number
void CDrawImage::ResetPaletteVersion()
{
m_PaletteVersion = PALETTE_VERSION;
}
// Increment the current palette version
void CDrawImage::IncrementPaletteVersion()
{
m_PaletteVersion++;
}
// Constructor must initialise the base allocator. Each sample we create has a
// palette version cookie on board. When the source filter changes the palette
// during streaming the window object increments an internal cookie counter it
// keeps as well. When it comes to render the samples it looks at the cookie
// values and if they don't match then it knows to update the sample's colour
// table. However we always create samples with a cookie of PALETTE_VERSION
// If there have been multiple format changes and we disconnect and reconnect
// thereby causing the samples to be reallocated we will create them with a
// cookie much lower than the current version, this isn't a problem since it
// will be seen by the window object and the versions will then be updated
CImageAllocator::CImageAllocator(CBaseFilter *pFilter,
TCHAR *pName,
HRESULT *phr) :
CBaseAllocator(pName,NULL,phr,TRUE,TRUE),
m_pFilter(pFilter)
{
ASSERT(phr);
ASSERT(pFilter);
}
// Check our DIB buffers have been released
#ifdef DEBUG
CImageAllocator::~CImageAllocator()
{
ASSERT(m_bCommitted == FALSE);
}
#endif
// Called from destructor and also from base class to free resources. We work
// our way through the list of media samples deleting the DIBSECTION created
// for each. All samples should be back in our list so there is no chance a
// filter is still using one to write on the display or hold on a pending list
void CImageAllocator::Free()
{
ASSERT(m_lAllocated == m_lFree.GetCount());
EXECUTE_ASSERT(GdiFlush());
CImageSample *pSample;
DIBDATA *pDibData;
while (m_lFree.GetCount() != 0) {
pSample = (CImageSample *) m_lFree.RemoveHead();
pDibData = pSample->GetDIBData();
EXECUTE_ASSERT(DeleteObject(pDibData->hBitmap));
EXECUTE_ASSERT(CloseHandle(pDibData->hMapping));
delete pSample;
}
m_lAllocated = 0;
}
// Prepare the allocator by checking all the input parameters
STDMETHODIMP CImageAllocator::CheckSizes(ALLOCATOR_PROPERTIES *pRequest)
{
// Check we have a valid connection
if (m_pMediaType == NULL) {
return VFW_E_NOT_CONNECTED;
}
// NOTE We always create a DIB section with the source format type which
// may contain a source palette. When we do the BitBlt drawing operation
// the target display device may contain a different palette (we may not
// have the focus) in which case GDI will do after the palette mapping
VIDEOINFOHEADER *pVideoInfo = (VIDEOINFOHEADER *) m_pMediaType->Format();
// When we call CreateDIBSection it implicitly maps only enough memory
// for the image as defined by thee BITMAPINFOHEADER. If the user asks
// for an image smaller than this then we reject the call, if they ask
// for an image larger than this then we return what they can have
if ((DWORD) pRequest->cbBuffer < pVideoInfo->bmiHeader.biSizeImage) {
return E_INVALIDARG;
}
// Reject buffer prefixes
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -