【问题标题】:Play FLAC via DirectShow通过 DirectShow 播放 FLAC
【发布时间】:2021-03-14 12:00:30
【问题描述】:

我想写一个简单的(只有一个 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, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (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", L"Async Reader Source", &ARS);
        hr = CoCreateInstance(CLSID_MPEG1Splitter, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void **)&AudioDecoderFilter);
        hr = player->AddFilter(AudioDecoderFilter, L"MPEG1Splitter");
    }

    IBaseFilter *PCM = NULL;
    hr = CoCreateInstance(CLSID_ACMWrapper, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void **)&PCM);
    hr = player->AddFilter(PCM, L"PCM");

    IBaseFilter *DSE = NULL;
    hr = CoCreateInstance(CLSID_DSoundRender, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (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, PINDIR_INPUT), NULL);
    //PCM -> DSE
    hr = GetPin(PCM, PINDIR_OUTPUT)->Connect(GetPin(DSE, PINDIR_INPUT), 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, CW_USEDEFAULT, 460, 240, NULL, NULL, hInstance, NULL);
    if (hwnd == NULL) { MessageBox(NULL, "Window Creation Failed!", "Error!", MB_ICONEXCLAMATION | MB_OK); return 0; }
    ShowWindow(hwnd, nCmdShow);
    UpdateWindow(hwnd);

    Player(false);

    while (GetMessage(&Msg, NULL, 0, 0) > 0)
    {
        TranslateMessage(&Msg);
        DispatchMessage(&Msg);
    }
    return Msg.wParam;
}

我使用的是 VS2015,原生 C++。

我也会尝试使用 LibFLAC,但我已经被困在那里无法构建,因为它抛出了数百个错误,我最终减少到不到 20 个,但几个小时后我已经放弃了痛苦。

https://github.com/xiph/flac

https://ftp.osuosl.org/pub/xiph/releases/oggdsf/

【问题讨论】:

  • 为什么不使用微软推荐的WASAPI播放音频?
  • 另外,为什么不直接从文件中获取 RAW 样本并编写一个简单的自定义转换例程?
  • Directshow 已过时这就是您使用 VisualStudio 2015 的原因。
  • 通常我编写我的应用程序以从 XP 运行到 Win10。据我所知,Wasapi 是与 Vista 一起出现的。这就是为什么我想使用 Directshow 来解决它。如何从 FLAC 中获取 RAW 样本? “简单的自定义转换例程”您可以链接到示例,看看它是什么样子的吗?

标签: c++ media-player directshow flac


【解决方案1】:

Windows 未附带 DirectShow 的 FLAC 解码器。因此,通过 DirectShow 播放 FLAC 音频的能力需要第三方解码器。如果您不想回复编解码器包,则需要将某些 FLAC 解码器与 DirectShow 接口捆绑在一起,或者在代码中实现解码器。 https://xiph.org/dshow 对我来说似乎是最好的第三方解码器选项,在 FLAC 库上实现 DirectShow 过滤器需要一些开发工作,这对于所讨论的任务来说可能是矫枉过正。

【讨论】:

  • 你没有写任何新东西。我知道你推荐的编解码器。如果您阅读了我的问题,我还链接了您在底部提到的编解码器并描述了为什么我不能使用它。
  • 关键是您必须在您认为无法使用的选项中进行选择。还有另一个:Windows 具有媒体基础转换形式的 FLAC 解码器,您可以在其上开发 DirectShow 包装器并以这种方式启用解码。您不太可能采用这种方式,因为它看起来比链接您已经遇到问题的 libflac 更复杂。
  • 感谢您详细说明我不能做什么,但我知道这些,不会帮助我解决问题。是的,我不能使用这些库,这就是我打开这个问题帖子的原因。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多