00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
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
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
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 );
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
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
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
00849 FindFiles(path + _T("\\VIDEO_TS\\video_ts.ifo"), files);
00850 if(files.GetCount() > 0) return CDROM_DVDVideo;
00851
00852
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
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
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;
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
01621 {"Creoles and pidgins,", "cpf", ""},
01622
01623 {"Creoles and pidgins,", "cpp", ""},
01624
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
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
02168
02169 TRACE(_T("CFile::GetStatus has thrown an exception\n"));
02170 e->Delete();
02171 return false;
02172 }
02173 }
02174
02175
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 }