00001 #include "StdAfx.h"
00002 #include <atlbase.h>
00003 #include "..\..\..\DSUtil\MediaTypes.h"
00004 #include <initguid.h>
00005 #include "qtdec.h"
00006
00007 using namespace QT;
00008
00009 static DWORD DWSWAP(DWORD dw) {return(((dw&0xff)<<24)|((dw&0xff00)<<8)|((dw&0xff0000)>>8)|((dw&0xff000000)>>24));}
00010
00011 #ifdef REGISTER_FILTER
00012
00013 const AMOVIESETUP_MEDIATYPE sudPinTypesIn[] =
00014 {
00015 {&MEDIATYPE_Video, &MEDIASUBTYPE_NULL},
00016 };
00017
00018 const AMOVIESETUP_MEDIATYPE sudPinTypesOut[] =
00019 {
00020 {&MEDIATYPE_Video, &MEDIASUBTYPE_NULL},
00021 };
00022
00023 const AMOVIESETUP_PIN sudpPins[] =
00024 {
00025 { L"Input",
00026 FALSE,
00027 FALSE,
00028 FALSE,
00029 FALSE,
00030 &CLSID_NULL,
00031 NULL,
00032 countof(sudPinTypesIn),
00033 sudPinTypesIn
00034 },
00035 { L"Output",
00036 FALSE,
00037 TRUE,
00038 FALSE,
00039 FALSE,
00040 &CLSID_NULL,
00041 NULL,
00042 countof(sudPinTypesOut),
00043 sudPinTypesOut
00044 }
00045 };
00046
00047 const AMOVIESETUP_FILTER sudFilter =
00048 {
00049 &CLSID_QTDec,
00050 L"QuickTime Decoder",
00051 MERIT_DO_NOT_USE,
00052 countof(sudpPins),
00053 sudpPins
00054 };
00055
00056 CFactoryTemplate g_Templates[] =
00057 {
00058 { L"QuickTime Decoder"
00059 , &CLSID_QTDec
00060 , CQTDec::CreateInstance
00061 , NULL
00062 , &sudFilter }
00063 };
00064
00065 int g_cTemplates = countof(g_Templates);
00066
00067 STDAPI DllRegisterServer()
00068 {
00069 return AMovieDllRegisterServer2(TRUE);
00070 }
00071
00072 STDAPI DllUnregisterServer()
00073 {
00074 return AMovieDllRegisterServer2(FALSE);
00075 }
00076
00077 extern "C" BOOL WINAPI DllEntryPoint(HINSTANCE, ULONG, LPVOID);
00078
00079 BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved)
00080 {
00081 return DllEntryPoint((HINSTANCE)hModule, dwReason, 0);
00082 }
00083
00084
00085
00086
00087
00088 CUnknown* WINAPI CQTDec::CreateInstance(LPUNKNOWN lpunk, HRESULT* phr)
00089 {
00090 CUnknown* punk = new CQTDec(lpunk, phr);
00091 if(punk == NULL) *phr = E_OUTOFMEMORY;
00092 return punk;
00093 }
00094
00095 #endif
00096
00097 CQTDec::CQTDec(LPUNKNOWN lpunk, HRESULT* phr)
00098 : CTransformFilter(NAME("CQTDec"), lpunk, CLSID_QTDec)
00099 , m_fQtInitialized(false)
00100 , m_hImageDescription(NULL)
00101 , m_pImageGWorld(NULL)
00102 {
00103 if(phr) *phr = S_OK;
00104
00105 m_fQtInitialized = false;
00106 if(InitializeQTML(0) != 0) {if(phr) *phr = E_FAIL; return;}
00107
00108 m_fQtInitialized = true;
00109 }
00110
00111 CQTDec::~CQTDec()
00112 {
00113 FreeImageDescription(m_hImageDescription);
00114 FreeGWorld(m_pImageGWorld);
00115
00116 if(m_fQtInitialized)
00117 {
00118
00119 TerminateQTML();
00120 }
00121 }
00122
00123
00124
00125 bool CQTDec::CanDecompress(OSType fourcc, bool& fYUY2, bool& fUYVY)
00126 {
00127 fYUY2 = fUYVY = false;
00128
00129 ComponentDescription cd = {decompressorComponentType, fourcc, 0, 0, cmpIsMissing};
00130
00131 if(Component decompressor = FindNextComponent(0, &cd))
00132 {
00133 do
00134 {
00135 OSErr err;
00136 Handle cpix = NULL;
00137 if(noErr == (err = GetComponentPublicResource(decompressor, FOUR_CHAR_CODE('cpix'), 1, &cpix)))
00138 {
00139 int cpixFormatCount = GetHandleSize(cpix) / sizeof(OSType);
00140 for(int i = 0; i < cpixFormatCount; i++)
00141 {
00142 switch((*(OSType**)cpix)[i])
00143 {
00144 case 'yuvs': fYUY2 = true; break;
00145 case '2vuy': fUYVY = true; break;
00146 default: break;
00147 }
00148 }
00149
00150 DisposeHandle(cpix);
00151 }
00152
00153 decompressor = FindNextComponent(decompressor, &cd);
00154 }
00155 while(decompressor && !(fYUY2 && fUYVY));
00156
00157 return(true);
00158 }
00159
00160 return(false);
00161 }
00162
00163 ImageDescriptionHandle CQTDec::MakeImageDescription()
00164 {
00165 if(!m_pInput->IsConnected())
00166 return NULL;
00167
00168 VIDEOINFOHEADER* vih = (VIDEOINFOHEADER*)m_pInput->CurrentMediaType().pbFormat;
00169 BITMAPINFOHEADER& bih = vih->bmiHeader;
00170
00171 ImageDescriptionHandle h = (ImageDescriptionHandle)NewHandleClear(sizeof(ImageDescription));
00172
00173 if(h)
00174 {
00175 (**h).idSize = sizeof(ImageDescription);
00176 (**h).cType = DWSWAP(bih.biCompression);
00177 (**h).temporalQuality = 0;
00178 (**h).spatialQuality = codecNormalQuality;
00179 (**h).width = (short)bih.biWidth;
00180 (**h).height = (short)abs(bih.biHeight);
00181 (**h).hRes = 72 << 16;
00182 (**h).vRes = 72 << 16;
00183 (**h).frameCount = 1;
00184 (**h).depth = bih.biBitCount;
00185 (**h).clutID = -1;
00186 }
00187
00188 return h;
00189 }
00190
00191 GWorldPtr CQTDec::MakeGWorld()
00192 {
00193 if(!m_pOutput->IsConnected())
00194 return NULL;
00195
00196 const CMediaType& mt = m_pOutput->CurrentMediaType();
00197 VIDEOINFOHEADER* vih = (VIDEOINFOHEADER*)mt.pbFormat;
00198 BITMAPINFOHEADER& bih = vih->bmiHeader;
00199
00200 GWorldPtr pImageWorld = NULL;
00201 Rect rect = {0, 0, (short)abs(bih.biHeight), (short)bih.biWidth};
00202
00203 OSType PixelFormat =
00204 mt.subtype == MEDIASUBTYPE_YUY2 ? kYUVSPixelFormat :
00205 mt.subtype == MEDIASUBTYPE_UYVY ? k2vuyPixelFormat :
00206 mt.subtype == MEDIASUBTYPE_RGB32 ? k32BGRAPixelFormat :
00207 mt.subtype == MEDIASUBTYPE_RGB565 ? k16LE565PixelFormat :
00208 mt.subtype == MEDIASUBTYPE_RGB555 ? k16LE555PixelFormat :
00209 0;
00210
00211 if(!PixelFormat || noErr != QTNewGWorld(&pImageWorld, PixelFormat, &rect, NULL, NULL, 0))
00212 pImageWorld = NULL;
00213
00214 if(pImageWorld)
00215 LockPixels(GetGWorldPixMap(pImageWorld));
00216
00217 return pImageWorld;
00218 }
00219
00220 void CQTDec::FreeImageDescription(ImageDescriptionHandle& hImageDescription)
00221 {
00222 if(hImageDescription)
00223 {
00224 DisposeHandle((Handle)hImageDescription);
00225 hImageDescription = NULL;
00226 }
00227 }
00228
00229 void CQTDec::FreeGWorld(GWorldPtr& pImageGWorld)
00230 {
00231 if(pImageGWorld)
00232 {
00233 UnlockPixels(GetGWorldPixMap(pImageGWorld));
00234 DisposeGWorld(pImageGWorld);
00235 pImageGWorld = NULL;
00236 }
00237 }
00238
00239
00240
00241 HRESULT CQTDec::BreakConnect(PIN_DIRECTION dir)
00242 {
00243 if(dir == PINDIR_INPUT)
00244 {
00245 m_mts.RemoveAll();
00246 }
00247 else if(dir == PINDIR_OUTPUT)
00248 {
00249 FreeImageDescription(m_hImageDescription);
00250 FreeGWorld(m_pImageGWorld);
00251 }
00252
00253 return __super::BreakConnect(dir);
00254 }
00255
00256 HRESULT CQTDec::CompleteConnect(PIN_DIRECTION dir, IPin* pReceivePin)
00257 {
00258 if(dir == PINDIR_INPUT)
00259 {
00260 m_mts.RemoveAll();
00261
00262 VIDEOINFOHEADER* vihin = (VIDEOINFOHEADER*)m_pInput->CurrentMediaType().pbFormat;
00263 BITMAPINFOHEADER& bihin = vihin->bmiHeader;
00264
00265 bool fYUY2 = false, fUYVY = false;
00266 if(CanDecompress(DWSWAP(bihin.biCompression), fYUY2, fUYVY))
00267 {
00268 CMediaType mt;
00269 mt.majortype = MEDIATYPE_Video;
00270 mt.subtype = MEDIASUBTYPE_None;
00271 mt.formattype = FORMAT_VideoInfo;
00272 mt.bFixedSizeSamples = TRUE;
00273 mt.bTemporalCompression = FALSE;
00274 mt.lSampleSize = 0;
00275 mt.pUnk = NULL;
00276
00277 VIDEOINFOHEADER vih;
00278 memset(&vih, 0, sizeof(vih));
00279 vih.AvgTimePerFrame = vihin->AvgTimePerFrame;
00280 vih.rcSource = vihin->rcSource;
00281 vih.rcTarget = vihin->rcTarget;
00282 vih.dwBitRate = vihin->dwBitRate;
00283 vih.dwBitErrorRate = vihin->dwBitErrorRate;
00284
00285 BITMAPINFOHEADER& bih = vih.bmiHeader;
00286 bih.biSize = sizeof(bih);
00287 bih.biWidth = bihin.biWidth;
00288 bih.biHeight = abs(bihin.biHeight);
00289 bih.biPlanes = 1;
00290 bih.biXPelsPerMeter = bih.biYPelsPerMeter = 0;
00291 bih.biClrUsed = bih.biClrImportant = 0;
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318 {
00319 VIDEOINFOHEADER* vihout = (VIDEOINFOHEADER*)mt.AllocFormatBuffer(sizeof(VIDEOINFOHEADER));
00320 memcpy(vihout, &vih, sizeof(vih));
00321
00322 BITMAPINFOHEADER& bihout = vihout->bmiHeader;
00323 bihout.biBitCount = 32;
00324 bihout.biSizeImage = bihout.biWidth*abs(bihout.biHeight)*bihout.biBitCount>>3;
00325
00326 mt.subtype = MEDIASUBTYPE_RGB32;
00327
00328 ((VIDEOINFOHEADER*)mt.pbFormat)->bmiHeader.biCompression = BI_BITFIELDS;
00329 ((VIDEOINFOHEADER*)mt.pbFormat)->bmiHeader.biHeight = -bih.biHeight;
00330 CorrectMediaType(&mt);
00331 m_mts.Add(mt);
00332
00333 ((VIDEOINFOHEADER*)mt.pbFormat)->bmiHeader.biCompression = BI_RGB;
00334 ((VIDEOINFOHEADER*)mt.pbFormat)->bmiHeader.biHeight = bih.biHeight;
00335 CorrectMediaType(&mt);
00336 m_mts.Add(mt);
00337 }
00338
00339
00340 {
00341 VIDEOINFOHEADER* vihout = (VIDEOINFOHEADER*)mt.AllocFormatBuffer(sizeof(VIDEOINFOHEADER));
00342 memcpy(vihout, &vih, sizeof(vih));
00343
00344 BITMAPINFOHEADER& bihout = vihout->bmiHeader;
00345 bihout.biBitCount = 16;
00346 bihout.biSizeImage = bihout.biWidth*abs(bihout.biHeight)*bihout.biBitCount>>3;
00347
00348 mt.subtype = MEDIASUBTYPE_RGB565;
00349
00350 ((VIDEOINFOHEADER*)mt.pbFormat)->bmiHeader.biCompression = BI_BITFIELDS;
00351 ((VIDEOINFOHEADER*)mt.pbFormat)->bmiHeader.biHeight = -bih.biHeight;
00352 CorrectMediaType(&mt);
00353 m_mts.Add(mt);
00354
00355 ((VIDEOINFOHEADER*)mt.pbFormat)->bmiHeader.biCompression = BI_RGB;
00356 ((VIDEOINFOHEADER*)mt.pbFormat)->bmiHeader.biHeight = bih.biHeight;
00357 CorrectMediaType(&mt);
00358 m_mts.Add(mt);
00359
00360 mt.subtype = MEDIASUBTYPE_RGB555;
00361
00362 ((VIDEOINFOHEADER*)mt.pbFormat)->bmiHeader.biCompression = BI_BITFIELDS;
00363 ((VIDEOINFOHEADER*)mt.pbFormat)->bmiHeader.biHeight = -bih.biHeight;
00364 CorrectMediaType(&mt);
00365 m_mts.Add(mt);
00366
00367 ((VIDEOINFOHEADER*)mt.pbFormat)->bmiHeader.biCompression = BI_RGB;
00368 ((VIDEOINFOHEADER*)mt.pbFormat)->bmiHeader.biHeight = bih.biHeight;
00369 CorrectMediaType(&mt);
00370 m_mts.Add(mt);
00371 }
00372 }
00373 }
00374 else if(dir == PINDIR_OUTPUT)
00375 {
00376 FreeGWorld(m_pImageGWorld);
00377 m_pImageGWorld = MakeGWorld();
00378 }
00379
00380 return __super::CompleteConnect(dir, pReceivePin);
00381 }
00382
00383 HRESULT CQTDec::StartStreaming()
00384 {
00385 FreeImageDescription(m_hImageDescription);
00386 m_hImageDescription = MakeImageDescription();
00387
00388 if(!m_hImageDescription)
00389 return E_FAIL;
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400 m_outSeqID = 0;
00401
00402 OSErr err;
00403
00404 DecompressorComponent decompressor = NULL;
00405
00406 err = FindCodec((*m_hImageDescription)->cType, anyCodec, NULL, &decompressor);
00407
00408 CodecInfo info;
00409 err = GetCodecInfo(&info, (*m_hImageDescription)->cType, decompressor);
00410
00411 err = DecompressSequenceBeginS(
00412 &m_outSeqID, m_hImageDescription,
00413 NULL, 0,
00414 m_pImageGWorld, NULL,
00415 NULL, NULL, srcCopy, (RgnHandle)NULL,
00416 codecFlagUseImageBuffer, codecNormalQuality, anyCodec);
00417
00418 if(noErr != err || m_outSeqID == 0)
00419 return E_FAIL;
00420
00421 return __super::StartStreaming();
00422 }
00423
00424
00425 HRESULT CQTDec::StopStreaming()
00426 {
00427 if(m_outSeqID)
00428 {
00429 OSErr err = CDSequenceEnd(m_outSeqID);
00430 m_outSeqID = 0;
00431 }
00432
00433 FreeImageDescription(m_hImageDescription);
00434
00435 return __super::StopStreaming();
00436 }
00437
00438 HRESULT CQTDec::Transform(IMediaSample* pSample, IMediaSample* pOutSample)
00439 {
00440 HRESULT hr;
00441
00442 BYTE* pIn = NULL;
00443 if(FAILED(hr = pSample->GetPointer(&pIn))) return hr;
00444 long len = pSample->GetActualDataLength();
00445 if(len <= 0) return S_FALSE;
00446
00447 BYTE* pOut = NULL;
00448 if(FAILED(hr = pOutSample->GetPointer(&pOut))) return hr;
00449 int size = pOutSample->GetSize();
00450
00451 VIDEOINFOHEADER* vih = (VIDEOINFOHEADER*)m_pOutput->CurrentMediaType().pbFormat;
00452 BITMAPINFOHEADER& bih = vih->bmiHeader;
00453
00454 OSErr err;
00455
00456 {
00457 AM_MEDIA_TYPE* pmt = NULL;
00458 if(S_OK == pSample->GetMediaType((AM_MEDIA_TYPE**)&pmt) && pmt)
00459 {
00460 CMediaType mt(*pmt);
00461 DeleteMediaType(pmt), pmt = NULL;
00462
00463 if(mt != m_pInput->CurrentMediaType())
00464 {
00465 StopStreaming();
00466 m_pInput->SetMediaType(&mt);
00467 StartStreaming();
00468 }
00469 }
00470 }
00471
00472 CodecFlags inf = codecFlagNoScreenUpdate, outf = 0;
00473
00474 err = DecompressSequenceFrameWhen(m_outSeqID, (Ptr)pIn, len, inf, &outf, NULL, NULL);
00475
00476 {
00477 PixMapHandle hPixMap = GetGWorldPixMap(m_pImageGWorld);
00478 Ptr pPixels = GetPixBaseAddr(hPixMap);
00479 long theRowBytes = QTGetPixMapHandleRowBytes(hPixMap);
00480
00481 DWORD pitch = bih.biWidth*bih.biBitCount>>3;
00482
00483 for(int i = 0, h = abs(bih.biHeight); i < h; i++)
00484 {
00485 memcpy(pOut + i*pitch, (BYTE*)pPixels + i*theRowBytes, min(pitch, theRowBytes));
00486 }
00487 }
00488
00489
00490
00491
00492
00493
00494
00495
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505
00506
00507
00508
00509
00510
00511
00512
00513
00514
00515
00516
00517
00518
00519
00520
00521
00522
00523
00524
00525
00526
00527
00528
00529
00530
00531
00532
00533
00534
00535
00536
00537
00538
00539 return S_OK;
00540 }
00541
00542 HRESULT CQTDec::CheckInputType(const CMediaType* mtIn)
00543 {
00544 if(mtIn->majortype != MEDIATYPE_Video || mtIn->formattype != FORMAT_VideoInfo)
00545 return VFW_E_TYPE_NOT_ACCEPTED;
00546
00547 VIDEOINFOHEADER* vih = (VIDEOINFOHEADER*)mtIn->pbFormat;
00548 BITMAPINFOHEADER& bih = vih->bmiHeader;
00549
00550 OSErr err;
00551 ComponentInstance ci;
00552 if(noErr == (err = OpenADefaultComponent('imdc', DWSWAP(bih.biCompression), &ci)))
00553 {
00554 err = CloseComponent(ci);
00555 return S_OK;
00556 }
00557
00558 return VFW_E_TYPE_NOT_ACCEPTED;
00559 }
00560
00561 HRESULT CQTDec::CheckTransform(const CMediaType* mtIn, const CMediaType* mtOut)
00562 {
00563 return S_OK;
00564
00565 return VFW_E_TYPE_NOT_ACCEPTED;
00566 }
00567
00568 HRESULT CQTDec::DecideBufferSize(IMemAllocator* pAllocator, ALLOCATOR_PROPERTIES* pProperties)
00569 {
00570 if(m_pInput->IsConnected() == FALSE) return E_UNEXPECTED;
00571
00572 CComPtr<IMemAllocator> pAllocatorIn;
00573 m_pInput->GetAllocator(&pAllocatorIn);
00574 if(!pAllocatorIn) return E_UNEXPECTED;
00575
00576 pAllocatorIn->GetProperties(pProperties);
00577
00578 VIDEOINFOHEADER* vih = (VIDEOINFOHEADER*)m_pInput->CurrentMediaType().pbFormat;
00579 BITMAPINFOHEADER& bih = vih->bmiHeader;
00580
00581 pProperties->cBuffers = 1;
00582 pProperties->cbBuffer = bih.biWidth*abs(bih.biHeight)*4;
00583 pProperties->cbAlign = 1;
00584 pProperties->cbPrefix = 0;
00585
00586 HRESULT hr;
00587 ALLOCATOR_PROPERTIES Actual;
00588 if(FAILED(hr = pAllocator->SetProperties(pProperties, &Actual)))
00589 return hr;
00590
00591 return(pProperties->cBuffers > Actual.cBuffers || pProperties->cbBuffer > Actual.cbBuffer
00592 ? E_FAIL
00593 : NOERROR);
00594 }
00595
00596 HRESULT CQTDec::GetMediaType(int iPosition, CMediaType* pmt)
00597 {
00598 if(m_pInput->IsConnected() == FALSE) return E_UNEXPECTED;
00599
00600 if(iPosition < 0) return E_INVALIDARG;
00601 if(iPosition >= m_mts.GetCount()) return VFW_S_NO_MORE_ITEMS;
00602
00603 *pmt = m_mts[iPosition];
00604
00605 return S_OK;
00606 }