windows-nt/Source/XPSP1/NT/multimedia/dshow/dmo/dvdec/dvdec.cpp

746 lines
22 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
#include <dmocom.h>
#define DMO_NOATL // xfwrap.h needs this to work w/o ATL
#include <dmobase.h>
#include "decode.h"
#include <amvideo.h>
#include "resource.h"
#include "strmif.h" // DVINFO
#include "initguid.h"
DEFINE_GUID(CLSID_DVDecDMO, 0xb321fd8b,0xcf6c,0x4bbe,0xaf,0x37,0xd1,0xa5,0x10,0xe4,0xee,0xee);
DEFINE_GUID(MEDIASUBTYPE_dvc, 0x20637664,0x0000,0x0010,0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71);
const DWORD bits565[] = {0x00F800,0x0007E0,0x00001F};
class CDVDec : public CComBase,
public C1for1QCDMO,
public ISpecifyPropertyPages,
public IIPDVDec
{
public:
DECLARE_IUNKNOWN;
STDMETHODIMP NDQueryInterface(REFIID riid, void **ppv);
static CComBase *CreateInstance(IUnknown *pUnk, HRESULT *phr);
CDVDec(IUnknown *pUnk, HRESULT *phr);
~CDVDec();
// entry points called by the base class
HRESULT GetInputType(ULONG ulTypeIndex, DMO_MEDIA_TYPE *pmt);
HRESULT GetOutputType(ULONG ulTypeIndex, DMO_MEDIA_TYPE *pmt);
HRESULT CheckInputType(const DMO_MEDIA_TYPE *pmt);
HRESULT CheckOutputType(const DMO_MEDIA_TYPE *pmt);
HRESULT QCProcess(BYTE* pIn,ULONG ulBytesIn,BYTE* pOut,ULONG* pulProduced);
HRESULT GetSampleSizes(ULONG* ulMaxInputSize, ULONG* ulMaxOutputSize);
HRESULT Init();
// internal methods
HRESULT MapInputTypeToOutputType(const DMO_MEDIA_TYPE *pmtIn, DMO_MEDIA_TYPE *pmtOut);
void InitDestinationVideoInfo(VIDEOINFO *pVI, DWORD Comp, int n);
long ActualHeight(long biHeight);
void SetDimensions();
// ISpecifyPropertyPages interface
STDMETHODIMP GetPages(CAUUID *pPages);
// Entry points for communicating with the property page
STDMETHODIMP get_IPDisplay(int *iDisplay);
STDMETHODIMP put_IPDisplay(int iDisplay);
private:
char *m_pMem;
int m_iDisplay;
long m_lPicWidth;
long m_lPicHeight;
long m_lStride;
DWORD m_CodecCap;
DWORD m_CodecReq;
};
CComBase* CDVDec::CreateInstance(IUnknown *pUnk, HRESULT *phr) {
return new CDVDec(pUnk, phr);
}
HRESULT CDVDec::get_IPDisplay(int *iDisplay) {
CDMOAutoLock l(&m_cs);
*iDisplay = m_iDisplay;
return NOERROR;
}
HRESULT CDVDec::put_IPDisplay(int iDisplay) {
CDMOAutoLock l(&m_cs);
m_iDisplay = iDisplay;
SetDimensions();
return NOERROR;
}
// Set m_lPicHeight and m_lPicWidth based on the m_iDisplay setting.
// The way this sets m_lPicHeight assumes NTSC, but the value of m_lPicHeight
// is used only for mediatype *enumeration* - the mediatype *checking* code
// will accept matching PAL values as well.
void CDVDec::SetDimensions() {
switch (m_iDisplay) {
case IDC_DEC360x240:
m_lPicWidth = 360;
m_lPicHeight = 240;
break;
case IDC_DEC720x480:
m_lPicWidth = 720;
m_lPicHeight = 480;
break;
case IDC_DEC180x120:
m_lPicWidth = 180;
m_lPicHeight = 120;
break;
case IDC_DEC88x60:
m_lPicWidth = 88;
m_lPicHeight = 60;
break;
// no default
}
}
CDVDec::CDVDec(IUnknown *pUnk, HRESULT *phr)
: CComBase(pUnk, phr),
m_pMem(NULL),
m_iDisplay(IDC_DEC360x240)
{
SetDimensions();
m_CodecCap = AM_DVDEC_DC |
AM_DVDEC_Quarter |
AM_DVDEC_Half |
AM_DVDEC_Full |
AM_DVDEC_NTSC |
AM_DVDEC_PAL |
AM_DVDEC_RGB24 |
AM_DVDEC_UYVY |
AM_DVDEC_YUY2 |
AM_DVDEC_RGB565 |
AM_DVDEC_RGB555 |
AM_DVDEC_RGB8 |
AM_DVDEC_DVSD |
AM_DVDEC_MMX;
}
CDVDec::~CDVDec() {
delete[] m_pMem;
}
HRESULT CDVDec::NDQueryInterface(REFIID riid, void **ppv) {
if (riid == IID_IMediaObject)
return GetInterface((IMediaObject*)this, ppv);
if (riid == IID_ISpecifyPropertyPages)
return GetInterface((ISpecifyPropertyPages*)this, ppv);
if (riid == IID_IIPDVDec)
return GetInterface((IIPDVDec*)this, ppv);
if (riid == IID_IDMOQualityControl)
return GetInterface((IDMOQualityControl*)this, ppv);
return CComBase::NDQueryInterface(riid, ppv);
}
// Returns the clsid's of the property pages we support
STDMETHODIMP CDVDec::GetPages(CAUUID *pPages)
{
pPages->cElems = 1;
pPages->pElems = (GUID *) CoTaskMemAlloc(sizeof(GUID));
if (pPages->pElems == NULL)
{
return E_OUTOFMEMORY;
}
*(pPages->pElems) = CLSID_DVDecPropertiesPage;
return NOERROR;
}
/***********************************************************************\
* IsMMXCPU
*
* Function to check if the current processor is an MMX processor.
*
\***********************************************************************/
BOOL IsMMXCPU() {
#ifdef _X86_
//////////////////////////////////////////////////////
// work around for Cyrix M2 hang (when MMX flag is on)
// emit cpuid and detect Cyrix M2, if its present, then return FALSE
// WARNING: This will not work in 64 bit architectures
__try
{
DWORD s1, s2, s3; // temporary holders for the vendor name
__asm
{
// null out eax
mov eax, 0x00;
// load opcode CPUID == (0x0FA2)
_emit 0x0f;
_emit 0xa2;
mov s1, ebx; // copy "Cyri" (backwards)
mov s2, edx; // copy "xIns" (backwards)
mov s3, ecx; // copy "tead" (backwards)
}
//DbgLog((LOG_TRACE, 1, TEXT("CPUID Instruction Supported")));
// check Vendor Id
if( (s1 == (('i' << 24) | ('r' << 16) | ('y' << 8) | ('C')))
&& (s2 == (('s' << 24) | ('n' << 16) | ('I' << 8) | ('x')))
&& (s3 == (('d' << 24) | ('a' << 16) | ('e' << 8) | ('t'))) )
{
//DbgLog((LOG_TRACE, 1, TEXT("Cyrix detected")));
return FALSE;
}
else
{
// otherwise it's some other vendor and continue with MMX detection
//DbgLog((LOG_TRACE, 1, TEXT("Cyrix not found, reverting to MMX detection")));
}
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
// log it and continue on to MMX detection sequence
//DbgLog((LOG_TRACE, 1, TEXT("CPUID instruction not supported, reverting to MMX detection")));
}
// END Cyrix M2 detection
//////////////////////////////////////////////////////
//
// If this is an Intel platform we need to make sure that we
// are running on a machine that supports MMX instructions
//
__try {
__asm _emit 0fh;
__asm _emit 77h;
return TRUE;
}
__except(EXCEPTION_EXECUTE_HANDLER) {
return FALSE;
}
#else
return FALSE;
#endif
}
///////////////////////////////////////////////////////////////
// //
// M E D I A T Y P E N E G O T I A T I O N C O D E //
// //
///////////////////////////////////////////////////////////////
//
// A note about the mediatype code below.
//
// The code in GetOutputType(), CheckOutputType(), and Init() largely came from
// the original DV decoder's CheckInputType(), CheckTransform(), SetMediaType(),
// and GetMediaType(). I had to shuffle pieces of code around a lot to fit the
// different framework. I tried to understand the code while porting it, but
// some of it is still beyond me, so it is quite possible I introduced some bugs
// in the process.
//
/////////////////////////////////////////////////////////////////////
// Helpers. These were mostly inlined in the original DV decoder, //
// but I made them functions to eliminate some code duplication. //
// Again, I probably introduced bugs in the process. //
/////////////////////////////////////////////////////////////////////
long CDVDec::ActualHeight(long biHeight) {
//
// This function uses biHieght only to determine whether this format is PAL or
// NTSC. Once that is determined, the code completely ignores the actual value
// of biHeight and relies exclusively on m_iDisplay. I do not understand why
// this makes sense, but I swear that this is effectively what the code in the
// original DV decoder does.
//
if ((biHeight == 480) ||
(biHeight == 240) ||
(biHeight == 120) ||
(biHeight == 60)) { // NTSC
if (m_iDisplay == IDC_DEC720x480)
return 480;
if (m_iDisplay == IDC_DEC360x240)
return 240;
if (m_iDisplay == IDC_DEC180x120)
return 120;
if (m_iDisplay == IDC_DEC88x60)
return 60;
return 0;
}
if ((biHeight == 576) ||
(biHeight == 288) ||
(biHeight == 144) ||
(biHeight == 72)) { // PAL
if (m_iDisplay == IDC_DEC720x480)
return 576;
if (m_iDisplay == IDC_DEC360x240)
return 288;
if (m_iDisplay == IDC_DEC180x120)
return 144;
if (m_iDisplay == IDC_DEC88x60)
return 72;
return 0;
}
return 0;
}
DWORD InputReq(REFGUID subtype) {
if ((subtype == MEDIASUBTYPE_dvsd) ||
(subtype == MEDIASUBTYPE_dvc))
return AM_DVDEC_DVSD;
if (subtype == MEDIASUBTYPE_dvhd)
return AM_DVDEC_DVHD;
if (subtype == MEDIASUBTYPE_dvsl)
return AM_DVDEC_DVSL;
return 0;
}
DWORD OutputReq(REFGUID subtype) {
if (subtype == MEDIASUBTYPE_UYVY)
return AM_DVDEC_UYVY;
if (subtype == MEDIASUBTYPE_YUY2)
return AM_DVDEC_YUY2;
if (subtype == MEDIASUBTYPE_RGB565)
return AM_DVDEC_RGB565;
else if (subtype == MEDIASUBTYPE_RGB555)
return AM_DVDEC_RGB555;
if (subtype == MEDIASUBTYPE_RGB24)
return AM_DVDEC_RGB24;
if (subtype == MEDIASUBTYPE_Y41P)
return AM_DVDEC_Y41P;
if (subtype == MEDIASUBTYPE_RGB8)
return AM_DVDEC_RGB8;
return 0;
}
DWORD ScaleReq(long biHeight, long biWidth) {
if ((biHeight == 480) || (biHeight == 576)) {
if (biWidth != 720)
return 0;
return AM_DVDEC_Full;
}
if ((biHeight == 240) || (biHeight == 288)) {
if (biWidth != 360)
return 0;
return AM_DVDEC_Half;
}
if ((biHeight == 120) || (biHeight == 144)) {
if (biWidth != 180)
return 0;
return AM_DVDEC_Quarter;
}
if ((biHeight == 60) || (biHeight == 72)) {
if (biWidth != 88)
return 0;
return AM_DVDEC_DC;
}
return 0;
}
void GetHeightAndWidth(VIDEOINFO *videoInfo, long *pbiHeight, long *pbiWidth) {
// if rcTarget is not empty, use its dimensions instead of biWidth and biHeight,
// to see if it's an acceptable size. Then use biWidth as the stride.
RECT* prcDst = &(videoInfo->rcTarget);
if (!IsRectEmpty(prcDst)) {
*pbiHeight = abs(prcDst->bottom - prcDst->top);
*pbiWidth = abs(prcDst->right - prcDst->left);
}
else {
*pbiHeight = abs(videoInfo->bmiHeader.biHeight);
*pbiWidth = videoInfo->bmiHeader.biWidth;
}
}
///////////////////////////
// End mediatype helpers //
///////////////////////////
///////////////////////////////////
// Public mediatype entry points //
///////////////////////////////////
HRESULT CDVDec::GetInputType(ULONG ulTypeIndex, DMO_MEDIA_TYPE *pmt) {
return DMO_E_NO_MORE_ITEMS;
}
HRESULT CDVDec::GetOutputType(ULONG ulTypeIndex, DMO_MEDIA_TYPE *pmt) {
DMO_MEDIA_TYPE* pmtIn = InputType();
if (!pmtIn)
return DMO_E_NO_MORE_ITEMS;
pmt->majortype = MEDIATYPE_Video;
pmt->formattype = FORMAT_VideoInfo;
DWORD cbFormat;
DWORD dwCompression;
int nBitCount;
//looking for format flag
DWORD dw = 1L << 5; //first output format flag is the 7th bit in m_CodecCap
do {
dw <<= 1;
while (!(m_CodecCap & dw))//will not do unlimited loop since AM_DVDEC_DVSD has to be 1
dw <<= 1;
if (dw > AM_DVDEC_Y41P)
return DMO_E_NO_MORE_ITEMS;
if (ulTypeIndex == 0)
break;
ulTypeIndex--;
} while (1);
dw = m_CodecCap & dw;
switch (dw ) {
case AM_DVDEC_YUY2:
cbFormat = SIZE_VIDEOHEADER;
dwCompression = MAKEFOURCC('Y','U','Y','2');
nBitCount = 16;
pmt->subtype = MEDIASUBTYPE_YUY2;
break;
case AM_DVDEC_UYVY:
cbFormat = SIZE_VIDEOHEADER;
dwCompression = MAKEFOURCC('U','Y','V','Y');
nBitCount = 16;
pmt->subtype = MEDIASUBTYPE_UYVY;
break;
case AM_DVDEC_RGB24:
cbFormat = SIZE_VIDEOHEADER;
dwCompression = BI_RGB;
nBitCount = 24;
pmt->subtype = MEDIASUBTYPE_RGB24;
break;
case AM_DVDEC_RGB565:
cbFormat = SIZE_VIDEOHEADER + SIZE_MASKS;
dwCompression = BI_BITFIELDS;
nBitCount = 16;
pmt->subtype = MEDIASUBTYPE_RGB565;
break;
case AM_DVDEC_RGB555:
cbFormat = SIZE_VIDEOHEADER;
dwCompression = BI_RGB;
nBitCount = 16;
pmt->subtype = MEDIASUBTYPE_RGB555;
break;
case AM_DVDEC_RGB8:
cbFormat = SIZE_VIDEOHEADER+SIZE_PALETTE;
dwCompression = BI_RGB;
nBitCount = 8;
pmt->subtype = MEDIASUBTYPE_RGB8;
break;
case AM_DVDEC_Y41P:
cbFormat = SIZE_VIDEOHEADER;
dwCompression = MAKEFOURCC('Y','4','1','P');
nBitCount = 12;
pmt->subtype = MEDIASUBTYPE_Y41P;
break;
default:
return DMO_E_NO_MORE_ITEMS;
}
MoInitMediaType(pmt, cbFormat);
// copy input format block
// Dirty trick ! The original DV decoder does this, and it seems to work,
// but I don't have enough knowledge about what goes on in the format block
// to feel confident about this.
memcpy(pmt->pbFormat, pmtIn->pbFormat, min(pmt->cbFormat, pmtIn->cbFormat));
VIDEOINFO* pVideoInfo = (VIDEOINFO *)pmt->pbFormat;
InitDestinationVideoInfo(pVideoInfo, dwCompression, nBitCount);
if (dw == AM_DVDEC_RGB565) {
DWORD *pdw;
pdw = (DWORD *)(HEADER(pVideoInfo) + 1);
pdw[iRED] = bits565[iRED];
pdw[iGREEN] = bits565[iGREEN];
pdw[iBLUE] = bits565[iBLUE];
}
pmt->bTemporalCompression = FALSE;
pmt->lSampleSize = HEADER(pVideoInfo)->biSizeImage;
return S_OK;
}
HRESULT CDVDec::CheckInputType(const DMO_MEDIA_TYPE *pmt) {
if (pmt->majortype != MEDIATYPE_Video)
return DMO_E_TYPE_NOT_ACCEPTED;
// check format block
if (!(((pmt->formattype == FORMAT_VideoInfo) &&
(pmt->cbFormat >= SIZE_VIDEOHEADER) &&
(pmt->pbFormat != NULL)) ||
((pmt->formattype == FORMAT_DvInfo) &&
(pmt->cbFormat >= SIZE_VIDEOHEADER) &&
(pmt->pbFormat != NULL))))
return DMO_E_TYPE_NOT_ACCEPTED;
DWORD dwReq = InputReq(pmt->subtype);
if (!(dwReq & m_CodecCap))
return DMO_E_TYPE_NOT_ACCEPTED;
if (!ActualHeight((HEADER((VIDEOINFO*)pmt->pbFormat))->biHeight))
return DMO_E_TYPE_NOT_ACCEPTED;
return NOERROR;
}
HRESULT CDVDec::CheckOutputType(const DMO_MEDIA_TYPE *pmt) {
// check major type
if (pmt->majortype != MEDIATYPE_Video)
return DMO_E_TYPE_NOT_ACCEPTED;
// check format block
if ((pmt->formattype != FORMAT_VideoInfo) ||
(pmt->cbFormat < SIZE_VIDEOHEADER) ||
(pmt->pbFormat == NULL))
return DMO_E_TYPE_NOT_ACCEPTED;
// check subtype
DWORD dwTmp = OutputReq(pmt->subtype);
if(!(m_CodecCap & dwTmp))
return DMO_E_TYPE_NOT_ACCEPTED;
VIDEOINFO* videoInfo = (VIDEOINFO *)pmt->pbFormat;
RECT* prcSrc = &(videoInfo->rcSource);
RECT* prcDst = &(videoInfo->rcTarget);
//if rcSource is not empty, it must be the same as rcTarget, otherwise, FAIL
if (!IsRectEmpty(prcSrc)) {
if ((prcSrc->left != prcDst->left) ||
(prcSrc->top != prcDst->top) ||
(prcSrc->right != prcDst->right) ||
(prcSrc->bottom != prcDst->bottom))
return DMO_E_TYPE_NOT_ACCEPTED;
}
// Also, make sure biWidth and biHeight are bigger than the rcTarget size.
if (!IsRectEmpty(prcDst)) {
if((abs(videoInfo->bmiHeader.biHeight) < abs(prcDst->bottom - prcDst->top)) ||
(abs(videoInfo->bmiHeader.biWidth) < abs(prcDst->right - prcDst->left)))
return DMO_E_TYPE_NOT_ACCEPTED;
}
long biHeight, biWidth;
GetHeightAndWidth(videoInfo, &biHeight, &biWidth);
//check down stream filter's require height and width
dwTmp = ScaleReq(biHeight, biWidth);
if (!(m_CodecCap & dwTmp))
return DMO_E_TYPE_NOT_ACCEPTED;
return NOERROR;
}
///////////////////////////////////////
// End public mediatype entry points //
///////////////////////////////////////
//
// Fills in common video and bitmap info header fields
// Stolen from the original DV decoder, which I hear in turn stole it from
// some other filter. Needless to say, I do not thoroughly understand it.
//
void
CDVDec::InitDestinationVideoInfo(
VIDEOINFO *pVideoInfo,
DWORD dwComppression,
int nBitCount
)
{
LPBITMAPINFOHEADER lpbi = HEADER(pVideoInfo);
lpbi->biSize = sizeof(BITMAPINFOHEADER);
lpbi->biWidth = m_lPicWidth;
lpbi->biHeight = m_lPicHeight;
lpbi->biPlanes = 1;
lpbi->biBitCount = (WORD)nBitCount;
lpbi->biXPelsPerMeter = 0;
lpbi->biYPelsPerMeter = 0;
lpbi->biCompression = dwComppression;
lpbi->biSizeImage = DIBSIZE(*lpbi);
//pVideoInfo->bmiHeader.biClrUsed = STDPALCOLOURS;
//pVideoInfo->bmiHeader.biClrImportant = STDPALCOLOURS;
if(nBitCount >8 ){
lpbi->biClrUsed = 0;
lpbi->biClrImportant = 0;
}else if( nBitCount==8)
{
lpbi->biClrUsed = SIZE_PALETTE / sizeof(RGBQUAD);
lpbi->biClrImportant = 0;
RGBQUAD * prgb = (RGBQUAD *) (lpbi+1);
// fixed PALETTE table (0 <= i < 256)
for(int i=0; i<256;i++)
{
prgb[i].rgbRed = (i/64) << 6;
prgb[i].rgbGreen = ((i/4)%16) << 4;
prgb[i].rgbBlue = (i%4) << 6 ;
prgb[i].rgbReserved =0;
}
}
pVideoInfo->rcSource.top = 0;
pVideoInfo->rcSource.left = 0;
pVideoInfo->rcSource.right = m_lPicWidth;
pVideoInfo->rcSource.bottom = m_lPicHeight;
if( m_lPicHeight== 576 || m_lPicHeight== 288 || m_lPicHeight== 144 || m_lPicHeight== 72 )
pVideoInfo->AvgTimePerFrame = 10000000 / 25; //InVidInfo->AvgTimePerFrame;
else
pVideoInfo->AvgTimePerFrame = 10000000 / 30; //InVidInfo->AvgTimePerFrame;
pVideoInfo->rcTarget = pVideoInfo->rcSource;
//
// The "bit" rate is image size in bytes times 8 (to convert to bits)
// divided by the AvgTimePerFrame. This result is in bits per 100 nSec,
// so we multiply by 10000000 to convert to bits per second, this multiply
// is combined with "times" 8 above so the calculations becomes:
//
// BitRate = (biSizeImage * 80000000) / AvgTimePerFrame
//
LARGE_INTEGER li;
li.QuadPart = pVideoInfo->AvgTimePerFrame;
pVideoInfo->dwBitRate = MulDiv(lpbi->biSizeImage, 80000000, li.LowPart);
pVideoInfo->dwBitErrorRate = 0L;
}
///////////////////////////////////////////////////////////////////////
// //
// E N D M E D I A T Y P E N E G O T I A T I O N C O D E //
// //
///////////////////////////////////////////////////////////////////////
HRESULT CDVDec::GetSampleSizes(ULONG* pulMaxInputSize, ULONG* pulMaxOutputSize) {
DMO_MEDIA_TYPE *pmtIn = InputType();
DMO_MEDIA_TYPE *pmtOut = OutputType();
if (!pmtIn || !pmtOut)
return DMO_E_TYPE_NOT_SET;
long lHeight = ActualHeight((HEADER((VIDEOINFO*)pmtIn->pbFormat))->biHeight);
if (lHeight % 60 == 0)
*pulMaxInputSize = 150*80*10; // NTSC
else if (lHeight % 72 == 0)
*pulMaxInputSize = 150*80*12; // PAL
else
return E_FAIL;
*pulMaxOutputSize = pmtOut->lSampleSize;
return NOERROR;
}
//
// Like with mediatype nogotiation, the logic here came straight from the
// original DV decoder. I made minor code changes, but they should not
// affect the outcome.
//
HRESULT CDVDec::Init() {
HRESULT hr;
DMO_MEDIA_TYPE *pmtIn = InputType();
DMO_MEDIA_TYPE *pmtOut = OutputType();
m_lPicHeight = ActualHeight((HEADER((VIDEOINFO*)pmtIn->pbFormat))->biHeight);
m_CodecReq = 0;
m_CodecReq |= InputReq(pmtIn->subtype);
m_CodecReq |= OutputReq(pmtOut->subtype);
// size
long biHeight, biWidth;
VIDEOINFO* pvi = (VIDEOINFO*)pmtOut->pbFormat;
GetHeightAndWidth(pvi, &biHeight, &biWidth);
m_CodecReq |= ScaleReq(biHeight, biWidth);
if (m_lPicHeight % 60 == 0)
m_CodecReq |= AM_DVDEC_NTSC;
else
m_CodecReq |= AM_DVDEC_PAL;
if (IsMMXCPU() && (m_CodecCap & AM_DVDEC_MMX))
m_CodecReq |= AM_DVDEC_MMX;
//m_lStride = ((pvi->bmiHeader.biWidth * pvi->bmiHeader.biBitCount) + 7) / 8;
m_lStride = pvi->bmiHeader.biWidth ;
m_lStride = (m_lStride + 3) & ~3;
#define ABSOL(x) (x < 0 ? -x : x)
if ((pvi->bmiHeader.biHeight < 0) || (pvi->bmiHeader.biCompression > BI_BITFIELDS))
m_lStride = ABSOL(m_lStride); //directDraw
else
m_lStride = -ABSOL(m_lStride); //DIB
//memory for MEI's decoder
if (m_pMem == NULL)
m_pMem = new char[440000];
if(m_pMem == NULL)
return E_OUTOFMEMORY;
return C1for1QCDMO::Init();
}
HRESULT CDVDec::QCProcess(BYTE* pIn, ULONG ulBytesIn, BYTE* pOut, ULONG* pulProduced) {
*m_pMem = 0;
HRESULT hr = DvDecodeAFrame(pIn ,pOut, m_CodecReq, m_lStride, m_pMem);
if (hr != S_OK)
return E_FAIL;
*pulProduced = OutputType()->lSampleSize;
return NOERROR;
}
//
// COM DLL stuff
//
struct CComClassTemplate g_ComClassTemplates[] = {
{
&CLSID_DVDecDMO,
CDVDec::CreateInstance
}
};
int g_cComClassTemplates = 1;
STDAPI DllRegisterServer(void) {
HRESULT hr;
// Register as a COM class
hr = CreateCLSIDRegKey(CLSID_DVDecDMO, "DV decoder media object");
if (FAILED(hr))
return hr;
// Now register as a DMO
DMO_PARTIAL_MEDIATYPE mtIn[4];
mtIn[0].type = MEDIATYPE_Video;
mtIn[0].subtype = MEDIASUBTYPE_dvsd;
mtIn[1].type = MEDIATYPE_Video;
mtIn[1].subtype = MEDIASUBTYPE_dvhd;
mtIn[2].type = MEDIATYPE_Video;
mtIn[2].subtype = MEDIASUBTYPE_dvsl;
mtIn[3].type = MEDIATYPE_Video;
mtIn[3].subtype = MEDIASUBTYPE_dvc;
DMO_PARTIAL_MEDIATYPE mtOut[6];
mtOut[0].type = MEDIATYPE_Video;
mtOut[0].subtype = MEDIASUBTYPE_UYVY;
mtOut[1].type = MEDIATYPE_Video;
mtOut[1].subtype = MEDIASUBTYPE_YUY2;
mtOut[2].type = MEDIATYPE_Video;
mtOut[2].subtype = MEDIASUBTYPE_RGB565;
mtOut[3].type = MEDIATYPE_Video;
mtOut[3].subtype = MEDIASUBTYPE_RGB555;
mtOut[4].type = MEDIATYPE_Video;
mtOut[4].subtype = MEDIASUBTYPE_RGB24;
mtOut[5].type = MEDIATYPE_Video;
mtOut[5].subtype = MEDIASUBTYPE_Y41P;
return DMORegister(L"DV decoder", CLSID_DVDecDMO, DMOCATEGORY_VIDEO_DECODER, 0, 4, mtIn, 6, mtOut);
}
STDAPI DllUnregisterServer(void) {
// Delete our clsid key
RemoveCLSIDRegKey(CLSID_DVDecDMO);
return DMOUnregister(CLSID_DVDecDMO, GUID_NULL);
}