aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt6
-rw-r--r--addons/repository.xbmc.org/addon.xml10
-rw-r--r--addons/resource.language.en_gb/resources/strings.po6
-rw-r--r--addons/screensaver.xbmc.builtin.black/addon.xml.in (renamed from addons/screensaver.xbmc.builtin.black/addon.xml)2
-rw-r--r--addons/screensaver.xbmc.builtin.dim/addon.xml.in (renamed from addons/screensaver.xbmc.builtin.dim/addon.xml)2
-rw-r--r--addons/skin.estouchy/media/epg_archive.pngbin0 -> 416 bytes
-rw-r--r--addons/skin.estouchy/xml/ViewsPVR.xml16
-rw-r--r--addons/skin.estuary/media/icons/pvr/PVR-HasArchive.pngbin0 -> 738 bytes
-rw-r--r--addons/skin.estuary/media/windows/pvr/archive.pngbin0 -> 417 bytes
-rw-r--r--addons/skin.estuary/xml/Home.xml4
-rw-r--r--addons/skin.estuary/xml/Variables.xml3
-rw-r--r--cmake/addons/CMakeLists.txt2
-rw-r--r--cmake/addons/depends/common/kodi-platform/kodi-platform.txt2
-rw-r--r--cmake/scripts/common/CompilerSettings.cmake6
-rw-r--r--cmake/treedata/common/subdirs.txt1
-rw-r--r--cmake/treedata/optional/common/gbm.txt1
-rwxr-xr-xsystem/settings/settings.xml2
-rw-r--r--system/shaders/GL/1.2/gl_convolution-4x4.glsl2
-rw-r--r--system/shaders/GL/1.2/gl_convolution-6x6.glsl2
-rw-r--r--system/shaders/GL/1.5/gl_convolution-4x4.glsl2
-rw-r--r--system/shaders/GL/1.5/gl_convolution-6x6.glsl2
-rw-r--r--xbmc/Application.cpp4
-rw-r--r--xbmc/GUIInfoManager.cpp18
-rw-r--r--xbmc/addons/PVRClient.cpp27
-rw-r--r--xbmc/addons/PVRClient.h12
-rw-r--r--xbmc/addons/ScreenSaver.cpp9
-rw-r--r--xbmc/addons/Visualization.cpp9
-rw-r--r--xbmc/addons/binary-addons/AddonDll.cpp3
-rw-r--r--xbmc/addons/interfaces/AudioEngine.cpp382
-rw-r--r--xbmc/addons/interfaces/AudioEngine.h181
-rw-r--r--xbmc/addons/interfaces/CMakeLists.txt2
-rw-r--r--xbmc/addons/interfaces/GUI/General.cpp6
-rw-r--r--xbmc/addons/interfaces/GUI/General.h1
-rw-r--r--xbmc/addons/kodi-addon-dev-kit/include/kodi/AddonBase.h5
-rw-r--r--xbmc/addons/kodi-addon-dev-kit/include/kodi/AudioEngine.h586
-rw-r--r--xbmc/addons/kodi-addon-dev-kit/include/kodi/CMakeLists.txt1
-rw-r--r--xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/Screensaver.h17
-rw-r--r--xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/Visualization.h8
-rw-r--r--xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/CMakeLists.txt3
-rw-r--r--xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/General.h34
-rw-r--r--xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/controls/Rendering.h8
-rw-r--r--xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/definitions.h1
-rw-r--r--xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/gl/CMakeLists.txt7
-rw-r--r--xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/gl/GL.h109
-rw-r--r--xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/gl/GLonDX.h369
-rw-r--r--xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/gl/Shader.h353
-rw-r--r--xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/renderHelper.h77
-rw-r--r--xbmc/addons/kodi-addon-dev-kit/include/kodi/versions.h10
-rw-r--r--xbmc/addons/kodi-addon-dev-kit/include/kodi/xbmc_epg_types.h1
-rw-r--r--xbmc/addons/kodi-addon-dev-kit/include/kodi/xbmc_pvr_dll.h19
-rw-r--r--xbmc/addons/kodi-addon-dev-kit/include/kodi/xbmc_pvr_types.h13
-rw-r--r--xbmc/addons/settings/AddonSettings.cpp8
-rw-r--r--xbmc/cores/RetroPlayer/buffers/RenderBufferPoolOpenGL.cpp5
-rw-r--r--xbmc/cores/RetroPlayer/buffers/RenderBufferPoolOpenGLES.cpp5
-rw-r--r--xbmc/cores/RetroPlayer/rendering/VideoRenderers/RPBaseRenderer.cpp10
-rw-r--r--xbmc/cores/RetroPlayer/rendering/VideoRenderers/RPRendererGuiTexture.cpp18
-rw-r--r--xbmc/cores/RetroPlayer/rendering/VideoRenderers/RPRendererOpenGL.cpp22
-rw-r--r--xbmc/cores/RetroPlayer/rendering/VideoRenderers/RPRendererOpenGLES.cpp22
-rw-r--r--xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.cpp184
-rw-r--r--xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.h43
-rw-r--r--xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemux.h5
-rw-r--r--xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxClient.cpp8
-rw-r--r--xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxClient.h1
-rw-r--r--xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStream.h1
-rw-r--r--xbmc/cores/VideoPlayer/DVDInputStreams/InputStreamPVRBase.cpp6
-rw-r--r--xbmc/cores/VideoPlayer/DVDInputStreams/InputStreamPVRBase.h1
-rw-r--r--xbmc/cores/VideoPlayer/Process/gbm/CMakeLists.txt7
-rw-r--r--xbmc/cores/VideoPlayer/Process/gbm/ProcessInfoGBM.cpp34
-rw-r--r--xbmc/cores/VideoPlayer/Process/gbm/ProcessInfoGBM.h26
-rw-r--r--xbmc/cores/VideoPlayer/Process/gbm/VideoBufferDRMPRIME.cpp134
-rw-r--r--xbmc/cores/VideoPlayer/Process/gbm/VideoBufferDRMPRIME.h108
-rw-r--r--xbmc/cores/VideoPlayer/VideoPlayer.cpp25
-rw-r--r--xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/DRMPRIMEEGL.cpp7
-rw-r--r--xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/DRMPRIMEEGL.h7
-rw-r--r--xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/RendererDRMPRIME.cpp21
-rw-r--r--xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/RendererDRMPRIMEGLES.cpp6
-rw-r--r--xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/VideoLayerBridgeDRMPRIME.cpp19
-rw-r--r--xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/VideoLayerBridgeDRMPRIME.h18
-rw-r--r--xbmc/cores/VideoPlayer/VideoRenderers/VideoShaders/VideoFilterShaderGL.cpp4
-rw-r--r--xbmc/cores/VideoPlayer/VideoRenderers/VideoShaders/VideoFilterShaderGLES.cpp3
-rw-r--r--xbmc/cores/paplayer/VideoPlayerCodec.cpp12
-rw-r--r--xbmc/dialogs/GUIDialogKeyboardTouch.cpp2
-rw-r--r--xbmc/guilib/guiinfo/GUIInfoLabels.h2
-rw-r--r--xbmc/interfaces/json-rpc/schema/types.json10
-rw-r--r--xbmc/interfaces/json-rpc/schema/version.txt2
-rw-r--r--xbmc/interfaces/legacy/File.h34
-rw-r--r--xbmc/music/dialogs/GUIDialogMusicInfo.cpp16
-rw-r--r--xbmc/platform/darwin/ios-common/CMakeLists.txt8
-rw-r--r--xbmc/platform/darwin/ios-common/IOSKeyboard.h (renamed from xbmc/platform/darwin/ios/IOSKeyboard.h)4
-rw-r--r--xbmc/platform/darwin/ios-common/IOSKeyboard.mm (renamed from xbmc/platform/darwin/ios/IOSKeyboard.mm)8
-rw-r--r--xbmc/platform/darwin/ios-common/IOSKeyboardView.h (renamed from xbmc/platform/darwin/ios/IOSKeyboardView.h)2
-rw-r--r--xbmc/platform/darwin/ios-common/IOSKeyboardView.mm (renamed from xbmc/platform/darwin/ios/IOSKeyboardView.mm)10
-rw-r--r--xbmc/platform/darwin/ios/CMakeLists.txt7
-rw-r--r--xbmc/platform/darwin/ios/IOSEAGLView.mm2
-rw-r--r--xbmc/platform/darwin/ios/XBMCApplication.mm2
-rw-r--r--xbmc/platform/darwin/ios/XBMCController.mm2
-rw-r--r--xbmc/platform/darwin/ios/XBMCDebugHelpers.h28
-rw-r--r--xbmc/platform/linux/input/LibInputKeyboard.cpp2
-rw-r--r--xbmc/pvr/PVRDatabase.cpp25
-rw-r--r--xbmc/pvr/PVRDatabase.h2
-rw-r--r--xbmc/pvr/PVRGUIInfo.cpp14
-rw-r--r--xbmc/pvr/channels/PVRChannel.cpp13
-rw-r--r--xbmc/pvr/channels/PVRChannel.h6
-rw-r--r--xbmc/pvr/channels/PVRChannelGroup.cpp2
-rw-r--r--xbmc/pvr/channels/PVRChannelGroupInternal.cpp8
-rw-r--r--xbmc/pvr/epg/Epg.cpp12
-rw-r--r--xbmc/pvr/epg/EpgContainer.cpp16
-rw-r--r--xbmc/pvr/epg/EpgContainer.h4
-rw-r--r--xbmc/pvr/epg/EpgDatabase.cpp7
-rw-r--r--xbmc/pvr/epg/EpgInfoTag.cpp13
-rw-r--r--xbmc/pvr/epg/EpgInfoTag.h7
-rw-r--r--xbmc/settings/AdvancedSettings.cpp6
-rw-r--r--xbmc/settings/Settings.cpp2
-rw-r--r--xbmc/settings/Settings.h2
-rw-r--r--xbmc/utils/ScraperUrl.cpp2
-rw-r--r--xbmc/video/VideoThumbLoader.cpp12
-rw-r--r--xbmc/windowing/WinSystem.h11
-rw-r--r--xbmc/windowing/gbm/WinSystemGbm.cpp12
-rw-r--r--xbmc/windowing/gbm/WinSystemGbmGLESContext.cpp2
-rw-r--r--xbmc/windowing/win10/WinSystemWin10DX.h1
-rw-r--r--xbmc/windowing/windows/WinSystemWin32DX.h1
121 files changed, 2917 insertions, 520 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 67e10f71c6..bfd702f500 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -35,13 +35,9 @@ include(cmake/scripts/common/Macros.cmake)
include(cmake/scripts/common/ProjectMacros.cmake)
core_find_versions()
include(cmake/scripts/${CORE_SYSTEM_NAME}/PathSetup.cmake)
+include(cmake/scripts/common/CompilerSettings.cmake)
include(ExternalProject)
-# Languages and global compiler settings
-set(CMAKE_CXX_STANDARD 11)
-set(CMAKE_CXX_STANDARD_REQUIRED ON)
-set(CMAKE_CXX_EXTENSIONS OFF)
-set(CMAKE_ASM_FLAGS "${CMAKE_C_FLAGS} -x assembler-with-cpp")
# general
option(VERBOSE "Enable verbose output?" OFF)
diff --git a/addons/repository.xbmc.org/addon.xml b/addons/repository.xbmc.org/addon.xml
index c431c0fbca..a80f963e93 100644
--- a/addons/repository.xbmc.org/addon.xml
+++ b/addons/repository.xbmc.org/addon.xml
@@ -1,17 +1,17 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<addon id="repository.xbmc.org"
name="Kodi Add-on repository"
- version="3.1.5"
+ version="3.2.0"
provider-name="Team Kodi">
<requires>
<import addon="xbmc.addon" version="12.0.0"/>
</requires>
<extension point="xbmc.addon.repository">
<!-- Do not forget to bump add-on version when changing paths to force a repo refresh -->
- <info>http://mirrors.kodi.tv/addons/leia/addons.xml.gz</info>
- <checksum verify="sha256">http://mirrors.kodi.tv/addons/leia/addons.xml.gz?sha256</checksum>
- <datadir>https://mirrors.kodi.tv/addons/leia</datadir>
- <artdir>http://mirrors.kodi.tv/addons/leia</artdir>
+ <info>http://mirrors.kodi.tv/addons/matrix/addons.xml.gz</info>
+ <checksum verify="sha256">http://mirrors.kodi.tv/addons/matrix/addons.xml.gz?sha256</checksum>
+ <datadir>https://mirrors.kodi.tv/addons/matrix</datadir>
+ <artdir>http://mirrors.kodi.tv/addons/matrix</artdir>
<hashes>sha256</hashes>
</extension>
<extension point="xbmc.addon.metadata">
diff --git a/addons/resource.language.en_gb/resources/strings.po b/addons/resource.language.en_gb/resources/strings.po
index 24c1e5d635..c7365ab87c 100644
--- a/addons/resource.language.en_gb/resources/strings.po
+++ b/addons/resource.language.en_gb/resources/strings.po
@@ -9587,10 +9587,10 @@ msgctxt "#19071"
msgid "Update interval"
msgstr ""
-#. pvr settings "do not store epg data in local database" setting label
+#. pvr settings "store epg data in database" setting label
#: system/settings/settings.xml
msgctxt "#19072"
-msgid "Don't cache in local database"
+msgid "Store data in database"
msgstr ""
#. pvr settings "delay channel switch" setting label
@@ -18682,7 +18682,7 @@ msgstr ""
#: system/settings/settings.xml
msgctxt "#36223"
-msgid "By default, the guide data is cached in a local database to speed up importing on startup."
+msgid "Activate to store epg data in a database. This may speedup importing epg data on startup."
msgstr ""
#: system/settings/settings.xml
diff --git a/addons/screensaver.xbmc.builtin.black/addon.xml b/addons/screensaver.xbmc.builtin.black/addon.xml.in
index ed951a71e5..44ffa0600c 100644
--- a/addons/screensaver.xbmc.builtin.black/addon.xml
+++ b/addons/screensaver.xbmc.builtin.black/addon.xml.in
@@ -3,7 +3,7 @@
name="Black"
version="1.0.32"
provider-name="Team Kodi">
- <extension point="xbmc.ui.screensaver" library=""/>
+ <extension point="xbmc.ui.screensaver" library_@CORE_SYSTEM_NAME@="dummy.so"/>
<extension point="xbmc.addon.metadata">
<summary lang="af_ZA">Sluimerskerm wat jou skerm swart maak.</summary>
<summary lang="am_ET">መመልከቻ ማዳኛ የእርስዎን መመልከቻ ጥቁር ያደርገዋል </summary>
diff --git a/addons/screensaver.xbmc.builtin.dim/addon.xml b/addons/screensaver.xbmc.builtin.dim/addon.xml.in
index 963395d46a..c43cbd8330 100644
--- a/addons/screensaver.xbmc.builtin.dim/addon.xml
+++ b/addons/screensaver.xbmc.builtin.dim/addon.xml.in
@@ -3,7 +3,7 @@
name="Dim"
version="1.0.54"
provider-name="Team Kodi">
- <extension point="xbmc.ui.screensaver" library=""/>
+ <extension point="xbmc.ui.screensaver" library_@CORE_SYSTEM_NAME@="dummy.so"/>
<extension point="xbmc.addon.metadata">
<summary lang="af_ZA">Sluimerskerm wat jou skerm verdof</summary>
<summary lang="am_ET">መመልከቻ ማዳኛ የ እርስዎን መመልከቻ ፈዘዝ ያደርገዋል </summary>
diff --git a/addons/skin.estouchy/media/epg_archive.png b/addons/skin.estouchy/media/epg_archive.png
new file mode 100644
index 0000000000..bf02128d67
--- /dev/null
+++ b/addons/skin.estouchy/media/epg_archive.png
Binary files differ
diff --git a/addons/skin.estouchy/xml/ViewsPVR.xml b/addons/skin.estouchy/xml/ViewsPVR.xml
index a9290088c5..4b13e86584 100644
--- a/addons/skin.estouchy/xml/ViewsPVR.xml
+++ b/addons/skin.estouchy/xml/ViewsPVR.xml
@@ -324,6 +324,14 @@
<texture>epg_schedule.png</texture>
<visible>ListItem.HasTimer</visible>
</control>
+ <control type="image">
+ <posx>5</posx>
+ <posy>45</posy>
+ <width>20</width>
+ <height>20</height>
+ <texture>epg_archive.png</texture>
+ <visible>![ListItem.IsRecording | ListItem.HasTimer] + ListItem.IsPlayable</visible>
+ </control>
</itemlayout>
<focusedlayout width="40" height="65">
<control type="image" id="2">
@@ -370,6 +378,14 @@
<texture>epg_schedule.png</texture>
<visible>ListItem.HasTimer</visible>
</control>
+ <control type="image">
+ <posx>7</posx>
+ <posy>44</posy>
+ <width>15</width>
+ <height>15</height>
+ <texture>epg_archive.png</texture>
+ <visible>![ListItem.IsRecording | ListItem.HasTimer] + ListItem.IsPlayable</visible>
+ </control>
</focusedlayout>
</control>
</include>
diff --git a/addons/skin.estuary/media/icons/pvr/PVR-HasArchive.png b/addons/skin.estuary/media/icons/pvr/PVR-HasArchive.png
new file mode 100644
index 0000000000..1eebcf8a71
--- /dev/null
+++ b/addons/skin.estuary/media/icons/pvr/PVR-HasArchive.png
Binary files differ
diff --git a/addons/skin.estuary/media/windows/pvr/archive.png b/addons/skin.estuary/media/windows/pvr/archive.png
new file mode 100644
index 0000000000..a832a88821
--- /dev/null
+++ b/addons/skin.estuary/media/windows/pvr/archive.png
Binary files differ
diff --git a/addons/skin.estuary/xml/Home.xml b/addons/skin.estuary/xml/Home.xml
index 410eceb59b..6964c72db6 100644
--- a/addons/skin.estuary/xml/Home.xml
+++ b/addons/skin.estuary/xml/Home.xml
@@ -527,7 +527,7 @@
<orientation>vertical</orientation>
<pagecontrol>14010</pagecontrol>
<visible>Integer.IsGreater(Container(14100).NumItems,0) | Container(14100).IsUpdating</visible>
- <itemlayout width="330" height="396">
+ <itemlayout width="330" height="401">
<control type="group">
<top>130</top>
<include content="InfoWallMusicLayout">
@@ -536,7 +536,7 @@
</include>
</control>
</itemlayout>
- <focusedlayout width="330" height="396">
+ <focusedlayout width="330" height="401">
<control type="group">
<depth>DepthContentPopout</depth>
<top>130</top>
diff --git a/addons/skin.estuary/xml/Variables.xml b/addons/skin.estuary/xml/Variables.xml
index 5ae334f527..3bcb9945f8 100644
--- a/addons/skin.estuary/xml/Variables.xml
+++ b/addons/skin.estuary/xml/Variables.xml
@@ -3,6 +3,7 @@
<variable name="PVRStatusImageVar">
<value condition="ListItem.IsRecording">windows/pvr/record.png</value>
<value condition="ListItem.HasTimer | ListItem.HasTimerSchedule">windows/pvr/timer.png</value>
+ <value condition="ListItem.HasArchive">windows/pvr/archive.png</value>
</variable>
<variable name="AutoCompletionContentVar">
<value condition="System.HasAddon(plugin.program.autocompletion) + !System.HasHiddenInput">plugin://plugin.program.autocompletion?info=autocomplete&amp;&amp;id=$INFO[Control.GetLabel(312).index(1)]&amp;&amp;limit=9</value>
@@ -338,6 +339,7 @@
<value condition="ListItem.IsCollection">overlays/set.png</value>
<value condition="ListItem.IsPlaying">overlays/watched/OverlayPlaying-List.png</value>
<value condition="ListItem.IsResumable">overlays/watched/resume.png</value>
+ <value condition="ListItem.HasArchive">windows/pvr/archive.png</value>
<value condition="Integer.IsGreater(ListItem.Playcount,0)">$INFO[ListItem.Overlay]</value>
</variable>
<!-- Breadcrumbs -->
@@ -430,6 +432,7 @@
<value condition="ListItem.HasTimer + !ListItem.TimerIsActive">icons/pvr/PVR-HasTimerDisabled.png</value>
<value condition="ListItem.HasTimerSchedule">icons/pvr/PVR-HasTimerSchedule.png</value>
<value condition="ListItem.HasTimer">icons/pvr/PVR-HasTimer.png</value>
+ <value condition="ListItem.IsPlayable">icons/pvr/PVR-HasArchive.png</value>
</variable>
<variable name="SeasonEpisodeLabel">
<value condition="String.IsEmpty(ListItem.EpisodeName)">$INFO[ListItem.Season,S]$INFO[ListItem.Episode,E]</value>
diff --git a/cmake/addons/CMakeLists.txt b/cmake/addons/CMakeLists.txt
index 5fc798b545..8f0420f945 100644
--- a/cmake/addons/CMakeLists.txt
+++ b/cmake/addons/CMakeLists.txt
@@ -80,6 +80,8 @@ if (CMAKE_SYSTEM_NAME STREQUAL WindowsStore)
-DCMAKE_SYSTEM_VERSION=${CMAKE_SYSTEM_VERSION})
endif()
+include(${CORE_SOURCE_DIR}/cmake/scripts/common/CompilerSettings.cmake)
+
set(BUILD_ARGS -DCMAKE_PREFIX_PATH=${CMAKE_PREFIX_PATH}
-DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
-DPACKAGE_CONFIG_PATH=${ADDON_DEPENDS_PATH}/lib/pkgconfig
diff --git a/cmake/addons/depends/common/kodi-platform/kodi-platform.txt b/cmake/addons/depends/common/kodi-platform/kodi-platform.txt
index c553769683..de8cd225fe 100644
--- a/cmake/addons/depends/common/kodi-platform/kodi-platform.txt
+++ b/cmake/addons/depends/common/kodi-platform/kodi-platform.txt
@@ -1 +1 @@
-kodi-platform https://github.com/xbmc/kodi-platform e8574b883ffa2131f2eeb96ff3724d60b21130f7
+kodi-platform https://github.com/xbmc/kodi-platform 915da086fa7b4ea72796052a04ed6de95501b95c
diff --git a/cmake/scripts/common/CompilerSettings.cmake b/cmake/scripts/common/CompilerSettings.cmake
new file mode 100644
index 0000000000..48cc69bd65
--- /dev/null
+++ b/cmake/scripts/common/CompilerSettings.cmake
@@ -0,0 +1,6 @@
+# Languages and global compiler settings
+set(CMAKE_CXX_STANDARD 11)
+set(CMAKE_CXX_STANDARD_REQUIRED ON)
+set(CMAKE_CXX_EXTENSIONS OFF)
+set(CMAKE_ASM_FLAGS "${CMAKE_C_FLAGS} -x assembler-with-cpp")
+
diff --git a/cmake/treedata/common/subdirs.txt b/cmake/treedata/common/subdirs.txt
index 083e8ef314..cd82b5a0e4 100644
--- a/cmake/treedata/common/subdirs.txt
+++ b/cmake/treedata/common/subdirs.txt
@@ -11,6 +11,7 @@ xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance addons_kodi-addon-dev
xbmc/addons/kodi-addon-dev-kit/include/kodi/gui addons_kodi-addon-dev-kit_include_kodi_gui
xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/controls addons_kodi-addon-dev-kit_include_kodi_gui_controls
xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/dialogs addons_kodi-addon-dev-kit_include_kodi_gui_dialogs
+xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/gl addons_kodi-addon-dev-kit_include_kodi_gui_gl
xbmc/addons/kodi-addon-dev-kit/include/kodi/tools addons_kodi-addon-dev-kit_include_kodi_tools
xbmc/addons/settings addons_settings
xbmc/commons commons
diff --git a/cmake/treedata/optional/common/gbm.txt b/cmake/treedata/optional/common/gbm.txt
index 5d898d40b2..ff07e6fbc9 100644
--- a/cmake/treedata/optional/common/gbm.txt
+++ b/cmake/treedata/optional/common/gbm.txt
@@ -1,2 +1,3 @@
xbmc/cores/RetroPlayer/process/gbm cores/RetroPlayer/process/gbm # GBM
+xbmc/cores/VideoPlayer/Process/gbm cores/VideoPlayer/Process/gbm # GBM
xbmc/windowing/gbm windowing/gbm # GBM
diff --git a/system/settings/settings.xml b/system/settings/settings.xml
index b924e7d808..9df19c2d43 100755
--- a/system/settings/settings.xml
+++ b/system/settings/settings.xml
@@ -1391,7 +1391,7 @@
<default>false</default>
<control type="toggle" />
</setting>
- <setting id="epg.ignoredbforclient" type="boolean" label="19072" help="36223">
+ <setting id="epg.storeepgindatabase" type="boolean" label="19072" help="36223">
<level>2</level>
<default>false</default>
<control type="toggle" />
diff --git a/system/shaders/GL/1.2/gl_convolution-4x4.glsl b/system/shaders/GL/1.2/gl_convolution-4x4.glsl
index 0f580fea41..32d955d8fb 100644
--- a/system/shaders/GL/1.2/gl_convolution-4x4.glsl
+++ b/system/shaders/GL/1.2/gl_convolution-4x4.glsl
@@ -35,7 +35,7 @@ uniform sampler1D kernelTex;
half4 weight(float pos)
{
-#if (HAS_FLOAT_TEXTURE)
+#if defined(HAS_FLOAT_TEXTURE)
return texture1D(kernelTex, pos);
#else
return texture1D(kernelTex, pos) * 2.0 - 1.0;
diff --git a/system/shaders/GL/1.2/gl_convolution-6x6.glsl b/system/shaders/GL/1.2/gl_convolution-6x6.glsl
index 057d6dfed8..01328a0c11 100644
--- a/system/shaders/GL/1.2/gl_convolution-6x6.glsl
+++ b/system/shaders/GL/1.2/gl_convolution-6x6.glsl
@@ -35,7 +35,7 @@ uniform sampler1D kernelTex;
half3 weight(float pos)
{
-#if (HAS_FLOAT_TEXTURE)
+#if defined(HAS_FLOAT_TEXTURE)
return texture1D(kernelTex, pos).rgb;
#else
return texture1D(kernelTex, pos).rgb * 2.0 - 1.0;
diff --git a/system/shaders/GL/1.5/gl_convolution-4x4.glsl b/system/shaders/GL/1.5/gl_convolution-4x4.glsl
index 84e92c6967..144676ee27 100644
--- a/system/shaders/GL/1.5/gl_convolution-4x4.glsl
+++ b/system/shaders/GL/1.5/gl_convolution-4x4.glsl
@@ -18,7 +18,7 @@ uniform sampler1D kernelTex;
half4 weight(float pos)
{
-#if (HAS_FLOAT_TEXTURE)
+#if defined(HAS_FLOAT_TEXTURE)
return texture(kernelTex, pos);
#else
return texture(kernelTex, pos) * 2.0 - 1.0;
diff --git a/system/shaders/GL/1.5/gl_convolution-6x6.glsl b/system/shaders/GL/1.5/gl_convolution-6x6.glsl
index 950192d496..4af3744ae1 100644
--- a/system/shaders/GL/1.5/gl_convolution-6x6.glsl
+++ b/system/shaders/GL/1.5/gl_convolution-6x6.glsl
@@ -18,7 +18,7 @@ uniform sampler1D kernelTex;
half3 weight(float pos)
{
-#if (HAS_FLOAT_TEXTURE)
+#if defined(HAS_FLOAT_TEXTURE)
return texture(kernelTex, pos).rgb;
#else
return texture(kernelTex, pos).rgb * 2.0 - 1.0;
diff --git a/xbmc/Application.cpp b/xbmc/Application.cpp
index 1c4f5dfcd0..c0ae967e7e 100644
--- a/xbmc/Application.cpp
+++ b/xbmc/Application.cpp
@@ -3085,6 +3085,10 @@ void CApplication::OnPlayerCloseFile(const CFileItem &file, const CBookmark &boo
bool playCountUpdate = false;
float percent = 0.0f;
+ // Make sure we don't reset existing bookmark etc. on eg. player start failure
+ if (bookmark.timeInSeconds == 0.0f)
+ return;
+
if (m_stackHelper.GetRegisteredStack(fileItem) != nullptr && m_stackHelper.GetRegisteredStackTotalTimeMs(fileItem) > 0)
{
// regular stack case: we have to save the bookmark on the stack
diff --git a/xbmc/GUIInfoManager.cpp b/xbmc/GUIInfoManager.cpp
index f44a5f5515..bc533ac54b 100644
--- a/xbmc/GUIInfoManager.cpp
+++ b/xbmc/GUIInfoManager.cpp
@@ -3685,6 +3685,22 @@ const infomap container_str[] = {{ "property", CONTAINER_PROPERTY },
/// @return **True** when the selected programme is being recorded (PVR).
/// <p>
/// }
+/// \table_row3{ <b>`ListItem.IsPlayable`</b>,
+/// \anchor ListItem_IsPlayable
+/// _boolean_,
+/// @return **True** when the selected programme can be played (PVR)
+/// <p><hr>
+/// @skinning_v19 **[New Boolean Condition]** \link ListItem_IsPlayable `ListItem.IsPlayable`\endlink
+/// <p>
+/// }
+/// \table_row3{ <b>`ListItem.HasArchive`</b>,
+/// \anchor ListItem_HasArchive
+/// _boolean_,
+/// @return **True** when the selected channel has a server-side back buffer (PVR)
+/// <p><hr>
+/// @skinning_v19 **[New Boolean Condition]** \link ListItem_HasArchive `ListItem.HasArchive`\endlink
+/// <p>
+/// }
/// \table_row3{ <b>`ListItem.IsEncrypted`</b>,
/// \anchor ListItem_IsEncrypted
/// _boolean_,
@@ -5814,6 +5830,8 @@ const infomap listitem_labels[]= {{ "thumb", LISTITEM_THUMB },
{ "hasreminderrule", LISTITEM_HASREMINDERRULE },
{ "hasrecording", LISTITEM_HASRECORDING },
{ "isrecording", LISTITEM_ISRECORDING },
+ { "isplayable", LISTITEM_ISPLAYABLE },
+ { "hasarchive", LISTITEM_HASARCHIVE },
{ "inprogress", LISTITEM_INPROGRESS },
{ "isencrypted", LISTITEM_ISENCRYPTED },
{ "progress", LISTITEM_PROGRESS },
diff --git a/xbmc/addons/PVRClient.cpp b/xbmc/addons/PVRClient.cpp
index 364a7f3c42..1ec29dfe59 100644
--- a/xbmc/addons/PVRClient.cpp
+++ b/xbmc/addons/PVRClient.cpp
@@ -591,25 +591,13 @@ PVR_ERROR CPVRClient::RenameChannel(const CPVRChannelPtr &channel)
}, m_clientCapabilities.SupportsChannelSettings());
}
-PVR_ERROR CPVRClient::GetEPGForChannel(const std::shared_ptr<CPVREpgChannelData>& channelData,
+PVR_ERROR CPVRClient::GetEPGForChannel(int iChannelUid,
CPVREpg* epg,
time_t start /* = 0 */,
time_t end /* = 0 */,
bool bSaveInDb /* = false */)
{
- return DoAddonCall(__FUNCTION__, [this, channelData, epg, start, end, bSaveInDb](const AddonInstance* addon) {
-
- //! @todo PVR Addon API Change: Change GetEPGForChannel param from 'PVR_CHANNEL channel' to 'int iUniqueId'.
- PVR_CHANNEL addonChannel = {0};
-
- // mandatory
- addonChannel.iUniqueId = channelData->UniqueClientChannelId();
- addonChannel.bIsRadio = channelData->IsRadio();
-
- // optional
- strncpy(addonChannel.strChannelName, channelData->ChannelName().c_str(), sizeof(addonChannel.strChannelName) - 1);
- strncpy(addonChannel.strIconPath, channelData->IconPath().c_str(), sizeof(addonChannel.strIconPath) - 1);
- addonChannel.bIsHidden = channelData->IsHidden();
+ return DoAddonCall(__FUNCTION__, [this, iChannelUid, epg, start, end, bSaveInDb](const AddonInstance* addon) {
ADDON_HANDLE_STRUCT handle;
handle.callerAddress = this;
@@ -619,7 +607,7 @@ PVR_ERROR CPVRClient::GetEPGForChannel(const std::shared_ptr<CPVREpgChannelData>
int iPVRTimeCorrection = CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_iPVRTimeCorrection;
return addon->GetEPGForChannel(&handle,
- addonChannel,
+ iChannelUid,
start ? start - iPVRTimeCorrection : 0,
end ? end - iPVRTimeCorrection : 0);
}, m_clientCapabilities.SupportsEPG());
@@ -674,7 +662,6 @@ public:
iFlags = kodiTag->Flags();
iGenreType = kodiTag->GenreType();
iGenreSubType = kodiTag->GenreSubType();
- bNotify = kodiTag->Notify();
strTitle = m_strTitle.c_str();
strPlotOutline = m_strPlotOutline.c_str();
strPlot = m_strPlot.c_str();
@@ -1306,6 +1293,14 @@ PVR_ERROR CPVRClient::SetSpeed(int speed)
});
}
+PVR_ERROR CPVRClient::FillBuffer(bool mode)
+{
+ return DoAddonCall(__FUNCTION__, [mode](const AddonInstance* addon) {
+ addon->FillBuffer(mode);
+ return PVR_ERROR_NO_ERROR;
+ });
+}
+
PVR_ERROR CPVRClient::CanPauseStream(bool &bCanPause) const
{
bCanPause = false;
diff --git a/xbmc/addons/PVRClient.h b/xbmc/addons/PVRClient.h
index 604ad2b166..8bf7b01839 100644
--- a/xbmc/addons/PVRClient.h
+++ b/xbmc/addons/PVRClient.h
@@ -401,14 +401,14 @@ namespace PVR
/*!
* @brief Request an EPG table for a channel from the client.
- * @param channelData The data for the channel to get the EPG table for.
+ * @param iChannelUid The UID of the channel to get the EPG table for.
* @param epg The table to write the data to.
* @param start The start time to use.
* @param end The end time to use.
* @param bSaveInDb If true, tell the callback method to save any new entry in the database or not. see CAddonCallbacksPVR::PVRTransferEpgEntry()
* @return PVR_ERROR_NO_ERROR if the table has been fetched successfully.
*/
- PVR_ERROR GetEPGForChannel(const std::shared_ptr<CPVREpgChannelData>& channelData, CPVREpg* epg, time_t start = 0, time_t end = 0, bool bSaveInDb = false);
+ PVR_ERROR GetEPGForChannel(int iChannelUid, CPVREpg* epg, time_t start = 0, time_t end = 0, bool bSaveInDb = false);
/*!
* Tell the client the time frame to use when notifying epg events back to Kodi. The client might push epg events asynchronously
@@ -706,6 +706,14 @@ namespace PVR
*/
PVR_ERROR SetSpeed(int speed);
+ /*!
+ * @brief Notify the pvr addon/demuxer that Kodi wishes to fill demux queue
+ * @param mode for setting on/off
+ * @return PVR_ERROR_NO_ERROR on success, respective error code otherwise.
+ * @remarks Optional, and only used if addon has its own demuxer.
+ */
+ PVR_ERROR FillBuffer(bool mode);
+
//@}
/** @name PVR recording stream methods */
//@{
diff --git a/xbmc/addons/ScreenSaver.cpp b/xbmc/addons/ScreenSaver.cpp
index e2653042ba..27af4be8e2 100644
--- a/xbmc/addons/ScreenSaver.cpp
+++ b/xbmc/addons/ScreenSaver.cpp
@@ -11,9 +11,6 @@
#include "windowing/GraphicContext.h"
#include "windowing/WinSystem.h"
#include "utils/log.h"
-#ifdef TARGET_WINDOWS
-#include "rendering/dx/DeviceResources.h"
-#endif
namespace ADDON
{
@@ -26,13 +23,9 @@ CScreenSaver::CScreenSaver(BinaryAddonBasePtr addonBase)
m_profile = CSpecialProtocol::TranslatePath(Profile());
m_struct = {{0}};
-#ifdef TARGET_WINDOWS
- m_struct.props.device = DX::DeviceResources::Get()->GetD3DContext();
-#else
- m_struct.props.device = nullptr;
-#endif
m_struct.props.x = 0;
m_struct.props.y = 0;
+ m_struct.props.device = CServiceBroker::GetWinSystem()->GetHWContext();
m_struct.props.width = CServiceBroker::GetWinSystem()->GetGfxContext().GetWidth();
m_struct.props.height = CServiceBroker::GetWinSystem()->GetGfxContext().GetHeight();
m_struct.props.pixelRatio = CServiceBroker::GetWinSystem()->GetGfxContext().GetResInfo().fPixelRatio;
diff --git a/xbmc/addons/Visualization.cpp b/xbmc/addons/Visualization.cpp
index 2075ca18b2..e33e3b9fc6 100644
--- a/xbmc/addons/Visualization.cpp
+++ b/xbmc/addons/Visualization.cpp
@@ -11,9 +11,6 @@
#include "filesystem/SpecialProtocol.h"
#include "guilib/GUIWindowManager.h"
#include "utils/log.h"
-#if defined(TARGET_WINDOWS)
-#include "rendering/dx/DeviceResources.h"
-#endif
namespace ADDON
{
@@ -27,15 +24,11 @@ CVisualization::CVisualization(ADDON::BinaryAddonBasePtr addonBase, float x, flo
m_profilePath = CSpecialProtocol::TranslatePath(Profile());
m_struct = {{0}};
-#if defined(TARGET_WINDOWS)
- m_struct.props.device = DX::DeviceResources::Get()->GetD3DContext();
-#else
- m_struct.props.device = nullptr;
-#endif
m_struct.props.x = static_cast<int>(x);
m_struct.props.y = static_cast<int>(y);
m_struct.props.width = static_cast<int>(w);
m_struct.props.height = static_cast<int>(h);
+ m_struct.props.device = CServiceBroker::GetWinSystem()->GetHWContext();
m_struct.props.pixelRatio = CServiceBroker::GetWinSystem()->GetGfxContext().GetResInfo().fPixelRatio;
m_struct.props.name = m_name.c_str();
m_struct.props.presets = m_presetsPath.c_str();
diff --git a/xbmc/addons/binary-addons/AddonDll.cpp b/xbmc/addons/binary-addons/AddonDll.cpp
index 2fb2c2cd84..2dd19ccde4 100644
--- a/xbmc/addons/binary-addons/AddonDll.cpp
+++ b/xbmc/addons/binary-addons/AddonDll.cpp
@@ -28,6 +28,7 @@
#include "Util.h"
// Global addon callback handle classes
+#include "addons/interfaces/AudioEngine.h"
#include "addons/interfaces/Filesystem.h"
#include "addons/interfaces/General.h"
#include "addons/interfaces/Network.h"
@@ -559,6 +560,7 @@ bool CAddonDll::InitInterface(KODI_HANDLE firstKodiInstance)
m_interface.toAddon = (KodiToAddonFuncTable_Addon*) calloc(1, sizeof(KodiToAddonFuncTable_Addon));
Interface_General::Init(&m_interface);
+ Interface_AudioEngine::Init(&m_interface);
Interface_Filesystem::Init(&m_interface);
Interface_Network::Init(&m_interface);
Interface_GUIGeneral::Init(&m_interface);
@@ -573,6 +575,7 @@ void CAddonDll::DeInitInterface()
Interface_GUIGeneral::DeInit(&m_interface);
Interface_Network::DeInit(&m_interface);
Interface_Filesystem::DeInit(&m_interface);
+ Interface_AudioEngine::DeInit(&m_interface);
Interface_General::DeInit(&m_interface);
if (m_interface.libBasePath)
diff --git a/xbmc/addons/interfaces/AudioEngine.cpp b/xbmc/addons/interfaces/AudioEngine.cpp
new file mode 100644
index 0000000000..99dbdbd4ad
--- /dev/null
+++ b/xbmc/addons/interfaces/AudioEngine.cpp
@@ -0,0 +1,382 @@
+/*
+ * Copyright (C) 2005-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#include "AudioEngine.h"
+
+#include "ServiceBroker.h"
+#include "addons/kodi-addon-dev-kit/include/kodi/AddonBase.h"
+#include "cores/AudioEngine/Interfaces/AE.h"
+#include "cores/AudioEngine/Interfaces/AEStream.h"
+#include "cores/AudioEngine/Utils/AEChannelData.h"
+#include "cores/AudioEngine/Utils/AEStreamData.h"
+#include "utils/log.h"
+
+using namespace kodi; // addon-dev-kit namespace
+using namespace kodi::audioengine; // addon-dev-kit namespace
+
+namespace ADDON
+{
+
+void Interface_AudioEngine::Init(AddonGlobalInterface* addonInterface)
+{
+ addonInterface->toKodi->kodi_audioengine = static_cast<AddonToKodiFuncTable_kodi_audioengine*>(malloc(sizeof(AddonToKodiFuncTable_kodi_audioengine)));
+
+ // write KODI audio DSP specific add-on function addresses to callback table
+ addonInterface->toKodi->kodi_audioengine->make_stream = audioengine_make_stream;
+ addonInterface->toKodi->kodi_audioengine->free_stream = audioengine_free_stream;
+ addonInterface->toKodi->kodi_audioengine->get_current_sink_format = audioengine_get_current_sink_format;
+
+ // AEStream add-on function callback table
+ addonInterface->toKodi->kodi_audioengine->aestream_get_space = aestream_get_space;
+ addonInterface->toKodi->kodi_audioengine->aestream_add_data = aestream_add_data;
+ addonInterface->toKodi->kodi_audioengine->aestream_get_delay = aestream_get_delay;
+ addonInterface->toKodi->kodi_audioengine->aestream_is_buffering = aestream_is_buffering;
+ addonInterface->toKodi->kodi_audioengine->aestream_get_cache_time = aestream_get_cache_time;
+ addonInterface->toKodi->kodi_audioengine->aestream_get_cache_total = aestream_get_cache_total;
+ addonInterface->toKodi->kodi_audioengine->aestream_pause = aestream_pause;
+ addonInterface->toKodi->kodi_audioengine->aestream_resume = aestream_resume;
+ addonInterface->toKodi->kodi_audioengine->aestream_drain = aestream_drain;
+ addonInterface->toKodi->kodi_audioengine->aestream_is_draining = aestream_is_draining;
+ addonInterface->toKodi->kodi_audioengine->aestream_is_drained = aestream_is_drained;
+ addonInterface->toKodi->kodi_audioengine->aestream_flush = aestream_flush;
+ addonInterface->toKodi->kodi_audioengine->aestream_get_volume = aestream_get_volume;
+ addonInterface->toKodi->kodi_audioengine->aestream_set_volume = aestream_set_volume;
+ addonInterface->toKodi->kodi_audioengine->aestream_get_amplification = aestream_get_amplification;
+ addonInterface->toKodi->kodi_audioengine->aestream_set_amplification = aestream_set_amplification;
+ addonInterface->toKodi->kodi_audioengine->aestream_get_frame_size = aestream_get_frame_size;
+ addonInterface->toKodi->kodi_audioengine->aestream_get_channel_count = aestream_get_channel_count;
+ addonInterface->toKodi->kodi_audioengine->aestream_get_sample_rate = aestream_get_sample_rate;
+ addonInterface->toKodi->kodi_audioengine->aestream_get_data_format = aestream_get_data_format;
+ addonInterface->toKodi->kodi_audioengine->aestream_get_resample_ratio = aestream_get_resample_ratio;
+ addonInterface->toKodi->kodi_audioengine->aestream_set_resample_ratio = aestream_set_resample_ratio;
+}
+
+void Interface_AudioEngine::DeInit(AddonGlobalInterface* addonInterface)
+{
+ if (addonInterface->toKodi) /* <-- Safe check, needed so long old addon way is present */
+ {
+ free(addonInterface->toKodi->kodi_audioengine);
+ addonInterface->toKodi->kodi_audioengine = nullptr;
+ }
+}
+
+AEStreamHandle* Interface_AudioEngine::audioengine_make_stream(void* kodiBase, AudioEngineFormat* streamFormat, unsigned int options)
+{
+ if (!kodiBase || !streamFormat)
+ {
+ CLog::Log(LOGERROR, "Interface_AudioEngine::{} - invalid stream data (kodiBase='%p', streamFormat='%p')",
+ __FUNCTION__, kodiBase, static_cast<void*>(streamFormat));
+ return nullptr;
+ }
+
+ AEAudioFormat format;
+ format.m_dataFormat = streamFormat->m_dataFormat;
+ format.m_sampleRate = streamFormat->m_sampleRate;
+ format.m_channelLayout = streamFormat->m_channels;
+
+ /* Translate addon options to kodi's options */
+ int kodiOption = 0;
+ if (options & AUDIO_STREAM_FORCE_RESAMPLE)
+ kodiOption |= AESTREAM_FORCE_RESAMPLE;
+ if (options & AUDIO_STREAM_PAUSED)
+ kodiOption |= AESTREAM_PAUSED;
+ if (options & AUDIO_STREAM_AUTOSTART)
+ kodiOption |= AESTREAM_AUTOSTART;
+
+ return CServiceBroker::GetActiveAE()->MakeStream(format, kodiOption);
+}
+
+void Interface_AudioEngine::audioengine_free_stream(void* kodiBase, AEStreamHandle* streamHandle)
+{
+ if (!kodiBase || !streamHandle)
+ {
+ CLog::Log(LOGERROR, "Interface_AudioEngine::{} - invalid stream data (kodiBase='%p', streamHandle='%p')", __FUNCTION__, kodiBase, streamHandle);
+ return;
+ }
+
+ CServiceBroker::GetActiveAE()->FreeStream(static_cast<IAEStream*>(streamHandle), true);
+}
+
+bool Interface_AudioEngine::audioengine_get_current_sink_format(void* kodiBase, AudioEngineFormat *format)
+{
+ if (!kodiBase || !format)
+ {
+ CLog::Log(LOGERROR, "Interface_AudioEngine::{} - invalid stream data (kodiBase='%p', format='%p')", __FUNCTION__, kodiBase, static_cast<void*>(format));
+ return false;
+ }
+
+ AEAudioFormat sinkFormat;
+ if (!CServiceBroker::GetActiveAE()->GetCurrentSinkFormat(sinkFormat))
+ {
+ CLog::Log(LOGERROR, "Interface_AudioEngine::{} - failed to get current sink format from AE!", __FUNCTION__);
+ return false;
+ }
+
+ format->m_channelCount = sinkFormat.m_channelLayout.Count();
+ for (unsigned int ch = 0; ch < format->m_channelCount; ++ch)
+ {
+ format->m_channels[ch] = sinkFormat.m_channelLayout[ch];
+ }
+
+ format->m_dataFormat = sinkFormat.m_dataFormat;
+ format->m_sampleRate = sinkFormat.m_sampleRate;
+ format->m_frames = sinkFormat.m_frames;
+ format->m_frameSize = sinkFormat.m_frameSize;
+
+ return true;
+}
+
+unsigned int Interface_AudioEngine::aestream_get_space(void* kodiBase, AEStreamHandle* streamHandle)
+{
+ if (!kodiBase || !streamHandle)
+ {
+ CLog::Log(LOGERROR, "Interface_AudioEngine::{} - invalid stream data (kodiBase='%p', streamHandle='%p')", __FUNCTION__, kodiBase, streamHandle);
+ return 0;
+ }
+
+ return static_cast<IAEStream*>(streamHandle)->GetSpace();
+}
+
+unsigned int Interface_AudioEngine::aestream_add_data(void* kodiBase, AEStreamHandle* streamHandle, uint8_t* const *data,
+ unsigned int offset, unsigned int frames, double pts, bool hasDownmix,
+ double centerMixLevel)
+{
+ if (!kodiBase || !streamHandle)
+ {
+ CLog::Log(LOGERROR, "Interface_AudioEngine::{} - invalid stream data (kodiBase='%p', streamHandle='%p')", __FUNCTION__, kodiBase, streamHandle);
+ return 0;
+ }
+
+ IAEStream::ExtData extData;
+ extData.pts = pts;
+ extData.hasDownmix = hasDownmix;
+ extData.centerMixLevel = centerMixLevel;
+ return static_cast<IAEStream*>(streamHandle)->AddData(data, offset, frames, &extData);
+}
+
+double Interface_AudioEngine::aestream_get_delay(void* kodiBase, AEStreamHandle* streamHandle)
+{
+ if (!kodiBase || !streamHandle)
+ {
+ CLog::Log(LOGERROR, "Interface_AudioEngine::{} - invalid stream data (kodiBase='%p', streamHandle='%p')", __FUNCTION__, kodiBase, streamHandle);
+ return -1.0;
+ }
+
+ return static_cast<IAEStream*>(streamHandle)->GetDelay();
+}
+
+bool Interface_AudioEngine::aestream_is_buffering(void* kodiBase, AEStreamHandle* streamHandle)
+{
+ if (!kodiBase || !streamHandle)
+ {
+ CLog::Log(LOGERROR, "Interface_AudioEngine::{} - invalid stream data (kodiBase='%p', streamHandle='%p')", __FUNCTION__, kodiBase, streamHandle);
+ return false;
+ }
+
+ return static_cast<IAEStream*>(streamHandle)->IsBuffering();
+}
+
+double Interface_AudioEngine::aestream_get_cache_time(void* kodiBase, AEStreamHandle* streamHandle)
+{
+ if (!kodiBase || !streamHandle)
+ {
+ CLog::Log(LOGERROR, "Interface_AudioEngine::{} - invalid stream data (kodiBase='%p', streamHandle='%p')", __FUNCTION__, kodiBase, streamHandle);
+ return -1.0;
+ }
+
+ return static_cast<IAEStream*>(streamHandle)->GetCacheTime();
+}
+
+double Interface_AudioEngine::aestream_get_cache_total(void* kodiBase, AEStreamHandle* streamHandle)
+{
+ if (!kodiBase || !streamHandle)
+ {
+ CLog::Log(LOGERROR, "Interface_AudioEngine::{} - invalid stream data (kodiBase='%p', streamHandle='%p')", __FUNCTION__, kodiBase, streamHandle);
+ return -1.0;
+ }
+
+ return static_cast<IAEStream*>(streamHandle)->GetCacheTotal();
+}
+
+void Interface_AudioEngine::aestream_pause(void* kodiBase, AEStreamHandle* streamHandle)
+{
+ if (!kodiBase || !streamHandle)
+ {
+ CLog::Log(LOGERROR, "Interface_AudioEngine::{} - invalid stream data (kodiBase='%p', streamHandle='%p')", __FUNCTION__, kodiBase, streamHandle);
+ return;
+ }
+
+ static_cast<IAEStream*>(streamHandle)->Pause();
+}
+
+void Interface_AudioEngine::aestream_resume(void* kodiBase, AEStreamHandle* streamHandle)
+{
+ if (!kodiBase || !streamHandle)
+ {
+ CLog::Log(LOGERROR, "Interface_AudioEngine::{} - invalid stream data (kodiBase='%p', streamHandle='%p')", __FUNCTION__, kodiBase, streamHandle);
+ return;
+ }
+
+ static_cast<IAEStream*>(streamHandle)->Resume();
+}
+
+void Interface_AudioEngine::aestream_drain(void* kodiBase, AEStreamHandle* streamHandle, bool wait)
+{
+ if (!kodiBase || !streamHandle)
+ {
+ CLog::Log(LOGERROR, "Interface_AudioEngine::{} - invalid stream data (kodiBase='%p', streamHandle='%p')", __FUNCTION__, kodiBase, streamHandle);
+ return;
+ }
+
+ static_cast<IAEStream*>(streamHandle)->Drain(wait);
+}
+
+bool Interface_AudioEngine::aestream_is_draining(void* kodiBase, AEStreamHandle* streamHandle)
+{
+ if (!kodiBase || !streamHandle)
+ {
+ CLog::Log(LOGERROR, "Interface_AudioEngine::{} - invalid stream data (kodiBase='%p', streamHandle='%p')", __FUNCTION__, kodiBase, streamHandle);
+ return false;
+ }
+
+ return static_cast<IAEStream*>(streamHandle)->IsDraining();
+}
+
+bool Interface_AudioEngine::aestream_is_drained(void* kodiBase, AEStreamHandle* streamHandle)
+{
+ if (!kodiBase || !streamHandle)
+ {
+ CLog::Log(LOGERROR, "Interface_AudioEngine::{} - invalid stream data (kodiBase='%p', streamHandle='%p')", __FUNCTION__, kodiBase, streamHandle);
+ return false;
+ }
+
+ return static_cast<IAEStream*>(streamHandle)->IsDrained();
+}
+
+void Interface_AudioEngine::aestream_flush(void* kodiBase, AEStreamHandle* streamHandle)
+{
+ if (!kodiBase || !streamHandle)
+ {
+ CLog::Log(LOGERROR, "Interface_AudioEngine::{} - invalid stream data (kodiBase='%p', streamHandle='%p')", __FUNCTION__, kodiBase, streamHandle);
+ return;
+ }
+
+ static_cast<IAEStream*>(streamHandle)->Flush();
+}
+
+float Interface_AudioEngine::aestream_get_volume(void* kodiBase, AEStreamHandle* streamHandle)
+{
+ if (!kodiBase || !streamHandle)
+ {
+ CLog::Log(LOGERROR, "Interface_AudioEngine::{} - invalid stream data (kodiBase='%p', streamHandle='%p')", __FUNCTION__, kodiBase, streamHandle);
+ return -1.0f;
+ }
+
+ return static_cast<IAEStream*>(streamHandle)->GetVolume();
+}
+
+void Interface_AudioEngine::aestream_set_volume(void* kodiBase, AEStreamHandle* streamHandle, float volume)
+{
+ if (!kodiBase || !streamHandle)
+ {
+ CLog::Log(LOGERROR, "Interface_AudioEngine::{} - invalid stream data (kodiBase='%p', streamHandle='%p')", __FUNCTION__, kodiBase, streamHandle);
+ return;
+ }
+
+ static_cast<IAEStream*>(streamHandle)->SetVolume(volume);
+}
+
+float Interface_AudioEngine::aestream_get_amplification(void* kodiBase, AEStreamHandle* streamHandle)
+{
+ if (!kodiBase || !streamHandle)
+ {
+ CLog::Log(LOGERROR, "Interface_AudioEngine::{} - invalid stream data (kodiBase='%p', streamHandle='%p')", __FUNCTION__, kodiBase, streamHandle);
+ return -1.0f;
+ }
+
+ return static_cast<IAEStream*>(streamHandle)->GetAmplification();
+}
+
+void Interface_AudioEngine::aestream_set_amplification(void* kodiBase, AEStreamHandle* streamHandle, float amplify)
+{
+ if (!kodiBase || !streamHandle)
+ {
+ CLog::Log(LOGERROR, "Interface_AudioEngine::{} - invalid stream data (kodiBase='%p', streamHandle='%p')", __FUNCTION__, kodiBase, streamHandle);
+ return;
+ }
+
+ static_cast<IAEStream*>(streamHandle)->SetAmplification(amplify);
+}
+
+unsigned int Interface_AudioEngine::aestream_get_frame_size(void* kodiBase, AEStreamHandle* streamHandle)
+{
+ if (!kodiBase || !streamHandle)
+ {
+ CLog::Log(LOGERROR, "Interface_AudioEngine::{} - invalid stream data (kodiBase='%p', streamHandle='%p')", __FUNCTION__, kodiBase, streamHandle);
+ return 0;
+ }
+
+ return static_cast<IAEStream*>(streamHandle)->GetFrameSize();
+}
+
+unsigned int Interface_AudioEngine::aestream_get_channel_count(void* kodiBase, AEStreamHandle* streamHandle)
+{
+ if (!kodiBase || !streamHandle)
+ {
+ CLog::Log(LOGERROR, "Interface_AudioEngine::{} - invalid stream data (kodiBase='%p', streamHandle='%p')", __FUNCTION__, kodiBase, streamHandle);
+ return 0;
+ }
+
+ return static_cast<IAEStream*>(streamHandle)->GetChannelCount();
+}
+
+unsigned int Interface_AudioEngine::aestream_get_sample_rate(void* kodiBase, AEStreamHandle* streamHandle)
+{
+ if (!kodiBase || !streamHandle)
+ {
+ CLog::Log(LOGERROR, "Interface_AudioEngine::{} - invalid stream data (kodiBase='%p', streamHandle='%p')", __FUNCTION__, kodiBase, streamHandle);
+ return 0;
+ }
+
+ return static_cast<IAEStream*>(streamHandle)->GetSampleRate();
+}
+
+AEDataFormat Interface_AudioEngine::aestream_get_data_format(void* kodiBase, AEStreamHandle* streamHandle)
+{
+ if (!kodiBase || !streamHandle)
+ {
+ CLog::Log(LOGERROR, "Interface_AudioEngine::{} - invalid stream data (kodiBase='%p', streamHandle='%p')", __FUNCTION__, kodiBase, streamHandle);
+ return AE_FMT_INVALID;
+ }
+
+ return static_cast<IAEStream*>(streamHandle)->GetDataFormat();
+}
+
+double Interface_AudioEngine::aestream_get_resample_ratio(void* kodiBase, AEStreamHandle* streamHandle)
+{
+ if (!kodiBase || !streamHandle)
+ {
+ CLog::Log(LOGERROR, "Interface_AudioEngine::{} - invalid stream data (kodiBase='%p', streamHandle='%p')", __FUNCTION__, kodiBase, streamHandle);
+ return -1.0f;
+ }
+
+ return static_cast<IAEStream*>(streamHandle)->GetResampleRatio();
+}
+
+void Interface_AudioEngine::aestream_set_resample_ratio(void* kodiBase, AEStreamHandle* streamHandle, double ratio)
+{
+ if (!kodiBase || !streamHandle)
+ {
+ CLog::Log(LOGERROR, "Interface_AudioEngine::{} - invalid stream data (kodiBase='%p', streamHandle='%p')", __FUNCTION__, kodiBase, streamHandle);
+ return;
+ }
+
+ static_cast<IAEStream*>(streamHandle)->SetResampleRatio(ratio);
+}
+
+} /* namespace ADDON */
diff --git a/xbmc/addons/interfaces/AudioEngine.h b/xbmc/addons/interfaces/AudioEngine.h
new file mode 100644
index 0000000000..434cda6208
--- /dev/null
+++ b/xbmc/addons/interfaces/AudioEngine.h
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2005-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#pragma once
+
+#include "addons/kodi-addon-dev-kit/include/kodi/AudioEngine.h"
+
+namespace ADDON
+{
+
+struct Interface_AudioEngine
+{
+ static void Init(AddonGlobalInterface* addonInterface);
+ static void DeInit(AddonGlobalInterface* addonInterface);
+
+ /**
+ * Creates and returns a new handle to an IAEStream in the format specified, this function should never fail
+ * @param[in] streamFormat Format to use for stream
+ * @param[in] options A bit field of stream options (see: enum AEStreamOptions)
+ * @return a new Handle to an IAEStream that will accept data in the requested format
+ */
+ static AEStreamHandle* audioengine_make_stream(void *kodiBase, AudioEngineFormat* streamFormat, unsigned int options);
+
+ /**
+ * This method will remove the specifyed stream from the engine.
+ * For OSX/IOS this is essential to reconfigure the audio output.
+ * @param[in] streamHandle The stream to be altered
+ */
+ static void audioengine_free_stream(void *kodiBase, AEStreamHandle* streamHandle);
+
+ /**
+ * Get the current sink data format
+ *
+ * @param[in] sinkFormat sink data format. For more details see AudioEngineFormat.
+ * @return Returns true on success, else false.
+ */
+ static bool audioengine_get_current_sink_format(void* kodiBase, AudioEngineFormat *sinkFormat);
+
+ /**
+ * Returns the amount of space available in the stream
+ * @return The number of bytes AddData will consume
+ */
+ static unsigned int aestream_get_space(void* kodiBase, AEStreamHandle* streamHandle);
+
+ /**
+ * Add planar or interleaved PCM data to the stream
+ * @param[in] data array of pointers to the planes
+ * @param[in] offset to frame in frames
+ * @param[in] frames number of frames
+ * @return The number of frames consumed
+ */
+ static unsigned int aestream_add_data(void* kodiBase, AEStreamHandle* streamHandle, uint8_t* const *data,
+ unsigned int offset, unsigned int frames, double pts, bool hasDownmix,
+ double centerMixLevel);
+
+ /**
+ * Returns the time in seconds that it will take
+ * for the next added packet to be heard from the speakers.
+ * @return seconds
+ */
+ static double aestream_get_delay(void* kodiBase, AEStreamHandle* streamHandle);
+
+ /**
+ * Returns if the stream is buffering
+ * @return True if the stream is buffering
+ */
+ static bool aestream_is_buffering(void* kodiBase, AEStreamHandle* streamHandle);
+
+ /**
+ * Returns the time in seconds that it will take
+ * to underrun the cache if no sample is added.
+ * @return seconds
+ */
+ static double aestream_get_cache_time(void* kodiBase, AEStreamHandle* streamHandle);
+
+ /**
+ * Returns the total time in seconds of the cache
+ * @return seconds
+ */
+ static double aestream_get_cache_total(void* kodiBase, AEStreamHandle* streamHandle);
+
+ /**
+ * Pauses the stream playback
+ */
+ static void aestream_pause(void* kodiBase, AEStreamHandle* streamHandle);
+
+ /**
+ * Resumes the stream after pausing
+ */
+ static void aestream_resume(void* kodiBase, AEStreamHandle* streamHandle);
+
+ /**
+ * Start draining the stream
+ * @note Once called AddData will not consume more data.
+ */
+ static void aestream_drain(void* kodiBase, AEStreamHandle* streamHandle, bool wait);
+
+ /**
+ * Returns true if the is stream draining
+ */
+ static bool aestream_is_draining(void* kodiBase, AEStreamHandle* streamHandle);
+
+ /**
+ * Returns true if the is stream has finished draining
+ */
+ static bool aestream_is_drained(void* kodiBase, AEStreamHandle* streamHandle);
+
+ /**
+ * Flush all buffers dropping the audio data
+ */
+ static void aestream_flush(void* kodiBase, AEStreamHandle* streamHandle);
+
+ /**
+ * Return the stream's current volume level
+ * @return The volume level between 0.0 and 1.0
+ */
+ static float aestream_get_volume(void* kodiBase, AEStreamHandle* streamHandle);
+
+ /**
+ * Set the stream's volume level
+ * @param volume The new volume level between 0.0 and 1.0
+ */
+ static void aestream_set_volume(void* kodiBase, AEStreamHandle* streamHandle, float volume);
+
+ /**
+ * Gets the stream's volume amplification in linear units.
+ * @return The volume amplification factor between 1.0 and 1000.0
+ */
+ static float aestream_get_amplification(void* kodiBase, AEStreamHandle* streamHandle);
+
+ /**
+ * Sets the stream's volume amplification in linear units.
+ * @param amplify The volume amplification factor between 1.0 and 1000.0
+ */
+ static void aestream_set_amplification(void* kodiBase, AEStreamHandle* streamHandle, float amplify);
+
+ /**
+ * Returns the size of one audio frame in bytes (channelCount * resolution)
+ * @return The size in bytes of one frame
+ */
+ static unsigned int aestream_get_frame_size(void* kodiBase, AEStreamHandle* streamHandle);
+
+ /**
+ * Returns the number of channels the stream is configured to accept
+ * @return The channel count
+ */
+ static unsigned int aestream_get_channel_count(void* kodiBase, AEStreamHandle* streamHandle);
+
+ /**
+ * Returns the stream's sample rate, if the stream is using a dynamic sample rate, this value will NOT reflect any changes made by calls to SetResampleRatio()
+ * @return The stream's sample rate (eg, 48000)
+ */
+ static unsigned int aestream_get_sample_rate(void* kodiBase, AEStreamHandle* streamHandle);
+
+ /**
+ * Return the data format the stream has been configured with
+ * @return The stream's data format (eg, AE_FMT_S16LE)
+ */
+ static AEDataFormat aestream_get_data_format(void* kodiBase, AEStreamHandle* streamHandle);
+
+ /**
+ * Return the resample ratio
+ * @note This will return an undefined value if the stream is not resampling
+ * @return the current resample ratio or undefined if the stream is not resampling
+ */
+ static double aestream_get_resample_ratio(void* kodiBase, AEStreamHandle* streamHandle);
+
+ /**
+ * Sets the resample ratio
+ * @note This function may return false if the stream is not resampling, if you wish to use this be sure to set the AESTREAM_FORCE_RESAMPLE option
+ * @param[in] ratio the new sample rate ratio, calculated by ((double)desiredRate / (double)GetSampleRate())
+ */
+ static void aestream_set_resample_ratio(void* kodiBase, AEStreamHandle* streamHandle, double ratio);
+};
+
+} /* namespace ADDON */
diff --git a/xbmc/addons/interfaces/CMakeLists.txt b/xbmc/addons/interfaces/CMakeLists.txt
index a064cf2d5d..cd2f330a97 100644
--- a/xbmc/addons/interfaces/CMakeLists.txt
+++ b/xbmc/addons/interfaces/CMakeLists.txt
@@ -1,9 +1,11 @@
set(SOURCES AddonInterfaces.cpp
+ AudioEngine.cpp
General.cpp
Filesystem.cpp
Network.cpp)
set(HEADERS AddonInterfaces.h
+ AudioEngine.h
General.h
Filesystem.h
Network.h)
diff --git a/xbmc/addons/interfaces/GUI/General.cpp b/xbmc/addons/interfaces/GUI/General.cpp
index ab5ede29c5..f03a040dd6 100644
--- a/xbmc/addons/interfaces/GUI/General.cpp
+++ b/xbmc/addons/interfaces/GUI/General.cpp
@@ -91,6 +91,7 @@ void Interface_GUIGeneral::Init(AddonGlobalInterface* addonInterface)
addonInterface->toKodi->kodi_gui->general->get_video_resolution = get_video_resolution;
addonInterface->toKodi->kodi_gui->general->get_current_window_dialog_id = get_current_window_dialog_id;
addonInterface->toKodi->kodi_gui->general->get_current_window_id = get_current_window_id;
+ addonInterface->toKodi->kodi_gui->general->get_hw_context = get_hw_context;
}
void Interface_GUIGeneral::DeInit(AddonGlobalInterface* addonInterface)
@@ -213,6 +214,11 @@ int Interface_GUIGeneral::get_current_window_id(void* kodiBase)
return CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow();
}
+void* Interface_GUIGeneral::get_hw_context(void* kodiBase)
+{
+ return CServiceBroker::GetWinSystem()->GetHWContext();
+}
+
//@}
} /* namespace ADDON */
diff --git a/xbmc/addons/interfaces/GUI/General.h b/xbmc/addons/interfaces/GUI/General.h
index fc1170cc5c..0042329b0f 100644
--- a/xbmc/addons/interfaces/GUI/General.h
+++ b/xbmc/addons/interfaces/GUI/General.h
@@ -48,6 +48,7 @@ namespace ADDON
static int get_video_resolution(void* kodiBase);
static int get_current_window_dialog_id(void* kodiBase);
static int get_current_window_id(void* kodiBase);
+ static void* get_hw_context(void* kodiBase);
//@}
private:
diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/AddonBase.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/AddonBase.h
index db39f8693d..d7da3ac388 100644
--- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/AddonBase.h
+++ b/xbmc/addons/kodi-addon-dev-kit/include/kodi/AddonBase.h
@@ -11,6 +11,7 @@
#include <stdarg.h> /* va_list, va_start, va_arg, va_end */
#include <cstdlib>
#include <cstring>
+#include <memory>
#include <stdexcept>
#include <string>
#include <vector>
@@ -61,6 +62,7 @@
namespace kodi { namespace addon { class CAddonBase; }}
namespace kodi { namespace addon { class IAddonInstance; }}
+namespace kodi { namespace gui { struct IRenderHelper; }}
extern "C" {
@@ -334,6 +336,9 @@ public:
return CreateInstance(instanceType, instanceID, instance, addonInstance);
}
+ /* Background helper for GUI render systems, e.g. Screensaver or Visualization */
+ std::shared_ptr<kodi::gui::IRenderHelper> m_renderHelper;
+
/* Global variables of class */
static AddonGlobalInterface* m_interface; // Interface function table to hold addresses on add-on and from kodi
static std::string m_strGlobalApiVersion;
diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/AudioEngine.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/AudioEngine.h
new file mode 100644
index 0000000000..051d4955d6
--- /dev/null
+++ b/xbmc/addons/kodi-addon-dev-kit/include/kodi/AudioEngine.h
@@ -0,0 +1,586 @@
+/*
+ * Copyright (C) 2005-2019 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#pragma once
+
+#include "AddonBase.h"
+
+#ifdef BUILD_KODI_ADDON
+#include "AEChannelData.h"
+#else
+#include "cores/AudioEngine/Utils/AEChannelData.h"
+#endif
+
+//==============================================================================
+///
+/// \defgroup cpp_kodi_audioengine Interface - kodi::audioengine
+/// \ingroup cpp
+/// @brief **Audio engine functions**
+///
+///
+/// It has the header \ref AudioEngine.h "#include <kodi/AudioEngine.h>" be included
+/// to enjoy it.
+///
+//------------------------------------------------------------------------------
+
+//==============================================================================
+///
+/// \defgroup cpp_kodi_audioengine_Defs Definitions, structures and enumerators
+/// \ingroup cpp_kodi_audioengine
+/// @brief **Library definition values**
+///
+//------------------------------------------------------------------------------
+
+extern "C"
+{
+
+//============================================================================
+/// \ingroup cpp_kodi_audioengine_Defs
+/// @brief Bit options to pass to CAddonAEStream
+///
+typedef enum AudioEngineStreamOptions
+{
+ /// force resample even if rates match
+ AUDIO_STREAM_FORCE_RESAMPLE = 1 << 0,
+ /// create the stream paused
+ AUDIO_STREAM_PAUSED = 1 << 1,
+ /// autostart the stream when enough data is buffered
+ AUDIO_STREAM_AUTOSTART = 1 << 2,
+} AudioEngineStreamOptions;
+//----------------------------------------------------------------------------
+
+//============================================================================
+/// \defgroup cpp_kodi_audioengine_Defs_AudioEngineFormat struct AudioEngineFormat
+/// \ingroup cpp_kodi_audioengine_Defs
+/// @brief The audio format structure that fully defines a stream's audio
+/// information
+///
+//@{
+struct AudioEngineFormat
+{
+ /// The stream's data format (eg, AE_FMT_S16LE)
+ enum AEDataFormat m_dataFormat;
+
+ /// The stream's sample rate (eg, 48000)
+ unsigned int m_sampleRate;
+
+ /// The encoded streams sample rate if a bitstream, otherwise undefined
+ unsigned int m_encodedRate;
+
+ /// The amount of used speaker channels
+ unsigned int m_channelCount;
+
+ /// The stream's channel layout
+ enum AEChannel m_channels[AE_CH_MAX];
+
+ /// The number of frames per period
+ unsigned int m_frames;
+
+ /// The size of one frame in bytes
+ unsigned int m_frameSize;
+
+ AudioEngineFormat()
+ {
+ m_dataFormat = AE_FMT_INVALID;
+ m_sampleRate = 0;
+ m_encodedRate = 0;
+ m_frames = 0;
+ m_frameSize = 0;
+ m_channelCount = 0;
+
+ for (unsigned int ch = 0; ch < AE_CH_MAX; ++ch)
+ {
+ m_channels[ch] = AE_CH_MAX;
+ }
+ }
+
+ /// Function to compare the format structure with another
+ bool compareFormat(const AudioEngineFormat *fmt)
+ {
+ if (!fmt)
+ {
+ return false;
+ }
+
+ if (m_dataFormat != fmt->m_dataFormat ||
+ m_sampleRate != fmt->m_sampleRate ||
+ m_encodedRate != fmt->m_encodedRate ||
+ m_frames != fmt->m_frames ||
+ m_frameSize != fmt->m_frameSize ||
+ m_channelCount != fmt->m_channelCount)
+ {
+ return false;
+ }
+
+ for (unsigned int ch = 0; ch < AE_CH_MAX; ++ch)
+ {
+ if (fmt->m_channels[ch] != m_channels[ch])
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+};
+//@}
+//----------------------------------------------------------------------------
+
+/* A stream handle pointer, which is only used internally by the addon stream handle */
+typedef void AEStreamHandle;
+
+/*
+ * Function address structure, not need to visible on dev kit doxygen
+ * documentation
+ */
+typedef struct AddonToKodiFuncTable_kodi_audioengine
+{
+ AEStreamHandle* (*make_stream)(void *kodiBase, AudioEngineFormat* format, unsigned int options);
+ void (*free_stream)(void *kodiBase, AEStreamHandle *stream);
+ bool (*get_current_sink_format)(void *kodiBase, AudioEngineFormat* sink_format);
+
+ // Audio Engine Stream definitions
+ unsigned int (*aestream_get_space)(void *kodiBase, AEStreamHandle *handle);
+ unsigned int (*aestream_add_data)(void *kodiBase, AEStreamHandle *handle, uint8_t* const *data,
+ unsigned int offset, unsigned int frames, double pts, bool hasDownmix,
+ double centerMixLevel);
+ double (*aestream_get_delay)(void *kodiBase, AEStreamHandle *handle);
+ bool (*aestream_is_buffering)(void *kodiBase, AEStreamHandle *handle);
+ double (*aestream_get_cache_time)(void *kodiBase, AEStreamHandle *handle);
+ double (*aestream_get_cache_total)(void *kodiBase, AEStreamHandle *handle);
+ void (*aestream_pause)(void *kodiBase, AEStreamHandle *handle);
+ void (*aestream_resume)(void *kodiBase, AEStreamHandle *handle);
+ void (*aestream_drain)(void *kodiBase, AEStreamHandle *handle, bool wait);
+ bool (*aestream_is_draining)(void *kodiBase, AEStreamHandle *handle);
+ bool (*aestream_is_drained)(void *kodiBase, AEStreamHandle *handle);
+ void (*aestream_flush)(void *kodiBase, AEStreamHandle *handle);
+ float (*aestream_get_volume)(void *kodiBase, AEStreamHandle *handle);
+ void (*aestream_set_volume)(void *kodiBase, AEStreamHandle *handle, float volume);
+ float (*aestream_get_amplification)(void *kodiBase, AEStreamHandle *handle);
+ void (*aestream_set_amplification)(void *kodiBase, AEStreamHandle *handle, float amplify);
+ unsigned int (*aestream_get_frame_size)(void *kodiBase, AEStreamHandle *handle);
+ unsigned int (*aestream_get_channel_count)(void *kodiBase, AEStreamHandle *handle);
+ unsigned int (*aestream_get_sample_rate)(void *kodiBase, AEStreamHandle *handle);
+ AEDataFormat (*aestream_get_data_format)(void *kodiBase, AEStreamHandle *handle);
+ double (*aestream_get_resample_ratio)(void *kodiBase, AEStreamHandle *handle);
+ void (*aestream_set_resample_ratio)(void *kodiBase, AEStreamHandle *handle, double ratio);
+} AddonToKodiFuncTable_kodi_audioengine;
+
+} /* extern "C" */
+
+namespace kodi
+{
+namespace audioengine
+{
+
+//============================================================================
+///
+/// \defgroup cpp_kodi_audioengine_CAddonAEStream class CAddonAEStream
+/// \ingroup cpp_kodi_audioengine
+/// @brief **Audio Engine Stream Class**
+///
+///
+/// It has the header \ref AudioEngine.h "#include <kodi/AudioEngine.h>" be
+/// included to enjoy it.
+///
+//----------------------------------------------------------------------------
+class CAddonAEStream
+{
+public:
+ //==========================================================================
+ /// @ingroup cpp_kodi_audioengine_CAddonAEStream
+ /// @brief Contructs new class to an Kodi IAEStream in the format specified.
+ ///
+ /// @param[in] format The data format the incoming audio will be in
+ /// (e.g. \ref AE_FMT_S16LE)
+ /// @param[in] options [opt] A bit field of stream options (see: enum \ref AudioEngineStreamOptions)
+ ///
+ ///
+ /// ------------------------------------------------------------------------
+ ///
+ /// **Audio engine format information:**
+ /// @code
+ /// /*
+ /// * Audio engine format information
+ /// *
+ /// * Only as example shown here! See always the original structure on related header.
+ /// */
+ /// typedef struct AudioEngineFormat
+ /// {
+ /// enum AEDataFormat m_dataFormat; /* The stream's data format (eg, AE_FMT_S16LE) */
+ /// unsigned int m_sampleRate; /* The stream's sample rate (eg, 48000) */
+ /// unsigned int m_encodedRate; /* The encoded streams sample rate if a bitstream, otherwise undefined */
+ /// unsigned int m_channelCount; /* The amount of used speaker channels */
+ /// enum AEChannel m_channels[AE_CH_MAX]; /* The stream's channel layout */
+ /// unsigned int m_frames; /* The number of frames per period */
+ /// unsigned int m_frameSamples; /* The number of samples in one frame */
+ /// unsigned int m_frameSize; /* The size of one frame in bytes */
+ ///
+ /// /* Function to compare the format structure with another */
+ /// bool compareFormat(const AudioEngineFormat *fmt);
+ /// } AudioEngineFormat;
+ /// @endcode
+ ///
+ /// ------------------------------------------------------------------------
+ ///
+ /// **Bit options to pass to CAELib_Stream (on Kodi by <c>IAE::MakeStream</c>)**
+ ///
+ /// | enum AEStreamOptions | Value: | Description:
+ /// |----------------------------:|:------:|:-----------------------------------
+ /// | AUDIO_STREAM_FORCE_RESAMPLE | 1 << 0 | Force resample even if rates match
+ /// | AUDIO_STREAM_PAUSED | 1 << 1 | Create the stream paused
+ /// | AUDIO_STREAM_AUTOSTART | 1 << 2 | Autostart the stream when enough data is buffered
+ ///
+ ///
+ /// ------------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.cpp}
+ ///
+ /// #include <kodi/AudioEngine.h>
+ ///
+ /// using namespace kodi::audioengine;
+ ///
+ /// ...
+ ///
+ /// AudioEngineFormat format;
+ /// format.m_dataFormat = AE_FMT_FLOAT;
+ /// format.m_channelCount = 2;
+ /// format.m_channels[0] = AE_CH_FL;
+ /// format.m_channels[1] = AE_CH_FR;
+ /// format.m_channels[2] = AE_CH_NULL;
+ /// format.m_sampleRate = 48000;
+ /// format.m_frameSize = sizeof(float)*format.m_channelCount;
+ /// format.m_frames = 512;
+ /// CAddonAEStream* stream = new CAddonAEStream(format, AE_STREAM_AUTOSTART);
+ ///
+ /// ~~~~~~~~~~~~~
+ ///
+ CAddonAEStream(AudioEngineFormat format, unsigned int options = 0)
+ : m_kodiBase(::kodi::addon::CAddonBase::m_interface->toKodi->kodiBase),
+ m_cb(::kodi::addon::CAddonBase::m_interface->toKodi->kodi_audioengine)
+ {
+ m_StreamHandle = m_cb->make_stream(m_kodiBase, &format, options);
+ if (m_StreamHandle == nullptr)
+ {
+ kodi::Log(ADDON_LOG_FATAL, "CAddonAEStream: make_stream failed!");
+ }
+ }
+ //--------------------------------------------------------------------------
+
+ //==========================================================================
+ /// @ingroup cpp_kodi_audioengine_CAddonAEStream
+ /// @brief Class destructor
+ ///
+ ~CAddonAEStream()
+ {
+ if (m_StreamHandle)
+ {
+ m_cb->free_stream(m_kodiBase, m_StreamHandle);
+ m_StreamHandle = nullptr;
+ }
+ }
+ //--------------------------------------------------------------------------
+
+ //==========================================================================
+ /// @ingroup cpp_kodi_audioengine_CAddonAEStream
+ /// @brief Returns the amount of space available in the stream
+ ///
+ /// @return The number of bytes AddData will consume
+ ///
+ unsigned int GetSpace()
+ {
+ return m_cb->aestream_get_space(m_kodiBase, m_StreamHandle);
+ }
+ //--------------------------------------------------------------------------
+
+ //==========================================================================
+ /// @ingroup cpp_kodi_audioengine_CAddonAEStream
+ /// @brief Add planar or interleaved PCM data to the stream
+ ///
+ /// @param[in] data array of pointers to the planes
+ /// @param[in] offset to frame in frames
+ /// @param[in] frames number of frames
+ /// @param[in] pts [opt] presentation timestamp, default is 0
+ /// @param[in] hasDownmix [opt] set true if downmix is present, default is false
+ /// @param[in] centerMixLevel [opt] level to mix left and right to center default is 1.0
+ /// @return The number of frames consumed
+ ///
+ unsigned int AddData(uint8_t* const *data, unsigned int offset, unsigned int frames,
+ double pts = 0, bool hasDownmix = false, double centerMixLevel = 1.0)
+ {
+ return m_cb->aestream_add_data(m_kodiBase, m_StreamHandle, data, offset, frames, pts, hasDownmix, centerMixLevel);
+ }
+ //--------------------------------------------------------------------------
+
+ //==========================================================================
+ /// @ingroup cpp_kodi_audioengine_CAddonAEStream
+ /// @brief Returns the time in seconds that it will take for the next added
+ /// packet to be heard from the speakers.
+ ///
+ /// @return seconds
+ ///
+ double GetDelay()
+ {
+ return m_cb->aestream_get_delay(m_kodiBase, m_StreamHandle);
+ }
+ //--------------------------------------------------------------------------
+
+ //==========================================================================
+ /// @ingroup cpp_kodi_audioengine_CAddonAEStream
+ /// @brief Returns if the stream is buffering
+ ///
+ /// @return True if the stream is buffering
+ ///
+ bool IsBuffering()
+ {
+ return m_cb->aestream_is_buffering(m_kodiBase, m_StreamHandle);
+ }
+ //--------------------------------------------------------------------------
+
+ //==========================================================================
+ /// @ingroup cpp_kodi_audioengine_CAddonAEStream
+ /// @brief Returns the time in seconds of the stream's cached audio samples.
+ /// Engine buffers excluded.
+ ///
+ /// @return seconds
+ ///
+ double GetCacheTime()
+ {
+ return m_cb->aestream_get_cache_time(m_kodiBase, m_StreamHandle);
+ }
+ //--------------------------------------------------------------------------
+
+ //==========================================================================
+ /// @ingroup cpp_kodi_audioengine_CAddonAEStream
+ /// @brief Returns the total time in seconds of the cache
+ ///
+ /// @return seconds
+ ///
+ double GetCacheTotal()
+ {
+ return m_cb->aestream_get_cache_total(m_kodiBase, m_StreamHandle);
+ }
+ //--------------------------------------------------------------------------
+
+ //==========================================================================
+ /// @ingroup cpp_kodi_audioengine_CAddonAEStream
+ /// @brief Pauses the stream playback
+ ///
+ void Pause()
+ {
+ return m_cb->aestream_pause(m_kodiBase, m_StreamHandle);
+ }
+ //--------------------------------------------------------------------------
+
+ //==========================================================================
+ /// @ingroup cpp_kodi_audioengine_CAddonAEStream
+ /// @brief Resumes the stream after pausing
+ ///
+ void Resume()
+ {
+ return m_cb->aestream_resume(m_kodiBase, m_StreamHandle);
+ }
+ //--------------------------------------------------------------------------
+
+ //==========================================================================
+ /// @ingroup cpp_kodi_audioengine_CAddonAEStream
+ /// @brief Start draining the stream
+ ///
+ /// @param[in] wait [opt] Wait until drain is finished if set to
+ /// true, otherwise it returns direct
+ ///
+ /// @note Once called AddData will not consume more data.
+ ///
+ void Drain(bool wait = true)
+ {
+ return m_cb->aestream_drain(m_kodiBase, m_StreamHandle, wait);
+ }
+ //--------------------------------------------------------------------------
+
+ //==========================================================================
+ /// @ingroup cpp_kodi_audioengine_CAddonAEStream
+ /// @brief Returns true if the is stream draining
+ ///
+ bool IsDraining()
+ {
+ return m_cb->aestream_is_draining(m_kodiBase, m_StreamHandle);
+ }
+ //--------------------------------------------------------------------------
+
+ //==========================================================================
+ /// @ingroup cpp_kodi_audioengine_CAddonAEStream
+ /// @brief Returns true if the is stream has finished draining
+ ///
+ bool IsDrained()
+ {
+ return m_cb->aestream_is_drained(m_kodiBase, m_StreamHandle);
+ }
+ //--------------------------------------------------------------------------
+
+ //==========================================================================
+ /// @ingroup cpp_kodi_audioengine_CAddonAEStream
+ /// @brief Flush all buffers dropping the audio data
+ ///
+ void Flush()
+ {
+ return m_cb->aestream_flush(m_kodiBase, m_StreamHandle);
+ }
+ //--------------------------------------------------------------------------
+
+ //==========================================================================
+ /// @ingroup cpp_kodi_audioengine_CAddonAEStream
+ /// @brief Return the stream's current volume level
+ ///
+ /// @return The volume level between 0.0 and 1.0
+ ///
+ float GetVolume()
+ {
+ return m_cb->aestream_get_volume(m_kodiBase, m_StreamHandle);
+ }
+ //--------------------------------------------------------------------------
+
+ //==========================================================================
+ /// @ingroup cpp_kodi_audioengine_CAddonAEStream
+ /// @brief Set the stream's volume level
+ ///
+ /// @param[in] volume The new volume level between 0.0 and 1.0
+ ///
+ void SetVolume(float volume)
+ {
+ return m_cb->aestream_set_volume(m_kodiBase, m_StreamHandle, volume);
+ }
+ //--------------------------------------------------------------------------
+
+ //==========================================================================
+ /// @ingroup cpp_kodi_audioengine_CAddonAEStream
+ /// @brief Gets the stream's volume amplification in linear units.
+ ///
+ /// @return The volume amplification factor between 1.0 and 1000.0
+ ///
+ float GetAmplification()
+ {
+ return m_cb->aestream_get_amplification(m_kodiBase, m_StreamHandle);
+ }
+ //--------------------------------------------------------------------------
+
+ //==========================================================================
+ /// @ingroup cpp_kodi_audioengine_CAddonAEStream
+ /// @brief Sets the stream's volume amplification in linear units.
+ ///
+ /// @param[in] amplify The volume amplification factor between
+ /// 1.0 and 1000.0
+ ///
+ void SetAmplification(float amplify)
+ {
+ return m_cb->aestream_set_amplification(m_kodiBase, m_StreamHandle, amplify);
+ }
+ //--------------------------------------------------------------------------
+
+ //==========================================================================
+ /// @ingroup cpp_kodi_audioengine_CAddonAEStream
+ /// @brief Returns the size of one audio frame in bytes (channelCount * resolution)
+ ///
+ /// @return The size in bytes of one frame
+ ///
+ unsigned int GetFrameSize() const
+ {
+ return m_cb->aestream_get_frame_size(m_kodiBase, m_StreamHandle);
+ }
+ //--------------------------------------------------------------------------
+
+ //==========================================================================
+ /// @ingroup cpp_kodi_audioengine_CAddonAEStream
+ /// @brief Returns the number of channels the stream is configured to accept
+ ///
+ /// @return The channel count
+ ///
+ unsigned int GetChannelCount() const
+ {
+ return m_cb->aestream_get_channel_count(m_kodiBase, m_StreamHandle);
+ }
+ //--------------------------------------------------------------------------
+
+ //==========================================================================
+ /// @ingroup cpp_kodi_audioengine_CAddonAEStream
+ /// @brief Returns the stream's sample rate, if the stream is using a dynamic
+ /// sample rate, this value will NOT reflect any changes made by calls to
+ /// SetResampleRatio()
+ ///
+ /// @return The stream's sample rate (eg, 48000)
+ ///
+ unsigned int GetSampleRate() const
+ {
+ return m_cb->aestream_get_sample_rate(m_kodiBase, m_StreamHandle);
+ }
+ //--------------------------------------------------------------------------
+
+ //==========================================================================
+ /// @ingroup cpp_kodi_audioengine_CAddonAEStream
+ /// @brief Return the data format the stream has been configured with
+ ///
+ /// @return The stream's data format (eg, AUDIOENGINE_FMT_S16LE)
+ ///
+ AEDataFormat GetDataFormat() const
+ {
+ return m_cb->aestream_get_data_format(m_kodiBase, m_StreamHandle);
+ }
+ //--------------------------------------------------------------------------
+
+ //==========================================================================
+ /// @ingroup cpp_kodi_audioengine_CAddonAEStream
+ /// @brief Return the resample ratio
+ ///
+ /// @note This will return an undefined value if the stream is not resampling
+ ///
+ /// @return the current resample ratio or undefined if the stream is not resampling
+ ///
+ double GetResampleRatio()
+ {
+ return m_cb->aestream_get_resample_ratio(m_kodiBase, m_StreamHandle);
+ }
+ //--------------------------------------------------------------------------
+
+ //==========================================================================
+ /// @ingroup cpp_kodi_audioengine_CAddonAEStream
+ /// @brief Sets the resample ratio
+ ///
+ /// @note This function may return false if the stream is not resampling, if
+ /// you wish to use this be sure to set the AESTREAM_FORCE_RESAMPLE option
+ ///
+ /// @param[in] ratio the new sample rate ratio, calculated by
+ /// ((double)desiredRate / (double)GetSampleRate())
+ ///
+ void SetResampleRatio(double ratio)
+ {
+ m_cb->aestream_set_resample_ratio(m_kodiBase, m_StreamHandle, ratio);
+ }
+ //--------------------------------------------------------------------------
+
+private:
+ void* m_kodiBase;
+ AddonToKodiFuncTable_kodi_audioengine* m_cb;
+ AEStreamHandle *m_StreamHandle;
+};
+
+//============================================================================
+/// @ingroup cpp_kodi_audioengine
+/// @brief Get the current sink data format
+///
+/// @param[in] format Current sink data format. For more details see AudioEngineFormat.
+/// @return Returns true on success, else false.
+///
+inline bool GetCurrentSinkFormat(AudioEngineFormat &format)
+{
+ using namespace kodi::addon;
+ return CAddonBase::m_interface->toKodi->kodi_audioengine->get_current_sink_format(CAddonBase::m_interface->toKodi->kodiBase, &format);
+}
+//----------------------------------------------------------------------------
+
+} /* audioengine */
+} /* kodi */
diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/CMakeLists.txt b/xbmc/addons/kodi-addon-dev-kit/include/kodi/CMakeLists.txt
index 2b98154966..6d644dbb3e 100644
--- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/CMakeLists.txt
+++ b/xbmc/addons/kodi-addon-dev-kit/include/kodi/CMakeLists.txt
@@ -1,4 +1,5 @@
set(HEADERS AddonBase.h
+ AudioEngine.h
Filesystem.h
General.h
Network.h
diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/Screensaver.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/Screensaver.h
index c4f8005c1c..cc942ab82b 100644
--- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/Screensaver.h
+++ b/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/Screensaver.h
@@ -9,6 +9,7 @@
#pragma once
#include "../AddonBase.h"
+#include "../gui/renderHelper.h"
namespace kodi { namespace addon { class CInstanceScreensaver; }}
@@ -418,19 +419,35 @@ namespace addon
inline static bool ADDON_Start(AddonInstance_Screensaver* instance)
{
+ instance->toAddon.addonInstance->m_renderHelper = kodi::gui::GetRenderHelper();
return instance->toAddon.addonInstance->Start();
}
inline static void ADDON_Stop(AddonInstance_Screensaver* instance)
{
instance->toAddon.addonInstance->Stop();
+ instance->toAddon.addonInstance->m_renderHelper = nullptr;
}
inline static void ADDON_Render(AddonInstance_Screensaver* instance)
{
+ if (!instance->toAddon.addonInstance->m_renderHelper)
+ return;
+ instance->toAddon.addonInstance->m_renderHelper->Begin();
instance->toAddon.addonInstance->Render();
+ instance->toAddon.addonInstance->m_renderHelper->End();
}
+ /*
+ * Background render helper holds here and in addon base.
+ * In addon base also to have for the others, and stored here for the worst
+ * case where this class is independent from base and base becomes closed
+ * before.
+ *
+ * This is on Kodi with GL unused and the calls to there are empty (no work)
+ * On Kodi with Direct X where angle is present becomes this used.
+ */
+ std::shared_ptr<kodi::gui::IRenderHelper> m_renderHelper;
AddonInstance_Screensaver* m_instanceData;
};
diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/Visualization.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/Visualization.h
index 6c2969373c..d7ad1f16aa 100644
--- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/Visualization.h
+++ b/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/Visualization.h
@@ -14,6 +14,7 @@
*/
#include "../AddonBase.h"
+#include "../gui/renderHelper.h"
namespace kodi { namespace addon { class CInstanceVisualization; }}
@@ -665,12 +666,14 @@ namespace addon
inline static bool ADDON_Start(const AddonInstance_Visualization* addon, int channels, int samplesPerSec, int bitsPerSample, const char* songName)
{
+ addon->toAddon.addonInstance->m_renderHelper = kodi::gui::GetRenderHelper();
return addon->toAddon.addonInstance->Start(channels, samplesPerSec, bitsPerSample, songName);
}
inline static void ADDON_Stop(const AddonInstance_Visualization* addon)
{
addon->toAddon.addonInstance->Stop();
+ addon->toAddon.addonInstance->m_renderHelper = nullptr;
}
inline static void ADDON_AudioData(const AddonInstance_Visualization* addon, const float* audioData, int audioDataLength, float *freqData, int freqDataLength)
@@ -685,7 +688,11 @@ namespace addon
inline static void ADDON_Render(const AddonInstance_Visualization* addon)
{
+ if (!addon->toAddon.addonInstance->m_renderHelper)
+ return;
+ addon->toAddon.addonInstance->m_renderHelper->Begin();
addon->toAddon.addonInstance->Render();
+ addon->toAddon.addonInstance->m_renderHelper->End();
}
inline static void ADDON_GetInfo(const AddonInstance_Visualization* addon, VIS_INFO *info)
@@ -745,6 +752,7 @@ namespace addon
return addon->toAddon.addonInstance->IsLocked();
}
+ std::shared_ptr<kodi::gui::IRenderHelper> m_renderHelper;
bool m_presetLockedByUser = false;
AddonInstance_Visualization* m_instanceData;
};
diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/CMakeLists.txt b/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/CMakeLists.txt
index 91cef7f5ad..834ec00a19 100644
--- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/CMakeLists.txt
+++ b/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/CMakeLists.txt
@@ -1,7 +1,8 @@
set(HEADERS General.h
ListItem.h
Window.h
- definitions.h)
+ definitions.h
+ renderHelper.h)
if(NOT ENABLE_STATIC_LIBS)
core_add_library(addons_kodi-addon-dev-kit_include_kodi_gui)
diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/General.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/General.h
index 30b6d89d85..a3b8bcb430 100644
--- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/General.h
+++ b/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/General.h
@@ -106,7 +106,7 @@ namespace gui
/// **Example:**
/// ~~~~~~~~~~~~~{.cpp}
/// ..
- /// int wid = kodi::gui::GetCurrentWindowDialogId()
+ /// int wid = kodi::gui::GetCurrentWindowDialogId();
/// ..
/// ~~~~~~~~~~~~~
///
@@ -130,7 +130,7 @@ namespace gui
/// **Example:**
/// ~~~~~~~~~~~~~{.cpp}
/// ..
- /// int wid = kodi::gui::GetCurrentWindowId()
+ /// int wid = kodi::gui::GetCurrentWindowId();
/// ..
/// ~~~~~~~~~~~~~
///
@@ -141,5 +141,35 @@ namespace gui
}
//--------------------------------------------------------------------------
+ //==========================================================================
+ ///
+ /// \ingroup cpp_kodi_gui
+ /// \brief To get hardware specific device context interface
+ ///
+ /// \return The currently active device context
+ ///
+ /// \warning This function is only be supported under Windows, on all other
+ /// OS it return `nullptr`!
+ ///
+ /// \note Returned Windows class pointer is `ID3D11DeviceContext1`.
+ ///
+ ///
+ ///-------------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.cpp}
+ /// #include <d3d11_1.h>
+ /// ..
+ /// ID3D11DeviceContext1* context = static_cast<ID3D11DeviceContext1*>(kodi::gui::GetHWContext());
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ inline void* GetHWContext()
+ {
+ using namespace ::kodi::addon;
+ return CAddonBase::m_interface->toKodi->kodi_gui->general->get_hw_context(CAddonBase::m_interface->toKodi->kodiBase);
+ }
+ //--------------------------------------------------------------------------
+
} /* namespace gui */
} /* namespace kodi */
diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/controls/Rendering.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/controls/Rendering.h
index b3dadcd9e3..2ad7e1f0d2 100644
--- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/controls/Rendering.h
+++ b/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/controls/Rendering.h
@@ -10,6 +10,7 @@
#include "../../AddonBase.h"
#include "../Window.h"
+#include "../renderHelper.h"
namespace kodi
{
@@ -179,17 +180,23 @@ namespace controls
*/
static bool OnCreateCB(void* cbhdl, int x, int y, int w, int h, void* device)
{
+ static_cast<CRendering*>(cbhdl)->m_renderHelper = kodi::gui::GetRenderHelper();
return static_cast<CRendering*>(cbhdl)->Create(x, y, w, h, device);
}
static void OnRenderCB(void* cbhdl)
{
+ if (!static_cast<CRendering*>(cbhdl)->m_renderHelper)
+ return;
+ static_cast<CRendering*>(cbhdl)->m_renderHelper->Begin();
static_cast<CRendering*>(cbhdl)->Render();
+ static_cast<CRendering*>(cbhdl)->m_renderHelper->End();
}
static void OnStopCB(void* cbhdl)
{
static_cast<CRendering*>(cbhdl)->Stop();
+ static_cast<CRendering*>(cbhdl)->m_renderHelper = nullptr;
}
static bool OnDirtyCB(void* cbhdl)
@@ -197,6 +204,7 @@ namespace controls
return static_cast<CRendering*>(cbhdl)->Dirty();
}
+ std::shared_ptr<kodi::gui::IRenderHelper> m_renderHelper;
};
} /* namespace controls */
diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/definitions.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/definitions.h
index 770a4160ed..b8b4cbf2b9 100644
--- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/definitions.h
+++ b/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/definitions.h
@@ -26,6 +26,7 @@ typedef struct AddonToKodiFuncTable_kodi_gui_general
int (*get_video_resolution)(void* kodiBase);
int (*get_current_window_dialog_id)(void* kodiBase);
int (*get_current_window_id)(void* kodiBase);
+ void* (*get_hw_context)(void* kodiBase);
} AddonToKodiFuncTable_kodi_gui_general;
typedef struct AddonToKodiFuncTable_kodi_gui_control_button
diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/gl/CMakeLists.txt b/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/gl/CMakeLists.txt
new file mode 100644
index 0000000000..a9ab70c977
--- /dev/null
+++ b/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/gl/CMakeLists.txt
@@ -0,0 +1,7 @@
+set(HEADERS GL.h
+ GLonDX.h
+ Shader.h)
+
+if(NOT ENABLE_STATIC_LIBS)
+ core_add_library(addons_kodi-addon-dev-kit_include_kodi_gui_gl)
+endif()
diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/gl/GL.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/gl/GL.h
new file mode 100644
index 0000000000..ad4fe3da0e
--- /dev/null
+++ b/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/gl/GL.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2005-2019 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#pragma once
+
+//==============================================================================
+///
+/// \defgroup cpp_kodi_gui_gl Kodi OpenGL helpers
+/// \ingroup cpp_kodi_gui
+/// \brief Auxiliary functions for Open GL
+///
+/// This group includes help for definitions, functions, and classes for
+/// OpenGL.
+///
+/// To use OpenGL for your system, add the \ref GL.h "#include <kodi/gui/gl/GL.h>".
+///
+///
+///-----------------------------------------------------------------------------
+///
+/// The \ref HAS_GL is declared if Open GL is required and \ref HAS_GLES if Open GL
+/// Embedded Systems (ES) is required, with ES the version is additionally given
+/// in the definition, this can be "2" or "3".
+///
+///
+///-----------------------------------------------------------------------------
+///
+/// Following \ref GL_TYPE_STRING define can be used, for example, to manage
+/// different folders for GL and GLES and make the selection easier.
+/// This are on OpenGL **"`GL`"** and on Open GL|ES **"`GLES`"**.
+/// **Example:**
+/// ~~~~~~~~~~~~~~~~~{.cpp}
+/// kodi::GetAddonPath("resources/shaders/" GL_TYPE_STRING "/frag.glsl");
+/// ~~~~~~~~~~~~~~~~~
+///
+///
+///----------------------------------------------------------------------------
+///
+/// In addition, \ref BUFFER_OFFSET is declared in it which can be used to give an
+/// offset on the array to GL.
+/// **Example:**
+/// ~~~~~~~~~~~~~~~~~{.cpp}
+/// const struct PackedVertex {
+/// float position[3]; // Position x, y, z
+/// float color[4]; // Color r, g, b, a
+/// } vertices[3] = {
+/// { { -0.5f, -0.5f, 0.0f }, { 1.0f, 0.0f, 0.0f, 1.0f } },
+/// { { 0.5f, -0.5f, 0.0f }, { 0.0f, 1.0f, 0.0f, 1.0f } },
+/// { { 0.0f, 0.5f, 0.0f }, { 0.0f, 0.0f, 1.0f, 1.0f } }
+/// };
+///
+/// glVertexAttribPointer(m_aPosition, 3, GL_FLOAT, GL_FALSE, sizeof(PackedVertex), BUFFER_OFFSET(offsetof(PackedVertex, position)));
+/// glEnableVertexAttribArray(m_aPosition);
+///
+/// glVertexAttribPointer(m_aColor, 4, GL_FLOAT, GL_FALSE, sizeof(PackedVertex), BUFFER_OFFSET(offsetof(PackedVertex, color)));
+/// glEnableVertexAttribArray(m_aColor);
+/// ~~~~~~~~~~~~~~~~~
+
+#if HAS_GL
+ #define GL_TYPE_STRING "GL"
+ // always define GL_GLEXT_PROTOTYPES before include gl headers
+ #if !defined(GL_GLEXT_PROTOTYPES)
+ #define GL_GLEXT_PROTOTYPES
+ #endif
+ #if defined(TARGET_LINUX)
+ #include <GL/gl.h>
+ #include <GL/glext.h>
+ #elif defined(TARGET_FREEBSD)
+ #include <GL/gl.h>
+ #elif defined(TARGET_DARWIN)
+ #include <OpenGL/gl3.h>
+ #include <OpenGL/gl3ext.h>
+ #elif defined(WIN32)
+ #error Use of GL under Windows is not possible
+ #endif
+#elif HAS_GLES >= 2
+ #define GL_TYPE_STRING "GLES"
+ #if defined(WIN32)
+ #if defined(HAS_ANGLE)
+ #include <angle_gl.h>
+ #else
+ #error Use of GLES only be available under Windows by the use of angle
+ #endif
+ #elif defined(TARGET_DARWIN)
+ #if HAS_GLES == 3
+ #include <OpenGLES/ES3/gl.h>
+ #include <OpenGLES/ES3/glext.h>
+ #else
+ #include <OpenGLES/ES2/gl.h>
+ #include <OpenGLES/ES2/glext.h>
+ #endif
+ #else
+ #if HAS_GLES == 3
+ #include <GLES3/gl3.h>
+ #include <GLES3/gl3ext.h>
+ #else
+ #include <GLES2/gl2.h>
+ #include <GLES2/gl2ext.h>
+ #endif
+ #endif
+#endif
+
+#ifndef BUFFER_OFFSET
+#define BUFFER_OFFSET(i) ((char *)nullptr + (i))
+#endif
diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/gl/GLonDX.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/gl/GLonDX.h
new file mode 100644
index 0000000000..01d222c9e3
--- /dev/null
+++ b/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/gl/GLonDX.h
@@ -0,0 +1,369 @@
+/*
+ * Copyright (C) 2005-2019 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#pragma once
+
+#include <angle_gl.h>
+#include <d3d11.h>
+#include <d3dcompiler.h>
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <kodi/AddonBase.h>
+#include <kodi/gui/General.h>
+#include <wrl/client.h>
+
+#pragma comment( lib, "d3dcompiler.lib" )
+#ifndef GL_CLIENT_VERSION
+#define GL_CLIENT_VERSION 3
+#endif
+
+namespace kodi
+{
+namespace gui
+{
+namespace gl
+{
+
+class CGLonDX : public kodi::gui::IRenderHelper
+{
+public:
+ explicit CGLonDX() : m_pContext(reinterpret_cast<ID3D11DeviceContext*>(kodi::gui::GetHWContext())) {}
+ ~CGLonDX() override { destruct(); }
+
+ bool Init() override
+ {
+ EGLint egl_display_attrs[] =
+ {
+ EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE,
+ EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE, EGL_DONT_CARE,
+ EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE, EGL_DONT_CARE,
+ EGL_EXPERIMENTAL_PRESENT_PATH_ANGLE, EGL_EXPERIMENTAL_PRESENT_PATH_FAST_ANGLE,
+ EGL_NONE
+ };
+ EGLint egl_config_attrs[] =
+ {
+ EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, EGL_ALPHA_SIZE, 8,
+ EGL_BIND_TO_TEXTURE_RGBA, EGL_TRUE,
+ EGL_RENDERABLE_TYPE, GL_CLIENT_VERSION == 3 ? EGL_OPENGL_ES3_BIT : EGL_OPENGL_ES2_BIT,
+ EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
+ EGL_NONE
+ };
+ EGLint egl_context_attrs[] =
+ {
+ EGL_CONTEXT_CLIENT_VERSION, GL_CLIENT_VERSION, EGL_NONE
+ };
+
+ m_eglDisplay = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, egl_display_attrs);
+ if (m_eglDisplay == EGL_NO_DISPLAY)
+ {
+ Log(ADDON_LOG_ERROR, "GLonDX: unable to get EGL display (%s)", eglGetErrorString());
+ return false;
+ }
+
+ if (eglInitialize(m_eglDisplay, nullptr, nullptr) != EGL_TRUE)
+ {
+ Log(ADDON_LOG_ERROR, "GLonDX: unable to init EGL display (%s)", eglGetErrorString());
+ return false;
+ }
+
+ EGLint numConfigs = 0;
+ if (eglChooseConfig(m_eglDisplay, egl_config_attrs, &m_eglConfig, 1, &numConfigs) != EGL_TRUE || numConfigs == 0)
+ {
+ Log(ADDON_LOG_ERROR, "GLonDX: unable to get EGL config (%s)", eglGetErrorString());
+ return false;
+ }
+
+ m_eglContext = eglCreateContext(m_eglDisplay, m_eglConfig, nullptr, egl_context_attrs);
+ if (m_eglContext == EGL_NO_CONTEXT)
+ {
+ Log(ADDON_LOG_ERROR, "GLonDX: unable to create EGL context (%s)", eglGetErrorString());
+ return false;
+ }
+
+ if (!createD3DResources())
+ return false;
+
+ if (eglMakeCurrent(m_eglDisplay, m_eglBuffer, m_eglBuffer, m_eglContext) != EGL_TRUE)
+ {
+ Log(ADDON_LOG_ERROR, "GLonDX: unable to make current EGL (%s)", eglGetErrorString());
+ return false;
+ }
+ return true;
+ }
+
+ void CheckGL(ID3D11DeviceContext* device)
+ {
+ if (m_pContext != device)
+ {
+ m_pSRView = nullptr;
+ m_pVShader = nullptr;
+ m_pPShader = nullptr;
+ m_pContext = device;
+
+ if (m_eglBuffer != EGL_NO_SURFACE)
+ {
+ eglMakeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+ eglDestroySurface(m_eglDisplay, m_eglBuffer);
+ m_eglBuffer = EGL_NO_SURFACE;
+ }
+
+ // create new resources
+ if (!createD3DResources())
+ return;
+
+ eglMakeCurrent(m_eglDisplay, m_eglBuffer, m_eglBuffer, m_eglContext);
+ }
+ }
+
+ void Begin() override
+ {
+ // confirm on begin D3D context is correct
+ CheckGL(reinterpret_cast<ID3D11DeviceContext*>(kodi::gui::GetHWContext()));
+
+ glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
+ glClear(GL_COLOR_BUFFER_BIT);
+ }
+
+ void End() override
+ {
+ glFlush();
+
+ // set our primitive shaders
+ m_pContext->VSSetShader(m_pVShader.Get(), nullptr, 0);
+ m_pContext->PSSetShader(m_pPShader.Get(), nullptr, 0);
+ m_pContext->PSSetShaderResources(0, 1, m_pSRView.GetAddressOf());
+ // draw texture
+ m_pContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
+ m_pContext->IASetVertexBuffers(0, 0, nullptr, nullptr, nullptr);
+ m_pContext->IASetInputLayout(nullptr);
+ m_pContext->Draw(4, 0);
+ // unset shaders
+ m_pContext->PSSetShader(nullptr, nullptr, 0);
+ m_pContext->VSSetShader(nullptr, nullptr, 0);
+ // unbind our view
+ ID3D11ShaderResourceView* views[1] = {};
+ m_pContext->PSSetShaderResources(0, 1, views);
+ }
+
+private:
+ enum ShaderType
+ {
+ VERTEX_SHADER,
+ PIXEL_SHADER
+ };
+
+ bool createD3DResources()
+ {
+ HANDLE sharedHandle;
+ Microsoft::WRL::ComPtr<ID3D11Device> pDevice;
+ Microsoft::WRL::ComPtr<ID3D11RenderTargetView> pRTView;
+ Microsoft::WRL::ComPtr<ID3D11Resource> pRTResource;
+ Microsoft::WRL::ComPtr<ID3D11Texture2D> pRTTexture;
+ Microsoft::WRL::ComPtr<ID3D11Texture2D> pOffScreenTexture;
+ Microsoft::WRL::ComPtr<IDXGIResource> dxgiResource;
+
+ m_pContext->GetDevice(&pDevice);
+ m_pContext->OMGetRenderTargets(1, &pRTView, nullptr);
+ if (!pRTView)
+ return false;
+
+ pRTView->GetResource(&pRTResource);
+ if (FAILED(pRTResource.As(&pRTTexture)))
+ return false;
+
+ D3D11_TEXTURE2D_DESC texDesc;
+ pRTTexture->GetDesc(&texDesc);
+ texDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
+ texDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET;
+ texDesc.MiscFlags = D3D11_RESOURCE_MISC_SHARED;
+ if (FAILED(pDevice->CreateTexture2D(&texDesc, nullptr, &pOffScreenTexture)))
+ {
+ Log(ADDON_LOG_ERROR, "GLonDX: unable to create intermediate texture");
+ return false;
+ }
+
+ CD3D11_SHADER_RESOURCE_VIEW_DESC srvDesc(pOffScreenTexture.Get(), D3D11_SRV_DIMENSION_TEXTURE2D);
+ if (FAILED(pDevice->CreateShaderResourceView(pOffScreenTexture.Get(), &srvDesc, &m_pSRView)))
+ {
+ Log(ADDON_LOG_ERROR, "GLonDX: unable to create shader view");
+ return false;
+ }
+
+ if (FAILED(pOffScreenTexture.As(&dxgiResource)) ||
+ FAILED(dxgiResource->GetSharedHandle(&sharedHandle)))
+ {
+ Log(ADDON_LOG_ERROR, "GLonDX: unable get shared handle for texture");
+ return false;
+ }
+
+ // initiate simple shaders
+ if (FAILED(d3dCreateShader(VERTEX_SHADER, vs_out_shader_text, &m_pVShader)))
+ {
+ Log(ADDON_LOG_ERROR, "GLonDX: unable to create vertex shader view");
+ return false;
+ }
+
+ if (FAILED(d3dCreateShader(PIXEL_SHADER, ps_out_shader_text, &m_pPShader)))
+ {
+ Log(ADDON_LOG_ERROR, "GLonDX: unable to create pixel shader view");
+ return false;
+ }
+
+ // create EGL buffer from D3D shared texture
+ EGLint egl_buffer_attrs[] =
+ {
+ EGL_WIDTH, static_cast<EGLint>(texDesc.Width),
+ EGL_HEIGHT, static_cast<EGLint>(texDesc.Height),
+ EGL_TEXTURE_TARGET, EGL_TEXTURE_2D,
+ EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGBA,
+ EGL_NONE
+ };
+
+ m_eglBuffer = eglCreatePbufferFromClientBuffer(m_eglDisplay,
+ EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE,
+ sharedHandle, m_eglConfig, egl_buffer_attrs);
+
+ if (m_eglBuffer == EGL_NO_SURFACE)
+ {
+ Log(ADDON_LOG_ERROR, "GLonDX: unable to create EGL buffer (%s)", eglGetErrorString());
+ return false;
+ }
+ return true;
+ }
+
+ HRESULT d3dCreateShader(ShaderType shaderType, const std::string& source, IUnknown** ppShader) const
+ {
+ Microsoft::WRL::ComPtr<ID3DBlob> pBlob;
+ Microsoft::WRL::ComPtr<ID3DBlob> pErrors;
+
+ auto hr = D3DCompile(source.c_str(), source.length(), nullptr, nullptr, nullptr, "main",
+ shaderType == PIXEL_SHADER ? "ps_4_0" : "vs_4_0", 0, 0, &pBlob, &pErrors);
+
+ if (SUCCEEDED(hr))
+ {
+ Microsoft::WRL::ComPtr<ID3D11Device> pDevice;
+ m_pContext->GetDevice(&pDevice);
+
+ if (shaderType == PIXEL_SHADER)
+ {
+ hr = pDevice->CreatePixelShader(pBlob->GetBufferPointer(), pBlob->GetBufferSize(), nullptr,
+ reinterpret_cast<ID3D11PixelShader**>(ppShader));
+ }
+ else
+ {
+ hr = pDevice->CreateVertexShader(pBlob->GetBufferPointer(), pBlob->GetBufferSize(), nullptr,
+ reinterpret_cast<ID3D11VertexShader**>(ppShader));
+ }
+
+ if (FAILED(hr))
+ {
+ Log(ADDON_LOG_ERROR, "GLonDX: unable to create %s shader",
+ shaderType == PIXEL_SHADER ? "pixel" : "vertex");
+ }
+ }
+ else
+ {
+ Log(ADDON_LOG_ERROR, "GLonDX: unable to compile shader (%s)", pErrors->GetBufferPointer());
+ }
+ return hr;
+ }
+
+ static const char* eglGetErrorString()
+ {
+#define CASE_STR( value ) case value: return #value
+ switch (eglGetError())
+ {
+ CASE_STR(EGL_SUCCESS);
+ CASE_STR(EGL_NOT_INITIALIZED);
+ CASE_STR(EGL_BAD_ACCESS);
+ CASE_STR(EGL_BAD_ALLOC);
+ CASE_STR(EGL_BAD_ATTRIBUTE);
+ CASE_STR(EGL_BAD_CONTEXT);
+ CASE_STR(EGL_BAD_CONFIG);
+ CASE_STR(EGL_BAD_CURRENT_SURFACE);
+ CASE_STR(EGL_BAD_DISPLAY);
+ CASE_STR(EGL_BAD_SURFACE);
+ CASE_STR(EGL_BAD_MATCH);
+ CASE_STR(EGL_BAD_PARAMETER);
+ CASE_STR(EGL_BAD_NATIVE_PIXMAP);
+ CASE_STR(EGL_BAD_NATIVE_WINDOW);
+ CASE_STR(EGL_CONTEXT_LOST);
+ default:
+ return "Unknown";
+ }
+#undef CASE_STR
+ }
+
+ void destruct()
+ {
+ if (m_eglDisplay != EGL_NO_DISPLAY)
+ {
+ eglMakeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+
+ if (m_eglBuffer != EGL_NO_SURFACE)
+ {
+ eglDestroySurface(m_eglDisplay, m_eglBuffer);
+ m_eglBuffer = EGL_NO_SURFACE;
+ }
+
+ if (m_eglContext != EGL_NO_CONTEXT)
+ {
+ eglDestroyContext(m_eglDisplay, m_eglContext);
+ m_eglContext = EGL_NO_CONTEXT;
+ }
+
+ eglTerminate(m_eglDisplay);
+ m_eglDisplay = EGL_NO_DISPLAY;
+ }
+
+ m_pSRView = nullptr;
+ m_pVShader = nullptr;
+ m_pPShader = nullptr;
+ m_pContext = nullptr;
+ }
+
+ EGLConfig m_eglConfig = EGL_NO_CONFIG_KHR;
+ EGLDisplay m_eglDisplay = EGL_NO_DISPLAY;
+ EGLContext m_eglContext = EGL_NO_CONTEXT;
+ EGLSurface m_eglBuffer = EGL_NO_SURFACE;
+
+ ID3D11DeviceContext* m_pContext = nullptr; // don't hold context
+ Microsoft::WRL::ComPtr<ID3D11ShaderResourceView> m_pSRView = nullptr;
+ Microsoft::WRL::ComPtr<ID3D11VertexShader> m_pVShader = nullptr;
+ Microsoft::WRL::ComPtr<ID3D11PixelShader> m_pPShader = nullptr;
+
+#define TO_STRING(...) #__VA_ARGS__
+ std::string vs_out_shader_text = TO_STRING(
+ void main(uint id : SV_VertexId, out float2 tex : TEXCOORD0, out float4 pos : SV_POSITION)
+ {
+ tex = float2(id % 2, (id % 4) >> 1);
+ pos = float4((tex.x - 0.5f) * 2, -(tex.y - 0.5f) * 2, 0, 1);
+ });
+
+ std::string ps_out_shader_text = TO_STRING(
+ Texture2D texMain : register(t0);
+ SamplerState Sampler
+ {
+ Filter = MIN_MAG_MIP_LINEAR;
+ AddressU = CLAMP;
+ AddressV = CLAMP;
+ Comparison = NEVER;
+ };
+
+ float4 main(in float2 tex : TEXCOORD0) : SV_TARGET
+ {
+ return texMain.Sample(Sampler, tex);
+ });
+#undef TO_STRING
+}; /* class CGLonDX */
+
+} /* namespace gl */
+
+using CRenderHelper = gl::CGLonDX;
+} /* namespace gui */
+} /* namespace kodi */
diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/gl/Shader.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/gl/Shader.h
new file mode 100644
index 0000000000..350395ad5b
--- /dev/null
+++ b/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/gl/Shader.h
@@ -0,0 +1,353 @@
+/*
+ * Copyright (C) 2005-2019 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#pragma once
+
+#include "GL.h"
+
+#include <stdio.h>
+#include <vector>
+#include <string>
+
+#include <kodi/AddonBase.h>
+#include <kodi/Filesystem.h>
+
+#define LOG_SIZE 1024
+#define GLchar char
+
+namespace kodi
+{
+namespace gui
+{
+namespace gl
+{
+
+//========================================================================
+/// CShader - base class
+class ATTRIBUTE_HIDDEN CShader
+{
+public:
+ CShader() = default;
+ virtual ~CShader() = default;
+ virtual bool Compile(const std::string& extraBegin = "",
+ const std::string& extraEnd = "") = 0;
+ virtual void Free() = 0;
+ virtual GLuint Handle() = 0;
+
+ bool LoadSource(const std::string& file)
+ {
+ char buffer[16384];
+
+ kodi::vfs::CFile source;
+ if (!source.OpenFile(file))
+ {
+ kodi::Log(ADDON_LOG_ERROR, "CShader::%s: Failed to open file '%s'", __FUNCTION__, file.c_str());
+ return false;
+ }
+ size_t len = source.Read(buffer, sizeof(buffer));
+ m_source.assign(buffer);
+ m_source[len] = 0;
+ source.Close();
+ return true;
+ }
+
+ bool OK() const { return m_compiled; }
+
+protected:
+ std::string m_source;
+ std::string m_lastLog;
+ bool m_compiled = false;
+};
+//------------------------------------------------------------------------
+
+//========================================================================
+/// CVertexShader
+class ATTRIBUTE_HIDDEN CVertexShader : public CShader
+{
+public:
+ CVertexShader() = default;
+ ~CVertexShader() override { Free(); }
+
+ void Free() override
+ {
+ if (m_vertexShader)
+ glDeleteShader(m_vertexShader);
+ m_vertexShader = 0;
+ }
+
+ bool Compile(const std::string& extraBegin = "",
+ const std::string& extraEnd = "") override
+ {
+ GLint params[4];
+
+ Free();
+
+ m_vertexShader = glCreateShader(GL_VERTEX_SHADER);
+
+ GLsizei count = 0;
+ const char *sources[3];
+ if (!extraBegin.empty())
+ sources[count++] = extraBegin.c_str();
+ if (!m_source.empty())
+ sources[count++] = m_source.c_str();
+ if (!extraEnd.empty())
+ sources[count++] = extraEnd.c_str();
+
+ glShaderSource(m_vertexShader, count, sources, nullptr);
+ glCompileShader(m_vertexShader);
+ glGetShaderiv(m_vertexShader, GL_COMPILE_STATUS, params);
+ if (params[0] != GL_TRUE)
+ {
+ GLchar log[LOG_SIZE];
+ glGetShaderInfoLog(m_vertexShader, LOG_SIZE, nullptr, log);
+ kodi::Log(ADDON_LOG_ERROR, "CVertexShader::%s: %s", __FUNCTION__, log);
+ fprintf(stderr, "CVertexShader::%s: %s\n", __FUNCTION__, log);
+ m_lastLog = log;
+ m_compiled = false;
+ }
+ else
+ {
+ GLchar log[LOG_SIZE];
+ glGetShaderInfoLog(m_vertexShader, LOG_SIZE, nullptr, log);
+ m_lastLog = log;
+ m_compiled = true;
+ }
+ return m_compiled;
+ }
+
+ GLuint Handle() override { return m_vertexShader; }
+
+protected:
+ GLuint m_vertexShader = 0;
+};
+//------------------------------------------------------------------------
+
+//========================================================================
+/// CPixelShader
+class ATTRIBUTE_HIDDEN CPixelShader : public CShader
+{
+public:
+ CPixelShader() = default;
+ ~CPixelShader() { Free(); }
+ void Free() override
+ {
+ if (m_pixelShader)
+ glDeleteShader(m_pixelShader);
+ m_pixelShader = 0;
+ }
+
+ bool Compile(const std::string& extraBegin = "",
+ const std::string& extraEnd = "") override
+ {
+ GLint params[4];
+
+ Free();
+
+ m_pixelShader = glCreateShader(GL_FRAGMENT_SHADER);
+
+ GLsizei count = 0;
+ const char *sources[3];
+ if (!extraBegin.empty())
+ sources[count++] = extraBegin.c_str();
+ if (!m_source.empty())
+ sources[count++] = m_source.c_str();
+ if (!extraEnd.empty())
+ sources[count++] = extraEnd.c_str();
+
+ glShaderSource(m_pixelShader, count, sources, 0);
+ glCompileShader(m_pixelShader);
+ glGetShaderiv(m_pixelShader, GL_COMPILE_STATUS, params);
+ if (params[0] != GL_TRUE)
+ {
+ GLchar log[LOG_SIZE];
+ glGetShaderInfoLog(m_pixelShader, LOG_SIZE, nullptr, log);
+ kodi::Log(ADDON_LOG_ERROR, "CPixelShader::%s: %s", __FUNCTION__, log);
+ fprintf(stderr, "CPixelShader::%s: %s\n", __FUNCTION__, log);
+ m_lastLog = log;
+ m_compiled = false;
+ }
+ else
+ {
+ GLchar log[LOG_SIZE];
+ glGetShaderInfoLog(m_pixelShader, LOG_SIZE, nullptr, log);
+ m_lastLog = log;
+ m_compiled = true;
+ }
+ return m_compiled;
+ }
+
+ GLuint Handle() override { return m_pixelShader; }
+
+protected:
+ GLuint m_pixelShader = 0;
+};
+//------------------------------------------------------------------------
+
+//========================================================================
+/// CShaderProgram
+class ATTRIBUTE_HIDDEN CShaderProgram
+{
+public:
+ CShaderProgram() = default;
+ CShaderProgram(const std::string &vert, const std::string &frag)
+ {
+ LoadShaderFiles(vert, frag);
+ }
+
+ virtual ~CShaderProgram()
+ {
+ ShaderFree();
+ }
+
+ bool LoadShaderFiles(const std::string &vert, const std::string &frag)
+ {
+ if (!kodi::vfs::FileExists(vert) || !m_pVP.LoadSource(vert))
+ {
+ kodi::Log(ADDON_LOG_ERROR, "%s: Failed to load '%s'", __func__, vert.c_str());
+ return false;
+ }
+
+ if (!kodi::vfs::FileExists(frag) || !m_pFP.LoadSource(frag))
+ {
+ kodi::Log(ADDON_LOG_ERROR, "%s: Failed to load '%s'", __func__, frag.c_str());
+ return false;
+ }
+
+ return true;
+ }
+
+ bool CompileAndLink(const std::string& vertexExtraBegin = "",
+ const std::string& vertexExtraEnd = "",
+ const std::string& fragmentExtraBegin = "",
+ const std::string& fragmentExtraEnd = "")
+ {
+ GLint params[4];
+
+ // free resources
+ ShaderFree();
+ m_ok = false;
+
+ // compiled vertex shader
+ if (!m_pVP.Compile(vertexExtraBegin, vertexExtraEnd))
+ {
+ kodi::Log(ADDON_LOG_ERROR, "GL: Error compiling vertex shader");
+ return false;
+ }
+
+ // compile pixel shader
+ if (!m_pFP.Compile(fragmentExtraBegin, fragmentExtraEnd))
+ {
+ m_pVP.Free();
+ kodi::Log(ADDON_LOG_ERROR, "GL: Error compiling fragment shader");
+ return false;
+ }
+
+ // create program object
+ m_shaderProgram = glCreateProgram();
+ if (!m_shaderProgram)
+ {
+ kodi::Log(ADDON_LOG_ERROR, "CShaderProgram::%s: Failed to create GL program", __FUNCTION__);
+ ShaderFree();
+ return false;
+ }
+
+ // attach the vertex shader
+ glAttachShader(m_shaderProgram, m_pVP.Handle());
+ glAttachShader(m_shaderProgram, m_pFP.Handle());
+
+ // link the program
+ glLinkProgram(m_shaderProgram);
+ glGetProgramiv(m_shaderProgram, GL_LINK_STATUS, params);
+ if (params[0] != GL_TRUE)
+ {
+ GLchar log[LOG_SIZE];
+ glGetProgramInfoLog(m_shaderProgram, LOG_SIZE, nullptr, log);
+ kodi::Log(ADDON_LOG_ERROR, "CShaderProgram::%s: %s", __FUNCTION__, log);
+ fprintf(stderr, "CShaderProgram::%s: %s\n", __FUNCTION__, log);
+ ShaderFree();
+ return false;
+ }
+
+ m_validated = false;
+ m_ok = true;
+ OnCompiledAndLinked();
+ return true;
+ }
+
+ bool EnableShader()
+ {
+ if (ShaderOK())
+ {
+ glUseProgram(m_shaderProgram);
+ if (OnEnabled())
+ {
+ if (!m_validated)
+ {
+ // validate the program
+ GLint params[4];
+ glValidateProgram(m_shaderProgram);
+ glGetProgramiv(m_shaderProgram, GL_VALIDATE_STATUS, params);
+ if (params[0] != GL_TRUE)
+ {
+ GLchar log[LOG_SIZE];
+ glGetProgramInfoLog(m_shaderProgram, LOG_SIZE, nullptr, log);
+ kodi::Log(ADDON_LOG_ERROR, "CShaderProgram::%s: %s", __FUNCTION__, log);
+ fprintf(stderr, "CShaderProgram::%s: %s\n", __FUNCTION__, log);
+ }
+ m_validated = true;
+ }
+ return true;
+ }
+ else
+ {
+ glUseProgram(0);
+ return false;
+ }
+ return true;
+ }
+ return false;
+ }
+
+ void DisableShader()
+ {
+ if (ShaderOK())
+ {
+ glUseProgram(0);
+ OnDisabled();
+ }
+ }
+
+ ATTRIBUTE_FORCEINLINE bool ShaderOK() const { return m_ok; }
+ ATTRIBUTE_FORCEINLINE CVertexShader& VertexShader() { return m_pVP; }
+ ATTRIBUTE_FORCEINLINE CPixelShader& PixelShader() { return m_pFP; }
+ ATTRIBUTE_FORCEINLINE GLuint ProgramHandle() { return m_shaderProgram; }
+
+ virtual void OnCompiledAndLinked() {};
+ virtual bool OnEnabled() { return false; };
+ virtual void OnDisabled() {};
+
+private:
+ void ShaderFree()
+ {
+ if (m_shaderProgram)
+ glDeleteProgram(m_shaderProgram);
+ m_shaderProgram = 0;
+ m_ok = false;
+ }
+
+ CVertexShader m_pVP;
+ CPixelShader m_pFP;
+ GLuint m_shaderProgram = 0;
+ bool m_ok = false;
+ bool m_validated = false;
+};
+//------------------------------------------------------------------------
+
+} /* namespace gl */
+} /* namespace gui */
+} /* namespace kodi */
diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/renderHelper.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/renderHelper.h
new file mode 100644
index 0000000000..87d7b19ab2
--- /dev/null
+++ b/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/renderHelper.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2005-2019 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#pragma once
+
+#include "../AddonBase.h"
+
+namespace kodi
+{
+namespace gui
+{
+struct IRenderHelper
+{
+ virtual ~IRenderHelper() = default;
+ virtual bool Init() = 0;
+ virtual void Begin() = 0;
+ virtual void End() = 0;
+}; /* class IRenderHelper */
+} /* namespace gui */
+} /* namespace kodi */
+
+#if defined(WIN32) && defined(HAS_ANGLE)
+#include "gl/GLonDX.h"
+#else
+/*
+ * Default background GUI render helper class
+ */
+namespace kodi
+{
+namespace gui
+{
+struct CRenderHelperStub : public IRenderHelper
+{
+ bool Init() override { return true; }
+ void Begin() override { }
+ void End() override { }
+}; /* class CRenderHelperStub */
+
+using CRenderHelper = CRenderHelperStub;
+} /* namespace gui */
+} /* namespace kodi */
+#endif
+
+namespace kodi
+{
+namespace gui
+{
+
+/*
+ * Create render background handler, e.g. becomes on "Windows" Angle used
+ * to emulate GL.
+ *
+ * This only be used internal and not from addon's direct.
+ *
+ * Function defines here and not in CAddonBase because of a hen and egg problem.
+ */
+inline std::shared_ptr<IRenderHelper> GetRenderHelper()
+{
+ using namespace ::kodi::addon;
+ if (CAddonBase::m_interface->addonBase->m_renderHelper)
+ return CAddonBase::m_interface->addonBase->m_renderHelper;
+
+ const std::shared_ptr<kodi::gui::IRenderHelper> renderHelper(new CRenderHelper());
+ if (!renderHelper->Init())
+ return nullptr;
+
+ CAddonBase::m_interface->addonBase->m_renderHelper = renderHelper; // Hold on base for other types
+ return renderHelper;
+}
+
+} /* namespace gui */
+} /* namespace kodi */
diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/versions.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/versions.h
index a37dbe014c..4ba563f68c 100644
--- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/versions.h
+++ b/xbmc/addons/kodi-addon-dev-kit/include/kodi/versions.h
@@ -44,14 +44,14 @@
#define ADDON_GLOBAL_VERSION_GENERAL_XML_ID "kodi.binary.global.general"
#define ADDON_GLOBAL_VERSION_GENERAL_DEPENDS "General.h"
-#define ADDON_GLOBAL_VERSION_GUI "5.12.0"
+#define ADDON_GLOBAL_VERSION_GUI "5.12.1"
#define ADDON_GLOBAL_VERSION_GUI_MIN "5.10.0"
#define ADDON_GLOBAL_VERSION_GUI_XML_ID "kodi.binary.global.gui"
#define ADDON_GLOBAL_VERSION_GUI_DEPENDS "libKODI_guilib.h" \
"gui/"
-#define ADDON_GLOBAL_VERSION_AUDIOENGINE "1.0.1"
-#define ADDON_GLOBAL_VERSION_AUDIOENGINE_MIN "1.0.1"
+#define ADDON_GLOBAL_VERSION_AUDIOENGINE "1.0.2"
+#define ADDON_GLOBAL_VERSION_AUDIOENGINE_MIN "1.0.2"
#define ADDON_GLOBAL_VERSION_AUDIOENGINE_XML_ID "kodi.binary.global.audioengine"
#define ADDON_GLOBAL_VERSION_AUDIOENGINE_DEPENDS "AudioEngine.h"
@@ -98,8 +98,8 @@
#define ADDON_INSTANCE_VERSION_PERIPHERAL_DEPENDS "addon-instance/Peripheral.h" \
"addon-instance/PeripheralUtils.h"
-#define ADDON_INSTANCE_VERSION_PVR "5.10.4"
-#define ADDON_INSTANCE_VERSION_PVR_MIN "5.10.0"
+#define ADDON_INSTANCE_VERSION_PVR "6.0.0"
+#define ADDON_INSTANCE_VERSION_PVR_MIN "6.0.0"
#define ADDON_INSTANCE_VERSION_PVR_XML_ID "kodi.binary.instance.pvr"
#define ADDON_INSTANCE_VERSION_PVR_DEPENDS "xbmc_pvr_dll.h" \
"xbmc_pvr_types.h" \
diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/xbmc_epg_types.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/xbmc_epg_types.h
index 7b11ed8347..30503d5690 100644
--- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/xbmc_epg_types.h
+++ b/xbmc/addons/kodi-addon-dev-kit/include/kodi/xbmc_epg_types.h
@@ -100,7 +100,6 @@ extern "C" {
time_t firstAired; /*!< @brief (optional) first aired in UTC */
int iParentalRating; /*!< @brief (optional) parental rating */
int iStarRating; /*!< @brief (optional) star rating */
- bool bNotify; /*!< @brief (optional) notify the user when this event starts */
int iSeriesNumber; /*!< @brief (optional) series number */
int iEpisodeNumber; /*!< @brief (optional) episode number */
int iEpisodePartNumber; /*!< @brief (optional) episode part number */
diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/xbmc_pvr_dll.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/xbmc_pvr_dll.h
index 42a2abd779..26e9099a71 100644
--- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/xbmc_pvr_dll.h
+++ b/xbmc/addons/kodi-addon-dev-kit/include/kodi/xbmc_pvr_dll.h
@@ -78,14 +78,14 @@ extern "C"
* Request the EPG for a channel from the backend.
* EPG entries are added to Kodi by calling TransferEpgEntry() on the callback.
* @param handle Handle to pass to the callback method.
- * @param channel The channel to get the EPG table for.
+ * @param iChannelUid The UID of the channel to get the EPG table for.
* @param iStart Get events after this time (UTC).
* @param iEnd Get events before this time (UTC).
* @return PVR_ERROR_NO_ERROR if the table has been fetched successfully.
* @remarks Required if bSupportsEPG is set to true.
* Return PVR_ERROR_NOT_IMPLEMENTED if this add-on won't provide this function.
*/
- PVR_ERROR GetEPGForChannel(ADDON_HANDLE handle, const PVR_CHANNEL& channel, time_t iStart, time_t iEnd);
+ PVR_ERROR GetEPGForChannel(ADDON_HANDLE handle, int iChannelUid, time_t iStart, time_t iEnd);
/*
* Check if the given EPG tag can be recorded.
@@ -641,16 +641,17 @@ extern "C"
void SetSpeed(int speed);
/*!
- * Get the hostname of the pvr backend server
- * @return hostname as ip address or alias. If backend does not utilize a server, return empty string.
+ * Notify the pvr addon/demuxer that Kodi wishes to fill demux queue
+ * @param mode The requested filling mode
+ * @remarks Optional, and only used if addon has its own demuxer.
*/
- const char* GetBackendHostname();
+ void FillBuffer(bool mode);
/*!
- * Check if timeshift is active
- * @return true if timeshift is active
+ * Get the hostname of the pvr backend server
+ * @return hostname as ip address or alias. If backend does not utilize a server, return empty string.
*/
- bool IsTimeshifting();
+ const char* GetBackendHostname();
/*!
* Check for real-time streaming
@@ -753,6 +754,7 @@ extern "C"
pClient->toAddon.CanSeekStream = CanSeekStream;
pClient->toAddon.SeekTime = SeekTime;
pClient->toAddon.SetSpeed = SetSpeed;
+ pClient->toAddon.FillBuffer = FillBuffer;
pClient->toAddon.OpenRecordedStream = OpenRecordedStream;
pClient->toAddon.CloseRecordedStream = CloseRecordedStream;
@@ -767,7 +769,6 @@ extern "C"
pClient->toAddon.GetBackendHostname = GetBackendHostname;
- pClient->toAddon.IsTimeshifting = IsTimeshifting;
pClient->toAddon.IsRealTimeStream = IsRealTimeStream;
pClient->toAddon.SetEPGTimeFrame = SetEPGTimeFrame;
diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/xbmc_pvr_types.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/xbmc_pvr_types.h
index 4752023bac..999d3b391b 100644
--- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/xbmc_pvr_types.h
+++ b/xbmc/addons/kodi-addon-dev-kit/include/kodi/xbmc_pvr_types.h
@@ -55,8 +55,8 @@ struct DemuxPacket;
#define PVR_ADDON_TIMERTYPE_ARRAY_SIZE 32
#define PVR_ADDON_TIMERTYPE_VALUES_ARRAY_SIZE 512
#define PVR_ADDON_TIMERTYPE_VALUES_ARRAY_SIZE_SMALL 128
-#define PVR_ADDON_TIMERTYPE_STRING_LENGTH 64
-#define PVR_ADDON_ATTRIBUTE_DESC_LENGTH 64
+#define PVR_ADDON_TIMERTYPE_STRING_LENGTH 128
+#define PVR_ADDON_ATTRIBUTE_DESC_LENGTH 128
#define PVR_ADDON_ATTRIBUTE_VALUES_ARRAY_SIZE 512
#define PVR_ADDON_DESCRAMBLE_INFO_STRING_LENGTH 64
@@ -311,12 +311,10 @@ extern "C" {
bool bSupportsRecordingsRename; /*!< @brief true if the backend supports renaming recordings. */
bool bSupportsRecordingsLifetimeChange; /*!< @brief true if the backend supports changing lifetime for recordings. */
bool bSupportsDescrambleInfo; /*!< @brief true if the backend supports descramble information for playing channels. */
+ bool bSupportsAsyncEPGTransfer; /*!< @brief true if this addon-on supports asynchronous transfer of epg events to Kodi using the callback function EpgEventStateChange. */
unsigned int iRecordingsLifetimesSize; /*!< @brief (required) Count of possible values for PVR_RECORDING.iLifetime. 0 means lifetime is not supported for recordings or no own value definition wanted, but to use Kodi defaults of 1..365. */
PVR_ATTRIBUTE_INT_VALUE recordingsLifetimeValues[PVR_ADDON_ATTRIBUTE_VALUES_ARRAY_SIZE]; /*!< @brief (optional) Array containing the possible values for PVR_RECORDING.iLifetime. Must be filled if iLifetimesSize > 0 */
-
- // TODO: cleanup: move this member up after the other bools with the next incompatible pvr addon api change.
- bool bSupportsAsyncEPGTransfer; /*!< @brief true if this addon-on supports asynchronous transfer of epg events to Kodi using the callback function EpgEventStateChange. */
} ATTRIBUTE_PACKED PVR_ADDON_CAPABILITIES;
/*!
@@ -403,6 +401,7 @@ extern "C" {
unsigned int iEncryptionSystem; /*!< @brief (optional) the encryption ID or CaID of this channel */
char strIconPath[PVR_ADDON_URL_STRING_LENGTH]; /*!< @brief (optional) path to the channel icon (if present) */
bool bIsHidden; /*!< @brief (optional) true if this channel is marked as hidden */
+ bool bHasArchive; /*!< @brief (optional) true if this channel has a server-side back buffer */
} ATTRIBUTE_PACKED PVR_CHANNEL;
typedef struct PVR_CHANNEL_GROUP
@@ -635,7 +634,7 @@ extern "C" {
const char* (__cdecl* GetConnectionString)(void);
PVR_ERROR (__cdecl* GetDriveSpace)(long long*, long long*);
PVR_ERROR (__cdecl* MenuHook)(const PVR_MENUHOOK&, const PVR_MENUHOOK_DATA&);
- PVR_ERROR (__cdecl* GetEPGForChannel)(ADDON_HANDLE, const PVR_CHANNEL&, time_t, time_t);
+ PVR_ERROR (__cdecl* GetEPGForChannel)(ADDON_HANDLE, int, time_t, time_t);
PVR_ERROR (__cdecl* IsEPGTagRecordable)(const EPG_TAG*, bool*);
PVR_ERROR (__cdecl* IsEPGTagPlayable)(const EPG_TAG*, bool*);
PVR_ERROR (__cdecl* GetEPGTagEdl)(const EPG_TAG*, PVR_EDL_ENTRY[], int*);
@@ -691,8 +690,8 @@ extern "C" {
bool (__cdecl* CanSeekStream)(void);
bool (__cdecl* SeekTime)(double, bool, double*);
void (__cdecl* SetSpeed)(int);
+ void (__cdecl* FillBuffer)(bool);
const char* (__cdecl* GetBackendHostname)(void);
- bool (__cdecl* IsTimeshifting)(void);
bool (__cdecl* IsRealTimeStream)(void);
PVR_ERROR (__cdecl* SetEPGTimeFrame)(int);
void (__cdecl* OnSystemSleep)(void);
diff --git a/xbmc/addons/settings/AddonSettings.cpp b/xbmc/addons/settings/AddonSettings.cpp
index 00fb3bb4fd..1b86a72b9e 100644
--- a/xbmc/addons/settings/AddonSettings.cpp
+++ b/xbmc/addons/settings/AddonSettings.cpp
@@ -22,6 +22,7 @@
#include "guilib/LocalizeStrings.h"
#include "messaging/ApplicationMessenger.h"
#include "settings/SettingAddon.h"
+#include "settings/SettingConditions.h"
#include "settings/SettingControl.h"
#include "settings/SettingDateTime.h"
#include "settings/SettingPath.h"
@@ -392,6 +393,13 @@ void CAddonSettings::InitializeControls()
void CAddonSettings::InitializeConditions()
{
+ CSettingConditions::Initialize();
+
+ // add basic conditions
+ const std::set<std::string>& simpleConditions = CSettingConditions::GetSimpleConditions();
+ for (const auto& condition : simpleConditions)
+ GetSettingsManager()->AddCondition(condition);
+
GetSettingsManager()->AddDynamicCondition("InfoBool", InfoBool);
}
diff --git a/xbmc/cores/RetroPlayer/buffers/RenderBufferPoolOpenGL.cpp b/xbmc/cores/RetroPlayer/buffers/RenderBufferPoolOpenGL.cpp
index b774c91ab3..3ef9356b7b 100644
--- a/xbmc/cores/RetroPlayer/buffers/RenderBufferPoolOpenGL.cpp
+++ b/xbmc/cores/RetroPlayer/buffers/RenderBufferPoolOpenGL.cpp
@@ -18,10 +18,7 @@ using namespace RETRO;
bool CRenderBufferPoolOpenGL::IsCompatible(const CRenderVideoSettings &renderSettings) const
{
- if (!CRPRendererOpenGL::SupportsScalingMethod(renderSettings.GetScalingMethod()))
- return false;
-
- return true;
+ return CRPRendererOpenGL::SupportsScalingMethod(renderSettings.GetScalingMethod());
}
IRenderBuffer *CRenderBufferPoolOpenGL::CreateRenderBuffer(void *header /* = nullptr */)
diff --git a/xbmc/cores/RetroPlayer/buffers/RenderBufferPoolOpenGLES.cpp b/xbmc/cores/RetroPlayer/buffers/RenderBufferPoolOpenGLES.cpp
index e90a55bdd2..3e9c763ddf 100644
--- a/xbmc/cores/RetroPlayer/buffers/RenderBufferPoolOpenGLES.cpp
+++ b/xbmc/cores/RetroPlayer/buffers/RenderBufferPoolOpenGLES.cpp
@@ -23,10 +23,7 @@ CRenderBufferPoolOpenGLES::CRenderBufferPoolOpenGLES(CRenderContext &context)
bool CRenderBufferPoolOpenGLES::IsCompatible(const CRenderVideoSettings &renderSettings) const
{
- if (!CRPRendererOpenGLES::SupportsScalingMethod(renderSettings.GetScalingMethod()))
- return false;
-
- return true;
+ return CRPRendererOpenGLES::SupportsScalingMethod(renderSettings.GetScalingMethod());
}
IRenderBuffer *CRenderBufferPoolOpenGLES::CreateRenderBuffer(void *header /* = nullptr */)
diff --git a/xbmc/cores/RetroPlayer/rendering/VideoRenderers/RPBaseRenderer.cpp b/xbmc/cores/RetroPlayer/rendering/VideoRenderers/RPBaseRenderer.cpp
index 48535180cb..9295d85107 100644
--- a/xbmc/cores/RetroPlayer/rendering/VideoRenderers/RPBaseRenderer.cpp
+++ b/xbmc/cores/RetroPlayer/rendering/VideoRenderers/RPBaseRenderer.cpp
@@ -36,10 +36,7 @@ CRPBaseRenderer::~CRPBaseRenderer()
bool CRPBaseRenderer::IsCompatible(const CRenderVideoSettings &settings) const
{
- if (!m_bufferPool->IsCompatible(settings))
- return false;
-
- return true;
+ return m_bufferPool->IsCompatible(settings);
}
bool CRPBaseRenderer::Configure(AVPixelFormat format)
@@ -70,10 +67,7 @@ void CRPBaseRenderer::FrameMove()
bool CRPBaseRenderer::IsVisible() const
{
- if (m_renderFrameCount <= m_lastRender + VISIBLE_DURATION_FRAME_COUNT)
- return true;
-
- return false;
+ return m_renderFrameCount <= m_lastRender + VISIBLE_DURATION_FRAME_COUNT;
}
void CRPBaseRenderer::SetBuffer(IRenderBuffer *buffer)
diff --git a/xbmc/cores/RetroPlayer/rendering/VideoRenderers/RPRendererGuiTexture.cpp b/xbmc/cores/RetroPlayer/rendering/VideoRenderers/RPRendererGuiTexture.cpp
index 5485358cad..01f30710da 100644
--- a/xbmc/cores/RetroPlayer/rendering/VideoRenderers/RPRendererGuiTexture.cpp
+++ b/xbmc/cores/RetroPlayer/rendering/VideoRenderers/RPRendererGuiTexture.cpp
@@ -53,10 +53,7 @@ CRenderBufferPoolGuiTexture::CRenderBufferPoolGuiTexture(SCALINGMETHOD scalingMe
bool CRenderBufferPoolGuiTexture::IsCompatible(const CRenderVideoSettings &renderSettings) const
{
- if (renderSettings.GetScalingMethod() != m_scalingMethod)
- return false;
-
- return true;
+ return renderSettings.GetScalingMethod() == m_scalingMethod;
}
IRenderBuffer *CRenderBufferPoolGuiTexture::CreateRenderBuffer(void *header /* = nullptr */)
@@ -73,15 +70,10 @@ CRPRendererGuiTexture::CRPRendererGuiTexture(const CRenderSettings &renderSettin
bool CRPRendererGuiTexture::Supports(RENDERFEATURE feature) const
{
- if (feature == RENDERFEATURE::STRETCH ||
- feature == RENDERFEATURE::ZOOM ||
- feature == RENDERFEATURE::PIXEL_RATIO ||
- feature == RENDERFEATURE::ROTATION)
- {
- return true;
- }
-
- return false;
+ return feature == RENDERFEATURE::STRETCH ||
+ feature == RENDERFEATURE::ZOOM ||
+ feature == RENDERFEATURE::PIXEL_RATIO ||
+ feature == RENDERFEATURE::ROTATION;
}
void CRPRendererGuiTexture::RenderInternal(bool clear, uint8_t alpha)
diff --git a/xbmc/cores/RetroPlayer/rendering/VideoRenderers/RPRendererOpenGL.cpp b/xbmc/cores/RetroPlayer/rendering/VideoRenderers/RPRendererOpenGL.cpp
index 6bb90b1887..8e91704440 100644
--- a/xbmc/cores/RetroPlayer/rendering/VideoRenderers/RPRendererOpenGL.cpp
+++ b/xbmc/cores/RetroPlayer/rendering/VideoRenderers/RPRendererOpenGL.cpp
@@ -127,26 +127,16 @@ void CRPRendererOpenGL::FlushInternal()
bool CRPRendererOpenGL::Supports(RENDERFEATURE feature) const
{
- if (feature == RENDERFEATURE::STRETCH ||
- feature == RENDERFEATURE::ZOOM ||
- feature == RENDERFEATURE::PIXEL_RATIO ||
- feature == RENDERFEATURE::ROTATION)
- {
- return true;
- }
-
- return false;
+ return feature == RENDERFEATURE::STRETCH ||
+ feature == RENDERFEATURE::ZOOM ||
+ feature == RENDERFEATURE::PIXEL_RATIO ||
+ feature == RENDERFEATURE::ROTATION;
}
bool CRPRendererOpenGL::SupportsScalingMethod(SCALINGMETHOD method)
{
- if (method == SCALINGMETHOD::NEAREST ||
- method == SCALINGMETHOD::LINEAR)
- {
- return true;
- }
-
- return false;
+ return method == SCALINGMETHOD::NEAREST ||
+ method == SCALINGMETHOD::LINEAR;
}
void CRPRendererOpenGL::ClearBackBuffer()
diff --git a/xbmc/cores/RetroPlayer/rendering/VideoRenderers/RPRendererOpenGLES.cpp b/xbmc/cores/RetroPlayer/rendering/VideoRenderers/RPRendererOpenGLES.cpp
index a613f7674a..057a00541f 100644
--- a/xbmc/cores/RetroPlayer/rendering/VideoRenderers/RPRendererOpenGLES.cpp
+++ b/xbmc/cores/RetroPlayer/rendering/VideoRenderers/RPRendererOpenGLES.cpp
@@ -92,26 +92,16 @@ void CRPRendererOpenGLES::FlushInternal()
bool CRPRendererOpenGLES::Supports(RENDERFEATURE feature) const
{
- if (feature == RENDERFEATURE::STRETCH ||
- feature == RENDERFEATURE::ZOOM ||
- feature == RENDERFEATURE::PIXEL_RATIO ||
- feature == RENDERFEATURE::ROTATION)
- {
- return true;
- }
-
- return false;
+ return feature == RENDERFEATURE::STRETCH ||
+ feature == RENDERFEATURE::ZOOM ||
+ feature == RENDERFEATURE::PIXEL_RATIO ||
+ feature == RENDERFEATURE::ROTATION;
}
bool CRPRendererOpenGLES::SupportsScalingMethod(SCALINGMETHOD method)
{
- if (method == SCALINGMETHOD::NEAREST ||
- method == SCALINGMETHOD::LINEAR)
- {
- return true;
- }
-
- return false;
+ return method == SCALINGMETHOD::NEAREST ||
+ method == SCALINGMETHOD::LINEAR;
}
void CRPRendererOpenGLES::ClearBackBuffer()
diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.cpp
index 382b163a71..48796e944b 100644
--- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.cpp
+++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.cpp
@@ -10,6 +10,7 @@
#include "ServiceBroker.h"
#include "cores/VideoPlayer/DVDCodecs/DVDFactoryCodec.h"
+#include "cores/VideoPlayer/Process/gbm/VideoBufferDRMPRIME.h"
#include "settings/Settings.h"
#include "settings/SettingsComponent.h"
#include "settings/lib/Setting.h"
@@ -24,137 +25,6 @@ extern "C" {
using namespace KODI::WINDOWING::GBM;
-//------------------------------------------------------------------------------
-// Video Buffers
-//------------------------------------------------------------------------------
-
-CVideoBufferDRMPRIME::CVideoBufferDRMPRIME(IVideoBufferPool& pool, int id)
- : CVideoBuffer(id)
-{
- m_pFrame = av_frame_alloc();
-}
-
-CVideoBufferDRMPRIME::~CVideoBufferDRMPRIME()
-{
- Unref();
- av_frame_free(&m_pFrame);
-}
-
-void CVideoBufferDRMPRIME::SetRef(AVFrame* frame)
-{
- av_frame_move_ref(m_pFrame, frame);
-}
-
-void CVideoBufferDRMPRIME::Unref()
-{
- av_frame_unref(m_pFrame);
-}
-
-int CVideoBufferDRMPRIME::GetColorEncoding() const
-{
- switch (m_pFrame->colorspace)
- {
- case AVCOL_SPC_BT2020_CL:
- case AVCOL_SPC_BT2020_NCL:
- return DRM_COLOR_YCBCR_BT2020;
- case AVCOL_SPC_SMPTE170M:
- case AVCOL_SPC_BT470BG:
- case AVCOL_SPC_FCC:
- return DRM_COLOR_YCBCR_BT601;
- case AVCOL_SPC_BT709:
- return DRM_COLOR_YCBCR_BT709;
- case AVCOL_SPC_RESERVED:
- case AVCOL_SPC_UNSPECIFIED:
- default:
- if (m_pFrame->width > 1024 || m_pFrame->height >= 600)
- return DRM_COLOR_YCBCR_BT709;
- else
- return DRM_COLOR_YCBCR_BT601;
- }
-}
-
-int CVideoBufferDRMPRIME::GetColorRange() const
-{
- switch (m_pFrame->color_range)
- {
- case AVCOL_RANGE_JPEG:
- return DRM_COLOR_YCBCR_FULL_RANGE;
- case AVCOL_RANGE_MPEG:
- default:
- return DRM_COLOR_YCBCR_LIMITED_RANGE;
- }
-}
-
-//------------------------------------------------------------------------------
-
-class CVideoBufferPoolDRMPRIME
- : public IVideoBufferPool
-{
-public:
- ~CVideoBufferPoolDRMPRIME();
- void Return(int id) override;
- CVideoBuffer* Get() override;
-
-protected:
- CCriticalSection m_critSection;
- std::vector<CVideoBufferDRMPRIME*> m_all;
- std::deque<int> m_used;
- std::deque<int> m_free;
-};
-
-CVideoBufferPoolDRMPRIME::~CVideoBufferPoolDRMPRIME()
-{
- for (auto buf : m_all)
- delete buf;
-}
-
-CVideoBuffer* CVideoBufferPoolDRMPRIME::Get()
-{
- CSingleLock lock(m_critSection);
-
- CVideoBufferDRMPRIME* buf = nullptr;
- if (!m_free.empty())
- {
- int idx = m_free.front();
- m_free.pop_front();
- m_used.push_back(idx);
- buf = m_all[idx];
- }
- else
- {
- int id = m_all.size();
- buf = new CVideoBufferDRMPRIME(*this, id);
- m_all.push_back(buf);
- m_used.push_back(id);
- }
-
- buf->Acquire(GetPtr());
- return buf;
-}
-
-void CVideoBufferPoolDRMPRIME::Return(int id)
-{
- CSingleLock lock(m_critSection);
-
- m_all[id]->Unref();
- auto it = m_used.begin();
- while (it != m_used.end())
- {
- if (*it == id)
- {
- m_used.erase(it);
- break;
- }
- else
- ++it;
- }
- m_free.push_back(id);
-}
-
-//------------------------------------------------------------------------------
-// main class
-//------------------------------------------------------------------------------
-
CDVDVideoCodecDRMPRIME::CDVDVideoCodecDRMPRIME(CProcessInfo& processInfo)
: CDVDVideoCodec(processInfo)
{
@@ -220,11 +90,17 @@ static const AVCodec* FindDecoder(CDVDStreamInfo& hints)
return nullptr;
}
-static enum AVPixelFormat GetFormat(struct AVCodecContext* avctx, const enum AVPixelFormat* fmt)
+enum AVPixelFormat CDVDVideoCodecDRMPRIME::GetFormat(struct AVCodecContext* avctx, const enum AVPixelFormat* fmt)
{
for (int n = 0; fmt[n] != AV_PIX_FMT_NONE; n++)
+ {
if (fmt[n] == AV_PIX_FMT_DRM_PRIME)
+ {
+ CDVDVideoCodecDRMPRIME* ctx = static_cast<CDVDVideoCodecDRMPRIME*>(avctx->opaque);
+ ctx->UpdateProcessInfo(avctx, fmt[n]);
return fmt[n];
+ }
+ }
return AV_PIX_FMT_NONE;
}
@@ -259,6 +135,7 @@ bool CDVDVideoCodecDRMPRIME::Open(CDVDStreamInfo& hints, CDVDCodecOptions& optio
}
m_pCodecContext->pix_fmt = AV_PIX_FMT_DRM_PRIME;
+ m_pCodecContext->opaque = static_cast<void*>(this);
m_pCodecContext->get_format = GetFormat;
m_pCodecContext->codec_tag = hints.codec_tag;
m_pCodecContext->coded_width = hints.width;
@@ -281,27 +158,25 @@ bool CDVDVideoCodecDRMPRIME::Open(CDVDStreamInfo& hints, CDVDCodecOptions& optio
return false;
}
- if (m_pCodecContext->pix_fmt != AV_PIX_FMT_DRM_PRIME)
- {
- CLog::Log(LOGNOTICE, "CDVDVideoCodecDRMPRIME::%s - unexpected pix fmt %s", __FUNCTION__, av_get_pix_fmt_name(m_pCodecContext->pix_fmt));
- avcodec_free_context(&m_pCodecContext);
- return false;
- }
-
- const char* pixFmtName = av_get_pix_fmt_name(m_pCodecContext->pix_fmt);
- m_processInfo.SetVideoPixelFormat(pixFmtName ? pixFmtName : "");
- m_processInfo.SetVideoDimensions(hints.width, hints.height);
+ UpdateProcessInfo(m_pCodecContext, m_pCodecContext->pix_fmt);
m_processInfo.SetVideoDeintMethod("none");
m_processInfo.SetVideoDAR(hints.aspect);
- if (pCodec->name)
- m_name = std::string("ff-") + pCodec->name;
+ return true;
+}
+
+void CDVDVideoCodecDRMPRIME::UpdateProcessInfo(struct AVCodecContext* avctx, const enum AVPixelFormat pix_fmt)
+{
+ const char* pixFmtName = av_get_pix_fmt_name(pix_fmt);
+ m_processInfo.SetVideoPixelFormat(pixFmtName ? pixFmtName : "");
+ m_processInfo.SetVideoDimensions(avctx->coded_width, avctx->coded_height);
+
+ if (avctx->codec && avctx->codec->name)
+ m_name = std::string("ff-") + avctx->codec->name;
else
m_name = "ffmpeg";
- m_processInfo.SetVideoDecoderName(m_name, true);
-
- return true;
+ m_processInfo.SetVideoDecoderName(m_name, pix_fmt == AV_PIX_FMT_DRM_PRIME);
}
bool CDVDVideoCodecDRMPRIME::AddData(const DemuxPacket& packet)
@@ -412,9 +287,18 @@ CDVDVideoCodec::VCReturn CDVDVideoCodecDRMPRIME::GetPicture(VideoPicture* pVideo
SetPictureParams(pVideoPicture);
- CVideoBufferDRMPRIME* buffer = dynamic_cast<CVideoBufferDRMPRIME*>(m_videoBufferPool->Get());
- buffer->SetRef(m_pFrame);
- pVideoPicture->videoBuffer = buffer;
+ if (m_pFrame->format == AV_PIX_FMT_DRM_PRIME)
+ {
+ CVideoBufferDRMPRIME* buffer = dynamic_cast<CVideoBufferDRMPRIME*>(m_videoBufferPool->Get());
+ buffer->SetRef(m_pFrame);
+ pVideoPicture->videoBuffer = buffer;
+ }
+
+ if (!pVideoPicture->videoBuffer)
+ {
+ CLog::Log(LOGERROR, "CDVDVideoCodecDRMPRIME::{} - videoBuffer:nullptr format:{}", __FUNCTION__, av_get_pix_fmt_name(static_cast<AVPixelFormat>(m_pFrame->format)));
+ return VC_ERROR;
+ }
return VC_PICTURE;
}
diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.h b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.h
index cb2929e545..8d399eb5bc 100644
--- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.h
+++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.h
@@ -13,45 +13,6 @@
#include "cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodec.h"
#include "cores/VideoPlayer/Process/VideoBuffer.h"
-extern "C" {
-#include <libavutil/frame.h>
-#include <libavutil/hwcontext_drm.h>
-}
-
-// Color enums is copied from linux include/drm/drm_color_mgmt.h (strangely not part of uapi)
-enum drm_color_encoding {
- DRM_COLOR_YCBCR_BT601,
- DRM_COLOR_YCBCR_BT709,
- DRM_COLOR_YCBCR_BT2020,
-};
-enum drm_color_range {
- DRM_COLOR_YCBCR_LIMITED_RANGE,
- DRM_COLOR_YCBCR_FULL_RANGE,
-};
-
-class CVideoBufferPoolDRMPRIME;
-
-class CVideoBufferDRMPRIME
- : public CVideoBuffer
-{
-public:
- CVideoBufferDRMPRIME(IVideoBufferPool& pool, int id);
- ~CVideoBufferDRMPRIME();
- void SetRef(AVFrame* frame);
- void Unref();
-
- uint32_t m_fb_id = 0;
- uint32_t m_handles[AV_DRM_MAX_PLANES] = {0};
-
- AVDRMFrameDescriptor* GetDescriptor() const { return reinterpret_cast<AVDRMFrameDescriptor*>(m_pFrame->data[0]); }
- uint32_t GetWidth() const { return m_pFrame->width; }
- uint32_t GetHeight() const { return m_pFrame->height; }
- int GetColorEncoding() const;
- int GetColorRange() const;
-protected:
- AVFrame* m_pFrame = nullptr;
-};
-
class CDVDVideoCodecDRMPRIME
: public CDVDVideoCodec
{
@@ -73,10 +34,12 @@ public:
protected:
void Drain();
void SetPictureParams(VideoPicture* pVideoPicture);
+ void UpdateProcessInfo(struct AVCodecContext* avctx, const enum AVPixelFormat fmt);
+ static enum AVPixelFormat GetFormat(struct AVCodecContext* avctx, const enum AVPixelFormat* fmt);
std::string m_name;
int m_codecControlFlags = 0;
AVCodecContext* m_pCodecContext = nullptr;
AVFrame* m_pFrame = nullptr;
- std::shared_ptr<CVideoBufferPoolDRMPRIME> m_videoBufferPool;
+ std::shared_ptr<IVideoBufferPool> m_videoBufferPool;
};
diff --git a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemux.h b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemux.h
index a8a6dd9b24..65803dc868 100644
--- a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemux.h
+++ b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemux.h
@@ -278,6 +278,11 @@ public:
virtual void SetSpeed(int iSpeed) { }
/*
+ * Let demuxer know if we want to fill demux queue
+ */
+ virtual void FillBuffer(bool mode) { }
+
+ /*
* returns the total time in msec
*/
virtual int GetStreamLength() { return 0; }
diff --git a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxClient.cpp b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxClient.cpp
index 48e8275c22..994c28c278 100644
--- a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxClient.cpp
+++ b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxClient.cpp
@@ -631,6 +631,14 @@ void CDVDDemuxClient::SetSpeed (int speed)
}
}
+void CDVDDemuxClient::FillBuffer(bool mode)
+{
+ if (m_IDemux)
+ {
+ m_IDemux->FillBuffer(mode);
+ }
+}
+
void CDVDDemuxClient::EnableStream(int id, bool enable)
{
if (m_IDemux)
diff --git a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxClient.h b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxClient.h
index c96a936d34..9f4ef7e374 100644
--- a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxClient.h
+++ b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxClient.h
@@ -32,6 +32,7 @@ public:
DemuxPacket* Read() override;
bool SeekTime(double time, bool backwards = false, double* startpts = NULL) override;
void SetSpeed(int iSpeed) override;
+ void FillBuffer(bool mode) override;
CDemuxStream* GetStream(int iStreamId) const override;
std::vector<CDemuxStream*> GetStreams() const override;
int GetNrOfStreams() const override;
diff --git a/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStream.h b/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStream.h
index 8dc39442c9..bb48694025 100644
--- a/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStream.h
+++ b/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStream.h
@@ -128,6 +128,7 @@ public:
virtual bool OpenStream(int iStreamId) { return false; };
virtual int GetNrOfStreams() const = 0;
virtual void SetSpeed(int iSpeed) = 0;
+ virtual void FillBuffer(bool mode) {};
virtual bool SeekTime(double time, bool backward = false, double* startpts = NULL) = 0;
virtual void AbortDemux() = 0;
virtual void FlushDemux() = 0;
diff --git a/xbmc/cores/VideoPlayer/DVDInputStreams/InputStreamPVRBase.cpp b/xbmc/cores/VideoPlayer/DVDInputStreams/InputStreamPVRBase.cpp
index ac2fa2fbc8..d706bc30d7 100644
--- a/xbmc/cores/VideoPlayer/DVDInputStreams/InputStreamPVRBase.cpp
+++ b/xbmc/cores/VideoPlayer/DVDInputStreams/InputStreamPVRBase.cpp
@@ -217,6 +217,12 @@ void CInputStreamPVRBase::SetSpeed(int Speed)
m_client->SetSpeed(Speed);
}
+void CInputStreamPVRBase::FillBuffer(bool mode)
+{
+ if (m_client)
+ m_client->FillBuffer(mode);
+}
+
bool CInputStreamPVRBase::SeekTime(double timems, bool backwards, double *startpts)
{
if (m_client)
diff --git a/xbmc/cores/VideoPlayer/DVDInputStreams/InputStreamPVRBase.h b/xbmc/cores/VideoPlayer/DVDInputStreams/InputStreamPVRBase.h
index c339599ccd..66e6762354 100644
--- a/xbmc/cores/VideoPlayer/DVDInputStreams/InputStreamPVRBase.h
+++ b/xbmc/cores/VideoPlayer/DVDInputStreams/InputStreamPVRBase.h
@@ -58,6 +58,7 @@ public:
std::vector<CDemuxStream*> GetStreams() const override;
int GetNrOfStreams() const override;
void SetSpeed(int iSpeed) override;
+ void FillBuffer(bool mode) override;
bool SeekTime(double time, bool backward = false, double* startpts = NULL) override;
void AbortDemux() override;
void FlushDemux() override;
diff --git a/xbmc/cores/VideoPlayer/Process/gbm/CMakeLists.txt b/xbmc/cores/VideoPlayer/Process/gbm/CMakeLists.txt
new file mode 100644
index 0000000000..d1398d77a3
--- /dev/null
+++ b/xbmc/cores/VideoPlayer/Process/gbm/CMakeLists.txt
@@ -0,0 +1,7 @@
+set(SOURCES ProcessInfoGBM.cpp
+ VideoBufferDRMPRIME.cpp)
+
+set(HEADERS ProcessInfoGBM.h
+ VideoBufferDRMPRIME.h)
+
+core_add_library(processGBM)
diff --git a/xbmc/cores/VideoPlayer/Process/gbm/ProcessInfoGBM.cpp b/xbmc/cores/VideoPlayer/Process/gbm/ProcessInfoGBM.cpp
new file mode 100644
index 0000000000..0228319397
--- /dev/null
+++ b/xbmc/cores/VideoPlayer/Process/gbm/ProcessInfoGBM.cpp
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2019 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#include "ProcessInfoGBM.h"
+
+using namespace VIDEOPLAYER;
+
+CProcessInfo* CProcessInfoGBM::Create()
+{
+ return new CProcessInfoGBM();
+}
+
+void CProcessInfoGBM::Register()
+{
+ CProcessInfo::RegisterProcessControl("gbm", CProcessInfoGBM::Create);
+}
+
+CProcessInfoGBM::CProcessInfoGBM()
+{
+}
+
+EINTERLACEMETHOD CProcessInfoGBM::GetFallbackDeintMethod()
+{
+#if defined(__arm__)
+ return EINTERLACEMETHOD::VS_INTERLACEMETHOD_DEINTERLACE_HALF;
+#else
+ return CProcessInfo::GetFallbackDeintMethod();
+#endif
+}
diff --git a/xbmc/cores/VideoPlayer/Process/gbm/ProcessInfoGBM.h b/xbmc/cores/VideoPlayer/Process/gbm/ProcessInfoGBM.h
new file mode 100644
index 0000000000..479e4fde4c
--- /dev/null
+++ b/xbmc/cores/VideoPlayer/Process/gbm/ProcessInfoGBM.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2019 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#pragma once
+
+#include "cores/IPlayer.h"
+#include "cores/VideoPlayer/Process/ProcessInfo.h"
+
+namespace VIDEOPLAYER
+{
+
+class CProcessInfoGBM : public CProcessInfo
+{
+public:
+ CProcessInfoGBM();
+ static CProcessInfo* Create();
+ static void Register();
+ EINTERLACEMETHOD GetFallbackDeintMethod() override;
+};
+
+} // namespace VIDEOPLAYER
diff --git a/xbmc/cores/VideoPlayer/Process/gbm/VideoBufferDRMPRIME.cpp b/xbmc/cores/VideoPlayer/Process/gbm/VideoBufferDRMPRIME.cpp
new file mode 100644
index 0000000000..719f0185bc
--- /dev/null
+++ b/xbmc/cores/VideoPlayer/Process/gbm/VideoBufferDRMPRIME.cpp
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2017-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#include "VideoBufferDRMPRIME.h"
+
+#include "threads/SingleLock.h"
+
+extern "C"
+{
+#include <libavcodec/avcodec.h>
+#include <libavutil/pixdesc.h>
+}
+
+IVideoBufferDRMPRIME::IVideoBufferDRMPRIME(int id)
+ : CVideoBuffer(id)
+{
+}
+
+CVideoBufferDRMPRIME::CVideoBufferDRMPRIME(IVideoBufferPool& pool, int id)
+ : IVideoBufferDRMPRIME(id)
+{
+ m_pFrame = av_frame_alloc();
+}
+
+CVideoBufferDRMPRIME::~CVideoBufferDRMPRIME()
+{
+ Unref();
+ av_frame_free(&m_pFrame);
+}
+
+void CVideoBufferDRMPRIME::SetRef(AVFrame* frame)
+{
+ av_frame_move_ref(m_pFrame, frame);
+}
+
+void CVideoBufferDRMPRIME::Unref()
+{
+ av_frame_unref(m_pFrame);
+}
+
+int CVideoBufferDRMPRIME::GetColorEncoding() const
+{
+ switch (m_pFrame->colorspace)
+ {
+ case AVCOL_SPC_BT2020_CL:
+ case AVCOL_SPC_BT2020_NCL:
+ return DRM_COLOR_YCBCR_BT2020;
+ case AVCOL_SPC_SMPTE170M:
+ case AVCOL_SPC_BT470BG:
+ case AVCOL_SPC_FCC:
+ return DRM_COLOR_YCBCR_BT601;
+ case AVCOL_SPC_BT709:
+ return DRM_COLOR_YCBCR_BT709;
+ case AVCOL_SPC_RESERVED:
+ case AVCOL_SPC_UNSPECIFIED:
+ default:
+ if (m_pFrame->width > 1024 || m_pFrame->height >= 600)
+ return DRM_COLOR_YCBCR_BT709;
+ else
+ return DRM_COLOR_YCBCR_BT601;
+ }
+}
+
+int CVideoBufferDRMPRIME::GetColorRange() const
+{
+ switch (m_pFrame->color_range)
+ {
+ case AVCOL_RANGE_JPEG:
+ return DRM_COLOR_YCBCR_FULL_RANGE;
+ case AVCOL_RANGE_MPEG:
+ default:
+ return DRM_COLOR_YCBCR_LIMITED_RANGE;
+ }
+}
+
+bool CVideoBufferDRMPRIME::IsValid() const
+{
+ AVDRMFrameDescriptor* descriptor = GetDescriptor();
+ return descriptor && descriptor->nb_layers;
+}
+
+CVideoBufferPoolDRMPRIME::~CVideoBufferPoolDRMPRIME()
+{
+ for (auto buf : m_all)
+ delete buf;
+}
+
+CVideoBuffer* CVideoBufferPoolDRMPRIME::Get()
+{
+ CSingleLock lock(m_critSection);
+
+ CVideoBufferDRMPRIME* buf = nullptr;
+ if (!m_free.empty())
+ {
+ int idx = m_free.front();
+ m_free.pop_front();
+ m_used.push_back(idx);
+ buf = m_all[idx];
+ }
+ else
+ {
+ int id = m_all.size();
+ buf = new CVideoBufferDRMPRIME(*this, id);
+ m_all.push_back(buf);
+ m_used.push_back(id);
+ }
+
+ buf->Acquire(GetPtr());
+ return buf;
+}
+
+void CVideoBufferPoolDRMPRIME::Return(int id)
+{
+ CSingleLock lock(m_critSection);
+
+ m_all[id]->Unref();
+ auto it = m_used.begin();
+ while (it != m_used.end())
+ {
+ if (*it == id)
+ {
+ m_used.erase(it);
+ break;
+ }
+ else
+ ++it;
+ }
+ m_free.push_back(id);
+}
diff --git a/xbmc/cores/VideoPlayer/Process/gbm/VideoBufferDRMPRIME.h b/xbmc/cores/VideoPlayer/Process/gbm/VideoBufferDRMPRIME.h
new file mode 100644
index 0000000000..643395a681
--- /dev/null
+++ b/xbmc/cores/VideoPlayer/Process/gbm/VideoBufferDRMPRIME.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2017-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#pragma once
+
+#include "cores/VideoPlayer/Process/VideoBuffer.h"
+
+extern "C"
+{
+#include <libavutil/frame.h>
+#include <libavutil/hwcontext_drm.h>
+}
+
+// Color enums is copied from linux include/drm/drm_color_mgmt.h (strangely not part of uapi)
+enum drm_color_encoding
+{
+ DRM_COLOR_YCBCR_BT601,
+ DRM_COLOR_YCBCR_BT709,
+ DRM_COLOR_YCBCR_BT2020,
+};
+enum drm_color_range
+{
+ DRM_COLOR_YCBCR_LIMITED_RANGE,
+ DRM_COLOR_YCBCR_FULL_RANGE,
+};
+
+class IVideoBufferDRMPRIME : public CVideoBuffer
+{
+public:
+ IVideoBufferDRMPRIME() = delete;
+ virtual ~IVideoBufferDRMPRIME() = default;
+
+ virtual AVDRMFrameDescriptor* GetDescriptor() const = 0;
+ virtual uint32_t GetWidth() const = 0;
+ virtual uint32_t GetHeight() const = 0;
+ virtual int GetColorEncoding() const
+ {
+ return DRM_COLOR_YCBCR_BT709;
+ };
+ virtual int GetColorRange() const
+ {
+ return DRM_COLOR_YCBCR_LIMITED_RANGE;
+ };
+
+ virtual bool IsValid() const
+ {
+ return true;
+ };
+ virtual bool Map()
+ {
+ return true;
+ };
+ virtual void Unmap() {};
+
+ uint32_t m_fb_id = 0;
+ uint32_t m_handles[AV_DRM_MAX_PLANES] = {};
+
+protected:
+ explicit IVideoBufferDRMPRIME(int id);
+};
+
+class CVideoBufferDRMPRIME : public IVideoBufferDRMPRIME
+{
+public:
+ CVideoBufferDRMPRIME(IVideoBufferPool& pool, int id);
+ ~CVideoBufferDRMPRIME();
+ void SetRef(AVFrame* frame);
+ void Unref();
+
+ AVDRMFrameDescriptor* GetDescriptor() const override
+ {
+ return reinterpret_cast<AVDRMFrameDescriptor*>(m_pFrame->data[0]);
+ }
+ uint32_t GetWidth() const override
+ {
+ return m_pFrame->width;
+ }
+ uint32_t GetHeight() const override
+ {
+ return m_pFrame->height;
+ }
+ int GetColorEncoding() const override;
+ int GetColorRange() const override;
+
+ bool IsValid() const override;
+
+protected:
+ AVFrame* m_pFrame = nullptr;
+};
+
+class CVideoBufferPoolDRMPRIME : public IVideoBufferPool
+{
+public:
+ ~CVideoBufferPoolDRMPRIME();
+ void Return(int id) override;
+ CVideoBuffer* Get() override;
+
+protected:
+ CCriticalSection m_critSection;
+ std::vector<CVideoBufferDRMPRIME*> m_all;
+ std::deque<int> m_used;
+ std::deque<int> m_free;
+};
diff --git a/xbmc/cores/VideoPlayer/VideoPlayer.cpp b/xbmc/cores/VideoPlayer/VideoPlayer.cpp
index 4ea7b45812..c62a26b860 100644
--- a/xbmc/cores/VideoPlayer/VideoPlayer.cpp
+++ b/xbmc/cores/VideoPlayer/VideoPlayer.cpp
@@ -1447,6 +1447,24 @@ void CVideoPlayer::Process()
// make sure we run subtitle process here
m_VideoPlayerSubtitle->Process(m_clock.GetClock() + m_State.time_offset - m_VideoPlayerVideo->GetSubtitleDelay(), m_State.time_offset);
+ // tell demuxer if we want to fill buffers
+ if (m_demuxerSpeed != DVD_PLAYSPEED_PAUSE)
+ {
+ int audioLevel = 90;
+ int videoLevel = 90;
+ bool fillBuffer = false;
+ if (m_CurrentAudio.id >= 0)
+ audioLevel = m_VideoPlayerAudio->GetLevel();
+ if (m_CurrentVideo.id >= 0)
+ videoLevel = m_processInfo->GetLevelVQ();
+ if (videoLevel < 85 && audioLevel < 85)
+ {
+ fillBuffer = true;
+ }
+ if (m_pDemuxer)
+ m_pDemuxer->FillBuffer(fillBuffer);
+ }
+
// if the queues are full, no need to read more
if ((!m_VideoPlayerAudio->AcceptsData() && m_CurrentAudio.id >= 0) ||
(!m_VideoPlayerVideo->AcceptsData() && m_CurrentVideo.id >= 0))
@@ -1472,11 +1490,6 @@ void CVideoPlayer::Process()
m_demuxerSpeed = m_playSpeed;
}
- // always yield to players if they have data levels > 50 percent
- if((m_VideoPlayerAudio->GetLevel() > 50 || m_CurrentAudio.id < 0) &&
- (m_processInfo->GetLevelVQ() > 50 || m_CurrentVideo.id < 0))
- Sleep(0);
-
DemuxPacket* pPacket = NULL;
CDemuxStream *pStream = NULL;
ReadPacket(pPacket, pStream);
@@ -3983,6 +3996,8 @@ void CVideoPlayer::FlushBuffers(double pts, bool accurate, bool sync)
m_clock.Discontinuity(pts);
UpdatePlayState(0);
+ m_demuxerSpeed = DVD_PLAYSPEED_NORMAL;
+
if (m_omxplayer_mode)
{
m_OmxPlayerState.av_clock.OMXFlush();
diff --git a/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/DRMPRIMEEGL.cpp b/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/DRMPRIMEEGL.cpp
index 91809f8ebe..17dd7e1e19 100644
--- a/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/DRMPRIMEEGL.cpp
+++ b/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/DRMPRIMEEGL.cpp
@@ -15,11 +15,14 @@ void CDRMPRIMETexture::Init(EGLDisplay eglDisplay)
m_eglImage.reset(new CEGLImage(eglDisplay));
}
-bool CDRMPRIMETexture::Map(CVideoBufferDRMPRIME *buffer)
+bool CDRMPRIMETexture::Map(IVideoBufferDRMPRIME* buffer)
{
if (m_primebuffer)
return true;
+ if (!buffer->Map())
+ return false;
+
m_texWidth = buffer->GetWidth();
m_texHeight = buffer->GetHeight();
@@ -74,6 +77,8 @@ void CDRMPRIMETexture::Unmap()
glDeleteTextures(1, &m_texture);
+ m_primebuffer->Unmap();
+
m_primebuffer->Release();
m_primebuffer = nullptr;
}
diff --git a/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/DRMPRIMEEGL.h b/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/DRMPRIMEEGL.h
index abc4890acb..55cb2be330 100644
--- a/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/DRMPRIMEEGL.h
+++ b/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/DRMPRIMEEGL.h
@@ -8,15 +8,16 @@
#pragma once
-#include "cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.h"
+#include "cores/VideoPlayer/Process/gbm/VideoBufferDRMPRIME.h"
#include "utils/EGLImage.h"
+#include "utils/Geometry.h"
#include "system_gl.h"
class CDRMPRIMETexture
{
public:
- bool Map(CVideoBufferDRMPRIME *buffer);
+ bool Map(IVideoBufferDRMPRIME* buffer);
void Unmap();
void Init(EGLDisplay eglDisplay);
@@ -24,7 +25,7 @@ public:
CSizeInt GetTextureSize() { return { m_texWidth, m_texHeight }; }
protected:
- CVideoBufferDRMPRIME *m_primebuffer{nullptr};
+ IVideoBufferDRMPRIME* m_primebuffer{nullptr};
std::unique_ptr<CEGLImage> m_eglImage;
const GLenum m_textureTarget{GL_TEXTURE_EXTERNAL_OES};
diff --git a/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/RendererDRMPRIME.cpp b/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/RendererDRMPRIME.cpp
index 295b269c82..df0fb6fd9c 100644
--- a/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/RendererDRMPRIME.cpp
+++ b/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/RendererDRMPRIME.cpp
@@ -8,20 +8,21 @@
#include "RendererDRMPRIME.h"
-#include "cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.h"
+#include "ServiceBroker.h"
+#include "cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodec.h"
+#include "cores/VideoPlayer/Process/gbm/VideoBufferDRMPRIME.h"
#include "cores/VideoPlayer/VideoRenderers/HwDecRender/VideoLayerBridgeDRMPRIME.h"
#include "cores/VideoPlayer/VideoRenderers/RenderCapture.h"
#include "cores/VideoPlayer/VideoRenderers/RenderFactory.h"
#include "cores/VideoPlayer/VideoRenderers/RenderFlags.h"
-#include "settings/lib/Setting.h"
#include "settings/DisplaySettings.h"
#include "settings/Settings.h"
#include "settings/SettingsComponent.h"
+#include "settings/lib/Setting.h"
#include "utils/log.h"
+#include "windowing/GraphicContext.h"
#include "windowing/gbm/DRMAtomic.h"
#include "windowing/gbm/WinSystemGbm.h"
-#include "windowing/GraphicContext.h"
-#include "ServiceBroker.h"
using namespace KODI::WINDOWING::GBM;
@@ -34,7 +35,7 @@ CRendererDRMPRIME::~CRendererDRMPRIME()
CBaseRenderer* CRendererDRMPRIME::Create(CVideoBuffer* buffer)
{
- if (buffer && dynamic_cast<CVideoBufferDRMPRIME*>(buffer) &&
+ if (buffer && dynamic_cast<IVideoBufferDRMPRIME*>(buffer) &&
CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(SETTING_VIDEOPLAYER_USEPRIMERENDERER) == 0)
{
CWinSystemGbm* winSystem = dynamic_cast<CWinSystemGbm*>(CServiceBroker::GetWinSystem());
@@ -132,7 +133,7 @@ bool CRendererDRMPRIME::NeedBuffer(int index)
if (m_iLastRenderBuffer == index)
return true;
- CVideoBufferDRMPRIME* buffer = dynamic_cast<CVideoBufferDRMPRIME*>(m_buffers[index].videoBuffer);
+ IVideoBufferDRMPRIME* buffer = dynamic_cast<IVideoBufferDRMPRIME*>(m_buffers[index].videoBuffer);
if (buffer && buffer->m_fb_id)
return true;
@@ -162,12 +163,8 @@ void CRendererDRMPRIME::RenderUpdate(int index, int index2, bool clear, unsigned
return;
}
- CVideoBufferDRMPRIME* buffer = dynamic_cast<CVideoBufferDRMPRIME*>(m_buffers[index].videoBuffer);
- if (!buffer)
- return;
-
- AVDRMFrameDescriptor* descriptor = buffer->GetDescriptor();
- if (!descriptor || !descriptor->nb_layers)
+ IVideoBufferDRMPRIME* buffer = dynamic_cast<IVideoBufferDRMPRIME*>(m_buffers[index].videoBuffer);
+ if (!buffer || !buffer->IsValid())
return;
if (!m_videoLayerBridge)
diff --git a/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/RendererDRMPRIMEGLES.cpp b/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/RendererDRMPRIMEGLES.cpp
index c812217d35..bbe8409cba 100644
--- a/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/RendererDRMPRIMEGLES.cpp
+++ b/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/RendererDRMPRIMEGLES.cpp
@@ -25,7 +25,7 @@ CRendererDRMPRIMEGLES::~CRendererDRMPRIMEGLES()
CBaseRenderer* CRendererDRMPRIMEGLES::Create(CVideoBuffer* buffer)
{
- if (buffer && dynamic_cast<CVideoBufferDRMPRIME*>(buffer))
+ if (buffer && dynamic_cast<IVideoBufferDRMPRIME*>(buffer))
return new CRendererDRMPRIMEGLES();
return nullptr;
@@ -99,9 +99,9 @@ bool CRendererDRMPRIMEGLES::UploadTexture(int index)
{
CPictureBuffer &buf = m_buffers[index];
- CVideoBufferDRMPRIME *buffer = dynamic_cast<CVideoBufferDRMPRIME*>(buf.videoBuffer);
+ IVideoBufferDRMPRIME* buffer = dynamic_cast<IVideoBufferDRMPRIME*>(buf.videoBuffer);
- if (!buffer)
+ if (!buffer || !buffer->IsValid())
{
CLog::Log(LOGNOTICE, "CRendererDRMPRIMEGLES::%s - no buffer", __FUNCTION__);
return false;
diff --git a/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/VideoLayerBridgeDRMPRIME.cpp b/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/VideoLayerBridgeDRMPRIME.cpp
index 1e7acae2c1..3277d3667c 100644
--- a/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/VideoLayerBridgeDRMPRIME.cpp
+++ b/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/VideoLayerBridgeDRMPRIME.cpp
@@ -8,7 +8,7 @@
#include "VideoLayerBridgeDRMPRIME.h"
-#include "cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.h"
+#include "cores/VideoPlayer/Process/gbm/VideoBufferDRMPRIME.h"
#include "utils/log.h"
#include "windowing/gbm/DRMUtils.h"
@@ -33,7 +33,7 @@ void CVideoLayerBridgeDRMPRIME::Disable()
m_DRM->AddProperty(plane, "CRTC_ID", 0);
}
-void CVideoLayerBridgeDRMPRIME::Acquire(CVideoBufferDRMPRIME* buffer)
+void CVideoLayerBridgeDRMPRIME::Acquire(IVideoBufferDRMPRIME* buffer)
{
// release the buffer that is no longer presented on screen
Release(m_prev_buffer);
@@ -46,7 +46,7 @@ void CVideoLayerBridgeDRMPRIME::Acquire(CVideoBufferDRMPRIME* buffer)
m_buffer->Acquire();
}
-void CVideoLayerBridgeDRMPRIME::Release(CVideoBufferDRMPRIME* buffer)
+void CVideoLayerBridgeDRMPRIME::Release(IVideoBufferDRMPRIME* buffer)
{
if (!buffer)
return;
@@ -55,11 +55,14 @@ void CVideoLayerBridgeDRMPRIME::Release(CVideoBufferDRMPRIME* buffer)
buffer->Release();
}
-bool CVideoLayerBridgeDRMPRIME::Map(CVideoBufferDRMPRIME* buffer)
+bool CVideoLayerBridgeDRMPRIME::Map(IVideoBufferDRMPRIME* buffer)
{
if (buffer->m_fb_id)
return true;
+ if (!buffer->Map())
+ return false;
+
AVDRMFrameDescriptor* descriptor = buffer->GetDescriptor();
uint32_t handles[4] = {0}, pitches[4] = {0}, offsets[4] = {0}, flags = 0;
uint64_t modifier[4] = {0};
@@ -108,7 +111,7 @@ bool CVideoLayerBridgeDRMPRIME::Map(CVideoBufferDRMPRIME* buffer)
return true;
}
-void CVideoLayerBridgeDRMPRIME::Unmap(CVideoBufferDRMPRIME* buffer)
+void CVideoLayerBridgeDRMPRIME::Unmap(IVideoBufferDRMPRIME* buffer)
{
if (buffer->m_fb_id)
{
@@ -125,9 +128,11 @@ void CVideoLayerBridgeDRMPRIME::Unmap(CVideoBufferDRMPRIME* buffer)
buffer->m_handles[i] = 0;
}
}
+
+ buffer->Unmap();
}
-void CVideoLayerBridgeDRMPRIME::Configure(CVideoBufferDRMPRIME* buffer)
+void CVideoLayerBridgeDRMPRIME::Configure(IVideoBufferDRMPRIME* buffer)
{
struct plane* plane = m_DRM->GetVideoPlane();
if (m_DRM->SupportsProperty(plane, "COLOR_ENCODING") &&
@@ -138,7 +143,7 @@ void CVideoLayerBridgeDRMPRIME::Configure(CVideoBufferDRMPRIME* buffer)
}
}
-void CVideoLayerBridgeDRMPRIME::SetVideoPlane(CVideoBufferDRMPRIME* buffer, const CRect& destRect)
+void CVideoLayerBridgeDRMPRIME::SetVideoPlane(IVideoBufferDRMPRIME* buffer, const CRect& destRect)
{
if (!Map(buffer))
{
diff --git a/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/VideoLayerBridgeDRMPRIME.h b/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/VideoLayerBridgeDRMPRIME.h
index b29488b1a3..ade17ac0c3 100644
--- a/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/VideoLayerBridgeDRMPRIME.h
+++ b/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/VideoLayerBridgeDRMPRIME.h
@@ -24,7 +24,7 @@ namespace GBM
}
}
-class CVideoBufferDRMPRIME;
+class IVideoBufferDRMPRIME;
class CVideoLayerBridgeDRMPRIME
: public KODI::WINDOWING::GBM::CVideoLayerBridge
@@ -34,19 +34,19 @@ public:
~CVideoLayerBridgeDRMPRIME();
void Disable() override;
- virtual void Configure(CVideoBufferDRMPRIME* buffer);
- virtual void SetVideoPlane(CVideoBufferDRMPRIME* buffer, const CRect& destRect);
+ virtual void Configure(IVideoBufferDRMPRIME* buffer);
+ virtual void SetVideoPlane(IVideoBufferDRMPRIME* buffer, const CRect& destRect);
virtual void UpdateVideoPlane();
protected:
std::shared_ptr<KODI::WINDOWING::GBM::CDRMUtils> m_DRM;
private:
- void Acquire(CVideoBufferDRMPRIME* buffer);
- void Release(CVideoBufferDRMPRIME* buffer);
- bool Map(CVideoBufferDRMPRIME* buffer);
- void Unmap(CVideoBufferDRMPRIME* buffer);
+ void Acquire(IVideoBufferDRMPRIME* buffer);
+ void Release(IVideoBufferDRMPRIME* buffer);
+ bool Map(IVideoBufferDRMPRIME* buffer);
+ void Unmap(IVideoBufferDRMPRIME* buffer);
- CVideoBufferDRMPRIME* m_buffer = nullptr;
- CVideoBufferDRMPRIME* m_prev_buffer = nullptr;
+ IVideoBufferDRMPRIME* m_buffer = nullptr;
+ IVideoBufferDRMPRIME* m_prev_buffer = nullptr;
};
diff --git a/xbmc/cores/VideoPlayer/VideoRenderers/VideoShaders/VideoFilterShaderGL.cpp b/xbmc/cores/VideoPlayer/VideoRenderers/VideoShaders/VideoFilterShaderGL.cpp
index f800997ffe..70aa734537 100644
--- a/xbmc/cores/VideoPlayer/VideoRenderers/VideoShaders/VideoFilterShaderGL.cpp
+++ b/xbmc/cores/VideoPlayer/VideoRenderers/VideoShaders/VideoFilterShaderGL.cpp
@@ -84,9 +84,7 @@ ConvolutionFilterShader::ConvolutionFilterShader(ESCALINGMETHOD method, bool str
}
if (m_floattex)
- defines = "#define HAS_FLOAT_TEXTURE 1\n";
- else
- defines = "#define HAS_FLOAT_TEXTURE 0\n";
+ defines = "#define HAS_FLOAT_TEXTURE\n";
//don't compile in stretch support when it's not needed
if (stretch)
diff --git a/xbmc/cores/VideoPlayer/VideoRenderers/VideoShaders/VideoFilterShaderGLES.cpp b/xbmc/cores/VideoPlayer/VideoRenderers/VideoShaders/VideoFilterShaderGLES.cpp
index ce1885042f..a9aa0d6f8e 100644
--- a/xbmc/cores/VideoPlayer/VideoRenderers/VideoShaders/VideoFilterShaderGLES.cpp
+++ b/xbmc/cores/VideoPlayer/VideoRenderers/VideoShaders/VideoFilterShaderGLES.cpp
@@ -99,12 +99,11 @@ ConvolutionFilterShader::ConvolutionFilterShader(ESCALINGMETHOD method)
if (m_floattex)
{
m_internalformat = GL_RGBA16F_EXT;
- defines = "#define HAS_FLOAT_TEXTURE 1\n";
+ defines = "#define HAS_FLOAT_TEXTURE\n";
}
else
{
m_internalformat = GL_RGBA;
- defines = "#define HAS_FLOAT_TEXTURE 0\n";
}
CLog::Log(LOGDEBUG, "GL: ConvolutionFilterShader: using %s defines:\n%s", shadername.c_str(), defines.c_str());
diff --git a/xbmc/cores/paplayer/VideoPlayerCodec.cpp b/xbmc/cores/paplayer/VideoPlayerCodec.cpp
index 4edadf0454..ae0fd31558 100644
--- a/xbmc/cores/paplayer/VideoPlayerCodec.cpp
+++ b/xbmc/cores/paplayer/VideoPlayerCodec.cpp
@@ -213,10 +213,10 @@ bool VideoPlayerCodec::Init(const CFileItem &file, unsigned int filecache)
m_bCanSeek = false;
if (m_pInputStream->Seek(0, SEEK_POSSIBLE))
{
- if (Seek(1))
+ if (m_pDemuxer->SeekTime(1, true))
{
// rewind stream to beginning
- Seek(0);
+ m_pDemuxer->SeekTime(0, true);
m_bCanSeek = true;
}
else
@@ -510,7 +510,7 @@ CAEStreamInfo::DataType VideoPlayerCodec::GetPassthroughStreamType(AVCodecID cod
break;
case AV_CODEC_ID_DTS:
- format.m_streamInfo.m_type = CAEStreamInfo::STREAM_TYPE_DTSHD_CORE;
+ format.m_streamInfo.m_type = CAEStreamInfo::STREAM_TYPE_DTSHD;
format.m_streamInfo.m_sampleRate = samplerate;
break;
@@ -520,6 +520,12 @@ CAEStreamInfo::DataType VideoPlayerCodec::GetPassthroughStreamType(AVCodecID cod
bool supports = CServiceBroker::GetActiveAE()->SupportsRaw(format);
+ if (!supports && codecId == AV_CODEC_ID_DTS)
+ {
+ format.m_streamInfo.m_type = CAEStreamInfo::STREAM_TYPE_DTSHD_CORE;
+ supports = CServiceBroker::GetActiveAE()->SupportsRaw(format);
+ }
+
if (supports)
return format.m_streamInfo.m_type;
else
diff --git a/xbmc/dialogs/GUIDialogKeyboardTouch.cpp b/xbmc/dialogs/GUIDialogKeyboardTouch.cpp
index 6451ff8b88..a79caed044 100644
--- a/xbmc/dialogs/GUIDialogKeyboardTouch.cpp
+++ b/xbmc/dialogs/GUIDialogKeyboardTouch.cpp
@@ -8,7 +8,7 @@
#include "GUIDialogKeyboardTouch.h"
#if defined(TARGET_DARWIN_IOS)
-#include "platform/darwin/ios/IOSKeyboard.h"
+#include "platform/darwin/ios-common/IOSKeyboard.h"
#endif
CGUIDialogKeyboardTouch::CGUIDialogKeyboardTouch()
diff --git a/xbmc/guilib/guiinfo/GUIInfoLabels.h b/xbmc/guilib/guiinfo/GUIInfoLabels.h
index b6df15b3cc..d5c906b89c 100644
--- a/xbmc/guilib/guiinfo/GUIInfoLabels.h
+++ b/xbmc/guilib/guiinfo/GUIInfoLabels.h
@@ -870,6 +870,8 @@
#define LISTITEM_PROPERTY (LISTITEM_START + 182)
#define LISTITEM_EPG_EVENT_ICON (LISTITEM_START + 183)
#define LISTITEM_HASREMINDERRULE (LISTITEM_START + 184)
+#define LISTITEM_HASARCHIVE (LISTITEM_START + 185)
+#define LISTITEM_ISPLAYABLE (LISTITEM_START + 186)
#define LISTITEM_END (LISTITEM_START + 2500)
diff --git a/xbmc/interfaces/json-rpc/schema/types.json b/xbmc/interfaces/json-rpc/schema/types.json
index 6bed040301..17282f61c8 100644
--- a/xbmc/interfaces/json-rpc/schema/types.json
+++ b/xbmc/interfaces/json-rpc/schema/types.json
@@ -977,7 +977,7 @@
"firstaired", "hastimer", "isactive", "parentalrating",
"wasactive", "thumbnail", "rating", "originaltitle", "cast",
"director", "writer", "year", "imdbnumber", "hastimerrule",
- "hasrecording", "recording", "isseries" ]
+ "hasrecording", "recording", "isseries", "isplayable" ]
}
},
"PVR.Details.Broadcast": {
@@ -1012,7 +1012,8 @@
"hastimerrule": { "type": "boolean" },
"hasrecording": { "type": "boolean" },
"recording": { "type": "string" },
- "isseries": { "type": "boolean" }
+ "isseries": { "type": "boolean" },
+ "isplayable": { "type": "boolean" }
}
},
"PVR.Fields.Channel": {
@@ -1020,7 +1021,7 @@
"items": { "type": "string",
"enum": [ "thumbnail", "channeltype", "hidden", "locked", "channel", "lastplayed",
"broadcastnow", "broadcastnext", "uniqueid", "icon", "channelnumber",
- "subchannelnumber", "isrecording" ]
+ "subchannelnumber", "isrecording", "hasarchive" ]
}
},
"PVR.Details.Channel": {
@@ -1039,7 +1040,8 @@
"icon": { "type": "string" },
"channelnumber": { "type": "integer" },
"subchannelnumber": { "type": "integer" },
- "isrecording": { "type": "boolean" }
+ "isrecording": { "type": "boolean" },
+ "hasarchive": { "type": "boolean" }
}
},
"PVR.Details.ChannelGroup": {
diff --git a/xbmc/interfaces/json-rpc/schema/version.txt b/xbmc/interfaces/json-rpc/schema/version.txt
index 4f3c1d9eec..a028c7d043 100644
--- a/xbmc/interfaces/json-rpc/schema/version.txt
+++ b/xbmc/interfaces/json-rpc/schema/version.txt
@@ -1 +1 @@
-JSONRPC_VERSION 10.4.0
+JSONRPC_VERSION 10.5.0
diff --git a/xbmc/interfaces/legacy/File.h b/xbmc/interfaces/legacy/File.h
index 9eb18a05c2..cc3efc0fc7 100644
--- a/xbmc/interfaces/legacy/File.h
+++ b/xbmc/interfaces/legacy/File.h
@@ -111,7 +111,7 @@ namespace XBMCAddon
/// ~~~~~~~~~~~~~{.py}
/// ..
/// f = xbmcvfs.File(file)
- /// b = f.read()
+ /// b = f.readBytes()
/// f.close()
/// ..
/// ~~~~~~~~~~~~~
@@ -182,11 +182,12 @@ namespace XBMCAddon
/// Seek to position in file.
///
/// @param seekBytes position in the file
- /// @param iWhence where in a file to seek from[0 beginning,
+ /// @param iWhence [opt] where in a file to seek from[0 beginning,
/// 1 current , 2 end position]
///
///
///-----------------------------------------------------------------------
+ /// @python_v19 Function changed. param **iWhence** is now optional.
///
/// **Example:**
/// ~~~~~~~~~~~~~{.py}
@@ -199,7 +200,34 @@ namespace XBMCAddon
///
seek(...);
#else
- inline long long seek(long long seekBytes, int iWhence) { DelayedCallGuard dg(languageHook); return file->Seek(seekBytes,iWhence); }
+ inline long long seek(long long seekBytes, int iWhence = SEEK_SET) { DelayedCallGuard dg(languageHook); return file->Seek(seekBytes,iWhence); }
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_file
+ /// @brief \python_func{ tell() }
+ ///-----------------------------------------------------------------------
+ /// Get the current position in the file.
+ ///
+ /// @return The file position
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v19 New function added
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// f = xbmcvfs.File(file)
+ /// s = f.tell()
+ /// f.close()
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ tell();
+#else
+ inline long long tell() { DelayedCallGuard dg(languageHook); return file->GetPosition(); }
#endif
#ifdef DOXYGEN_SHOULD_USE_THIS
diff --git a/xbmc/music/dialogs/GUIDialogMusicInfo.cpp b/xbmc/music/dialogs/GUIDialogMusicInfo.cpp
index 72f52fe658..dde8506d0f 100644
--- a/xbmc/music/dialogs/GUIDialogMusicInfo.cpp
+++ b/xbmc/music/dialogs/GUIDialogMusicInfo.cpp
@@ -755,22 +755,6 @@ void CGUIDialogMusicInfo::OnGetArt()
item->SetLabel(g_localizeStrings.Get(13512));
items.Add(item);
}
- else if (m_item->HasArt("thumb"))
- {
- // For missing art of that type add the thumb (when it exists and not a fallback)
- CGUIListItem::ArtMap::const_iterator i = primeArt.find("thumb");
- if (i != primeArt.end())
- {
- CFileItemPtr item(new CFileItem("thumb://Thumb", false));
- item->SetArt("thumb", m_item->GetArt("thumb"));
- if (m_bArtistInfo)
- item->SetIconImage("DefaultArtistCover.png");
- else
- item->SetIconImage("DefaultAlbumCover.png");
- item->SetLabel(g_localizeStrings.Get(21371));
- items.Add(item);
- }
- }
// Grab the thumbnails of this art type scraped from the web
std::vector<std::string> remotethumbs;
diff --git a/xbmc/platform/darwin/ios-common/CMakeLists.txt b/xbmc/platform/darwin/ios-common/CMakeLists.txt
index 8b78aabc9a..f9e35bed32 100644
--- a/xbmc/platform/darwin/ios-common/CMakeLists.txt
+++ b/xbmc/platform/darwin/ios-common/CMakeLists.txt
@@ -1,5 +1,9 @@
-set(SOURCES AnnounceReceiver.mm)
+set(SOURCES AnnounceReceiver.mm
+ IOSKeyboard.mm
+ IOSKeyboardView.mm)
-set(HEADERS AnnounceReceiver.h)
+set(HEADERS AnnounceReceiver.h
+ IOSKeyboard.h
+ IOSKeyboardView.h)
core_add_library(platform_ios-common)
diff --git a/xbmc/platform/darwin/ios/IOSKeyboard.h b/xbmc/platform/darwin/ios-common/IOSKeyboard.h
index 798b39845e..75b17e8e0e 100644
--- a/xbmc/platform/darwin/ios/IOSKeyboard.h
+++ b/xbmc/platform/darwin/ios-common/IOSKeyboard.h
@@ -13,11 +13,11 @@
class CIOSKeyboard : public CGUIKeyboard
{
public:
- CIOSKeyboard():m_pCharCallback(NULL),m_bCanceled(false){}
+ CIOSKeyboard():m_pCharCallback(nullptr),m_bCanceled(false){}
virtual bool ShowAndGetInput(char_callback_t pCallback, const std::string &initialString, std::string &typedString, const std::string &heading, bool bHiddenInput);
virtual void Cancel();
void fireCallback(const std::string &str);
- void invalidateCallback() {m_pCharCallback = NULL;}
+ void invalidateCallback() {m_pCharCallback = nullptr;}
virtual bool SetTextToKeyboard(const std::string &text, bool closeKeyboard = false);
private:
diff --git a/xbmc/platform/darwin/ios/IOSKeyboard.mm b/xbmc/platform/darwin/ios-common/IOSKeyboard.mm
index daf5c97318..692ab74b9e 100644
--- a/xbmc/platform/darwin/ios/IOSKeyboard.mm
+++ b/xbmc/platform/darwin/ios-common/IOSKeyboard.mm
@@ -6,11 +6,11 @@
* See LICENSES/README.md for more information.
*/
-#include "XBMCController.h"
-#include "IOSKeyboard.h"
-#include "IOSKeyboardView.h"
-#include "XBMCDebugHelpers.h"
#include "platform/darwin/DarwinUtils.h"
+#include "platform/darwin/NSLogDebugHelpers.h"
+#include "platform/darwin/ios/XBMCController.h"
+#include "platform/darwin/ios-common/IOSKeyboard.h"
+#include "platform/darwin/ios-common/IOSKeyboardView.h"
#import "platform/darwin/AutoPool.h"
diff --git a/xbmc/platform/darwin/ios/IOSKeyboardView.h b/xbmc/platform/darwin/ios-common/IOSKeyboardView.h
index 8c2dd2eec5..5ec2971f5f 100644
--- a/xbmc/platform/darwin/ios/IOSKeyboardView.h
+++ b/xbmc/platform/darwin/ios-common/IOSKeyboardView.h
@@ -7,7 +7,7 @@
*/
#import <UIKit/UIKit.h>
-#include "IOSKeyboard.h"
+#include "platform/darwin/ios-common/IOSKeyboard.h"
@interface KeyboardView : UIView <UITextFieldDelegate>
{
diff --git a/xbmc/platform/darwin/ios/IOSKeyboardView.mm b/xbmc/platform/darwin/ios-common/IOSKeyboardView.mm
index 40adc404b9..86f18ecfc2 100644
--- a/xbmc/platform/darwin/ios/IOSKeyboardView.mm
+++ b/xbmc/platform/darwin/ios-common/IOSKeyboardView.mm
@@ -10,11 +10,11 @@
#include "threads/Event.h"
#include "Application.h"
-#import "IOSKeyboardView.h"
-#import "IOSScreenManager.h"
-#import "XBMCController.h"
-#import "XBMCDebugHelpers.h"
-#include "IOSKeyboard.h"
+#import "platform/darwin/NSLogDebugHelpers.h"
+#import "platform/darwin/ios/IOSScreenManager.h"
+#import "platform/darwin/ios/XBMCController.h"
+#import "platform/darwin/ios-common/IOSKeyboard.h"
+#import "platform/darwin/ios-common/IOSKeyboardView.h"
static CEvent keyboardFinishedEvent;
diff --git a/xbmc/platform/darwin/ios/CMakeLists.txt b/xbmc/platform/darwin/ios/CMakeLists.txt
index 368345d23f..188c3e7ca6 100644
--- a/xbmc/platform/darwin/ios/CMakeLists.txt
+++ b/xbmc/platform/darwin/ios/CMakeLists.txt
@@ -1,17 +1,12 @@
set(SOURCES IOSEAGLView.mm
IOSExternalTouchController.mm
- IOSKeyboard.mm
- IOSKeyboardView.mm
IOSScreenManager.mm
XBMCController.mm)
set(HEADERS IOSEAGLView.h
IOSExternalTouchController.h
- IOSKeyboard.h
- IOSKeyboardView.h
IOSScreenManager.h
XBMCApplication.h
- XBMCController.h
- XBMCDebugHelpers.h)
+ XBMCController.h)
core_add_library(platform_ios)
diff --git a/xbmc/platform/darwin/ios/IOSEAGLView.mm b/xbmc/platform/darwin/ios/IOSEAGLView.mm
index c764524ba2..df9b63c3c2 100644
--- a/xbmc/platform/darwin/ios/IOSEAGLView.mm
+++ b/xbmc/platform/darwin/ios/IOSEAGLView.mm
@@ -31,7 +31,7 @@
#import "platform/darwin/AutoPool.h"
#import "platform/darwin/DarwinUtils.h"
#import "platform/darwin/ios-common/AnnounceReceiver.h"
-#import "XBMCDebugHelpers.h"
+#import "platform/darwin/NSLogDebugHelpers.h"
using namespace KODI::MESSAGING;
diff --git a/xbmc/platform/darwin/ios/XBMCApplication.mm b/xbmc/platform/darwin/ios/XBMCApplication.mm
index a44831d1ce..8b44e2a4a1 100644
--- a/xbmc/platform/darwin/ios/XBMCApplication.mm
+++ b/xbmc/platform/darwin/ios/XBMCApplication.mm
@@ -12,7 +12,7 @@
#import "XBMCApplication.h"
#import "XBMCController.h"
#import "IOSScreenManager.h"
-#import "XBMCDebugHelpers.h"
+#import "platform/darwin/NSLogDebugHelpers.h"
#import <objc/runtime.h>
@implementation XBMCApplicationDelegate
diff --git a/xbmc/platform/darwin/ios/XBMCController.mm b/xbmc/platform/darwin/ios/XBMCController.mm
index b84b18fd25..5c14627b7f 100644
--- a/xbmc/platform/darwin/ios/XBMCController.mm
+++ b/xbmc/platform/darwin/ios/XBMCController.mm
@@ -48,7 +48,7 @@ using namespace KODI::MESSAGING;
#import "XBMCController.h"
#import "IOSScreenManager.h"
#import "XBMCApplication.h"
-#import "XBMCDebugHelpers.h"
+#import "platform/darwin/NSLogDebugHelpers.h"
#import "platform/darwin/AutoPool.h"
XBMCController *g_xbmcController;
diff --git a/xbmc/platform/darwin/ios/XBMCDebugHelpers.h b/xbmc/platform/darwin/ios/XBMCDebugHelpers.h
deleted file mode 100644
index 3997701c34..0000000000
--- a/xbmc/platform/darwin/ios/XBMCDebugHelpers.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * XBMCDebugHelpers.h
- * xbmclauncher
- *
- * Created by Stephan Diederich on 21.09.08.
- * Copyright 2008 University Heidelberg. All rights reserved.
- *
- * Copyright (C) 2008-2018 Team Kodi
- * This file is part of Kodi - https://kodi.tv
- *
- * SPDX-License-Identifier: GPL-2.0-or-later
- * See LICENSES/README.md for more information.
- */
-
-#define DEBUG
-#ifdef DEBUG
-#define LOG(s, ...) NSLog(@"[DEBUG] " s, ##__VA_ARGS__)
-#define ILOG(s, ...) NSLog(@"[INFO] " s, ##__VA_ARGS__)
-#define ELOG(s, ...) NSLog(@"[ERROR] " s, ##__VA_ARGS__)
-#define DLOG(s, ...) LOG(s, ##__VA_ARGS__)
-#else
-#define LOG(s, ...)
-#define ILOG(s, ...) NSLog(@"[INFO] " s, ##__VA_ARGS__)
-#define ELOG(s, ...) NSLog(@"[ERROR] " s, ##__VA_ARGS__)
-#define DLOG(s, ...) LOG(s, ##__VA_ARGS__)
-#endif
-
-#define PRINT_SIGNATURE() LOG(@"%s", __PRETTY_FUNCTION__)
diff --git a/xbmc/platform/linux/input/LibInputKeyboard.cpp b/xbmc/platform/linux/input/LibInputKeyboard.cpp
index 270f574675..9bbc9de434 100644
--- a/xbmc/platform/linux/input/LibInputKeyboard.cpp
+++ b/xbmc/platform/linux/input/LibInputKeyboard.cpp
@@ -137,7 +137,7 @@ static const std::map<xkb_keysym_t, XBMCKey> xkbMap =
// Media keys
{ XKB_KEY_XF86Eject, XBMCK_EJECT },
- // XBMCK_STOP clashes with XBMCK_MEDIA_STOP
+ { XKB_KEY_Cancel, XBMCK_STOP },
{ XKB_KEY_XF86AudioRecord, XBMCK_RECORD },
// XBMCK_REWIND clashes with XBMCK_MEDIA_REWIND
{ XKB_KEY_XF86Phone, XBMCK_PHONE },
diff --git a/xbmc/pvr/PVRDatabase.cpp b/xbmc/pvr/PVRDatabase.cpp
index ee11feda1b..8e85d5cd8c 100644
--- a/xbmc/pvr/PVRDatabase.cpp
+++ b/xbmc/pvr/PVRDatabase.cpp
@@ -93,7 +93,8 @@ void CPVRDatabase::CreateTables()
"sEPGScraper varchar(32), "
"iLastWatched integer, "
"iClientId integer, " //! @todo use mapping table
- "idEpg integer"
+ "idEpg integer, "
+ "bHasArchive bool"
")"
);
@@ -191,6 +192,9 @@ void CPVRDatabase::UpdateTables(int iVersion)
if (iVersion < 33)
m_pDS->exec(sqlCreateTimersTable);
+
+ if (iVersion < 34)
+ m_pDS->exec("ALTER TABLE channels ADD bHasArchive bool");
}
/********** Client methods **********/
@@ -279,11 +283,11 @@ bool CPVRDatabase::Delete(const CPVRChannel &channel)
int CPVRDatabase::Get(CPVRChannelGroup &results, bool bCompressDB)
{
int iReturn(0);
- bool bIgnoreEpgDB = CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(CSettings::SETTING_EPG_IGNOREDBFORCLIENT);
+ bool bUseEpgDB = CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(CSettings::SETTING_EPG_STOREEPGINDATABASE);
std::string strQuery = PrepareSQL("SELECT channels.idChannel, channels.iUniqueId, channels.bIsRadio, channels.bIsHidden, channels.bIsUserSetIcon, channels.bIsUserSetName, "
"channels.sIconPath, channels.sChannelName, channels.bIsVirtual, channels.bEPGEnabled, channels.sEPGScraper, channels.iLastWatched, channels.iClientId, channels.bIsLocked, "
- "map_channelgroups_channels.iChannelNumber, map_channelgroups_channels.iSubChannelNumber, channels.idEpg "
+ "map_channelgroups_channels.iChannelNumber, map_channelgroups_channels.iSubChannelNumber, channels.idEpg, channels.bHasArchive "
"FROM map_channelgroups_channels "
"LEFT JOIN channels ON channels.idChannel = map_channelgroups_channels.idChannel "
"WHERE map_channelgroups_channels.idGroup = %u", results.GroupID());
@@ -310,7 +314,8 @@ int CPVRDatabase::Get(CPVRChannelGroup &results, bool bCompressDB)
channel->m_strEPGScraper = m_pDS->fv("sEPGScraper").get_asString();
channel->m_iLastWatched = static_cast<time_t>(m_pDS->fv("iLastWatched").get_asInt());
channel->m_iClientId = m_pDS->fv("iClientId").get_asInt();
- channel->m_iEpgId = bIgnoreEpgDB ? -1 : m_pDS->fv("idEpg").get_asInt();
+ channel->m_iEpgId = bUseEpgDB ? m_pDS->fv("idEpg").get_asInt() : -1;
+ channel->m_bHasArchive = m_pDS->fv("bHasArchive").get_asBool();
channel->UpdateEncryptionName();
PVRChannelGroupMember newMember(channel,
@@ -798,11 +803,11 @@ bool CPVRDatabase::Persist(CPVRChannel &channel, bool bCommit)
strQuery = PrepareSQL("INSERT INTO channels ("
"iUniqueId, bIsRadio, bIsHidden, bIsUserSetIcon, bIsUserSetName, bIsLocked, "
"sIconPath, sChannelName, bIsVirtual, bEPGEnabled, sEPGScraper, iLastWatched, iClientId, "
- "idEpg) "
- "VALUES (%i, %i, %i, %i, %i, %i, '%s', '%s', %i, %i, '%s', %u, %i, %i)",
+ "idEpg, bHasArchive) "
+ "VALUES (%i, %i, %i, %i, %i, %i, '%s', '%s', %i, %i, '%s', %u, %i, %i, %i)",
channel.UniqueID(), (channel.IsRadio() ? 1 :0), (channel.IsHidden() ? 1 : 0), (channel.IsUserSetIcon() ? 1 : 0), (channel.IsUserSetName() ? 1 : 0), (channel.IsLocked() ? 1 : 0),
channel.IconPath().c_str(), channel.ChannelName().c_str(), 0, (channel.EPGEnabled() ? 1 : 0), channel.EPGScraper().c_str(), static_cast<unsigned int>(channel.LastWatched()), channel.ClientID(),
- channel.EpgID());
+ channel.EpgID(), channel.HasArchive());
}
else
{
@@ -810,12 +815,12 @@ bool CPVRDatabase::Persist(CPVRChannel &channel, bool bCommit)
strQuery = PrepareSQL("REPLACE INTO channels ("
"iUniqueId, bIsRadio, bIsHidden, bIsUserSetIcon, bIsUserSetName, bIsLocked, "
"sIconPath, sChannelName, bIsVirtual, bEPGEnabled, sEPGScraper, iLastWatched, iClientId, "
- "idChannel, idEpg) "
- "VALUES (%i, %i, %i, %i, %i, %i, '%s', '%s', %i, %i, '%s', %u, %i, %s, %i)",
+ "idChannel, idEpg, bHasArchive) "
+ "VALUES (%i, %i, %i, %i, %i, %i, '%s', '%s', %i, %i, '%s', %u, %i, %s, %i, %i)",
channel.UniqueID(), (channel.IsRadio() ? 1 :0), (channel.IsHidden() ? 1 : 0), (channel.IsUserSetIcon() ? 1 : 0), (channel.IsUserSetName() ? 1 : 0), (channel.IsLocked() ? 1 : 0),
channel.IconPath().c_str(), channel.ChannelName().c_str(), 0, (channel.EPGEnabled() ? 1 : 0), channel.EPGScraper().c_str(), static_cast<unsigned int>(channel.LastWatched()), channel.ClientID(),
strValue.c_str(),
- channel.EpgID());
+ channel.EpgID(), channel.HasArchive());
}
if (QueueInsertQuery(strQuery))
diff --git a/xbmc/pvr/PVRDatabase.h b/xbmc/pvr/PVRDatabase.h
index efae17af19..a801ea6d2c 100644
--- a/xbmc/pvr/PVRDatabase.h
+++ b/xbmc/pvr/PVRDatabase.h
@@ -51,7 +51,7 @@ namespace PVR
* @brief Get the minimal database version that is required to operate correctly.
* @return The minimal database version.
*/
- int GetSchemaVersion() const override { return 33; }
+ int GetSchemaVersion() const override { return 34; }
/*!
* @brief Get the default sqlite database filename.
diff --git a/xbmc/pvr/PVRGUIInfo.cpp b/xbmc/pvr/PVRGUIInfo.cpp
index b6ae88c218..9be9d36067 100644
--- a/xbmc/pvr/PVRGUIInfo.cpp
+++ b/xbmc/pvr/PVRGUIInfo.cpp
@@ -1107,6 +1107,20 @@ bool CPVRGUIInfo::GetListItemAndPlayerBool(const CFileItem *item, const CGUIInfo
{
switch (info.m_info)
{
+ case LISTITEM_HASARCHIVE:
+ if (item->IsPVRChannel())
+ {
+ bValue = item->GetPVRChannelInfoTag()->HasArchive();
+ return true;
+ }
+ break;
+ case LISTITEM_ISPLAYABLE:
+ if (item->IsEPG())
+ {
+ bValue = item->GetEPGInfoTag()->IsPlayable();
+ return true;
+ }
+ break;
case LISTITEM_ISRECORDING:
if (item->IsPVRChannel())
{
diff --git a/xbmc/pvr/channels/PVRChannel.cpp b/xbmc/pvr/channels/PVRChannel.cpp
index b33ac83e63..385a0a0cf1 100644
--- a/xbmc/pvr/channels/PVRChannel.cpp
+++ b/xbmc/pvr/channels/PVRChannel.cpp
@@ -46,6 +46,7 @@ CPVRChannel::CPVRChannel(bool bRadio /* = false */)
m_bIsLocked = false;
m_iLastWatched = 0;
m_bChanged = false;
+ m_bHasArchive = false;
m_iEpgId = -1;
m_bEPGEnabled = true;
@@ -78,6 +79,7 @@ CPVRChannel::CPVRChannel(const PVR_CHANNEL &channel, unsigned int iClientId)
m_strEPGScraper = "client";
m_iEpgId = -1;
m_bChanged = false;
+ m_bHasArchive = channel.bHasArchive;
if (m_strChannelName.empty())
m_strChannelName = StringUtils::Format("%s %d", g_localizeStrings.Get(19029).c_str(), m_iUniqueId);
@@ -113,6 +115,7 @@ void CPVRChannel::Serialize(CVariant& value) const
epg->Serialize(value["broadcastnext"]);
value["isrecording"] = false; // compat
+ value["hasarchive"] = m_bHasArchive;
}
/********** XBMC related channel methods **********/
@@ -178,12 +181,14 @@ bool CPVRChannel::UpdateFromClient(const CPVRChannelPtr &channel)
if (m_clientChannelNumber != channel->m_clientChannelNumber ||
m_strInputFormat != channel->InputFormat() ||
m_iClientEncryptionSystem != channel->EncryptionSystem() ||
- m_strClientChannelName != channel->ClientChannelName())
+ m_strClientChannelName != channel->ClientChannelName() ||
+ m_bHasArchive != channel->HasArchive())
{
m_clientChannelNumber = channel->m_clientChannelNumber;
m_strInputFormat = channel->InputFormat();
m_iClientEncryptionSystem = channel->EncryptionSystem();
m_strClientChannelName = channel->ClientChannelName();
+ m_bHasArchive = channel->HasArchive();
UpdateEncryptionName();
SetChanged();
@@ -301,6 +306,12 @@ void CPVRChannel::SetRadioRDSInfoTag(const std::shared_ptr<CPVRRadioRDSInfoTag>&
m_rdsTag = tag;
}
+bool CPVRChannel::HasArchive(void) const
+{
+ CSingleLock lock(m_critSection);
+ return m_bHasArchive;
+}
+
bool CPVRChannel::SetIconPath(const std::string &strIconPath, bool bIsUserSetIcon /* = false */)
{
CSingleLock lock(m_critSection);
diff --git a/xbmc/pvr/channels/PVRChannel.h b/xbmc/pvr/channels/PVRChannel.h
index cf040c3e58..bd74a4e5ba 100644
--- a/xbmc/pvr/channels/PVRChannel.h
+++ b/xbmc/pvr/channels/PVRChannel.h
@@ -151,6 +151,11 @@ namespace PVR
void SetRadioRDSInfoTag(const std::shared_ptr<CPVRRadioRDSInfoTag>& tag);
/*!
+ * @return True if this channel has archive support, false otherwise
+ */
+ bool HasArchive(void) const;
+
+ /*!
* @return The path to the icon for this channel.
*/
std::string IconPath(void) const;
@@ -440,6 +445,7 @@ namespace PVR
bool m_bChanged; /*!< true if anything in this entry was changed that needs to be persisted */
CPVRChannelNumber m_channelNumber; /*!< the number this channel has in the currently selected channel group */
std::shared_ptr<CPVRRadioRDSInfoTag> m_rdsTag; /*! < the radio rds data, if available for the channel. */
+ bool m_bHasArchive; /*!< true if this channel supports archive */
//@}
/*! @name EPG related channel data
diff --git a/xbmc/pvr/channels/PVRChannelGroup.cpp b/xbmc/pvr/channels/PVRChannelGroup.cpp
index ac140fcae2..a3ebd15eb9 100644
--- a/xbmc/pvr/channels/PVRChannelGroup.cpp
+++ b/xbmc/pvr/channels/PVRChannelGroup.cpp
@@ -926,7 +926,7 @@ std::vector<std::shared_ptr<CPVREpgInfoTag>> CPVRChannelGroup::GetEPGAll(bool bI
channel = (*it).channel;
if (!channel->IsHidden())
{
- bool bEmpty = false;
+ bool bEmpty = true;
CPVREpgPtr epg = channel->GetEPG();
if (epg)
diff --git a/xbmc/pvr/channels/PVRChannelGroupInternal.cpp b/xbmc/pvr/channels/PVRChannelGroupInternal.cpp
index 015fa291ba..4941292f67 100644
--- a/xbmc/pvr/channels/PVRChannelGroupInternal.cpp
+++ b/xbmc/pvr/channels/PVRChannelGroupInternal.cpp
@@ -244,15 +244,19 @@ bool CPVRChannelGroupInternal::AddAndUpdateChannels(const CPVRChannelGroup &chan
if (existingChannel.channel->UpdateFromClient(it->second.channel))
{
bReturn = true;
- CLog::LogFC(LOGDEBUG, LOGPVR, "Updated %s channel '%s' from PVR client", m_bRadio ? "radio" : "TV", it->second.channel->ChannelName().c_str());
+ CLog::LogFC(LOGDEBUG, LOGPVR, "Updated {} channel '{}' from PVR client", m_bRadio ? "radio" : "TV", it->second.channel->ChannelName());
}
}
else
{
/* new channel */
UpdateFromClient(it->second.channel, bUseBackendChannelNumbers ? it->second.channel->ClientChannelNumber() : CPVRChannelNumber());
+ if (it->second.channel->CreateEPG())
+ {
+ CLog::LogFC(LOGDEBUG, LOGPVR, "Created EPG for {} channel '{}' from PVR client", m_bRadio ? "radio" : "TV", it->second.channel->ChannelName());
+ }
bReturn = true;
- CLog::LogFC(LOGDEBUG, LOGPVR,"Added %s channel '%s' from PVR client", m_bRadio ? "radio" : "TV", it->second.channel->ChannelName().c_str());
+ CLog::LogFC(LOGDEBUG, LOGPVR, "Added {} channel '{}' from PVR client", m_bRadio ? "radio" : "TV", it->second.channel->ChannelName());
}
}
diff --git a/xbmc/pvr/epg/Epg.cpp b/xbmc/pvr/epg/Epg.cpp
index 42ec788c20..a72065be89 100644
--- a/xbmc/pvr/epg/Epg.cpp
+++ b/xbmc/pvr/epg/Epg.cpp
@@ -241,7 +241,7 @@ CPVREpgInfoTagPtr CPVREpg::GetTagBetween(const CDateTime &beginTime, const CDate
if (tag)
{
m_tags.insert(std::make_pair(tag->StartAsUTC(), tag));
- UpdateEntry(tag, !CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(CSettings::SETTING_EPG_IGNOREDBFORCLIENT));
+ UpdateEntry(tag, CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(CSettings::SETTING_EPG_STOREEPGINDATABASE));
}
}
@@ -258,11 +258,12 @@ void CPVREpg::AddEntry(const CPVREpgInfoTag &tag)
newTag = it->second;
else
{
- newTag = std::make_shared<CPVREpgInfoTag>(m_channelData, m_iEpgID);
+ newTag.reset(new CPVREpgInfoTag());
m_tags.insert(std::make_pair(tag.StartAsUTC(), newTag));
}
newTag->Update(tag);
+ newTag->SetChannelData(m_channelData);
newTag->SetEpgID(m_iEpgID);
}
@@ -348,13 +349,14 @@ bool CPVREpg::UpdateEntry(const CPVREpgInfoTagPtr &tag, bool bUpdateDatabase)
}
else
{
- infoTag = std::make_shared<CPVREpgInfoTag>(m_channelData, m_iEpgID);
+ infoTag.reset(new CPVREpgInfoTag());
infoTag->SetUniqueBroadcastID(tag->UniqueBroadcastID());
m_tags.insert(std::make_pair(tag->StartAsUTC(), infoTag));
bNewTag = true;
}
infoTag->Update(*tag, bNewTag);
+ infoTag->SetChannelData(m_channelData);
infoTag->SetEpgID(m_iEpgID);
if (bUpdateDatabase)
@@ -627,7 +629,7 @@ bool CPVREpg::UpdateFromScraper(time_t start, time_t end, bool bForceUpdate)
{
CLog::LogFC(LOGDEBUG, LOGEPG, "Updating EPG for channel '%s' from client '%i'",
m_channelData->ChannelName().c_str(), m_channelData->ClientId());
- return (client->GetEPGForChannel(m_channelData, this, start, end) == PVR_ERROR_NO_ERROR);
+ return (client->GetEPGForChannel(m_channelData->UniqueClientChannelId(), this, start, end) == PVR_ERROR_NO_ERROR);
}
}
else
@@ -698,7 +700,7 @@ bool CPVREpg::LoadFromClients(time_t start, time_t end, bool bForceUpdate)
const std::shared_ptr<CPVREpg> tmpEpg = std::make_shared<CPVREpg>(m_iEpgID, m_strName, m_strScraperName, m_channelData);
if (tmpEpg->UpdateFromScraper(start, end, bForceUpdate))
- bReturn = UpdateEntries(*tmpEpg, !CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(CSettings::SETTING_EPG_IGNOREDBFORCLIENT));
+ bReturn = UpdateEntries(*tmpEpg, CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(CSettings::SETTING_EPG_STOREEPGINDATABASE));
return bReturn;
}
diff --git a/xbmc/pvr/epg/EpgContainer.cpp b/xbmc/pvr/epg/EpgContainer.cpp
index 7abc52a013..b6cc66700b 100644
--- a/xbmc/pvr/epg/EpgContainer.cpp
+++ b/xbmc/pvr/epg/EpgContainer.cpp
@@ -95,7 +95,7 @@ CPVREpgContainer::CPVREpgContainer(void) :
CThread("EPGUpdater"),
m_database(new CPVREpgDatabase),
m_settings({
- CSettings::SETTING_EPG_IGNOREDBFORCLIENT,
+ CSettings::SETTING_EPG_STOREEPGINDATABASE,
CSettings::SETTING_EPG_EPGUPDATE,
CSettings::SETTING_EPG_FUTURE_DAYSTODISPLAY,
CSettings::SETTING_EPG_PAST_DAYSTODISPLAY,
@@ -261,7 +261,7 @@ void CPVREpgContainer::LoadFromDB(void)
{
CSingleLock lock(m_critSection);
- if (m_bLoaded || IgnoreDB())
+ if (m_bLoaded || !UseDatabase())
return;
bool bLoaded = true;
@@ -298,7 +298,7 @@ void CPVREpgContainer::LoadFromDB(void)
bool CPVREpgContainer::PersistAll(void)
{
- bool bReturn = IgnoreDB();
+ bool bReturn = !UseDatabase();
if (!bReturn)
{
@@ -589,7 +589,7 @@ bool CPVREpgContainer::RemoveOldEntries(void)
epgEntry.second->Cleanup(cleanupTime);
/* remove the old entries from the database */
- if (!IgnoreDB())
+ if (UseDatabase())
m_database->DeleteEpgEntries(cleanupTime);
CSingleLock lock(m_critSection);
@@ -615,7 +615,7 @@ bool CPVREpgContainer::DeleteEpg(const CPVREpgPtr &epg, bool bDeleteFromDatabase
m_channelUidToEpgMap.erase(epgEntry1);
CLog::LogFC(LOGDEBUG, LOGEPG, "Deleting EPG table %s (%d)", epg->Name().c_str(), epg->EpgID());
- if (bDeleteFromDatabase && !IgnoreDB())
+ if (bDeleteFromDatabase && UseDatabase())
m_database->Delete(*epgEntry->second);
epgEntry->second->UnregisterObserver(this);
@@ -624,9 +624,9 @@ bool CPVREpgContainer::DeleteEpg(const CPVREpgPtr &epg, bool bDeleteFromDatabase
return true;
}
-bool CPVREpgContainer::IgnoreDB() const
+bool CPVREpgContainer::UseDatabase() const
{
- return m_settings.GetBoolValue(CSettings::SETTING_EPG_IGNOREDBFORCLIENT);
+ return m_settings.GetBoolValue(CSettings::SETTING_EPG_STOREEPGINDATABASE);
}
bool CPVREpgContainer::InterruptUpdate(void) const
@@ -686,7 +686,7 @@ bool CPVREpgContainer::UpdateEPG(bool bOnlyPending /* = false */)
/* load or update all EPG tables */
unsigned int iCounter = 0;
- const std::shared_ptr<CPVREpgDatabase> database = IgnoreDB() ? nullptr : GetEpgDatabase();
+ const std::shared_ptr<CPVREpgDatabase> database = UseDatabase() ? GetEpgDatabase() : nullptr;
for (const auto& epgEntry : m_epgIdToEpgMap)
{
if (InterruptUpdate())
diff --git a/xbmc/pvr/epg/EpgContainer.h b/xbmc/pvr/epg/EpgContainer.h
index 47fce4baa2..2d09c49e6c 100644
--- a/xbmc/pvr/epg/EpgContainer.h
+++ b/xbmc/pvr/epg/EpgContainer.h
@@ -147,9 +147,9 @@ namespace PVR
/*!
* @brief Check whether data should be persisted to the EPG database.
- * @return True if data should not be persisted to the EPG database, false otherwise.
+ * @return True if data should be persisted to the EPG database, false otherwise.
*/
- bool IgnoreDB() const;
+ bool UseDatabase() const;
/*!
* @brief Notify EPG container that there are pending manual EPG updates
diff --git a/xbmc/pvr/epg/EpgDatabase.cpp b/xbmc/pvr/epg/EpgDatabase.cpp
index 8d08d45ee4..83e8fcf482 100644
--- a/xbmc/pvr/epg/EpgDatabase.cpp
+++ b/xbmc/pvr/epg/EpgDatabase.cpp
@@ -87,7 +87,7 @@ void CPVREpgDatabase::CreateTables(void)
"iFirstAired integer, "
"iParentalRating integer, "
"iStarRating integer, "
- "bNotify bool, "
+ "bNotify bool, " // Unused. Could be removed, but beware: sqlite does not support 'ALTER TABLE x DROP COLUMN y'.
"iSeriesId integer, "
"iEpisodeId integer, "
"iEpisodePart integer, "
@@ -275,7 +275,6 @@ std::vector<std::shared_ptr<CPVREpgInfoTag>> CPVREpgDatabase::Get(const CPVREpg
newTag->m_genre = newTag->Tokenize(m_pDS->fv("sGenre").get_asString());
newTag->m_iParentalRating = m_pDS->fv("iParentalRating").get_asInt();
newTag->m_iStarRating = m_pDS->fv("iStarRating").get_asInt();
- newTag->m_bNotify = m_pDS->fv("bNotify").get_asBool();
newTag->m_iEpisodeNumber = m_pDS->fv("iEpisodeId").get_asInt();
newTag->m_iEpisodePart = m_pDS->fv("iEpisodePart").get_asInt();
newTag->m_strEpisodeName = m_pDS->fv("sEpisodeName").get_asString().c_str();
@@ -390,7 +389,7 @@ int CPVREpgDatabase::Persist(const CPVREpgInfoTag &tag, bool bSingleUpdate /* =
tag.OriginalTitle().c_str(), tag.DeTokenize(tag.Cast()).c_str(), tag.DeTokenize(tag.Directors()).c_str(),
tag.DeTokenize(tag.Writers()).c_str(), tag.Year(), tag.IMDBNumber().c_str(),
tag.Icon().c_str(), tag.GenreType(), tag.GenreSubType(), strGenre.c_str(),
- static_cast<unsigned int>(iFirstAired), tag.ParentalRating(), tag.StarRating(), tag.Notify(),
+ static_cast<unsigned int>(iFirstAired), tag.ParentalRating(), tag.StarRating(), false /* unused */,
tag.SeriesNumber(), tag.EpisodeNumber(), tag.EpisodePart(), tag.EpisodeName().c_str(), tag.Flags(), tag.SeriesLink().c_str(),
tag.UniqueBroadcastID());
}
@@ -406,7 +405,7 @@ int CPVREpgDatabase::Persist(const CPVREpgInfoTag &tag, bool bSingleUpdate /* =
tag.OriginalTitle().c_str(), tag.DeTokenize(tag.Cast()).c_str(), tag.DeTokenize(tag.Directors()).c_str(),
tag.DeTokenize(tag.Writers()).c_str(), tag.Year(), tag.IMDBNumber().c_str(),
tag.Icon().c_str(), tag.GenreType(), tag.GenreSubType(), strGenre.c_str(),
- static_cast<unsigned int>(iFirstAired), tag.ParentalRating(), tag.StarRating(), tag.Notify(),
+ static_cast<unsigned int>(iFirstAired), tag.ParentalRating(), tag.StarRating(), false /* unused */,
tag.SeriesNumber(), tag.EpisodeNumber(), tag.EpisodePart(), tag.EpisodeName().c_str(), tag.Flags(), tag.SeriesLink().c_str(),
tag.UniqueBroadcastID(), iBroadcastId);
}
diff --git a/xbmc/pvr/epg/EpgInfoTag.cpp b/xbmc/pvr/epg/EpgInfoTag.cpp
index 8c37ffe3b7..fee757055e 100644
--- a/xbmc/pvr/epg/EpgInfoTag.cpp
+++ b/xbmc/pvr/epg/EpgInfoTag.cpp
@@ -41,8 +41,7 @@ CPVREpgInfoTag::CPVREpgInfoTag(const std::shared_ptr<CPVREpgChannelData>& channe
}
CPVREpgInfoTag::CPVREpgInfoTag(const EPG_TAG& data, int iClientId, const std::shared_ptr<CPVREpgChannelData>& channelData, int iEpgID)
-: m_bNotify(data.bNotify),
- m_iParentalRating(data.iParentalRating),
+: m_iParentalRating(data.iParentalRating),
m_iStarRating(data.iStarRating),
m_iSeriesNumber(data.iSeriesNumber),
m_iEpisodeNumber(data.iEpisodeNumber),
@@ -116,8 +115,7 @@ bool CPVREpgInfoTag::operator ==(const CPVREpgInfoTag& right) const
return true;
CSingleLock lock(m_critSection);
- return (m_bNotify == right.m_bNotify &&
- m_iDatabaseID == right.m_iDatabaseID &&
+ return (m_iDatabaseID == right.m_iDatabaseID &&
m_iGenreType == right.m_iGenreType &&
m_iGenreSubType == right.m_iGenreSubType &&
m_iParentalRating == right.m_iParentalRating &&
@@ -468,11 +466,6 @@ int CPVREpgInfoTag::StarRating(void) const
return m_iStarRating;
}
-bool CPVREpgInfoTag::Notify(void) const
-{
- return m_bNotify;
-}
-
int CPVREpgInfoTag::SeriesNumber(void) const
{
return m_iSeriesNumber;
@@ -528,7 +521,6 @@ bool CPVREpgInfoTag::Update(const CPVREpgInfoTag &tag, bool bUpdateBroadcastId /
m_firstAired != tag.m_firstAired ||
m_iParentalRating != tag.m_iParentalRating ||
m_iStarRating != tag.m_iStarRating ||
- m_bNotify != tag.m_bNotify ||
m_iEpisodeNumber != tag.m_iEpisodeNumber ||
m_iEpisodePart != tag.m_iEpisodePart ||
m_iSeriesNumber != tag.m_iSeriesNumber ||
@@ -580,7 +572,6 @@ bool CPVREpgInfoTag::Update(const CPVREpgInfoTag &tag, bool bUpdateBroadcastId /
m_firstAired = tag.m_firstAired;
m_iParentalRating = tag.m_iParentalRating;
m_iStarRating = tag.m_iStarRating;
- m_bNotify = tag.m_bNotify;
m_iEpisodeNumber = tag.m_iEpisodeNumber;
m_iEpisodePart = tag.m_iEpisodePart;
m_iSeriesNumber = tag.m_iSeriesNumber;
diff --git a/xbmc/pvr/epg/EpgInfoTag.h b/xbmc/pvr/epg/EpgInfoTag.h
index a61c45930b..1486c2e5f3 100644
--- a/xbmc/pvr/epg/EpgInfoTag.h
+++ b/xbmc/pvr/epg/EpgInfoTag.h
@@ -292,12 +292,6 @@ namespace PVR
int StarRating(void) const;
/*!
- * @brief Notify on start if true.
- * @return Notify on start.
- */
- bool Notify(void) const;
-
- /*!
* @brief The series number of this event.
* @return The series number.
*/
@@ -435,7 +429,6 @@ namespace PVR
*/
CDateTime GetCurrentPlayingTime(void) const;
- bool m_bNotify = false; /*!< notify on start */
int m_iDatabaseID = -1; /*!< database ID */
int m_iGenreType = 0; /*!< genre type */
int m_iGenreSubType = 0; /*!< genre subtype */
diff --git a/xbmc/settings/AdvancedSettings.cpp b/xbmc/settings/AdvancedSettings.cpp
index 35997d5c0c..a119bc983c 100644
--- a/xbmc/settings/AdvancedSettings.cpp
+++ b/xbmc/settings/AdvancedSettings.cpp
@@ -429,7 +429,7 @@ void CAdvancedSettings::Initialize()
m_databaseVideo.Reset();
m_pictureExtensions = ".png|.jpg|.jpeg|.bmp|.gif|.ico|.tif|.tiff|.tga|.pcx|.cbz|.zip|.rss|.webp|.jp2|.apng";
- m_musicExtensions = ".nsv|.m4a|.flac|.aac|.strm|.pls|.rm|.rma|.mpa|.wav|.wma|.ogg|.mp3|.mp2|.m3u|.gdm|.imf|.m15|.sfx|.uni|.ac3|.dts|.cue|.aif|.aiff|.wpl|.xspf|.ape|.mac|.mpc|.mp+|.mpp|.shn|.zip|.wv|.dsp|.xsp|.xwav|.waa|.wvs|.wam|.gcm|.idsp|.mpdsp|.mss|.spt|.rsd|.sap|.cmc|.cmr|.dmc|.mpt|.mpd|.rmt|.tmc|.tm8|.tm2|.oga|.url|.pxml|.tta|.rss|.wtv|.mka|.tak|.opus|.dff|.dsf|.m4b";
+ m_musicExtensions = ".nsv|.m4a|.flac|.aac|.strm|.pls|.rm|.rma|.mpa|.wav|.wma|.ogg|.mp3|.mp2|.m3u|.gdm|.imf|.m15|.sfx|.uni|.ac3|.dts|.cue|.aif|.aiff|.wpl|.xspf|.ape|.mac|.mpc|.mp+|.mpp|.shn|.zip|.wv|.dsp|.xsp|.xwav|.waa|.wvs|.wam|.gcm|.idsp|.mpdsp|.mss|.spt|.rsd|.sap|.cmc|.cmr|.dmc|.mpt|.mpd|.rmt|.tmc|.tm8|.tm2|.oga|.url|.pxml|.tta|.rss|.wtv|.mka|.tak|.opus|.dff|.dsf|.m4b|.dtshd";
m_videoExtensions = ".m4v|.3g2|.3gp|.nsv|.tp|.ts|.ty|.strm|.pls|.rm|.rmvb|.mpd|.m3u|.m3u8|.ifo|.mov|.qt|.divx|.xvid|.bivx|.vob|.nrg|.img|.iso|.udf|.pva|.wmv|.asf|.asx|.ogm|.m2v|.avi|.bin|.dat|.mpg|.mpeg|.mp4|.mkv|.mk3d|.avc|.vp3|.svq3|.nuv|.viv|.dv|.fli|.flv|.001|.wpl|.xspf|.zip|.vdr|.dvr-ms|.xsp|.mts|.m2t|.m2ts|.evo|.ogv|.sdp|.avs|.rec|.url|.pxml|.vc1|.h264|.rcv|.rss|.mpls|.webm|.bdmv|.wtv|.trp|.f4v";
m_subtitlesExtensions = ".utf|.utf8|.utf-8|.sub|.srt|.smi|.rt|.txt|.ssa|.text|.ssa|.aqt|.jss|.ass|.idx|.ifo|.zip";
m_discStubExtensions = ".disc";
@@ -1050,10 +1050,10 @@ void CAdvancedSettings::ParseSettingsFile(const std::string &file)
{
std::string strFrom, strTo;
TiXmlNode* pFrom = pSubstitute->FirstChild("from");
- if (pFrom)
+ if (pFrom && !pFrom->NoChildren())
strFrom = CSpecialProtocol::TranslatePath(pFrom->FirstChild()->Value()).c_str();
TiXmlNode* pTo = pSubstitute->FirstChild("to");
- if (pTo)
+ if (pTo && !pTo->NoChildren())
strTo = pTo->FirstChild()->Value();
if (!strFrom.empty() && !strTo.empty())
diff --git a/xbmc/settings/Settings.cpp b/xbmc/settings/Settings.cpp
index 0ae68f34d4..20b28c7bd7 100644
--- a/xbmc/settings/Settings.cpp
+++ b/xbmc/settings/Settings.cpp
@@ -207,7 +207,7 @@ const std::string CSettings::SETTING_EPG_SELECTACTION = "epg.selectaction";
const std::string CSettings::SETTING_EPG_HIDENOINFOAVAILABLE = "epg.hidenoinfoavailable";
const std::string CSettings::SETTING_EPG_EPGUPDATE = "epg.epgupdate";
const std::string CSettings::SETTING_EPG_PREVENTUPDATESWHILEPLAYINGTV = "epg.preventupdateswhileplayingtv";
-const std::string CSettings::SETTING_EPG_IGNOREDBFORCLIENT = "epg.ignoredbforclient";
+const std::string CSettings::SETTING_EPG_STOREEPGINDATABASE = "epg.storeepgindatabase";
const std::string CSettings::SETTING_EPG_RESETEPG = "epg.resetepg";
const std::string CSettings::SETTING_PVRPLAYBACK_SWITCHTOFULLSCREEN = "pvrplayback.switchtofullscreen";
const std::string CSettings::SETTING_PVRPLAYBACK_SIGNALQUALITY = "pvrplayback.signalquality";
diff --git a/xbmc/settings/Settings.h b/xbmc/settings/Settings.h
index d0743b32d3..7a49a1f2bc 100644
--- a/xbmc/settings/Settings.h
+++ b/xbmc/settings/Settings.h
@@ -170,7 +170,7 @@ public:
static const std::string SETTING_EPG_HIDENOINFOAVAILABLE;
static const std::string SETTING_EPG_EPGUPDATE;
static const std::string SETTING_EPG_PREVENTUPDATESWHILEPLAYINGTV;
- static const std::string SETTING_EPG_IGNOREDBFORCLIENT;
+ static const std::string SETTING_EPG_STOREEPGINDATABASE;
static const std::string SETTING_EPG_RESETEPG;
static const std::string SETTING_PVRPLAYBACK_SWITCHTOFULLSCREEN;
static const std::string SETTING_PVRPLAYBACK_SIGNALQUALITY;
diff --git a/xbmc/utils/ScraperUrl.cpp b/xbmc/utils/ScraperUrl.cpp
index b4595faf92..baa22a68e9 100644
--- a/xbmc/utils/ScraperUrl.cpp
+++ b/xbmc/utils/ScraperUrl.cpp
@@ -374,7 +374,7 @@ void CScraperUrl::GetThumbURLs(std::vector<std::string> &thumbs, const std::stri
{
for (std::vector<SUrlEntry>::const_iterator iter = m_url.begin(); iter != m_url.end(); ++iter)
{
- if (iter->m_aspect == type || type.empty() || type == "thumb" || iter->m_aspect.empty())
+ if (iter->m_aspect == type || type.empty() || iter->m_aspect.empty())
{
if ((iter->m_type == CScraperUrl::URL_TYPE_GENERAL && season == -1)
|| (iter->m_type == CScraperUrl::URL_TYPE_SEASON && iter->m_season == season))
diff --git a/xbmc/video/VideoThumbLoader.cpp b/xbmc/video/VideoThumbLoader.cpp
index 75946ca442..2e9c9a5936 100644
--- a/xbmc/video/VideoThumbLoader.cpp
+++ b/xbmc/video/VideoThumbLoader.cpp
@@ -108,7 +108,7 @@ bool CThumbExtractor::DoWork()
CTextureDetails details;
details.file = CTextureCache::GetCacheFile(m_target) + ".jpg";
result = CDVDFileInfo::ExtractThumb(m_item, details, m_fillStreamDetails ? &m_item.GetVideoInfoTag()->m_streamDetails : nullptr, m_pos);
- if(result)
+ if (result)
{
CTextureCache::GetInstance().AddCachedTexture(m_target, details);
m_item.SetProperty("HasAutoThumb", true);
@@ -360,7 +360,15 @@ bool CVideoThumbLoader::LoadItemCached(CFileItem* pItem)
!setting->FindIntInList(CSettings::VIDEOLIBRARY_THUMB_SHOW_UNWATCHED_EPISODE)
)
{
- pItem->SetArt("thumb", "OverlaySpoiler.png");
+ // use fanart if available
+ if (pItem->HasArt("fanart"))
+ {
+ pItem->SetArt("thumb", pItem->GetArt("fanart"));
+ }
+ else
+ {
+ pItem->SetArt("thumb", "OverlaySpoiler.png");
+ }
}
m_videoDatabase->Close();
diff --git a/xbmc/windowing/WinSystem.h b/xbmc/windowing/WinSystem.h
index 6e84c49e5f..e8c13a159b 100644
--- a/xbmc/windowing/WinSystem.h
+++ b/xbmc/windowing/WinSystem.h
@@ -139,6 +139,17 @@ public:
// Access render system interface
CGraphicContext& GetGfxContext();
+ /**
+ * Get OS specific hardware context
+ *
+ * \return OS specific context or nullptr if OS not have
+ *
+ * \note This function is currently only related to Windows with DirectX,
+ * all other OS where use GL returns nullptr.
+ * Returned Windows class pointer is ID3D11DeviceContext1.
+ */
+ virtual void* GetHWContext() { return nullptr; }
+
protected:
void UpdateDesktopResolution(RESOLUTION_INFO& newRes, const std::string &output, int width, int height, float refreshRate, uint32_t dwFlags);
virtual std::unique_ptr<KODI::WINDOWING::IOSScreenSaver> GetOSScreenSaverImpl() { return nullptr; }
diff --git a/xbmc/windowing/gbm/WinSystemGbm.cpp b/xbmc/windowing/gbm/WinSystemGbm.cpp
index 4a3291a550..5cee802be2 100644
--- a/xbmc/windowing/gbm/WinSystemGbm.cpp
+++ b/xbmc/windowing/gbm/WinSystemGbm.cpp
@@ -207,11 +207,19 @@ void CWinSystemGbm::FlipPage(bool rendered, bool videoLayer)
m_videoLayerBridge->Disable();
}
- struct gbm_bo *bo = m_GBM->LockFrontBuffer();
+ struct gbm_bo *bo = nullptr;
+
+ if (rendered)
+ {
+ bo = m_GBM->LockFrontBuffer();
+ }
m_DRM->FlipPage(bo, rendered, videoLayer);
- m_GBM->ReleaseBuffer();
+ if (rendered)
+ {
+ m_GBM->ReleaseBuffer();
+ }
if (m_videoLayerBridge && !videoLayer)
{
diff --git a/xbmc/windowing/gbm/WinSystemGbmGLESContext.cpp b/xbmc/windowing/gbm/WinSystemGbmGLESContext.cpp
index c24cb919ae..f763577117 100644
--- a/xbmc/windowing/gbm/WinSystemGbmGLESContext.cpp
+++ b/xbmc/windowing/gbm/WinSystemGbmGLESContext.cpp
@@ -14,6 +14,7 @@
#include "cores/RetroPlayer/rendering/VideoRenderers/RPRendererGBM.h"
#include "cores/RetroPlayer/rendering/VideoRenderers/RPRendererOpenGLES.h"
#include "cores/VideoPlayer/DVDCodecs/DVDFactoryCodec.h"
+#include "cores/VideoPlayer/Process/gbm/ProcessInfoGBM.h"
#include "cores/VideoPlayer/VideoRenderers/LinuxRendererGLES.h"
#include "cores/VideoPlayer/VideoRenderers/RenderFactory.h"
@@ -65,6 +66,7 @@ bool CWinSystemGbmGLESContext::InitWindowSystem()
CRendererDRMPRIMEGLES::Register();
CRendererDRMPRIME::Register();
CDVDVideoCodecDRMPRIME::Register();
+ VIDEOPLAYER::CProcessInfoGBM::Register();
return true;
}
diff --git a/xbmc/windowing/win10/WinSystemWin10DX.h b/xbmc/windowing/win10/WinSystemWin10DX.h
index 5edfd27bd8..61c747224c 100644
--- a/xbmc/windowing/win10/WinSystemWin10DX.h
+++ b/xbmc/windowing/win10/WinSystemWin10DX.h
@@ -25,6 +25,7 @@ public:
void PresentRenderImpl(bool rendered) override;
bool DPIChanged(WORD dpi, RECT windowRect) const override;
bool DestroyRenderSystem() override;
+ void* GetHWContext() override { return m_deviceResources->GetD3DContext(); }
void UninitHooks();
void InitHooks(IDXGIOutput* pOutput);
diff --git a/xbmc/windowing/windows/WinSystemWin32DX.h b/xbmc/windowing/windows/WinSystemWin32DX.h
index 3a613c2643..8a79c8be65 100644
--- a/xbmc/windowing/windows/WinSystemWin32DX.h
+++ b/xbmc/windowing/windows/WinSystemWin32DX.h
@@ -30,6 +30,7 @@ public:
bool DPIChanged(WORD dpi, RECT windowRect) const override;
void SetWindow(HWND hWnd) const;
bool DestroyRenderSystem() override;
+ void* GetHWContext() override { return m_deviceResources->GetD3DContext(); }
void UninitHooks();
void InitHooks(IDXGIOutput* pOutput);