DirectShow mp4 проигрыватель

Рейтинг: 0Ответов: 1Опубликовано: 23.04.2023

В наличии винда Win7 x64 и студия VS2019.

Давно хочу увидеть какой-то живой пример исходников mp4 плеера. DirectShow вроде как должен уметь показывать видео.

У microsoft даже есть туториал DirectShow проигрывателя, там можно добавлять свои фильтры.

Кое-как получилось проиграть видео, но первый кадр ещё ничего себе, а остальное квадратиками. Некоторые видео более менее ничего себе, но большинство очень плохое качество. Какие фильтры для mp4+h264 (самые распространённые mp4) нужно подключить, и какие у них GUID?

С нуля понятно такую программу не напишешь, нашёл у microsoft примеры, скачал https://github.com/microsoft/Windows-classic-samples их.

Там в папке Samples\Win7Samples\Multimedia\DirectShow\Players\DShowPlayer Есть проэкт DShowPlayer.sln. Часть либ он берет с папки Samples\Win7Samples\Multimedia\DirectShow\common

Удалось с 3-го раза подружить между собой все *.cpp и *.h Чего то не сразу дошло что папку common нужно тоже перекопировать на два уровня ниже. Проэкт поднялся. AVI проигрывает нормально, а mp4 не играеет вообще никак.

Судя по сообщениям "не найдена комбинация фильтвов", понимаю что проблема с кодеками. Зная что есть старенький kmplayer который всё играет, нашел как ax-фильтр подкинуть в DirectShow. По моей логике - сначало нужен сплитер, который разделит потоки на аудио-видео. Думаю... это mp4splitter.ax. Нагуглил его GUID и как добавить фильтр. Открываем DShowPlayer.cpp, и допиливаем его, как ниже

// DShowPlayer.cpp: Implements DirectShow playback functionality.
// ....
// Находим метод
HRESULT DShowPlayer::OpenFile(const WCHAR* sFileName)
{
HRESULT hr = S_OK;
IBaseFilter *pSource = NULL;
// Create a new filter graph. (This also closes the old one, if any.)
hr = InitializeGraph(); 
// Add the source filter to the graph.
if (SUCCEEDED(hr))
{
    hr = m_pGraph->AddSourceFilter(sFileName, NULL, &pSource);
}
// Добавляем сюда кодек
IUnknown* pUnk = 0; // Переменная для кодека
IUnknown* pUnk2 = 0;
GUID CLSID_MPEG4Splitter; // Гуид для кодека
CLSIDFromString(L"{61F47056-E400-43D3-AF1E-AB7DFFD4C4AD}", &CLSID_MPEG4Splitter); // Может можно проще, так точно работает
hr = CreateObjectFromPath(TEXT("mp4splitter.ax"), CLSID_MPEG4Splitter, &pUnk); // Загружаем фильтр
if (pUnk != 0) hr = pUnk->QueryInterface(IID_IBaseFilter, (void**)&pUnk2); // Приводим к нужному интерфейсу
if (pUnk2 != 0)
    m_pGraph->AddFilter((IBaseFilter*)pUnk2, L"mp4splitter"); // Добавляем фильтр
// Остальное без изменений

Дальше... тут https://stackoverflow.com/questions/11191996/using-a-directshow-filter-without-registering-it-via-a-private-cocreateinstance забираем метод CreateObjectFromPath и добавляем его в DShowPlayer.cpp

typedef HRESULT(STDAPICALLTYPE* FN_DLLGETCLASSOBJECT)(REFCLSID clsid, REFIID iid, void** ppv);

HRESULT CreateObjectFromPath(TCHAR* pPath, REFCLSID clsid, IUnknown** ppUnk)
{
    // load the target DLL directly
    HMODULE lib = LoadLibrary(pPath);
    if (!lib)
    {
        return HRESULT_FROM_WIN32(GetLastError());
    }

    // the entry point is an exported function
    FN_DLLGETCLASSOBJECT fn = (FN_DLLGETCLASSOBJECT)GetProcAddress(lib, "DllGetClassObject");
    if (fn == NULL)
    {
        return HRESULT_FROM_WIN32(GetLastError());
    }

    // create a class factory
    IUnknown * pUnk;
    HRESULT hr = fn(clsid, IID_IUnknown, (void**)(IUnknown**)&pUnk);
    if (SUCCEEDED(hr))
    {
        IClassFactory * pCF = (IClassFactory*) pUnk;
        if (pCF == NULL)
        {
            hr = E_NOINTERFACE;
        }
        else
        {
            // ask the class factory to create the object
            hr = pCF->CreateInstance(NULL, IID_IUnknown, (void**)ppUnk);
        }
    }
    return hr;
}

После таких махинаций mp4 начало некрасиво, но кое-как проигрывать.

Осталось понять какие ".ax" нужно взять, и какие guid кодеков из ax нужно добавить.

Ответы

▲ 0Принят

В один день вдруг всё заработало. И я понял в чем была проблема.

Есть есть разделение windows на две ветки по разрядности x86, и x64

В windows x86, вероятнее всего код заработает (не проверял, будет возможность проверю).

В windows x64 (точнее win7 x64) ситуация следующая. Если код собрать x86 - то программа не читает видео, поддерживается только старое mp2(avi). Если код собрать под x64, то всё нормально работает, mp4 проигрывает, кодеки интегрированые с виндой подхватываются. Думаю этот баг может проявиться в том, что какие-то небольшие старые x86 игры могут перестать играть ролики через DirectShow (теоретически).

Т.е. если у вас не работает этот код шаг 1 - проверить кодеки, шаг 2 - проверить разрядность сборки и винды.