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(¤t);
// ここで現在の再生位置を使って何かを行う
// 例: シークバーの更新など
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(¤t);
current += seconds * 10000000; // 100-nanosecond units
m_pSeeking->SetPositions(¤t, 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(¤t);
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;
}
このコードで動画プレイヤーを起動して動画を選ぶと
となり再生できません。
何が関係し何がおかしいのでしょうか。
ぜひ、教えてください。
環境
VS 2022のみ