Source code of Windows XP (NT5)
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.

745 lines
22 KiB

  1. #include <dmocom.h>
  2. #define DMO_NOATL // xfwrap.h needs this to work w/o ATL
  3. #include <dmobase.h>
  4. #include "decode.h"
  5. #include <amvideo.h>
  6. #include "resource.h"
  7. #include "strmif.h" // DVINFO
  8. #include "initguid.h"
  9. DEFINE_GUID(CLSID_DVDecDMO, 0xb321fd8b,0xcf6c,0x4bbe,0xaf,0x37,0xd1,0xa5,0x10,0xe4,0xee,0xee);
  10. DEFINE_GUID(MEDIASUBTYPE_dvc, 0x20637664,0x0000,0x0010,0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71);
  11. const DWORD bits565[] = {0x00F800,0x0007E0,0x00001F};
  12. class CDVDec : public CComBase,
  13. public C1for1QCDMO,
  14. public ISpecifyPropertyPages,
  15. public IIPDVDec
  16. {
  17. public:
  18. DECLARE_IUNKNOWN;
  19. STDMETHODIMP NDQueryInterface(REFIID riid, void **ppv);
  20. static CComBase *CreateInstance(IUnknown *pUnk, HRESULT *phr);
  21. CDVDec(IUnknown *pUnk, HRESULT *phr);
  22. ~CDVDec();
  23. // entry points called by the base class
  24. HRESULT GetInputType(ULONG ulTypeIndex, DMO_MEDIA_TYPE *pmt);
  25. HRESULT GetOutputType(ULONG ulTypeIndex, DMO_MEDIA_TYPE *pmt);
  26. HRESULT CheckInputType(const DMO_MEDIA_TYPE *pmt);
  27. HRESULT CheckOutputType(const DMO_MEDIA_TYPE *pmt);
  28. HRESULT QCProcess(BYTE* pIn,ULONG ulBytesIn,BYTE* pOut,ULONG* pulProduced);
  29. HRESULT GetSampleSizes(ULONG* ulMaxInputSize, ULONG* ulMaxOutputSize);
  30. HRESULT Init();
  31. // internal methods
  32. HRESULT MapInputTypeToOutputType(const DMO_MEDIA_TYPE *pmtIn, DMO_MEDIA_TYPE *pmtOut);
  33. void InitDestinationVideoInfo(VIDEOINFO *pVI, DWORD Comp, int n);
  34. long ActualHeight(long biHeight);
  35. void SetDimensions();
  36. // ISpecifyPropertyPages interface
  37. STDMETHODIMP GetPages(CAUUID *pPages);
  38. // Entry points for communicating with the property page
  39. STDMETHODIMP get_IPDisplay(int *iDisplay);
  40. STDMETHODIMP put_IPDisplay(int iDisplay);
  41. private:
  42. char *m_pMem;
  43. int m_iDisplay;
  44. long m_lPicWidth;
  45. long m_lPicHeight;
  46. long m_lStride;
  47. DWORD m_CodecCap;
  48. DWORD m_CodecReq;
  49. };
  50. CComBase* CDVDec::CreateInstance(IUnknown *pUnk, HRESULT *phr) {
  51. return new CDVDec(pUnk, phr);
  52. }
  53. HRESULT CDVDec::get_IPDisplay(int *iDisplay) {
  54. CDMOAutoLock l(&m_cs);
  55. *iDisplay = m_iDisplay;
  56. return NOERROR;
  57. }
  58. HRESULT CDVDec::put_IPDisplay(int iDisplay) {
  59. CDMOAutoLock l(&m_cs);
  60. m_iDisplay = iDisplay;
  61. SetDimensions();
  62. return NOERROR;
  63. }
  64. // Set m_lPicHeight and m_lPicWidth based on the m_iDisplay setting.
  65. // The way this sets m_lPicHeight assumes NTSC, but the value of m_lPicHeight
  66. // is used only for mediatype *enumeration* - the mediatype *checking* code
  67. // will accept matching PAL values as well.
  68. void CDVDec::SetDimensions() {
  69. switch (m_iDisplay) {
  70. case IDC_DEC360x240:
  71. m_lPicWidth = 360;
  72. m_lPicHeight = 240;
  73. break;
  74. case IDC_DEC720x480:
  75. m_lPicWidth = 720;
  76. m_lPicHeight = 480;
  77. break;
  78. case IDC_DEC180x120:
  79. m_lPicWidth = 180;
  80. m_lPicHeight = 120;
  81. break;
  82. case IDC_DEC88x60:
  83. m_lPicWidth = 88;
  84. m_lPicHeight = 60;
  85. break;
  86. // no default
  87. }
  88. }
  89. CDVDec::CDVDec(IUnknown *pUnk, HRESULT *phr)
  90. : CComBase(pUnk, phr),
  91. m_pMem(NULL),
  92. m_iDisplay(IDC_DEC360x240)
  93. {
  94. SetDimensions();
  95. m_CodecCap = AM_DVDEC_DC |
  96. AM_DVDEC_Quarter |
  97. AM_DVDEC_Half |
  98. AM_DVDEC_Full |
  99. AM_DVDEC_NTSC |
  100. AM_DVDEC_PAL |
  101. AM_DVDEC_RGB24 |
  102. AM_DVDEC_UYVY |
  103. AM_DVDEC_YUY2 |
  104. AM_DVDEC_RGB565 |
  105. AM_DVDEC_RGB555 |
  106. AM_DVDEC_RGB8 |
  107. AM_DVDEC_DVSD |
  108. AM_DVDEC_MMX;
  109. }
  110. CDVDec::~CDVDec() {
  111. delete[] m_pMem;
  112. }
  113. HRESULT CDVDec::NDQueryInterface(REFIID riid, void **ppv) {
  114. if (riid == IID_IMediaObject)
  115. return GetInterface((IMediaObject*)this, ppv);
  116. if (riid == IID_ISpecifyPropertyPages)
  117. return GetInterface((ISpecifyPropertyPages*)this, ppv);
  118. if (riid == IID_IIPDVDec)
  119. return GetInterface((IIPDVDec*)this, ppv);
  120. if (riid == IID_IDMOQualityControl)
  121. return GetInterface((IDMOQualityControl*)this, ppv);
  122. return CComBase::NDQueryInterface(riid, ppv);
  123. }
  124. // Returns the clsid's of the property pages we support
  125. STDMETHODIMP CDVDec::GetPages(CAUUID *pPages)
  126. {
  127. pPages->cElems = 1;
  128. pPages->pElems = (GUID *) CoTaskMemAlloc(sizeof(GUID));
  129. if (pPages->pElems == NULL)
  130. {
  131. return E_OUTOFMEMORY;
  132. }
  133. *(pPages->pElems) = CLSID_DVDecPropertiesPage;
  134. return NOERROR;
  135. }
  136. /***********************************************************************\
  137. * IsMMXCPU
  138. *
  139. * Function to check if the current processor is an MMX processor.
  140. *
  141. \***********************************************************************/
  142. BOOL IsMMXCPU() {
  143. #ifdef _X86_
  144. //////////////////////////////////////////////////////
  145. // work around for Cyrix M2 hang (when MMX flag is on)
  146. // emit cpuid and detect Cyrix M2, if its present, then return FALSE
  147. // WARNING: This will not work in 64 bit architectures
  148. __try
  149. {
  150. DWORD s1, s2, s3; // temporary holders for the vendor name
  151. __asm
  152. {
  153. // null out eax
  154. mov eax, 0x00;
  155. // load opcode CPUID == (0x0FA2)
  156. _emit 0x0f;
  157. _emit 0xa2;
  158. mov s1, ebx; // copy "Cyri" (backwards)
  159. mov s2, edx; // copy "xIns" (backwards)
  160. mov s3, ecx; // copy "tead" (backwards)
  161. }
  162. //DbgLog((LOG_TRACE, 1, TEXT("CPUID Instruction Supported")));
  163. // check Vendor Id
  164. if( (s1 == (('i' << 24) | ('r' << 16) | ('y' << 8) | ('C')))
  165. && (s2 == (('s' << 24) | ('n' << 16) | ('I' << 8) | ('x')))
  166. && (s3 == (('d' << 24) | ('a' << 16) | ('e' << 8) | ('t'))) )
  167. {
  168. //DbgLog((LOG_TRACE, 1, TEXT("Cyrix detected")));
  169. return FALSE;
  170. }
  171. else
  172. {
  173. // otherwise it's some other vendor and continue with MMX detection
  174. //DbgLog((LOG_TRACE, 1, TEXT("Cyrix not found, reverting to MMX detection")));
  175. }
  176. }
  177. __except(EXCEPTION_EXECUTE_HANDLER)
  178. {
  179. // log it and continue on to MMX detection sequence
  180. //DbgLog((LOG_TRACE, 1, TEXT("CPUID instruction not supported, reverting to MMX detection")));
  181. }
  182. // END Cyrix M2 detection
  183. //////////////////////////////////////////////////////
  184. //
  185. // If this is an Intel platform we need to make sure that we
  186. // are running on a machine that supports MMX instructions
  187. //
  188. __try {
  189. __asm _emit 0fh;
  190. __asm _emit 77h;
  191. return TRUE;
  192. }
  193. __except(EXCEPTION_EXECUTE_HANDLER) {
  194. return FALSE;
  195. }
  196. #else
  197. return FALSE;
  198. #endif
  199. }
  200. ///////////////////////////////////////////////////////////////
  201. // //
  202. // M E D I A T Y P E N E G O T I A T I O N C O D E //
  203. // //
  204. ///////////////////////////////////////////////////////////////
  205. //
  206. // A note about the mediatype code below.
  207. //
  208. // The code in GetOutputType(), CheckOutputType(), and Init() largely came from
  209. // the original DV decoder's CheckInputType(), CheckTransform(), SetMediaType(),
  210. // and GetMediaType(). I had to shuffle pieces of code around a lot to fit the
  211. // different framework. I tried to understand the code while porting it, but
  212. // some of it is still beyond me, so it is quite possible I introduced some bugs
  213. // in the process.
  214. //
  215. /////////////////////////////////////////////////////////////////////
  216. // Helpers. These were mostly inlined in the original DV decoder, //
  217. // but I made them functions to eliminate some code duplication. //
  218. // Again, I probably introduced bugs in the process. //
  219. /////////////////////////////////////////////////////////////////////
  220. long CDVDec::ActualHeight(long biHeight) {
  221. //
  222. // This function uses biHieght only to determine whether this format is PAL or
  223. // NTSC. Once that is determined, the code completely ignores the actual value
  224. // of biHeight and relies exclusively on m_iDisplay. I do not understand why
  225. // this makes sense, but I swear that this is effectively what the code in the
  226. // original DV decoder does.
  227. //
  228. if ((biHeight == 480) ||
  229. (biHeight == 240) ||
  230. (biHeight == 120) ||
  231. (biHeight == 60)) { // NTSC
  232. if (m_iDisplay == IDC_DEC720x480)
  233. return 480;
  234. if (m_iDisplay == IDC_DEC360x240)
  235. return 240;
  236. if (m_iDisplay == IDC_DEC180x120)
  237. return 120;
  238. if (m_iDisplay == IDC_DEC88x60)
  239. return 60;
  240. return 0;
  241. }
  242. if ((biHeight == 576) ||
  243. (biHeight == 288) ||
  244. (biHeight == 144) ||
  245. (biHeight == 72)) { // PAL
  246. if (m_iDisplay == IDC_DEC720x480)
  247. return 576;
  248. if (m_iDisplay == IDC_DEC360x240)
  249. return 288;
  250. if (m_iDisplay == IDC_DEC180x120)
  251. return 144;
  252. if (m_iDisplay == IDC_DEC88x60)
  253. return 72;
  254. return 0;
  255. }
  256. return 0;
  257. }
  258. DWORD InputReq(REFGUID subtype) {
  259. if ((subtype == MEDIASUBTYPE_dvsd) ||
  260. (subtype == MEDIASUBTYPE_dvc))
  261. return AM_DVDEC_DVSD;
  262. if (subtype == MEDIASUBTYPE_dvhd)
  263. return AM_DVDEC_DVHD;
  264. if (subtype == MEDIASUBTYPE_dvsl)
  265. return AM_DVDEC_DVSL;
  266. return 0;
  267. }
  268. DWORD OutputReq(REFGUID subtype) {
  269. if (subtype == MEDIASUBTYPE_UYVY)
  270. return AM_DVDEC_UYVY;
  271. if (subtype == MEDIASUBTYPE_YUY2)
  272. return AM_DVDEC_YUY2;
  273. if (subtype == MEDIASUBTYPE_RGB565)
  274. return AM_DVDEC_RGB565;
  275. else if (subtype == MEDIASUBTYPE_RGB555)
  276. return AM_DVDEC_RGB555;
  277. if (subtype == MEDIASUBTYPE_RGB24)
  278. return AM_DVDEC_RGB24;
  279. if (subtype == MEDIASUBTYPE_Y41P)
  280. return AM_DVDEC_Y41P;
  281. if (subtype == MEDIASUBTYPE_RGB8)
  282. return AM_DVDEC_RGB8;
  283. return 0;
  284. }
  285. DWORD ScaleReq(long biHeight, long biWidth) {
  286. if ((biHeight == 480) || (biHeight == 576)) {
  287. if (biWidth != 720)
  288. return 0;
  289. return AM_DVDEC_Full;
  290. }
  291. if ((biHeight == 240) || (biHeight == 288)) {
  292. if (biWidth != 360)
  293. return 0;
  294. return AM_DVDEC_Half;
  295. }
  296. if ((biHeight == 120) || (biHeight == 144)) {
  297. if (biWidth != 180)
  298. return 0;
  299. return AM_DVDEC_Quarter;
  300. }
  301. if ((biHeight == 60) || (biHeight == 72)) {
  302. if (biWidth != 88)
  303. return 0;
  304. return AM_DVDEC_DC;
  305. }
  306. return 0;
  307. }
  308. void GetHeightAndWidth(VIDEOINFO *videoInfo, long *pbiHeight, long *pbiWidth) {
  309. // if rcTarget is not empty, use its dimensions instead of biWidth and biHeight,
  310. // to see if it's an acceptable size. Then use biWidth as the stride.
  311. RECT* prcDst = &(videoInfo->rcTarget);
  312. if (!IsRectEmpty(prcDst)) {
  313. *pbiHeight = abs(prcDst->bottom - prcDst->top);
  314. *pbiWidth = abs(prcDst->right - prcDst->left);
  315. }
  316. else {
  317. *pbiHeight = abs(videoInfo->bmiHeader.biHeight);
  318. *pbiWidth = videoInfo->bmiHeader.biWidth;
  319. }
  320. }
  321. ///////////////////////////
  322. // End mediatype helpers //
  323. ///////////////////////////
  324. ///////////////////////////////////
  325. // Public mediatype entry points //
  326. ///////////////////////////////////
  327. HRESULT CDVDec::GetInputType(ULONG ulTypeIndex, DMO_MEDIA_TYPE *pmt) {
  328. return DMO_E_NO_MORE_ITEMS;
  329. }
  330. HRESULT CDVDec::GetOutputType(ULONG ulTypeIndex, DMO_MEDIA_TYPE *pmt) {
  331. DMO_MEDIA_TYPE* pmtIn = InputType();
  332. if (!pmtIn)
  333. return DMO_E_NO_MORE_ITEMS;
  334. pmt->majortype = MEDIATYPE_Video;
  335. pmt->formattype = FORMAT_VideoInfo;
  336. DWORD cbFormat;
  337. DWORD dwCompression;
  338. int nBitCount;
  339. //looking for format flag
  340. DWORD dw = 1L << 5; //first output format flag is the 7th bit in m_CodecCap
  341. do {
  342. dw <<= 1;
  343. while (!(m_CodecCap & dw))//will not do unlimited loop since AM_DVDEC_DVSD has to be 1
  344. dw <<= 1;
  345. if (dw > AM_DVDEC_Y41P)
  346. return DMO_E_NO_MORE_ITEMS;
  347. if (ulTypeIndex == 0)
  348. break;
  349. ulTypeIndex--;
  350. } while (1);
  351. dw = m_CodecCap & dw;
  352. switch (dw ) {
  353. case AM_DVDEC_YUY2:
  354. cbFormat = SIZE_VIDEOHEADER;
  355. dwCompression = MAKEFOURCC('Y','U','Y','2');
  356. nBitCount = 16;
  357. pmt->subtype = MEDIASUBTYPE_YUY2;
  358. break;
  359. case AM_DVDEC_UYVY:
  360. cbFormat = SIZE_VIDEOHEADER;
  361. dwCompression = MAKEFOURCC('U','Y','V','Y');
  362. nBitCount = 16;
  363. pmt->subtype = MEDIASUBTYPE_UYVY;
  364. break;
  365. case AM_DVDEC_RGB24:
  366. cbFormat = SIZE_VIDEOHEADER;
  367. dwCompression = BI_RGB;
  368. nBitCount = 24;
  369. pmt->subtype = MEDIASUBTYPE_RGB24;
  370. break;
  371. case AM_DVDEC_RGB565:
  372. cbFormat = SIZE_VIDEOHEADER + SIZE_MASKS;
  373. dwCompression = BI_BITFIELDS;
  374. nBitCount = 16;
  375. pmt->subtype = MEDIASUBTYPE_RGB565;
  376. break;
  377. case AM_DVDEC_RGB555:
  378. cbFormat = SIZE_VIDEOHEADER;
  379. dwCompression = BI_RGB;
  380. nBitCount = 16;
  381. pmt->subtype = MEDIASUBTYPE_RGB555;
  382. break;
  383. case AM_DVDEC_RGB8:
  384. cbFormat = SIZE_VIDEOHEADER+SIZE_PALETTE;
  385. dwCompression = BI_RGB;
  386. nBitCount = 8;
  387. pmt->subtype = MEDIASUBTYPE_RGB8;
  388. break;
  389. case AM_DVDEC_Y41P:
  390. cbFormat = SIZE_VIDEOHEADER;
  391. dwCompression = MAKEFOURCC('Y','4','1','P');
  392. nBitCount = 12;
  393. pmt->subtype = MEDIASUBTYPE_Y41P;
  394. break;
  395. default:
  396. return DMO_E_NO_MORE_ITEMS;
  397. }
  398. MoInitMediaType(pmt, cbFormat);
  399. // copy input format block
  400. // Dirty trick ! The original DV decoder does this, and it seems to work,
  401. // but I don't have enough knowledge about what goes on in the format block
  402. // to feel confident about this.
  403. memcpy(pmt->pbFormat, pmtIn->pbFormat, min(pmt->cbFormat, pmtIn->cbFormat));
  404. VIDEOINFO* pVideoInfo = (VIDEOINFO *)pmt->pbFormat;
  405. InitDestinationVideoInfo(pVideoInfo, dwCompression, nBitCount);
  406. if (dw == AM_DVDEC_RGB565) {
  407. DWORD *pdw;
  408. pdw = (DWORD *)(HEADER(pVideoInfo) + 1);
  409. pdw[iRED] = bits565[iRED];
  410. pdw[iGREEN] = bits565[iGREEN];
  411. pdw[iBLUE] = bits565[iBLUE];
  412. }
  413. pmt->bTemporalCompression = FALSE;
  414. pmt->lSampleSize = HEADER(pVideoInfo)->biSizeImage;
  415. return S_OK;
  416. }
  417. HRESULT CDVDec::CheckInputType(const DMO_MEDIA_TYPE *pmt) {
  418. if (pmt->majortype != MEDIATYPE_Video)
  419. return DMO_E_TYPE_NOT_ACCEPTED;
  420. // check format block
  421. if (!(((pmt->formattype == FORMAT_VideoInfo) &&
  422. (pmt->cbFormat >= SIZE_VIDEOHEADER) &&
  423. (pmt->pbFormat != NULL)) ||
  424. ((pmt->formattype == FORMAT_DvInfo) &&
  425. (pmt->cbFormat >= SIZE_VIDEOHEADER) &&
  426. (pmt->pbFormat != NULL))))
  427. return DMO_E_TYPE_NOT_ACCEPTED;
  428. DWORD dwReq = InputReq(pmt->subtype);
  429. if (!(dwReq & m_CodecCap))
  430. return DMO_E_TYPE_NOT_ACCEPTED;
  431. if (!ActualHeight((HEADER((VIDEOINFO*)pmt->pbFormat))->biHeight))
  432. return DMO_E_TYPE_NOT_ACCEPTED;
  433. return NOERROR;
  434. }
  435. HRESULT CDVDec::CheckOutputType(const DMO_MEDIA_TYPE *pmt) {
  436. // check major type
  437. if (pmt->majortype != MEDIATYPE_Video)
  438. return DMO_E_TYPE_NOT_ACCEPTED;
  439. // check format block
  440. if ((pmt->formattype != FORMAT_VideoInfo) ||
  441. (pmt->cbFormat < SIZE_VIDEOHEADER) ||
  442. (pmt->pbFormat == NULL))
  443. return DMO_E_TYPE_NOT_ACCEPTED;
  444. // check subtype
  445. DWORD dwTmp = OutputReq(pmt->subtype);
  446. if(!(m_CodecCap & dwTmp))
  447. return DMO_E_TYPE_NOT_ACCEPTED;
  448. VIDEOINFO* videoInfo = (VIDEOINFO *)pmt->pbFormat;
  449. RECT* prcSrc = &(videoInfo->rcSource);
  450. RECT* prcDst = &(videoInfo->rcTarget);
  451. //if rcSource is not empty, it must be the same as rcTarget, otherwise, FAIL
  452. if (!IsRectEmpty(prcSrc)) {
  453. if ((prcSrc->left != prcDst->left) ||
  454. (prcSrc->top != prcDst->top) ||
  455. (prcSrc->right != prcDst->right) ||
  456. (prcSrc->bottom != prcDst->bottom))
  457. return DMO_E_TYPE_NOT_ACCEPTED;
  458. }
  459. // Also, make sure biWidth and biHeight are bigger than the rcTarget size.
  460. if (!IsRectEmpty(prcDst)) {
  461. if((abs(videoInfo->bmiHeader.biHeight) < abs(prcDst->bottom - prcDst->top)) ||
  462. (abs(videoInfo->bmiHeader.biWidth) < abs(prcDst->right - prcDst->left)))
  463. return DMO_E_TYPE_NOT_ACCEPTED;
  464. }
  465. long biHeight, biWidth;
  466. GetHeightAndWidth(videoInfo, &biHeight, &biWidth);
  467. //check down stream filter's require height and width
  468. dwTmp = ScaleReq(biHeight, biWidth);
  469. if (!(m_CodecCap & dwTmp))
  470. return DMO_E_TYPE_NOT_ACCEPTED;
  471. return NOERROR;
  472. }
  473. ///////////////////////////////////////
  474. // End public mediatype entry points //
  475. ///////////////////////////////////////
  476. //
  477. // Fills in common video and bitmap info header fields
  478. // Stolen from the original DV decoder, which I hear in turn stole it from
  479. // some other filter. Needless to say, I do not thoroughly understand it.
  480. //
  481. void
  482. CDVDec::InitDestinationVideoInfo(
  483. VIDEOINFO *pVideoInfo,
  484. DWORD dwComppression,
  485. int nBitCount
  486. )
  487. {
  488. LPBITMAPINFOHEADER lpbi = HEADER(pVideoInfo);
  489. lpbi->biSize = sizeof(BITMAPINFOHEADER);
  490. lpbi->biWidth = m_lPicWidth;
  491. lpbi->biHeight = m_lPicHeight;
  492. lpbi->biPlanes = 1;
  493. lpbi->biBitCount = (WORD)nBitCount;
  494. lpbi->biXPelsPerMeter = 0;
  495. lpbi->biYPelsPerMeter = 0;
  496. lpbi->biCompression = dwComppression;
  497. lpbi->biSizeImage = DIBSIZE(*lpbi);
  498. //pVideoInfo->bmiHeader.biClrUsed = STDPALCOLOURS;
  499. //pVideoInfo->bmiHeader.biClrImportant = STDPALCOLOURS;
  500. if(nBitCount >8 ){
  501. lpbi->biClrUsed = 0;
  502. lpbi->biClrImportant = 0;
  503. }else if( nBitCount==8)
  504. {
  505. lpbi->biClrUsed = SIZE_PALETTE / sizeof(RGBQUAD);
  506. lpbi->biClrImportant = 0;
  507. RGBQUAD * prgb = (RGBQUAD *) (lpbi+1);
  508. // fixed PALETTE table (0 <= i < 256)
  509. for(int i=0; i<256;i++)
  510. {
  511. prgb[i].rgbRed = (i/64) << 6;
  512. prgb[i].rgbGreen = ((i/4)%16) << 4;
  513. prgb[i].rgbBlue = (i%4) << 6 ;
  514. prgb[i].rgbReserved =0;
  515. }
  516. }
  517. pVideoInfo->rcSource.top = 0;
  518. pVideoInfo->rcSource.left = 0;
  519. pVideoInfo->rcSource.right = m_lPicWidth;
  520. pVideoInfo->rcSource.bottom = m_lPicHeight;
  521. if( m_lPicHeight== 576 || m_lPicHeight== 288 || m_lPicHeight== 144 || m_lPicHeight== 72 )
  522. pVideoInfo->AvgTimePerFrame = 10000000 / 25; //InVidInfo->AvgTimePerFrame;
  523. else
  524. pVideoInfo->AvgTimePerFrame = 10000000 / 30; //InVidInfo->AvgTimePerFrame;
  525. pVideoInfo->rcTarget = pVideoInfo->rcSource;
  526. //
  527. // The "bit" rate is image size in bytes times 8 (to convert to bits)
  528. // divided by the AvgTimePerFrame. This result is in bits per 100 nSec,
  529. // so we multiply by 10000000 to convert to bits per second, this multiply
  530. // is combined with "times" 8 above so the calculations becomes:
  531. //
  532. // BitRate = (biSizeImage * 80000000) / AvgTimePerFrame
  533. //
  534. LARGE_INTEGER li;
  535. li.QuadPart = pVideoInfo->AvgTimePerFrame;
  536. pVideoInfo->dwBitRate = MulDiv(lpbi->biSizeImage, 80000000, li.LowPart);
  537. pVideoInfo->dwBitErrorRate = 0L;
  538. }
  539. ///////////////////////////////////////////////////////////////////////
  540. // //
  541. // 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 //
  542. // //
  543. ///////////////////////////////////////////////////////////////////////
  544. HRESULT CDVDec::GetSampleSizes(ULONG* pulMaxInputSize, ULONG* pulMaxOutputSize) {
  545. DMO_MEDIA_TYPE *pmtIn = InputType();
  546. DMO_MEDIA_TYPE *pmtOut = OutputType();
  547. if (!pmtIn || !pmtOut)
  548. return DMO_E_TYPE_NOT_SET;
  549. long lHeight = ActualHeight((HEADER((VIDEOINFO*)pmtIn->pbFormat))->biHeight);
  550. if (lHeight % 60 == 0)
  551. *pulMaxInputSize = 150*80*10; // NTSC
  552. else if (lHeight % 72 == 0)
  553. *pulMaxInputSize = 150*80*12; // PAL
  554. else
  555. return E_FAIL;
  556. *pulMaxOutputSize = pmtOut->lSampleSize;
  557. return NOERROR;
  558. }
  559. //
  560. // Like with mediatype nogotiation, the logic here came straight from the
  561. // original DV decoder. I made minor code changes, but they should not
  562. // affect the outcome.
  563. //
  564. HRESULT CDVDec::Init() {
  565. HRESULT hr;
  566. DMO_MEDIA_TYPE *pmtIn = InputType();
  567. DMO_MEDIA_TYPE *pmtOut = OutputType();
  568. m_lPicHeight = ActualHeight((HEADER((VIDEOINFO*)pmtIn->pbFormat))->biHeight);
  569. m_CodecReq = 0;
  570. m_CodecReq |= InputReq(pmtIn->subtype);
  571. m_CodecReq |= OutputReq(pmtOut->subtype);
  572. // size
  573. long biHeight, biWidth;
  574. VIDEOINFO* pvi = (VIDEOINFO*)pmtOut->pbFormat;
  575. GetHeightAndWidth(pvi, &biHeight, &biWidth);
  576. m_CodecReq |= ScaleReq(biHeight, biWidth);
  577. if (m_lPicHeight % 60 == 0)
  578. m_CodecReq |= AM_DVDEC_NTSC;
  579. else
  580. m_CodecReq |= AM_DVDEC_PAL;
  581. if (IsMMXCPU() && (m_CodecCap & AM_DVDEC_MMX))
  582. m_CodecReq |= AM_DVDEC_MMX;
  583. //m_lStride = ((pvi->bmiHeader.biWidth * pvi->bmiHeader.biBitCount) + 7) / 8;
  584. m_lStride = pvi->bmiHeader.biWidth ;
  585. m_lStride = (m_lStride + 3) & ~3;
  586. #define ABSOL(x) (x < 0 ? -x : x)
  587. if ((pvi->bmiHeader.biHeight < 0) || (pvi->bmiHeader.biCompression > BI_BITFIELDS))
  588. m_lStride = ABSOL(m_lStride); //directDraw
  589. else
  590. m_lStride = -ABSOL(m_lStride); //DIB
  591. //memory for MEI's decoder
  592. if (m_pMem == NULL)
  593. m_pMem = new char[440000];
  594. if(m_pMem == NULL)
  595. return E_OUTOFMEMORY;
  596. return C1for1QCDMO::Init();
  597. }
  598. HRESULT CDVDec::QCProcess(BYTE* pIn, ULONG ulBytesIn, BYTE* pOut, ULONG* pulProduced) {
  599. *m_pMem = 0;
  600. HRESULT hr = DvDecodeAFrame(pIn ,pOut, m_CodecReq, m_lStride, m_pMem);
  601. if (hr != S_OK)
  602. return E_FAIL;
  603. *pulProduced = OutputType()->lSampleSize;
  604. return NOERROR;
  605. }
  606. //
  607. // COM DLL stuff
  608. //
  609. struct CComClassTemplate g_ComClassTemplates[] = {
  610. {
  611. &CLSID_DVDecDMO,
  612. CDVDec::CreateInstance
  613. }
  614. };
  615. int g_cComClassTemplates = 1;
  616. STDAPI DllRegisterServer(void) {
  617. HRESULT hr;
  618. // Register as a COM class
  619. hr = CreateCLSIDRegKey(CLSID_DVDecDMO, "DV decoder media object");
  620. if (FAILED(hr))
  621. return hr;
  622. // Now register as a DMO
  623. DMO_PARTIAL_MEDIATYPE mtIn[4];
  624. mtIn[0].type = MEDIATYPE_Video;
  625. mtIn[0].subtype = MEDIASUBTYPE_dvsd;
  626. mtIn[1].type = MEDIATYPE_Video;
  627. mtIn[1].subtype = MEDIASUBTYPE_dvhd;
  628. mtIn[2].type = MEDIATYPE_Video;
  629. mtIn[2].subtype = MEDIASUBTYPE_dvsl;
  630. mtIn[3].type = MEDIATYPE_Video;
  631. mtIn[3].subtype = MEDIASUBTYPE_dvc;
  632. DMO_PARTIAL_MEDIATYPE mtOut[6];
  633. mtOut[0].type = MEDIATYPE_Video;
  634. mtOut[0].subtype = MEDIASUBTYPE_UYVY;
  635. mtOut[1].type = MEDIATYPE_Video;
  636. mtOut[1].subtype = MEDIASUBTYPE_YUY2;
  637. mtOut[2].type = MEDIATYPE_Video;
  638. mtOut[2].subtype = MEDIASUBTYPE_RGB565;
  639. mtOut[3].type = MEDIATYPE_Video;
  640. mtOut[3].subtype = MEDIASUBTYPE_RGB555;
  641. mtOut[4].type = MEDIATYPE_Video;
  642. mtOut[4].subtype = MEDIASUBTYPE_RGB24;
  643. mtOut[5].type = MEDIATYPE_Video;
  644. mtOut[5].subtype = MEDIASUBTYPE_Y41P;
  645. return DMORegister(L"DV decoder", CLSID_DVDecDMO, DMOCATEGORY_VIDEO_DECODER, 0, 4, mtIn, 6, mtOut);
  646. }
  647. STDAPI DllUnregisterServer(void) {
  648. // Delete our clsid key
  649. RemoveCLSIDRegKey(CLSID_DVDecDMO);
  650. return DMOUnregister(CLSID_DVDecDMO, GUID_NULL);
  651. }