@ryou1128

Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

自作Directshowプレイヤー 再生できない

VS2022で自作のDirectShowビデオプレイヤー作ってます。

コードはこんな感じです。

dshowはどこにもありませんでしたが動くみたいです。

VideoPlayer.cpp


#include "VideoPlayer.h"
#include <Shlobj.h>
#include <dshow.h>
#include <dvdmedia.h>
#include <thread>
#include <strsafe.h>

// LAV FiltersCLSIDを定義
static const GUID CLSID_LAVSplitter =
{ 0x171252A0, 0x8820, 0x4AFE, { 0x9D, 0xF8, 0x5C, 0x92, 0xB2, 0xD6, 0x6B, 0x04 } };
static const GUID CLSID_LAVVideoDecoder =
{ 0xEE30215D, 0x164F, 0x4A92, { 0xA4, 0xEB, 0x9D, 0x4C, 0x13, 0x39, 0x0F, 0x9F } };
static const GUID CLSID_LAVAudioDecoder =
{ 0xE8E73B6B, 0x4CB3, 0x44A4, { 0xBE, 0x99, 0x4F, 0x7B, 0xCB, 0x96, 0xE4, 0x91 } };

#define TIMER_STREAMPOSPOLLER 1
#define WM_FILE_OPENED (WM_APP + 1)

// デバッグ出力用の関数
void DebugMsg(const wchar_t* format, ...)
{
    wchar_t buffer[1024];
    va_list args;
    va_start(args, format);
    StringCbVPrintfW(buffer, sizeof(buffer), format, args);
    va_end(args);
    OutputDebugStringW(buffer);
}

// DirectShow のエラー情報を取得する関数
void GetDirectShowError(HRESULT hr, wchar_t* errorMsg, int errorMsgSize)
{
    DWORD_PTR args[1] = { (DWORD_PTR)hr };
    AMGetErrorTextW(hr, errorMsg, errorMsgSize);
    DebugMsg(L"DirectShow Error: 0x%08x - %s\n", hr, errorMsg);
}

VideoPlayer::VideoPlayer() : m_hwnd(NULL), m_pGraph(NULL), m_pControl(NULL), m_pWindow(NULL),
m_pSeeking(NULL), m_pBasicAudio(NULL), m_isPlaying(false), m_isFullScreen(false) {}

VideoPlayer::~VideoPlayer() {
    if (m_pControl) m_pControl->Release();
    if (m_pWindow) m_pWindow->Release();
    if (m_pSeeking) m_pSeeking->Release();
    if (m_pBasicAudio) m_pBasicAudio->Release();
    if (m_pGraph) m_pGraph->Release();
    CoUninitialize();
}

bool VideoPlayer::Initialize(HINSTANCE hInstance) {
    const wchar_t CLASS_NAME[] = L"Video Player";
    WNDCLASS wc = {};
    wc.lpfnWndProc = WindowProc;
    wc.hInstance = hInstance;
    wc.lpszClassName = CLASS_NAME;
    RegisterClass(&wc);

    m_hwnd = CreateWindowEx(
        0,
        CLASS_NAME,
        L"Video Player",
        WS_OVERLAPPEDWINDOW | WS_VISIBLE,
        CW_USEDEFAULT, CW_USEDEFAULT, 800, 600,
        NULL, NULL, hInstance, this
    );

    if (m_hwnd == NULL) return false;

    ShowWindow(m_hwnd, SW_SHOW);

    CoInitialize(NULL);
    HRESULT hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void**)&m_pGraph);
    if (FAILED(hr)) return false;

    hr = m_pGraph->QueryInterface(IID_IMediaControl, (void**)&m_pControl);
    if (FAILED(hr)) return false;

    hr = m_pGraph->QueryInterface(IID_IVideoWindow, (void**)&m_pWindow);
    if (FAILED(hr)) return false;

    hr = m_pGraph->QueryInterface(IID_IMediaSeeking, (void**)&m_pSeeking);
    if (FAILED(hr)) return false;

    hr = m_pGraph->QueryInterface(IID_IBasicAudio, (void**)&m_pBasicAudio);
    if (FAILED(hr)) return false;

    // タイマーの設定
    SetTimer(m_hwnd, TIMER_STREAMPOSPOLLER, 100, NULL);

    return true;
}

