DSUtil.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 <atlcoll.h>
00024 #include <afxtempl.h>
00025 #include <Shlwapi.h>
00026 #include <atlpath.h>
00027 #include <Vfw.h>
00028 #include "..\..\include\winddk\devioctl.h"
00029 #include "..\..\include\winddk\ntddcdrm.h"
00030 #include "DSUtil.h"
00031 #include "..\..\include\moreuuids.h"
00032 
00033 void DumpStreamConfig(TCHAR* fn, IAMStreamConfig* pAMVSCCap)
00034 {
00035         CString s, ss;
00036         CStdioFile f;
00037         if(!f.Open(fn, CFile::modeCreate|CFile::modeWrite|CFile::typeText))
00038                 return;
00039 
00040         int cnt = 0, size = 0;
00041         if(FAILED(pAMVSCCap->GetNumberOfCapabilities(&cnt, &size)))
00042                 return;
00043 
00044         s.Empty();
00045         s.Format(_T("cnt %d, size %d\n"), cnt, size);
00046         f.WriteString(s);
00047 
00048         if(size == sizeof(VIDEO_STREAM_CONFIG_CAPS))
00049         {
00050                 for(int i = 0; i < cnt; i++)
00051                 {
00052                         AM_MEDIA_TYPE* pmt = NULL;
00053 
00054                         VIDEO_STREAM_CONFIG_CAPS caps;
00055                         memset(&caps, 0, sizeof(caps));
00056 
00057                         s.Empty();
00058                         ss.Format(_T("%d\n"), i); s += ss;
00059                         f.WriteString(s);
00060 
00061                         if(FAILED(pAMVSCCap->GetStreamCaps(i, &pmt, (BYTE*)&caps)))
00062                                 continue;
00063 
00064                         {
00065                                 s.Empty();
00066                                 ss.Format(_T("VIDEO_STREAM_CONFIG_CAPS\n")); s += ss;
00067                                 ss.Format(_T("\tVideoStandard 0x%08x\n"), caps.VideoStandard); s += ss;
00068                                 ss.Format(_T("\tInputSize %dx%d\n"), caps.InputSize); s += ss;
00069                                 ss.Format(_T("\tCroppingSize %dx%d - %dx%d\n"), caps.MinCroppingSize, caps.MaxCroppingSize); s += ss;
00070                                 ss.Format(_T("\tCropGranularity %d, %d\n"), caps.CropGranularityX, caps.CropGranularityY); s += ss;
00071                                 ss.Format(_T("\tCropAlign %d, %d\n"), caps.CropAlignX, caps.CropAlignY); s += ss;
00072                                 ss.Format(_T("\tOutputSize %dx%d - %dx%d\n"), caps.MinOutputSize, caps.MaxOutputSize); s += ss;
00073                                 ss.Format(_T("\tOutputGranularity %d, %d\n"), caps.OutputGranularityX, caps.OutputGranularityY); s += ss;
00074                                 ss.Format(_T("\tStretchTaps %d, %d\n"), caps.StretchTapsX, caps.StretchTapsY); s += ss;
00075                                 ss.Format(_T("\tShrinkTaps %d, %d\n"), caps.ShrinkTapsX, caps.ShrinkTapsY); s += ss;
00076                                 ss.Format(_T("\tFrameInterval %I64d, %I64d (%.4f, %.4f)\n"), 
00077                                         caps.MinFrameInterval, caps.MaxFrameInterval,
00078                                         (float)10000000/caps.MinFrameInterval, (float)10000000/caps.MaxFrameInterval); s += ss;
00079                                 ss.Format(_T("\tBitsPerSecond %d - %d\n"), caps.MinBitsPerSecond, caps.MaxBitsPerSecond); s += ss;
00080                                 f.WriteString(s);
00081                         }
00082 
00083                         BITMAPINFOHEADER* pbh;
00084                         if(pmt->formattype == FORMAT_VideoInfo) 
00085                         {
00086                                 VIDEOINFOHEADER* vih = (VIDEOINFOHEADER*)pmt->pbFormat;
00087                                 pbh = &vih->bmiHeader;
00088 
00089                                 s.Empty();
00090                                 ss.Format(_T("FORMAT_VideoInfo\n")); s += ss;
00091                                 ss.Format(_T("\tAvgTimePerFrame %I64d, %.4f\n"), vih->AvgTimePerFrame, (float)10000000/vih->AvgTimePerFrame); s += ss;
00092                                 ss.Format(_T("\trcSource %d,%d,%d,%d\n"), vih->rcSource); s += ss;
00093                                 ss.Format(_T("\trcTarget %d,%d,%d,%d\n"), vih->rcTarget); s += ss;
00094                                 f.WriteString(s);
00095                         }
00096                         else if(pmt->formattype == FORMAT_VideoInfo2) 
00097                         {
00098                                 VIDEOINFOHEADER2* vih = (VIDEOINFOHEADER2*)pmt->pbFormat;
00099                                 pbh = &vih->bmiHeader;
00100 
00101                                 s.Empty();
00102                                 ss.Format(_T("FORMAT_VideoInfo2\n")); s += ss;
00103                                 ss.Format(_T("\tAvgTimePerFrame %I64d, %.4f\n"), vih->AvgTimePerFrame, (float)10000000/vih->AvgTimePerFrame); s += ss;
00104                                 ss.Format(_T("\trcSource %d,%d,%d,%d\n"), vih->rcSource); s += ss;
00105                                 ss.Format(_T("\trcTarget %d,%d,%d,%d\n"), vih->rcTarget); s += ss;
00106                                 ss.Format(_T("\tdwInterlaceFlags 0x%x\n"), vih->dwInterlaceFlags); s += ss;
00107                                 ss.Format(_T("\tdwPictAspectRatio %d:%d\n"), vih->dwPictAspectRatioX, vih->dwPictAspectRatioY); s += ss;
00108                                 f.WriteString(s);
00109                         }
00110                         else
00111                         {
00112                                 DeleteMediaType(pmt);
00113                                 continue;
00114                         }
00115 
00116                         s.Empty();
00117                         ss.Format(_T("BITMAPINFOHEADER\n")); s += ss;
00118                         ss.Format(_T("\tbiCompression %x\n"), pbh->biCompression); s += ss;
00119                         ss.Format(_T("\tbiWidth %d\n"), pbh->biWidth); s += ss;
00120                         ss.Format(_T("\tbiHeight %d\n"), pbh->biHeight); s += ss;
00121                         ss.Format(_T("\tbiBitCount %d\n"), pbh->biBitCount); s += ss;
00122                         ss.Format(_T("\tbiPlanes %d\n"), pbh->biPlanes); s += ss;
00123                         ss.Format(_T("\tbiSizeImage %d\n"), pbh->biSizeImage); s += ss;
00124                         f.WriteString(s);
00125 
00126                         DeleteMediaType(pmt);
00127                 }
00128         }
00129         else if(size == sizeof(AUDIO_STREAM_CONFIG_CAPS))
00130         {
00131                 // TODO
00132         }
00133 }
00134 
00135 int CountPins(IBaseFilter* pBF, int& nIn, int& nOut, int& nInC, int& nOutC)
00136 {
00137         nIn = nOut = 0;
00138         nInC = nOutC = 0;
00139 
00140         BeginEnumPins(pBF, pEP, pPin)
00141         {
00142                 PIN_DIRECTION dir;
00143                 if(SUCCEEDED(pPin->QueryDirection(&dir)))
00144                 {
00145                         CComPtr<IPin> pPinConnectedTo;
00146                         pPin->ConnectedTo(&pPinConnectedTo);
00147 
00148                         if(dir == PINDIR_INPUT) {nIn++; if(pPinConnectedTo) nInC++;}
00149                         else if(dir == PINDIR_OUTPUT) {nOut++; if(pPinConnectedTo) nOutC++;}
00150                 }
00151         }
00152         EndEnumPins
00153 
00154         return(nIn+nOut);
00155 }
00156 
00157 bool IsSplitter(IBaseFilter* pBF, bool fCountConnectedOnly)
00158 {
00159         int nIn, nOut, nInC, nOutC;
00160         CountPins(pBF, nIn, nOut, nInC, nOutC);
00161         return(fCountConnectedOnly ? nOutC > 1 : nOut > 1);
00162 }
00163 
00164 bool IsMultiplexer(IBaseFilter* pBF, bool fCountConnectedOnly)
00165 {
00166         int nIn, nOut, nInC, nOutC;
00167         CountPins(pBF, nIn, nOut, nInC, nOutC);
00168         return(fCountConnectedOnly ? nInC > 1 : nIn > 1);
00169 }
00170 
00171 bool IsStreamStart(IBaseFilter* pBF)
00172 {
00173         CComQIPtr<IAMFilterMiscFlags> pAMMF(pBF);
00174         if(pAMMF && pAMMF->GetMiscFlags()&AM_FILTER_MISC_FLAGS_IS_SOURCE)
00175                 return(true);
00176 
00177         int nIn, nOut, nInC, nOutC;
00178         CountPins(pBF, nIn, nOut, nInC, nOutC);
00179         AM_MEDIA_TYPE mt;
00180         CComPtr<IPin> pIn = GetFirstPin(pBF);
00181         return((nOut > 1)
00182                 || (nOut > 0 && nIn == 1 && pIn && SUCCEEDED(pIn->ConnectionMediaType(&mt)) && mt.majortype == MEDIATYPE_Stream));
00183 }
00184 
00185 bool IsStreamEnd(IBaseFilter* pBF)
00186 {
00187         int nIn, nOut, nInC, nOutC;
00188         CountPins(pBF, nIn, nOut, nInC, nOutC);
00189         return(nOut == 0);
00190 }
00191 
00192 bool IsVideoRenderer(IBaseFilter* pBF)
00193 {
00194         int nIn, nOut, nInC, nOutC;
00195         CountPins(pBF, nIn, nOut, nInC, nOutC);
00196 
00197         if(nInC > 0 && nOut == 0)
00198         {
00199                 BeginEnumPins(pBF, pEP, pPin)
00200                 {
00201                         AM_MEDIA_TYPE mt;
00202                         if(S_OK != pPin->ConnectionMediaType(&mt))
00203                                 continue;
00204 
00205                         FreeMediaType(mt);
00206 
00207                         return(!!(mt.majortype == MEDIATYPE_Video));
00208                                 /*&& (mt.formattype == FORMAT_VideoInfo || mt.formattype == FORMAT_VideoInfo2));*/
00209                 }
00210                 EndEnumPins
00211         }
00212 
00213         CLSID clsid;
00214         memcpy(&clsid, &GUID_NULL, sizeof(clsid));
00215         pBF->GetClassID(&clsid);
00216 
00217         return(clsid == CLSID_VideoRenderer || clsid == CLSID_VideoRendererDefault);
00218 }
00219 
00220 #include <initguid.h>
00221 
00222 DEFINE_GUID(CLSID_ReClock, 
00223 0x9dc15360, 0x914c, 0x46b8, 0xb9, 0xdf, 0xbf, 0xe6, 0x7f, 0xd3, 0x6c, 0x6a); 
00224 
00225 bool IsAudioWaveRenderer(IBaseFilter* pBF)
00226 {
00227         int nIn, nOut, nInC, nOutC;
00228         CountPins(pBF, nIn, nOut, nInC, nOutC);
00229 
00230         if(nInC > 0 && nOut == 0 && CComQIPtr<IBasicAudio>(pBF))
00231         {
00232                 BeginEnumPins(pBF, pEP, pPin)
00233                 {
00234                         AM_MEDIA_TYPE mt;
00235                         if(S_OK != pPin->ConnectionMediaType(&mt))
00236                                 continue;
00237 
00238                         FreeMediaType(mt);
00239 
00240                         return(!!(mt.majortype == MEDIATYPE_Audio)
00241                                 /*&& mt.formattype == FORMAT_WaveFormatEx*/);
00242                 }
00243                 EndEnumPins
00244         }
00245 
00246         CLSID clsid;
00247         memcpy(&clsid, &GUID_NULL, sizeof(clsid));
00248         pBF->GetClassID(&clsid);
00249 
00250         return(clsid == CLSID_DSoundRender || clsid == CLSID_AudioRender || clsid == CLSID_ReClock
00251                 || clsid == __uuidof(CNullAudioRenderer) || clsid == __uuidof(CNullUAudioRenderer));
00252 }
00253 
00254 IBaseFilter* GetUpStreamFilter(IBaseFilter* pBF, IPin* pInputPin)
00255 {
00256         BeginEnumPins(pBF, pEP, pPin)
00257         {
00258                 if(pInputPin && pInputPin != pPin) continue;
00259 
00260                 PIN_DIRECTION dir;
00261                 CComPtr<IPin> pPinConnectedTo;
00262                 if(SUCCEEDED(pPin->QueryDirection(&dir)) && dir == PINDIR_INPUT
00263                 && SUCCEEDED(pPin->ConnectedTo(&pPinConnectedTo)))
00264                 {
00265                         return(GetFilterFromPin(pPinConnectedTo));
00266                 }
00267         }
00268         EndEnumPins
00269 
00270         return(NULL);
00271 }
00272 
00273 IPin* GetUpStreamPin(IBaseFilter* pBF, IPin* pInputPin)
00274 {
00275         BeginEnumPins(pBF, pEP, pPin)
00276         {
00277                 if(pInputPin && pInputPin != pPin) continue;
00278 
00279                 PIN_DIRECTION dir;
00280                 CComPtr<IPin> pPinConnectedTo;
00281                 if(SUCCEEDED(pPin->QueryDirection(&dir)) && dir == PINDIR_INPUT
00282                 && SUCCEEDED(pPin->ConnectedTo(&pPinConnectedTo)))
00283                 {
00284                         IPin* pRet = pPinConnectedTo.Detach();
00285                         pRet->Release();
00286                         return(pRet);
00287                 }
00288         }
00289         EndEnumPins
00290 
00291         return(NULL);
00292 }
00293 
00294 IPin* GetFirstPin(IBaseFilter* pBF, PIN_DIRECTION dir)
00295 {
00296         if(!pBF) return(NULL);
00297 
00298         BeginEnumPins(pBF, pEP, pPin)
00299         {
00300                 PIN_DIRECTION dir2;
00301                 pPin->QueryDirection(&dir2);
00302                 if(dir == dir2)
00303                 {
00304                         IPin* pRet = pPin.Detach();
00305                         pRet->Release();
00306                         return(pRet);
00307                 }
00308         }
00309         EndEnumPins
00310 
00311         return(NULL);
00312 }
00313 
00314 IPin* GetFirstDisconnectedPin(IBaseFilter* pBF, PIN_DIRECTION dir)
00315 {
00316         if(!pBF) return(NULL);
00317 
00318         BeginEnumPins(pBF, pEP, pPin)
00319         {
00320                 PIN_DIRECTION dir2;
00321                 pPin->QueryDirection(&dir2);
00322                 CComPtr<IPin> pPinTo;
00323                 if(dir == dir2 && (S_OK != pPin->ConnectedTo(&pPinTo)))
00324                 {
00325                         IPin* pRet = pPin.Detach();
00326                         pRet->Release();
00327                         return(pRet);
00328                 }
00329         }
00330         EndEnumPins
00331 
00332         return(NULL);
00333 }
00334 
00335 int RenderFilterPins(IBaseFilter* pBF, IGraphBuilder* pGB, bool fAll)
00336 {
00337         int nPinsRendered = 0;
00338 
00339         CInterfaceList<IPin> pProcessedPins;
00340 
00341         BeginEnumPins(pBF, pEP, pPin)
00342         {
00343                 PIN_DIRECTION dir;
00344                 CComPtr<IPin> pPinConnectedTo;
00345                 if(SUCCEEDED(pPin->QueryDirection(&dir)) && dir == PINDIR_OUTPUT
00346                 && FAILED(pPin->ConnectedTo(&pPinConnectedTo))
00347                 && !pProcessedPins.Find(pPin))
00348                 {
00349                         CPinInfo pi;
00350                         if(SUCCEEDED(pPin->QueryPinInfo(&pi)))
00351                         {
00352                                 if(pi.achName[0] == '~' && !fAll)
00353                                 {
00354                                         pProcessedPins.AddTail(pPin);
00355                                         continue;
00356                                 }
00357                         }
00358 
00359                         if(FAILED(pPin->ConnectedTo(&pPinConnectedTo)))
00360                         {
00361                                 if(SUCCEEDED(pGB->Render(pPin)) && SUCCEEDED(pPin->ConnectedTo(&pPinConnectedTo)))
00362                                         nPinsRendered++;
00363                         }
00364                                 
00365                         pEP->Reset();
00366                 }
00367 
00368                 pProcessedPins.AddTail(pPin);
00369         }
00370         EndEnumPins
00371 
00372         return(nPinsRendered);
00373 }
00374 
00375 void NukeDownstream(IBaseFilter* pBF, IFilterGraph* pFG)
00376 {
00377         if(!pBF) return;
00378 
00379         BeginEnumPins(pBF, pEP, pPin)
00380         {
00381                 CComPtr<IPin> pPinTo;
00382                 CPinInfo pi;
00383         if(SUCCEEDED(pPin->ConnectedTo(&pPinTo)) && pPinTo
00384                 && SUCCEEDED(pPinTo->QueryPinInfo(&pi)))
00385                 {
00386                         if(pi.dir == PINDIR_INPUT)
00387                         {
00388                                 NukeDownstream(pi.pFilter, pFG);
00389                                 pFG->Disconnect(pPinTo);
00390                                 pFG->Disconnect(pPin);
00391                                 pFG->RemoveFilter(pi.pFilter);
00392                         }
00393                 }
00394         }
00395         EndEnumPins
00396 }
00397 
00398 void NukeDownstream(IPin* pPin, IFilterGraph* pFG)
00399 {
00400         CComPtr<IPin> pPinTo;
00401         if(!pPin || FAILED(pPin->ConnectedTo(&pPinTo)) || !pPinTo)
00402                 return;
00403 
00404         CPinInfo pi;
00405         if(FAILED(pPinTo->QueryPinInfo(&pi)) || pi.dir != PINDIR_INPUT)
00406                 return;
00407 
00408         NukeDownstream(pi.pFilter, pFG);
00409 
00410         pFG->RemoveFilter(pi.pFilter);
00411 }
00412 
00413 HRESULT AddFilterToGraph(IFilterGraph* pFG, IBaseFilter* pBF, WCHAR* pName)
00414 {
00415         return GetGraphFromFilter(pBF) ? S_FALSE : pFG->AddFilter(pBF, pName);
00416 }
00417 
00418 IBaseFilter* FindFilter(LPCWSTR clsid, IFilterGraph* pFG)
00419 {
00420         CLSID clsid2;
00421         CLSIDFromString(CComBSTR(clsid), &clsid2);
00422         return(FindFilter(clsid2, pFG));
00423 }
00424 
00425 IBaseFilter* FindFilter(const CLSID& clsid, IFilterGraph* pFG)
00426 {
00427         BeginEnumFilters(pFG, pEF, pBF)
00428         {
00429                 CLSID clsid2;
00430                 if(SUCCEEDED(pBF->GetClassID(&clsid2)) && clsid == clsid2)
00431                         return(pBF);
00432         }
00433         EndEnumFilters
00434 
00435         return NULL;
00436 }
00437 
00438 CStringW GetFilterName(IBaseFilter* pBF)
00439 {
00440         CStringW name;
00441         CFilterInfo fi;
00442         if(pBF && SUCCEEDED(pBF->QueryFilterInfo(&fi)))
00443                 name = fi.achName;
00444         return(name);
00445 }
00446 
00447 CStringW GetPinName(IPin* pPin)
00448 {
00449         CStringW name;
00450         CPinInfo pi;
00451         if(pPin && SUCCEEDED(pPin->QueryPinInfo(&pi))) 
00452                 name = pi.achName;
00453         return(name);
00454 }
00455 
00456 IFilterGraph* GetGraphFromFilter(IBaseFilter* pBF)
00457 {
00458         if(!pBF) return NULL;
00459         IFilterGraph* pGraph = NULL;
00460         CFilterInfo fi;
00461         if(pBF && SUCCEEDED(pBF->QueryFilterInfo(&fi)))
00462                 pGraph = fi.pGraph;
00463         return(pGraph);
00464 }
00465 
00466 IBaseFilter* GetFilterFromPin(IPin* pPin)
00467 {
00468         if(!pPin) return NULL;
00469         IBaseFilter* pBF = NULL;
00470         CPinInfo pi;
00471         if(pPin && SUCCEEDED(pPin->QueryPinInfo(&pi)))
00472                 pBF = pi.pFilter;
00473         return(pBF);
00474 }
00475 
00476 IPin* AppendFilter(IPin* pPin, CString DisplayName, IGraphBuilder* pGB)
00477 {
00478         IPin* pRet = pPin;
00479 
00480         CInterfaceList<IBaseFilter> pFilters;
00481 
00482         do
00483         {
00484                 if(!pPin || DisplayName.IsEmpty() || !pGB)
00485                         break;
00486 
00487                 CComPtr<IPin> pPinTo;
00488                 PIN_DIRECTION dir;
00489                 if(FAILED(pPin->QueryDirection(&dir)) || dir != PINDIR_OUTPUT || SUCCEEDED(pPin->ConnectedTo(&pPinTo)))
00490                         break;
00491 
00492                 CComPtr<IBindCtx> pBindCtx;
00493                 CreateBindCtx(0, &pBindCtx);
00494 
00495                 CComPtr<IMoniker> pMoniker;
00496                 ULONG chEaten;
00497                 if(S_OK != MkParseDisplayName(pBindCtx, CComBSTR(DisplayName), &chEaten, &pMoniker))
00498                         break;
00499 
00500                 CComPtr<IBaseFilter> pBF;
00501                 if(FAILED(pMoniker->BindToObject(pBindCtx, 0, IID_IBaseFilter, (void**)&pBF)) || !pBF)
00502                         break;
00503 
00504                 CComPtr<IPropertyBag> pPB;
00505                 if(FAILED(pMoniker->BindToStorage(pBindCtx, 0, IID_IPropertyBag, (void**)&pPB)))
00506                         break;
00507 
00508                 CComVariant var;
00509                 if(FAILED(pPB->Read(CComBSTR(_T("FriendlyName")), &var, NULL)))
00510                         break;
00511 
00512                 pFilters.AddTail(pBF);
00513                 BeginEnumFilters(pGB, pEnum, pBF2) 
00514                         pFilters.AddTail(pBF2); 
00515                 EndEnumFilters
00516 
00517                 if(FAILED(pGB->AddFilter(pBF, CStringW(var.bstrVal))))
00518                         break;
00519 
00520                 BeginEnumFilters(pGB, pEnum, pBF2) 
00521                         if(!pFilters.Find(pBF2) && SUCCEEDED(pGB->RemoveFilter(pBF2))) 
00522                                 pEnum->Reset();
00523                 EndEnumFilters
00524 
00525                 pPinTo = GetFirstPin(pBF, PINDIR_INPUT);
00526                 if(!pPinTo)
00527                 {
00528                         pGB->RemoveFilter(pBF);
00529                         break;
00530                 }
00531 
00532                 HRESULT hr;
00533                 if(FAILED(hr = pGB->ConnectDirect(pPin, pPinTo, NULL)))
00534                 {
00535                         hr = pGB->Connect(pPin, pPinTo);
00536                         pGB->RemoveFilter(pBF);
00537                         break;
00538                 }
00539 
00540                 BeginEnumFilters(pGB, pEnum, pBF2) 
00541                         if(!pFilters.Find(pBF2) && SUCCEEDED(pGB->RemoveFilter(pBF2))) 
00542                                 pEnum->Reset();
00543                 EndEnumFilters
00544 
00545                 pRet = GetFirstPin(pBF, PINDIR_OUTPUT);
00546                 if(!pRet)
00547                 {
00548                         pRet = pPin;
00549                         pGB->RemoveFilter(pBF);
00550                         break;
00551                 }
00552         }
00553         while(false);
00554 
00555         return(pRet);
00556 }
00557 
00558 IPin* InsertFilter(IPin* pPin, CString DisplayName, IGraphBuilder* pGB)
00559 {
00560         do
00561         {
00562                 if(!pPin || DisplayName.IsEmpty() || !pGB)
00563                         break;
00564 
00565                 PIN_DIRECTION dir;
00566                 if(FAILED(pPin->QueryDirection(&dir)))
00567                         break;
00568 
00569                 CComPtr<IPin> pFrom, pTo;
00570 
00571                 if(dir == PINDIR_INPUT)
00572                 {
00573                         pPin->ConnectedTo(&pFrom);
00574                         pTo = pPin;
00575                 }
00576                 else if(dir == PINDIR_OUTPUT)
00577                 {
00578                         pFrom = pPin;
00579                         pPin->ConnectedTo(&pTo);
00580                 }
00581                 
00582                 if(!pFrom || !pTo)
00583                         break;
00584 
00585                 CComPtr<IBindCtx> pBindCtx;
00586                 CreateBindCtx(0, &pBindCtx);
00587 
00588                 CComPtr<IMoniker> pMoniker;
00589                 ULONG chEaten;
00590                 if(S_OK != MkParseDisplayName(pBindCtx, CComBSTR(DisplayName), &chEaten, &pMoniker))
00591                         break;
00592 
00593                 CComPtr<IBaseFilter> pBF;
00594                 if(FAILED(pMoniker->BindToObject(pBindCtx, 0, IID_IBaseFilter, (void**)&pBF)) || !pBF)
00595                         break;
00596 
00597                 CComPtr<IPropertyBag> pPB;
00598                 if(FAILED(pMoniker->BindToStorage(pBindCtx, 0, IID_IPropertyBag, (void**)&pPB)))
00599                         break;
00600 
00601                 CComVariant var;
00602                 if(FAILED(pPB->Read(CComBSTR(_T("FriendlyName")), &var, NULL)))
00603                         break;
00604 
00605                 if(FAILED(pGB->AddFilter(pBF, CStringW(var.bstrVal))))
00606                         break;
00607 
00608                 CComPtr<IPin> pFromTo = GetFirstPin(pBF, PINDIR_INPUT);
00609                 if(!pFromTo)
00610                 {
00611                         pGB->RemoveFilter(pBF);
00612                         break;
00613                 }
00614 
00615                 if(FAILED(pGB->Disconnect(pFrom)) || FAILED(pGB->Disconnect(pTo)))
00616                 {
00617                         pGB->RemoveFilter(pBF);
00618                         pGB->ConnectDirect(pFrom, pTo, NULL);
00619                         break;
00620                 }
00621 
00622                 HRESULT hr;
00623                 if(FAILED(hr = pGB->ConnectDirect(pFrom, pFromTo, NULL)))
00624                 {
00625                         pGB->RemoveFilter(pBF);
00626                         pGB->ConnectDirect(pFrom, pTo, NULL);
00627                         break;
00628                 }
00629 
00630                 CComPtr<IPin> pToFrom = GetFirstPin(pBF, PINDIR_OUTPUT);
00631                 if(!pToFrom)
00632                 {
00633                         pGB->RemoveFilter(pBF);
00634                         pGB->ConnectDirect(pFrom, pTo, NULL);
00635                         break;
00636                 }
00637 
00638                 if(FAILED(pGB->ConnectDirect(pToFrom, pTo, NULL)))
00639                 {
00640                         pGB->RemoveFilter(pBF);
00641                         pGB->ConnectDirect(pFrom, pTo, NULL);
00642                         break;
00643                 }
00644 
00645                 pPin = pToFrom;
00646         }
00647         while(false);
00648 
00649         return(pPin);
00650 }
00651 
00652 int Eval_Exception(int n_except)
00653 {
00654     if(n_except == STATUS_ACCESS_VIOLATION)
00655         {
00656                 AfxMessageBox(_T("The property page of this filter has just caused a\nmemory access violation. The application will gently die now :)"));
00657         }
00658         
00659         return EXCEPTION_CONTINUE_SEARCH;
00660 }
00661 
00662 void MyOleCreatePropertyFrame(HWND hwndOwner, UINT x, UINT y, LPCOLESTR lpszCaption, ULONG cObjects, LPUNKNOWN FAR* lplpUnk, ULONG cPages, LPCLSID lpPageClsID, LCID lcid, DWORD dwReserved, LPVOID lpvReserved)
00663 {
00664         __try
00665         {
00666                 OleCreatePropertyFrame(hwndOwner, x, y, lpszCaption, cObjects, lplpUnk, cPages, lpPageClsID, lcid, dwReserved, lpvReserved);
00667         }
00668         __except(Eval_Exception(GetExceptionCode()))
00669         {
00670                 // No code; this block never executed.
00671         }
00672 }
00673 
00674 void ShowPPage(CString DisplayName, HWND hParentWnd)
00675 {
00676         CComPtr<IBindCtx> pBindCtx;
00677         CreateBindCtx(0, &pBindCtx);
00678 
00679         CComPtr<IMoniker> pMoniker;
00680         ULONG chEaten;
00681         if(S_OK != MkParseDisplayName(pBindCtx, CStringW(DisplayName), &chEaten, &pMoniker))
00682                 return;
00683 
00684         CComPtr<IBaseFilter> pBF;
00685         if(FAILED(pMoniker->BindToObject(pBindCtx, 0, IID_IBaseFilter, (void**)&pBF)) || !pBF)
00686                 return;
00687 
00688         ShowPPage(pBF, hParentWnd);     
00689 }
00690 
00691 void ShowPPage(IUnknown* pUnk, HWND hParentWnd)
00692 {
00693         CComQIPtr<ISpecifyPropertyPages> pSPP = pUnk;
00694         if(!pSPP) return;
00695 
00696         CString str;
00697 
00698         CComQIPtr<IBaseFilter> pBF = pSPP;
00699         CFilterInfo fi;
00700         CComQIPtr<IPin> pPin = pSPP;
00701         CPinInfo pi;
00702         if(pBF && SUCCEEDED(pBF->QueryFilterInfo(&fi)))
00703                 str = fi.achName;
00704         else if(pPin && SUCCEEDED(pPin->QueryPinInfo(&pi)))
00705                 str = pi.achName;
00706 
00707         CAUUID caGUID;
00708         caGUID.pElems = NULL;
00709         if(SUCCEEDED(pSPP->GetPages(&caGUID)))
00710         {
00711                 IUnknown* lpUnk = NULL;
00712                 pSPP.QueryInterface(&lpUnk);
00713                 MyOleCreatePropertyFrame(
00714                         hParentWnd, 0, 0, CStringW(str), 
00715                         1, (IUnknown**)&lpUnk, 
00716                         caGUID.cElems, caGUID.pElems, 
00717                         0, 0, NULL);
00718                 lpUnk->Release();
00719 
00720                 if(caGUID.pElems) CoTaskMemFree(caGUID.pElems);
00721         }
00722 }
00723 
00724 CLSID GetCLSID(IBaseFilter* pBF)
00725 {
00726         CLSID clsid = GUID_NULL;
00727         if(pBF) pBF->GetClassID(&clsid);
00728         return(clsid);
00729 }
00730 
00731 CLSID GetCLSID(IPin* pPin)
00732 {
00733         return(GetCLSID(GetFilterFromPin(pPin)));
00734 }
00735 
00736 bool IsCLSIDRegistered(LPCTSTR clsid)
00737 {
00738         CString rootkey1(_T("CLSID\\"));
00739         CString rootkey2(_T("CLSID\\{083863F1-70DE-11d0-BD40-00A0C911CE86}\\Instance\\"));
00740 
00741         return ERROR_SUCCESS == CRegKey().Open(HKEY_CLASSES_ROOT, rootkey1 + clsid, KEY_READ)
00742                 || ERROR_SUCCESS == CRegKey().Open(HKEY_CLASSES_ROOT, rootkey2 + clsid, KEY_READ);
00743 }
00744 
00745 bool IsCLSIDRegistered(const CLSID& clsid)
00746 {
00747         bool fRet = false;
00748 
00749         LPOLESTR pStr = NULL;
00750         if(S_OK == StringFromCLSID(clsid, &pStr) && pStr)
00751         {
00752                 fRet = IsCLSIDRegistered(CString(pStr));
00753                 CoTaskMemFree(pStr);
00754         }
00755 
00756         return(fRet);
00757 }
00758 
00759 void StringToBin(CString s, CByteArray& data)
00760 {
00761         s.Trim();
00762         ASSERT((s.GetLength()&1) == 0);
00763         data.SetSize(s.GetLength()/2);
00764 
00765         BYTE b = 0;
00766 
00767         s.MakeUpper();
00768         for(int i = 0, j = s.GetLength(); i < j; i++)
00769         {
00770                 TCHAR c = s[i];
00771                 if(c >= '0' && c <= '9') 
00772                 {
00773                         if(!(i&1)) b = ((char(c-'0')<<4)&0xf0)|(b&0x0f);
00774                         else b = (char(c-'0')&0x0f)|(b&0xf0);
00775                 }
00776                 else if(c >= 'A' && c <= 'F')
00777                 {
00778                         if(!(i&1)) b = ((char(c-'A'+10)<<4)&0xf0)|(b&0x0f);
00779                         else b = (char(c-'A'+10)&0x0f)|(b&0xf0);
00780                 }
00781                 else break;
00782 
00783                 if(i&1)
00784                 {
00785                         data[i>>1] = b;
00786                         b = 0;
00787                 }
00788         }
00789 }
00790 
00791 CString BinToString(BYTE* ptr, int len)
00792 {
00793         CString ret;
00794 
00795         while(len-- > 0)
00796         {
00797                 TCHAR high, low;
00798                 high = (*ptr>>4) >= 10 ? (*ptr>>4)-10 + 'A' : (*ptr>>4) + '0';
00799                 low = (*ptr&0xf) >= 10 ? (*ptr&0xf)-10 + 'A' : (*ptr&0xf) + '0';
00800 
00801                 CString s;
00802                 s.Format(_T("%c%c"), high, low);
00803                 ret += s;
00804 
00805                 ptr++;
00806         }
00807 
00808         return(ret);
00809 }
00810 
00811 static void FindFiles(CString fn, CList<CString>& files)
00812 {
00813         CString path = fn;
00814         path.Replace('/', '\\');
00815         path = path.Left(path.ReverseFind('\\')+1);
00816 
00817         WIN32_FIND_DATA findData;
00818         HANDLE h = FindFirstFile(fn, &findData);
00819         if(h != INVALID_HANDLE_VALUE)
00820         {
00821                 do {files.AddTail(path + findData.cFileName);}
00822                 while(FindNextFile(h, &findData));
00823 
00824                 FindClose(h);
00825         }
00826 }
00827 
00828 cdrom_t GetCDROMType(TCHAR drive, CList<CString>& files)
00829 {
00830         files.RemoveAll();
00831 
00832         CString path;
00833         path.Format(_T("%c:"), drive);
00834 
00835         if(GetDriveType(path + _T("\\")) == DRIVE_CDROM)
00836         {
00837                 // CDROM_VideoCD
00838                 FindFiles(path + _T("\\mpegav\\avseq??.dat"), files);
00839                 FindFiles(path + _T("\\mpegav\\avseq??.mpg"), files);
00840                 FindFiles(path + _T("\\mpeg2\\avseq??.dat"), files);
00841                 FindFiles(path + _T("\\mpeg2\\avseq??.mpg"), files);
00842                 FindFiles(path + _T("\\mpegav\\music??.dat"), files);
00843                 FindFiles(path + _T("\\mpegav\\music??.mpg"), files);
00844                 FindFiles(path + _T("\\mpeg2\\music??.dat"), files);
00845                 FindFiles(path + _T("\\mpeg2\\music??.mpg"), files);
00846                 if(files.GetCount() > 0) return CDROM_VideoCD;
00847 
00848                 // CDROM_DVDVideo
00849                 FindFiles(path + _T("\\VIDEO_TS\\video_ts.ifo"), files);
00850                 if(files.GetCount() > 0) return CDROM_DVDVideo;
00851 
00852                 // CDROM_Audio
00853                 if(!(GetVersion()&0x80000000))
00854                 {
00855                         HANDLE hDrive = CreateFile(CString(_T("\\\\.\\")) + path, GENERIC_READ, FILE_SHARE_READ, NULL, 
00856                                 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, (HANDLE)NULL);
00857                         if(hDrive != INVALID_HANDLE_VALUE)
00858                         {
00859                                 DWORD BytesReturned;
00860                                 CDROM_TOC TOC;
00861                                 if(DeviceIoControl(hDrive, IOCTL_CDROM_READ_TOC, NULL, 0, &TOC, sizeof(TOC), &BytesReturned, 0))
00862                                 {
00863                                         for(int i = TOC.FirstTrack; i <= TOC.LastTrack; i++)
00864                                         {
00865                                                 // MMC-3 Draft Revision 10g: Table 222 – Q Sub-channel control field
00866                                                 TOC.TrackData[i-1].Control &= 5;
00867                                                 if(TOC.TrackData[i-1].Control == 0 || TOC.TrackData[i-1].Control == 1) 
00868                                                 {
00869                                                         CString fn;
00870                                                         fn.Format(_T("%s\\track%02d.cda"), path, i);
00871                                                         files.AddTail(fn);
00872                                                 }
00873                                         }
00874                                 }
00875 
00876                                 CloseHandle(hDrive);
00877                         }
00878                 }
00879                 if(files.GetCount() > 0) return CDROM_Audio;
00880 
00881                 // it is a cdrom but nothing special
00882                 return CDROM_Unknown;
00883         }
00884         
00885         return CDROM_NotFound;
00886 }
00887 
00888 CString GetDriveLabel(TCHAR drive)
00889 {
00890         CString label;
00891 
00892         CString path;
00893         path.Format(_T("%c:\\"), drive);
00894         TCHAR VolumeNameBuffer[MAX_PATH], FileSystemNameBuffer[MAX_PATH];
00895         DWORD VolumeSerialNumber, MaximumComponentLength, FileSystemFlags;
00896         if(GetVolumeInformation(path, 
00897                 VolumeNameBuffer, MAX_PATH, &VolumeSerialNumber, &MaximumComponentLength, 
00898                 &FileSystemFlags, FileSystemNameBuffer, MAX_PATH))
00899         {
00900                 label = VolumeNameBuffer;
00901         }
00902 
00903         return(label);
00904 }
00905 
00906 bool GetKeyFrames(CString fn, CUIntArray& kfs)
00907 {
00908         kfs.RemoveAll();
00909 
00910         CString fn2 = CString(fn).MakeLower();
00911         if(fn2.Mid(fn2.ReverseFind('.')+1) == _T("avi"))
00912         {
00913                 AVIFileInit();
00914             
00915                 PAVIFILE pfile;
00916                 if(AVIFileOpen(&pfile, fn, OF_SHARE_DENY_WRITE, 0L) == 0)
00917                 {
00918                         AVIFILEINFO afi;
00919                         memset(&afi, 0, sizeof(afi));
00920                         AVIFileInfo(pfile, &afi, sizeof(AVIFILEINFO));
00921 
00922                         CComPtr<IAVIStream> pavi;
00923                         if(AVIFileGetStream(pfile, &pavi, streamtypeVIDEO, 0) == AVIERR_OK)
00924                         {
00925                                 AVISTREAMINFO si;
00926                                 AVIStreamInfo(pavi, &si, sizeof(si));
00927 
00928                                 if(afi.dwCaps&AVIFILECAPS_ALLKEYFRAMES)
00929                                 {
00930                                         kfs.SetSize(si.dwLength);
00931                                         for(int kf = 0; kf < si.dwLength; kf++) kfs[kf] = kf;
00932                                 }
00933                                 else
00934                                 {
00935                                         for(int kf = 0; ; kf++)
00936                                         {
00937                                                 kf = pavi->FindSample(kf, FIND_KEY|FIND_NEXT);
00938                                                 if(kf < 0 || kfs.GetCount() > 0 && kfs[kfs.GetCount()-1] >= kf) break;
00939                                                 kfs.Add(kf);
00940                                         }
00941 
00942                                         if(kfs.GetCount() > 0 && kfs[kfs.GetCount()-1] < si.dwLength-1)
00943                                         {
00944                                                 kfs.Add(si.dwLength-1);
00945                                         }
00946                                 }
00947                         }
00948 
00949                         AVIFileRelease(pfile);
00950                 }
00951 
00952                 AVIFileExit();
00953         }
00954 
00955         return(kfs.GetCount() > 0);
00956 }
00957 
00958 DVD_HMSF_TIMECODE RT2HMSF(REFERENCE_TIME rt, double fps)
00959 {
00960         DVD_HMSF_TIMECODE hmsf = 
00961         {
00962                 (BYTE)((rt/10000000/60/60)),
00963                 (BYTE)((rt/10000000/60)%60),
00964                 (BYTE)((rt/10000000)%60),
00965                 (BYTE)(1.0*((rt/10000)%1000) * fps / 1000)
00966         };
00967 
00968         return hmsf;
00969 }
00970 
00971 REFERENCE_TIME HMSF2RT(DVD_HMSF_TIMECODE hmsf, double fps)
00972 {
00973         if(fps == 0) {hmsf.bFrames = 0; fps = 1;}
00974         return (REFERENCE_TIME)((((REFERENCE_TIME)hmsf.bHours*60+hmsf.bMinutes)*60+hmsf.bSeconds)*1000+1.0*hmsf.bFrames*1000/fps)*10000;
00975 }
00976 
00977 HRESULT AddToRot(IUnknown* pUnkGraph, DWORD* pdwRegister) 
00978 {
00979     CComPtr<IRunningObjectTable> pROT;
00980     if(FAILED(GetRunningObjectTable(0, &pROT)))
00981                 return E_FAIL;
00982 
00983         WCHAR wsz[256];
00984     swprintf(wsz, L"FilterGraph %08p pid %08x (MPC)", (DWORD_PTR)pUnkGraph, GetCurrentProcessId());
00985 
00986     HRESULT hr;
00987 
00988         CComPtr<IMoniker> pMoniker;
00989     if(SUCCEEDED(hr = CreateItemMoniker(L"!", wsz, &pMoniker)))
00990         hr = pROT->Register(ROTFLAGS_REGISTRATIONKEEPSALIVE, pUnkGraph, pMoniker, pdwRegister);
00991 
00992         return hr;
00993 }
00994 
00995 void RemoveFromRot(DWORD& dwRegister)
00996 {
00997         CComPtr<IRunningObjectTable> pROT;
00998     if(SUCCEEDED(GetRunningObjectTable(0, &pROT)))
00999         pROT->Revoke(dwRegister);
01000         dwRegister = 0;
01001 }
01002 
01003 void memsetd(void* dst, unsigned int c, int nbytes)
01004 {
01005         __asm
01006         {
01007                 mov eax, c
01008                 mov ecx, nbytes
01009                 shr ecx, 2
01010                 mov edi, dst
01011                 cld
01012                 rep stosd
01013         }
01014 }
01015 
01016 bool ExtractBIH(const AM_MEDIA_TYPE* pmt, BITMAPINFOHEADER* bih)
01017 {
01018         if(pmt)
01019         {
01020                 if(pmt->formattype == FORMAT_VideoInfo)
01021                 {
01022                         VIDEOINFOHEADER* vih = (VIDEOINFOHEADER*)pmt->pbFormat;
01023                         memcpy(bih, &vih->bmiHeader, sizeof(BITMAPINFOHEADER));
01024                 }
01025                 else if(pmt->formattype == FORMAT_VideoInfo2)
01026                 {
01027                         VIDEOINFOHEADER2* vih = (VIDEOINFOHEADER2*)pmt->pbFormat;
01028                         memcpy(bih, &vih->bmiHeader, sizeof(BITMAPINFOHEADER));
01029                 }
01030                 else if(pmt->formattype == FORMAT_MPEGVideo)
01031                 {
01032                         VIDEOINFOHEADER* vih = &((MPEG1VIDEOINFO*)pmt->pbFormat)->hdr;
01033                         memcpy(bih, &vih->bmiHeader, sizeof(BITMAPINFOHEADER));
01034                 }
01035                 else if(pmt->formattype == FORMAT_MPEG2_VIDEO)
01036                 {
01037                         VIDEOINFOHEADER2* vih = &((MPEG2VIDEOINFO*)pmt->pbFormat)->hdr;
01038                         memcpy(bih, &vih->bmiHeader, sizeof(BITMAPINFOHEADER));
01039                 }
01040                 else if(pmt->formattype == FORMAT_DiracVideoInfo)
01041                 {
01042                         VIDEOINFOHEADER2* vih = &((DIRACINFOHEADER*)pmt->pbFormat)->hdr;
01043                         memcpy(bih, &vih->bmiHeader, sizeof(BITMAPINFOHEADER));
01044                 }
01045 
01046                 return(true);
01047         }
01048         
01049         return(false);
01050 }
01051 
01052 bool ExtractBIH(IMediaSample* pMS, BITMAPINFOHEADER* bih)
01053 {
01054         AM_MEDIA_TYPE* pmt = NULL;
01055         pMS->GetMediaType(&pmt);
01056         if(pmt)
01057         {
01058                 bool fRet = ExtractBIH(pmt, bih);
01059                 DeleteMediaType(pmt);
01060                 return(fRet);
01061         }
01062         
01063         return(false);
01064 }
01065 
01066 bool ExtractDim(const AM_MEDIA_TYPE* pmt, int& w, int& h, int& arx, int& ary)
01067 {
01068         w = h = arx = ary = 0;
01069 
01070         if(pmt->formattype == FORMAT_VideoInfo || pmt->formattype == FORMAT_MPEGVideo)
01071         {
01072                 VIDEOINFOHEADER* vih = (VIDEOINFOHEADER*)pmt->pbFormat;
01073                 w = vih->bmiHeader.biWidth;
01074                 h = abs(vih->bmiHeader.biHeight);
01075                 arx = w * vih->bmiHeader.biYPelsPerMeter;
01076                 ary = h * vih->bmiHeader.biXPelsPerMeter;
01077         }
01078         else if(pmt->formattype == FORMAT_VideoInfo2 || pmt->formattype == FORMAT_MPEG2_VIDEO || pmt->formattype == FORMAT_DiracVideoInfo)
01079         {
01080                 VIDEOINFOHEADER2* vih = (VIDEOINFOHEADER2*)pmt->pbFormat;
01081                 w = vih->bmiHeader.biWidth;
01082                 h = abs(vih->bmiHeader.biHeight);
01083                 arx = vih->dwPictAspectRatioX;
01084                 ary = vih->dwPictAspectRatioY;
01085         }
01086         else
01087         {
01088                 return(false);
01089         }
01090 
01091         if(!arx || !ary)
01092         {
01093                 arx = w;
01094                 ary = h;
01095         }
01096 
01097         BYTE* ptr = NULL;
01098         DWORD len = 0;
01099 
01100         if(pmt->formattype == FORMAT_MPEGVideo)
01101         {
01102                 ptr = ((MPEG1VIDEOINFO*)pmt->pbFormat)->bSequenceHeader;
01103                 len = ((MPEG1VIDEOINFO*)pmt->pbFormat)->cbSequenceHeader;
01104 
01105                 if(ptr && len >= 8 && *(DWORD*)ptr == 0xb3010000)
01106                 {
01107                         w = (ptr[4]<<4)|(ptr[5]>>4);
01108                         h = ((ptr[5]&0xf)<<8)|ptr[6];
01109                         float ar[] = 
01110                         {
01111                                 1.0000f,1.0000f,0.6735f,0.7031f,
01112                                 0.7615f,0.8055f,0.8437f,0.8935f,
01113                                 0.9157f,0.9815f,1.0255f,1.0695f,
01114                                 1.0950f,1.1575f,1.2015f,1.0000f,
01115                         };
01116                         arx = (int)((float)w / ar[ptr[7]>>4] + 0.5);
01117                         ary = h;
01118                 }
01119         }
01120         else if(pmt->formattype == FORMAT_MPEG2_VIDEO)
01121         {
01122                 ptr = (BYTE*)((MPEG2VIDEOINFO*)pmt->pbFormat)->dwSequenceHeader; 
01123                 len = ((MPEG2VIDEOINFO*)pmt->pbFormat)->cbSequenceHeader;
01124 
01125                 if(ptr && len >= 8 && *(DWORD*)ptr == 0xb3010000)
01126                 {
01127                         w = (ptr[4]<<4)|(ptr[5]>>4);
01128                         h = ((ptr[5]&0xf)<<8)|ptr[6];
01129                         struct {int x, y;} ar[] = {{w,h},{4,3},{16,9},{221,100},{w,h}};
01130                         int i = min(max(ptr[7]>>4, 1), 5)-1;
01131                         arx = ar[i].x;
01132                         ary = ar[i].y;
01133                 }
01134         }
01135 
01136         if(ptr && len >= 8)
01137         {
01138 
01139         }
01140 
01141         DWORD a = arx, b = ary;
01142     while(a) {int tmp = a; a = b % tmp; b = tmp;}
01143         if(b) arx /= b, ary /= b;
01144 
01145         return(true);
01146 }
01147 
01148 bool MakeMPEG2MediaType(CMediaType& mt, BYTE* seqhdr, DWORD len, int w, int h)
01149 {
01150         if(len < 4 || *(DWORD*)seqhdr != 0xb3010000) return false;
01151 
01152         BYTE* seqhdr_ext = NULL;
01153 
01154         BYTE* seqhdr_end = seqhdr + 11;
01155         if(seqhdr_end - seqhdr > len) return false;
01156         if(*seqhdr_end & 0x02) seqhdr_end += 64;
01157         if(seqhdr_end - seqhdr > len) return false;
01158         if(*seqhdr_end & 0x01) seqhdr_end += 64;
01159         if(seqhdr_end - seqhdr > len) return false;
01160         seqhdr_end++;
01161         if(seqhdr_end - seqhdr > len) return false;
01162         if(len - (seqhdr_end - seqhdr) > 4 && *(DWORD*)seqhdr_end == 0xb5010000) {seqhdr_ext = seqhdr_end; seqhdr_end += 10;}
01163         if(seqhdr_end - seqhdr > len) return false;
01164 
01165         len = seqhdr_end - seqhdr;
01166         
01167         mt = CMediaType();
01168 
01169         mt.majortype = MEDIATYPE_Video;
01170         mt.subtype = MEDIASUBTYPE_MPEG2_VIDEO;
01171         mt.formattype = FORMAT_MPEG2Video;
01172 
01173         MPEG2VIDEOINFO* vih = (MPEG2VIDEOINFO*)mt.AllocFormatBuffer(FIELD_OFFSET(MPEG2VIDEOINFO, dwSequenceHeader) + len);
01174         memset(mt.Format(), 0, mt.FormatLength());
01175         vih->hdr.bmiHeader.biSize = sizeof(vih->hdr.bmiHeader);
01176         vih->hdr.bmiHeader.biWidth = w;
01177         vih->hdr.bmiHeader.biHeight = h;
01178 
01179         BYTE* pSequenceHeader = (BYTE*)vih->dwSequenceHeader;
01180         memcpy(pSequenceHeader, seqhdr, len);
01181         vih->cbSequenceHeader = len;
01182         
01183         static char profile[8] = 
01184         {
01185                 0, AM_MPEG2Profile_High, AM_MPEG2Profile_SpatiallyScalable, AM_MPEG2Profile_SNRScalable, 
01186                 AM_MPEG2Profile_Main, AM_MPEG2Profile_Simple, 0, 0
01187         };
01188 
01189         static char level[16] =
01190         {
01191                 0, 0, 0, 0, 
01192                 AM_MPEG2Level_High, 0, AM_MPEG2Level_High1440, 0, 
01193                 AM_MPEG2Level_Main, 0, AM_MPEG2Level_Low, 0, 
01194                 0, 0, 0, 0
01195         };
01196 
01197         if(seqhdr_ext && (seqhdr_ext[4] & 0xf0) == 0x10)
01198         {
01199                 vih->dwProfile = profile[seqhdr_ext[4] & 0x07];
01200                 vih->dwLevel = level[seqhdr_ext[5] >> 4];
01201         }
01202 
01203         return true;
01204 }
01205 
01206 unsigned __int64 GetFileVersion(LPCTSTR fn)
01207 {
01208         unsigned __int64 ret = 0;
01209 
01210         DWORD buff[4];
01211         VS_FIXEDFILEINFO* pvsf = (VS_FIXEDFILEINFO*)buff;
01212         DWORD d; // a variable that GetFileVersionInfoSize sets to zero (but why is it needed ?????????????????????????????? :)
01213         DWORD len = GetFileVersionInfoSize((TCHAR*)fn, &d);
01214         
01215         if(len)
01216         {
01217                 TCHAR* b1 = new TCHAR[len];
01218                 if(b1)
01219                 {
01220             UINT uLen;
01221             if(GetFileVersionInfo((TCHAR*)fn, 0, len, b1) && VerQueryValue(b1, _T("\\"), (void**)&pvsf, &uLen))
01222             {
01223                                 ret = ((unsigned __int64)pvsf->dwFileVersionMS<<32) | pvsf->dwFileVersionLS;
01224             }
01225 
01226             delete [] b1;
01227                 }
01228         }
01229 
01230         return ret;
01231 }
01232 
01233 bool CreateFilter(CStringW DisplayName, IBaseFilter** ppBF, CStringW& FriendlyName)
01234 {
01235         if(!ppBF) return(false);
01236 
01237         *ppBF = NULL;
01238         FriendlyName.Empty();
01239 
01240         CComPtr<IBindCtx> pBindCtx;
01241         CreateBindCtx(0, &pBindCtx);
01242 
01243         CComPtr<IMoniker> pMoniker;
01244         ULONG chEaten;
01245         if(S_OK != MkParseDisplayName(pBindCtx, CComBSTR(DisplayName), &chEaten, &pMoniker))
01246                 return(false);
01247 
01248         if(FAILED(pMoniker->BindToObject(pBindCtx, 0, IID_IBaseFilter, (void**)ppBF)) || !*ppBF)
01249                 return(false);
01250 
01251         CComPtr<IPropertyBag> pPB;
01252         CComVariant var;
01253         if(SUCCEEDED(pMoniker->BindToStorage(pBindCtx, 0, IID_IPropertyBag, (void**)&pPB))
01254         && SUCCEEDED(pPB->Read(CComBSTR(_T("FriendlyName")), &var, NULL)))
01255                 FriendlyName = var.bstrVal;
01256 
01257         return(true);
01258 }
01259 
01260 IBaseFilter* AppendFilter(IPin* pPin, IMoniker* pMoniker, IGraphBuilder* pGB)
01261 {
01262         do
01263         {
01264                 if(!pPin || !pMoniker || !pGB)
01265                         break;
01266 
01267                 CComPtr<IPin> pPinTo;
01268                 PIN_DIRECTION dir;
01269                 if(FAILED(pPin->QueryDirection(&dir)) || dir != PINDIR_OUTPUT || SUCCEEDED(pPin->ConnectedTo(&pPinTo)))
01270                         break;
01271 
01272                 CComPtr<IBindCtx> pBindCtx;
01273                 CreateBindCtx(0, &pBindCtx);
01274 
01275                 CComPtr<IPropertyBag> pPB;
01276                 if(FAILED(pMoniker->BindToStorage(pBindCtx, 0, IID_IPropertyBag, (void**)&pPB)))
01277                         break;
01278 
01279                 CComVariant var;
01280                 if(FAILED(pPB->Read(CComBSTR(_T("FriendlyName")), &var, NULL)))
01281                         break;
01282 
01283                 CComPtr<IBaseFilter> pBF;
01284                 if(FAILED(pMoniker->BindToObject(pBindCtx, 0, IID_IBaseFilter, (void**)&pBF)) || !pBF)
01285                         break;
01286 
01287                 if(FAILED(pGB->AddFilter(pBF, CStringW(var.bstrVal))))
01288                         break;
01289 
01290                 BeginEnumPins(pBF, pEP, pPinTo)
01291                 {
01292                         PIN_DIRECTION dir;
01293                         if(FAILED(pPinTo->QueryDirection(&dir)) || dir != PINDIR_INPUT)
01294                                 continue;
01295 
01296                         if(SUCCEEDED(pGB->ConnectDirect(pPin, pPinTo, NULL)))
01297                                 return(pBF);
01298                 }
01299                 EndEnumFilters
01300 
01301                 pGB->RemoveFilter(pBF);
01302         }
01303         while(false);
01304 
01305         return(NULL);
01306 }
01307 
01308 CStringW GetFriendlyName(CStringW DisplayName)
01309 {
01310         CStringW FriendlyName;
01311 
01312         CComPtr<IBindCtx> pBindCtx;
01313         CreateBindCtx(0, &pBindCtx);
01314 
01315         CComPtr<IMoniker> pMoniker;
01316         ULONG chEaten;
01317         if(S_OK != MkParseDisplayName(pBindCtx, CComBSTR(DisplayName), &chEaten, &pMoniker))
01318                 return(false);
01319 
01320         CComPtr<IPropertyBag> pPB;
01321         CComVariant var;
01322         if(SUCCEEDED(pMoniker->BindToStorage(pBindCtx, 0, IID_IPropertyBag, (void**)&pPB))
01323         && SUCCEEDED(pPB->Read(CComBSTR(_T("FriendlyName")), &var, NULL)))
01324                 FriendlyName = var.bstrVal;
01325 
01326         return FriendlyName;
01327 }
01328 
01329 typedef struct
01330 {
01331         CString path;
01332         HINSTANCE hInst;
01333         CLSID clsid;
01334 } ExternalObject;
01335 
01336 static CList<ExternalObject> s_extobjs;
01337 
01338 HRESULT LoadExternalObject(LPCTSTR path, REFCLSID clsid, REFIID iid, void** ppv)
01339 {
01340         CheckPointer(ppv, E_POINTER);
01341 
01342         CString fullpath = MakeFullPath(path);
01343 
01344         HINSTANCE hInst = NULL;
01345         bool fFound = false;
01346 
01347         POSITION pos = s_extobjs.GetHeadPosition();
01348         while(pos)
01349         {
01350                 ExternalObject& eo = s_extobjs.GetNext(pos);
01351                 if(!eo.path.CompareNoCase(fullpath))
01352                 {
01353                         hInst = eo.hInst;
01354                         fFound = true;
01355                         break;
01356                 }
01357         }
01358 
01359         HRESULT hr = E_FAIL;
01360 
01361         if(hInst || (hInst = CoLoadLibrary(CComBSTR(fullpath), TRUE)))
01362         {
01363                 typedef HRESULT (__stdcall * PDllGetClassObject)(REFCLSID rclsid, REFIID riid, LPVOID* ppv);
01364                 PDllGetClassObject p = (PDllGetClassObject)GetProcAddress(hInst, "DllGetClassObject");
01365 
01366                 if(p && FAILED(hr = p(clsid, iid, ppv)))
01367                 {
01368                         CComPtr<IClassFactory> pCF;
01369                         if(SUCCEEDED(hr = p(clsid, __uuidof(IClassFactory), (void**)&pCF)))
01370                         {
01371                                 hr = pCF->CreateInstance(NULL, iid, ppv);
01372                         }
01373                 }
01374         }
01375 
01376         if(FAILED(hr) && hInst && !fFound)
01377         {
01378                 CoFreeLibrary(hInst);
01379                 return hr;
01380         }
01381 
01382         if(hInst && !fFound)
01383         {
01384                 ExternalObject eo;
01385                 eo.path = fullpath;
01386                 eo.hInst = hInst;
01387                 eo.clsid = clsid;
01388                 s_extobjs.AddTail(eo);
01389         }
01390 
01391         return hr;
01392 }
01393 
01394 HRESULT LoadExternalFilter(LPCTSTR path, REFCLSID clsid, IBaseFilter** ppBF)
01395 {
01396         return LoadExternalObject(path, clsid, __uuidof(IBaseFilter), (void**)ppBF);
01397 }
01398 
01399 HRESULT LoadExternalPropertyPage(IPersist* pP, REFCLSID clsid, IPropertyPage** ppPP)
01400 {
01401         CLSID clsid2 = GUID_NULL;
01402         if(FAILED(pP->GetClassID(&clsid2))) return E_FAIL;
01403 
01404         POSITION pos = s_extobjs.GetHeadPosition();
01405         while(pos)
01406         {
01407                 ExternalObject& eo = s_extobjs.GetNext(pos);
01408                 if(eo.clsid == clsid2)
01409                 {
01410                         return LoadExternalObject(eo.path, clsid, __uuidof(IPropertyPage), (void**)ppPP);
01411                 }
01412         }
01413 
01414         return E_FAIL;
01415 }
01416 
01417 void UnloadExternalObjects()
01418 {
01419         POSITION pos = s_extobjs.GetHeadPosition();
01420         while(pos)
01421         {
01422                 ExternalObject& eo = s_extobjs.GetNext(pos);
01423                 CoFreeLibrary(eo.hInst);
01424         }
01425         s_extobjs.RemoveAll();
01426 }
01427 
01428 CString MakeFullPath(LPCTSTR path)
01429 {
01430         CString full(path);
01431         full.Replace('/', '\\');
01432 
01433         CString fn;
01434         fn.ReleaseBuffer(GetModuleFileName(AfxGetInstanceHandle(), fn.GetBuffer(MAX_PATH), MAX_PATH));
01435         CPath p(fn);
01436 
01437         if(full.GetLength() >= 2 && full[0] == '\\' && full[1] != '\\')
01438         {
01439                 p.StripToRoot();
01440                 full = CString(p) + full.Mid(1); 
01441         }
01442         else if(full.Find(_T(":\\")) < 0)
01443         {
01444                 p.RemoveFileSpec();
01445                 p.AddBackslash();
01446                 full = CString(p) + full;
01447         }
01448 
01449         CPath c(full);
01450         c.Canonicalize();
01451         return CString(c);
01452 }
01453 
01454 //
01455 
01456 CString GetMediaTypeName(const GUID& guid)
01457 {
01458         CString ret = guid == GUID_NULL 
01459                 ? _T("Any type") 
01460                 : CString(GuidNames[guid]);
01461 
01462         if(ret == _T("FOURCC GUID"))
01463         {
01464                 CString str;
01465                 if(guid.Data1 >= 0x10000)
01466                         str.Format(_T("Video: %c%c%c%c"), (guid.Data1>>0)&0xff, (guid.Data1>>8)&0xff, (guid.Data1>>16)&0xff, (guid.Data1>>24)&0xff);
01467                 else
01468                         str.Format(_T("Audio: 0x%08x"), guid.Data1);
01469                 ret = str;
01470         }
01471         else if(ret == _T("Unknown GUID Name"))
01472         {
01473                 WCHAR null[128] = {0}, buff[128];
01474                 StringFromGUID2(GUID_NULL, null, 127);
01475                 ret = CString(CStringW(StringFromGUID2(guid, buff, 127) ? buff : null));
01476         }
01477 
01478         return ret;
01479 }
01480 
01481 GUID GUIDFromCString(CString str)
01482 {
01483         GUID guid = GUID_NULL;
01484         CLSIDFromString(CComBSTR(str), &guid);
01485         return guid;
01486 }
01487 
01488 CString CStringFromGUID(const GUID& guid)
01489 {
01490         WCHAR null[128] = {0}, buff[128];
01491         StringFromGUID2(GUID_NULL, null, 127);
01492         return CString(StringFromGUID2(guid, buff, 127) > 0 ? buff : null);
01493 }
01494 
01495 CStringW UTF8To16(LPCSTR utf8)
01496 {
01497         CStringW str;
01498         int n = MultiByteToWideChar(CP_UTF8, 0, utf8, -1, NULL, 0)-1;
01499         if(n < 0) return str;
01500         str.ReleaseBuffer(MultiByteToWideChar(CP_UTF8, 0, utf8, -1, str.GetBuffer(n), n+1)-1);
01501         return str;
01502 }
01503 
01504 CStringA UTF16To8(LPCWSTR utf16)
01505 {
01506         CStringA str;
01507         int n = WideCharToMultiByte(CP_UTF8, 0, utf16, -1, NULL, 0, NULL, NULL)-1;
01508         if(n < 0) return str;
01509         str.ReleaseBuffer(WideCharToMultiByte(CP_UTF8, 0, utf16, -1, str.GetBuffer(n), n+1, NULL, NULL)-1);
01510         return str;
01511 }
01512 
01513 static struct {LPCSTR name, iso6392, iso6391;} s_isolangs[] = 
01514 {
01515         {"Abkhazian", "abk", "ab"},
01516         {"Achinese", "ace", ""},
01517         {"Acoli", "ach", ""},
01518         {"Adangme", "ada", ""},
01519         {"Afar", "aar", "aa"},
01520         {"Afrihili", "afh", ""},
01521         {"Afrikaans", "afr", "af"},
01522         {"Afro-Asiatic (Other)", "afa", ""},
01523         {"Akan", "aka", "ak"},
01524         {"Akkadian", "akk", ""},
01525         {"Albanian", "alb", "sq"},
01526         {"Albanian", "sqi", "sq"},
01527         {"Aleut", "ale", ""},
01528         {"Algonquian languages", "alg", ""},
01529         {"Altaic (Other)", "tut", ""},
01530         {"Amharic", "amh", "am"},
01531         {"Apache languages", "apa", ""},
01532         {"Arabic", "ara", "ar"},
01533         {"Aragonese", "arg", "an"},
01534         {"Aramaic", "arc", ""},
01535         {"Arapaho", "arp", ""},
01536         {"Araucanian", "arn", ""},
01537         {"Arawak", "arw", ""},
01538         {"Armenian", "arm", "hy"},
01539         {"Armenian", "hye", "hy"},
01540         {"Artificial (Other)", "art", ""},
01541         {"Assamese", "asm", "as"},
01542         {"Asturian; Bable", "ast", ""},
01543         {"Athapascan languages", "ath", ""},
01544         {"Australian languages", "aus", ""},
01545         {"Austronesian (Other)", "map", ""},
01546         {"Avaric", "ava", "av"},
01547         {"Avestan", "ave", "ae"},
01548         {"Awadhi", "awa", ""},
01549         {"Aymara", "aym", "ay"},
01550         {"Azerbaijani", "aze", "az"},
01551         {"Bable; Asturian", "ast", ""},
01552         {"Balinese", "ban", ""},
01553         {"Baltic (Other)", "bat", ""},
01554         {"Baluchi", "bal", ""},
01555         {"Bambara", "bam", "bm"},
01556         {"Bamileke languages", "bai", ""},
01557         {"Banda", "bad", ""},
01558         {"Bantu (Other)", "bnt", ""},
01559         {"Basa", "bas", ""},
01560         {"Bashkir", "bak", "ba"},
01561         {"Basque", "baq", "eu"},
01562         {"Basque", "eus", "eu"},
01563         {"Batak (Indonesia)", "btk", ""},
01564         {"Beja", "bej", ""},
01565         {"Belarusian", "bel", "be"},
01566         {"Bemba", "bem", ""},
01567         {"Bengali", "ben", "bn"},
01568         {"Berber (Other)", "ber", ""},
01569         {"Bhojpuri", "bho", ""},
01570         {"Bihari", "bih", "bh"},
01571         {"Bikol", "bik", ""},
01572         {"Bini", "bin", ""},
01573         {"Bislama", "bis", "bi"},
01574         {"Bokmċl, Norwegian; Norwegian Bokmċl", "nob", "nb"},
01575         {"Bosnian", "bos", "bs"},
01576         {"Braj", "bra", ""},
01577         {"Breton", "bre", "br"},
01578         {"Buginese", "bug", ""},
01579         {"Bulgarian", "bul", "bg"},
01580         {"Buriat", "bua", ""},
01581         {"Burmese", "bur", "my"},
01582         {"Burmese", "mya", "my"},
01583         {"Caddo", "cad", ""},
01584         {"Carib", "car", ""},
01585         {"Spanish; Castilian", "spa", "es"},
01586         {"Catalan", "cat", "ca"},
01587         {"Caucasian (Other)", "cau", ""},
01588         {"Cebuano", "ceb", ""},
01589         {"Celtic (Other)", "cel", ""},
01590         {"Central American Indian (Other)", "cai", ""},
01591         {"Chagatai", "chg", ""},
01592         {"Chamic languages", "cmc", ""},
01593         {"Chamorro", "cha", "ch"},
01594         {"Chechen", "che", "ce"},
01595         {"Cherokee", "chr", ""},
01596         {"Chewa; Chichewa; Nyanja", "nya", "ny"},
01597         {"Cheyenne", "chy", ""},
01598         {"Chibcha", "chb", ""},
01599         {"Chichewa; Chewa; Nyanja", "nya", "ny"},
01600         {"Chinese", "chi", "zh"},
01601         {"Chinese", "zho", "zh"},
01602         {"Chinook jargon", "chn", ""},
01603         {"Chipewyan", "chp", ""},
01604         {"Choctaw", "cho", ""},
01605         {"Chuang; Zhuang", "zha", "za"},
01606         {"Church Slavic; Old Church Slavonic", "chu", "cu"},
01607         {"Old Church Slavonic; Old Slavonic; ", "chu", "cu"},
01608         {"Church Slavonic; Old Bulgarian; Church Slavic;", "chu", "cu"},
01609         {"Old Slavonic; Church Slavonic; Old Bulgarian;", "chu", "cu"},
01610         {"Church Slavic; Old Church Slavonic", "chu", "cu"},
01611         {"Chuukese", "chk", ""},
01612         {"Chuvash", "chv", "cv"},
01613         {"Coptic", "cop", ""},
01614         {"Cornish", "cor", "kw"},
01615         {"Corsican", "cos", "co"},
01616         {"Cree", "cre", "cr"},
01617         {"Creek", "mus", ""},
01618         {"Creoles and pidgins (Other)", "crp", ""},
01619         {"Creoles and pidgins,", "cpe", ""},
01620         //   {"English-based (Other)", "", ""},
01621         {"Creoles and pidgins,", "cpf", ""},
01622         //   {"French-based (Other)", "", ""},
01623         {"Creoles and pidgins,", "cpp", ""},
01624         //   {"Portuguese-based (Other)", "", ""},
01625         {"Croatian", "scr", "hr"},
01626         {"Croatian", "hrv", "hr"},
01627         {"Cushitic (Other)", "cus", ""},
01628         {"Czech", "cze", "cs"},
01629         {"Czech", "ces", "cs"},
01630         {"Dakota", "dak", ""},
01631         {"Danish", "dan", "da"},
01632         {"Dargwa", "dar", ""},
01633         {"Dayak", "day", ""},
01634         {"Delaware", "del", ""},
01635         {"Dinka", "din", ""},
01636         {"Divehi", "div", "dv"},
01637         {"Dogri", "doi", ""},
01638         {"Dogrib", "dgr", ""},
01639         {"Dravidian (Other)", "dra", ""},
01640         {"Duala", "dua", ""},
01641         {"Dutch; Flemish", "dut", "nl"},
01642         {"Dutch; Flemish", "nld", "nl"},
01643         {"Dutch, Middle (ca. 1050-1350)", "dum", ""},
01644         {"Dyula", "dyu", ""},
01645         {"Dzongkha", "dzo", "dz"},
01646         {"Efik", "efi", ""},
01647         {"Egyptian (Ancient)", "egy", ""},
01648         {"Ekajuk", "eka", ""},
01649         {"Elamite", "elx", ""},
01650         {"English", "eng", "en"},
01651         {"English, Middle (1100-1500)", "enm", ""},
01652         {"English, Old (ca.450-1100)", "ang", ""},
01653         {"Esperanto", "epo", "eo"},
01654         {"Estonian", "est", "et"},
01655         {"Ewe", "ewe", "ee"},
01656         {"Ewondo", "ewo", ""},
01657         {"Fang", "fan", ""},
01658         {"Fanti", "fat", ""},
01659         {"Faroese", "fao", "fo"},
01660         {"Fijian", "fij", "fj"},
01661         {"Finnish", "fin", "fi"},
01662         {"Finno-Ugrian (Other)", "fiu", ""},
01663         {"Flemish; Dutch", "dut", "nl"},
01664         {"Flemish; Dutch", "nld", "nl"},
01665         {"Fon", "fon", ""},
01666         {"French", "fre", "fr"},
01667         {"French", "fra*", "fr"},
01668         {"French, Middle (ca.1400-1600)", "frm", ""},
01669         {"French, Old (842-ca.1400)", "fro", ""},
01670         {"Frisian", "fry", "fy"},
01671         {"Friulian", "fur", ""},
01672         {"Fulah", "ful", "ff"},
01673         {"Ga", "gaa", ""},
01674         {"Gaelic; Scottish Gaelic", "gla", "gd"},
01675         {"Gallegan", "glg", "gl"},
01676         {"Ganda", "lug", "lg"},
01677         {"Gayo", "gay", ""},
01678         {"Gbaya", "gba", ""},
01679         {"Geez", "gez", ""},
01680         {"Georgian", "geo", "ka"},
01681         {"Georgian", "kat", "ka"},
01682         {"German", "ger", "de"},
01683         {"German", "deu", "de"},
01684         {"German, Low; Saxon, Low; Low German; Low Saxon", "nds", ""},
01685         {"German, Middle High (ca.1050-1500)", "gmh", ""},
01686         {"German, Old High (ca.750-1050)", "goh", ""},
01687         {"Germanic (Other)", "gem", ""},
01688         {"Gikuyu; Kikuyu", "kik", "ki"},
01689         {"Gilbertese", "gil", ""},
01690         {"Gondi", "gon", ""},
01691         {"Gorontalo", "gor", ""},
01692         {"Gothic", "got", ""},
01693         {"Grebo", "grb", ""},
01694         {"Greek, Ancient (to 1453)", "grc", ""},
01695         {"Greek, Modern (1453-)", "gre", "el"},
01696         {"Greek, Modern (1453-)", "ell", "el"},
01697         {"Greenlandic; Kalaallisut", "kal", "kl"},
01698         {"Guarani", "grn", "gn"},
01699         {"Gujarati", "guj", "gu"},
01700         {"Gwich´in", "gwi", ""},
01701         {"Haida", "hai", ""},
01702         {"Hausa", "hau", "ha"},
01703         {"Hawaiian", "haw", ""},
01704         {"Hebrew", "heb", "he"},
01705         {"Herero", "her", "hz"},
01706         {"Hiligaynon", "hil", ""},
01707         {"Himachali", "him", ""},
01708         {"Hindi", "hin", "hi"},
01709         {"Hiri Motu", "hmo", "ho"},
01710         {"Hittite", "hit", ""},
01711         {"Hmong", "hmn", ""},
01712         {"Hungarian", "hun", "hu"},
01713         {"Hupa", "hup", ""},
01714         {"Iban", "iba", ""},
01715         {"Icelandic", "ice", "is"},
01716         {"Icelandic", "isl", "is"},
01717         {"Ido", "ido", "io"},
01718         {"Igbo", "ibo", "ig"},
01719         {"Ijo", "ijo", ""},
01720         {"Iloko", "ilo", ""},
01721         {"Inari Sami", "smn", ""},
01722         {"Indic (Other)", "inc", ""},
01723         {"Indo-European (Other)", "ine", ""},
01724         {"Indonesian", "ind", "id"},
01725         {"Ingush", "inh", ""},
01726         {"Interlingua (International", "ina", "ia"},
01727         //   {"Auxiliary Language Association)", "", ""},
01728         {"Interlingue", "ile", "ie"},
01729         {"Inuktitut", "iku", "iu"},
01730         {"Inupiaq", "ipk", "ik"},
01731         {"Iranian (Other)", "ira", ""},
01732         {"Irish", "gle", "ga"},
01733         {"Irish, Middle (900-1200)", "mga", ""},
01734         {"Irish, Old (to 900)", "sga", ""},
01735         {"Iroquoian languages", "iro", ""},
01736         {"Italian", "ita", "it"},
01737         {"Japanese", "jpn", "ja"},
01738         {"Javanese", "jav", "jv"},
01739         {"Judeo-Arabic", "jrb", ""},
01740         {"Judeo-Persian", "jpr", ""},
01741         {"Kabardian", "kbd", ""},
01742         {"Kabyle", "kab", ""},
01743         {"Kachin", "kac", ""},
01744         {"Kalaallisut; Greenlandic", "kal", "kl"},
01745         {"Kamba", "kam", ""},
01746         {"Kannada", "kan", "kn"},
01747         {"Kanuri", "kau", "kr"},
01748         {"Kara-Kalpak", "kaa", ""},
01749         {"Karen", "kar", ""},
01750         {"Kashmiri", "kas", "ks"},
01751         {"Kawi", "kaw", ""},
01752         {"Kazakh", "kaz", "kk"},
01753         {"Khasi", "kha", ""},
01754         {"Khmer", "khm", "km"},
01755         {"Khoisan (Other)", "khi", ""},
01756         {"Khotanese", "kho", ""},
01757         {"Kikuyu; Gikuyu", "kik", "ki"},
01758         {"Kimbundu", "kmb", ""},
01759         {"Kinyarwanda", "kin", "rw"},
01760         {"Kirghiz", "kir", "ky"},
01761         {"Komi", "kom", "kv"},
01762         {"Kongo", "kon", "kg"},
01763         {"Konkani", "kok", ""},
01764         {"Korean", "kor", "ko"},
01765         {"Kosraean", "kos", ""},
01766         {"Kpelle", "kpe", ""},
01767         {"Kru", "kro", ""},
01768         {"Kuanyama; Kwanyama", "kua", "kj"},
01769         {"Kumyk", "kum", ""},
01770         {"Kurdish", "kur", "ku"},
01771         {"Kurukh", "kru", ""},
01772         {"Kutenai", "kut", ""},
01773         {"Kwanyama, Kuanyama", "kua", "kj"},
01774         {"Ladino", "lad", ""},
01775         {"Lahnda", "lah", ""},
01776         {"Lamba", "lam", ""},
01777         {"Lao", "lao", "lo"},
01778         {"Latin", "lat", "la"},
01779         {"Latvian", "lav", "lv"},
01780         {"Letzeburgesch; Luxembourgish", "ltz", "lb"},
01781         {"Lezghian", "lez", ""},
01782         {"Limburgan; Limburger; Limburgish", "lim", "li"},
01783         {"Limburger; Limburgan; Limburgish;", "lim", "li"},
01784         {"Limburgish; Limburger; Limburgan", "lim", "li"},
01785         {"Lingala", "lin", "ln"},
01786         {"Lithuanian", "lit", "lt"},
01787         {"Low German; Low Saxon; German, Low; Saxon, Low", "nds", ""},
01788         {"Low Saxon; Low German; Saxon, Low; German, Low", "nds", ""},
01789         {"Lozi", "loz", ""},
01790         {"Luba-Katanga", "lub", "lu"},
01791         {"Luba-Lulua", "lua", ""},
01792         {"Luiseno", "lui", ""},
01793         {"Lule Sami", "smj", ""},
01794         {"Lunda", "lun", ""},
01795         {"Luo (Kenya and Tanzania)", "luo", ""},
01796         {"Lushai", "lus", ""},
01797         {"Luxembourgish; Letzeburgesch", "ltz", "lb"},
01798         {"Macedonian", "mac", "mk"},
01799         {"Macedonian", "mkd", "mk"},
01800         {"Madurese", "mad", ""},
01801         {"Magahi", "mag", ""},
01802         {"Maithili", "mai", ""},
01803         {"Makasar", "mak", ""},
01804         {"Malagasy", "mlg", "mg"},
01805         {"Malay", "may", "ms"},
01806         {"Malay", "msa", "ms"},
01807         {"Malayalam", "mal", "ml"},
01808         {"Maltese", "mlt", "mt"},
01809         {"Manchu", "mnc", ""},
01810         {"Mandar", "mdr", ""},
01811         {"Mandingo", "man", ""},
01812         {"Manipuri", "mni", ""},
01813         {"Manobo languages", "mno", ""},
01814         {"Manx", "glv", "gv"},
01815         {"Maori", "mao", "mi"},
01816         {"Maori", "mri", "mi"},
01817         {"Marathi", "mar", "mr"},
01818         {"Mari", "chm", ""},
01819         {"Marshallese", "mah", "mh"},
01820         {"Marwari", "mwr", ""},
01821         {"Masai", "mas", ""},
01822         {"Mayan languages", "myn", ""},
01823         {"Mende", "men", ""},
01824         {"Micmac", "mic", ""},
01825         {"Minangkabau", "min", ""},
01826         {"Miscellaneous languages", "mis", ""},
01827         {"Mohawk", "moh", ""},
01828         {"Moldavian", "mol", "mo"},
01829         {"Mon-Khmer (Other)", "mkh", ""},
01830         {"Mongo", "lol", ""},
01831         {"Mongolian", "mon", "mn"},
01832         {"Mossi", "mos", ""},
01833         {"Multiple languages", "mul", ""},
01834         {"Munda languages", "mun", ""},
01835         {"Nahuatl", "nah", ""},
01836         {"Nauru", "nau", "na"},
01837         {"Navaho, Navajo", "nav", "nv"},
01838         {"Navajo; Navaho", "nav", "nv"},
01839         {"Ndebele, North", "nde", "nd"},
01840         {"Ndebele, South", "nbl", "nr"},
01841         {"Ndonga", "ndo", "ng"},
01842         {"Neapolitan", "nap", ""},
01843         {"Nepali", "nep", "ne"},
01844         {"Newari", "new", ""},
01845         {"Nias", "nia", ""},
01846         {"Niger-Kordofanian (Other)", "nic", ""},
01847         {"Nilo-Saharan (Other)", "ssa", ""},
01848         {"Niuean", "niu", ""},
01849         {"Norse, Old", "non", ""},
01850         {"North American Indian (Other)", "nai", ""},
01851         {"Northern Sami", "sme", "se"},
01852         {"North Ndebele", "nde", "nd"},
01853         {"Norwegian", "nor", "no"},
01854         {"Norwegian Bokmċl; Bokmċl, Norwegian", "nob", "nb"},
01855         {"Norwegian Nynorsk; Nynorsk, Norwegian", "nno", "nn"},
01856         {"Nubian languages", "nub", ""},
01857         {"Nyamwezi", "nym", ""},
01858         {"Nyanja; Chichewa; Chewa", "nya", "ny"},
01859         {"Nyankole", "nyn", ""},
01860         {"Nynorsk, Norwegian; Norwegian Nynorsk", "nno", "nn"},
01861         {"Nyoro", "nyo", ""},
01862         {"Nzima", "nzi", ""},
01863         {"Occitan (post 1500},; Provençal", "oci", "oc"},
01864         {"Ojibwa", "oji", "oj"},
01865         {"Old Bulgarian; Old Slavonic; Church Slavonic;", "chu", "cu"},
01866         {"Oriya", "ori", "or"},
01867         {"Oromo", "orm", "om"},
01868         {"Osage", "osa", ""},
01869         {"Ossetian; Ossetic", "oss", "os"},
01870         {"Ossetic; Ossetian", "oss", "os"},
01871         {"Otomian languages", "oto", ""},
01872         {"Pahlavi", "pal", ""},
01873         {"Palauan", "pau", ""},
01874         {"Pali", "pli", "pi"},
01875         {"Pampanga", "pam", ""},
01876         {"Pangasinan", "pag", ""},
01877         {"Panjabi", "pan", "pa"},
01878         {"Papiamento", "pap", ""},
01879         {"Papuan (Other)", "paa", ""},
01880         {"Persian", "per", "fa"},
01881         {"Persian", "fas", "fa"},
01882         {"Persian, Old (ca.600-400 B.C.)", "peo", ""},
01883         {"Philippine (Other)", "phi", ""},
01884         {"Phoenician", "phn", ""},
01885         {"Pohnpeian", "pon", ""},
01886         {"Polish", "pol", "pl"},
01887         {"Portuguese", "por", "pt"},
01888         {"Prakrit languages", "pra", ""},
01889         {"Provençal; Occitan (post 1500)", "oci", "oc"},
01890         {"Provençal, Old (to 1500)", "pro", ""},
01891         {"Pushto", "pus", "ps"},
01892         {"Quechua", "que", "qu"},
01893         {"Raeto-Romance", "roh", "rm"},
01894         {"Rajasthani", "raj", ""},
01895         {"Rapanui", "rap", ""},
01896         {"Rarotongan", "rar", ""},
01897         {"Reserved for local use", "qaa-qtz", ""},
01898         {"Romance (Other)", "roa", ""},
01899         {"Romanian", "rum", "ro"},
01900         {"Romanian", "ron", "ro"},
01901         {"Romany", "rom", ""},
01902         {"Rundi", "run", "rn"},
01903         {"Russian", "rus", "ru"},
01904         {"Salishan languages", "sal", ""},
01905         {"Samaritan Aramaic", "sam", ""},
01906         {"Sami languages (Other)", "smi", ""},
01907         {"Samoan", "smo", "sm"},
01908         {"Sandawe", "sad", ""},
01909         {"Sango", "sag", "sg"},
01910         {"Sanskrit", "san", "sa"},
01911         {"Santali", "sat", ""},
01912         {"Sardinian", "srd", "sc"},
01913         {"Sasak", "sas", ""},
01914         {"Saxon, Low; German, Low; Low Saxon; Low German", "nds", ""},
01915         {"Scots", "sco", ""},
01916         {"Scottish Gaelic; Gaelic", "gla", "gd"},
01917         {"Selkup", "sel", ""},
01918         {"Semitic (Other)", "sem", ""},
01919         {"Serbian", "scc", "sr"},
01920         {"Serbian", "srp", "sr"},
01921         {"Serer", "srr", ""},
01922         {"Shan", "shn", ""},
01923         {"Shona", "sna", "sn"},
01924         {"Sichuan Yi", "iii", "ii"},
01925         {"Sidamo", "sid", ""},
01926         {"Sign languages", "sgn", ""},
01927         {"Siksika", "bla", ""},
01928         {"Sindhi", "snd", "sd"},
01929         {"Sinhalese", "sin", "si"},
01930         {"Sino-Tibetan (Other)", "sit", ""},
01931         {"Siouan languages", "sio", ""},
01932         {"Skolt Sami", "sms", ""},
01933         {"Slave (Athapascan)", "den", ""},
01934         {"Slavic (Other)", "sla", ""},
01935         {"Slovak", "slo", "sk"},
01936         {"Slovak", "slk", "sk"},
01937         {"Slovenian", "slv", "sl"},
01938         {"Sogdian", "sog", ""},
01939         {"Somali", "som", "so"},
01940         {"Songhai", "son", ""},
01941         {"Soninke", "snk", ""},
01942         {"Sorbian languages", "wen", ""},
01943         {"Sotho, Northern", "nso", ""},
01944         {"Sotho, Southern", "sot", "st"},
01945         {"South American Indian (Other)", "sai", ""},
01946         {"Southern Sami", "sma", ""},
01947         {"South Ndebele", "nbl", "nr"},
01948         {"Spanish; Castilian", "spa", "es"},
01949         {"Sukuma", "suk", ""},
01950         {"Sumerian", "sux", ""},
01951         {"Sundanese", "sun", "su"},
01952         {"Susu", "sus", ""},
01953         {"Swahili", "swa", "sw"},
01954         {"Swati", "ssw", "ss"},
01955         {"Swedish", "swe", "sv"},
01956         {"Syriac", "syr", ""},
01957         {"Tagalog", "tgl", "tl"},
01958         {"Tahitian", "tah", "ty"},
01959         {"Tai (Other)", "tai", ""},
01960         {"Tajik", "tgk", "tg"},
01961         {"Tamashek", "tmh", ""},
01962         {"Tamil", "tam", "ta"},
01963         {"Tatar", "tat", "tt"},
01964         {"Telugu", "tel", "te"},
01965         {"Tereno", "ter", ""},
01966         {"Tetum", "tet", ""},
01967         {"Thai", "tha", "th"},
01968         {"Tibetan", "tib", "bo"},
01969         {"Tibetan", "bod", "bo"},
01970         {"Tigre", "tig", ""},
01971         {"Tigrinya", "tir", "ti"},
01972         {"Timne", "tem", ""},
01973         {"Tiv", "tiv", ""},
01974         {"Tlingit", "tli", ""},
01975         {"Tok Pisin", "tpi", ""},
01976         {"Tokelau", "tkl", ""},
01977         {"Tonga (Nyasa)", "tog", ""},
01978         {"Tonga (Tonga Islands)", "ton", "to"},
01979         {"Tsimshian", "tsi", ""},
01980         {"Tsonga", "tso", "ts"},
01981         {"Tswana", "tsn", "tn"},
01982         {"Tumbuka", "tum", ""},
01983         {"Tupi languages", "tup", ""},
01984         {"Turkish", "tur", "tr"},
01985         {"Turkish, Ottoman (1500-1928)", "ota", ""},
01986         {"Turkmen", "tuk", "tk"},
01987         {"Tuvalu", "tvl", ""},
01988         {"Tuvinian", "tyv", ""},
01989         {"Twi", "twi", "tw"},
01990         {"Ugaritic", "uga", ""},
01991         {"Uighur", "uig", "ug"},
01992         {"Ukrainian", "ukr", "uk"},
01993         {"Umbundu", "umb", ""},
01994         {"Undetermined", "und", ""},
01995         {"Urdu", "urd", "ur"},
01996         {"Uzbek", "uzb", "uz"},
01997         {"Vai", "vai", ""},
01998         {"Venda", "ven", "ve"},
01999         {"Vietnamese", "vie", "vi"},
02000         {"Volapük", "vol", "vo"},
02001         {"Votic", "vot", ""},
02002         {"Wakashan languages", "wak", ""},
02003         {"Walamo", "wal", ""},
02004         {"Walloon", "wln", "wa"},
02005         {"Waray", "war", ""},
02006         {"Washo", "was", ""},
02007         {"Welsh", "wel", "cy"},
02008         {"Welsh", "cym", "cy"},
02009         {"Wolof", "wol", "wo"},
02010         {"Xhosa", "xho", "xh"},
02011         {"Yakut", "sah", ""},
02012         {"Yao", "yao", ""},
02013         {"Yapese", "yap", ""},
02014         {"Yiddish", "yid", "yi"},
02015         {"Yoruba", "yor", "yo"},
02016         {"Yupik languages", "ypk", ""},
02017         {"Zande", "znd", ""},
02018         {"Zapotec", "zap", ""},
02019         {"Zenaga", "zen", ""},
02020         {"Zhuang; Chuang", "zha", "za"},
02021         {"Zulu", "zul", "zu"},
02022         {"Zuni", "zun", ""},
02023         {"Classical Newari", "nwc", ""},
02024         {"Klingon", "tlh", ""},
02025         {"Blin", "byn", ""},
02026         {"Lojban", "jbo", ""},
02027         {"Lower Sorbian", "dsb", ""},
02028         {"Upper Sorbian", "hsb", ""},
02029         {"Kashubian", "csb", ""},
02030         {"Crimean Turkish", "crh", ""},
02031         {"Erzya", "myv", ""},
02032         {"Moksha", "mdf", ""},
02033         {"Karachay-Balkar", "krc", ""},
02034         {"Adyghe", "ady", ""},
02035         {"Udmurt", "udm", ""},
02036         {"Dargwa", "dar", ""},
02037         {"Ingush", "inh", ""},
02038         {"Nogai", "nog", ""},
02039         {"Haitian", "hat", "ht"},
02040         {"Kalmyk", "xal", ""},
02041         {"", "", ""},
02042 };
02043 
02044 CString ISO6391ToLanguage(LPCSTR code)
02045 {
02046         CHAR tmp[2+1];
02047         strncpy(tmp, code, 2);
02048         tmp[2] = 0;
02049         _strlwr(tmp);
02050         for(int i = 0, j = countof(s_isolangs); i < j; i++)
02051                 if(!strcmp(s_isolangs[i].iso6391, tmp))
02052                 {
02053                         CString ret = CString(CStringA(s_isolangs[i].name));
02054                         int i = ret.Find(';');
02055                         if(i > 0) ret = ret.Left(i);
02056                         return ret;
02057                 }
02058         return(_T(""));
02059 }
02060 
02061 CString ISO6392ToLanguage(LPCSTR code)
02062 {
02063         CHAR tmp[3+1];
02064         strncpy(tmp, code, 3);
02065         tmp[3] = 0;
02066         _strlwr(tmp);
02067         for(int i = 0, j = countof(s_isolangs); i < j; i++)
02068         {
02069                 if(!strcmp(s_isolangs[i].iso6392, tmp))
02070                 {
02071                         CString ret = CString(CStringA(s_isolangs[i].name));
02072                         int i = ret.Find(';');
02073                         if(i > 0) ret = ret.Left(i);
02074                         return ret;
02075                 }
02076         }
02077         return _T("");
02078 }
02079 
02080 CString ISO6391To6392(LPCSTR code)
02081 {
02082         CHAR tmp[2+1];
02083         strncpy(tmp, code, 2);
02084         tmp[2] = 0;
02085         _strlwr(tmp);
02086         for(int i = 0, j = countof(s_isolangs); i < j; i++)
02087                 if(!strcmp(s_isolangs[i].iso6391, tmp))
02088                         return CString(CStringA(s_isolangs[i].iso6392));
02089         return _T("");
02090 }
02091 
02092 CString LanguageToISO6392(LPCTSTR lang)
02093 {
02094         CString str = lang;
02095         str.MakeLower();
02096         for(int i = 0, j = countof(s_isolangs); i < j; i++)
02097         {
02098                 CList<CString> sl;
02099                 Explode(CString(s_isolangs[i].name), sl, ';');
02100                 POSITION pos = sl.GetHeadPosition();
02101                 while(pos)
02102                 {
02103                         if(!str.CompareNoCase(sl.GetNext(pos)))
02104                                 return CString(s_isolangs[i].iso6392);
02105                 }
02106         }
02107         return _T("");
02108 }
02109 
02110 int MakeAACInitData(BYTE* pData, int profile, int freq, int channels)
02111 {
02112         int srate_idx;
02113 
02114         if(92017 <= freq) srate_idx = 0;
02115         else if(75132 <= freq) srate_idx = 1;
02116         else if(55426 <= freq) srate_idx = 2;
02117         else if(46009 <= freq) srate_idx = 3;
02118         else if(37566 <= freq) srate_idx = 4;
02119         else if(27713 <= freq) srate_idx = 5;
02120         else if(23004 <= freq) srate_idx = 6;
02121         else if(18783 <= freq) srate_idx = 7;
02122         else if(13856 <= freq) srate_idx = 8;
02123         else if(11502 <= freq) srate_idx = 9;
02124         else if(9391 <= freq) srate_idx = 10;
02125         else srate_idx = 11;
02126 
02127         pData[0] = ((abs(profile) + 1) << 3) | ((srate_idx & 0xe) >> 1);
02128         pData[1] = ((srate_idx & 0x1) << 7) | (channels << 3);
02129 
02130         int ret = 2;
02131 
02132         if(profile < 0)
02133         {
02134                 freq *= 2;
02135 
02136                 if(92017 <= freq) srate_idx = 0;
02137                 else if(75132 <= freq) srate_idx = 1;
02138                 else if(55426 <= freq) srate_idx = 2;
02139                 else if(46009 <= freq) srate_idx = 3;
02140                 else if(37566 <= freq) srate_idx = 4;
02141                 else if(27713 <= freq) srate_idx = 5;
02142                 else if(23004 <= freq) srate_idx = 6;
02143                 else if(18783 <= freq) srate_idx = 7;
02144                 else if(13856 <= freq) srate_idx = 8;
02145                 else if(11502 <= freq) srate_idx = 9;
02146                 else if(9391 <= freq) srate_idx = 10;
02147                 else srate_idx = 11;
02148 
02149                 pData[2] = 0x2B7>>3;
02150                 pData[3] = (BYTE)((0x2B7<<5) | 5);
02151                 pData[4] = (1<<7) | (srate_idx<<3);
02152 
02153                 ret = 5;
02154         }
02155 
02156         return(ret);
02157 }
02158 
02159 BOOL CFileGetStatus(LPCTSTR lpszFileName, CFileStatus& status)
02160 {
02161         try
02162         {
02163                 return CFile::GetStatus(lpszFileName, status);
02164         }
02165         catch(CException* e)
02166         {
02167                 // MFCBUG: E_INVALIDARG / "Parameter is incorrect" is thrown for certain cds (vs2003)
02168                 // http://groups.google.co.uk/groups?hl=en&lr=&ie=UTF-8&threadm=OZuXYRzWDHA.536%40TK2MSFTNGP10.phx.gbl&rnum=1&prev=/groups%3Fhl%3Den%26lr%3D%26ie%3DISO-8859-1
02169                 TRACE(_T("CFile::GetStatus has thrown an exception\n"));
02170                 e->Delete();
02171                 return false;
02172         }
02173 }
02174 
02175 // filter registration helpers
02176 
02177 bool DeleteRegKey(LPCTSTR pszKey, LPCTSTR pszSubkey)
02178 {
02179         bool bOK = false;
02180 
02181         HKEY hKey;
02182         LONG ec = ::RegOpenKeyEx(HKEY_CLASSES_ROOT, pszKey, 0, KEY_ALL_ACCESS, &hKey);
02183         if(ec == ERROR_SUCCESS)
02184         {
02185                 if(pszSubkey != 0)
02186                         ec = ::RegDeleteKey(hKey, pszSubkey);
02187 
02188                 bOK = (ec == ERROR_SUCCESS);
02189 
02190                 ::RegCloseKey(hKey);
02191         }
02192 
02193         return bOK;
02194 }
02195 
02196 bool SetRegKeyValue(LPCTSTR pszKey, LPCTSTR pszSubkey, LPCTSTR pszValueName, LPCTSTR pszValue)
02197 {
02198         bool bOK = false;
02199 
02200         CString szKey(pszKey);
02201         if(pszSubkey != 0)
02202                 szKey += CString(_T("\\")) + pszSubkey;
02203 
02204         HKEY hKey;
02205         LONG ec = ::RegCreateKeyEx(HKEY_CLASSES_ROOT, szKey, 0, 0, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, 0, &hKey, 0);
02206         if(ec == ERROR_SUCCESS)
02207         {
02208                 if(pszValue != 0)
02209                 {
02210                         ec = ::RegSetValueEx(hKey, pszValueName, 0, REG_SZ,
02211                                 reinterpret_cast<BYTE*>(const_cast<LPTSTR>(pszValue)),
02212                                 (_tcslen(pszValue) + 1) * sizeof(TCHAR));
02213                 }
02214 
02215                 bOK = (ec == ERROR_SUCCESS);
02216 
02217                 ::RegCloseKey(hKey);
02218         }
02219 
02220         return bOK;
02221 }
02222 
02223 bool SetRegKeyValue(LPCTSTR pszKey, LPCTSTR pszSubkey, LPCTSTR pszValue)
02224 {
02225         return SetRegKeyValue(pszKey, pszSubkey, 0, pszValue);
02226 }
02227 
02228 void RegisterSourceFilter(const CLSID& clsid, const GUID& subtype2, LPCTSTR chkbytes, LPCTSTR ext, ...)
02229 {
02230         CString null = CStringFromGUID(GUID_NULL);
02231         CString majortype = CStringFromGUID(MEDIATYPE_Stream);
02232         CString subtype = CStringFromGUID(subtype2);
02233 
02234         SetRegKeyValue(_T("Media Type\\") + majortype, subtype, _T("0"), chkbytes);
02235         SetRegKeyValue(_T("Media Type\\") + majortype, subtype, _T("Source Filter"), CStringFromGUID(clsid));
02236         
02237         DeleteRegKey(_T("Media Type\\") + null, subtype);
02238 
02239         va_list marker;
02240         va_start(marker, ext);
02241         for(; ext; ext = va_arg(marker, LPCTSTR))
02242                 DeleteRegKey(_T("Media Type\\Extensions"), ext);
02243         va_end(marker);
02244 }
02245 
02246 void RegisterSourceFilter(const CLSID& clsid, const GUID& subtype2, const CList<CString>& chkbytes, LPCTSTR ext, ...)
02247 {
02248         CString null = CStringFromGUID(GUID_NULL);
02249         CString majortype = CStringFromGUID(MEDIATYPE_Stream);
02250         CString subtype = CStringFromGUID(subtype2);
02251 
02252         POSITION pos = chkbytes.GetHeadPosition();
02253         for(int i = 0; pos; i++)
02254         {
02255                 CString idx;
02256                 idx.Format(_T("%d"), i);
02257                 SetRegKeyValue(_T("Media Type\\") + majortype, subtype, idx, chkbytes.GetNext(pos));
02258         }
02259 
02260         SetRegKeyValue(_T("Media Type\\") + majortype, subtype, _T("Source Filter"), CStringFromGUID(clsid));
02261         
02262         DeleteRegKey(_T("Media Type\\") + null, subtype);
02263 
02264         va_list marker;
02265         va_start(marker, ext);
02266         for(; ext; ext = va_arg(marker, LPCTSTR))
02267                 DeleteRegKey(_T("Media Type\\Extensions"), ext);
02268         va_end(marker);
02269 }
02270 
02271 void UnRegisterSourceFilter(const GUID& subtype)
02272 {
02273         DeleteRegKey(_T("Media Type\\") + CStringFromGUID(MEDIATYPE_Stream), CStringFromGUID(subtype));
02274 }

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