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 }

Generated on Tue Dec 13 14:47:51 2005 for guliverkli by  doxygen 1.4.5