void VideoPlayer::Run() {
    MSG msg;
    BOOL bRet;
    while ((bRet = GetMessage(&msg, NULL, 0, 0)) != 0) {
        if (bRet == -1) {
            // エラー処理
            OutputDebugString(L"GetMessage failed\n");
            break;
        }
        else {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }

        // アイドル時の処理
        OnIdle();
    }
}

void VideoPlayer::OnIdle() {
    // ここにアイドル時の処理を追加
    // : 再生位置の更新、UI更新など
    UpdatePosition();
    UpdateUI();
}

void VideoPlayer::UpdatePosition() {
    if (m_pSeeking && m_isPlaying) {
        LONGLONG current;
        m_pSeeking->GetCurrentPosition(&current);
        // ここで現在の再生位置を使って何かを行う
        // : シークバーの更新など
        UpdateSeekBar(current);
    }
}

void VideoPlayer::UpdateSeekBar(LONGLONG position) {
    // シークバーの更新処理
    // : 実際のシークバーの実装はUIフレームワークに依存します
    // ここでは簡単な例として、コンソールに出力します
    double seconds = position / 10000000.0;
    wchar_t buffer[256];
    swprintf_s(buffer, L"Current position: %.2f seconds\n", seconds);
    OutputDebugString(buffer);
}

void VideoPlayer::UpdateUI() {
    // UIの更新処理
    // : 再生/一時停止ボタンの状態更新、音量表示の更新など
    InvalidateRect(m_hwnd, NULL, FALSE);
}

LRESULT CALLBACK VideoPlayer::WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
    VideoPlayer* pThis = NULL;
    if (uMsg == WM_NCCREATE) {
        CREATESTRUCT* pCreate = (CREATESTRUCT*)lParam;
        pThis = (VideoPlayer*)pCreate->lpCreateParams;
        SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)pThis);
    }
    else {
        pThis = (VideoPlayer*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
    }
    if (pThis) {
        return pThis->HandleMessage(hwnd, uMsg, wParam, lParam);
    }
    else {
        return DefWindowProc(hwnd, uMsg, wParam, lParam);
    }
}

