746 lines
22 KiB
C++
746 lines
22 KiB
C++
#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);
|
|
}
|
|
|