0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

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

Posted at

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

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

VideoPlayer.cpp

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

// LAV FiltersのCLSIDを定義
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
となり再生できません。
何が関係し何がおかしいのでしょうか。
ぜひ、教えてください。

環境
VS 2022のみ

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?