diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index 891ecdbe5..a5c462e9c 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -124,6 +124,7 @@ jobs: runs-on: windows-latest env: VCINSTALLDIR: 'C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC' + QT_VERSION: 5.15.0 steps: - name: Checkout uses: actions/checkout@v1 @@ -137,20 +138,37 @@ jobs: tr -d '\n' < version > temp && mv temp version echo -n "-PR#${{ github.event.pull_request.number }}" >> version + - name: Cache Qt + uses: actions/cache@v2 + id: cache-qt-windows + with: + path: ${{ runner.workspace }}/Qt + key: ${{ runner.os }}-Qt.${{ env.QT_VERSION }} + - name: Install Qt uses: jurplel/install-qt-action@v2 with: - version: '5.15.0' + version: ${{env.QT_VERSION}} target: 'desktop' arch: 'win64_msvc2019_64' + cached: ${{ steps.cache-qt-windows.outputs.cache-hit }} - - name: Install Python - uses: actions/setup-python@v1 + - name: Cache Chocolatey downloads + uses: actions/cache@v2 with: - python-version: '3.x' + path: C:\Users\runneradmin\AppData\Local\Temp\chocolatey + key: ${{ runner.os }}-chocolatey + + - name: "Remove Redistributable" + shell: cmd + run: | + MsiExec.exe /passive /X{F0C3E5D1-1ADE-321E-8167-68EF0DE699A5} + MsiExec.exe /passive /X{1D8E6291-B0D5-35EC-8441-6616F567A0F7} - - name: Install OpenSSL & NSIS - run: choco install --no-progress openssl nsis -y + - name: Install Python, NSIS, OpenSSL, DirectX SDK + shell: powershell + run: | + choco install --no-progress python nsis openssl directx-sdk -y - name: Set up x64 build architecture environment shell: cmd diff --git a/.github/workflows/push-master.yml b/.github/workflows/push-master.yml index 80e79aafb..55b3b03a0 100644 --- a/.github/workflows/push-master.yml +++ b/.github/workflows/push-master.yml @@ -95,26 +95,44 @@ jobs: runs-on: windows-latest env: VCINSTALLDIR: 'C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC' + QT_VERSION: 5.15.0 steps: - name: Checkout uses: actions/checkout@v1 with: submodules: true + - name: Cache Qt + uses: actions/cache@v2 + id: cache-qt-windows + with: + path: ${{ runner.workspace }}/Qt + key: ${{ runner.os }}-Qt.${{ env.QT_VERSION }} + - name: Install Qt uses: jurplel/install-qt-action@v2 with: - version: '5.15.0' + version: ${{ env.QT_VERSION }} target: 'desktop' arch: 'win64_msvc2019_64' + cached: ${{ steps.cache-qt-windows.outputs.cache-hit }} - - name: Install Python - uses: actions/setup-python@v1 + - name: Cache Chocolatey downloads + uses: actions/cache@v2 with: - python-version: '3.x' + path: C:\Users\runneradmin\AppData\Local\Temp\chocolatey + key: ${{ runner.os }}-chocolatey + + - name: "Remove Redistributable" + shell: cmd + run: | + MsiExec.exe /passive /X{F0C3E5D1-1ADE-321E-8167-68EF0DE699A5} + MsiExec.exe /passive /X{1D8E6291-B0D5-35EC-8441-6616F567A0F7} - - name: Install OpenSSL & NSIS - run: choco install --no-progress openssl nsis -y + - name: Install Python, NSIS, OpenSSL, DirectX SDK + shell: powershell + run: | + choco install --no-progress python nsis openssl directx-sdk -y - name: Set up x64 build architecture environment shell: cmd diff --git a/CMakeLists.txt b/CMakeLists.txt index dd5c76065..e047df020 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,9 +39,9 @@ endif() SET ( DEFAULT_AMLOGIC OFF ) SET ( DEFAULT_DISPMANX OFF ) SET ( DEFAULT_OSX OFF ) +SET ( DEFAULT_QT ON ) SET ( DEFAULT_X11 OFF ) SET ( DEFAULT_XCB OFF ) -SET ( DEFAULT_QT ON ) SET ( DEFAULT_WS281XPWM OFF ) SET ( DEFAULT_AVAHI ON ) SET ( DEFAULT_USE_SHARED_AVAHI_LIBS ON ) @@ -58,6 +58,8 @@ IF ( ${CMAKE_SYSTEM} MATCHES "Linux" ) SET ( DEFAULT_FB ON ) SET ( DEFAULT_USB_HID ON ) SET ( DEFAULT_CEC ON ) +ELSEIF ( WIN32 ) + SET ( DEFAULT_DX ON ) ELSE() SET ( DEFAULT_V4L2 OFF ) SET ( DEFAULT_FB OFF ) @@ -190,6 +192,9 @@ message(STATUS "ENABLE_XCB = ${ENABLE_XCB}") option(ENABLE_QT "Enable the qt grabber" ${DEFAULT_QT}) message(STATUS "ENABLE_QT = ${ENABLE_QT}") +option(ENABLE_DX "Enable the DirectX grabber" ${DEFAULT_DX}) +message(STATUS "ENABLE_DX = ${ENABLE_DX}") + option(ENABLE_TESTS "Compile additional test applications" ${DEFAULT_TESTS}) message(STATUS "ENABLE_TESTS = ${ENABLE_TESTS}") @@ -303,6 +308,12 @@ if (CMAKE_CXX_COMPILER_ID MATCHES "MSVC") message(STATUS "Set Qt5 module path: ${SUBDIRQT}") SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${SUBDIRQT}/msvc2019_64/lib/cmake/Qt5") endif() + + # Search for DirectX9 + if (ENABLE_DX) + find_package(DirectX9 REQUIRED) + endif() + endif() # Use GNU gold linker if available diff --git a/HyperionConfig.h.in b/HyperionConfig.h.in index 655a6ec38..00537e71c 100644 --- a/HyperionConfig.h.in +++ b/HyperionConfig.h.in @@ -24,6 +24,9 @@ // Define to enable the qt grabber #cmakedefine ENABLE_QT +// Define to enable the DirectX grabber +#cmakedefine ENABLE_DX + // Define to enable the spi-device #cmakedefine ENABLE_SPIDEV diff --git a/cmake/FindDirectX9.cmake b/cmake/FindDirectX9.cmake new file mode 100644 index 000000000..e09049ddf --- /dev/null +++ b/cmake/FindDirectX9.cmake @@ -0,0 +1,32 @@ +# Find the DirectX 9 includes and library +# This module defines: +# DIRECTX9_INCLUDE_DIRS, where to find d3d9.h, etc. +# DIRECTX9_LIBRARIES, libraries to link against to use DirectX. +# DIRECTX9_FOUND, If false, do not try to use DirectX. +# DIRECTX9_ROOT_DIR, directory where DirectX was installed. + +set(DIRECTX9_INCLUDE_PATHS + "$ENV{DXSDK_DIR}/Include" + "$ENV{DIRECTX_ROOT}/Include" + "C:/Program Files (x86)/Microsoft DirectX SDK (June 2010)/Include" + "C:/Program Files/Microsoft DirectX SDK (June 2010)/Include" +) +find_path(DIRECTX9_INCLUDE_DIRS d3dx9.h ${DIRECTX9_INCLUDE_PATHS} NO_DEFAULT_PATH) + +get_filename_component(DIRECTX9_ROOT_DIR "${DIRECTX9_INCLUDE_DIRS}/.." ABSOLUTE) + +if (CMAKE_SIZEOF_VOID_P EQUAL 8) + set(DIRECTX9_LIBRARY_PATHS "${DIRECTX9_ROOT_DIR}/Lib/x64") +else () + set(DIRECTX9_LIBRARY_PATHS "${DIRECTX9_ROOT_DIR}/Lib/x86" "${DIRECTX9_ROOT_DIR}/Lib") +endif () + +find_library(DIRECTX9_D3D9_LIBRARY d3d9 ${DIRECTX9_LIBRARY_PATHS} NO_DEFAULT_PATH) +find_library(DIRECTX9_D3DX9_LIBRARY d3dx9 ${DIRECTX9_LIBRARY_PATHS} NO_DEFAULT_PATH) +find_library(DIRECTX9_DXERR_LIBRARY DxErr ${DIRECTX9_LIBRARY_PATHS} NO_DEFAULT_PATH) +set(DIRECTX9_LIBRARIES ${DIRECTX9_D3D9_LIBRARY} ${DIRECTX9_D3DX9_LIBRARY} ${DIRECTX9_DXERR_LIBRARY}) + +# handle the QUIETLY and REQUIRED arguments and set DIRECTX9_FOUND to TRUE if all listed variables are TRUE +include(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(DirectX9 DEFAULT_MSG DIRECTX9_ROOT_DIR DIRECTX9_LIBRARIES DIRECTX9_INCLUDE_DIRS) +mark_as_advanced(DIRECTX9_INCLUDE_DIRS DIRECTX9_D3D9_LIBRARY DIRECTX9_D3DX9_LIBRARY DIRECTX9_DXERR_LIBRARY) diff --git a/include/grabber/DirectXGrabber.h b/include/grabber/DirectXGrabber.h new file mode 100644 index 000000000..39f56d498 --- /dev/null +++ b/include/grabber/DirectXGrabber.h @@ -0,0 +1,79 @@ +#pragma once + +#include + +// DirectX 9 header +#include +#include + +// Hyperion-utils includes +#include +#include + +/// +/// @brief The DirectX9 capture implementation +/// +class DirectXGrabber : public Grabber +{ +public: + + DirectXGrabber(int cropLeft, int cropRight, int cropTop, int cropBottom, int pixelDecimation, int display); + + virtual ~DirectXGrabber(); + + /// + /// Captures a single snapshot of the display and writes the data to the given image. The + /// provided image should have the same dimensions as the configured values (_width and + /// _height) + /// + /// @param[out] image The snapped screenshot + /// + virtual int grabFrame(Image & image); + + /// + /// @brief Set a new video mode + /// + virtual void setVideoMode(VideoMode mode); + + /// + /// @brief Apply new width/height values, overwrite Grabber.h implementation + /// + virtual bool setWidthHeight(int width, int height) { return true; }; + + /// + /// @brief Apply new pixelDecimation + /// + virtual void setPixelDecimation(int pixelDecimation); + + /// + /// Set the crop values + /// @param cropLeft Left pixel crop + /// @param cropRight Right pixel crop + /// @param cropTop Top pixel crop + /// @param cropBottom Bottom pixel crop + /// + virtual void setCropping(unsigned cropLeft, unsigned cropRight, unsigned cropTop, unsigned cropBottom); + +private: + /// + /// @brief Setup a new capture display, will free the previous one + /// @return True on success, false if no display is found + /// + bool setupDisplay(); + + /// + /// @brief free the _screen pointer + /// + void freeResources(); + +private: + int _pixelDecimation; + unsigned _displayWidth; + unsigned _displayHeight; + RECT* _srcRect; + + IDirect3D9* _d3d9; + IDirect3DDevice9* _device; + IDirect3DSurface9* _surface; + IDirect3DSurface9* _surfaceDest; +}; diff --git a/include/grabber/DirectXWrapper.h b/include/grabber/DirectXWrapper.h new file mode 100644 index 000000000..d0bcb0b02 --- /dev/null +++ b/include/grabber/DirectXWrapper.h @@ -0,0 +1,36 @@ +#pragma once + +#include +#include + +class DirectXWrapper: public GrabberWrapper +{ +public: + /// + /// Constructs the DirectX grabber with a specified grab size and update rate. + /// + /// @param[in] cropLeft Remove from left [pixels] + /// @param[in] cropRight Remove from right [pixels] + /// @param[in] cropTop Remove from top [pixels] + /// @param[in] cropBottom Remove from bottom [pixels] + /// @param[in] pixelDecimation Decimation factor for image [pixels] + /// @param[in] display The display used[index] + /// @param[in] updateRate_Hz The image grab rate [Hz] + /// + DirectXWrapper(int cropLeft, int cropRight, int cropTop, int cropBottom, int pixelDecimation, int display, const unsigned updateRate_Hz); + + /// + /// Destructor of this DirectX grabber. Releases any claimed resources. + /// + virtual ~DirectXWrapper() {}; + +public slots: + /// + /// Performs a single frame grab and computes the led-colors + /// + virtual void action(); + +private: + /// The actual grabber + DirectXGrabber _grabber; +}; diff --git a/libsrc/grabber/CMakeLists.txt b/libsrc/grabber/CMakeLists.txt index 3faec2535..302aece44 100644 --- a/libsrc/grabber/CMakeLists.txt +++ b/libsrc/grabber/CMakeLists.txt @@ -29,3 +29,7 @@ endif() if (ENABLE_QT) add_subdirectory(qt) endif() + +if (ENABLE_DX) + add_subdirectory(directx) +endif() diff --git a/libsrc/grabber/directx/CMakeLists.txt b/libsrc/grabber/directx/CMakeLists.txt new file mode 100644 index 000000000..16db7dd2a --- /dev/null +++ b/libsrc/grabber/directx/CMakeLists.txt @@ -0,0 +1,14 @@ +# Define the current source locations +SET( CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include/grabber ) +SET( CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/grabber/directx ) + +include_directories(${DIRECTX9_INCLUDE_DIRS}) + +FILE ( GLOB DIRECTX_GRAB_SOURCES "${CURRENT_HEADER_DIR}/DirectX*.h" "${CURRENT_SOURCE_DIR}/*.h" "${CURRENT_SOURCE_DIR}/*.cpp" ) + +add_library( directx-grabber ${DIRECTX_GRAB_SOURCES} ) + +target_link_libraries(directx-grabber + hyperion + ${DIRECTX9_LIBRARIES} +) diff --git a/libsrc/grabber/directx/DirectXGrabber.cpp b/libsrc/grabber/directx/DirectXGrabber.cpp new file mode 100644 index 000000000..f8cd3f23b --- /dev/null +++ b/libsrc/grabber/directx/DirectXGrabber.cpp @@ -0,0 +1,181 @@ +#include +#include +#include +#pragma comment(lib, "d3d9.lib") +#pragma comment(lib,"d3dx9.lib") + +DirectXGrabber::DirectXGrabber(int cropLeft, int cropRight, int cropTop, int cropBottom, int pixelDecimation, int display) + : Grabber("DXGRABBER", 0, 0, cropLeft, cropRight, cropTop, cropBottom) + , _pixelDecimation(pixelDecimation) + , _displayWidth(0) + , _displayHeight(0) + , _srcRect(0) + , _d3d9(nullptr) + , _device(nullptr) + , _surface(nullptr) +{ + // init + setupDisplay(); +} + +DirectXGrabber::~DirectXGrabber() +{ + freeResources(); +} + +void DirectXGrabber::freeResources() +{ + if (_surface) + _surface->Release(); + + if (_device) + _device->Release(); + + if (_d3d9) + _d3d9->Release(); + + delete _srcRect; +} + +bool DirectXGrabber::setupDisplay() +{ + freeResources(); + + D3DDISPLAYMODE ddm; + D3DPRESENT_PARAMETERS d3dpp; + + if ((_d3d9 = Direct3DCreate9(D3D_SDK_VERSION)) == nullptr) + { + Error(_log, "Failed to create Direct3D"); + return false; + } + + if (FAILED(_d3d9->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &ddm))) + { + Error(_log, "Failed to get current display mode"); + return false; + } + + SecureZeroMemory(&d3dpp, sizeof(D3DPRESENT_PARAMETERS)); + + d3dpp.Windowed = TRUE; + d3dpp.Flags = D3DPRESENTFLAG_LOCKABLE_BACKBUFFER; + d3dpp.BackBufferFormat = ddm.Format; + d3dpp.BackBufferHeight = _displayHeight = ddm.Height; + d3dpp.BackBufferWidth = _displayWidth = ddm.Width; + d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE; + d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; + d3dpp.hDeviceWindow = nullptr; + d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT; + d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT; + + if (FAILED(_d3d9->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, nullptr, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &_device))) + { + Error(_log, "CreateDevice failed"); + return false; + } + + if (FAILED(_device->CreateOffscreenPlainSurface(ddm.Width, ddm.Height, D3DFMT_A8R8G8B8, D3DPOOL_SCRATCH, &_surface, nullptr))) + { + Error(_log, "CreateOffscreenPlainSurface failed"); + return false; + } + + int width = _displayWidth / _pixelDecimation; + int height =_displayHeight / _pixelDecimation; + + // calculate final image dimensions and adjust top/left cropping in 3D modes + _srcRect = new RECT; + switch (_videoMode) + { + case VideoMode::VIDEO_3DSBS: + _width = width / 2; + _height = height; + _srcRect->left = _cropLeft * _pixelDecimation / 2; + _srcRect->top = _cropTop * _pixelDecimation; + _srcRect->right = (_displayWidth / 2) - (_cropRight * _pixelDecimation); + _srcRect->bottom = _displayHeight - (_cropBottom * _pixelDecimation); + break; + case VideoMode::VIDEO_3DTAB: + _width = width; + _height = height / 2; + _srcRect->left = _cropLeft * _pixelDecimation; + _srcRect->top = (_cropTop * _pixelDecimation) / 2; + _srcRect->right = _displayWidth - (_cropRight * _pixelDecimation); + _srcRect->bottom = (_displayHeight / 2) - (_cropBottom * _pixelDecimation); + break; + case VideoMode::VIDEO_2D: + default: + _width = width; + _height = height; + _srcRect->left = _cropLeft * _pixelDecimation; + _srcRect->top = _cropTop * _pixelDecimation; + _srcRect->right = _displayWidth - _cropRight * _pixelDecimation; + _srcRect->bottom = _displayHeight - _cropBottom * _pixelDecimation; + break; + } + + if (FAILED(_device->CreateOffscreenPlainSurface(_width, _height, D3DFMT_R8G8B8, D3DPOOL_SCRATCH, &_surfaceDest, nullptr))) + { + Error(_log, "CreateOffscreenPlainSurface failed"); + return false; + } + + Info(_log, "Update output image resolution to [%dx%d]", _width, _height); + return true; +} + +int DirectXGrabber::grabFrame(Image & image) +{ + if (!_enabled) + return 0; + + if (FAILED(_device->GetFrontBufferData(0, _surface))) + { + // reinit, this will disable capture on failure + Error(_log, "Unable to get Buffer Surface Data"); + setEnabled(setupDisplay()); + return -1; + } + + D3DXLoadSurfaceFromSurface(_surfaceDest, nullptr, nullptr, _surface, nullptr, _srcRect, D3DX_DEFAULT, 0); + + D3DLOCKED_RECT lockedRect; + if (FAILED(_surfaceDest->LockRect(&lockedRect, nullptr, D3DLOCK_NO_DIRTY_UPDATE | D3DLOCK_NOSYSLOCK | D3DLOCK_READONLY))) + { + Error(_log, "Unable to lock destination Front Buffer Surface"); + return 0; + } + + memcpy(image.memptr(), lockedRect.pBits, _width * _height * 3); + for (int idx = 0; idx < _width * _height; idx++) + { + const ColorRgb & color = image.memptr()[idx]; + image.memptr()[idx] = ColorRgb{color.blue, color.green, color.red}; + } + + if (FAILED(_surfaceDest->UnlockRect())) + { + Error(_log, "Unable to unlock destination Front Buffer Surface"); + return 0; + } + + return 0; +} + +void DirectXGrabber::setVideoMode(VideoMode mode) +{ + Grabber::setVideoMode(mode); + setupDisplay(); +} + +void DirectXGrabber::setPixelDecimation(int pixelDecimation) +{ + _pixelDecimation = pixelDecimation; +} + +void DirectXGrabber::setCropping(unsigned cropLeft, unsigned cropRight, unsigned cropTop, unsigned cropBottom) +{ + Grabber::setCropping(cropLeft, cropRight, cropTop, cropBottom); + setupDisplay(); +} diff --git a/libsrc/grabber/directx/DirectXWrapper.cpp b/libsrc/grabber/directx/DirectXWrapper.cpp new file mode 100644 index 000000000..260189031 --- /dev/null +++ b/libsrc/grabber/directx/DirectXWrapper.cpp @@ -0,0 +1,11 @@ +#include + +DirectXWrapper::DirectXWrapper(int cropLeft, int cropRight, int cropTop, int cropBottom, int pixelDecimation, int display, const unsigned updateRate_Hz) + : GrabberWrapper("DirectX", &_grabber, 0, 0, updateRate_Hz) + , _grabber(cropLeft, cropRight, cropTop, cropBottom, pixelDecimation, display) +{} + +void DirectXWrapper::action() +{ + transferFrame(_grabber); +} diff --git a/libsrc/hyperion/schema/schema-framegrabber.json b/libsrc/hyperion/schema/schema-framegrabber.json index 4ef1cfb73..ac8d57e5d 100644 --- a/libsrc/hyperion/schema/schema-framegrabber.json +++ b/libsrc/hyperion/schema/schema-framegrabber.json @@ -7,10 +7,10 @@ { "type" : "string", "title" : "edt_conf_fg_type_title", - "enum" : ["auto","dispmanx","amlogic","x11", "xcb", "framebuffer","qt"], + "enum" : ["auto","dispmanx","amlogic","x11", "xcb", "framebuffer","qt","dx"], "options": { - "enum_titles": ["edt_conf_enum_automatic","DispmanX","AMLogic","X11", "XCB", "Framebuffer","QT"] + "enum_titles": ["edt_conf_enum_automatic","DispmanX","AMLogic","X11", "XCB", "Framebuffer","QT", "DirectX9"] }, "default" : "auto", "propertyOrder" : 2 diff --git a/src/hyperiond/CMakeLists.txt b/src/hyperiond/CMakeLists.txt index ce6e7b6ad..2ec4cf758 100644 --- a/src/hyperiond/CMakeLists.txt +++ b/src/hyperiond/CMakeLists.txt @@ -103,6 +103,11 @@ if (ENABLE_QT) target_link_libraries(hyperiond qt-grabber) endif () +if (ENABLE_DX) + include_directories(${DIRECTX9_INCLUDE_DIRS}) + target_link_libraries(hyperiond directx-grabber) +endif () + if (ENABLE_CEC) target_link_libraries(hyperiond cechandler) endif () diff --git a/src/hyperiond/hyperiond.cpp b/src/hyperiond/hyperiond.cpp index 197518e57..c036a07dd 100644 --- a/src/hyperiond/hyperiond.cpp +++ b/src/hyperiond/hyperiond.cpp @@ -81,6 +81,7 @@ HyperionDaemon::HyperionDaemon(const QString rootPath, QObject *parent, bool log , _fbGrabber(nullptr) , _osxGrabber(nullptr) , _qtGrabber(nullptr) + , _dxGrabber(nullptr) , _ssdp(nullptr) , _cecHandler(nullptr) , _currVideoMode(VideoMode::VIDEO_2D) @@ -135,7 +136,7 @@ HyperionDaemon::HyperionDaemon(const QString rootPath, QObject *parent, bool log connect(this, &HyperionDaemon::videoMode, _instanceManager, &HyperionIManager::newVideoMode); // ---- grabber ----- -#if !defined(ENABLE_DISPMANX) && !defined(ENABLE_OSX) && !defined(ENABLE_FB) && !defined(ENABLE_X11) && !defined(ENABLE_XCB) && !defined(ENABLE_AMLOGIC) && !defined(ENABLE_QT) +#if !defined(ENABLE_DISPMANX) && !defined(ENABLE_OSX) && !defined(ENABLE_FB) && !defined(ENABLE_X11) && !defined(ENABLE_XCB) && !defined(ENABLE_AMLOGIC) && !defined(ENABLE_QT) && !defined(ENABLE_DX) Warning(_log, "No platform capture can be instantiated, because all grabbers have been left out from the build"); #endif @@ -244,6 +245,7 @@ void HyperionDaemon::freeObjects() delete _fbGrabber; delete _osxGrabber; delete _qtGrabber; + delete _dxGrabber; delete _v4l2Grabber; _v4l2Grabber = nullptr; @@ -253,6 +255,7 @@ void HyperionDaemon::freeObjects() _fbGrabber = nullptr; _osxGrabber = nullptr; _qtGrabber = nullptr; + _dxGrabber = nullptr; } void HyperionDaemon::startNetworkServices() @@ -458,6 +461,14 @@ void HyperionDaemon::handleSettingsUpdate(settings::type settingsType, const QJs _qtGrabber = nullptr; } #endif + #ifdef ENABLE_DX + if(_dxGrabber != nullptr) + { + _dxGrabber->stop(); + delete _dxGrabber; + _dxGrabber = nullptr; + } + #endif // create/start capture interface if (type == "framebuffer") @@ -516,6 +527,14 @@ void HyperionDaemon::handleSettingsUpdate(settings::type settingsType, const QJs _qtGrabber->tryStart(); #endif } + else if (type == "dx") + { + if (_dxGrabber == nullptr) + createGrabberDx(grabberConfig); + #ifdef ENABLE_DX + _dxGrabber->tryStart(); + #endif + } else { Error(_log, "Unknown platform capture type: %s", QSTRING_CSTR(type)); @@ -670,6 +689,25 @@ void HyperionDaemon::createGrabberQt(const QJsonObject &grabberConfig) #endif } +void HyperionDaemon::createGrabberDx(const QJsonObject &grabberConfig) +{ +#ifdef ENABLE_DX + _dxGrabber = new DirectXWrapper( + _grabber_cropLeft, _grabber_cropRight, _grabber_cropTop, _grabber_cropBottom, + grabberConfig["pixelDecimation"].toInt(8), + grabberConfig["display"].toInt(0), + _grabber_frequency); + + // connect to HyperionDaemon signal + connect(this, &HyperionDaemon::videoMode, _dxGrabber, &DirectXWrapper::setVideoMode); + connect(this, &HyperionDaemon::settingsChanged, _dxGrabber, &DirectXWrapper::handleSettingsUpdate); + + Info(_log, "DirectX grabber created"); +#else + Error(_log, "The DirectX grabber can not be instantiated, because it has been left out from the build"); +#endif +} + void HyperionDaemon::createGrabberFramebuffer(const QJsonObject &grabberConfig) { #ifdef ENABLE_FB diff --git a/src/hyperiond/hyperiond.h b/src/hyperiond/hyperiond.h index cff949607..1b76b28bc 100644 --- a/src/hyperiond/hyperiond.h +++ b/src/hyperiond/hyperiond.h @@ -52,6 +52,12 @@ typedef QObject QtWrapper; #endif +#ifdef ENABLE_DX + #include +#else + typedef QObject DirectXWrapper; +#endif + #include #include @@ -153,6 +159,7 @@ private slots: void createGrabberXcb(const QJsonObject & grabberConfig); void createGrabberQt(const QJsonObject & grabberConfig); void createCecHandler(); + void createGrabberDx(const QJsonObject & grabberConfig); Logger* _log; HyperionIManager* _instanceManager; @@ -171,6 +178,7 @@ private slots: FramebufferWrapper* _fbGrabber; OsxWrapper* _osxGrabber; QtWrapper* _qtGrabber; + DirectXWrapper* _dxGrabber; SSDPHandler* _ssdp; CECHandler* _cecHandler; FlatBufferServer* _flatBufferServer;