Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2113 lines
70 KiB

// Copyright (c) 1994 - 1999 Microsoft Corporation. All Rights Reserved.
//
// Prototype wrapper for old video decompressors
//
#include <streams.h>
#include <windowsx.h>
#ifdef FILTER_DLL
#include <vfw.h>
// define the GUIDs for streams and my CLSID in this file
#include <initguid.h>
#endif
#include <dynlink.h>
#include "dec.h"
#include "safeseh.h"
#include "msvidkey.h"
// you can never have too many parentheses!
#define ABS(x) (((x) > 0) ? (x) : -(x))
// how to build an explicit FOURCC
#define FCC(ch4) ((((DWORD)(ch4) & 0xFF) << 24) | \
(((DWORD)(ch4) & 0xFF00) << 8) | \
(((DWORD)(ch4) & 0xFF0000) >> 8) | \
(((DWORD)(ch4) & 0xFF000000) >> 24))
// #define OFFER_NEGATIVE_HEIGHTS
// ***************************************************************
// here are the current bugs that without fixes, would play wrong:
//
// * Hooking up a YUV type to the ASF writer, without forcing the codec
// see -biHeight on the output, will result in a flipped image being written
// **** When Primary Surface is already taken ****
// WINX to 16/24/32 - plays black
// WINX to 8 bit - corrupted
// (H.263 codec at fault for the following:)
// I420 320x240 to 24 - corrupted
// I420 160x120 to 24 - corrupted
// I420 320x240 to 16 - flipped
// I420 160x120 to 16 - flipped
// IYUV 320x240 to 16 - flipped
// IYUV 160x240 to 16 - flipped
// ************************************************
// **** When Primary Surface is not taken ****
// WNV1 to 24 faults display
// IYUV 320x240 to 24 is flipped
// IYUV 160x120 to 24 is flipped
// IYUV 320x240 to 16 is flipped
// IYUV 160x120 to 16 is flipped
// ********************************************
// ***************************************************************
// ***************************************************************
// setup data
const AMOVIESETUP_MEDIATYPE
sudAVIDecType = { &MEDIATYPE_Video // clsMajorType
, &MEDIASUBTYPE_NULL }; // clsMinorType
const AMOVIESETUP_PIN
psudAVIDecPins[] = { { L"Input" // strName
, FALSE // bRendered
, FALSE // bOutput
, FALSE // bZero
, FALSE // bMany
, &CLSID_NULL // clsConnectsToFilter
, L"Output" // strConnectsToPin
, 1 // nTypes
, &sudAVIDecType } // lpTypes
, { L"Output" // strName
, FALSE // bRendered
, TRUE // bOutput
, FALSE // bZero
, FALSE // bMany
, &CLSID_NULL // clsConnectsToFilter
, L"Input" // strConnectsToPin
, 1 // nTypes
, &sudAVIDecType } }; // lpTypes
const AMOVIESETUP_FILTER
sudAVIDec = { &CLSID_AVIDec // clsID
, L"AVI Decompressor" // strName
, MERIT_NORMAL // dwMerit
, 2 // nPins
, psudAVIDecPins }; // lpPin
#ifdef FILTER_DLL
// list of class ids and creator functions for class factory
CFactoryTemplate g_Templates[] = {
{ L"AVI Decompressor"
, &CLSID_AVIDec
, CAVIDec::CreateInstance
, NULL
, &sudAVIDec }
};
int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]);
// exported entry points for registration and
// unregistration (in this case they only call
// through to default implmentations).
//
STDAPI DllRegisterServer()
{
return AMovieDllRegisterServer2( TRUE );
}
STDAPI DllUnregisterServer()
{
return AMovieDllRegisterServer2( FALSE );
}
#endif
// --- CAVICodec ----------------------------------------
CAVIDec::CAVIDec(TCHAR *pName, LPUNKNOWN pUnk, HRESULT * phr)
: CVideoTransformFilter(pName, pUnk, CLSID_AVIDec),
m_hic(NULL),
m_FourCCIn(0),
m_fStreaming(FALSE),
m_fPassFormatChange(FALSE),
m_bUseEx( FALSE ),
m_fToRenderer( false )
#ifdef _X86_
,
m_hhpShared(NULL)
#endif
{
DbgLog((LOG_TRACE,2,TEXT("*Instantiating the DEC filter")));
#ifdef PERF
m_idSkip = MSR_REGISTER(TEXT("AVI Decoder Skip frame"));
m_idLate = MSR_REGISTER(TEXT("AVI Decoder late"));
m_idFrameType = MSR_REGISTER(TEXT("AVI Frame type (1=Key)"));
#endif
m_bNoSkip = GetProfileInt(TEXT("Quartz"), TEXT("AVINoSkip"), 0);
}
CAVIDec::~CAVIDec()
{
if (m_hic) {
ICClose(m_hic);
}
DbgLog((LOG_TRACE,2,TEXT("*Destroying the DEC filter")));
}
// this goes in the factory template table to create new instances
CUnknown * CAVIDec::CreateInstance(LPUNKNOWN pUnk, HRESULT * phr)
{
return new CAVIDec(TEXT("VFW decompression filter"), pUnk, phr);
}
HRESULT CAVIDec::Transform(IMediaSample * pIn, IMediaSample * pOut)
{
DWORD_PTR err = 0;
FOURCCMap fccOut;
CMediaType *pmtIn;
DbgLog((LOG_TRACE,6,TEXT("*::Transform")));
// codec not open ?
if (m_hic == 0) {
DbgLog((LOG_ERROR,1,TEXT("Can't transform, no codec open")));
return E_UNEXPECTED;
}
if (pIn == NULL || pOut == NULL) {
DbgLog((LOG_ERROR,1,TEXT("Can't transform, NULL arguments")));
return E_UNEXPECTED;
}
// we haven't started streaming yet?
if (!m_fStreaming) {
DbgLog((LOG_ERROR,1,TEXT("Can't transform, not streaming")));
return E_UNEXPECTED;
}
// make sure we have valid input and output pointers
BYTE * pSrc;
HRESULT hr = pIn->GetPointer(&pSrc);
if (FAILED(hr)) {
DbgLog((LOG_ERROR,1,TEXT("Error getting input sample data")));
return hr;
}
BYTE * pDst;
hr = pOut->GetPointer(&pDst);
if (FAILED(hr)) {
DbgLog((LOG_ERROR,1,TEXT("Error getting output sample data")));
return hr;
}
LPBITMAPINFOHEADER lpbiSrc = &InputFormat( )->bmiHeader;
LPBITMAPINFOHEADER lpbiDst = &IntOutputFormat( )->bmiHeader; // internal
// ICDecompress needs this to be the actual size of this frame, but
// we can't go changing this for good, so we'll put it back later
DWORD biSizeImageOld = lpbiSrc->biSizeImage;
lpbiSrc->biSizeImage = pIn->GetActualDataLength();
// we just received a format change from the source. So we better notify
// the guy downstream of the format change
pIn->GetMediaType((AM_MEDIA_TYPE **)&pmtIn);
// sometimes we don't end up passing anything to the renderer (eg preroll)
// so once we notice a format change we will keep trying to pass it to
// the renderer until we succeed. Don't waste time trying if we KNOW we're
// not going to do it.
if (pmtIn != NULL && pmtIn->Format() != NULL)
m_fPassFormatChange = TRUE;
DeleteMediaType(pmtIn);
if (m_fPassFormatChange && pIn->IsPreroll() != S_OK &&
pIn->GetActualDataLength() > 0) {
CMediaType cmt;
CopyMediaType((AM_MEDIA_TYPE *)&cmt, &m_pOutput->CurrentMediaType());
LPBITMAPINFOHEADER lpbi = HEADER(cmt.Format());
// if we're decompressing 8 bit to 8 bit, I'm assuming this is a
// palette change, so get the new palette
// VFW palette changes always have the same number of colours
if (lpbi && lpbiSrc && lpbiSrc->biBitCount == 8 &&
lpbi->biBitCount == 8) {
ASSERT(lpbi->biClrUsed == lpbiSrc->biClrUsed);
if (lpbi->biClrUsed == lpbiSrc->biClrUsed) {
DbgLog((LOG_TRACE,2,TEXT("Dynamic palette change suspected - doing it")));
CopyMemory(lpbi + 1, lpbiSrc + 1,
(lpbiSrc->biClrUsed ? lpbiSrc->biClrUsed : 256) *
sizeof(RGBQUAD));
pOut->SetMediaType(&cmt);
}
}
}
// some RLE-compressed videos have the initial frame broken
// into several separate frames. To work round this problem, avifile.dll
// reads and decodes all of these frames into a single decompressed frame.
// If we detect this (an RLE frame with the size of a decompressed frame)
// then we just copy it.
if ((lpbiSrc->biCompression == BI_RLE8) &&
(pIn->GetActualDataLength() == (long)lpbiDst->biSizeImage)) {
CopyMemory(pDst, pSrc, lpbiDst->biSizeImage);
} else {
BOOL dwFlags = 0;
if (pIn->IsPreroll() == S_OK) {
DbgLog((LOG_TRACE,6,TEXT("This is a preroll")));
dwFlags |= ICDECOMPRESS_PREROLL;
}
if (pIn->GetActualDataLength() <= 0) {
DbgLog((LOG_TRACE,6,TEXT("This is a NULL frame")));
dwFlags |= ICDECOMPRESS_NULLFRAME;
}
if(pIn->IsSyncPoint() == S_OK) {
DbgLog((LOG_TRACE,6,TEXT("This is a keyframe")));
} else {
dwFlags |= ICDECOMPRESS_NOTKEYFRAME;
}
// PLEASE don't ever send this flag to a codec! Some codecs take this as
// a hint to speed up, unfortunately others are slightly less clever and
// all they do when told to speed up is to send the same frame over and
// over again! Which in turn means that bugs get raised against me for
// random reasons such as when the window is being blown up full screen
// !!! well, we should do this SOMETIMES, shouldn't we?
//
// if (m_itrLate>0) {
// dwFlags |= ICDECOMPRESS_HURRYUP; // might help - who knows?
// }
#ifdef _X86_
// Fix the exception handling for win95
BOOL bPatchedExceptions = m_hhpShared != NULL && BeginScarySEH(m_pvShared);
#endif // _X86_
// If we're doing something really funky, use ICDecompressEx
// we use m_bUseEx here instead of ShoudUseEx because ICDecompressExBegin
// has already been called, and m_bUseEx will already have been set
if( m_bUseEx ) {
// these rects should ALWAYS be filled in
//
RECT rcS, rcT;
GetSrcTargetRects( IntOutputFormat( ), &rcS, &rcT );
DbgLog((LOG_TRACE,4,TEXT("Calling ICDecompressEx")));
err = ICDecompressEx(m_hic, dwFlags, lpbiSrc, pSrc,
rcS.left, rcS.top,
rcS.right - rcS.left,
rcS.bottom - rcS.top,
lpbiDst, pDst,
rcT.left,
// !!! What about when the big rect is the movie size, and there's a subrect?
// Should I do this hack or not?
// !!! How should I munge the source rect?
(lpbiDst->biHeight > 0) ? rcT.top :
(ABS(lpbiDst->biHeight) - rcT.bottom),
rcT.right - rcT.left,
rcT.bottom - rcT.top);
} else {
DbgLog((LOG_TRACE,4,TEXT("Calling ICDecompress")));
err = ICDecompress(m_hic, dwFlags, lpbiSrc, pSrc, lpbiDst, pDst);
}
#ifdef _X86_
if (bPatchedExceptions) {
EndScarySEH(m_pvShared);
}
#endif // _X86_
if ((LONG_PTR)err < 0) {
DbgLog((LOG_ERROR,1,TEXT("Error in ICDecompress(Ex) 0x%x"), (LONG)err));
// Note we can get 0 size samples from capture drivers which pipeline
// Because buffers must be returned in the order they are got
// the capture driver may have to invalidate 1 buffer by making
// it 0 length if it gets bad data.
err = ICERR_DONTDRAW;
}
}
// now put this back, or it'll shrink until we only decode part of each frm
lpbiSrc->biSizeImage = biSizeImageOld;
// decompressed frames are always key
pOut->SetSyncPoint(TRUE);
// Check if this is preroll to get from keyframe to the current frame,
// or a null frame, or if the decompressor doesn't want this frame drawn.
// If so, we want to decompress it into the output buffer but not
// deliver it. Returning S_FALSE tells the base class not to deliver
// this sample.
if (pIn->IsPreroll() == S_OK || err == ICERR_DONTDRAW ||
pIn->GetActualDataLength() <= 0) {
DbgLog((LOG_TRACE,5,TEXT("don't pass this to renderer")));
return S_FALSE;
}
pOut->SetActualDataLength(lpbiDst->biSizeImage);
// If there's a pending format change to pass to the renderer, we are now
// doing it
m_fPassFormatChange = FALSE;
return S_OK;
}
// check if you can support mtIn
HRESULT CAVIDec::CheckInputType(const CMediaType* pmtIn)
{
FOURCCMap fccHandlerIn;
HIC hic;
BOOL fOpenedHIC = FALSE;
DbgLog((LOG_TRACE,3,TEXT("*::CheckInputType")));
if (pmtIn == NULL || pmtIn->Format() == NULL) {
DbgLog((LOG_TRACE,3,TEXT("Rejecting: type/format is NULL")));
return E_INVALIDARG;
}
// we only support MEDIATYPE_Video
if (*pmtIn->Type() != MEDIATYPE_Video) {
DbgLog((LOG_TRACE,3,TEXT("Rejecting: not VIDEO")));
return E_INVALIDARG;
}
// check this is a VIDEOINFOHEADER type
if (*pmtIn->FormatType() != FORMAT_VideoInfo) {
DbgLog((LOG_TRACE,3,TEXT("Rejecting: format not VIDINFO")));
return E_INVALIDARG;
}
fccHandlerIn.SetFOURCC(pmtIn->Subtype());
if (fccHandlerIn != *pmtIn->Subtype()) {
DbgLog((LOG_TRACE,3,TEXT("Rejecting: subtype not a FOURCC")));
return E_INVALIDARG;
}
DbgLog((LOG_TRACE,3,TEXT("Checking fccType: %lx biCompression: %lx"),
fccHandlerIn.GetFOURCC(),
HEADER(pmtIn->Format())->biCompression));
// We are a decompressor only - reject anything uncompressed.
// Conversions between RGB types is done by COLOUR.DLL
if (HEADER(pmtIn->Format())->biCompression == BI_BITFIELDS ||
HEADER(pmtIn->Format())->biCompression == BI_RGB)
{
DbgLog((LOG_TRACE,3,TEXT("Rejecting: This is uncompressed already!")));
return E_INVALIDARG;
}
// look for a decompressor for this format
if (fccHandlerIn.GetFOURCC() != m_FourCCIn) {
DbgLog((LOG_TRACE,4,TEXT("opening a decompressor")));
// This won't find MSVC called CRAM or MRLE called 1
// hic = ICOpen(ICTYPE_VIDEO, fccHandlerIn.GetFOURCC(),
// ICMODE_DECOMPRESS);
// !!! This still won't find MRLE called 'RLE '
hic = ICLocate(ICTYPE_VIDEO, fccHandlerIn.GetFOURCC(),
HEADER(pmtIn->Format()), NULL, ICMODE_DECOMPRESS);
if (hic)
fOpenedHIC = TRUE;
} else {
DbgLog((LOG_TRACE,4,TEXT("using a cached decompressor")));
hic = m_hic;
}
if (!hic) {
DbgLog((LOG_ERROR,1,TEXT("Error: Can't open a decompressor")));
if (FCC('rpza') == fccHandlerIn.GetFOURCC()) {
return VFW_E_RPZA;
} else {
return VFW_E_NO_DECOMPRESSOR;
}
} else {
if (ICDecompressQuery(hic, HEADER(pmtIn->Format()), NULL)) {
DbgLog((LOG_ERROR,1,TEXT("Error: Decompressor rejected format")));
if (fOpenedHIC)
ICClose(hic);
return VFW_E_TYPE_NOT_ACCEPTED;
}
// IV41 crashes for Y41P -> RGB8. We have a native Indeo 4
// filter, so we could perhaps refuse IV41 altogether.
if(fccHandlerIn.GetFOURCC() == FCC('Y41P'))
{
ICINFO IcInfo;
if(ICGetInfo( hic, &IcInfo, sizeof( IcInfo ) ) != 0) {
if(IcInfo.fccHandler == FCC('IV41')) {
if(fOpenedHIC) {
ICClose(hic);
}
return VFW_E_TYPE_NOT_ACCEPTED;
}
}
}
// remember this hic to save time if asked again, if it won't
// interfere with an existing connection. If a connection is
// broken, we will remember the next hic.
if (!m_pInput->IsConnected()) {
DbgLog((LOG_TRACE,4,TEXT("caching this decompressor")));
if (fOpenedHIC && m_hic)
ICClose(m_hic);
#ifdef DEBUG
if( fOpenedHIC )
{
ICINFO IcInfo;
memset( &IcInfo, 0, sizeof( IcInfo ) );
IcInfo.dwSize = sizeof( IcInfo );
LRESULT lr = ICGetInfo( hic, &IcInfo, sizeof( IcInfo ) );
if( lr != 0 )
{
WCHAR wszOutput[512];
long len = 32; // could be only 5. I'm paranoid.
if( IcInfo.szDriver ) len += wcslen( IcInfo.szDriver );
if( IcInfo.szDescription ) len += wcslen( IcInfo.szDescription );
wcscpy( wszOutput, L"DEC:" );
if( IcInfo.szDriver )
{
WCHAR drive[_MAX_PATH];
WCHAR path[_MAX_PATH];
WCHAR file[_MAX_PATH];
WCHAR ext[_MAX_PATH];
_wsplitpath( IcInfo.szDriver, drive, path, file, ext );
wcscat( wszOutput, file );
wcscat( wszOutput, ext );
}
if( IcInfo.szDescription )
{
wcscat( wszOutput, L" (" );
wcscat( wszOutput, IcInfo.szDescription );
wcscat( wszOutput, L")" );
}
DbgLog((LOG_TRACE, 1, TEXT("%ls"), wszOutput));
}
}
#endif
m_hic = hic;
m_FourCCIn = fccHandlerIn.GetFOURCC();
} else if (fOpenedHIC) {
DbgLog((LOG_TRACE,4,TEXT("not caching decompressor - we're connected")));
ICClose(hic);
}
}
return NOERROR;
}
// check if you can support the transform from this input to this output
HRESULT CAVIDec::CheckTransform(const CMediaType* pmtIn,
const CMediaType* pmtOut)
{
HIC hic = NULL;
FOURCCMap fccIn;
FOURCCMap fccOut;
DWORD_PTR err;
BOOL fOpenedHIC = FALSE;
DbgLog((LOG_TRACE,3,TEXT("*::CheckTransform")));
if (pmtIn == NULL || pmtOut == NULL || pmtIn->Format() == NULL ||
pmtOut->Format() == NULL) {
DbgLog((LOG_TRACE,3,TEXT("Rejecting: type/format is NULL")));
return E_INVALIDARG;
}
// we can't convert between toplevel types.
if (*pmtIn->Type() != *pmtOut->Type()) {
DbgLog((LOG_TRACE,3,TEXT("Rejecting: types don't match")));
return E_INVALIDARG;
}
// and we only accept video
if (*pmtIn->Type() != MEDIATYPE_Video) {
DbgLog((LOG_TRACE,3,TEXT("Rejecting: type not VIDEO")));
return E_INVALIDARG;
}
// no ICM codecs can decompress to ARGB.
//
if( *pmtOut->Subtype( ) == MEDIASUBTYPE_ARGB32 )
{
return E_INVALIDARG;
}
// check this is a VIDEOINFOHEADER type
if (*pmtOut->FormatType() != FORMAT_VideoInfo) {
DbgLog((LOG_TRACE,3,TEXT("Rejecting: output format type not VIDINFO")));
return E_INVALIDARG;
}
if (*pmtIn->FormatType() != FORMAT_VideoInfo) {
DbgLog((LOG_TRACE,3,TEXT("Rejecting: input format type not VIDINFO")));
return E_INVALIDARG;
}
fccIn.SetFOURCC(pmtIn->Subtype());
if (fccIn != *pmtIn->Subtype()) {
DbgLog((LOG_TRACE,3,TEXT("Rejecting: input subtype not a FOURCC")));
return E_INVALIDARG;
}
ASSERT(pmtOut->Format());
// this stinks for slowness, but we've made a rule that whenever we talk
// to a codec with YUV, we're going to force biHeight to be -. This at least
// forces us to be consistent when talking to the ICM drivers
//
VIDEOINFOHEADER * pVIHin = (VIDEOINFOHEADER*) pmtIn->Format( );
VIDEOINFOHEADER * pVIHout = (VIDEOINFOHEADER*) pmtOut->Format( );
CMediaType cmtOutCopy(*pmtOut);
VIDEOINFOHEADER * pVIHoutCopy = (VIDEOINFOHEADER *)cmtOutCopy.Format();
BITMAPINFOHEADER &outBIHcopy = pVIHoutCopy->bmiHeader;
BITMAPINFOHEADER * pBIHout = &outBIHcopy;
BITMAPINFOHEADER * pBIHin = &pVIHin->bmiHeader;
if( ( outBIHcopy.biHeight > 0 ) && IsYUVType( pmtOut ) )
{
DbgLog((LOG_TRACE,3,TEXT(" checktransform flipping output biHeight to -, since YUV")));
outBIHcopy.biHeight *= -1;
}
// these rects should ALWAYS be filled in, since the commented out
// code below just copied, then filled in anyhow
//
RECT rcS, rcT;
GetSrcTargetRects( pVIHout, &rcS, &rcT );
DbgLog((LOG_TRACE,3,TEXT("Check fccIn: %lx biCompIn: %lx bitDepthIn: %d"),
fccIn.GetFOURCC(),
pBIHin->biCompression,
pBIHin->biBitCount));
DbgLog((LOG_TRACE,3,TEXT("biWidthIn: %ld biHeightIn: %ld biSizeIn: %ld"),
pBIHin->biWidth,
pBIHin->biHeight,
pBIHin->biSize));
DbgLog((LOG_TRACE,3,TEXT("fccOut: %lx biCompOut: %lx bitDepthOut: %d"),
fccOut.GetFOURCC(),
pBIHout->biCompression,
pBIHout->biBitCount));
DbgLog((LOG_TRACE,3,TEXT("biWidthOut: %ld biHeightOut: %ld"),
pBIHout->biWidth,
pBIHout->biHeight));
DbgLog((LOG_TRACE,3,TEXT("rcSrc: (%ld, %ld, %ld, %ld)"),
rcS.left, rcS.top, rcS.right, rcS.bottom));
DbgLog((LOG_TRACE,3,TEXT("rcDst: (%ld, %ld, %ld, %ld)"),
rcT.left, rcT.top, rcT.right, rcT.bottom));
// ehr: if the output pin exists, and is NOT connected, then reject
// transforms between matching media types. If the output pin is connected,
// then the video renderer might suggest going from YUV to YUV in mid-stride,
// which we should allow querying for
//
if( !m_fToRenderer && m_pOutput && !m_pOutput->IsConnected( ) )
{
if( HEADER( pVIHin )->biCompression == HEADER( pVIHout )->biCompression )
{
DbgLog((LOG_TRACE,3,TEXT("Rejecting: dec used as pass-thru, same compression formats")));
return E_INVALIDARG;
}
else if( IsYUVType( pmtIn ) && IsYUVType( pmtOut ) )
{
// also don't allow yuv to yuv conversions, to avoid endless connections to ourself
// for certain codecs that do uyvy to yuy2 conversions and back (since our merit is high)
DbgLog((LOG_TRACE,3,TEXT("Rejecting: dec used as yuv to yuv, which we don't allow")));
return E_INVALIDARG;
}
}
// find a codec for this transform
// I assume that we've already got a codec open
ASSERT(m_hic);
// the right codec better be open!
// When reconnecting, we'll get called with a new input, but same output,
// and better admit we can handle it
if (m_FourCCIn != fccIn.GetFOURCC()) {
DbgLog((LOG_TRACE,4,TEXT("Testing with a newly opened decompressor")));
hic = ICLocate(ICTYPE_VIDEO, fccIn.GetFOURCC(),
pBIHin, NULL, ICMODE_DECOMPRESS);
if (hic)
fOpenedHIC = TRUE;
} else {
// We already have the right codec open to try this transform
DbgLog((LOG_TRACE,4,TEXT("Testing with the cached decompressor")));
hic = m_hic;
}
if (!hic) {
DbgLog((LOG_ERROR,1,TEXT("Error: Can't find a decompressor")));
return E_FAIL;
}
// If we are being asked to do something funky, we have to use ICDecompressEx
// We need to call ShouldsUseEx here because m_bUseEx isn't in context, we're just
// calling ICDecompress(Ex?)Query
if( ShouldUseExFuncs( hic, pVIHin, pVIHout ) ) {
DbgLog((LOG_TRACE,4,TEXT("Trying this format with ICDecompressEx")));
err = ICDecompressExQuery(hic, 0, pBIHin, NULL,
rcS.left, rcS.top,
rcS.right - rcS.left,
rcS.bottom - rcS.top,
pBIHout, NULL,
rcT.left, rcT.top,
rcT.right - rcT.left,
rcT.bottom - rcT.top);
} else {
DbgLog((LOG_TRACE,4,TEXT("Trying this format with ICDecompress")));
err = ICDecompressQuery(hic, pBIHin, pBIHout);
}
// if we just opened it, close it.
if (fOpenedHIC)
ICClose(hic);
if (err != ICERR_OK) {
DbgLog((LOG_TRACE,3,TEXT("decompressor rejected this transform")));
return E_FAIL;
}
return NOERROR;
}
// overriden to know when the media type is actually set
HRESULT CAVIDec::SetMediaType(PIN_DIRECTION direction,const CMediaType *pmt)
{
FOURCCMap fccHandler;
if (direction == PINDIR_OUTPUT) {
// Please call me if this goes off. -DannyMi
ASSERT(!m_fStreaming);
// OK, we've finally decided on what codec to use. See if it
// supports temporal compression, but can't do it without needing
// the undisturbed previous bits. If so, then we need to use
// 1 read only buffer on our output pin (in DecideAllocator and
// DecideBufferSize)
ASSERT(m_hic);
ICINFO icinfo;
DWORD dw = ICGetInfo(m_hic, &icinfo, sizeof(icinfo));
m_fTemporal = TRUE; // better safe than sorry?
if (dw > 0) {
m_fTemporal = (icinfo.dwFlags & VIDCF_TEMPORAL) &&
!(icinfo.dwFlags & VIDCF_FASTTEMPORALD);
}
DbgLog((LOG_TRACE,3,TEXT("Temporal compressor=%d"), m_fTemporal));
DbgLog((LOG_TRACE,3,TEXT("***::SetMediaType (output)")));
DbgLog((LOG_TRACE,3,TEXT("Output type is: biComp=%lx biBitCount=%d"),
HEADER(OutputFormat())->biCompression,
HEADER(OutputFormat())->biBitCount));
return NOERROR;
}
ASSERT(direction == PINDIR_INPUT);
DbgLog((LOG_TRACE,3,TEXT("***::SetMediaType (input)")));
DbgLog((LOG_TRACE,3,TEXT("Input type is: biComp=%lx biBitCount=%d"),
HEADER(InputFormat())->biCompression,
HEADER(InputFormat())->biBitCount));
// Please call me if this goes off. -DannyMi
ASSERT(!m_fStreaming);
// We better have one of these opened by now
ASSERT(m_hic);
// We better have the RIGHT one open
FOURCCMap fccIn;
fccIn.SetFOURCC(pmt->Subtype());
// Please call me if this goes off. -DannyMi
// Maybe a dynamic input format change? But that shouldn't call
// SetMediaType, or it will force a reconnect of the output which is bad.
ASSERT(m_FourCCIn == fccIn.GetFOURCC());
// !!! BUG! We won't let somebody reconnect our input from cinepak to
// RLE if our output is 24 bit RGB because RLE can't decompress to 24 bit
// We would have to override CheckMediaType not to call CheckTransform
// with the current output type
if (m_pOutput && m_pOutput->IsConnected()) {
DbgLog((LOG_TRACE,2,TEXT("***Changing IN when OUT already connected")));
DbgLog((LOG_TRACE,2,TEXT("Reconnecting the output pin...")));
// This shouldn't fail, we're not changing the media type
m_pGraph->Reconnect(m_pOutput);
}
return NOERROR;
}
// Return our preferred output media types (in order)
// remember that we do not need to support all of these formats -
// if one is considered potentially suitable, our CheckTransform method
// will be called to check if it is acceptable right now.
// Remember that the enumerator calling this will stop enumeration as soon as
// it receives a S_FALSE return.
//
// NOTE: We can't enumerate the codecs so we are pulling random formats out
// of our butt!
HRESULT CAVIDec::GetMediaType(int iPosition,CMediaType *pmt)
{
LARGE_INTEGER li;
FOURCCMap fccHandler;
VIDEOINFOHEADER *pf;
DbgLog((LOG_TRACE,3,TEXT("*::GetMediaType #%d"), iPosition));
if (pmt == NULL) {
DbgLog((LOG_TRACE,3,TEXT("Media type is NULL, no can do")));
return E_INVALIDARG;
}
// Output choices depend on the input connected
if (!m_pInput->CurrentMediaType().IsValid()) {
DbgLog((LOG_TRACE,3,TEXT("No input type set yet, no can do")));
return E_FAIL;
}
if (iPosition < 0) {
return E_INVALIDARG;
}
// Caution: These are given out of order. be careful renumbering
// the case statements !!!
switch (iPosition) {
// Offer the compressor's favourite after all the YUV and RGB's we offer, so
// we don't end up always using 8 bit or 24 bit over YUV just cuz it's the
// compressor's favourite
// cinepak crashes on win95 and osr2
// // Offer CPLA (Cinepak's favourite and best looking)
// case 0:
// {
// DbgLog((LOG_TRACE,3,TEXT("Giving Media Type 0: CPLA")));
// *pmt = m_pInput->CurrentMediaType(); // gets width, height, etc.
// // only offer positive heights so downstream connections aren't confused
// HEADER(pmt->Format())->biHeight = ABS(HEADER(pmt->Format())->biHeight);
// // Can't error, can only be smaller
// pmt->ReallocFormatBuffer(SIZE_PREHEADER + sizeof(BITMAPINFOHEADER));
// LPBITMAPINFOHEADER lpbi = HEADER(pmt->Format());
// lpbi->biSize = sizeof(BITMAPINFOHEADER);
// lpbi->biCompression = MKFOURCC('C','P','L','A');
// lpbi->biBitCount = 12;
// lpbi->biClrUsed = 0;
// lpbi->biClrImportant = 0;
// lpbi->biSizeImage = DIBSIZE(*lpbi);
// pmt->SetSubtype(&MEDIASUBTYPE_CPLA);
// break;
// }
// offer CLJR (Cinepak and Cirrus Logic can do this)
case 0:
{
DbgLog((LOG_TRACE,3,TEXT("Giving Media Type 1: CLJR")));
*pmt = m_pInput->CurrentMediaType(); // gets width, height, etc.
// only offer positive heights so downstream connections aren't confused
HEADER(pmt->Format())->biHeight = ABS(HEADER(pmt->Format())->biHeight);
// Can't error, can only be smaller
pmt->ReallocFormatBuffer(SIZE_PREHEADER + sizeof(BITMAPINFOHEADER));
LPBITMAPINFOHEADER lpbi = HEADER(pmt->Format());
lpbi->biSize = sizeof(BITMAPINFOHEADER);
lpbi->biCompression = MKFOURCC('C','L','J','R');
lpbi->biBitCount = 8;
lpbi->biClrUsed = 0;
lpbi->biClrImportant = 0;
lpbi->biSizeImage = DIBSIZE(*lpbi);
pmt->SetSubtype(&MEDIASUBTYPE_CLJR);
break;
}
// offer UYVY (Cinepak can do this)
case 1:
{
DbgLog((LOG_TRACE,3,TEXT("Giving Media Type 3: UYVY")));
*pmt = m_pInput->CurrentMediaType(); // gets width, height, etc.
// only offer positive heights so downstream connections aren't confused
HEADER(pmt->Format())->biHeight = ABS(HEADER(pmt->Format())->biHeight);
// Can't error, can only be smaller
pmt->ReallocFormatBuffer(SIZE_PREHEADER + sizeof(BITMAPINFOHEADER));
LPBITMAPINFOHEADER lpbi = HEADER(pmt->Format());
lpbi->biSize = sizeof(BITMAPINFOHEADER);
lpbi->biCompression = MKFOURCC('U','Y','V','Y');
lpbi->biBitCount = 16;
lpbi->biClrUsed = 0;
lpbi->biClrImportant = 0;
lpbi->biSizeImage = DIBSIZE(*lpbi);
pmt->SetSubtype(&MEDIASUBTYPE_UYVY);
break;
}
// offer YUY2 (Cinepak can do this)
case 2:
{
DbgLog((LOG_TRACE,3,TEXT("Giving Media Type 4: YUY2")));
*pmt = m_pInput->CurrentMediaType(); // gets width, height, etc.
// only offer positive heights so downstream connections aren't confused
HEADER(pmt->Format())->biHeight = ABS(HEADER(pmt->Format())->biHeight);
// Can't error, can only be smaller
pmt->ReallocFormatBuffer(SIZE_PREHEADER + sizeof(BITMAPINFOHEADER));
LPBITMAPINFOHEADER lpbi = HEADER(pmt->Format());
lpbi->biSize = sizeof(BITMAPINFOHEADER);
lpbi->biCompression = MKFOURCC('Y','U','Y','2');
lpbi->biBitCount = 16;
lpbi->biClrUsed = 0;
lpbi->biClrImportant = 0;
lpbi->biSizeImage = DIBSIZE(*lpbi);
pmt->SetSubtype(&MEDIASUBTYPE_YUY2);
break;
}
// Offer 32 bpp RGB
case 3:
{
DbgLog((LOG_TRACE,3,TEXT("Giving Media Type 5: 32 bit RGB")));
*pmt = m_pInput->CurrentMediaType(); // gets width, height, etc.
// only offer positive heights so downstream connections aren't confused
HEADER(pmt->Format())->biHeight = ABS(HEADER(pmt->Format())->biHeight);
// Can't error, can only be smaller
pmt->ReallocFormatBuffer(SIZE_PREHEADER + sizeof(BITMAPINFOHEADER));
LPBITMAPINFOHEADER lpbi = HEADER(pmt->Format());
lpbi->biSize = sizeof(BITMAPINFOHEADER);
lpbi->biCompression = BI_RGB;
lpbi->biBitCount = 32;
lpbi->biClrUsed = 0;
lpbi->biClrImportant = 0;
lpbi->biSizeImage = DIBSIZE(*lpbi);
pmt->SetSubtype(&MEDIASUBTYPE_RGB32);
break;
}
// Offer 24 bpp RGB
case 4:
{
DbgLog((LOG_TRACE,3,TEXT("Giving Media Type 6: 24 bit RGB")));
*pmt = m_pInput->CurrentMediaType(); // gets width, height, etc.
// only offer positive heights so downstream connections aren't confused
HEADER(pmt->Format())->biHeight = ABS(HEADER(pmt->Format())->biHeight);
// Can't error, can only be smaller
pmt->ReallocFormatBuffer(SIZE_PREHEADER + sizeof(BITMAPINFOHEADER));
LPBITMAPINFOHEADER lpbi = HEADER(pmt->Format());
lpbi->biSize = sizeof(BITMAPINFOHEADER);
lpbi->biCompression = BI_RGB;
lpbi->biBitCount = 24;
lpbi->biClrUsed = 0;
lpbi->biClrImportant = 0;
lpbi->biSizeImage = DIBSIZE(*lpbi);
pmt->SetSubtype(&MEDIASUBTYPE_RGB24);
break;
}
// Offer 16 bpp RGB 565 before 555
case 5:
{
DbgLog((LOG_TRACE,3,TEXT("Giving Media Type 7: 565 RGB")));
*pmt = m_pInput->CurrentMediaType(); // gets width, height, etc.
// only offer positive heights so downstream connections aren't confused
HEADER(pmt->Format())->biHeight = ABS(HEADER(pmt->Format())->biHeight);
if (pmt->ReallocFormatBuffer(SIZE_PREHEADER + sizeof(BITMAPINFOHEADER) +
SIZE_MASKS) == NULL) {
DbgLog((LOG_ERROR,1,TEXT("Out of memory reallocating format")));
return E_OUTOFMEMORY;
}
// update the RGB 565 bit field masks
LPBITMAPINFOHEADER lpbi = HEADER(pmt->Format());
lpbi->biSize = sizeof(BITMAPINFOHEADER);
lpbi->biCompression = BI_BITFIELDS;
lpbi->biBitCount = 16;
lpbi->biClrUsed = 0;
lpbi->biClrImportant = 0;
lpbi->biSizeImage = DIBSIZE(*lpbi);
DWORD *pdw = (DWORD *) (lpbi+1);
pdw[iRED] = bits565[iRED];
pdw[iGREEN] = bits565[iGREEN];
pdw[iBLUE] = bits565[iBLUE];
pmt->SetSubtype(&MEDIASUBTYPE_RGB565);
break;
}
// Offer 16 bpp RGB 555
case 6:
{
DbgLog((LOG_TRACE,3,TEXT("Giving Media Type 8: 555 RGB")));
*pmt = m_pInput->CurrentMediaType(); // gets width, height, etc.
// only offer positive heights so downstream connections aren't confused
HEADER(pmt->Format())->biHeight = ABS(HEADER(pmt->Format())->biHeight);
// Can't error, can only be smaller
pmt->ReallocFormatBuffer(SIZE_PREHEADER + sizeof(BITMAPINFOHEADER));
LPBITMAPINFOHEADER lpbi = HEADER(pmt->Format());
lpbi->biSize = sizeof(BITMAPINFOHEADER);
lpbi->biCompression = BI_RGB;
lpbi->biBitCount = 16;
lpbi->biClrUsed = 0;
lpbi->biClrImportant = 0;
lpbi->biSizeImage = DIBSIZE(*lpbi);
pmt->SetSubtype(&MEDIASUBTYPE_RGB555);
break;
}
// Offer 8 bpp palettised
case 7:
{
DbgLog((LOG_TRACE,3,TEXT("Giving Media Type 9: 8 bit RGB")));
*pmt = m_pInput->CurrentMediaType(); // gets width, height, etc.
// only offer positive heights so downstream connections aren't confused
HEADER(pmt->Format())->biHeight = ABS(HEADER(pmt->Format())->biHeight);
if (pmt->ReallocFormatBuffer(SIZE_PREHEADER +
sizeof(BITMAPINFOHEADER) + SIZE_PALETTE) == NULL) {
DbgLog((LOG_ERROR,1,TEXT("Out of memory reallocating format")));
return E_OUTOFMEMORY;
}
LPBITMAPINFOHEADER lpbi = HEADER(pmt->Format());
lpbi->biSize = sizeof(BITMAPINFOHEADER);
lpbi->biCompression = BI_RGB;
lpbi->biBitCount = 8;
lpbi->biSizeImage = DIBSIZE(*lpbi);
// we need the source VIDEOINFOHEADER type to get any palette from and
// also the number of bytes size it allocated. We copy the palette
// from the input format in case the codec can't deliver it to us
VIDEOINFOHEADER *pSourceInfo = InputFormat();
int nBitDepth = pSourceInfo->bmiHeader.biBitCount;
int nColours = pSourceInfo->bmiHeader.biClrUsed;
if (nColours == 0 && nBitDepth <=8)
nColours = 1 << nBitDepth;
// if there is a palette present then copy the maximum number of bytes
// available which is bounded by the memory we previously allocated
if (nColours > 0) {
CopyMemory((PVOID)(lpbi + 1),
(PVOID) COLORS(pSourceInfo),
min(SIZE_PALETTE,nColours * sizeof(RGBQUAD)));
lpbi->biClrUsed = nColours;
lpbi->biClrImportant = 0;
} else {
// I DON'T KNOW WHY somebody thought this was necessary, but might
// as well keep it, just in case. ONLY DO IT if the source guy
// didn't have a palette, or we'll zero out system colours
// by mistake. - DannyMi 5/97
// this is really painful, if we are running on a true colour
// display we still want the codec to give us the correct palette
// colours, but some of them return garbage for the VGA colours so
// if we are on a device which isn't palettised then we zero fill
// the twenty VGA entries - some british guy 5/95
HDC hdc = GetDC(NULL);
BOOL fPalette = FALSE;
if (hdc) {
fPalette = GetDeviceCaps(hdc, RASTERCAPS) & RC_PALETTE;
ReleaseDC(NULL,hdc);
}
if (!fPalette) {
ZeroMemory((lpbi + 1),10 * sizeof(RGBQUAD));
ZeroMemory((LPBYTE)(lpbi + 1) + 246 * sizeof(RGBQUAD),
10 * sizeof(RGBQUAD));
}
}
// Read palette from codec - will write palette to output lpbi
// ignore any error: the palette used will be from the source
// in that case (which we have already copied)
ICDecompressGetPalette(m_hic, HEADER(pSourceInfo), lpbi);
pmt->SetSubtype(&MEDIASUBTYPE_RGB8);
break;
}
#ifdef OFFER_NEGATIVE_HEIGHTS
// offer CLJR (Cinepak and Cirrus Logic can do this)
case 8:
{
DbgLog((LOG_TRACE,3,TEXT("Giving Media Type 1: CLJR")));
*pmt = m_pInput->CurrentMediaType(); // gets width, height, etc.
// now offer negative type
HEADER(pmt->Format())->biHeight = -ABS(HEADER(pmt->Format())->biHeight);
// Can't error, can only be smaller
pmt->ReallocFormatBuffer(SIZE_PREHEADER + sizeof(BITMAPINFOHEADER));
LPBITMAPINFOHEADER lpbi = HEADER(pmt->Format());
lpbi->biSize = sizeof(BITMAPINFOHEADER);
lpbi->biCompression = MKFOURCC('C','L','J','R');
lpbi->biBitCount = 8;
lpbi->biClrUsed = 0;
lpbi->biClrImportant = 0;
lpbi->biSizeImage = DIBSIZE(*lpbi);
lpbi->biHeight = -abs( lpbi->biHeight );
pmt->SetSubtype(&MEDIASUBTYPE_CLJR);
break;
}
// offer UYVY (Cinepak can do this)
case 9:
{
DbgLog((LOG_TRACE,3,TEXT("Giving Media Type 3: UYVY")));
*pmt = m_pInput->CurrentMediaType(); // gets width, height, etc.
// now offer negative type
HEADER(pmt->Format())->biHeight = -ABS(HEADER(pmt->Format())->biHeight);
// Can't error, can only be smaller
pmt->ReallocFormatBuffer(SIZE_PREHEADER + sizeof(BITMAPINFOHEADER));
LPBITMAPINFOHEADER lpbi = HEADER(pmt->Format());
lpbi->biSize = sizeof(BITMAPINFOHEADER);
lpbi->biCompression = MKFOURCC('U','Y','V','Y');
lpbi->biBitCount = 16;
lpbi->biClrUsed = 0;
lpbi->biClrImportant = 0;
lpbi->biSizeImage = DIBSIZE(*lpbi);
lpbi->biHeight = -abs( lpbi->biHeight );
pmt->SetSubtype(&MEDIASUBTYPE_UYVY);
break;
}
// offer YUY2 (Cinepak can do this)
case 10:
{
DbgLog((LOG_TRACE,3,TEXT("Giving Media Type 4: YUY2")));
*pmt = m_pInput->CurrentMediaType(); // gets width, height, etc.
// now offer negative type
HEADER(pmt->Format())->biHeight = -ABS(HEADER(pmt->Format())->biHeight);
// Can't error, can only be smaller
pmt->ReallocFormatBuffer(SIZE_PREHEADER + sizeof(BITMAPINFOHEADER));
LPBITMAPINFOHEADER lpbi = HEADER(pmt->Format());
lpbi->biSize = sizeof(BITMAPINFOHEADER);
lpbi->biCompression = MKFOURCC('Y','U','Y','2');
lpbi->biBitCount = 16;
lpbi->biClrUsed = 0;
lpbi->biClrImportant = 0;
lpbi->biSizeImage = DIBSIZE(*lpbi);
lpbi->biHeight = -abs( lpbi->biHeight );
pmt->SetSubtype(&MEDIASUBTYPE_YUY2);
break;
}
// Offer 32 bpp RGB
case 11:
{
DbgLog((LOG_TRACE,3,TEXT("Giving Media Type 5: 32 bit RGB")));
*pmt = m_pInput->CurrentMediaType(); // gets width, height, etc.
// now offer negative type
HEADER(pmt->Format())->biHeight = -ABS(HEADER(pmt->Format())->biHeight);
// Can't error, can only be smaller
pmt->ReallocFormatBuffer(SIZE_PREHEADER + sizeof(BITMAPINFOHEADER));
LPBITMAPINFOHEADER lpbi = HEADER(pmt->Format());
lpbi->biSize = sizeof(BITMAPINFOHEADER);
lpbi->biCompression = BI_RGB;
lpbi->biBitCount = 32;
lpbi->biClrUsed = 0;
lpbi->biClrImportant = 0;
lpbi->biSizeImage = DIBSIZE(*lpbi);
lpbi->biHeight = -abs( lpbi->biHeight );
pmt->SetSubtype(&MEDIASUBTYPE_RGB32);
break;
}
// Offer 24 bpp RGB
case 12:
{
DbgLog((LOG_TRACE,3,TEXT("Giving Media Type 6: 24 bit RGB")));
*pmt = m_pInput->CurrentMediaType(); // gets width, height, etc.
// now offer negative type
HEADER(pmt->Format())->biHeight = -ABS(HEADER(pmt->Format())->biHeight);
// Can't error, can only be smaller
pmt->ReallocFormatBuffer(SIZE_PREHEADER + sizeof(BITMAPINFOHEADER));
LPBITMAPINFOHEADER lpbi = HEADER(pmt->Format());
lpbi->biSize = sizeof(BITMAPINFOHEADER);
lpbi->biCompression = BI_RGB;
lpbi->biBitCount = 24;
lpbi->biClrUsed = 0;
lpbi->biClrImportant = 0;
lpbi->biSizeImage = DIBSIZE(*lpbi);
lpbi->biHeight = -abs( lpbi->biHeight );
pmt->SetSubtype(&MEDIASUBTYPE_RGB24);
break;
}
// Offer 16 bpp RGB 565 before 555
case 13:
{
DbgLog((LOG_TRACE,3,TEXT("Giving Media Type 7: 565 RGB")));
*pmt = m_pInput->CurrentMediaType(); // gets width, height, etc.
// now offer negative type
HEADER(pmt->Format())->biHeight = -ABS(HEADER(pmt->Format())->biHeight);
if (pmt->ReallocFormatBuffer(SIZE_PREHEADER + sizeof(BITMAPINFOHEADER) +
SIZE_MASKS) == NULL) {
DbgLog((LOG_ERROR,1,TEXT("Out of memory reallocating format")));
return E_OUTOFMEMORY;
}
// update the RGB 565 bit field masks
LPBITMAPINFOHEADER lpbi = HEADER(pmt->Format());
lpbi->biSize = sizeof(BITMAPINFOHEADER);
lpbi->biCompression = BI_BITFIELDS;
lpbi->biBitCount = 16;
lpbi->biClrUsed = 0;
lpbi->biClrImportant = 0;
lpbi->biSizeImage = DIBSIZE(*lpbi);
lpbi->biHeight = -abs( lpbi->biHeight );
DWORD *pdw = (DWORD *) (lpbi+1);
pdw[iRED] = bits565[iRED];
pdw[iGREEN] = bits565[iGREEN];
pdw[iBLUE] = bits565[iBLUE];
pmt->SetSubtype(&MEDIASUBTYPE_RGB565);
break;
}
// Offer 16 bpp RGB 555
case 14:
{
DbgLog((LOG_TRACE,3,TEXT("Giving Media Type 8: 555 RGB")));
*pmt = m_pInput->CurrentMediaType(); // gets width, height, etc.
// now offer negative type
HEADER(pmt->Format())->biHeight = -ABS(HEADER(pmt->Format())->biHeight);
// Can't error, can only be smaller
pmt->ReallocFormatBuffer(SIZE_PREHEADER + sizeof(BITMAPINFOHEADER));
LPBITMAPINFOHEADER lpbi = HEADER(pmt->Format());
lpbi->biSize = sizeof(BITMAPINFOHEADER);
lpbi->biCompression = BI_RGB;
lpbi->biBitCount = 16;
lpbi->biClrUsed = 0;
lpbi->biClrImportant = 0;
lpbi->biSizeImage = DIBSIZE(*lpbi);
lpbi->biHeight = -abs( lpbi->biHeight );
pmt->SetSubtype(&MEDIASUBTYPE_RGB555);
break;
}
// Offer 8 bpp palettised
case 15:
{
DbgLog((LOG_TRACE,3,TEXT("Giving Media Type 9: 8 bit RGB")));
*pmt = m_pInput->CurrentMediaType(); // gets width, height, etc.
// now offer negative type
HEADER(pmt->Format())->biHeight = -ABS(HEADER(pmt->Format())->biHeight);
if (pmt->ReallocFormatBuffer(SIZE_PREHEADER +
sizeof(BITMAPINFOHEADER) + SIZE_PALETTE) == NULL) {
DbgLog((LOG_ERROR,1,TEXT("Out of memory reallocating format")));
return E_OUTOFMEMORY;
}
LPBITMAPINFOHEADER lpbi = HEADER(pmt->Format());
lpbi->biSize = sizeof(BITMAPINFOHEADER);
lpbi->biCompression = BI_RGB;
lpbi->biBitCount = 8;
lpbi->biSizeImage = DIBSIZE(*lpbi);
lpbi->biHeight = -abs( lpbi->biHeight );
// we need the source VIDEOINFOHEADER type to get any palette from and
// also the number of bytes size it allocated. We copy the palette
// from the input format in case the codec can't deliver it to us
VIDEOINFOHEADER *pSourceInfo = InputFormat();
int nBitDepth = pSourceInfo->bmiHeader.biBitCount;
int nColours = pSourceInfo->bmiHeader.biClrUsed;
if (nColours == 0 && nBitDepth <=8)
nColours = 1 << nBitDepth;
// if there is a palette present then copy the maximum number of bytes
// available which is bounded by the memory we previously allocated
if (nColours > 0) {
CopyMemory((PVOID)(lpbi + 1),
(PVOID) COLORS(pSourceInfo),
min(SIZE_PALETTE,nColours * sizeof(RGBQUAD)));
lpbi->biClrUsed = nColours;
lpbi->biClrImportant = 0;
} else {
// I DON'T KNOW WHY somebody thought this was necessary, but might
// as well keep it, just in case. ONLY DO IT if the source guy
// didn't have a palette, or we'll zero out system colours
// by mistake. - DannyMi 5/97
// this is really painful, if we are running on a true colour
// display we still want the codec to give us the correct palette
// colours, but some of them return garbage for the VGA colours so
// if we are on a device which isn't palettised then we zero fill
// the twenty VGA entries - some british guy 5/95
HDC hdc = GetDC(NULL);
BOOL fPalette = FALSE;
if (hdc) {
fPalette = GetDeviceCaps(hdc, RASTERCAPS) & RC_PALETTE;
ReleaseDC(NULL,hdc);
}
if (!fPalette) {
ZeroMemory((lpbi + 1),10 * sizeof(RGBQUAD));
ZeroMemory((LPBYTE)(lpbi + 1) + 246 * sizeof(RGBQUAD),
10 * sizeof(RGBQUAD));
}
}
// Read palette from codec - will write palette to output lpbi
// ignore any error: the palette used will be from the source
// in that case (which we have already copied)
ICDecompressGetPalette(m_hic, HEADER(pSourceInfo), lpbi);
pmt->SetSubtype(&MEDIASUBTYPE_RGB8);
break;
}
// !!! This comes last because it might fail, and stop enumerating
case 16:
#else
case 8:
#endif
{
DbgLog((LOG_TRACE,3,TEXT("Giving Last Media Type: default codec out")));
// ask the codec to recommend an output format size and add on the
// space required by the extra members in the VIDEOINFOHEADER structure
ULONG cb = ICDecompressGetFormatSize(m_hic,
HEADER(InputFormat()));
if (cb <= 0) {
DbgLog((LOG_ERROR,1,TEXT("Error %d in ICDecompressGetFormatSize"),
cb));
return E_FAIL;
}
// allocate a VIDEOINFOHEADER for the default output format
cb += SIZE_PREHEADER;
pf = (VIDEOINFOHEADER *)pmt->AllocFormatBuffer(cb);
if (pf == NULL) {
DbgLog((LOG_ERROR,1,TEXT("Error allocating format buffer")));
return E_OUTOFMEMORY;
}
RESET_HEADER(pf);
DWORD dwerr = ICDecompressGetFormat(m_hic,
HEADER(InputFormat()),
HEADER(pmt->Format()));
if (ICERR_OK != dwerr) {
DbgLog((LOG_ERROR,1,TEXT("Error from ICDecompressGetFormat")));
return E_FAIL;
}
DbgLog((LOG_TRACE,3,TEXT("biComp: %x biBitCount: %d"),
HEADER(pmt->Format())->biCompression,
HEADER(pmt->Format())->biBitCount));
const GUID SubTypeGUID = GetBitmapSubtype(HEADER(pmt->Format()));
pmt->SetSubtype(&SubTypeGUID);
break;
}
default:
return VFW_S_NO_MORE_ITEMS;
}
// now set the common things about the media type
pf = (VIDEOINFOHEADER *)pmt->Format();
pf->AvgTimePerFrame = InputFormat( )->AvgTimePerFrame;
li.QuadPart = pf->AvgTimePerFrame;
if (li.LowPart)
pf->dwBitRate = MulDiv(pf->bmiHeader.biSizeImage, 80000000, li.LowPart);
pf->dwBitErrorRate = 0L;
pmt->SetType(&MEDIATYPE_Video);
pmt->SetSampleSize(pf->bmiHeader.biSizeImage);
pmt->SetFormatType(&FORMAT_VideoInfo);
pmt->SetTemporalCompression(FALSE);
return NOERROR;
}
HRESULT CAVIDec::CheckConnect(PIN_DIRECTION dir,IPin *pPin)
{
m_fToRenderer = false;
if(dir == PINDIR_OUTPUT)
{
PIN_INFO pi;
HRESULT hr = pPin->QueryPinInfo(&pi);
if(hr == S_OK && pi.pFilter) {
CLSID clsid;
if(pi.pFilter->GetClassID(&clsid) == S_OK &&
clsid == CLSID_VideoMixingRenderer) {
m_fToRenderer = true;
}
pi.pFilter->Release();
}
}
return CVideoTransformFilter::CheckConnect(dir, pPin);
}
HRESULT CAVIDec::BreakConnect(PIN_DIRECTION dir)
{
// probably no need to reset because we will always set before
// checking this variable
m_fToRenderer = false;
return CVideoTransformFilter::BreakConnect(dir);
}
// overridden to create a CDecOutputPin
// !!! base class changes won't get picked up by me
//
CBasePin * CAVIDec::GetPin(int n)
{
HRESULT hr = S_OK;
// Create an input pin if necessary
if (m_pInput == NULL) {
m_pInput = new CTransformInputPin(NAME("Transform input pin"),
this, // Owner filter
&hr, // Result code
L"XForm In"); // Pin name
// Can't fail
ASSERT(SUCCEEDED(hr));
if (m_pInput == NULL) {
return NULL;
}
m_pOutput = (CTransformOutputPin *)
new CDecOutputPin(NAME("Transform output pin"),
this, // Owner filter
&hr, // Result code
L"XForm Out"); // Pin name
// Can't fail
ASSERT(SUCCEEDED(hr));
if (m_pOutput == NULL) {
delete m_pInput;
m_pInput = NULL;
}
}
// Return the appropriate pin
if (n == 0) {
return m_pInput;
} else
if (n == 1) {
return m_pOutput;
} else {
return NULL;
}
}
// overridden to properly mark buffers read only or not in NotifyAllocator
// !!! base class changes won't get picked up by me
//
HRESULT CDecOutputPin::DecideAllocator(IMemInputPin *pPin, IMemAllocator **ppAlloc)
{
HRESULT hr = NOERROR;
*ppAlloc = NULL;
// get downstream prop request
// the derived class may modify this in DecideBufferSize, but
// we assume that he will consistently modify it the same way,
// so we only get it once
ALLOCATOR_PROPERTIES prop;
ZeroMemory(&prop, sizeof(prop));
// whatever he returns, we assume prop is either all zeros
// or he has filled it out.
pPin->GetAllocatorRequirements(&prop);
// if he doesn't care about alignment, then set it to 1
if (prop.cbAlign == 0) {
prop.cbAlign = 1;
}
/* Try the allocator provided by the input pin */
hr = pPin->GetAllocator(ppAlloc);
if (SUCCEEDED(hr)) {
hr = DecideBufferSize(*ppAlloc, &prop);
if (SUCCEEDED(hr)) {
// temporal compression ==> read only buffers
hr = pPin->NotifyAllocator(*ppAlloc,
((CAVIDec *)m_pFilter)->m_fTemporal);
if (SUCCEEDED(hr)) {
return NOERROR;
}
}
}
/* If the GetAllocator failed we may not have an interface */
if (*ppAlloc) {
(*ppAlloc)->Release();
*ppAlloc = NULL;
}
/* Try the output pin's allocator by the same method */
hr = InitAllocator(ppAlloc);
if (SUCCEEDED(hr)) {
// note - the properties passed here are in the same
// structure as above and may have been modified by
// the previous call to DecideBufferSize
hr = DecideBufferSize(*ppAlloc, &prop);
if (SUCCEEDED(hr)) {
// temporal compression ==> read only buffers
hr = pPin->NotifyAllocator(*ppAlloc,
((CAVIDec *)m_pFilter)->m_fTemporal);
if (SUCCEEDED(hr)) {
return NOERROR;
}
}
}
/* Likewise we may not have an interface to release */
if (*ppAlloc) {
(*ppAlloc)->Release();
*ppAlloc = NULL;
}
return hr;
}
// called from CBaseOutputPin to prepare the allocator's count
// of buffers and sizes
HRESULT CAVIDec::DecideBufferSize(IMemAllocator * pAllocator,
ALLOCATOR_PROPERTIES *pProperties)
{
// David assures me this won't be called with NULL output mt.
ASSERT(m_pOutput->CurrentMediaType().IsValid());
ASSERT(pAllocator);
ASSERT(pProperties);
ASSERT(m_hic);
// If we are doing temporal compression where we need the undisturbed
// previous bits, we insist on 1 buffer (also our default)
if (m_fTemporal || pProperties->cBuffers == 0)
pProperties->cBuffers = 1;
// set the size of buffers based on the expected output frame size
pProperties->cbBuffer = m_pOutput->CurrentMediaType().GetSampleSize();
ASSERT(pProperties->cbBuffer);
ALLOCATOR_PROPERTIES Actual;
HRESULT hr = pAllocator->SetProperties(pProperties,&Actual);
if (FAILED(hr)) {
DbgLog((LOG_ERROR,1,TEXT("Error in SetProperties")));
return hr;
}
if (Actual.cbBuffer < pProperties->cbBuffer) {
// can't use this allocator
DbgLog((LOG_ERROR,1,TEXT("Can't use allocator - buffer too small")));
return E_INVALIDARG;
}
// For temporal compressors, we MUST get exactly one buffer, since we assume
// that the previous decompressed frame is already present in the output
// buffer. The alternative is to copy the bits from a saved location before
// doing the decompression, but that is not nice.
if (m_fTemporal && Actual.cBuffers != 1) {
// can't use this allocator
DbgLog((LOG_ERROR,1,TEXT("Can't use allocator - need exactly 1 buffer")));
return E_INVALIDARG;
}
DbgLog((LOG_TRACE,2,TEXT("Using %d buffers of size %d"),
Actual.cBuffers, Actual.cbBuffer));
// It happens - connect me to the mux. I don't care
//ASSERT(Actual.cbAlign == 1);
//ASSERT(Actual.cbPrefix == 0);
//DbgLog((LOG_TRACE,1,TEXT("Buffer Align=%d Prefix=%d"), Actual.cbAlign, Actual.cbPrefix));
return S_OK;
}
#include "..\..\..\filters\asf\wmsdk\inc\wmsdk.h"
HRESULT CAVIDec::StartStreaming()
{
DWORD_PTR err;
DbgLog((LOG_TRACE,2,TEXT("*::StartStreaming")));
// first copy the media type to our internal one. Type changes on the output pin
// will cause this to update, which is good.
//
m_mtFixedOut = m_pOutput->CurrentMediaType( );
// see if we need to fix up biHeight on m_mtFixedOut if we output YUV
// this will change m_mtFixedOut's biHeight if necessary
//
CheckNegBiHeight( );
VIDEOINFOHEADER * pVIHout = IntOutputFormat( ); // internal
VIDEOINFOHEADER * pVIHin = InputFormat( );
LPBITMAPINFOHEADER lpbiSrc = HEADER(pVIHin);
LPBITMAPINFOHEADER lpbiDst = HEADER(pVIHout);
if (!m_fStreaming) {
if (lpbiSrc->biCompression == 0x3334504d && m_pGraph) { // !!! MP43
IObjectWithSite *pSite;
HRESULT hrKey = m_pGraph->QueryInterface(IID_IObjectWithSite, (VOID **)&pSite);
if (SUCCEEDED(hrKey)) {
IServiceProvider *pSP;
hrKey = pSite->GetSite(IID_IServiceProvider, (VOID **)&pSP);
pSite->Release();
if (SUCCEEDED(hrKey)) {
IUnknown *pKey;
hrKey = pSP->QueryService(__uuidof(IWMReader), IID_IUnknown, (void **) &pKey);
pSP->Release();
if (SUCCEEDED(hrKey)) {
// !!! verify key?
pKey->Release();
DbgLog((LOG_TRACE, 1, "Dec: Unlocking MP43 codec"));
//
// Use GetState() to set the key into a particular
// instance of the codec. While it looks odd
// to be using ICGetState to set values, it is correct!
//
DWORD dwSize = ICGetStateSize( m_hic );
if( dwSize <= 256 )
{
CHAR rgcBuf[256];
MSVIDUNLOCKKEY *pks;
pks = (MSVIDUNLOCKKEY *)rgcBuf;
pks->dwVersion = MSMP43KEY_VERSION;
pks->guidKey = __uuidof( MSMP43KEY_V1 );
ICGetState( m_hic, rgcBuf, dwSize );
} else {
ASSERT(0);
}
}
}
}
}
// indeo codec (V4.11.15.60) crashes in ICDecompressBegin with
// the 2.0 runtime because of this call
// cinepak blows up thinking CLJR is palettised, too
if (lpbiSrc->biCompression != FCC('IV41') &&
lpbiDst->biCompression != FCC('CLJR')) {
ICDecompressSetPalette(m_hic, lpbiDst);
}
// start off with it being false
//
m_bUseEx = FALSE;
// Start Streaming Decompression - if we're doing something funky, use
// ICDecompressEx
// find out if we can set m_bUseEx by calling ShoudUseEx...
if( ShouldUseExFuncs( m_hic, pVIHin, pVIHout ) ) {
// these rects should ALWAYS be filled in
//
RECT rcS, rcT;
GetSrcTargetRects( pVIHout, &rcS, &rcT );
// set it here now that we've called DecompressExBegin
//
m_bUseEx = TRUE;
DbgLog((LOG_TRACE,3,TEXT("Calling ICDecompressExBegin")));
err = ICDecompressExBegin(m_hic, 0,
lpbiSrc, NULL,
rcS.left, rcS.top,
rcS.right - rcS.left,
rcS.bottom - rcS.top,
lpbiDst, NULL,
rcT.left,
// !!! What about when the big rect is the movie size, and there's a subrect?
// Should I do this hack or not?
// !!! How should I munge the source rect?
(lpbiDst->biHeight > 0) ? rcT.top :
(ABS(lpbiDst->biHeight) - rcT.bottom),
rcT.right - rcT.left,
rcT.bottom - rcT.top);
} else {
DbgLog((LOG_TRACE,3,TEXT("Calling ICDecompressBegin")));
err = ICDecompressBegin(m_hic, lpbiSrc, lpbiDst);
if( err != ICERR_OK )
{
DbgLog((LOG_TRACE,2,TEXT("ICDecompressBegin failed")));
// something went wrong. If the heighth was -,
// then we'll try again with a + height
//
if( lpbiDst->biHeight < 0 )
{
DbgLog((LOG_TRACE,2,TEXT("trying ICDecompressBegin with flipped biHeight")));
lpbiDst->biHeight = abs( lpbiDst->biHeight );
LRESULT err2 = 0;
err2 = ICDecompressBegin(m_hic, lpbiSrc, lpbiDst);
if( err2 == ICERR_OK )
{
DbgLog((LOG_TRACE,2,TEXT("that worked!")));
int erudolphsezcallmeifthisgoesoff = 0;
ASSERT( erudolphsezcallmeifthisgoesoff );
err = err2;
}
else
{
DbgLog((LOG_TRACE,2,TEXT("didn't work, so we'll fail")));
// put it back to - so we don't confuse anybody
//
lpbiDst->biHeight = -lpbiDst->biHeight;
}
}
}
}
if (ICERR_OK == err) {
m_fStreaming = TRUE;
#ifdef _X86_
// Create our exception handler heap
ASSERT(m_hhpShared == NULL);
if (g_osInfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
m_hhpShared = CreateFileMapping(INVALID_HANDLE_VALUE,
NULL,
PAGE_READWRITE,
0,
20,
NULL);
if (m_hhpShared) {
m_pvShared = MapViewOfFile(m_hhpShared,
FILE_MAP_WRITE,
0,
0,
20);
if (m_pvShared == NULL) {
EXECUTE_ASSERT(CloseHandle(m_hhpShared));
m_hhpShared = NULL;
} else {
DbgLog((LOG_TRACE, 1, TEXT("Shared memory at %8.8X"),
m_pvShared));
}
}
}
#endif // _X86_
} else {
DbgLog((LOG_ERROR,1,TEXT("Error %d in ICDecompress(Ex)Begin"),err));
return E_FAIL;
}
} // if !m_fStreaming
return CVideoTransformFilter::StartStreaming();
}
HRESULT CAVIDec::StopStreaming()
{
DbgLog((LOG_TRACE,2,TEXT("*::StopStreaming")));
if (m_fStreaming) {
ASSERT(m_hic);
// Stop whichever one was started, m_bUseEx tells us which
if( m_bUseEx ) {
ICDecompressExEnd(m_hic);
} else {
ICDecompressEnd(m_hic);
}
m_fStreaming = FALSE;
#ifdef _X86_
if (m_hhpShared) {
EXECUTE_ASSERT(UnmapViewOfFile(m_pvShared));
EXECUTE_ASSERT(CloseHandle(m_hhpShared));;
m_hhpShared = NULL;
}
#endif // _X86_
}
return NOERROR;
}
// We're now streaming - tell the codec to hurry up from now on
STDMETHODIMP CAVIDec::Run(REFERENCE_TIME tStart)
{
if (m_State == State_Paused && m_hic) {
DbgLog((LOG_TRACE,3,TEXT("Sending ICM_DRAW_START to the codec")));
ICDrawStart(m_hic);
}
return CBaseFilter::Run(tStart);
}
// We're no longer streaming (from the codec's point of view)
STDMETHODIMP CAVIDec::Pause(void)
{
if (m_State == State_Running && m_hic) {
DbgLog((LOG_TRACE,3,TEXT("Sending ICM_DRAW_STOP to the codec")));
ICDrawStop(m_hic);
}
return CTransformFilter::Pause();
}
// ehr: this little bit of code is a hakk for OSR4.1 bug #117296, which
// is that if you connect a YUV type to the WM (ASF) writer filter,
// since it doesn't suggest and we don't offer -biHeight YUV, the
// Cinepak codec (and possibly others) are told they are decompressing
// to a +biHeight YUV format, and for Cinepak at least, this produces
// YUV video that is inverted, which should NEVER happen. This fixes
// that by telling ALL codecs that if they are decoding to YUV, they
// are doing it to -biHeight YUV, no matter what the connected output
// mediatype is. (We are lying to the codec, but since the rule is that
// + or - biHeight YUV is always "normal", then it's okay)
// We fool the codec by keeping a copy of the media type that's connected
// on the output pin, but we switch around the sign on the biHeight on
// our private copy.
// check for YUV types that need a negative biHeight
// only called from StartStreaming, m_mtFixed(In)Out is already set
void CAVIDec::CheckNegBiHeight( )
{
if( ( IntOutputFormat( )->bmiHeader.biHeight > 0 ) && IsYUVType( &m_mtFixedOut ) )
{
IntOutputFormat( )->bmiHeader.biHeight *= -1;
DbgLog((LOG_TRACE,1,TEXT("Dec:Flipping internal output biHeight to negative")));
}
}
BOOL CAVIDec::IsYUVType( const AM_MEDIA_TYPE * pmt)
{
if( NULL == pmt )
{
return FALSE;
}
//
// !! WARNING: If a YUV type is ever added to this list which has a biSize > sizeof(BITMAPINFOHEADER)
// then other updates will be required, since the code which handles ensuring negative
// biHeights are passed to ICM calls assumes biSize = BITMAPINFOHEADER size for YUV types, to
// avoid dynamic allocations.
//
// packed formats we care about
const GUID * pYUVs[] =
{
// packed formats
&MEDIASUBTYPE_UYVY,
&MEDIASUBTYPE_YUY2,
&MEDIASUBTYPE_CLJR,
&MEDIASUBTYPE_Y211,
&MEDIASUBTYPE_Y411,
&MEDIASUBTYPE_YUYV,
&MEDIASUBTYPE_Y41P,
&MEDIASUBTYPE_YVYU,
// planar formats
&MEDIASUBTYPE_YVU9,
&MEDIASUBTYPE_IF09,
&MEDIASUBTYPE_YV12,
&MEDIASUBTYPE_IYUV,
&MEDIASUBTYPE_CLPL
};
int gTypes = sizeof(pYUVs) / sizeof(pYUVs[0]);
for( int i = 0 ; i < gTypes ; i++ )
{
if( pmt->subtype == *pYUVs[i] ) return TRUE;
}
return FALSE;
}
// called from CheckTransform, StartStreaming, Transform
// we NEVER pass back empty rects. Anybody who calls this function is about to
// use them for ICDecompressQueryEx or ICDecompressEx, and those functions
// don't want empty rects, ever. Never call IntOutputFormat( ) from here,
// they may not be set by now.
void CAVIDec::GetSrcTargetRects( const VIDEOINFOHEADER * pVIH, RECT * pSource, RECT * pTarget )
{
if( IsRectEmpty( &pVIH->rcSource ) ) {
const VIDEOINFOHEADER* pvihInputFormat = InputFormat();
pSource->left = 0;
pSource->top = 0;
pSource->right = pvihInputFormat->bmiHeader.biWidth;
pSource->bottom = abs( pvihInputFormat->bmiHeader.biHeight );
} else {
*pSource = pVIH->rcSource;
}
if( IsRectEmpty( &pVIH->rcTarget ) ) {
pTarget->left = 0;
pTarget->top = 0;
pTarget->right = pVIH->bmiHeader.biWidth;
pTarget->bottom = abs( pVIH->bmiHeader.biHeight );
} else {
*pTarget = pVIH->rcTarget;
}
}
// this function determines if the ICDecompresEx function is used or not.
// Unless a certain driver says it needs to, ICDecompressEx WON'T be called if
// the rects are blank, or if they match the destination width/height
// This function is called from only two places: StartStreaming, and CheckTransform.
BOOL CAVIDec::ShouldUseExFuncs( HIC hic, const VIDEOINFOHEADER * pVIHin, const VIDEOINFOHEADER * pVIHout )
{
if( ShouldUseExFuncsByDriver( hic, &pVIHin->bmiHeader, &pVIHout->bmiHeader ) )
{
return TRUE;
}
// if the rects have something in them, and they are not just the full-size values,
// then we know we need to call the Ex functions
//
const RECT * pSource = &pVIHout->rcSource;
const RECT * pTarget = &pVIHout->rcTarget;
if( !IsRectEmpty( pSource ) )
{
if( pSource->left != 0 || pSource->right != pVIHout->bmiHeader.biWidth || pSource->top != 0 || pSource->bottom != abs( pVIHout->bmiHeader.biHeight ) )
return TRUE;
}
if( !IsRectEmpty( pTarget ) )
{
if( pTarget->left != 0 || pTarget->right != pVIHout->bmiHeader.biWidth || pTarget->top != 0 || pTarget->bottom != abs( pVIHout->bmiHeader.biHeight ) )
return TRUE;
}
return FALSE; // too bad it has to check all the above to get to this point. :-(
}
/******************************************************************************
ShouldUseExFuncsByDriver
WNV1: If you don't call the Ex funcs, memory will get corrupted.
WINX: If you don't call the Ex funcs, it'll play upside down
I420, IYUV, M263, M26X:
This function was created to work around bug 257820 and bug 259129. Both
bugs are in the Windows Bugs database. Bug 257820's title is "B2: USB: I420
codec causes video to replay upside down.". Bug 259129's title is "B2:USB:
IYUV codec causes upside down preview in GraphEdit". Both bugs occur because
the MSH263.DRV codec can produce upside-down bitmaps. The bug occurs when the
AVI Decompressor does not specify a source rectangle or target rectangle and it
asks MSH263.DRV to output top-down RGB bitmaps.
******************************************************************************/
bool CAVIDec::ShouldUseExFuncsByDriver( HIC hic, const BITMAPINFOHEADER * lpbiSrc, const BITMAPINFOHEADER * lpbiDst )
{
// WNV1 will corrupt memory in 24 bit upside down without Ex called
if( lpbiSrc->biCompression == '1VNW' )
{
return true;
}
// WINX will play upside down without Ex called
if( lpbiSrc->biCompression == 'XNIW' )
{
return true;
}
// all output types serviced by MSH263.drv need fixing. But we don't
// want to call ICGetInfo over and over again, so we need to test the
// input types that MSH263 offers first
if(
lpbiSrc->biCompression == '024I' ||
lpbiSrc->biCompression == 'VUYI' ||
lpbiSrc->biCompression == '362M' ||
lpbiSrc->biCompression == 'X62M' ||
0 ) // just to make the above lines look nice.
{
// Is this a top-down DIBs (negative height) bitmap?
if( lpbiDst->biHeight >= 0 ) {
return false;
}
// Are we outputing non-RGB bitmaps?
if( (BI_RGB != lpbiDst->biCompression ) && (BI_BITFIELDS != lpbiDst->biCompression ) ) {
return false;
}
// Determine if we are using the MSH263.DRV decoder.
ICINFO infoDecompressor;
infoDecompressor.dwSize = sizeof(ICINFO);
ASSERT( m_hic != 0 );
LRESULT lr = ICGetInfo( hic, &infoDecompressor, sizeof(infoDecompressor) );
// ICGetInfo() returns 0 if an error occurs. The worst that can happen if this
// fails is that the video may be upside-down. Since upside-down video is better
// than no video we will ignore the failure. For more information see
// CAVIDec::ShouldUseExFuncsByDriver()'s function comment.
if( 0 == lr ) {
return false;
}
const WCHAR MSH263_DRIVER_NAME[] = L"MS H.263";
// lstrcmpiW() returns 0 if the two strings match.
if( 0 != lstrcmpiW( infoDecompressor.szName, MSH263_DRIVER_NAME ) ) {
return false;
}
DbgLog((LOG_TRACE,2,TEXT("MSH263 detected, using Ex funcs")));
return true;
}
// default is no...
//
return false;
}
#pragma warning(disable:4514) // inline function removed.