//----------------------------------------------------------------------------
// File: YuvGray.cpp
//
// Description:
// YuvGray is a DirectShow transform filter that converts UYVY color images
// to grayscale.
//-----------------------------------------------------------------------------
#ifdef _DEBUG
#ifndef DEBUG
#define DEBUG
#endif
#endif
#include <streams.h> // DirectShow base class library
#include <aviriff.h> // defines 'FCC' macro
// Forward declares
void GetVideoInfoParameters(
const VIDEOINFOHEADER *pvih, // Pointer to the format header.
BYTE * const pbData, // Pointer to the first address in the buffer.
DWORD *pdwWidth, // Returns the width in pixels.
DWORD *pdwHeight, // Returns the height in pixels.
LONG *plStrideInBytes, // Add this to a row to get the new row down
BYTE **ppbTop, // Returns pointer to the first byte in the top row of pixels.
bool bYuv
);
bool IsValidUYVY(const CMediaType *pmt);
// Define the filter's CLSID
// {A6512C9F-A47B-45ba-A054-0DB0D4BB87F7}
static const GUID CLSID_YuvGray =
{ 0xa6512c9f, 0xa47b, 0x45ba, { 0xa0, 0x54, 0xd, 0xb0, 0xd4, 0xbb, 0x87, 0xf7 } };
static const WCHAR g_wszName[] = L"YUV Filter"; // A name for the filter
//----------------------------------------------------------------------------
// CYuvGray Class
//
// This class defines the filter. It inherits CTransformFilter, which is a
// base class for copy-transform filters.
//-----------------------------------------------------------------------------
class CYuvGray : public CTransformFilter
{
public:
// ctor
CYuvGray(LPUNKNOWN pUnk, HRESULT *phr) :
CTransformFilter(NAME("YUV Transform Filter"), pUnk, CLSID_YuvGray)
{}
// Overridden CTransformFilter methods
HRESULT CheckInputType(const CMediaType *mtIn);
HRESULT CheckTransform(const CMediaType *mtIn, const CMediaType *mtOut);
HRESULT DecideBufferSize(IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *pProp);
HRESULT GetMediaType(int iPosition, CMediaType *pMediaType);
HRESULT Transform(IMediaSample *pIn, IMediaSample *pOut);
// Override this so we can grab the video format
HRESULT SetMediaType(PIN_DIRECTION direction, const CMediaType *pmt);
// Static object-creation method (for the class factory)
static CUnknown * WINAPI CreateInstance(LPUNKNOWN pUnk, HRESULT *pHr);
private:
HRESULT ProcessFrame(BYTE *pbInput, BYTE *pbOutput, long *pcbByte);
VIDEOINFOHEADER m_VihIn; // Holds the current video format (input)
VIDEOINFOHEADER m_VihOut; // Holds the current video format (output)
};
//----------------------------------------------------------------------------
// CYuvGray::CheckInputType
//
// checks whether a specified media type is acceptable for input.
// Examine a proposed input type. Returns S_OK if we can accept his input type
// or VFW_E_TYPE_NOT_ACCEPTED otherwise. This filter accepts UYVY types only.
//-----------------------------------------------------------------------------
HRESULT CYuvGray::CheckInputType(const CMediaType *pmt)
{
if (IsValidUYVY(pmt))
{
return S_OK;
}
else
{
return VFW_E_TYPE_NOT_ACCEPTED;
}
}
//----------------------------------------------------------------------------
// CYuvGray::CheckTransform
//
// Compare an input type with an output type, and see if we can convert from
// one to the other. The input type is known to be OK from ::CheckInputType,
// so this is really a check on the output type.
//-----------------------------------------------------------------------------
HRESULT CYuvGray::CheckTransform(const CMediaType *mtIn, const CMediaType *mtOut)
{
if (!IsValidUYVY(mtOut))
{
return VFW_E_TYPE_NOT_ACCEPTED;
}
BITMAPINFOHEADER *pBmi = HEADER(mtIn);
BITMAPINFOHEADER *pBmi2 = HEADER(mtOut);
if ((pBmi->biWidth <= pBmi2->biWidth) &&
(pBmi->biHeight == abs(pBmi2->biHeight)))
{
return S_OK;
}
return VFW_E_TYPE_NOT_ACCEPTED;
}
//----------------------------------------------------------------------------
// CYuvGray::GetMediaType
//
// Return an output type that we like, in order of preference, by index number.
//
// iPosition: index number
// pMediaType: Write the media type into this object.
//-----------------------------------------------------------------------------
HRESULT CYuvGray::GetMediaType(int iPosition, CMediaType *pMediaType)
{
// The output pin calls this method only if the input pin is connected.
ASSERT(m_pInput->IsConnected());
// There is only one output type that we want, which is the input type.
if (iPosition < 0)
{
return E_INVALIDARG;
}
else if (iPosition == 0)
{ // retrieves the media type for the current pin connection
return m_pInput->ConnectionMediaType(pMediaType);
}
return VFW_S_NO_MORE_ITEMS;
}
//----------------------------------------------------------------------------
// CYuvGray::DecideBufferSize
//
// Decide the buffer size and other allocator properties, for the downstream
// allocator.
//
// pAlloc: Pointer to the allocator.
// pProp: Contains the downstream filter's request (or all zeroes)
//-----------------------------------------------------------------------------
HRESULT CYuvGray::DecideBufferSize(IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *pProp)
{
// Make sure the input pin connected.
if (!m_pInput->IsConnected())
{
return E_UNEXPECTED;
}
// Our strategy here is to use the upstream allocator as the guideline, but
// also defer to the downstream filter's request when it's compatible with us.
// First, find the upstream allocator...
ALLOCATOR_PROPERTIES InputProps;
IMemAllocator *pAllocInput = 0;
HRESULT hr = m_pInput->GetAllocator(&pAllocInput);
if (FAILED(hr))
{
return hr;
}
// ... now get the properters
hr = pAllocInput->GetProperties(&InputProps);
pAllocInput->Release();
if (FAILED(hr))
{
return hr;
}
// Buffer alignment should be non-zero [zero alignment makes no sense!]
if (pProp->cbAlign == 0)
{
pProp->cbAlign = 1;
}
// Number of buffers must be non-zero
if (pProp->cbBuffer == 0)
{
pProp->cBuffers = 1;
}
// For buffer size, find the maximum of the upstream size and
// the downstream filter's request.
pProp->cbBuffer = max(InputProps.cbBuffer, pProp->cbBuffer);
// Now set the properties on the allocator that was given to us,
ALLOCATOR_PROPERTIES Actual;
hr = pAlloc->SetProperties(pProp, &Actual);
if (FAILED(hr))
{
return hr;
}
// Even if SetProperties succeeds, the actual properties might be
// different than what we asked for. We check the result, but we only
// look at the properties that we care about. The downstream filter
// will look at them when NotifyAllocator is called.
if (InputProps.cbBuffer > Actual.cbBuffer)
{
return E_FAIL;
}
return S_OK;
}
//----------------------------------------------------------------------------
// CYuvGray::SetMediaType
//
// The CTransformFilter class calls this method when the media type is
// set on either pin. This gives us a chance to grab the format block.
//
// direction: Which pin (input or output)
// pmt: The media type that is being set.
//
// The method is called when the media type is set on one of the filter's pins.
// Note: If the pins were friend classes of the filter, we could access the
// connection type directly. But this is easier than sub-classing the pins.
//------------------
- 1
- 2
- 3
前往页