LRESULT VideoPlayer::HandleMessage(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
    switch (uMsg) {
    case WM_PAINT:
        OnPaint();
        return 0;
    case WM_COMMAND:
        OnCommand(LOWORD(wParam));
        return 0;
    case WM_TIMER:
        OnTimer(wParam);
        return 0;
    case WM_LBUTTONDOWN:
        OutputDebugString(L"WM_LBUTTONDOWN received\n");
        if (!m_isPlaying) {
            OpenFile(NULL);
        }
        return 0;
    case WM_KEYDOWN:
        switch (wParam) {
        case VK_SPACE:
            TogglePlayPause();
            break;
        case VK_LEFT:
            Seek(-5);
            break;
        case VK_RIGHT:
            Seek(5);
            break;
        case VK_UP:
            AdjustVolume(100);
            break;
        case VK_DOWN:
            AdjustVolume(-100);
            break;
        case VK_RETURN:
            if (GetAsyncKeyState(VK_MENU) & 0x8000) {
                OutputDebugString(L"Alt+Enter pressed\n");
                ToggleFullScreen();
                return 0;
            }
            break;
        }
        return 0;
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    case WM_FILE_OPENED:
        OnFileOpened();
        return 0;
    }
    return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

void VideoPlayer::OnCommand(int id) {
    switch (id) {
    case ID_FILE_OPEN:
        OpenFile(NULL);
        break;
    case ID_PLAY_PAUSE:
        TogglePlayPause();
        break;
    default:
        // その他のコマンド
        break;
    }
}

void VideoPlayer::OnTimer(UINT_PTR nIDEvent) {
    switch (nIDEvent) {
    case TIMER_STREAMPOSPOLLER:
        UpdatePosition();
        break;
        // その他のタイマー処理
    }
}

void VideoPlayer::OpenFile(const wchar_t* fileName) {
    if (fileName == NULL) {
        OPENFILENAME ofn = { 0 };
        wchar_t szFile[260] = { 0 };
        ofn.lStructSize = sizeof(ofn);
        ofn.hwndOwner = m_hwnd;
        ofn.lpstrFile = szFile;
        ofn.nMaxFile = sizeof(szFile);
        ofn.lpstrFilter = L"All\0*.*\0Video Files\0*.AVI;*.MP4;*.WMV\0";
        ofn.nFilterIndex = 2;
        ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
        if (GetOpenFileName(&ofn) == TRUE) {
            fileName = szFile;
        }
        else {
            return;
        }
    }

    AsyncOpenFile(fileName);
}

void VideoPlayer::AsyncOpenFile(const wchar_t* fileName) {
    // 別スレッドでファイルを開く処理を実行
    std::thread([this, fileName]() {
        HRESULT hr = BuildGraph(fileName);
        if (SUCCEEDED(hr)) {
            // ファイルが開かれたことを通知
            PostMessage(m_hwnd, WM_FILE_OPENED, 0, 0);
        }
        else {
            HandleError(hr, L"Failed to open file");
        }
        }).detach();
}

void VideoPlayer::OnFileOpened() {
    m_pWindow->put_Owner((OAHWND)m_hwnd);
    m_pWindow->put_WindowStyle(WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN);
    RECT rc;
    GetClientRect(m_hwnd, &rc);
    m_pWindow->SetWindowPosition(0, 0, rc.right, rc.bottom);
    m_pWindow->put_Visible(OATRUE);
    m_pWindow->SetWindowForeground(OATRUE);

    m_pControl->Run();
    m_isPlaying = true;
}

void VideoPlayer::HandleError(HRESULT hr, const wchar_t* operation) {
    if (FAILED(hr)) {
        wchar_t errorMsg[512];
        wchar_t errorDesc[256];
        AMGetErrorText(hr, errorDesc, 256);
        swprintf_s(errorMsg, L"%s failed.\nError code: 0x%08x\nDescription: %s", operation, hr, errorDesc);

        if (hr == VFW_E_NOT_FOUND) {
            wcscat_s(errorMsg, L"\n\nThis error often occurs when a required codec or filter is not installed.");
            wcscat_s(errorMsg, L"\nPlease ensure you have the necessary codecs installed on your system.");
        }

        MessageBox(m_hwnd, errorMsg, L"Error", MB_OK | MB_ICONERROR);

        // デバッグ出力
        OutputDebugString(errorMsg);
    }
}

void VideoPlayer::TogglePlayPause() {
    if (m_isPlaying) {
        m_pControl->Pause();
    }
    else {
        m_pControl->Run();
    }
    m_isPlaying = !m_isPlaying;
}

void VideoPlayer::Seek(long seconds) {
    if (m_pSeeking) {
        LONGLONG current;
        m_pSeeking->GetCurrentPosition(&current);
        current += seconds * 10000000; // 100-nanosecond units
        m_pSeeking->SetPositions(&current, AM_SEEKING_AbsolutePositioning, NULL, AM_SEEKING_NoPositioning);
    }
}

void VideoPlayer::AdjustVolume(long delta) {
    if (m_pBasicAudio) {
        long volume;
        m_pBasicAudio->get_Volume(&volume);
        volume = max(-10000, min(0, volume + delta));
        m_pBasicAudio->put_Volume(volume);
    }
}

void VideoPlayer::ToggleFullScreen() {
    m_isFullScreen = !m_isFullScreen;
    if (m_isFullScreen) {
        GetWindowRect(m_hwnd, &m_windowedRect);
        MONITORINFO mi = { sizeof(mi) };
        if (GetMonitorInfo(MonitorFromWindow(m_hwnd, MONITOR_DEFAULTTONEAREST), &mi)) {
            SetWindowLong(m_hwnd, GWL_STYLE, WS_POPUP | WS_VISIBLE);
            SetWindowPos(m_hwnd, HWND_TOP,
                mi.rcMonitor.left, mi.rcMonitor.top,
                mi.rcMonitor.right - mi.rcMonitor.left,
                mi.rcMonitor.bottom - mi.rcMonitor.top,
                SWP_NOOWNERZORDER | SWP_FRAMECHANGED);
        }
    }
    else {
        SetWindowLong(m_hwnd, GWL_STYLE, WS_OVERLAPPEDWINDOW | WS_VISIBLE);
        SetWindowPos(m_hwnd, NULL,
            m_windowedRect.left, m_windowedRect.top,
            m_windowedRect.right - m_windowedRect.left,
            m_windowedRect.bottom - m_windowedRect.top,
            SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_FRAMECHANGED);
    }

    if (m_pWindow) {
        RECT rc;
        GetClientRect(m_hwnd, &rc);
        m_pWindow->SetWindowPosition(0, 0, rc.right, rc.bottom);
        m_pWindow->put_FullScreenMode(m_isFullScreen ? OATRUE : OAFALSE);
    }
}

HRESULT VideoPlayer::AddFilterByCLSID(const GUID& clsid, IBaseFilter** ppF, LPCWSTR wszName) {
    *ppF = nullptr;
    IBaseFilter* pFilter = nullptr;
    HRESULT hr = CoCreateInstance(clsid, nullptr, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void**)&pFilter);
    if (FAILED(hr)) {
        return hr;
    }

    hr = m_pGraph->AddFilter(pFilter, wszName);
    if (FAILED(hr)) {
        pFilter->Release();
        return hr;
    }

    *ppF = pFilter;
    return S_OK;
}
HRESULT VideoPlayer::ConnectFilters(IBaseFilter* pSource, IBaseFilter* pDest) {
    IPin* pOut = NULL;
    IPin* pIn = NULL;
    HRESULT hr = S_OK;

    // ソースフィルタの未接続の出力ピンを取得
    pOut = GetUnconnectedPin(pSource, PINDIR_OUTPUT);
    if (!pOut) return E_FAIL;

    // デスティネーションフィルタの未接続の入力ピンを取得
    pIn = GetUnconnectedPin(pDest, PINDIR_INPUT);
    if (!pIn) {
        pOut->Release();
        return E_FAIL;
    }

    // ピンを接続
    hr = m_pGraph->Connect(pOut, pIn);
    pOut->Release();
    pIn->Release();

    return hr;
}

