Increase ParseScript cache from 30 to 90 seconds
[xy_vsfilter.git] / src / dsutil / DSUtil.cpp
blob2f1d863abc4e900571f48f40d91ecea93985d89b
1 /*
2 * Copyright (C) 2003-2006 Gabest
3 * http://www.gabest.org
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with GNU Make; see the file COPYING. If not, write to
17 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18 * http://www.gnu.org/copyleft/gpl.html
22 #include "stdafx.h"
23 #include <Vfw.h>
24 #include "..\..\include\winddk\devioctl.h"
25 #include "..\..\include\winddk\ntddcdrm.h"
26 #include "DSUtil.h"
27 #include "Mpeg2Def.h"
28 #include "vd.h"
29 #include "..\..\..\include\moreuuids.h"
30 #include <emmintrin.h>
31 #include <math.h>
32 #include <InitGuid.h>
33 #include <d3d9types.h>
34 #include <dxva.h>
35 #include <dxva2api.h>
37 void DumpStreamConfig(TCHAR* fn, IAMStreamConfig* pAMVSCCap)
39 CString s, ss;
40 CStdioFile f;
41 if(!f.Open(fn, CFile::modeCreate|CFile::modeWrite|CFile::typeText))
42 return;
44 int cnt = 0, size = 0;
45 if(FAILED(pAMVSCCap->GetNumberOfCapabilities(&cnt, &size)))
46 return;
48 s.Empty();
49 s.Format(_T("cnt %d, size %d\n"), cnt, size);
50 f.WriteString(s);
52 if(size == sizeof(VIDEO_STREAM_CONFIG_CAPS))
54 for(int i = 0; i < cnt; i++)
56 AM_MEDIA_TYPE* pmt = NULL;
58 VIDEO_STREAM_CONFIG_CAPS caps;
59 memset(&caps, 0, sizeof(caps));
61 s.Empty();
62 ss.Format(_T("%d\n"), i); s += ss;
63 f.WriteString(s);
65 if(FAILED(pAMVSCCap->GetStreamCaps(i, &pmt, (BYTE*)&caps)))
66 continue;
69 s.Empty();
70 ss.Format(_T("VIDEO_STREAM_CONFIG_CAPS\n")); s += ss;
71 ss.Format(_T("\tVideoStandard 0x%08x\n"), caps.VideoStandard); s += ss;
72 ss.Format(_T("\tInputSize %dx%d\n"), caps.InputSize); s += ss;
73 ss.Format(_T("\tCroppingSize %dx%d - %dx%d\n"), caps.MinCroppingSize, caps.MaxCroppingSize); s += ss;
74 ss.Format(_T("\tCropGranularity %d, %d\n"), caps.CropGranularityX, caps.CropGranularityY); s += ss;
75 ss.Format(_T("\tCropAlign %d, %d\n"), caps.CropAlignX, caps.CropAlignY); s += ss;
76 ss.Format(_T("\tOutputSize %dx%d - %dx%d\n"), caps.MinOutputSize, caps.MaxOutputSize); s += ss;
77 ss.Format(_T("\tOutputGranularity %d, %d\n"), caps.OutputGranularityX, caps.OutputGranularityY); s += ss;
78 ss.Format(_T("\tStretchTaps %d, %d\n"), caps.StretchTapsX, caps.StretchTapsY); s += ss;
79 ss.Format(_T("\tShrinkTaps %d, %d\n"), caps.ShrinkTapsX, caps.ShrinkTapsY); s += ss;
80 ss.Format(_T("\tFrameInterval %I64d, %I64d (%.4f, %.4f)\n"),
81 caps.MinFrameInterval, caps.MaxFrameInterval,
82 (float)10000000/caps.MinFrameInterval, (float)10000000/caps.MaxFrameInterval); s += ss;
83 ss.Format(_T("\tBitsPerSecond %d - %d\n"), caps.MinBitsPerSecond, caps.MaxBitsPerSecond); s += ss;
84 f.WriteString(s);
87 BITMAPINFOHEADER* pbh;
88 if(pmt->formattype == FORMAT_VideoInfo)
90 VIDEOINFOHEADER* vih = (VIDEOINFOHEADER*)pmt->pbFormat;
91 pbh = &vih->bmiHeader;
93 s.Empty();
94 ss.Format(_T("FORMAT_VideoInfo\n")); s += ss;
95 ss.Format(_T("\tAvgTimePerFrame %I64d, %.4f\n"), vih->AvgTimePerFrame, (float)10000000/vih->AvgTimePerFrame); s += ss;
96 ss.Format(_T("\trcSource %d,%d,%d,%d\n"), vih->rcSource); s += ss;
97 ss.Format(_T("\trcTarget %d,%d,%d,%d\n"), vih->rcTarget); s += ss;
98 f.WriteString(s);
100 else if(pmt->formattype == FORMAT_VideoInfo2)
102 VIDEOINFOHEADER2* vih = (VIDEOINFOHEADER2*)pmt->pbFormat;
103 pbh = &vih->bmiHeader;
105 s.Empty();
106 ss.Format(_T("FORMAT_VideoInfo2\n")); s += ss;
107 ss.Format(_T("\tAvgTimePerFrame %I64d, %.4f\n"), vih->AvgTimePerFrame, (float)10000000/vih->AvgTimePerFrame); s += ss;
108 ss.Format(_T("\trcSource %d,%d,%d,%d\n"), vih->rcSource); s += ss;
109 ss.Format(_T("\trcTarget %d,%d,%d,%d\n"), vih->rcTarget); s += ss;
110 ss.Format(_T("\tdwInterlaceFlags 0x%x\n"), vih->dwInterlaceFlags); s += ss;
111 ss.Format(_T("\tdwPictAspectRatio %d:%d\n"), vih->dwPictAspectRatioX, vih->dwPictAspectRatioY); s += ss;
112 f.WriteString(s);
114 else
116 DeleteMediaType(pmt);
117 continue;
120 s.Empty();
121 ss.Format(_T("BITMAPINFOHEADER\n")); s += ss;
122 ss.Format(_T("\tbiCompression %x\n"), pbh->biCompression); s += ss;
123 ss.Format(_T("\tbiWidth %d\n"), pbh->biWidth); s += ss;
124 ss.Format(_T("\tbiHeight %d\n"), pbh->biHeight); s += ss;
125 ss.Format(_T("\tbiBitCount %d\n"), pbh->biBitCount); s += ss;
126 ss.Format(_T("\tbiPlanes %d\n"), pbh->biPlanes); s += ss;
127 ss.Format(_T("\tbiSizeImage %d\n"), pbh->biSizeImage); s += ss;
128 f.WriteString(s);
130 DeleteMediaType(pmt);
133 else if(size == sizeof(AUDIO_STREAM_CONFIG_CAPS))
135 // TODO
139 int CountPins(IBaseFilter* pBF, int& nIn, int& nOut, int& nInC, int& nOutC)
141 nIn = nOut = 0;
142 nInC = nOutC = 0;
144 BeginEnumPins(pBF, pEP, pPin)
146 PIN_DIRECTION dir;
147 if(SUCCEEDED(pPin->QueryDirection(&dir)))
149 CComPtr<IPin> pPinConnectedTo;
150 pPin->ConnectedTo(&pPinConnectedTo);
152 if(dir == PINDIR_INPUT) {nIn++; if(pPinConnectedTo) nInC++;}
153 else if(dir == PINDIR_OUTPUT) {nOut++; if(pPinConnectedTo) nOutC++;}
156 EndEnumPins
158 return(nIn+nOut);
161 bool IsSplitter(IBaseFilter* pBF, bool fCountConnectedOnly)
163 int nIn, nOut, nInC, nOutC;
164 CountPins(pBF, nIn, nOut, nInC, nOutC);
165 return(fCountConnectedOnly ? nOutC > 1 : nOut > 1);
168 bool IsMultiplexer(IBaseFilter* pBF, bool fCountConnectedOnly)
170 int nIn, nOut, nInC, nOutC;
171 CountPins(pBF, nIn, nOut, nInC, nOutC);
172 return(fCountConnectedOnly ? nInC > 1 : nIn > 1);
175 bool IsStreamStart(IBaseFilter* pBF)
177 CComQIPtr<IAMFilterMiscFlags> pAMMF(pBF);
178 if(pAMMF && pAMMF->GetMiscFlags()&AM_FILTER_MISC_FLAGS_IS_SOURCE)
179 return(true);
181 int nIn, nOut, nInC, nOutC;
182 CountPins(pBF, nIn, nOut, nInC, nOutC);
183 AM_MEDIA_TYPE mt;
184 CComPtr<IPin> pIn = GetFirstPin(pBF);
185 return((nOut > 1)
186 || (nOut > 0 && nIn == 1 && pIn && SUCCEEDED(pIn->ConnectionMediaType(&mt)) && mt.majortype == MEDIATYPE_Stream));
189 bool IsStreamEnd(IBaseFilter* pBF)
191 int nIn, nOut, nInC, nOutC;
192 CountPins(pBF, nIn, nOut, nInC, nOutC);
193 return(nOut == 0);
196 bool IsVideoRenderer(IBaseFilter* pBF)
198 int nIn, nOut, nInC, nOutC;
199 CountPins(pBF, nIn, nOut, nInC, nOutC);
201 if(nInC > 0 && nOut == 0)
203 BeginEnumPins(pBF, pEP, pPin)
205 AM_MEDIA_TYPE mt;
206 if(S_OK != pPin->ConnectionMediaType(&mt))
207 continue;
209 FreeMediaType(mt);
211 return(!!(mt.majortype == MEDIATYPE_Video));
212 /*&& (mt.formattype == FORMAT_VideoInfo || mt.formattype == FORMAT_VideoInfo2));*/
214 EndEnumPins
217 CLSID clsid;
218 memcpy(&clsid, &GUID_NULL, sizeof(clsid));
219 pBF->GetClassID(&clsid);
221 return(clsid == CLSID_VideoRenderer || clsid == CLSID_VideoRendererDefault);
224 #include <initguid.h>
226 DEFINE_GUID(CLSID_ReClock,
227 0x9dc15360, 0x914c, 0x46b8, 0xb9, 0xdf, 0xbf, 0xe6, 0x7f, 0xd3, 0x6c, 0x6a);
229 bool IsAudioWaveRenderer(IBaseFilter* pBF)
231 int nIn, nOut, nInC, nOutC;
232 CountPins(pBF, nIn, nOut, nInC, nOutC);
234 if(nInC > 0 && nOut == 0 && CComQIPtr<IBasicAudio>(pBF))
236 BeginEnumPins(pBF, pEP, pPin)
238 AM_MEDIA_TYPE mt;
239 if(S_OK != pPin->ConnectionMediaType(&mt))
240 continue;
242 FreeMediaType(mt);
244 return(!!(mt.majortype == MEDIATYPE_Audio)
245 /*&& mt.formattype == FORMAT_WaveFormatEx*/);
247 EndEnumPins
250 CLSID clsid;
251 memcpy(&clsid, &GUID_NULL, sizeof(clsid));
252 pBF->GetClassID(&clsid);
254 return(clsid == CLSID_DSoundRender || clsid == CLSID_AudioRender || clsid == CLSID_ReClock
255 || clsid == __uuidof(CNullAudioRenderer) || clsid == __uuidof(CNullUAudioRenderer));
258 IBaseFilter* GetUpStreamFilter(IBaseFilter* pBF, IPin* pInputPin)
260 return GetFilterFromPin(GetUpStreamPin(pBF, pInputPin));
263 IPin* GetUpStreamPin(IBaseFilter* pBF, IPin* pInputPin)
265 BeginEnumPins(pBF, pEP, pPin)
267 if(pInputPin && pInputPin != pPin) continue;
269 PIN_DIRECTION dir;
270 CComPtr<IPin> pPinConnectedTo;
271 if(SUCCEEDED(pPin->QueryDirection(&dir)) && dir == PINDIR_INPUT
272 && SUCCEEDED(pPin->ConnectedTo(&pPinConnectedTo)))
274 IPin* pRet = pPinConnectedTo.Detach();
275 pRet->Release();
276 return(pRet);
279 EndEnumPins
281 return(NULL);
284 IPin* GetFirstPin(IBaseFilter* pBF, PIN_DIRECTION dir)
286 if(!pBF) return(NULL);
288 BeginEnumPins(pBF, pEP, pPin)
290 PIN_DIRECTION dir2;
291 pPin->QueryDirection(&dir2);
292 if(dir == dir2)
294 IPin* pRet = pPin.Detach();
295 pRet->Release();
296 return(pRet);
299 EndEnumPins
301 return(NULL);
304 IPin* GetFirstDisconnectedPin(IBaseFilter* pBF, PIN_DIRECTION dir)
306 if(!pBF) return(NULL);
308 BeginEnumPins(pBF, pEP, pPin)
310 PIN_DIRECTION dir2;
311 pPin->QueryDirection(&dir2);
312 CComPtr<IPin> pPinTo;
313 if(dir == dir2 && (S_OK != pPin->ConnectedTo(&pPinTo)))
315 IPin* pRet = pPin.Detach();
316 pRet->Release();
317 return(pRet);
320 EndEnumPins
322 return(NULL);
325 IBaseFilter* FindFilter(LPCWSTR clsid, IFilterGraph* pFG)
327 CLSID clsid2;
328 CLSIDFromString(CComBSTR(clsid), &clsid2);
329 return(FindFilter(clsid2, pFG));
332 IBaseFilter* FindFilter(const CLSID& clsid, IFilterGraph* pFG)
334 BeginEnumFilters(pFG, pEF, pBF)
336 CLSID clsid2;
337 if(SUCCEEDED(pBF->GetClassID(&clsid2)) && clsid == clsid2)
338 return(pBF);
340 EndEnumFilters
342 return NULL;
345 CStringW GetFilterName(IBaseFilter* pBF)
347 CStringW name;
348 CFilterInfo fi;
349 if(pBF && SUCCEEDED(pBF->QueryFilterInfo(&fi)))
350 name = fi.achName;
351 return(name);
354 CStringW GetPinName(IPin* pPin)
356 CStringW name;
357 CPinInfo pi;
358 if(pPin && SUCCEEDED(pPin->QueryPinInfo(&pi)))
359 name = pi.achName;
360 return(name);
363 IFilterGraph* GetGraphFromFilter(IBaseFilter* pBF)
365 if(!pBF) return NULL;
366 IFilterGraph* pGraph = NULL;
367 CFilterInfo fi;
368 if(pBF && SUCCEEDED(pBF->QueryFilterInfo(&fi)))
369 pGraph = fi.pGraph;
370 return(pGraph);
373 IBaseFilter* GetFilterFromPin(IPin* pPin)
375 if(!pPin) return NULL;
376 IBaseFilter* pBF = NULL;
377 CPinInfo pi;
378 if(pPin && SUCCEEDED(pPin->QueryPinInfo(&pi)))
379 pBF = pi.pFilter;
380 return(pBF);
383 IPin* AppendFilter(IPin* pPin, CString DisplayName, IGraphBuilder* pGB)
385 IPin* pRet = pPin;
387 CInterfaceList<IBaseFilter> pFilters;
391 if(!pPin || DisplayName.IsEmpty() || !pGB)
392 break;
394 CComPtr<IPin> pPinTo;
395 PIN_DIRECTION dir;
396 if(FAILED(pPin->QueryDirection(&dir)) || dir != PINDIR_OUTPUT || SUCCEEDED(pPin->ConnectedTo(&pPinTo)))
397 break;
399 CComPtr<IBindCtx> pBindCtx;
400 CreateBindCtx(0, &pBindCtx);
402 CComPtr<IMoniker> pMoniker;
403 ULONG chEaten;
404 if(S_OK != MkParseDisplayName(pBindCtx, CComBSTR(DisplayName), &chEaten, &pMoniker))
405 break;
407 CComPtr<IBaseFilter> pBF;
408 if(FAILED(pMoniker->BindToObject(pBindCtx, 0, IID_IBaseFilter, (void**)&pBF)) || !pBF)
409 break;
411 CComPtr<IPropertyBag> pPB;
412 if(FAILED(pMoniker->BindToStorage(pBindCtx, 0, IID_IPropertyBag, (void**)&pPB)))
413 break;
415 CComVariant var;
416 if(FAILED(pPB->Read(CComBSTR(_T("FriendlyName")), &var, NULL)))
417 break;
419 pFilters.AddTail(pBF);
420 BeginEnumFilters(pGB, pEnum, pBF2)
421 pFilters.AddTail(pBF2);
422 EndEnumFilters
424 if(FAILED(pGB->AddFilter(pBF, CStringW(var.bstrVal))))
425 break;
427 BeginEnumFilters(pGB, pEnum, pBF2)
428 if(!pFilters.Find(pBF2) && SUCCEEDED(pGB->RemoveFilter(pBF2)))
429 pEnum->Reset();
430 EndEnumFilters
432 pPinTo = GetFirstPin(pBF, PINDIR_INPUT);
433 if(!pPinTo)
435 pGB->RemoveFilter(pBF);
436 break;
439 HRESULT hr;
440 if(FAILED(hr = pGB->ConnectDirect(pPin, pPinTo, NULL)))
442 hr = pGB->Connect(pPin, pPinTo);
443 pGB->RemoveFilter(pBF);
444 break;
447 BeginEnumFilters(pGB, pEnum, pBF2)
448 if(!pFilters.Find(pBF2) && SUCCEEDED(pGB->RemoveFilter(pBF2)))
449 pEnum->Reset();
450 EndEnumFilters
452 pRet = GetFirstPin(pBF, PINDIR_OUTPUT);
453 if(!pRet)
455 pRet = pPin;
456 pGB->RemoveFilter(pBF);
457 break;
460 while(false);
462 return(pRet);
465 IPin* InsertFilter(IPin* pPin, CString DisplayName, IGraphBuilder* pGB)
469 if(!pPin || DisplayName.IsEmpty() || !pGB)
470 break;
472 PIN_DIRECTION dir;
473 if(FAILED(pPin->QueryDirection(&dir)))
474 break;
476 CComPtr<IPin> pFrom, pTo;
478 if(dir == PINDIR_INPUT)
480 pPin->ConnectedTo(&pFrom);
481 pTo = pPin;
483 else if(dir == PINDIR_OUTPUT)
485 pFrom = pPin;
486 pPin->ConnectedTo(&pTo);
489 if(!pFrom || !pTo)
490 break;
492 CComPtr<IBindCtx> pBindCtx;
493 CreateBindCtx(0, &pBindCtx);
495 CComPtr<IMoniker> pMoniker;
496 ULONG chEaten;
497 if(S_OK != MkParseDisplayName(pBindCtx, CComBSTR(DisplayName), &chEaten, &pMoniker))
498 break;
500 CComPtr<IBaseFilter> pBF;
501 if(FAILED(pMoniker->BindToObject(pBindCtx, 0, IID_IBaseFilter, (void**)&pBF)) || !pBF)
502 break;
504 CComPtr<IPropertyBag> pPB;
505 if(FAILED(pMoniker->BindToStorage(pBindCtx, 0, IID_IPropertyBag, (void**)&pPB)))
506 break;
508 CComVariant var;
509 if(FAILED(pPB->Read(CComBSTR(_T("FriendlyName")), &var, NULL)))
510 break;
512 if(FAILED(pGB->AddFilter(pBF, CStringW(var.bstrVal))))
513 break;
515 CComPtr<IPin> pFromTo = GetFirstPin(pBF, PINDIR_INPUT);
516 if(!pFromTo)
518 pGB->RemoveFilter(pBF);
519 break;
522 if(FAILED(pGB->Disconnect(pFrom)) || FAILED(pGB->Disconnect(pTo)))
524 pGB->RemoveFilter(pBF);
525 pGB->ConnectDirect(pFrom, pTo, NULL);
526 break;
529 HRESULT hr;
530 if(FAILED(hr = pGB->ConnectDirect(pFrom, pFromTo, NULL)))
532 pGB->RemoveFilter(pBF);
533 pGB->ConnectDirect(pFrom, pTo, NULL);
534 break;
537 CComPtr<IPin> pToFrom = GetFirstPin(pBF, PINDIR_OUTPUT);
538 if(!pToFrom)
540 pGB->RemoveFilter(pBF);
541 pGB->ConnectDirect(pFrom, pTo, NULL);
542 break;
545 if(FAILED(pGB->ConnectDirect(pToFrom, pTo, NULL)))
547 pGB->RemoveFilter(pBF);
548 pGB->ConnectDirect(pFrom, pTo, NULL);
549 break;
552 pPin = pToFrom;
554 while(false);
556 return(pPin);
559 void ExtractMediaTypes(IPin* pPin, CAtlArray<GUID>& types)
561 types.RemoveAll();
563 BeginEnumMediaTypes(pPin, pEM, pmt)
565 bool fFound = false;
567 for(int i = 0; !fFound && i < types.GetCount(); i += 2)
569 if(types[i] == pmt->majortype && types[i+1] == pmt->subtype)
570 fFound = true;
573 if(!fFound)
575 types.Add(pmt->majortype);
576 types.Add(pmt->subtype);
579 EndEnumMediaTypes(pmt)
582 void ExtractMediaTypes(IPin* pPin, CAtlList<CMediaType>& mts)
584 mts.RemoveAll();
586 BeginEnumMediaTypes(pPin, pEM, pmt)
588 bool fFound = false;
590 POSITION pos = mts.GetHeadPosition();
591 while(!fFound && pos)
593 CMediaType& mt = mts.GetNext(pos);
594 if(mt.majortype == pmt->majortype && mt.subtype == pmt->subtype)
595 fFound = true;
598 if(!fFound)
600 mts.AddTail(CMediaType(*pmt));
603 EndEnumMediaTypes(pmt)
606 int Eval_Exception(int n_except)
608 if(n_except == STATUS_ACCESS_VIOLATION)
610 AfxMessageBox(_T("The property page of this filter has just caused a\nmemory access violation. The application will gently die now :)"));
613 return EXCEPTION_CONTINUE_SEARCH;
616 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)
618 __try
620 OleCreatePropertyFrame(hwndOwner, x, y, lpszCaption, cObjects, lplpUnk, cPages, lpPageClsID, lcid, dwReserved, lpvReserved);
622 __except(Eval_Exception(GetExceptionCode()))
624 // No code; this block never executed.
628 void ShowPPage(CString DisplayName, HWND hParentWnd)
630 CComPtr<IBindCtx> pBindCtx;
631 CreateBindCtx(0, &pBindCtx);
633 CComPtr<IMoniker> pMoniker;
634 ULONG chEaten;
635 if(S_OK != MkParseDisplayName(pBindCtx, CStringW(DisplayName), &chEaten, &pMoniker))
636 return;
638 CComPtr<IBaseFilter> pBF;
639 if(FAILED(pMoniker->BindToObject(pBindCtx, 0, IID_IBaseFilter, (void**)&pBF)) || !pBF)
640 return;
642 ShowPPage(pBF, hParentWnd);
645 void ShowPPage(IUnknown* pUnk, HWND hParentWnd)
647 CComQIPtr<ISpecifyPropertyPages> pSPP = pUnk;
648 if(!pSPP) return;
650 CString str;
652 CComQIPtr<IBaseFilter> pBF = pSPP;
653 CFilterInfo fi;
654 CComQIPtr<IPin> pPin = pSPP;
655 CPinInfo pi;
656 if(pBF && SUCCEEDED(pBF->QueryFilterInfo(&fi)))
657 str = fi.achName;
658 else if(pPin && SUCCEEDED(pPin->QueryPinInfo(&pi)))
659 str = pi.achName;
661 CAUUID caGUID;
662 caGUID.pElems = NULL;
663 if(SUCCEEDED(pSPP->GetPages(&caGUID)))
665 IUnknown* lpUnk = NULL;
666 pSPP.QueryInterface(&lpUnk);
667 MyOleCreatePropertyFrame(
668 hParentWnd, 0, 0, CStringW(str),
669 1, (IUnknown**)&lpUnk,
670 caGUID.cElems, caGUID.pElems,
671 0, 0, NULL);
672 lpUnk->Release();
674 if(caGUID.pElems) CoTaskMemFree(caGUID.pElems);
678 CLSID GetCLSID(IBaseFilter* pBF)
680 CLSID clsid = GUID_NULL;
681 if(pBF) pBF->GetClassID(&clsid);
682 return(clsid);
685 CLSID GetCLSID(IPin* pPin)
687 return(GetCLSID(GetFilterFromPin(pPin)));
690 bool IsCLSIDRegistered(LPCTSTR clsid)
692 CString rootkey1(_T("CLSID\\"));
693 CString rootkey2(_T("CLSID\\{083863F1-70DE-11d0-BD40-00A0C911CE86}\\Instance\\"));
695 return ERROR_SUCCESS == CRegKey().Open(HKEY_CLASSES_ROOT, rootkey1 + clsid, KEY_READ)
696 || ERROR_SUCCESS == CRegKey().Open(HKEY_CLASSES_ROOT, rootkey2 + clsid, KEY_READ);
699 bool IsCLSIDRegistered(const CLSID& clsid)
701 bool fRet = false;
703 LPOLESTR pStr = NULL;
704 if(S_OK == StringFromCLSID(clsid, &pStr) && pStr)
706 fRet = IsCLSIDRegistered(CString(pStr));
707 CoTaskMemFree(pStr);
710 return(fRet);
713 void CStringToBin(CString str, CAtlArray<BYTE>& data)
715 str.Trim();
716 ASSERT((str.GetLength()&1) == 0);
717 data.SetCount(str.GetLength()/2);
719 BYTE b = 0;
721 str.MakeUpper();
722 for(int i = 0, j = str.GetLength(); i < j; i++)
724 TCHAR c = str[i];
725 if(c >= '0' && c <= '9')
727 if(!(i&1)) b = ((char(c-'0')<<4)&0xf0)|(b&0x0f);
728 else b = (char(c-'0')&0x0f)|(b&0xf0);
730 else if(c >= 'A' && c <= 'F')
732 if(!(i&1)) b = ((char(c-'A'+10)<<4)&0xf0)|(b&0x0f);
733 else b = (char(c-'A'+10)&0x0f)|(b&0xf0);
735 else break;
737 if(i&1)
739 data[i>>1] = b;
740 b = 0;
745 CString BinToCString(BYTE* ptr, int len)
747 CString ret;
749 while(len-- > 0)
751 TCHAR high, low;
752 high = (*ptr>>4) >= 10 ? (*ptr>>4)-10 + 'A' : (*ptr>>4) + '0';
753 low = (*ptr&0xf) >= 10 ? (*ptr&0xf)-10 + 'A' : (*ptr&0xf) + '0';
755 CString str;
756 str.Format(_T("%c%c"), high, low);
757 ret += str;
759 ptr++;
762 return(ret);
765 static void FindFiles(CString fn, CAtlList<CString>& files)
767 CString path = fn;
768 path.Replace('/', '\\');
769 path = path.Left(path.ReverseFind('\\')+1);
771 WIN32_FIND_DATA findData;
772 HANDLE h = FindFirstFile(fn, &findData);
773 if(h != INVALID_HANDLE_VALUE)
775 do {files.AddTail(path + findData.cFileName);}
776 while(FindNextFile(h, &findData));
778 FindClose(h);
782 cdrom_t GetCDROMType(TCHAR drive, CAtlList<CString>& files)
784 files.RemoveAll();
786 CString path;
787 path.Format(_T("%c:"), drive);
789 if(GetDriveType(path + _T("\\")) == DRIVE_CDROM)
791 // CDROM_VideoCD
792 FindFiles(path + _T("\\mpegav\\avseq??.dat"), files);
793 FindFiles(path + _T("\\mpegav\\avseq??.mpg"), files);
794 FindFiles(path + _T("\\mpeg2\\avseq??.dat"), files);
795 FindFiles(path + _T("\\mpeg2\\avseq??.mpg"), files);
796 FindFiles(path + _T("\\mpegav\\music??.dat"), files);
797 FindFiles(path + _T("\\mpegav\\music??.mpg"), files);
798 FindFiles(path + _T("\\mpeg2\\music??.dat"), files);
799 FindFiles(path + _T("\\mpeg2\\music??.mpg"), files);
800 if(files.GetCount() > 0) return CDROM_VideoCD;
802 // CDROM_DVDVideo
803 FindFiles(path + _T("\\VIDEO_TS\\video_ts.ifo"), files);
804 if(files.GetCount() > 0) return CDROM_DVDVideo;
806 // CDROM_Audio
807 if(!(GetVersion()&0x80000000))
809 HANDLE hDrive = CreateFile(CString(_T("\\\\.\\")) + path, GENERIC_READ, FILE_SHARE_READ, NULL,
810 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, (HANDLE)NULL);
811 if(hDrive != INVALID_HANDLE_VALUE)
813 DWORD BytesReturned;
814 CDROM_TOC TOC;
815 if(DeviceIoControl(hDrive, IOCTL_CDROM_READ_TOC, NULL, 0, &TOC, sizeof(TOC), &BytesReturned, 0))
817 for(int i = TOC.FirstTrack; i <= TOC.LastTrack; i++)
819 // MMC-3 Draft Revision 10g: Table 222 ?Q Sub-channel control field
820 TOC.TrackData[i-1].Control &= 5;
821 if(TOC.TrackData[i-1].Control == 0 || TOC.TrackData[i-1].Control == 1)
823 CString fn;
824 fn.Format(_T("%s\\track%02d.cda"), path, i);
825 files.AddTail(fn);
830 CloseHandle(hDrive);
833 if(files.GetCount() > 0) return CDROM_Audio;
835 // it is a cdrom but nothing special
836 return CDROM_Unknown;
839 return CDROM_NotFound;
842 CString GetDriveLabel(TCHAR drive)
844 CString label;
846 CString path;
847 path.Format(_T("%c:\\"), drive);
848 TCHAR VolumeNameBuffer[MAX_PATH], FileSystemNameBuffer[MAX_PATH];
849 DWORD VolumeSerialNumber, MaximumComponentLength, FileSystemFlags;
850 if(GetVolumeInformation(path,
851 VolumeNameBuffer, MAX_PATH, &VolumeSerialNumber, &MaximumComponentLength,
852 &FileSystemFlags, FileSystemNameBuffer, MAX_PATH))
854 label = VolumeNameBuffer;
857 return(label);
860 bool GetKeyFrames(CString fn, CUIntArray& kfs)
862 kfs.RemoveAll();
864 CString fn2 = CString(fn).MakeLower();
865 if(fn2.Mid(fn2.ReverseFind('.')+1) == _T("avi"))
867 AVIFileInit();
869 PAVIFILE pfile;
870 if(AVIFileOpen(&pfile, fn, OF_SHARE_DENY_WRITE, 0L) == 0)
872 AVIFILEINFO afi;
873 memset(&afi, 0, sizeof(afi));
874 AVIFileInfo(pfile, &afi, sizeof(AVIFILEINFO));
876 CComPtr<IAVIStream> pavi;
877 if(AVIFileGetStream(pfile, &pavi, streamtypeVIDEO, 0) == AVIERR_OK)
879 AVISTREAMINFO si;
880 AVIStreamInfo(pavi, &si, sizeof(si));
882 if(afi.dwCaps&AVIFILECAPS_ALLKEYFRAMES)
884 kfs.SetSize(si.dwLength);
885 for(int kf = 0; kf < si.dwLength; kf++) kfs[kf] = kf;
887 else
889 for(int kf = 0; ; kf++)
891 kf = pavi->FindSample(kf, FIND_KEY|FIND_NEXT);
892 if(kf < 0 || kfs.GetCount() > 0 && kfs[kfs.GetCount()-1] >= kf) break;
893 kfs.Add(kf);
896 if(kfs.GetCount() > 0 && kfs[kfs.GetCount()-1] < si.dwLength-1)
898 kfs.Add(si.dwLength-1);
903 AVIFileRelease(pfile);
906 AVIFileExit();
909 return(kfs.GetCount() > 0);
912 DVD_HMSF_TIMECODE RT2HMSF(REFERENCE_TIME rt, double fps)
914 DVD_HMSF_TIMECODE hmsf =
916 (BYTE)((rt/10000000/60/60)),
917 (BYTE)((rt/10000000/60)%60),
918 (BYTE)((rt/10000000)%60),
919 (BYTE)(1.0*((rt/10000)%1000) * fps / 1000)
922 return hmsf;
925 REFERENCE_TIME HMSF2RT(DVD_HMSF_TIMECODE hmsf, double fps)
927 if(fps == 0) {hmsf.bFrames = 0; fps = 1;}
928 return (REFERENCE_TIME)((((REFERENCE_TIME)hmsf.bHours*60+hmsf.bMinutes)*60+hmsf.bSeconds)*1000+1.0*hmsf.bFrames*1000/fps)*10000;
931 void memsetd(void* dst, unsigned int c, size_t nbytes)
933 #ifndef _WIN64
934 if (!(g_cpuid.m_flags & g_cpuid.sse2)) {
935 __asm {
936 mov eax, c
937 mov ecx, nbytes
938 shr ecx, 2
939 mov edi, dst
941 rep stosd
943 return;
945 #endif
946 size_t n = nbytes / 4;
947 size_t o = n - (n % 4);
949 __m128i val = _mm_set1_epi32 ( (int)c );
950 if (((uintptr_t)dst & 0x0F) == 0) { // 16-byte aligned
951 for (size_t i = 0; i < o; i+=4) {
952 _mm_store_si128( (__m128i*)&(((DWORD*)dst)[i]), val );
954 } else {
955 for (size_t i = 0; i < o; i+=4) {
956 _mm_storeu_si128( (__m128i*)&(((DWORD*)dst)[i]), val );
960 switch(n - o) {
961 case 3:
962 ((DWORD*)dst)[o + 2] = c;
963 case 2:
964 ((DWORD*)dst)[o + 1] = c;
965 case 1:
966 ((DWORD*)dst)[o + 0] = c;
970 void memsetw(void* dst, unsigned short c, size_t nbytes)
972 memsetd(dst, c << 16 | c, nbytes);
974 size_t n = nbytes / 2;
975 size_t o = (n / 2) * 2;
976 if ((n - o) == 1) {
977 ((WORD*)dst)[o] = c;
981 bool ExtractBIH(const AM_MEDIA_TYPE* pmt, BITMAPINFOHEADER* bih)
983 if(pmt && bih)
985 memset(bih, 0, sizeof(*bih));
987 if(pmt->formattype == FORMAT_VideoInfo)
989 VIDEOINFOHEADER* vih = (VIDEOINFOHEADER*)pmt->pbFormat;
990 memcpy(bih, &vih->bmiHeader, sizeof(BITMAPINFOHEADER));
991 return true;
993 else if(pmt->formattype == FORMAT_VideoInfo2)
995 VIDEOINFOHEADER2* vih = (VIDEOINFOHEADER2*)pmt->pbFormat;
996 memcpy(bih, &vih->bmiHeader, sizeof(BITMAPINFOHEADER));
997 return true;
999 else if(pmt->formattype == FORMAT_MPEGVideo)
1001 VIDEOINFOHEADER* vih = &((MPEG1VIDEOINFO*)pmt->pbFormat)->hdr;
1002 memcpy(bih, &vih->bmiHeader, sizeof(BITMAPINFOHEADER));
1003 return true;
1005 else if(pmt->formattype == FORMAT_MPEG2_VIDEO)
1007 VIDEOINFOHEADER2* vih = &((MPEG2VIDEOINFO*)pmt->pbFormat)->hdr;
1008 memcpy(bih, &vih->bmiHeader, sizeof(BITMAPINFOHEADER));
1009 return true;
1011 else if(pmt->formattype == FORMAT_DiracVideoInfo)
1013 VIDEOINFOHEADER2* vih = &((DIRACINFOHEADER*)pmt->pbFormat)->hdr;
1014 memcpy(bih, &vih->bmiHeader, sizeof(BITMAPINFOHEADER));
1015 return true;
1019 return false;
1022 bool ExtractBIH(IMediaSample* pMS, BITMAPINFOHEADER* bih)
1024 AM_MEDIA_TYPE* pmt = NULL;
1025 pMS->GetMediaType(&pmt);
1026 if(pmt)
1028 bool fRet = ExtractBIH(pmt, bih);
1029 DeleteMediaType(pmt);
1030 return(fRet);
1033 return(false);
1036 bool ExtractDim(const AM_MEDIA_TYPE* pmt, int& w, int& h, int& arx, int& ary)
1038 w = h = arx = ary = 0;
1040 if(pmt->formattype == FORMAT_VideoInfo || pmt->formattype == FORMAT_MPEGVideo)
1042 VIDEOINFOHEADER* vih = (VIDEOINFOHEADER*)pmt->pbFormat;
1043 w = vih->bmiHeader.biWidth;
1044 h = abs(vih->bmiHeader.biHeight);
1045 arx = w * vih->bmiHeader.biYPelsPerMeter;
1046 ary = h * vih->bmiHeader.biXPelsPerMeter;
1048 else if(pmt->formattype == FORMAT_VideoInfo2 || pmt->formattype == FORMAT_MPEG2_VIDEO || pmt->formattype == FORMAT_DiracVideoInfo)
1050 VIDEOINFOHEADER2* vih = (VIDEOINFOHEADER2*)pmt->pbFormat;
1051 w = vih->bmiHeader.biWidth;
1052 h = abs(vih->bmiHeader.biHeight);
1053 arx = vih->dwPictAspectRatioX;
1054 ary = vih->dwPictAspectRatioY;
1056 else
1058 return(false);
1061 if(!arx || !ary)
1063 arx = w;
1064 ary = h;
1067 BYTE* ptr = NULL;
1068 DWORD len = 0;
1070 if(pmt->formattype == FORMAT_MPEGVideo)
1072 ptr = ((MPEG1VIDEOINFO*)pmt->pbFormat)->bSequenceHeader;
1073 len = ((MPEG1VIDEOINFO*)pmt->pbFormat)->cbSequenceHeader;
1075 if(ptr && len >= 8 && *(DWORD*)ptr == 0xb3010000)
1077 w = (ptr[4]<<4)|(ptr[5]>>4);
1078 h = ((ptr[5]&0xf)<<8)|ptr[6];
1079 float ar[] =
1081 1.0000f,1.0000f,0.6735f,0.7031f,
1082 0.7615f,0.8055f,0.8437f,0.8935f,
1083 0.9157f,0.9815f,1.0255f,1.0695f,
1084 1.0950f,1.1575f,1.2015f,1.0000f,
1086 arx = (int)((float)w / ar[ptr[7]>>4] + 0.5);
1087 ary = h;
1090 else if(pmt->formattype == FORMAT_MPEG2_VIDEO)
1092 ptr = (BYTE*)((MPEG2VIDEOINFO*)pmt->pbFormat)->dwSequenceHeader;
1093 len = ((MPEG2VIDEOINFO*)pmt->pbFormat)->cbSequenceHeader;
1095 if(ptr && len >= 8 && *(DWORD*)ptr == 0xb3010000)
1097 w = (ptr[4]<<4)|(ptr[5]>>4);
1098 h = ((ptr[5]&0xf)<<8)|ptr[6];
1099 struct {int x, y;} ar[] = {{w,h},{4,3},{16,9},{221,100},{w,h}};
1100 int i = min(max(ptr[7]>>4, 1), 5)-1;
1101 arx = ar[i].x;
1102 ary = ar[i].y;
1106 if(ptr && len >= 8)
1111 DWORD a = arx, b = ary;
1112 while(a) {int tmp = a; a = b % tmp; b = tmp;}
1113 if(b) arx /= b, ary /= b;
1115 return(true);
1118 bool MakeMPEG2MediaType(CMediaType& mt, BYTE* seqhdr, DWORD len, int w, int h)
1120 if(len < 4 || *(DWORD*)seqhdr != 0xb3010000) return false;
1122 BYTE* seqhdr_ext = NULL;
1124 BYTE* seqhdr_end = seqhdr + 11;
1125 if(seqhdr_end - seqhdr > len) return false;
1126 if(*seqhdr_end & 0x02) seqhdr_end += 64;
1127 if(seqhdr_end - seqhdr > len) return false;
1128 if(*seqhdr_end & 0x01) seqhdr_end += 64;
1129 if(seqhdr_end - seqhdr > len) return false;
1130 seqhdr_end++;
1131 if(seqhdr_end - seqhdr > len) return false;
1132 if(len - (seqhdr_end - seqhdr) > 4 && *(DWORD*)seqhdr_end == 0xb5010000) {seqhdr_ext = seqhdr_end; seqhdr_end += 10;}
1133 if(seqhdr_end - seqhdr > len) return false;
1135 len = seqhdr_end - seqhdr;
1137 mt = CMediaType();
1139 mt.majortype = MEDIATYPE_Video;
1140 mt.subtype = MEDIASUBTYPE_MPEG2_VIDEO;
1141 mt.formattype = FORMAT_MPEG2Video;
1143 MPEG2VIDEOINFO* vih = (MPEG2VIDEOINFO*)mt.AllocFormatBuffer(FIELD_OFFSET(MPEG2VIDEOINFO, dwSequenceHeader) + len);
1144 memset(mt.Format(), 0, mt.FormatLength());
1145 vih->hdr.bmiHeader.biSize = sizeof(vih->hdr.bmiHeader);
1146 vih->hdr.bmiHeader.biWidth = w;
1147 vih->hdr.bmiHeader.biHeight = h;
1149 BYTE* pSequenceHeader = (BYTE*)vih->dwSequenceHeader;
1150 memcpy(pSequenceHeader, seqhdr, len);
1151 vih->cbSequenceHeader = len;
1153 static char profile[8] =
1155 0, AM_MPEG2Profile_High, AM_MPEG2Profile_SpatiallyScalable, AM_MPEG2Profile_SNRScalable,
1156 AM_MPEG2Profile_Main, AM_MPEG2Profile_Simple, 0, 0
1159 static char level[16] =
1161 0, 0, 0, 0,
1162 AM_MPEG2Level_High, 0, AM_MPEG2Level_High1440, 0,
1163 AM_MPEG2Level_Main, 0, AM_MPEG2Level_Low, 0,
1164 0, 0, 0, 0
1167 if(seqhdr_ext && (seqhdr_ext[4] & 0xf0) == 0x10)
1169 vih->dwProfile = profile[seqhdr_ext[4] & 0x07];
1170 vih->dwLevel = level[seqhdr_ext[5] >> 4];
1173 return true;
1176 unsigned __int64 GetFileVersion(LPCTSTR fn)
1178 unsigned __int64 ret = 0;
1180 DWORD buff[4];
1181 VS_FIXEDFILEINFO* pvsf = (VS_FIXEDFILEINFO*)buff;
1182 DWORD d; // a variable that GetFileVersionInfoSize sets to zero (but why is it needed ?????????????????????????????? :)
1183 DWORD len = GetFileVersionInfoSize((TCHAR*)fn, &d);
1185 if(len)
1187 TCHAR* b1 = new TCHAR[len];
1188 if(b1)
1190 UINT uLen;
1191 if(GetFileVersionInfo((TCHAR*)fn, 0, len, b1) && VerQueryValue(b1, _T("\\"), (void**)&pvsf, &uLen))
1193 ret = ((unsigned __int64)pvsf->dwFileVersionMS<<32) | pvsf->dwFileVersionLS;
1196 delete [] b1;
1200 return ret;
1203 bool CreateFilter(CStringW DisplayName, IBaseFilter** ppBF, CStringW& FriendlyName)
1205 if(!ppBF) return(false);
1207 *ppBF = NULL;
1208 FriendlyName.Empty();
1210 CComPtr<IBindCtx> pBindCtx;
1211 CreateBindCtx(0, &pBindCtx);
1213 CComPtr<IMoniker> pMoniker;
1214 ULONG chEaten;
1215 if(S_OK != MkParseDisplayName(pBindCtx, CComBSTR(DisplayName), &chEaten, &pMoniker))
1216 return(false);
1218 if(FAILED(pMoniker->BindToObject(pBindCtx, 0, IID_IBaseFilter, (void**)ppBF)) || !*ppBF)
1219 return(false);
1221 CComPtr<IPropertyBag> pPB;
1222 CComVariant var;
1223 if(SUCCEEDED(pMoniker->BindToStorage(pBindCtx, 0, IID_IPropertyBag, (void**)&pPB))
1224 && SUCCEEDED(pPB->Read(CComBSTR(_T("FriendlyName")), &var, NULL)))
1225 FriendlyName = var.bstrVal;
1227 return(true);
1230 IBaseFilter* AppendFilter(IPin* pPin, IMoniker* pMoniker, IGraphBuilder* pGB)
1234 if(!pPin || !pMoniker || !pGB)
1235 break;
1237 CComPtr<IPin> pPinTo;
1238 PIN_DIRECTION dir;
1239 if(FAILED(pPin->QueryDirection(&dir)) || dir != PINDIR_OUTPUT || SUCCEEDED(pPin->ConnectedTo(&pPinTo)))
1240 break;
1242 CComPtr<IBindCtx> pBindCtx;
1243 CreateBindCtx(0, &pBindCtx);
1245 CComPtr<IPropertyBag> pPB;
1246 if(FAILED(pMoniker->BindToStorage(pBindCtx, 0, IID_IPropertyBag, (void**)&pPB)))
1247 break;
1249 CComVariant var;
1250 if(FAILED(pPB->Read(CComBSTR(_T("FriendlyName")), &var, NULL)))
1251 break;
1253 CComPtr<IBaseFilter> pBF;
1254 if(FAILED(pMoniker->BindToObject(pBindCtx, 0, IID_IBaseFilter, (void**)&pBF)) || !pBF)
1255 break;
1257 if(FAILED(pGB->AddFilter(pBF, CStringW(var.bstrVal))))
1258 break;
1260 BeginEnumPins(pBF, pEP, pPinTo)
1262 PIN_DIRECTION dir;
1263 if(FAILED(pPinTo->QueryDirection(&dir)) || dir != PINDIR_INPUT)
1264 continue;
1266 if(SUCCEEDED(pGB->ConnectDirect(pPin, pPinTo, NULL)))
1267 return(pBF);
1269 EndEnumFilters
1271 pGB->RemoveFilter(pBF);
1273 while(false);
1275 return(NULL);
1278 CStringW GetFriendlyName(CStringW DisplayName)
1280 CStringW FriendlyName;
1282 CComPtr<IBindCtx> pBindCtx;
1283 CreateBindCtx(0, &pBindCtx);
1285 CComPtr<IMoniker> pMoniker;
1286 ULONG chEaten;
1287 if(S_OK != MkParseDisplayName(pBindCtx, CComBSTR(DisplayName), &chEaten, &pMoniker))
1288 return(false);
1290 CComPtr<IPropertyBag> pPB;
1291 CComVariant var;
1292 if(SUCCEEDED(pMoniker->BindToStorage(pBindCtx, 0, IID_IPropertyBag, (void**)&pPB))
1293 && SUCCEEDED(pPB->Read(CComBSTR(_T("FriendlyName")), &var, NULL)))
1294 FriendlyName = var.bstrVal;
1296 return FriendlyName;
1299 typedef struct
1301 CString path;
1302 HINSTANCE hInst;
1303 CLSID clsid;
1304 } ExternalObject;
1306 static CAtlList<ExternalObject> s_extobjs;
1308 HRESULT LoadExternalObject(LPCTSTR path, REFCLSID clsid, REFIID iid, void** ppv)
1310 CheckPointer(ppv, E_POINTER);
1312 CString fullpath = MakeFullPath(path);
1314 HINSTANCE hInst = NULL;
1315 bool fFound = false;
1317 POSITION pos = s_extobjs.GetHeadPosition();
1318 while(pos)
1320 ExternalObject& eo = s_extobjs.GetNext(pos);
1321 if(!eo.path.CompareNoCase(fullpath))
1323 hInst = eo.hInst;
1324 fFound = true;
1325 break;
1329 HRESULT hr = E_FAIL;
1331 if(hInst || (hInst = CoLoadLibrary(CComBSTR(fullpath), TRUE)))
1333 typedef HRESULT (__stdcall * PDllGetClassObject)(REFCLSID rclsid, REFIID riid, LPVOID* ppv);
1334 PDllGetClassObject p = (PDllGetClassObject)GetProcAddress(hInst, "DllGetClassObject");
1336 if(p && FAILED(hr = p(clsid, iid, ppv)))
1338 CComPtr<IClassFactory> pCF;
1339 if(SUCCEEDED(hr = p(clsid, __uuidof(IClassFactory), (void**)&pCF)))
1341 hr = pCF->CreateInstance(NULL, iid, ppv);
1346 if(FAILED(hr) && hInst && !fFound)
1348 CoFreeLibrary(hInst);
1349 return hr;
1352 if(hInst && !fFound)
1354 ExternalObject eo;
1355 eo.path = fullpath;
1356 eo.hInst = hInst;
1357 eo.clsid = clsid;
1358 s_extobjs.AddTail(eo);
1361 return hr;
1364 HRESULT LoadExternalFilter(LPCTSTR path, REFCLSID clsid, IBaseFilter** ppBF)
1366 return LoadExternalObject(path, clsid, __uuidof(IBaseFilter), (void**)ppBF);
1369 HRESULT LoadExternalPropertyPage(IPersist* pP, REFCLSID clsid, IPropertyPage** ppPP)
1371 CLSID clsid2 = GUID_NULL;
1372 if(FAILED(pP->GetClassID(&clsid2))) return E_FAIL;
1374 POSITION pos = s_extobjs.GetHeadPosition();
1375 while(pos)
1377 ExternalObject& eo = s_extobjs.GetNext(pos);
1378 if(eo.clsid == clsid2)
1380 return LoadExternalObject(eo.path, clsid, __uuidof(IPropertyPage), (void**)ppPP);
1384 return E_FAIL;
1387 void UnloadExternalObjects()
1389 POSITION pos = s_extobjs.GetHeadPosition();
1390 while(pos)
1392 ExternalObject& eo = s_extobjs.GetNext(pos);
1393 CoFreeLibrary(eo.hInst);
1395 s_extobjs.RemoveAll();
1398 CString MakeFullPath(LPCTSTR path)
1400 CString full(path);
1401 full.Replace('/', '\\');
1403 CString fn;
1404 fn.ReleaseBuffer(GetModuleFileName(AfxGetInstanceHandle(), fn.GetBuffer(MAX_PATH), MAX_PATH));
1405 CPath p(fn);
1407 if(full.GetLength() >= 2 && full[0] == '\\' && full[1] != '\\')
1409 p.StripToRoot();
1410 full = CString(p) + full.Mid(1);
1412 else if(full.Find(_T(":\\")) < 0)
1414 p.RemoveFileSpec();
1415 p.AddBackslash();
1416 full = CString(p) + full;
1419 CPath c(full);
1420 c.Canonicalize();
1421 return CString(c);
1426 CString GetMediaTypeName(const GUID& guid)
1428 CString ret = guid == GUID_NULL
1429 ? _T("Any type")
1430 : CString(GuidNames[guid]);
1432 if(ret == _T("FOURCC GUID"))
1434 CString str;
1435 if(guid.Data1 >= 0x10000)
1436 str.Format(_T("Video: %c%c%c%c"), (guid.Data1>>0)&0xff, (guid.Data1>>8)&0xff, (guid.Data1>>16)&0xff, (guid.Data1>>24)&0xff);
1437 else
1438 str.Format(_T("Audio: 0x%08x"), guid.Data1);
1439 ret = str;
1441 else if(ret == _T("Unknown GUID Name"))
1443 WCHAR null[128] = {0}, buff[128];
1444 StringFromGUID2(GUID_NULL, null, 127);
1445 ret = CString(CStringW(StringFromGUID2(guid, buff, 127) ? buff : null));
1448 return ret;
1451 GUID GUIDFromCString(CString str)
1453 GUID guid = GUID_NULL;
1454 HRESULT hr = CLSIDFromString(CComBSTR(str), &guid);
1455 ASSERT(SUCCEEDED(hr));
1456 return guid;
1459 HRESULT GUIDFromCString(CString str, GUID& guid)
1461 guid = GUID_NULL;
1462 return CLSIDFromString(CComBSTR(str), &guid);
1465 CString CStringFromGUID(const GUID& guid)
1467 WCHAR null[128] = {0}, buff[128];
1468 StringFromGUID2(GUID_NULL, null, 127);
1469 return CString(StringFromGUID2(guid, buff, 127) > 0 ? buff : null);
1472 CStringW UTF8To16(LPCSTR utf8)
1474 CStringW str;
1475 int n = MultiByteToWideChar(CP_UTF8, 0, utf8, -1, NULL, 0)-1;
1476 if(n < 0) return str;
1477 str.ReleaseBuffer(MultiByteToWideChar(CP_UTF8, 0, utf8, -1, str.GetBuffer(n), n+1)-1);
1478 return str;
1481 CStringA UTF16To8(LPCWSTR utf16)
1483 CStringA str;
1484 int n = WideCharToMultiByte(CP_UTF8, 0, utf16, -1, NULL, 0, NULL, NULL)-1;
1485 if(n < 0) return str;
1486 str.ReleaseBuffer(WideCharToMultiByte(CP_UTF8, 0, utf16, -1, str.GetBuffer(n), n+1, NULL, NULL)-1);
1487 return str;
1490 static struct {
1491 LPCSTR name, iso6392, iso6391;
1492 LCID lcid;
1493 } s_isolangs[] = { // TODO : fill LCID !!!
1494 {"Abkhazian", "abk", "ab"},
1495 {"Achinese", "ace", ""},
1496 {"Acoli", "ach", ""},
1497 {"Adangme", "ada", ""},
1498 {"Afar", "aar", "aa"},
1499 {"Afrihili", "afh", ""},
1500 {"Afrikaans", "afr", "af", MAKELCID( MAKELANGID(LANG_AFRIKAANS, SUBLANG_DEFAULT), SORT_DEFAULT)},
1501 {"Afro-Asiatic (Other)", "afa", ""},
1502 {"Akan", "aka", "ak"},
1503 {"Akkadian", "akk", ""},
1504 {"Albanian", "alb", "sq"},
1505 {"Albanian", "sqi", "sq", MAKELCID( MAKELANGID(LANG_ALBANIAN, SUBLANG_DEFAULT), SORT_DEFAULT)},
1506 {"Aleut", "ale", ""},
1507 {"Algonquian languages", "alg", ""},
1508 {"Altaic (Other)", "tut", ""},
1509 {"Amharic", "amh", "am"},
1510 {"Apache languages", "apa", ""},
1511 {"Arabic", "ara", "ar", MAKELCID( MAKELANGID(LANG_ARABIC, SUBLANG_DEFAULT), SORT_DEFAULT)},
1512 {"Aragonese", "arg", "an"},
1513 {"Aramaic", "arc", ""},
1514 {"Arapaho", "arp", ""},
1515 {"Araucanian", "arn", ""},
1516 {"Arawak", "arw", ""},
1517 {"Armenian", "arm", "hy", MAKELCID( MAKELANGID(LANG_ARMENIAN, SUBLANG_DEFAULT), SORT_DEFAULT)},
1518 {"Armenian", "hye", "hy", MAKELCID( MAKELANGID(LANG_ARMENIAN, SUBLANG_DEFAULT), SORT_DEFAULT)},
1519 {"Artificial (Other)", "art", ""},
1520 {"Assamese", "asm", "as", MAKELCID( MAKELANGID(LANG_ASSAMESE, SUBLANG_DEFAULT), SORT_DEFAULT)},
1521 {"Asturian; Bable", "ast", ""},
1522 {"Athapascan languages", "ath", ""},
1523 {"Australian languages", "aus", ""},
1524 {"Austronesian (Other)", "map", ""},
1525 {"Avaric", "ava", "av"},
1526 {"Avestan", "ave", "ae"},
1527 {"Awadhi", "awa", ""},
1528 {"Aymara", "aym", "ay"},
1529 {"Azerbaijani", "aze", "az", MAKELCID( MAKELANGID(LANG_AZERI, SUBLANG_DEFAULT), SORT_DEFAULT)},
1530 {"Bable; Asturian", "ast", ""},
1531 {"Balinese", "ban", ""},
1532 {"Baltic (Other)", "bat", ""},
1533 {"Baluchi", "bal", ""},
1534 {"Bambara", "bam", "bm"},
1535 {"Bamileke languages", "bai", ""},
1536 {"Banda", "bad", ""},
1537 {"Bantu (Other)", "bnt", ""},
1538 {"Basa", "bas", ""},
1539 {"Bashkir", "bak", "ba", MAKELCID( MAKELANGID(LANG_BASHKIR, SUBLANG_DEFAULT), SORT_DEFAULT)},
1540 {"Basque", "baq", "eu", MAKELCID( MAKELANGID(LANG_BASQUE, SUBLANG_DEFAULT), SORT_DEFAULT)},
1541 {"Basque", "eus", "eu", MAKELCID( MAKELANGID(LANG_BASQUE, SUBLANG_DEFAULT), SORT_DEFAULT)},
1542 {"Batak (Indonesia)", "btk", ""},
1543 {"Beja", "bej", ""},
1544 {"Belarusian", "bel", "be", MAKELCID( MAKELANGID(LANG_BELARUSIAN, SUBLANG_DEFAULT), SORT_DEFAULT)},
1545 {"Bemba", "bem", ""},
1546 {"Bengali", "ben", "bn", MAKELCID( MAKELANGID(LANG_BENGALI, SUBLANG_DEFAULT), SORT_DEFAULT)},
1547 {"Berber (Other)", "ber", ""},
1548 {"Bhojpuri", "bho", ""},
1549 {"Bihari", "bih", "bh"},
1550 {"Bikol", "bik", ""},
1551 {"Bini", "bin", ""},
1552 {"Bislama", "bis", "bi"},
1553 {"Bokmål, Norwegian; Norwegian Bokmål", "nob", "nb"},
1554 {"Bosnian", "bos", "bs"},
1555 {"Braj", "bra", ""},
1556 {"Breton", "bre", "br", MAKELCID( MAKELANGID(LANG_BRETON, SUBLANG_DEFAULT), SORT_DEFAULT)},
1557 {"Buginese", "bug", ""},
1558 {"Bulgarian", "bul", "bg", MAKELCID( MAKELANGID(LANG_BULGARIAN, SUBLANG_DEFAULT), SORT_DEFAULT)},
1559 {"Buriat", "bua", ""},
1560 {"Burmese", "bur", "my"},
1561 {"Burmese", "mya", "my"},
1562 {"Caddo", "cad", ""},
1563 {"Carib", "car", ""},
1564 {"Spanish; Castilian", "spa", "es", MAKELCID( MAKELANGID(LANG_SPANISH, SUBLANG_DEFAULT), SORT_DEFAULT)},
1565 {"Catalan", "cat", "ca", MAKELCID( MAKELANGID(LANG_CATALAN, SUBLANG_DEFAULT), SORT_DEFAULT)},
1566 {"Caucasian (Other)", "cau", ""},
1567 {"Cebuano", "ceb", ""},
1568 {"Celtic (Other)", "cel", ""},
1569 {"Central American Indian (Other)", "cai", ""},
1570 {"Chagatai", "chg", ""},
1571 {"Chamic languages", "cmc", ""},
1572 {"Chamorro", "cha", "ch"},
1573 {"Chechen", "che", "ce"},
1574 {"Cherokee", "chr", ""},
1575 {"Chewa; Chichewa; Nyanja", "nya", "ny"},
1576 {"Cheyenne", "chy", ""},
1577 {"Chibcha", "chb", ""},
1578 {"Chichewa; Chewa; Nyanja", "nya", "ny"},
1579 {"Chinese", "chi", "zh", MAKELCID( MAKELANGID(LANG_CHINESE, SUBLANG_DEFAULT), SORT_DEFAULT)},
1580 {"Chinese", "zho", "zh"},
1581 {"Chinook jargon", "chn", ""},
1582 {"Chipewyan", "chp", ""},
1583 {"Choctaw", "cho", ""},
1584 {"Chuang; Zhuang", "zha", "za"},
1585 {"Church Slavic; Old Church Slavonic", "chu", "cu"},
1586 {"Old Church Slavonic; Old Slavonic; ", "chu", "cu"},
1587 {"Church Slavonic; Old Bulgarian; Church Slavic;", "chu", "cu"},
1588 {"Old Slavonic; Church Slavonic; Old Bulgarian;", "chu", "cu"},
1589 {"Church Slavic; Old Church Slavonic", "chu", "cu"},
1590 {"Chuukese", "chk", ""},
1591 {"Chuvash", "chv", "cv"},
1592 {"Coptic", "cop", ""},
1593 {"Cornish", "cor", "kw"},
1594 {"Corsican", "cos", "co", MAKELCID( MAKELANGID(LANG_CORSICAN, SUBLANG_DEFAULT), SORT_DEFAULT)},
1595 {"Cree", "cre", "cr"},
1596 {"Creek", "mus", ""},
1597 {"Creoles and pidgins (Other)", "crp", ""},
1598 {"Creoles and pidgins,", "cpe", ""},
1599 // {"English-based (Other)", "", ""},
1600 {"Creoles and pidgins,", "cpf", ""},
1601 // {"French-based (Other)", "", ""},
1602 {"Creoles and pidgins,", "cpp", ""},
1603 // {"Portuguese-based (Other)", "", ""},
1604 {"Croatian", "scr", "hr", MAKELCID( MAKELANGID(LANG_CROATIAN, SUBLANG_DEFAULT), SORT_DEFAULT)},
1605 {"Croatian", "hrv", "hr", MAKELCID( MAKELANGID(LANG_CROATIAN, SUBLANG_DEFAULT), SORT_DEFAULT)},
1606 {"Cushitic (Other)", "cus", ""},
1607 {"Czech", "cze", "cs", MAKELCID( MAKELANGID(LANG_CZECH, SUBLANG_DEFAULT), SORT_DEFAULT)},
1608 {"Czech", "ces", "cs", MAKELCID( MAKELANGID(LANG_CZECH, SUBLANG_DEFAULT), SORT_DEFAULT)},
1609 {"Dakota", "dak", ""},
1610 {"Danish", "dan", "da", MAKELCID( MAKELANGID(LANG_DANISH, SUBLANG_DEFAULT), SORT_DEFAULT)},
1611 {"Dargwa", "dar", ""},
1612 {"Dayak", "day", ""},
1613 {"Delaware", "del", ""},
1614 {"Dinka", "din", ""},
1615 {"Divehi", "div", "dv", MAKELCID( MAKELANGID(LANG_DIVEHI, SUBLANG_DEFAULT), SORT_DEFAULT)},
1616 {"Dogri", "doi", ""},
1617 {"Dogrib", "dgr", ""},
1618 {"Dravidian (Other)", "dra", ""},
1619 {"Duala", "dua", ""},
1620 {"Dutch; Flemish", "dut", "nl", MAKELCID( MAKELANGID(LANG_DUTCH, SUBLANG_DEFAULT), SORT_DEFAULT)},
1621 {"Dutch; Flemish", "nld", "nl", MAKELCID( MAKELANGID(LANG_DUTCH, SUBLANG_DEFAULT), SORT_DEFAULT)},
1622 {"Dutch, Middle (ca. 1050-1350)", "dum", ""},
1623 {"Dyula", "dyu", ""},
1624 {"Dzongkha", "dzo", "dz"},
1625 {"Efik", "efi", ""},
1626 {"Egyptian (Ancient)", "egy", ""},
1627 {"Ekajuk", "eka", ""},
1628 {"Elamite", "elx", ""},
1629 {"English", "eng", "en", MAKELCID( MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), SORT_DEFAULT)},
1630 {"English, Middle (1100-1500)", "enm", ""},
1631 {"English, Old (ca.450-1100)", "ang", ""},
1632 {"Esperanto", "epo", "eo"},
1633 {"Estonian", "est", "et", MAKELCID( MAKELANGID(LANG_ESTONIAN, SUBLANG_DEFAULT), SORT_DEFAULT)},
1634 {"Ewe", "ewe", "ee"},
1635 {"Ewondo", "ewo", ""},
1636 {"Fang", "fan", ""},
1637 {"Fanti", "fat", ""},
1638 {"Faroese", "fao", "fo", MAKELCID( MAKELANGID(LANG_FAEROESE, SUBLANG_DEFAULT), SORT_DEFAULT)},
1639 {"Fijian", "fij", "fj"},
1640 {"Finnish", "fin", "fi", MAKELCID( MAKELANGID(LANG_FINNISH, SUBLANG_DEFAULT), SORT_DEFAULT)},
1641 {"Finno-Ugrian (Other)", "fiu", ""},
1642 {"Flemish; Dutch", "dut", "nl"},
1643 {"Flemish; Dutch", "nld", "nl"},
1644 {"Fon", "fon", ""},
1645 {"French", "fre", "fr", MAKELCID( MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), SORT_DEFAULT)},
1646 {"French", "fra*", "fr", MAKELCID( MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), SORT_DEFAULT)},
1647 {"French", "fra", "fr", MAKELCID( MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), SORT_DEFAULT)},
1648 {"French, Middle (ca.1400-1600)", "frm", ""},
1649 {"French, Old (842-ca.1400)", "fro", ""},
1650 {"Frisian", "fry", "fy", MAKELCID( MAKELANGID(LANG_FRISIAN, SUBLANG_DEFAULT), SORT_DEFAULT)},
1651 {"Friulian", "fur", ""},
1652 {"Fulah", "ful", "ff"},
1653 {"Ga", "gaa", ""},
1654 {"Gaelic; Scottish Gaelic", "gla", "gd", MAKELCID( MAKELANGID(LANG_GALICIAN, SUBLANG_DEFAULT), SORT_DEFAULT)},
1655 {"Gallegan", "glg", "gl"},
1656 {"Ganda", "lug", "lg"},
1657 {"Gayo", "gay", ""},
1658 {"Gbaya", "gba", ""},
1659 {"Geez", "gez", ""},
1660 {"Georgian", "geo", "ka", MAKELCID( MAKELANGID(LANG_GEORGIAN, SUBLANG_DEFAULT), SORT_DEFAULT)},
1661 {"Georgian", "kat", "ka", MAKELCID( MAKELANGID(LANG_GEORGIAN, SUBLANG_DEFAULT), SORT_DEFAULT)},
1662 {"German", "ger", "de", MAKELCID( MAKELANGID(LANG_GERMAN, SUBLANG_DEFAULT), SORT_DEFAULT)},
1663 {"German", "deu", "de", MAKELCID( MAKELANGID(LANG_GERMAN, SUBLANG_DEFAULT), SORT_DEFAULT)},
1664 {"German, Low; Saxon, Low; Low German; Low Saxon", "nds", ""},
1665 {"German, Middle High (ca.1050-1500)", "gmh", ""},
1666 {"German, Old High (ca.750-1050)", "goh", ""},
1667 {"Germanic (Other)", "gem", ""},
1668 {"Gikuyu; Kikuyu", "kik", "ki"},
1669 {"Gilbertese", "gil", ""},
1670 {"Gondi", "gon", ""},
1671 {"Gorontalo", "gor", ""},
1672 {"Gothic", "got", ""},
1673 {"Grebo", "grb", ""},
1674 {"Greek, Ancient (to 1453)", "grc", "", MAKELCID( MAKELANGID(LANG_GREEK, SUBLANG_DEFAULT), SORT_DEFAULT)},
1675 {"Greek, Modern (1453-)", "gre", "el", MAKELCID( MAKELANGID(LANG_GREEK, SUBLANG_DEFAULT), SORT_DEFAULT)},
1676 {"Greek, Modern (1453-)", "ell", "el", MAKELCID( MAKELANGID(LANG_GREEK, SUBLANG_DEFAULT), SORT_DEFAULT)},
1677 {"Greenlandic; Kalaallisut", "kal", "kl", MAKELCID( MAKELANGID(LANG_GREENLANDIC, SUBLANG_DEFAULT), SORT_DEFAULT)},
1678 {"Guarani", "grn", "gn"},
1679 {"Gujarati", "guj", "gu", MAKELCID( MAKELANGID(LANG_GUJARATI, SUBLANG_DEFAULT), SORT_DEFAULT)},
1680 {"Gwich´in", "gwi", ""},
1681 {"Haida", "hai", ""},
1682 {"Hausa", "hau", "ha", MAKELCID( MAKELANGID(LANG_HAUSA, SUBLANG_DEFAULT), SORT_DEFAULT)},
1683 {"Hawaiian", "haw", ""},
1684 {"Hebrew", "heb", "he", MAKELCID( MAKELANGID(LANG_HEBREW, SUBLANG_DEFAULT), SORT_DEFAULT)},
1685 {"Herero", "her", "hz"},
1686 {"Hiligaynon", "hil", ""},
1687 {"Himachali", "him", ""},
1688 {"Hindi", "hin", "hi", MAKELCID( MAKELANGID(LANG_HINDI, SUBLANG_DEFAULT), SORT_DEFAULT)},
1689 {"Hiri Motu", "hmo", "ho"},
1690 {"Hittite", "hit", ""},
1691 {"Hmong", "hmn", ""},
1692 {"Hungarian", "hun", "hu", MAKELCID( MAKELANGID(LANG_HUNGARIAN, SUBLANG_DEFAULT), SORT_DEFAULT)},
1693 {"Hupa", "hup", ""},
1694 {"Iban", "iba", ""},
1695 {"Icelandic", "ice", "is", MAKELCID( MAKELANGID(LANG_ICELANDIC, SUBLANG_DEFAULT), SORT_DEFAULT)},
1696 {"Icelandic", "isl", "is", MAKELCID( MAKELANGID(LANG_ICELANDIC, SUBLANG_DEFAULT), SORT_DEFAULT)},
1697 {"Ido", "ido", "io"},
1698 {"Igbo", "ibo", "ig", MAKELCID( MAKELANGID(LANG_IGBO, SUBLANG_DEFAULT), SORT_DEFAULT)},
1699 {"Ijo", "ijo", ""},
1700 {"Iloko", "ilo", ""},
1701 {"Inari Sami", "smn", ""},
1702 {"Indic (Other)", "inc", ""},
1703 {"Indo-European (Other)", "ine", ""},
1704 {"Indonesian", "ind", "id", MAKELCID( MAKELANGID(LANG_INDONESIAN, SUBLANG_DEFAULT), SORT_DEFAULT)},
1705 {"Ingush", "inh", ""},
1706 {"Interlingua (International", "ina", "ia"},
1707 // {"Auxiliary Language Association)", "", ""},
1708 {"Interlingue", "ile", "ie"},
1709 {"Inuktitut", "iku", "iu", MAKELCID( MAKELANGID(LANG_INUKTITUT, SUBLANG_DEFAULT), SORT_DEFAULT)},
1710 {"Inupiaq", "ipk", "ik"},
1711 {"Iranian (Other)", "ira", ""},
1712 {"Irish", "gle", "ga", MAKELCID( MAKELANGID(LANG_IRISH, SUBLANG_DEFAULT), SORT_DEFAULT)},
1713 {"Irish, Middle (900-1200)", "mga", "", MAKELCID( MAKELANGID(LANG_IRISH, SUBLANG_DEFAULT), SORT_DEFAULT)},
1714 {"Irish, Old (to 900)", "sga", "", MAKELCID( MAKELANGID(LANG_IRISH, SUBLANG_DEFAULT), SORT_DEFAULT)},
1715 {"Iroquoian languages", "iro", ""},
1716 {"Italian", "ita", "it", MAKELCID( MAKELANGID(LANG_ITALIAN, SUBLANG_DEFAULT), SORT_DEFAULT)},
1717 {"Japanese", "jpn", "ja", MAKELCID( MAKELANGID(LANG_JAPANESE, SUBLANG_DEFAULT), SORT_DEFAULT)},
1718 {"Javanese", "jav", "jv"},
1719 {"Judeo-Arabic", "jrb", ""},
1720 {"Judeo-Persian", "jpr", ""},
1721 {"Kabardian", "kbd", ""},
1722 {"Kabyle", "kab", ""},
1723 {"Kachin", "kac", ""},
1724 {"Kalaallisut; Greenlandic", "kal", "kl"},
1725 {"Kamba", "kam", ""},
1726 {"Kannada", "kan", "kn", MAKELCID( MAKELANGID(LANG_KANNADA, SUBLANG_DEFAULT), SORT_DEFAULT)},
1727 {"Kanuri", "kau", "kr"},
1728 {"Kara-Kalpak", "kaa", ""},
1729 {"Karen", "kar", ""},
1730 {"Kashmiri", "kas", "ks", MAKELCID( MAKELANGID(LANG_KASHMIRI, SUBLANG_DEFAULT), SORT_DEFAULT)},
1731 {"Kawi", "kaw", ""},
1732 {"Kazakh", "kaz", "kk", MAKELCID( MAKELANGID(LANG_KAZAK, SUBLANG_DEFAULT), SORT_DEFAULT)},
1733 {"Khasi", "kha", ""},
1734 {"Khmer", "khm", "km", MAKELCID( MAKELANGID(LANG_KHMER, SUBLANG_DEFAULT), SORT_DEFAULT)},
1735 {"Khoisan (Other)", "khi", ""},
1736 {"Khotanese", "kho", ""},
1737 {"Kikuyu; Gikuyu", "kik", "ki"},
1738 {"Kimbundu", "kmb", ""},
1739 {"Kinyarwanda", "kin", "rw", MAKELCID( MAKELANGID(LANG_KINYARWANDA, SUBLANG_DEFAULT), SORT_DEFAULT)},
1740 {"Kirghiz", "kir", "ky"},
1741 {"Komi", "kom", "kv"},
1742 {"Kongo", "kon", "kg"},
1743 {"Konkani", "kok", "", MAKELCID( MAKELANGID(LANG_KONKANI, SUBLANG_DEFAULT), SORT_DEFAULT)},
1744 {"Korean", "kor", "ko", MAKELCID( MAKELANGID(LANG_KOREAN, SUBLANG_DEFAULT), SORT_DEFAULT)},
1745 {"Kosraean", "kos", ""},
1746 {"Kpelle", "kpe", ""},
1747 {"Kru", "kro", ""},
1748 {"Kuanyama; Kwanyama", "kua", "kj"},
1749 {"Kumyk", "kum", ""},
1750 {"Kurdish", "kur", "ku"},
1751 {"Kurukh", "kru", ""},
1752 {"Kutenai", "kut", ""},
1753 {"Kwanyama, Kuanyama", "kua", "kj"},
1754 {"Ladino", "lad", ""},
1755 {"Lahnda", "lah", ""},
1756 {"Lamba", "lam", ""},
1757 {"Lao", "lao", "lo", MAKELCID( MAKELANGID(LANG_LAO, SUBLANG_DEFAULT), SORT_DEFAULT)},
1758 {"Latin", "lat", "la"},
1759 {"Latvian", "lav", "lv", MAKELCID( MAKELANGID(LANG_LATVIAN, SUBLANG_DEFAULT), SORT_DEFAULT)},
1760 {"Letzeburgesch; Luxembourgish", "ltz", "lb"},
1761 {"Lezghian", "lez", ""},
1762 {"Limburgan; Limburger; Limburgish", "lim", "li"},
1763 {"Limburger; Limburgan; Limburgish;", "lim", "li"},
1764 {"Limburgish; Limburger; Limburgan", "lim", "li"},
1765 {"Lingala", "lin", "ln"},
1766 {"Lithuanian", "lit", "lt", MAKELCID( MAKELANGID(LANG_LITHUANIAN, SUBLANG_DEFAULT), SORT_DEFAULT)},
1767 {"Low German; Low Saxon; German, Low; Saxon, Low", "nds", ""},
1768 {"Low Saxon; Low German; Saxon, Low; German, Low", "nds", ""},
1769 {"Lozi", "loz", ""},
1770 {"Luba-Katanga", "lub", "lu"},
1771 {"Luba-Lulua", "lua", ""},
1772 {"Luiseno", "lui", ""},
1773 {"Lule Sami", "smj", ""},
1774 {"Lunda", "lun", ""},
1775 {"Luo (Kenya and Tanzania)", "luo", ""},
1776 {"Lushai", "lus", ""},
1777 {"Luxembourgish; Letzeburgesch", "ltz", "lb", MAKELCID( MAKELANGID(LANG_LUXEMBOURGISH, SUBLANG_DEFAULT), SORT_DEFAULT)},
1778 {"Macedonian", "mac", "mk", MAKELCID( MAKELANGID(LANG_MACEDONIAN, SUBLANG_DEFAULT), SORT_DEFAULT)},
1779 {"Macedonian", "mkd", "mk", MAKELCID( MAKELANGID(LANG_MACEDONIAN, SUBLANG_DEFAULT), SORT_DEFAULT)},
1780 {"Madurese", "mad", ""},
1781 {"Magahi", "mag", ""},
1782 {"Maithili", "mai", ""},
1783 {"Makasar", "mak", ""},
1784 {"Malagasy", "mlg", "mg"},
1785 {"Malay", "may", "ms", MAKELCID( MAKELANGID(LANG_MALAY, SUBLANG_DEFAULT), SORT_DEFAULT)},
1786 {"Malay", "msa", "ms", MAKELCID( MAKELANGID(LANG_MALAY, SUBLANG_DEFAULT), SORT_DEFAULT)},
1787 {"Malayalam", "mal", "ml", MAKELCID( MAKELANGID(LANG_MALAYALAM, SUBLANG_DEFAULT), SORT_DEFAULT)},
1788 {"Maltese", "mlt", "mt", MAKELCID( MAKELANGID(LANG_MALTESE, SUBLANG_DEFAULT), SORT_DEFAULT)},
1789 {"Manchu", "mnc", ""},
1790 {"Mandar", "mdr", ""},
1791 {"Mandingo", "man", ""},
1792 {"Manipuri", "mni", "", MAKELCID( MAKELANGID(LANG_MANIPURI, SUBLANG_DEFAULT), SORT_DEFAULT)},
1793 {"Manobo languages", "mno", ""},
1794 {"Manx", "glv", "gv"},
1795 {"Maori", "mao", "mi", MAKELCID( MAKELANGID(LANG_MAORI, SUBLANG_DEFAULT), SORT_DEFAULT)},
1796 {"Maori", "mri", "mi", MAKELCID( MAKELANGID(LANG_MAORI, SUBLANG_DEFAULT), SORT_DEFAULT)},
1797 {"Marathi", "mar", "mr", MAKELCID( MAKELANGID(LANG_MARATHI, SUBLANG_DEFAULT), SORT_DEFAULT)},
1798 {"Mari", "chm", ""},
1799 {"Marshallese", "mah", "mh"},
1800 {"Marwari", "mwr", ""},
1801 {"Masai", "mas", ""},
1802 {"Mayan languages", "myn", ""},
1803 {"Mende", "men", ""},
1804 {"Micmac", "mic", ""},
1805 {"Minangkabau", "min", ""},
1806 {"Miscellaneous languages", "mis", ""},
1807 {"Mohawk", "moh", "", MAKELCID( MAKELANGID(LANG_MOHAWK, SUBLANG_DEFAULT), SORT_DEFAULT)},
1808 {"Moldavian", "mol", "mo"},
1809 {"Mon-Khmer (Other)", "mkh", ""},
1810 {"Mongo", "lol", ""},
1811 {"Mongolian", "mon", "mn", MAKELCID( MAKELANGID(LANG_MONGOLIAN, SUBLANG_DEFAULT), SORT_DEFAULT)},
1812 {"Mossi", "mos", ""},
1813 {"Multiple languages", "mul", ""},
1814 {"Munda languages", "mun", ""},
1815 {"Nahuatl", "nah", ""},
1816 {"Nauru", "nau", "na"},
1817 {"Navaho, Navajo", "nav", "nv"},
1818 {"Navajo; Navaho", "nav", "nv"},
1819 {"Ndebele, North", "nde", "nd"},
1820 {"Ndebele, South", "nbl", "nr"},
1821 {"Ndonga", "ndo", "ng"},
1822 {"Neapolitan", "nap", ""},
1823 {"Nepali", "nep", "ne", MAKELCID( MAKELANGID(LANG_NEPALI, SUBLANG_DEFAULT), SORT_DEFAULT)},
1824 {"Newari", "new", ""},
1825 {"Nias", "nia", ""},
1826 {"Niger-Kordofanian (Other)", "nic", ""},
1827 {"Nilo-Saharan (Other)", "ssa", ""},
1828 {"Niuean", "niu", ""},
1829 {"Norse, Old", "non", ""},
1830 {"North American Indian (Other)", "nai", ""},
1831 {"Northern Sami", "sme", "se"},
1832 {"North Ndebele", "nde", "nd"},
1833 {"Norwegian", "nor", "no", MAKELCID( MAKELANGID(LANG_NORWEGIAN, SUBLANG_DEFAULT), SORT_DEFAULT)},
1834 {"Norwegian Bokmål; Bokmål, Norwegian", "nob", "nb", MAKELCID( MAKELANGID(LANG_NORWEGIAN, SUBLANG_DEFAULT), SORT_DEFAULT)},
1835 {"Norwegian Nynorsk; Nynorsk, Norwegian", "nno", "nn", MAKELCID( MAKELANGID(LANG_NORWEGIAN, SUBLANG_DEFAULT), SORT_DEFAULT)},
1836 {"Nubian languages", "nub", ""},
1837 {"Nyamwezi", "nym", ""},
1838 {"Nyanja; Chichewa; Chewa", "nya", "ny"},
1839 {"Nyankole", "nyn", ""},
1840 {"Nynorsk, Norwegian; Norwegian Nynorsk", "nno", "nn"},
1841 {"Nyoro", "nyo", ""},
1842 {"Nzima", "nzi", ""},
1843 {"Occitan (post 1500},; Provençal", "oci", "oc", MAKELCID( MAKELANGID(LANG_OCCITAN, SUBLANG_DEFAULT), SORT_DEFAULT)},
1844 {"Ojibwa", "oji", "oj"},
1845 {"Old Bulgarian; Old Slavonic; Church Slavonic;", "chu", "cu"},
1846 {"Oriya", "ori", "or"},
1847 {"Oromo", "orm", "om"},
1848 {"Osage", "osa", ""},
1849 {"Ossetian; Ossetic", "oss", "os"},
1850 {"Ossetic; Ossetian", "oss", "os"},
1851 {"Otomian languages", "oto", ""},
1852 {"Pahlavi", "pal", ""},
1853 {"Palauan", "pau", ""},
1854 {"Pali", "pli", "pi"},
1855 {"Pampanga", "pam", ""},
1856 {"Pangasinan", "pag", ""},
1857 {"Panjabi", "pan", "pa"},
1858 {"Papiamento", "pap", ""},
1859 {"Papuan (Other)", "paa", ""},
1860 {"Persian", "per", "fa", MAKELCID( MAKELANGID(LANG_PERSIAN, SUBLANG_DEFAULT), SORT_DEFAULT)},
1861 {"Persian", "fas", "fa", MAKELCID( MAKELANGID(LANG_PERSIAN, SUBLANG_DEFAULT), SORT_DEFAULT)},
1862 {"Persian, Old (ca.600-400 B.C.)", "peo", ""},
1863 {"Philippine (Other)", "phi", ""},
1864 {"Phoenician", "phn", ""},
1865 {"Pohnpeian", "pon", ""},
1866 {"Polish", "pol", "pl", MAKELCID( MAKELANGID(LANG_POLISH, SUBLANG_DEFAULT), SORT_DEFAULT)},
1867 {"Portuguese", "por", "pt", MAKELCID( MAKELANGID(LANG_PORTUGUESE, SUBLANG_DEFAULT), SORT_DEFAULT)},
1868 {"Prakrit languages", "pra", ""},
1869 {"Provençal; Occitan (post 1500)", "oci", "oc"},
1870 {"Provençal, Old (to 1500)", "pro", ""},
1871 {"Pushto", "pus", "ps"},
1872 {"Quechua", "que", "qu", MAKELCID( MAKELANGID(LANG_QUECHUA, SUBLANG_DEFAULT), SORT_DEFAULT)},
1873 {"Raeto-Romance", "roh", "rm"},
1874 {"Rajasthani", "raj", ""},
1875 {"Rapanui", "rap", ""},
1876 {"Rarotongan", "rar", ""},
1877 {"Reserved for local use", "qaa-qtz", ""},
1878 {"Romance (Other)", "roa", ""},
1879 {"Romanian", "rum", "ro", MAKELCID( MAKELANGID(LANG_ROMANIAN, SUBLANG_DEFAULT), SORT_DEFAULT)},
1880 {"Romanian", "ron", "ro", MAKELCID( MAKELANGID(LANG_ROMANIAN, SUBLANG_DEFAULT), SORT_DEFAULT)},
1881 {"Romany", "rom", ""},
1882 {"Rundi", "run", "rn"},
1883 {"Russian", "rus", "ru", MAKELCID( MAKELANGID(LANG_RUSSIAN, SUBLANG_DEFAULT), SORT_DEFAULT)},
1884 {"Salishan languages", "sal", ""},
1885 {"Samaritan Aramaic", "sam", ""},
1886 {"Sami languages (Other)", "smi", ""},
1887 {"Samoan", "smo", "sm"},
1888 {"Sandawe", "sad", ""},
1889 {"Sango", "sag", "sg"},
1890 {"Sanskrit", "san", "sa", MAKELCID( MAKELANGID(LANG_SANSKRIT, SUBLANG_DEFAULT), SORT_DEFAULT)},
1891 {"Santali", "sat", ""},
1892 {"Sardinian", "srd", "sc"},
1893 {"Sasak", "sas", ""},
1894 {"Saxon, Low; German, Low; Low Saxon; Low German", "nds", ""},
1895 {"Scots", "sco", ""},
1896 {"Scottish Gaelic; Gaelic", "gla", "gd"},
1897 {"Selkup", "sel", ""},
1898 {"Semitic (Other)", "sem", ""},
1899 {"Serbian", "scc", "sr", MAKELCID( MAKELANGID(LANG_SERBIAN, SUBLANG_DEFAULT), SORT_DEFAULT)},
1900 {"Serbian", "srp", "sr", MAKELCID( MAKELANGID(LANG_SERBIAN, SUBLANG_DEFAULT), SORT_DEFAULT)},
1901 {"Serer", "srr", ""},
1902 {"Shan", "shn", ""},
1903 {"Shona", "sna", "sn"},
1904 {"Sichuan Yi", "iii", "ii"},
1905 {"Sidamo", "sid", ""},
1906 {"Sign languages", "sgn", ""},
1907 {"Siksika", "bla", ""},
1908 {"Sindhi", "snd", "sd", MAKELCID( MAKELANGID(LANG_SINDHI, SUBLANG_DEFAULT), SORT_DEFAULT)},
1909 {"Sinhalese", "sin", "si", MAKELCID( MAKELANGID(LANG_SINHALESE, SUBLANG_DEFAULT), SORT_DEFAULT)},
1910 {"Sino-Tibetan (Other)", "sit", ""},
1911 {"Siouan languages", "sio", ""},
1912 {"Skolt Sami", "sms", ""},
1913 {"Slave (Athapascan)", "den", ""},
1914 {"Slavic (Other)", "sla", ""},
1915 {"Slovak", "slo", "sk", MAKELCID( MAKELANGID(LANG_SLOVAK, SUBLANG_DEFAULT), SORT_DEFAULT)},
1916 {"Slovak", "slk", "sk", MAKELCID( MAKELANGID(LANG_SLOVAK, SUBLANG_DEFAULT), SORT_DEFAULT)},
1917 {"Slovenian", "slv", "sl", MAKELCID( MAKELANGID(LANG_SLOVENIAN, SUBLANG_DEFAULT), SORT_DEFAULT)},
1918 {"Sogdian", "sog", ""},
1919 {"Somali", "som", "so"},
1920 {"Songhai", "son", ""},
1921 {"Soninke", "snk", ""},
1922 {"Sorbian languages", "wen", ""},
1923 {"Sotho, Northern", "nso", "", MAKELCID( MAKELANGID(LANG_SOTHO, SUBLANG_DEFAULT), SORT_DEFAULT)},
1924 {"Sotho, Southern", "sot", "st", MAKELCID( MAKELANGID(LANG_SOTHO, SUBLANG_DEFAULT), SORT_DEFAULT)},
1925 {"South American Indian (Other)", "sai", ""},
1926 {"Southern Sami", "sma", ""},
1927 {"South Ndebele", "nbl", "nr"},
1928 {"Spanish; Castilian", "spa", "es", MAKELCID( MAKELANGID(LANG_SPANISH, SUBLANG_DEFAULT), SORT_DEFAULT)},
1929 {"Sukuma", "suk", ""},
1930 {"Sumerian", "sux", ""},
1931 {"Sundanese", "sun", "su"},
1932 {"Susu", "sus", ""},
1933 {"Swahili", "swa", "sw", MAKELCID( MAKELANGID(LANG_SWAHILI, SUBLANG_DEFAULT), SORT_DEFAULT)},
1934 {"Swati", "ssw", "ss"},
1935 {"Swedish", "swe", "sv", MAKELCID( MAKELANGID(LANG_SWEDISH, SUBLANG_DEFAULT), SORT_DEFAULT)},
1936 {"Syriac", "syr", "", MAKELCID( MAKELANGID(LANG_SYRIAC, SUBLANG_DEFAULT), SORT_DEFAULT)},
1937 {"Tagalog", "tgl", "tl"},
1938 {"Tahitian", "tah", "ty"},
1939 {"Tai (Other)", "tai", ""},
1940 {"Tajik", "tgk", "tg", MAKELCID( MAKELANGID(LANG_TAJIK, SUBLANG_DEFAULT), SORT_DEFAULT)},
1941 {"Tamashek", "tmh", ""},
1942 {"Tamil", "tam", "ta", MAKELCID( MAKELANGID(LANG_TAMIL, SUBLANG_DEFAULT), SORT_DEFAULT)},
1943 {"Tatar", "tat", "tt", MAKELCID( MAKELANGID(LANG_TATAR, SUBLANG_DEFAULT), SORT_DEFAULT)},
1944 {"Telugu", "tel", "te", MAKELCID( MAKELANGID(LANG_TELUGU, SUBLANG_DEFAULT), SORT_DEFAULT)},
1945 {"Tereno", "ter", ""},
1946 {"Tetum", "tet", ""},
1947 {"Thai", "tha", "th", MAKELCID( MAKELANGID(LANG_THAI, SUBLANG_DEFAULT), SORT_DEFAULT)},
1948 {"Tibetan", "tib", "bo", MAKELCID( MAKELANGID(LANG_TIBETAN, SUBLANG_DEFAULT), SORT_DEFAULT)},
1949 {"Tibetan", "bod", "bo", MAKELCID( MAKELANGID(LANG_TIBETAN, SUBLANG_DEFAULT), SORT_DEFAULT)},
1950 {"Tigre", "tig", ""},
1951 {"Tigrinya", "tir", "ti", MAKELCID( MAKELANGID(LANG_TIGRIGNA, SUBLANG_DEFAULT), SORT_DEFAULT)},
1952 {"Timne", "tem", ""},
1953 {"Tiv", "tiv", ""},
1954 {"Tlingit", "tli", ""},
1955 {"Tok Pisin", "tpi", ""},
1956 {"Tokelau", "tkl", ""},
1957 {"Tonga (Nyasa)", "tog", ""},
1958 {"Tonga (Tonga Islands)", "ton", "to"},
1959 {"Tsimshian", "tsi", ""},
1960 {"Tsonga", "tso", "ts"},
1961 {"Tswana", "tsn", "tn", MAKELCID( MAKELANGID(LANG_TSWANA, SUBLANG_DEFAULT), SORT_DEFAULT)},
1962 {"Tumbuka", "tum", ""},
1963 {"Tupi languages", "tup", ""},
1964 {"Turkish", "tur", "tr", MAKELCID( MAKELANGID(LANG_TURKISH, SUBLANG_DEFAULT), SORT_DEFAULT)},
1965 {"Turkish, Ottoman (1500-1928)", "ota", "", MAKELCID( MAKELANGID(LANG_TURKISH, SUBLANG_DEFAULT), SORT_DEFAULT)},
1966 {"Turkmen", "tuk", "tk", MAKELCID( MAKELANGID(LANG_TURKMEN, SUBLANG_DEFAULT), SORT_DEFAULT)},
1967 {"Tuvalu", "tvl", ""},
1968 {"Tuvinian", "tyv", ""},
1969 {"Twi", "twi", "tw"},
1970 {"Ugaritic", "uga", ""},
1971 {"Uighur", "uig", "ug", MAKELCID( MAKELANGID(LANG_UIGHUR, SUBLANG_DEFAULT), SORT_DEFAULT)},
1972 {"Ukrainian", "ukr", "uk", MAKELCID( MAKELANGID(LANG_UKRAINIAN, SUBLANG_DEFAULT), SORT_DEFAULT)},
1973 {"Umbundu", "umb", ""},
1974 {"Undetermined", "und", ""},
1975 {"Urdu", "urd", "ur", MAKELCID( MAKELANGID(LANG_URDU, SUBLANG_DEFAULT), SORT_DEFAULT)},
1976 {"Uzbek", "uzb", "uz", MAKELCID( MAKELANGID(LANG_UZBEK, SUBLANG_DEFAULT), SORT_DEFAULT)},
1977 {"Vai", "vai", ""},
1978 {"Venda", "ven", "ve"},
1979 {"Vietnamese", "vie", "vi", MAKELCID( MAKELANGID(LANG_VIETNAMESE, SUBLANG_DEFAULT), SORT_DEFAULT)},
1980 {"Volapuk", "vol", "vo"},
1981 {"Votic", "vot", ""},
1982 {"Wakashan languages", "wak", ""},
1983 {"Walamo", "wal", ""},
1984 {"Walloon", "wln", "wa"},
1985 {"Waray", "war", ""},
1986 {"Washo", "was", ""},
1987 {"Welsh", "wel", "cy", MAKELCID( MAKELANGID(LANG_WELSH, SUBLANG_DEFAULT), SORT_DEFAULT)},
1988 {"Welsh", "cym", "cy", MAKELCID( MAKELANGID(LANG_WELSH, SUBLANG_DEFAULT), SORT_DEFAULT)},
1989 {"Wolof", "wol", "wo", MAKELCID( MAKELANGID(LANG_WOLOF, SUBLANG_DEFAULT), SORT_DEFAULT)},
1990 {"Xhosa", "xho", "xh", MAKELCID( MAKELANGID(LANG_XHOSA, SUBLANG_DEFAULT), SORT_DEFAULT)},
1991 {"Yakut", "sah", "", MAKELCID( MAKELANGID(LANG_YAKUT, SUBLANG_DEFAULT), SORT_DEFAULT)},
1992 {"Yao", "yao", ""},
1993 {"Yapese", "yap", ""},
1994 {"Yiddish", "yid", "yi"},
1995 {"Yoruba", "yor", "yo", MAKELCID( MAKELANGID(LANG_YORUBA, SUBLANG_DEFAULT), SORT_DEFAULT)},
1996 {"Yupik languages", "ypk", ""},
1997 {"Zande", "znd", ""},
1998 {"Zapotec", "zap", ""},
1999 {"Zenaga", "zen", ""},
2000 {"Zhuang; Chuang", "zha", "za"},
2001 {"Zulu", "zul", "zu", MAKELCID( MAKELANGID(LANG_ZULU, SUBLANG_DEFAULT), SORT_DEFAULT)},
2002 {"Zuni", "zun", ""},
2003 {"Classical Newari", "nwc", ""},
2004 {"Klingon", "tlh", ""},
2005 {"Blin", "byn", ""},
2006 {"Lojban", "jbo", ""},
2007 {"Lower Sorbian", "dsb", ""},
2008 {"Upper Sorbian", "hsb", ""},
2009 {"Kashubian", "csb", ""},
2010 {"Crimean Turkish", "crh", ""},
2011 {"Erzya", "myv", ""},
2012 {"Moksha", "mdf", ""},
2013 {"Karachay-Balkar", "krc", ""},
2014 {"Adyghe", "ady", ""},
2015 {"Udmurt", "udm", ""},
2016 {"Dargwa", "dar", ""},
2017 {"Ingush", "inh", ""},
2018 {"Nogai", "nog", ""},
2019 {"Haitian", "hat", "ht"},
2020 {"Kalmyk", "xal", ""},
2021 {"", "", ""},
2022 {"No subtitles", "---", "", (LCID)LCID_NOSUBTITLES},
2025 CString ISO6391ToLanguage(LPCSTR code)
2027 CHAR tmp[2+1];
2028 strncpy(tmp, code, 2);
2029 tmp[2] = 0;
2030 _strlwr(tmp);
2031 for(int i = 0, j = countof(s_isolangs); i < j; i++)
2032 if(!strcmp(s_isolangs[i].iso6391, tmp))
2034 CString ret = CString(CStringA(s_isolangs[i].name));
2035 int i = ret.Find(';');
2036 if(i > 0) ret = ret.Left(i);
2037 return ret;
2039 return(_T(""));
2042 CString ISO6392ToLanguage(LPCSTR code)
2044 CHAR tmp[3+1];
2045 strncpy(tmp, code, 3);
2046 tmp[3] = 0;
2047 _strlwr(tmp);
2048 for(int i = 0, j = countof(s_isolangs); i < j; i++)
2050 if(!strcmp(s_isolangs[i].iso6392, tmp))
2052 CString ret = CString(CStringA(s_isolangs[i].name));
2053 int i = ret.Find(';');
2054 if(i > 0) ret = ret.Left(i);
2055 return ret;
2058 return CString(code);
2061 LCID ISO6391ToLcid(LPCSTR code)
2063 CHAR tmp[3+1];
2064 strncpy_s(tmp, code, 3);
2065 tmp[3] = 0;
2066 _strlwr_s(tmp);
2067 for(ptrdiff_t i = 0, j = countof(s_isolangs); i < j; i++) {
2068 if(!strcmp(s_isolangs[i].iso6391, code)) {
2069 return s_isolangs[i].lcid;
2072 return 0;
2075 LCID ISO6392ToLcid(LPCSTR code)
2077 CHAR tmp[3+1];
2078 strncpy_s(tmp, code, 3);
2079 tmp[3] = 0;
2080 _strlwr_s(tmp);
2081 for(ptrdiff_t i = 0, j = countof(s_isolangs); i < j; i++) {
2082 if(!strcmp(s_isolangs[i].iso6392, tmp)) {
2083 return s_isolangs[i].lcid;
2086 return 0;
2089 CString ISO6391To6392(LPCSTR code)
2091 CHAR tmp[2+1];
2092 strncpy(tmp, code, 2);
2093 tmp[2] = 0;
2094 _strlwr(tmp);
2095 for(int i = 0, j = countof(s_isolangs); i < j; i++)
2096 if(!strcmp(s_isolangs[i].iso6391, tmp))
2097 return CString(CStringA(s_isolangs[i].iso6392));
2098 return _T("");
2101 CString ISO6392To6391(LPCSTR code)
2103 CHAR tmp[3+1];
2104 strncpy(tmp, code, 3);
2105 tmp[3] = 0;
2106 _strlwr(tmp);
2107 for(int i = 0, j = countof(s_isolangs); i < j; i++)
2108 if(!strcmp(s_isolangs[i].iso6392, tmp))
2109 return CString(CStringA(s_isolangs[i].iso6391));
2110 return _T("");
2113 CString LanguageToISO6392(LPCTSTR lang)
2115 CString str = lang;
2116 str.MakeLower();
2117 for(int i = 0, j = countof(s_isolangs); i < j; i++)
2119 CAtlList<CString> sl;
2120 Explode(CString(s_isolangs[i].name), sl, ';');
2121 POSITION pos = sl.GetHeadPosition();
2122 while(pos)
2124 if(!str.CompareNoCase(sl.GetNext(pos)))
2125 return CString(s_isolangs[i].iso6392);
2128 return _T("");
2131 int MakeAACInitData(BYTE* pData, int profile, int freq, int channels)
2133 int srate_idx;
2135 if(92017 <= freq) srate_idx = 0;
2136 else if(75132 <= freq) srate_idx = 1;
2137 else if(55426 <= freq) srate_idx = 2;
2138 else if(46009 <= freq) srate_idx = 3;
2139 else if(37566 <= freq) srate_idx = 4;
2140 else if(27713 <= freq) srate_idx = 5;
2141 else if(23004 <= freq) srate_idx = 6;
2142 else if(18783 <= freq) srate_idx = 7;
2143 else if(13856 <= freq) srate_idx = 8;
2144 else if(11502 <= freq) srate_idx = 9;
2145 else if(9391 <= freq) srate_idx = 10;
2146 else srate_idx = 11;
2148 pData[0] = ((abs(profile) + 1) << 3) | ((srate_idx & 0xe) >> 1);
2149 pData[1] = ((srate_idx & 0x1) << 7) | (channels << 3);
2151 int ret = 2;
2153 if(profile < 0)
2155 freq *= 2;
2157 if(92017 <= freq) srate_idx = 0;
2158 else if(75132 <= freq) srate_idx = 1;
2159 else if(55426 <= freq) srate_idx = 2;
2160 else if(46009 <= freq) srate_idx = 3;
2161 else if(37566 <= freq) srate_idx = 4;
2162 else if(27713 <= freq) srate_idx = 5;
2163 else if(23004 <= freq) srate_idx = 6;
2164 else if(18783 <= freq) srate_idx = 7;
2165 else if(13856 <= freq) srate_idx = 8;
2166 else if(11502 <= freq) srate_idx = 9;
2167 else if(9391 <= freq) srate_idx = 10;
2168 else srate_idx = 11;
2170 pData[2] = 0x2B7>>3;
2171 pData[3] = (BYTE)((0x2B7<<5) | 5);
2172 pData[4] = (1<<7) | (srate_idx<<3);
2174 ret = 5;
2177 return(ret);
2180 BOOL CFileGetStatus(LPCTSTR lpszFileName, CFileStatus& status)
2184 return CFile::GetStatus(lpszFileName, status);
2186 catch(CException* e)
2188 // MFCBUG: E_INVALIDARG / "Parameter is incorrect" is thrown for certain cds (vs2003)
2189 // 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
2190 TRACE(_T("CFile::GetStatus has thrown an exception\n"));
2191 e->Delete();
2192 return false;
2196 // filter registration helpers
2198 bool DeleteRegKey(LPCTSTR pszKey, LPCTSTR pszSubkey)
2200 bool bOK = false;
2202 HKEY hKey;
2203 LONG ec = ::RegOpenKeyEx(HKEY_CLASSES_ROOT, pszKey, 0, KEY_ALL_ACCESS, &hKey);
2204 if(ec == ERROR_SUCCESS)
2206 if(pszSubkey != 0)
2207 ec = ::RegDeleteKey(hKey, pszSubkey);
2209 bOK = (ec == ERROR_SUCCESS);
2211 ::RegCloseKey(hKey);
2214 return bOK;
2217 bool SetRegKeyValue(LPCTSTR pszKey, LPCTSTR pszSubkey, LPCTSTR pszValueName, LPCTSTR pszValue)
2219 bool bOK = false;
2221 CString szKey(pszKey);
2222 if(pszSubkey != 0)
2223 szKey += CString(_T("\\")) + pszSubkey;
2225 HKEY hKey;
2226 LONG ec = ::RegCreateKeyEx(HKEY_CLASSES_ROOT, szKey, 0, 0, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, 0, &hKey, 0);
2227 if(ec == ERROR_SUCCESS)
2229 if(pszValue != 0)
2231 ec = ::RegSetValueEx(hKey, pszValueName, 0, REG_SZ,
2232 reinterpret_cast<BYTE*>(const_cast<LPTSTR>(pszValue)),
2233 (_tcslen(pszValue) + 1) * sizeof(TCHAR));
2236 bOK = (ec == ERROR_SUCCESS);
2238 ::RegCloseKey(hKey);
2241 return bOK;
2244 bool SetRegKeyValue(LPCTSTR pszKey, LPCTSTR pszSubkey, LPCTSTR pszValue)
2246 return SetRegKeyValue(pszKey, pszSubkey, 0, pszValue);
2249 void RegisterSourceFilter(const CLSID& clsid, const GUID& subtype2, LPCTSTR chkbytes, LPCTSTR ext, ...)
2251 CString null = CStringFromGUID(GUID_NULL);
2252 CString majortype = CStringFromGUID(MEDIATYPE_Stream);
2253 CString subtype = CStringFromGUID(subtype2);
2255 SetRegKeyValue(_T("Media Type\\") + majortype, subtype, _T("0"), chkbytes);
2256 SetRegKeyValue(_T("Media Type\\") + majortype, subtype, _T("Source Filter"), CStringFromGUID(clsid));
2258 DeleteRegKey(_T("Media Type\\") + null, subtype);
2260 va_list marker;
2261 va_start(marker, ext);
2262 for(; ext; ext = va_arg(marker, LPCTSTR))
2263 DeleteRegKey(_T("Media Type\\Extensions"), ext);
2264 va_end(marker);
2267 void RegisterSourceFilter(const CLSID& clsid, const GUID& subtype2, const CAtlList<CString>& chkbytes, LPCTSTR ext, ...)
2269 CString null = CStringFromGUID(GUID_NULL);
2270 CString majortype = CStringFromGUID(MEDIATYPE_Stream);
2271 CString subtype = CStringFromGUID(subtype2);
2273 POSITION pos = chkbytes.GetHeadPosition();
2274 for(int i = 0; pos; i++)
2276 CString idx;
2277 idx.Format(_T("%d"), i);
2278 SetRegKeyValue(_T("Media Type\\") + majortype, subtype, idx, chkbytes.GetNext(pos));
2281 SetRegKeyValue(_T("Media Type\\") + majortype, subtype, _T("Source Filter"), CStringFromGUID(clsid));
2283 DeleteRegKey(_T("Media Type\\") + null, subtype);
2285 va_list marker;
2286 va_start(marker, ext);
2287 for(; ext; ext = va_arg(marker, LPCTSTR))
2288 DeleteRegKey(_T("Media Type\\Extensions"), ext);
2289 va_end(marker);
2292 void UnRegisterSourceFilter(const GUID& subtype)
2294 DeleteRegKey(_T("Media Type\\") + CStringFromGUID(MEDIATYPE_Stream), CStringFromGUID(subtype));
2297 // hour, minute, second, millisec
2298 CString ReftimeToString(const REFERENCE_TIME& rtVal)
2300 CString strTemp;
2301 LONGLONG llTotalMs = ConvertToMilliseconds (rtVal);
2302 int lHour = (int)(llTotalMs / (1000*60*60));
2303 int lMinute = (llTotalMs / (1000*60)) % 60;
2304 int lSecond = (llTotalMs / 1000) % 60;
2305 int lMillisec = llTotalMs % 1000;
2306 strTemp.Format (_T("%02d:%02d:%02d,%03d"), lHour, lMinute, lSecond, lMillisec);
2307 return strTemp;
2310 // hour, minute, second (round)
2311 CString ReftimeToString2(const REFERENCE_TIME& rtVal)
2313 CString strTemp;
2314 LONGLONG seconds = (rtVal + 5000000) / 10000000;
2315 int lHour = (int)(seconds / 3600);
2316 int lMinute = (int)(seconds / 60 % 60);
2317 int lSecond = (int)(seconds % 60);
2319 strTemp.Format (_T("%02d:%02d:%02d"), lHour, lMinute, lSecond);
2320 return strTemp;
2323 CString DVDtimeToString(const DVD_HMSF_TIMECODE& rtVal, bool bAlwaysShowHours)
2325 CString strTemp;
2326 if (rtVal.bHours > 0 || bAlwaysShowHours) {
2327 strTemp.Format(_T("%02d:%02d:%02d"), rtVal.bHours, rtVal.bMinutes, rtVal.bSeconds);
2328 } else {
2329 strTemp.Format(_T("%02d:%02d"), rtVal.bMinutes, rtVal.bSeconds);
2331 return strTemp;
2334 REFERENCE_TIME StringToReftime(LPCTSTR strVal)
2336 REFERENCE_TIME rt = 0;
2337 int lHour = 0;
2338 int lMinute = 0;
2339 int lSecond = 0;
2340 int lMillisec = 0;
2342 if (_stscanf_s (strVal, _T("%02d:%02d:%02d,%03d"), &lHour, &lMinute, &lSecond, &lMillisec) == 4) {
2343 rt = ( (((lHour*24)+lMinute)*60 + lSecond) * MILLISECONDS + lMillisec ) * (UNITS/MILLISECONDS);
2346 return rt;
2349 const double Rec601_Kr = 0.299;
2350 const double Rec601_Kb = 0.114;
2351 const double Rec601_Kg = 0.587;
2352 COLORREF YCrCbToRGB_Rec601(BYTE Y, BYTE Cr, BYTE Cb)
2355 double rp = Y + 2*(Cr-128)*(1.0-Rec601_Kr);
2356 double gp = Y - 2*(Cb-128)*(1.0-Rec601_Kb)*Rec601_Kb/Rec601_Kg - 2*(Cr-128)*(1.0-Rec601_Kr)*Rec601_Kr/Rec601_Kg;
2357 double bp = Y + 2*(Cb-128)*(1.0-Rec601_Kb);
2359 return RGB (fabs(rp), fabs(gp), fabs(bp));
2362 DWORD YCrCbToRGB_Rec601(BYTE A, BYTE Y, BYTE Cr, BYTE Cb)
2365 double rp = Y + 2*(Cr-128)*(1.0-Rec601_Kr);
2366 double gp = Y - 2*(Cb-128)*(1.0-Rec601_Kb)*Rec601_Kb/Rec601_Kg - 2*(Cr-128)*(1.0-Rec601_Kr)*Rec601_Kr/Rec601_Kg;
2367 double bp = Y + 2*(Cb-128)*(1.0-Rec601_Kb);
2369 return D3DCOLOR_ARGB(A, (BYTE)fabs(rp), (BYTE)fabs(gp), (BYTE)fabs(bp));
2373 const double Rec709_Kr = 0.2125;
2374 const double Rec709_Kb = 0.0721;
2375 const double Rec709_Kg = 0.7154;
2377 COLORREF YCrCbToRGB_Rec709(BYTE Y, BYTE Cr, BYTE Cb)
2380 double rp = Y + 2*(Cr-128)*(1.0-Rec709_Kr);
2381 double gp = Y - 2*(Cb-128)*(1.0-Rec709_Kb)*Rec709_Kb/Rec709_Kg - 2*(Cr-128)*(1.0-Rec709_Kr)*Rec709_Kr/Rec709_Kg;
2382 double bp = Y + 2*(Cb-128)*(1.0-Rec709_Kb);
2384 return RGB (fabs(rp), fabs(gp), fabs(bp));
2387 DWORD YCrCbToRGB_Rec709(BYTE A, BYTE Y, BYTE Cr, BYTE Cb)
2390 double rp = Y + 2*(Cr-128)*(1.0-Rec709_Kr);
2391 double gp = Y - 2*(Cb-128)*(1.0-Rec709_Kb)*Rec709_Kb/Rec709_Kg - 2*(Cr-128)*(1.0-Rec709_Kr)*Rec709_Kr/Rec709_Kg;
2392 double bp = Y + 2*(Cb-128)*(1.0-Rec709_Kb);
2394 return D3DCOLOR_ARGB (A, (BYTE)fabs(rp), (BYTE)fabs(gp), (BYTE)fabs(bp));