|
|
#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); }
|