IPin* VideoPlayer::GetUnconnectedPin(IBaseFilter* pFilter, PIN_DIRECTION PinDir) {
    IEnumPins* pEnum = NULL;
    IPin* pPin = NULL;
    HRESULT hr = pFilter->EnumPins(&pEnum);
    if (FAILED(hr)) return NULL;

    while (pEnum->Next(1, &pPin, NULL) == S_OK) {
        PIN_DIRECTION ThisPinDir;
        pPin->QueryDirection(&ThisPinDir);
        if (ThisPinDir == PinDir) {
            IPin* pTmp = NULL;
            hr = pPin->ConnectedTo(&pTmp);
            if (SUCCEEDED(hr)) {
                pTmp->Release();
            }
            else {
                pEnum->Release();
                return pPin;
            }
        }
        pPin->Release();
    }
    pEnum->Release();
    return NULL;
}

void VideoPlayer::EnumerateFilters() {
    IEnumFilters* pEnum = NULL;
    IBaseFilter* pFilter = NULL;
    ULONG cFetched;

    m_filterList.clear();

    HRESULT hr = m_pGraph->EnumFilters(&pEnum);
    if (FAILED(hr)) return;

    while (pEnum->Next(1, &pFilter, &cFetched) == S_OK) {
        FILTER_INFO filterInfo;
        hr = pFilter->QueryFilterInfo(&filterInfo);
        if (SUCCEEDED(hr)) {
            m_filterList.push_back(filterInfo.achName);
            filterInfo.pGraph->Release();
        }
        pFilter->Release();
    }
    pEnum->Release();
}

