⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 winutil.cpp

📁 basic class basic classbasic class
💻 CPP
📖 第 1 页 / 共 5 页
字号:
{
#ifdef WINUTIL_STUB
    STUBRET(GDI_ERROR);
#else

    HBITMAP     hbm = NULL;
    HBITMAP     hbmOld;
    int         iStride;
    HDC         hdcSrc;
    int         iRet;
    PLOGPALETTE pPal;
    HPALETTE    hpal = NULL;
    HPALETTE    hpalOld;

    // Check input pointers
    if ((lpBitsInfo == NULL) || (lpBits == NULL))
	    return GDI_ERROR;

    // Stride is bitmap width in bytes, DWORD aligned
    iStride = ((lpBitsInfo->bmiHeader.biWidth * lpBitsInfo->bmiHeader.biBitCount / 8) + 3) & ~3;

    // Make a source DC to blt from
    hdcSrc = CreateCompatibleDC(hdc);
    if (hdcSrc == NULL)
    {
	    iRet = GDI_ERROR;
	    goto cleanup;
    }

    // Wrap a GDI BITMAP object around these bitmap bits, using "secret" MGDI function
    hbm = CreateBitmapFromPointer(lpBitsInfo, iStride, (PVOID)lpBits);
    if (hbm == NULL)
    {
	    iRet = GDI_ERROR;
	    goto cleanup;
    }
    hbmOld = (HBITMAP)SelectObject(hdcSrc, hbm);
    if (hbmOld == NULL)
    {
	    iRet = GDI_ERROR;
	    goto cleanup;
    }

    // Do we need a palette?
    if ((lpBitsInfo->bmiHeader.biCompression == BI_RGB) && (iUsage == DIB_RGB_COLORS) && (lpBitsInfo->bmiHeader.biBitCount <= 8))
    {
	    DWORD cColors = lpBitsInfo->bmiHeader.biClrUsed;
	
	    if (cColors == 0)
	    {
	        cColors = 1 << lpBitsInfo->bmiHeader.biBitCount;
	    }
	    pPal = (PLOGPALETTE)LocalAlloc(LMEM_FIXED, sizeof(LOGPALETTE) +
						   sizeof(PALETTEENTRY) * cColors);
	    if (pPal == NULL)
	    {
	        iRet = GDI_ERROR;
	        goto cleanup;
	    }
	    pPal->palVersion = 0x300;
	    pPal->palNumEntries = (WORD)cColors;
	    for (WORD idx = 0; idx < cColors; idx++)
	    {
	        pPal->palPalEntry[idx].peRed   = lpBitsInfo->bmiColors[idx].rgbRed;
	        pPal->palPalEntry[idx].peGreen = lpBitsInfo->bmiColors[idx].rgbGreen;
	        pPal->palPalEntry[idx].peBlue  = lpBitsInfo->bmiColors[idx].rgbBlue;
	        pPal->palPalEntry[idx].peFlags = 0;
	    }
	    hpal = CreatePalette(pPal);
	    if (hpal == NULL)
	    {
	        LocalFree(pPal);
	        iRet = GDI_ERROR;
	        goto cleanup;
	    }
	    hpalOld = SelectPalette(hdcSrc, hpal, FALSE);
	    LocalFree(pPal);
    }

    // Do the Blt

    if ( StretchBlt(hdc,    XDest,  YDest,  nDestWidth, nDestHeight,
		    hdcSrc, XSrc,   YSrc,   nSrcWidth,  nSrcHeight, dwRop))
    {
    	// REVIEW martsh: doesn't take into account clipping.  Should this be nDestHeight?
	    iRet = nSrcHeight > 0 ? nSrcHeight : -nSrcHeight;
    }
    else
    {
	    iRet = GDI_ERROR;
    }

cleanup:

    if (hbm)
    {
	    SelectObject(hdcSrc, hbmOld);
	    DeleteObject(hbm);
    }

    // Did we use a palette?
    if (hpal)
    {
	    SelectPalette(hdcSrc, hpalOld, FALSE);
	    DeleteObject(hpal);
    }
    if (hdcSrc)
    {
	    DeleteDC(hdcSrc);
    }

	return iRet;
#endif // WINUTIL_STUB
}
#endif // UNDER_CE


// 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)
{
#ifdef WINUTIL_STUB
    STUBNORET;
#else
    // Get the BITMAPINFOHEADER for the connection

    ASSERT(m_pMediaType);
    BITMAPINFOHEADER *pbmi = GetBitmapInfoHeader (m_pMediaType);
    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
    // 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

#ifndef UNDER_CE
    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
    }
#else // !UNDER_CE
    CeStretchDIBits(
        (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
#endif // !UNDER_CE

    // 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
#endif // WINUTIL_STUB
}


// 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)
{
#ifdef WINUTIL_STUB
    STUBRET(FALSE);
#else
    SetDrawContext();
    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);
#ifndef UNDER_CE
        EXECUTE_ASSERT(GdiFlush());
#endif // UNDER_CE
        NotifyEndDraw();
        return TRUE;
    }

    // This is a DIBSECTION buffer

    FastRender(pMediaSample);
#ifndef UNDER_CE
    EXECUTE_ASSERT(GdiFlush());
#endif // UNDER_CE
    NotifyEndDraw();
    return TRUE;
#endif // WINUTIL_STUB
}


// 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()
{
#ifdef WINUTIL_STUB
    STUBNORET;
#else
    m_MemoryDC = m_pBaseWindow->GetMemoryHDC();
    m_hdc = m_pBaseWindow->GetWindowHDC();
#endif // WINUTIL_STUB
}


// 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)
{
#ifdef WINUTIL_STUB
    STUBNORET;
#else
    ASSERT(pTargetRect);
    m_TargetRect = *pTargetRect;
    SetStretchMode();
#endif // WINUTIL_STUB
}


// Return the current target rectangle

void CDrawImage::GetTargetRect(RECT *pTargetRect)
{
#ifdef WINUTIL_STUB
    STUBNORET;
#else
    ASSERT(pTargetRect);
    *pTargetRect = m_TargetRect;
#endif // WINUTIL_STUB
}


// 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)
{
#ifdef WINUTIL_STUB
    STUBNORET;
#else
    ASSERT(pSourceRect);
    m_SourceRect = *pSourceRect;
    SetStretchMode();
#endif // WINUTIL_STUB
}


// Return the current source rectangle

void CDrawImage::GetSourceRect(RECT *pSourceRect)
{
#ifdef WINUTIL_STUB
    STUBNORET;
#else
    ASSERT(pSourceRect);
    *pSourceRect = m_SourceRect;
#endif // WINUTIL_STUB
}


// 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()
{
#ifdef WINUTIL_STUB
    STUBNORET;
#else
    // 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;
        }
    }
#endif // WINUTIL_STUB
}


// 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)
{
#ifdef WINUTIL_STUB
    STUBNORET;
#else
    m_bUsingImageAllocator = bUsingImageAllocator;
#endif // WINUTIL_STUB
}


// Are we using the image DIBSECTION allocator

BOOL CDrawImage::UsingImageAllocator()

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -