/* * Copyright (C) 2003-2006 Gabest * http://www.gabest.org * * This Program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This Program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Make; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * http://www.gnu.org/copyleft/gpl.html * */ #include "stdafx.h" #include #include "../include/winddk/devioctl.h" #include "../include/winddk/ntddcdrm.h" #include "DSUtil.h" #include "../include/moreuuids.h" void DumpStreamConfig(TCHAR* fn, IAMStreamConfig* pAMVSCCap) { CString s, ss; CStdioFile f; if(!f.Open(fn, CFile::modeCreate|CFile::modeWrite|CFile::typeText)) return; int cnt = 0, size = 0; if(FAILED(pAMVSCCap->GetNumberOfCapabilities(&cnt, &size))) return; s.Empty(); s.Format(_T("cnt %d, size %d\n"), cnt, size); f.WriteString(s); if(size == sizeof(VIDEO_STREAM_CONFIG_CAPS)) { for(int i = 0; i < cnt; i++) { AM_MEDIA_TYPE* pmt = NULL; VIDEO_STREAM_CONFIG_CAPS caps; memset(&caps, 0, sizeof(caps)); s.Empty(); ss.Format(_T("%d\n"), i); s += ss; f.WriteString(s); if(FAILED(pAMVSCCap->GetStreamCaps(i, &pmt, (BYTE*)&caps))) continue; { s.Empty(); ss.Format(_T("VIDEO_STREAM_CONFIG_CAPS\n")); s += ss; ss.Format(_T("\tVideoStandard 0x%08x\n"), caps.VideoStandard); s += ss; ss.Format(_T("\tInputSize %dx%d\n"), caps.InputSize); s += ss; ss.Format(_T("\tCroppingSize %dx%d - %dx%d\n"), caps.MinCroppingSize, caps.MaxCroppingSize); s += ss; ss.Format(_T("\tCropGranularity %d, %d\n"), caps.CropGranularityX, caps.CropGranularityY); s += ss; ss.Format(_T("\tCropAlign %d, %d\n"), caps.CropAlignX, caps.CropAlignY); s += ss; ss.Format(_T("\tOutputSize %dx%d - %dx%d\n"), caps.MinOutputSize, caps.MaxOutputSize); s += ss; ss.Format(_T("\tOutputGranularity %d, %d\n"), caps.OutputGranularityX, caps.OutputGranularityY); s += ss; ss.Format(_T("\tStretchTaps %d, %d\n"), caps.StretchTapsX, caps.StretchTapsY); s += ss; ss.Format(_T("\tShrinkTaps %d, %d\n"), caps.ShrinkTapsX, caps.ShrinkTapsY); s += ss; ss.Format(_T("\tFrameInterval %I64d, %I64d (%.4f, %.4f)\n"), caps.MinFrameInterval, caps.MaxFrameInterval, (float)10000000/caps.MinFrameInterval, (float)10000000/caps.MaxFrameInterval); s += ss; ss.Format(_T("\tBitsPerSecond %d - %d\n"), caps.MinBitsPerSecond, caps.MaxBitsPerSecond); s += ss; f.WriteString(s); } BITMAPINFOHEADER* pbh; if(pmt->formattype == FORMAT_VideoInfo) { VIDEOINFOHEADER* vih = (VIDEOINFOHEADER*)pmt->pbFormat; pbh = &vih->bmiHeader; s.Empty(); ss.Format(_T("FORMAT_VideoInfo\n")); s += ss; ss.Format(_T("\tAvgTimePerFrame %I64d, %.4f\n"), vih->AvgTimePerFrame, (float)10000000/vih->AvgTimePerFrame); s += ss; ss.Format(_T("\trcSource %d,%d,%d,%d\n"), vih->rcSource); s += ss; ss.Format(_T("\trcTarget %d,%d,%d,%d\n"), vih->rcTarget); s += ss; f.WriteString(s); } else if(pmt->formattype == FORMAT_VideoInfo2) { VIDEOINFOHEADER2* vih = (VIDEOINFOHEADER2*)pmt->pbFormat; pbh = &vih->bmiHeader; s.Empty(); ss.Format(_T("FORMAT_VideoInfo2\n")); s += ss; ss.Format(_T("\tAvgTimePerFrame %I64d, %.4f\n"), vih->AvgTimePerFrame, (float)10000000/vih->AvgTimePerFrame); s += ss; ss.Format(_T("\trcSource %d,%d,%d,%d\n"), vih->rcSource); s += ss; ss.Format(_T("\trcTarget %d,%d,%d,%d\n"), vih->rcTarget); s += ss; ss.Format(_T("\tdwInterlaceFlags 0x%x\n"), vih->dwInterlaceFlags); s += ss; ss.Format(_T("\tdwPictAspectRatio %d:%d\n"), vih->dwPictAspectRatioX, vih->dwPictAspectRatioY); s += ss; f.WriteString(s); } else { DeleteMediaType(pmt); continue; } s.Empty(); ss.Format(_T("BITMAPINFOHEADER\n")); s += ss; ss.Format(_T("\tbiCompression %x\n"), pbh->biCompression); s += ss; ss.Format(_T("\tbiWidth %d\n"), pbh->biWidth); s += ss; ss.Format(_T("\tbiHeight %d\n"), pbh->biHeight); s += ss; ss.Format(_T("\tbiBitCount %d\n"), pbh->biBitCount); s += ss; ss.Format(_T("\tbiPlanes %d\n"), pbh->biPlanes); s += ss; ss.Format(_T("\tbiSizeImage %d\n"), pbh->biSizeImage); s += ss; f.WriteString(s); DeleteMediaType(pmt); } } else if(size == sizeof(AUDIO_STREAM_CONFIG_CAPS)) { // TODO } } int CountPins(IBaseFilter* pBF, int& nIn, int& nOut, int& nInC, int& nOutC) { nIn = nOut = 0; nInC = nOutC = 0; BeginEnumPins(pBF, pEP, pPin) { PIN_DIRECTION dir; if(SUCCEEDED(pPin->QueryDirection(&dir))) { CComPtr pPinConnectedTo; pPin->ConnectedTo(&pPinConnectedTo); if(dir == PINDIR_INPUT) {nIn++; if(pPinConnectedTo) nInC++;} else if(dir == PINDIR_OUTPUT) {nOut++; if(pPinConnectedTo) nOutC++;} } } EndEnumPins return(nIn+nOut); } bool IsSplitter(IBaseFilter* pBF, bool fCountConnectedOnly) { int nIn, nOut, nInC, nOutC; CountPins(pBF, nIn, nOut, nInC, nOutC); return(fCountConnectedOnly ? nOutC > 1 : nOut > 1); } bool IsMultiplexer(IBaseFilter* pBF, bool fCountConnectedOnly) { int nIn, nOut, nInC, nOutC; CountPins(pBF, nIn, nOut, nInC, nOutC); return(fCountConnectedOnly ? nInC > 1 : nIn > 1); } bool IsStreamStart(IBaseFilter* pBF) { CComQIPtr pAMMF(pBF); if(pAMMF && pAMMF->GetMiscFlags()&AM_FILTER_MISC_FLAGS_IS_SOURCE) return(true); int nIn, nOut, nInC, nOutC; CountPins(pBF, nIn, nOut, nInC, nOutC); AM_MEDIA_TYPE mt; CComPtr pIn = GetFirstPin(pBF); return((nOut > 1) || (nOut > 0 && nIn == 1 && pIn && SUCCEEDED(pIn->ConnectionMediaType(&mt)) && mt.majortype == MEDIATYPE_Stream)); } bool IsStreamEnd(IBaseFilter* pBF) { int nIn, nOut, nInC, nOutC; CountPins(pBF, nIn, nOut, nInC, nOutC); return(nOut == 0); } bool IsVideoRenderer(IBaseFilter* pBF) { int nIn, nOut, nInC, nOutC; CountPins(pBF, nIn, nOut, nInC, nOutC); if(nInC > 0 && nOut == 0) { BeginEnumPins(pBF, pEP, pPin) { AM_MEDIA_TYPE mt; if(S_OK != pPin->ConnectionMediaType(&mt)) continue; FreeMediaType(mt); return(!!(mt.majortype == MEDIATYPE_Video)); /*&& (mt.formattype == FORMAT_VideoInfo || mt.formattype == FORMAT_VideoInfo2));*/ } EndEnumPins } CLSID clsid; memcpy(&clsid, &GUID_NULL, sizeof(clsid)); pBF->GetClassID(&clsid); return(clsid == CLSID_VideoRenderer || clsid == CLSID_VideoRendererDefault); } #include DEFINE_GUID(CLSID_ReClock, 0x9dc15360, 0x914c, 0x46b8, 0xb9, 0xdf, 0xbf, 0xe6, 0x7f, 0xd3, 0x6c, 0x6a); bool IsAudioWaveRenderer(IBaseFilter* pBF) { int nIn, nOut, nInC, nOutC; CountPins(pBF, nIn, nOut, nInC, nOutC); if(nInC > 0 && nOut == 0 && CComQIPtr(pBF)) { BeginEnumPins(pBF, pEP, pPin) { AM_MEDIA_TYPE mt; if(S_OK != pPin->ConnectionMediaType(&mt)) continue; FreeMediaType(mt); return(!!(mt.majortype == MEDIATYPE_Audio) /*&& mt.formattype == FORMAT_WaveFormatEx*/); } EndEnumPins } CLSID clsid; memcpy(&clsid, &GUID_NULL, sizeof(clsid)); pBF->GetClassID(&clsid); return(clsid == CLSID_DSoundRender || clsid == CLSID_AudioRender || clsid == CLSID_ReClock || clsid == __uuidof(CNullAudioRenderer) || clsid == __uuidof(CNullUAudioRenderer)); } IBaseFilter* GetUpStreamFilter(IBaseFilter* pBF, IPin* pInputPin) { return GetFilterFromPin(GetUpStreamPin(pBF, pInputPin)); } IPin* GetUpStreamPin(IBaseFilter* pBF, IPin* pInputPin) { BeginEnumPins(pBF, pEP, pPin) { if(pInputPin && pInputPin != pPin) continue; PIN_DIRECTION dir; CComPtr pPinConnectedTo; if(SUCCEEDED(pPin->QueryDirection(&dir)) && dir == PINDIR_INPUT && SUCCEEDED(pPin->ConnectedTo(&pPinConnectedTo))) { IPin* pRet = pPinConnectedTo.Detach(); pRet->Release(); return(pRet); } } EndEnumPins return(NULL); } IPin* GetFirstPin(IBaseFilter* pBF, PIN_DIRECTION dir) { if(!pBF) return(NULL); BeginEnumPins(pBF, pEP, pPin) { PIN_DIRECTION dir2; pPin->QueryDirection(&dir2); if(dir == dir2) { IPin* pRet = pPin.Detach(); pRet->Release(); return(pRet); } } EndEnumPins return(NULL); } IPin* GetFirstDisconnectedPin(IBaseFilter* pBF, PIN_DIRECTION dir) { if(!pBF) return(NULL); BeginEnumPins(pBF, pEP, pPin) { PIN_DIRECTION dir2; pPin->QueryDirection(&dir2); CComPtr pPinTo; if(dir == dir2 && (S_OK != pPin->ConnectedTo(&pPinTo))) { IPin* pRet = pPin.Detach(); pRet->Release(); return(pRet); } } EndEnumPins return(NULL); } IBaseFilter* FindFilter(LPCWSTR clsid, IFilterGraph* pFG) { CLSID clsid2; CLSIDFromString(CComBSTR(clsid), &clsid2); return(FindFilter(clsid2, pFG)); } IBaseFilter* FindFilter(const CLSID& clsid, IFilterGraph* pFG) { BeginEnumFilters(pFG, pEF, pBF) { CLSID clsid2; if(SUCCEEDED(pBF->GetClassID(&clsid2)) && clsid == clsid2) return(pBF); } EndEnumFilters return NULL; } CStringW GetFilterName(IBaseFilter* pBF) { CStringW name; CFilterInfo fi; if(pBF && SUCCEEDED(pBF->QueryFilterInfo(&fi))) name = fi.achName; return(name); } CStringW GetPinName(IPin* pPin) { CStringW name; CPinInfo pi; if(pPin && SUCCEEDED(pPin->QueryPinInfo(&pi))) name = pi.achName; return(name); } IFilterGraph* GetGraphFromFilter(IBaseFilter* pBF) { if(!pBF) return NULL; IFilterGraph* pGraph = NULL; CFilterInfo fi; if(pBF && SUCCEEDED(pBF->QueryFilterInfo(&fi))) pGraph = fi.pGraph; return(pGraph); } IBaseFilter* GetFilterFromPin(IPin* pPin) { if(!pPin) return NULL; IBaseFilter* pBF = NULL; CPinInfo pi; if(pPin && SUCCEEDED(pPin->QueryPinInfo(&pi))) pBF = pi.pFilter; return(pBF); } IPin* AppendFilter(IPin* pPin, CString DisplayName, IGraphBuilder* pGB) { IPin* pRet = pPin; CInterfaceList pFilters; do { if(!pPin || DisplayName.IsEmpty() || !pGB) break; CComPtr pPinTo; PIN_DIRECTION dir; if(FAILED(pPin->QueryDirection(&dir)) || dir != PINDIR_OUTPUT || SUCCEEDED(pPin->ConnectedTo(&pPinTo))) break; CComPtr pBindCtx; CreateBindCtx(0, &pBindCtx); CComPtr pMoniker; ULONG chEaten; if(S_OK != MkParseDisplayName(pBindCtx, CComBSTR(DisplayName), &chEaten, &pMoniker)) break; CComPtr pBF; if(FAILED(pMoniker->BindToObject(pBindCtx, 0, IID_IBaseFilter, (void**)&pBF)) || !pBF) break; CComPtr pPB; if(FAILED(pMoniker->BindToStorage(pBindCtx, 0, IID_IPropertyBag, (void**)&pPB))) break; CComVariant var; if(FAILED(pPB->Read(CComBSTR(_T("FriendlyName")), &var, NULL))) break; pFilters.AddTail(pBF); BeginEnumFilters(pGB, pEnum, pBF2) pFilters.AddTail(pBF2); EndEnumFilters if(FAILED(pGB->AddFilter(pBF, CStringW(var.bstrVal)))) break; BeginEnumFilters(pGB, pEnum, pBF2) if(!pFilters.Find(pBF2) && SUCCEEDED(pGB->RemoveFilter(pBF2))) pEnum->Reset(); EndEnumFilters pPinTo = GetFirstPin(pBF, PINDIR_INPUT); if(!pPinTo) { pGB->RemoveFilter(pBF); break; } HRESULT hr; if(FAILED(hr = pGB->ConnectDirect(pPin, pPinTo, NULL))) { hr = pGB->Connect(pPin, pPinTo); pGB->RemoveFilter(pBF); break; } BeginEnumFilters(pGB, pEnum, pBF2) if(!pFilters.Find(pBF2) && SUCCEEDED(pGB->RemoveFilter(pBF2))) pEnum->Reset(); EndEnumFilters pRet = GetFirstPin(pBF, PINDIR_OUTPUT); if(!pRet) { pRet = pPin; pGB->RemoveFilter(pBF); break; } } while(false); return(pRet); } IPin* InsertFilter(IPin* pPin, CString DisplayName, IGraphBuilder* pGB) { do { if(!pPin || DisplayName.IsEmpty() || !pGB) break; PIN_DIRECTION dir; if(FAILED(pPin->QueryDirection(&dir))) break; CComPtr pFrom, pTo; if(dir == PINDIR_INPUT) { pPin->ConnectedTo(&pFrom); pTo = pPin; } else if(dir == PINDIR_OUTPUT) { pFrom = pPin; pPin->ConnectedTo(&pTo); } if(!pFrom || !pTo) break; CComPtr pBindCtx; CreateBindCtx(0, &pBindCtx); CComPtr pMoniker; ULONG chEaten; if(S_OK != MkParseDisplayName(pBindCtx, CComBSTR(DisplayName), &chEaten, &pMoniker)) break; CComPtr pBF; if(FAILED(pMoniker->BindToObject(pBindCtx, 0, IID_IBaseFilter, (void**)&pBF)) || !pBF) break; CComPtr pPB; if(FAILED(pMoniker->BindToStorage(pBindCtx, 0, IID_IPropertyBag, (void**)&pPB))) break; CComVariant var; if(FAILED(pPB->Read(CComBSTR(_T("FriendlyName")), &var, NULL))) break; if(FAILED(pGB->AddFilter(pBF, CStringW(var.bstrVal)))) break; CComPtr pFromTo = GetFirstPin(pBF, PINDIR_INPUT); if(!pFromTo) { pGB->RemoveFilter(pBF); break; } if(FAILED(pGB->Disconnect(pFrom)) || FAILED(pGB->Disconnect(pTo))) { pGB->RemoveFilter(pBF); pGB->ConnectDirect(pFrom, pTo, NULL); break; } HRESULT hr; if(FAILED(hr = pGB->ConnectDirect(pFrom, pFromTo, NULL))) { pGB->RemoveFilter(pBF); pGB->ConnectDirect(pFrom, pTo, NULL); break; } CComPtr pToFrom = GetFirstPin(pBF, PINDIR_OUTPUT); if(!pToFrom) { pGB->RemoveFilter(pBF); pGB->ConnectDirect(pFrom, pTo, NULL); break; } if(FAILED(pGB->ConnectDirect(pToFrom, pTo, NULL))) { pGB->RemoveFilter(pBF); pGB->ConnectDirect(pFrom, pTo, NULL); break; } pPin = pToFrom; } while(false); return(pPin); } void ExtractMediaTypes(IPin* pPin, CAtlArray& types) { types.RemoveAll(); BeginEnumMediaTypes(pPin, pEM, pmt) { bool fFound = false; for(int i = 0; !fFound && i < types.GetCount(); i += 2) { if(types[i] == pmt->majortype && types[i+1] == pmt->subtype) fFound = true; } if(!fFound) { types.Add(pmt->majortype); types.Add(pmt->subtype); } } EndEnumMediaTypes(pmt) } void ExtractMediaTypes(IPin* pPin, CAtlList& mts) { mts.RemoveAll(); BeginEnumMediaTypes(pPin, pEM, pmt) { bool fFound = false; POSITION pos = mts.GetHeadPosition(); while(!fFound && pos) { CMediaType& mt = mts.GetNext(pos); if(mt.majortype == pmt->majortype && mt.subtype == pmt->subtype) fFound = true; } if(!fFound) { mts.AddTail(CMediaType(*pmt)); } } EndEnumMediaTypes(pmt) } int Eval_Exception(int n_except) { if(n_except == STATUS_ACCESS_VIOLATION) { AfxMessageBox(_T("The property page of this filter has just caused a\nmemory access violation. The application will gently die now :)")); } return EXCEPTION_CONTINUE_SEARCH; } 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) { __try { OleCreatePropertyFrame(hwndOwner, x, y, lpszCaption, cObjects, lplpUnk, cPages, lpPageClsID, lcid, dwReserved, lpvReserved); } __except(Eval_Exception(GetExceptionCode())) { // No code; this block never executed. } } void ShowPPage(CString DisplayName, HWND hParentWnd) { CComPtr pBindCtx; CreateBindCtx(0, &pBindCtx); CComPtr pMoniker; ULONG chEaten; if(S_OK != MkParseDisplayName(pBindCtx, CStringW(DisplayName), &chEaten, &pMoniker)) return; CComPtr pBF; if(FAILED(pMoniker->BindToObject(pBindCtx, 0, IID_IBaseFilter, (void**)&pBF)) || !pBF) return; ShowPPage(pBF, hParentWnd); } void ShowPPage(IUnknown* pUnk, HWND hParentWnd) { CComQIPtr pSPP = pUnk; if(!pSPP) return; CString str; CComQIPtr pBF = pSPP; CFilterInfo fi; CComQIPtr pPin = pSPP; CPinInfo pi; if(pBF && SUCCEEDED(pBF->QueryFilterInfo(&fi))) str = fi.achName; else if(pPin && SUCCEEDED(pPin->QueryPinInfo(&pi))) str = pi.achName; CAUUID caGUID; caGUID.pElems = NULL; if(SUCCEEDED(pSPP->GetPages(&caGUID))) { IUnknown* lpUnk = NULL; pSPP.QueryInterface(&lpUnk); MyOleCreatePropertyFrame( hParentWnd, 0, 0, CStringW(str), 1, (IUnknown**)&lpUnk, caGUID.cElems, caGUID.pElems, 0, 0, NULL); lpUnk->Release(); if(caGUID.pElems) CoTaskMemFree(caGUID.pElems); } } CLSID GetCLSID(IBaseFilter* pBF) { CLSID clsid = GUID_NULL; if(pBF) pBF->GetClassID(&clsid); return(clsid); } CLSID GetCLSID(IPin* pPin) { return(GetCLSID(GetFilterFromPin(pPin))); } bool IsCLSIDRegistered(LPCTSTR clsid) { CString rootkey1(_T("CLSID\\")); CString rootkey2(_T("CLSID\\{083863F1-70DE-11d0-BD40-00A0C911CE86}\\Instance\\")); return ERROR_SUCCESS == CRegKey().Open(HKEY_CLASSES_ROOT, rootkey1 + clsid, KEY_READ) || ERROR_SUCCESS == CRegKey().Open(HKEY_CLASSES_ROOT, rootkey2 + clsid, KEY_READ); } bool IsCLSIDRegistered(const CLSID& clsid) { bool fRet = false; LPOLESTR pStr = NULL; if(S_OK == StringFromCLSID(clsid, &pStr) && pStr) { fRet = IsCLSIDRegistered(CString(pStr)); CoTaskMemFree(pStr); } return(fRet); } void CStringToBin(CString str, CAtlArray& data) { str.Trim(); ASSERT((str.GetLength()&1) == 0); data.SetCount(str.GetLength()/2); BYTE b = 0; str.MakeUpper(); for(int i = 0, j = str.GetLength(); i < j; i++) { TCHAR c = str[i]; if(c >= '0' && c <= '9') { if(!(i&1)) b = ((char(c-'0')<<4)&0xf0)|(b&0x0f); else b = (char(c-'0')&0x0f)|(b&0xf0); } else if(c >= 'A' && c <= 'F') { if(!(i&1)) b = ((char(c-'A'+10)<<4)&0xf0)|(b&0x0f); else b = (char(c-'A'+10)&0x0f)|(b&0xf0); } else break; if(i&1) { data[i>>1] = b; b = 0; } } } CString BinToCString(BYTE* ptr, int len) { CString ret; while(len-- > 0) { TCHAR high, low; high = (*ptr>>4) >= 10 ? (*ptr>>4)-10 + 'A' : (*ptr>>4) + '0'; low = (*ptr&0xf) >= 10 ? (*ptr&0xf)-10 + 'A' : (*ptr&0xf) + '0'; CString str; str.Format(_T("%c%c"), high, low); ret += str; ptr++; } return(ret); } static void FindFiles(CString fn, CAtlList& files) { CString path = fn; path.Replace('/', '\\'); path = path.Left(path.ReverseFind('\\')+1); WIN32_FIND_DATA findData; HANDLE h = FindFirstFile(fn, &findData); if(h != INVALID_HANDLE_VALUE) { do {files.AddTail(path + findData.cFileName);} while(FindNextFile(h, &findData)); FindClose(h); } } cdrom_t GetCDROMType(TCHAR drive, CAtlList& files) { files.RemoveAll(); CString path; path.Format(_T("%c:"), drive); if(GetDriveType(path + _T("\\")) == DRIVE_CDROM) { // CDROM_VideoCD FindFiles(path + _T("\\mpegav\\avseq??.dat"), files); FindFiles(path + _T("\\mpegav\\avseq??.mpg"), files); FindFiles(path + _T("\\mpeg2\\avseq??.dat"), files); FindFiles(path + _T("\\mpeg2\\avseq??.mpg"), files); FindFiles(path + _T("\\mpegav\\music??.dat"), files); FindFiles(path + _T("\\mpegav\\music??.mpg"), files); FindFiles(path + _T("\\mpeg2\\music??.dat"), files); FindFiles(path + _T("\\mpeg2\\music??.mpg"), files); if(files.GetCount() > 0) return CDROM_VideoCD; // CDROM_DVDVideo FindFiles(path + _T("\\VIDEO_TS\\video_ts.ifo"), files); if(files.GetCount() > 0) return CDROM_DVDVideo; // CDROM_Audio if(!(GetVersion()&0x80000000)) { HANDLE hDrive = CreateFile(CString(_T("\\\\.\\")) + path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, (HANDLE)NULL); if(hDrive != INVALID_HANDLE_VALUE) { DWORD BytesReturned; CDROM_TOC TOC; if(DeviceIoControl(hDrive, IOCTL_CDROM_READ_TOC, NULL, 0, &TOC, sizeof(TOC), &BytesReturned, 0)) { for(int i = TOC.FirstTrack; i <= TOC.LastTrack; i++) { // MMC-3 Draft Revision 10g: Table 222 – Q Sub-channel control field TOC.TrackData[i-1].Control &= 5; if(TOC.TrackData[i-1].Control == 0 || TOC.TrackData[i-1].Control == 1) { CString fn; fn.Format(_T("%s\\track%02d.cda"), path, i); files.AddTail(fn); } } } CloseHandle(hDrive); } } if(files.GetCount() > 0) return CDROM_Audio; // it is a cdrom but nothing special return CDROM_Unknown; } return CDROM_NotFound; } CString GetDriveLabel(TCHAR drive) { CString label; CString path; path.Format(_T("%c:\\"), drive); TCHAR VolumeNameBuffer[MAX_PATH], FileSystemNameBuffer[MAX_PATH]; DWORD VolumeSerialNumber, MaximumComponentLength, FileSystemFlags; if(GetVolumeInformation(path, VolumeNameBuffer, MAX_PATH, &VolumeSerialNumber, &MaximumComponentLength, &FileSystemFlags, FileSystemNameBuffer, MAX_PATH)) { label = VolumeNameBuffer; } return(label); } bool GetKeyFrames(CString fn, CUIntArray& kfs) { kfs.RemoveAll(); CString fn2 = CString(fn).MakeLower(); if(fn2.Mid(fn2.ReverseFind('.')+1) == _T("avi")) { AVIFileInit(); PAVIFILE pfile; if(AVIFileOpen(&pfile, fn, OF_SHARE_DENY_WRITE, 0L) == 0) { AVIFILEINFO afi; memset(&afi, 0, sizeof(afi)); AVIFileInfo(pfile, &afi, sizeof(AVIFILEINFO)); CComPtr pavi; if(AVIFileGetStream(pfile, &pavi, streamtypeVIDEO, 0) == AVIERR_OK) { AVISTREAMINFO si; AVIStreamInfo(pavi, &si, sizeof(si)); if(afi.dwCaps&AVIFILECAPS_ALLKEYFRAMES) { kfs.SetSize(si.dwLength); for(int kf = 0; kf < si.dwLength; kf++) kfs[kf] = kf; } else { for(int kf = 0; ; kf++) { kf = pavi->FindSample(kf, FIND_KEY|FIND_NEXT); if(kf < 0 || kfs.GetCount() > 0 && kfs[kfs.GetCount()-1] >= kf) break; kfs.Add(kf); } if(kfs.GetCount() > 0 && kfs[kfs.GetCount()-1] < si.dwLength-1) { kfs.Add(si.dwLength-1); } } } AVIFileRelease(pfile); } AVIFileExit(); } return(kfs.GetCount() > 0); } DVD_HMSF_TIMECODE RT2HMSF(REFERENCE_TIME rt, double fps) { DVD_HMSF_TIMECODE hmsf = { (BYTE)((rt/10000000/60/60)), (BYTE)((rt/10000000/60)%60), (BYTE)((rt/10000000)%60), (BYTE)(1.0*((rt/10000)%1000) * fps / 1000) }; return hmsf; } REFERENCE_TIME HMSF2RT(DVD_HMSF_TIMECODE hmsf, double fps) { if(fps == 0) {hmsf.bFrames = 0; fps = 1;} return (REFERENCE_TIME)((((REFERENCE_TIME)hmsf.bHours*60+hmsf.bMinutes)*60+hmsf.bSeconds)*1000+1.0*hmsf.bFrames*1000/fps)*10000; } void memsetd(void* dst, unsigned int c, int nbytes) { __asm { mov eax, c mov ecx, nbytes shr ecx, 2 mov edi, dst cld rep stosd } } bool ExtractBIH(const AM_MEDIA_TYPE* pmt, BITMAPINFOHEADER* bih) { if(pmt && bih) { memset(bih, 0, sizeof(*bih)); if(pmt->formattype == FORMAT_VideoInfo) { VIDEOINFOHEADER* vih = (VIDEOINFOHEADER*)pmt->pbFormat; memcpy(bih, &vih->bmiHeader, sizeof(BITMAPINFOHEADER)); return true; } else if(pmt->formattype == FORMAT_VideoInfo2) { VIDEOINFOHEADER2* vih = (VIDEOINFOHEADER2*)pmt->pbFormat; memcpy(bih, &vih->bmiHeader, sizeof(BITMAPINFOHEADER)); return true; } else if(pmt->formattype == FORMAT_MPEGVideo) { VIDEOINFOHEADER* vih = &((MPEG1VIDEOINFO*)pmt->pbFormat)->hdr; memcpy(bih, &vih->bmiHeader, sizeof(BITMAPINFOHEADER)); return true; } else if(pmt->formattype == FORMAT_MPEG2_VIDEO) { VIDEOINFOHEADER2* vih = &((MPEG2VIDEOINFO*)pmt->pbFormat)->hdr; memcpy(bih, &vih->bmiHeader, sizeof(BITMAPINFOHEADER)); return true; } else if(pmt->formattype == FORMAT_DiracVideoInfo) { VIDEOINFOHEADER2* vih = &((DIRACINFOHEADER*)pmt->pbFormat)->hdr; memcpy(bih, &vih->bmiHeader, sizeof(BITMAPINFOHEADER)); return true; } } return false; } bool ExtractBIH(IMediaSample* pMS, BITMAPINFOHEADER* bih) { AM_MEDIA_TYPE* pmt = NULL; pMS->GetMediaType(&pmt); if(pmt) { bool fRet = ExtractBIH(pmt, bih); DeleteMediaType(pmt); return(fRet); } return(false); } bool ExtractDim(const AM_MEDIA_TYPE* pmt, int& w, int& h, int& arx, int& ary) { w = h = arx = ary = 0; if(pmt->formattype == FORMAT_VideoInfo || pmt->formattype == FORMAT_MPEGVideo) { VIDEOINFOHEADER* vih = (VIDEOINFOHEADER*)pmt->pbFormat; w = vih->bmiHeader.biWidth; h = abs(vih->bmiHeader.biHeight); arx = w * vih->bmiHeader.biYPelsPerMeter; ary = h * vih->bmiHeader.biXPelsPerMeter; } else if(pmt->formattype == FORMAT_VideoInfo2 || pmt->formattype == FORMAT_MPEG2_VIDEO || pmt->formattype == FORMAT_DiracVideoInfo) { VIDEOINFOHEADER2* vih = (VIDEOINFOHEADER2*)pmt->pbFormat; w = vih->bmiHeader.biWidth; h = abs(vih->bmiHeader.biHeight); arx = vih->dwPictAspectRatioX; ary = vih->dwPictAspectRatioY; } else { return(false); } if(!arx || !ary) { arx = w; ary = h; } BYTE* ptr = NULL; DWORD len = 0; if(pmt->formattype == FORMAT_MPEGVideo) { ptr = ((MPEG1VIDEOINFO*)pmt->pbFormat)->bSequenceHeader; len = ((MPEG1VIDEOINFO*)pmt->pbFormat)->cbSequenceHeader; if(ptr && len >= 8 && *(DWORD*)ptr == 0xb3010000) { w = (ptr[4]<<4)|(ptr[5]>>4); h = ((ptr[5]&0xf)<<8)|ptr[6]; float ar[] = { 1.0000f,1.0000f,0.6735f,0.7031f, 0.7615f,0.8055f,0.8437f,0.8935f, 0.9157f,0.9815f,1.0255f,1.0695f, 1.0950f,1.1575f,1.2015f,1.0000f, }; arx = (int)((float)w / ar[ptr[7]>>4] + 0.5); ary = h; } } else if(pmt->formattype == FORMAT_MPEG2_VIDEO) { ptr = (BYTE*)((MPEG2VIDEOINFO*)pmt->pbFormat)->dwSequenceHeader; len = ((MPEG2VIDEOINFO*)pmt->pbFormat)->cbSequenceHeader; if(ptr && len >= 8 && *(DWORD*)ptr == 0xb3010000) { w = (ptr[4]<<4)|(ptr[5]>>4); h = ((ptr[5]&0xf)<<8)|ptr[6]; struct {int x, y;} ar[] = {{w,h},{4,3},{16,9},{221,100},{w,h}}; int i = min(max(ptr[7]>>4, 1), 5)-1; arx = ar[i].x; ary = ar[i].y; } } if(ptr && len >= 8) { } DWORD a = arx, b = ary; while(a) {int tmp = a; a = b % tmp; b = tmp;} if(b) arx /= b, ary /= b; return(true); } bool MakeMPEG2MediaType(CMediaType& mt, BYTE* seqhdr, DWORD len, int w, int h) { if(len < 4 || *(DWORD*)seqhdr != 0xb3010000) return false; BYTE* seqhdr_ext = NULL; BYTE* seqhdr_end = seqhdr + 11; if(seqhdr_end - seqhdr > len) return false; if(*seqhdr_end & 0x02) seqhdr_end += 64; if(seqhdr_end - seqhdr > len) return false; if(*seqhdr_end & 0x01) seqhdr_end += 64; if(seqhdr_end - seqhdr > len) return false; seqhdr_end++; if(seqhdr_end - seqhdr > len) return false; if(len - (seqhdr_end - seqhdr) > 4 && *(DWORD*)seqhdr_end == 0xb5010000) {seqhdr_ext = seqhdr_end; seqhdr_end += 10;} if(seqhdr_end - seqhdr > len) return false; len = seqhdr_end - seqhdr; mt = CMediaType(); mt.majortype = MEDIATYPE_Video; mt.subtype = MEDIASUBTYPE_MPEG2_VIDEO; mt.formattype = FORMAT_MPEG2Video; MPEG2VIDEOINFO* vih = (MPEG2VIDEOINFO*)mt.AllocFormatBuffer(FIELD_OFFSET(MPEG2VIDEOINFO, dwSequenceHeader) + len); memset(mt.Format(), 0, mt.FormatLength()); vih->hdr.bmiHeader.biSize = sizeof(vih->hdr.bmiHeader); vih->hdr.bmiHeader.biWidth = w; vih->hdr.bmiHeader.biHeight = h; BYTE* pSequenceHeader = (BYTE*)vih->dwSequenceHeader; memcpy(pSequenceHeader, seqhdr, len); vih->cbSequenceHeader = len; static char profile[8] = { 0, AM_MPEG2Profile_High, AM_MPEG2Profile_SpatiallyScalable, AM_MPEG2Profile_SNRScalable, AM_MPEG2Profile_Main, AM_MPEG2Profile_Simple, 0, 0 }; static char level[16] = { 0, 0, 0, 0, AM_MPEG2Level_High, 0, AM_MPEG2Level_High1440, 0, AM_MPEG2Level_Main, 0, AM_MPEG2Level_Low, 0, 0, 0, 0, 0 }; if(seqhdr_ext && (seqhdr_ext[4] & 0xf0) == 0x10) { vih->dwProfile = profile[seqhdr_ext[4] & 0x07]; vih->dwLevel = level[seqhdr_ext[5] >> 4]; } return true; } unsigned __int64 GetFileVersion(LPCTSTR fn) { unsigned __int64 ret = 0; DWORD buff[4]; VS_FIXEDFILEINFO* pvsf = (VS_FIXEDFILEINFO*)buff; DWORD d; // a variable that GetFileVersionInfoSize sets to zero (but why is it needed ?????????????????????????????? :) DWORD len = GetFileVersionInfoSize((TCHAR*)fn, &d); if(len) { TCHAR* b1 = new TCHAR[len]; if(b1) { UINT uLen; if(GetFileVersionInfo((TCHAR*)fn, 0, len, b1) && VerQueryValue(b1, _T("\\"), (void**)&pvsf, &uLen)) { ret = ((unsigned __int64)pvsf->dwFileVersionMS<<32) | pvsf->dwFileVersionLS; } delete [] b1; } } return ret; } bool CreateFilter(CStringW DisplayName, IBaseFilter** ppBF, CStringW& FriendlyName) { if(!ppBF) return(false); *ppBF = NULL; FriendlyName.Empty(); CComPtr pBindCtx; CreateBindCtx(0, &pBindCtx); CComPtr pMoniker; ULONG chEaten; if(S_OK != MkParseDisplayName(pBindCtx, CComBSTR(DisplayName), &chEaten, &pMoniker)) return(false); if(FAILED(pMoniker->BindToObject(pBindCtx, 0, IID_IBaseFilter, (void**)ppBF)) || !*ppBF) return(false); CComPtr pPB; CComVariant var; if(SUCCEEDED(pMoniker->BindToStorage(pBindCtx, 0, IID_IPropertyBag, (void**)&pPB)) && SUCCEEDED(pPB->Read(CComBSTR(_T("FriendlyName")), &var, NULL))) FriendlyName = var.bstrVal; return(true); } IBaseFilter* AppendFilter(IPin* pPin, IMoniker* pMoniker, IGraphBuilder* pGB) { do { if(!pPin || !pMoniker || !pGB) break; CComPtr pPinTo; PIN_DIRECTION dir; if(FAILED(pPin->QueryDirection(&dir)) || dir != PINDIR_OUTPUT || SUCCEEDED(pPin->ConnectedTo(&pPinTo))) break; CComPtr pBindCtx; CreateBindCtx(0, &pBindCtx); CComPtr pPB; if(FAILED(pMoniker->BindToStorage(pBindCtx, 0, IID_IPropertyBag, (void**)&pPB))) break; CComVariant var; if(FAILED(pPB->Read(CComBSTR(_T("FriendlyName")), &var, NULL))) break; CComPtr pBF; if(FAILED(pMoniker->BindToObject(pBindCtx, 0, IID_IBaseFilter, (void**)&pBF)) || !pBF) break; if(FAILED(pGB->AddFilter(pBF, CStringW(var.bstrVal)))) break; BeginEnumPins(pBF, pEP, pPinTo) { PIN_DIRECTION dir; if(FAILED(pPinTo->QueryDirection(&dir)) || dir != PINDIR_INPUT) continue; if(SUCCEEDED(pGB->ConnectDirect(pPin, pPinTo, NULL))) return(pBF); } EndEnumFilters pGB->RemoveFilter(pBF); } while(false); return(NULL); } CStringW GetFriendlyName(CStringW DisplayName) { CStringW FriendlyName; CComPtr pBindCtx; CreateBindCtx(0, &pBindCtx); CComPtr pMoniker; ULONG chEaten; if(S_OK != MkParseDisplayName(pBindCtx, CComBSTR(DisplayName), &chEaten, &pMoniker)) return(false); CComPtr pPB; CComVariant var; if(SUCCEEDED(pMoniker->BindToStorage(pBindCtx, 0, IID_IPropertyBag, (void**)&pPB)) && SUCCEEDED(pPB->Read(CComBSTR(_T("FriendlyName")), &var, NULL))) FriendlyName = var.bstrVal; return FriendlyName; } typedef struct { CString path; HINSTANCE hInst; CLSID clsid; } ExternalObject; static CAtlList s_extobjs; HRESULT LoadExternalObject(LPCTSTR path, REFCLSID clsid, REFIID iid, void** ppv) { CheckPointer(ppv, E_POINTER); CString fullpath = MakeFullPath(path); HINSTANCE hInst = NULL; bool fFound = false; POSITION pos = s_extobjs.GetHeadPosition(); while(pos) { ExternalObject& eo = s_extobjs.GetNext(pos); if(!eo.path.CompareNoCase(fullpath)) { hInst = eo.hInst; fFound = true; break; } } HRESULT hr = E_FAIL; if(hInst || (hInst = CoLoadLibrary(CComBSTR(fullpath), TRUE))) { typedef HRESULT (__stdcall * PDllGetClassObject)(REFCLSID rclsid, REFIID riid, LPVOID* ppv); PDllGetClassObject p = (PDllGetClassObject)GetProcAddress(hInst, "DllGetClassObject"); if(p && FAILED(hr = p(clsid, iid, ppv))) { CComPtr pCF; if(SUCCEEDED(hr = p(clsid, __uuidof(IClassFactory), (void**)&pCF))) { hr = pCF->CreateInstance(NULL, iid, ppv); } } } if(FAILED(hr) && hInst && !fFound) { CoFreeLibrary(hInst); return hr; } if(hInst && !fFound) { ExternalObject eo; eo.path = fullpath; eo.hInst = hInst; eo.clsid = clsid; s_extobjs.AddTail(eo); } return hr; } HRESULT LoadExternalFilter(LPCTSTR path, REFCLSID clsid, IBaseFilter** ppBF) { return LoadExternalObject(path, clsid, __uuidof(IBaseFilter), (void**)ppBF); } HRESULT LoadExternalPropertyPage(IPersist* pP, REFCLSID clsid, IPropertyPage** ppPP) { CLSID clsid2 = GUID_NULL; if(FAILED(pP->GetClassID(&clsid2))) return E_FAIL; POSITION pos = s_extobjs.GetHeadPosition(); while(pos) { ExternalObject& eo = s_extobjs.GetNext(pos); if(eo.clsid == clsid2) { return LoadExternalObject(eo.path, clsid, __uuidof(IPropertyPage), (void**)ppPP); } } return E_FAIL; } void UnloadExternalObjects() { POSITION pos = s_extobjs.GetHeadPosition(); while(pos) { ExternalObject& eo = s_extobjs.GetNext(pos); CoFreeLibrary(eo.hInst); } s_extobjs.RemoveAll(); } CString MakeFullPath(LPCTSTR path) { CString full(path); full.Replace('/', '\\'); CString fn; fn.ReleaseBuffer(GetModuleFileName(AfxGetInstanceHandle(), fn.GetBuffer(MAX_PATH), MAX_PATH)); CPath p(fn); if(full.GetLength() >= 2 && full[0] == '\\' && full[1] != '\\') { p.StripToRoot(); full = CString(p) + full.Mid(1); } else if(full.Find(_T(":\\")) < 0) { p.RemoveFileSpec(); p.AddBackslash(); full = CString(p) + full; } CPath c(full); c.Canonicalize(); return CString(c); } // CString GetMediaTypeName(const GUID& guid) { CString ret = guid == GUID_NULL ? _T("Any type") : CString(GuidNames[guid]); if(ret == _T("FOURCC GUID")) { CString str; if(guid.Data1 >= 0x10000) str.Format(_T("Video: %c%c%c%c"), (guid.Data1>>0)&0xff, (guid.Data1>>8)&0xff, (guid.Data1>>16)&0xff, (guid.Data1>>24)&0xff); else str.Format(_T("Audio: 0x%08x"), guid.Data1); ret = str; } else if(ret == _T("Unknown GUID Name")) { WCHAR null[128] = {0}, buff[128]; StringFromGUID2(GUID_NULL, null, 127); ret = CString(CStringW(StringFromGUID2(guid, buff, 127) ? buff : null)); } return ret; } GUID GUIDFromCString(CString str) { GUID guid = GUID_NULL; HRESULT hr = CLSIDFromString(CComBSTR(str), &guid); ASSERT(SUCCEEDED(hr)); return guid; } HRESULT GUIDFromCString(CString str, GUID& guid) { guid = GUID_NULL; return CLSIDFromString(CComBSTR(str), &guid); } CString CStringFromGUID(const GUID& guid) { WCHAR null[128] = {0}, buff[128]; StringFromGUID2(GUID_NULL, null, 127); return CString(StringFromGUID2(guid, buff, 127) > 0 ? buff : null); } CStringW UTF8To16(LPCSTR utf8) { CStringW str; int n = MultiByteToWideChar(CP_UTF8, 0, utf8, -1, NULL, 0)-1; if(n < 0) return str; str.ReleaseBuffer(MultiByteToWideChar(CP_UTF8, 0, utf8, -1, str.GetBuffer(n), n+1)-1); return str; } CStringA UTF16To8(LPCWSTR utf16) { CStringA str; int n = WideCharToMultiByte(CP_UTF8, 0, utf16, -1, NULL, 0, NULL, NULL)-1; if(n < 0) return str; str.ReleaseBuffer(WideCharToMultiByte(CP_UTF8, 0, utf16, -1, str.GetBuffer(n), n+1, NULL, NULL)-1); return str; } static struct {LPCSTR name, iso6392, iso6391;} s_isolangs[] = { {"Abkhazian", "abk", "ab"}, {"Achinese", "ace", ""}, {"Acoli", "ach", ""}, {"Adangme", "ada", ""}, {"Afar", "aar", "aa"}, {"Afrihili", "afh", ""}, {"Afrikaans", "afr", "af"}, {"Afro-Asiatic (Other)", "afa", ""}, {"Akan", "aka", "ak"}, {"Akkadian", "akk", ""}, {"Albanian", "alb", "sq"}, {"Albanian", "sqi", "sq"}, {"Aleut", "ale", ""}, {"Algonquian languages", "alg", ""}, {"Altaic (Other)", "tut", ""}, {"Amharic", "amh", "am"}, {"Apache languages", "apa", ""}, {"Arabic", "ara", "ar"}, {"Aragonese", "arg", "an"}, {"Aramaic", "arc", ""}, {"Arapaho", "arp", ""}, {"Araucanian", "arn", ""}, {"Arawak", "arw", ""}, {"Armenian", "arm", "hy"}, {"Armenian", "hye", "hy"}, {"Artificial (Other)", "art", ""}, {"Assamese", "asm", "as"}, {"Asturian; Bable", "ast", ""}, {"Athapascan languages", "ath", ""}, {"Australian languages", "aus", ""}, {"Austronesian (Other)", "map", ""}, {"Avaric", "ava", "av"}, {"Avestan", "ave", "ae"}, {"Awadhi", "awa", ""}, {"Aymara", "aym", "ay"}, {"Azerbaijani", "aze", "az"}, {"Bable; Asturian", "ast", ""}, {"Balinese", "ban", ""}, {"Baltic (Other)", "bat", ""}, {"Baluchi", "bal", ""}, {"Bambara", "bam", "bm"}, {"Bamileke languages", "bai", ""}, {"Banda", "bad", ""}, {"Bantu (Other)", "bnt", ""}, {"Basa", "bas", ""}, {"Bashkir", "bak", "ba"}, {"Basque", "baq", "eu"}, {"Basque", "eus", "eu"}, {"Batak (Indonesia)", "btk", ""}, {"Beja", "bej", ""}, {"Belarusian", "bel", "be"}, {"Bemba", "bem", ""}, {"Bengali", "ben", "bn"}, {"Berber (Other)", "ber", ""}, {"Bhojpuri", "bho", ""}, {"Bihari", "bih", "bh"}, {"Bikol", "bik", ""}, {"Bini", "bin", ""}, {"Bislama", "bis", "bi"}, {"Bokmål, Norwegian; Norwegian Bokmål", "nob", "nb"}, {"Bosnian", "bos", "bs"}, {"Braj", "bra", ""}, {"Breton", "bre", "br"}, {"Buginese", "bug", ""}, {"Bulgarian", "bul", "bg"}, {"Buriat", "bua", ""}, {"Burmese", "bur", "my"}, {"Burmese", "mya", "my"}, {"Caddo", "cad", ""}, {"Carib", "car", ""}, {"Spanish; Castilian", "spa", "es"}, {"Catalan", "cat", "ca"}, {"Caucasian (Other)", "cau", ""}, {"Cebuano", "ceb", ""}, {"Celtic (Other)", "cel", ""}, {"Central American Indian (Other)", "cai", ""}, {"Chagatai", "chg", ""}, {"Chamic languages", "cmc", ""}, {"Chamorro", "cha", "ch"}, {"Chechen", "che", "ce"}, {"Cherokee", "chr", ""}, {"Chewa; Chichewa; Nyanja", "nya", "ny"}, {"Cheyenne", "chy", ""}, {"Chibcha", "chb", ""}, {"Chichewa; Chewa; Nyanja", "nya", "ny"}, {"Chinese", "chi", "zh"}, {"Chinese", "zho", "zh"}, {"Chinook jargon", "chn", ""}, {"Chipewyan", "chp", ""}, {"Choctaw", "cho", ""}, {"Chuang; Zhuang", "zha", "za"}, {"Church Slavic; Old Church Slavonic", "chu", "cu"}, {"Old Church Slavonic; Old Slavonic; ", "chu", "cu"}, {"Church Slavonic; Old Bulgarian; Church Slavic;", "chu", "cu"}, {"Old Slavonic; Church Slavonic; Old Bulgarian;", "chu", "cu"}, {"Church Slavic; Old Church Slavonic", "chu", "cu"}, {"Chuukese", "chk", ""}, {"Chuvash", "chv", "cv"}, {"Coptic", "cop", ""}, {"Cornish", "cor", "kw"}, {"Corsican", "cos", "co"}, {"Cree", "cre", "cr"}, {"Creek", "mus", ""}, {"Creoles and pidgins (Other)", "crp", ""}, {"Creoles and pidgins,", "cpe", ""}, // {"English-based (Other)", "", ""}, {"Creoles and pidgins,", "cpf", ""}, // {"French-based (Other)", "", ""}, {"Creoles and pidgins,", "cpp", ""}, // {"Portuguese-based (Other)", "", ""}, {"Croatian", "scr", "hr"}, {"Croatian", "hrv", "hr"}, {"Cushitic (Other)", "cus", ""}, {"Czech", "cze", "cs"}, {"Czech", "ces", "cs"}, {"Dakota", "dak", ""}, {"Danish", "dan", "da"}, {"Dargwa", "dar", ""}, {"Dayak", "day", ""}, {"Delaware", "del", ""}, {"Dinka", "din", ""}, {"Divehi", "div", "dv"}, {"Dogri", "doi", ""}, {"Dogrib", "dgr", ""}, {"Dravidian (Other)", "dra", ""}, {"Duala", "dua", ""}, {"Dutch; Flemish", "dut", "nl"}, {"Dutch; Flemish", "nld", "nl"}, {"Dutch, Middle (ca. 1050-1350)", "dum", ""}, {"Dyula", "dyu", ""}, {"Dzongkha", "dzo", "dz"}, {"Efik", "efi", ""}, {"Egyptian (Ancient)", "egy", ""}, {"Ekajuk", "eka", ""}, {"Elamite", "elx", ""}, {"English", "eng", "en"}, {"English, Middle (1100-1500)", "enm", ""}, {"English, Old (ca.450-1100)", "ang", ""}, {"Esperanto", "epo", "eo"}, {"Estonian", "est", "et"}, {"Ewe", "ewe", "ee"}, {"Ewondo", "ewo", ""}, {"Fang", "fan", ""}, {"Fanti", "fat", ""}, {"Faroese", "fao", "fo"}, {"Fijian", "fij", "fj"}, {"Finnish", "fin", "fi"}, {"Finno-Ugrian (Other)", "fiu", ""}, {"Flemish; Dutch", "dut", "nl"}, {"Flemish; Dutch", "nld", "nl"}, {"Fon", "fon", ""}, {"French", "fre", "fr"}, {"French", "fra*", "fr"}, {"French, Middle (ca.1400-1600)", "frm", ""}, {"French, Old (842-ca.1400)", "fro", ""}, {"Frisian", "fry", "fy"}, {"Friulian", "fur", ""}, {"Fulah", "ful", "ff"}, {"Ga", "gaa", ""}, {"Gaelic; Scottish Gaelic", "gla", "gd"}, {"Gallegan", "glg", "gl"}, {"Ganda", "lug", "lg"}, {"Gayo", "gay", ""}, {"Gbaya", "gba", ""}, {"Geez", "gez", ""}, {"Georgian", "geo", "ka"}, {"Georgian", "kat", "ka"}, {"German", "ger", "de"}, {"German", "deu", "de"}, {"German, Low; Saxon, Low; Low German; Low Saxon", "nds", ""}, {"German, Middle High (ca.1050-1500)", "gmh", ""}, {"German, Old High (ca.750-1050)", "goh", ""}, {"Germanic (Other)", "gem", ""}, {"Gikuyu; Kikuyu", "kik", "ki"}, {"Gilbertese", "gil", ""}, {"Gondi", "gon", ""}, {"Gorontalo", "gor", ""}, {"Gothic", "got", ""}, {"Grebo", "grb", ""}, {"Greek, Ancient (to 1453)", "grc", ""}, {"Greek, Modern (1453-)", "gre", "el"}, {"Greek, Modern (1453-)", "ell", "el"}, {"Greenlandic; Kalaallisut", "kal", "kl"}, {"Guarani", "grn", "gn"}, {"Gujarati", "guj", "gu"}, {"Gwich´in", "gwi", ""}, {"Haida", "hai", ""}, {"Hausa", "hau", "ha"}, {"Hawaiian", "haw", ""}, {"Hebrew", "heb", "he"}, {"Herero", "her", "hz"}, {"Hiligaynon", "hil", ""}, {"Himachali", "him", ""}, {"Hindi", "hin", "hi"}, {"Hiri Motu", "hmo", "ho"}, {"Hittite", "hit", ""}, {"Hmong", "hmn", ""}, {"Hungarian", "hun", "hu"}, {"Hupa", "hup", ""}, {"Iban", "iba", ""}, {"Icelandic", "ice", "is"}, {"Icelandic", "isl", "is"}, {"Ido", "ido", "io"}, {"Igbo", "ibo", "ig"}, {"Ijo", "ijo", ""}, {"Iloko", "ilo", ""}, {"Inari Sami", "smn", ""}, {"Indic (Other)", "inc", ""}, {"Indo-European (Other)", "ine", ""}, {"Indonesian", "ind", "id"}, {"Ingush", "inh", ""}, {"Interlingua (International", "ina", "ia"}, // {"Auxiliary Language Association)", "", ""}, {"Interlingue", "ile", "ie"}, {"Inuktitut", "iku", "iu"}, {"Inupiaq", "ipk", "ik"}, {"Iranian (Other)", "ira", ""}, {"Irish", "gle", "ga"}, {"Irish, Middle (900-1200)", "mga", ""}, {"Irish, Old (to 900)", "sga", ""}, {"Iroquoian languages", "iro", ""}, {"Italian", "ita", "it"}, {"Japanese", "jpn", "ja"}, {"Javanese", "jav", "jv"}, {"Judeo-Arabic", "jrb", ""}, {"Judeo-Persian", "jpr", ""}, {"Kabardian", "kbd", ""}, {"Kabyle", "kab", ""}, {"Kachin", "kac", ""}, {"Kalaallisut; Greenlandic", "kal", "kl"}, {"Kamba", "kam", ""}, {"Kannada", "kan", "kn"}, {"Kanuri", "kau", "kr"}, {"Kara-Kalpak", "kaa", ""}, {"Karen", "kar", ""}, {"Kashmiri", "kas", "ks"}, {"Kawi", "kaw", ""}, {"Kazakh", "kaz", "kk"}, {"Khasi", "kha", ""}, {"Khmer", "khm", "km"}, {"Khoisan (Other)", "khi", ""}, {"Khotanese", "kho", ""}, {"Kikuyu; Gikuyu", "kik", "ki"}, {"Kimbundu", "kmb", ""}, {"Kinyarwanda", "kin", "rw"}, {"Kirghiz", "kir", "ky"}, {"Komi", "kom", "kv"}, {"Kongo", "kon", "kg"}, {"Konkani", "kok", ""}, {"Korean", "kor", "ko"}, {"Kosraean", "kos", ""}, {"Kpelle", "kpe", ""}, {"Kru", "kro", ""}, {"Kuanyama; Kwanyama", "kua", "kj"}, {"Kumyk", "kum", ""}, {"Kurdish", "kur", "ku"}, {"Kurukh", "kru", ""}, {"Kutenai", "kut", ""}, {"Kwanyama, Kuanyama", "kua", "kj"}, {"Ladino", "lad", ""}, {"Lahnda", "lah", ""}, {"Lamba", "lam", ""}, {"Lao", "lao", "lo"}, {"Latin", "lat", "la"}, {"Latvian", "lav", "lv"}, {"Letzeburgesch; Luxembourgish", "ltz", "lb"}, {"Lezghian", "lez", ""}, {"Limburgan; Limburger; Limburgish", "lim", "li"}, {"Limburger; Limburgan; Limburgish;", "lim", "li"}, {"Limburgish; Limburger; Limburgan", "lim", "li"}, {"Lingala", "lin", "ln"}, {"Lithuanian", "lit", "lt"}, {"Low German; Low Saxon; German, Low; Saxon, Low", "nds", ""}, {"Low Saxon; Low German; Saxon, Low; German, Low", "nds", ""}, {"Lozi", "loz", ""}, {"Luba-Katanga", "lub", "lu"}, {"Luba-Lulua", "lua", ""}, {"Luiseno", "lui", ""}, {"Lule Sami", "smj", ""}, {"Lunda", "lun", ""}, {"Luo (Kenya and Tanzania)", "luo", ""}, {"Lushai", "lus", ""}, {"Luxembourgish; Letzeburgesch", "ltz", "lb"}, {"Macedonian", "mac", "mk"}, {"Macedonian", "mkd", "mk"}, {"Madurese", "mad", ""}, {"Magahi", "mag", ""}, {"Maithili", "mai", ""}, {"Makasar", "mak", ""}, {"Malagasy", "mlg", "mg"}, {"Malay", "may", "ms"}, {"Malay", "msa", "ms"}, {"Malayalam", "mal", "ml"}, {"Maltese", "mlt", "mt"}, {"Manchu", "mnc", ""}, {"Mandar", "mdr", ""}, {"Mandingo", "man", ""}, {"Manipuri", "mni", ""}, {"Manobo languages", "mno", ""}, {"Manx", "glv", "gv"}, {"Maori", "mao", "mi"}, {"Maori", "mri", "mi"}, {"Marathi", "mar", "mr"}, {"Mari", "chm", ""}, {"Marshallese", "mah", "mh"}, {"Marwari", "mwr", ""}, {"Masai", "mas", ""}, {"Mayan languages", "myn", ""}, {"Mende", "men", ""}, {"Micmac", "mic", ""}, {"Minangkabau", "min", ""}, {"Miscellaneous languages", "mis", ""}, {"Mohawk", "moh", ""}, {"Moldavian", "mol", "mo"}, {"Mon-Khmer (Other)", "mkh", ""}, {"Mongo", "lol", ""}, {"Mongolian", "mon", "mn"}, {"Mossi", "mos", ""}, {"Multiple languages", "mul", ""}, {"Munda languages", "mun", ""}, {"Nahuatl", "nah", ""}, {"Nauru", "nau", "na"}, {"Navaho, Navajo", "nav", "nv"}, {"Navajo; Navaho", "nav", "nv"}, {"Ndebele, North", "nde", "nd"}, {"Ndebele, South", "nbl", "nr"}, {"Ndonga", "ndo", "ng"}, {"Neapolitan", "nap", ""}, {"Nepali", "nep", "ne"}, {"Newari", "new", ""}, {"Nias", "nia", ""}, {"Niger-Kordofanian (Other)", "nic", ""}, {"Nilo-Saharan (Other)", "ssa", ""}, {"Niuean", "niu", ""}, {"Norse, Old", "non", ""}, {"North American Indian (Other)", "nai", ""}, {"Northern Sami", "sme", "se"}, {"North Ndebele", "nde", "nd"}, {"Norwegian", "nor", "no"}, {"Norwegian Bokmål; Bokmål, Norwegian", "nob", "nb"}, {"Norwegian Nynorsk; Nynorsk, Norwegian", "nno", "nn"}, {"Nubian languages", "nub", ""}, {"Nyamwezi", "nym", ""}, {"Nyanja; Chichewa; Chewa", "nya", "ny"}, {"Nyankole", "nyn", ""}, {"Nynorsk, Norwegian; Norwegian Nynorsk", "nno", "nn"}, {"Nyoro", "nyo", ""}, {"Nzima", "nzi", ""}, {"Occitan (post 1500},; Provençal", "oci", "oc"}, {"Ojibwa", "oji", "oj"}, {"Old Bulgarian; Old Slavonic; Church Slavonic;", "chu", "cu"}, {"Oriya", "ori", "or"}, {"Oromo", "orm", "om"}, {"Osage", "osa", ""}, {"Ossetian; Ossetic", "oss", "os"}, {"Ossetic; Ossetian", "oss", "os"}, {"Otomian languages", "oto", ""}, {"Pahlavi", "pal", ""}, {"Palauan", "pau", ""}, {"Pali", "pli", "pi"}, {"Pampanga", "pam", ""}, {"Pangasinan", "pag", ""}, {"Panjabi", "pan", "pa"}, {"Papiamento", "pap", ""}, {"Papuan (Other)", "paa", ""}, {"Persian", "per", "fa"}, {"Persian", "fas", "fa"}, {"Persian, Old (ca.600-400 B.C.)", "peo", ""}, {"Philippine (Other)", "phi", ""}, {"Phoenician", "phn", ""}, {"Pohnpeian", "pon", ""}, {"Polish", "pol", "pl"}, {"Portuguese", "por", "pt"}, {"Prakrit languages", "pra", ""}, {"Provençal; Occitan (post 1500)", "oci", "oc"}, {"Provençal, Old (to 1500)", "pro", ""}, {"Pushto", "pus", "ps"}, {"Quechua", "que", "qu"}, {"Raeto-Romance", "roh", "rm"}, {"Rajasthani", "raj", ""}, {"Rapanui", "rap", ""}, {"Rarotongan", "rar", ""}, {"Reserved for local use", "qaa-qtz", ""}, {"Romance (Other)", "roa", ""}, {"Romanian", "rum", "ro"}, {"Romanian", "ron", "ro"}, {"Romany", "rom", ""}, {"Rundi", "run", "rn"}, {"Russian", "rus", "ru"}, {"Salishan languages", "sal", ""}, {"Samaritan Aramaic", "sam", ""}, {"Sami languages (Other)", "smi", ""}, {"Samoan", "smo", "sm"}, {"Sandawe", "sad", ""}, {"Sango", "sag", "sg"}, {"Sanskrit", "san", "sa"}, {"Santali", "sat", ""}, {"Sardinian", "srd", "sc"}, {"Sasak", "sas", ""}, {"Saxon, Low; German, Low; Low Saxon; Low German", "nds", ""}, {"Scots", "sco", ""}, {"Scottish Gaelic; Gaelic", "gla", "gd"}, {"Selkup", "sel", ""}, {"Semitic (Other)", "sem", ""}, {"Serbian", "scc", "sr"}, {"Serbian", "srp", "sr"}, {"Serer", "srr", ""}, {"Shan", "shn", ""}, {"Shona", "sna", "sn"}, {"Sichuan Yi", "iii", "ii"}, {"Sidamo", "sid", ""}, {"Sign languages", "sgn", ""}, {"Siksika", "bla", ""}, {"Sindhi", "snd", "sd"}, {"Sinhalese", "sin", "si"}, {"Sino-Tibetan (Other)", "sit", ""}, {"Siouan languages", "sio", ""}, {"Skolt Sami", "sms", ""}, {"Slave (Athapascan)", "den", ""}, {"Slavic (Other)", "sla", ""}, {"Slovak", "slo", "sk"}, {"Slovak", "slk", "sk"}, {"Slovenian", "slv", "sl"}, {"Sogdian", "sog", ""}, {"Somali", "som", "so"}, {"Songhai", "son", ""}, {"Soninke", "snk", ""}, {"Sorbian languages", "wen", ""}, {"Sotho, Northern", "nso", ""}, {"Sotho, Southern", "sot", "st"}, {"South American Indian (Other)", "sai", ""}, {"Southern Sami", "sma", ""}, {"South Ndebele", "nbl", "nr"}, {"Spanish; Castilian", "spa", "es"}, {"Sukuma", "suk", ""}, {"Sumerian", "sux", ""}, {"Sundanese", "sun", "su"}, {"Susu", "sus", ""}, {"Swahili", "swa", "sw"}, {"Swati", "ssw", "ss"}, {"Swedish", "swe", "sv"}, {"Syriac", "syr", ""}, {"Tagalog", "tgl", "tl"}, {"Tahitian", "tah", "ty"}, {"Tai (Other)", "tai", ""}, {"Tajik", "tgk", "tg"}, {"Tamashek", "tmh", ""}, {"Tamil", "tam", "ta"}, {"Tatar", "tat", "tt"}, {"Telugu", "tel", "te"}, {"Tereno", "ter", ""}, {"Tetum", "tet", ""}, {"Thai", "tha", "th"}, {"Tibetan", "tib", "bo"}, {"Tibetan", "bod", "bo"}, {"Tigre", "tig", ""}, {"Tigrinya", "tir", "ti"}, {"Timne", "tem", ""}, {"Tiv", "tiv", ""}, {"Tlingit", "tli", ""}, {"Tok Pisin", "tpi", ""}, {"Tokelau", "tkl", ""}, {"Tonga (Nyasa)", "tog", ""}, {"Tonga (Tonga Islands)", "ton", "to"}, {"Tsimshian", "tsi", ""}, {"Tsonga", "tso", "ts"}, {"Tswana", "tsn", "tn"}, {"Tumbuka", "tum", ""}, {"Tupi languages", "tup", ""}, {"Turkish", "tur", "tr"}, {"Turkish, Ottoman (1500-1928)", "ota", ""}, {"Turkmen", "tuk", "tk"}, {"Tuvalu", "tvl", ""}, {"Tuvinian", "tyv", ""}, {"Twi", "twi", "tw"}, {"Ugaritic", "uga", ""}, {"Uighur", "uig", "ug"}, {"Ukrainian", "ukr", "uk"}, {"Umbundu", "umb", ""}, {"Undetermined", "und", ""}, {"Urdu", "urd", "ur"}, {"Uzbek", "uzb", "uz"}, {"Vai", "vai", ""}, {"Venda", "ven", "ve"}, {"Vietnamese", "vie", "vi"}, {"Volapük", "vol", "vo"}, {"Votic", "vot", ""}, {"Wakashan languages", "wak", ""}, {"Walamo", "wal", ""}, {"Walloon", "wln", "wa"}, {"Waray", "war", ""}, {"Washo", "was", ""}, {"Welsh", "wel", "cy"}, {"Welsh", "cym", "cy"}, {"Wolof", "wol", "wo"}, {"Xhosa", "xho", "xh"}, {"Yakut", "sah", ""}, {"Yao", "yao", ""}, {"Yapese", "yap", ""}, {"Yiddish", "yid", "yi"}, {"Yoruba", "yor", "yo"}, {"Yupik languages", "ypk", ""}, {"Zande", "znd", ""}, {"Zapotec", "zap", ""}, {"Zenaga", "zen", ""}, {"Zhuang; Chuang", "zha", "za"}, {"Zulu", "zul", "zu"}, {"Zuni", "zun", ""}, {"Classical Newari", "nwc", ""}, {"Klingon", "tlh", ""}, {"Blin", "byn", ""}, {"Lojban", "jbo", ""}, {"Lower Sorbian", "dsb", ""}, {"Upper Sorbian", "hsb", ""}, {"Kashubian", "csb", ""}, {"Crimean Turkish", "crh", ""}, {"Erzya", "myv", ""}, {"Moksha", "mdf", ""}, {"Karachay-Balkar", "krc", ""}, {"Adyghe", "ady", ""}, {"Udmurt", "udm", ""}, {"Dargwa", "dar", ""}, {"Ingush", "inh", ""}, {"Nogai", "nog", ""}, {"Haitian", "hat", "ht"}, {"Kalmyk", "xal", ""}, {"", "", ""}, }; CString ISO6391ToLanguage(LPCSTR code) { CHAR tmp[2+1]; strncpy(tmp, code, 2); tmp[2] = 0; _strlwr(tmp); for(int i = 0, j = countof(s_isolangs); i < j; i++) if(!strcmp(s_isolangs[i].iso6391, tmp)) { CString ret = CString(CStringA(s_isolangs[i].name)); int i = ret.Find(';'); if(i > 0) ret = ret.Left(i); return ret; } return(_T("")); } CString ISO6392ToLanguage(LPCSTR code) { CHAR tmp[3+1]; strncpy(tmp, code, 3); tmp[3] = 0; _strlwr(tmp); for(int i = 0, j = countof(s_isolangs); i < j; i++) { if(!strcmp(s_isolangs[i].iso6392, tmp)) { CString ret = CString(CStringA(s_isolangs[i].name)); int i = ret.Find(';'); if(i > 0) ret = ret.Left(i); return ret; } } return _T(""); } CString ISO6391To6392(LPCSTR code) { CHAR tmp[2+1]; strncpy(tmp, code, 2); tmp[2] = 0; _strlwr(tmp); for(int i = 0, j = countof(s_isolangs); i < j; i++) if(!strcmp(s_isolangs[i].iso6391, tmp)) return CString(CStringA(s_isolangs[i].iso6392)); return _T(""); } CString ISO6392To6391(LPCSTR code) { CHAR tmp[3+1]; strncpy(tmp, code, 3); tmp[3] = 0; _strlwr(tmp); for(int i = 0, j = countof(s_isolangs); i < j; i++) if(!strcmp(s_isolangs[i].iso6392, tmp)) return CString(CStringA(s_isolangs[i].iso6391)); return _T(""); } CString LanguageToISO6392(LPCTSTR lang) { CString str = lang; str.MakeLower(); for(int i = 0, j = countof(s_isolangs); i < j; i++) { CAtlList sl; Explode(CString(s_isolangs[i].name), sl, ';'); POSITION pos = sl.GetHeadPosition(); while(pos) { if(!str.CompareNoCase(sl.GetNext(pos))) return CString(s_isolangs[i].iso6392); } } return _T(""); } int MakeAACInitData(BYTE* pData, int profile, int freq, int channels) { int srate_idx; if(92017 <= freq) srate_idx = 0; else if(75132 <= freq) srate_idx = 1; else if(55426 <= freq) srate_idx = 2; else if(46009 <= freq) srate_idx = 3; else if(37566 <= freq) srate_idx = 4; else if(27713 <= freq) srate_idx = 5; else if(23004 <= freq) srate_idx = 6; else if(18783 <= freq) srate_idx = 7; else if(13856 <= freq) srate_idx = 8; else if(11502 <= freq) srate_idx = 9; else if(9391 <= freq) srate_idx = 10; else srate_idx = 11; pData[0] = ((abs(profile) + 1) << 3) | ((srate_idx & 0xe) >> 1); pData[1] = ((srate_idx & 0x1) << 7) | (channels << 3); int ret = 2; if(profile < 0) { freq *= 2; if(92017 <= freq) srate_idx = 0; else if(75132 <= freq) srate_idx = 1; else if(55426 <= freq) srate_idx = 2; else if(46009 <= freq) srate_idx = 3; else if(37566 <= freq) srate_idx = 4; else if(27713 <= freq) srate_idx = 5; else if(23004 <= freq) srate_idx = 6; else if(18783 <= freq) srate_idx = 7; else if(13856 <= freq) srate_idx = 8; else if(11502 <= freq) srate_idx = 9; else if(9391 <= freq) srate_idx = 10; else srate_idx = 11; pData[2] = 0x2B7>>3; pData[3] = (BYTE)((0x2B7<<5) | 5); pData[4] = (1<<7) | (srate_idx<<3); ret = 5; } return(ret); } BOOL CFileGetStatus(LPCTSTR lpszFileName, CFileStatus& status) { try { return CFile::GetStatus(lpszFileName, status); } catch(CException* e) { // MFCBUG: E_INVALIDARG / "Parameter is incorrect" is thrown for certain cds (vs2003) // 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 TRACE(_T("CFile::GetStatus has thrown an exception\n")); e->Delete(); return false; } } // filter registration helpers bool DeleteRegKey(LPCTSTR pszKey, LPCTSTR pszSubkey) { bool bOK = false; HKEY hKey; LONG ec = ::RegOpenKeyEx(HKEY_CLASSES_ROOT, pszKey, 0, KEY_ALL_ACCESS, &hKey); if(ec == ERROR_SUCCESS) { if(pszSubkey != 0) ec = ::RegDeleteKey(hKey, pszSubkey); bOK = (ec == ERROR_SUCCESS); ::RegCloseKey(hKey); } return bOK; } bool SetRegKeyValue(LPCTSTR pszKey, LPCTSTR pszSubkey, LPCTSTR pszValueName, LPCTSTR pszValue) { bool bOK = false; CString szKey(pszKey); if(pszSubkey != 0) szKey += CString(_T("\\")) + pszSubkey; HKEY hKey; LONG ec = ::RegCreateKeyEx(HKEY_CLASSES_ROOT, szKey, 0, 0, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, 0, &hKey, 0); if(ec == ERROR_SUCCESS) { if(pszValue != 0) { ec = ::RegSetValueEx(hKey, pszValueName, 0, REG_SZ, reinterpret_cast(const_cast(pszValue)), (_tcslen(pszValue) + 1) * sizeof(TCHAR)); } bOK = (ec == ERROR_SUCCESS); ::RegCloseKey(hKey); } return bOK; } bool SetRegKeyValue(LPCTSTR pszKey, LPCTSTR pszSubkey, LPCTSTR pszValue) { return SetRegKeyValue(pszKey, pszSubkey, 0, pszValue); } void RegisterSourceFilter(const CLSID& clsid, const GUID& subtype2, LPCTSTR chkbytes, LPCTSTR ext, ...) { CString null = CStringFromGUID(GUID_NULL); CString majortype = CStringFromGUID(MEDIATYPE_Stream); CString subtype = CStringFromGUID(subtype2); SetRegKeyValue(_T("Media Type\\") + majortype, subtype, _T("0"), chkbytes); SetRegKeyValue(_T("Media Type\\") + majortype, subtype, _T("Source Filter"), CStringFromGUID(clsid)); DeleteRegKey(_T("Media Type\\") + null, subtype); va_list marker; va_start(marker, ext); for(; ext; ext = va_arg(marker, LPCTSTR)) DeleteRegKey(_T("Media Type\\Extensions"), ext); va_end(marker); } void RegisterSourceFilter(const CLSID& clsid, const GUID& subtype2, const CAtlList& chkbytes, LPCTSTR ext, ...) { CString null = CStringFromGUID(GUID_NULL); CString majortype = CStringFromGUID(MEDIATYPE_Stream); CString subtype = CStringFromGUID(subtype2); POSITION pos = chkbytes.GetHeadPosition(); for(int i = 0; pos; i++) { CString idx; idx.Format(_T("%d"), i); SetRegKeyValue(_T("Media Type\\") + majortype, subtype, idx, chkbytes.GetNext(pos)); } SetRegKeyValue(_T("Media Type\\") + majortype, subtype, _T("Source Filter"), CStringFromGUID(clsid)); DeleteRegKey(_T("Media Type\\") + null, subtype); va_list marker; va_start(marker, ext); for(; ext; ext = va_arg(marker, LPCTSTR)) DeleteRegKey(_T("Media Type\\Extensions"), ext); va_end(marker); } void UnRegisterSourceFilter(const GUID& subtype) { DeleteRegKey(_T("Media Type\\") + CStringFromGUID(MEDIATYPE_Stream), CStringFromGUID(subtype)); }