aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--addons/resource.language.en_gb/resources/strings.po9
-rw-r--r--addons/skin.estuary/language/resource.language.en_gb/strings.po17
-rw-r--r--addons/skin.estuary/media/icons/menumarks/star.pngbin0 -> 467 bytes
-rw-r--r--addons/skin.estuary/media/icons/menumarks/tick.pngbin0 -> 267 bytes
-rw-r--r--addons/skin.estuary/xml/DialogSelect.xml5
-rw-r--r--addons/skin.estuary/xml/Includes_DialogSelect.xml544
-rw-r--r--addons/skin.estuary/xml/Includes_SettingsDialog.xml18
-rw-r--r--addons/skin.estuary/xml/Variables.xml33
-rw-r--r--cmake/treedata/common/subdirs.txt1
-rw-r--r--system/keymaps/customcontroller.Harmony.xml4
-rw-r--r--system/keymaps/keyboard.xml8
-rw-r--r--system/keymaps/remote.xml4
-rw-r--r--xbmc/GUIInfoManager.cpp9
-rw-r--r--xbmc/Util.cpp10
-rw-r--r--xbmc/addons/interfaces/Filesystem.cpp5
-rw-r--r--xbmc/addons/interfaces/gui/GUITranslator.cpp6
-rw-r--r--xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/input/action_ids.h9
-rw-r--r--xbmc/addons/kodi-dev-kit/include/kodi/versions.h2
-rw-r--r--xbmc/application/ApplicationPlayer.cpp8
-rw-r--r--xbmc/application/ApplicationPlayer.h4
-rw-r--r--xbmc/cores/IPlayer.h40
-rw-r--r--xbmc/cores/VideoPlayer/Interface/StreamInfo.h7
-rw-r--r--xbmc/cores/VideoPlayer/VideoPlayer.cpp22
-rw-r--r--xbmc/cores/VideoPlayer/VideoPlayer.h3
-rw-r--r--xbmc/cores/paplayer/PAPlayer.h2
-rw-r--r--xbmc/guilib/GUIComponent.cpp4
-rw-r--r--xbmc/guilib/GUIComponent.h2
-rw-r--r--xbmc/guilib/GUIWindowManager.cpp6
-rw-r--r--xbmc/guilib/WindowIDs.h4
-rw-r--r--xbmc/guilib/guiinfo/GUIInfoLabels.h1
-rw-r--r--xbmc/guilib/guiinfo/VideoGUIInfo.cpp3
-rw-r--r--xbmc/guilib/handlers/CMakeLists.txt7
-rw-r--r--xbmc/guilib/handlers/GUIAnnouncementHandlerContainer.cpp16
-rw-r--r--xbmc/guilib/handlers/GUIAnnouncementHandlerContainer.h29
-rw-r--r--xbmc/guilib/handlers/sources/GUISourcesAnnouncementHandler.cpp42
-rw-r--r--xbmc/guilib/handlers/sources/GUISourcesAnnouncementHandler.h26
-rw-r--r--xbmc/input/WindowTranslator.cpp3
-rw-r--r--xbmc/input/actions/ActionIDs.h9
-rw-r--r--xbmc/input/actions/ActionTranslator.cpp3
-rw-r--r--xbmc/interfaces/IAnnouncer.h44
-rw-r--r--xbmc/network/ZeroconfBrowser.h3
-rw-r--r--xbmc/network/mdns/ZeroconfBrowserMDNS.cpp14
-rw-r--r--xbmc/network/upnp/UPnP.cpp21
-rw-r--r--xbmc/network/upnp/UPnPRenderer.cpp1
-rw-r--r--xbmc/platform/android/network/ZeroconfBrowserAndroid.cpp13
-rw-r--r--xbmc/platform/darwin/network/ZeroconfBrowserDarwin.cpp13
-rw-r--r--xbmc/pvr/addons/PVRClient.cpp4
-rw-r--r--xbmc/video/PlayerController.cpp35
-rw-r--r--xbmc/video/VideoDatabase.cpp2
-rw-r--r--xbmc/video/dialogs/GUIDialogAudioSettings.cpp36
-rw-r--r--xbmc/video/dialogs/GUIDialogAudioSettings.h7
-rw-r--r--xbmc/video/dialogs/GUIDialogSubtitleSettings.cpp14
-rw-r--r--xbmc/video/dialogs/GUIDialogSubtitleSettings.h5
-rw-r--r--xbmc/video/dialogs/GUIDialogVideoInfo.cpp30
-rw-r--r--xbmc/video/guilib/CMakeLists.txt2
-rw-r--r--xbmc/video/guilib/VideoStreamSelectHelper.cpp518
-rw-r--r--xbmc/video/guilib/VideoStreamSelectHelper.h29
-rw-r--r--xbmc/video/windows/GUIWindowVideoBase.cpp1
58 files changed, 1559 insertions, 158 deletions
diff --git a/addons/resource.language.en_gb/resources/strings.po b/addons/resource.language.en_gb/resources/strings.po
index 46d1d6174f..2ec1005854 100644
--- a/addons/resource.language.en_gb/resources/strings.po
+++ b/addons/resource.language.en_gb/resources/strings.po
@@ -2196,6 +2196,10 @@ msgctxt "#459"
msgid "Subs"
msgstr ""
+#: xbmc/video/PlayerController.cpp
+#: xbmc/video/dialogs/GUIDialogAudioSettings.cpp
+#: addons/skin.estuary/xml/DialogPlayerProcessInfo.xml
+#: xbmc/video/guilib/VideoStreamSelectHelper.cpp
msgctxt "#460"
msgid "Audio stream"
msgstr ""
@@ -2204,8 +2208,10 @@ msgctxt "#461"
msgid "[active]"
msgstr ""
+#: xbmc/video/dialogs/GUIDialogSubtitleSettings.cpp
+#: xbmc/video/guilib/VideoStreamSelectHelper.cpp
msgctxt "#462"
-msgid "Subtitle"
+msgid "Subtitle stream"
msgstr ""
msgctxt "#463"
@@ -22827,6 +22833,7 @@ msgstr ""
#. Label for an option to select the video stream to play if current video has more than one video stream
#: xbmc/video/dialogs/GUIDialogVideoSettings.cpp
#: xbmc/video/PlayerController.cpp
+#: xbmc/video/guilib/VideoStreamSelectHelper.cpp
msgctxt "#38031"
msgid "Video stream"
msgstr ""
diff --git a/addons/skin.estuary/language/resource.language.en_gb/strings.po b/addons/skin.estuary/language/resource.language.en_gb/strings.po
index 229f0b95e5..d6f2bc6c04 100644
--- a/addons/skin.estuary/language/resource.language.en_gb/strings.po
+++ b/addons/skin.estuary/language/resource.language.en_gb/strings.po
@@ -502,7 +502,12 @@ msgctxt "#31107"
msgid "WideList"
msgstr ""
-#empty strings from id 31108 to 31109
+#empty strings from id 31108 to 31108
+
+#: /xml/VideoOSD.xml
+msgctxt "#31109"
+msgid "Video streams"
+msgstr ""
#: /xml/Home.xml
msgctxt "#31110"
@@ -516,7 +521,7 @@ msgstr ""
#: /xml/VideoOSD.xml
msgctxt "#31112"
-msgid "Toggle audio stream"
+msgid "Audio streams"
msgstr ""
#: /xml/Custom_1107_SearchDialog.xml
@@ -531,7 +536,7 @@ msgstr ""
#: /xml/VideoOSD.xml
msgctxt "#31115"
-msgid "Toggle subtitle"
+msgid "Subtitles streams"
msgstr ""
#: /xml/Includes_Home.xml
@@ -924,3 +929,9 @@ msgstr ""
msgctxt "#31611"
msgid "System"
msgstr ""
+
+#: /xml/Includes_DialogSelect.xml
+#. Audio channels
+msgctxt "#31612"
+msgid "channels"
+msgstr ""
diff --git a/addons/skin.estuary/media/icons/menumarks/star.png b/addons/skin.estuary/media/icons/menumarks/star.png
new file mode 100644
index 0000000000..da55f2ea2a
--- /dev/null
+++ b/addons/skin.estuary/media/icons/menumarks/star.png
Binary files differ
diff --git a/addons/skin.estuary/media/icons/menumarks/tick.png b/addons/skin.estuary/media/icons/menumarks/tick.png
new file mode 100644
index 0000000000..c5a89ca6f8
--- /dev/null
+++ b/addons/skin.estuary/media/icons/menumarks/tick.png
Binary files differ
diff --git a/addons/skin.estuary/xml/DialogSelect.xml b/addons/skin.estuary/xml/DialogSelect.xml
index 308c14b743..cafeb37998 100644
--- a/addons/skin.estuary/xml/DialogSelect.xml
+++ b/addons/skin.estuary/xml/DialogSelect.xml
@@ -4,7 +4,10 @@
<include>Animation_DialogPopupOpenClose</include>
<depth>DepthOSD</depth>
<controls>
- <include condition="![Window.IsActive(selectvideoversion) | Window.IsActive(selectvideoextra) | Window.IsActive(gamesaves) | Window.IsActive(gamestretchmode) | Window.IsActive(gamevideofilter) | Window.IsActive(gamevideorotation) | Window.IsActive(ingamesaves)]">DefaultDialogSelectLayout</include>
+ <include condition="![Window.IsActive(videoselectdialog) | Window.IsActive(audioselectdialog) | Window.IsActive(subtitleselectdialog) | Window.IsActive(selectvideoversion) | Window.IsActive(selectvideoextra) | Window.IsActive(gamesaves) | Window.IsActive(gamestretchmode) | Window.IsActive(gamevideofilter) | Window.IsActive(gamevideorotation) | Window.IsActive(ingamesaves)]">DefaultDialogSelectLayout</include>
+ <include condition="Window.IsActive(videoselectdialog)">VideoDialogSelectVideoLayout</include>
+ <include condition="Window.IsActive(audioselectdialog)">VideoDialogSelectAudioLayout</include>
+ <include condition="Window.IsActive(subtitleselectdialog)">VideoDialogSelectSubtitleLayout</include>
<include condition="Window.IsActive(gamesaves)">GameDialogSelectSaveLayout</include>
<include condition="Window.IsActive(gamevideofilter)">GameDialogSelectFilterLayout</include>
<include condition="Window.IsActive(gamestretchmode)">GameDialogSelectViewLayout</include>
diff --git a/addons/skin.estuary/xml/Includes_DialogSelect.xml b/addons/skin.estuary/xml/Includes_DialogSelect.xml
index 7ca4f0d459..72049e69dd 100644
--- a/addons/skin.estuary/xml/Includes_DialogSelect.xml
+++ b/addons/skin.estuary/xml/Includes_DialogSelect.xml
@@ -194,6 +194,550 @@
</control>
</control>
</include>
+ <include name="VideoDialogSelectVideoLayout">
+ <!--
+ Available ListItem video stream properties:
+ stream.description, stream.codec, stream.language, stream.resolution, stream.bitrate,
+ stream.fps, stream.is3d, stream.stereomode, stream.hdrtype, stream.isdefault, stream.isforced,
+ stream.ishearingimpaired, stream.isvisualimpaired
+ -->
+ <control type="group">
+ <centertop>50%</centertop>
+ <centerleft>50%</centerleft>
+ <height>750</height>
+ <width>1220</width>
+ <include content="DialogBackgroundCommons">
+ <param name="width" value="1220" />
+ <param name="height" value="750" />
+ <param name="header_label" value="" />
+ <param name="header_id" value="1" />
+ </include>
+ <control type="image">
+ <left>0</left>
+ <top>80</top>
+ <width>920</width>
+ <bottom>2</bottom>
+ <texture border="40">buttons/dialogbutton-nofo.png</texture>
+ </control>
+ <control type="list" id="3">
+ <left>20</left>
+ <top>100</top>
+ <width>880</width>
+ <bottom>20</bottom>
+ <onup>3</onup>
+ <ondown>3</ondown>
+ <onleft>9001</onleft>
+ <onright>61</onright>
+ <pagecontrol>61</pagecontrol>
+ <scrolltime>200</scrolltime>
+ <include content="DefaultSimpleListLayout">
+ <param name="width" value="880" />
+ <param name="list_id" value="3" />
+ </include>
+ </control>
+ <control type="list" id="6">
+ <left>20</left>
+ <top>100</top>
+ <width>880</width>
+ <bottom>20</bottom>
+ <onup>6</onup>
+ <ondown>6</ondown>
+ <onleft>9001</onleft>
+ <onright>61</onright>
+ <pagecontrol>61</pagecontrol>
+ <scrolltime>200</scrolltime>
+ <itemlayout height="100" width="880">
+ <control type="image">
+ <left>10</left>
+ <top>16</top>
+ <width>30</width>
+ <height>30</height>
+ <aspectratio>keep</aspectratio>
+ <aligny>center</aligny>
+ <texture>icons/menumarks/tick.png</texture>
+ <visible>ListItem.IsSelected</visible>
+ </control>
+ <control type="label">
+ <left>50</left>
+ <top>0</top>
+ <right>80</right>
+ <height>60</height>
+ <font>font14</font>
+ <aligny>center</aligny>
+ <label>$INFO[ListItem.Property(stream.codec)]$INFO[ListItem.Property(stream.resolution),$COMMA ]$INFO[ListItem.Property(stream.bitrate),$COMMA , kbps]$INFO[ListItem.Property(stream.fps),$COMMA , fps]$VAR[VideoStreamDialogVideoItemLabelVar, - [LIGHT],[/LIGHT]]</label>
+ </control>
+ <control type="textbox">
+ <left>50</left>
+ <top>50</top>
+ <right>80</right>
+ <height>67</height>
+ <font>font12</font>
+ <textcolor>grey</textcolor>
+ <label>$INFO[ListItem.Property(stream.description),, ]$INFO[ListItem.Property(stream.language),(,)]</label>
+ </control>
+ <control type="image">
+ <left>830</left>
+ <top>16</top>
+ <width>30</width>
+ <height>30</height>
+ <aspectratio>keep</aspectratio>
+ <aligny>center</aligny>
+ <texture>icons/menumarks/star.png</texture>
+ <visible>ListItem.Property(stream.isdefault)</visible>
+ </control>
+ </itemlayout>
+ <focusedlayout height="100" width="880">
+ <control type="image">
+ <left>0</left>
+ <top>0</top>
+ <right>0</right>
+ <bottom>0</bottom>
+ <texture colordiffuse="button_focus">lists/focus.png</texture>
+ <animation effect="fade" start="100" end="50" time="0">UnFocus</animation>
+ </control>
+ <control type="image">
+ <left>10</left>
+ <top>16</top>
+ <width>30</width>
+ <height>30</height>
+ <aspectratio>keep</aspectratio>
+ <aligny>center</aligny>
+ <texture>icons/menumarks/tick.png</texture>
+ <visible>ListItem.IsSelected</visible>
+ </control>
+ <control type="label">
+ <left>50</left>
+ <top>0</top>
+ <right>80</right>
+ <height>60</height>
+ <aligny>center</aligny>
+ <scroll>true</scroll>
+ <font>font14</font>
+ <label>$INFO[ListItem.Property(stream.codec)]$INFO[ListItem.Property(stream.resolution),$COMMA ]$INFO[ListItem.Property(stream.bitrate),$COMMA , kbps]$INFO[ListItem.Property(stream.fps),$COMMA , fps]$VAR[VideoStreamDialogVideoItemLabelVar, - [LIGHT],[/LIGHT]]</label>
+ </control>
+ <control type="textbox">
+ <left>50</left>
+ <top>50</top>
+ <right>80</right>
+ <height>67</height>
+ <font>font12</font>
+ <label>$INFO[ListItem.Property(stream.description),, ]$INFO[ListItem.Property(stream.language),(,)]</label>
+ </control>
+ <control type="image">
+ <left>830</left>
+ <top>16</top>
+ <width>30</width>
+ <height>30</height>
+ <aspectratio>keep</aspectratio>
+ <aligny>center</aligny>
+ <texture>icons/menumarks/star.png</texture>
+ <visible>ListItem.Property(stream.isdefault)</visible>
+ </control>
+ </focusedlayout>
+ </control>
+ <control type="scrollbar" id="61">
+ <left>910</left>
+ <top>100</top>
+ <width>12</width>
+ <bottom>20</bottom>
+ <onleft condition="Control.IsVisible(3)">3</onleft>
+ <onleft condition="Control.IsVisible(6)">6</onleft>
+ <onright>9001</onright>
+ <orientation>vertical</orientation>
+ </control>
+ <control type="label">
+ <left>925</left>
+ <bottom>10</bottom>
+ <width>275</width>
+ <height>35</height>
+ <font>font12</font>
+ <align>right</align>
+ <textcolor>grey</textcolor>
+ <label>$VAR[SelectLabel]</label>
+ </control>
+ <control type="grouplist" id="9001">
+ <left>920</left>
+ <top>80</top>
+ <onleft>61</onleft>
+ <itemgap>dialogbuttons_itemgap</itemgap>
+ <onright>3</onright>
+ <include content="DefaultDialogButton">
+ <param name="id" value="5" />
+ <param name="label" value="" />
+ </include>
+ <include content="DefaultDialogButton">
+ <param name="id" value="8" />
+ <param name="label" value="" />
+ </include>
+ <include content="DefaultDialogButton">
+ <param name="id" value="7" />
+ <param name="label" value="$LOCALIZE[222]" />
+ </include>
+ </control>
+ </control>
+ </include>
+ <include name="VideoDialogSelectAudioLayout">
+ <!--
+ Available ListItem audio stream properties:
+ stream.description, stream.codec, stream.codecdesc, stream.channels,
+ stream.isdefault, stream.isforced, stream.isoriginal, stream.ishearingimpaired, stream.isvisualimpaired
+ -->
+ <control type="group">
+ <centertop>50%</centertop>
+ <centerleft>50%</centerleft>
+ <height>750</height>
+ <width>1220</width>
+ <include content="DialogBackgroundCommons">
+ <param name="width" value="1220" />
+ <param name="height" value="750" />
+ <param name="header_label" value="" />
+ <param name="header_id" value="1" />
+ </include>
+ <control type="image">
+ <left>0</left>
+ <top>80</top>
+ <width>920</width>
+ <bottom>2</bottom>
+ <texture border="40">buttons/dialogbutton-nofo.png</texture>
+ </control>
+ <control type="list" id="3">
+ <left>20</left>
+ <top>100</top>
+ <width>880</width>
+ <bottom>20</bottom>
+ <onup>3</onup>
+ <ondown>3</ondown>
+ <onleft>9001</onleft>
+ <onright>61</onright>
+ <pagecontrol>61</pagecontrol>
+ <scrolltime>200</scrolltime>
+ <include content="DefaultSimpleListLayout">
+ <param name="width" value="880" />
+ <param name="list_id" value="3" />
+ </include>
+ </control>
+ <control type="list" id="6">
+ <left>20</left>
+ <top>100</top>
+ <width>880</width>
+ <bottom>20</bottom>
+ <onup>6</onup>
+ <ondown>6</ondown>
+ <onleft>9001</onleft>
+ <onright>61</onright>
+ <pagecontrol>61</pagecontrol>
+ <scrolltime>200</scrolltime>
+ <itemlayout height="130" width="880">
+ <control type="image">
+ <left>10</left>
+ <top>16</top>
+ <width>30</width>
+ <height>30</height>
+ <aspectratio>keep</aspectratio>
+ <aligny>center</aligny>
+ <texture>icons/menumarks/tick.png</texture>
+ <visible>ListItem.IsSelected</visible>
+ </control>
+- <control type="label">
+ <left>50</left>
+ <top>0</top>
+ <right>80</right>
+ <height>60</height>
+ <font>font14</font>
+ <aligny>center</aligny>
+ <label>$INFO[ListItem.Label]$VAR[VideoStreamDialogAudioItemLabelVar, - [LIGHT],[/LIGHT]]</label>
+ </control>
+ <control type="textbox">
+ <left>50</left>
+ <top>50</top>
+ <right>80</right>
+ <height>80</height>
+ <font>font12</font>
+ <textcolor>grey</textcolor>
+ <label>$INFO[ListItem.Property(stream.codecdesc),, - ]$INFO[ListItem.Property(stream.channels),$LOCALIZE[31612]: ][CR]$INFO[ListItem.Property(stream.description)]</label>
+ </control>
+ <control type="image">
+ <left>830</left>
+ <top>16</top>
+ <width>30</width>
+ <height>30</height>
+ <aspectratio>keep</aspectratio>
+ <aligny>center</aligny>
+ <texture>icons/menumarks/star.png</texture>
+ <visible>ListItem.Property(stream.isdefault)</visible>
+ </control>
+ </itemlayout>
+ <focusedlayout height="130" width="880">
+ <control type="image">
+ <left>0</left>
+ <top>0</top>
+ <right>0</right>
+ <bottom>0</bottom>
+ <texture colordiffuse="button_focus">lists/focus.png</texture>
+ <animation effect="fade" start="100" end="50" time="0">UnFocus</animation>
+ </control>
+ <control type="image">
+ <left>10</left>
+ <top>16</top>
+ <width>30</width>
+ <height>30</height>
+ <aspectratio>keep</aspectratio>
+ <aligny>center</aligny>
+ <texture>icons/menumarks/tick.png</texture>
+ <visible>ListItem.IsSelected</visible>
+ </control>
+ <control type="label">
+ <left>50</left>
+ <top>0</top>
+ <right>80</right>
+ <height>60</height>
+ <aligny>center</aligny>
+ <scroll>true</scroll>
+ <font>font14</font>
+ <label>$INFO[ListItem.Label]$VAR[VideoStreamDialogAudioItemLabelVar, - [LIGHT],[/LIGHT]]</label>
+ </control>
+ <control type="textbox">
+ <left>50</left>
+ <top>50</top>
+ <right>80</right>
+ <height>80</height>
+ <font>font12</font>
+ <label>$INFO[ListItem.Property(stream.codecdesc),, - ]$INFO[ListItem.Property(stream.channels),$LOCALIZE[31612]: ][CR]$INFO[ListItem.Property(stream.description)]</label>
+ </control>
+ <control type="image">
+ <left>830</left>
+ <top>16</top>
+ <width>30</width>
+ <height>30</height>
+ <aspectratio>keep</aspectratio>
+ <aligny>center</aligny>
+ <texture>icons/menumarks/star.png</texture>
+ <visible>ListItem.Property(stream.isdefault)</visible>
+ </control>
+ </focusedlayout>
+ </control>
+ <control type="scrollbar" id="61">
+ <left>910</left>
+ <top>100</top>
+ <width>12</width>
+ <bottom>20</bottom>
+ <onleft condition="Control.IsVisible(3)">3</onleft>
+ <onleft condition="Control.IsVisible(6)">6</onleft>
+ <onright>9001</onright>
+ <orientation>vertical</orientation>
+ </control>
+ <control type="label">
+ <left>925</left>
+ <bottom>10</bottom>
+ <width>275</width>
+ <height>35</height>
+ <font>font12</font>
+ <align>right</align>
+ <textcolor>grey</textcolor>
+ <label>$VAR[SelectLabel]</label>
+ </control>
+ <control type="grouplist" id="9001">
+ <left>920</left>
+ <top>80</top>
+ <onleft>61</onleft>
+ <itemgap>dialogbuttons_itemgap</itemgap>
+ <onright>3</onright>
+ <include content="DefaultDialogButton">
+ <param name="id" value="5" />
+ <param name="label" value="" />
+ </include>
+ <include content="DefaultDialogButton">
+ <param name="id" value="8" />
+ <param name="label" value="" />
+ </include>
+ <include content="DefaultDialogButton">
+ <param name="id" value="7" />
+ <param name="label" value="$LOCALIZE[222]" />
+ </include>
+ </control>
+ </control>
+ </include>
+ <include name="VideoDialogSelectSubtitleLayout">
+ <!--
+ Available ListItem subtitle stream properties:
+ stream.description, stream.codec, stream.isdefault, stream.isforced, stream.isoriginal,
+ stream.ishearingimpaired, stream.isvisualimpaired, stream.isexternal
+ -->
+ <control type="group">
+ <centertop>50%</centertop>
+ <centerleft>50%</centerleft>
+ <height>750</height>
+ <width>1220</width>
+ <include content="DialogBackgroundCommons">
+ <param name="width" value="1220" />
+ <param name="height" value="750" />
+ <param name="header_label" value="" />
+ <param name="header_id" value="1" />
+ </include>
+ <control type="image">
+ <left>0</left>
+ <top>80</top>
+ <width>920</width>
+ <bottom>2</bottom>
+ <texture border="40">buttons/dialogbutton-nofo.png</texture>
+ </control>
+ <control type="list" id="3">
+ <left>20</left>
+ <top>100</top>
+ <width>880</width>
+ <bottom>20</bottom>
+ <onup>3</onup>
+ <ondown>3</ondown>
+ <onleft>9001</onleft>
+ <onright>61</onright>
+ <pagecontrol>61</pagecontrol>
+ <scrolltime>200</scrolltime>
+ <include content="DefaultSimpleListLayout">
+ <param name="width" value="880" />
+ <param name="list_id" value="3" />
+ </include>
+ </control>
+ <control type="list" id="6">
+ <left>20</left>
+ <top>100</top>
+ <width>880</width>
+ <bottom>20</bottom>
+ <onup>6</onup>
+ <ondown>6</ondown>
+ <onleft>9001</onleft>
+ <onright>61</onright>
+ <pagecontrol>61</pagecontrol>
+ <scrolltime>200</scrolltime>
+ <itemlayout height="100" width="880">
+ <control type="image">
+ <left>10</left>
+ <top>16</top>
+ <width>30</width>
+ <height>30</height>
+ <aspectratio>keep</aspectratio>
+ <aligny>center</aligny>
+ <texture>icons/menumarks/tick.png</texture>
+ <visible>ListItem.IsSelected</visible>
+ </control>
+ <control type="label">
+ <left>50</left>
+ <top>0</top>
+ <right>80</right>
+ <height>60</height>
+ <font>font14</font>
+ <aligny>center</aligny>
+ <label>$INFO[ListItem.Label]$VAR[VideoStreamDialogSubItemLabelVar, - [LIGHT],[/LIGHT]]</label>
+ </control>
+ <control type="textbox">
+ <left>50</left>
+ <top>50</top>
+ <right>80</right>
+ <height>67</height>
+ <font>font12</font>
+ <textcolor>grey</textcolor>
+ <label>$INFO[ListItem.Property(stream.description)]</label>
+ </control>
+ <control type="image">
+ <left>830</left>
+ <top>16</top>
+ <width>30</width>
+ <height>30</height>
+ <aspectratio>keep</aspectratio>
+ <aligny>center</aligny>
+ <texture>icons/menumarks/star.png</texture>
+ <visible>ListItem.Property(stream.isdefault)</visible>
+ </control>
+ </itemlayout>
+ <focusedlayout height="100" width="880">
+ <control type="image">
+ <left>0</left>
+ <top>0</top>
+ <right>0</right>
+ <bottom>0</bottom>
+ <texture colordiffuse="button_focus">lists/focus.png</texture>
+ <animation effect="fade" start="100" end="50" time="0">UnFocus</animation>
+ </control>
+ <control type="image">
+ <left>10</left>
+ <top>16</top>
+ <width>30</width>
+ <height>30</height>
+ <aspectratio>keep</aspectratio>
+ <aligny>center</aligny>
+ <texture>icons/menumarks/tick.png</texture>
+ <visible>ListItem.IsSelected</visible>
+ </control>
+ <control type="label">
+ <left>50</left>
+ <top>0</top>
+ <right>80</right>
+ <height>60</height>
+ <aligny>center</aligny>
+ <scroll>true</scroll>
+ <font>font14</font>
+ <label>$INFO[ListItem.Label]$VAR[VideoStreamDialogSubItemLabelVar, - [LIGHT],[/LIGHT]]</label>
+ </control>
+ <control type="textbox">
+ <left>50</left>
+ <top>50</top>
+ <right>80</right>
+ <height>67</height>
+ <font>font12</font>
+ <label>$INFO[ListItem.Property(stream.description)]</label>
+ </control>
+ <control type="image">
+ <left>830</left>
+ <top>16</top>
+ <width>30</width>
+ <height>30</height>
+ <aspectratio>keep</aspectratio>
+ <aligny>center</aligny>
+ <texture>icons/menumarks/star.png</texture>
+ <visible>ListItem.Property(stream.isdefault)</visible>
+ </control>
+ </focusedlayout>
+ </control>
+ <control type="scrollbar" id="61">
+ <left>910</left>
+ <top>100</top>
+ <width>12</width>
+ <bottom>20</bottom>
+ <onleft condition="Control.IsVisible(3)">3</onleft>
+ <onleft condition="Control.IsVisible(6)">6</onleft>
+ <onright>9001</onright>
+ <orientation>vertical</orientation>
+ </control>
+ <control type="label">
+ <left>925</left>
+ <bottom>10</bottom>
+ <width>275</width>
+ <height>35</height>
+ <font>font12</font>
+ <align>right</align>
+ <textcolor>grey</textcolor>
+ <label>$VAR[SelectLabel]</label>
+ </control>
+ <control type="grouplist" id="9001">
+ <left>920</left>
+ <top>80</top>
+ <onleft>61</onleft>
+ <itemgap>dialogbuttons_itemgap</itemgap>
+ <onright>3</onright>
+ <include content="DefaultDialogButton">
+ <param name="id" value="5" />
+ <param name="label" value="" />
+ </include>
+ <include content="DefaultDialogButton">
+ <param name="id" value="8" />
+ <param name="label" value="" />
+ </include>
+ <include content="DefaultDialogButton">
+ <param name="id" value="7" />
+ <param name="label" value="$LOCALIZE[222]" />
+ </include>
+ </control>
+ </control>
+ </include>
<include name="GameDialogSelectSaveLayout">
<control type="group">
<centertop>50%</centertop>
diff --git a/addons/skin.estuary/xml/Includes_SettingsDialog.xml b/addons/skin.estuary/xml/Includes_SettingsDialog.xml
index 7d8aa3cab9..1dedc8b9a8 100644
--- a/addons/skin.estuary/xml/Includes_SettingsDialog.xml
+++ b/addons/skin.estuary/xml/Includes_SettingsDialog.xml
@@ -25,19 +25,25 @@
<onclick>ActivateWindow(osdcmssettings)</onclick>
<visible>System.HasCMS</visible>
</control>
+ <control type="button" id="22106">
+ <include>DialogSettingButton</include>
+ <label>$LOCALIZE[31115]</label>
+ <label2>$VAR[ActiveVideoPlayerSubtitleLanguage]</label2>
+ <onclick>DialogSelectSubtitle</onclick>
+ <visible>VideoPlayer.HasSubtitles</visible>
+ </control>
<control type="button" id="22105">
<include>DialogSettingButton</include>
<label>$LOCALIZE[31112]</label>
<label2>[B]$INFO[VideoPlayer.AudioLanguage][/B]</label2>
- <onclick>AudioNextLanguage</onclick>
+ <onclick>DialogSelectAudio</onclick>
<visible>Integer.IsGreater(VideoPlayer.AudioStreamCount,1)</visible>
</control>
- <control type="button" id="22106">
+ <control type="button" id="22110">
<include>DialogSettingButton</include>
- <label>$LOCALIZE[31115]</label>
- <label2>$VAR[ActiveVideoPlayerSubtitleLanguage]</label2>
- <onclick>NextSubtitle</onclick>
- <visible>VideoPlayer.HasSubtitles</visible>
+ <label>$LOCALIZE[31109]</label>
+ <onclick>DialogSelectVideo</onclick>
+ <visible>Integer.IsGreater(VideoPlayer.VideoStreamCount,1)</visible>
</control>
<control type="button" id="22107">
<include>DialogSettingButton</include>
diff --git a/addons/skin.estuary/xml/Variables.xml b/addons/skin.estuary/xml/Variables.xml
index fb320882e8..49382061a9 100644
--- a/addons/skin.estuary/xml/Variables.xml
+++ b/addons/skin.estuary/xml/Variables.xml
@@ -967,4 +967,37 @@
<variable name="PVRInstanceName">
<value condition="Integer.IsGreater(PVR.ClientCount,1)">$INFO[ListItem.PVRClientName,[COLOR grey]$LOCALIZE[31137]:[/COLOR] ,]$INFO[ListItem.PVRInstanceName, (,)]</value>
</variable>
+ <variable name="VideoStreamDialogVideoItemLabelVar">
+ <value condition="String.IsEqual(ListItem.Property(stream.isforced),true)+String.IsEqual(ListItem.Property(stream.ishearingimpaired),true)">$LOCALIZE[39106], $LOCALIZE[39107]</value>
+ <value condition="String.IsEqual(ListItem.Property(stream.isforced),true)+String.IsEqual(ListItem.Property(stream.isvisualimpaired),true)">$LOCALIZE[39106], $LOCALIZE[39108]</value>
+ <value condition="String.IsEqual(ListItem.Property(stream.ishearingimpaired),true)">$LOCALIZE[39107]</value>
+ <value condition="String.IsEqual(ListItem.Property(stream.isvisualimpaired),true)">$LOCALIZE[39108]</value>
+ <value condition="String.IsEqual(ListItem.Property(stream.isforced),true)">$LOCALIZE[39106]</value>
+ </variable>
+ <variable name="VideoStreamDialogAudioItemLabelVar">
+ <value condition="String.IsEqual(ListItem.Property(stream.isoriginal),true)+String.IsEqual(ListItem.Property(stream.isforced),true)+String.IsEqual(ListItem.Property(stream.ishearingimpaired),true)">$LOCALIZE[39111], $LOCALIZE[39106], $LOCALIZE[39107]</value>
+ <value condition="String.IsEqual(ListItem.Property(stream.isoriginal),true)+String.IsEqual(ListItem.Property(stream.isforced),true)+String.IsEqual(ListItem.Property(stream.isvisualimpaired),true)">$LOCALIZE[39111], $LOCALIZE[39106], $LOCALIZE[39108]</value>
+ <value condition="String.IsEqual(ListItem.Property(stream.isoriginal),true)+String.IsEqual(ListItem.Property(stream.isforced),true)">$LOCALIZE[39111], $LOCALIZE[39106]</value>
+ <value condition="String.IsEqual(ListItem.Property(stream.isoriginal),true)+String.IsEqual(ListItem.Property(stream.ishearingimpaired),true)">$LOCALIZE[39111], $LOCALIZE[39107]</value>
+ <value condition="String.IsEqual(ListItem.Property(stream.isoriginal),true)+String.IsEqual(ListItem.Property(stream.isvisualimpaired),true)">$LOCALIZE[39111], $LOCALIZE[39108]</value>
+ <value condition="String.IsEqual(ListItem.Property(stream.isforced),true)+String.IsEqual(ListItem.Property(stream.ishearingimpaired),true)">$LOCALIZE[39106], $LOCALIZE[39107]</value>
+ <value condition="String.IsEqual(ListItem.Property(stream.isforced),true)+String.IsEqual(ListItem.Property(stream.isvisualimpaired),true)">$LOCALIZE[39106], $LOCALIZE[39108]</value>
+ <value condition="String.IsEqual(ListItem.Property(stream.ishearingimpaired),true)">$LOCALIZE[39107]</value>
+ <value condition="String.IsEqual(ListItem.Property(stream.isvisualimpaired),true)">$LOCALIZE[39108]</value>
+ <value condition="String.IsEqual(ListItem.Property(stream.isforced),true)">$LOCALIZE[39106]</value>
+ <value condition="String.IsEqual(ListItem.Property(stream.isoriginal),true)">$LOCALIZE[39111]</value>
+ </variable>
+ <variable name="VideoStreamDialogSubItemLabelVar">
+ <value condition="String.IsEqual(ListItem.Property(stream.isoriginal),true)+String.IsEqual(ListItem.Property(stream.isforced),true)+String.IsEqual(ListItem.Property(stream.ishearingimpaired),true)">$LOCALIZE[39111], $LOCALIZE[39106], $LOCALIZE[39107]</value>
+ <value condition="String.IsEqual(ListItem.Property(stream.isoriginal),true)+String.IsEqual(ListItem.Property(stream.isforced),true)+String.IsEqual(ListItem.Property(stream.isvisualimpaired),true)">$LOCALIZE[39111], $LOCALIZE[39106], $LOCALIZE[39108]</value>
+ <value condition="String.IsEqual(ListItem.Property(stream.isoriginal),true)+String.IsEqual(ListItem.Property(stream.isforced),true)">$LOCALIZE[39111], $LOCALIZE[39106]</value>
+ <value condition="String.IsEqual(ListItem.Property(stream.isoriginal),true)+String.IsEqual(ListItem.Property(stream.ishearingimpaired),true)">$LOCALIZE[39111], $LOCALIZE[39107]</value>
+ <value condition="String.IsEqual(ListItem.Property(stream.isoriginal),true)+String.IsEqual(ListItem.Property(stream.isvisualimpaired),true)">$LOCALIZE[39111], $LOCALIZE[39108]</value>
+ <value condition="String.IsEqual(ListItem.Property(stream.isforced),true)+String.IsEqual(ListItem.Property(stream.ishearingimpaired),true)">$LOCALIZE[39106], $LOCALIZE[39107]</value>
+ <value condition="String.IsEqual(ListItem.Property(stream.isforced),true)+String.IsEqual(ListItem.Property(stream.isvisualimpaired),true)">$LOCALIZE[39106], $LOCALIZE[39108]</value>
+ <value condition="String.IsEqual(ListItem.Property(stream.ishearingimpaired),true)">$LOCALIZE[39107]</value>
+ <value condition="String.IsEqual(ListItem.Property(stream.isvisualimpaired),true)">$LOCALIZE[39108]</value>
+ <value condition="String.IsEqual(ListItem.Property(stream.isforced),true)">$LOCALIZE[39106]</value>
+ <value condition="String.IsEqual(ListItem.Property(stream.isoriginal),true)">$LOCALIZE[39111]</value>
+ </variable>
</includes>
diff --git a/cmake/treedata/common/subdirs.txt b/cmake/treedata/common/subdirs.txt
index 00bd9396e5..f4e46076fb 100644
--- a/cmake/treedata/common/subdirs.txt
+++ b/cmake/treedata/common/subdirs.txt
@@ -16,6 +16,7 @@ xbmc/dialogs dialogs
xbmc/favourites favourites
xbmc/guilib guilib
xbmc/guilib/guiinfo guilib_guiinfo
+xbmc/guilib/handlers guilib_announcement_handlers
xbmc/guilib/listproviders guilib_listproviders
xbmc/imagefiles imagefiles
xbmc/messaging messaging
diff --git a/system/keymaps/customcontroller.Harmony.xml b/system/keymaps/customcontroller.Harmony.xml
index 77f288dfc2..98e3f21906 100644
--- a/system/keymaps/customcontroller.Harmony.xml
+++ b/system/keymaps/customcontroller.Harmony.xml
@@ -94,10 +94,10 @@
<!-- F8 --> <button id="196">ActivateWindow(FavouritesBrowser)</button>
<!-- F9 --> <button id="173">ShowVideoMenu</button>
<!-- F10 --> <button id="174">ShowSubtitles</button>
- <!-- F11 --> <button id="175">NextSubtitle</button>
+ <!-- F11 --> <button id="175">DialogSelectSubtitle</button>
<!-- F12 --> <button id="176">ActivateWindow(Videos)</button>
<!-- F13 --> <button id="163">Playlist</button>
- <!-- F14 --> <button id="164">AudioNextLanguage</button>
+ <!-- F14 --> <button id="164">DialogSelectAudio</button>
<!-- Large Down --> <button id="182">PageDown</button>
<!-- Large Up --> <button id="181">PageUp</button>
<!-- pwrToggle --> <button id="166">ShutDown()</button>
diff --git a/system/keymaps/keyboard.xml b/system/keymaps/keyboard.xml
index ac0033d7f8..4b69e9b8c3 100644
--- a/system/keymaps/keyboard.xml
+++ b/system/keymaps/keyboard.xml
@@ -371,7 +371,7 @@
<zoom>AspectRatio</zoom>
<t>ShowSubtitles</t>
<t mod="ctrl">SubtitleAlign</t>
- <l>NextSubtitle</l>
+ <l>DialogSelectSubtitle</l>
<left>StepBack</left>
<right>StepForward</right>
<up>ChapterOrBigStepForward</up>
@@ -381,11 +381,11 @@
<left mod="alt">PlayerControl(tempodown)</left>
<right mod="alt">PlayerControl(tempoup)</right>
<a>AudioDelay</a>
- <a mod="ctrl">AudioNextLanguage</a>
+ <a mod="ctrl">DialogSelectAudio</a>
<escape>Fullscreen</escape>
<c>Playlist</c>
<v>ActivateWindow(Teletext)</v>
- <v mod="ctrl">VideoNextStream</v>
+ <v mod="ctrl">DialogSelectVideo</v>
<text>ActivateWindow(Teletext)</text>
<up mod="ctrl">SubtitleShiftUp</up>
<down mod="ctrl">SubtitleShiftDown</down>
@@ -583,7 +583,7 @@
<z>AspectRatio</z>
<zoom>AspectRatio</zoom>
<t>ShowSubtitles</t>
- <l>NextSubtitle</l>
+ <l>DialogSelectSubtitle</l>
<a>AudioDelay</a>
<escape>Fullscreen</escape>
<return>Select</return>
diff --git a/system/keymaps/remote.xml b/system/keymaps/remote.xml
index 5c0baf7e9d..5306e94cb9 100644
--- a/system/keymaps/remote.xml
+++ b/system/keymaps/remote.xml
@@ -198,9 +198,9 @@
<info>Info</info>
<guide>ActivateWindow(TVGuide)</guide>
<teletext>ActivateWindow(Teletext)</teletext>
- <subtitle>NextSubtitle</subtitle>
+ <subtitle>DialogSelectSubtitle</subtitle>
<star>NextSubtitle</star>
- <language>AudioNextLanguage</language>
+ <language>DialogSelectAudio</language>
<playlist>Playlist</playlist>
<hash>AudioNextLanguage</hash>
<pageplus>SkipNext</pageplus>
diff --git a/xbmc/GUIInfoManager.cpp b/xbmc/GUIInfoManager.cpp
index 4bfc07d3d1..ee12786f60 100644
--- a/xbmc/GUIInfoManager.cpp
+++ b/xbmc/GUIInfoManager.cpp
@@ -3976,6 +3976,14 @@ const infomap musicplayer[] = {{ "title", MUSICPLAYER_TITLE },
/// @skinning_v20 **[New Infolabel]** \link VideoPlayer_AudioStreamCount `VideoPlayer.AudioStreamCount`\endlink
/// <p>
/// }
+/// \table_row3{ <b>`VideoPlayer.VideoStreamCount`</b>,
+/// \anchor VideoPlayer_VideoStreamCount
+/// _integer_,
+/// @return The number of video streams of the currently playing video.
+/// <p><hr>
+/// @skinning_v22 **[New Infolabel]** \link VideoPlayer_VideoStreamCount `VideoPlayer.VideoStreamCount`\endlink
+/// <p>
+/// }
/// \table_row3{ <b>`VideoPlayer.HdrType`</b>,
/// \anchor VideoPlayer_HdrType
/// _string_,
@@ -4086,6 +4094,7 @@ const infomap videoplayer[] = {{ "title", VIDEOPLAYER_TITLE },
{ "uniqueid", VIDEOPLAYER_UNIQUEID },
{ "tvshowdbid", VIDEOPLAYER_TVSHOWDBID },
{ "audiostreamcount", VIDEOPLAYER_AUDIOSTREAMCOUNT },
+ { "videostreamcount", VIDEOPLAYER_VIDEOSTREAMCOUNT },
{ "hdrtype", VIDEOPLAYER_HDR_TYPE },
{ "art", VIDEOPLAYER_ART},
{ "videoversionname", VIDEOPLAYER_VIDEOVERSION_NAME},
diff --git a/xbmc/Util.cpp b/xbmc/Util.cpp
index cd761165e3..de9dd6f8b4 100644
--- a/xbmc/Util.cpp
+++ b/xbmc/Util.cpp
@@ -2200,6 +2200,16 @@ ExternalStreamInfo CUtil::GetExternalStreamDetailsFromFilename(const std::string
info.flag |= StreamFlags::FLAG_FORCED;
continue;
}
+ else if (!flag_tmp.compare("original"))
+ {
+ info.flag |= StreamFlags::FLAG_ORIGINAL;
+ continue;
+ }
+ else if (!flag_tmp.compare("impaired"))
+ {
+ info.flag |= StreamFlags::FLAG_HEARING_IMPAIRED;
+ continue;
+ }
if (info.language.empty())
{
diff --git a/xbmc/addons/interfaces/Filesystem.cpp b/xbmc/addons/interfaces/Filesystem.cpp
index 9f22b67ecc..eb35cb7b54 100644
--- a/xbmc/addons/interfaces/Filesystem.cpp
+++ b/xbmc/addons/interfaces/Filesystem.cpp
@@ -151,8 +151,11 @@ unsigned int Interface_Filesystem::TranslateFileReadBitsToKodi(unsigned int addo
kodiFlags |= READ_AUDIO_VIDEO;
if (addonFlags & ADDON_READ_AFTER_WRITE)
kodiFlags |= READ_AFTER_WRITE;
- if (addonFlags & READ_REOPEN)
+ if (addonFlags & ADDON_READ_REOPEN)
kodiFlags |= READ_REOPEN;
+ //! @todo Add ADDON_READ_NO_BUFFER to filesystem.h in the binary addon devkit
+ if (addonFlags & READ_NO_BUFFER)
+ kodiFlags |= READ_NO_BUFFER;
return kodiFlags;
}
diff --git a/xbmc/addons/interfaces/gui/GUITranslator.cpp b/xbmc/addons/interfaces/gui/GUITranslator.cpp
index 2062f38667..bcc38b4815 100644
--- a/xbmc/addons/interfaces/gui/GUITranslator.cpp
+++ b/xbmc/addons/interfaces/gui/GUITranslator.cpp
@@ -552,6 +552,12 @@ int CAddonGUITranslator::TranslateActionIdToKodi(ADDON_ACTION addonId)
return ACTION_SHOW_SUBTITLES;
case ADDON_ACTION_NEXT_SUBTITLE:
return ACTION_NEXT_SUBTITLE;
+ case ADDON_ACTION_DIALOG_SELECT_VIDEO:
+ return ACTION_DIALOG_SELECT_VIDEO;
+ case ADDON_ACTION_DIALOG_SELECT_AUDIO:
+ return ACTION_DIALOG_SELECT_AUDIO;
+ case ADDON_ACTION_DIALOG_SELECT_SUBTITLE:
+ return ACTION_DIALOG_SELECT_SUBTITLE;
case ADDON_ACTION_PLAYER_DEBUG:
return ACTION_PLAYER_DEBUG;
case ADDON_ACTION_NEXT_PICTURE:
diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/input/action_ids.h b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/input/action_ids.h
index b7e8f9c6d2..0f779ce464 100644
--- a/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/input/action_ids.h
+++ b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/input/action_ids.h
@@ -677,6 +677,15 @@ enum ADDON_ACTION
/// @brief <b>`267`</b>: Tempo decrease in current file played. global action, can be used anywhere
ADDON_ACTION_PLAYER_DECREASE_TEMPO = 267,
+ /// @brief <b>`270 `</b>: Open the dialog window to select a video stream
+ ADDON_ACTION_DIALOG_SELECT_VIDEO = 270,
+
+ /// @brief <b>`271 `</b>: Open the dialog window to select a audio stream
+ ADDON_ACTION_DIALOG_SELECT_AUDIO = 271,
+
+ /// @brief <b>`272 `</b>: Open the dialog window to select a subtitle stream
+ ADDON_ACTION_DIALOG_SELECT_SUBTITLE = 272,
+
/// @brief <b>`300`</b>: Voice actions
ADDON_ACTION_VOICE_RECOGNIZE = 300,
diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/versions.h b/xbmc/addons/kodi-dev-kit/include/kodi/versions.h
index c4c45d6f95..34de2017ac 100644
--- a/xbmc/addons/kodi-dev-kit/include/kodi/versions.h
+++ b/xbmc/addons/kodi-dev-kit/include/kodi/versions.h
@@ -49,7 +49,7 @@
#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.15.0"
+#define ADDON_GLOBAL_VERSION_GUI "5.15.1"
#define ADDON_GLOBAL_VERSION_GUI_MIN "5.15.0"
#define ADDON_GLOBAL_VERSION_GUI_XML_ID "kodi.binary.global.gui"
#define ADDON_GLOBAL_VERSION_GUI_DEPENDS "c-api/gui/input/action_ids.h" \
diff --git a/xbmc/application/ApplicationPlayer.cpp b/xbmc/application/ApplicationPlayer.cpp
index 9a59242a85..a222557677 100644
--- a/xbmc/application/ApplicationPlayer.cpp
+++ b/xbmc/application/ApplicationPlayer.cpp
@@ -760,18 +760,18 @@ void CApplicationPlayer::LoadPage(int p, int sp, unsigned char* buffer)
player->LoadPage(p, sp, buffer);
}
-void CApplicationPlayer::GetAudioCapabilities(std::vector<int>& audioCaps) const
+void CApplicationPlayer::GetAudioCapabilities(std::vector<IPlayerAudioCaps>& caps) const
{
const std::shared_ptr<const IPlayer> player = GetInternal();
if (player)
- player->GetAudioCapabilities(audioCaps);
+ player->GetAudioCapabilities(caps);
}
-void CApplicationPlayer::GetSubtitleCapabilities(std::vector<int>& subCaps) const
+void CApplicationPlayer::GetSubtitleCapabilities(std::vector<IPlayerSubtitleCaps>& caps) const
{
const std::shared_ptr<const IPlayer> player = GetInternal();
if (player)
- player->GetSubtitleCapabilities(subCaps);
+ player->GetSubtitleCapabilities(caps);
}
int CApplicationPlayer::SeekChapter(int iChapter)
diff --git a/xbmc/application/ApplicationPlayer.h b/xbmc/application/ApplicationPlayer.h
index ccee506bd6..ae901d4058 100644
--- a/xbmc/application/ApplicationPlayer.h
+++ b/xbmc/application/ApplicationPlayer.h
@@ -83,7 +83,7 @@ public:
bool CanPause() const;
bool CanSeek() const;
int GetAudioDelay() const;
- void GetAudioCapabilities(std::vector<int>& audioCaps) const;
+ void GetAudioCapabilities(std::vector<IPlayerAudioCaps>& caps) const;
int GetAudioStream();
int GetAudioStreamCount() const;
void GetAudioStreamInfo(int index, AudioStreamInfo& info) const;
@@ -98,7 +98,7 @@ public:
KODI::PLAYLIST::Id GetPreferredPlaylist() const;
int GetSubtitleDelay() const;
int GetSubtitle();
- void GetSubtitleCapabilities(std::vector<int>& subCaps) const;
+ void GetSubtitleCapabilities(std::vector<IPlayerSubtitleCaps>& caps) const;
int GetSubtitleCount() const;
void GetSubtitleStreamInfo(int index, SubtitleStreamInfo& info) const;
bool GetSubtitleVisible() const;
diff --git a/xbmc/cores/IPlayer.h b/xbmc/cores/IPlayer.h
index d988d77527..8f6bd763bf 100644
--- a/xbmc/cores/IPlayer.h
+++ b/xbmc/cores/IPlayer.h
@@ -50,22 +50,24 @@ public:
class CFileItem;
-enum IPlayerAudioCapabilities
+// \brief Player Audio capabilities
+enum class IPlayerAudioCaps
{
- IPC_AUD_ALL,
- IPC_AUD_OFFSET,
- IPC_AUD_AMP,
- IPC_AUD_SELECT_STREAM,
- IPC_AUD_OUTPUT_STEREO,
- IPC_AUD_SELECT_OUTPUT
+ ALL, // All capabilities supported
+ SELECT_STREAM, // Support to change stream
+ SELECT_OUTPUT, // Support to select an output device
+ OUTPUT_STEREO, // Support output in stereo mode
+ OFFSET, // Support to change sync offset
+ VOLUME_AMP, // Support volume amplification
};
-enum IPlayerSubtitleCapabilities
+// \brief Player Subtitle capabilities
+enum class IPlayerSubtitleCaps
{
- IPC_SUBS_ALL,
- IPC_SUBS_SELECT,
- IPC_SUBS_EXTERNAL,
- IPC_SUBS_OFFSET
+ ALL, // All capabilities supported
+ SELECT_STREAM, // Support to change stream
+ EXTERNAL, // Support to load external subtitles
+ OFFSET, // Support to change sync offset
};
enum ERENDERFEATURE
@@ -211,16 +213,20 @@ public:
virtual std::string GetPlayerState() { return ""; }
virtual bool SetPlayerState(const std::string& state) { return false; }
- virtual void GetAudioCapabilities(std::vector<int>& audioCaps) const
+ /*!
+ * \brief Define the audio capabilities of the player
+ */
+ virtual void GetAudioCapabilities(std::vector<IPlayerAudioCaps>& caps) const
{
- audioCaps.assign(1, IPC_AUD_ALL);
+ caps.assign(1, IPlayerAudioCaps::ALL);
}
+
/*!
- \brief define the subtitle capabilities of the player
+ * \brief Define the subtitle capabilities of the player
*/
- virtual void GetSubtitleCapabilities(std::vector<int>& subCaps) const
+ virtual void GetSubtitleCapabilities(std::vector<IPlayerSubtitleCaps>& caps) const
{
- subCaps.assign(1, IPC_SUBS_ALL);
+ caps.assign(1, IPlayerSubtitleCaps::ALL);
}
/*!
diff --git a/xbmc/cores/VideoPlayer/Interface/StreamInfo.h b/xbmc/cores/VideoPlayer/Interface/StreamInfo.h
index df67662e9b..924931e9b6 100644
--- a/xbmc/cores/VideoPlayer/Interface/StreamInfo.h
+++ b/xbmc/cores/VideoPlayer/Interface/StreamInfo.h
@@ -45,6 +45,7 @@ struct StreamInfo
std::string language;
std::string name;
std::string codecName;
+ std::string codecDesc;
StreamFlags flags = StreamFlags::FLAG_NONE;
protected:
@@ -60,7 +61,9 @@ struct AudioStreamInfo : StreamInfo
};
struct SubtitleStreamInfo : StreamInfo
-{};
+{
+ bool isExternal{false};
+};
struct VideoStreamInfo : StreamInfo
{
@@ -73,6 +76,8 @@ struct VideoStreamInfo : StreamInfo
std::string stereoMode;
int angles = 0;
StreamHdrType hdrType = StreamHdrType::HDR_TYPE_NONE;
+ uint32_t fpsRate{0};
+ uint32_t fpsScale{0};
};
struct ProgramInfo
diff --git a/xbmc/cores/VideoPlayer/VideoPlayer.cpp b/xbmc/cores/VideoPlayer/VideoPlayer.cpp
index 1deb7d2ba7..5a20ca0fff 100644
--- a/xbmc/cores/VideoPlayer/VideoPlayer.cpp
+++ b/xbmc/cores/VideoPlayer/VideoPlayer.cpp
@@ -454,6 +454,7 @@ void CSelectionStreams::Update(const std::shared_ptr<CDVDInputStream>& input,
AudioStreamInfo info = nav->GetAudioStreamInfo(i);
s.name = info.name;
s.codec = info.codecName;
+ s.codecDesc = info.codecDesc;
s.language = g_LangCodeExpander.ConvertToISO6392B(info.language);
s.channels = info.channels;
s.flags = info.flags;
@@ -472,6 +473,7 @@ void CSelectionStreams::Update(const std::shared_ptr<CDVDInputStream>& input,
SubtitleStreamInfo info = nav->GetSubtitleStreamInfo(i);
s.name = info.name;
+ s.codec = info.codecName;
s.flags = info.flags;
s.language = g_LangCodeExpander.ConvertToISO6392B(info.language);
Update(s);
@@ -535,17 +537,12 @@ void CSelectionStreams::Update(const std::shared_ptr<CDVDInputStream>& input,
s.stereo_mode = vstream->stereo_mode;
s.bitrate = vstream->iBitRate;
s.hdrType = vstream->hdr_type;
+ s.fpsRate = static_cast<uint32_t>(vstream->iFpsRate);
+ s.fpsScale = static_cast<uint32_t>(vstream->iFpsScale);
}
if(stream->type == STREAM_AUDIO)
{
- std::string type;
- type = static_cast<CDemuxStreamAudio*>(stream)->GetStreamType();
- if(type.length() > 0)
- {
- if(s.name.length() > 0)
- s.name += " - ";
- s.name += type;
- }
+ s.codecDesc = static_cast<CDemuxStreamAudio*>(stream)->GetStreamType();
s.channels = static_cast<CDemuxStreamAudio*>(stream)->iChannels;
s.bitrate = static_cast<CDemuxStreamAudio*>(stream)->iBitRate;
}
@@ -795,7 +792,8 @@ bool CVideoPlayer::OpenInputStream()
// find any available external subtitles
std::vector<std::string> filenames;
- if (!URIUtils::IsUPnP(m_item.GetPath()))
+ if (!URIUtils::IsUPnP(m_item.GetPath()) &&
+ !m_item.GetProperty("no-ext-subs-scan").asBoolean(false))
CUtil::ScanForExternalSubtitles(m_item.GetDynPath(), filenames);
// load any subtitles from file item
@@ -5297,6 +5295,8 @@ void CVideoPlayer::GetVideoStreamInfo(int streamId, VideoStreamInfo& info) const
info.stereoMode = s.stereo_mode;
info.flags = s.flags;
info.hdrType = s.hdrType;
+ info.fpsRate = s.fpsRate;
+ info.fpsScale = s.fpsScale;
}
int CVideoPlayer::GetVideoStreamCount() const
@@ -5342,6 +5342,7 @@ void CVideoPlayer::GetAudioStreamInfo(int index, AudioStreamInfo& info) const
info.bitrate = s.bitrate;
info.channels = s.channels;
info.codecName = s.codec;
+ info.codecDesc = s.codecDesc;
info.flags = s.flags;
}
@@ -5386,7 +5387,10 @@ void CVideoPlayer::GetSubtitleStreamInfo(int index, SubtitleStreamInfo& info) co
info.name += "(Invalid)";
info.language = s.language;
+ info.codecName = s.codec;
info.flags = s.flags;
+ info.isExternal = STREAM_SOURCE_MASK(s.source) == STREAM_SOURCE_DEMUX_SUB ||
+ STREAM_SOURCE_MASK(s.source) == STREAM_SOURCE_TEXT;
}
void CVideoPlayer::SetSubtitle(int iStream)
diff --git a/xbmc/cores/VideoPlayer/VideoPlayer.h b/xbmc/cores/VideoPlayer/VideoPlayer.h
index f340b85e83..1546505830 100644
--- a/xbmc/cores/VideoPlayer/VideoPlayer.h
+++ b/xbmc/cores/VideoPlayer/VideoPlayer.h
@@ -187,6 +187,7 @@ struct SelectionStream
int id = 0;
int64_t demuxerId = -1;
std::string codec;
+ std::string codecDesc;
int channels = 0;
int bitrate = 0;
int width = 0;
@@ -197,6 +198,8 @@ struct SelectionStream
std::string stereo_mode;
float aspect_ratio = 0.0f;
StreamHdrType hdrType = StreamHdrType::HDR_TYPE_NONE;
+ uint32_t fpsScale{0};
+ uint32_t fpsRate{0};
};
class CSelectionStreams
diff --git a/xbmc/cores/paplayer/PAPlayer.h b/xbmc/cores/paplayer/PAPlayer.h
index c2a77dd84a..ae7059bfd8 100644
--- a/xbmc/cores/paplayer/PAPlayer.h
+++ b/xbmc/cores/paplayer/PAPlayer.h
@@ -50,7 +50,7 @@ public:
void GetAudioStreamInfo(int index, AudioStreamInfo& info) const override;
void SetTime(int64_t time) override;
void SeekTime(int64_t iTime = 0) override;
- void GetAudioCapabilities(std::vector<int>& audioCaps) const override {}
+ void GetAudioCapabilities(std::vector<IPlayerAudioCaps>& caps) const override {}
int GetAudioStreamCount() const override { return 1; }
int GetAudioStream() override { return 0; }
diff --git a/xbmc/guilib/GUIComponent.cpp b/xbmc/guilib/GUIComponent.cpp
index 5c8b414fd8..449a85d073 100644
--- a/xbmc/guilib/GUIComponent.cpp
+++ b/xbmc/guilib/GUIComponent.cpp
@@ -18,6 +18,7 @@
#include "TextureManager.h"
#include "URL.h"
#include "dialogs/GUIDialogYesNo.h"
+#include "handlers/GUIAnnouncementHandlerContainer.h"
#include <memory>
@@ -28,7 +29,8 @@ CGUIComponent::CGUIComponent()
m_stereoscopicsManager(std::make_unique<CStereoscopicsManager>()),
m_guiInfoManager(std::make_unique<CGUIInfoManager>()),
m_guiColorManager(std::make_unique<CGUIColorManager>()),
- m_guiAudioManager(std::make_unique<CGUIAudioManager>())
+ m_guiAudioManager(std::make_unique<CGUIAudioManager>()),
+ m_announcementHandlerContainer(std::make_unique<CGUIAnnouncementHandlerContainer>())
{
}
diff --git a/xbmc/guilib/GUIComponent.h b/xbmc/guilib/GUIComponent.h
index b7eb75c58a..2e3e7aadff 100644
--- a/xbmc/guilib/GUIComponent.h
+++ b/xbmc/guilib/GUIComponent.h
@@ -18,6 +18,7 @@ class CStereoscopicsManager;
class CGUIInfoManager;
class CGUIColorManager;
class CGUIAudioManager;
+class CGUIAnnouncementHandlerContainer;
class CGUIComponent
{
@@ -47,4 +48,5 @@ protected:
std::unique_ptr<CGUIInfoManager> m_guiInfoManager;
std::unique_ptr<CGUIColorManager> m_guiColorManager;
std::unique_ptr<CGUIAudioManager> m_guiAudioManager;
+ std::unique_ptr<CGUIAnnouncementHandlerContainer> m_announcementHandlerContainer;
};
diff --git a/xbmc/guilib/GUIWindowManager.cpp b/xbmc/guilib/GUIWindowManager.cpp
index 065a68cbb8..2999fb4960 100644
--- a/xbmc/guilib/GUIWindowManager.cpp
+++ b/xbmc/guilib/GUIWindowManager.cpp
@@ -299,6 +299,9 @@ void CGUIWindowManager::CreateWindows()
Add(new CGUIDialogVideoManagerExtras);
Add(new CGUIDialogSelect(WINDOW_DIALOG_SELECT_VIDEO_VERSION));
Add(new CGUIDialogSelect(WINDOW_DIALOG_SELECT_VIDEO_EXTRA));
+ Add(new CGUIDialogSelect(WINDOW_DIALOG_SELECT_VIDEO_STREAM));
+ Add(new CGUIDialogSelect(WINDOW_DIALOG_SELECT_AUDIO_STREAM));
+ Add(new CGUIDialogSelect(WINDOW_DIALOG_SELECT_SUBTITLE_STREAM));
Add(new CGUIDialogTextViewer);
Add(new CGUIWindowFullScreen);
@@ -386,6 +389,9 @@ bool CGUIWindowManager::DestroyWindows()
DestroyWindow(WINDOW_DIALOG_SLIDER);
DestroyWindow(WINDOW_DIALOG_MEDIA_FILTER);
DestroyWindow(WINDOW_DIALOG_SUBTITLES);
+ DestroyWindow(WINDOW_DIALOG_SELECT_VIDEO_STREAM);
+ DestroyWindow(WINDOW_DIALOG_SELECT_AUDIO_STREAM);
+ DestroyWindow(WINDOW_DIALOG_SELECT_SUBTITLE_STREAM);
DestroyWindow(WINDOW_DIALOG_COLOR_PICKER);
/* Delete PVR related windows and dialogs */
diff --git a/xbmc/guilib/WindowIDs.h b/xbmc/guilib/WindowIDs.h
index 40e4724543..318569115b 100644
--- a/xbmc/guilib/WindowIDs.h
+++ b/xbmc/guilib/WindowIDs.h
@@ -180,6 +180,10 @@
#define WINDOW_DIALOG_SELECT_VIDEO_EXTRA 12016
#define WINDOW_DIALOG_MANAGE_VIDEO_EXTRAS 12017
+#define WINDOW_DIALOG_SELECT_VIDEO_STREAM 12300
+#define WINDOW_DIALOG_SELECT_AUDIO_STREAM 12301
+#define WINDOW_DIALOG_SELECT_SUBTITLE_STREAM 12302
+
#define WINDOW_WEATHER 12600
#define WINDOW_SCREENSAVER 12900
#define WINDOW_DIALOG_VIDEO_OSD 12901
diff --git a/xbmc/guilib/guiinfo/GUIInfoLabels.h b/xbmc/guilib/guiinfo/GUIInfoLabels.h
index 613aff347f..3138987c6a 100644
--- a/xbmc/guilib/guiinfo/GUIInfoLabels.h
+++ b/xbmc/guilib/guiinfo/GUIInfoLabels.h
@@ -281,6 +281,7 @@
#define VIDEOPLAYER_UNIQUEID 294
#define VIDEOPLAYER_AUDIOSTREAMCOUNT 295
#define VIDEOPLAYER_VIDEOVERSION_NAME 296
+#define VIDEOPLAYER_VIDEOSTREAMCOUNT 297
// Videoplayer infobools
#define VIDEOPLAYER_HASSUBTITLES 300
diff --git a/xbmc/guilib/guiinfo/VideoGUIInfo.cpp b/xbmc/guilib/guiinfo/VideoGUIInfo.cpp
index 0a112ea3ef..406cc06793 100644
--- a/xbmc/guilib/guiinfo/VideoGUIInfo.cpp
+++ b/xbmc/guilib/guiinfo/VideoGUIInfo.cpp
@@ -759,6 +759,9 @@ bool CVideoGUIInfo::GetInt(int& value, const CGUIListItem *gitem, int contextWin
///////////////////////////////////////////////////////////////////////////////////////////////
// VIDEOPLAYER_*
///////////////////////////////////////////////////////////////////////////////////////////////
+ case VIDEOPLAYER_VIDEOSTREAMCOUNT:
+ value = m_appPlayer->GetVideoStreamCount();
+ return true;
case VIDEOPLAYER_AUDIOSTREAMCOUNT:
value = m_appPlayer->GetAudioStreamCount();
return true;
diff --git a/xbmc/guilib/handlers/CMakeLists.txt b/xbmc/guilib/handlers/CMakeLists.txt
new file mode 100644
index 0000000000..fc052e35df
--- /dev/null
+++ b/xbmc/guilib/handlers/CMakeLists.txt
@@ -0,0 +1,7 @@
+set(SOURCES GUIAnnouncementHandlerContainer.cpp
+ sources/GUISourcesAnnouncementHandler.cpp)
+
+set(HEADERS GUIAnnouncementHandlerContainer.h
+ sources/GUISourcesAnnouncementHandler.h)
+
+core_add_library(guilib_announcement_handlers)
diff --git a/xbmc/guilib/handlers/GUIAnnouncementHandlerContainer.cpp b/xbmc/guilib/handlers/GUIAnnouncementHandlerContainer.cpp
new file mode 100644
index 0000000000..f7a5fbae4a
--- /dev/null
+++ b/xbmc/guilib/handlers/GUIAnnouncementHandlerContainer.cpp
@@ -0,0 +1,16 @@
+/*
+ * Copyright (C) 2024 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 "GUIAnnouncementHandlerContainer.h"
+
+#include "sources/GUISourcesAnnouncementHandler.h"
+
+CGUIAnnouncementHandlerContainer::CGUIAnnouncementHandlerContainer()
+{
+ m_announcementHandlers.emplace_back(std::make_unique<CGUISourcesAnnouncementHandler>());
+}
diff --git a/xbmc/guilib/handlers/GUIAnnouncementHandlerContainer.h b/xbmc/guilib/handlers/GUIAnnouncementHandlerContainer.h
new file mode 100644
index 0000000000..40122c5dbb
--- /dev/null
+++ b/xbmc/guilib/handlers/GUIAnnouncementHandlerContainer.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2024 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 "interfaces/IAnnouncer.h"
+
+#include <memory>
+#include <vector>
+
+/*!
+\brief This class is a container of announcement handlers per application component. It allows the GUI Layer
+to execute GUI Actions upon receiving announcements from other components effectively decoupling GUI
+from other components.
+*/
+class CGUIAnnouncementHandlerContainer final
+{
+public:
+ CGUIAnnouncementHandlerContainer();
+ ~CGUIAnnouncementHandlerContainer() = default;
+
+private:
+ std::vector<std::unique_ptr<ANNOUNCEMENT::IAnnouncer>> m_announcementHandlers;
+};
diff --git a/xbmc/guilib/handlers/sources/GUISourcesAnnouncementHandler.cpp b/xbmc/guilib/handlers/sources/GUISourcesAnnouncementHandler.cpp
new file mode 100644
index 0000000000..251f0e14ec
--- /dev/null
+++ b/xbmc/guilib/handlers/sources/GUISourcesAnnouncementHandler.cpp
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2024 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 "GUISourcesAnnouncementHandler.h"
+
+#include "GUIUserMessages.h"
+#include "ServiceBroker.h"
+#include "guilib/GUIComponent.h"
+#include "guilib/GUIWindowManager.h"
+#include "interfaces/AnnouncementManager.h"
+
+CGUISourcesAnnouncementHandler::CGUISourcesAnnouncementHandler()
+{
+ CServiceBroker::GetAnnouncementManager()->AddAnnouncer(this);
+}
+
+CGUISourcesAnnouncementHandler::~CGUISourcesAnnouncementHandler()
+{
+ CServiceBroker::GetAnnouncementManager()->RemoveAnnouncer(this);
+}
+
+void CGUISourcesAnnouncementHandler::Announce(ANNOUNCEMENT::AnnouncementFlag flag,
+ const std::string& sender,
+ const std::string& message,
+ const CVariant& data)
+{
+ // We are only interested in sources changes
+ if ((flag & ANNOUNCEMENT::Sources) == 0)
+ return;
+
+ if (message == "OnAdded" || message == "OnRemoved" || message == "OnUpdated")
+ {
+ CGUIMessage message(GUI_MSG_NOTIFY_ALL, 0, 0, GUI_MSG_UPDATE_PATH);
+ message.SetStringParam(data.asString());
+ CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(message);
+ }
+}
diff --git a/xbmc/guilib/handlers/sources/GUISourcesAnnouncementHandler.h b/xbmc/guilib/handlers/sources/GUISourcesAnnouncementHandler.h
new file mode 100644
index 0000000000..0ec166fdf1
--- /dev/null
+++ b/xbmc/guilib/handlers/sources/GUISourcesAnnouncementHandler.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2024 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 "interfaces/IAnnouncer.h"
+
+/*!
+\brief Handler for announcements of type sources
+*/
+class CGUISourcesAnnouncementHandler : public ANNOUNCEMENT::IAnnouncer
+{
+public:
+ CGUISourcesAnnouncementHandler();
+ ~CGUISourcesAnnouncementHandler();
+
+ void Announce(ANNOUNCEMENT::AnnouncementFlag flag,
+ const std::string& sender,
+ const std::string& message,
+ const CVariant& data) override;
+};
diff --git a/xbmc/input/WindowTranslator.cpp b/xbmc/input/WindowTranslator.cpp
index 795c854f0f..9eeaceb63f 100644
--- a/xbmc/input/WindowTranslator.cpp
+++ b/xbmc/input/WindowTranslator.cpp
@@ -177,6 +177,9 @@ const CWindowTranslator::WindowMapByName CWindowTranslator::WindowMappingByName
{"ingamesaves", WINDOW_DIALOG_IN_GAME_SAVES},
{"gamesaves", WINDOW_DIALOG_GAME_SAVES},
{"gameagents", WINDOW_DIALOG_GAME_AGENTS},
+ {"videoselectdialog", WINDOW_DIALOG_SELECT_VIDEO_STREAM},
+ {"audioselectdialog", WINDOW_DIALOG_SELECT_AUDIO_STREAM},
+ {"subtitleselectdialog", WINDOW_DIALOG_SELECT_SUBTITLE_STREAM},
};
namespace
diff --git a/xbmc/input/actions/ActionIDs.h b/xbmc/input/actions/ActionIDs.h
index ddd0d44cb6..11f9ed251d 100644
--- a/xbmc/input/actions/ActionIDs.h
+++ b/xbmc/input/actions/ActionIDs.h
@@ -458,6 +458,15 @@ constexpr const int ACTION_KEYBOARD_COMPOSING_KEY_FINISHED = 265;
constexpr const int ACTION_PLAYER_INCREASE_TEMPO = 266;
constexpr const int ACTION_PLAYER_DECREASE_TEMPO = 267;
+//! Open the dialog window to select a video stream
+constexpr const int ACTION_DIALOG_SELECT_VIDEO = 270;
+
+//! Open the dialog window to select a audio stream
+constexpr const int ACTION_DIALOG_SELECT_AUDIO = 271;
+
+//! Open the dialog window to select a subtitle stream
+constexpr const int ACTION_DIALOG_SELECT_SUBTITLE = 272;
+
// Voice actions
constexpr const int ACTION_VOICE_RECOGNIZE = 300;
diff --git a/xbmc/input/actions/ActionTranslator.cpp b/xbmc/input/actions/ActionTranslator.cpp
index c47ee6b305..7233418115 100644
--- a/xbmc/input/actions/ActionTranslator.cpp
+++ b/xbmc/input/actions/ActionTranslator.cpp
@@ -55,6 +55,9 @@ static const std::map<ActionName, ActionID> ActionMappings = {
{"nextsubtitle", ACTION_NEXT_SUBTITLE},
{"browsesubtitle", ACTION_BROWSE_SUBTITLE},
{"cyclesubtitle", ACTION_CYCLE_SUBTITLE},
+ {"dialogselectvideo", ACTION_DIALOG_SELECT_VIDEO},
+ {"dialogselectaudio", ACTION_DIALOG_SELECT_AUDIO},
+ {"dialogselectsubtitle", ACTION_DIALOG_SELECT_SUBTITLE},
{"playerdebug", ACTION_PLAYER_DEBUG},
{"playerdebugvideo", ACTION_PLAYER_DEBUG_VIDEO},
{"codecinfo", ACTION_PLAYER_PROCESS_INFO},
diff --git a/xbmc/interfaces/IAnnouncer.h b/xbmc/interfaces/IAnnouncer.h
index 7c20203573..513fb25937 100644
--- a/xbmc/interfaces/IAnnouncer.h
+++ b/xbmc/interfaces/IAnnouncer.h
@@ -13,33 +13,35 @@
class CVariant;
namespace ANNOUNCEMENT
{
- enum AnnouncementFlag
- {
- Player = 0x001,
- Playlist = 0x002,
- GUI = 0x004,
- System = 0x008,
- VideoLibrary = 0x010,
- AudioLibrary = 0x020,
- Application = 0x040,
- Input = 0x080,
- PVR = 0x100,
- Other = 0x200,
- Info = 0x400
- };
+enum AnnouncementFlag
+{
+ Player = 0x001,
+ Playlist = 0x002,
+ GUI = 0x004,
+ System = 0x008,
+ VideoLibrary = 0x010,
+ AudioLibrary = 0x020,
+ Application = 0x040,
+ Input = 0x080,
+ PVR = 0x100,
+ Other = 0x200,
+ Info = 0x400,
+ Sources = 0x800
+};
- const auto ANNOUNCE_ALL = (Player | Playlist | GUI | System | VideoLibrary | AudioLibrary | Application | Input | ANNOUNCEMENT::PVR | Other);
+const auto ANNOUNCE_ALL = (Player | Playlist | GUI | System | VideoLibrary | AudioLibrary |
+ Application | Input | ANNOUNCEMENT::PVR | Other);
- /*!
+/*!
\brief Returns a string representation for the
given AnnouncementFlag
\param notification Specific AnnouncementFlag
\return String representation of the given AnnouncementFlag
*/
- inline const char *AnnouncementFlagToString(const AnnouncementFlag &notification)
+inline const char* AnnouncementFlagToString(const AnnouncementFlag& notification)
+{
+ switch (notification)
{
- switch (notification)
- {
case Player:
return "Player";
case Playlist:
@@ -62,10 +64,12 @@ namespace ANNOUNCEMENT
return "Other";
case Info:
return "Info";
+ case Sources:
+ return "Sources";
default:
return "Unknown";
- }
}
+}
class IAnnouncer
{
diff --git a/xbmc/network/ZeroconfBrowser.h b/xbmc/network/ZeroconfBrowser.h
index 76a4439a11..7f104eabc5 100644
--- a/xbmc/network/ZeroconfBrowser.h
+++ b/xbmc/network/ZeroconfBrowser.h
@@ -89,8 +89,7 @@ public:
void Stop();
///returns the list of found services
- /// if this is updated, the following message with "zeroconf://" as path is sent:
- /// CGUIMessage message(GUI_MSG_NOTIFY_ALL, 0, 0, GUI_MSG_UPDATE_PATH);
+ /// if this is updated, a source update announcement with "zeroconf://" as path is sent:
std::vector<ZeroconfService> GetFoundServices();
///@}
diff --git a/xbmc/network/mdns/ZeroconfBrowserMDNS.cpp b/xbmc/network/mdns/ZeroconfBrowserMDNS.cpp
index c4a1c1ecab..9546dcc6b5 100644
--- a/xbmc/network/mdns/ZeroconfBrowserMDNS.cpp
+++ b/xbmc/network/mdns/ZeroconfBrowserMDNS.cpp
@@ -8,11 +8,8 @@
#include "ZeroconfBrowserMDNS.h"
-#include "GUIUserMessages.h"
#include "ServiceBroker.h"
-#include "guilib/GUIComponent.h"
-#include "guilib/GUIMessage.h"
-#include "guilib/GUIWindowManager.h"
+#include "interfaces/AnnouncementManager.h"
#include "network/DNSNameCache.h"
#include "utils/log.h"
@@ -88,10 +85,11 @@ void DNSSD_API CZeroconfBrowserMDNS::BrowserCallback(DNSServiceRef browser,
}
if(! (flags & kDNSServiceFlagsMoreComing) )
{
- CGUIMessage message(GUI_MSG_NOTIFY_ALL, 0, 0, GUI_MSG_UPDATE_PATH);
- message.SetStringParam("zeroconf://");
- CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(message);
- CLog::Log(LOGDEBUG, "ZeroconfBrowserMDNS::BrowserCallback sent gui update for path zeroconf://");
+ CServiceBroker::GetAnnouncementManager()->Announce(ANNOUNCEMENT::Sources, "OnUpdated",
+ CVariant{"zeroconf://"});
+ CLog::Log(
+ LOGDEBUG,
+ "ZeroconfBrowserMDNS::BrowserCallback sent source update announce for path zeroconf://");
}
}
else
diff --git a/xbmc/network/upnp/UPnP.cpp b/xbmc/network/upnp/UPnP.cpp
index 2acfc55069..371efbace2 100644
--- a/xbmc/network/upnp/UPnP.cpp
+++ b/xbmc/network/upnp/UPnP.cpp
@@ -13,7 +13,6 @@
#include "UPnP.h"
#include "FileItem.h"
-#include "GUIUserMessages.h"
#include "ServiceBroker.h"
#include "UPnPInternal.h"
#include "UPnPRenderer.h"
@@ -21,8 +20,7 @@
#include "UPnPSettings.h"
#include "URL.h"
#include "cores/playercorefactory/PlayerCoreFactory.h"
-#include "guilib/GUIComponent.h"
-#include "guilib/GUIWindowManager.h"
+#include "interfaces/AnnouncementManager.h"
#include "messaging/ApplicationMessenger.h"
#include "network/Network.h"
#include "profiles/ProfileManager.h"
@@ -171,19 +169,15 @@ public:
// PLT_MediaBrowser methods
bool OnMSAdded(PLT_DeviceDataReference& device) override
{
- CGUIMessage message(GUI_MSG_NOTIFY_ALL, 0, 0, GUI_MSG_UPDATE_PATH);
- message.SetStringParam("upnp://");
- CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(message);
+ CServiceBroker::GetAnnouncementManager()->Announce(ANNOUNCEMENT::Sources, "OnAdded",
+ CVariant{"upnp://"});
return PLT_SyncMediaBrowser::OnMSAdded(device);
}
void OnMSRemoved(PLT_DeviceDataReference& device) override
{
- PLT_SyncMediaBrowser::OnMSRemoved(device);
-
- CGUIMessage message(GUI_MSG_NOTIFY_ALL, 0, 0, GUI_MSG_UPDATE_PATH);
- message.SetStringParam("upnp://");
- CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(message);
+ CServiceBroker::GetAnnouncementManager()->Announce(ANNOUNCEMENT::Sources, "OnRemoved",
+ CVariant{"upnp://"});
PLT_SyncMediaBrowser::OnMSRemoved(device);
}
@@ -202,9 +196,8 @@ public:
}
m_logger->debug("notified container update {}", (const char*)path);
- CGUIMessage message(GUI_MSG_NOTIFY_ALL, 0, 0, GUI_MSG_UPDATE_PATH);
- message.SetStringParam(path.GetChars());
- CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(message);
+ CServiceBroker::GetAnnouncementManager()->Announce(ANNOUNCEMENT::Sources, "OnUpdated",
+ CVariant{path.GetChars()});
}
bool MarkWatched(const CFileItem& item, const bool watched)
diff --git a/xbmc/network/upnp/UPnPRenderer.cpp b/xbmc/network/upnp/UPnPRenderer.cpp
index acf6296d3b..196824fbee 100644
--- a/xbmc/network/upnp/UPnPRenderer.cpp
+++ b/xbmc/network/upnp/UPnPRenderer.cpp
@@ -686,6 +686,7 @@ NPT_Result CUPnPRenderer::PlayMedia(const NPT_String& uri,
}
else
{
+ item->SetProperty("no-ext-subs-scan", true);
CFileItemList* l = new CFileItemList; //don't delete,
l->Add(std::make_shared<CFileItem>(*item));
CServiceBroker::GetAppMessenger()->PostMsg(TMSG_MEDIA_PLAY, -1, -1, static_cast<void*>(l));
diff --git a/xbmc/platform/android/network/ZeroconfBrowserAndroid.cpp b/xbmc/platform/android/network/ZeroconfBrowserAndroid.cpp
index dd6db2576b..d31564f5ea 100644
--- a/xbmc/platform/android/network/ZeroconfBrowserAndroid.cpp
+++ b/xbmc/platform/android/network/ZeroconfBrowserAndroid.cpp
@@ -8,11 +8,8 @@
#include "ZeroconfBrowserAndroid.h"
-#include "GUIUserMessages.h"
#include "ServiceBroker.h"
-#include "guilib/GUIComponent.h"
-#include "guilib/GUIMessage.h"
-#include "guilib/GUIWindowManager.h"
+#include "interfaces/AnnouncementManager.h"
#include "network/DNSNameCache.h"
#include "utils/log.h"
@@ -241,10 +238,10 @@ void CZeroconfBrowserAndroidDiscover::onServiceFound(const jni::CJNINsdServiceIn
s.GetName(), s.GetType(), s.GetDomain());
m_browser->addDiscoveredService(this, s);
- CGUIMessage message(GUI_MSG_NOTIFY_ALL, 0, 0, GUI_MSG_UPDATE_PATH);
- message.SetStringParam("zeroconf://");
- CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(message);
- CLog::Log(LOGDEBUG, "CZeroconfBrowserAndroidDiscover::onServiceFound sent gui update for path zeroconf://");
+ CServiceBroker::GetAnnouncementManager()->Announce(ANNOUNCEMENT::Sources, "OnUpdated",
+ CVariant{"zeroconf://"});
+ CLog::Log(LOGDEBUG, "CZeroconfBrowserAndroidDiscover::onServiceFound sent source update announce "
+ "for path zeroconf://");
}
void CZeroconfBrowserAndroidDiscover::onServiceLost(const jni::CJNINsdServiceInfo& serviceInfo)
diff --git a/xbmc/platform/darwin/network/ZeroconfBrowserDarwin.cpp b/xbmc/platform/darwin/network/ZeroconfBrowserDarwin.cpp
index 50515d0879..e2078a3520 100644
--- a/xbmc/platform/darwin/network/ZeroconfBrowserDarwin.cpp
+++ b/xbmc/platform/darwin/network/ZeroconfBrowserDarwin.cpp
@@ -8,11 +8,8 @@
#include "ZeroconfBrowserDarwin.h"
-#include "GUIUserMessages.h"
#include "ServiceBroker.h"
-#include "guilib/GUIComponent.h"
-#include "guilib/GUIMessage.h"
-#include "guilib/GUIWindowManager.h"
+#include "interfaces/AnnouncementManager.h"
#include "utils/log.h"
#include "platform/darwin/DarwinUtils.h"
@@ -168,10 +165,10 @@ void CZeroconfBrowserDarwin::BrowserCallback(CFNetServiceBrowserRef browser, CFO
}
if (! (flags & kCFNetServiceFlagMoreComing) )
{
- CGUIMessage message(GUI_MSG_NOTIFY_ALL, 0, 0, GUI_MSG_UPDATE_PATH);
- message.SetStringParam("zeroconf://");
- CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(message);
- CLog::Log(LOGDEBUG, "CZeroconfBrowserDarwin::BrowserCallback sent gui update for path zeroconf://");
+ CServiceBroker::GetAnnouncementManager()->Announce(ANNOUNCEMENT::Sources, "OnUpdated",
+ CVariant{"zeroconf://"});
+ CLog::Log(LOGDEBUG, "CZeroconfBrowserDarwin::BrowserCallback sent sources update "
+ "announcement for path zeroconf://");
}
} else
{
diff --git a/xbmc/pvr/addons/PVRClient.cpp b/xbmc/pvr/addons/PVRClient.cpp
index 8d56392567..4e1fca84b9 100644
--- a/xbmc/pvr/addons/PVRClient.cpp
+++ b/xbmc/pvr/addons/PVRClient.cpp
@@ -269,7 +269,8 @@ public:
prop.iKey = entry.first;
prop.eType = entry.second.type;
prop.iValue = entry.second.value.asInteger32();
- prop.strValue = entry.second.value.asString().c_str();
+ m_customPropStringValues.emplace_back(entry.second.value.asString());
+ prop.strValue = m_customPropStringValues.back().c_str();
++idx;
}
customProps = m_customProps.get();
@@ -283,6 +284,7 @@ private:
const std::string m_directory;
const std::string m_summary;
const std::string m_seriesLink;
+ std::vector<std::string> m_customPropStringValues;
std::unique_ptr<PVR_SETTING_KEY_VALUE_PAIR[]> m_customProps;
};
diff --git a/xbmc/video/PlayerController.cpp b/xbmc/video/PlayerController.cpp
index 35025c517b..ace0f0a637 100644
--- a/xbmc/video/PlayerController.cpp
+++ b/xbmc/video/PlayerController.cpp
@@ -31,6 +31,7 @@
#include "utils/StringUtils.h"
#include "utils/Variant.h"
#include "video/dialogs/GUIDialogAudioSettings.h"
+#include "video/guilib/VideoStreamSelectHelper.h"
using namespace KODI;
using namespace UTILS;
@@ -141,6 +142,12 @@ bool CPlayerController::OnAction(const CAction &action)
return true;
}
+ case ACTION_DIALOG_SELECT_SUBTITLE:
+ {
+ VIDEO::GUILIB::OpenDialogSelectSubtitleStream();
+ return true;
+ }
+
case ACTION_SUBTITLE_DELAY_MIN:
{
float videoSubsDelayRange = CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_videoSubsDelayRange;
@@ -224,19 +231,29 @@ bool CPlayerController::OnAction(const CAction &action)
if (++currentAudio >= audioStreamCount)
currentAudio = 0;
appPlayer->SetAudioStream(currentAudio); // Set the audio stream to the one selected
- std::string aud;
+
std::string lan;
AudioStreamInfo info;
appPlayer->GetAudioStreamInfo(currentAudio, info);
if (!g_LangCodeExpander.Lookup(info.language, lan))
lan = g_localizeStrings.Get(13205); // Unknown
- if (info.name.empty())
- aud = lan;
- else
- aud = StringUtils::Format("{} - {}", lan, info.name);
+
+ std::string textInfo = lan;
+ if (!info.name.empty())
+ textInfo += " - " + info.name;
+ if (!info.codecDesc.empty())
+ textInfo += " (" + info.codecDesc + ")";
+
std::string caption = g_localizeStrings.Get(460);
caption += StringUtils::Format(" ({}/{})", currentAudio + 1, audioStreamCount);
- CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Info, caption, aud, DisplTime, false, MsgTime);
+ CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Info, caption, textInfo,
+ DisplTime, false, MsgTime);
+ return true;
+ }
+
+ case ACTION_DIALOG_SELECT_AUDIO:
+ {
+ VIDEO::GUILIB::OpenDialogSelectAudioStream();
return true;
}
@@ -259,6 +276,12 @@ bool CPlayerController::OnAction(const CAction &action)
return true;
}
+ case ACTION_DIALOG_SELECT_VIDEO:
+ {
+ VIDEO::GUILIB::OpenDialogSelectVideoStream();
+ return true;
+ }
+
case ACTION_ZOOM_IN:
{
CVideoSettings vs = appPlayer->GetVideoSettings();
diff --git a/xbmc/video/VideoDatabase.cpp b/xbmc/video/VideoDatabase.cpp
index f333bb334b..20b8724977 100644
--- a/xbmc/video/VideoDatabase.cpp
+++ b/xbmc/video/VideoDatabase.cpp
@@ -4994,6 +4994,8 @@ void CVideoDatabase::SetArtForItem(int mediaId, const MediaType &mediaType, cons
sql = PrepareSQL("INSERT INTO art(media_id, media_type, type, url) VALUES (%d, '%s', '%s', '%s')", mediaId, mediaType.c_str(), artType.c_str(), url.c_str());
m_pDS->exec(sql);
}
+
+ AnnounceUpdate(mediaType, mediaId);
}
catch (...)
{
diff --git a/xbmc/video/dialogs/GUIDialogAudioSettings.cpp b/xbmc/video/dialogs/GUIDialogAudioSettings.cpp
index 9c8b1b10ff..e8371ffa3b 100644
--- a/xbmc/video/dialogs/GUIDialogAudioSettings.cpp
+++ b/xbmc/video/dialogs/GUIDialogAudioSettings.cpp
@@ -263,7 +263,7 @@ void CGUIDialogAudioSettings::InitializeSettings()
std::static_pointer_cast<CSettingControlSlider>(settingAudioVolume->GetControl())->SetFormatter(SettingFormatterPercentAsDecibel);
// audio volume amplification setting
- if (SupportsAudioFeature(IPC_AUD_AMP))
+ if (SupportsAudioFeature(IPlayerAudioCaps::VOLUME_AMP))
{
std::shared_ptr<CSettingNumber> settingAudioVolumeAmplification = AddSlider(groupAudio, SETTING_AUDIO_VOLUME_AMPLIFICATION, 660, SettingLevel::Basic, videoSettings.m_VolumeAmplification, 14054, VOLUME_DRC_MINIMUM * 0.01f, (VOLUME_DRC_MAXIMUM - VOLUME_DRC_MINIMUM) / 6000.0f, VOLUME_DRC_MAXIMUM * 0.01f);
settingAudioVolumeAmplification->SetDependencies(depsAudioOutputPassthroughDisabled);
@@ -277,7 +277,7 @@ void CGUIDialogAudioSettings::InitializeSettings()
}
// audio delay setting
- if (SupportsAudioFeature(IPC_AUD_OFFSET))
+ if (SupportsAudioFeature(IPlayerAudioCaps::OFFSET))
{
std::shared_ptr<CSettingNumber> settingAudioDelay = AddSlider(
groupAudio, SETTING_AUDIO_DELAY, 297, SettingLevel::Basic, videoSettings.m_AudioDelay, 0,
@@ -289,11 +289,11 @@ void CGUIDialogAudioSettings::InitializeSettings()
}
// audio stream setting
- if (SupportsAudioFeature(IPC_AUD_SELECT_STREAM))
+ if (SupportsAudioFeature(IPlayerAudioCaps::SELECT_STREAM))
AddAudioStreams(groupAudio, SETTING_AUDIO_STREAM);
// audio digital/analog setting
- if (SupportsAudioFeature(IPC_AUD_SELECT_OUTPUT))
+ if (SupportsAudioFeature(IPlayerAudioCaps::SELECT_OUTPUT))
{
m_passthrough = CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(CSettings::SETTING_AUDIOOUTPUT_PASSTHROUGH);
AddToggle(groupAudio, SETTING_AUDIO_PASSTHROUGH, 348, SettingLevel::Basic, m_passthrough);
@@ -303,11 +303,11 @@ void CGUIDialogAudioSettings::InitializeSettings()
AddButton(groupSaveAsDefault, SETTING_AUDIO_MAKE_DEFAULT, 12376, SettingLevel::Basic);
}
-bool CGUIDialogAudioSettings::SupportsAudioFeature(int feature)
+bool CGUIDialogAudioSettings::SupportsAudioFeature(IPlayerAudioCaps feature)
{
- for (Features::iterator itr = m_audioCaps.begin(); itr != m_audioCaps.end(); ++itr)
+ for (IPlayerAudioCaps cap : m_audioCaps)
{
- if (*itr == feature || *itr == IPC_AUD_ALL)
+ if (cap == feature || cap == IPlayerAudioCaps::ALL)
return true;
}
@@ -346,15 +346,14 @@ void CGUIDialogAudioSettings::AudioStreamsOptionFiller(const SettingConstPtr& se
{
const auto& components = CServiceBroker::GetAppComponents();
const auto appPlayer = components.GetComponent<CApplicationPlayer>();
- int audioStreamCount = appPlayer->GetAudioStreamCount();
+ const int audioStreamCount = appPlayer->GetAudioStreamCount();
- std::string strFormat = "{:s} - {:s} - {:d} " + g_localizeStrings.Get(10127);
+ std::string channelsLabel = g_localizeStrings.Get(10127);
std::string strUnknown = "[" + g_localizeStrings.Get(13205) + "]";
// cycle through each audio stream and add it to our list control
for (int i = 0; i < audioStreamCount; ++i)
{
- std::string strItem;
std::string strLanguage;
AudioStreamInfo info;
@@ -363,14 +362,19 @@ void CGUIDialogAudioSettings::AudioStreamsOptionFiller(const SettingConstPtr& se
if (!g_LangCodeExpander.Lookup(info.language, strLanguage))
strLanguage = strUnknown;
- if (info.name.length() == 0)
- info.name = strUnknown;
+ std::string textInfo = strLanguage;
+ if (!info.name.empty())
+ textInfo += " - " + info.name;
- strItem = StringUtils::Format(strFormat, strLanguage, info.name, info.channels);
+ textInfo += " (";
+ if (!info.codecDesc.empty())
+ textInfo += info.codecDesc + ", ";
- strItem += FormatFlags(info.flags);
- strItem += StringUtils::Format(" ({}/{})", i + 1, audioStreamCount);
- list.emplace_back(strItem, i);
+ textInfo += std::to_string(info.channels) + " " + channelsLabel + ")";
+
+ textInfo += FormatFlags(info.flags);
+ textInfo += StringUtils::Format(" ({}/{})", i + 1, audioStreamCount);
+ list.emplace_back(textInfo, i);
}
if (list.empty())
diff --git a/xbmc/video/dialogs/GUIDialogAudioSettings.h b/xbmc/video/dialogs/GUIDialogAudioSettings.h
index de69b77ae7..d07b694e68 100644
--- a/xbmc/video/dialogs/GUIDialogAudioSettings.h
+++ b/xbmc/video/dialogs/GUIDialogAudioSettings.h
@@ -15,6 +15,7 @@
#include <utility>
#include <vector>
+enum class IPlayerAudioCaps;
class CVariant;
struct IntegerSettingOption;
@@ -44,7 +45,7 @@ protected:
// specialization of CGUIDialogSettingsManualBase
void InitializeSettings() override;
- bool SupportsAudioFeature(int feature);
+ bool SupportsAudioFeature(IPlayerAudioCaps feature);
void AddAudioStreams(const std::shared_ptr<CSettingGroup>& group, const std::string& settingId);
@@ -75,8 +76,8 @@ protected:
int m_audioStream;
bool m_passthrough = false;
- typedef std::vector<int> Features;
- Features m_audioCaps;
+ std::vector<IPlayerAudioCaps> m_audioCaps;
+
private:
static std::string FormatFlags(StreamFlags flags);
};
diff --git a/xbmc/video/dialogs/GUIDialogSubtitleSettings.cpp b/xbmc/video/dialogs/GUIDialogSubtitleSettings.cpp
index 171c69a294..20dd6d8b4b 100644
--- a/xbmc/video/dialogs/GUIDialogSubtitleSettings.cpp
+++ b/xbmc/video/dialogs/GUIDialogSubtitleSettings.cpp
@@ -297,18 +297,18 @@ void CGUIDialogSubtitleSettings::InitializeSettings()
AddToggle(groupSubtitles, SETTING_SUBTITLE_ENABLE, 13397, SettingLevel::Basic, m_subtitleVisible);
// subtitle delay setting
- if (SupportsSubtitleFeature(IPC_SUBS_OFFSET))
+ if (SupportsSubtitleFeature(IPlayerSubtitleCaps::OFFSET))
{
std::shared_ptr<CSettingNumber> settingSubtitleDelay = AddSlider(groupSubtitles, SETTING_SUBTITLE_DELAY, 22006, SettingLevel::Basic, videoSettings.m_SubtitleDelay, 0, -CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_videoSubsDelayRange, 0.1f, CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_videoSubsDelayRange, 22006, usePopup);
std::static_pointer_cast<CSettingControlSlider>(settingSubtitleDelay->GetControl())->SetFormatter(SettingFormatterDelay);
}
// subtitle stream setting
- if (SupportsSubtitleFeature(IPC_SUBS_SELECT))
+ if (SupportsSubtitleFeature(IPlayerSubtitleCaps::SELECT_STREAM))
AddSubtitleStreams(groupSubtitles, SETTING_SUBTITLE_STREAM);
// subtitle browser setting
- if (SupportsSubtitleFeature(IPC_SUBS_EXTERNAL))
+ if (SupportsSubtitleFeature(IPlayerSubtitleCaps::EXTERNAL))
AddButton(groupSubtitles, SETTING_SUBTITLE_BROWSER, 13250, SettingLevel::Basic);
AddButton(groupSubtitles, SETTING_SUBTITLE_SEARCH, 24134, SettingLevel::Basic);
@@ -317,11 +317,11 @@ void CGUIDialogSubtitleSettings::InitializeSettings()
AddButton(groupSaveAsDefault, SETTING_MAKE_DEFAULT, 12376, SettingLevel::Basic);
}
-bool CGUIDialogSubtitleSettings::SupportsSubtitleFeature(int feature)
+bool CGUIDialogSubtitleSettings::SupportsSubtitleFeature(IPlayerSubtitleCaps feature)
{
- for (auto item : m_subtitleCapabilities)
+ for (IPlayerSubtitleCaps cap : m_subtitleCapabilities)
{
- if (item == feature || item == IPC_SUBS_ALL)
+ if (cap == feature || cap == IPlayerSubtitleCaps::ALL)
return true;
}
return false;
@@ -417,6 +417,8 @@ std::string CGUIDialogSubtitleSettings::FormatFlags(StreamFlags flags)
localizedFlags.emplace_back(g_localizeStrings.Get(39107));
if (flags & StreamFlags::FLAG_VISUAL_IMPAIRED)
localizedFlags.emplace_back(g_localizeStrings.Get(39108));
+ if (flags & StreamFlags::FLAG_ORIGINAL)
+ localizedFlags.emplace_back(g_localizeStrings.Get(39111));
std::string formated = StringUtils::Join(localizedFlags, ", ");
diff --git a/xbmc/video/dialogs/GUIDialogSubtitleSettings.h b/xbmc/video/dialogs/GUIDialogSubtitleSettings.h
index 65216ede38..5889734939 100644
--- a/xbmc/video/dialogs/GUIDialogSubtitleSettings.h
+++ b/xbmc/video/dialogs/GUIDialogSubtitleSettings.h
@@ -15,6 +15,7 @@
#include <utility>
#include <vector>
+enum class IPlayerSubtitleCaps;
class CVariant;
struct IntegerSettingOption;
@@ -44,7 +45,7 @@ protected:
void InitializeSettings() override;
private:
- bool SupportsSubtitleFeature(int feature);
+ bool SupportsSubtitleFeature(IPlayerSubtitleCaps feature);
void AddSubtitleStreams(const std::shared_ptr<CSettingGroup>& group,
const std::string& settingId);
@@ -53,7 +54,7 @@ private:
bool m_subtitleVisible;
std::shared_ptr<CSettingInt> m_subtitleStreamSetting;
- std::vector<int> m_subtitleCapabilities;
+ std::vector<IPlayerSubtitleCaps> m_subtitleCapabilities;
static std::string FormatFlags(StreamFlags flags);
static void SubtitleStreamsOptionFiller(const std::shared_ptr<const CSetting>& setting,
diff --git a/xbmc/video/dialogs/GUIDialogVideoInfo.cpp b/xbmc/video/dialogs/GUIDialogVideoInfo.cpp
index f7c931e4b0..d297a15634 100644
--- a/xbmc/video/dialogs/GUIDialogVideoInfo.cpp
+++ b/xbmc/video/dialogs/GUIDialogVideoInfo.cpp
@@ -864,8 +864,9 @@ void AddHardCodedAndExtendedArtTypes(std::vector<std::string>& artTypes, const C
}
// Add art types currently assigned to the media item
-void AddCurrentArtTypes(std::vector<std::string>& artTypes, const CVideoInfoTag& tag,
- CVideoDatabase& db)
+void AddCurrentArtTypes(std::vector<std::string>& artTypes,
+ const CVideoInfoTag& tag,
+ CVideoDatabase& db)
{
std::map<std::string, std::string> currentArt;
@@ -883,8 +884,9 @@ void AddCurrentArtTypes(std::vector<std::string>& artTypes, const CVideoInfoTag&
}
// Add art types that exist for other media items of the same type
-void AddMediaTypeArtTypes(std::vector<std::string>& artTypes, const CVideoInfoTag& tag,
- CVideoDatabase& db)
+void AddMediaTypeArtTypes(std::vector<std::string>& artTypes,
+ const CVideoInfoTag& tag,
+ CVideoDatabase& db)
{
std::vector<std::string> dbArtTypes;
db.GetArtTypes(tag.m_type, dbArtTypes);
@@ -896,8 +898,9 @@ void AddMediaTypeArtTypes(std::vector<std::string>& artTypes, const CVideoInfoTa
}
// Add art types from available but unassigned artwork for this media item
-void AddAvailableArtTypes(std::vector<std::string>& artTypes, const CVideoInfoTag& tag,
- CVideoDatabase& db)
+void AddAvailableArtTypes(std::vector<std::string>& artTypes,
+ const CVideoInfoTag& tag,
+ CVideoDatabase& db)
{
for (const auto& artType : db.GetAvailableArtTypesForItem(tag.m_iDbId, tag.m_type))
{
@@ -930,6 +933,7 @@ public:
bool ChooseArtType();
const std::string& GetArtType() const { return m_artType; }
+ void UpdateArtType(const std::string& type, const std::string& art) const;
private:
std::shared_ptr<CFileItem> m_item;
@@ -938,6 +942,15 @@ private:
std::string m_artType;
};
+void CArtTypeChooser::UpdateArtType(const std::string& type, const std::string& art) const
+{
+ m_item->SetArt(type, art);
+ if (!m_items.IsEmpty())
+ for (auto& item : m_items)
+ if (item->GetProperty("type") == type)
+ item->SetArt("thumb", art);
+}
+
bool CArtTypeChooser::ChooseArtType()
{
CGUIDialogSelect* dialog =
@@ -1832,7 +1845,10 @@ bool CGUIDialogVideoInfo::ChooseAndManageVideoItemArtwork(const std::shared_ptr<
if (!chooser.ChooseArtType())
break;
- result = ManageVideoItemArtwork(item, item->GetVideoInfoTag()->m_type, chooser.GetArtType());
+ const std::string chosenArtType{chooser.GetArtType()};
+ result = ManageVideoItemArtwork(item, item->GetVideoInfoTag()->m_type, chosenArtType);
+ if (result)
+ chooser.UpdateArtType(chosenArtType, item->GetArt(chosenArtType));
} while (true);
diff --git a/xbmc/video/guilib/CMakeLists.txt b/xbmc/video/guilib/CMakeLists.txt
index 64192185c6..83205a56a4 100644
--- a/xbmc/video/guilib/CMakeLists.txt
+++ b/xbmc/video/guilib/CMakeLists.txt
@@ -1,12 +1,14 @@
set(SOURCES VideoGUIUtils.cpp
VideoPlayActionProcessor.cpp
VideoSelectActionProcessor.cpp
+ VideoStreamSelectHelper.cpp
VideoVersionHelper.cpp)
set(HEADERS VideoAction.h
VideoGUIUtils.h
VideoPlayActionProcessor.h
VideoSelectActionProcessor.h
+ VideoStreamSelectHelper.h
VideoVersionHelper.h)
core_add_library(video_guilib)
diff --git a/xbmc/video/guilib/VideoStreamSelectHelper.cpp b/xbmc/video/guilib/VideoStreamSelectHelper.cpp
new file mode 100644
index 0000000000..93d7a80936
--- /dev/null
+++ b/xbmc/video/guilib/VideoStreamSelectHelper.cpp
@@ -0,0 +1,518 @@
+/*
+ * Copyright (C) 2024 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 "VideoStreamSelectHelper.h"
+
+#include "FileItem.h"
+#include "FileItemList.h"
+#include "ServiceBroker.h"
+#include "application/ApplicationComponents.h"
+#include "application/ApplicationPlayer.h"
+#include "dialogs/GUIDialogSelect.h"
+#include "guilib/GUIComponent.h"
+#include "guilib/GUIWindowManager.h"
+#include "guilib/LocalizeStrings.h"
+#include "utils/LangCodeExpander.h"
+#include "utils/StreamDetails.h"
+#include "utils/StringUtils.h"
+#include "utils/log.h"
+
+namespace
+{
+constexpr int STREAM_ID_DISABLE = -2; // Stream id referred to item that disable the stream
+constexpr int STREAM_ID_NONE = -1; // Stream id referred to item for "none" stream
+
+// \brief Make a FileItem entry with "Disable" label, allow to disable a stream
+const std::shared_ptr<CFileItem> MakeFileItemDisable(bool isSelected)
+{
+ const auto fileItem{std::make_shared<CFileItem>(g_localizeStrings.Get(24021))};
+ fileItem->Select(isSelected);
+ fileItem->SetProperty("stream.id", STREAM_ID_DISABLE);
+ return fileItem;
+}
+
+// \brief Make a FileItem entry with "None" label, signal an empty list
+const std::shared_ptr<CFileItem> MakeFileItemNone()
+{
+ const auto fileItem{std::make_shared<CFileItem>(g_localizeStrings.Get(231))};
+ fileItem->SetProperty("stream.id", STREAM_ID_NONE);
+ return fileItem;
+}
+
+std::shared_ptr<const CFileItem> OpenSelectDialog(CGUIDialogSelect& dialog,
+ int headingId,
+ const CFileItemList& itemsToDisplay)
+{
+ dialog.Reset();
+ dialog.SetHeading(headingId);
+ dialog.SetUseDetails(true);
+ dialog.SetMultiSelection(false);
+ dialog.SetItems(itemsToDisplay);
+
+ dialog.Open();
+
+ if (dialog.IsConfirmed())
+ return dialog.GetSelectedFileItem();
+
+ return {};
+}
+
+std::string ConvertFpsToString(float value)
+{
+ if (value == 0.0f)
+ return "";
+
+ std::string str{StringUtils::Format("{:.3f}", value)};
+ // Keep numbers after the comma only if they are not 0
+ const size_t zeroPos = str.find_last_not_of("0");
+ if (zeroPos != std::string::npos)
+ str.erase(zeroPos + 1);
+
+ if (str.back() == '.')
+ str.pop_back();
+
+ return str;
+}
+
+struct VideoStreamInfoExt : VideoStreamInfo
+{
+ VideoStreamInfoExt(int id, const VideoStreamInfo& info) : VideoStreamInfo(info)
+ {
+ streamId = id;
+ isDefault = info.flags & StreamFlags::FLAG_DEFAULT;
+ isForced = info.flags & StreamFlags::FLAG_FORCED;
+ isHearingImpaired = info.flags & StreamFlags::FLAG_HEARING_IMPAIRED;
+ isVisualImpaired = info.flags & StreamFlags::FLAG_VISUAL_IMPAIRED;
+ }
+
+ int streamId{0};
+ std::string languageDesc;
+ bool isDefault{false};
+ bool isForced{false};
+ bool isHearingImpaired{false};
+ bool isVisualImpaired{false};
+};
+
+struct AudioStreamInfoExt : AudioStreamInfo
+{
+ AudioStreamInfoExt(int id, const AudioStreamInfo& info) : AudioStreamInfo(info)
+ {
+ streamId = id;
+
+ if (!g_LangCodeExpander.Lookup(info.language, languageDesc))
+ languageDesc = g_localizeStrings.Get(13205); // Unknown
+
+ isDefault = info.flags & StreamFlags::FLAG_DEFAULT;
+ isForced = info.flags & StreamFlags::FLAG_FORCED;
+ isHearingImpaired = info.flags & StreamFlags::FLAG_HEARING_IMPAIRED;
+ isVisualImpaired = info.flags & StreamFlags::FLAG_VISUAL_IMPAIRED;
+ isOriginal = info.flags & StreamFlags::FLAG_ORIGINAL;
+ }
+
+ int streamId{0};
+ std::string languageDesc;
+ bool isDefault{false};
+ bool isForced{false};
+ bool isHearingImpaired{false};
+ bool isVisualImpaired{false};
+ bool isOriginal{false};
+};
+
+struct SubtitleStreamInfoExt : SubtitleStreamInfo
+{
+ SubtitleStreamInfoExt(int id, const SubtitleStreamInfo& info) : SubtitleStreamInfo(info)
+ {
+ streamId = id;
+
+ if (!g_LangCodeExpander.Lookup(info.language, languageDesc))
+ languageDesc = g_localizeStrings.Get(13205); // Unknown
+
+ isDefault = info.flags & StreamFlags::FLAG_DEFAULT;
+ isForced = info.flags & StreamFlags::FLAG_FORCED;
+ isHearingImpaired = info.flags & StreamFlags::FLAG_HEARING_IMPAIRED;
+ isVisualImpaired = info.flags & StreamFlags::FLAG_VISUAL_IMPAIRED;
+ isOriginal = info.flags & StreamFlags::FLAG_ORIGINAL;
+ }
+
+ int streamId{0};
+ std::string languageDesc;
+ bool isDefault{false};
+ bool isForced{false};
+ bool isHearingImpaired{false};
+ bool isVisualImpaired{false};
+ bool isOriginal{false};
+};
+
+struct SortComparerStreamVideo
+{
+ bool operator()(const VideoStreamInfoExt& a, const VideoStreamInfoExt& b)
+ {
+ if (a.language != b.language)
+ {
+ return a.language < b.language;
+ }
+ if (a.codecName != b.codecName)
+ {
+ return a.codecName < b.codecName;
+ }
+ if (a.hdrType != b.hdrType)
+ {
+ return a.hdrType < b.hdrType;
+ }
+ if (a.fpsRate != b.fpsRate)
+ {
+ return a.fpsRate < b.fpsRate;
+ }
+ if (a.fpsScale != b.fpsScale)
+ {
+ return a.fpsScale < b.fpsScale;
+ }
+ if (a.height != b.height)
+ {
+ return a.height < b.height;
+ }
+ if (a.width != b.width)
+ {
+ return a.width < b.width;
+ }
+ return a.bitrate < b.bitrate;
+ }
+};
+
+struct SortComparerStreamAudio
+{
+ bool operator()(const AudioStreamInfoExt& a, const AudioStreamInfoExt& b)
+ {
+ if (a.languageDesc != b.languageDesc)
+ {
+ return a.languageDesc < b.languageDesc;
+ }
+ if (a.isOriginal != b.isOriginal)
+ {
+ return a.isOriginal < b.isOriginal;
+ }
+ if (a.isHearingImpaired != b.isHearingImpaired)
+ {
+ return a.isHearingImpaired < b.isHearingImpaired;
+ }
+ if (a.isVisualImpaired != b.isVisualImpaired)
+ {
+ return a.isVisualImpaired < b.isVisualImpaired;
+ }
+ if (a.isForced != b.isForced)
+ {
+ return a.isForced < b.isForced;
+ }
+ if (a.channels != b.channels)
+ {
+ return a.channels < b.channels;
+ }
+ if (a.bitrate != b.bitrate)
+ {
+ return a.bitrate < b.bitrate;
+ }
+ if (a.samplerate != b.samplerate)
+ {
+ return a.samplerate < b.samplerate;
+ }
+ return a.codecName < b.codecName;
+ }
+};
+
+struct SortComparerStreamSubtitle
+{
+ bool operator()(const SubtitleStreamInfoExt& a, const SubtitleStreamInfoExt& b)
+ {
+ if (a.isExternal != b.isExternal)
+ {
+ return a.isExternal > b.isExternal;
+ }
+ if (a.languageDesc != b.languageDesc)
+ {
+ return a.languageDesc < b.languageDesc;
+ }
+ if (a.isOriginal != b.isOriginal)
+ {
+ return a.isOriginal < b.isOriginal;
+ }
+ if (a.isHearingImpaired != b.isHearingImpaired)
+ {
+ return a.isHearingImpaired < b.isHearingImpaired;
+ }
+ if (a.isVisualImpaired != b.isVisualImpaired)
+ {
+ return a.isVisualImpaired < b.isVisualImpaired;
+ }
+ if (a.isForced != b.isForced)
+ {
+ return a.isForced < b.isForced;
+ }
+ return a.codecName < b.codecName;
+ }
+};
+
+bool SupportsAudioFeature(IPlayerAudioCaps feature, const std::vector<IPlayerAudioCaps>& caps)
+{
+ for (IPlayerAudioCaps cap : caps)
+ {
+ if (cap == feature || cap == IPlayerAudioCaps::ALL)
+ return true;
+ }
+
+ return false;
+}
+
+bool SupportsSubtitleFeature(IPlayerSubtitleCaps feature,
+ const std::vector<IPlayerSubtitleCaps>& caps)
+{
+ for (IPlayerSubtitleCaps cap : caps)
+ {
+ if (cap == feature || cap == IPlayerSubtitleCaps::ALL)
+ return true;
+ }
+ return false;
+}
+
+} // unnamed namespace
+
+void KODI::VIDEO::GUILIB::OpenDialogSelectVideoStream()
+{
+ CGUIDialogSelect* dialog{CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogSelect>(
+ WINDOW_DIALOG_SELECT_VIDEO_STREAM)};
+ if (!dialog)
+ {
+ CLog::LogF(LOGERROR, "Unable to get WINDOW_DIALOG_SELECT_VIDEO_STREAM dialog instance");
+ return;
+ }
+
+ auto& components = CServiceBroker::GetAppComponents();
+ auto appPlayer = components.GetComponent<CApplicationPlayer>();
+ const int streamCount = appPlayer->GetVideoStreamCount();
+ const int selectedId = appPlayer->GetVideoStream();
+
+ std::vector<VideoStreamInfoExt> streams;
+ streams.reserve(streamCount);
+
+ // Collect all streams
+ for (int i = 0; i < streamCount; ++i)
+ {
+ VideoStreamInfo info;
+ appPlayer->GetVideoStreamInfo(i, info);
+ streams.emplace_back(i, info);
+ }
+
+ // Sort streams
+ std::sort(streams.begin(), streams.end(), SortComparerStreamVideo());
+
+ // Convert streams to FileItem's
+ CFileItemList itemsToDisplay;
+ itemsToDisplay.Reserve(streams.size());
+
+ for (const VideoStreamInfoExt& info : streams)
+ {
+ const auto fileItem = std::make_shared<CFileItem>(info.name);
+ fileItem->SetProperty("stream.id", info.streamId);
+ fileItem->SetProperty("stream.description", info.name);
+ fileItem->SetProperty("stream.codec", info.codecName);
+
+ std::string languageDesc;
+ g_LangCodeExpander.Lookup(info.language, languageDesc);
+ fileItem->SetProperty("stream.language", languageDesc);
+
+ fileItem->SetProperty("stream.resolution",
+ std::to_string(info.width) + "x" + std::to_string(info.height));
+ fileItem->SetProperty("stream.bitrate",
+ static_cast<int>(std::lrint(static_cast<double>(info.bitrate) / 1000.0)));
+
+ float fps = static_cast<float>(info.fpsRate);
+ if (fps > 0.0f && info.fpsScale > 0)
+ fps /= info.fpsScale;
+
+ fileItem->SetProperty("stream.fps", ConvertFpsToString(fps));
+
+ fileItem->SetProperty("stream.is3d", !info.stereoMode.empty() && info.stereoMode != "mono");
+ fileItem->SetProperty("stream.stereomode", info.stereoMode);
+ fileItem->SetProperty("stream.hdrtype", CStreamDetails::HdrTypeToString(info.hdrType));
+
+ fileItem->SetProperty("stream.isdefault", info.isDefault);
+ fileItem->SetProperty("stream.isforced", info.isForced);
+ fileItem->SetProperty("stream.ishearingimpaired", info.isHearingImpaired);
+ fileItem->SetProperty("stream.isvisualimpaired", info.isVisualImpaired);
+ if (selectedId == info.streamId)
+ fileItem->Select(true);
+
+ itemsToDisplay.Add(fileItem);
+ }
+
+ if (itemsToDisplay.IsEmpty())
+ itemsToDisplay.Add(MakeFileItemNone());
+
+ const auto selectedItem = OpenSelectDialog(*dialog, 38031, itemsToDisplay);
+ if (selectedItem)
+ {
+ const int id = selectedItem->GetProperty("stream.id").asInteger32(STREAM_ID_NONE);
+
+ if (id != STREAM_ID_NONE)
+ appPlayer->SetVideoStream(id);
+ }
+}
+
+void KODI::VIDEO::GUILIB::OpenDialogSelectAudioStream()
+{
+ CGUIDialogSelect* dialog{CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogSelect>(
+ WINDOW_DIALOG_SELECT_AUDIO_STREAM)};
+ if (!dialog)
+ {
+ CLog::LogF(LOGERROR, "Unable to get WINDOW_DIALOG_SELECT_AUDIO_STREAM dialog instance");
+ return;
+ }
+
+ auto& components = CServiceBroker::GetAppComponents();
+ auto appPlayer = components.GetComponent<CApplicationPlayer>();
+
+ std::vector<IPlayerAudioCaps> caps;
+ appPlayer->GetAudioCapabilities(caps);
+ if (!SupportsAudioFeature(IPlayerAudioCaps::SELECT_STREAM, caps))
+ return;
+
+ const int streamCount = appPlayer->GetAudioStreamCount();
+ const int selectedId = appPlayer->GetAudioStream();
+
+ std::vector<AudioStreamInfoExt> streams;
+ streams.reserve(streamCount);
+
+ // Collect all streams
+ for (int i = 0; i < streamCount; ++i)
+ {
+ AudioStreamInfo info;
+ appPlayer->GetAudioStreamInfo(i, info);
+ streams.emplace_back(i, info);
+ }
+
+ // Sort streams
+ std::sort(streams.begin(), streams.end(), SortComparerStreamAudio());
+
+ // Convert streams to FileItem's
+ CFileItemList itemsToDisplay;
+ itemsToDisplay.Reserve(streams.size());
+
+ for (const AudioStreamInfoExt& info : streams)
+ {
+ CFileItemPtr fileItem = std::make_shared<CFileItem>(info.languageDesc);
+ fileItem->SetProperty("stream.id", info.streamId);
+ fileItem->SetProperty("stream.description", info.name);
+ fileItem->SetProperty("stream.codec", info.codecName);
+ fileItem->SetProperty("stream.codecdesc", info.codecDesc);
+ fileItem->SetProperty("stream.channels", info.channels);
+
+ fileItem->SetProperty("stream.isdefault", info.isDefault);
+ fileItem->SetProperty("stream.isforced", info.isForced);
+ fileItem->SetProperty("stream.ishearingimpaired", info.isHearingImpaired);
+ fileItem->SetProperty("stream.isvisualimpaired", info.isVisualImpaired);
+ fileItem->SetProperty("stream.isoriginal", info.isOriginal);
+ if (selectedId == info.streamId)
+ fileItem->Select(true);
+
+ itemsToDisplay.Add(fileItem);
+ }
+
+ if (itemsToDisplay.IsEmpty())
+ itemsToDisplay.Add(MakeFileItemNone());
+
+ const auto selectedItem = OpenSelectDialog(*dialog, 460, itemsToDisplay);
+ if (selectedItem)
+ {
+ const int id = selectedItem->GetProperty("stream.id").asInteger32(STREAM_ID_NONE);
+
+ if (id != STREAM_ID_NONE)
+ appPlayer->SetAudioStream(id);
+ }
+}
+
+void KODI::VIDEO::GUILIB::OpenDialogSelectSubtitleStream()
+{
+ CGUIDialogSelect* dialog{CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogSelect>(
+ WINDOW_DIALOG_SELECT_SUBTITLE_STREAM)};
+ if (!dialog)
+ {
+ CLog::LogF(LOGERROR, "Unable to get WINDOW_DIALOG_SELECT_SUBTITLE_STREAM dialog instance");
+ return;
+ }
+
+ auto& components = CServiceBroker::GetAppComponents();
+ auto appPlayer = components.GetComponent<CApplicationPlayer>();
+
+ std::vector<IPlayerSubtitleCaps> caps;
+ appPlayer->GetSubtitleCapabilities(caps);
+ if (!SupportsSubtitleFeature(IPlayerSubtitleCaps::SELECT_STREAM, caps))
+ return;
+
+ const int streamCount = appPlayer->GetSubtitleCount();
+ const int selectedId = appPlayer->GetSubtitle();
+ const bool isSubtitleEnabled = appPlayer->GetSubtitleVisible();
+
+ std::vector<SubtitleStreamInfoExt> streams;
+ streams.reserve(streamCount);
+
+ // Collect all streams
+ for (int i = 0; i < streamCount; ++i)
+ {
+ SubtitleStreamInfo info;
+ appPlayer->GetSubtitleStreamInfo(i, info);
+ streams.emplace_back(i, info);
+ }
+
+ // Sort streams
+ std::sort(streams.begin(), streams.end(), SortComparerStreamSubtitle());
+
+ // Convert streams to FileItem's
+ CFileItemList itemsToDisplay;
+ itemsToDisplay.Reserve(streams.size() + 1);
+
+ for (const SubtitleStreamInfoExt& info : streams)
+ {
+ CFileItemPtr fileItem = std::make_shared<CFileItem>(info.languageDesc);
+ fileItem->SetProperty("stream.id", info.streamId);
+ fileItem->SetProperty("stream.description", info.name);
+ fileItem->SetProperty("stream.codec", info.codecName);
+
+ fileItem->SetProperty("stream.isdefault", info.isDefault);
+ fileItem->SetProperty("stream.isforced", info.isForced);
+ fileItem->SetProperty("stream.isoriginal", info.isOriginal);
+ fileItem->SetProperty("stream.ishearingimpaired", info.isHearingImpaired);
+ fileItem->SetProperty("stream.isvisualimpaired", info.isVisualImpaired);
+ fileItem->SetProperty("stream.isexternal", info.isExternal);
+ if (selectedId == info.streamId && isSubtitleEnabled)
+ fileItem->Select(true);
+
+ itemsToDisplay.Add(fileItem);
+ }
+
+ if (itemsToDisplay.IsEmpty())
+ itemsToDisplay.Add(MakeFileItemNone());
+ else
+ itemsToDisplay.AddFront(MakeFileItemDisable(!isSubtitleEnabled), 0);
+
+ const auto selectedItem = OpenSelectDialog(*dialog, 462, itemsToDisplay);
+ if (selectedItem)
+ {
+ const int id = selectedItem->GetProperty("stream.id").asInteger32(STREAM_ID_NONE);
+
+ if (id == STREAM_ID_DISABLE)
+ {
+ appPlayer->SetSubtitleVisible(false);
+ }
+ else if (id != STREAM_ID_NONE)
+ {
+ appPlayer->SetSubtitle(id);
+
+ if (!appPlayer->GetSubtitleVisible())
+ appPlayer->SetSubtitleVisible(true);
+ }
+ }
+}
diff --git a/xbmc/video/guilib/VideoStreamSelectHelper.h b/xbmc/video/guilib/VideoStreamSelectHelper.h
new file mode 100644
index 0000000000..598682422b
--- /dev/null
+++ b/xbmc/video/guilib/VideoStreamSelectHelper.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2024 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
+
+namespace KODI::VIDEO::GUILIB
+{
+
+/*!
+ * \brief Open dialog window to select/change video stream
+ */
+void OpenDialogSelectVideoStream();
+
+/*!
+ * \brief Open dialog window to select/change audio stream
+ */
+void OpenDialogSelectAudioStream();
+
+/*!
+ * \brief Open dialog window to select/change subtitle stream
+ */
+void OpenDialogSelectSubtitleStream();
+
+} // namespace KODI::VIDEO::GUILIB
diff --git a/xbmc/video/windows/GUIWindowVideoBase.cpp b/xbmc/video/windows/GUIWindowVideoBase.cpp
index a875ae4bfa..d231a809f7 100644
--- a/xbmc/video/windows/GUIWindowVideoBase.cpp
+++ b/xbmc/video/windows/GUIWindowVideoBase.cpp
@@ -65,7 +65,6 @@
#include "video/guilib/VideoGUIUtils.h"
#include "video/guilib/VideoPlayActionProcessor.h"
#include "video/guilib/VideoSelectActionProcessor.h"
-#include "video/guilib/VideoVersionHelper.h"
#include "view/GUIViewState.h"
#include <memory>