- Main Page
- Namespaces
- Classes
- Files
- Directories

- File List
- File Members

# 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 }