void VideoPlayer::DebugFilterGraph() {
    IEnumFilters* pEnum = NULL;
    IBaseFilter* pFilter = NULL;
    HRESULT hr = m_pGraph->EnumFilters(&pEnum);
    if (FAILED(hr)) {
        DebugMsg(L"Failed to enumerate filters: 0x%08x\n", hr);
        return;
    }

    while (pEnum->Next(1, &pFilter, NULL) == S_OK) {
        FILTER_INFO filterInfo;
        hr = pFilter->QueryFilterInfo(&filterInfo);
        if (SUCCEEDED(hr)) {
            DebugMsg(L"Filter: %s\n", filterInfo.achName);
            filterInfo.pGraph->Release();

            IEnumPins* pEnumPins = NULL;
            IPin* pPin = NULL;
            hr = pFilter->EnumPins(&pEnumPins);
            if (SUCCEEDED(hr)) {
                while (pEnumPins->Next(1, &pPin, NULL) == S_OK) {
                    PIN_INFO pinInfo;
                    hr = pPin->QueryPinInfo(&pinInfo);
                    if (SUCCEEDED(hr)) {
                        DebugMsg(L"  Pin: %s (%s)\n", pinInfo.achName,
                            (pinInfo.dir == PINDIR_INPUT) ? L"Input" : L"Output");
                        pinInfo.pFilter->Release();

                        IPin* pConnectedPin = NULL;
                        hr = pPin->ConnectedTo(&pConnectedPin);
                        if (SUCCEEDED(hr)) {
                            PIN_INFO connectedPinInfo;
                            hr = pConnectedPin->QueryPinInfo(&connectedPinInfo);
                            if (SUCCEEDED(hr)) {
                                DebugMsg(L"    Connected to: %s on %s\n",
                                    connectedPinInfo.achName,
                                    connectedPinInfo.pFilter ? connectedPinInfo.achName : L"Unknown");
                                connectedPinInfo.pFilter->Release();
                            }
                            pConnectedPin->Release();
                        }
                        else {
                            DebugMsg(L"    Not connected\n");
                        }
                    }
                    pPin->Release();
                }
                pEnumPins->Release();
            }
        }
        pFilter->Release();
    }
    pEnum->Release();
}

