- Main Page
- Namespaces
- Classes
- Files
- Directories

- File List
- File Members

# QTDec.cpp

    00001 /*
    00002  *      Copyright (C) 2003-2005 Gabest
    00003  *      http://www.gabest.org
    00004  *
    00005  *  This Program is free software; you can redistribute it and/or modify
    00006  *  it under the terms of the GNU General Public License as published by
    00007  *  the Free Software Foundation; either version 2, or (at your option)
    00008  *  any later version.
    00009  *
    00010  *  This Program is distributed in the hope that it will be useful,
    00011  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
    00012  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    00013  *  GNU General Public License for more details.
    00014  *
    00015  *  You should have received a copy of the GNU General Public License
    00016  *  along with GNU Make; see the file COPYING.  If not, write to
    00017  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
    00018  *  http://www.gnu.org/copyleft/gpl.html
    00019  *
    00020  */
    00021
    00022 #include "StdAfx.h"
    00023 #include <atlbase.h>
    00024 #include "..\..\..\DSUtil\MediaTypes.h"
    00025 #include <initguid.h>
    00026 #include "qtdec.h"
    00027
    00028 using namespace QT;
    00029
    00030 static DWORD DWSWAP(DWORD dw) {return(((dw&0xff)<<24)|((dw&0xff00)<<8)|((dw&0xff0000)>>8)|((dw&0xff000000)>>24));}
    00031
    00032 #ifdef REGISTER_FILTER
    00033
    00034 const AMOVIESETUP_MEDIATYPE sudPinTypesIn[] =
    00035 {
    00036         {&MEDIATYPE_Video, &MEDIASUBTYPE_NULL},
    00037 };
    00038
    00039 const AMOVIESETUP_MEDIATYPE sudPinTypesOut[] =
    00040 {
    00041         {&MEDIATYPE_Video, &MEDIASUBTYPE_NULL},
    00042 };
    00043
    00044 const AMOVIESETUP_PIN sudpPins[] =
    00045 {
    00046     { L"Input",             // Pins string name
    00047       FALSE,                // Is it rendered
    00048       FALSE,                // Is it an output
    00049       FALSE,                // Are we allowed none
    00050       FALSE,                // And allowed many
    00051       &CLSID_NULL,          // Connects to filter
    00052       NULL,                 // Connects to pin
    00053       countof(sudPinTypesIn),   // Number of types
    00054       sudPinTypesIn                     // Pin information
    00055     },
    00056     { L"Output",            // Pins string name
    00057       FALSE,                // Is it rendered
    00058       TRUE,                 // Is it an output
    00059       FALSE,                // Are we allowed none
    00060       FALSE,                // And allowed many
    00061       &CLSID_NULL,          // Connects to filter
    00062       NULL,                 // Connects to pin
    00063       countof(sudPinTypesOut),  // Number of types
    00064       sudPinTypesOut            // Pin information
    00065     }
    00066 };
    00067
    00068 const AMOVIESETUP_FILTER sudFilter =
    00069 {
    00070     &CLSID_QTDec,                       // Filter CLSID
    00071     L"QuickTime Decoder",       // String name
    00072     MERIT_DO_NOT_USE/*MERIT_NORMAL*/,                   // Filter merit
    00073     countof(sudpPins),  // Number of pins
    00074     sudpPins                // Pin information
    00075 };
    00076
    00077 CFactoryTemplate g_Templates[] =
    00078 {
    00079     { L"QuickTime Decoder"
    00080     , &CLSID_QTDec
    00081     , CQTDec::CreateInstance
    00082     , NULL
    00083     , &sudFilter }
    00084 };
    00085
    00086 int g_cTemplates = countof(g_Templates);
    00087
    00088 STDAPI DllRegisterServer()
    00089 {
    00090         return AMovieDllRegisterServer2(TRUE);
    00091 }
    00092
    00093 STDAPI DllUnregisterServer()
    00094 {
    00095         return AMovieDllRegisterServer2(FALSE);
    00096 }
    00097
    00098 extern "C" BOOL WINAPI DllEntryPoint(HINSTANCE, ULONG, LPVOID);
    00099
    00100 BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved)
    00101 {
    00102     return DllEntryPoint((HINSTANCE)hModule, dwReason, 0); // "DllMain" of the dshow baseclasses;
    00103 }
    00104
    00105 //
    00106 // CQTDec
    00107 //
    00108
    00109 CUnknown* WINAPI CQTDec::CreateInstance(LPUNKNOWN lpunk, HRESULT* phr)
    00110 {
    00111     CUnknown* punk = new CQTDec(lpunk, phr);
    00112     if(punk == NULL) *phr = E_OUTOFMEMORY;
    00113         return punk;
    00114 }
    00115
    00116 #endif
    00117
    00118 CQTDec::CQTDec(LPUNKNOWN lpunk, HRESULT* phr)
    00119         : CTransformFilter(NAME("CQTDec"), lpunk, CLSID_QTDec)
    00120         , m_fQtInitialized(false)
    00121         , m_pImageGWorld(NULL)
    00122         , m_hImageDesc(NULL)
    00123         , m_cinst(NULL)
    00124 {
    00125         if(phr) *phr = S_OK;
    00126
    00127         m_fQtInitialized = false;
    00128         if(InitializeQTML(0) != 0) {if(phr) *phr = E_FAIL; return;}
    00129 //      if(EnterMovies() != 0) {TerminateQTML(); if(phr) *phr = E_FAIL; return;}
    00130         m_fQtInitialized = true;
    00131 }
    00132
    00133 CQTDec::~CQTDec()
    00134 {
    00135         if(m_cinst)
    00136                 CloseComponent(m_cinst),
    00137                 m_cinst = NULL;
    00138
    00139         if(m_hImageDesc)
    00140                 DisposeHandle((Handle)m_hImageDesc),
    00141                 m_hImageDesc = NULL;
    00142
    00143         FreeGWorld(m_pImageGWorld);
    00144
    00145         if(m_fQtInitialized)
    00146         {
    00147 //              ExitMovies();
    00148                 TerminateQTML();
    00149         }
    00150 }
    00151
    00152 //
    00153
    00154 GWorldPtr CQTDec::MakeGWorld()
    00155 {
    00156         if(!m_pOutput->IsConnected())
    00157                 return NULL;
    00158
    00159         const CMediaType& mt = m_pOutput->CurrentMediaType();
    00160         VIDEOINFOHEADER* vih = (VIDEOINFOHEADER*)mt.pbFormat;
    00161         BITMAPINFOHEADER& bih = vih->bmiHeader;
    00162
    00163         GWorldPtr pImageWorld = NULL;
    00164         Rect rect = {0, 0, (short)abs(bih.biHeight), (short)bih.biWidth};
    00165
    00166         OSType PixelFormat =
    00167                 mt.subtype == MEDIASUBTYPE_YUY2 ? kYUVSPixelFormat : // 'yuvs'
    00168                 mt.subtype == MEDIASUBTYPE_UYVY ? k2vuyPixelFormat : // '2vuy'
    00169                 mt.subtype == MEDIASUBTYPE_RGB32 ? k32BGRAPixelFormat : // 'BGRA'
    00170                 mt.subtype == MEDIASUBTYPE_RGB565 ? k16LE565PixelFormat : // 'L565'
    00171                 mt.subtype == MEDIASUBTYPE_RGB555 ? k16LE555PixelFormat : // 'L555'
    00172                 0;
    00173
    00174         if(!PixelFormat || noErr != QTNewGWorld(&pImageWorld, PixelFormat, &rect, NULL, NULL, 0))
    00175                 pImageWorld = NULL;
    00176
    00177         if(pImageWorld)
    00178         LockPixels(GetGWorldPixMap(pImageWorld));
    00179
    00180         return pImageWorld;
    00181 }
    00182
    00183 void CQTDec::FreeGWorld(GWorldPtr& pImageGWorld)
    00184 {
    00185         if(pImageGWorld)
    00186         {
    00187         UnlockPixels(GetGWorldPixMap(pImageGWorld));
    00188                 DisposeGWorld(pImageGWorld);
    00189                 pImageGWorld = NULL;
    00190         }
    00191 }
    00192
    00193 bool CQTDec::InitComponent()
    00194 {
    00195         if(m_cinst)
    00196                 CloseComponent(m_cinst),
    00197                 m_cinst = NULL;
    00198
    00199         if(m_hImageDesc)
    00200                 DisposeHandle((Handle)m_hImageDesc),
    00201                 m_hImageDesc = NULL;
    00202
    00203         if(!m_pInput->IsConnected())
    00204                 return NULL;
    00205
    00206         BITMAPINFOHEADER& bih = ((VIDEOINFOHEADER*)m_pInput->CurrentMediaType().pbFormat)->bmiHeader;
    00207
    00208         ComponentDescription cd = {decompressorComponentType, DWSWAP(bih.biCompression), 0, 0, 0};
    00209         Component c = FindNextComponent(0, &cd);
    00210         if(!c) return(false);
    00211
    00212         m_cinst = OpenComponent(c);
    00213         if(!m_cinst) return(false);
    00214
    00215         ComponentResult cres;
    00216
    00217     ImageSubCodecDecompressCapabilities icap;
    00218     memset(&icap, 0, sizeof(icap));
    00219     cres = ImageCodecInitialize(m_cinst, &icap);
    00220
    00221     CodecInfo cinfo;
    00222     memset(&cinfo, 0, sizeof(cinfo));
    00223     cres = ImageCodecGetCodecInfo(m_cinst, &cinfo);
    00224
    00225         m_hImageDesc = (ImageDescriptionHandle)NewHandleClear(sizeof(ImageDescription));
    00226         if(!m_hImageDesc)
    00227                 return(false);
    00228
    00229     (**m_hImageDesc).idSize = sizeof(ImageDescription);
    00230         (**m_hImageDesc).cType = DWSWAP(bih.biCompression);
    00231     (**m_hImageDesc).temporalQuality = 0;
    00232     (**m_hImageDesc).spatialQuality = codecNormalQuality;
    00233         (**m_hImageDesc).width = (short)bih.biWidth;
    00234     (**m_hImageDesc).height = (short)abs(bih.biHeight);
    00235     (**m_hImageDesc).hRes = 72 << 16;
    00236     (**m_hImageDesc).vRes = 72 << 16;
    00237     (**m_hImageDesc).frameCount = 1; // ?
    00238         (**m_hImageDesc).depth = bih.biBitCount; // should be 24 for unknown/compressed types
    00239     (**m_hImageDesc).clutID = -1;
    00240
    00241         memset(&m_cdpar, 0, sizeof(m_cdpar));
    00242     m_cdpar.imageDescription = m_hImageDesc;
    00243     m_cdpar.startLine = 0;
    00244     m_cdpar.stopLine = (**m_hImageDesc).height;
    00245     m_cdpar.frameNumber = 1;
    00246     m_cdpar.matrixFlags = 0;
    00247     m_cdpar.matrixType = 0;
    00248     m_cdpar.matrix = 0;
    00249     m_cdpar.capabilities = &m_ccap;
    00250         memset(&m_ccap, 0, sizeof(m_ccap));
    00251     m_cdpar.accuracy = codecNormalQuality;
    00252     m_cdpar.port = m_pImageGWorld;
    00253         Rect rect = {0, 0, (**m_hImageDesc).height, (**m_hImageDesc).width};
    00254         m_cdpar.srcRect = rect;
    00255     m_cdpar.transferMode = srcCopy;
    00256     m_cdpar.dstPixMap = **GetGWorldPixMap(m_pImageGWorld);
    00257
    00258     cres = ImageCodecPreDecompress(m_cinst, &m_cdpar);
    00259
    00260         return(true);
    00261 }
    00262
    00263 //
    00264
    00265 HRESULT CQTDec::BreakConnect(PIN_DIRECTION dir)
    00266 {
    00267         if(dir == PINDIR_INPUT)
    00268         {
    00269                 m_mts.RemoveAll();
    00270         }
    00271         else if(dir == PINDIR_OUTPUT)
    00272         {
    00273                 FreeGWorld(m_pImageGWorld);
    00274         }
    00275
    00276         return __super::BreakConnect(dir);
    00277 }
    00278
    00279 HRESULT CQTDec::CompleteConnect(PIN_DIRECTION dir, IPin* pReceivePin)
    00280 {
    00281         if(dir == PINDIR_INPUT)
    00282         {
    00283                 m_mts.RemoveAll();
    00284
    00285                 VIDEOINFOHEADER* vihin = (VIDEOINFOHEADER*)m_pInput->CurrentMediaType().pbFormat;
    00286                 BITMAPINFOHEADER& bihin = vihin->bmiHeader;
    00287
    00288                 CMediaType mt;
    00289                 mt.majortype = MEDIATYPE_Video;
    00290                 mt.subtype = MEDIASUBTYPE_None;
    00291                 mt.formattype = FORMAT_VideoInfo;
    00292                 mt.bFixedSizeSamples = TRUE;
    00293                 mt.bTemporalCompression = FALSE;
    00294                 mt.lSampleSize = 0;
    00295                 mt.pUnk = NULL;
    00296
    00297                 VIDEOINFOHEADER vih;
    00298                 memset(&vih, 0, sizeof(vih));
    00299                 vih.AvgTimePerFrame = vihin->AvgTimePerFrame;
    00300                 vih.rcSource = vihin->rcSource;
    00301                 vih.rcTarget = vihin->rcTarget;
    00302                 vih.dwBitRate = vihin->dwBitRate;
    00303                 vih.dwBitErrorRate = vihin->dwBitErrorRate;
    00304
    00305                 BITMAPINFOHEADER& bih = vih.bmiHeader;
    00306                 bih.biSize = sizeof(bih);
    00307                 bih.biWidth = bihin.biWidth;
    00308                 bih.biHeight = abs(bihin.biHeight);
    00309                 bih.biPlanes = 1;
    00310                 bih.biXPelsPerMeter = bih.biYPelsPerMeter = 0;
    00311                 bih.biClrUsed = bih.biClrImportant = 0;
    00312
    00313 //              if(fRGB32) // always can decompress to (?)
    00314                 {
    00315                         VIDEOINFOHEADER* vihout = (VIDEOINFOHEADER*)mt.AllocFormatBuffer(sizeof(VIDEOINFOHEADER));
    00316                         memcpy(vihout, &vih, sizeof(vih));
    00317
    00318                         BITMAPINFOHEADER& bihout = vihout->bmiHeader;
    00319                         bihout.biBitCount = 32;
    00320                         bihout.biSizeImage = bihout.biWidth*abs(bihout.biHeight)*bihout.biBitCount>>3;
    00321
    00322                         mt.subtype = MEDIASUBTYPE_RGB32;
    00323
    00324                         ((VIDEOINFOHEADER*)mt.pbFormat)->bmiHeader.biCompression = BI_BITFIELDS;
    00325                         ((VIDEOINFOHEADER*)mt.pbFormat)->bmiHeader.biHeight = -bih.biHeight;
    00326                         CorrectMediaType(&mt);
    00327                         m_mts.Add(mt);
    00328
    00329                         ((VIDEOINFOHEADER*)mt.pbFormat)->bmiHeader.biCompression = BI_RGB;
    00330                         ((VIDEOINFOHEADER*)mt.pbFormat)->bmiHeader.biHeight = bih.biHeight;
    00331                         CorrectMediaType(&mt);
    00332                         m_mts.Add(mt);
    00333                 }
    00334
    00335 //              if(fRGB16) // always can decompress to (?)
    00336                 {
    00337                         VIDEOINFOHEADER* vihout = (VIDEOINFOHEADER*)mt.AllocFormatBuffer(sizeof(VIDEOINFOHEADER));
    00338                         memcpy(vihout, &vih, sizeof(vih));
    00339
    00340                         BITMAPINFOHEADER& bihout = vihout->bmiHeader;
    00341                         bihout.biBitCount = 16;
    00342                         bihout.biSizeImage = bihout.biWidth*abs(bihout.biHeight)*bihout.biBitCount>>3;
    00343
    00344                         mt.subtype = MEDIASUBTYPE_RGB565;
    00345
    00346                         ((VIDEOINFOHEADER*)mt.pbFormat)->bmiHeader.biCompression = BI_BITFIELDS;
    00347                         ((VIDEOINFOHEADER*)mt.pbFormat)->bmiHeader.biHeight = -bih.biHeight;
    00348                         CorrectMediaType(&mt);
    00349                         m_mts.Add(mt);
    00350
    00351                         ((VIDEOINFOHEADER*)mt.pbFormat)->bmiHeader.biCompression = BI_RGB;
    00352                         ((VIDEOINFOHEADER*)mt.pbFormat)->bmiHeader.biHeight = bih.biHeight;
    00353                         CorrectMediaType(&mt);
    00354                         m_mts.Add(mt);
    00355
    00356                         mt.subtype = MEDIASUBTYPE_RGB555;
    00357
    00358                         ((VIDEOINFOHEADER*)mt.pbFormat)->bmiHeader.biCompression = BI_BITFIELDS;
    00359                         ((VIDEOINFOHEADER*)mt.pbFormat)->bmiHeader.biHeight = -bih.biHeight;
    00360                         CorrectMediaType(&mt);
    00361                         m_mts.Add(mt);
    00362
    00363                         ((VIDEOINFOHEADER*)mt.pbFormat)->bmiHeader.biCompression = BI_RGB;
    00364                         ((VIDEOINFOHEADER*)mt.pbFormat)->bmiHeader.biHeight = bih.biHeight;
    00365                         CorrectMediaType(&mt);
    00366                         m_mts.Add(mt);
    00367                 }
    00368         }
    00369         else if(dir == PINDIR_OUTPUT)
    00370         {
    00371                 FreeGWorld(m_pImageGWorld);
    00372                 m_pImageGWorld = MakeGWorld();
    00373         }
    00374
    00375         return __super::CompleteConnect(dir, pReceivePin);
    00376 }
    00377
    00378 HRESULT CQTDec::Transform(IMediaSample* pSample, IMediaSample* pOutSample)
    00379 {
    00380         HRESULT hr;
    00381
    00382         BYTE* pIn = NULL;
    00383         if(FAILED(hr = pSample->GetPointer(&pIn))) return hr;
    00384         long len = pSample->GetActualDataLength();
    00385         if(len <= 0) return S_FALSE;
    00386
    00387         BYTE* pOut = NULL;
    00388         if(FAILED(hr = pOutSample->GetPointer(&pOut))) return hr;
    00389         int size = pOutSample->GetSize();
    00390
    00391         VIDEOINFOHEADER* vih = (VIDEOINFOHEADER*)m_pOutput->CurrentMediaType().pbFormat;
    00392         BITMAPINFOHEADER& bih = vih->bmiHeader;
    00393
    00394         bool fInitialized = true;
    00395
    00396         if(m_cinst)
    00397         {
    00398                 AM_MEDIA_TYPE* pmt = NULL;
    00399                 if(S_OK == pSample->GetMediaType((AM_MEDIA_TYPE**)&pmt) && pmt)
    00400                 {
    00401                         CMediaType mt(*pmt);
    00402                         DeleteMediaType(pmt), pmt = NULL;
    00403
    00404                         if(mt != m_pInput->CurrentMediaType())
    00405                         {
    00406                                 m_pInput->SetMediaType(&mt);
    00407                                 fInitialized = InitComponent();
    00408                         }
    00409                 }
    00410         }
    00411         else
    00412         {
    00413                 fInitialized = InitComponent();
    00414         }
    00415
    00416         if(!fInitialized)
    00417                 return E_FAIL;
    00418
    00419         m_cdpar.data = (Ptr)pIn;
    00420         m_cdpar.bufferSize = len;
    00421         (**m_cdpar.imageDescription).dataSize = len;
    00422     ComponentResult cres = ImageCodecBandDecompress(m_cinst, &m_cdpar);
    00423     m_cdpar.frameNumber++;
    00424
    00425         if(cres == noErr)
    00426         {
    00427                 PixMapHandle hPixMap = GetGWorldPixMap(m_pImageGWorld);
    00428                 Ptr pPixels = GetPixBaseAddr(hPixMap);
    00429                 long theRowBytes = QTGetPixMapHandleRowBytes(hPixMap);
    00430
    00431                 DWORD pitch = bih.biWidth*bih.biBitCount>>3;
    00432
    00433                 for(int i = 0, h = abs(bih.biHeight); i < h; i++)
    00434                 {
    00435                         memcpy(pOut + i*pitch, (BYTE*)pPixels + i*theRowBytes, min(pitch, theRowBytes));
    00436                 }
    00437         }
    00438
    00439         return S_OK;
    00440 }
    00441
    00442 HRESULT CQTDec::CheckInputType(const CMediaType* mtIn)
    00443 {
    00444         if(mtIn->majortype != MEDIATYPE_Video || mtIn->formattype != FORMAT_VideoInfo)
    00445                 return VFW_E_TYPE_NOT_ACCEPTED;
    00446
    00447         VIDEOINFOHEADER* vih = (VIDEOINFOHEADER*)mtIn->pbFormat;
    00448         BITMAPINFOHEADER& bih = vih->bmiHeader;
    00449
    00450         OSErr err;
    00451         ComponentInstance ci;
    00452         if(noErr == (err = OpenADefaultComponent('imdc', DWSWAP(bih.biCompression), &ci)))
    00453         {
    00454                 err = CloseComponent(ci);
    00455                 return S_OK;
    00456         }
    00457
    00458         return VFW_E_TYPE_NOT_ACCEPTED;
    00459 }
    00460
    00461 HRESULT CQTDec::CheckTransform(const CMediaType* mtIn, const CMediaType* mtOut)
    00462 {
    00463         return S_OK;
    00464         // TODO
    00465         return VFW_E_TYPE_NOT_ACCEPTED;
    00466 }
    00467
    00468 HRESULT CQTDec::DecideBufferSize(IMemAllocator* pAllocator, ALLOCATOR_PROPERTIES* pProperties)
    00469 {
    00470         if(m_pInput->IsConnected() == FALSE) return E_UNEXPECTED;
    00471
    00472         CComPtr<IMemAllocator> pAllocatorIn;
    00473         m_pInput->GetAllocator(&pAllocatorIn);
    00474         if(!pAllocatorIn) return E_UNEXPECTED;
    00475
    00476         pAllocatorIn->GetProperties(pProperties);
    00477
    00478         VIDEOINFOHEADER* vih = (VIDEOINFOHEADER*)m_pInput->CurrentMediaType().pbFormat;
    00479         BITMAPINFOHEADER& bih = vih->bmiHeader;
    00480
    00481         pProperties->cBuffers = 1;
    00482         pProperties->cbBuffer = bih.biWidth*abs(bih.biHeight)*4; // TODO
    00483         pProperties->cbAlign = 1;
    00484         pProperties->cbPrefix = 0;
    00485
    00486         HRESULT hr;
    00487         ALLOCATOR_PROPERTIES Actual;
    00488     if(FAILED(hr = pAllocator->SetProperties(pProperties, &Actual)))
    00489                 return hr;
    00490
    00491     return(pProperties->cBuffers > Actual.cBuffers || pProperties->cbBuffer > Actual.cbBuffer
    00492                 ? E_FAIL
    00493                 : NOERROR);
    00494 }
    00495
    00496 HRESULT CQTDec::GetMediaType(int iPosition, CMediaType* pmt)
    00497 {
    00498     if(m_pInput->IsConnected() == FALSE) return E_UNEXPECTED;
    00499
    00500         if(iPosition < 0) return E_INVALIDARG;
    00501         if(iPosition >= m_mts.GetCount()) return VFW_S_NO_MORE_ITEMS;
    00502
    00503         *pmt = m_mts[iPosition];
    00504
    00505         return S_OK;
    00506 }