問題描述
枚舉 Windows 上所有可用視頻編解碼器的最佳方法? (Best way to enumerate all available video codecs on Windows?)
我正在尋找一種枚舉 Windows XP/Vista 機器上所有視頻編解碼器的好方法。
我需要向用戶展示一組視頻編解碼器,包括壓縮器和解壓縮器。輸出看起來類似於
可用解碼器 DiVX 版本 6.0 XVID Motion JPEG CompanyX 的 MPEG‑2 解碼器 Windows Media Video **可用編碼器** DiVX 版本 6.0 Windows Media Video
問題我遇到的是沒有可靠的方法來捕獲系統可用的所有解碼器。例如:
- 您可以使用 DirectShow 枚舉所有解壓縮器,但這不會告訴您有關壓縮器(編碼器)的任何信息。
- 您可以枚舉所有 Video For Windows 組件, 但是您沒有任何跡象表明這些是編碼器還是解碼器。
- 有 DirectShow 過濾器可以很好地為您完成這項工作(例如 Motion JPEG 過濾器),但沒有跡象表明特定的 DirectShow 過濾器是“視頻解碼器”。
有沒有人使用任何 Windows API 找到了針對此問題的通用解決方案?Windows Vista Media Foundation API 是否解決了這些問題?
參考解法
方法 1:
This is best handled by DirectShow.
DirectShow is currently a part of the platform SDK.
HRESULT extractFriendlyName( IMoniker* pMk, std::wstring& str )
{
assert( pMk != 0 );
IPropertyBag* pBag = 0;
HRESULT hr = pMk‑>BindToStorage(0, 0, IID_IPropertyBag, (void **)&pBag );
if( FAILED( hr ) || pBag == 0 )
{
return hr;
}
VARIANT var;
var.vt = VT_BSTR;
hr = pBag‑>Read(L"FriendlyName", &var, NULL);
if( SUCCEEDED( hr ) && var.bstrVal != 0 )
{
str = reinterpret_cast<wchar_t*>( var.bstrVal );
SysFreeString(var.bstrVal);
}
pBag‑>Release();
return hr;
}
HRESULT enumerateDShowFilterList( const CLSID& category )
{
HRESULT rval = S_OK;
HRESULT hr;
ICreateDevEnum* pCreateDevEnum = 0; // volatile, will be destroyed at the end
hr = ::CoCreateInstance( CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, reinterpret_cast<void**>( &pCreateDevEnum ) );
assert( SUCCEEDED( hr ) && pCreateDevEnum != 0 );
if( FAILED( hr ) || pCreateDevEnum == 0 )
{
return hr;
}
IEnumMoniker* pEm = 0;
hr = pCreateDevEnum‑>CreateClassEnumerator( category, &pEm, 0 );
// If hr == S_FALSE, no error is occured. In this case pEm is NULL, because
// a filter does not exist e.g no video capture devives are connected to
// the computer or no codecs are installed.
assert( SUCCEEDED( hr ) && ((hr == S_OK && pEm != 0 ) || hr == S_FALSE) );
if( FAILED( hr ) )
{
pCreateDevEnum‑>Release();
return hr;
}
if( hr == S_OK && pEm != 0 ) // In this case pEm is != NULL
{
pEm‑>Reset();
ULONG cFetched;
IMoniker* pM = 0;
while( pEm‑>Next(1, &pM, &cFetched) == S_OK && pM != 0 )
{
std::wstring str;
if( SUCCEEDED( extractFriendlyName( pM, str ) )
{
// str contains the friendly name of the filter
// pM‑>BindToObject creates the filter
std::wcout << str << std::endl;
}
pM‑>Release();
}
pEm‑>Release();
}
pCreateDevEnum‑>Release();
return rval;
}
The following call enumerates all video compressors to the console :
enumerateDShowFilterList( CLSID_VideoCompressorCategory );
The MSDN page Filter Categories lists all other 'official' categories.
I hope that is a good starting point for you.
方法 2:
The answer above doesn't account for decompressors. There is no CLSID_VideoDecompressorCategory. Is the are a way to ask a filter if it is a video decompressor?
Not that I know of.
Most filters in this list are codecs, so contain both a encoder and decoder.
The filters in the
CLSID_ActiveMovieCategories
are wrappers around the VfW filters installed.
(Some software companies create their own categories, so there may be 'non official' categories on some machines)
If you want to see all installed categories, use GraphEdit which is supplied with the DirectShow SDK.
GraphEdit itself is a great tool to see what DirectShow does under the hood. So maybe that may be a source of more information about the filters (and their interactions) on your system.
方法 3:
Another point I forgot.
The Windows Media Foundation is a toolkit for using WMV/WMA. It does not provide all things that DirectShow supports. It is really only a SDK for Windows Media. There are bindings in WMV/WMA to DirectShow, so that you can use WM* files/streams in DirectShow applications.
(by Nick Haddad、Christopher、Christopher、Christopher)