HRESULT VideoPlayer::BuildGraph(const wchar_t* fileName) {
    HRESULT hr;
    wchar_t errorMsg[256];

    DebugMsg(L"Building graph for file: %s\n", fileName);

    // 既存のフィルタグラフをクリア
    if (m_pGraph) {
        m_pGraph->Release();
        m_pGraph = NULL;
    }

    // 新しいフィルタグラフを作成
    hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void**)&m_pGraph);
    if (FAILED(hr)) {
        GetDirectShowError(hr, errorMsg, sizeof(errorMsg) / sizeof(wchar_t));
        DebugMsg(L"Failed to create FilterGraph: %s\n", errorMsg);
        return hr;
    }

    // LAV Splitter, LAV Video Decoder, LAV Audio Decoderを追加
    IBaseFilter* pLAVSplitter = NULL, * pLAVVideoDecoder = NULL, * pLAVAudioDecoder = NULL;

    hr = AddFilterByCLSID(CLSID_LAVSplitter, &pLAVSplitter, L"LAV Splitter");
    if (FAILED(hr)) {
        GetDirectShowError(hr, errorMsg, sizeof(errorMsg) / sizeof(wchar_t));
        DebugMsg(L"Failed to load LAVSplitter: %s\n", errorMsg);
        return hr;
    }

    hr = AddFilterByCLSID(CLSID_LAVVideoDecoder, &pLAVVideoDecoder, L"LAV Video Decoder");
    if (FAILED(hr)) {
        GetDirectShowError(hr, errorMsg, sizeof(errorMsg) / sizeof(wchar_t));
        DebugMsg(L"Failed to load LAVVideoDecoder: %s\n", errorMsg);
        return hr;
    }

    hr = AddFilterByCLSID(CLSID_LAVAudioDecoder, &pLAVAudioDecoder, L"LAV Audio Decoder");
    if (FAILED(hr)) {
        GetDirectShowError(hr, errorMsg, sizeof(errorMsg) / sizeof(wchar_t));
        DebugMsg(L"Failed to load LAVAudioDecoder: %s\n", errorMsg);
        return hr;
    }

    // ファイルソースフィルタを追加
    IBaseFilter* pSource = NULL;
    hr = m_pGraph->AddSourceFilter(fileName, L"Source", &pSource);
    if (FAILED(hr)) {
        GetDirectShowError(hr, errorMsg, sizeof(errorMsg) / sizeof(wchar_t));
        DebugMsg(L"Failed to add source filter: %s\n", errorMsg);
        return hr;
    }

    // フィルタを接続
    hr = ConnectFilters(pSource, pLAVSplitter);
    if (FAILED(hr)) {
        GetDirectShowError(hr, errorMsg, sizeof(errorMsg) / sizeof(wchar_t));
        DebugMsg(L"Failed to connect Source to LAVSplitter: %s\n", errorMsg);
        return hr;
    }

    hr = ConnectFilters(pLAVSplitter, pLAVVideoDecoder);
    if (FAILED(hr)) {
        GetDirectShowError(hr, errorMsg, sizeof(errorMsg) / sizeof(wchar_t));
        DebugMsg(L"Failed to connect LAVSplitter to LAVVideoDecoder: %s\n", errorMsg);
        return hr;
    }

    hr = ConnectFilters(pLAVSplitter, pLAVAudioDecoder);
    if (FAILED(hr)) {
        GetDirectShowError(hr, errorMsg, sizeof(errorMsg) / sizeof(wchar_t));
        DebugMsg(L"Failed to connect LAVSplitter to LAVAudioDecoder: %s\n", errorMsg);
        return hr;
    }

    // レンダラーを追加して接続
    hr = m_pGraph->Render(GetUnconnectedPin(pLAVVideoDecoder, PINDIR_OUTPUT));
    if (FAILED(hr)) {
        GetDirectShowError(hr, errorMsg, sizeof(errorMsg) / sizeof(wchar_t));
        DebugMsg(L"Failed to render video output: %s\n", errorMsg);
        return hr;
    }

    hr = m_pGraph->Render(GetUnconnectedPin(pLAVAudioDecoder, PINDIR_OUTPUT));
    if (FAILED(hr)) {
        GetDirectShowError(hr, errorMsg, sizeof(errorMsg) / sizeof(wchar_t));
        DebugMsg(L"Failed to render audio output: %s\n", errorMsg);
        return hr;
    }

    // 必要なインターフェースを取得
    hr = m_pGraph->QueryInterface(IID_IMediaControl, (void**)&m_pControl);
    if (FAILED(hr)) {
        GetDirectShowError(hr, errorMsg, sizeof(errorMsg) / sizeof(wchar_t));
        DebugMsg(L"Failed to get IMediaControl: %s\n", errorMsg);
        return hr;
    }

    hr = m_pGraph->QueryInterface(IID_IVideoWindow, (void**)&m_pWindow);
    if (FAILED(hr)) {
        GetDirectShowError(hr, errorMsg, sizeof(errorMsg) / sizeof(wchar_t));
        DebugMsg(L"Failed to get IVideoWindow: %s\n", errorMsg);
        return hr;
    }

    hr = m_pGraph->QueryInterface(IID_IMediaSeeking, (void**)&m_pSeeking);
    if (FAILED(hr)) {
        GetDirectShowError(hr, errorMsg, sizeof(errorMsg) / sizeof(wchar_t));
        DebugMsg(L"Failed to get IMediaSeeking: %s\n", errorMsg);
        return hr;
    }

    hr = m_pGraph->QueryInterface(IID_IBasicAudio, (void**)&m_pBasicAudio);
    if (FAILED(hr)) {
        GetDirectShowError(hr, errorMsg, sizeof(errorMsg) / sizeof(wchar_t));
        DebugMsg(L"Failed to get IBasicAudio: %s\n", errorMsg);
        return hr;
    }

    // フィルタグラフの状態を確認
    DebugFilterGraph();

    return S_OK;
}

