?? winutil.cpp
字號:
if (pRequest->cbPrefix > 0) {
return E_INVALIDARG;
}
pRequest->cbBuffer = pVideoInfo->bmiHeader.biSizeImage;
return NOERROR;
}
// Agree the number of media sample buffers and their sizes. The base class
// this allocator is derived from allows samples to be aligned only on byte
// boundaries NOTE the buffers are not allocated until the Commit call
STDMETHODIMP CImageAllocator::SetProperties(
ALLOCATOR_PROPERTIES * pRequest,
ALLOCATOR_PROPERTIES * pActual)
{
ALLOCATOR_PROPERTIES Adjusted = *pRequest;
// Check the parameters fit with the current connection
HRESULT hr = CheckSizes(&Adjusted);
if (FAILED(hr)) {
return hr;
}
return CBaseAllocator::SetProperties(&Adjusted, pActual);
}
// Commit the memory by allocating the agreed number of media samples. For
// each sample we are committed to creating we have a CImageSample object
// that we use to manage it's resources. This is initialised with a DIBDATA
// structure that contains amongst other things the GDI DIBSECTION handle
// We will access the renderer media type during this so we must have locked
// (to prevent the format changing for example). The class overrides Commit
// and Decommit to do this locking (base class Commit in turn calls Alloc)
HRESULT CImageAllocator::Alloc(void)
{
ASSERT(m_pMediaType);
CImageSample *pSample;
DIBDATA DibData;
// Check the base allocator says it's ok to continue
HRESULT hr = CBaseAllocator::Alloc();
if (FAILED(hr)) {
return hr;
}
// We create a new memory mapped object although we don't map it into our
// address space because GDI does that in CreateDIBSection. It is possible
// that we run out of resources before creating all the samples in which
// case the available sample list is left with those already created
ASSERT(m_lAllocated == 0);
while (m_lAllocated < m_lCount) {
// Create and initialise a shared memory GDI buffer
HRESULT hr = CreateDIB(m_lSize,DibData);
if (FAILED(hr)) {
return hr;
}
// Create the sample object and pass it the DIBDATA
pSample = CreateImageSample(DibData.pBase,m_lSize);
if (pSample == NULL) {
EXECUTE_ASSERT(DeleteObject(DibData.hBitmap));
EXECUTE_ASSERT(CloseHandle(DibData.hMapping));
return E_OUTOFMEMORY;
}
// Add the completed sample to the available list
pSample->SetDIBData(&DibData);
m_lFree.Add(pSample);
m_lAllocated++;
}
return NOERROR;
}
// We have a virtual method that allocates the samples so that a derived class
// may override it and allocate more specialised sample objects. So long as it
// derives its samples from CImageSample then all this code will still work ok
CImageSample *CImageAllocator::CreateImageSample(LPBYTE pData,LONG Length)
{
HRESULT hr = NOERROR;
CImageSample *pSample;
// Allocate the new sample and check the return codes
pSample = new CImageSample((CBaseAllocator *) this, // Base class
NAME("Video sample"), // DEBUG name
(HRESULT *) &hr, // Return code
(LPBYTE) pData, // DIB address
(LONG) Length); // Size of DIB
if (pSample == NULL || FAILED(hr)) {
delete pSample;
return NULL;
}
return pSample;
}
// This function allocates a shared memory block for use by the source filter
// generating DIBs for us to render. The memory block is created in shared
// memory so that GDI doesn't have to copy the memory when we do a BitBlt
HRESULT CImageAllocator::CreateDIB(LONG InSize,DIBDATA &DibData)
{
BITMAPINFO *pbmi; // Format information for pin
BYTE *pBase; // Pointer to the actual image
HANDLE hMapping; // Handle to mapped object
HBITMAP hBitmap; // DIB section bitmap handle
// Create a file mapping object and map into our address space
hMapping = CreateFileMapping(hMEMORY, // Use system page file
NULL, // No security attributes
PAGE_READWRITE, // Full access to memory
(DWORD) 0, // Less than 4Gb in size
InSize, // Size of buffer
NULL); // No name to section
if (hMapping == NULL) {
DWORD Error = GetLastError();
return MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, Error);
}
// 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
pbmi = (BITMAPINFO *) HEADER(m_pMediaType->Format());
if (m_pMediaType == NULL) {
DbgBreak("Invalid media type");
}
hBitmap = CreateDIBSection((HDC) NULL, // NO device context
pbmi, // Format information
DIB_RGB_COLORS, // Use the palette
(VOID **) &pBase, // Pointer to image data
hMapping, // Mapped memory handle
(DWORD) 0); // Offset into memory
if (hBitmap == NULL || pBase == NULL) {
EXECUTE_ASSERT(CloseHandle(hMapping));
DWORD Error = GetLastError();
return MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, Error);
}
// Initialise the DIB information structure
DibData.hBitmap = hBitmap;
DibData.hMapping = hMapping;
DibData.pBase = pBase;
DibData.PaletteVersion = PALETTE_VERSION;
GetObject(hBitmap,sizeof(DIBSECTION),(VOID *)&DibData.DibSection);
return NOERROR;
}
// We use the media type during the DIBSECTION creation
void CImageAllocator::NotifyMediaType(CMediaType *pMediaType)
{
m_pMediaType = pMediaType;
}
// Overriden to increment the owning object's reference count
STDMETHODIMP_(ULONG) CImageAllocator::NonDelegatingAddRef()
{
return m_pFilter->AddRef();
}
// Overriden to decrement the owning object's reference count
STDMETHODIMP_(ULONG) CImageAllocator::NonDelegatingRelease()
{
return m_pFilter->Release();
}
// If you derive a class from CMediaSample that has to transport specialised
// member variables and entry points then there are three alternate solutions
// The first is to create a memory buffer larger than actually required by the
// sample and store your information either at the beginning of it or at the
// end, the former being moderately safer allowing for misbehaving transform
// filters. You then adjust the buffer address when you create the base media
// sample. This has the disadvantage of breaking up the memory allocated to
// the samples into separate blocks. The second solution is to implement a
// class derived from CMediaSample and support additional interface(s) that
// convey your private data. This means defining a custom interface. The final
// alternative is to create a class that inherits from CMediaSample and adds
// the private data structures, when you get an IMediaSample in your Receive()
// call check to see if your allocator is being used, and if it is then cast
// the IMediaSample into one of your objects. Additional checks can be made
// to ensure the sample's this pointer is known to be one of your own objects
CImageSample::CImageSample(CBaseAllocator *pAllocator,
TCHAR *pName,
HRESULT *phr,
LPBYTE pBuffer,
LONG length) :
CMediaSample(pName,pAllocator,phr,pBuffer,length),
m_bInit(FALSE)
{
ASSERT(pAllocator);
ASSERT(pBuffer);
}
// Set the shared memory DIB information
void CImageSample::SetDIBData(DIBDATA *pDibData)
{
ASSERT(pDibData);
m_DibData = *pDibData;
m_bInit = TRUE;
}
// Retrieve the shared memory DIB data
DIBDATA *CImageSample::GetDIBData()
{
ASSERT(m_bInit == TRUE);
return &m_DibData;
}
// This class handles the creation of a palette. It is fairly specialist and
// is intended to simplify palette management for video renderer filters. It
// is for this reason that the constructor requires three other objects with
// which it interacts, namely a base media filter, a base window and a base
// drawing object although the base window or the draw object may be NULL to
// ignore that part of us. We try not to create and install palettes unless
// absolutely necessary as they typically require WM_PALETTECHANGED messages
// to be sent to every window thread in the system which is very expensive
CImagePalette::CImagePalette(CBaseFilter *pBaseFilter,
CBaseWindow *pBaseWindow,
CDrawImage *pDrawImage) :
m_pBaseWindow(pBaseWindow),
m_pFilter(pBaseFilter),
m_pDrawImage(pDrawImage),
m_hPalette(NULL)
{
ASSERT(m_pFilter);
}
// Destructor
#ifdef DEBUG
CImagePalette::~CImagePalette()
{
ASSERT(m_hPalette == NULL);
}
#endif
// We allow dynamic format changes of the palette but rather than change the
// palette every time we call this to work out whether an update is required.
// If the original type didn't use a palette and the new one does (or vica
// versa) then we return TRUE. If neither formats use a palette we'll return
// FALSE. If both formats use a palette we compare their colours and return
// FALSE if they match. This therefore short circuits palette creation unless
// absolutely necessary since installing palettes is an expensive operation
BOOL CImagePalette::ShouldUpdate(const VIDEOINFOHEADER *pNewInfo,
const VIDEOINFOHEADER *pOldInfo)
{
// We may not have a current format yet
if (pOldInfo == NULL) {
return TRUE;
}
// Do both formats not require a palette
if (ContainsPalette(pNewInfo) == FALSE) {
if (ContainsPalette(pOldInfo) == FALSE) {
return FALSE;
}
}
// Compare the colours to see if they match
DWORD VideoEntries = pNewInfo->bmiHeader.biClrUsed;
if (ContainsPalette(pNewInfo) == TRUE)
if (ContainsPalette(pOldInfo) == TRUE)
if (pOldInfo->bmiHeader.biClrUsed == VideoEntries)
if (pOldInfo->bmiHeader.biClrUsed > 0)
if (memcmp((PVOID) GetBitmapPalette(pNewInfo),
(PVOID) GetBitmapPalette(pOldInfo),
VideoEntries * sizeof(RGBQUAD)) == 0) {
return FALSE;
}
return TRUE;
}
// This is normally called when the input pin type is set to install a palette
// We will typically be called from two different places. The first is when we
// have negotiated a palettised media type after connection, the other is when
// we receive a new type during processing with an updated palette in which
// case we must remove and release the resources held by the current palette
// We can be passed an optional device name if we wish to prepare a palette
// for a specific monitor on a multi monitor system
HRESULT CImagePalette::PreparePalette(const CMediaType *pmtNew,
const CMediaType *pmtOld,
LPSTR szDevice)
{
const VIDEOINFOHEADER *pNewInfo = (VIDEOINFOHEADER *) pmtNew->Format();
const VIDEOINFOHEADER *pOldInfo = (VIDEOINFOHEADER *) pmtOld->Format();
ASSERT(pNewInfo);
// This is an performance optimisation, when we get a media type we check
// to see if the format requires a palette change. If either we need one
// when previously we didn't or vica versa then this returns TRUE, if we
// previously needed a palette and we do now it compares their colours
if (ShouldUpdate(pNewInfo,pOldInfo) == FALSE) {
NOTE("No update needed");
return S_FALSE;
}
// We must notify the filter graph that the application may have changed
// the palette although in practice we don't bother checking to see if it
// is really different. If it tries to get the palette either the window
// or renderer lock will ensure it doesn't get in until we are finished
RemovePalette();
m_pFilter->NotifyEvent(EC_PALETTE_CHANGED,0,0);
// Do we need a palette for the new format
if (ContainsPalette(pNewInfo) == FALSE) {
NOTE("New has no palette");
return S_FALSE;
}
if (m_pBaseWindow) {
m_pBaseWindow->LockPaletteLock();
}
// If we're changing the palette on the fly then we increment our palette
// cookie which is compared against the cookie also stored in all of our
// DIBSECTION media samples. If they don't match when we come to draw it
// then we know the sample is out of date and we'll update it's palette
NOTE("Making new colour palette");
m_hPalette = MakePalette(pNewInfo, szDevice);
ASSERT(m_hPalette != NULL);
if (m_pBaseWindow) {
m_pBaseWindow->UnlockPaletteLock();
}
// The window in which the new palette is to be realised may be a NULL
// pointer to signal that no window is in use, if so we don't call it
// Some
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -