From 4d59c6a933ae28fb5e00c6461bb10bdfa8defe5f Mon Sep 17 00:00:00 2001 From: APTX Date: Thu, 14 Feb 2013 14:27:40 +0100 Subject: [PATCH] Aniplayer2, Qt5, no phonon --- .gitignore | 76 +++ aniplayer2.pro | 8 + aniplayer2/aniplayer.cpp | 43 ++ aniplayer2/aniplayer.h | 49 ++ aniplayer2/aniplayer2.pri | 5 + aniplayer2/aniplayer2.pro | 25 + aniplayer2/aniplayer2_global.h | 12 + aniplayer2/videowidget.cpp | 6 + aniplayer2/videowidget.h | 19 + aniplayer2_dshow/aniplayer2_dshow.pri | 5 + aniplayer2_dshow/aniplayer2_dshow.pro | 29 ++ aniplayer2_dshow/aniplayer2_dshow_global.h | 12 + aniplayer2_dshow/aniplayerdshow.cpp | 63 +++ aniplayer2_dshow/aniplayerdshow.h | 36 ++ aniplayer2_dshow/aniplayerdshowinternal.cpp | 488 ++++++++++++++++++++ aniplayer2_dshow/aniplayerdshowinternal.h | 68 +++ aniplayer2_dshow/videowidgetdshow.cpp | 19 + aniplayer2_dshow/videowidgetdshow.h | 30 ++ config.pri | 0 player/main.cpp | 11 + player/mainwindow.cpp | 32 ++ player/mainwindow.h | 26 ++ player/mainwindow.ui | 24 + player/player.pro | 20 + 24 files changed, 1106 insertions(+) create mode 100644 .gitignore create mode 100644 aniplayer2.pro create mode 100644 aniplayer2/aniplayer.cpp create mode 100644 aniplayer2/aniplayer.h create mode 100644 aniplayer2/aniplayer2.pri create mode 100644 aniplayer2/aniplayer2.pro create mode 100644 aniplayer2/aniplayer2_global.h create mode 100644 aniplayer2/videowidget.cpp create mode 100644 aniplayer2/videowidget.h create mode 100644 aniplayer2_dshow/aniplayer2_dshow.pri create mode 100644 aniplayer2_dshow/aniplayer2_dshow.pro create mode 100644 aniplayer2_dshow/aniplayer2_dshow_global.h create mode 100644 aniplayer2_dshow/aniplayerdshow.cpp create mode 100644 aniplayer2_dshow/aniplayerdshow.h create mode 100644 aniplayer2_dshow/aniplayerdshowinternal.cpp create mode 100644 aniplayer2_dshow/aniplayerdshowinternal.h create mode 100644 aniplayer2_dshow/videowidgetdshow.cpp create mode 100644 aniplayer2_dshow/videowidgetdshow.h create mode 100644 config.pri create mode 100644 player/main.cpp create mode 100644 player/mainwindow.cpp create mode 100644 player/mainwindow.h create mode 100644 player/mainwindow.ui create mode 100644 player/player.pro diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2f6642b --- /dev/null +++ b/.gitignore @@ -0,0 +1,76 @@ +# This file is used to ignore files which are generated +# ---------------------------------------------------------------------------- + +*~ +*.a +*.core +*.moc +*.o +*.obj +*.orig +*.rej +*.so +*_pch.h.cpp +*_resource.rc +*.qm +.#* +*.*# +core +.qmake.cache +tags +.DS_Store +*.debug +Makefile* +*.prl +*.app +moc_*.cpp +ui_*.h +qrc_*.cpp + +# qtcreator generated files +*.pro.user +*.pro.user.* +*.autosave + +# xemacs temporary files +*.flc + +# Vim temporary files +.*.swp + +# Visual Studio generated files +*.ib_pdb_index +*.idb +*.ilk +*.pdb +*.sln +*.suo +*.vcproj +*vcproj.*.*.user +*.ncb +*.exp + +# MinGW generated files +*.Debug +*.Release + +# Directories to ignore +# --------------------- + +build +debug +release +lib/qtsingleapplication/lib +lib/qtsingleapplication/examples +lib/qtsingleapplication/doc +.tmp +qtc-gdbmacros + +# Binaries +# -------- +build/*.dll +build/*.lib +build/*.exe +build/*.so* + + diff --git a/aniplayer2.pro b/aniplayer2.pro new file mode 100644 index 0000000..83c1f96 --- /dev/null +++ b/aniplayer2.pro @@ -0,0 +1,8 @@ +TEMPLATE = subdirs +CONFIG += ordered + +include(config.pri) + +SUBDIRS += aniplayer2 +win32: SUBDIRS += aniplayer2_dshow +SUBDIRS += player diff --git a/aniplayer2/aniplayer.cpp b/aniplayer2/aniplayer.cpp new file mode 100644 index 0000000..4937394 --- /dev/null +++ b/aniplayer2/aniplayer.cpp @@ -0,0 +1,43 @@ +#include "aniplayer.h" + + +AniPlayer::AniPlayer(QObject *parent) : QObject(parent), m_state(Stopped) +{ +} + +AniPlayer::~AniPlayer() +{ +} + +AniPlayer::State AniPlayer::state() const +{ + return m_state; +} + +void AniPlayer::open(const QString &file) +{ + iopen(file); +} + +void AniPlayer::play() +{ + iplay(); +} + +void AniPlayer::pause() +{ + ipause(); +} + +void AniPlayer::stop() +{ + istop(); +} + +void AniPlayer::togglePause() +{ + if (m_state == Paused) + play(); + else + pause(); +} diff --git a/aniplayer2/aniplayer.h b/aniplayer2/aniplayer.h new file mode 100644 index 0000000..6601c6d --- /dev/null +++ b/aniplayer2/aniplayer.h @@ -0,0 +1,49 @@ +#ifndef ANIPLAYER_H +#define ANIPLAYER_H + +#include "aniplayer2_global.h" + +#include +#include + +class VideoWidget; + +class ANIPLAYER2SHARED_EXPORT AniPlayer : public QObject +{ + Q_OBJECT +public: + enum State + { + Stopped, + Playing, + Paused, + Error + }; + + AniPlayer(QObject *parent = 0); + virtual ~AniPlayer(); + + virtual VideoWidget *videoWidget() = 0; + virtual void widgetChanged() = 0; + + State state() const; + +public slots: + void open(const QString &file); + void play(); + void pause(); + void stop(); + + void togglePause(); + + +protected: + virtual void iopen(const QString &file) = 0; + virtual void iplay() = 0; + virtual void ipause() = 0; + virtual void istop() = 0; + + State m_state; +}; + +#endif // ANIPLAYER_H diff --git a/aniplayer2/aniplayer2.pri b/aniplayer2/aniplayer2.pri new file mode 100644 index 0000000..7757fbb --- /dev/null +++ b/aniplayer2/aniplayer2.pri @@ -0,0 +1,5 @@ +INCLUDEPATH += $$PWD +INCLUDEPATH += $$PWD +DEPENDPATH += $$PWD +LIBS += -laniplayer2 +LIBS += -L$$PWD/../build diff --git a/aniplayer2/aniplayer2.pro b/aniplayer2/aniplayer2.pro new file mode 100644 index 0000000..05d613e --- /dev/null +++ b/aniplayer2/aniplayer2.pro @@ -0,0 +1,25 @@ +QT += core gui + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +TARGET = aniplayer2 +DESTDIR = ../build + +TEMPLATE = lib + +DEFINES += ANIPLAYER2_LIBRARY + +SOURCES += aniplayer.cpp + +HEADERS += aniplayer2_global.h \ + aniplayer.h\ + videowidget.h + + +HEADERS += \ + + +SOURCES += \ + videowidget.cpp + +include(../config.pri) diff --git a/aniplayer2/aniplayer2_global.h b/aniplayer2/aniplayer2_global.h new file mode 100644 index 0000000..c26d14c --- /dev/null +++ b/aniplayer2/aniplayer2_global.h @@ -0,0 +1,12 @@ +#ifndef ANIPLAYER2_GLOBAL_H +#define ANIPLAYER2_GLOBAL_H + +#include + +#if defined(ANIPLAYER2_LIBRARY) +# define ANIPLAYER2SHARED_EXPORT Q_DECL_EXPORT +#else +# define ANIPLAYER2SHARED_EXPORT Q_DECL_IMPORT +#endif + +#endif // LIBANIPLAYER2_GLOBAL_H diff --git a/aniplayer2/videowidget.cpp b/aniplayer2/videowidget.cpp new file mode 100644 index 0000000..de69e87 --- /dev/null +++ b/aniplayer2/videowidget.cpp @@ -0,0 +1,6 @@ +#include "videowidget.h" + +VideoWidget::VideoWidget(QWidget *parent) : + QWidget(parent) +{ +} diff --git a/aniplayer2/videowidget.h b/aniplayer2/videowidget.h new file mode 100644 index 0000000..67648ad --- /dev/null +++ b/aniplayer2/videowidget.h @@ -0,0 +1,19 @@ +#ifndef VIDEOWIDGET_H +#define VIDEOWIDGET_H + +#include "aniplayer2_global.h" +#include + +class ANIPLAYER2SHARED_EXPORT VideoWidget : public QWidget +{ + Q_OBJECT +public: + explicit VideoWidget(QWidget *parent = 0); + +signals: + +public slots: + +}; + +#endif // VIDEOWIDGET_H diff --git a/aniplayer2_dshow/aniplayer2_dshow.pri b/aniplayer2_dshow/aniplayer2_dshow.pri new file mode 100644 index 0000000..6a0e8e5 --- /dev/null +++ b/aniplayer2_dshow/aniplayer2_dshow.pri @@ -0,0 +1,5 @@ +INCLUDEPATH += $$PWD +INCLUDEPATH += $$PWD +DEPENDPATH += $$PWD +LIBS += -laniplayer2_dshow +LIBS += -L$$PWD/../build diff --git a/aniplayer2_dshow/aniplayer2_dshow.pro b/aniplayer2_dshow/aniplayer2_dshow.pro new file mode 100644 index 0000000..7bef14d --- /dev/null +++ b/aniplayer2_dshow/aniplayer2_dshow.pro @@ -0,0 +1,29 @@ +QT += core gui + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +TARGET = aniplayer2_dshow +DESTDIR = ../build + +TEMPLATE = lib + +DEFINES += ANIPLAYER2_DSHOW_LIBRARY + + +HEADERS += aniplayer2_dshow_global.h + +HEADERS += \ + aniplayerdshow.h \ + aniplayerdshowinternal.h \ + videowidgetdshow.h + + +SOURCES += \ + aniplayerdshow.cpp \ + aniplayerdshowinternal.cpp \ + videowidgetdshow.cpp + +include(../config.pri) +include(../aniplayer2/aniplayer2.pri) + +LIBS += -lstrmiids -lole32 diff --git a/aniplayer2_dshow/aniplayer2_dshow_global.h b/aniplayer2_dshow/aniplayer2_dshow_global.h new file mode 100644 index 0000000..b5d8367 --- /dev/null +++ b/aniplayer2_dshow/aniplayer2_dshow_global.h @@ -0,0 +1,12 @@ +#ifndef ANIPLAYER2_DSHOW_GLOBAL_H +#define ANIPLAYER2_DSHOW_GLOBAL_H + +#include + +#if defined(ANIPLAYER2_DSHOW_LIBRARY) +# define ANIPLAYER2_DSHOWSHARED_EXPORT Q_DECL_EXPORT +#else +# define ANIPLAYER2_DSHOWSHARED_EXPORT Q_DECL_IMPORT +#endif + +#endif // ANIPLAYER2_DSHOW_GLOBAL_H diff --git a/aniplayer2_dshow/aniplayerdshow.cpp b/aniplayer2_dshow/aniplayerdshow.cpp new file mode 100644 index 0000000..63e6f34 --- /dev/null +++ b/aniplayer2_dshow/aniplayerdshow.cpp @@ -0,0 +1,63 @@ +#include "aniplayerdshow.h" + +#include "aniplayerdshowinternal.h" +#include "videowidgetdshow.h" + +#include + +AniPlayerDShow::AniPlayerDShow(QObject *parent) : + AniPlayer(parent) +{ + HRESULT hr; + + hr = CoInitialize(NULL); + if (FAILED(hr)) + qDebug() << "Failed to initialize COM"; + + m_videoWidget = new VideoWidgetDShow(this); + d = new AniPlayerDShowInternal(this); +} + +AniPlayerDShow::~AniPlayerDShow() +{ + CoUninitialize(); +} + +VideoWidget *AniPlayerDShow::videoWidget() +{ + return m_videoWidget; +} + +void AniPlayerDShow::widgetChanged() +{ + d->UpdateVideoWindow(0); + d->Repaint(); +} + +void AniPlayerDShow::iopen(const QString &file) +{ + d->OpenFile(reinterpret_cast(file.utf16())); +} + +void AniPlayerDShow::iplay() +{ + if (m_state == Paused || m_state == Stopped) + if (d->play()) + m_state = Playing; +} + +void AniPlayerDShow::ipause() +{ + if (m_state != Playing) + return; + + if (d->pause()) + m_state = Paused; +} + +void AniPlayerDShow::istop() +{ + if (m_state == Playing || m_state == Paused) + if (d->stop()) + m_state = Stopped; +} diff --git a/aniplayer2_dshow/aniplayerdshow.h b/aniplayer2_dshow/aniplayerdshow.h new file mode 100644 index 0000000..6b6f4ac --- /dev/null +++ b/aniplayer2_dshow/aniplayerdshow.h @@ -0,0 +1,36 @@ +#ifndef ANIPLAYERDSHOW_H +#define ANIPLAYERDSHOW_H + +#include "aniplayer2_dshow_global.h" +#include + +class VideoWidgetDShow; + +struct AniPlayerDShowInternal; + +class ANIPLAYER2_DSHOWSHARED_EXPORT AniPlayerDShow : public AniPlayer +{ + Q_OBJECT +public: + explicit AniPlayerDShow(QObject *parent = 0); + ~AniPlayerDShow(); + + VideoWidget *videoWidget(); + void widgetChanged(); + + +signals: + +protected: + void iopen(const QString &file); + void iplay(); + void ipause(); + void istop(); + +private: + AniPlayerDShowInternal *d; + + VideoWidgetDShow *m_videoWidget; +}; + +#endif // ANIPLAYERDSHOW_H diff --git a/aniplayer2_dshow/aniplayerdshowinternal.cpp b/aniplayer2_dshow/aniplayerdshowinternal.cpp new file mode 100644 index 0000000..51fe5cd --- /dev/null +++ b/aniplayer2_dshow/aniplayerdshowinternal.cpp @@ -0,0 +1,488 @@ +#include "aniplayerdshowinternal.h" + +#include "videowidgetdshow.h" +#include "aniplayerdshow.h" + +#include +#include + +HRESULT IsPinConnected(IPin *pPin, BOOL *pResult); +HRESULT IsPinDirection(IPin *pPin, PIN_DIRECTION dir, BOOL *pResult); +HRESULT AddFilterByCLSID(IGraphBuilder *pGraph, REFGUID clsid, IBaseFilter **ppF, LPCWSTR wszName); +HRESULT FindConnectedPin(IBaseFilter *pFilter, PIN_DIRECTION PinDir, IPin **ppPin); + +AniPlayerDShowInternal::AniPlayerDShowInternal(AniPlayerDShow *player_) : player(player_) +{ + pGraph = 0; + pControl = 0; + pEvent = 0; + pSeeking = 0; + + pEVR = 0; + pVideoDisplay = 0; +} + +AniPlayerDShowInternal::~AniPlayerDShowInternal() +{ + SafeRelease(&pControl); + SafeRelease(&pEvent); + SafeRelease(&pGraph); + SafeRelease(&pSeeking) +} + +bool AniPlayerDShowInternal::play() +{ + HRESULT hr = pControl->Run(); + return SUCCEEDED(hr); +} + +bool AniPlayerDShowInternal::pause() +{ + HRESULT hr = pControl->Pause(); + return SUCCEEDED(hr); +} + +bool AniPlayerDShowInternal::stop() +{ + HRESULT hr = pControl->Stop(); + return SUCCEEDED(hr); +} + +QSize AniPlayerDShowInternal::videoSize() const +{ + if (!pVideoDisplay) + return QSize(); + + SIZE nativeSize; + SIZE aspectRatioSize; + + pVideoDisplay->GetNativeVideoSize(&nativeSize, &aspectRatioSize); + + return QSize(nativeSize.cx, nativeSize.cy); +} + +HRESULT AniPlayerDShowInternal::InitializeGraph() +{ + TearDownGraph(); + + // Create the Filter Graph Manager. + HRESULT hr = CoCreateInstance(CLSID_FilterGraph, NULL, + CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pGraph)); + if (FAILED(hr)) + { + goto done; + } + + hr = pGraph->QueryInterface(IID_PPV_ARGS(&pControl)); + if (FAILED(hr)) + { + goto done; + } + + hr = pGraph->QueryInterface(IID_PPV_ARGS(&pEvent)); + if (FAILED(hr)) + { + goto done; + } +/* + // Set up event notification. + hr = pEvent->SetNotifyWindow((OAHWND)m_hwnd, WM_GRAPH_EVENT, NULL); + if (FAILED(hr)) + { + goto done; + } +*/ +// m_state = STATE_STOPPED; + +done: + return hr; +} + +void AniPlayerDShowInternal::TearDownGraph() +{ +/* + // Stop sending event messages + if (pEvent) + { + pEvent->SetNotifyWindow((OAHWND)NULL, NULL, NULL); + } +*/ + SafeRelease(&pGraph); + SafeRelease(&pControl); + SafeRelease(&pEvent); + SafeRelease(&pSeeking); + +// delete m_pVideo; +// pVideo = NULL; + +// m_state = STATE_NO_GRAPH; +} + + +HRESULT AniPlayerDShowInternal::RenderStreams(IBaseFilter *pSource) +{ + BOOL bRenderedAnyPin = FALSE; + + IFilterGraph2 *pGraph2 = NULL; + IEnumPins *pEnum = NULL; + IBaseFilter *pAudioRenderer = NULL; + HRESULT hr = pGraph->QueryInterface(IID_PPV_ARGS(&pGraph2)); + if (FAILED(hr)) + { + goto done; + } + + // Add the video renderer to the graph + hr = CreateVideoRenderer(); + if (FAILED(hr)) + { + goto done; + } + + // Add the DSound Renderer to the graph. + hr = AddFilterByCLSID(pGraph, CLSID_DSoundRender, + &pAudioRenderer, L"Audio Renderer"); + if (FAILED(hr)) + { + goto done; + } + + // Enumerate the pins on the source filter. + hr = pSource->EnumPins(&pEnum); + if (FAILED(hr)) + { + goto done; + } + + // Loop through all the pins + IPin *pPin; + while (S_OK == pEnum->Next(1, &pPin, NULL)) + { + // Try to render this pin. + // It's OK if we fail some pins, if at least one pin renders. + HRESULT hr2 = pGraph2->RenderEx(pPin, AM_RENDEREX_RENDERTOEXISTINGRENDERERS, NULL); + + pPin->Release(); + if (SUCCEEDED(hr2)) + { + bRenderedAnyPin = TRUE; + } + } + + hr = FinalizeGraph(); + if (FAILED(hr)) + { + goto done; + } + + // Remove the audio renderer, if not used. + BOOL bRemoved; + hr = RemoveUnconnectedRenderer(pGraph, pAudioRenderer, &bRemoved); + +done: + SafeRelease(&pEnum); + SafeRelease(&pAudioRenderer); + SafeRelease(&pGraph2); + + // If we succeeded to this point, make sure we rendered at least one + // stream. + if (SUCCEEDED(hr)) + { + if (!bRenderedAnyPin) + { + hr = VFW_E_CANNOT_RENDER; + } + } + return hr; +} + +HRESULT AniPlayerDShowInternal::RemoveUnconnectedRenderer(IGraphBuilder *pGraph, IBaseFilter *pRenderer, BOOL *pbRemoved) +{ + IPin *pPin = NULL; + + *pbRemoved = FALSE; + + // Look for a connected input pin on the renderer. + + HRESULT hr = FindConnectedPin(pRenderer, PINDIR_INPUT, &pPin); + SafeRelease(&pPin); + + // If this function succeeds, the renderer is connected, so we don't remove it. + // If it fails, it means the renderer is not connected to anything, so + // we remove it. + + if (FAILED(hr)) + { + hr = pGraph->RemoveFilter(pRenderer); + *pbRemoved = TRUE; + } + + return hr; +} + +HRESULT AniPlayerDShowInternal::AddVideoRenderer() +{ + IBaseFilter *npEVR = NULL; + + HRESULT hr = AddFilterByCLSID(pGraph, CLSID_EnhancedVideoRenderer, &npEVR, L"EVR"); + + if (FAILED(hr)) + { + goto done; + } + + hr = InitializeEVR(npEVR, &pVideoDisplay); + if (FAILED(hr)) + { + goto done; + } + + // Note: Because IMFVideoDisplayControl is a service interface, + // you cannot QI the pointer to get back the IBaseFilter pointer. + // Therefore, we need to cache the IBaseFilter pointer. + + pEVR = npEVR; + pEVR->AddRef(); + +done: + SafeRelease(&npEVR); + return hr; +} + +HRESULT AniPlayerDShowInternal::CreateVideoRenderer() +{ + HRESULT hr = AddVideoRenderer(); + + return hr; +} + +HRESULT AniPlayerDShowInternal::OpenFile(PCWSTR pszFileName) +{ + IBaseFilter *pSource = NULL; + + // Create a new filter graph. (This also closes the old one, if any.) + HRESULT hr = InitializeGraph(); + if (FAILED(hr)) + { + goto done; + } + + // Add the source filter to the graph. + hr = pGraph->AddSourceFilter(pszFileName, NULL, &pSource); + if (FAILED(hr)) + { + goto done; + } + + // Try to render the streams. + hr = RenderStreams(pSource); + +done: + if (FAILED(hr)) + { + TearDownGraph(); + } + SafeRelease(&pSource); + return hr; +} + +HRESULT AniPlayerDShowInternal::Repaint() +{ + if (pVideoDisplay) + { + return pVideoDisplay->RepaintVideo(); + } + else + { + return S_OK; + } +} + +HRESULT AniPlayerDShowInternal::UpdateVideoWindow(const LPRECT prc) +{ + if (pVideoDisplay == NULL) + { + return S_OK; // no-op + } + + if (prc) + { + return pVideoDisplay->SetVideoPosition(NULL, prc); + } + else + { + + RECT rc; + GetClientRect(hwnd(), &rc); + return pVideoDisplay->SetVideoPosition(NULL, &rc); + } +} + +HRESULT AniPlayerDShowInternal::InitializeEVR(IBaseFilter *pEVR, IMFVideoDisplayControl **ppDisplayControl) +{ + IMFGetService *pGS = NULL; + IMFVideoDisplayControl *pDisplay = NULL; + + HRESULT hr = pEVR->QueryInterface(IID_PPV_ARGS(&pGS)); + if (FAILED(hr)) + { + goto done; + } + + hr = pGS->GetService(MR_VIDEO_RENDER_SERVICE, IID_PPV_ARGS(&pDisplay)); + if (FAILED(hr)) + { + goto done; + } + + // Set the clipping window. + hr = pDisplay->SetVideoWindow(hwnd()); + if (FAILED(hr)) + { + goto done; + } + + // Preserve aspect ratio by letter-boxing + hr = pDisplay->SetAspectRatioMode(MFVideoARMode_PreservePicture); + if (FAILED(hr)) + { + goto done; + } + + // Return the IMFVideoDisplayControl pointer to the caller. + *ppDisplayControl = pDisplay; + (*ppDisplayControl)->AddRef(); + +done: + SafeRelease(&pGS); + SafeRelease(&pDisplay); + return hr; +} + +HRESULT IsPinConnected(IPin *pPin, BOOL *pResult) +{ + IPin *pTmp = NULL; + HRESULT hr = pPin->ConnectedTo(&pTmp); + if (SUCCEEDED(hr)) + { + *pResult = TRUE; + } + else if (hr == VFW_E_NOT_CONNECTED) + { + // The pin is not connected. This is not an error for our purposes. + *pResult = FALSE; + hr = S_OK; + } + + SafeRelease(&pTmp); + return hr; +} + +HRESULT IsPinDirection(IPin *pPin, PIN_DIRECTION dir, BOOL *pResult) +{ + PIN_DIRECTION pinDir; + HRESULT hr = pPin->QueryDirection(&pinDir); + if (SUCCEEDED(hr)) + { + *pResult = (pinDir == dir); + } + return hr; +} + +HRESULT AddFilterByCLSID(IGraphBuilder *pGraph, const GUID &clsid, IBaseFilter **ppF, LPCWSTR wszName) +{ + *ppF = 0; + + IBaseFilter *pFilter = NULL; + + HRESULT hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, + IID_PPV_ARGS(&pFilter)); + if (FAILED(hr)) + { + goto done; + } + + hr = pGraph->AddFilter(pFilter, wszName); + if (FAILED(hr)) + { + goto done; + } + + *ppF = pFilter; + (*ppF)->AddRef(); + +done: + SafeRelease(&pFilter); + return hr; +} + +HRESULT FindConnectedPin(IBaseFilter *pFilter, PIN_DIRECTION PinDir, IPin **ppPin) +{ + *ppPin = NULL; + + IEnumPins *pEnum = NULL; + IPin *pPin = NULL; + + HRESULT hr = pFilter->EnumPins(&pEnum); + if (FAILED(hr)) + { + return hr; + } + + BOOL bFound = FALSE; + while (S_OK == pEnum->Next(1, &pPin, NULL)) + { + BOOL bIsConnected; + hr = IsPinConnected(pPin, &bIsConnected); + if (SUCCEEDED(hr)) + { + if (bIsConnected) + { + hr = IsPinDirection(pPin, PinDir, &bFound); + } + } + + if (FAILED(hr)) + { + pPin->Release(); + break; + } + if (bFound) + { + *ppPin = pPin; + break; + } + pPin->Release(); + } + + pEnum->Release(); + + if (!bFound) + { + hr = VFW_E_NOT_FOUND; + } + return hr; +} + +HWND AniPlayerDShowInternal::hwnd() const +{ + return (HWND) player->videoWidget()->winId(); +} + + +HRESULT AniPlayerDShowInternal::FinalizeGraph() +{ + if (pEVR == NULL) + { + return S_OK; + } + + BOOL bRemoved; + HRESULT hr = RemoveUnconnectedRenderer(pGraph, pEVR, &bRemoved); + if (bRemoved) + { + SafeRelease(&pEVR); + SafeRelease(&pVideoDisplay); + } + return hr; +} diff --git a/aniplayer2_dshow/aniplayerdshowinternal.h b/aniplayer2_dshow/aniplayerdshowinternal.h new file mode 100644 index 0000000..8a72dfe --- /dev/null +++ b/aniplayer2_dshow/aniplayerdshowinternal.h @@ -0,0 +1,68 @@ +#ifndef ANIPLAYERDSHOWINTERNAL_H +#define ANIPLAYERDSHOWINTERNAL_H + +#include + +#include + +class AniPlayerDShow; + +struct IBaseFilter; +struct IGraphBuilder; +struct IMediaControl; +struct IMediaEvent; +struct IMediaSeeking; +struct IMFVideoDisplayControl; + +struct AniPlayerDShowInternal +{ +public: + AniPlayerDShowInternal(AniPlayerDShow *player_); + ~AniPlayerDShowInternal(); + + bool play(); + bool pause(); + bool stop(); + + QSize videoSize() const; + + HRESULT InitializeGraph(); + void TearDownGraph(); + HRESULT CreateVideoRenderer(); + HRESULT RenderStreams(IBaseFilter *pSource); + HRESULT RemoveUnconnectedRenderer(IGraphBuilder *pGraph, IBaseFilter *pRenderer, BOOL *pbRemoved); + HRESULT InitializeEVR(IBaseFilter *pEVR, IMFVideoDisplayControl** ppDisplayControl); + + + HRESULT AddVideoRenderer(); + HRESULT FinalizeGraph(); + + HRESULT OpenFile(PCWSTR pszFileName); + + IGraphBuilder *pGraph; + IMediaControl *pControl; + IMediaEvent *pEvent; + IMediaSeeking *pSeeking; + + IBaseFilter *pEVR; + IMFVideoDisplayControl *pVideoDisplay; + + HRESULT Repaint(); + HRESULT UpdateVideoWindow(const LPRECT prc); + + + HWND hwnd() const; + + AniPlayerDShow *player; +}; + +template void SafeRelease(T **ppT) +{ + if (*ppT) + { + (*ppT)->Release(); + *ppT = NULL; + } +} + +#endif // ANIPLAYERDSHOWINTERNAL_H diff --git a/aniplayer2_dshow/videowidgetdshow.cpp b/aniplayer2_dshow/videowidgetdshow.cpp new file mode 100644 index 0000000..41cc994 --- /dev/null +++ b/aniplayer2_dshow/videowidgetdshow.cpp @@ -0,0 +1,19 @@ +#include "videowidgetdshow.h" + +#include "aniplayerdshow.h" + +VideoWidgetDShow::VideoWidgetDShow(AniPlayerDShow *player_, QWidget *parent) : + VideoWidget(parent), player(player_) +{ + setPalette(QPalette(Qt::black)); + setAttribute(Qt::WA_OpaquePaintEvent, true); + setAttribute(Qt::WA_NoSystemBackground, true); + setAttribute(Qt::WA_PaintOnScreen, true); + setAutoFillBackground(false); +} + +void VideoWidgetDShow::resizeEvent(QResizeEvent *e) +{ + player->widgetChanged(); + VideoWidget::resizeEvent(e); +} diff --git a/aniplayer2_dshow/videowidgetdshow.h b/aniplayer2_dshow/videowidgetdshow.h new file mode 100644 index 0000000..1d36cfd --- /dev/null +++ b/aniplayer2_dshow/videowidgetdshow.h @@ -0,0 +1,30 @@ +#ifndef VIDEOWIDGETDSHOW_H +#define VIDEOWIDGETDSHOW_H + +#include "aniplayer2_dshow_global.h" +#include + +class AniPlayerDShow; + +class ANIPLAYER2_DSHOWSHARED_EXPORT VideoWidgetDShow : public VideoWidget +{ + Q_OBJECT +public: + explicit VideoWidgetDShow(AniPlayerDShow *player_, QWidget *parent = 0); + + QPaintEngine* paintEngine() const + { + return 0; + } +signals: + +public slots: + +protected: + void resizeEvent(QResizeEvent *e); + +private: + AniPlayerDShow *player; +}; + +#endif // VIDEOWIDGETDSHOW_H diff --git a/config.pri b/config.pri new file mode 100644 index 0000000..e69de29 diff --git a/player/main.cpp b/player/main.cpp new file mode 100644 index 0000000..0063be9 --- /dev/null +++ b/player/main.cpp @@ -0,0 +1,11 @@ +#include "mainwindow.h" +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + MainWindow w; + w.show(); + + return a.exec(); +} diff --git a/player/mainwindow.cpp b/player/mainwindow.cpp new file mode 100644 index 0000000..2c7dbef --- /dev/null +++ b/player/mainwindow.cpp @@ -0,0 +1,32 @@ +#include "mainwindow.h" +#include "ui_mainwindow.h" + +#ifdef Q_OS_WIN +# include +#endif + +#include + +MainWindow::MainWindow(QWidget *parent) : + QMainWindow(parent), + ui(new Ui::MainWindow) +{ + player = new AniPlayerDShow(this); + + player->open("E:/Anime/Accel World OVA/Accel World OVA - 01 - OVA - [UTW][3e56ee18].mkv"); + player->play(); + + ui->setupUi(this); + + QAction *a = new QAction("Pause", this); + a->setShortcut(QKeySequence("Space")); + connect(a, SIGNAL(triggered()), player, SLOT(togglePause())); + addAction(a); + + setCentralWidget(player->videoWidget()); +} + +MainWindow::~MainWindow() +{ + delete ui; +} diff --git a/player/mainwindow.h b/player/mainwindow.h new file mode 100644 index 0000000..b87b77c --- /dev/null +++ b/player/mainwindow.h @@ -0,0 +1,26 @@ +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include + +namespace Ui { +class MainWindow; +} + +class AniPlayer; + +class MainWindow : public QMainWindow +{ + Q_OBJECT + +public: + explicit MainWindow(QWidget *parent = 0); + ~MainWindow(); + +private: + Ui::MainWindow *ui; + + AniPlayer *player; +}; + +#endif // MAINWINDOW_H diff --git a/player/mainwindow.ui b/player/mainwindow.ui new file mode 100644 index 0000000..6050363 --- /dev/null +++ b/player/mainwindow.ui @@ -0,0 +1,24 @@ + + MainWindow + + + + 0 + 0 + 400 + 300 + + + + MainWindow + + + + + + + + + + + diff --git a/player/player.pro b/player/player.pro new file mode 100644 index 0000000..b1c0092 --- /dev/null +++ b/player/player.pro @@ -0,0 +1,20 @@ +QT += core gui + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +TEMPLATE = app + +TARGET = player +DESTDIR = ../build + + +SOURCES += main.cpp\ + mainwindow.cpp + +HEADERS += mainwindow.h + +FORMS += mainwindow.ui + +include(../config.pri) +include(../aniplayer2/aniplayer2.pri) +win32:include(../aniplayer2_dshow/aniplayer2_dshow.pri) -- 2.52.0