void VideoPlayer::OnPaint() {
    PAINTSTRUCT ps;
    HDC hdc = BeginPaint(m_hwnd, &ps);
    // ここに描画コードを追加
    // : 再生時間の表示、シークバーの描画など
    if (m_pSeeking) {
        LONGLONG duration;
        m_pSeeking->GetDuration(&duration);
        LONGLONG current;
        m_pSeeking->GetCurrentPosition(&current);

        wchar_t timeStr[100];
        swprintf_s(timeStr, L"Time: %02d:%02d:%02d / %02d:%02d:%02d",
            (int)(current / 10000000) / 3600,
            ((int)(current / 10000000) % 3600) / 60,
            (int)(current / 10000000) % 60,
            (int)(duration / 10000000) / 3600,
            ((int)(duration / 10000000) % 3600) / 60,
            (int)(duration / 10000000) % 60);
        TextOut(hdc, 10, 10, timeStr, static_cast<int>(wcslen(timeStr)));
    }
    EndPaint(m_hwnd, &ps);
}



VideoPlayer.h


#ifndef VIDEOPLAYER_H
#define VIDEOPLAYER_H

#include <windows.h>
#include <dshow.h>
#include <vector>
#include <string>

#define ID_FILE_OPEN 1001
#define ID_PLAY_PAUSE 1002

class VideoPlayer {
public:
    VideoPlayer();
    ~VideoPlayer();
    bool Initialize(HINSTANCE hInstance);
    void Run();

private:
    static LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
    LRESULT HandleMessage(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
    void OpenFile(const wchar_t* fileName);
    void TogglePlayPause();
    void Seek(long seconds);
    void AdjustVolume(long delta);
    void ToggleFullScreen();

    HRESULT BuildGraph(const wchar_t* fileName);
    HRESULT ConnectFilters(IBaseFilter* pSource, IBaseFilter* pDest);
    HRESULT AddFilterByCLSID(const GUID& clsid, IBaseFilter** ppF, LPCWSTR wszName);
    IPin* GetUnconnectedPin(IBaseFilter* pFilter, PIN_DIRECTION PinDir);
    void EnumerateFilters();
    void DebugFilterGraph();

    void OnIdle();
    void UpdatePosition();
    void UpdateSeekBar(LONGLONG position);
    void UpdateUI();
    void OnPaint();
    void OnCommand(int id);
    void OnTimer(UINT_PTR nIDEvent);
    void AsyncOpenFile(const wchar_t* fileName);
    void OnFileOpened();
    void HandleError(HRESULT hr, const wchar_t* operation);

    HWND m_hwnd;
    IGraphBuilder* m_pGraph;
    IMediaControl* m_pControl;
    IVideoWindow* m_pWindow;
    IMediaSeeking* m_pSeeking;
    IBasicAudio* m_pBasicAudio;
    bool m_isPlaying;
    bool m_isFullScreen;
    RECT m_windowedRect;

    std::vector<std::wstring> m_filterList;
    IMediaEventEx* m_pEvent;
};

#endif // VIDEOPLAYER_H
main.cpp
#include "VideoPlayer.h"
#include <windows.h>


int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    VideoPlayer player;
    if (player.Initialize(hInstance))
    {
        player.Run();
    }
    return 0;
}

このコードで動画プレイヤーを起動して動画を選ぶとerror.png

となり再生できません。
何が関係し何がおかしいのでしょうか。
ぜひ、教えてください。
LAVやFFdshowはあります。

環境
Win11
VS 2022のみ

0 likes

1Answer

詳しくは分かりませんが、再生しようとした動画に対応した codec が無い のではないでしょうか?

再生しようとした動画の圧縮形式はなんでしょうか?

ffmpegをインストールしているなら、ffmpeg -i ファイル名 で詳細を確認できます。

0Like

Comments

  1. @ryou1128

    Questioner

    返信ありがとうございます。
    h264 mp4ですね。m2tsも将来的には再生させたいです。

  2. @ryou1128

    Questioner

    コーデックファイルをルートに入れてもダメですね。。

Your answer might help someone💌