问题描述
我想写一个简单的(只有一个 exe)音乐播放器。 如果我想播放 mp3,播放器可以工作,但如果我想使用 MadFLAC 过滤器,则播放器不起作用。 我无法连接 MadFLAC 引脚。始终删除 0x80040207 错误。 (我认为,MadFLAC 过滤器已正确加载,我可以毫无错误地添加到 GraphBuilder 并在 EnumFilters 中查看。)
我不坚持使用 MadFLAC。我对所有其他选项感兴趣,我可以通过 DirectShow 播放 FLAC 文件,而无需将编解码器包安装到客户端 PC。
这是我的简化代码:
#include <windows.h>
#include <strmif.h>
#include <control.h>
#include <uuids.h>
#pragma comment(lib,"strmiids.lib")
IPin* GetPin(IBaseFilter *bFilter,PIN_DIRECTION pindir)
{
IEnumPins *EnumPin;
bFilter->EnumPins(&EnumPin);
unsigned long int num;
IPin *TempPin = NULL;
do {
EnumPin->Next(1,&TempPin,&num);
if (num != 0)
{
PIN_INFO PinInfo;
TempPin->QueryPinInfo(&PinInfo);
if (PinInfo.dir == pindir) break;
}
} while (num != 0);
return TempPin;
}
typedef HRESULT __stdcall DLLGETCLASSOBJECT(REFCLSID rclsid,REFIID riid,void **ppv);
HRESULT CreateFilterFromFile(HINSTANCE hLibInst,GUID TGUID,void **Filter) {
IClassFactory * ClassFactory;
HRESULT Result = S_FALSE;
FARPROC func;
func = GetProcAddress(hLibInst,"DllGetClassObject");
if (func != NULL)
{
IClassFactory *classFactory;
DLLGETCLASSOBJECT *dllGetClassObject = (DLLGETCLASSOBJECT*)func;
Result = dllGetClassObject(TGUID,IID_IClassFactory,(void**)&classFactory);
if (SUCCEEDED(Result))
{
Result = classFactory->CreateInstance(NULL,IID_IBaseFilter,Filter);
classFactory->Release();
}
}
return Result;
}
LRESULT CALLBACK WndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)
{
switch (msg)
{
case WM_CLOSE:
DestroyWindow(hwnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd,msg,wParam,lParam);
}
return 0;
}
void Player(bool isFlac) {
IGraphBuilder * player;
IMediaControl * mcontrol;
CoCreateInstance(CLSID_FilterGraph,NULL,CLSCTX_INPROC_SERVER,IID_IGraphBuilder,(void **)&player);
player->QueryInterface(IID_IMediaControl,(void **)&mcontrol);
IBaseFilter *ARS = NULL;
HRESULT hr = CoCreateInstance(CLSID_AsyncReader,(void **)&ARS);
IBaseFilter * AudioDecoderFilter = NULL;
if (isFlac) {
hr = player->AddSourceFilter(L"D:\\test.flac",L"Async Reader Source",&ARS);
GUID CLSID_MadFlacAudioDecoder;
CLSIDFromString(L"{6B257121-CBB6-46B3-ABFA-B14DFA98C4A6}",&CLSID_MadFlacAudioDecoder);
HINSTANCE FHMPCAudioFilterInst = CoLoadLibrary(L"d:\\_MadFlac\\madFlac.ax",true);
if (FHMPCAudioFilterInst != 0) {
hr = CreateFilterFromFile(FHMPCAudioFilterInst,CLSID_MadFlacAudioDecoder,(void **)&AudioDecoderFilter);
if (AudioDecoderFilter != NULL) {
player->AddFilter(AudioDecoderFilter,L"MadFLAC Audio decoder (internal)");
}
}
}
else {
hr = player->AddSourceFilter(L"D:\\test.mp3",&ARS);
hr = CoCreateInstance(CLSID_MPEG1Splitter,(void **)&AudioDecoderFilter);
hr = player->AddFilter(AudioDecoderFilter,L"MPEG1Splitter");
}
IBaseFilter *PCM = NULL;
hr = CoCreateInstance(CLSID_ACMWrapper,(void **)&PCM);
hr = player->AddFilter(PCM,L"PCM");
IBaseFilter *DSE = NULL;
hr = CoCreateInstance(CLSID_DSoundRender,(void **)&DSE);
hr = player->AddFilter(DSE,L"Direct Renderer");
//ARS -> AdioDecoder
hr = GetPin(ARS,PINDIR_OUTPUT)->Connect(GetPin(AudioDecoderFilter,PINDIR_INPUT),NULL);
//If I use MadFLAC filter this hresult is 0x80040207
if (FAILED(hr)) MessageBoxA(NULL,"There is no common media type between these pins.","Error",NULL);
//AudioDecoderFilter -> PCM
hr = GetPin(AudioDecoderFilter,PINDIR_OUTPUT)->Connect(GetPin(PCM,NULL);
//PCM -> DSE
hr = GetPin(PCM,PINDIR_OUTPUT)->Connect(GetPin(DSE,NULL);
//ListGraph(player);
mcontrol->Run();
}
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow)
{
WNDCLASSEX wc;
HWND hwnd;
MSG Msg;
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = 0;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL,IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL,IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.lpszMenuName = NULL;
wc.lpszClassName = "Teszt";
wc.hIconSm = LoadIcon(NULL,IDI_APPLICATION);
if (!RegisterClassEx(&wc)) { MessageBox(NULL,"Window Registration Failed!","Error!",MB_ICONEXCLAMATION | MB_OK); return 0; }
hwnd = CreateWindowEx(WS_EX_CLIENTEDGE,"Teszt","AppName",WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU,CW_USEDEFAULT,460,240,hInstance,NULL);
if (hwnd == NULL) { MessageBox(NULL,"Window Creation Failed!",MB_ICONEXCLAMATION | MB_OK); return 0; }
ShowWindow(hwnd,nCmdShow);
UpdateWindow(hwnd);
Player(false);
while (GetMessage(&Msg,0) > 0)
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
return Msg.wParam;
}
我使用 VS2015,原生 C++。
我也会尝试使用 LibFLAC,但我已经被困在那里无法构建,因为它抛出了数百个错误,我最终减少到不到 20 个,但几个小时后我已经放弃了痛苦。
https://ftp.osuosl.org/pub/xiph/releases/oggdsf/
解决方法
Windows 未附带用于 DirectShow 的 FLAC 解码器。因此,通过 DirectShow 播放 FLAC 音频需要第三方解码器。如果您不想回复编解码器包,则需要将某些 FLAC 解码器与 DirectShow 接口捆绑在一起,或者在代码中实现解码器。 https://xiph.org/dshow 对我来说似乎是最好的第三方解码器选项,在 FLAC 库上实现 DirectShow 过滤器需要一些开发工作,这对于相关任务来说可能是一种矫枉过正。