diff options
374 files changed, 5215 insertions, 3241 deletions
diff --git a/.gitignore b/.gitignore index d65eb08d45..39ef1aa169 100644 --- a/.gitignore +++ b/.gitignore @@ -309,6 +309,7 @@ lib/cpluff/stamp-h1 #/tools/depends /tools/depends/native/*/*native/ +/tools/depends/target/*/aarch64-linux-gnu/ /tools/depends/native/JsonSchemaBuilder/bin/ /tools/depends/native/TexturePacker/bin/ /tools/depends/target/ffmpeg/.ffmpeg-installed diff --git a/addons/kodi.imagedecoder/addon.xml b/addons/kodi.imagedecoder/addon.xml new file mode 100644 index 0000000000..aa0af75ad1 --- /dev/null +++ b/addons/kodi.imagedecoder/addon.xml @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="UTF-8"?> +<addon id="kodi.imagedecoder" version="1.0.0" provider-name="Team Kodi"> + <backwards-compatibility abi="1.0.0"/> + <requires> + <import addon="xbmc.core" version="0.1.0"/> + </requires> +</addon> diff --git a/addons/metadata.demo.artists/demo.py b/addons/metadata.demo.artists/demo.py index 819528cda2..98f071ba80 100644 --- a/addons/metadata.demo.artists/demo.py +++ b/addons/metadata.demo.artists/demo.py @@ -46,6 +46,9 @@ if action == 'find': liz.setProperty('artist.genre', 'classical / jazz') liz.setProperty('artist.born', '2012') xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]), url="/path/to/artist2", listitem=liz, isFolder=True) +elif action == 'resolveid': + liz=xbmcgui.ListItem(path='/path/to/artist2', offscreen=True) + xbmcplugin.setResolvedUrl(handle=int(sys.argv[1]), succeeded=True, listitem=liz) elif action == 'getdetails': url=urllib.unquote_plus(params["url"]) print 'Artist with url %s' %(url) diff --git a/addons/resource.language.en_gb/resources/strings.po b/addons/resource.language.en_gb/resources/strings.po index 0cdc64916a..d8b58cec6e 100644 --- a/addons/resource.language.en_gb/resources/strings.po +++ b/addons/resource.language.en_gb/resources/strings.po @@ -1179,6 +1179,7 @@ msgid "Fetching CD information" msgstr "" #: xbmc/dialogs/GUIDialogFileBrowser.cpp +#: xbmc/pvr/PVRGUIActions.cpp #: xbmc/video/dialogs/GUIDialogVideoInfo.cpp #: xbmc/music/windows/GUIWindowMusicBase.cpp #: xbmc/video/windows/GUIWindowVideoNav.cpp @@ -3631,7 +3632,7 @@ msgstr "" #empty strings from id 824 to 827 #. Text for notification that a timer rule has been deleted -#: xbmc/pvr/timers/PVRTimers.cpp +#: xbmc/pvr/timers/PVRTimerInfoTag.cpp msgctxt "#828" msgid "Timer rule deleted" msgstr "" @@ -9016,7 +9017,7 @@ msgstr "" #: addons/skin.estuary/xml/SkinSettings.xml: #: addons/skin.estuary/xml/Variables.xml #: xbmc/pvr/channels/PVRChannelGroupsContainer.cpp -#: xbmc/pvr/PVRManager.cpp +#: xbmc/pvr/PVRGUIActions.cpp msgctxt "#19020" msgid "TV" msgstr "" @@ -9026,7 +9027,7 @@ msgstr "" #: addons/skin.estuary/xml/SkinSettings.xml #: addons/skin.estuary/xml/Variables.xml #: xbmc/pvr/channels/PVRChannelGroupsContainer.cpp -#: xbmc/pvr/PVRManager.cpp +#: xbmc/pvr/PVRGUIActions.cpp msgctxt "#19021" msgid "Radio" msgstr "" @@ -9114,12 +9115,10 @@ msgstr "" #. generic 'information' label used in different places, like labels for message box headers #: xbmc/event/windows/GUIWindowEventLog.cpp -#: xbmc/pvr/addons/PVRClients.cpp +#: xbmc/pvr/dialogs/GUIDialogPVRChannelManager.cpp #: xbmc/pvr/dialogs/GUIDialogPVRGroupManager.cpp #: xbmc/pvr/dialogs/GUIDialogPVRGuideInfo.cpp -#: xbmc/pvr/recordings/PVRRecording.cpp #: xbmc/pvr/timers/PVRTimerInfoTag.cpp -#: xbmc/pvr/timers/PVRTimers.cpp #: xbmc/pvr/windows/GUIWindowPVRTimersBase.cpp #: xbmc/pvr/PVRGUIActions.cpp #: xbmc/pvr/PVRManager.cpp @@ -9156,7 +9155,7 @@ msgid "Show signal quality" msgstr "" #. message box text stating that a PVR backend does not support a certain functionality. -#: xbmc/pvr/addons/PVRClients.cpp +#: xbmc/pvr/dialogs/GUIDialogPVRChannelManager.cpp msgctxt "#19038" msgid "Not supported by the PVR backend." msgstr "" @@ -9345,11 +9344,7 @@ msgctxt "#19067" msgid "This event is already being recorded." msgstr "" -#. error box text stating that a given pvr recording could not be deleted -#: xbmc/pvr/recording/PVRRecording.cpp -msgctxt "#19068" -msgid "This recording couldn't be deleted. Check the log for more information about this message." -msgstr "" +#empty string with id 19068 #. Electronic program guide #: addons/skin.estuary/xml/Variables.xml @@ -9452,7 +9447,7 @@ msgstr "" #. Label for "Instant recording action" setting #: system/settings/settings.xml -#: xbmc/pvr/PVRManager.cpp +#: xbmc/pvr/PVRGUIActions.cpp msgctxt "#19086" msgid "Instant recording action" msgstr "" @@ -9476,19 +9471,19 @@ msgid "Ask what to do" msgstr "" #. Label for "Instant recording action" dialog settings value -#: xbmc/pvr/PVRManager.cpp +#: xbmc/pvr/PVRGUIActions.cpp msgctxt "#19090" msgid "Record the next %d minutes" msgstr "" #. Label for "Instant recording action" dialog settings value -#: xbmc/pvr/PVRManager.cpp +#: xbmc/pvr/PVRGUIActions.cpp msgctxt "#19091" msgid "Record current show (%s)" msgstr "" #. Label for "Instant recording action" dialog settings value -#: xbmc/pvr/PVRManager.cpp +#: xbmc/pvr/PVRGUIActions.cpp msgctxt "#19092" msgid "Record next show (%s)" msgstr "" @@ -9592,7 +9587,7 @@ msgstr "" #. message box text stating that a timer could not be saved #: xbmc/pvr/timers/PVRTimerInfoTag.cpp -#: xbmc/pvr/timers/PVRTimers.cpp +#: xbmc/pvr/PVRGUIActions.cpp msgctxt "#19109" msgid "Couldn't save timer. Check the log for more information about this message." msgstr "" @@ -9604,8 +9599,7 @@ msgid "An unexpected error occurred. Try again later or check the log for more i msgstr "" #. message box text stating that a PVR backend error occured -#: xbmc/pvr/addons/PVRClients.cpp -#: xbmc/pvr/recording/PVRRecording.cpp +#: xbmc/pvr/PVRGUIActions.cpp #: xbmc/pvr/timers/PVRTimerInfoTag.cpp msgctxt "#19111" msgid "PVR backend error. Check the log for more information about this message." @@ -9653,7 +9647,7 @@ msgid "Can't use PVR functions while searching." msgstr "" #. channel scan backend selection dialog text -#: xbmc/pvr/addons/PVRClients.cpp +#: xbmc/pvr/PVRGUIActions.cpp msgctxt "#19119" msgid "On which backend do you want to search?" msgstr "" @@ -9810,11 +9804,7 @@ msgctxt "#19146" msgid "Groups" msgstr "" -#. message box text stating that a PVR backend does not support a certain functionality. -#: xbmc/pvr/recording/PVRRecording.cpp -msgctxt "#19147" -msgid "The PVR backend does not support this action. Check the log for more information about this message." -msgstr "" +#empty string with id 191407 #: addons/skin.estuary/xml/DialogPVRRadioRDSInfo.xml #: addons/skin.estuary/xml/DialogPVRGuideSearch.xml @@ -9910,7 +9900,7 @@ msgid "Recordings" msgstr "" #. error box text stating that recording could not be started -#: xbmc/pvr/PVRManager.cpp +#: xbmc/pvr/PVRGUIActions.cpp msgctxt "#19164" msgid "Can't start recording. Check the log for more information about this message." msgstr "" @@ -9920,8 +9910,10 @@ msgctxt "#19165" msgid "Switch" msgstr "" -#. label for header of system information's PVR section +#. label for header of misc PVR GUI elements #: xbmc/windows/GUIWindowSystemInfo.cpp +#: xbmc/pvr/PVRManager.cpp +#: xbmc/pvr/PVRGUIActions.cpp msgctxt "#19166" msgid "PVR information" msgstr "" @@ -10076,13 +10068,13 @@ msgid "PVR service" msgstr "" #. error message box text stating that none of the available pvr clients does support channel scanning -#: xbmc/pvr/addons/PVRClients.cpp +#: xbmc/pvr/PVRGUIActions.cpp msgctxt "#19192" msgid "None of the connected PVR backends supports scanning for channels." msgstr "" #. error message box text stating that a given pvr channel could not be played -#: xbmc/pvr/addons/PVRClients.cpp +#: xbmc/pvr/PVRGUIActions.cpp msgctxt "#19193" msgid "The channel scan can't be started. Check the log for more information about this message." msgstr "" @@ -10099,7 +10091,7 @@ msgid "Client actions" msgstr "" #. value for "pvr client specific actions" dialog headers -#: xbmc/pvr/addons/PVRClients.cpp +#: xbmc/pvr/PVRGUIActions.cpp msgctxt "#19196" msgid "PVR client specific actions" msgstr "" @@ -10208,7 +10200,7 @@ msgid "Enter a valid URL for the new channel" msgstr "" #. message box text stating that a pvr backend does not support timers -#: xbmc/pvr/timers/PVRTimers.cpp +#: xbmc/pvr/timers/PVRGUIActions.cpp #: xbmc/pvr/windows/GUIWindowsPVRTimersBase.cpp msgctxt "#19215" msgid "The PVR backend does not support timers." @@ -10482,27 +10474,21 @@ msgid "Change PIN" msgstr "" #. generic 'parental control enter pin' label -#: xbmc/pvr/dialogs/GUIDialogPVRChannelManager.cpp -#: xbmc/pvr/PVRManager.cpp -#: xbmc/settings/SettingConditions.cpp +#: xbmc/pvr/PVRGUIActions.cpp msgctxt "#19262" msgid "Parental control. Enter PIN:" msgstr "" -#. label for 'parental control pin' verification dialog -#: xbmc/pvr/PVRManager.cpp -msgctxt "#19263" -msgid "Locked channel. Enter PIN:" -msgstr "" +# empty string with id 19263 #. label for 'incorrect pin' error dialog header -#: xbmc/pvr/PVRManager.cpp +#: xbmc/pvr/PVRGUIActions.cpp msgctxt "#19264" msgid "Incorrect PIN" msgstr "" #. label for 'incorrect pin' error dialog text -#: xbmc/pvr/PVRManager.cpp +#: xbmc/pvr/PVRGUIActions.cpp msgctxt "#19265" msgid "The entered PIN was incorrect." msgstr "" @@ -11270,23 +11256,7 @@ msgctxt "#19687" msgid "Play recording" msgstr "" -#. label for 'scanning for pvr services' dialog header -#: xbmc/addons/PVRClient.cpp -msgctxt "#19688" -msgid "Scanning for PVR services" -msgstr "" - -#. label for 'scanning for pvr services' dialog text -#: xbmc/addons/PVRClient.cpp -msgctxt "#19689" -msgid "%s service found at %s" -msgstr "" - -#. label for 'scanning for pvr services' dialog text -#: xbmc/addons/PVRClient.cpp -msgctxt "#19690" -msgid "Do you want to use this service?" -msgstr "" +#empty strings from id 19688 to 19690 #. Text for shutdown confirmation dialog. #: xbmc/pvr/PVRManager.cpp @@ -12638,7 +12608,10 @@ msgctxt "#20381" msgid "Specials" msgstr "" -#empty string with id 20382 +#: xbmc/filesystem/VideoDatabaseDirectory/DirectoryNodeOverview.cpp +msgctxt "#20382" +msgid "Recently added" +msgstr "" msgctxt "#20383" msgid "Selected folder contains a single video" @@ -14783,17 +14756,19 @@ msgctxt "#24093" msgid "Checking %s..." msgstr "" -#empty string with id 24094 +#: xbmc/addons/AddonInstaller.cpp +msgctxt "#24094" +msgid "Add-on disabled due to being marked broken in repository." +msgstr "" #: xbmc/addons/GUIDialogAddonInfo.cpp msgctxt "#24095" msgid "Local package cache" msgstr "" -#: xbmc/addons/Repository.cpp #: addons/skin.estuary/xml/DialogAddonInfo.xml msgctxt "#24096" -msgid "Add-on is incompatible or has been marked broken in repository." +msgid "Add-on has been marked broken in repository." msgstr "" #: xbmc/addons/Repository.cpp @@ -16465,16 +16440,19 @@ msgstr "" #empty string with id 35013 #. Help text of the button to fix the bug where buttons are skipped in the controller dialog. %s - list of disabled buttons and axes +#: xbmc/games/controllers/dialogs/GUIDialogButtonCapture.cpp msgctxt "#35014" msgid "Some controllers have buttons and axes that interfere with mapping. Press these now to disable them:[CR]%s" msgstr "" -#. Name of a controller button, e.g. Button 1. %d - button index +#. Name of a controller button, e.g. "Button 1". %d - button index +#: xbmc/input/joysticks/JoystickTranslator.cpp msgctxt "#35015" msgid "Button %d" msgstr "" -#. Name of a controller axis, e.g. Axis 2. %d - axis index +#. Name of a controller axis, e.g. "Axis 2". %d - axis index +#: xbmc/input/joysticks/JoystickTranslator.cpp msgctxt "#35016" msgid "Axis %d" msgstr "" @@ -16498,7 +16476,13 @@ msgctxt "#35019" msgid "Ignore input" msgstr "" -#empty strings from id 35020 to 35048 +#. Help text of the dialog to detect analog buttons on controllers. %s - list of detected axes +#: xbmc/games/controllers/dialogs/GUIDialogAxisDetection.cpp +msgctxt "#35020" +msgid "Press all analog buttons now to detect them:[CR][CR]%s" +msgstr "" + +#empty strings from id 35021 to 35048 #. Name of game add-ons category #: xbmc/addons/Addon.cpp @@ -20254,7 +20238,13 @@ msgctxt "#38061" msgid "Fetch additional information for albums and artists? This could take some time so you may prefer to do this later" msgstr "" -#empty strings from id 38062 to 38099 +#. Full tag scanning question on library update (by default tags are only scanned when the file has changed since last time) +#: xbmc/Application.cpp +msgctxt "#38062" +msgid "Do full tag scan even when music files are unchanged?" +msgstr "" + +#empty strings from id 38063 to 38099 #. Description of section #14200 "Player"" #: system/settings/settings.xml @@ -20424,3 +20414,8 @@ msgstr "" msgctxt "#39014" msgid "Would you also like to remove all related data (e.g. settings) of this add-on?" msgstr "" + +#: /xbmc/addons/Addon.cpp +msgctxt "#39015" +msgid "Image decoder" +msgstr "" diff --git a/addons/skin.estouchy/xml/CustomVolume.xml b/addons/skin.estouchy/xml/CustomVolume.xml index df87f5e7c7..4a94a1a8e8 100644 --- a/addons/skin.estouchy/xml/CustomVolume.xml +++ b/addons/skin.estouchy/xml/CustomVolume.xml @@ -11,7 +11,7 @@ <texturenofocus></texturenofocus> <texturefocus></texturefocus> <onclick>Back</onclick> - <visible>![Window.IsVisible(Notification) | Window.IsVisible(VolumeBar)]</visible> + <visible>![Window.IsVisible(Notification) | Window.IsVisible(VolumeBar) | Window.IsVisible(SeekBar)]</visible> </control> <control type="group"> <posx>430</posx> @@ -19,7 +19,7 @@ <width>420</width> <height>78</height> <include>16x9_xPos_Relocation</include> - <visible>![Window.IsVisible(Notification) | Window.IsVisible(VolumeBar)]</visible> + <visible>![Window.IsVisible(Notification) | Window.IsVisible(VolumeBar) | Window.IsVisible(SeekBar)]</visible> <control type="label"> <description>label</description> <posx>20</posx> diff --git a/addons/skin.estouchy/xml/DialogSeekBar.xml b/addons/skin.estouchy/xml/DialogSeekBar.xml index bfe6d61c65..64bd320f01 100644 --- a/addons/skin.estouchy/xml/DialogSeekBar.xml +++ b/addons/skin.estouchy/xml/DialogSeekBar.xml @@ -1,3 +1,69 @@ <?xml version="1.0" encoding="UTF-8"?> <window> + <visible>[Window.IsActive(FullscreenVideo) | Window.IsActive(Visualisation)] + ![Window.IsActive(VideoOSD) | Window.IsActive(MusicOSD)] + [Player.Seeking | Player.DisplayAfterSeek]</visible> + <controls> + <control type="group"> + <posx>364</posx> + <posy>10</posy> + <include>VisibleFadeEffect</include> + <control type="label"> + <posx>0</posx> + <posy>0</posy> + <width>180</width> + <height>32</height> + <font>font20_title</font> + <aligny>center</aligny> + <label>$INFO[Player.Time(hh:mm:ss)]</label> + </control> + <control type="label"> + <posx>0</posx> + <posy>0</posy> + <width>552</width> + <height>32</height> + <font>font20_title</font> + <align>center</align> + <aligny>center</aligny> + <label>$VAR[SeekLabel]</label> + </control> + <control type="label"> + <posx>552</posx> + <posy>0</posy> + <width>180</width> + <height>32</height> + <font>font20_title</font> + <align>right</align> + <aligny>center</aligny> + <label>$INFO[Player.Duration(hh:mm:ss)]</label> + </control> + <control type="progress"> + <description>Progressbar</description> + <posx>0</posx> + <posy>40</posy> + <width>552</width> + <height>12</height> + <info>Player.Cache</info> + <midtexture colordiffuse="grey2">white.png</midtexture> + <texturebg></texturebg> + </control> + <control type="progress"> + <description>Progressbar</description> + <posx>0</posx> + <posy>40</posy> + <width>552</width> + <height>12</height> + <info>Player.Progress</info> + </control> + <control type="slider" id="87"> + <description>Seek Slider</description> + <posx>0</posx> + <posy>30</posy> + <width>552</width> + <height>32</height> + <action>seek</action> + <texturesliderbar></texturesliderbar> + <textureslidernib></textureslidernib> + <textureslidernibfocus></textureslidernibfocus> + </control> + </control> + </controls> </window> diff --git a/addons/skin.estouchy/xml/SlideShow.xml b/addons/skin.estouchy/xml/SlideShow.xml index bfe6d61c65..e27f40ac2d 100644 --- a/addons/skin.estouchy/xml/SlideShow.xml +++ b/addons/skin.estouchy/xml/SlideShow.xml @@ -1,3 +1,13 @@ <?xml version="1.0" encoding="UTF-8"?> <window> + <controls> + <control type="image"> + <centerleft>50%</centerleft> + <centertop>50%</centertop> + <width>283</width> + <height>283</height> + <texture>icon_settings_player.png</texture> + <visible>SlideShow.IsVideo + [![Player.Playing + Player.HasVideo] | SlideShow.IsPaused]</visible> + </control> + </controls> </window> diff --git a/addons/skin.estouchy/xml/ViewsList.xml b/addons/skin.estouchy/xml/ViewsList.xml index ad100fd8c9..e0c32771b4 100644 --- a/addons/skin.estouchy/xml/ViewsList.xml +++ b/addons/skin.estouchy/xml/ViewsList.xml @@ -42,7 +42,7 @@ <height>62</height> <texture background="true">$VAR[PosterThumb]</texture> <aspectratio>keep</aspectratio> - <visible>Container.Content(Movies) | Container.Content(Seasons) | Container.Content(TVShows) | Container.Content(Episodes) | Container.Content(MusicVideos) | Container.Content(Artists) | Container.Content(Albums) | Container.Content(Songs) | [Container.Content(Addons) + !ListItem.IsFolder] | Container.Content(Actors) | Container.Content(Sets) | [Window.IsVisible(Pictures) + !String.IsEmpty(Container.FolderPath)]</visible> + <visible>Container.Content(Movies) | Container.Content(Seasons) | Container.Content(TVShows) | Container.Content(Episodes) | Container.Content(MusicVideos) | Container.Content(Videos) | Container.Content(Artists) | Container.Content(Albums) | Container.Content(Songs) | [Container.Content(Addons) + !ListItem.IsFolder] | Container.Content(Actors) | Container.Content(Sets) | [Window.IsVisible(Pictures) + !String.IsEmpty(Container.FolderPath)]</visible> </control> <control type="image"> <posx>4</posx> @@ -74,7 +74,7 @@ <align>right</align> <aligny>center</aligny> <label>$INFO[ListItem.Label2]</label> - <animation effect="slide" start="0" end ="100,0" time="0" condition="![Container.Content(Movies) | Container.Content(Episodes) | Container.Content(MusicVideos)]">Conditional</animation> + <animation effect="slide" start="0" end ="100,0" time="0" condition="![Container.Content(Movies) | Container.Content(Episodes) | Container.Content(MusicVideos) | Container.Content(Videos)]">Conditional</animation> <animation effect="slide" start="0" end ="-40,0" time="0" condition="Container.Content(TVShows)">Conditional</animation> <visible>!Window.IsVisible(AddonBrowser)</visible> </control> @@ -105,7 +105,7 @@ <width>60</width> <height>40</height> <texture>$INFO[ListItem.VideoResolution,flagging/resolution/,.png]</texture> - <visible>[Container.Content(Movies) | Container.Content(Episodes) | Container.Content(MusicVideos)]</visible> + <visible>[Container.Content(Movies) | Container.Content(Episodes) | Container.Content(MusicVideos) | Container.Content(Videos)]</visible> </control> <control type="image"> <posx>110r</posx> @@ -122,7 +122,7 @@ <height>26</height> <aspectratio>keep</aspectratio> <texture>OverlayWatching.png</texture> - <visible>[Container.Content(Movies) | Container.Content(Episodes) | Container.Content(MusicVideos)] + ListItem.IsResumable</visible> + <visible>[Container.Content(Movies) | Container.Content(Episodes) | Container.Content(MusicVideos) | Container.Content(Videos)] + ListItem.IsResumable</visible> </control> <control type="image"> <posx>50r</posx> @@ -130,7 +130,7 @@ <width>30</width> <height>30</height> <texture>$INFO[ListItem.Overlay]</texture> - <visible>[Container.Content(Movies) | Container.Content(TVShows) | Container.Content(Seasons) | Container.Content(Episodes) | Container.Content(MusicVideos)] + !ListItem.IsResumable</visible> + <visible>[Container.Content(Movies) | Container.Content(TVShows) | Container.Content(Seasons) | Container.Content(Episodes) | Container.Content(MusicVideos) | Container.Content(Videos)] + !ListItem.IsResumable</visible> </control> <control type="label"> <posx>$PARAM[label2-posx]</posx> @@ -184,7 +184,7 @@ <height>62</height> <texture background="true">$VAR[PosterThumb]</texture> <aspectratio>keep</aspectratio> - <visible>Container.Content(Movies) | Container.Content(Seasons) | Container.Content(TVShows) | Container.Content(Episodes) | Container.Content(MusicVideos) | Container.Content(Artists) | Container.Content(Albums) | Container.Content(Songs) | [Container.Content(Addons) + !ListItem.IsFolder] | Container.Content(Actors) | Container.Content(Sets) | [Window.IsVisible(Pictures) + !String.IsEmpty(Container.FolderPath)]</visible> + <visible>Container.Content(Movies) | Container.Content(Seasons) | Container.Content(TVShows) | Container.Content(Episodes) | Container.Content(MusicVideos) | Container.Content(Videos) | Container.Content(Artists) | Container.Content(Albums) | Container.Content(Songs) | [Container.Content(Addons) + !ListItem.IsFolder] | Container.Content(Actors) | Container.Content(Sets) | [Window.IsVisible(Pictures) + !String.IsEmpty(Container.FolderPath)]</visible> </control> <control type="image"> <posx>4</posx> @@ -216,7 +216,7 @@ <align>right</align> <aligny>center</aligny> <label>$INFO[ListItem.Label2]</label> - <animation effect="slide" start="0" end ="100,0" time="0" condition="![Container.Content(Movies) | Container.Content(Episodes) | Container.Content(MusicVideos)]">Conditional</animation> + <animation effect="slide" start="0" end ="100,0" time="0" condition="![Container.Content(Movies) | Container.Content(Episodes) | Container.Content(MusicVideos) | Container.Content(Videos)]">Conditional</animation> <animation effect="slide" start="0" end ="-40,0" time="0" condition="Container.Content(TVShows)">Conditional</animation> <visible>!Window.IsVisible(AddonBrowser)</visible> </control> @@ -247,7 +247,7 @@ <width>60</width> <height>40</height> <texture>$INFO[ListItem.VideoResolution,flagging/resolution/,.png]</texture> - <visible>[Container.Content(Movies) | Container.Content(Episodes) | Container.Content(MusicVideos)]</visible> + <visible>[Container.Content(Movies) | Container.Content(Episodes) | Container.Content(MusicVideos) | Container.Content(Videos)]</visible> </control> <control type="image"> <posx>110r</posx> @@ -264,7 +264,7 @@ <height>26</height> <aspectratio>keep</aspectratio> <texture>OverlayWatching.png</texture> - <visible>[Container.Content(Movies) | Container.Content(Episodes) | Container.Content(MusicVideos)] + ListItem.IsResumable</visible> + <visible>[Container.Content(Movies) | Container.Content(Episodes) | Container.Content(MusicVideos) | Container.Content(Videos)] + ListItem.IsResumable</visible> </control> <control type="image"> <posx>50r</posx> @@ -272,7 +272,7 @@ <width>30</width> <height>30</height> <texture>$INFO[ListItem.Overlay]</texture> - <visible>[Container.Content(Movies) | Container.Content(TVShows) | Container.Content(Seasons) | Container.Content(Episodes) | Container.Content(MusicVideos)] + !ListItem.IsResumable</visible> + <visible>[Container.Content(Movies) | Container.Content(TVShows) | Container.Content(Seasons) | Container.Content(Episodes) | Container.Content(MusicVideos) | Container.Content(Videos)] + !ListItem.IsResumable</visible> </control> <control type="label"> <posx>$PARAM[label2-posx]</posx> diff --git a/addons/skin.estouchy/xml/ViewsThumbnail.xml b/addons/skin.estouchy/xml/ViewsThumbnail.xml index fcc599a9ac..a3e4dade5a 100644 --- a/addons/skin.estouchy/xml/ViewsThumbnail.xml +++ b/addons/skin.estouchy/xml/ViewsThumbnail.xml @@ -17,7 +17,7 @@ <animation effect="slide" start="0,0" end="-1,0" time="0" condition="String.IsEqual(Skin.AspectRatio,4:3)">Conditional</animation> <animation effect="slide" start="0,0" end="-1,0" time="0" condition="String.IsEqual(Skin.AspectRatio,16:9) + Container.Content(Episodes)">Conditional</animation> <animation effect="slide" start="0,0" end="28,0" time="0" condition="String.IsEqual(Skin.AspectRatio,4:3) + Container.Content(Episodes)">Conditional</animation> - <itemlayout condition="!Container.Content(Movies) + !Container.Content(Seasons) + !Container.Content(Episodes) + !Container.Content(TVShows) + !Container.Content(MusicVideos)" height="250" width="218"> + <itemlayout condition="!Container.Content(Movies) + !Container.Content(Seasons) + !Container.Content(Episodes) + !Container.Content(TVShows) + !Container.Content(MusicVideos) + !Container.Content(Videos)" height="250" width="218"> <control type="image"> <posx>5</posx> <posy>0</posy> @@ -73,7 +73,7 @@ <visible>Window.IsVisible(AddonBrowser) + String.IsEqual(ListItem.Label2,$LOCALIZE[305])</visible> </control> </itemlayout> - <focusedlayout condition="!Container.Content(Movies) + !Container.Content(Seasons) + !Container.Content(Episodes) + !Container.Content(TVShows) + !Container.Content(MusicVideos)" height="250" width="218"> + <focusedlayout condition="!Container.Content(Movies) + !Container.Content(Seasons) + !Container.Content(Episodes) + !Container.Content(TVShows) + !Container.Content(MusicVideos) + !Container.Content(Videos)" height="250" width="218"> <control type="image"> <posx>5</posx> <posy>0</posy> @@ -247,7 +247,7 @@ <texture>$INFO[ListItem.Overlay]</texture> </control> </focusedlayout> - <itemlayout condition="Container.Content(Episodes) | Container.Content(MusicVideos)" height="250" width="$PARAM[layout-width]"> + <itemlayout condition="Container.Content(Episodes) | Container.Content(MusicVideos) | Container.Content(Videos)" height="250" width="$PARAM[layout-width]"> <control type="image"> <posx>0</posx> <posy>0</posy> @@ -298,7 +298,7 @@ <texture>$INFO[ListItem.Overlay]</texture> </control> </itemlayout> - <focusedlayout condition="Container.Content(Episodes) | Container.Content(MusicVideos)" height="250" width="$PARAM[layout-width]"> + <focusedlayout condition="Container.Content(Episodes) | Container.Content(MusicVideos) | Container.Content(Videos)" height="250" width="$PARAM[layout-width]"> <control type="image"> <posx>0</posx> <posy>0</posy> diff --git a/addons/skin.estuary/xml/AddonBrowser.xml b/addons/skin.estuary/xml/AddonBrowser.xml index f3ee214b28..dd211bcc78 100644 --- a/addons/skin.estuary/xml/AddonBrowser.xml +++ b/addons/skin.estuary/xml/AddonBrowser.xml @@ -63,7 +63,7 @@ <control type="group"> <height>78</height> <bottom>0</bottom> - <visible>$EXP[sidebar_focused]</visible> + <visible>$EXP[sidebar_visible]</visible> <animation effect="fade" time="300">VisibleChange</animation> <include content="LeftAlignedInfo"> <param name="main_label" value="$INFO[Window(AddonBrowser).Property(Updated)]" /> diff --git a/addons/skin.estuary/xml/Constants_1920.xml b/addons/skin.estuary/xml/Constants_1920.xml index d85f2d53d2..f9b714beff 100644 --- a/addons/skin.estuary/xml/Constants_1920.xml +++ b/addons/skin.estuary/xml/Constants_1920.xml @@ -7,5 +7,5 @@ <constant name="tvrecordings_width">1060</constant> <constant name="eventloglist_width">1430</constant> <constant name="playlisteditorlist_width">770</constant> - <constant name="playlistlist_width">904</constant> + <constant name="playlistlist_width">896</constant> </includes> diff --git a/addons/skin.estuary/xml/Constants_2560.xml b/addons/skin.estuary/xml/Constants_2560.xml index fea8fc5886..ba83217abd 100644 --- a/addons/skin.estuary/xml/Constants_2560.xml +++ b/addons/skin.estuary/xml/Constants_2560.xml @@ -7,5 +7,5 @@ <constant name="tvrecordings_width">1700</constant> <constant name="eventloglist_width">2070</constant> <constant name="playlisteditorlist_width">1410</constant> - <constant name="playlistlist_width">1544</constant> + <constant name="playlistlist_width">1536</constant> </includes> diff --git a/addons/skin.estuary/xml/DialogMusicInfo.xml b/addons/skin.estuary/xml/DialogMusicInfo.xml index 4f895ab4e2..08940cc059 100644 --- a/addons/skin.estuary/xml/DialogMusicInfo.xml +++ b/addons/skin.estuary/xml/DialogMusicInfo.xml @@ -31,7 +31,7 @@ <height>567</height> <aspectratio aligny="top">scale</aspectratio> <fadetime>300</fadetime> - <texture background="true" fallback="DefaultAudio.png">$INFO[ListItem.Art(thumb)]</texture> + <texture background="true">$VAR[MusicInfoThumbVar]</texture> </control> </control> <control type="group"> diff --git a/addons/skin.estuary/xml/Includes.xml b/addons/skin.estuary/xml/Includes.xml index b3f7993305..205e0ea551 100644 --- a/addons/skin.estuary/xml/Includes.xml +++ b/addons/skin.estuary/xml/Includes.xml @@ -34,7 +34,7 @@ <constant name="list_y_offset">0</constant> <constant name="list_item_height">80</constant> <expression name="infodialog_active">Window.IsActive(musicinformation) | Window.IsActive(songinformation) | Window.IsActive(movieinformation) | Window.IsActive(addoninformation) | Window.IsActive(pvrguideinfo) | Window.IsActive(pvrrecordinginfo) | Window.IsActive(pictureinfo) | Window.IsVisible(script-script.extendedinfo-DialogVideoInfo.xml) | Window.IsVisible(script-script.extendedinfo-DialogInfo.xml) | Window.IsVisible(script-script.extendedinfo-VideoList.xml)</expression> - <expression name="sidebar_focused">ControlGroup(9000).HasFocus | Control.HasFocus(6130)</expression> + <expression name="sidebar_visible">ControlGroup(9000).HasFocus | Control.HasFocus(6130) | Window.IsActive(MyPlaylist.xml)</expression> <include name="CommonScrollbars"> <control type="group"> <animation effect="fade" start="100" end="0" time="150">WindowClose</animation> @@ -320,6 +320,7 @@ <font>$PARAM[font]</font> <aligny>center</aligny> <label>$INFO[ListItem.Label]</label> + <scroll>true</scroll> </control> </focusedlayout> </definition> diff --git a/addons/skin.estuary/xml/Includes_MediaMenu.xml b/addons/skin.estuary/xml/Includes_MediaMenu.xml index 89cb087b65..9a3c103748 100644 --- a/addons/skin.estuary/xml/Includes_MediaMenu.xml +++ b/addons/skin.estuary/xml/Includes_MediaMenu.xml @@ -198,7 +198,7 @@ <onleft>14100</onleft> <onup>8</onup> <ondown>6056</ondown> - <visible>Player.HasMedia + [$EXP[sidebar_focused]]</visible> + <visible>Player.HasMedia + [$EXP[sidebar_visible]]</visible> <visible>!System.HasActiveModalDialog</visible> <include content="BottomMainMenuToggleItem"> <param name="control_id" value="14101" /> @@ -241,7 +241,7 @@ <include>OpenClose_Left</include> <depth>DepthSideBlade</depth> <left>-520</left> - <animation type="Conditional" condition="$EXP[sidebar_focused]" reversible="true"> + <animation type="Conditional" condition="$EXP[sidebar_visible]" reversible="true"> <effect type="slide" start="0" end="520" time="400" tween="cubic" easing="out" /> </animation> <control type="image"> @@ -249,7 +249,7 @@ <height>100%</height> <aspectratio>scale</aspectratio> <texture colordiffuse="80FFFFFF">colors/black.png</texture> - <visible>$EXP[sidebar_focused] + !System.HasActiveModalDialog</visible> + <visible>$EXP[sidebar_visible] + !System.HasActiveModalDialog</visible> <animation effect="fade" time="200">VisibleChange</animation> </control> <control type="image"> @@ -269,41 +269,45 @@ </control> </include> <include name="MediaMenuNowPlaying"> - <control type="grouplist" id="14100"> - <animation effect="fade" start="0" end="100" time="400">WindowOpen</animation> - <animation effect="fade" start="100" end="0" time="300">WindowClose</animation> - <animation effect="fade" time="300">VisibleChange</animation> - <orientation>horizontal</orientation> - <itemgap>-17</itemgap> - <left>5</left> - <onleft>14100</onleft> - <width>450</width> - <visible>Player.HasMedia + [$EXP[sidebar_focused]]</visible> - <visible>!System.HasActiveModalDialog</visible> - <include content="BottomMainMenuToggleItem"> - <param name="control_id" value="14101" /> - <param name="onclick" value="PlayerControl(Play)" /> - <param name="icon_on" value="icons/now-playing/play.png" /> - <param name="icon_off" value="icons/now-playing/pause.png" /> - <param name="selected" value="Player.Paused" /> - </include> - <include content="IconButton"> - <param name="control_id" value="14102" /> - <param name="onclick" value="Stop" /> - <param name="onclick_2" value="SetFocus(50)" /> - <param name="icon" value="icons/now-playing/stop.png" /> - </include> - <include content="IconButton"> - <param name="control_id" value="14104" /> - <param name="onclick" value="PlayerControl(Next)" /> - <param name="icon" value="icons/now-playing/next.png" /> - </include> - <include content="IconButton"> - <param name="control_id" value="14105" /> - <param name="onclick" value="Fullscreen" /> - <param name="icon" value="icons/now-playing/fullscreen.png" /> - </include> - </control> + <param name="left">5</param> + <definition> + <control type="grouplist" id="14100"> + <animation effect="fade" start="0" end="100" time="400">WindowOpen</animation> + <animation effect="fade" start="100" end="0" time="300">WindowClose</animation> + <animation effect="fade" time="300">VisibleChange</animation> + <animation effect="slide" end="-10,0" time="0" condition ="Window.IsActive(MyPlaylist.xml)">Conditional</animation> + <orientation>horizontal</orientation> + <itemgap>-17</itemgap> + <left>$PARAM[left]</left> + <onleft>14100</onleft> + <width>450</width> + <visible>Player.HasMedia + [$EXP[sidebar_visible]]</visible> + <visible>!System.HasActiveModalDialog</visible> + <include content="BottomMainMenuToggleItem"> + <param name="control_id" value="14101" /> + <param name="onclick" value="PlayerControl(Play)" /> + <param name="icon_on" value="icons/now-playing/play.png" /> + <param name="icon_off" value="icons/now-playing/pause.png" /> + <param name="selected" value="Player.Paused" /> + </include> + <include content="IconButton"> + <param name="control_id" value="14102" /> + <param name="onclick" value="Stop" /> + <param name="onclick_2" value="SetFocus(50)" /> + <param name="icon" value="icons/now-playing/stop.png" /> + </include> + <include content="IconButton"> + <param name="control_id" value="14104" /> + <param name="onclick" value="PlayerControl(Next)" /> + <param name="icon" value="icons/now-playing/next.png" /> + </include> + <include content="IconButton"> + <param name="control_id" value="14105" /> + <param name="onclick" value="Fullscreen" /> + <param name="icon" value="icons/now-playing/fullscreen.png" /> + </include> + </control> + </definition> </include> <include name="MediaMenuListCommon"> <definition> @@ -343,7 +347,6 @@ </control> <control type="button" id="19"> <visible>Container.CanFilter + !Container.CanFilterAdvanced</visible> - <visible>!Container.Content()</visible> <include>MediaMenuItemsCommon</include> <label>$LOCALIZE[137]</label> </control> diff --git a/addons/skin.estuary/xml/MyPlaylist.xml b/addons/skin.estuary/xml/MyPlaylist.xml index 51361f04c8..f66dc10734 100644 --- a/addons/skin.estuary/xml/MyPlaylist.xml +++ b/addons/skin.estuary/xml/MyPlaylist.xml @@ -10,9 +10,9 @@ <control type="group"> <include>OpenClose_Left</include> <control type="fixedlist" id="50"> - <left>402</left> + <left>410</left> <top>list_y_offset</top> - <right>594</right> + <right>586</right> <bottom>list_y_offset</bottom> <scrolltime tween="cubic" easing="out">500</scrolltime> <orientation>vertical</orientation> @@ -79,7 +79,7 @@ <control type="group"> <depth>DepthContentPanel</depth> <include content="ContentPanel"> - <param name="width" value="462" /> + <param name="width" value="470" /> </include> <control type="grouplist" id="700"> <orientation>vertical</orientation> @@ -90,9 +90,9 @@ <ondown>700</ondown> <onleft>50</onleft> <onright>50</onright> - <width>402</width> + <width>410</width> <control type="radiobutton" id="20"> - <width>402</width> + <width>410</width> <height>110</height> <align>left</align> <aligny>top</aligny> @@ -115,6 +115,9 @@ <param name="control_id" value="22" /> <param name="label" value="$LOCALIZE[192]" /> </include> + <include content="MediaMenuNowPlaying"> + <param name="left" value="-5" /> + </include> </control> </control> </control> diff --git a/addons/skin.estuary/xml/MyVideoNav.xml b/addons/skin.estuary/xml/MyVideoNav.xml index 8b2b8f8da3..ea67f8e956 100644 --- a/addons/skin.estuary/xml/MyVideoNav.xml +++ b/addons/skin.estuary/xml/MyVideoNav.xml @@ -138,7 +138,7 @@ <include>MediaMenuItemsCommon</include> <label>$LOCALIZE[31056]</label> <onclick>ActivateWindow(videoplaylist)</onclick> - <visible>IntegerGreaterThan(Playlist.Length(video),0)</visible> + <visible>Integer.IsGreater(Playlist.Length(video),0)</visible> </control> <control type="button" id="621"> <description>Get more</description> diff --git a/addons/skin.estuary/xml/SlideShow.xml b/addons/skin.estuary/xml/SlideShow.xml index bfe6d61c65..666f38cbfb 100644 --- a/addons/skin.estuary/xml/SlideShow.xml +++ b/addons/skin.estuary/xml/SlideShow.xml @@ -1,3 +1,13 @@ <?xml version="1.0" encoding="UTF-8"?> <window> + <controls> + <control type="image"> + <centerleft>50%</centerleft> + <centertop>50%</centertop> + <width>256</width> + <height>256</height> + <texture>icons/settings/player.png</texture> + <visible>SlideShow.IsVideo + [![Player.Playing + Player.HasVideo] | SlideShow.IsPaused]</visible> + </control> + </controls> </window> diff --git a/addons/skin.estuary/xml/Variables.xml b/addons/skin.estuary/xml/Variables.xml index 35407add0b..007ed12300 100644 --- a/addons/skin.estuary/xml/Variables.xml +++ b/addons/skin.estuary/xml/Variables.xml @@ -65,6 +65,12 @@ <value condition="ListItem.IsFolder + String.IsEmpty(ListItem.Thumb)">DefaultFolderSquare.png</value> <value>$INFO[ListItem.Thumb]</value> </variable> + <variable name="MusicInfoThumbVar"> + <value condition="!String.IsEmpty(Listitem.Art(thumb))">$INFO[Listitem.Art(thumb)]</value> + <value condition="String.IsEqual(listitem.dbtype,artist)">DefaultArtist.png</value> + <value condition="String.IsEqual(listitem.dbtype,album)">DefaultAlbumCover.png</value> + <value>DefaultAudio.png</value> + </variable> <variable name="InfoWallThumbVar"> <value condition="!String.IsEmpty(Listitem.Art(poster))">$INFO[Listitem.Art(poster)]</value> <value>$INFO[ListItem.Icon]</value> diff --git a/addons/skin.estuary/xml/View_51_Poster.xml b/addons/skin.estuary/xml/View_51_Poster.xml index 2d3b96de61..ff91cb130d 100644 --- a/addons/skin.estuary/xml/View_51_Poster.xml +++ b/addons/skin.estuary/xml/View_51_Poster.xml @@ -190,6 +190,7 @@ <autoscroll time="3000" delay="7000" repeat="5000">!System.HasActiveModalDialog + Skin.HasSetting(AutoScroll)</autoscroll> <label>$INFO[ListItem.Plot]</label> <shadowcolor>text_shadow</shadowcolor> + <visible>!ListItem.IsCollection</visible> </control> </control> </control> diff --git a/addons/skin.estuary/xml/View_55_WideList.xml b/addons/skin.estuary/xml/View_55_WideList.xml index 6652a00893..7ce10ede2e 100644 --- a/addons/skin.estuary/xml/View_55_WideList.xml +++ b/addons/skin.estuary/xml/View_55_WideList.xml @@ -37,7 +37,7 @@ <aligny>center</aligny> <label>$INFO[ListItem.Year]</label> <shadowcolor>text_shadow</shadowcolor> - <visible>!Container.Content(tvshows) + !Container.Content(seasons) + !Container.Content(episodes) + !Container.Content(movies)</visible> + <visible>!Container.Content(tvshows) + !Container.Content(seasons) + !Container.Content(episodes) + !Container.Content(movies) + !Container.Content(videos)</visible> </control> <control type="image"> <left>35</left> @@ -45,7 +45,7 @@ <width>32</width> <height>32</height> <texture>$VAR[ListWatchedIconVar]</texture> - <visible>Container.Content(tvshows) | Container.Content(seasons) | Container.Content(episodes) | Container.Content(movies) | String.IsEmpty(ListItem.Year)</visible> + <visible>Container.Content(tvshows) | Container.Content(seasons) | Container.Content(episodes) | Container.Content(movies) | Container.Content(videos) | String.IsEmpty(ListItem.Year)</visible> </control> <control type="label"> <left>105</left> @@ -78,7 +78,7 @@ <label>$INFO[ListItem.Year]</label> <textcolor>button_focus</textcolor> <shadowcolor>text_shadow</shadowcolor> - <visible>!Container.Content(tvshows) + !Container.Content(seasons) + !Container.Content(episodes) + !Container.Content(movies)</visible> + <visible>!Container.Content(tvshows) + !Container.Content(seasons) + !Container.Content(episodes) + !Container.Content(movies) + !Container.Content(videos)</visible> </control> <control type="image"> <left>35</left> @@ -86,7 +86,7 @@ <width>32</width> <height>32</height> <texture colordiffuse="grey">$VAR[ListWatchedIconVar]</texture> - <visible>Container.Content(tvshows) | Container.Content(seasons) | Container.Content(episodes) | Container.Content(movies) | String.IsEmpty(ListItem.Year)</visible> + <visible>Container.Content(tvshows) | Container.Content(seasons) | Container.Content(episodes) | Container.Content(movies) | Container.Content(videos) | String.IsEmpty(ListItem.Year)</visible> </control> <control type="label"> <left>105</left> diff --git a/cmake/cpack/deb/packages/kodi-image-dev.txt.in b/cmake/cpack/deb/packages/kodi-image-dev.txt.in new file mode 100644 index 0000000000..e9b72f144e --- /dev/null +++ b/cmake/cpack/deb/packages/kodi-image-dev.txt.in @@ -0,0 +1,25 @@ +# kodi-image-dev debian package metadata +# +# Setting PACKAGE_SHLIBDEPS to 'ON' will cause CPack to use dpkg-shlibdeps to +# automatically generate the package dependency list and append its output to +# PACKAGE_DEPENDS list. Only useful for packages that contain binaries. +# +# PACKAGE_ARCHITECTURE should be set to 'all' only if package contains +# architecture agnostic data. CPack will set proper architecture (amd64/i386/etc) +# based on build options. +# +# Remaining settings are (hopefully) self-explanatory. + +PACKAGE_NAME @APP_NAME_LC@-image-dev +PACKAGE_ARCHITECTURE all +PACKAGE_SECTION libdevel +PACKAGE_PRIORITY optional +PACKAGE_SHLIBDEPS +PACKAGE_DEPENDS @APP_NAME_LC@-addon-dev +PACKAGE_RECOMMENDS +PACKAGE_SUGGESTS +PACKAGE_BREAKS +PACKAGE_REPLACES +PACKAGE_PROVIDES xbmc-image-dev +PACKAGE_DESCRIPTION_HEADER @APP_NAME@ Media Center (image add-ons dev package) +PACKAGE_DESCRIPTION_FOOTER This is the development package for @APP_NAME@'s image add-ons. diff --git a/cmake/installdata/common/addons.txt b/cmake/installdata/common/addons.txt index ad951eced6..0c8f296b59 100644 --- a/cmake/installdata/common/addons.txt +++ b/cmake/installdata/common/addons.txt @@ -5,6 +5,7 @@ addons/game.controller.default/* addons/kodi.adsp/* addons/kodi.audiodecoder/* addons/kodi.game/* +addons/kodi.imagedecoder/* addons/kodi.inputstream/* addons/kodi.peripheral/* addons/kodi.resource/* diff --git a/cmake/modules/FindEMBEDDED.cmake b/cmake/modules/FindEMBEDDED.cmake index 5e49716549..8034c4e959 100644 --- a/cmake/modules/FindEMBEDDED.cmake +++ b/cmake/modules/FindEMBEDDED.cmake @@ -13,4 +13,4 @@ if(NOT KODI_DEPENDSBUILD AND NOT TARGET_ARCH_ARM) return() endif() -find_path(EMBEDDED_FOUND NAMES include/linux/imxfb.h include/bcm_host.h PATHS /opt/vc) +find_path(EMBEDDED_FOUND NAMES include/linux/mxcfb.h include/bcm_host.h PATHS /opt/vc) diff --git a/cmake/modules/FindSSE.cmake b/cmake/modules/FindSSE.cmake index 055466367b..ba9fb541ed 100644 --- a/cmake/modules/FindSSE.cmake +++ b/cmake/modules/FindSSE.cmake @@ -14,13 +14,10 @@ if(CMAKE_SYSTEM_NAME MATCHES "Linux") string(COMPARE EQUAL "sse2" "${_SSE_THERE}" _SSE2_TRUE) CHECK_CXX_ACCEPTS_FLAG("-msse2" _SSE2_OK) - # /proc/cpuinfo apparently omits sse3 :( - string(REGEX REPLACE "^.*[^s](sse3).*$" "\\1" _SSE_THERE ${CPUINFO}) - string(COMPARE EQUAL "sse3" "${_SSE_THERE}" _SSE3_TRUE) - if(NOT _SSE3_TRUE) - string(REGEX REPLACE "^.*(T2300).*$" "\\1" _SSE_THERE ${CPUINFO}) - string(COMPARE EQUAL "T2300" "${_SSE_THERE}" _SSE3_TRUE) - endif() + # SSE3 is also known as the Prescott New Instructions (PNI) + # it's labeled as pni in /proc/cpuinfo + string(REGEX REPLACE "^.*(pni).*$" "\\1" _SSE_THERE ${CPUINFO}) + string(COMPARE EQUAL "pni" "${_SSE_THERE}" _SSE3_TRUE) CHECK_CXX_ACCEPTS_FLAG("-msse3" _SSE3_OK) string(REGEX REPLACE "^.*(ssse3).*$" "\\1" _SSE_THERE ${CPUINFO}) diff --git a/cmake/scripts/ios/ArchSetup.cmake b/cmake/scripts/ios/ArchSetup.cmake index bdd2656c1b..dbb7c4858e 100644 --- a/cmake/scripts/ios/ArchSetup.cmake +++ b/cmake/scripts/ios/ArchSetup.cmake @@ -36,7 +36,7 @@ list(APPEND DEPLIBS "-framework CoreFoundation" "-framework CoreVideo" set(ENABLE_DVDCSS OFF CACHE BOOL "" FORCE) set(ENABLE_OPTICAL OFF CACHE BOOL "" FORCE) -set(CMAKE_XCODE_ATTRIBUTE_IPHONEOS_DEPLOYMENT_TARGET "5.1") +set(CMAKE_XCODE_ATTRIBUTE_IPHONEOS_DEPLOYMENT_TARGET "6.0") set(CMAKE_XCODE_ATTRIBUTE_TARGETED_DEVICE_FAMILY "1,2") set(CMAKE_XCODE_ATTRIBUTE_INLINES_ARE_PRIVATE_EXTERN OFF) diff --git a/cmake/scripts/linux/Install.cmake b/cmake/scripts/linux/Install.cmake index 7c96e8f3ae..0462c77a11 100644 --- a/cmake/scripts/linux/Install.cmake +++ b/cmake/scripts/linux/Install.cmake @@ -196,6 +196,12 @@ install(FILES ${CMAKE_SOURCE_DIR}/xbmc/cores/AudioEngine/Utils/AEChannelData.h DESTINATION ${includedir}/${APP_NAME_LC} COMPONENT kodi-audio-dev) +# Install kodi-image-dev +install(FILES ${CMAKE_SOURCE_DIR}/xbmc/addons/kodi-addon-dev-kit/include/kodi/kodi_imagedec_types.h + ${CMAKE_SOURCE_DIR}/xbmc/addons/kodi-addon-dev-kit/include/kodi/kodi_imagedec_dll.h + DESTINATION ${includedir}/${APP_NAME_LC} + COMPONENT kodi-image-dev) + if(ENABLE_EVENTCLIENTS) # Install kodi-eventclients-common BT python files install(PROGRAMS ${CMAKE_SOURCE_DIR}/tools/EventClients/lib/python/bt/__init__.py diff --git a/cmake/treedata/common/video.txt b/cmake/treedata/common/video.txt index e7855a0809..acfb33bf57 100644 --- a/cmake/treedata/common/video.txt +++ b/cmake/treedata/common/video.txt @@ -1,5 +1,4 @@ xbmc/video video xbmc/video/dialogs video/dialogs xbmc/video/jobs video/jobs -xbmc/video/videosync video/sync xbmc/video/windows video/windows diff --git a/docs/README.android b/docs/README.android index d8e43b619c..8fb67a71f2 100644 --- a/docs/README.android +++ b/docs/README.android @@ -1,8 +1,8 @@ TOC 1. Introduction -2. Installing and setting up the Android environment -3. Getting the source code -4. Installing the required Ubuntu packages +2. Installing the required Ubuntu packages +3. Installing and setting up the Android environment +4. Getting the source code 5. How to compile 6. Installing Kodi in an Android system 7. Running and debugging Kodi in an Android system diff --git a/docs/README.ios.md b/docs/README.ios.md index 0a3adb56da..c7f9332153 100644 --- a/docs/README.ios.md +++ b/docs/README.ios.md @@ -60,6 +60,8 @@ constellations of Xcode and macOS versions (to be updated once we know more): 5. Xcode 7.x against iOS SDK 9.x on 10.10 (Yosemite) 6. Xcode 7.x against iOS SDK 9.x on 10.11 (El Capitan) 7. Xcode 7.x against iOS SDK 9.x on 10.12 (Sierra) +8. Xcode 8.x against iOS SDK 10.x (El Capitan) +9. Xcode 8.x against iOS SDK 10.x (Sierra) The preferred iOS SDK Version is 8.1. diff --git a/docs/README.raspberrypi b/docs/README.raspberrypi index b13d763c91..29eaa86273 100644 --- a/docs/README.raspberrypi +++ b/docs/README.raspberrypi @@ -32,8 +32,8 @@ build for the first Raspberry Pi, the commands have to be adapted to use $ sudo mkdir -p /opt/bcm-rootfs/opt $ sudo cp -r firmware/opt/vc /opt/bcm-rootfs/opt - $ sudo mkdir -p /opt/xbmc-bcm - $ sudo chmod 777 /opt/xbmc-bcm + $ sudo mkdir -p /opt/kodi-bcm + $ sudo chmod 777 /opt/kodi-bcm $ git clone https://github.com/xbmc/xbmc @@ -41,7 +41,7 @@ build for the first Raspberry Pi, the commands have to be adapted to use $ ./bootstrap $ PATH="$PATH:/opt/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin" \ ./configure --host=arm-linux-gnueabihf \ - --prefix=/opt/xbmc-bcm/xbmc-dbg \ + --prefix=/opt/kodi-bcm/kodi-dbg \ --with-toolchain=/usr/local/bcm-gcc/arm-bcm2708hardfp-linux-gnueabi/sysroot \ --with-firmware=/opt/bcm-rootfs \ --with-platform=raspberry-pi2 \ diff --git a/system/addon-manifest.xml b/system/addon-manifest.xml index fd7737470e..8d557bde9d 100644 --- a/system/addon-manifest.xml +++ b/system/addon-manifest.xml @@ -6,6 +6,7 @@ <addon>kodi.audiodecoder</addon> <addon>kodi.game</addon> <addon>kodi.guilib</addon> + <addon>kodi.imagedecoder</addon> <addon>kodi.inputstream</addon> <addon>kodi.peripheral</addon> <addon>kodi.resource</addon> diff --git a/system/library/video/movies/actors.xml b/system/library/video/movies/actors.xml index 48a0912272..ceccc45dc9 100644 --- a/system/library/video/movies/actors.xml +++ b/system/library/video/movies/actors.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" standalone="yes" ?> -<node order="4" type="filter"> +<node order="5" type="filter"> <label>344</label> <icon>DefaultActor.png</icon> <content>movies</content> diff --git a/system/library/video/movies/country.xml b/system/library/video/movies/country.xml index 1b68b82201..2f5a54f6d0 100644 --- a/system/library/video/movies/country.xml +++ b/system/library/video/movies/country.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" standalone="yes" ?> -<node order="8" type="filter"> +<node order="9" type="filter"> <label>20451</label> <icon>DefaultCountry.png</icon> <content>movies</content> diff --git a/system/library/video/movies/directors.xml b/system/library/video/movies/directors.xml index f074dcb6c0..60c672442f 100644 --- a/system/library/video/movies/directors.xml +++ b/system/library/video/movies/directors.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" standalone="yes" ?> -<node order="5" type="filter"> +<node order="6" type="filter"> <label>20348</label> <icon>DefaultDirector.png</icon> <content>movies</content> diff --git a/system/library/video/movies/genres.xml b/system/library/video/movies/genres.xml index 1764b03ed3..d57c7069dd 100644 --- a/system/library/video/movies/genres.xml +++ b/system/library/video/movies/genres.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" standalone="yes" ?> -<node order="1" type="filter"> +<node order="2" type="filter"> <label>135</label> <icon>DefaultGenre.png</icon> <content>movies</content> diff --git a/system/library/video/movies/recentlyaddedmovies.xml b/system/library/video/movies/recentlyaddedmovies.xml index 721d45237a..e61c22af2e 100644 --- a/system/library/video/movies/recentlyaddedmovies.xml +++ b/system/library/video/movies/recentlyaddedmovies.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8" standalone="yes" ?> -<node order="10" type="folder"> - <label>20386</label> +<node order="1" type="folder"> + <label>20382</label> <icon>DefaultRecentlyAddedMovies.png</icon> <path>videodb://recentlyaddedmovies/</path> </node> diff --git a/system/library/video/movies/sets.xml b/system/library/video/movies/sets.xml index 4f1e065b30..e8e9491907 100644 --- a/system/library/video/movies/sets.xml +++ b/system/library/video/movies/sets.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" standalone="yes" ?> -<node order="7" type="filter" visible="Library.HasContent(MovieSets)"> +<node order="8" type="filter" visible="Library.HasContent(MovieSets)"> <label>20434</label> <icon>DefaultSets.png</icon> <content>movies</content> diff --git a/system/library/video/movies/studios.xml b/system/library/video/movies/studios.xml index 6dd1f77ed8..d167cb8945 100644 --- a/system/library/video/movies/studios.xml +++ b/system/library/video/movies/studios.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" standalone="yes" ?> -<node order="6" type="filter"> +<node order="7" type="filter"> <label>20388</label> <icon>DefaultStudios.png</icon> <content>movies</content> diff --git a/system/library/video/movies/tags.xml b/system/library/video/movies/tags.xml index f2f09c370e..92b6521b2e 100644 --- a/system/library/video/movies/tags.xml +++ b/system/library/video/movies/tags.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" standalone="yes" ?> -<node order="9" type="filter"> +<node order="10" type="filter"> <label>20459</label> <icon>DefaultTags.png</icon> <content>movies</content> diff --git a/system/library/video/movies/titles.xml b/system/library/video/movies/titles.xml index ec41450b2f..9dfd483080 100644 --- a/system/library/video/movies/titles.xml +++ b/system/library/video/movies/titles.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" standalone="yes" ?> -<node order="2" type="filter"> +<node order="3" type="filter"> <label>10024</label> <icon>DefaultMovieTitle.png</icon> <content>movies</content> diff --git a/system/library/video/movies/years.xml b/system/library/video/movies/years.xml index 234bd9a963..30217f7740 100644 --- a/system/library/video/movies/years.xml +++ b/system/library/video/movies/years.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" standalone="yes" ?> -<node order="3" type="filter"> +<node order="4" type="filter"> <label>652</label> <icon>DefaultYear.png</icon> <content>movies</content> diff --git a/system/library/video/musicvideos/albums.xml b/system/library/video/musicvideos/albums.xml index ce44b5b6d6..ee0fbf9574 100644 --- a/system/library/video/musicvideos/albums.xml +++ b/system/library/video/musicvideos/albums.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" standalone="yes" ?> -<node order="5" type="filter"> +<node order="6" type="filter"> <label>132</label> <icon>DefaultMusicAlbums.png</icon> <content>musicvideos</content> diff --git a/system/library/video/musicvideos/artists.xml b/system/library/video/musicvideos/artists.xml index 4913592fd8..f73acd8ad7 100644 --- a/system/library/video/musicvideos/artists.xml +++ b/system/library/video/musicvideos/artists.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" standalone="yes" ?> -<node order="4" type="filter"> +<node order="5" type="filter"> <label>133</label> <icon>DefaultMusicArtists.png</icon> <content>musicvideos</content> diff --git a/system/library/video/musicvideos/directors.xml b/system/library/video/musicvideos/directors.xml index 880742b656..06cc0e06d4 100644 --- a/system/library/video/musicvideos/directors.xml +++ b/system/library/video/musicvideos/directors.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" standalone="yes" ?> -<node order="6" type="filter"> +<node order="7" type="filter"> <label>20348</label> <icon>DefaultDirector.png</icon> <content>musicvideos</content> diff --git a/system/library/video/musicvideos/genres.xml b/system/library/video/musicvideos/genres.xml index ed4812150e..77745f8a01 100644 --- a/system/library/video/musicvideos/genres.xml +++ b/system/library/video/musicvideos/genres.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" standalone="yes" ?> -<node order="1" type="filter"> +<node order="2" type="filter"> <label>135</label> <icon>DefaultGenre.png</icon> <content>musicvideos</content> diff --git a/system/library/video/musicvideos/recentlyaddedmusicvideos.xml b/system/library/video/musicvideos/recentlyaddedmusicvideos.xml index a8ee085e71..fed8cba25f 100644 --- a/system/library/video/musicvideos/recentlyaddedmusicvideos.xml +++ b/system/library/video/musicvideos/recentlyaddedmusicvideos.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8" standalone="yes" ?> -<node order="12" type="folder"> - <label>20390</label> +<node order="1" type="folder"> + <label>20382</label> <icon>DefaultRecentlyAddedMusicVideos.png</icon> <path>videodb://recentlyaddedmusicvideos/</path> </node> diff --git a/system/library/video/musicvideos/studios.xml b/system/library/video/musicvideos/studios.xml index 82023a4993..b6f2f779d3 100644 --- a/system/library/video/musicvideos/studios.xml +++ b/system/library/video/musicvideos/studios.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" standalone="yes" ?> -<node order="7" type="filter"> +<node order="8" type="filter"> <label>20388</label> <icon>DefaultStudios.png</icon> <content>musicvideos</content> diff --git a/system/library/video/musicvideos/tags.xml b/system/library/video/musicvideos/tags.xml index c63f826200..284bd4c9dd 100644 --- a/system/library/video/musicvideos/tags.xml +++ b/system/library/video/musicvideos/tags.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" standalone="yes" ?> -<node order="8" type="filter"> +<node order="9" type="filter"> <label>20459</label> <icon>DefaultTags.png</icon> <content>musicvideos</content> diff --git a/system/library/video/musicvideos/titles.xml b/system/library/video/musicvideos/titles.xml index adfcb1e254..aab72a993b 100644 --- a/system/library/video/musicvideos/titles.xml +++ b/system/library/video/musicvideos/titles.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" standalone="yes" ?> -<node order="2" type="filter"> +<node order="3" type="filter"> <label>10024</label> <icon>DefaultMusicVideoTitle.png</icon> <content>musicvideos</content> diff --git a/system/library/video/musicvideos/years.xml b/system/library/video/musicvideos/years.xml index 1f11fdf114..622002bc48 100644 --- a/system/library/video/musicvideos/years.xml +++ b/system/library/video/musicvideos/years.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" standalone="yes" ?> -<node order="3" type="filter"> +<node order="4" type="filter"> <label>652</label> <icon>DefaultYear.png</icon> <content>musicvideos</content> diff --git a/system/library/video/tvshows/actors.xml b/system/library/video/tvshows/actors.xml index 8e4f10ea04..19fc20eeb4 100644 --- a/system/library/video/tvshows/actors.xml +++ b/system/library/video/tvshows/actors.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" standalone="yes" ?> -<node order="4" type="filter"> +<node order="6" type="filter"> <label>344</label> <icon>DefaultActor.png</icon> <content>tvshows</content> diff --git a/system/library/video/tvshows/genres.xml b/system/library/video/tvshows/genres.xml index f3445092b0..bc066ce55c 100644 --- a/system/library/video/tvshows/genres.xml +++ b/system/library/video/tvshows/genres.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" standalone="yes" ?> -<node order="1" type="filter"> +<node order="3" type="filter"> <label>135</label> <icon>DefaultGenre.png</icon> <content>tvshows</content> diff --git a/system/library/video/tvshows/inprogressshows.xml b/system/library/video/tvshows/inprogressshows.xml index 146230c6ca..df725caee9 100644 --- a/system/library/video/tvshows/inprogressshows.xml +++ b/system/library/video/tvshows/inprogressshows.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8" standalone="yes" ?> -<node order="4" type="folder"> - <label>626</label> +<node order="2" type="folder"> + <label>575</label> <icon>DefaultInProgressShows.png</icon> <path>videodb://inprogresstvshows/</path> </node> diff --git a/system/library/video/tvshows/recentlyaddedepisodes.xml b/system/library/video/tvshows/recentlyaddedepisodes.xml index 6cf35dbfa6..3cfcda83cb 100644 --- a/system/library/video/tvshows/recentlyaddedepisodes.xml +++ b/system/library/video/tvshows/recentlyaddedepisodes.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8" standalone="yes" ?> -<node order="11" type="folder"> - <label>20387</label> +<node order="1" type="folder"> + <label>20382</label> <icon>DefaultRecentlyAddedEpisodes.png</icon> <path>videodb://recentlyaddedepisodes/</path> </node> diff --git a/system/library/video/tvshows/studios.xml b/system/library/video/tvshows/studios.xml index a7b49b9d3b..a7e1d24bda 100644 --- a/system/library/video/tvshows/studios.xml +++ b/system/library/video/tvshows/studios.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" standalone="yes" ?> -<node order="5" type="filter"> +<node order="7" type="filter"> <label>20388</label> <icon>DefaultStudios.png</icon> <content>tvshows</content> diff --git a/system/library/video/tvshows/tags.xml b/system/library/video/tvshows/tags.xml index 3bf9076d6e..6577990817 100644 --- a/system/library/video/tvshows/tags.xml +++ b/system/library/video/tvshows/tags.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" standalone="yes" ?> -<node order="6" type="filter"> +<node order="8" type="filter"> <label>20459</label> <icon>DefaultTags.png</icon> <content>tvshows</content> diff --git a/system/library/video/tvshows/titles.xml b/system/library/video/tvshows/titles.xml index c2415246ab..427f2674de 100644 --- a/system/library/video/tvshows/titles.xml +++ b/system/library/video/tvshows/titles.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" standalone="yes" ?> -<node order="2" type="filter"> +<node order="4" type="filter"> <label>10024</label> <icon>DefaultTVShowTitle.png</icon> <content>tvshows</content> diff --git a/system/library/video/tvshows/years.xml b/system/library/video/tvshows/years.xml index 1ea069d30d..26e1f1edc9 100644 --- a/system/library/video/tvshows/years.xml +++ b/system/library/video/tvshows/years.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" standalone="yes" ?> -<node order="3" type="filter"> +<node order="5" type="filter"> <label>652</label> <icon>DefaultYear.png</icon> <content>tvshows</content> diff --git a/tools/EventClients/Clients/WiiRemote/CWIID_WiiRemote.cpp b/tools/EventClients/Clients/WiiRemote/CWIID_WiiRemote.cpp index 3d232d26f8..a4efd8af65 100644 --- a/tools/EventClients/Clients/WiiRemote/CWIID_WiiRemote.cpp +++ b/tools/EventClients/Clients/WiiRemote/CWIID_WiiRemote.cpp @@ -163,7 +163,7 @@ void CWiiRemote::SetBluetoothAddress(const char *btaddr) bacpy(&m_btaddr, &b); } -void CWiiRemote::SetSensativity(float DeadX, float DeadY, int NumSamples) +void CWiiRemote::SetSensitivity(float DeadX, float DeadY, int NumSamples) { m_NumSamples = NumSamples; @@ -742,8 +742,8 @@ int main(int argc, char **argv) g_Ping = new CPacketHELO("WiiRemote", ICON_PNG, g_BluetoothIconPath.c_str()); g_WiiRemote.Initialize(my_addr, sockfd); g_WiiRemote.SetBluetoothAddress(btaddr); - g_WiiRemote.SetSensativity(DeadX, DeadY, NumSamples); - g_WiiRemote.SetSensativity(DeadX, DeadY, NumSamples); + g_WiiRemote.SetSensitivity(DeadX, DeadY, NumSamples); + g_WiiRemote.SetSensitivity(DeadX, DeadY, NumSamples); g_WiiRemote.SetJoystickMap(JoyMap); if (g_AllowMouse) g_WiiRemote.EnableMouseEmulation(); diff --git a/tools/EventClients/Clients/WiiRemote/CWIID_WiiRemote.h b/tools/EventClients/Clients/WiiRemote/CWIID_WiiRemote.h index 3a60479ca1..5dd7333fd3 100644 --- a/tools/EventClients/Clients/WiiRemote/CWIID_WiiRemote.h +++ b/tools/EventClients/Clients/WiiRemote/CWIID_WiiRemote.h @@ -90,7 +90,7 @@ public: bool Connect(); void SetBluetoothAddress(const char * btaddr); - void SetSensativity(float DeadX, float DeadY, int Samples); + void SetSensitivity(float DeadX, float DeadY, int Samples); void SetJoystickMap(const char *JoyMap); private: int m_NumSamples; diff --git a/tools/codegenerator/Helper.groovy b/tools/codegenerator/Helper.groovy index cf195a2dfe..2b474aeb16 100644 --- a/tools/codegenerator/Helper.groovy +++ b/tools/codegenerator/Helper.groovy @@ -43,7 +43,7 @@ public class Helper public static String newline = System.getProperty("line.separator"); public static File curTemplateFile = null; - public static void setTempateFile(File templateFile) { curTemplateFile = templateFile } + public static void setTemplateFile(File templateFile) { curTemplateFile = templateFile } /** * In order to use any of the typemap helper features, the Helper class needs to be initialized with @@ -57,7 +57,7 @@ public class Helper public static void setup(def template,List pclasses, Map poutTypemap, def defaultOutTypemap, Map pinTypemap, def defaultInTypemap) { - setTempateFile(template.binding.templateFile) + setTemplateFile(template.binding.templateFile) classes = pclasses ? pclasses : [] if (poutTypemap) outTypemap.putAll(poutTypemap) if (defaultOutTypemap) defaultOutTypeConversion = defaultOutTypemap diff --git a/tools/darwin/Configurations/App-iOS.xcconfig b/tools/darwin/Configurations/App-iOS.xcconfig index b7145c3c04..b70faba9a7 100644 --- a/tools/darwin/Configurations/App-iOS.xcconfig +++ b/tools/darwin/Configurations/App-iOS.xcconfig @@ -23,7 +23,7 @@ PRODUCT_NAME = $(APP_NAME) //build against latest SDKROOT = iphoneos -IPHONEOS_DEPLOYMENT_TARGET = 5.1 +IPHONEOS_DEPLOYMENT_TARGET = 6.0 ARCHS = armv7 VALID_ARCHS = armv7 diff --git a/tools/darwin/Support/Codesign.command b/tools/darwin/Support/Codesign.command index ff09f12309..528f74a0be 100755 --- a/tools/darwin/Support/Codesign.command +++ b/tools/darwin/Support/Codesign.command @@ -28,8 +28,13 @@ if [ "${PLATFORM_NAME}" == "iphoneos" ] || [ "${PLATFORM_NAME}" == "appletvos" ] # pull the CFBundleIdentifier out of the built xxx.app BUNDLEID=`mdls -raw -name kMDItemCFBundleIdentifier ${CODESIGNING_FOLDER_PATH}` + if [ "${BUNDLEID}" == "(null)" ] ; then + BUNDLEID=`/usr/libexec/PlistBuddy -c 'Print CFBundleIdentifier' ${CODESIGNING_FOLDER_PATH}/Info.plist` + fi + echo "CFBundleIdentifier is ${BUNDLEID}" + # Prefer the expanded name, if available. CODE_SIGN_IDENTITY_FOR_ITEMS="${EXPANDED_CODE_SIGN_IDENTITY_NAME}" if [ "${CODE_SIGN_IDENTITY_FOR_ITEMS}" = "" ] ; then diff --git a/tools/depends/Makefile.include.in b/tools/depends/Makefile.include.in index 0ddd0444e3..2affdb9b13 100644 --- a/tools/depends/Makefile.include.in +++ b/tools/depends/Makefile.include.in @@ -44,10 +44,18 @@ CONFIG_GUESS=@prefix@/@tool_dir@/share/automake-1.15/config.guess RPL=@prefix@/@tool_dir@/bin/python @prefix@/@tool_dir@/bin/rpl +USE_CCACHE=@use_ccache@ + LD=@LD@ -CC=@CC@ -CXX=@CXX@ -CPP=@CPP@ +ifneq (@use_ccache@,yes) + CC=@CC@ + CXX=@CXX@ + CPP=@CPP@ +else + CC=@CCACHE@ @CC@ + CXX=@CCACHE@ @CXX@ + CPP=@CCACHE@ @CPP@ +endif AR=@AR@ RANLIB=@RANLIB@ AS=@AS@ @@ -67,8 +75,13 @@ ifneq (@use_build_toolchain@,) PATH:=@use_build_toolchain@/bin:@use_build_toolchain@/usr/bin:$(PATH) endif LD_FOR_BUILD=@LD_FOR_BUILD@ -CC_FOR_BUILD=@CC_FOR_BUILD@ -CXX_FOR_BUILD=@CXX_FOR_BUILD@ +ifneq (@use_ccache@,yes) + CC_FOR_BUILD=@CC_FOR_BUILD@ + CXX_FOR_BUILD=@CXX_FOR_BUILD@ +else + CC_FOR_BUILD=@CCACHE@ @CC_FOR_BUILD@ + CXX_FOR_BUILD=@CCACHE@ @CXX_FOR_BUILD@ +endif AR_FOR_BUILD=@AR_FOR_BUILD@ RANLIB_FOR_BUILD=@RANLIB_FOR_BUILD@ AS_FOR_BUILD=@AS_FOR_BUILD@ diff --git a/tools/depends/configure.ac b/tools/depends/configure.ac index ac2ac3cf68..9caba4a654 100644 --- a/tools/depends/configure.ac +++ b/tools/depends/configure.ac @@ -37,6 +37,12 @@ AC_ARG_ENABLE([debug], [use_debug=$enableval], [use_debug=yes]) +AC_ARG_ENABLE([ccache], + [AS_HELP_STRING([--disable-ccache], + [disable ccache])], + [use_ccache=no], + [use_ccache=yes]) + AC_ARG_WITH([toolchain], [AS_HELP_STRING([--with-toolchain], [specify path to toolchain. Required for android. Defaults to xcode root for darwin, /usr for linux])], @@ -83,6 +89,12 @@ AC_ARG_ENABLE([gplv3], [use_gplv3=$enableval], [use_gplv3=yes]) +if test "$use_ccache" = "yes"; then + AC_CHECK_PROG(HAVE_CCACHE,ccache,"yes","no",) + if test "x$HAVE_CCACHE" = "xno" ; then + use_ccache=no + fi +fi AC_CHECK_PROG(HAVE_UNZIP,unzip,"yes","no",) if test "x$HAVE_UNZIP" = "xno" ; then @@ -341,7 +353,7 @@ case $host in found_sdk_version=[`$use_xcodebuild -showsdks | grep $target_platform | sort | tail -n 1 | awk '{ print $2}'`] use_sdk="${use_sdk:-$found_sdk_version}" sdk_name=$target_platform$use_sdk - platform_min_version="$target_platform-version-min=5.1" + platform_min_version="$target_platform-version-min=6.0" fi case $use_sdk in 4.*);; @@ -350,6 +362,7 @@ case $host in 7.*);; 8.*);; 9.*);; + 10.*);; *) AC_MSG_ERROR(error in configure of --with-sdk=$use_sdk) ;; @@ -489,6 +502,10 @@ if test "x$prefix" = "xNONE"; then AC_MSG_ERROR([No prefix path defined. Use for ex: --prefix=/opt/xbmc-depends]); fi +if test "$use_ccache" = "yes"; then + AC_PATH_TOOL([CCACHE], [ccache],, $PATH_FOR_HOST) +fi + if test -z $use_tarballs; then use_tarballs=$prefix/xbmc-tarballs fi @@ -620,8 +637,10 @@ AC_SUBST(need_libiconv) AC_SUBST(use_gplv3) AC_SUBST(has_libcrystax) AC_SUBST(use_xcode) +AC_SUBST(use_ccache) AC_OUTPUT +echo -e "ccache:\t $use_ccache" echo -e "toolchain:\t $use_toolchain" echo -e "cpu:\t\t $use_cpu" echo -e "host:\t\t $use_host" diff --git a/tools/depends/native/cmake-native/Makefile b/tools/depends/native/cmake-native/Makefile index a4788316a7..77e55535ac 100644 --- a/tools/depends/native/cmake-native/Makefile +++ b/tools/depends/native/cmake-native/Makefile @@ -1,6 +1,6 @@ include ../../Makefile.include PLATFORM=$(NATIVEPLATFORM) -DEPS= ../../Makefile.include.in Makefile +DEPS= ../../Makefile.include Makefile APPNAME=cmake VERSION=3.6.2 @@ -9,7 +9,7 @@ ARCHIVE=$(SOURCE).tar.gz # configuration settings -SETENV=CC=$(CC_FOR_BUILD) CXX=$(CXX_FOR_BUILD) LD=$(LD_FOR_BUILD) CFLAGS=$(NATIVE_CFLAGS) \ +SETENV=CC="$(CC_FOR_BUILD)" CXX="$(CXX_FOR_BUILD)" LD=$(LD_FOR_BUILD) CFLAGS=$(NATIVE_CFLAGS) \ CXXFLAGS=$(NATIVE_CXXFLAGS) LDFLAGS=$(NATIVE_LDFLAGS) ifeq ($(NATIVE_OS), osx) @@ -17,6 +17,9 @@ ifeq ($(NATIVE_OS), osx) endif CONFIGURE=./bootstrap --prefix=$(NATIVEPREFIX) --system-curl +ifeq ($(USE_CCACHE), yes) + CONFIGURE+=--enable-ccache +endif APP=$(PLATFORM)/bin/$(APPNAME) diff --git a/tools/depends/native/config.site.native.in b/tools/depends/native/config.site.native.in index 007ee5724a..ee9c747deb 100644 --- a/tools/depends/native/config.site.native.in +++ b/tools/depends/native/config.site.native.in @@ -1,6 +1,6 @@ LD="${LD:-@LD_FOR_BUILD@}" -CC="${CC:-@CC_FOR_BUILD@}" -CXX="${CXX:-@CXX_FOR_BUILD@}" +CC="${CC:-@CCACHE@ @CC_FOR_BUILD@}" +CXX="${CXX:-@CCACHE@ @CXX_FOR_BUILD@}" AR="${AR:-@AR_FOR_BUILD@}" RANLIB="${RANLIB:-@RANLIB_FOR_BUILD@}" AS="${AS:-@AS_FOR_BUILD@}" diff --git a/tools/depends/target/Toolchain.cmake.in b/tools/depends/target/Toolchain.cmake.in index 55922cd188..0fa21561b6 100644 --- a/tools/depends/target/Toolchain.cmake.in +++ b/tools/depends/target/Toolchain.cmake.in @@ -48,6 +48,15 @@ set(CMAKE_AR @AR@ CACHE FILEPATH "Archiver") set(CMAKE_LINKER @LD@ CACHE FILEPATH "Linker") set(CMAKE_STRIP @STRIP@ CACHE PATH "strip binary" FORCE) +if(PROJECT_SOURCE_DIR MATCHES "tools/depends") + if(@use_ccache@ STREQUAL "yes") + find_program(CCACHE_PROGRAM ccache) + if(CCACHE_PROGRAM) + set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "${CCACHE_PROGRAM}") + endif() + endif() +endif() + # where is the target environment set(CMAKE_FIND_ROOT_PATH @prefix@/@deps_dir@) set(CMAKE_LIBRARY_PATH @prefix@/@deps_dir@/lib) diff --git a/tools/depends/target/config-binaddons.site.in b/tools/depends/target/config-binaddons.site.in index d71c378810..47b3fcecc4 100644 --- a/tools/depends/target/config-binaddons.site.in +++ b/tools/depends/target/config-binaddons.site.in @@ -128,6 +128,12 @@ fi if test "@platform_os@" = "ios"; then + # Xcode 8 + 10.11, clock_gettime getentropy is present + # in 10.12 but will get wrongly detected if building on 10.11 + ac_cv_search_clock_gettime=no + ac_cv_func_clock_gettime=no + ac_cv_func_getentropy=no + # tweaks for libffi (ios must use llvm-gcc-4.2) if test "${PACKAGE_NAME}" = "libffi" ; then case "@use_xcode@" in diff --git a/tools/depends/target/config.site.in b/tools/depends/target/config.site.in index 8c7e68d47b..d3a2e2e3cc 100644 --- a/tools/depends/target/config.site.in +++ b/tools/depends/target/config.site.in @@ -5,9 +5,9 @@ host_alias=@use_host@ fi LD="@LD@" -CC="@CC@" -CXX="@CXX@" -CPP="@CPP@" +CC="@CCACHE@ @CC@" +CXX="@CCACHE@ @CXX@" +CPP="@CCACHE@ @CPP@" AR="@AR@" AS="@AS@" NM="@NM@" @@ -16,8 +16,8 @@ RANLIB="@RANLIB@" OBJDUMP="@OBJDUMP@" if test "@platform_os@" = "ios" ; then - export AS="@prefix@/@tool_dir@/bin/gas-preprocessor.pl @CC@ -arch @use_cpu@" - export CCAS="--tag CC @prefix@/@tool_dir@/bin/gas-preprocessor.pl @CC@ -arch @use_cpu@" + export AS="@prefix@/@tool_dir@/bin/gas-preprocessor.pl @CCACHE@ @CC@ -arch @use_cpu@" + export CCAS="--tag CC @prefix@/@tool_dir@/bin/gas-preprocessor.pl @CCACHE@ @CC@ -arch @use_cpu@" fi CFLAGS="@platform_cflags@ @platform_includes@ -isystem @prefix@/@deps_dir@/include $CFLAGS" @@ -150,6 +150,12 @@ fi if test "@platform_os@" = "ios"; then + # Xcode 8 + 10.11, clock_gettime and getentropy is present + # in 10.12 but will get wrongly detected if building on 10.11 + ac_cv_search_clock_gettime=no + ac_cv_func_clock_gettime=no + ac_cv_func_getentropy=no + # tweaks for libffi (ios must use llvm-gcc-4.2) if test "${PACKAGE_NAME}" = "libffi" ; then case "@use_xcode@" in diff --git a/tools/depends/target/curl/Makefile b/tools/depends/target/curl/Makefile index 11d85b9ef6..1d1dff194f 100644 --- a/tools/depends/target/curl/Makefile +++ b/tools/depends/target/curl/Makefile @@ -30,6 +30,9 @@ $(PLATFORM): $(TARBALLS_LOCATION)/$(ARCHIVE) $(DEPS) ifeq (osx, $(findstring osx, $(OS))) cd $(PLATFORM); patch -p1 < ../0001-HTTP-reset-expected-DL-UL-sizes-on-redirects.patch endif +ifeq (darwin, $(findstring darwin, $(HOST))) + cd $(PLATFORM); sed -ie "s/elif defined(HAVE_CLOCK_GETTIME_MONOTONIC)/#elif defined(HAVE_CLOCK_GETTIME_MONOTONIC_NOPE)/" lib/timeval.c +endif cd $(PLATFORM); $(CONFIGURE) $(LIBDYLIB): $(PLATFORM) diff --git a/tools/depends/target/ffmpeg/Makefile b/tools/depends/target/ffmpeg/Makefile index eaf9fc4931..9440021fef 100644 --- a/tools/depends/target/ffmpeg/Makefile +++ b/tools/depends/target/ffmpeg/Makefile @@ -8,7 +8,7 @@ APPLY_PATCHES=no # configuration settings ffmpg_config = --prefix=$(PREFIX) --extra-version="kodi-$(VERSION)" -ffmpg_config += --cc=$(CC) --cxx=$(CXX) --ar=$(AR) --ranlib=$(RANLIB) +ffmpg_config += --cc="$(CC)" --cxx="$(CXX)" --ar=$(AR) --ranlib=$(RANLIB) ffmpg_config += --disable-devices --disable-doc ffmpg_config += --disable-ffplay --disable-ffmpeg --disable-sdl ffmpg_config += --disable-ffprobe --disable-ffserver @@ -79,6 +79,9 @@ $(PLATFORM): $(TARBALLS_LOCATION)/$(ARCHIVE) $(DEPS) cd $(PLATFORM);\ CFLAGS="$(CFLAGS)" CXXFLAGS="$(CXXFLAGS)" CPPFLAGS="$(CPPFLAGS)" LDFLAGS="$(LDFLAGS)" \ ./configure $(ffmpg_config) +ifeq ($(OS), ios) + cd $(PLATFORM); sed -i -- 's/HAVE_CLOCK_GETTIME 1/HAVE_CLOCK_GETTIME 0/g' config.h +endif build: $(PLATFORM) $(MAKE) -C $(PLATFORM) diff --git a/tools/depends/target/gnutls/Makefile b/tools/depends/target/gnutls/Makefile index 1a7c2431c8..69efb3a5a1 100644 --- a/tools/depends/target/gnutls/Makefile +++ b/tools/depends/target/gnutls/Makefile @@ -33,7 +33,7 @@ $(PLATFORM): $(TARBALLS_LOCATION)/$(ARCHIVE) $(DEPS) cd $(PLATFORM); $(ARCHIVE_TOOL) $(ARCHIVE_TOOL_FLAGS) $(TARBALLS_LOCATION)/$(ARCHIVE) cd $(PLATFORM); patch -p0 < ../size-max.patch cd $(PLATFORM); $(CONFIGURE) -ifeq ($(OS),osx) +ifeq (darwin, $(findstring darwin, $(HOST))) cd $(PLATFORM); sed -ie "s/HAVE_GETENTROPY/HAVE_GETENTROPY_NOPE/" config.h endif diff --git a/tools/depends/target/openssl/Makefile b/tools/depends/target/openssl/Makefile index def05255ed..dcae452bcf 100644 --- a/tools/depends/target/openssl/Makefile +++ b/tools/depends/target/openssl/Makefile @@ -33,7 +33,7 @@ $(TARBALLS_LOCATION)/$(ARCHIVE): $(PLATFORM): $(TARBALLS_LOCATION)/$(ARCHIVE) $(DEPS) rm -rf $(PLATFORM); mkdir -p $(PLATFORM) cd $(PLATFORM); $(ARCHIVE_TOOL) $(ARCHIVE_TOOL_FLAGS) $(TARBALLS_LOCATION)/$(ARCHIVE) - cd $(PLATFORM); AR="$(AR)" CFLAGS="$(CFLAGS)" CC=$(CC) RANLIB=$(RANLIB) $(CONFIGURE) + cd $(PLATFORM); AR="$(AR)" CFLAGS="$(CFLAGS)" CC="$(CC)" RANLIB=$(RANLIB) $(CONFIGURE) if test "$(OS)" = "osx"; then \ sed -ie "s|CC= /usr/bin/gcc-4.2|CC= $(CC)|" "$(PLATFORM)/Makefile"; \ sed -ie "s|CFLAG= |CFLAG=$(CFLAGS) |" "$(PLATFORM)/Makefile"; \ diff --git a/tools/depends/target/samba-gplv3/Makefile b/tools/depends/target/samba-gplv3/Makefile index f5d84bac76..e15987d9c4 100644 --- a/tools/depends/target/samba-gplv3/Makefile +++ b/tools/depends/target/samba-gplv3/Makefile @@ -55,7 +55,7 @@ endif ifeq ($(TARGET_PLATFORM),appletvos) cd $(PLATFORM); patch -p0 < ../no_fork_and_exec.patch endif -ifeq ($(OS),osx) +ifeq (darwin, $(findstring darwin, $(HOST))) sed -ie "s|ifndef HAVE_CLOCK_GETTIME|if !defined(HAVE_CLOCK_GETTIME) \&\& !defined(CLOCK_REALTIME)|" "$(PLATFORM)/lib/replace/system/time.h" endif cd $(PLATFORM)/source3; $(CONFIGURE) diff --git a/xbmc/Application.cpp b/xbmc/Application.cpp index 11f8005d16..73141d8c37 100644 --- a/xbmc/Application.cpp +++ b/xbmc/Application.cpp @@ -2585,7 +2585,7 @@ void CApplication::OnApplicationMessage(ThreadMessage* pMsg) else pathToUrl = URIUtils::CreateArchivePath("rar", CURL(pMsg->strParam), ""); - CUtil::GetRecursiveListing(pathToUrl.Get(), items, g_advancedSettings.m_pictureExtensions, XFILE::DIR_FLAG_NO_FILE_DIRS); + CUtil::GetRecursiveListing(pathToUrl.Get(), items, g_advancedSettings.GetPictureExtensions(), XFILE::DIR_FLAG_NO_FILE_DIRS); if (items.Size() > 0) { pSlideShow->Reset(); @@ -2620,7 +2620,7 @@ void CApplication::OnApplicationMessage(ThreadMessage* pMsg) CFileItemList items; std::string strPath = pMsg->strParam; - std::string extensions = g_advancedSettings.m_pictureExtensions; + std::string extensions = g_advancedSettings.GetPictureExtensions(); if (pMsg->param1) extensions += "|.tbn"; CUtil::GetRecursiveListing(strPath, items, extensions); @@ -2745,11 +2745,14 @@ void CApplication::FrameMove(bool processEvents, bool processGUI) CSingleExit ex(g_graphicsContext); m_frameMoveGuard.unlock(); // Calculate a window size between 2 and 10ms, 4 continuous requests let the window grow by 1ms - unsigned int sleepTime = std::max(static_cast<unsigned int>(2), std::min(m_ProcessedExternalCalls >> 2, static_cast<unsigned int>(10))); + // WHen not playing video we allow it to increase to 80ms + unsigned int max_sleep = m_pPlayer->IsPlayingVideo() && !m_pPlayer->IsPausedPlayback() ? 10 : 80; + unsigned int sleepTime = std::max(static_cast<unsigned int>(2), std::min(m_ProcessedExternalCalls >> 2, max_sleep)); Sleep(sleepTime); m_frameMoveGuard.lock(); + m_ProcessedExternalDecay = 5; } - else + if (m_ProcessedExternalDecay && --m_ProcessedExternalDecay == 0) m_ProcessedExternalCalls = 0; } @@ -4093,7 +4096,9 @@ void CApplication::ActivateScreenSaver(bool forceType /*= false */) if (!forceType) { // set to Dim in the case of a dialog on screen or playing video - if (g_windowManager.HasModalDialog() || (m_pPlayer->IsPlayingVideo() && m_ServiceManager->GetSettings().GetBool(CSettings::SETTING_SCREENSAVER_USEDIMONPAUSE)) || g_PVRManager.IsRunningChannelScan()) + if (g_windowManager.HasModalDialog() || + (m_pPlayer->IsPlayingVideo() && m_ServiceManager->GetSettings().GetBool(CSettings::SETTING_SCREENSAVER_USEDIMONPAUSE)) || + CPVRGUIActions::GetInstance().IsRunningChannelScan()) { if (!CAddonMgr::GetInstance().GetAddon("screensaver.xbmc.builtin.dim", m_screenSaver)) m_screenSaver.reset(new CScreenSaver("")); @@ -5085,6 +5090,11 @@ void CApplication::StartMusicScan(const std::string &strDirectory, bool userInit flags |= CMusicInfoScanner::SCAN_ONLINE; if (!userInitiated || m_ServiceManager->GetSettings().GetBool(CSettings::SETTING_MUSICLIBRARY_BACKGROUNDUPDATE)) flags |= CMusicInfoScanner::SCAN_BACKGROUND; + // Ask for full rescan of music files + //! @todo replace with a music library setting in UI + if (g_advancedSettings.m_bMusicLibraryPromptFullTagScan) + if (CGUIDialogYesNo::ShowAndGetInput(CVariant{ 799 }, CVariant{ 38062 })) + flags |= CMusicInfoScanner::SCAN_RESCAN; } if (!(flags & CMusicInfoScanner::SCAN_BACKGROUND)) diff --git a/xbmc/Application.h b/xbmc/Application.h index 59a1ec96b2..93bf3cce99 100644 --- a/xbmc/Application.h +++ b/xbmc/Application.h @@ -519,6 +519,7 @@ private: CCriticalSection m_frameMoveGuard; /*!< critical section for synchronizing GUI actions from inside and outside (python) */ std::atomic_uint m_WaitingExternalCalls; /*!< counts threads wich are waiting to be processed in FrameMove */ unsigned int m_ProcessedExternalCalls; /*!< counts calls wich are processed during one "door open" cycle in FrameMove */ + unsigned int m_ProcessedExternalDecay = 0; /*!< counts to close door after a few frames of no python activity */ }; XBMC_GLOBAL_REF(CApplication,g_application); diff --git a/xbmc/FileItem.cpp b/xbmc/FileItem.cpp index 71e7c56a72..94d7bef42a 100644 --- a/xbmc/FileItem.cpp +++ b/xbmc/FileItem.cpp @@ -3200,11 +3200,11 @@ std::string CFileItem::GetLocalFanart() const return ""; CFileItemList items; - CDirectory::GetDirectory(strDir, items, g_advancedSettings.m_pictureExtensions, DIR_FLAG_NO_FILE_DIRS | DIR_FLAG_READ_CACHE | DIR_FLAG_NO_FILE_INFO); + CDirectory::GetDirectory(strDir, items, g_advancedSettings.GetPictureExtensions(), DIR_FLAG_NO_FILE_DIRS | DIR_FLAG_READ_CACHE | DIR_FLAG_NO_FILE_INFO); if (IsOpticalMediaFile()) { // grab from the optical media parent folder as well CFileItemList moreItems; - CDirectory::GetDirectory(GetLocalMetadataPath(), moreItems, g_advancedSettings.m_pictureExtensions, DIR_FLAG_NO_FILE_DIRS | DIR_FLAG_READ_CACHE | DIR_FLAG_NO_FILE_INFO); + CDirectory::GetDirectory(GetLocalMetadataPath(), moreItems, g_advancedSettings.GetPictureExtensions(), DIR_FLAG_NO_FILE_DIRS | DIR_FLAG_READ_CACHE | DIR_FLAG_NO_FILE_INFO); items.Append(moreItems); } diff --git a/xbmc/Util.cpp b/xbmc/Util.cpp index f2d69da28c..b705562c19 100644 --- a/xbmc/Util.cpp +++ b/xbmc/Util.cpp @@ -543,7 +543,7 @@ bool CUtil::IsTVRecording(const std::string& strFile) bool CUtil::IsPicture(const std::string& strFile) { return URIUtils::HasExtension(strFile, - g_advancedSettings.m_pictureExtensions + "|.tbn|.dds"); + g_advancedSettings.GetPictureExtensions()+ "|.tbn|.dds"); } bool CUtil::ExcludeFileOrFolder(const std::string& strFileOrFolder, const std::vector<std::string>& regexps) diff --git a/xbmc/addons/Addon.cpp b/xbmc/addons/Addon.cpp index ce6dc4fcb9..2a96ae09c1 100644 --- a/xbmc/addons/Addon.cpp +++ b/xbmc/addons/Addon.cpp @@ -110,6 +110,7 @@ static const TypeMapping types[] = {"kodi.adsp", ADDON_ADSPDLL, 24135, "DefaultAddonAudioDSP.png" }, {"kodi.inputstream", ADDON_INPUTSTREAM, 24048, "DefaultAddonInputstream.png" }, {"kodi.vfs", ADDON_VFS, 39013, "DefaultAddonVfs.png" }, + {"kodi.imagedecoder", ADDON_IMAGEDECODER, 39015, "DefaultAddonImageDecoder.png" }, }; std::string TranslateType(ADDON::TYPE type, bool pretty/*=false*/) diff --git a/xbmc/addons/AddonBuilder.cpp b/xbmc/addons/AddonBuilder.cpp index 2df8abcd3f..d47c5aa198 100644 --- a/xbmc/addons/AddonBuilder.cpp +++ b/xbmc/addons/AddonBuilder.cpp @@ -23,6 +23,7 @@ #include "addons/AudioEncoder.h" #include "addons/ContextMenuAddon.h" #include "addons/GameResource.h" +#include "addons/ImageDecoder.h" #include "addons/ImageResource.h" #include "addons/InputStream.h" #include "addons/LanguageResource.h" @@ -91,6 +92,7 @@ std::shared_ptr<IAddon> CAddonBuilder::Build() type == ADDON_AUDIOENCODER || type == ADDON_AUDIODECODER || type == ADDON_VFS || + type == ADDON_IMAGEDECODER || type == ADDON_INPUTSTREAM || type == ADDON_PERIPHERALDLL || type == ADDON_GAMEDLL) @@ -138,6 +140,8 @@ std::shared_ptr<IAddon> CAddonBuilder::Build() return CAudioEncoder::FromExtension(std::move(m_props), m_extPoint); case ADDON_AUDIODECODER: return CAudioDecoder::FromExtension(std::move(m_props), m_extPoint); + case ADDON_IMAGEDECODER: + return CImageDecoder::FromExtension(std::move(m_props), m_extPoint); case ADDON_INPUTSTREAM: return CInputStream::FromExtension(std::move(m_props), m_extPoint); case ADDON_PERIPHERALDLL: diff --git a/xbmc/addons/AddonDatabase.cpp b/xbmc/addons/AddonDatabase.cpp index 67ad41d247..ad655d6ae8 100644 --- a/xbmc/addons/AddonDatabase.cpp +++ b/xbmc/addons/AddonDatabase.cpp @@ -539,7 +539,6 @@ bool CAddonDatabase::GetAvailableVersions(const std::string& addonId, "WHERE " "repo.checksum IS NOT NULL AND repo.checksum != '' " "AND EXISTS (SELECT * FROM installed WHERE installed.addonID=repoID AND installed.enabled=1) " - "AND NOT EXISTS (SELECT * FROM broken WHERE broken.addonID=addons.addonID) " "AND addons.addonID='%s'", addonId.c_str()); m_pDS->query(sql.c_str()); diff --git a/xbmc/addons/AddonInstaller.cpp b/xbmc/addons/AddonInstaller.cpp index 9f2480ce88..55d300904d 100644 --- a/xbmc/addons/AddonInstaller.cpp +++ b/xbmc/addons/AddonInstaller.cpp @@ -228,14 +228,15 @@ void CAddonInstaller::Install(const std::string& addonId, const AddonVersion& ve } bool CAddonInstaller::DoInstall(const AddonPtr &addon, const RepositoryPtr& repo, - const std::string &hash /* = "" */, bool background /* = true */, bool modal /* = false */) + const std::string &hash /* = "" */, bool background /* = true */, bool modal /* = false */, + bool autoUpdate /* = false*/) { // check whether we already have the addon installing CSingleLock lock(m_critSection); if (m_downloadJobs.find(addon->ID()) != m_downloadJobs.end()) return false; - CAddonInstallJob* installJob = new CAddonInstallJob(addon, repo, hash); + CAddonInstallJob* installJob = new CAddonInstallJob(addon, repo, hash, autoUpdate); if (background) { // Workaround: because CAddonInstallJob is blocking waiting for other jobs, it needs to be run @@ -431,9 +432,18 @@ void CAddonInstaller::InstallUpdates() for (const auto& addon : updates) { if (!CAddonMgr::GetInstance().IsBlacklisted(addon->ID())) - CAddonInstaller::GetInstance().InstallOrUpdate(addon->ID()); + { + AddonPtr toInstall; + RepositoryPtr repo; + std::string hash; + if (CAddonInstallJob::GetAddonWithHash(addon->ID(), repo, toInstall, hash)) + DoInstall(toInstall, repo, hash, true, false, true); + } } +} +void CAddonInstaller::InstallUpdatesAndWait() +{ CSingleLock lock(m_critSection); if (!m_downloadJobs.empty()) { @@ -464,13 +474,15 @@ int64_t CAddonInstaller::EnumeratePackageFolder(std::map<std::string,CFileItemLi return size; } -CAddonInstallJob::CAddonInstallJob(const AddonPtr &addon, const AddonPtr &repo, const std::string &hash /* = "" */) +CAddonInstallJob::CAddonInstallJob(const AddonPtr &addon, const AddonPtr &repo, + const std::string &hash, bool isAutoUpdate) : m_addon(addon), m_repo(repo), - m_hash(hash) + m_hash(hash), + m_isAutoUpdate(isAutoUpdate) { AddonPtr dummy; - m_update = CAddonMgr::GetInstance().GetAddon(addon->ID(), dummy, ADDON_UNKNOWN, false); + m_isUpdate = CAddonMgr::GetInstance().GetAddon(addon->ID(), dummy, ADDON_UNKNOWN, false); } bool CAddonInstallJob::GetAddonWithHash(const std::string& addonID, RepositoryPtr& repo, @@ -605,20 +617,30 @@ bool CAddonInstallJob::DoWork() g_localizeStrings.LoadAddonStrings(URIUtils::AddFileToFolder(m_addon->Path(), "resources/language/"), CServiceBroker::GetSettings().GetString(CSettings::SETTING_LOCALE_LANGUAGE), m_addon->ID()); - ADDON::OnPostInstall(m_addon, m_update, IsModal()); + ADDON::OnPostInstall(m_addon, m_isUpdate, IsModal()); { CAddonDatabase database; database.Open(); database.SetOrigin(m_addon->ID(), m_repo ? m_repo->ID() : ""); - if (m_update) + if (m_isUpdate) database.SetLastUpdated(m_addon->ID(), CDateTime::GetCurrentDateTime()); } CEventLog::GetInstance().Add( - EventPtr(new CAddonManagementEvent(m_addon, m_update ? 24065 : 24064)), + EventPtr(new CAddonManagementEvent(m_addon, m_isUpdate ? 24065 : 24064)), !IsModal() && CServiceBroker::GetSettings().GetBool(CSettings::SETTING_ADDONS_NOTIFICATIONS), false); + if (m_isAutoUpdate && !m_addon->Broken().empty()) + { + CLog::Log(LOGDEBUG, "CAddonInstallJob[%s]: auto-disabling due to being marked as broken", m_addon->ID().c_str()); + CAddonMgr::GetInstance().DisableAddon(m_addon->ID()); + CEventLog::GetInstance().Add( + EventPtr(new CAddonManagementEvent(m_addon, 24094)), + CServiceBroker::GetSettings().GetBool(CSettings::SETTING_ADDONS_NOTIFICATIONS), + false); + } + // and we're done! MarkFinished(); return true; @@ -725,7 +747,7 @@ bool CAddonInstallJob::Install(const std::string &installFrom, const AddonPtr& r return false; } - CAddonInstallJob dependencyJob(addon, repoForDep, hash); + CAddonInstallJob dependencyJob(addon, repoForDep, hash, false); // pass our progress indicators to the temporary job and don't allow it to // show progress or information updates (no progress, title or text changes) diff --git a/xbmc/addons/AddonInstaller.h b/xbmc/addons/AddonInstaller.h index 57a38c9624..d42617adf2 100644 --- a/xbmc/addons/AddonInstaller.h +++ b/xbmc/addons/AddonInstaller.h @@ -95,6 +95,7 @@ public: bool HasJob(const std::string& ID) const; /*! Install update and block until all updates have installed. */ + void InstallUpdatesAndWait(); void InstallUpdates(); void OnJobComplete(unsigned int jobID, bool success, CJob* job); @@ -129,7 +130,7 @@ private: \return true on successful install, false on failure. */ bool DoInstall(const ADDON::AddonPtr &addon, const ADDON::RepositoryPtr &repo, - const std::string &hash = "", bool background = true, bool modal = false); + const std::string &hash = "", bool background = true, bool modal = false, bool autoUpdate = false); /*! \brief Check whether dependencies of an addon exist or are installable. Iterates through the addon's dependencies, checking they're installed or installable. @@ -153,7 +154,8 @@ private: class CAddonInstallJob : public CFileOperationJob { public: - CAddonInstallJob(const ADDON::AddonPtr &addon, const ADDON::AddonPtr &repo, const std::string &hash = ""); + CAddonInstallJob(const ADDON::AddonPtr& addon, const ADDON::AddonPtr& repo, + const std::string& hash, bool isAutoUpdate); virtual bool DoWork(); @@ -185,7 +187,8 @@ private: ADDON::AddonPtr m_addon; ADDON::AddonPtr m_repo; std::string m_hash; - bool m_update; + bool m_isUpdate; + bool m_isAutoUpdate; }; class CAddonUnInstallJob : public CFileOperationJob diff --git a/xbmc/addons/AddonManager.cpp b/xbmc/addons/AddonManager.cpp index 4c7c1cd5a3..8dd7395c35 100644 --- a/xbmc/addons/AddonManager.cpp +++ b/xbmc/addons/AddonManager.cpp @@ -848,19 +848,7 @@ bool CAddonMgr::IsAddonInstalled(const std::string& ID) bool CAddonMgr::CanAddonBeInstalled(const AddonPtr& addon) { - if (addon == NULL) - return false; - - CSingleLock lock(m_critSection); - // can't install already installed addon - if (IsAddonInstalled(addon->ID())) - return false; - - // can't install broken addons - if (!addon->Broken().empty()) - return false; - - return true; + return addon != nullptr &&!IsAddonInstalled(addon->ID()); } bool CAddonMgr::CanUninstall(const AddonPtr& addon) diff --git a/xbmc/addons/AddonSystemSettings.cpp b/xbmc/addons/AddonSystemSettings.cpp index 6f245936d5..f0f3dad990 100644 --- a/xbmc/addons/AddonSystemSettings.cpp +++ b/xbmc/addons/AddonSystemSettings.cpp @@ -148,7 +148,7 @@ std::vector<std::string> CAddonSystemSettings::MigrateAddons(std::function<void( CRepositoryUpdater::GetInstance().Await(); CLog::Log(LOGINFO, "ADDON: waiting for add-ons to update..."); - CAddonInstaller::GetInstance().InstallUpdates(); + CAddonInstaller::GetInstance().InstallUpdatesAndWait(); } auto incompatible = getIncompatible(); diff --git a/xbmc/addons/BinaryAddonCache.cpp b/xbmc/addons/BinaryAddonCache.cpp index 41f08ff6a5..c926c9eff3 100644 --- a/xbmc/addons/BinaryAddonCache.cpp +++ b/xbmc/addons/BinaryAddonCache.cpp @@ -34,6 +34,7 @@ void CBinaryAddonCache::Init() { m_addonsToCache = { ADDON_AUDIODECODER, + ADDON_IMAGEDECODER, ADDON_INPUTSTREAM, ADDON_PVRDLL, ADDON_GAMEDLL, diff --git a/xbmc/addons/CMakeLists.txt b/xbmc/addons/CMakeLists.txt index b6d26bcb5a..a2188c6739 100644 --- a/xbmc/addons/CMakeLists.txt +++ b/xbmc/addons/CMakeLists.txt @@ -18,6 +18,7 @@ set(SOURCES Addon.cpp GUIDialogAddonSettings.cpp GUIViewStateAddonBrowser.cpp GUIWindowAddonBrowser.cpp + ImageDecoder.cpp ImageResource.cpp InputStream.cpp LanguageResource.cpp @@ -58,6 +59,7 @@ set(HEADERS Addon.h GUIViewStateAddonBrowser.h GUIWindowAddonBrowser.h IAddon.h + ImageDecoder.h ImageResource.h InputStream.h LanguageResource.h diff --git a/xbmc/addons/GUIDialogAddonSettings.cpp b/xbmc/addons/GUIDialogAddonSettings.cpp index 274d30361b..7dc73d53f0 100644 --- a/xbmc/addons/GUIDialogAddonSettings.cpp +++ b/xbmc/addons/GUIDialogAddonSettings.cpp @@ -400,7 +400,7 @@ bool CGUIDialogAddonSettings::ShowVirtualKeyboard(int iControl) // convert mask qualifiers StringUtils::Replace(strMask, "$AUDIO", g_advancedSettings.GetMusicExtensions()); StringUtils::Replace(strMask, "$VIDEO", g_advancedSettings.m_videoExtensions); - StringUtils::Replace(strMask, "$IMAGE", g_advancedSettings.m_pictureExtensions); + StringUtils::Replace(strMask, "$IMAGE", g_advancedSettings.GetPictureExtensions()); #if defined(_WIN32_WINNT) StringUtils::Replace(strMask, "$EXECUTABLE", ".exe|.bat|.cmd|.py"); #else @@ -1039,6 +1039,12 @@ bool CGUIDialogAddonSettings::GetCondition(const std::string &condition, const i else value = StringUtils::Format("%i", ((CGUISpinControlEx*) control2)->GetValue()); break; + case CGUIControl::GUICONTROL_SETTINGS_SLIDER: + if (((CGUISettingsSliderControl *)control2)->GetType() == SLIDER_CONTROL_TYPE_INT) + value = StringUtils::Format("%i", ((CGUISettingsSliderControl *)control2)->GetIntValue()); + else + value = StringUtils::Format("%f", ((CGUISettingsSliderControl *)control2)->GetFloatValue()); + break; default: break; } diff --git a/xbmc/addons/IAddon.h b/xbmc/addons/IAddon.h index b58e19e752..f7b3a279ed 100644 --- a/xbmc/addons/IAddon.h +++ b/xbmc/addons/IAddon.h @@ -65,6 +65,7 @@ namespace ADDON ADDON_RESOURCE_UISOUNDS, ADDON_RESOURCE_GAMES, ADDON_VFS, + ADDON_IMAGEDECODER, ADDON_VIDEO, // virtual addon types ADDON_AUDIO, ADDON_IMAGE, diff --git a/xbmc/addons/ImageDecoder.cpp b/xbmc/addons/ImageDecoder.cpp new file mode 100644 index 0000000000..c22eaf142e --- /dev/null +++ b/xbmc/addons/ImageDecoder.cpp @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2013 Arne Morten Kvarving + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC; see the file COPYING. If not, see + * <http://www.gnu.org/licenses/>. + * + */ +#include "ImageDecoder.h" +#include "kodi-addon-dev-kit/include/kodi/kodi_imagedec_types.h" +#include "guilib/TextureFormats.h" + +static const std::map<int,int> KodiToAddonFormat = {{XB_FMT_A8R8G8B8, ADDON_IMG_FMT_A8R8G8B8}, + {XB_FMT_A8, ADDON_IMG_FMT_A8}, + {XB_FMT_RGBA8, ADDON_IMG_FMT_RGBA8}, + {XB_FMT_RGB8, ADDON_IMG_FMT_RGB8}}; + +namespace ADDON +{ + +std::unique_ptr<CImageDecoder> +CImageDecoder::FromExtension(AddonProps&& props, const cp_extension_t* ext) +{ + std::string mime = CAddonMgr::GetInstance().GetExtValue(ext->configuration, "@mimetype"); + std::string extension = CAddonMgr::GetInstance().GetExtValue(ext->configuration, "@extension"); + return std::unique_ptr<CImageDecoder>(new CImageDecoder(std::move(props), + std::move(mime), + std::move(extension))); +} + +CImageDecoder::CImageDecoder(AddonProps&& props, std::string mime, std::string extension) : + CAddonDll(std::move(props)), + m_mimetype(std::move(mime)), + m_extension(std::move(extension)) +{ +} + +CImageDecoder::~CImageDecoder() +{ + if (m_image && Initialized()) + m_struct.Close(m_image); +} + +bool CImageDecoder::LoadImageFromMemory(unsigned char* buffer, unsigned int bufSize, + unsigned int width, unsigned int height) +{ + if (!Initialized()) + return false; + + m_width = width; + m_height = height; + m_image = m_struct.LoadImage(buffer, bufSize, &m_width, &m_height); + + return m_image != nullptr; +} + +bool CImageDecoder::Decode(unsigned char* const pixels, unsigned int width, + unsigned int height, unsigned int pitch, + unsigned int format) +{ + if (!Initialized()) + return false; + + auto it = KodiToAddonFormat.find(format & XB_FMT_MASK); + if (it == KodiToAddonFormat.end()) + return false; + + bool result = m_struct.Decode(m_image, pixels, width, height, pitch, it->second); + m_width = width; + m_height = height; + + return result; +} + +bool CImageDecoder::Create(const std::string& mimetype) +{ + m_info.mimetype = mimetype.c_str(); + + return CAddonDll::Create(&m_struct, &m_info) == ADDON_STATUS_OK; +} + +} /*namespace ADDON*/ diff --git a/xbmc/addons/ImageDecoder.h b/xbmc/addons/ImageDecoder.h new file mode 100644 index 0000000000..4743281e11 --- /dev/null +++ b/xbmc/addons/ImageDecoder.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2013 Arne Morten Kvarving + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC; see the file COPYING. If not, see + * <http://www.gnu.org/licenses/>. + * + */ +#pragma once + +#include "AddonDll.h" +#include "addons/kodi-addon-dev-kit/include/kodi/kodi_imagedec_types.h" +#include "guilib/iimage.h" + +namespace ADDON +{ + class CImageDecoder : public CAddonDll, + public IImage + { + public: + static std::unique_ptr<CImageDecoder> FromExtension(AddonProps&&, + const cp_extension_t* ext); + explicit CImageDecoder(AddonProps props) : + CAddonDll(std::move(props)) + {} + + CImageDecoder(AddonProps&& props, std::string mimetypes, std::string extensions); + virtual ~CImageDecoder(); + + bool Create(const std::string& mimetype); + + bool CreateThumbnailFromSurface(unsigned char*, unsigned int, unsigned int, + unsigned int, unsigned int, const std::string&, + unsigned char*&, unsigned int&) { return false; } + + bool LoadImageFromMemory(unsigned char* buffer, unsigned int bufSize, + unsigned int width, unsigned int height); + bool Decode(unsigned char* const pixels, unsigned int width, + unsigned int height, unsigned int pitch, + unsigned int format); + + const std::string& GetMimetypes() const { return m_mimetype; } + const std::string& GetExtensions() const { return m_extension; } + protected: + void* m_image = nullptr; + std::string m_mimetype; + std::string m_extension; + IMAGEDEC_PROPS m_info; + KodiToAddonFuncTable_ImageDecoder m_struct = {}; + }; + +} /*namespace ADDON*/ diff --git a/xbmc/addons/PVRClient.cpp b/xbmc/addons/PVRClient.cpp index 60fed68942..9a54ff153c 100644 --- a/xbmc/addons/PVRClient.cpp +++ b/xbmc/addons/PVRClient.cpp @@ -18,18 +18,21 @@ * */ -#include "Application.h" +#include "PVRClient.h" + +#include <cassert> +#include <cmath> +#include <memory> +#include <algorithm> + #include "ServiceBroker.h" #include "addons/kodi-addon-dev-kit/include/kodi/libKODI_guilib.h" #include "epg/Epg.h" #include "filesystem/SpecialProtocol.h" -#include "messaging/ApplicationMessenger.h" -#include "messaging/helpers/DialogHelper.h" #include "settings/AdvancedSettings.h" #include "settings/Settings.h" #include "utils/log.h" #include "utils/StringUtils.h" -#include "utils/Variant.h" #include "pvr/PVRManager.h" #include "pvr/addons/PVRClients.h" @@ -39,55 +42,26 @@ #include "pvr/timers/PVRTimerInfoTag.h" #include "pvr/timers/PVRTimerType.h" -#include "PVRClient.h" - -#include <assert.h> -#include <cmath> -#include <memory> -#include <algorithm> - using namespace ADDON; using namespace PVR; using namespace EPG; -using namespace KODI::MESSAGING; - -using KODI::MESSAGING::HELPERS::DialogResponse; #define DEFAULT_INFO_STRING_VALUE "unknown" std::unique_ptr<CPVRClient> CPVRClient::FromExtension(AddonProps props, const cp_extension_t* ext) { - std::string strAvahiType = CAddonMgr::GetInstance().GetExtValue(ext->configuration, "@avahi_type"); - std::string strAvahiIpSetting = CAddonMgr::GetInstance().GetExtValue(ext->configuration, "@avahi_ip_setting"); - std::string strAvahiPortSetting = CAddonMgr::GetInstance().GetExtValue(ext->configuration, "@avahi_port_setting"); - return std::unique_ptr<CPVRClient>(new CPVRClient(std::move(props), strAvahiType, - strAvahiIpSetting, strAvahiPortSetting)); + return std::unique_ptr<CPVRClient>(new CPVRClient(std::move(props))); } CPVRClient::CPVRClient(AddonProps props) : CAddonDll(std::move(props)), - m_apiVersion("0.0.0"), - m_bAvahiServiceAdded(false) -{ - ResetProperties(); -} - -CPVRClient::CPVRClient(AddonProps props, const std::string& strAvahiType, const std::string& strAvahiIpSetting, - const std::string& strAvahiPortSetting) - : CAddonDll(std::move(props)), - m_strAvahiType(strAvahiType), - m_strAvahiIpSetting(strAvahiIpSetting), - m_strAvahiPortSetting(strAvahiPortSetting), - m_apiVersion("0.0.0"), - m_bAvahiServiceAdded(false) + m_apiVersion("0.0.0") { ResetProperties(); } CPVRClient::~CPVRClient(void) { - if (m_bAvahiServiceAdded) - CZeroconfBrowser::GetInstance()->RemoveServiceType(m_strAvahiType); Destroy(); } @@ -1253,7 +1227,7 @@ DemuxPacket* CPVRClient::DemuxRead(void) return NULL; } -bool CPVRClient::HaveMenuHooks(PVR_MENUHOOK_CAT cat) const +bool CPVRClient::HasMenuHooks(PVR_MENUHOOK_CAT cat) const { bool bReturn(false); if (m_bReadyToUse && !m_menuhooks.empty()) @@ -1618,77 +1592,6 @@ time_t CPVRClient::GetBufferTimeEnd(void) const return time; } -bool CPVRClient::CanAutoconfigure(void) const -{ - /** can only auto-configure when avahi details are provided in addon.xml */ - return !m_strAvahiType.empty() && - !m_strAvahiIpSetting.empty() && - !m_strAvahiPortSetting.empty(); -} - -bool CPVRClient::AutoconfigureRegisterType(void) -{ - if (!m_strAvahiType.empty()) - { - // AddServiceType() returns false when already registered - m_bAvahiServiceAdded |= CZeroconfBrowser::GetInstance()->AddServiceType(m_strAvahiType); - return true; - } - - return false; -} - -bool CPVRClient::Autoconfigure(void) -{ - bool bReturn(false); - - if (!CanAutoconfigure()) - return bReturn; - - std::string strHostPort; - std::vector<CZeroconfBrowser::ZeroconfService> found_services = CZeroconfBrowser::GetInstance()->GetFoundServices(); - for(std::vector<CZeroconfBrowser::ZeroconfService>::iterator it = found_services.begin(); !bReturn && it != found_services.end(); ++it) - { - /** found the type that we are looking for */ - if ((*it).GetType() == m_strAvahiType && std::find(m_rejectedAvahiHosts.begin(), m_rejectedAvahiHosts.end(), *it) == m_rejectedAvahiHosts.end()) - { - /** try to resolve */ - if(!CZeroconfBrowser::GetInstance()->ResolveService((*it))) - { - CLog::Log(LOGWARNING, "%s - %s service found but the host name couldn't be resolved", __FUNCTION__, (*it).GetName().c_str()); - } - else - { - // %s service found at %s - std::string strLogLine(StringUtils::Format(g_localizeStrings.Get(19689).c_str(), (*it).GetName().c_str(), (*it).GetIP().c_str())); - CLog::Log(LOGDEBUG, "%s - %s", __FUNCTION__, strLogLine.c_str()); - - if (DialogResponse::YES != - HELPERS::ShowYesNoDialogLines(CVariant{19688}, // Scanning for PVR services - CVariant{strLogLine}, - CVariant{19690})) // Do you want to use this service? - { - CLog::Log(LOGDEBUG, "%s - %s service found but not enabled by the user", __FUNCTION__, (*it).GetName().c_str()); - m_rejectedAvahiHosts.push_back(*it); - } - else - { - /** update the settings and return */ - std::string strPort(StringUtils::Format("%d", (*it).GetPort())); - UpdateSetting(m_strAvahiIpSetting, (*it).GetIP()); - UpdateSetting(m_strAvahiPortSetting, strPort); - SaveSettings(); - CLog::Log(LOGNOTICE, "%s - auto-configured %s using host '%s' and port '%d'", __FUNCTION__, (*it).GetName().c_str(), (*it).GetIP().c_str(), (*it).GetPort()); - - bReturn = true; - } - } - } - } - - return bReturn; -} - bool CPVRClient::IsRealTimeStream(void) const { bool bReturn(false); diff --git a/xbmc/addons/PVRClient.h b/xbmc/addons/PVRClient.h index ef58bca7c7..107720e347 100644 --- a/xbmc/addons/PVRClient.h +++ b/xbmc/addons/PVRClient.h @@ -27,7 +27,6 @@ #include "addons/Addon.h" #include "addons/AddonDll.h" #include "addons/kodi-addon-dev-kit/include/kodi/xbmc_pvr_types.h" -#include "network/ZeroconfBrowser.h" #include "pvr/channels/PVRChannel.h" #include "pvr/PVRTypes.h" @@ -66,9 +65,6 @@ namespace PVR static std::unique_ptr<CPVRClient> FromExtension(ADDON::AddonProps props, const cp_extension_t* ext); explicit CPVRClient(ADDON::AddonProps props); - CPVRClient(ADDON::AddonProps props, const std::string& strAvahiType, - const std::string& strAvahiIpSetting, const std::string& strAvahiPortSetting); - ~CPVRClient(void); virtual void OnDisabled() override; @@ -224,7 +220,7 @@ namespace PVR /*! * @return True if this add-on has menu hooks, false otherwise. */ - bool HaveMenuHooks(PVR_MENUHOOK_CAT cat) const; + bool HasMenuHooks(PVR_MENUHOOK_CAT cat) const; /*! * @return The menu hooks for this add-on. @@ -611,23 +607,6 @@ namespace PVR time_t GetBufferTimeEnd() const; /*! - * @return True if this add-on can be auto-configured via avahi, false otherwise - */ - bool CanAutoconfigure(void) const; - - /*! - * Registers the avahi type for this add-on - * @return True if registered, false if not. - */ - bool AutoconfigureRegisterType(void); - - /*! - * Try to auto-configure this add-on via avahi - * @return True if auto-configured and the configured was accepted by the user, false otherwise - */ - bool Autoconfigure(void); - - /*! * @brief is real-time stream? */ bool IsRealTimeStream() const; @@ -732,12 +711,8 @@ namespace PVR std::string m_strBackendHostname; /*!< the cached backend hostname */ /* stored strings to make sure const char* members in PVR_PROPERTIES stay valid */ - std::string m_strUserPath; /*!< @brief translated path to the user profile */ - std::string m_strClientPath; /*!< @brief translated path to this add-on */ - std::string m_strAvahiType; /*!< avahi service type */ - std::string m_strAvahiIpSetting; /*!< add-on setting name to change to the found ip address */ - std::string m_strAvahiPortSetting; /*!< add-on setting name to change to the found port number */ - std::vector<CZeroconfBrowser::ZeroconfService> m_rejectedAvahiHosts; /*!< hosts that were rejected by the user */ + std::string m_strUserPath; /*!< @brief translated path to the user profile */ + std::string m_strClientPath; /*!< @brief translated path to this add-on */ CCriticalSection m_critSection; @@ -746,7 +721,6 @@ namespace PVR bool m_bIsPlayingRecording; CPVRRecordingPtr m_playingRecording; ADDON::AddonVersion m_apiVersion; - bool m_bAvahiServiceAdded; PVR_PROPERTIES m_info; KodiToAddonFuncTable_PVR m_struct; }; diff --git a/xbmc/addons/Repository.cpp b/xbmc/addons/Repository.cpp index e64a3665c1..ce1e8ab7ed 100644 --- a/xbmc/addons/Repository.cpp +++ b/xbmc/addons/Repository.cpp @@ -257,48 +257,5 @@ bool CRepositoryUpdateJob::DoWork() } database.UpdateRepositoryContent(m_repo->ID(), m_repo->Version(), newChecksum, addons); - - //Notify about broken status changes - for (const auto& addon : addons) - { - AddonPtr localAddon; - if (!CAddonMgr::GetInstance().GetAddon(addon->ID(), localAddon)) - continue; - - if (localAddon && localAddon->Version() > addon->Version()) - //We have a newer version locally - continue; - - AddonPtr oldAddon; - database.GetAddon(addon->ID(), oldAddon); - - if (database.GetAddonVersion(addon->ID()).first > addon->Version()) - //Newer version in db (ie. in a different repo) - continue; - - std::string broken = addon->Broken(); - bool isBroken = !addon->Broken().empty(); - bool isBrokenInDb = oldAddon && !oldAddon->Broken().empty(); - if (isBroken && !isBrokenInDb) - { - //newly broken - if (HELPERS::ShowYesNoDialogLines(CVariant{addon->Name()}, CVariant{24096}, CVariant{24097}, CVariant{""}) - == DialogResponse::YES) - { - CAddonMgr::GetInstance().DisableAddon(addon->ID()); - } - - CLog::Log(LOGDEBUG, "CRepositoryUpdateJob[%s] addon '%s' marked broken. reason: \"%s\"", - m_repo->ID().c_str(), addon->ID().c_str(), broken.c_str()); - - CEventLog::GetInstance().Add(EventPtr(new CAddonManagementEvent(addon, 24096))); - } - else if (!isBroken && isBrokenInDb) - { - //Unbroken - CLog::Log(LOGDEBUG, "CRepositoryUpdateJob[%s] addon '%s' unbroken", - m_repo->ID().c_str(), addon->ID().c_str()); - } - } return true; } diff --git a/xbmc/addons/RepositoryUpdater.cpp b/xbmc/addons/RepositoryUpdater.cpp index ca008ce8a5..659c39012d 100644 --- a/xbmc/addons/RepositoryUpdater.cpp +++ b/xbmc/addons/RepositoryUpdater.cpp @@ -87,11 +87,7 @@ void CRepositoryUpdater::OnJobComplete(unsigned int jobID, bool success, CJob* j if (CServiceBroker::GetSettings().GetInt(CSettings::SETTING_ADDONS_AUTOUPDATES) == AUTO_UPDATES_ON) { - for (const auto& addon : updates) - { - if (!CAddonMgr::GetInstance().IsBlacklisted(addon->ID())) - CAddonInstaller::GetInstance().InstallOrUpdate(addon->ID()); - } + CAddonInstaller::GetInstance().InstallUpdates(); } ScheduleUpdate(); diff --git a/xbmc/addons/Scraper.cpp b/xbmc/addons/Scraper.cpp index 0fcf5d04f2..bfa272ac57 100644 --- a/xbmc/addons/Scraper.cpp +++ b/xbmc/addons/Scraper.cpp @@ -496,6 +496,20 @@ CScraperUrl CScraper::ResolveIDToUrl(const std::string& externalID) { CScraperUrl scurlRet; + if (m_isPython) + { + std::stringstream str; + str << "plugin://" << ID() + << "?action=resolveid&key=" << CURL::Encode(externalID); + + CFileItem item("resolve me", false); + + if (XFILE::CPluginDirectory::GetPluginResult(str.str(), item)) + scurlRet.ParseString(item.GetPath()); + + return scurlRet; + } + // scraper function takes an external ID, returns XML (see below) std::vector<std::string> vcsIn; vcsIn.push_back(externalID); diff --git a/xbmc/addons/addon-bindings.mk b/xbmc/addons/addon-bindings.mk index 6bbfe69dbe..aa2525b9b0 100644 --- a/xbmc/addons/addon-bindings.mk +++ b/xbmc/addons/addon-bindings.mk @@ -15,6 +15,8 @@ BINDINGS+=xbmc/addons/kodi-addon-dev-kit/include/kodi/xbmc_codec_types.h BINDINGS+=xbmc/addons/kodi-addon-dev-kit/include/kodi/xbmc_epg_types.h BINDINGS+=xbmc/addons/kodi-addon-dev-kit/include/kodi/kodi_game_dll.h BINDINGS+=xbmc/addons/kodi-addon-dev-kit/include/kodi/kodi_game_types.h +BINDINGS+=xbmc/addons/kodi-addon-dev-kit/include/kodi/kodi_imagedec_types.h +BINDINGS+=xbmc/addons/kodi-addon-dev-kit/include/kodi/kodi_imagedec_dll.h BINDINGS+=xbmc/addons/kodi-addon-dev-kit/include/kodi/kodi_inputstream_dll.h BINDINGS+=xbmc/addons/kodi-addon-dev-kit/include/kodi/kodi_inputstream_types.h BINDINGS+=xbmc/addons/kodi-addon-dev-kit/include/kodi/kodi_peripheral_dll.h diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/kodi_imagedec_dll.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/kodi_imagedec_dll.h new file mode 100644 index 0000000000..9438f242b9 --- /dev/null +++ b/xbmc/addons/kodi-addon-dev-kit/include/kodi/kodi_imagedec_dll.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2005-2013 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC; see the file COPYING. If not, see + * <http://www.gnu.org/licenses/>. + * + */ + +#pragma once + +#include <stdint.h> +#include "xbmc_addon_dll.h" +#include "kodi_imagedec_types.h" + +extern "C" +{ + void* LoadImage(unsigned char* buffer, unsigned int bufSize, + unsigned int* width, unsigned int* height); + + bool Decode(void* image, unsigned char* pixels, + unsigned int width, unsigned int height, + unsigned int pitch, unsigned int format); + + void Close(void* image); + + // function to export the above structure to Kodi + void __declspec(dllexport) get_addon(void* ptr) + { + KodiToAddonFuncTable_ImageDecoder* img = + static_cast<KodiToAddonFuncTable_ImageDecoder*>(ptr); + img->LoadImage = LoadImage; + img->Decode = Decode; + img->Close = Close; + } +}; diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/kodi_imagedec_types.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/kodi_imagedec_types.h new file mode 100644 index 0000000000..ad8eb54f23 --- /dev/null +++ b/xbmc/addons/kodi-addon-dev-kit/include/kodi/kodi_imagedec_types.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2005-2013 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC; see the file COPYING. If not, see + * <http://www.gnu.org/licenses/>. + * + */ + +#pragma once + +#include <stdint.h> + +#define ADDON_IMG_FMT_A8R8G8B8 1 +#define ADDON_IMG_FMT_A8 2 +#define ADDON_IMG_FMT_RGBA8 3 +#define ADDON_IMG_FMT_RGB8 4 + +extern "C" +{ + struct IMAGEDEC_PROPS + { + const char* mimetype; + }; + + typedef struct KodiToAddonFuncTable_ImageDecoder + { + //! \brief Initialize an encoder + //! \param buffer The data to read from memory + //! \param bufSize The buffer size + //! \param width The optimal width of image on entry, obtained width on return + //! \param height The optimal height of image, actual obtained height on return + //! \return Image or nullptr on error + void* (__cdecl* LoadImage) (unsigned char* buffer, unsigned int bufSize, + unsigned int* width, unsigned int* height); + + //! \brief Decode previously loaded image + //! \param image Image to decode + //! \param pixels Output buffer + //! \param width Width of output image + //! \param height Height of output image + //! \param pitch Pitch of output image + //! \param format Format of output image + bool (__cdecl* Decode) (void* image, unsigned char* pixels, + unsigned int width, unsigned int height, + unsigned int pitch, unsigned int format); + + //! \brief Close an opened image + //! \param image Image to close + //! \return True on success, false on failure + void (__cdecl* Close)(void* image); + } KodiToAddonFuncTable_ImageDecoder; +} diff --git a/xbmc/addons/test/TestAddonBuilder.cpp b/xbmc/addons/test/TestAddonBuilder.cpp index 51cd0b2f14..c30800b5f5 100644 --- a/xbmc/addons/test/TestAddonBuilder.cpp +++ b/xbmc/addons/test/TestAddonBuilder.cpp @@ -55,7 +55,7 @@ TEST_F(TestAddonBuilder, ShouldBuildDependencyAddons) EXPECT_EQ(deps, addon->GetDeps()); } -TEST_F(TestAddonBuilder, ShouldReturnDeivedType) +TEST_F(TestAddonBuilder, ShouldReturnDerivedType) { builder.SetType(ADDON_RESOURCE_LANGUAGE); auto addon = std::dynamic_pointer_cast<CLanguageResource>(builder.Build()); diff --git a/xbmc/addons/test/TestAddonFactory.cpp b/xbmc/addons/test/TestAddonFactory.cpp index c58539522c..00f37cd05c 100644 --- a/xbmc/addons/test/TestAddonFactory.cpp +++ b/xbmc/addons/test/TestAddonFactory.cpp @@ -57,7 +57,7 @@ TEST_F(TestAddonFactory, ShouldFailWhenAddonDoesNotHaveRequestedType) EXPECT_EQ(nullptr, addon); } -TEST_F(TestAddonFactory, ShouldPickFirstExtenstionWhenNotRequestingSpecificType) +TEST_F(TestAddonFactory, ShouldPickFirstExtensionWhenNotRequestingSpecificType) { cp_extension_t extensions[2] = { {&plugin, (char*)"xbmc.python.script", nullptr, nullptr, nullptr, nullptr}, @@ -71,7 +71,7 @@ TEST_F(TestAddonFactory, ShouldPickFirstExtenstionWhenNotRequestingSpecificType) EXPECT_EQ(ADDON_SCRIPT, addon->Type()); } -TEST_F(TestAddonFactory, ShouldIgnoreMetadataExtenstion) +TEST_F(TestAddonFactory, ShouldIgnoreMetadataExtension) { cp_extension_t extensions[2] = { {&plugin, (char*)"kodi.addon.metadata", nullptr, nullptr, nullptr, nullptr}, diff --git a/xbmc/cores/AudioEngine/AEDefines_override.h b/xbmc/cores/AudioEngine/AEDefines_override.h deleted file mode 100644 index e69de29bb2..0000000000 --- a/xbmc/cores/AudioEngine/AEDefines_override.h +++ /dev/null diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkAUDIOTRACK.cpp b/xbmc/cores/AudioEngine/Sinks/AESinkAUDIOTRACK.cpp index 9f5b8c24fc..bd85d4f771 100644 --- a/xbmc/cores/AudioEngine/Sinks/AESinkAUDIOTRACK.cpp +++ b/xbmc/cores/AudioEngine/Sinks/AESinkAUDIOTRACK.cpp @@ -245,7 +245,7 @@ bool CAESinkAUDIOTRACK::Initialize(AEAudioFormat &format, std::string &device) int stream = CJNIAudioManager::STREAM_MUSIC; m_encoding = CJNIAudioFormat::ENCODING_PCM_16BIT; - uint32_t distance = 192000; // max upper distance + uint32_t distance = UINT32_MAX; // max upper distance, update at least ones to use one of our samplerates for (auto& s : m_sink_sampleRates) { // prefer best match or alternatively something that divides nicely and @@ -825,7 +825,7 @@ void CAESinkAUDIOTRACK::EnumerateDevicesEx(AEDeviceInfoList &list, bool force) else { bool supports_192khz = false; - int test_sample[] = { 32000, 44100, 48000, 96000, 192000 }; + int test_sample[] = { 32000, 44100, 48000, 88200, 96000, 176400, 192000 }; int test_sample_sz = sizeof(test_sample) / sizeof(int); int encoding = CJNIAudioFormat::ENCODING_PCM_16BIT; if (CJNIAudioManager::GetSDKVersion() >= 21) diff --git a/xbmc/cores/AudioEngine/Sinks/osx/CoreAudioStream.cpp b/xbmc/cores/AudioEngine/Sinks/osx/CoreAudioStream.cpp index 7596537302..ced1200f21 100644 --- a/xbmc/cores/AudioEngine/Sinks/osx/CoreAudioStream.cpp +++ b/xbmc/cores/AudioEngine/Sinks/osx/CoreAudioStream.cpp @@ -130,7 +130,7 @@ UInt32 CCoreAudioStream::GetDirection() // WARNING - don't rely on this method - the return value of // GetTerminalType is driver specific - the checked return // values are only recommendations from apple -bool CCoreAudioStream::IsDigitalOuptut(AudioStreamID id) +bool CCoreAudioStream::IsDigitalOutput(AudioStreamID id) { UInt32 type = GetTerminalType(id); // yes apple is mixing types here... diff --git a/xbmc/cores/AudioEngine/Sinks/osx/CoreAudioStream.h b/xbmc/cores/AudioEngine/Sinks/osx/CoreAudioStream.h index 3f01060e85..ba6d883e8f 100644 --- a/xbmc/cores/AudioEngine/Sinks/osx/CoreAudioStream.h +++ b/xbmc/cores/AudioEngine/Sinks/osx/CoreAudioStream.h @@ -60,7 +60,7 @@ public: bool GetAvailablePhysicalFormats(StreamFormatList *pList); static bool GetAvailableVirtualFormats(AudioStreamID id, StreamFormatList *pList); static bool GetAvailablePhysicalFormats(AudioStreamID id, StreamFormatList *pList); - static bool IsDigitalOuptut(AudioStreamID id); + static bool IsDigitalOutput(AudioStreamID id); static bool GetStartingChannelInDevice(AudioStreamID id, UInt32 &startingChannel); protected: diff --git a/xbmc/cores/VideoPlayer/CMakeLists.txt b/xbmc/cores/VideoPlayer/CMakeLists.txt index 00d0232922..4ceff1b890 100644 --- a/xbmc/cores/VideoPlayer/CMakeLists.txt +++ b/xbmc/cores/VideoPlayer/CMakeLists.txt @@ -13,7 +13,8 @@ set(SOURCES DVDAudio.cpp VideoPlayerRadioRDS.cpp VideoPlayerSubtitle.cpp VideoPlayerTeletext.cpp - VideoPlayerVideo.cpp) + VideoPlayerVideo.cpp + VideoReferenceClock.cpp) set(HEADERS DVDAudio.h DVDClock.h @@ -32,6 +33,7 @@ set(HEADERS DVDAudio.h VideoPlayerRadioRDS.h VideoPlayerSubtitle.h VideoPlayerTeletext.h - VideoPlayerVideo.h) + VideoPlayerVideo.h + VideoReferenceClock.h) core_add_library(VideoPlayer) diff --git a/xbmc/cores/VideoPlayer/DVDClock.cpp b/xbmc/cores/VideoPlayer/DVDClock.cpp index f4ae45d816..4cf90d546e 100644 --- a/xbmc/cores/VideoPlayer/DVDClock.cpp +++ b/xbmc/cores/VideoPlayer/DVDClock.cpp @@ -19,7 +19,7 @@ */ #include "DVDClock.h" -#include "video/VideoReferenceClock.h" +#include "VideoReferenceClock.h" #include <math.h> #include "utils/MathUtils.h" #include "threads/SingleLock.h" diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/AMLCodec.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Video/AMLCodec.cpp index 9f2270ef44..c49ec70ef9 100644 --- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/AMLCodec.cpp +++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/AMLCodec.cpp @@ -26,36 +26,39 @@ #include "cores/VideoPlayer/DVDClock.h" #include "cores/VideoPlayer/VideoRenderers/RenderFlags.h" #include "cores/VideoPlayer/VideoRenderers/RenderManager.h" +#include "settings/AdvancedSettings.h" #include "guilib/GraphicContext.h" #include "settings/DisplaySettings.h" #include "settings/MediaSettings.h" #include "settings/Settings.h" +#include "threads/Atomics.h" #include "utils/AMLUtils.h" #include "utils/log.h" #include "utils/StringUtils.h" #include "utils/SysfsUtils.h" #include "utils/TimeUtils.h" -extern "C" { -#include "libavutil/avutil.h" -} // extern "C" - #include <unistd.h> #include <queue> #include <vector> #include <signal.h> -#include <semaphore.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <sys/ioctl.h> +#include <sys/utsname.h> #include <linux/videodev2.h> +#include <sys/poll.h> +#include <chrono> +#include <thread> // amcodec include extern "C" { #include <amcodec/codec.h> } // extern "C" +CEvent g_aml_sync_event; + class PosixFile { public: @@ -128,6 +131,11 @@ public: virtual int codec_set_cntl_mode(codec_para_t *pcodec, unsigned int mode)=0; virtual int codec_set_cntl_avthresh(codec_para_t *pcodec, unsigned int avthresh)=0; virtual int codec_set_cntl_syncthresh(codec_para_t *pcodec, unsigned int syncthresh)=0; + + virtual int codec_set_av_threshold(codec_para_t *pcodec, int threshold)=0; + virtual int codec_set_video_delay_limited_ms(codec_para_t *pcodec,int delay_ms)=0; + virtual int codec_get_video_delay_limited_ms(codec_para_t *pcodec,int *delay_ms)=0; + virtual int codec_get_video_cur_delay_ms(codec_para_t *pcodec,int *delay_ms)=0; }; class DllLibAmCodec : public DllDynamic, DllLibamCodecInterface @@ -151,6 +159,11 @@ class DllLibAmCodec : public DllDynamic, DllLibamCodecInterface DEFINE_METHOD2(int, codec_set_cntl_avthresh, (codec_para_t *p1, unsigned int p2)) DEFINE_METHOD2(int, codec_set_cntl_syncthresh,(codec_para_t *p1, unsigned int p2)) + DEFINE_METHOD2(int, codec_set_av_threshold, (codec_para_t *p1, int p2)) + DEFINE_METHOD2(int, codec_set_video_delay_limited_ms, (codec_para_t *p1, int p2)) + DEFINE_METHOD2(int, codec_get_video_delay_limited_ms, (codec_para_t *p1, int *p2)) + DEFINE_METHOD2(int, codec_get_video_cur_delay_ms, (codec_para_t *p1, int *p2)) + BEGIN_METHOD_RESOLVE() RESOLVE_METHOD(codec_init) RESOLVE_METHOD(codec_close) @@ -167,6 +180,11 @@ class DllLibAmCodec : public DllDynamic, DllLibamCodecInterface RESOLVE_METHOD(codec_set_cntl_mode) RESOLVE_METHOD(codec_set_cntl_avthresh) RESOLVE_METHOD(codec_set_cntl_syncthresh) + + RESOLVE_METHOD(codec_set_av_threshold) + RESOLVE_METHOD(codec_set_video_delay_limited_ms) + RESOLVE_METHOD(codec_get_video_delay_limited_ms) + RESOLVE_METHOD(codec_get_video_cur_delay_ms) END_METHOD_RESOLVE() public: @@ -218,14 +236,17 @@ public: #define TRICKMODE_I 0x01 #define TRICKMODE_FFFB 0x02 -// same as AV_NOPTS_VALUE -#define INT64_0 INT64_C(0x8000000000000000) +static const int64_t INT64_0 = 0x8000000000000000ULL; #define EXTERNAL_PTS (1) #define SYNC_OUTSIDE (2) +#define KEYFRAME_PTS_ONLY 0x100 // missing tags +#ifndef CODEC_TAG_VC_1 #define CODEC_TAG_VC_1 (0x312D4356) +#endif + #define CODEC_TAG_RV30 (0x30335652) #define CODEC_TAG_RV40 (0x30345652) #define CODEC_TAG_MJPEG (0x47504a4d) @@ -310,6 +331,19 @@ typedef struct am_private_t bool dumpdemux; } am_private_t; +typedef struct vframe_states +{ + int vf_pool_size; + int buf_free_num; + int buf_recycle_num; + int buf_avail_num; +} vframe_states_t; + +#ifndef AMSTREAM_IOC_VF_STATUS +#define AMSTREAM_IOC_MAGIC 'S' +#define AMSTREAM_IOC_VF_STATUS _IOR(AMSTREAM_IOC_MAGIC, 0x60, unsigned long) +#endif + /*************************************************************************/ /*************************************************************************/ void dumpfile_open(am_private_t *para) @@ -518,7 +552,7 @@ static void am_packet_init(am_packet_t *pkt) pkt->avduration = 0; pkt->isvalid = 0; pkt->newflag = 0; - pkt->lastpts = 0; + pkt->lastpts = INT64_0; pkt->data = NULL; pkt->buf = NULL; pkt->data_size = 0; @@ -543,46 +577,14 @@ void am_packet_release(am_packet_t *pkt) int check_in_pts(am_private_t *para, am_packet_t *pkt) { - int last_duration = 0; - static int last_v_duration = 0; - int64_t pts = 0; - - last_duration = last_v_duration; - - if (para->stream_type == AM_STREAM_ES) { - if ((int64_t)INT64_0 != pkt->avpts) { - pts = pkt->avpts; - - if (para->m_dll->codec_checkin_pts(pkt->codec, pts) != 0) { - CLog::Log(LOGDEBUG, "ERROR check in pts error!"); - return PLAYER_PTS_ERROR; - } - - } else if ((int64_t)INT64_0 != pkt->avdts) { - pts = pkt->avdts * last_duration; - - if (para->m_dll->codec_checkin_pts(pkt->codec, pts) != 0) { - CLog::Log(LOGDEBUG, "ERROR check in dts error!"); - return PLAYER_PTS_ERROR; - } - - last_v_duration = pkt->avduration ? pkt->avduration : 1; - } else { - if (!para->check_first_pts) { - if (para->m_dll->codec_checkin_pts(pkt->codec, 0) != 0) { - CLog::Log(LOGDEBUG, "ERROR check in 0 to video pts error!"); - return PLAYER_PTS_ERROR; - } - } - } - if (!para->check_first_pts) { - para->check_first_pts = 1; - } - } - if (pts > 0) - pkt->lastpts = pts; - - return PLAYER_SUCCESS; + if (para->stream_type == AM_STREAM_ES + && INT64_0 != pkt->avpts + && para->m_dll->codec_checkin_pts(pkt->codec, pkt->avpts) != 0) + { + CLog::Log(LOGDEBUG, "ERROR check in pts error!"); + return PLAYER_PTS_ERROR; + } + return PLAYER_SUCCESS; } static int write_header(am_private_t *para, am_packet_t *pkt) @@ -652,7 +654,7 @@ int write_av_packet(am_private_t *para, am_packet_t *pkt) } pkt->newflag = 0; } - + buf = pkt->data; size = pkt->data_size ; if (size == 0 && pkt->isvalid) { @@ -1319,9 +1321,14 @@ int set_header_info(am_private_t *para) /*************************************************************************/ CAMLCodec::CAMLCodec() - : CThread("CAMLCodec") + : m_opened(false) + , m_ptsIs64us(false) + , m_cur_pts(INT64_0) + , m_last_pts(0) + , m_bufferIndex(-1) + , m_state(0) + , m_frameSizeSum(0) { - m_opened = false; am_private = new am_private_t; memset(am_private, 0, sizeof(am_private_t)); m_dll = new DllLibAmCodec; @@ -1337,25 +1344,39 @@ CAMLCodec::CAMLCodec() CAMLCodec::~CAMLCodec() { - StopThread(); delete am_private; am_private = NULL; delete m_dll, m_dll = NULL; } +float CAMLCodec::OMXPtsToSeconds(int omxpts) +{ + return static_cast<float>(omxpts) / PTS_FREQ; +} + +int CAMLCodec::OMXDurationToNs(int duration) +{ + return static_cast<int>(static_cast<float>(duration) / PTS_FREQ * 1000000 ); +} + +int CAMLCodec::GetAmlDuration() const +{ + return am_private ? (am_private->video_rate * PTS_FREQ) / UNIT_FREQ : 0; +}; + bool CAMLCodec::OpenDecoder(CDVDStreamInfo &hints) { m_speed = DVD_PLAYSPEED_NORMAL; - m_1st_pts = 0; - m_cur_pts = 0; + m_cur_pts = INT64_0; m_dst_rect.SetRect(0, 0, 0, 0); m_zoom = -1; m_contrast = -1; m_brightness = -1; - m_vbufsize = 500000 * 2; - m_start_dts = 0; - m_start_pts = 0; + m_start_adj = 0; m_hints = hints; + m_state = 0; + m_frameSizes.clear(); + m_frameSizeSum = 0; if (!OpenAmlVideo(hints)) { @@ -1480,6 +1501,8 @@ bool CAMLCodec::OpenDecoder(CDVDStreamInfo &hints) break; case VFORMAT_MPEG4: am_private->gcodec.param = (void*)EXTERNAL_PTS; + if (m_hints.ptsinvalid) + am_private->gcodec.param = (void*)(EXTERNAL_PTS | KEYFRAME_PTS_ONLY); break; case VFORMAT_H264: case VFORMAT_H264MVC: @@ -1522,7 +1545,7 @@ bool CAMLCodec::OpenDecoder(CDVDStreamInfo &hints) case VFORMAT_VC1: // vc1 in an avi file if (m_hints.ptsinvalid) - am_private->gcodec.param = (void*)EXTERNAL_PTS; + am_private->gcodec.param = (void*)KEYFRAME_PTS_ONLY; break; case VFORMAT_HEVC: am_private->gcodec.format = VIDEO_DEC_FORMAT_HEVC; @@ -1546,9 +1569,10 @@ bool CAMLCodec::OpenDecoder(CDVDStreamInfo &hints) am_private->dumpdemux = false; dumpfile_open(am_private); - //! @bug make sure we are not stuck in pause (amcodec bug) - m_dll->codec_resume(&am_private->vcodec); + m_dll->codec_pause(&am_private->vcodec); + m_dll->codec_set_cntl_mode(&am_private->vcodec, TRICKMODE_NONE); + m_dll->codec_set_video_delay_limited_ms(&am_private->vcodec, 1000); m_dll->codec_set_cntl_avthresh(&am_private->vcodec, AV_SYNC_THRESH); m_dll->codec_set_cntl_syncthresh(&am_private->vcodec, 0); @@ -1558,8 +1582,6 @@ bool CAMLCodec::OpenDecoder(CDVDStreamInfo &hints) am_private->am_pkt.codec = &am_private->vcodec; pre_header_feeding(am_private, &am_private->am_pkt); - Create(); - m_display_rect = CRect(0, 0, CDisplaySettings::GetInstance().GetCurrentResolutionInfo().iWidth, CDisplaySettings::GetInstance().GetCurrentResolutionInfo().iHeight); std::string strScaler; @@ -1567,21 +1589,25 @@ bool CAMLCodec::OpenDecoder(CDVDStreamInfo &hints) if (strScaler.find("enabled") == std::string::npos) // Scaler not enabled, use screen size m_display_rect = CRect(0, 0, CDisplaySettings::GetInstance().GetCurrentResolutionInfo().iScreenWidth, CDisplaySettings::GetInstance().GetCurrentResolutionInfo().iScreenHeight); -/* - // if display is set to 1080xxx, then disable deinterlacer for HD content - // else bandwidth usage is too heavy and it will slow down video decoder. - char display_mode[256] = {0}; - SysfsUtils::GetString("/sys/class/display/mode", display_mode, 255); - if (strstr(display_mode,"1080")) - SysfsUtils::SetInt("/sys/module/di/parameters/bypass_all", 1); - else - SysfsUtils::SetInt("/sys/module/di/parameters/bypass_all", 0); -*/ + SysfsUtils::SetInt("/sys/class/video/freerun_mode", 1); + + + struct utsname un; + if (uname(&un) == 0) + { + int linuxversion[2]; + sscanf(un.release,"%d.%d", &linuxversion[0], &linuxversion[1]); + if (linuxversion[0] > 3 || (linuxversion[0] == 3 && linuxversion[1] >= 14)) + m_ptsIs64us = true; + } + + CLog::Log(LOGNOTICE, "CAMLCodec::OpenDecoder - using V4L2 pts format: %s", m_ptsIs64us ? "64Bit":"32Bit"); m_opened = true; // vcodec is open, update speed if it was // changed before VideoPlayer called OpenDecoder. SetSpeed(m_speed); + SetPollDevice(am_private->vcodec.cntl_handle); return true; } @@ -1600,7 +1626,7 @@ bool CAMLCodec::OpenAmlVideo(const CDVDStreamInfo &hints) m_defaultVfmMap = GetVfmMap("default"); SetVfmMap("default", "decoder ppmgr deinterlace amlvideo amvideo"); - SysfsUtils::SetInt("/sys/module/amlvideodri/parameters/freerun_mode", 1); + SysfsUtils::SetInt("/sys/module/amlvideodri/parameters/freerun_mode", 3); return true; } @@ -1636,12 +1662,13 @@ void CAMLCodec::SetVfmMap(const std::string &name, const std::string &map) void CAMLCodec::CloseDecoder() { CLog::Log(LOGDEBUG, "CAMLCodec::CloseDecoder"); - StopThread(); + + SetPollDevice(-1); // never leave vcodec ff/rw or paused. if (m_speed != DVD_PLAYSPEED_NORMAL) { - m_dll->codec_resume(&am_private->vcodec); + //m_dll->codec_resume(&am_private->vcodec); m_dll->codec_set_cntl_mode(&am_private->vcodec, TRICKMODE_NONE); } m_dll->codec_close(&am_private->vcodec); @@ -1672,6 +1699,8 @@ void CAMLCodec::Reset() if (!m_opened) return; + SetPollDevice(-1); + // set the system blackout_policy to leave the last frame showing int blackout_policy; SysfsUtils::GetInt("/sys/class/video/blackout_policy", blackout_policy); @@ -1680,11 +1709,14 @@ void CAMLCodec::Reset() // restore the speed (some amcodec versions require this) if (m_speed != DVD_PLAYSPEED_NORMAL) { - m_dll->codec_resume(&am_private->vcodec); m_dll->codec_set_cntl_mode(&am_private->vcodec, TRICKMODE_NONE); } + m_dll->codec_pause(&am_private->vcodec); + // reset the decoder m_dll->codec_reset(&am_private->vcodec); + m_dll->codec_set_video_delay_limited_ms(&am_private->vcodec, 1000); + dumpfile_close(am_private); dumpfile_open(am_private); @@ -1697,20 +1729,31 @@ void CAMLCodec::Reset() // restore the saved system blackout_policy value SysfsUtils::SetInt("/sys/class/video/blackout_policy", blackout_policy); - // reset some internal vars - m_1st_pts = 0; - m_cur_pts = 0; - m_ptsQueue.clear(); + // reset some interal vars + m_cur_pts = INT64_0; + m_state = 0; + m_start_adj = 0; + m_frameSizes.clear(); + m_frameSizeSum = 0; + SetSpeed(m_speed); + + SetPollDevice(am_private->vcodec.cntl_handle); } int CAMLCodec::Decode(uint8_t *pData, size_t iSize, double dts, double pts) { if (!m_opened) - return VC_BUFFER; + return VC_ERROR; + int rtn(0); + + float timesize(GetTimeSize()); if (pData) { + m_frameSizes.push_back(iSize); + m_frameSizeSum += iSize; + am_private->am_pkt.data = pData; am_private->am_pkt.data_size = iSize; @@ -1721,31 +1764,39 @@ int CAMLCodec::Decode(uint8_t *pData, size_t iSize, double dts, double pts) // handle pts, including 31bit wrap, aml can only handle 31 // bit pts as it uses an int in kernel. if (m_hints.ptsinvalid || pts == DVD_NOPTS_VALUE) - am_private->am_pkt.avpts = AV_NOPTS_VALUE; + am_private->am_pkt.avpts = INT64_0; else { am_private->am_pkt.avpts = 0.5 + (pts * PTS_FREQ) / DVD_TIME_BASE;\ - if (!m_start_pts && am_private->am_pkt.avpts >= 0x7fffffff) - m_start_pts = am_private->am_pkt.avpts & ~0x0000ffff; + if (!m_start_adj && am_private->am_pkt.avpts >= 0x7fffffff) + m_start_adj = am_private->am_pkt.avpts & ~0x0000ffff; + am_private->am_pkt.avpts -= m_start_adj; + m_state |= STATE_HASPTS; } - if (am_private->am_pkt.avpts != (int64_t)AV_NOPTS_VALUE) - am_private->am_pkt.avpts -= m_start_pts; // handle dts, including 31bit wrap, aml can only handle 31 // bit dts as it uses an int in kernel. if (dts == DVD_NOPTS_VALUE) - am_private->am_pkt.avdts = AV_NOPTS_VALUE; + am_private->am_pkt.avdts = am_private->am_pkt.avpts; else { am_private->am_pkt.avdts = 0.5 + (dts * PTS_FREQ) / DVD_TIME_BASE; - if (!m_start_dts && am_private->am_pkt.avdts >= 0x7fffffff) - m_start_dts = am_private->am_pkt.avdts & ~0x0000ffff; - } - if (am_private->am_pkt.avdts != (int64_t)AV_NOPTS_VALUE) - am_private->am_pkt.avdts -= m_start_dts; + if (!m_start_adj && am_private->am_pkt.avdts >= 0x7fffffff) + m_start_adj = am_private->am_pkt.avdts & ~0x0000ffff; + am_private->am_pkt.avdts -= m_start_adj; - //CLog::Log(LOGDEBUG, "CAMLCodec::Decode: iSize(%d), dts(%f), pts(%f), avdts(%llx), avpts(%llx)", - // iSize, dts, pts, am_private->am_pkt.avdts, am_private->am_pkt.avpts); + // For VC1 AML decoder uses PTS only on I-Frames + if (am_private->am_pkt.avpts == INT64_0 && (((size_t)am_private->gcodec.param) & KEYFRAME_PTS_ONLY)) + am_private->am_pkt.avpts = am_private->am_pkt.avdts; + } + // We use this to determine the fill state if no PTS is given + if (m_cur_pts == INT64_0) + { + m_cur_pts = am_private->am_pkt.avdts; + // No PTS given -> use first DTS for AML ptsserver initialization + if ((m_state & STATE_HASPTS) == 0) + am_private->am_pkt.avpts = am_private->am_pkt.avdts; + } // some formats need header/data tweaks. // the actual write occurs once in write_av_packet @@ -1767,80 +1818,142 @@ int CAMLCodec::Decode(uint8_t *pData, size_t iSize, double dts, double pts) loop++; } if (loop == 100) - { // Decoder got stuck; Reset Reset(); - } - // if we seek, then GetTimeSize is wrong as - // reports lastpts - cur_pts and hw decoder has - // not started outputing new pts values yet. - // so we grab the 1st pts sent into driver and - // use that to calc GetTimeSize. - if (m_1st_pts == 0) - m_1st_pts = am_private->am_pkt.lastpts; + if ((m_state & STATE_PREFILLED) == 0 && timesize >= 1.0) + m_state |= STATE_PREFILLED; } - // if we have still frames, demux size will be small - // and we need to pre-buffer more. - double target_timesize = 1.0; - if (iSize < 20) - target_timesize = 2.0; - - int rtn = 0; + if ((m_state & STATE_PREFILLED) != 0 && timesize > 0.5 && DequeueBuffer() == 0) + rtn |= VC_PICTURE; - // keep hw buffered demux above 1 second - if (GetTimeSize() < target_timesize) + if (((rtn & VC_PICTURE) == 0 && timesize < 2.0) || timesize < 1.0) rtn |= VC_BUFFER; - // wait until we get a new frame or 25ms, - if (m_ptsQueue.size() == 0) - m_ready_event.WaitMSec(25); - if (m_ptsQueue.size() > 0) + if (g_advancedSettings.CanLogComponent(LOGVIDEO)) { - CSingleLock lock(m_ptsQueueMutex); - m_cur_pts = m_ptsQueue.front(); - m_ptsQueue.pop_front(); - rtn |= VC_PICTURE; + CLog::Log(LOGDEBUG, "CAMLCodec::Decode: ret: %d, sz: %u, dts_in: %0.4lf[%llX], pts_in: %0.4lf[%llX], adj:%llu, ptsOut:%0.4f, amlpts:%d, idx:%u, timesize:%0.4f", + rtn, + static_cast<unsigned int>(iSize), + dts / DVD_TIME_BASE, am_private->am_pkt.avdts, + pts / DVD_TIME_BASE, am_private->am_pkt.avpts, + m_start_adj, + static_cast<float>(m_cur_pts)/PTS_FREQ, + static_cast<int>(m_cur_pts), + m_bufferIndex, + timesize + ); } -/* - CLog::Log(LOGDEBUG, "CAMLCodec::Decode: " - "rtn(%d), m_cur_pictcnt(%lld), m_cur_pts(%f), lastpts(%f), GetTimeSize(%f), GetDataSize(%d)", - rtn, m_cur_pictcnt, (float)m_cur_pts/PTS_FREQ, (float)am_private->am_pkt.lastpts/PTS_FREQ, GetTimeSize(), GetDataSize()); -*/ + return rtn; } -int CAMLCodec::DequeueBuffer(int64_t &pts) +std::atomic_flag CAMLCodec::m_pollSync = ATOMIC_FLAG_INIT; +int CAMLCodec::m_pollDevice; + +int CAMLCodec::PollFrame() +{ + CAtomicSpinLock lock(m_pollSync); + if (m_pollDevice < 0) + return 0; + + struct pollfd codec_poll_fd[1]; + + codec_poll_fd[0].fd = m_pollDevice; + codec_poll_fd[0].events = POLLOUT; + + if (poll(codec_poll_fd, 1, 100) > 0) + { + g_aml_sync_event.Set(); + return 1; + } + return 0; +} + +void CAMLCodec::SetPollDevice(int dev) { + CAtomicSpinLock lock(m_pollSync); + m_pollDevice = dev; +} + +int CAMLCodec::ReleaseFrame(const uint32_t index, bool drop) +{ + int ret; v4l2_buffer vbuf = { 0 }; vbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + vbuf.index = index; + + if (drop) + vbuf.flags |= V4L2_BUF_FLAG_DONE; + + if (g_advancedSettings.CanLogComponent(LOGVIDEO)) + CLog::Log(LOGDEBUG, "CAMLCodec::ReleaseFrame idx:%u", index); + + if ((ret = m_amlVideoFile->IOControl(VIDIOC_QBUF, &vbuf)) < 0) + CLog::Log(LOGERROR, "CAMLCodec::ReleaseFrame - VIDIOC_QBUF failed: %s", strerror(errno)); + return ret; +} + +int CAMLCodec::DequeueBuffer() +{ + v4l2_buffer vbuf = { 0 }; + vbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + + //Driver change from 10 to 0ms latency, throttle here + std::chrono::time_point<std::chrono::system_clock> now(std::chrono::system_clock::now()); if (m_amlVideoFile->IOControl(VIDIOC_DQBUF, &vbuf) < 0) { if (errno != EAGAIN) CLog::Log(LOGERROR, "CAMLCodec::DequeueBuffer - VIDIOC_DQBUF failed: %s", strerror(errno)); + + std::chrono::milliseconds elapsed(std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() - now).count()); + + if (elapsed < std::chrono::milliseconds(10)) + std::this_thread::sleep_for(std::chrono::milliseconds(10) - elapsed); + return -errno; } // Since kernel 3.14 Amlogic changed length and units of PTS values reported here. // To differentiate such PTS values we check for existence of omx_pts_interval_lower // parameter, because it was introduced since kernel 3.14. - if (access("/sys/module/amvideo/parameters/omx_pts_interval_lower", F_OK) != -1) + m_last_pts = m_cur_pts; + + if (m_ptsIs64us) { - pts = vbuf.timestamp.tv_sec & 0xFFFFFFFF; - pts <<= 32; - pts += vbuf.timestamp.tv_usec & 0xFFFFFFFF; - pts = (pts * PTS_FREQ) / DVD_TIME_BASE; + m_cur_pts = vbuf.timestamp.tv_sec & 0xFFFFFFFF; + m_cur_pts <<= 32; + m_cur_pts += vbuf.timestamp.tv_usec & 0xFFFFFFFF; + m_cur_pts = (m_cur_pts * PTS_FREQ) / DVD_TIME_BASE; } else { - pts = vbuf.timestamp.tv_usec; + m_cur_pts = vbuf.timestamp.tv_usec; } + m_bufferIndex = vbuf.index; return 0; } +float CAMLCodec::GetTimeSize() +{ + struct buf_status bs; + m_dll->codec_get_vbuf_state(&am_private->vcodec, &bs); + + //CLog::Log(LOGDEBUG, "CAMLCodec::Decode: buf status: s:%d dl:%d fl:%d rp:%u wp:%u",bs.size, bs.data_len, bs.free_len, bs.read_pointer, bs.write_pointer); + while (m_frameSizeSum > (unsigned int)bs.data_len) + { + m_frameSizeSum -= m_frameSizes.front(); + m_frameSizes.pop_front(); + } + if (bs.free_len < bs.data_len) + return 7.0; + + return (float)(m_frameSizes.size() * am_private->video_rate) / UNIT_FREQ; +} + bool CAMLCodec::GetPicture(DVDVideoPicture *pDvdVideoPicture) { if (!m_opened) @@ -1848,24 +1961,23 @@ bool CAMLCodec::GetPicture(DVDVideoPicture *pDvdVideoPicture) pDvdVideoPicture->iFlags = DVP_FLAG_ALLOCATED; pDvdVideoPicture->format = RENDER_FMT_AML; - pDvdVideoPicture->iDuration = (double)(am_private->video_rate * DVD_TIME_BASE) / UNIT_FREQ; - pDvdVideoPicture->dts = DVD_NOPTS_VALUE; - if (m_speed == DVD_PLAYSPEED_NORMAL) - pDvdVideoPicture->pts = (double)m_cur_pts / PTS_FREQ * DVD_TIME_BASE; + if (m_last_pts <= 0) + pDvdVideoPicture->iDuration = (double)(am_private->video_rate * DVD_TIME_BASE) / UNIT_FREQ; else - { - if (m_cur_pts == 0) - pDvdVideoPicture->pts = (double)m_1st_pts / PTS_FREQ * DVD_TIME_BASE; - else - pDvdVideoPicture->pts = (double)m_cur_pts / PTS_FREQ * DVD_TIME_BASE; - } + pDvdVideoPicture->iDuration = (double)((m_cur_pts - m_last_pts) * DVD_TIME_BASE) / PTS_FREQ; + + pDvdVideoPicture->dts = DVD_NOPTS_VALUE; + pDvdVideoPicture->pts = (double)GetCurPts() / PTS_FREQ * DVD_TIME_BASE; return true; } void CAMLCodec::SetSpeed(int speed) { + if (m_speed == speed) + return; + CLog::Log(LOGDEBUG, "CAMLCodec::SetSpeed, speed(%d)", speed); // update internal vars regardless @@ -1878,15 +1990,15 @@ void CAMLCodec::SetSpeed(int speed) switch(speed) { case DVD_PLAYSPEED_PAUSE: - m_dll->codec_pause(&am_private->vcodec); + //m_dll->codec_pause(&am_private->vcodec); m_dll->codec_set_cntl_mode(&am_private->vcodec, TRICKMODE_NONE); break; case DVD_PLAYSPEED_NORMAL: - m_dll->codec_resume(&am_private->vcodec); + //m_dll->codec_resume(&am_private->vcodec); m_dll->codec_set_cntl_mode(&am_private->vcodec, TRICKMODE_NONE); break; default: - m_dll->codec_resume(&am_private->vcodec); + //m_dll->codec_resume(&am_private->vcodec); if ((am_private->video_format == VFORMAT_H264) || (am_private->video_format == VFORMAT_H264_4K2K)) m_dll->codec_set_cntl_mode(&am_private->vcodec, TRICKMODE_FFFB); else @@ -1895,68 +2007,6 @@ void CAMLCodec::SetSpeed(int speed) } } -int CAMLCodec::GetDataSize() -{ - if (!m_opened) - return 0; - - struct buf_status vbuf ={0}; - if (m_dll->codec_get_vbuf_state(&am_private->vcodec, &vbuf) >= 0) - m_vbufsize = vbuf.size; - - return vbuf.data_len; -} - -double CAMLCodec::GetTimeSize() -{ - if (!m_opened) - return 0; - - // if m_cur_pts is zero, hw decoder was not started yet - // so we use the pts of the 1st demux packet that was send - // to hw decoder to calc timesize. - if (m_cur_pts == 0) - m_timesize = (double)(am_private->am_pkt.lastpts - m_1st_pts) / PTS_FREQ; - else - m_timesize = (double)(am_private->am_pkt.lastpts - GetOMXPts()) / PTS_FREQ; - - // lie to VideoPlayer, it is hardcoded to a max of 8 seconds, - // if you buffer more than 8 seconds, it goes nuts. - double timesize = m_timesize; - if (timesize < 0.0) - timesize = 0.0; - else if (timesize > 7.0) - timesize = 7.0; - - return timesize; -} - -void CAMLCodec::Process() -{ - CLog::Log(LOGDEBUG, "CAMLCodec::Process Started"); - - while (!m_bStop) - { - if (m_dll->codec_poll_cntl(&am_private->vcodec) < 0) - { - CLog::Log(LOGDEBUG, "CAMLCodec::Process: codec_poll_cntl failed"); - Sleep(10); - } - - { - CSingleLock lock(m_ptsQueueMutex); - int64_t pts = 0; - if (DequeueBuffer(pts) == 0) - { - m_ptsQueue.push_back(pts + m_start_pts); - m_ready_event.Set(); - } - } - } - - CLog::Log(LOGDEBUG, "CAMLCodec::Process Stopped"); -} - void CAMLCodec::ShowMainVideo(const bool show) { static int saved_disable_video = -1; @@ -2083,7 +2133,8 @@ void CAMLCodec::SetVideoRect(const CRect &SrcRect, const CRect &DestRect) case 1: case 3: { - int diff = (int) ((dst_rect.Height() - dst_rect.Width()) / 2); + double scale = (double)dst_rect.Height() / dst_rect.Width(); + int diff = (int) ((dst_rect.Height()*scale - dst_rect.Width()) / 2); dst_rect = CRect(DestRect.x1 - diff, DestRect.y1, DestRect.x2 + diff, DestRect.y2); } @@ -2208,3 +2259,9 @@ void CAMLCodec::SetVideoRect(const CRect &SrcRect, const CRect &DestRect) // that would show video playback, so show it. ShowMainVideo(true); } + +void CAMLCodec::SetVideoRate(int videoRate) +{ + if (am_private) + am_private->video_rate = videoRate; +} diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/AMLCodec.h b/xbmc/cores/VideoPlayer/DVDCodecs/Video/AMLCodec.h index ede815d805..402ef7f93a 100644 --- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/AMLCodec.h +++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/AMLCodec.h @@ -24,8 +24,9 @@ #include "cores/IPlayer.h" #include "guilib/Geometry.h" #include "rendering/RenderSystem.h" -#include "threads/Thread.h" + #include <deque> +#include <atomic> typedef struct am_private_t am_private_t; @@ -34,7 +35,7 @@ class DllLibAmCodec; class PosixFile; typedef std::shared_ptr<PosixFile> PosixFilePtr; -class CAMLCodec : public CThread +class CAMLCodec { public: CAMLCodec(); @@ -48,14 +49,18 @@ public: bool GetPicture(DVDVideoPicture* pDvdVideoPicture); void SetSpeed(int speed); - int GetDataSize(); - double GetTimeSize(); void SetVideoRect(const CRect &SrcRect, const CRect &DestRect); - int64_t GetCurPts() const { return m_cur_pts; } - int GetOMXPts() const { return static_cast<int>(m_cur_pts - m_start_pts); } + void SetVideoRate(int videoRate); + int64_t GetCurPts() const { return m_cur_pts + m_start_adj; } + int GetOMXPts() const { return static_cast<int>(m_cur_pts); } + uint32_t GetBufferIndex() const { return m_bufferIndex; }; + static float OMXPtsToSeconds(int omxpts); + static int OMXDurationToNs(int duration); + int GetAmlDuration() const; + int ReleaseFrame(const uint32_t index, bool bDrop = false); -protected: - virtual void Process(); + static int PollFrame(); + static void SetPollDevice(int device); private: void ShowMainVideo(const bool show); @@ -69,20 +74,20 @@ private: void CloseAmlVideo(); std::string GetVfmMap(const std::string &name); void SetVfmMap(const std::string &name, const std::string &map); - int DequeueBuffer(int64_t &pts); + int DequeueBuffer(); + float GetTimeSize(); DllLibAmCodec *m_dll; bool m_opened; + bool m_ptsIs64us; am_private_t *am_private; CDVDStreamInfo m_hints; - volatile int m_speed; - volatile int64_t m_1st_pts; - volatile int64_t m_cur_pts; - volatile double m_timesize; - volatile int64_t m_vbufsize; - int64_t m_start_dts; - int64_t m_start_pts; - CEvent m_ready_event; + int m_speed; + int64_t m_cur_pts; + uint32_t m_max_frame_size; + int64_t m_start_adj; + int64_t m_last_pts; + uint32_t m_bufferIndex; CRect m_dst_rect; CRect m_display_rect; @@ -95,8 +100,17 @@ private: int m_brightness; RESOLUTION m_video_res; + static const unsigned int STATE_PREFILLED = 1; + static const unsigned int STATE_HASPTS = 2; + + unsigned int m_state; + PosixFilePtr m_amlVideoFile; std::string m_defaultVfmMap; - std::deque<int64_t> m_ptsQueue; - CCriticalSection m_ptsQueueMutex; + + std::deque<uint32_t> m_frameSizes; + std::uint32_t m_frameSizeSum; + + static std::atomic_flag m_pollSync; + static int m_pollDevice; }; diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecAmlogic.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecAmlogic.cpp index d78631d0c6..ec0395974c 100644 --- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecAmlogic.cpp +++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecAmlogic.cpp @@ -30,6 +30,7 @@ #include "utils/log.h" #include "utils/SysfsUtils.h" #include "settings/Settings.h" +#include "threads/Thread.h" #define __MODULE_NAME__ "DVDVideoCodecAmlogic" @@ -43,16 +44,17 @@ typedef struct frame_queue { CDVDVideoCodecAmlogic::CDVDVideoCodecAmlogic(CProcessInfo &processInfo) : CDVDVideoCodec(processInfo), m_Codec(NULL), m_pFormatName("amcodec"), + m_opened(false), m_last_pts(0.0), m_frame_queue(NULL), m_queue_depth(0), m_framerate(0.0), m_video_rate(0), m_mpeg2_sequence(NULL), + m_drop(false), + m_has_keyframe(false), m_bitparser(NULL), - m_bitstream(NULL), - m_opened(false), - m_drop(false) + m_bitstream(NULL) { pthread_mutex_init(&m_queue_mutex, NULL); } @@ -125,14 +127,18 @@ bool CDVDVideoCodecAmlogic::Open(CDVDStreamInfo &hints, CDVDCodecOptions &option { m_bitstream = new CBitstreamConverter; m_bitstream->Open(m_hints.codec, (uint8_t*)m_hints.extradata, m_hints.extrasize, true); + m_bitstream->ResetKeyframe(); // make sure we do not leak the existing m_hints.extradata free(m_hints.extradata); m_hints.extrasize = m_bitstream->GetExtraSize(); m_hints.extradata = malloc(m_hints.extrasize); memcpy(m_hints.extradata, m_bitstream->GetExtraData(), m_hints.extrasize); } - //m_bitparser = new CBitstreamParser(); - //m_bitparser->Open(); + else + { + m_bitparser = new CBitstreamParser(); + m_bitparser->Open(); + } break; case AV_CODEC_ID_MPEG4: case AV_CODEC_ID_MSMPEG4V2: @@ -147,9 +153,9 @@ bool CDVDVideoCodecAmlogic::Open(CDVDStreamInfo &hints, CDVDCodecOptions &option // amcodec can't handle h263 return false; break; - case AV_CODEC_ID_FLV1: - m_pFormatName = "am-flv1"; - break; +// case AV_CODEC_ID_FLV1: +// m_pFormatName = "am-flv1"; +// break; case AV_CODEC_ID_RV10: case AV_CODEC_ID_RV20: case AV_CODEC_ID_RV30: @@ -236,6 +242,9 @@ bool CDVDVideoCodecAmlogic::Open(CDVDStreamInfo &hints, CDVDCodecOptions &option m_processInfo.SetVideoDecoderName(m_pFormatName, true); m_processInfo.SetVideoDimensions(m_hints.width, m_hints.height); m_processInfo.SetVideoDeintMethod("hardware"); + m_processInfo.SetVideoDAR(m_hints.aspect); + + m_has_keyframe = false; CLog::Log(LOGINFO, "%s: Opened Amlogic Codec", __MODULE_NAME__); return true; @@ -277,21 +286,35 @@ int CDVDVideoCodecAmlogic::Decode(uint8_t *pData, int iSize, double dts, double if (!m_bitstream->Convert(pData, iSize)) return VC_ERROR; + if (!m_bitstream->HasKeyframe()) + { + CLog::Log(LOGDEBUG, "%s::Decode waiting for keyframe (bitstream)", __MODULE_NAME__); + return VC_BUFFER; + } pData = m_bitstream->GetConvertBuffer(); iSize = m_bitstream->GetConvertSize(); } - - if (m_bitparser) - m_bitparser->FindIdrSlice(pData, iSize); - + else if (!m_has_keyframe && m_bitparser) + { + if (!m_bitparser->HasKeyframe(pData, iSize)) + { + CLog::Log(LOGDEBUG, "%s::Decode waiting for keyframe (bitparser)", __MODULE_NAME__); + return VC_BUFFER; + } + else + m_has_keyframe = true; + } FrameRateTracking( pData, iSize, dts, pts); - } - if (!m_opened) - { - if (m_Codec && !m_Codec->OpenDecoder(m_hints)) - CLog::Log(LOGERROR, "%s: Failed to open Amlogic Codec", __MODULE_NAME__); - m_opened = true; + if (!m_opened) + { + if (pts == DVD_NOPTS_VALUE) + m_hints.ptsinvalid = true; + + if (m_Codec && !m_Codec->OpenDecoder(m_hints)) + CLog::Log(LOGERROR, "%s: Failed to open Amlogic Codec", __MODULE_NAME__); + m_opened = true; + } } if (m_hints.ptsinvalid) @@ -307,6 +330,9 @@ void CDVDVideoCodecAmlogic::Reset(void) m_Codec->Reset(); m_mpeg2_sequence_pts = 0; + m_has_keyframe = false; + if (m_bitstream && m_hints.codec == AV_CODEC_ID_H264) + m_bitstream->ResetKeyframe(); } bool CDVDVideoCodecAmlogic::GetPicture(DVDVideoPicture* pDvdVideoPicture) @@ -315,7 +341,8 @@ bool CDVDVideoCodecAmlogic::GetPicture(DVDVideoPicture* pDvdVideoPicture) m_Codec->GetPicture(&m_videobuffer); *pDvdVideoPicture = m_videobuffer; - CDVDAmlogicInfo* info = new CDVDAmlogicInfo(this, m_Codec, m_Codec->GetOMXPts()); + CDVDAmlogicInfo* info = new CDVDAmlogicInfo(this, m_Codec, + m_Codec->GetOMXPts(), m_Codec->GetAmlDuration(), m_Codec->GetBufferIndex()); { CSingleLock lock(m_secure); @@ -363,7 +390,7 @@ void CDVDVideoCodecAmlogic::SetDropState(bool bDrop) // Freerun mode causes amvideo driver to ignore timing and process frames // as quickly as they are coming from decoder. By enabling freerun mode we can // skip rendering of the frames that are requested to be dropped by VideoPlayer. - SysfsUtils::SetInt("/sys/class/video/freerun_mode", bDrop ? 1 : 0); + //SysfsUtils::SetInt("/sys/class/video/freerun_mode", bDrop ? 1 : 0); } void CDVDVideoCodecAmlogic::SetSpeed(int iSpeed) @@ -372,22 +399,6 @@ void CDVDVideoCodecAmlogic::SetSpeed(int iSpeed) m_Codec->SetSpeed(iSpeed); } -int CDVDVideoCodecAmlogic::GetDataSize(void) -{ - if (m_Codec) - return m_Codec->GetDataSize(); - - return 0; -} - -double CDVDVideoCodecAmlogic::GetTimeSize(void) -{ - if (m_Codec) - return m_Codec->GetTimeSize(); - - return 0.0; -} - void CDVDVideoCodecAmlogic::FrameQueuePop(void) { if (!m_frame_queue || m_queue_depth == 0) @@ -466,8 +477,7 @@ void CDVDVideoCodecAmlogic::FrameRateTracking(uint8_t *pData, int iSize, double m_framerate = m_mpeg2_sequence->rate; m_video_rate = (int)(0.5 + (96000.0 / m_framerate)); - CLog::Log(LOGDEBUG, "%s: detected mpeg2 aspect ratio(%f), framerate(%f), video_rate(%d)", - __MODULE_NAME__, m_mpeg2_sequence->ratio, m_framerate, m_video_rate); + m_processInfo.SetVideoFps(m_framerate); // update m_hints for 1st frame fixup. switch(m_mpeg2_sequence->rate_info) @@ -526,7 +536,7 @@ void CDVDVideoCodecAmlogic::FrameRateTracking(uint8_t *pData, int iSize, double if (cur_pts == DVD_NOPTS_VALUE) cur_pts = m_frame_queue->dts; - pthread_mutex_unlock(&m_queue_mutex); + pthread_mutex_unlock(&m_queue_mutex); float duration = cur_pts - m_last_pts; m_last_pts = cur_pts; @@ -559,22 +569,10 @@ void CDVDVideoCodecAmlogic::FrameRateTracking(uint8_t *pData, int iSize, double break; // 25.000 (40000.000000) - case 40000: + case 39900 ... 40100: framerate = 25000.0 / 1000.0; break; - // 24.975 (40040.000000) - case 40040: - framerate = 25000.0 / 1001.0; - break; - - /* - // 24.000 (41666.666666) - case 41667: - framerate = 24000.0 / 1000.0; - break; - */ - // 23.976 (41708.33333) case 40200 ... 43200: // 23.976 seems to have the crappiest encodings :) @@ -592,6 +590,12 @@ void CDVDVideoCodecAmlogic::FrameRateTracking(uint8_t *pData, int iSize, double { m_framerate = framerate; m_video_rate = (int)(0.5 + (96000.0 / framerate)); + + if (m_Codec) + m_Codec->SetVideoRate(m_video_rate); + + m_processInfo.SetVideoFps(m_framerate); + CLog::Log(LOGDEBUG, "%s: detected new framerate(%f), video_rate(%d)", __MODULE_NAME__, m_framerate, m_video_rate); } @@ -607,11 +611,14 @@ void CDVDVideoCodecAmlogic::RemoveInfo(CDVDAmlogicInfo *info) m_inflight.erase(m_inflight.find(info)); } -CDVDAmlogicInfo::CDVDAmlogicInfo(CDVDVideoCodecAmlogic *codec, CAMLCodec *amlcodec, int omxPts) +CDVDAmlogicInfo::CDVDAmlogicInfo(CDVDVideoCodecAmlogic *codec, CAMLCodec *amlcodec, int omxPts, int amlDuration, uint32_t bufferIndex) : m_refs(0) , m_codec(codec) , m_amlCodec(amlcodec) , m_omxPts(omxPts) + , m_amlDuration(amlDuration) + , m_bufferIndex(bufferIndex) + , m_rendered(false) { } diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecAmlogic.h b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecAmlogic.h index 2c442413eb..9e57295701 100644 --- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecAmlogic.h +++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecAmlogic.h @@ -36,7 +36,7 @@ class CDVDVideoCodecAmlogic; class CDVDAmlogicInfo { public: - CDVDAmlogicInfo(CDVDVideoCodecAmlogic *codec, CAMLCodec *amlcodec, int omxPts); + CDVDAmlogicInfo(CDVDVideoCodecAmlogic *codec, CAMLCodec *amlcodec, int omxPts, int amlDuration, uint32_t bufferIndex); // reference counting CDVDAmlogicInfo* Retain(); @@ -44,7 +44,11 @@ public: CAMLCodec *getAmlCodec() const; int GetOmxPts() const { return m_omxPts; } + int GetAmlDuration() const { return m_amlDuration; } + uint32_t GetBufferIndex() const { return m_bufferIndex; }; void invalidate(); + void SetRendered() { m_rendered = true; }; + bool IsRendered() { return m_rendered; }; protected: long m_refs; @@ -52,7 +56,9 @@ protected: CDVDVideoCodecAmlogic* m_codec; CAMLCodec* m_amlCodec; - int m_omxPts; + int m_omxPts, m_amlDuration; + uint32_t m_bufferIndex; + bool m_rendered; }; class CDVDVideoCodecAmlogic : public CDVDVideoCodec @@ -71,8 +77,6 @@ public: virtual bool ClearPicture(DVDVideoPicture* pDvdVideoPicture); virtual void SetSpeed(int iSpeed); virtual void SetDropState(bool bDrop); - virtual int GetDataSize(void); - virtual double GetTimeSize(void); virtual const char* GetName(void) { return (const char*)m_pFormatName; } protected: @@ -98,6 +102,7 @@ protected: mpeg2_sequence *m_mpeg2_sequence; double m_mpeg2_sequence_pts; bool m_drop; + bool m_has_keyframe; CBitstreamParser *m_bitparser; CBitstreamConverter *m_bitstream; diff --git a/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamFile.cpp b/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamFile.cpp index 6f2d4f98cb..87cdc52dac 100644 --- a/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamFile.cpp +++ b/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamFile.cpp @@ -97,8 +97,8 @@ bool CDVDInputStreamFile::Open() return false; } - if (m_pFile->GetImplemenation() && (content.empty() || content == "application/octet-stream")) - m_content = m_pFile->GetImplemenation()->GetContent(); + if (m_pFile->GetImplementation() && (content.empty() || content == "application/octet-stream")) + m_content = m_pFile->GetImplementation()->GetContent(); m_eof = false; return true; diff --git a/xbmc/cores/VideoPlayer/DVDMessage.h b/xbmc/cores/VideoPlayer/DVDMessage.h index 7291399222..729068ef03 100644 --- a/xbmc/cores/VideoPlayer/DVDMessage.h +++ b/xbmc/cores/VideoPlayer/DVDMessage.h @@ -87,10 +87,6 @@ public: VIDEO_SET_ASPECT, // set aspectratio of video VIDEO_DRAIN, // wait for decoder to output last frame - // audio related messages - - AUDIO_SILENCE, - // subtitle related messages SUBTITLE_CLUTCHANGE, SUBTITLE_ADDFILE @@ -221,7 +217,6 @@ public: int time = 0; bool relative = false; bool backward = false; - bool flush = true; bool accurate = true; bool sync = true; bool restore = true; @@ -234,7 +229,6 @@ public: int GetTime() { return m_mode.time; } bool GetRelative() { return m_mode.relative; } bool GetBackward() { return m_mode.backward; } - bool GetFlush() { return m_mode.flush; } bool GetAccurate() { return m_mode.accurate; } bool GetRestore() { return m_mode.restore; } bool GetTrickPlay() { return m_mode.trickplay; } diff --git a/xbmc/cores/VideoPlayer/Edl.cpp b/xbmc/cores/VideoPlayer/Edl.cpp index c87fe21a79..9d2edda39d 100644 --- a/xbmc/cores/VideoPlayer/Edl.cpp +++ b/xbmc/cores/VideoPlayer/Edl.cpp @@ -46,6 +46,7 @@ void CEdl::Clear() m_vecCuts.clear(); m_vecSceneMarkers.clear(); m_iTotalCutTime = 0; + m_lastQueryTime = 0; } bool CEdl::ReadEditDecisionLists(const std::string& strMovie, const float fFrameRate, const int iHeight) @@ -822,8 +823,10 @@ std::string CEdl::GetInfo() const return strInfo.empty() ? "-" : strInfo; } -bool CEdl::InCut(const int iSeek, Cut *pCut) const +bool CEdl::InCut(const int iSeek, Cut *pCut) { + m_lastQueryTime = iSeek; + for (int i = 0; i < (int)m_vecCuts.size(); i++) { if (iSeek < m_vecCuts[i].start) // Early exit if not even up to the cut start time. @@ -840,6 +843,11 @@ bool CEdl::InCut(const int iSeek, Cut *pCut) const return false; } +int CEdl::GetLastQueryTime() const +{ + return m_lastQueryTime; +} + bool CEdl::GetNearestCut(bool bPlus, const int iSeek, Cut *pCut) const { if (bPlus) @@ -885,7 +893,7 @@ bool CEdl::GetNearestCut(bool bPlus, const int iSeek, Cut *pCut) const } } -bool CEdl::GetNextSceneMarker(bool bPlus, const int iClock, int *iSceneMarker) const +bool CEdl::GetNextSceneMarker(bool bPlus, const int iClock, int *iSceneMarker) { if (!HasSceneMarker()) return false; diff --git a/xbmc/cores/VideoPlayer/Edl.h b/xbmc/cores/VideoPlayer/Edl.h index c19b69fa5c..21c99088ea 100644 --- a/xbmc/cores/VideoPlayer/Edl.h +++ b/xbmc/cores/VideoPlayer/Edl.h @@ -53,18 +53,19 @@ public: int RemoveCutTime(int iSeek) const; int RestoreCutTime(int iClock) const; - bool InCut(int iSeek, Cut *pCut = NULL) const; + bool InCut(int iSeek, Cut *pCut = NULL); bool GetNearestCut(bool bPlus, const int iSeek, Cut *pCut) const; + int GetLastQueryTime() const; - bool GetNextSceneMarker(bool bPlus, const int iClock, int *iSceneMarker) const; + bool GetNextSceneMarker(bool bPlus, const int iClock, int *iSceneMarker); static std::string MillisecondsToTimeString(const int iMilliseconds); -protected: private: int m_iTotalCutTime; // ms std::vector<Cut> m_vecCuts; std::vector<int> m_vecSceneMarkers; + int m_lastQueryTime; bool ReadEdl(const std::string& strMovie, const float fFramesPerSecond); bool ReadComskip(const std::string& strMovie, const float fFramesPerSecond); diff --git a/xbmc/cores/VideoPlayer/Process/overrides/rbpi/ProcessInfoPi.cpp b/xbmc/cores/VideoPlayer/Process/overrides/rbpi/ProcessInfoPi.cpp index dab7a05956..f2fbe81aec 100644 --- a/xbmc/cores/VideoPlayer/Process/overrides/rbpi/ProcessInfoPi.cpp +++ b/xbmc/cores/VideoPlayer/Process/overrides/rbpi/ProcessInfoPi.cpp @@ -48,7 +48,7 @@ EINTERLACEMETHOD CProcessInfoPi::GetFallbackDeintMethod() bool CProcessInfoPi::AllowDTSHDDecode() { - if (g_RBP.RasberryPiVersion() == 1) + if (g_RBP.RaspberryPiVersion() == 1) return false; return true; } diff --git a/xbmc/cores/VideoPlayer/VideoPlayer.cpp b/xbmc/cores/VideoPlayer/VideoPlayer.cpp index 5945d06dea..2e1c637486 100644 --- a/xbmc/cores/VideoPlayer/VideoPlayer.cpp +++ b/xbmc/cores/VideoPlayer/VideoPlayer.cpp @@ -635,7 +635,6 @@ CVideoPlayer::CVideoPlayer(IPlayerCallback& callback) m_dvd.Clear(); m_State.Clear(); - m_EdlAutoSkipMarkers.Clear(); m_UpdateApplication = 0; m_bAbortRequest = false; @@ -747,7 +746,6 @@ bool CVideoPlayer::CloseFile(bool reopen) StopThread(); m_Edl.Clear(); - m_EdlAutoSkipMarkers.Clear(); m_HasVideo = false; m_HasAudio = false; @@ -1274,7 +1272,6 @@ void CVideoPlayer::Process() // look for any EDL files m_Edl.Clear(); - m_EdlAutoSkipMarkers.Clear(); if (m_CurrentVideo.id >= 0 && m_CurrentVideo.hint.fpsrate > 0 && m_CurrentVideo.hint.fpsscale > 0) { float fFramesPerSecond = (float)m_CurrentVideo.hint.fpsrate / (float)m_CurrentVideo.hint.fpsscale; @@ -1288,7 +1285,7 @@ void CVideoPlayer::Process() */ CEdl::Cut cut; int starttime = 0; - if(m_PlayerOptions.starttime > 0 || m_PlayerOptions.startpercent > 0) + if (m_PlayerOptions.starttime > 0 || m_PlayerOptions.startpercent > 0) { if (m_PlayerOptions.startpercent > 0 && m_pDemuxer) { @@ -1301,7 +1298,7 @@ void CVideoPlayer::Process() } CLog::Log(LOGDEBUG, "%s - Start position set to last stopped position: %d", __FUNCTION__, starttime); } - else if(m_Edl.InCut(0, &cut)) + else if (m_Edl.InCut(starttime, &cut)) { if (cut.action == CEdl::CUT) { @@ -1318,20 +1315,13 @@ void CVideoPlayer::Process() std::string strTimeString = StringUtils::SecondsToTimeString(cut.end / 1000, TIME_FORMAT_MM_SS); CGUIDialogKaiToast::QueueNotification(g_localizeStrings.Get(25011), strTimeString); - - /* - * Setup auto skip markers as if the commercial break had been skipped using standard - * detection. - */ - m_EdlAutoSkipMarkers.commbreak_start = cut.start; - m_EdlAutoSkipMarkers.commbreak_end = cut.end; - m_EdlAutoSkipMarkers.seek_to_start = true; } } - if(starttime > 0) + + if (starttime > 0) { double startpts = DVD_NOPTS_VALUE; - if(m_pDemuxer) + if (m_pDemuxer) { if (m_pDemuxer->SeekTime(starttime, false, &startpts)) CLog::Log(LOGDEBUG, "%s - starting demuxer from: %d", __FUNCTION__, starttime); @@ -1339,13 +1329,15 @@ void CVideoPlayer::Process() CLog::Log(LOGDEBUG, "%s - failed to start demuxing from: %d", __FUNCTION__, starttime); } - if(m_pSubtitleDemuxer) + if (m_pSubtitleDemuxer) { if(m_pSubtitleDemuxer->SeekTime(starttime, false, &startpts)) CLog::Log(LOGDEBUG, "%s - starting subtitle demuxer from: %d", __FUNCTION__, starttime); else CLog::Log(LOGDEBUG, "%s - failed to start subtitle demuxing from: %d", __FUNCTION__, starttime); } + + m_clock.Discontinuity(DVD_MSEC_TO_TIME(starttime)); } // make sure application know our info @@ -1372,7 +1364,6 @@ void CVideoPlayer::Process() CDVDMsgPlayerSeek::CMode mode; mode.time = (int)GetTime(); mode.backward = true; - mode.flush = true; mode.accurate = true; mode.sync = true; m_messenger.Put(new CDVDMsgPlayerSeek(mode)); @@ -1387,6 +1378,9 @@ void CVideoPlayer::Process() continue; } + // check if in a cut or commercial break that should be automatically skipped + CheckAutoSceneSkip(); + // handle messages send to this thread, like seek or demuxer reset requests HandleMessages(); @@ -1627,9 +1621,6 @@ void CVideoPlayer::Process() // process the packet ProcessPacket(pStream, pPacket); - // check if in a cut or commercial break that should be automatically skipped - CheckAutoSceneSkip(); - // update the player info for streams if (m_player_status_timer.IsTimePast()) { @@ -1727,24 +1718,13 @@ void CVideoPlayer::ProcessAudioData(CDemuxStream* pStream, DemuxPacket* pPacket) /* * If CheckSceneSkip() returns true then demux point is inside an EDL cut and the packets are dropped. - * If not inside a hard cut, but the demux point has reached an EDL mute section then trigger the - * AUDIO_SILENCE state. The AUDIO_SILENCE state is reverted as soon as the demux point is outside - * of any EDL section while EDL mute is still active. */ CEdl::Cut cut; if (CheckSceneSkip(m_CurrentAudio)) drop = true; - else if (m_Edl.InCut(DVD_TIME_TO_MSEC(m_CurrentAudio.dts + m_offset_pts), &cut) && cut.action == CEdl::MUTE // Inside EDL mute - && !m_EdlAutoSkipMarkers.mute) // Mute not already triggered - { - m_VideoPlayerAudio->SendMessage(new CDVDMsgBool(CDVDMsg::AUDIO_SILENCE, true)); - m_EdlAutoSkipMarkers.mute = true; - } - else if (!m_Edl.InCut(DVD_TIME_TO_MSEC(m_CurrentAudio.dts + m_offset_pts), &cut) // Outside of any EDL - && m_EdlAutoSkipMarkers.mute) // But the mute hasn't been removed yet + else if (m_Edl.InCut(DVD_TIME_TO_MSEC(m_CurrentAudio.dts + m_offset_pts), &cut) && cut.action == CEdl::MUTE) { - m_VideoPlayerAudio->SendMessage(new CDVDMsgBool(CDVDMsg::AUDIO_SILENCE, false)); - m_EdlAutoSkipMarkers.mute = false; + drop = true; } m_VideoPlayerAudio->SendMessage(new CDVDMsgDemuxerPacket(pPacket, drop)); @@ -1951,7 +1931,7 @@ void CVideoPlayer::HandlePlaySpeed() { CLog::Log(LOGDEBUG, "Stream stalled, start buffering. Audio: %d - Video: %d", m_VideoPlayerAudio->GetLevel(),m_VideoPlayerVideo->GetLevel()); - FlushBuffers(false); + FlushBuffers(DVD_NOPTS_VALUE, true, true); } } else @@ -1967,11 +1947,10 @@ void CVideoPlayer::HandlePlaySpeed() m_VideoPlayerAudio->GetLevel() == 0) { CLog::Log(LOGDEBUG,"CVideoPlayer::HandlePlaySpeed - audio stream stalled, triggering re-sync"); - FlushBuffers(false); + FlushBuffers(DVD_NOPTS_VALUE, true, true); CDVDMsgPlayerSeek::CMode mode; mode.time = (int)GetTime(); mode.backward = false; - mode.flush = true; mode.accurate = true; mode.sync = true; m_messenger.Put(new CDVDMsgPlayerSeek(mode)); @@ -2076,6 +2055,7 @@ void CVideoPlayer::HandlePlaySpeed() m_VideoPlayerAudio->SendMessage(new CDVDMsgDouble(CDVDMsg::GENERAL_RESYNC, clock), 1); m_VideoPlayerVideo->SendMessage(new CDVDMsgDouble(CDVDMsg::GENERAL_RESYNC, clock), 1); SetCaching(CACHESTATE_DONE); + UpdatePlayState(0); m_syncTimer.Set(3000); } @@ -2089,7 +2069,7 @@ void CVideoPlayer::HandlePlaySpeed() m_VideoPlayerVideo->IsStalled()) { CLog::Log(LOGWARNING, "VideoPlayer::Sync - stream player video does not start, flushing buffers"); - FlushBuffers(false); + FlushBuffers(DVD_NOPTS_VALUE, true, true); } } } @@ -2164,7 +2144,6 @@ void CVideoPlayer::HandlePlaySpeed() CDVDMsgPlayerSeek::CMode mode; mode.time = iTime; mode.backward = (GetPlaySpeed() < 0); - mode.flush = true; mode.accurate = false; mode.restore = false; mode.trickplay = true; @@ -2347,86 +2326,71 @@ void CVideoPlayer::CheckAutoSceneSkip() if (!m_Edl.HasCut()) return; - // Check that there is an audio and video stream. - if(m_CurrentAudio.id < 0 || - m_CurrentVideo.id < 0) + if((m_CurrentAudio.id < 0 || m_CurrentAudio.syncState != IDVDStreamPlayer::SYNC_INSYNC) || + (m_CurrentVideo.id < 0 || m_CurrentVideo.syncState != IDVDStreamPlayer::SYNC_INSYNC)) return; - // If there is a startpts defined for either the audio or video stream then VideoPlayer is still // still decoding frames to get to the previously requested seek point. - if (m_CurrentAudio.inited == false || m_CurrentVideo.inited == false) return; - if (m_CurrentAudio.dts == DVD_NOPTS_VALUE || - m_CurrentVideo.dts == DVD_NOPTS_VALUE) - return; - - const int64_t clock = m_omxplayer_mode ? GetTime() : DVD_TIME_TO_MSEC(std::min(m_CurrentAudio.dts, m_CurrentVideo.dts) + m_offset_pts); + const int64_t clock = GetTime(); + int lastPos = m_Edl.GetLastQueryTime(); CEdl::Cut cut; if (!m_Edl.InCut(clock, &cut)) return; - if (cut.action == CEdl::CUT && - !(cut.end == m_EdlAutoSkipMarkers.cut || cut.start == m_EdlAutoSkipMarkers.cut)) // To prevent looping if same cut again + if (cut.action == CEdl::CUT) { - CLog::Log(LOGDEBUG, "%s - Clock in EDL cut [%s - %s]: %s. Automatically skipping over.", - __FUNCTION__, CEdl::MillisecondsToTimeString(cut.start).c_str(), - CEdl::MillisecondsToTimeString(cut.end).c_str(), CEdl::MillisecondsToTimeString(clock).c_str()); - - //Seeking either goes to the start or the end of the cut depending on the play direction. - int seek = GetPlaySpeed() >= 0 ? cut.end : cut.start; - - // Seeking is NOT flushed so any content up to the demux point is retained when playing forwards. - CDVDMsgPlayerSeek::CMode mode; - mode.time = seek; - mode.backward = true; - mode.flush = false; - mode.accurate = false; - mode.restore = true; - mode.trickplay = false; - mode.sync = true; - m_messenger.Put(new CDVDMsgPlayerSeek(mode)); - - // Seek doesn't always work reliably. Last physical seek time is recorded to prevent looping - // if there was an error with seeking and it landed somewhere unexpected, perhaps back in the - // cut. The cut automatic skip marker is reset every 500ms allowing another attempt at the seek. - m_EdlAutoSkipMarkers.cut = GetPlaySpeed() >= 0 ? cut.end : cut.start; - } - else if (cut.action == CEdl::COMM_BREAK && GetPlaySpeed() >= 0 && - cut.start > m_EdlAutoSkipMarkers.commbreak_end) - { - std::string strTimeString = StringUtils::SecondsToTimeString((cut.end - cut.start) / 1000, TIME_FORMAT_MM_SS); - CGUIDialogKaiToast::QueueNotification(g_localizeStrings.Get(25011), strTimeString); - - if (m_SkipCommercials) + if ((GetPlaySpeed() > 0 && clock < cut.end - 1000) || + (GetPlaySpeed() < 0 && clock < cut.start + 1000)) { - CLog::Log(LOGDEBUG, "%s - Clock in commercial break [%s - %s]: %s. Automatically skipping to end of commercial break (only done once per break)", - __FUNCTION__, CEdl::MillisecondsToTimeString(cut.start).c_str(), CEdl::MillisecondsToTimeString(cut.end).c_str(), - CEdl::MillisecondsToTimeString(clock).c_str()); + CLog::Log(LOGDEBUG, "%s - Clock in EDL cut [%s - %s]: %s. Automatically skipping over.", + __FUNCTION__, CEdl::MillisecondsToTimeString(cut.start).c_str(), + CEdl::MillisecondsToTimeString(cut.end).c_str(), CEdl::MillisecondsToTimeString(clock).c_str()); + + //Seeking either goes to the start or the end of the cut depending on the play direction. + int seek = GetPlaySpeed() >= 0 ? cut.end : cut.start; - // Seeking is NOT flushed so any content up to the demux point is retained when playing forwards. CDVDMsgPlayerSeek::CMode mode; - mode.time = cut.end + 1; + mode.time = seek; mode.backward = true; - mode.flush = false; - mode.accurate = false; + mode.accurate = true; mode.restore = true; mode.trickplay = false; mode.sync = true; m_messenger.Put(new CDVDMsgPlayerSeek(mode)); } + } + else if (cut.action == CEdl::COMM_BREAK) + { + // marker for commbrak may be inaccurate. allow user to skip into break from the back + if (GetPlaySpeed() >= 0 && lastPos <= cut.start && clock < cut.end - 1000) + { + std::string strTimeString = StringUtils::SecondsToTimeString((cut.end - cut.start) / 1000, TIME_FORMAT_MM_SS); + CGUIDialogKaiToast::QueueNotification(g_localizeStrings.Get(25011), strTimeString); + + if (m_SkipCommercials) + { + CLog::Log(LOGDEBUG, "%s - Clock in commercial break [%s - %s]: %s. Automatically skipping to end of commercial break", + __FUNCTION__, CEdl::MillisecondsToTimeString(cut.start).c_str(), + CEdl::MillisecondsToTimeString(cut.end).c_str(), + CEdl::MillisecondsToTimeString(clock).c_str()); - // Each commercial break is only skipped once so poorly detected commercial breaks can be - // manually re-entered. Start and end are recorded to prevent looping and to allow seeking back - // to the start of the commercial break if incorrectly flagged. - m_EdlAutoSkipMarkers.commbreak_start = cut.start; - m_EdlAutoSkipMarkers.commbreak_end = cut.end; - m_EdlAutoSkipMarkers.seek_to_start = true; // Allow backwards Seek() to go directly to the start + CDVDMsgPlayerSeek::CMode mode; + mode.time = cut.end; + mode.backward = true; + mode.accurate = true; + mode.restore = false; + mode.trickplay = false; + mode.sync = true; + m_messenger.Put(new CDVDMsgPlayerSeek(mode)); + } + } } } @@ -2559,8 +2523,7 @@ void CVideoPlayer::HandleMessages() if (!msg.GetTrickPlay()) { g_infoManager.SetDisplayAfterSeek(100000); - if(msg.GetFlush()) - SetCaching(CACHESTATE_FLUSH); + SetCaching(CACHESTATE_FLUSH); } double start = DVD_NOPTS_VALUE; @@ -2596,7 +2559,7 @@ void CVideoPlayer::HandleMessages() m_State.dts = start; m_State.lastSeek = m_clock.GetAbsoluteClock(); - FlushBuffers(!msg.GetFlush(), start, msg.GetAccurate(), msg.GetSync()); + FlushBuffers(start, msg.GetAccurate(), msg.GetSync()); } else if (m_pDemuxer) { @@ -2607,7 +2570,7 @@ void CVideoPlayer::HandleMessages() m_State.dts = start; - FlushBuffers(false, start, false, true); + FlushBuffers(start, false, true); if (m_playSpeed != DVD_PLAYSPEED_PAUSE) { SetPlaySpeed(DVD_PLAYSPEED_NORMAL); @@ -2639,7 +2602,7 @@ void CVideoPlayer::HandleMessages() // This should always be the case. if(m_pDemuxer && m_pDemuxer->SeekChapter(msg.GetChapter(), &start)) { - FlushBuffers(false, start, true); + FlushBuffers(start, true, true); offset = DVD_TIME_TO_MSEC(start) - beforeSeek; m_callback.OnPlayBackSeekChapter(msg.GetChapter()); } @@ -2675,7 +2638,6 @@ void CVideoPlayer::HandleMessages() CDVDMsgPlayerSeek::CMode mode; mode.time = (int)GetTime(); mode.backward = true; - mode.flush = true; mode.accurate = true; mode.trickplay = true; mode.sync = true; @@ -2691,7 +2653,6 @@ void CVideoPlayer::HandleMessages() CDVDMsgPlayerSeek::CMode mode; mode.time = (int)GetTime(); mode.backward = true; - mode.flush = true; mode.accurate = true; mode.trickplay = true; mode.sync = true; @@ -2716,7 +2677,6 @@ void CVideoPlayer::HandleMessages() CDVDMsgPlayerSeek::CMode mode; mode.time = (int)GetTime(); mode.backward = true; - mode.flush = true; mode.accurate = true; mode.trickplay = true; mode.sync = true; @@ -2730,7 +2690,6 @@ void CVideoPlayer::HandleMessages() CDVDMsgPlayerSeek::CMode mode; mode.time = (int)GetTime(); mode.backward = true; - mode.flush = true; mode.accurate = true; mode.trickplay = true; mode.sync = true; @@ -2793,7 +2752,7 @@ void CVideoPlayer::HandleMessages() } else if (pMsg->IsType(CDVDMsg::GENERAL_FLUSH)) { - FlushBuffers(false); + FlushBuffers(DVD_NOPTS_VALUE, true, true); } else if (pMsg->IsType(CDVDMsg::PLAYER_SETSPEED)) { @@ -2839,7 +2798,6 @@ void CVideoPlayer::HandleMessages() CDVDMsgPlayerSeek::CMode mode; mode.time = iTime; mode.backward = m_playSpeed < 0; - mode.flush = true; mode.accurate = false; mode.trickplay = true; mode.sync = true; @@ -2858,7 +2816,6 @@ void CVideoPlayer::HandleMessages() CDVDMsgPlayerSeek::CMode mode; mode.time = (int)GetTime(); mode.backward = (speed < 0); - mode.flush = true; mode.accurate = true; mode.restore = false; mode.trickplay = true; @@ -2887,7 +2844,7 @@ void CVideoPlayer::HandleMessages() else if (pMsg->IsType(CDVDMsg::PLAYER_CHANNEL_SELECT_NUMBER) && m_messenger.GetPacketCount(CDVDMsg::PLAYER_CHANNEL_SELECT_NUMBER) == 0) { - FlushBuffers(false); + FlushBuffers(DVD_NOPTS_VALUE, true, true); CDVDInputStreamPVRManager* input = dynamic_cast<CDVDInputStreamPVRManager*>(m_pInputStream); //! @todo find a better solution for the "otherStreamHack" //! a stream is not supposed to be terminated before demuxer @@ -2914,7 +2871,7 @@ void CVideoPlayer::HandleMessages() else if (pMsg->IsType(CDVDMsg::PLAYER_CHANNEL_SELECT) && m_messenger.GetPacketCount(CDVDMsg::PLAYER_CHANNEL_SELECT) == 0) { - FlushBuffers(false); + FlushBuffers(DVD_NOPTS_VALUE, true, true); CDVDInputStreamPVRManager* input = dynamic_cast<CDVDInputStreamPVRManager*>(m_pInputStream); if (input && input->IsOtherStreamHack()) { @@ -2947,7 +2904,7 @@ void CVideoPlayer::HandleMessages() if (!bShowPreview) { g_infoManager.SetDisplayAfterSeek(100000); - FlushBuffers(false); + FlushBuffers(DVD_NOPTS_VALUE, true, true); if (input->IsOtherStreamHack()) { CloseDemuxer(); @@ -3185,52 +3142,6 @@ void CVideoPlayer::Seek(bool bPlus, bool bLargeStep, bool bChapterOverride) } bool restore = true; - if (m_Edl.HasCut()) - { - /* - * Alter the standard seek position based on whether any commercial breaks have been - * automatically skipped. - */ - const int clock = DVD_TIME_TO_MSEC(m_clock.GetClock()); - /* - * If a large backwards seek occurs within 10 seconds of the end of the last automated - * commercial skip, then seek back to the start of the commercial break under the assumption - * it was flagged incorrectly. 10 seconds grace period is allowed in case the watcher has to - * fumble around finding the remote. Only happens once per commercial break. - * - * Small skip does not trigger this in case the start of the commercial break was in fact fine - * but it skipped too far into the program. In that case small skip backwards behaves as normal. - */ - if (!bPlus && bLargeStep && - m_EdlAutoSkipMarkers.seek_to_start && - clock >= m_EdlAutoSkipMarkers.commbreak_end && - clock <= m_EdlAutoSkipMarkers.commbreak_end + 10*1000) // Only if within 10 seconds of the end (in msec) - { - CLog::Log(LOGDEBUG, "%s - Seeking back to start of commercial break [%s - %s] as large backwards skip activated within 10 seconds of the automatic commercial skip (only done once per break).", - __FUNCTION__, CEdl::MillisecondsToTimeString(m_EdlAutoSkipMarkers.commbreak_start).c_str(), - CEdl::MillisecondsToTimeString(m_EdlAutoSkipMarkers.commbreak_end).c_str()); - seekTarget = m_EdlAutoSkipMarkers.commbreak_start; - restore = false; - m_EdlAutoSkipMarkers.seek_to_start = false; // So this will only happen within the 10 second grace period once. - } - /* - * If big skip forward within the last "reverted" commercial break, seek to the end of the - * commercial break under the assumption that the break was incorrectly flagged and playback has - * now reached the actual start of the commercial break. Assume that the end is flagged more - * correctly than the landing point for a standard big skip (ends seem to be flagged more - * accurately than the start). - */ - else if (bPlus && bLargeStep && - clock >= m_EdlAutoSkipMarkers.commbreak_start && - clock <= m_EdlAutoSkipMarkers.commbreak_end) - { - CLog::Log(LOGDEBUG, "%s - Seeking to end of previously skipped commercial break [%s - %s] as big forwards skip activated within the break.", - __FUNCTION__, CEdl::MillisecondsToTimeString(m_EdlAutoSkipMarkers.commbreak_start).c_str(), - CEdl::MillisecondsToTimeString(m_EdlAutoSkipMarkers.commbreak_end).c_str()); - seekTarget = m_EdlAutoSkipMarkers.commbreak_end; - restore = false; - } - } int64_t time = GetTime(); if(g_application.CurrentFileItem().IsStack() && @@ -3245,7 +3156,6 @@ void CVideoPlayer::Seek(bool bPlus, bool bLargeStep, bool bChapterOverride) CDVDMsgPlayerSeek::CMode mode; mode.time = (int)seekTarget; mode.backward = !bPlus; - mode.flush = true; mode.accurate = false; mode.restore = restore; mode.trickplay = false; @@ -3280,7 +3190,6 @@ bool CVideoPlayer::SeekScene(bool bPlus) CDVDMsgPlayerSeek::CMode mode; mode.time = iScenemarker; mode.backward = !bPlus; - mode.flush = true; mode.accurate = false; mode.restore = false; mode.trickplay = false; @@ -3577,7 +3486,6 @@ void CVideoPlayer::SeekTime(int64_t iTime) CDVDMsgPlayerSeek::CMode mode; mode.time = (int)iTime; mode.backward = true; - mode.flush = true; mode.accurate = true; mode.trickplay = false; mode.sync = true; @@ -3595,7 +3503,6 @@ bool CVideoPlayer::SeekTimeRelative(int64_t iTime) mode.time = (int)iTime; mode.relative = true; mode.backward = (iTime < 0) ? true : false; - mode.flush = true; mode.accurate = false; mode.trickplay = false; mode.sync = true; @@ -4027,7 +3934,7 @@ bool CVideoPlayer::CloseStream(CCurrentStream& current, bool bWaitForBuffers) return true; } -void CVideoPlayer::FlushBuffers(bool queued, double pts, bool accurate, bool sync) +void CVideoPlayer::FlushBuffers(double pts, bool accurate, bool sync) { CLog::Log(LOGDEBUG, "CVideoPlayer::FlushBuffers - flushing buffers"); @@ -4068,63 +3975,45 @@ void CVideoPlayer::FlushBuffers(bool queued, double pts, bool accurate, bool syn m_CurrentRadioRDS.startpts = startpts; m_CurrentRadioRDS.packets = 0; - if (queued) - { - m_VideoPlayerAudio->SendMessage(new CDVDMsg(CDVDMsg::GENERAL_RESET)); - m_VideoPlayerVideo->SendMessage(new CDVDMsg(CDVDMsg::GENERAL_RESET)); - m_VideoPlayerSubtitle->SendMessage(new CDVDMsg(CDVDMsg::GENERAL_RESET)); - m_VideoPlayerTeletext->SendMessage(new CDVDMsg(CDVDMsg::GENERAL_RESET)); - m_VideoPlayerRadioRDS->SendMessage(new CDVDMsg(CDVDMsg::GENERAL_RESET)); + m_VideoPlayerAudio->Flush(sync); + m_VideoPlayerVideo->Flush(sync); + m_VideoPlayerSubtitle->Flush(); + m_VideoPlayerTeletext->Flush(); + m_VideoPlayerRadioRDS->Flush(); + + // clear subtitle and menu overlays + m_overlayContainer.Clear(); - CDVDMsgGeneralSynchronize* msg = new CDVDMsgGeneralSynchronize(10*1000, SYNCSOURCE_AUDIO | SYNCSOURCE_VIDEO); + if(m_playSpeed == DVD_PLAYSPEED_NORMAL || + m_playSpeed == DVD_PLAYSPEED_PAUSE) + { + // make sure players are properly flushed, should put them in stalled state + CDVDMsgGeneralSynchronize* msg = new CDVDMsgGeneralSynchronize(1000, SYNCSOURCE_AUDIO | SYNCSOURCE_VIDEO); m_VideoPlayerAudio->SendMessage(msg->Acquire(), 1); m_VideoPlayerVideo->SendMessage(msg->Acquire(), 1); msg->Wait(m_bStop, 0); msg->Release(); - } - else - { - m_VideoPlayerAudio->Flush(sync); - m_VideoPlayerVideo->Flush(sync); - m_VideoPlayerSubtitle->Flush(); - m_VideoPlayerTeletext->Flush(); - m_VideoPlayerRadioRDS->Flush(); - // clear subtitle and menu overlays - m_overlayContainer.Clear(); + // purge any pending PLAYER_STARTED messages + m_messenger.Flush(CDVDMsg::PLAYER_STARTED); - if(m_playSpeed == DVD_PLAYSPEED_NORMAL - || m_playSpeed == DVD_PLAYSPEED_PAUSE) + // we should now wait for init cache + SetCaching(CACHESTATE_FLUSH); + if (sync) { - // make sure players are properly flushed, should put them in stalled state - CDVDMsgGeneralSynchronize* msg = new CDVDMsgGeneralSynchronize(1000, SYNCSOURCE_AUDIO | SYNCSOURCE_VIDEO); - m_VideoPlayerAudio->SendMessage(msg->Acquire(), 1); - m_VideoPlayerVideo->SendMessage(msg->Acquire(), 1); - msg->Wait(m_bStop, 0); - msg->Release(); - - // purge any pending PLAYER_STARTED messages - m_messenger.Flush(CDVDMsg::PLAYER_STARTED); - - // we should now wait for init cache - SetCaching(CACHESTATE_FLUSH); - if (sync) - { - m_CurrentAudio.syncState = IDVDStreamPlayer::SYNC_STARTING; - m_CurrentVideo.syncState = IDVDStreamPlayer::SYNC_STARTING; - } + m_CurrentAudio.syncState = IDVDStreamPlayer::SYNC_STARTING; + m_CurrentVideo.syncState = IDVDStreamPlayer::SYNC_STARTING; } - - if(pts != DVD_NOPTS_VALUE && sync) - m_clock.Discontinuity(pts); - UpdatePlayState(0); } + if(pts != DVD_NOPTS_VALUE && sync) + m_clock.Discontinuity(pts); + UpdatePlayState(0); + if (m_omxplayer_mode) { m_OmxPlayerState.av_clock.OMXFlush(); - if (!queued) - m_OmxPlayerState.av_clock.OMXStop(); + m_OmxPlayerState.av_clock.OMXStop(); m_OmxPlayerState.av_clock.OMXPause(); m_OmxPlayerState.av_clock.OMXMediaTime(0.0); } @@ -4315,7 +4204,7 @@ int CVideoPlayer::OnDVDNavResult(void* pData, int iMessage) else { bool sync = !IsInMenuInternal(); - FlushBuffers(false, DVD_NOPTS_VALUE, false, sync); + FlushBuffers(DVD_NOPTS_VALUE, false, sync); m_dvd.syncClock = true; m_dvd.state = DVDSTATE_NORMAL; if (m_pDemuxer) @@ -4572,7 +4461,6 @@ bool CVideoPlayer::OnAction(const CAction &action) CDVDMsgPlayerSeek::CMode mode; mode.time = cut.end + 1; mode.backward = false; - mode.flush = true; mode.accurate = false; mode.restore = true; mode.trickplay = false; @@ -4612,7 +4500,6 @@ bool CVideoPlayer::OnAction(const CAction &action) CDVDMsgPlayerSeek::CMode mode; mode.time = cut.start - 1; mode.backward = true; - mode.flush = true; mode.accurate = false; mode.restore = true; mode.trickplay = false; @@ -4627,7 +4514,6 @@ bool CVideoPlayer::OnAction(const CAction &action) CDVDMsgPlayerSeek::CMode mode; mode.time = 0; mode.backward = true; - mode.flush = true; mode.accurate = false; mode.restore = true; mode.trickplay = false; @@ -5203,9 +5089,6 @@ bool CVideoPlayer::SwitchChannel(const CPVRChannelPtr &channel) if (g_PVRManager.IsPlayingChannel(channel)) return false; // desired channel already active, nothing to do. - if (!g_PVRManager.CheckParentalLock(channel)) - return false; - /* set GUI info */ if (!g_PVRManager.PerformChannelSwitch(channel, true)) return false; diff --git a/xbmc/cores/VideoPlayer/VideoPlayer.h b/xbmc/cores/VideoPlayer/VideoPlayer.h index 1cc1abbf5a..a19f3d1d7f 100644 --- a/xbmc/cores/VideoPlayer/VideoPlayer.h +++ b/xbmc/cores/VideoPlayer/VideoPlayer.h @@ -463,8 +463,7 @@ protected: double GetQueueTime(); bool GetCachingTimes(double& play_left, double& cache_left, double& file_offset); - - void FlushBuffers(bool queued, double pts = DVD_NOPTS_VALUE, bool accurate = true, bool sync = true); + void FlushBuffers(double pts, bool accurate, bool sync); void HandleMessages(); void HandlePlaySpeed(); @@ -586,25 +585,6 @@ protected: CEdl m_Edl; bool m_SkipCommercials; - struct SEdlAutoSkipMarkers { - - void Clear() - { - cut = -1; - commbreak_start = -1; - commbreak_end = -1; - seek_to_start = false; - mute = false; - } - - int cut; // last automatically skipped EDL cut seek position - int commbreak_start; // start time of the last commercial break automatically skipped - int commbreak_end; // end time of the last commercial break automatically skipped - bool seek_to_start; // whether seeking can go back to the start of a previously skipped break - bool mute; // whether EDL mute is on - - } m_EdlAutoSkipMarkers; - CPlayerOptions m_PlayerOptions; bool m_HasVideo; diff --git a/xbmc/cores/VideoPlayer/VideoPlayerAudio.cpp b/xbmc/cores/VideoPlayer/VideoPlayerAudio.cpp index a40c6191e5..9a5164eae9 100644 --- a/xbmc/cores/VideoPlayer/VideoPlayerAudio.cpp +++ b/xbmc/cores/VideoPlayer/VideoPlayerAudio.cpp @@ -70,7 +70,6 @@ CVideoPlayerAudio::CVideoPlayerAudio(CDVDClock* pClock, CDVDMessageQueue& parent m_stalled = true; m_paused = false; m_syncState = IDVDStreamPlayer::SYNC_STARTING; - m_silence = false; m_synctype = SYNC_DISCON; m_setsynctype = SYNC_DISCON; m_prevsynctype = -1; @@ -151,7 +150,6 @@ void CVideoPlayerAudio::OpenStream(CDVDStreamInfo &hints, CDVDAudioCodec* codec) m_prevsynctype = -1; m_prevskipped = false; - m_silence = false; m_maxspeedadjust = 5.0; @@ -346,12 +344,6 @@ void CVideoPlayerAudio::Process() } m_speed = speed; } - else if (pMsg->IsType(CDVDMsg::AUDIO_SILENCE)) - { - m_silence = static_cast<CDVDMsgBool*>(pMsg)->m_value; - CLog::Log(LOGDEBUG, "CVideoPlayerAudio - CDVDMsg::AUDIO_SILENCE(%f, %d)" - , m_audioClock, m_silence); - } else if (pMsg->IsType(CDVDMsg::GENERAL_STREAMCHANGE)) { CDVDMsgAudioCodecChange* msg(static_cast<CDVDMsgAudioCodecChange*>(pMsg)); @@ -458,14 +450,6 @@ void CVideoPlayerAudio::Process() m_messageParent.Put(new CDVDMsg(CDVDMsg::PLAYER_AVCHANGE)); } - // Zero out the frame data if we are supposed to silence the audio - if (m_silence) - { - int size = audioframe.nb_frames * audioframe.framesize / audioframe.planes; - for (unsigned int i=0; i<audioframe.planes; i++) - memset(audioframe.data[i], 0, size); - } - SetSyncType(audioframe.passthrough); if (!bPacketDrop) diff --git a/xbmc/cores/VideoPlayer/VideoPlayerAudio.h b/xbmc/cores/VideoPlayer/VideoPlayerAudio.h index ca1da99a23..3345fcf49e 100644 --- a/xbmc/cores/VideoPlayer/VideoPlayerAudio.h +++ b/xbmc/cores/VideoPlayer/VideoPlayerAudio.h @@ -95,7 +95,6 @@ protected: int m_speed; bool m_stalled; - bool m_silence; bool m_paused; IDVDStreamPlayer::ESyncState m_syncState; XbmcThreads::EndTime m_syncTimer; diff --git a/xbmc/video/VideoReferenceClock.cpp b/xbmc/cores/VideoPlayer/VideoReferenceClock.cpp index 83bed67a32..0dd7ea9b87 100644 --- a/xbmc/video/VideoReferenceClock.cpp +++ b/xbmc/cores/VideoPlayer/VideoReferenceClock.cpp @@ -24,36 +24,9 @@ #include "utils/TimeUtils.h" #include "threads/SingleLock.h" #include "guilib/GraphicContext.h" -#include "video/videosync/VideoSync.h" #include "settings/Settings.h" - -#if defined(HAS_GLX) -#include "video/videosync/VideoSyncGLX.h" -#endif -#if defined(HAVE_X11) -#include "video/videosync/VideoSyncDRM.h" +#include "windowing/VideoSync.h" #include "windowing/WindowingFactory.h" -#elif defined(TARGET_RASPBERRY_PI) -#include "video/videosync/VideoSyncPi.h" -#elif defined(HAS_IMXVPU) -#include "video/videosync/VideoSyncIMX.h" -#endif -#if defined(TARGET_WINDOWS) -#include "video/videosync/VideoSyncD3D.h" -#endif -#if defined(TARGET_DARWIN_OSX) -#include "video/videosync/VideoSyncOsx.h" -#endif -#if defined(TARGET_DARWIN_IOS) -#include "video/videosync/VideoSyncIos.h" -#endif -#if defined(TARGET_ANDROID) -#include "video/videosync/VideoSyncAndroid.h" -#endif - -#ifdef TARGET_POSIX -#include "linux/XTimeUtils.h" -#endif CVideoReferenceClock::CVideoReferenceClock() : CThread("RefClock") { @@ -70,8 +43,6 @@ CVideoReferenceClock::CVideoReferenceClock() : CThread("RefClock") m_MissedVblanks = 0; m_VblankTime = 0; - m_pVideoSync = nullptr; - Start(); } @@ -87,12 +58,13 @@ void CVideoReferenceClock::Start() Create(); } -void CVideoReferenceClock::CBUpdateClock(int NrVBlanks, uint64_t time, CVideoReferenceClock *clock) +void CVideoReferenceClock::CBUpdateClock(int NrVBlanks, uint64_t time, void *clock) { { - CSingleLock lock(clock->m_CritSection); - clock->m_VblankTime = time; - clock->UpdateClock(NrVBlanks, true); + CVideoReferenceClock *refClock = static_cast<CVideoReferenceClock*>(clock); + CSingleLock lock(refClock->m_CritSection); + refClock->m_VblankTime = time; + refClock->UpdateClock(NrVBlanks, true); } } @@ -103,30 +75,7 @@ void CVideoReferenceClock::Process() while(!m_bStop) { - //set up the vblank clock -#if defined(HAVE_X11) - std::string gpuvendor = g_Windowing.GetRenderVendor(); - std::transform(gpuvendor.begin(), gpuvendor.end(), gpuvendor.begin(), ::tolower); - if ((gpuvendor.compare(0, 5, "intel") == 0 || - gpuvendor.compare(0, 5, "x.org") == 0)) // AMD - m_pVideoSync = new CVideoSyncDRM(this); -#if defined(HAS_GLX) - else - m_pVideoSync = new CVideoSyncGLX(this); -#endif -#elif defined(TARGET_WINDOWS) - m_pVideoSync = new CVideoSyncD3D(this); -#elif defined(TARGET_DARWIN_OSX) - m_pVideoSync = new CVideoSyncOsx(this); -#elif defined(TARGET_DARWIN_IOS) - m_pVideoSync = new CVideoSyncIos(this); -#elif defined(TARGET_RASPBERRY_PI) - m_pVideoSync = new CVideoSyncPi(this); -#elif defined(HAS_IMXVPU) - m_pVideoSync = new CVideoSyncIMX(this); -#elif defined(TARGET_ANDROID) - m_pVideoSync = new CVideoSyncAndroid(this); -#endif + m_pVideoSync = g_Windowing.GetVideoSync(this); if (m_pVideoSync) { @@ -168,8 +117,7 @@ void CVideoReferenceClock::Process() if (m_pVideoSync) { m_pVideoSync->Cleanup(); - delete m_pVideoSync; - m_pVideoSync = nullptr; + m_pVideoSync.reset(); } if (!SetupSuccess) diff --git a/xbmc/video/VideoReferenceClock.h b/xbmc/cores/VideoPlayer/VideoReferenceClock.h index 659e4269a2..00f58bf7ec 100644 --- a/xbmc/video/VideoReferenceClock.h +++ b/xbmc/cores/VideoPlayer/VideoReferenceClock.h @@ -21,6 +21,7 @@ #include "threads/Thread.h" #include "threads/CriticalSection.h" +#include <memory> class CVideoSync; @@ -43,7 +44,7 @@ class CVideoReferenceClock : public CThread void UpdateClock(int NrVBlanks, bool CheckMissed); double UpdateInterval() const; int64_t TimeOfNextVblank() const; - static void CBUpdateClock(int NrVBlanks, uint64_t time, CVideoReferenceClock *clock); + static void CBUpdateClock(int NrVBlanks, uint64_t time, void *clock); int64_t m_CurrTime; //the current time of the clock when using vblank as clock source int64_t m_LastIntTime; //last interpolated clock value, to make sure the clock doesn't go backwards @@ -60,5 +61,5 @@ class CVideoReferenceClock : public CThread CCriticalSection m_CritSection; - CVideoSync *m_pVideoSync; + std::unique_ptr<CVideoSync> m_pVideoSync; }; diff --git a/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/RendererAML.cpp b/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/RendererAML.cpp index d8674c8578..292f07b9b6 100644 --- a/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/RendererAML.cpp +++ b/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/RendererAML.cpp @@ -21,26 +21,58 @@ #include "RendererAML.h" #if defined(HAS_LIBAMCODEC) -#include "cores/IPlayer.h" -#include "windowing/egl/EGLWrapper.h" #include "cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecAmlogic.h" #include "cores/VideoPlayer/DVDCodecs/Video/AMLCodec.h" #include "utils/log.h" -#include "utils/GLUtils.h" #include "utils/SysfsUtils.h" #include "settings/MediaSettings.h" #include "windowing/WindowingFactory.h" #include "cores/VideoPlayer/VideoRenderers/RenderCapture.h" +#include "settings/AdvancedSettings.h" CRendererAML::CRendererAML() + : m_prevVPts(-1) + , m_bConfigured(false) + , m_iRenderBuffer(0) { - m_prevPts = -1; } CRendererAML::~CRendererAML() { } +bool CRendererAML::Configure(unsigned int width, unsigned int height, unsigned int d_width, unsigned int d_height, float fps, unsigned flags, ERenderFormat format, unsigned extended_formatl, unsigned int orientation) +{ + m_sourceWidth = width; + m_sourceHeight = height; + m_renderOrientation = orientation; + + // Save the flags. + m_iFlags = flags; + m_format = format; + + // Calculate the input frame aspect ratio. + CalculateFrameAspectRatio(d_width, d_height); + SetViewMode(CMediaSettings::GetInstance().GetCurrentVideoSettings().m_ViewMode); + ManageRenderArea(); + + m_bConfigured = true; + + for (int i = 0 ; i < m_numRenderBuffers ; ++i) + m_buffers[i].hwDec = 0; + + return true; +} + +CRenderInfo CRendererAML::GetRenderInfo() +{ + CRenderInfo info; + info.formats.push_back(RENDER_FMT_BYPASS); + info.max_buffer_size = m_numRenderBuffers; + info.optimal_buffer_size = m_numRenderBuffers; + return info; +} + bool CRendererAML::RenderCapture(CRenderCapture* capture) { capture->BeginRender(); @@ -48,27 +80,50 @@ bool CRendererAML::RenderCapture(CRenderCapture* capture) return true; } +int CRendererAML::GetImage(YV12Image *image, int source, bool readonly) +{ + if (image == nullptr) + return -1; + + /* take next available buffer */ + if (source == -1) + source = (m_iRenderBuffer + 1) % m_numRenderBuffers; + + return source; +} + void CRendererAML::AddVideoPictureHW(DVDVideoPicture &picture, int index) { - YUVBUFFER &buf = m_buffers[index]; + BUFFER &buf = m_buffers[index]; if (picture.amlcodec) buf.hwDec = picture.amlcodec->Retain(); } void CRendererAML::ReleaseBuffer(int idx) { - YUVBUFFER &buf = m_buffers[idx]; + BUFFER &buf = m_buffers[idx]; if (buf.hwDec) { CDVDAmlogicInfo *amli = static_cast<CDVDAmlogicInfo *>(buf.hwDec); - SAFE_RELEASE(amli); + if (amli) + { + CAMLCodec *amlcodec; + if (!amli->IsRendered() && (amlcodec = amli->getAmlCodec())) + amlcodec->ReleaseFrame(amli->GetBufferIndex(), true); + SAFE_RELEASE(amli); + } buf.hwDec = NULL; } } -int CRendererAML::GetImageHook(YV12Image *image, int source, bool readonly) +void CRendererAML::FlipPage(int source) { - return source; + if( source >= 0 && source < m_numRenderBuffers ) + m_iRenderBuffer = source; + else + m_iRenderBuffer = (m_iRenderBuffer + 1) % m_numRenderBuffers; + + return; } bool CRendererAML::IsGuiLayer() @@ -104,37 +159,30 @@ EINTERLACEMETHOD CRendererAML::AutoInterlaceMethod() return VS_INTERLACEMETHOD_NONE; } -bool CRendererAML::LoadShadersHook() +void CRendererAML::Reset() { - CLog::Log(LOGNOTICE, "GL: Using AML render method"); - m_textureTarget = GL_TEXTURE_2D; - m_renderMethod = RENDER_BYPASS; - return false; + m_prevVPts = -1; } -bool CRendererAML::RenderHook(int index) -{ - return true;// nothing to be done for aml -} - -bool CRendererAML::RenderUpdateVideoHook(bool clear, DWORD flags, DWORD alpha) +void CRendererAML::RenderUpdate(bool clear, DWORD flags, DWORD alpha) { ManageRenderArea(); - CDVDAmlogicInfo *amli = static_cast<CDVDAmlogicInfo *>(m_buffers[m_iYV12RenderBuffer].hwDec); - if (amli && amli->GetOmxPts() != m_prevPts) - { - m_prevPts = amli->GetOmxPts(); - SysfsUtils::SetInt("/sys/module/amvideo/parameters/omx_pts", amli->GetOmxPts()); + CDVDAmlogicInfo *amli = static_cast<CDVDAmlogicInfo *>(m_buffers[m_iRenderBuffer].hwDec); + CAMLCodec *amlcodec = amli ? amli->getAmlCodec() : 0; - CAMLCodec *amlcodec = amli->getAmlCodec(); - if (amlcodec) + if(amlcodec) + { + int pts = amli->GetOmxPts(); + if (pts != m_prevVPts) + { + amlcodec->ReleaseFrame(amli->GetBufferIndex()); amlcodec->SetVideoRect(m_sourceRect, m_destRect); + amli->SetRendered(); + m_prevVPts = pts; + } } - - usleep(10000); - - return true; + CAMLCodec::PollFrame(); } #endif diff --git a/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/RendererAML.h b/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/RendererAML.h index 828f584a94..cd68401953 100644 --- a/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/RendererAML.h +++ b/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/RendererAML.h @@ -24,17 +24,29 @@ #if defined(HAS_LIBAMCODEC) -#include "cores/VideoPlayer/VideoRenderers/LinuxRendererGLES.h" +#include "cores/VideoPlayer/VideoRenderers/BaseRenderer.h" -class CRendererAML : public CLinuxRendererGLES +class CRendererAML : public CBaseRenderer { public: CRendererAML(); virtual ~CRendererAML(); - + virtual bool RenderCapture(CRenderCapture* capture); virtual void AddVideoPictureHW(DVDVideoPicture &picture, int index); virtual void ReleaseBuffer(int idx); + virtual bool Configure(unsigned int width, unsigned int height, unsigned int d_width, unsigned int d_height, float fps, unsigned flags, ERenderFormat format, unsigned extended_formatl, unsigned int orientation); + virtual bool IsConfigured(){ return m_bConfigured; }; + virtual CRenderInfo GetRenderInfo(); + virtual int GetImage(YV12Image *image, int source = -1, bool readonly = false); + virtual void ReleaseImage(int source, bool preserve = false){}; + virtual void FlipPage(int source); + virtual void PreInit(){}; + virtual void UnInit(){}; + virtual void Reset(); + virtual void Update(){}; + virtual void RenderUpdate(bool clear, unsigned int flags = 0, unsigned int alpha = 255); + virtual bool SupportsMultiPassRendering(){ return false; }; // Player functions virtual bool IsGuiLayer(); @@ -47,16 +59,19 @@ public: virtual EINTERLACEMETHOD AutoInterlaceMethod(); -protected: +private: + + int m_iRenderBuffer; + static const int m_numRenderBuffers = 4; - // hooks for hw dec renderer - virtual bool LoadShadersHook(); - virtual bool RenderHook(int index); - virtual int GetImageHook(YV12Image *image, int source = AUTOSOURCE, bool readonly = false); - virtual bool RenderUpdateVideoHook(bool clear, DWORD flags = 0, DWORD alpha = 255); + struct BUFFER + { + void *hwDec; + int duration; + } m_buffers[m_numRenderBuffers]; -private: - int m_prevPts; + int m_prevVPts; + bool m_bConfigured; }; #endif diff --git a/xbmc/cores/omxplayer/OMXAudioCodecOMX.cpp b/xbmc/cores/omxplayer/OMXAudioCodecOMX.cpp index 920ac4ab75..e399556582 100644 --- a/xbmc/cores/omxplayer/OMXAudioCodecOMX.cpp +++ b/xbmc/cores/omxplayer/OMXAudioCodecOMX.cpp @@ -65,7 +65,7 @@ bool COMXAudioCodecOMX::Open(CDVDStreamInfo &hints) { AVCodec* pCodec = NULL; - if (hints.codec == AV_CODEC_ID_DTS && g_RBP.RasberryPiVersion() > 1) + if (hints.codec == AV_CODEC_ID_DTS && g_RBP.RaspberryPiVersion() > 1) pCodec = avcodec_find_decoder_by_name("dcadec"); if (!pCodec) diff --git a/xbmc/cores/omxplayer/OMXPlayerAudio.cpp b/xbmc/cores/omxplayer/OMXPlayerAudio.cpp index 968724e81d..890d91c5cf 100644 --- a/xbmc/cores/omxplayer/OMXPlayerAudio.cpp +++ b/xbmc/cores/omxplayer/OMXPlayerAudio.cpp @@ -85,7 +85,6 @@ OMXPlayerAudio::OMXPlayerAudio(OMXClock *av_clock, CDVDMessageQueue& parent, CPr m_messageQueue.SetMaxTimeSize(8.0); m_passthrough = false; - m_silence = false; m_flush = false; } @@ -134,7 +133,6 @@ void OMXPlayerAudio::OpenStream(CDVDStreamInfo &hints, COMXAudioCodecOMX *codec) m_speed = DVD_PLAYSPEED_NORMAL; m_audioClock = DVD_NOPTS_VALUE; - m_silence = false; m_syncState = IDVDStreamPlayer::SYNC_STARTING; m_flush = false; m_stalled = m_messageQueue.GetPacketCount(CDVDMsg::DEMUXER_PACKET) == 0; @@ -277,12 +275,7 @@ bool OMXPlayerAudio::Decode(DemuxPacket *pkt, bool bDropPacket, bool bTrickPlay) if(!bDropPacket) { - // Zero out the frame data if we are supposed to silence the audio - if(m_silence) - memset(decoded, 0x0, decoded_size); - ret = m_omxAudio.AddPackets(decoded, decoded_size, dts, pts, m_pAudioCodec->GetFrameSize(), settings_changed); - if(ret != decoded_size) { CLog::Log(LOGERROR, "error ret %d decoded_size %d\n", ret, decoded_size); @@ -316,9 +309,6 @@ bool OMXPlayerAudio::Decode(DemuxPacket *pkt, bool bDropPacket, bool bTrickPlay) if(!bDropPacket) { - if(m_silence) - memset(pkt->pData, 0x0, pkt->iSize); - m_omxAudio.AddPackets(pkt->pData, pkt->iSize, m_audioClock, m_audioClock, 0, settings_changed); } @@ -456,14 +446,6 @@ void OMXPlayerAudio::Process() CLog::Log(LOGDEBUG, "COMXPlayerAudio - CDVDMsg::PLAYER_SETSPEED %d", m_speed); } } - else if (pMsg->IsType(CDVDMsg::AUDIO_SILENCE)) - { - m_silence = static_cast<CDVDMsgBool*>(pMsg)->m_value; - if (m_silence) - CLog::Log(LOGDEBUG, "COMXPlayerAudio - CDVDMsg::AUDIO_SILENCE(%f, 1)", m_audioClock); - else - CLog::Log(LOGDEBUG, "COMXPlayerAudio - CDVDMsg::AUDIO_SILENCE(%f, 0)", m_audioClock); - } else if (pMsg->IsType(CDVDMsg::GENERAL_STREAMCHANGE)) { COMXMsgAudioCodecChange* msg(static_cast<COMXMsgAudioCodecChange*>(pMsg)); diff --git a/xbmc/dbwrappers/Database.cpp b/xbmc/dbwrappers/Database.cpp index bd7974aeba..383ddb1606 100644 --- a/xbmc/dbwrappers/Database.cpp +++ b/xbmc/dbwrappers/Database.cpp @@ -574,7 +574,7 @@ bool CDatabase::Compress(bool bForce /* =true */) return true; } -void CDatabase::Interupt() +void CDatabase::Interrupt() { m_pDS->interrupt(); } diff --git a/xbmc/dbwrappers/Database.h b/xbmc/dbwrappers/Database.h index 593a8eac47..cf4a795b31 100644 --- a/xbmc/dbwrappers/Database.h +++ b/xbmc/dbwrappers/Database.h @@ -78,7 +78,7 @@ public: bool IsOpen(); void Close(); bool Compress(bool bForce=true); - void Interupt(); + void Interrupt(); bool Open(const DatabaseSettings &db); diff --git a/xbmc/dbwrappers/DatabaseQuery.cpp b/xbmc/dbwrappers/DatabaseQuery.cpp index b6c96fee65..1f6c8ad8ef 100644 --- a/xbmc/dbwrappers/DatabaseQuery.cpp +++ b/xbmc/dbwrappers/DatabaseQuery.cpp @@ -128,8 +128,7 @@ bool CDatabaseQueryRule::Load(const TiXmlNode *node, const std::string &encoding bool CDatabaseQueryRule::Load(const CVariant &obj) { - if (!obj.isObject() || - !obj.isMember("field") || !obj["field"].isString() || + if (!obj.isMember("field") || !obj["field"].isString() || !obj.isMember("operator") || !obj["operator"].isString()) return false; diff --git a/xbmc/dialogs/GUIDialogFileBrowser.cpp b/xbmc/dialogs/GUIDialogFileBrowser.cpp index f6e002e016..f373d08ca1 100644 --- a/xbmc/dialogs/GUIDialogFileBrowser.cpp +++ b/xbmc/dialogs/GUIDialogFileBrowser.cpp @@ -653,12 +653,12 @@ bool CGUIDialogFileBrowser::ShowAndGetImage(const CFileItemList &items, const VE bool CGUIDialogFileBrowser::ShowAndGetImage(const VECSOURCES &shares, const std::string &heading, std::string &path) { - return ShowAndGetFile(shares, g_advancedSettings.m_pictureExtensions, heading, path, true); // true for use thumbs + return ShowAndGetFile(shares, g_advancedSettings.GetPictureExtensions(), heading, path, true); // true for use thumbs } bool CGUIDialogFileBrowser::ShowAndGetImageList(const VECSOURCES &shares, const std::string &heading, std::vector<std::string> &path) { - return ShowAndGetFileList(shares, g_advancedSettings.m_pictureExtensions, heading, path, true); // true for use thumbs + return ShowAndGetFileList(shares, g_advancedSettings.GetPictureExtensions(), heading, path, true); // true for use thumbs } bool CGUIDialogFileBrowser::ShowAndGetDirectory(const VECSOURCES &shares, const std::string &heading, std::string &path, bool bWriteOnly) diff --git a/xbmc/filesystem/AddonsDirectory.cpp b/xbmc/filesystem/AddonsDirectory.cpp index 94dfa65502..d7c9e5972a 100644 --- a/xbmc/filesystem/AddonsDirectory.cpp +++ b/xbmc/filesystem/AddonsDirectory.cpp @@ -153,7 +153,7 @@ static bool IsGameAddon(const AddonPtr& addon) IsGameSupportAddon(addon); } -static bool IsDependecyType(TYPE type) +static bool IsDependencyType(TYPE type) { return dependencyTypes.find(type) != dependencyTypes.end(); } @@ -351,7 +351,7 @@ static void GenerateMainCategoryListing(const CURL& path, const VECADDONS& addon for (unsigned int i = ADDON_UNKNOWN + 1; i < ADDON_MAX - 1; ++i) { const TYPE type = (TYPE)i; - if (!IsInfoProviderType(type) && !IsLookAndFeelType(type) && !IsDependecyType(type) && !IsGameType(type)) + if (!IsInfoProviderType(type) && !IsLookAndFeelType(type) && !IsDependencyType(type) && !IsGameType(type)) uncategorized.insert(static_cast<TYPE>(i)); } GenerateTypeListing(path, uncategorized, addons, items); diff --git a/xbmc/filesystem/File.h b/xbmc/filesystem/File.h index adcac32bd8..02649a5088 100644 --- a/xbmc/filesystem/File.h +++ b/xbmc/filesystem/File.h @@ -129,7 +129,7 @@ public: int IoControl(EIoControl request, void* param); - IFile *GetImplemenation() { return m_pFile; } + IFile *GetImplementation() { return m_pFile; } // CURL interface static bool Exists(const CURL& file, bool bUseCache = true); diff --git a/xbmc/filesystem/FileCache.cpp b/xbmc/filesystem/FileCache.cpp index afea2fe5d5..8e1c95c7e5 100644 --- a/xbmc/filesystem/FileCache.cpp +++ b/xbmc/filesystem/FileCache.cpp @@ -146,7 +146,7 @@ void CFileCache::SetCacheStrategy(CCacheStrategy *pCache, bool bDeleteCache /* = IFile *CFileCache::GetFileImp() { - return m_source.GetImplemenation(); + return m_source.GetImplementation(); } bool CFileCache::Open(const CURL& url) @@ -568,15 +568,15 @@ void CFileCache::StopThread(bool bWait /*= true*/) std::string CFileCache::GetContent() { - if (!m_source.GetImplemenation()) + if (!m_source.GetImplementation()) return IFile::GetContent(); - return m_source.GetImplemenation()->GetContent(); + return m_source.GetImplementation()->GetContent(); } std::string CFileCache::GetContentCharset(void) { - IFile* impl = m_source.GetImplemenation(); + IFile* impl = m_source.GetImplementation(); if (!impl) return IFile::GetContentCharset(); diff --git a/xbmc/filesystem/PipeFile.cpp b/xbmc/filesystem/PipeFile.cpp index 28230fb447..72250e6e7c 100644 --- a/xbmc/filesystem/PipeFile.cpp +++ b/xbmc/filesystem/PipeFile.cpp @@ -217,8 +217,8 @@ void CPipeFile::RemoveListener(IPipeListener *l) } } -void CPipeFile::SetOpenThreashold(int threashold) +void CPipeFile::SetOpenThreshold(int threshold) { - m_pipe->SetOpenThreashold(threashold); + m_pipe->SetOpenThreshold(threshold); } diff --git a/xbmc/filesystem/PipeFile.h b/xbmc/filesystem/PipeFile.h index 27204f10e5..2991d1a68e 100644 --- a/xbmc/filesystem/PipeFile.h +++ b/xbmc/filesystem/PipeFile.h @@ -76,7 +76,7 @@ public: bool IsEmpty(); bool IsClosed(); - void SetOpenThreashold(int threashold); + void SetOpenThreshold(int threshold); protected: int64_t m_pos; diff --git a/xbmc/filesystem/PipesManager.cpp b/xbmc/filesystem/PipesManager.cpp index 63627964d9..5f91ba67f0 100644 --- a/xbmc/filesystem/PipesManager.cpp +++ b/xbmc/filesystem/PipesManager.cpp @@ -46,7 +46,7 @@ Pipe::~Pipe() { } -void Pipe::SetOpenThreashold(int threshold) +void Pipe::SetOpenThreshold(int threshold) { m_nOpenThreshold = threshold; } diff --git a/xbmc/filesystem/PipesManager.h b/xbmc/filesystem/PipesManager.h index 33294b1330..9e4b31aa0b 100644 --- a/xbmc/filesystem/PipesManager.h +++ b/xbmc/filesystem/PipesManager.h @@ -87,7 +87,7 @@ class Pipe bool IsEof(); int GetAvailableRead(); - void SetOpenThreashold(int threshold); + void SetOpenThreshold(int threshold); protected: diff --git a/xbmc/filesystem/RSSDirectory.cpp b/xbmc/filesystem/RSSDirectory.cpp index 36768e7774..12693d774e 100644 --- a/xbmc/filesystem/RSSDirectory.cpp +++ b/xbmc/filesystem/RSSDirectory.cpp @@ -93,7 +93,7 @@ static bool IsPathToMedia(const std::string& strPath ) return URIUtils::HasExtension(strPath, g_advancedSettings.m_videoExtensions + '|' + g_advancedSettings.GetMusicExtensions() + '|' + - g_advancedSettings.m_pictureExtensions); + g_advancedSettings.GetPictureExtensions()); } static bool IsPathToThumbnail(const std::string& strPath ) @@ -101,7 +101,7 @@ static bool IsPathToThumbnail(const std::string& strPath ) // Currently just check if this is an image, maybe we will add some // other checks later return URIUtils::HasExtension(strPath, - g_advancedSettings.m_pictureExtensions); + g_advancedSettings.GetPictureExtensions()); } static time_t ParseDate(const std::string & strDate) diff --git a/xbmc/filesystem/SFTPFile.cpp b/xbmc/filesystem/SFTPFile.cpp index 8fad5bd882..c97203b130 100644 --- a/xbmc/filesystem/SFTPFile.cpp +++ b/xbmc/filesystem/SFTPFile.cpp @@ -111,7 +111,7 @@ CSFTPSession::~CSFTPSession() Disconnect(); } -sftp_file CSFTPSession::CreateFileHande(const std::string &file) +sftp_file CSFTPSession::CreateFileHandle(const std::string &file) { if (m_connected) { @@ -603,7 +603,7 @@ bool CSFTPFile::Open(const CURL& url) if (m_session) { m_file = url.GetFileName().c_str(); - m_sftp_handle = m_session->CreateFileHande(m_file); + m_sftp_handle = m_session->CreateFileHandle(m_file); return (m_sftp_handle != NULL); } diff --git a/xbmc/filesystem/SFTPFile.h b/xbmc/filesystem/SFTPFile.h index 973b2df226..229ce4686b 100644 --- a/xbmc/filesystem/SFTPFile.h +++ b/xbmc/filesystem/SFTPFile.h @@ -60,7 +60,7 @@ public: CSFTPSession(const std::string &host, unsigned int port, const std::string &username, const std::string &password); virtual ~CSFTPSession(); - sftp_file CreateFileHande(const std::string &file); + sftp_file CreateFileHandle(const std::string &file); void CloseFileHandle(sftp_file handle); bool GetDirectory(const std::string &base, const std::string &folder, CFileItemList &items); bool DirectoryExists(const char *path); diff --git a/xbmc/games/addons/GameClient.cpp b/xbmc/games/addons/GameClient.cpp index 4c719e1eed..7530294e1a 100644 --- a/xbmc/games/addons/GameClient.cpp +++ b/xbmc/games/addons/GameClient.cpp @@ -56,6 +56,7 @@ #include <iterator> #include <utility> +using namespace KODI; using namespace GAME; #define EXTENSION_SEPARATOR "|" diff --git a/xbmc/games/addons/GameClientInput.cpp b/xbmc/games/addons/GameClientInput.cpp index 5cfb05132f..8e694d4bfb 100644 --- a/xbmc/games/addons/GameClientInput.cpp +++ b/xbmc/games/addons/GameClientInput.cpp @@ -27,6 +27,7 @@ #include <algorithm> #include <assert.h> +using namespace KODI; using namespace GAME; CGameClientInput::CGameClientInput(CGameClient* gameClient, int port, const ControllerPtr& controller, const KodiToAddonFuncTable_Game *dllStruct) : diff --git a/xbmc/games/addons/GameClientInput.h b/xbmc/games/addons/GameClientInput.h index e65fae8cdd..546ec775d1 100644 --- a/xbmc/games/addons/GameClientInput.h +++ b/xbmc/games/addons/GameClientInput.h @@ -34,7 +34,7 @@ namespace GAME * * Listens to game controller events and forwards them to the games (as game_input_event). */ - class CGameClientInput : public JOYSTICK::IInputHandler + class CGameClientInput : public KODI::JOYSTICK::IInputHandler { public: /*! @@ -50,7 +50,7 @@ namespace GAME virtual std::string ControllerID(void) const override; virtual bool HasFeature(const std::string& feature) const override; virtual bool AcceptsInput(void) override; - virtual JOYSTICK::INPUT_TYPE GetInputType(const std::string& feature) const override; + virtual KODI::JOYSTICK::INPUT_TYPE GetInputType(const std::string& feature) const override; virtual bool OnButtonPress(const std::string& feature, bool bPressed) override; virtual void OnButtonHold(const std::string& feature, unsigned int holdTimeMs) override { } virtual bool OnButtonMotion(const std::string& feature, float magnitude) override; diff --git a/xbmc/games/addons/GameClientKeyboard.cpp b/xbmc/games/addons/GameClientKeyboard.cpp index 0154e3406d..917da282ed 100644 --- a/xbmc/games/addons/GameClientKeyboard.cpp +++ b/xbmc/games/addons/GameClientKeyboard.cpp @@ -26,6 +26,7 @@ #include "input/Key.h" #include "utils/log.h" +using namespace KODI; using namespace GAME; #define BUTTON_INDEX_MASK 0x01ff diff --git a/xbmc/games/addons/GameClientKeyboard.h b/xbmc/games/addons/GameClientKeyboard.h index 0482ef641e..a82236863f 100644 --- a/xbmc/games/addons/GameClientKeyboard.h +++ b/xbmc/games/addons/GameClientKeyboard.h @@ -33,7 +33,7 @@ namespace GAME * * Listens to keyboard events and forwards them to the games (as game_input_event). */ - class CGameClientKeyboard : public KEYBOARD::IKeyboardHandler + class CGameClientKeyboard : public KODI::KEYBOARD::IKeyboardHandler { public: /*! diff --git a/xbmc/games/addons/GameClientMouse.cpp b/xbmc/games/addons/GameClientMouse.cpp index df1a0403f6..727b662bfa 100644 --- a/xbmc/games/addons/GameClientMouse.cpp +++ b/xbmc/games/addons/GameClientMouse.cpp @@ -26,6 +26,7 @@ #include "input/Key.h" #include "utils/log.h" +using namespace KODI; using namespace GAME; CGameClientMouse::CGameClientMouse(const CGameClient* gameClient, const KodiToAddonFuncTable_Game* dllStruct) : diff --git a/xbmc/games/addons/GameClientMouse.h b/xbmc/games/addons/GameClientMouse.h index e1b34ca1c8..4ab7a127a5 100644 --- a/xbmc/games/addons/GameClientMouse.h +++ b/xbmc/games/addons/GameClientMouse.h @@ -33,7 +33,7 @@ namespace GAME * * Listens to mouse events and forwards them to the games (as game_input_event). */ - class CGameClientMouse : public MOUSE::IMouseInputHandler + class CGameClientMouse : public KODI::MOUSE::IMouseInputHandler { public: /*! diff --git a/xbmc/games/controllers/ControllerFeature.cpp b/xbmc/games/controllers/ControllerFeature.cpp index 2801bd2790..4b15c39492 100644 --- a/xbmc/games/controllers/ControllerFeature.cpp +++ b/xbmc/games/controllers/ControllerFeature.cpp @@ -28,6 +28,7 @@ #include <sstream> +using namespace KODI; using namespace GAME; using namespace JOYSTICK; diff --git a/xbmc/games/controllers/ControllerFeature.h b/xbmc/games/controllers/ControllerFeature.h index 753c9837ac..9b90f68653 100644 --- a/xbmc/games/controllers/ControllerFeature.h +++ b/xbmc/games/controllers/ControllerFeature.h @@ -39,27 +39,27 @@ public: CControllerFeature& operator=(const CControllerFeature& rhs); - JOYSTICK::FEATURE_TYPE Type(void) const { return m_type; } - JOYSTICK::FEATURE_CATEGORY Category(void) const { return m_category; } + KODI::JOYSTICK::FEATURE_TYPE Type(void) const { return m_type; } + KODI::JOYSTICK::FEATURE_CATEGORY Category(void) const { return m_category; } const std::string& CategoryLabel(void) const { return m_strCategory; } const std::string& Name(void) const { return m_strName; } const std::string& Label(void) const { return m_strLabel; } unsigned int LabelID(void) const { return m_labelId; } - JOYSTICK::INPUT_TYPE InputType(void) const { return m_inputType; } + KODI::JOYSTICK::INPUT_TYPE InputType(void) const { return m_inputType; } bool Deserialize(const TiXmlElement* pElement, const CController* controller, - JOYSTICK::FEATURE_CATEGORY category, + KODI::JOYSTICK::FEATURE_CATEGORY category, const std::string& strCategory); private: - JOYSTICK::FEATURE_TYPE m_type; - JOYSTICK::FEATURE_CATEGORY m_category; + KODI::JOYSTICK::FEATURE_TYPE m_type; + KODI::JOYSTICK::FEATURE_CATEGORY m_category; std::string m_strCategory; std::string m_strName; std::string m_strLabel; unsigned int m_labelId; - JOYSTICK::INPUT_TYPE m_inputType; + KODI::JOYSTICK::INPUT_TYPE m_inputType; }; } diff --git a/xbmc/games/controllers/ControllerLayout.cpp b/xbmc/games/controllers/ControllerLayout.cpp index 48ae67ef99..dc7f8d5ddb 100644 --- a/xbmc/games/controllers/ControllerLayout.cpp +++ b/xbmc/games/controllers/ControllerLayout.cpp @@ -29,6 +29,7 @@ #include <algorithm> #include <sstream> +using namespace KODI; using namespace GAME; using namespace JOYSTICK; diff --git a/xbmc/games/controllers/ControllerLayout.h b/xbmc/games/controllers/ControllerLayout.h index 559fe27b43..db5dac2d7b 100644 --- a/xbmc/games/controllers/ControllerLayout.h +++ b/xbmc/games/controllers/ControllerLayout.h @@ -43,8 +43,8 @@ public: const std::vector<CControllerFeature>& Features(void) const { return m_features; } - unsigned int FeatureCount(JOYSTICK::FEATURE_TYPE type = JOYSTICK::FEATURE_TYPE::UNKNOWN, - JOYSTICK::INPUT_TYPE buttonType = JOYSTICK::INPUT_TYPE::UNKNOWN) const; + unsigned int FeatureCount(KODI::JOYSTICK::FEATURE_TYPE type = KODI::JOYSTICK::FEATURE_TYPE::UNKNOWN, + KODI::JOYSTICK::INPUT_TYPE buttonType = KODI::JOYSTICK::INPUT_TYPE::UNKNOWN) const; bool Deserialize(const TiXmlElement* pLayoutElement, const CController* controller); diff --git a/xbmc/games/controllers/ControllerTranslator.cpp b/xbmc/games/controllers/ControllerTranslator.cpp index e76226987c..72af8ed4e5 100644 --- a/xbmc/games/controllers/ControllerTranslator.cpp +++ b/xbmc/games/controllers/ControllerTranslator.cpp @@ -21,6 +21,7 @@ #include "ControllerTranslator.h" #include "ControllerDefinitions.h" +using namespace KODI; using namespace GAME; using namespace JOYSTICK; diff --git a/xbmc/games/controllers/ControllerTranslator.h b/xbmc/games/controllers/ControllerTranslator.h index df82aad557..ea8b06d3c4 100644 --- a/xbmc/games/controllers/ControllerTranslator.h +++ b/xbmc/games/controllers/ControllerTranslator.h @@ -30,14 +30,14 @@ namespace GAME class CControllerTranslator { public: - static const char* TranslateFeatureType(JOYSTICK::FEATURE_TYPE type); - static JOYSTICK::FEATURE_TYPE TranslateFeatureType(const std::string& strType); + static const char* TranslateFeatureType(KODI::JOYSTICK::FEATURE_TYPE type); + static KODI::JOYSTICK::FEATURE_TYPE TranslateFeatureType(const std::string& strType); - static const char* TranslateFeatureCategory(JOYSTICK::FEATURE_CATEGORY category); - static JOYSTICK::FEATURE_CATEGORY TranslateFeatureCategory(const std::string& strCategory); + static const char* TranslateFeatureCategory(KODI::JOYSTICK::FEATURE_CATEGORY category); + static KODI::JOYSTICK::FEATURE_CATEGORY TranslateFeatureCategory(const std::string& strCategory); - static const char* TranslateInputType(JOYSTICK::INPUT_TYPE type); - static JOYSTICK::INPUT_TYPE TranslateInputType(const std::string& strType); + static const char* TranslateInputType(KODI::JOYSTICK::INPUT_TYPE type); + static KODI::JOYSTICK::INPUT_TYPE TranslateInputType(const std::string& strType); }; } diff --git a/xbmc/games/controllers/dialogs/CMakeLists.txt b/xbmc/games/controllers/dialogs/CMakeLists.txt index 436712ca8c..2b398e98ed 100644 --- a/xbmc/games/controllers/dialogs/CMakeLists.txt +++ b/xbmc/games/controllers/dialogs/CMakeLists.txt @@ -1,5 +1,11 @@ -set(SOURCES GUIDialogButtonCapture.cpp) +set(SOURCES GUIDialogAxisDetection.cpp + GUIDialogButtonCapture.cpp + GUIDialogIgnoreInput.cpp +) -set(HEADERS GUIDialogButtonCapture.h) +set(HEADERS GUIDialogAxisDetection.h + GUIDialogButtonCapture.h + GUIDialogIgnoreInput.h +) core_add_library(games_controller_dialogs) diff --git a/xbmc/games/controllers/dialogs/GUIDialogAxisDetection.cpp b/xbmc/games/controllers/dialogs/GUIDialogAxisDetection.cpp new file mode 100644 index 0000000000..fb74519fa1 --- /dev/null +++ b/xbmc/games/controllers/dialogs/GUIDialogAxisDetection.cpp @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2017 Team Kodi + * http://kodi.tv + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this Program; see the file COPYING. If not, see + * <http://www.gnu.org/licenses/>. + * + */ + +#include "GUIDialogAxisDetection.h" +#include "guilib/LocalizeStrings.h" +#include "input/joysticks/DriverPrimitive.h" +#include "input/joysticks/IButtonMap.h" +#include "input/joysticks/JoystickTranslator.h" +#include "utils/StringUtils.h" + +#include <algorithm> + +using namespace KODI; +using namespace GAME; + +std::string CGUIDialogAxisDetection::GetDialogText() +{ + // "Press all analog buttons now to detect them:[CR][CR]%s" + std::string dialogText = g_localizeStrings.Get(35020); + + std::vector<std::string> primitives; + + for (const auto& axisEntry : m_detectedAxes) + { + JOYSTICK::CDriverPrimitive axis(axisEntry.second, 0, JOYSTICK::SEMIAXIS_DIRECTION::POSITIVE, 1); + primitives.emplace_back(JOYSTICK::CJoystickTranslator::GetPrimitiveName(axis)); + } + + return StringUtils::Format(dialogText.c_str(), StringUtils::Join(primitives, " | ").c_str()); +} + +std::string CGUIDialogAxisDetection::GetDialogHeader() +{ + return g_localizeStrings.Get(35058); // "Controller Configuration" +} + +bool CGUIDialogAxisDetection::MapPrimitiveInternal(JOYSTICK::IButtonMap* buttonMap, + JOYSTICK::IActionMap* actionMap, + const JOYSTICK::CDriverPrimitive& primitive) +{ + if (primitive.Type() == JOYSTICK::PRIMITIVE_TYPE::SEMIAXIS) + AddAxis(buttonMap->DeviceName(), primitive.Index()); + + return true; +} + +void CGUIDialogAxisDetection::OnLateAxis(const JOYSTICK::IButtonMap* buttonMap, unsigned int axisIndex) +{ + AddAxis(buttonMap->DeviceName(), axisIndex); +} + +void CGUIDialogAxisDetection::AddAxis(const std::string& deviceName, unsigned int axisIndex) +{ + auto it = std::find_if(m_detectedAxes.begin(), m_detectedAxes.end(), + [&deviceName, axisIndex](const AxisEntry& axis) + { + return axis.first == deviceName && + axis.second == axisIndex; + }); + + if (it == m_detectedAxes.end()) + { + m_detectedAxes.emplace_back(std::make_pair(deviceName, axisIndex)); + m_captureEvent.Set(); + } +} diff --git a/xbmc/games/controllers/dialogs/GUIDialogAxisDetection.h b/xbmc/games/controllers/dialogs/GUIDialogAxisDetection.h new file mode 100644 index 0000000000..2ad7c9b568 --- /dev/null +++ b/xbmc/games/controllers/dialogs/GUIDialogAxisDetection.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2017 Team Kodi + * http://kodi.tv + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this Program; see the file COPYING. If not, see + * <http://www.gnu.org/licenses/>. + * + */ +#pragma once + +#include "GUIDialogButtonCapture.h" + +#include <string> +#include <vector> +#include <utility> + +namespace GAME +{ + class CGUIDialogAxisDetection : public CGUIDialogButtonCapture + { + public: + CGUIDialogAxisDetection() = default; + + virtual ~CGUIDialogAxisDetection() = default; + + // specialization of IButtonMapper via CGUIDialogButtonCapture + void OnLateAxis(const KODI::JOYSTICK::IButtonMap* buttonMap, unsigned int axisIndex) override; + + protected: + // implementation of CGUIDialogButtonCapture + virtual std::string GetDialogText() override; + virtual std::string GetDialogHeader() override; + virtual bool MapPrimitiveInternal(KODI::JOYSTICK::IButtonMap* buttonMap, + KODI::JOYSTICK::IActionMap* actionMap, + const KODI::JOYSTICK::CDriverPrimitive& primitive) override; + virtual void OnClose(bool bAccepted) override { } + + private: + void AddAxis(const std::string& deviceName, unsigned int axisIndex); + + // Axis types + using DeviceName = std::string; + using AxisIndex = unsigned int; + using AxisEntry = std::pair<DeviceName, AxisIndex>; + using AxisVector = std::vector<AxisEntry>; + + // Axis detection + AxisVector m_detectedAxes; + }; +} diff --git a/xbmc/games/controllers/dialogs/GUIDialogButtonCapture.cpp b/xbmc/games/controllers/dialogs/GUIDialogButtonCapture.cpp index b65b544480..490f97a2b4 100644 --- a/xbmc/games/controllers/dialogs/GUIDialogButtonCapture.cpp +++ b/xbmc/games/controllers/dialogs/GUIDialogButtonCapture.cpp @@ -21,22 +21,20 @@ #include "GUIDialogButtonCapture.h" #include "dialogs/GUIDialogOK.h" #include "guilib/GUIWindowManager.h" -#include "guilib/LocalizeStrings.h" #include "guilib/WindowIDs.h" #include "input/joysticks/DefaultJoystick.h" #include "input/joysticks/IActionMap.h" #include "input/joysticks/IButtonMap.h" #include "input/joysticks/IButtonMapCallback.h" #include "input/joysticks/JoystickUtils.h" -#include "input/Key.h" -#include "utils/log.h" +#include "input/ActionIDs.h" #include "peripherals/Peripherals.h" -#include "utils/StringUtils.h" #include "utils/Variant.h" #include <algorithm> #include <iterator> +using namespace KODI; using namespace GAME; CGUIDialogButtonCapture::CGUIDialogButtonCapture() : @@ -59,27 +57,13 @@ void CGUIDialogButtonCapture::Show() Create(); - bool bAccepted = CGUIDialogOK::ShowAndGetInput(CVariant{ 35019 }, CVariant{ GetDialogText() }); // "Ignore input" + bool bAccepted = CGUIDialogOK::ShowAndGetInput(CVariant{ GetDialogHeader() }, CVariant{ GetDialogText() }); StopThread(false); m_captureEvent.Set(); - for (auto& callback : ButtonMapCallbacks()) - { - if (bAccepted) - { - // See documentation of IButtonMapCallback::ResetIgnoredPrimitives() - // for why this call is needed - if (m_deviceName.empty()) - callback.second->ResetIgnoredPrimitives(); - - if (m_deviceName.empty() || m_deviceName == callback.first) - callback.second->SaveButtonMap(); - } - else - callback.second->RevertButtonMap(); - } + OnClose(bAccepted); RemoveHooks(); } @@ -126,71 +110,7 @@ bool CGUIDialogButtonCapture::MapPrimitive(JOYSTICK::IButtonMap* buttonMap, } } - // Check if we have already started capturing primitives for a device - const bool bHasDevice = !m_deviceName.empty(); - - // If a primitive comes from a different device, ignore it - if (bHasDevice && m_deviceName != buttonMap->DeviceName()) - { - CLog::Log(LOGDEBUG, "%s: ignoring input from device %s", buttonMap->ControllerID().c_str(), buttonMap->DeviceName().c_str()); - return false; - } - - if (!bHasDevice) - { - CLog::Log(LOGDEBUG, "%s: capturing input for device %s", buttonMap->ControllerID().c_str(), buttonMap->DeviceName().c_str()); - m_deviceName = buttonMap->DeviceName(); - } - - if (AddPrimitive(primitive)) - { - buttonMap->SetIgnoredPrimitives(m_capturedPrimitives); - m_captureEvent.Set(); - } - - return true; -} - -bool CGUIDialogButtonCapture::AddPrimitive(const JOYSTICK::CDriverPrimitive& primitive) -{ - bool bValid = false; - - if (primitive.Type() == JOYSTICK::PRIMITIVE_TYPE::BUTTON || - primitive.Type() == JOYSTICK::PRIMITIVE_TYPE::SEMIAXIS) - { - auto PrimitiveMatch = [&primitive](const JOYSTICK::CDriverPrimitive& other) - { - return primitive.Type() == other.Type() && - primitive.Index() == other.Index(); - }; - - bValid = std::find_if(m_capturedPrimitives.begin(), m_capturedPrimitives.end(), PrimitiveMatch) == m_capturedPrimitives.end(); - } - - if (bValid) - { - m_capturedPrimitives.emplace_back(primitive); - return true; - } - - return false; -} - -std::string CGUIDialogButtonCapture::GetDialogText() -{ - // "Some controllers have buttons and axes that interfere with mapping. Press - // these now to disable them:[CR][CR]%s" - std::string dialogText = g_localizeStrings.Get(35014); - - std::vector<std::string> primitives; - - std::transform(m_capturedPrimitives.begin(), m_capturedPrimitives.end(), std::back_inserter(primitives), - [](const JOYSTICK::CDriverPrimitive& primitive) - { - return GetPrimitiveName(primitive); - }); - - return StringUtils::Format(dialogText.c_str(), StringUtils::Join(primitives, " | ").c_str()); + return MapPrimitiveInternal(buttonMap, actionMap, primitive); } void CGUIDialogButtonCapture::InstallHooks(void) @@ -225,21 +145,3 @@ void CGUIDialogButtonCapture::Notify(const Observable& obs, const ObservableMess break; } } - -std::string CGUIDialogButtonCapture::GetPrimitiveName(const JOYSTICK::CDriverPrimitive& primitive) -{ - std::string primitiveTemplate; - - switch (primitive.Type()) - { - case JOYSTICK::PRIMITIVE_TYPE::BUTTON: - primitiveTemplate = g_localizeStrings.Get(35015); // "Button %d" - break; - case JOYSTICK::PRIMITIVE_TYPE::SEMIAXIS: - primitiveTemplate = g_localizeStrings.Get(35016); // "Axis %d" - break; - default: break; - } - - return StringUtils::Format(primitiveTemplate.c_str(), primitive.Index()); -} diff --git a/xbmc/games/controllers/dialogs/GUIDialogButtonCapture.h b/xbmc/games/controllers/dialogs/GUIDialogButtonCapture.h index fe242c3e44..00cda4046a 100644 --- a/xbmc/games/controllers/dialogs/GUIDialogButtonCapture.h +++ b/xbmc/games/controllers/dialogs/GUIDialogButtonCapture.h @@ -19,55 +19,59 @@ */ #pragma once -#include "input/joysticks/DriverPrimitive.h" #include "input/joysticks/IButtonMapper.h" #include "threads/Event.h" #include "threads/Thread.h" #include "utils/Observer.h" +#include <string> #include <vector> namespace GAME { - class CGUIDialogButtonCapture : public JOYSTICK::IButtonMapper, + class CGUIDialogButtonCapture : public KODI::JOYSTICK::IButtonMapper, public Observer, protected CThread { public: CGUIDialogButtonCapture(); + virtual ~CGUIDialogButtonCapture() = default; + // implementation of IButtonMapper virtual std::string ControllerID(void) const override; virtual bool NeedsCooldown(void) const override { return false; } virtual bool Emulation(void) const override { return false; } virtual unsigned int ControllerNumber(void) const override { return 0; } - virtual bool MapPrimitive(JOYSTICK::IButtonMap* buttonMap, - JOYSTICK::IActionMap* actionMap, - const JOYSTICK::CDriverPrimitive& primitive) override; - virtual void OnEventFrame(const JOYSTICK::IButtonMap* buttonMap, bool bMotion) override { } + virtual bool MapPrimitive(KODI::JOYSTICK::IButtonMap* buttonMap, + KODI::JOYSTICK::IActionMap* actionMap, + const KODI::JOYSTICK::CDriverPrimitive& primitive) override; + virtual void OnEventFrame(const KODI::JOYSTICK::IButtonMap* buttonMap, bool bMotion) override { } + virtual void OnLateAxis(const KODI::JOYSTICK::IButtonMap* buttonMap, unsigned int axisIndex) override { } // implementation of Observer virtual void Notify(const Observable &obs, const ObservableMessage msg) override; + /*! + * \brief Show the dialog + */ void Show(); protected: // implementation of CThread virtual void Process() override; - private: - bool AddPrimitive(const JOYSTICK::CDriverPrimitive& primitive); + virtual std::string GetDialogText() = 0; + virtual std::string GetDialogHeader() = 0; + virtual bool MapPrimitiveInternal(KODI::JOYSTICK::IButtonMap* buttonMap, + KODI::JOYSTICK::IActionMap* actionMap, + const KODI::JOYSTICK::CDriverPrimitive& primitive) = 0; + virtual void OnClose(bool bAccepted) = 0; - std::string GetDialogText(); + CEvent m_captureEvent; + private: void InstallHooks(); void RemoveHooks(); - - static std::string GetPrimitiveName(const JOYSTICK::CDriverPrimitive& primitive); - - // Button capture parameters - std::string m_deviceName; - std::vector<JOYSTICK::CDriverPrimitive> m_capturedPrimitives; - CEvent m_captureEvent; }; } diff --git a/xbmc/games/controllers/dialogs/GUIDialogIgnoreInput.cpp b/xbmc/games/controllers/dialogs/GUIDialogIgnoreInput.cpp new file mode 100644 index 0000000000..a767340438 --- /dev/null +++ b/xbmc/games/controllers/dialogs/GUIDialogIgnoreInput.cpp @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2017 Team Kodi + * http://kodi.tv + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this Program; see the file COPYING. If not, see + * <http://www.gnu.org/licenses/>. + * + */ + +#include "GUIDialogIgnoreInput.h" +#include "guilib/LocalizeStrings.h" +#include "input/joysticks/IButtonMap.h" +#include "input/joysticks/IButtonMapCallback.h" +#include "input/joysticks/JoystickTranslator.h" +#include "utils/log.h" +#include "utils/StringUtils.h" + +#include <algorithm> +#include <iterator> + +using namespace KODI; +using namespace GAME; + +std::string CGUIDialogIgnoreInput::GetDialogText() +{ + // "Some controllers have buttons and axes that interfere with mapping. Press + // these now to disable them:[CR]%s" + std::string dialogText = g_localizeStrings.Get(35014); + + std::vector<std::string> primitives; + + std::transform(m_capturedPrimitives.begin(), m_capturedPrimitives.end(), std::back_inserter(primitives), + [](const JOYSTICK::CDriverPrimitive& primitive) + { + return JOYSTICK::CJoystickTranslator::GetPrimitiveName(primitive); + }); + + return StringUtils::Format(dialogText.c_str(), StringUtils::Join(primitives, " | ").c_str()); +} + +std::string CGUIDialogIgnoreInput::GetDialogHeader() +{ + + return g_localizeStrings.Get(35019); // "Ignore input" +} + +bool CGUIDialogIgnoreInput::MapPrimitiveInternal(JOYSTICK::IButtonMap* buttonMap, + JOYSTICK::IActionMap* actionMap, + const JOYSTICK::CDriverPrimitive& primitive) +{ + // Check if we have already started capturing primitives for a device + const bool bHasDevice = !m_deviceName.empty(); + + // If a primitive comes from a different device, ignore it + if (bHasDevice && m_deviceName != buttonMap->DeviceName()) + { + CLog::Log(LOGDEBUG, "%s: ignoring input from device %s", buttonMap->ControllerID().c_str(), buttonMap->DeviceName().c_str()); + return false; + } + + if (!bHasDevice) + { + CLog::Log(LOGDEBUG, "%s: capturing input for device %s", buttonMap->ControllerID().c_str(), buttonMap->DeviceName().c_str()); + m_deviceName = buttonMap->DeviceName(); + } + + if (AddPrimitive(primitive)) + { + buttonMap->SetIgnoredPrimitives(m_capturedPrimitives); + m_captureEvent.Set(); + } + + return true; +} + +void CGUIDialogIgnoreInput::OnClose(bool bAccepted) +{ + for (auto& callback : ButtonMapCallbacks()) + { + if (bAccepted) + { + // See documentation of IButtonMapCallback::ResetIgnoredPrimitives() + // for why this call is needed + if (m_deviceName.empty()) + callback.second->ResetIgnoredPrimitives(); + + if (m_deviceName.empty() || m_deviceName == callback.first) + callback.second->SaveButtonMap(); + } + else + callback.second->RevertButtonMap(); + } +} + +bool CGUIDialogIgnoreInput::AddPrimitive(const JOYSTICK::CDriverPrimitive& primitive) +{ + bool bValid = false; + + if (primitive.Type() == JOYSTICK::PRIMITIVE_TYPE::BUTTON || + primitive.Type() == JOYSTICK::PRIMITIVE_TYPE::SEMIAXIS) + { + auto PrimitiveMatch = [&primitive](const JOYSTICK::CDriverPrimitive& other) + { + return primitive.Type() == other.Type() && + primitive.Index() == other.Index(); + }; + + bValid = std::find_if(m_capturedPrimitives.begin(), m_capturedPrimitives.end(), PrimitiveMatch) == m_capturedPrimitives.end(); + } + + if (bValid) + { + m_capturedPrimitives.emplace_back(primitive); + return true; + } + + return false; +} diff --git a/xbmc/games/controllers/dialogs/GUIDialogIgnoreInput.h b/xbmc/games/controllers/dialogs/GUIDialogIgnoreInput.h new file mode 100644 index 0000000000..a4b358412a --- /dev/null +++ b/xbmc/games/controllers/dialogs/GUIDialogIgnoreInput.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2017 Team Kodi + * http://kodi.tv + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this Program; see the file COPYING. If not, see + * <http://www.gnu.org/licenses/>. + * + */ +#pragma once + +#include "GUIDialogButtonCapture.h" +#include "input/joysticks/DriverPrimitive.h" + +#include <string> +#include <vector> + +namespace GAME +{ + class CGUIDialogIgnoreInput : public CGUIDialogButtonCapture + { + public: + CGUIDialogIgnoreInput() = default; + + virtual ~CGUIDialogIgnoreInput() = default; + + protected: + // implementation of CGUIDialogButtonCapture + virtual std::string GetDialogText() override; + virtual std::string GetDialogHeader() override; + virtual bool MapPrimitiveInternal(KODI::JOYSTICK::IButtonMap* buttonMap, + KODI::JOYSTICK::IActionMap* actionMap, + const KODI::JOYSTICK::CDriverPrimitive& primitive) override; + void OnClose(bool bAccepted) override; + + private: + bool AddPrimitive(const KODI::JOYSTICK::CDriverPrimitive& primitive); + + std::string m_deviceName; + std::vector<KODI::JOYSTICK::CDriverPrimitive> m_capturedPrimitives; + }; +} diff --git a/xbmc/games/controllers/guicontrols/GUIAnalogStickButton.cpp b/xbmc/games/controllers/guicontrols/GUIAnalogStickButton.cpp index 8e1fb3971e..1ba9b81cba 100644 --- a/xbmc/games/controllers/guicontrols/GUIAnalogStickButton.cpp +++ b/xbmc/games/controllers/guicontrols/GUIAnalogStickButton.cpp @@ -24,6 +24,7 @@ #include <string> +using namespace KODI; using namespace GAME; CGUIAnalogStickButton::CGUIAnalogStickButton(const CGUIButtonControl& buttonTemplate, diff --git a/xbmc/games/controllers/guicontrols/GUIAnalogStickButton.h b/xbmc/games/controllers/guicontrols/GUIAnalogStickButton.h index 19990f36bf..c5d632b831 100644 --- a/xbmc/games/controllers/guicontrols/GUIAnalogStickButton.h +++ b/xbmc/games/controllers/guicontrols/GUIAnalogStickButton.h @@ -36,7 +36,7 @@ namespace GAME // implementation of IFeatureButton virtual bool PromptForInput(CEvent& waitEvent) override; virtual bool IsFinished(void) const override; - virtual JOYSTICK::ANALOG_STICK_DIRECTION GetDirection(void) const override; + virtual KODI::JOYSTICK::ANALOG_STICK_DIRECTION GetDirection(void) const override; virtual void Reset(void) override; private: diff --git a/xbmc/games/controllers/guicontrols/GUIFeatureButton.h b/xbmc/games/controllers/guicontrols/GUIFeatureButton.h index 354f314111..cd6583aaab 100644 --- a/xbmc/games/controllers/guicontrols/GUIFeatureButton.h +++ b/xbmc/games/controllers/guicontrols/GUIFeatureButton.h @@ -44,7 +44,7 @@ namespace GAME // partial implementation of IFeatureButton virtual const CControllerFeature& Feature(void) const override { return m_feature; } - virtual JOYSTICK::ANALOG_STICK_DIRECTION GetDirection(void) const override { return JOYSTICK::ANALOG_STICK_DIRECTION::UNKNOWN; } + virtual KODI::JOYSTICK::ANALOG_STICK_DIRECTION GetDirection(void) const override { return KODI::JOYSTICK::ANALOG_STICK_DIRECTION::UNKNOWN; } protected: bool DoPrompt(const std::string& strPrompt, const std::string& strWarn, const std::string& strFeature, CEvent& waitEvent); diff --git a/xbmc/games/controllers/windows/GUIConfigurationWizard.cpp b/xbmc/games/controllers/windows/GUIConfigurationWizard.cpp index 2e50db1b58..9071db44f8 100644 --- a/xbmc/games/controllers/windows/GUIConfigurationWizard.cpp +++ b/xbmc/games/controllers/windows/GUIConfigurationWizard.cpp @@ -19,16 +19,19 @@ */ #include "GUIConfigurationWizard.h" +#include "games/controllers/dialogs/GUIDialogAxisDetection.h" #include "games/controllers/guicontrols/GUIFeatureButton.h" #include "games/controllers/Controller.h" #include "games/controllers/ControllerFeature.h" #include "input/joysticks/IButtonMap.h" #include "input/joysticks/IButtonMapCallback.h" +#include "input/keyboard/KeymapActionMap.h" #include "input/InputManager.h" #include "peripherals/Peripherals.h" #include "threads/SingleLock.h" #include "utils/log.h" +using namespace KODI; using namespace GAME; #define ESC_KEY_CODE 27 @@ -40,16 +43,22 @@ using namespace GAME; CGUIConfigurationWizard::CGUIConfigurationWizard(bool bEmulation, unsigned int controllerNumber /* = 0 */) : CThread("GUIConfigurationWizard"), m_bEmulation(bEmulation), - m_controllerNumber(controllerNumber) + m_controllerNumber(controllerNumber), + m_actionMap(new KEYBOARD::CKeymapActionMap) { InitializeState(); } +CGUIConfigurationWizard::~CGUIConfigurationWizard(void) +{ +} + void CGUIConfigurationWizard::InitializeState(void) { m_currentButton = nullptr; m_currentDirection = JOYSTICK::ANALOG_STICK_DIRECTION::UNKNOWN; m_history.clear(); + m_lateAxisDetected = false; } void CGUIConfigurationWizard::Run(const std::string& strControllerId, const std::vector<IFeatureButton*>& buttons) @@ -85,7 +94,7 @@ void CGUIConfigurationWizard::OnUnfocus(IFeatureButton* button) bool CGUIConfigurationWizard::Abort(bool bWait /* = true */) { - if (IsRunning()) + if (!m_bStop) { StopThread(false); @@ -106,6 +115,8 @@ void CGUIConfigurationWizard::Process(void) InstallHooks(); + bool bLateAxisDetected = false; + { CSingleLock lock(m_stateMutex); for (IFeatureButton* button : m_buttons) @@ -138,6 +149,8 @@ void CGUIConfigurationWizard::Process(void) break; } + bLateAxisDetected = m_lateAxisDetected; + // Finished mapping InitializeState(); } @@ -145,17 +158,27 @@ void CGUIConfigurationWizard::Process(void) for (auto callback : ButtonMapCallbacks()) callback.second->SaveButtonMap(); - bool bInMotion; - + if (bLateAxisDetected) { - CSingleLock lock(m_motionMutex); - bInMotion = !m_bInMotion.empty(); + CGUIDialogAxisDetection dialog; + dialog.Show(); } - - if (bInMotion) + else { - CLog::Log(LOGDEBUG, "Configuration wizard: waiting %ums for axes to neutralize", POST_MAPPING_WAIT_TIME_MS); - m_motionlessEvent.WaitMSec(POST_MAPPING_WAIT_TIME_MS); + // Wait for motion to stop to avoid sending analog actions for the button + // that is pressed immediately after button mapping finishes. + bool bInMotion; + + { + CSingleLock lock(m_motionMutex); + bInMotion = !m_bInMotion.empty(); + } + + if (bInMotion) + { + CLog::Log(LOGDEBUG, "Configuration wizard: waiting %ums for axes to neutralize", POST_MAPPING_WAIT_TIME_MS); + m_motionlessEvent.WaitMSec(POST_MAPPING_WAIT_TIME_MS); + } } RemoveHooks(); @@ -243,6 +266,14 @@ void CGUIConfigurationWizard::OnEventFrame(const JOYSTICK::IButtonMap* buttonMap OnMotionless(buttonMap); } +void CGUIConfigurationWizard::OnLateAxis(const JOYSTICK::IButtonMap* buttonMap, unsigned int axisIndex) +{ + CSingleLock lock(m_stateMutex); + + m_lateAxisDetected = true; + Abort(false); +} + void CGUIConfigurationWizard::OnMotion(const JOYSTICK::IButtonMap* buttonMap) { CSingleLock lock(m_motionMutex); @@ -260,7 +291,38 @@ void CGUIConfigurationWizard::OnMotionless(const JOYSTICK::IButtonMap* buttonMap bool CGUIConfigurationWizard::OnKeyPress(const CKey& key) { - return Abort(false); + using namespace KEYBOARD; + + bool bHandled = false; + + switch (m_actionMap->GetActionID(key)) + { + case ACTION_MOVE_LEFT: + case ACTION_MOVE_RIGHT: + case ACTION_MOVE_UP: + case ACTION_MOVE_DOWN: + case ACTION_PAGE_UP: + case ACTION_PAGE_DOWN: + // Abort and allow motion + Abort(false); + bHandled = false; + break; + + case ACTION_PARENT_DIR: + case ACTION_PREVIOUS_MENU: + case ACTION_STOP: + // Abort and prevent action + Abort(false); + bHandled = true; + break; + + default: + // Absorb keypress + bHandled = true; + break; + } + + return bHandled; } bool CGUIConfigurationWizard::OnButtonPress(const std::string& button) diff --git a/xbmc/games/controllers/windows/GUIConfigurationWizard.h b/xbmc/games/controllers/windows/GUIConfigurationWizard.h index 4076afd9fc..a006ae5f78 100644 --- a/xbmc/games/controllers/windows/GUIConfigurationWizard.h +++ b/xbmc/games/controllers/windows/GUIConfigurationWizard.h @@ -29,23 +29,32 @@ #include "threads/Thread.h" #include "utils/Observer.h" +#include <memory> #include <set> #include <string> #include <vector> +namespace KODI +{ +namespace KEYBOARD +{ + class IActionMap; +} +} + namespace GAME { class CGUIConfigurationWizard : public IConfigurationWizard, - public JOYSTICK::IButtonMapper, - public KEYBOARD::IKeyboardHandler, - public MOUSE::IMouseInputHandler, + public KODI::JOYSTICK::IButtonMapper, + public KODI::KEYBOARD::IKeyboardHandler, + public KODI::MOUSE::IMouseInputHandler, public Observer, protected CThread { public: CGUIConfigurationWizard(bool bEmulation, unsigned int controllerNumber = 0); - virtual ~CGUIConfigurationWizard(void) { } + virtual ~CGUIConfigurationWizard(void); // implementation of IConfigurationWizard virtual void Run(const std::string& strControllerId, const std::vector<IFeatureButton*>& buttons) override; @@ -57,10 +66,11 @@ namespace GAME virtual bool NeedsCooldown(void) const override { return true; } virtual bool Emulation(void) const override { return m_bEmulation; } virtual unsigned int ControllerNumber(void) const override { return m_controllerNumber; } - virtual bool MapPrimitive(JOYSTICK::IButtonMap* buttonMap, - JOYSTICK::IActionMap* actionMap, - const JOYSTICK::CDriverPrimitive& primitive) override; - virtual void OnEventFrame(const JOYSTICK::IButtonMap* buttonMap, bool bMotion) override; + virtual bool MapPrimitive(KODI::JOYSTICK::IButtonMap* buttonMap, + KODI::JOYSTICK::IActionMap* actionMap, + const KODI::JOYSTICK::CDriverPrimitive& primitive) override; + virtual void OnEventFrame(const KODI::JOYSTICK::IButtonMap* buttonMap, bool bMotion) override; + virtual void OnLateAxis(const KODI::JOYSTICK::IButtonMap* buttonMap, unsigned int axisIndex) override; // implementation of IKeyboardHandler virtual bool OnKeyPress(const CKey& key) override; @@ -84,8 +94,8 @@ namespace GAME void InstallHooks(void); void RemoveHooks(void); - void OnMotion(const JOYSTICK::IButtonMap* buttonMap); - void OnMotionless(const JOYSTICK::IButtonMap* buttonMap); + void OnMotion(const KODI::JOYSTICK::IButtonMap* buttonMap); + void OnMotionless(const KODI::JOYSTICK::IButtonMap* buttonMap); // Construction parameters const bool m_bEmulation; @@ -97,14 +107,18 @@ namespace GAME // State variables and mutex IFeatureButton* m_currentButton; - JOYSTICK::ANALOG_STICK_DIRECTION m_currentDirection; - std::set<JOYSTICK::CDriverPrimitive> m_history; // History to avoid repeated features + KODI::JOYSTICK::ANALOG_STICK_DIRECTION m_currentDirection; + std::set<KODI::JOYSTICK::CDriverPrimitive> m_history; // History to avoid repeated features + bool m_lateAxisDetected; // Set to true if an axis is detected during button mapping CCriticalSection m_stateMutex; // Synchronization events CEvent m_inputEvent; CEvent m_motionlessEvent; CCriticalSection m_motionMutex; - std::set<const JOYSTICK::IButtonMap*> m_bInMotion; + std::set<const KODI::JOYSTICK::IButtonMap*> m_bInMotion; + + // Keyboard handling + std::unique_ptr<KODI::KEYBOARD::IActionMap> m_actionMap; }; } diff --git a/xbmc/games/controllers/windows/GUIControllerWindow.cpp b/xbmc/games/controllers/windows/GUIControllerWindow.cpp index 6fb34a82f5..7316f8758d 100644 --- a/xbmc/games/controllers/windows/GUIControllerWindow.cpp +++ b/xbmc/games/controllers/windows/GUIControllerWindow.cpp @@ -26,7 +26,7 @@ #include "addons/GUIWindowAddonBrowser.h" #include "addons/IAddon.h" #include "addons/AddonManager.h" -#include "games/controllers/dialogs/GUIDialogButtonCapture.h" +#include "games/controllers/dialogs/GUIDialogIgnoreInput.h" #include "guilib/GUIButtonControl.h" #include "guilib/GUIControl.h" #include "guilib/GUIMessage.h" @@ -322,6 +322,6 @@ void CGUIControllerWindow::ShowHelp(void) void CGUIControllerWindow::ShowButtonCaptureDialog(void) { - CGUIDialogButtonCapture dialog; + CGUIDialogIgnoreInput dialog; dialog.Show(); } diff --git a/xbmc/games/controllers/windows/GUIFeatureList.cpp b/xbmc/games/controllers/windows/GUIFeatureList.cpp index 6518d1957c..9633495e91 100644 --- a/xbmc/games/controllers/windows/GUIFeatureList.cpp +++ b/xbmc/games/controllers/windows/GUIFeatureList.cpp @@ -34,6 +34,7 @@ #include "guilib/GUIWindow.h" #include "messaging/ApplicationMessenger.h" +using namespace KODI; using namespace GAME; CGUIFeatureList::CGUIFeatureList(CGUIWindow* window, const std::string& windowParam) : diff --git a/xbmc/games/controllers/windows/IConfigurationWindow.h b/xbmc/games/controllers/windows/IConfigurationWindow.h index 5f57a5bb8f..43f141640e 100644 --- a/xbmc/games/controllers/windows/IConfigurationWindow.h +++ b/xbmc/games/controllers/windows/IConfigurationWindow.h @@ -173,7 +173,7 @@ namespace GAME * \return The next direction to be prompted, or UNKNOWN if this isn't an * analog stick or the prompt is finished */ - virtual JOYSTICK::ANALOG_STICK_DIRECTION GetDirection(void) const = 0; + virtual KODI::JOYSTICK::ANALOG_STICK_DIRECTION GetDirection(void) const = 0; /*! * \brief Reset button after prompting for input has finished diff --git a/xbmc/games/ports/PortManager.cpp b/xbmc/games/ports/PortManager.cpp index 5eafc923f9..6809e00959 100644 --- a/xbmc/games/ports/PortManager.cpp +++ b/xbmc/games/ports/PortManager.cpp @@ -26,6 +26,7 @@ #include <algorithm> +using namespace KODI; using namespace GAME; using namespace JOYSTICK; using namespace PERIPHERALS; diff --git a/xbmc/games/ports/PortManager.h b/xbmc/games/ports/PortManager.h index 289c9ee935..b466ca8814 100644 --- a/xbmc/games/ports/PortManager.h +++ b/xbmc/games/ports/PortManager.h @@ -26,8 +26,18 @@ #include <map> #include <vector> -namespace JOYSTICK { class IInputHandler; } -namespace PERIPHERALS { class CPeripheral; } +namespace KODI +{ +namespace JOYSTICK +{ + class IInputHandler; +} +} + +namespace PERIPHERALS +{ + class CPeripheral; +} namespace GAME { @@ -50,7 +60,7 @@ namespace GAME * \param port The port number belonging to the game client * \param requiredType Used to restrict port to devices of only a certain type */ - void OpenPort(JOYSTICK::IInputHandler* handler, + void OpenPort(KODI::JOYSTICK::IInputHandler* handler, unsigned int port, PERIPHERALS::PeripheralType requiredType = PERIPHERALS::PERIPHERAL_UNKNOWN); @@ -59,7 +69,7 @@ namespace GAME * * \param handler The handler used to open the port */ - void ClosePort(JOYSTICK::IInputHandler* handler); + void ClosePort(KODI::JOYSTICK::IInputHandler* handler); /*! * \brief Map a list of devices to the available ports @@ -72,14 +82,14 @@ namespace GAME * attempt to honor that request. */ void MapDevices(const PERIPHERALS::PeripheralVector& devices, - std::map<PERIPHERALS::PeripheralPtr, JOYSTICK::IInputHandler*>& deviceToPortMap); + std::map<PERIPHERALS::PeripheralPtr, KODI::JOYSTICK::IInputHandler*>& deviceToPortMap); private: - JOYSTICK::IInputHandler* AssignToPort(const PERIPHERALS::PeripheralPtr& device, bool checkPortNumber = true); + KODI::JOYSTICK::IInputHandler* AssignToPort(const PERIPHERALS::PeripheralPtr& device, bool checkPortNumber = true); struct SPort { - JOYSTICK::IInputHandler* handler; // Input handler for this port + KODI::JOYSTICK::IInputHandler* handler; // Input handler for this port unsigned int port; // Port number belonging to the game client PERIPHERALS::PeripheralType requiredType; void* device; diff --git a/xbmc/games/ports/PortMapper.cpp b/xbmc/games/ports/PortMapper.cpp index 2471c39a2b..282eb513ef 100644 --- a/xbmc/games/ports/PortMapper.cpp +++ b/xbmc/games/ports/PortMapper.cpp @@ -23,6 +23,7 @@ #include "peripherals/devices/Peripheral.h" #include "peripherals/Peripherals.h" +using namespace KODI; using namespace GAME; using namespace JOYSTICK; using namespace PERIPHERALS; diff --git a/xbmc/games/ports/PortMapper.h b/xbmc/games/ports/PortMapper.h index 60330039a2..4d14445812 100644 --- a/xbmc/games/ports/PortMapper.h +++ b/xbmc/games/ports/PortMapper.h @@ -24,7 +24,14 @@ #include <map> -namespace JOYSTICK { class IInputHandler; } +namespace KODI +{ +namespace JOYSTICK +{ + class IInputHandler; +} +} + namespace GAME { class CPortMapper : public Observer @@ -39,6 +46,6 @@ namespace GAME private: void ProcessPeripherals(); - std::map<PERIPHERALS::PeripheralPtr, JOYSTICK::IInputHandler*> m_portMap; + std::map<PERIPHERALS::PeripheralPtr, KODI::JOYSTICK::IInputHandler*> m_portMap; }; } diff --git a/xbmc/guilib/GUIMultiImage.cpp b/xbmc/guilib/GUIMultiImage.cpp index 4d43531401..83b8839637 100644 --- a/xbmc/guilib/GUIMultiImage.cpp +++ b/xbmc/guilib/GUIMultiImage.cpp @@ -315,7 +315,7 @@ bool CGUIMultiImage::CMultiImageJob::DoWork() URIUtils::AddSlashAtEnd(realPath); CFileItemList items; - CDirectory::GetDirectory(realPath, items, g_advancedSettings.m_pictureExtensions + "|.tbn|.dds", DIR_FLAG_NO_FILE_DIRS | DIR_FLAG_NO_FILE_INFO); + CDirectory::GetDirectory(realPath, items, g_advancedSettings.GetPictureExtensions()+ "|.tbn|.dds", DIR_FLAG_NO_FILE_DIRS | DIR_FLAG_NO_FILE_INFO); for (int i=0; i < items.Size(); i++) { CFileItem* pItem = items[i].get(); diff --git a/xbmc/guilib/GUISliderControl.h b/xbmc/guilib/GUISliderControl.h index 717be42376..196ef2586a 100644 --- a/xbmc/guilib/GUISliderControl.h +++ b/xbmc/guilib/GUISliderControl.h @@ -86,6 +86,7 @@ public: void SetIntInterval(int iInterval); void SetFloatInterval(float fInterval); void SetType(int iType) { m_iType = iType; }; + int GetType() const { return m_iType; } virtual std::string GetDescription() const; void SetTextValue(const std::string &textValue) { m_textValue = textValue; }; void SetAction(const std::string &action); diff --git a/xbmc/guilib/GUIWindowManager.cpp b/xbmc/guilib/GUIWindowManager.cpp index 77ab06e490..9186b15893 100644 --- a/xbmc/guilib/GUIWindowManager.cpp +++ b/xbmc/guilib/GUIWindowManager.cpp @@ -995,6 +995,8 @@ bool CGUIWindowManager::OnAction(const CAction &action) const break; return false; } + CLog::Log(LOGWARNING, "CGUIWindowManager - %s - ignoring action %i, because topmost modal dialog closing animation is running", + __FUNCTION__, action.GetID()); return true; // do nothing with the action until the anim is finished } lock.Enter(); diff --git a/xbmc/guilib/TextureFormats.h b/xbmc/guilib/TextureFormats.h new file mode 100644 index 0000000000..ee8b68dc37 --- /dev/null +++ b/xbmc/guilib/TextureFormats.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2005-2013 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC; see the file COPYING. If not, see + * <http://www.gnu.org/licenses/>. + * + */ + +#pragma once + +#define XB_FMT_MASK 0xffff ///< mask for format info - other flags are outside this +#define XB_FMT_DXT_MASK 15 +#define XB_FMT_UNKNOWN 0 +#define XB_FMT_DXT1 1 +#define XB_FMT_DXT3 2 +#define XB_FMT_DXT5 4 +#define XB_FMT_DXT5_YCoCg 8 +#define XB_FMT_A8R8G8B8 16 // texture.xbt byte order (matches BGRA8) +#define XB_FMT_A8 32 +#define XB_FMT_RGBA8 64 +#define XB_FMT_RGB8 128 +#define XB_FMT_OPAQUE 65536 diff --git a/xbmc/guilib/XBTF.h b/xbmc/guilib/XBTF.h index 53dc6d997e..4e6499ad80 100644 --- a/xbmc/guilib/XBTF.h +++ b/xbmc/guilib/XBTF.h @@ -28,18 +28,7 @@ static const std::string XBTF_MAGIC = "XBTF"; static const std::string XBTF_VERSION = "2"; -#define XB_FMT_MASK 0xffff ///< mask for format info - other flags are outside this -#define XB_FMT_DXT_MASK 15 -#define XB_FMT_UNKNOWN 0 -#define XB_FMT_DXT1 1 -#define XB_FMT_DXT3 2 -#define XB_FMT_DXT5 4 -#define XB_FMT_DXT5_YCoCg 8 -#define XB_FMT_A8R8G8B8 16 // texture.xbt byte order (matches BGRA8) -#define XB_FMT_A8 32 -#define XB_FMT_RGBA8 64 -#define XB_FMT_RGB8 128 -#define XB_FMT_OPAQUE 65536 +#include "TextureFormats.h" class CXBTFFrame { diff --git a/xbmc/guilib/imagefactory.cpp b/xbmc/guilib/imagefactory.cpp index 1500dfdba0..beb9d79ccd 100644 --- a/xbmc/guilib/imagefactory.cpp +++ b/xbmc/guilib/imagefactory.cpp @@ -20,7 +20,15 @@ #include "imagefactory.h" #include "guilib/FFmpegImage.h" +#include "addons/BinaryAddonCache.h" +#include "addons/ImageDecoder.h" #include "utils/Mime.h" +#include "utils/StringUtils.h" +#include "ServiceBroker.h" + +#include <algorithm> + +using namespace ADDON; IImage* ImageFactory::CreateLoader(const std::string& strFileName) { @@ -38,5 +46,20 @@ IImage* ImageFactory::CreateLoader(const CURL& url) IImage* ImageFactory::CreateLoaderFromMimeType(const std::string& strMimeType) { + VECADDONS codecs; + ADDON::CBinaryAddonCache &addonCache = CServiceBroker::GetBinaryAddonCache(); + addonCache.GetAddons(codecs, ADDON::ADDON_IMAGEDECODER); + for (auto& codec : codecs) + { + std::shared_ptr<CImageDecoder> enc(std::static_pointer_cast<CImageDecoder>(codec)); + std::vector<std::string> mime = StringUtils::Split(enc->GetMimetypes(), "|"); + if (std::find(mime.begin(), mime.end(), strMimeType) != mime.end()) + { + CImageDecoder* result = new CImageDecoder(*enc); + result->Create(strMimeType); + return result; + } + } + return new CFFmpegImage(strMimeType); } diff --git a/xbmc/input/Action.cpp b/xbmc/input/Action.cpp new file mode 100644 index 0000000000..5bab5ae99f --- /dev/null +++ b/xbmc/input/Action.cpp @@ -0,0 +1,153 @@ +/* + * Copyright (C) 2005-2017 Team Kodi + * http://kodi.tv + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this Program; see the file COPYING. If not, see + * <http://www.gnu.org/licenses/>. + * + */ + +#include "Action.h" +#include "ActionIDs.h" +#include "ButtonTranslator.h" +#include "Key.h" + +CAction::CAction(int actionID, float amount1 /* = 1.0f */, float amount2 /* = 0.0f */, const std::string &name /* = "" */, unsigned int holdTime /*= 0*/) +{ + m_id = actionID; + m_amount[0] = amount1; + m_amount[1] = amount2; + for (unsigned int i = 2; i < max_amounts; i++) + m_amount[i] = 0; + m_name = name; + m_repeat = 0; + m_buttonCode = 0; + m_unicode = 0; + m_holdTime = holdTime; +} + +CAction::CAction(int actionID, unsigned int state, float posX, float posY, float offsetX, float offsetY, const std::string &name): + m_name(name) +{ + m_id = actionID; + m_amount[0] = posX; + m_amount[1] = posY; + m_amount[2] = offsetX; + m_amount[3] = offsetY; + for (unsigned int i = 4; i < max_amounts; i++) + m_amount[i] = 0; + m_repeat = 0; + m_buttonCode = 0; + m_unicode = 0; + m_holdTime = state; +} + +CAction::CAction(int actionID, wchar_t unicode) +{ + m_id = actionID; + for (unsigned int i = 0; i < max_amounts; i++) + m_amount[i] = 0; + m_repeat = 0; + m_buttonCode = 0; + m_unicode = unicode; + m_holdTime = 0; +} + +CAction::CAction(int actionID, const std::string &name, const CKey &key): + m_name(name) +{ + m_id = actionID; + m_amount[0] = 1; // digital button (could change this for repeat acceleration) + for (unsigned int i = 1; i < max_amounts; i++) + m_amount[i] = 0; + m_repeat = key.GetRepeat(); + m_buttonCode = key.GetButtonCode(); + m_unicode = 0; + m_holdTime = key.GetHeld(); + // get the action amounts of the analog buttons + if (key.GetButtonCode() == KEY_BUTTON_LEFT_ANALOG_TRIGGER) + m_amount[0] = (float)key.GetLeftTrigger() / 255.0f; + else if (key.GetButtonCode() == KEY_BUTTON_RIGHT_ANALOG_TRIGGER) + m_amount[0] = (float)key.GetRightTrigger() / 255.0f; + else if (key.GetButtonCode() == KEY_BUTTON_LEFT_THUMB_STICK) + { + m_amount[0] = key.GetLeftThumbX(); + m_amount[1] = key.GetLeftThumbY(); + } + else if (key.GetButtonCode() == KEY_BUTTON_RIGHT_THUMB_STICK) + { + m_amount[0] = key.GetRightThumbX(); + m_amount[1] = key.GetRightThumbY(); + } + else if (key.GetButtonCode() == KEY_BUTTON_LEFT_THUMB_STICK_UP) + m_amount[0] = key.GetLeftThumbY(); + else if (key.GetButtonCode() == KEY_BUTTON_LEFT_THUMB_STICK_DOWN) + m_amount[0] = -key.GetLeftThumbY(); + else if (key.GetButtonCode() == KEY_BUTTON_LEFT_THUMB_STICK_LEFT) + m_amount[0] = -key.GetLeftThumbX(); + else if (key.GetButtonCode() == KEY_BUTTON_LEFT_THUMB_STICK_RIGHT) + m_amount[0] = key.GetLeftThumbX(); + else if (key.GetButtonCode() == KEY_BUTTON_RIGHT_THUMB_STICK_UP) + m_amount[0] = key.GetRightThumbY(); + else if (key.GetButtonCode() == KEY_BUTTON_RIGHT_THUMB_STICK_DOWN) + m_amount[0] = -key.GetRightThumbY(); + else if (key.GetButtonCode() == KEY_BUTTON_RIGHT_THUMB_STICK_LEFT) + m_amount[0] = -key.GetRightThumbX(); + else if (key.GetButtonCode() == KEY_BUTTON_RIGHT_THUMB_STICK_RIGHT) + m_amount[0] = key.GetRightThumbX(); +} + +CAction::CAction(int actionID, const std::string &name): + m_name(name) +{ + m_id = actionID; + for (unsigned int i = 0; i < max_amounts; i++) + m_amount[i] = 0; + m_repeat = 0; + m_buttonCode = 0; + m_unicode = 0; + m_holdTime = 0; +} + +CAction& CAction::operator=(const CAction& rhs) +{ + if (this != &rhs) + { + m_id = rhs.m_id; + for (unsigned int i = 0; i < max_amounts; i++) + m_amount[i] = rhs.m_amount[i]; + m_name = rhs.m_name; + m_repeat = rhs.m_repeat; + m_buttonCode = rhs.m_buttonCode; + m_unicode = rhs.m_unicode; + m_holdTime = rhs.m_holdTime; + m_text = rhs.m_text; + } + return *this; +} + +bool CAction::IsMouse() const +{ + return (m_id >= ACTION_MOUSE_START && m_id <= ACTION_MOUSE_END); +} + +bool CAction::IsGesture() const +{ + return (m_id >= ACTION_GESTURE_NOTIFY && m_id <= ACTION_GESTURE_END); +} + +bool CAction::IsAnalog() const +{ + return CButtonTranslator::IsAnalog(m_id); +} diff --git a/xbmc/input/Action.h b/xbmc/input/Action.h new file mode 100644 index 0000000000..e6941652a8 --- /dev/null +++ b/xbmc/input/Action.h @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2005-2017 Team Kodi + * http://kodi.tv + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this Program; see the file COPYING. If not, see + * <http://www.gnu.org/licenses/>. + * + */ +#pragma once + +#include <string> + +#ifndef SWIG + +class CKey; + +/*! + \ingroup actionkeys + \brief class encapsulating information regarding a particular user action to be sent to windows and controls + */ +class CAction +{ +public: + CAction(int actionID, float amount1 = 1.0f, float amount2 = 0.0f, const std::string &name = "", unsigned int holdTime = 0); + CAction(int actionID, wchar_t unicode); + CAction(int actionID, unsigned int state, float posX, float posY, float offsetX, float offsetY, const std::string &name = ""); + CAction(int actionID, const std::string &name, const CKey &key); + CAction(int actionID, const std::string &name); + + CAction(const CAction& other) { *this = other; } + CAction& operator=(const CAction& rhs); + + /*! \brief Identifier of the action + \return id of the action + */ + int GetID() const { return m_id; }; + + /*! \brief Is this an action from the mouse + \return true if this is a mouse action, false otherwise + */ + bool IsMouse() const; + + bool IsGesture() const; + + /*! \brief Human-readable name of the action + \return name of the action + */ + const std::string &GetName() const { return m_name; }; + + /*! \brief Text of the action if any + \return text payload of this action. + */ + const std::string &GetText() const { return m_text; }; + + /*! \brief Set the text payload of the action + \param text to be set + */ + void SetText(const std::string &text) { m_text = text; }; + + /*! \brief Get an amount associated with this action + \param zero-based index of amount to retrieve, defaults to 0 + \return an amount associated with this action + */ + float GetAmount(unsigned int index = 0) const { return (index < max_amounts) ? m_amount[index] : 0; }; + + /*! \brief Unicode value associated with this action + \return unicode value associated with this action, for keyboard input. + */ + wchar_t GetUnicode() const { return m_unicode; }; + + /*! \brief Time in ms that the key has been held + \return time that the key has been held down in ms. + */ + unsigned int GetHoldTime() const { return m_holdTime; }; + + /*! \brief Time since last repeat in ms + \return time since last repeat in ms. Returns 0 if unknown. + */ + float GetRepeat() const { return m_repeat; }; + + /*! \brief Button code that triggered this action + \return button code + */ + unsigned int GetButtonCode() const { return m_buttonCode; }; + + bool IsAnalog() const; + +private: + int m_id; + std::string m_name; + + static const unsigned int max_amounts = 4; // Must be at least 4. + float m_amount[max_amounts]; + + float m_repeat; + unsigned int m_holdTime; + unsigned int m_buttonCode; + wchar_t m_unicode; + std::string m_text; +}; + +#endif diff --git a/xbmc/input/ActionIDs.h b/xbmc/input/ActionIDs.h new file mode 100644 index 0000000000..986f275a53 --- /dev/null +++ b/xbmc/input/ActionIDs.h @@ -0,0 +1,305 @@ +/* + * Copyright (C) 2005-2017 Team Kodi + * http://kodi.tv + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this Program; see the file COPYING. If not, see + * <http://www.gnu.org/licenses/>. + * + */ +#pragma once + +/** + * \defgroup kodi_key_action_ids Action Id's + * \ingroup python_xbmcgui_window_cb + * \ingroup python_xbmcgui_action + * @{ + * @brief Actions that we have defined. + */ +#define ACTION_NONE 0 +#define ACTION_MOVE_LEFT 1 +#define ACTION_MOVE_RIGHT 2 +#define ACTION_MOVE_UP 3 +#define ACTION_MOVE_DOWN 4 +#define ACTION_PAGE_UP 5 +#define ACTION_PAGE_DOWN 6 +#define ACTION_SELECT_ITEM 7 +#define ACTION_HIGHLIGHT_ITEM 8 +#define ACTION_PARENT_DIR 9 +#define ACTION_PREVIOUS_MENU 10 +#define ACTION_SHOW_INFO 11 + +#define ACTION_PAUSE 12 +#define ACTION_STOP 13 +#define ACTION_NEXT_ITEM 14 +#define ACTION_PREV_ITEM 15 +#define ACTION_FORWARD 16 //!< Can be used to specify specific action in a window, Playback control is handled in ACTION_PLAYER_* +#define ACTION_REWIND 17 //!< Can be used to specify specific action in a window, Playback control is handled in ACTION_PLAYER_* + +#define ACTION_SHOW_GUI 18 //!< toggle between GUI and movie or GUI and visualisation. +#define ACTION_ASPECT_RATIO 19 //!< toggle quick-access zoom modes. Can b used in videoFullScreen.zml window id=2005 +#define ACTION_STEP_FORWARD 20 //!< seek +1% in the movie. Can b used in videoFullScreen.xml window id=2005 +#define ACTION_STEP_BACK 21 //!< seek -1% in the movie. Can b used in videoFullScreen.xml window id=2005 +#define ACTION_BIG_STEP_FORWARD 22 //!< seek +10% in the movie. Can b used in videoFullScreen.xml window id=2005 +#define ACTION_BIG_STEP_BACK 23 //!< seek -10% in the movie. Can b used in videoFullScreen.xml window id=2005 +#define ACTION_SHOW_OSD 24 //!< show/hide OSD. Can b used in videoFullScreen.xml window id=2005 +#define ACTION_SHOW_SUBTITLES 25 //!< turn subtitles on/off. Can b used in videoFullScreen.xml window id=2005 +#define ACTION_NEXT_SUBTITLE 26 //!< switch to next subtitle of movie. Can b used in videoFullScreen.xml window id=2005 +#define ACTION_PLAYER_DEBUG 27 //!< show debug info for VideoPlayer +#define ACTION_NEXT_PICTURE 28 //!< show next picture of slideshow. Can b used in slideshow.xml window id=2007 +#define ACTION_PREV_PICTURE 29 //!< show previous picture of slideshow. Can b used in slideshow.xml window id=2007 +#define ACTION_ZOOM_OUT 30 //!< zoom in picture during slideshow. Can b used in slideshow.xml window id=2007 +#define ACTION_ZOOM_IN 31 //!< zoom out picture during slideshow. Can b used in slideshow.xml window id=2007 +#define ACTION_TOGGLE_SOURCE_DEST 32 //!< used to toggle between source view and destination view. Can be used in myfiles.xml window id=3 +#define ACTION_SHOW_PLAYLIST 33 //!< used to toggle between current view and playlist view. Can b used in all mymusic xml files +#define ACTION_QUEUE_ITEM 34 //!< used to queue a item to the playlist. Can b used in all mymusic xml files +#define ACTION_REMOVE_ITEM 35 //!< not used anymore +#define ACTION_SHOW_FULLSCREEN 36 //!< not used anymore +#define ACTION_ZOOM_LEVEL_NORMAL 37 //!< zoom 1x picture during slideshow. Can b used in slideshow.xml window id=2007 +#define ACTION_ZOOM_LEVEL_1 38 //!< zoom 2x picture during slideshow. Can b used in slideshow.xml window id=2007 +#define ACTION_ZOOM_LEVEL_2 39 //!< zoom 3x picture during slideshow. Can b used in slideshow.xml window id=2007 +#define ACTION_ZOOM_LEVEL_3 40 //!< zoom 4x picture during slideshow. Can b used in slideshow.xml window id=2007 +#define ACTION_ZOOM_LEVEL_4 41 //!< zoom 5x picture during slideshow. Can b used in slideshow.xml window id=2007 +#define ACTION_ZOOM_LEVEL_5 42 //!< zoom 6x picture during slideshow. Can b used in slideshow.xml window id=2007 +#define ACTION_ZOOM_LEVEL_6 43 //!< zoom 7x picture during slideshow. Can b used in slideshow.xml window id=2007 +#define ACTION_ZOOM_LEVEL_7 44 //!< zoom 8x picture during slideshow. Can b used in slideshow.xml window id=2007 +#define ACTION_ZOOM_LEVEL_8 45 //!< zoom 9x picture during slideshow. Can b used in slideshow.xml window id=2007 +#define ACTION_ZOOM_LEVEL_9 46 //!< zoom 10x picture during slideshow. Can b used in slideshow.xml window id=2007 + +#define ACTION_CALIBRATE_SWAP_ARROWS 47 //!< select next arrow. Can b used in: settingsScreenCalibration.xml windowid=11 +#define ACTION_CALIBRATE_RESET 48 //!< reset calibration to defaults. Can b used in: `settingsScreenCalibration.xml` windowid=11/settingsUICalibration.xml windowid=10 +#define ACTION_ANALOG_MOVE 49 //!< analog thumbstick move. Can b used in: `slideshow.xml` windowid=2007/settingsScreenCalibration.xml windowid=11/settingsUICalibration.xml windowid=10 + //!< @note see also ACTION_ANALOG_MOVE_X, ACTION_ANALOG_MOVE_Y +#define ACTION_ROTATE_PICTURE_CW 50 //!< rotate current picture clockwise during slideshow. Can be used in slideshow.xml window id=2007 +#define ACTION_ROTATE_PICTURE_CCW 51 //!< rotate current picture counterclockwise during slideshow. Can be used in slideshow.xml window id=2007 + +#define ACTION_SUBTITLE_DELAY_MIN 52 //!< Decrease subtitle/movie Delay. Can b used in videoFullScreen.xml window id=2005 +#define ACTION_SUBTITLE_DELAY_PLUS 53 //!< Increase subtitle/movie Delay. Can b used in videoFullScreen.xml window id=2005 +#define ACTION_AUDIO_DELAY_MIN 54 //!< Increase avsync delay. Can b used in videoFullScreen.xml window id=2005 +#define ACTION_AUDIO_DELAY_PLUS 55 //!< Decrease avsync delay. Can b used in videoFullScreen.xml window id=2005 +#define ACTION_AUDIO_NEXT_LANGUAGE 56 //!< Select next language in movie. Can b used in videoFullScreen.xml window id=2005 +#define ACTION_CHANGE_RESOLUTION 57 //!< switch 2 next resolution. Can b used during screen calibration settingsScreenCalibration.xml windowid=11 + +#define REMOTE_0 58 //!< remote keys 0-9. are used by multiple windows +#define REMOTE_1 59 //!< for example in videoFullScreen.xml window id=2005 you can +#define REMOTE_2 60 //!< enter time (mmss) to jump to particular point in the movie +#define REMOTE_3 61 +#define REMOTE_4 62 //!< with spincontrols you can enter 3digit number to quickly set +#define REMOTE_5 63 //!< spincontrol to desired value +#define REMOTE_6 64 +#define REMOTE_7 65 +#define REMOTE_8 66 +#define REMOTE_9 67 + +#define ACTION_PLAY 68 //!< Unused at the moment +#define ACTION_PLAYER_PROCESS_INFO 69 //!< show player process info (video decoder, pixel format, pvr signal strength and the like +#define ACTION_SMALL_STEP_BACK 76 //!< jumps a few seconds back during playback of movie. Can b used in videoFullScreen.xml window id=2005 + +#define ACTION_PLAYER_FORWARD 77 //!< FF in current file played. global action, can be used anywhere +#define ACTION_PLAYER_REWIND 78 //!< RW in current file played. global action, can be used anywhere +#define ACTION_PLAYER_PLAY 79 //!< Play current song. Unpauses song and sets playspeed to 1x. global action, can be used anywhere + +#define ACTION_DELETE_ITEM 80 //!< delete current selected item. Can be used in myfiles.xml window id=3 and in myvideoTitle.xml window id=25 +#define ACTION_COPY_ITEM 81 //!< copy current selected item. Can be used in myfiles.xml window id=3 +#define ACTION_MOVE_ITEM 82 //!< move current selected item. Can be used in myfiles.xml window id=3 +#define ACTION_TAKE_SCREENSHOT 85 //!< take a screenshot +#define ACTION_RENAME_ITEM 87 //!< rename item + +#define ACTION_VOLUME_UP 88 +#define ACTION_VOLUME_DOWN 89 +#define ACTION_VOLAMP 90 +#define ACTION_MUTE 91 +#define ACTION_NAV_BACK 92 +#define ACTION_VOLAMP_UP 93 +#define ACTION_VOLAMP_DOWN 94 + +#define ACTION_CREATE_EPISODE_BOOKMARK 95 //!< Creates an episode bookmark on the currently playing video file containing more than one episode +#define ACTION_CREATE_BOOKMARK 96 //!< Creates a bookmark of the currently playing video file + +#define ACTION_CHAPTER_OR_BIG_STEP_FORWARD 97 //!< Goto the next chapter, if not available perform a big step forward +#define ACTION_CHAPTER_OR_BIG_STEP_BACK 98 //!< Goto the previous chapter, if not available perform a big step back + +#define ACTION_CYCLE_SUBTITLE 99 //!< switch to next subtitle of movie, but will not enable/disable the subtitles. Can be used in videoFullScreen.xml window id=2005 + +#define ACTION_MOUSE_START 100 +#define ACTION_MOUSE_LEFT_CLICK 100 +#define ACTION_MOUSE_RIGHT_CLICK 101 +#define ACTION_MOUSE_MIDDLE_CLICK 102 +#define ACTION_MOUSE_DOUBLE_CLICK 103 +#define ACTION_MOUSE_WHEEL_UP 104 +#define ACTION_MOUSE_WHEEL_DOWN 105 +#define ACTION_MOUSE_DRAG 106 +#define ACTION_MOUSE_MOVE 107 +#define ACTION_MOUSE_LONG_CLICK 108 +#define ACTION_MOUSE_END 109 + +#define ACTION_BACKSPACE 110 +#define ACTION_SCROLL_UP 111 +#define ACTION_SCROLL_DOWN 112 +#define ACTION_ANALOG_FORWARD 113 +#define ACTION_ANALOG_REWIND 114 + +#define ACTION_MOVE_ITEM_UP 115 //!< move item up in playlist +#define ACTION_MOVE_ITEM_DOWN 116 //!< move item down in playlist +#define ACTION_CONTEXT_MENU 117 //!< pops up the context menu + +// stuff for virtual keyboard shortcuts +#define ACTION_SHIFT 118 //!< stuff for virtual keyboard shortcuts +#define ACTION_SYMBOLS 119 //!< stuff for virtual keyboard shortcuts +#define ACTION_CURSOR_LEFT 120 //!< stuff for virtual keyboard shortcuts +#define ACTION_CURSOR_RIGHT 121 //!< stuff for virtual keyboard shortcuts + +#define ACTION_BUILT_IN_FUNCTION 122 + +#define ACTION_SHOW_OSD_TIME 123 //!< displays current time, can be used in videoFullScreen.xml window id=2005 +#define ACTION_ANALOG_SEEK_FORWARD 124 //!< seeks forward, and displays the seek bar. +#define ACTION_ANALOG_SEEK_BACK 125 //!< seeks backward, and displays the seek bar. + +#define ACTION_VIS_PRESET_SHOW 126 +#define ACTION_VIS_PRESET_NEXT 128 +#define ACTION_VIS_PRESET_PREV 129 +#define ACTION_VIS_PRESET_LOCK 130 +#define ACTION_VIS_PRESET_RANDOM 131 +#define ACTION_VIS_RATE_PRESET_PLUS 132 +#define ACTION_VIS_RATE_PRESET_MINUS 133 + +#define ACTION_SHOW_VIDEOMENU 134 +#define ACTION_ENTER 135 + +#define ACTION_INCREASE_RATING 136 +#define ACTION_DECREASE_RATING 137 + +#define ACTION_NEXT_SCENE 138 //!< switch to next scene/cutpoint in movie +#define ACTION_PREV_SCENE 139 //!< switch to previous scene/cutpoint in movie + +#define ACTION_NEXT_LETTER 140 //!< jump through a list or container by letter +#define ACTION_PREV_LETTER 141 + +#define ACTION_JUMP_SMS2 142 //!< jump direct to a particular letter using SMS-style input +#define ACTION_JUMP_SMS3 143 +#define ACTION_JUMP_SMS4 144 +#define ACTION_JUMP_SMS5 145 +#define ACTION_JUMP_SMS6 146 +#define ACTION_JUMP_SMS7 147 +#define ACTION_JUMP_SMS8 148 +#define ACTION_JUMP_SMS9 149 + +#define ACTION_FILTER_CLEAR 150 +#define ACTION_FILTER_SMS2 151 +#define ACTION_FILTER_SMS3 152 +#define ACTION_FILTER_SMS4 153 +#define ACTION_FILTER_SMS5 154 +#define ACTION_FILTER_SMS6 155 +#define ACTION_FILTER_SMS7 156 +#define ACTION_FILTER_SMS8 157 +#define ACTION_FILTER_SMS9 158 + +#define ACTION_FIRST_PAGE 159 +#define ACTION_LAST_PAGE 160 + +#define ACTION_AUDIO_DELAY 161 +#define ACTION_SUBTITLE_DELAY 162 +#define ACTION_MENU 163 + +#define ACTION_SET_RATING 164 + +#define ACTION_RECORD 170 + +#define ACTION_PASTE 180 +#define ACTION_NEXT_CONTROL 181 +#define ACTION_PREV_CONTROL 182 +#define ACTION_CHANNEL_SWITCH 183 +#define ACTION_CHANNEL_UP 184 +#define ACTION_CHANNEL_DOWN 185 +#define ACTION_NEXT_CHANNELGROUP 186 +#define ACTION_PREVIOUS_CHANNELGROUP 187 +#define ACTION_PVR_PLAY 188 +#define ACTION_PVR_PLAY_TV 189 +#define ACTION_PVR_PLAY_RADIO 190 +#define ACTION_PVR_SHOW_TIMER_RULE 191 + +#define ACTION_TOGGLE_FULLSCREEN 199 //!< switch 2 desktop resolution +#define ACTION_TOGGLE_WATCHED 200 //!< Toggle watched status (videos) +#define ACTION_SCAN_ITEM 201 //!< scan item +#define ACTION_TOGGLE_DIGITAL_ANALOG 202 //!< switch digital <-> analog +#define ACTION_RELOAD_KEYMAPS 203 //!< reloads CButtonTranslator's keymaps +#define ACTION_GUIPROFILE_BEGIN 204 //!< start the GUIControlProfiler running + +#define ACTION_TELETEXT_RED 215 //!< Teletext Color button <b>Red</b> to control TopText +#define ACTION_TELETEXT_GREEN 216 //!< Teletext Color button <b>Green</b> to control TopText +#define ACTION_TELETEXT_YELLOW 217 //!< Teletext Color button <b>Yellow</b> to control TopText +#define ACTION_TELETEXT_BLUE 218 //!< Teletext Color button <b>Blue</b> to control TopText + +#define ACTION_INCREASE_PAR 219 +#define ACTION_DECREASE_PAR 220 + +#define ACTION_VSHIFT_UP 227 //!< shift up video image in VideoPlayer +#define ACTION_VSHIFT_DOWN 228 //!< shift down video image in VideoPlayer + +#define ACTION_PLAYER_PLAYPAUSE 229 //!< Play/pause. If playing it pauses, if paused it plays. + +#define ACTION_SUBTITLE_VSHIFT_UP 230 //!< shift up subtitles in VideoPlayer +#define ACTION_SUBTITLE_VSHIFT_DOWN 231 //!< shift down subtitles in VideoPlayer +#define ACTION_SUBTITLE_ALIGN 232 //!< toggle vertical alignment of subtitles + +#define ACTION_FILTER 233 + +#define ACTION_SWITCH_PLAYER 234 + +#define ACTION_STEREOMODE_NEXT 235 +#define ACTION_STEREOMODE_PREVIOUS 236 +#define ACTION_STEREOMODE_TOGGLE 237 //!< turns 3d mode on/off +#define ACTION_STEREOMODE_SELECT 238 +#define ACTION_STEREOMODE_TOMONO 239 +#define ACTION_STEREOMODE_SET 240 + +#define ACTION_SETTINGS_RESET 241 +#define ACTION_SETTINGS_LEVEL_CHANGE 242 + +#define ACTION_TRIGGER_OSD 243 //!< show autoclosing OSD. Can b used in videoFullScreen.xml window id=2005 +#define ACTION_INPUT_TEXT 244 +#define ACTION_VOLUME_SET 245 +#define ACTION_TOGGLE_COMMSKIP 246 + +#define ACTION_TOUCH_TAP 401 //!< touch actions +#define ACTION_TOUCH_TAP_TEN 410 //!< touch actions +#define ACTION_TOUCH_LONGPRESS 411 //!< touch actions +#define ACTION_TOUCH_LONGPRESS_TEN 420 //!< touch actions + +#define ACTION_GESTURE_NOTIFY 500 +#define ACTION_GESTURE_BEGIN 501 +#define ACTION_GESTURE_ZOOM 502 //!< sendaction with point and currentPinchScale (fingers together < 1.0 -> fingers apart > 1.0) +#define ACTION_GESTURE_ROTATE 503 +#define ACTION_GESTURE_PAN 504 + +#define ACTION_GESTURE_SWIPE_LEFT 511 +#define ACTION_GESTURE_SWIPE_LEFT_TEN 520 +#define ACTION_GESTURE_SWIPE_RIGHT 521 +#define ACTION_GESTURE_SWIPE_RIGHT_TEN 530 +#define ACTION_GESTURE_SWIPE_UP 531 +#define ACTION_GESTURE_SWIPE_UP_TEN 540 +#define ACTION_GESTURE_SWIPE_DOWN 541 +#define ACTION_GESTURE_SWIPE_DOWN_TEN 550 +// 5xx is reserved for additional gesture actions +#define ACTION_GESTURE_END 599 + +// other, non-gesture actions +#define ACTION_ANALOG_MOVE_X 601 //!< analog thumbstick move, horizontal axis; see ACTION_ANALOG_MOVE +#define ACTION_ANALOG_MOVE_Y 602 //!< analog thumbstick move, vertical axis; see ACTION_ANALOG_MOVE +//@} + +// The NOOP action can be specified to disable an input event. This is +// useful in user keyboard.xml etc to disable actions specified in the +// system mappings. ERROR action is used to play an error sound +#define ACTION_ERROR 998 +#define ACTION_NOOP 999 diff --git a/xbmc/input/ButtonTranslator.cpp b/xbmc/input/ButtonTranslator.cpp index 67455196f8..cc628c0316 100644 --- a/xbmc/input/ButtonTranslator.cpp +++ b/xbmc/input/ButtonTranslator.cpp @@ -911,7 +911,7 @@ CAction CButtonTranslator::GetGlobalAction(const CKey &key) return GetAction(-1, key, true); } -bool CButtonTranslator::HasLonpressMapping(int window, const CKey &key) +bool CButtonTranslator::HasLongpressMapping(int window, const CKey &key) { std::map<int, buttonMap>::const_iterator it = m_translatorMap.find(window); if (it != m_translatorMap.end()) @@ -940,11 +940,11 @@ bool CButtonTranslator::HasLonpressMapping(int window, const CKey &key) { // first check if we have a fallback for the window int fallbackWindow = GetFallbackWindow(window); - if (fallbackWindow > -1 && HasLonpressMapping(fallbackWindow, key)) + if (fallbackWindow > -1 && HasLongpressMapping(fallbackWindow, key)) return true; // fallback to default section - return HasLonpressMapping(-1, key); + return HasLongpressMapping(-1, key); } return false; diff --git a/xbmc/input/ButtonTranslator.h b/xbmc/input/ButtonTranslator.h index 1cbac59453..0ccd82ebc6 100644 --- a/xbmc/input/ButtonTranslator.h +++ b/xbmc/input/ButtonTranslator.h @@ -79,7 +79,7 @@ public: \param key to search a mapping for \return true if a longpress mapping exists */ - bool HasLonpressMapping(int window, const CKey &key); + bool HasLongpressMapping(int window, const CKey &key); /*! \brief Obtain the action configured for a given window and key \param window the window id diff --git a/xbmc/input/CMakeLists.txt b/xbmc/input/CMakeLists.txt index a961423028..a1fec26d31 100644 --- a/xbmc/input/CMakeLists.txt +++ b/xbmc/input/CMakeLists.txt @@ -1,4 +1,5 @@ -set(SOURCES ButtonTranslator.cpp +set(SOURCES Action.cpp + ButtonTranslator.cpp InertialScrollingHandler.cpp InputCodingTableBaiduPY.cpp InputCodingTableBasePY.cpp @@ -12,7 +13,9 @@ set(SOURCES ButtonTranslator.cpp MouseStat.cpp XBMC_keytable.cpp) -set(HEADERS ButtonTranslator.h +set(HEADERS Action.h + ActionIDs.h + ButtonTranslator.h InertialScrollingHandler.h InputCodingTable.h InputCodingTableBaiduPY.h diff --git a/xbmc/input/InputManager.cpp b/xbmc/input/InputManager.cpp index 4f1663fed9..b24387ec82 100644 --- a/xbmc/input/InputManager.cpp +++ b/xbmc/input/InputManager.cpp @@ -70,7 +70,8 @@ using EVENTSERVER::CEventServer; #endif -using namespace KODI::MESSAGING; +using namespace KODI; +using namespace MESSAGING; using PERIPHERALS::CPeripherals; CInputManager::CInputManager() : @@ -368,7 +369,7 @@ bool CInputManager::OnEvent(XBMC_Event& newEvent) // Do not repeat long presses break; } - if (!CButtonTranslator::GetInstance().HasLonpressMapping(g_windowManager.GetActiveWindowID(), key)) + if (!CButtonTranslator::GetInstance().HasLongpressMapping(g_windowManager.GetActiveWindowID(), key)) { m_LastKey.Reset(); OnKey(key); diff --git a/xbmc/input/InputManager.h b/xbmc/input/InputManager.h index ba31cfcbf3..f161315179 100644 --- a/xbmc/input/InputManager.h +++ b/xbmc/input/InputManager.h @@ -39,6 +39,8 @@ class CKey; +namespace KODI +{ namespace KEYBOARD { class IKeyboardHandler; @@ -50,6 +52,7 @@ namespace MOUSE class IMouseDriverHandler; class IMouseInputHandler; } +} /// \addtogroup input /// \{ @@ -244,13 +247,13 @@ public: * * \param handler The handler to call on keyboard input. */ - void RegisterKeyboardHandler(KEYBOARD::IKeyboardHandler* handler); + void RegisterKeyboardHandler(KODI::KEYBOARD::IKeyboardHandler* handler); /*! \brief Unregisters handler from keyboard input. * * \param[in] handler The handler to unregister from keyboard input. */ - void UnregisterKeyboardHandler(KEYBOARD::IKeyboardHandler* handler); + void UnregisterKeyboardHandler(KODI::KEYBOARD::IKeyboardHandler* handler); /*! \brief Registers a handler to be called on mouse input (e.g a game client). * @@ -258,13 +261,13 @@ public: * \return[in] The controller ID that serves as a context for incoming events. * \sa IMouseButtonMap */ - std::string RegisterMouseHandler(MOUSE::IMouseInputHandler* handler); + std::string RegisterMouseHandler(KODI::MOUSE::IMouseInputHandler* handler); /*! \brief Unregisters handler from mouse input. * * \param[in] handler The handler to unregister from mouse input. */ - void UnregisterMouseHandler(MOUSE::IMouseInputHandler* handler); + void UnregisterMouseHandler(KODI::MOUSE::IMouseInputHandler* handler); private: @@ -316,18 +319,18 @@ private: std::vector<CAction> m_queuedActions; CCriticalSection m_actionMutex; - std::vector<KEYBOARD::IKeyboardHandler*> m_keyboardHandlers; + std::vector<KODI::KEYBOARD::IKeyboardHandler*> m_keyboardHandlers; struct MouseHandlerHandle { - MOUSE::IMouseInputHandler* inputHandler; - std::unique_ptr<MOUSE::IMouseDriverHandler> driverHandler; + KODI::MOUSE::IMouseInputHandler* inputHandler; + std::unique_ptr<KODI::MOUSE::IMouseDriverHandler> driverHandler; }; std::vector<MouseHandlerHandle> m_mouseHandlers; - std::unique_ptr<MOUSE::IMouseButtonMap> m_mouseButtonMap; + std::unique_ptr<KODI::MOUSE::IMouseButtonMap> m_mouseButtonMap; - std::unique_ptr<KEYBOARD::IKeyboardHandler> m_keyboardEasterEgg; + std::unique_ptr<KODI::KEYBOARD::IKeyboardHandler> m_keyboardEasterEgg; }; /// \} diff --git a/xbmc/input/Key.cpp b/xbmc/input/Key.cpp index a200663332..aa428ecb9e 100644 --- a/xbmc/input/Key.cpp +++ b/xbmc/input/Key.cpp @@ -20,7 +20,6 @@ #include "system.h" #include "input/Key.h" -#include "input/ButtonTranslator.h" CKey::CKey(void) { @@ -171,122 +170,3 @@ void CKey::SetFromService(bool fromService) m_fromService = fromService; } - -CAction::CAction(int actionID, float amount1 /* = 1.0f */, float amount2 /* = 0.0f */, const std::string &name /* = "" */, unsigned int holdTime /*= 0*/) -{ - m_id = actionID; - m_amount[0] = amount1; - m_amount[1] = amount2; - for (unsigned int i = 2; i < max_amounts; i++) - m_amount[i] = 0; - m_name = name; - m_repeat = 0; - m_buttonCode = 0; - m_unicode = 0; - m_holdTime = holdTime; -} - -CAction::CAction(int actionID, unsigned int state, float posX, float posY, float offsetX, float offsetY, const std::string &name): - m_name(name) -{ - m_id = actionID; - m_amount[0] = posX; - m_amount[1] = posY; - m_amount[2] = offsetX; - m_amount[3] = offsetY; - for (unsigned int i = 4; i < max_amounts; i++) - m_amount[i] = 0; - m_repeat = 0; - m_buttonCode = 0; - m_unicode = 0; - m_holdTime = state; -} - -CAction::CAction(int actionID, wchar_t unicode) -{ - m_id = actionID; - for (unsigned int i = 0; i < max_amounts; i++) - m_amount[i] = 0; - m_repeat = 0; - m_buttonCode = 0; - m_unicode = unicode; - m_holdTime = 0; -} - -CAction::CAction(int actionID, const std::string &name, const CKey &key): - m_name(name) -{ - m_id = actionID; - m_amount[0] = 1; // digital button (could change this for repeat acceleration) - for (unsigned int i = 1; i < max_amounts; i++) - m_amount[i] = 0; - m_repeat = key.GetRepeat(); - m_buttonCode = key.GetButtonCode(); - m_unicode = 0; - m_holdTime = key.GetHeld(); - // get the action amounts of the analog buttons - if (key.GetButtonCode() == KEY_BUTTON_LEFT_ANALOG_TRIGGER) - m_amount[0] = (float)key.GetLeftTrigger() / 255.0f; - else if (key.GetButtonCode() == KEY_BUTTON_RIGHT_ANALOG_TRIGGER) - m_amount[0] = (float)key.GetRightTrigger() / 255.0f; - else if (key.GetButtonCode() == KEY_BUTTON_LEFT_THUMB_STICK) - { - m_amount[0] = key.GetLeftThumbX(); - m_amount[1] = key.GetLeftThumbY(); - } - else if (key.GetButtonCode() == KEY_BUTTON_RIGHT_THUMB_STICK) - { - m_amount[0] = key.GetRightThumbX(); - m_amount[1] = key.GetRightThumbY(); - } - else if (key.GetButtonCode() == KEY_BUTTON_LEFT_THUMB_STICK_UP) - m_amount[0] = key.GetLeftThumbY(); - else if (key.GetButtonCode() == KEY_BUTTON_LEFT_THUMB_STICK_DOWN) - m_amount[0] = -key.GetLeftThumbY(); - else if (key.GetButtonCode() == KEY_BUTTON_LEFT_THUMB_STICK_LEFT) - m_amount[0] = -key.GetLeftThumbX(); - else if (key.GetButtonCode() == KEY_BUTTON_LEFT_THUMB_STICK_RIGHT) - m_amount[0] = key.GetLeftThumbX(); - else if (key.GetButtonCode() == KEY_BUTTON_RIGHT_THUMB_STICK_UP) - m_amount[0] = key.GetRightThumbY(); - else if (key.GetButtonCode() == KEY_BUTTON_RIGHT_THUMB_STICK_DOWN) - m_amount[0] = -key.GetRightThumbY(); - else if (key.GetButtonCode() == KEY_BUTTON_RIGHT_THUMB_STICK_LEFT) - m_amount[0] = -key.GetRightThumbX(); - else if (key.GetButtonCode() == KEY_BUTTON_RIGHT_THUMB_STICK_RIGHT) - m_amount[0] = key.GetRightThumbX(); -} - -CAction::CAction(int actionID, const std::string &name): - m_name(name) -{ - m_id = actionID; - for (unsigned int i = 0; i < max_amounts; i++) - m_amount[i] = 0; - m_repeat = 0; - m_buttonCode = 0; - m_unicode = 0; - m_holdTime = 0; -} - -CAction& CAction::operator=(const CAction& rhs) -{ - if (this != &rhs) - { - m_id = rhs.m_id; - for (unsigned int i = 0; i < max_amounts; i++) - m_amount[i] = rhs.m_amount[i]; - m_name = rhs.m_name; - m_repeat = rhs.m_repeat; - m_buttonCode = rhs.m_buttonCode; - m_unicode = rhs.m_unicode; - m_holdTime = rhs.m_holdTime; - m_text = rhs.m_text; - } - return *this; -} - -bool CAction::IsAnalog() const -{ - return CButtonTranslator::IsAnalog(m_id); -} diff --git a/xbmc/input/Key.h b/xbmc/input/Key.h index bdc478cbd5..9836315721 100644 --- a/xbmc/input/Key.h +++ b/xbmc/input/Key.h @@ -24,6 +24,10 @@ * */ +//! @todo Remove dependence on CAction +#include "Action.h" +#include "ActionIDs.h" + #include <string> #include <stdint.h> @@ -135,292 +139,6 @@ #define KEY_INVALID 0xFFFF -// actions that we have defined... -/** - * \defgroup kodi_key_action_ids Action Id's - * \ingroup python_xbmcgui_window_cb - * \ingroup python_xbmcgui_action - * @{ - * @brief Actions that we have defined. - */ -#define ACTION_NONE 0 -#define ACTION_MOVE_LEFT 1 -#define ACTION_MOVE_RIGHT 2 -#define ACTION_MOVE_UP 3 -#define ACTION_MOVE_DOWN 4 -#define ACTION_PAGE_UP 5 -#define ACTION_PAGE_DOWN 6 -#define ACTION_SELECT_ITEM 7 -#define ACTION_HIGHLIGHT_ITEM 8 -#define ACTION_PARENT_DIR 9 -#define ACTION_PREVIOUS_MENU 10 -#define ACTION_SHOW_INFO 11 - -#define ACTION_PAUSE 12 -#define ACTION_STOP 13 -#define ACTION_NEXT_ITEM 14 -#define ACTION_PREV_ITEM 15 -#define ACTION_FORWARD 16 //!< Can be used to specify specific action in a window, Playback control is handled in ACTION_PLAYER_* -#define ACTION_REWIND 17 //!< Can be used to specify specific action in a window, Playback control is handled in ACTION_PLAYER_* - -#define ACTION_SHOW_GUI 18 //!< toggle between GUI and movie or GUI and visualisation. -#define ACTION_ASPECT_RATIO 19 //!< toggle quick-access zoom modes. Can b used in videoFullScreen.zml window id=2005 -#define ACTION_STEP_FORWARD 20 //!< seek +1% in the movie. Can b used in videoFullScreen.xml window id=2005 -#define ACTION_STEP_BACK 21 //!< seek -1% in the movie. Can b used in videoFullScreen.xml window id=2005 -#define ACTION_BIG_STEP_FORWARD 22 //!< seek +10% in the movie. Can b used in videoFullScreen.xml window id=2005 -#define ACTION_BIG_STEP_BACK 23 //!< seek -10% in the movie. Can b used in videoFullScreen.xml window id=2005 -#define ACTION_SHOW_OSD 24 //!< show/hide OSD. Can b used in videoFullScreen.xml window id=2005 -#define ACTION_SHOW_SUBTITLES 25 //!< turn subtitles on/off. Can b used in videoFullScreen.xml window id=2005 -#define ACTION_NEXT_SUBTITLE 26 //!< switch to next subtitle of movie. Can b used in videoFullScreen.xml window id=2005 -#define ACTION_PLAYER_DEBUG 27 //!< show debug info for VideoPlayer -#define ACTION_NEXT_PICTURE 28 //!< show next picture of slideshow. Can b used in slideshow.xml window id=2007 -#define ACTION_PREV_PICTURE 29 //!< show previous picture of slideshow. Can b used in slideshow.xml window id=2007 -#define ACTION_ZOOM_OUT 30 //!< zoom in picture during slideshow. Can b used in slideshow.xml window id=2007 -#define ACTION_ZOOM_IN 31 //!< zoom out picture during slideshow. Can b used in slideshow.xml window id=2007 -#define ACTION_TOGGLE_SOURCE_DEST 32 //!< used to toggle between source view and destination view. Can be used in myfiles.xml window id=3 -#define ACTION_SHOW_PLAYLIST 33 //!< used to toggle between current view and playlist view. Can b used in all mymusic xml files -#define ACTION_QUEUE_ITEM 34 //!< used to queue a item to the playlist. Can b used in all mymusic xml files -#define ACTION_REMOVE_ITEM 35 //!< not used anymore -#define ACTION_SHOW_FULLSCREEN 36 //!< not used anymore -#define ACTION_ZOOM_LEVEL_NORMAL 37 //!< zoom 1x picture during slideshow. Can b used in slideshow.xml window id=2007 -#define ACTION_ZOOM_LEVEL_1 38 //!< zoom 2x picture during slideshow. Can b used in slideshow.xml window id=2007 -#define ACTION_ZOOM_LEVEL_2 39 //!< zoom 3x picture during slideshow. Can b used in slideshow.xml window id=2007 -#define ACTION_ZOOM_LEVEL_3 40 //!< zoom 4x picture during slideshow. Can b used in slideshow.xml window id=2007 -#define ACTION_ZOOM_LEVEL_4 41 //!< zoom 5x picture during slideshow. Can b used in slideshow.xml window id=2007 -#define ACTION_ZOOM_LEVEL_5 42 //!< zoom 6x picture during slideshow. Can b used in slideshow.xml window id=2007 -#define ACTION_ZOOM_LEVEL_6 43 //!< zoom 7x picture during slideshow. Can b used in slideshow.xml window id=2007 -#define ACTION_ZOOM_LEVEL_7 44 //!< zoom 8x picture during slideshow. Can b used in slideshow.xml window id=2007 -#define ACTION_ZOOM_LEVEL_8 45 //!< zoom 9x picture during slideshow. Can b used in slideshow.xml window id=2007 -#define ACTION_ZOOM_LEVEL_9 46 //!< zoom 10x picture during slideshow. Can b used in slideshow.xml window id=2007 - -#define ACTION_CALIBRATE_SWAP_ARROWS 47 //!< select next arrow. Can b used in: settingsScreenCalibration.xml windowid=11 -#define ACTION_CALIBRATE_RESET 48 //!< reset calibration to defaults. Can b used in: `settingsScreenCalibration.xml` windowid=11/settingsUICalibration.xml windowid=10 -#define ACTION_ANALOG_MOVE 49 //!< analog thumbstick move. Can b used in: `slideshow.xml` windowid=2007/settingsScreenCalibration.xml windowid=11/settingsUICalibration.xml windowid=10 - //!< @note see also ACTION_ANALOG_MOVE_X, ACTION_ANALOG_MOVE_Y -#define ACTION_ROTATE_PICTURE_CW 50 //!< rotate current picture clockwise during slideshow. Can be used in slideshow.xml window id=2007 -#define ACTION_ROTATE_PICTURE_CCW 51 //!< rotate current picture counterclockwise during slideshow. Can be used in slideshow.xml window id=2007 - -#define ACTION_SUBTITLE_DELAY_MIN 52 //!< Decrease subtitle/movie Delay. Can b used in videoFullScreen.xml window id=2005 -#define ACTION_SUBTITLE_DELAY_PLUS 53 //!< Increase subtitle/movie Delay. Can b used in videoFullScreen.xml window id=2005 -#define ACTION_AUDIO_DELAY_MIN 54 //!< Increase avsync delay. Can b used in videoFullScreen.xml window id=2005 -#define ACTION_AUDIO_DELAY_PLUS 55 //!< Decrease avsync delay. Can b used in videoFullScreen.xml window id=2005 -#define ACTION_AUDIO_NEXT_LANGUAGE 56 //!< Select next language in movie. Can b used in videoFullScreen.xml window id=2005 -#define ACTION_CHANGE_RESOLUTION 57 //!< switch 2 next resolution. Can b used during screen calibration settingsScreenCalibration.xml windowid=11 - -#define REMOTE_0 58 //!< remote keys 0-9. are used by multiple windows -#define REMOTE_1 59 //!< for example in videoFullScreen.xml window id=2005 you can -#define REMOTE_2 60 //!< enter time (mmss) to jump to particular point in the movie -#define REMOTE_3 61 -#define REMOTE_4 62 //!< with spincontrols you can enter 3digit number to quickly set -#define REMOTE_5 63 //!< spincontrol to desired value -#define REMOTE_6 64 -#define REMOTE_7 65 -#define REMOTE_8 66 -#define REMOTE_9 67 - -#define ACTION_PLAY 68 //!< Unused at the moment -#define ACTION_PLAYER_PROCESS_INFO 69 //!< show player process info (video decoder, pixel format, pvr signal strength and the like -#define ACTION_SMALL_STEP_BACK 76 //!< jumps a few seconds back during playback of movie. Can b used in videoFullScreen.xml window id=2005 - -#define ACTION_PLAYER_FORWARD 77 //!< FF in current file played. global action, can be used anywhere -#define ACTION_PLAYER_REWIND 78 //!< RW in current file played. global action, can be used anywhere -#define ACTION_PLAYER_PLAY 79 //!< Play current song. Unpauses song and sets playspeed to 1x. global action, can be used anywhere - -#define ACTION_DELETE_ITEM 80 //!< delete current selected item. Can be used in myfiles.xml window id=3 and in myvideoTitle.xml window id=25 -#define ACTION_COPY_ITEM 81 //!< copy current selected item. Can be used in myfiles.xml window id=3 -#define ACTION_MOVE_ITEM 82 //!< move current selected item. Can be used in myfiles.xml window id=3 -#define ACTION_TAKE_SCREENSHOT 85 //!< take a screenshot -#define ACTION_RENAME_ITEM 87 //!< rename item - -#define ACTION_VOLUME_UP 88 -#define ACTION_VOLUME_DOWN 89 -#define ACTION_VOLAMP 90 -#define ACTION_MUTE 91 -#define ACTION_NAV_BACK 92 -#define ACTION_VOLAMP_UP 93 -#define ACTION_VOLAMP_DOWN 94 - -#define ACTION_CREATE_EPISODE_BOOKMARK 95 //!< Creates an episode bookmark on the currently playing video file containing more than one episode -#define ACTION_CREATE_BOOKMARK 96 //!< Creates a bookmark of the currently playing video file - -#define ACTION_CHAPTER_OR_BIG_STEP_FORWARD 97 //!< Goto the next chapter, if not available perform a big step forward -#define ACTION_CHAPTER_OR_BIG_STEP_BACK 98 //!< Goto the previous chapter, if not available perform a big step back - -#define ACTION_CYCLE_SUBTITLE 99 //!< switch to next subtitle of movie, but will not enable/disable the subtitles. Can be used in videoFullScreen.xml window id=2005 - -#define ACTION_MOUSE_START 100 -#define ACTION_MOUSE_LEFT_CLICK 100 -#define ACTION_MOUSE_RIGHT_CLICK 101 -#define ACTION_MOUSE_MIDDLE_CLICK 102 -#define ACTION_MOUSE_DOUBLE_CLICK 103 -#define ACTION_MOUSE_WHEEL_UP 104 -#define ACTION_MOUSE_WHEEL_DOWN 105 -#define ACTION_MOUSE_DRAG 106 -#define ACTION_MOUSE_MOVE 107 -#define ACTION_MOUSE_LONG_CLICK 108 -#define ACTION_MOUSE_END 109 - -#define ACTION_BACKSPACE 110 -#define ACTION_SCROLL_UP 111 -#define ACTION_SCROLL_DOWN 112 -#define ACTION_ANALOG_FORWARD 113 -#define ACTION_ANALOG_REWIND 114 - -#define ACTION_MOVE_ITEM_UP 115 //!< move item up in playlist -#define ACTION_MOVE_ITEM_DOWN 116 //!< move item down in playlist -#define ACTION_CONTEXT_MENU 117 //!< pops up the context menu - -// stuff for virtual keyboard shortcuts -#define ACTION_SHIFT 118 //!< stuff for virtual keyboard shortcuts -#define ACTION_SYMBOLS 119 //!< stuff for virtual keyboard shortcuts -#define ACTION_CURSOR_LEFT 120 //!< stuff for virtual keyboard shortcuts -#define ACTION_CURSOR_RIGHT 121 //!< stuff for virtual keyboard shortcuts - -#define ACTION_BUILT_IN_FUNCTION 122 - -#define ACTION_SHOW_OSD_TIME 123 //!< displays current time, can be used in videoFullScreen.xml window id=2005 -#define ACTION_ANALOG_SEEK_FORWARD 124 //!< seeks forward, and displays the seek bar. -#define ACTION_ANALOG_SEEK_BACK 125 //!< seeks backward, and displays the seek bar. - -#define ACTION_VIS_PRESET_SHOW 126 -#define ACTION_VIS_PRESET_NEXT 128 -#define ACTION_VIS_PRESET_PREV 129 -#define ACTION_VIS_PRESET_LOCK 130 -#define ACTION_VIS_PRESET_RANDOM 131 -#define ACTION_VIS_RATE_PRESET_PLUS 132 -#define ACTION_VIS_RATE_PRESET_MINUS 133 - -#define ACTION_SHOW_VIDEOMENU 134 -#define ACTION_ENTER 135 - -#define ACTION_INCREASE_RATING 136 -#define ACTION_DECREASE_RATING 137 - -#define ACTION_NEXT_SCENE 138 //!< switch to next scene/cutpoint in movie -#define ACTION_PREV_SCENE 139 //!< switch to previous scene/cutpoint in movie - -#define ACTION_NEXT_LETTER 140 //!< jump through a list or container by letter -#define ACTION_PREV_LETTER 141 - -#define ACTION_JUMP_SMS2 142 //!< jump direct to a particular letter using SMS-style input -#define ACTION_JUMP_SMS3 143 -#define ACTION_JUMP_SMS4 144 -#define ACTION_JUMP_SMS5 145 -#define ACTION_JUMP_SMS6 146 -#define ACTION_JUMP_SMS7 147 -#define ACTION_JUMP_SMS8 148 -#define ACTION_JUMP_SMS9 149 - -#define ACTION_FILTER_CLEAR 150 -#define ACTION_FILTER_SMS2 151 -#define ACTION_FILTER_SMS3 152 -#define ACTION_FILTER_SMS4 153 -#define ACTION_FILTER_SMS5 154 -#define ACTION_FILTER_SMS6 155 -#define ACTION_FILTER_SMS7 156 -#define ACTION_FILTER_SMS8 157 -#define ACTION_FILTER_SMS9 158 - -#define ACTION_FIRST_PAGE 159 -#define ACTION_LAST_PAGE 160 - -#define ACTION_AUDIO_DELAY 161 -#define ACTION_SUBTITLE_DELAY 162 -#define ACTION_MENU 163 - -#define ACTION_SET_RATING 164 - -#define ACTION_RECORD 170 - -#define ACTION_PASTE 180 -#define ACTION_NEXT_CONTROL 181 -#define ACTION_PREV_CONTROL 182 -#define ACTION_CHANNEL_SWITCH 183 -#define ACTION_CHANNEL_UP 184 -#define ACTION_CHANNEL_DOWN 185 -#define ACTION_NEXT_CHANNELGROUP 186 -#define ACTION_PREVIOUS_CHANNELGROUP 187 -#define ACTION_PVR_PLAY 188 -#define ACTION_PVR_PLAY_TV 189 -#define ACTION_PVR_PLAY_RADIO 190 -#define ACTION_PVR_SHOW_TIMER_RULE 191 - -#define ACTION_TOGGLE_FULLSCREEN 199 //!< switch 2 desktop resolution -#define ACTION_TOGGLE_WATCHED 200 //!< Toggle watched status (videos) -#define ACTION_SCAN_ITEM 201 //!< scan item -#define ACTION_TOGGLE_DIGITAL_ANALOG 202 //!< switch digital <-> analog -#define ACTION_RELOAD_KEYMAPS 203 //!< reloads CButtonTranslator's keymaps -#define ACTION_GUIPROFILE_BEGIN 204 //!< start the GUIControlProfiler running - -#define ACTION_TELETEXT_RED 215 //!< Teletext Color button <b>Red</b> to control TopText -#define ACTION_TELETEXT_GREEN 216 //!< Teletext Color button <b>Green</b> to control TopText -#define ACTION_TELETEXT_YELLOW 217 //!< Teletext Color button <b>Yellow</b> to control TopText -#define ACTION_TELETEXT_BLUE 218 //!< Teletext Color button <b>Blue</b> to control TopText - -#define ACTION_INCREASE_PAR 219 -#define ACTION_DECREASE_PAR 220 - -#define ACTION_VSHIFT_UP 227 //!< shift up video image in VideoPlayer -#define ACTION_VSHIFT_DOWN 228 //!< shift down video image in VideoPlayer - -#define ACTION_PLAYER_PLAYPAUSE 229 //!< Play/pause. If playing it pauses, if paused it plays. - -#define ACTION_SUBTITLE_VSHIFT_UP 230 //!< shift up subtitles in VideoPlayer -#define ACTION_SUBTITLE_VSHIFT_DOWN 231 //!< shift down subtitles in VideoPlayer -#define ACTION_SUBTITLE_ALIGN 232 //!< toggle vertical alignment of subtitles - -#define ACTION_FILTER 233 - -#define ACTION_SWITCH_PLAYER 234 - -#define ACTION_STEREOMODE_NEXT 235 -#define ACTION_STEREOMODE_PREVIOUS 236 -#define ACTION_STEREOMODE_TOGGLE 237 //!< turns 3d mode on/off -#define ACTION_STEREOMODE_SELECT 238 -#define ACTION_STEREOMODE_TOMONO 239 -#define ACTION_STEREOMODE_SET 240 - -#define ACTION_SETTINGS_RESET 241 -#define ACTION_SETTINGS_LEVEL_CHANGE 242 - -#define ACTION_TRIGGER_OSD 243 //!< show autoclosing OSD. Can b used in videoFullScreen.xml window id=2005 -#define ACTION_INPUT_TEXT 244 -#define ACTION_VOLUME_SET 245 -#define ACTION_TOGGLE_COMMSKIP 246 - -#define ACTION_TOUCH_TAP 401 //!< touch actions -#define ACTION_TOUCH_TAP_TEN 410 //!< touch actions -#define ACTION_TOUCH_LONGPRESS 411 //!< touch actions -#define ACTION_TOUCH_LONGPRESS_TEN 420 //!< touch actions - -#define ACTION_GESTURE_NOTIFY 500 -#define ACTION_GESTURE_BEGIN 501 -#define ACTION_GESTURE_ZOOM 502 //!< sendaction with point and currentPinchScale (fingers together < 1.0 -> fingers apart > 1.0) -#define ACTION_GESTURE_ROTATE 503 -#define ACTION_GESTURE_PAN 504 - -#define ACTION_GESTURE_SWIPE_LEFT 511 -#define ACTION_GESTURE_SWIPE_LEFT_TEN 520 -#define ACTION_GESTURE_SWIPE_RIGHT 521 -#define ACTION_GESTURE_SWIPE_RIGHT_TEN 530 -#define ACTION_GESTURE_SWIPE_UP 531 -#define ACTION_GESTURE_SWIPE_UP_TEN 540 -#define ACTION_GESTURE_SWIPE_DOWN 541 -#define ACTION_GESTURE_SWIPE_DOWN_TEN 550 -// 5xx is reserved for additional gesture actions -#define ACTION_GESTURE_END 599 - -// other, non-gesture actions -#define ACTION_ANALOG_MOVE_X 601 //!< analog thumbstick move, horizontal axis; see ACTION_ANALOG_MOVE -#define ACTION_ANALOG_MOVE_Y 602 //!< analog thumbstick move, vertical axis; see ACTION_ANALOG_MOVE -//@} - -// The NOOP action can be specified to disable an input event. This is -// useful in user keyboard.xml etc to disable actions specified in the -// system mappings. ERROR action is used to play an error sound -#define ACTION_ERROR 998 -#define ACTION_NOOP 999 - #define ICON_TYPE_NONE 101 #define ICON_TYPE_PROGRAMS 102 #define ICON_TYPE_MUSIC 103 @@ -432,93 +150,6 @@ #ifndef SWIG -class CKey; - -/*! - \ingroup actionkeys - \brief class encapsulating information regarding a particular user action to be sent to windows and controls - */ -class CAction -{ -public: - CAction(int actionID, float amount1 = 1.0f, float amount2 = 0.0f, const std::string &name = "", unsigned int holdTime = 0); - CAction(int actionID, wchar_t unicode); - CAction(int actionID, unsigned int state, float posX, float posY, float offsetX, float offsetY, const std::string &name = ""); - CAction(int actionID, const std::string &name, const CKey &key); - CAction(int actionID, const std::string &name); - - CAction(const CAction& other) { *this = other; } - CAction& operator=(const CAction& rhs); - - /*! \brief Identifier of the action - \return id of the action - */ - int GetID() const { return m_id; }; - - /*! \brief Is this an action from the mouse - \return true if this is a mouse action, false otherwise - */ - bool IsMouse() const { return (m_id >= ACTION_MOUSE_START && m_id <= ACTION_MOUSE_END); }; - - bool IsGesture() const { return (m_id >= ACTION_GESTURE_NOTIFY && m_id <= ACTION_GESTURE_END); }; - - /*! \brief Human-readable name of the action - \return name of the action - */ - const std::string &GetName() const { return m_name; }; - - /*! \brief Text of the action if any - \return text payload of this action. - */ - const std::string &GetText() const { return m_text; }; - - /*! \brief Set the text payload of the action - \param text to be set - */ - void SetText(const std::string &text) { m_text = text; }; - - /*! \brief Get an amount associated with this action - \param zero-based index of amount to retrieve, defaults to 0 - \return an amount associated with this action - */ - float GetAmount(unsigned int index = 0) const { return (index < max_amounts) ? m_amount[index] : 0; }; - - /*! \brief Unicode value associated with this action - \return unicode value associated with this action, for keyboard input. - */ - wchar_t GetUnicode() const { return m_unicode; }; - - /*! \brief Time in ms that the key has been held - \return time that the key has been held down in ms. - */ - unsigned int GetHoldTime() const { return m_holdTime; }; - - /*! \brief Time since last repeat in ms - \return time since last repeat in ms. Returns 0 if unknown. - */ - float GetRepeat() const { return m_repeat; }; - - /*! \brief Button code that triggered this action - \return button code - */ - unsigned int GetButtonCode() const { return m_buttonCode; }; - - bool IsAnalog() const; - -private: - int m_id; - std::string m_name; - - static const unsigned int max_amounts = 4; // Must be at least 4. - float m_amount[max_amounts]; - - float m_repeat; - unsigned int m_holdTime; - unsigned int m_buttonCode; - wchar_t m_unicode; - std::string m_text; -}; - /*! \ingroup actionkeys, mouse \brief Simple class for mouse events diff --git a/xbmc/input/joysticks/DeadzoneFilter.cpp b/xbmc/input/joysticks/DeadzoneFilter.cpp index 0bf30738d0..988c36a539 100644 --- a/xbmc/input/joysticks/DeadzoneFilter.cpp +++ b/xbmc/input/joysticks/DeadzoneFilter.cpp @@ -27,6 +27,7 @@ #include <cmath> #include <vector> +using namespace KODI; using namespace JOYSTICK; #define AXIS_EPSILON 0.01f // Allowed noise for detecting discrete D-pads (value of 0.007 when centered has been observed) diff --git a/xbmc/input/joysticks/DeadzoneFilter.h b/xbmc/input/joysticks/DeadzoneFilter.h index 750ef4ed44..403bffdc59 100644 --- a/xbmc/input/joysticks/DeadzoneFilter.h +++ b/xbmc/input/joysticks/DeadzoneFilter.h @@ -24,6 +24,8 @@ namespace PERIPHERALS class CPeripheral; } +namespace KODI +{ namespace JOYSTICK { class IButtonMap; @@ -85,3 +87,4 @@ namespace JOYSTICK PERIPHERALS::CPeripheral* const m_peripheral; }; } +} diff --git a/xbmc/input/joysticks/DefaultJoystick.cpp b/xbmc/input/joysticks/DefaultJoystick.cpp index d474023850..70ef187c78 100644 --- a/xbmc/input/joysticks/DefaultJoystick.cpp +++ b/xbmc/input/joysticks/DefaultJoystick.cpp @@ -31,6 +31,7 @@ #define ANALOG_DIGITAL_THRESHOLD 0.5f +using namespace KODI; using namespace JOYSTICK; CDefaultJoystick::CDefaultJoystick(void) : diff --git a/xbmc/input/joysticks/DefaultJoystick.h b/xbmc/input/joysticks/DefaultJoystick.h index 0c22e14a2c..77a2720b75 100644 --- a/xbmc/input/joysticks/DefaultJoystick.h +++ b/xbmc/input/joysticks/DefaultJoystick.h @@ -34,6 +34,8 @@ #define DEFAULT_LEFT_STICK_NAME "leftstick" #define DEFAULT_RIGHT_STICK_NAME "rightstick" +namespace KODI +{ namespace JOYSTICK { class IKeymapHandler; @@ -105,3 +107,4 @@ namespace JOYSTICK std::unique_ptr<IButtonSequence> m_easterEgg; }; } +} diff --git a/xbmc/input/joysticks/DriverPrimitive.cpp b/xbmc/input/joysticks/DriverPrimitive.cpp index 1a222acb20..9766f3594a 100644 --- a/xbmc/input/joysticks/DriverPrimitive.cpp +++ b/xbmc/input/joysticks/DriverPrimitive.cpp @@ -20,6 +20,7 @@ #include "DriverPrimitive.h" +using namespace KODI; using namespace JOYSTICK; CDriverPrimitive::CDriverPrimitive(void) diff --git a/xbmc/input/joysticks/DriverPrimitive.h b/xbmc/input/joysticks/DriverPrimitive.h index 736b33dd3a..7354853a29 100644 --- a/xbmc/input/joysticks/DriverPrimitive.h +++ b/xbmc/input/joysticks/DriverPrimitive.h @@ -23,6 +23,8 @@ #include <stdint.h> +namespace KODI +{ namespace JOYSTICK { /*! @@ -146,3 +148,4 @@ namespace JOYSTICK unsigned int m_range; }; } +} diff --git a/xbmc/input/joysticks/IActionMap.h b/xbmc/input/joysticks/IActionMap.h index 5fc5c9fc2f..3c9ceb77ec 100644 --- a/xbmc/input/joysticks/IActionMap.h +++ b/xbmc/input/joysticks/IActionMap.h @@ -22,6 +22,8 @@ #include "JoystickTypes.h" #include "input/Key.h" +namespace KODI +{ namespace JOYSTICK { class CDriverPrimitive; @@ -55,3 +57,4 @@ namespace JOYSTICK virtual int GetActionID(const FeatureName& feature) = 0; }; } +} diff --git a/xbmc/input/joysticks/IButtonMap.h b/xbmc/input/joysticks/IButtonMap.h index 4fc109e327..5e3d4157de 100644 --- a/xbmc/input/joysticks/IButtonMap.h +++ b/xbmc/input/joysticks/IButtonMap.h @@ -25,6 +25,8 @@ #include <string> #include <vector> +namespace KODI +{ namespace JOYSTICK { /*! @@ -248,3 +250,4 @@ namespace JOYSTICK virtual void RevertButtonMap() = 0; }; } +} diff --git a/xbmc/input/joysticks/IButtonMapCallback.h b/xbmc/input/joysticks/IButtonMapCallback.h index 4d22f91ba4..c71c99281d 100644 --- a/xbmc/input/joysticks/IButtonMapCallback.h +++ b/xbmc/input/joysticks/IButtonMapCallback.h @@ -19,6 +19,8 @@ */ #pragma once +namespace KODI +{ namespace JOYSTICK { /*! @@ -53,3 +55,4 @@ namespace JOYSTICK virtual void RevertButtonMap() = 0; }; } +} diff --git a/xbmc/input/joysticks/IButtonMapper.h b/xbmc/input/joysticks/IButtonMapper.h index 9cbd199224..855f76b108 100644 --- a/xbmc/input/joysticks/IButtonMapper.h +++ b/xbmc/input/joysticks/IButtonMapper.h @@ -22,6 +22,8 @@ #include <map> #include <string> +namespace KODI +{ namespace JOYSTICK { class CDriverPrimitive; @@ -109,6 +111,17 @@ namespace JOYSTICK */ virtual void OnEventFrame(const IButtonMap* buttonMap, bool bMotion) = 0; + /*! + * \brief Called when an axis has been detected after mapping began + * + * \param axisIndex The index of the axis being discovered + * + * Some joystick drivers don't report an initial value for analog axes. + * + * Called in the same thread as \ref IButtonMapper::MapPrimitive. + */ + virtual void OnLateAxis(const IButtonMap* buttonMap, unsigned int axisIndex) = 0; + // Button map callback interface void SetButtonMapCallback(const std::string& deviceName, IButtonMapCallback* callback) { m_callbacks[deviceName] = callback; } void ResetButtonMapCallbacks(void) { m_callbacks.clear(); } @@ -118,3 +131,4 @@ namespace JOYSTICK std::map<std::string, IButtonMapCallback*> m_callbacks; }; } +} diff --git a/xbmc/input/joysticks/IButtonSequence.h b/xbmc/input/joysticks/IButtonSequence.h index d2646582e4..31b64c4e5b 100644 --- a/xbmc/input/joysticks/IButtonSequence.h +++ b/xbmc/input/joysticks/IButtonSequence.h @@ -21,6 +21,8 @@ #include "JoystickTypes.h" +namespace KODI +{ namespace JOYSTICK { class IButtonSequence @@ -31,3 +33,4 @@ namespace JOYSTICK virtual bool OnButtonPress(const FeatureName& feature) = 0; }; } +} diff --git a/xbmc/input/joysticks/IDriverHandler.h b/xbmc/input/joysticks/IDriverHandler.h index b58a921ff7..5843b868d6 100644 --- a/xbmc/input/joysticks/IDriverHandler.h +++ b/xbmc/input/joysticks/IDriverHandler.h @@ -21,6 +21,8 @@ #include "JoystickTypes.h" +namespace KODI +{ namespace JOYSTICK { /*! @@ -80,3 +82,4 @@ namespace JOYSTICK virtual void ProcessAxisMotions(void) = 0; }; } +} diff --git a/xbmc/input/joysticks/IDriverReceiver.h b/xbmc/input/joysticks/IDriverReceiver.h index df181ea838..0255a7b752 100644 --- a/xbmc/input/joysticks/IDriverReceiver.h +++ b/xbmc/input/joysticks/IDriverReceiver.h @@ -19,6 +19,8 @@ */ #pragma once +namespace KODI +{ namespace JOYSTICK { /*! @@ -41,3 +43,4 @@ namespace JOYSTICK virtual bool SetMotorState(unsigned int motorIndex, float magnitude) = 0; }; } +} diff --git a/xbmc/input/joysticks/IInputHandler.h b/xbmc/input/joysticks/IInputHandler.h index 44629f5c52..9b6795f921 100644 --- a/xbmc/input/joysticks/IInputHandler.h +++ b/xbmc/input/joysticks/IInputHandler.h @@ -23,6 +23,8 @@ #include <string> +namespace KODI +{ namespace JOYSTICK { class IInputReceiver; @@ -133,3 +135,4 @@ namespace JOYSTICK IInputReceiver* m_receiver; }; } +} diff --git a/xbmc/input/joysticks/IInputReceiver.h b/xbmc/input/joysticks/IInputReceiver.h index 182e27ab0b..2292ce87a2 100644 --- a/xbmc/input/joysticks/IInputReceiver.h +++ b/xbmc/input/joysticks/IInputReceiver.h @@ -21,6 +21,8 @@ #include "JoystickTypes.h" +namespace KODI +{ namespace JOYSTICK { /*! @@ -43,3 +45,4 @@ namespace JOYSTICK virtual bool SetRumbleState(const FeatureName& feature, float magnitude) = 0; }; } +} diff --git a/xbmc/input/joysticks/IKeymapHandler.h b/xbmc/input/joysticks/IKeymapHandler.h index 83e21c6666..efdbdb367f 100644 --- a/xbmc/input/joysticks/IKeymapHandler.h +++ b/xbmc/input/joysticks/IKeymapHandler.h @@ -21,6 +21,8 @@ #include "JoystickTypes.h" +namespace KODI +{ namespace JOYSTICK { /*! @@ -75,3 +77,4 @@ namespace JOYSTICK virtual void OnAnalogKey(unsigned int buttonKeyId, float magnitude) = 0; }; } +} diff --git a/xbmc/input/joysticks/JoystickEasterEgg.cpp b/xbmc/input/joysticks/JoystickEasterEgg.cpp index d50b79edab..aea96fc390 100644 --- a/xbmc/input/joysticks/JoystickEasterEgg.cpp +++ b/xbmc/input/joysticks/JoystickEasterEgg.cpp @@ -24,6 +24,7 @@ #include "guilib/WindowIDs.h" #include "settings/Settings.h" +using namespace KODI; using namespace JOYSTICK; std::vector<FeatureName> CJoystickEasterEgg::m_sequence = { diff --git a/xbmc/input/joysticks/JoystickEasterEgg.h b/xbmc/input/joysticks/JoystickEasterEgg.h index fe239fcec7..78e1fe978e 100644 --- a/xbmc/input/joysticks/JoystickEasterEgg.h +++ b/xbmc/input/joysticks/JoystickEasterEgg.h @@ -23,6 +23,8 @@ #include <vector> +namespace KODI +{ namespace JOYSTICK { /*! @@ -45,3 +47,4 @@ namespace JOYSTICK unsigned int m_state; }; } +} diff --git a/xbmc/input/joysticks/JoystickMonitor.cpp b/xbmc/input/joysticks/JoystickMonitor.cpp index ee081bea4d..3aef3c8442 100644 --- a/xbmc/input/joysticks/JoystickMonitor.cpp +++ b/xbmc/input/joysticks/JoystickMonitor.cpp @@ -22,6 +22,7 @@ #include "Application.h" #include "input/InputManager.h" +using namespace KODI; using namespace JOYSTICK; bool CJoystickMonitor::OnButtonMotion(unsigned int buttonIndex, bool bPressed) diff --git a/xbmc/input/joysticks/JoystickMonitor.h b/xbmc/input/joysticks/JoystickMonitor.h index 6409ea0544..912d2039a0 100644 --- a/xbmc/input/joysticks/JoystickMonitor.h +++ b/xbmc/input/joysticks/JoystickMonitor.h @@ -21,6 +21,8 @@ #include "IDriverHandler.h" +namespace KODI +{ namespace JOYSTICK { /*! @@ -45,3 +47,4 @@ namespace JOYSTICK bool ResetTimers(void); }; } +} diff --git a/xbmc/input/joysticks/JoystickTranslator.cpp b/xbmc/input/joysticks/JoystickTranslator.cpp index e1f76a9f26..80e932efbc 100644 --- a/xbmc/input/joysticks/JoystickTranslator.cpp +++ b/xbmc/input/joysticks/JoystickTranslator.cpp @@ -19,7 +19,11 @@ */ #include "JoystickTranslator.h" +#include "guilib/LocalizeStrings.h" +#include "input/joysticks/DriverPrimitive.h" +#include "utils/StringUtils.h" +using namespace KODI; using namespace JOYSTICK; const char* CJoystickTranslator::HatStateToString(HAT_STATE state) @@ -59,3 +63,21 @@ ANALOG_STICK_DIRECTION CJoystickTranslator::VectorToAnalogStickDirection(float x return ANALOG_STICK_DIRECTION::UNKNOWN; } + +std::string CJoystickTranslator::GetPrimitiveName(const CDriverPrimitive& primitive) +{ + std::string primitiveTemplate; + + switch (primitive.Type()) + { + case PRIMITIVE_TYPE::BUTTON: + primitiveTemplate = g_localizeStrings.Get(35015); // "Button %d" + break; + case PRIMITIVE_TYPE::SEMIAXIS: + primitiveTemplate = g_localizeStrings.Get(35016); // "Axis %d" + break; + default: break; + } + + return StringUtils::Format(primitiveTemplate.c_str(), primitive.Index()); +} diff --git a/xbmc/input/joysticks/JoystickTranslator.h b/xbmc/input/joysticks/JoystickTranslator.h index 2c26e54416..e6a5f0ce44 100644 --- a/xbmc/input/joysticks/JoystickTranslator.h +++ b/xbmc/input/joysticks/JoystickTranslator.h @@ -21,8 +21,12 @@ #include "JoystickTypes.h" +namespace KODI +{ namespace JOYSTICK { + class CDriverPrimitive; + /*! * \brief Joystick translation utilities */ @@ -60,5 +64,15 @@ namespace JOYSTICK * ANALOG_STICK_DIRECTION::UNKNOWN if x and y are both 0 */ static ANALOG_STICK_DIRECTION VectorToAnalogStickDirection(float x, float y); + + /*! + * \brief Get the localized name of the primitive + * + * \param primitive The primitive, currently only buttons and axes are supported + * + * \return A title for the primitive, e.g. "Button 0" or "Axis 1" + */ + static std::string GetPrimitiveName(const CDriverPrimitive& primitive); }; } +} diff --git a/xbmc/input/joysticks/JoystickTypes.h b/xbmc/input/joysticks/JoystickTypes.h index a01a8881d1..7a56bae039 100644 --- a/xbmc/input/joysticks/JoystickTypes.h +++ b/xbmc/input/joysticks/JoystickTypes.h @@ -26,6 +26,8 @@ #include <string> +namespace KODI +{ namespace JOYSTICK { /*! @@ -137,3 +139,4 @@ namespace JOYSTICK MOTOR, // a rumble motor }; } +} diff --git a/xbmc/input/joysticks/JoystickUtils.h b/xbmc/input/joysticks/JoystickUtils.h index 88bf9e4f4d..665e75673e 100644 --- a/xbmc/input/joysticks/JoystickUtils.h +++ b/xbmc/input/joysticks/JoystickUtils.h @@ -24,29 +24,37 @@ /// \ingroup joystick /// \{ -inline JOYSTICK::HAT_DIRECTION& operator|=(JOYSTICK::HAT_DIRECTION& lhs, JOYSTICK::HAT_DIRECTION rhs) +namespace KODI { - return lhs = static_cast<JOYSTICK::HAT_DIRECTION>(static_cast<int>(lhs) | static_cast<int>(rhs)); +namespace JOYSTICK +{ + +inline HAT_DIRECTION& operator|=(HAT_DIRECTION& lhs, HAT_DIRECTION rhs) +{ + return lhs = static_cast<HAT_DIRECTION>(static_cast<int>(lhs) | static_cast<int>(rhs)); } -inline JOYSTICK::HAT_STATE& operator|=(JOYSTICK::HAT_STATE& lhs, JOYSTICK::HAT_STATE rhs) +inline HAT_STATE& operator|=(HAT_STATE& lhs, HAT_STATE rhs) { - return lhs = static_cast<JOYSTICK::HAT_STATE>(static_cast<int>(lhs) | static_cast<int>(rhs)); + return lhs = static_cast<HAT_STATE>(static_cast<int>(lhs) | static_cast<int>(rhs)); } -inline bool operator&(JOYSTICK::HAT_STATE lhs, JOYSTICK::HAT_DIRECTION rhs) +inline bool operator&(HAT_STATE lhs, HAT_DIRECTION rhs) { return (static_cast<int>(lhs) & static_cast<int>(rhs)) ? true : false; } -inline JOYSTICK::SEMIAXIS_DIRECTION operator*(JOYSTICK::SEMIAXIS_DIRECTION lhs, int rhs) +inline SEMIAXIS_DIRECTION operator*(SEMIAXIS_DIRECTION lhs, int rhs) { - return static_cast<JOYSTICK::SEMIAXIS_DIRECTION>(static_cast<int>(lhs) * rhs); + return static_cast<SEMIAXIS_DIRECTION>(static_cast<int>(lhs) * rhs); } -inline float operator*(float lhs, JOYSTICK::SEMIAXIS_DIRECTION rhs) +inline float operator*(float lhs, SEMIAXIS_DIRECTION rhs) { return lhs * static_cast<int>(rhs); } +} +} + /// \} diff --git a/xbmc/input/joysticks/KeymapHandler.cpp b/xbmc/input/joysticks/KeymapHandler.cpp index ca14cc5da8..b0fb082774 100644 --- a/xbmc/input/joysticks/KeymapHandler.cpp +++ b/xbmc/input/joysticks/KeymapHandler.cpp @@ -28,13 +28,11 @@ #include <algorithm> using namespace KODI; -using namespace MESSAGING; +using namespace JOYSTICK; #define HOLD_TIMEOUT_MS 500 #define REPEAT_TIMEOUT_MS 50 -using namespace JOYSTICK; - CKeymapHandler::CKeymapHandler(void) : m_lastButtonPress(0), m_lastDigitalActionMs(0) diff --git a/xbmc/input/joysticks/KeymapHandler.h b/xbmc/input/joysticks/KeymapHandler.h index 39dbbf14db..13dd940743 100644 --- a/xbmc/input/joysticks/KeymapHandler.h +++ b/xbmc/input/joysticks/KeymapHandler.h @@ -23,6 +23,8 @@ #include <vector> +namespace KODI +{ namespace JOYSTICK { /*! @@ -61,3 +63,4 @@ namespace JOYSTICK std::vector<unsigned int> m_pressedButtons; }; } +} diff --git a/xbmc/input/joysticks/RumbleGenerator.cpp b/xbmc/input/joysticks/RumbleGenerator.cpp index a45bf5dbea..894d056f3f 100644 --- a/xbmc/input/joysticks/RumbleGenerator.cpp +++ b/xbmc/input/joysticks/RumbleGenerator.cpp @@ -33,6 +33,7 @@ // From game.controller.default profile #define WEAK_MOTOR_NAME "rightmotor" +using namespace KODI; using namespace JOYSTICK; CRumbleGenerator::CRumbleGenerator(const std::string& controllerId) : @@ -130,7 +131,7 @@ std::vector<std::string> CRumbleGenerator::GetMotors(const std::string& controll { for (const CControllerFeature& feature : controller->Layout().Features()) { - if (feature.Type() == JOYSTICK::FEATURE_TYPE::MOTOR) + if (feature.Type() == FEATURE_TYPE::MOTOR) motors.push_back(feature.Name()); } } diff --git a/xbmc/input/joysticks/RumbleGenerator.h b/xbmc/input/joysticks/RumbleGenerator.h index c3431bd0eb..26474c4cf7 100644 --- a/xbmc/input/joysticks/RumbleGenerator.h +++ b/xbmc/input/joysticks/RumbleGenerator.h @@ -21,6 +21,8 @@ #include "threads/Thread.h" +namespace KODI +{ namespace JOYSTICK { class IInputReceiver; @@ -59,3 +61,4 @@ namespace JOYSTICK RUMBLE_TYPE m_type; }; } +} diff --git a/xbmc/input/joysticks/dialogs/GUIDialogNewJoystick.cpp b/xbmc/input/joysticks/dialogs/GUIDialogNewJoystick.cpp index 6223eb3c5e..d0b42d9dae 100644 --- a/xbmc/input/joysticks/dialogs/GUIDialogNewJoystick.cpp +++ b/xbmc/input/joysticks/dialogs/GUIDialogNewJoystick.cpp @@ -25,6 +25,7 @@ #include "messaging/helpers/DialogHelper.h" #include "settings/Settings.h" +using namespace KODI; using namespace JOYSTICK; CGUIDialogNewJoystick::CGUIDialogNewJoystick() : @@ -49,7 +50,7 @@ void CGUIDialogNewJoystick::ShowAsync() void CGUIDialogNewJoystick::Process() { - using namespace KODI::MESSAGING::HELPERS; + using namespace MESSAGING::HELPERS; // "New controller detected" // "A new controller has been detected. Configuration can be done at any time in "Settings -> System Settings -> Input". Would you like to configure it now?" diff --git a/xbmc/input/joysticks/dialogs/GUIDialogNewJoystick.h b/xbmc/input/joysticks/dialogs/GUIDialogNewJoystick.h index b44ba37dfb..71bff72aec 100644 --- a/xbmc/input/joysticks/dialogs/GUIDialogNewJoystick.h +++ b/xbmc/input/joysticks/dialogs/GUIDialogNewJoystick.h @@ -21,6 +21,8 @@ #include "threads/Thread.h" +namespace KODI +{ namespace JOYSTICK { class CGUIDialogNewJoystick : protected CThread @@ -36,3 +38,4 @@ namespace JOYSTICK virtual void Process() override; }; } +} diff --git a/xbmc/input/joysticks/generic/ButtonMapping.cpp b/xbmc/input/joysticks/generic/ButtonMapping.cpp index b5c6b23949..9b74ff52c0 100644 --- a/xbmc/input/joysticks/generic/ButtonMapping.cpp +++ b/xbmc/input/joysticks/generic/ButtonMapping.cpp @@ -36,6 +36,7 @@ #include <assert.h> #include <cmath> +using namespace KODI; using namespace JOYSTICK; using namespace XbmcThreads; @@ -185,6 +186,12 @@ void CAxisDetector::SetEmitted(const CDriverPrimitive& activePrimitive) void CAxisDetector::DetectType(float position) { + // Some platforms don't report a value until the axis is first changed. + // Detection relies on an initial value, so this axis will be disabled until + // the user begins button mapping again. + if (m_config.bLateDiscovery) + return; + // Update range if a range of > 1 is observed if (std::abs(position - m_config.center) > 1.0f) m_config.range = 2; @@ -241,7 +248,8 @@ CButtonMapping::CButtonMapping(IButtonMapper* buttonMapper, IButtonMap* buttonMa m_buttonMapper(buttonMapper), m_buttonMap(buttonMap), m_actionMap(actionMap), - m_lastAction(0) + m_lastAction(0), + m_frameCount(0) { assert(m_buttonMapper != nullptr); assert(m_buttonMap != nullptr); @@ -274,7 +282,7 @@ CButtonMapping::CButtonMapping(IButtonMapper* buttonMapper, IButtonMap* buttonMa axisConfig.center = primitive.Center(); axisConfig.range = primitive.Range(); - GetAxis(primitive.Index(), axisConfig).SetEmitted(primitive); + GetAxis(primitive.Index(), primitive.Center(), axisConfig).SetEmitted(primitive); } } } @@ -291,7 +299,7 @@ bool CButtonMapping::OnHatMotion(unsigned int hatIndex, HAT_STATE state) bool CButtonMapping::OnAxisMotion(unsigned int axisIndex, float position, int center, unsigned int range) { - return GetAxis(axisIndex).OnMotion(position); + return GetAxis(axisIndex, position).OnMotion(position); } void CButtonMapping::ProcessAxisMotions(void) @@ -300,6 +308,8 @@ void CButtonMapping::ProcessAxisMotions(void) axis.second.ProcessMotion(); m_buttonMapper->OnEventFrame(m_buttonMap, IsMapping()); + + m_frameCount++; } void CButtonMapping::SaveButtonMap() @@ -389,15 +399,33 @@ CHatDetector& CButtonMapping::GetHat(unsigned int hatIndex) } CAxisDetector& CButtonMapping::GetAxis(unsigned int axisIndex, + float position, const AxisConfiguration& initialConfig /* = AxisConfiguration() */) { auto itAxis = m_axes.find(axisIndex); if (itAxis == m_axes.end()) { - m_axes.insert(std::make_pair(axisIndex, CAxisDetector(this, axisIndex, initialConfig))); + AxisConfiguration config(initialConfig); + + if (m_frameCount >= 2) + { + config.bLateDiscovery = true; + OnLateDiscovery(axisIndex); + } + + // Report axis + CLog::Log(LOGDEBUG, "Axis %u discovered at position %.04f after %lu frames", + axisIndex, position, static_cast<unsigned long>(m_frameCount)); + + m_axes.insert(std::make_pair(axisIndex, CAxisDetector(this, axisIndex, config))); itAxis = m_axes.find(axisIndex); } return itAxis->second; } + +void CButtonMapping::OnLateDiscovery(unsigned int axisIndex) +{ + m_buttonMapper->OnLateAxis(m_buttonMap, axisIndex); +} diff --git a/xbmc/input/joysticks/generic/ButtonMapping.h b/xbmc/input/joysticks/generic/ButtonMapping.h index e75de46c59..5961483977 100644 --- a/xbmc/input/joysticks/generic/ButtonMapping.h +++ b/xbmc/input/joysticks/generic/ButtonMapping.h @@ -24,7 +24,10 @@ #include "input/joysticks/IDriverHandler.h" #include <map> +#include <stdint.h> +namespace KODI +{ namespace JOYSTICK { class CButtonMapping; @@ -75,6 +78,7 @@ namespace JOYSTICK bool bKnown = false; int center = 0; unsigned int range = 1; + bool bLateDiscovery = false; }; class CAxisDetector @@ -240,9 +244,11 @@ namespace JOYSTICK private: bool IsMapping() const; + void OnLateDiscovery(unsigned int axisIndex); + CButtonDetector& GetButton(unsigned int buttonIndex); CHatDetector& GetHat(unsigned int hatIndex); - CAxisDetector& GetAxis(unsigned int axisIndex, const AxisConfiguration& initialConfig = AxisConfiguration()); + CAxisDetector& GetAxis(unsigned int axisIndex, float position, const AxisConfiguration& initialConfig = AxisConfiguration()); // Construction parameters IButtonMapper* const m_buttonMapper; @@ -252,6 +258,8 @@ namespace JOYSTICK std::map<unsigned int, CButtonDetector> m_buttons; std::map<unsigned int, CHatDetector> m_hats; std::map<unsigned int, CAxisDetector> m_axes; - unsigned int m_lastAction; + unsigned int m_lastAction; + uint64_t m_frameCount; }; } +} diff --git a/xbmc/input/joysticks/generic/DriverReceiving.cpp b/xbmc/input/joysticks/generic/DriverReceiving.cpp index d44eabd1c0..beb6bb9ea6 100644 --- a/xbmc/input/joysticks/generic/DriverReceiving.cpp +++ b/xbmc/input/joysticks/generic/DriverReceiving.cpp @@ -23,6 +23,7 @@ #include "input/joysticks/IButtonMap.h" #include "input/joysticks/IDriverReceiver.h" +using namespace KODI; using namespace JOYSTICK; CDriverReceiving::CDriverReceiving(IDriverReceiver* receiver, IButtonMap* buttonMap) diff --git a/xbmc/input/joysticks/generic/DriverReceiving.h b/xbmc/input/joysticks/generic/DriverReceiving.h index b35cfc442e..bfadfa5397 100644 --- a/xbmc/input/joysticks/generic/DriverReceiving.h +++ b/xbmc/input/joysticks/generic/DriverReceiving.h @@ -24,6 +24,8 @@ #include <map> +namespace KODI +{ namespace JOYSTICK { class IDriverReceiver; @@ -52,3 +54,4 @@ namespace JOYSTICK IButtonMap* const m_buttonMap; }; } +} diff --git a/xbmc/input/joysticks/generic/FeatureHandling.cpp b/xbmc/input/joysticks/generic/FeatureHandling.cpp index 850dd871ea..24a4b35d67 100644 --- a/xbmc/input/joysticks/generic/FeatureHandling.cpp +++ b/xbmc/input/joysticks/generic/FeatureHandling.cpp @@ -27,6 +27,7 @@ #include <vector> +using namespace KODI; using namespace JOYSTICK; #define ANALOG_DIGITAL_THRESHOLD 0.5f diff --git a/xbmc/input/joysticks/generic/FeatureHandling.h b/xbmc/input/joysticks/generic/FeatureHandling.h index 52d992be01..3d276771c0 100644 --- a/xbmc/input/joysticks/generic/FeatureHandling.h +++ b/xbmc/input/joysticks/generic/FeatureHandling.h @@ -23,6 +23,8 @@ #include <memory> +namespace KODI +{ namespace JOYSTICK { class CDriverPrimitive; @@ -225,3 +227,4 @@ namespace JOYSTICK float m_zAxisState; }; } +} diff --git a/xbmc/input/joysticks/generic/InputHandling.cpp b/xbmc/input/joysticks/generic/InputHandling.cpp index 94f93c5a39..98ec01f3a5 100644 --- a/xbmc/input/joysticks/generic/InputHandling.cpp +++ b/xbmc/input/joysticks/generic/InputHandling.cpp @@ -28,6 +28,7 @@ #include <array> #include <cmath> +using namespace KODI; using namespace JOYSTICK; CGUIDialogNewJoystick* const CInputHandling::m_dialog = new CGUIDialogNewJoystick; diff --git a/xbmc/input/joysticks/generic/InputHandling.h b/xbmc/input/joysticks/generic/InputHandling.h index dd6e82733e..2a0f2453f0 100644 --- a/xbmc/input/joysticks/generic/InputHandling.h +++ b/xbmc/input/joysticks/generic/InputHandling.h @@ -25,6 +25,8 @@ #include <map> +namespace KODI +{ namespace JOYSTICK { class CDriverPrimitive; @@ -72,3 +74,4 @@ namespace JOYSTICK static CGUIDialogNewJoystick* const m_dialog; }; } +} diff --git a/xbmc/input/keyboard/CMakeLists.txt b/xbmc/input/keyboard/CMakeLists.txt index ed121ac30a..69d84b8d3a 100644 --- a/xbmc/input/keyboard/CMakeLists.txt +++ b/xbmc/input/keyboard/CMakeLists.txt @@ -1,6 +1,11 @@ -set(SOURCES KeyboardEasterEgg.cpp) +set(SOURCES KeyboardEasterEgg.cpp + KeymapActionMap.cpp +) -set(HEADERS IKeyboardHandler.h - KeyboardEasterEgg.h) +set(HEADERS IActionMap.h + IKeyboardHandler.h + KeyboardEasterEgg.h + KeymapActionMap.h +) core_add_library(input_keyboard) diff --git a/xbmc/input/keyboard/IActionMap.h b/xbmc/input/keyboard/IActionMap.h new file mode 100644 index 0000000000..ae89742d41 --- /dev/null +++ b/xbmc/input/keyboard/IActionMap.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2017 Team Kodi + * http://kodi.tv + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this Program; see the file COPYING. If not, see + * <http://www.gnu.org/licenses/>. + * + */ +#pragma once + +class CKey; + +namespace KODI +{ +namespace KEYBOARD +{ + /*! + * \brief Interface for translating keys to action IDs + */ + class IActionMap + { + public: + virtual ~IActionMap() = default; + + /*! + * \brief Get the action ID mapped to the specified key + * + * \param key The key to look up + * + * \return The action ID from Action.h, or ACTION_NONE if no action is + * mapped to the specified key + */ + virtual unsigned int GetActionID(const CKey& key) = 0; + }; +} +} diff --git a/xbmc/input/keyboard/IKeyboardHandler.h b/xbmc/input/keyboard/IKeyboardHandler.h index 5958aac650..b19712bbc1 100644 --- a/xbmc/input/keyboard/IKeyboardHandler.h +++ b/xbmc/input/keyboard/IKeyboardHandler.h @@ -21,6 +21,8 @@ class CKey; +namespace KODI +{ namespace KEYBOARD { /*! @@ -49,3 +51,4 @@ namespace KEYBOARD virtual void OnKeyRelease(const CKey& key) = 0; }; } +} diff --git a/xbmc/input/keyboard/KeyboardEasterEgg.cpp b/xbmc/input/keyboard/KeyboardEasterEgg.cpp index a2f089256c..c9fd7179b9 100644 --- a/xbmc/input/keyboard/KeyboardEasterEgg.cpp +++ b/xbmc/input/keyboard/KeyboardEasterEgg.cpp @@ -22,6 +22,7 @@ #include "input/joysticks/JoystickEasterEgg.h" #include "input/Key.h" +using namespace KODI; using namespace KEYBOARD; std::vector<XBMCVKey> CKeyboardEasterEgg::m_sequence = { diff --git a/xbmc/input/keyboard/KeyboardEasterEgg.h b/xbmc/input/keyboard/KeyboardEasterEgg.h index 7d3888644c..e98187be26 100644 --- a/xbmc/input/keyboard/KeyboardEasterEgg.h +++ b/xbmc/input/keyboard/KeyboardEasterEgg.h @@ -24,6 +24,8 @@ #include <vector> +namespace KODI +{ namespace KEYBOARD { /*! @@ -45,3 +47,4 @@ namespace KEYBOARD unsigned int m_state; }; } +} diff --git a/xbmc/input/keyboard/KeymapActionMap.cpp b/xbmc/input/keyboard/KeymapActionMap.cpp new file mode 100644 index 0000000000..41fe927186 --- /dev/null +++ b/xbmc/input/keyboard/KeymapActionMap.cpp @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2017 Team Kodi + * http://kodi.tv + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this Program; see the file COPYING. If not, see + * <http://www.gnu.org/licenses/>. + * + */ + +#include "KeymapActionMap.h" +#include "guilib/GUIWindowManager.h" +#include "input/Action.h" +#include "input/ButtonTranslator.h" +#include "input/Key.h" + +using namespace KODI; +using namespace KEYBOARD; + +unsigned int CKeymapActionMap::GetActionID(const CKey& key) +{ + CAction action = CButtonTranslator::GetInstance().GetAction(g_windowManager.GetActiveWindowID(), key); + return action.GetID(); +} diff --git a/xbmc/input/keyboard/KeymapActionMap.h b/xbmc/input/keyboard/KeymapActionMap.h new file mode 100644 index 0000000000..8f67cc8686 --- /dev/null +++ b/xbmc/input/keyboard/KeymapActionMap.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2017 Team Kodi + * http://kodi.tv + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this Program; see the file COPYING. If not, see + * <http://www.gnu.org/licenses/>. + * + */ +#pragma once + +#include "input/keyboard/IActionMap.h" + +namespace KODI +{ +namespace KEYBOARD +{ + class CKeymapActionMap : public IActionMap + { + public: + CKeymapActionMap(void) = default; + + virtual ~CKeymapActionMap(void) = default; + + // implementation of IActionMap + virtual unsigned int GetActionID(const CKey& key) override; + }; +} +} diff --git a/xbmc/input/keyboard/generic/JoystickEmulation.cpp b/xbmc/input/keyboard/generic/JoystickEmulation.cpp index de4ce1850f..f292b2b5fd 100644 --- a/xbmc/input/keyboard/generic/JoystickEmulation.cpp +++ b/xbmc/input/keyboard/generic/JoystickEmulation.cpp @@ -27,6 +27,7 @@ #define BUTTON_INDEX_MASK 0x01ff +using namespace KODI; using namespace KEYBOARD; CJoystickEmulation::CJoystickEmulation(JOYSTICK::IDriverHandler* handler) : diff --git a/xbmc/input/keyboard/generic/JoystickEmulation.h b/xbmc/input/keyboard/generic/JoystickEmulation.h index 1bab9b7434..12bc40301a 100644 --- a/xbmc/input/keyboard/generic/JoystickEmulation.h +++ b/xbmc/input/keyboard/generic/JoystickEmulation.h @@ -23,6 +23,8 @@ #include <vector> +namespace KODI +{ namespace JOYSTICK { class IDriverHandler; @@ -63,3 +65,4 @@ namespace KEYBOARD std::vector<KeyEvent> m_pressedKeys; }; } +} diff --git a/xbmc/input/mouse/IMouseButtonMap.h b/xbmc/input/mouse/IMouseButtonMap.h index 80d812da4f..2f24161056 100644 --- a/xbmc/input/mouse/IMouseButtonMap.h +++ b/xbmc/input/mouse/IMouseButtonMap.h @@ -21,6 +21,8 @@ #include <string> +namespace KODI +{ namespace MOUSE { /*! @@ -73,3 +75,4 @@ namespace MOUSE virtual bool GetButtonIndex(const std::string& feature, unsigned int& buttonIndex) = 0; }; } +} diff --git a/xbmc/input/mouse/IMouseDriverHandler.h b/xbmc/input/mouse/IMouseDriverHandler.h index 9da004a4a4..b3d674016c 100644 --- a/xbmc/input/mouse/IMouseDriverHandler.h +++ b/xbmc/input/mouse/IMouseDriverHandler.h @@ -19,6 +19,8 @@ */ #pragma once +namespace KODI +{ namespace MOUSE { /*! @@ -57,3 +59,4 @@ namespace MOUSE virtual void OnButtonRelease(unsigned int button) = 0; }; } +} diff --git a/xbmc/input/mouse/IMouseInputHandler.h b/xbmc/input/mouse/IMouseInputHandler.h index 6eda79b954..c388229181 100644 --- a/xbmc/input/mouse/IMouseInputHandler.h +++ b/xbmc/input/mouse/IMouseInputHandler.h @@ -21,6 +21,8 @@ #include <string> +namespace KODI +{ namespace MOUSE { /*! @@ -67,3 +69,4 @@ namespace MOUSE virtual void OnButtonRelease(const std::string& button) = 0; }; } +} diff --git a/xbmc/input/mouse/MouseWindowingButtonMap.cpp b/xbmc/input/mouse/MouseWindowingButtonMap.cpp index e2da4ae005..11442c596a 100644 --- a/xbmc/input/mouse/MouseWindowingButtonMap.cpp +++ b/xbmc/input/mouse/MouseWindowingButtonMap.cpp @@ -23,6 +23,7 @@ #include <algorithm> +using namespace KODI; using namespace MOUSE; #define CONTROLLER_PROFILE "game.controller.mouse" diff --git a/xbmc/input/mouse/MouseWindowingButtonMap.h b/xbmc/input/mouse/MouseWindowingButtonMap.h index a728257178..f3c7c43d23 100644 --- a/xbmc/input/mouse/MouseWindowingButtonMap.h +++ b/xbmc/input/mouse/MouseWindowingButtonMap.h @@ -25,6 +25,8 @@ #include <utility> #include <vector> +namespace KODI +{ namespace MOUSE { /*! @@ -47,3 +49,4 @@ namespace MOUSE static std::string m_pointerName; }; } +} diff --git a/xbmc/input/mouse/generic/MouseInputHandling.cpp b/xbmc/input/mouse/generic/MouseInputHandling.cpp index 641dd48ecb..9459b4bb4c 100644 --- a/xbmc/input/mouse/generic/MouseInputHandling.cpp +++ b/xbmc/input/mouse/generic/MouseInputHandling.cpp @@ -22,6 +22,7 @@ #include "input/mouse/IMouseButtonMap.h" #include "input/mouse/IMouseInputHandler.h" +using namespace KODI; using namespace MOUSE; CMouseInputHandling::CMouseInputHandling(IMouseInputHandler* handler, IMouseButtonMap* buttonMap) : diff --git a/xbmc/input/mouse/generic/MouseInputHandling.h b/xbmc/input/mouse/generic/MouseInputHandling.h index be1f7a94b6..291e1da9fd 100644 --- a/xbmc/input/mouse/generic/MouseInputHandling.h +++ b/xbmc/input/mouse/generic/MouseInputHandling.h @@ -21,6 +21,8 @@ #include "input/mouse/IMouseDriverHandler.h" +namespace KODI +{ namespace MOUSE { class IMouseInputHandler; @@ -53,3 +55,4 @@ namespace MOUSE int m_y; }; } +} diff --git a/xbmc/interfaces/json-rpc/FileOperations.cpp b/xbmc/interfaces/json-rpc/FileOperations.cpp index ab0ed83a67..1797e4a5db 100644 --- a/xbmc/interfaces/json-rpc/FileOperations.cpp +++ b/xbmc/interfaces/json-rpc/FileOperations.cpp @@ -100,7 +100,7 @@ JSONRPC_STATUS CFileOperations::GetDirectory(const std::string &method, ITranspo else if (media == "pictures") { regexps = g_advancedSettings.m_pictureExcludeFromListingRegExps; - extensions = g_advancedSettings.m_pictureExtensions; + extensions = g_advancedSettings.GetPictureExtensions(); } if (CDirectory::GetDirectory(strPath, items, extensions)) @@ -362,7 +362,7 @@ bool CFileOperations::FillFileItemList(const CVariant ¶meterObject, CFileIte else if (media == "pictures") { regexps = g_advancedSettings.m_pictureExcludeFromListingRegExps; - extensions = g_advancedSettings.m_pictureExtensions; + extensions = g_advancedSettings.GetPictureExtensions(); } CDirectory directory; diff --git a/xbmc/interfaces/json-rpc/JSONRPC.cpp b/xbmc/interfaces/json-rpc/JSONRPC.cpp index c784ff5960..3749fe55d9 100644 --- a/xbmc/interfaces/json-rpc/JSONRPC.cpp +++ b/xbmc/interfaces/json-rpc/JSONRPC.cpp @@ -313,13 +313,13 @@ bool CJSONRPC::HandleMethodCall(const CVariant& request, CVariant& response, ITr inline bool CJSONRPC::IsProperJSONRPC(const CVariant& inputroot) { - return inputroot.isObject() && inputroot.isMember("jsonrpc") && inputroot["jsonrpc"].isString() && inputroot["jsonrpc"] == CVariant("2.0") && inputroot.isMember("method") && inputroot["method"].isString() && (!inputroot.isMember("params") || inputroot["params"].isArray() || inputroot["params"].isObject()); + return inputroot.isMember("jsonrpc") && inputroot["jsonrpc"].isString() && inputroot["jsonrpc"] == CVariant("2.0") && inputroot.isMember("method") && inputroot["method"].isString() && (!inputroot.isMember("params") || inputroot["params"].isArray() || inputroot["params"].isObject()); } inline void CJSONRPC::BuildResponse(const CVariant& request, JSONRPC_STATUS code, const CVariant& result, CVariant& response) { response["jsonrpc"] = "2.0"; - response["id"] = request.isObject() && request.isMember("id") ? request["id"] : CVariant(); + response["id"] = request.isMember("id") ? request["id"] : CVariant(); switch (code) { diff --git a/xbmc/interfaces/json-rpc/JSONUtils.h b/xbmc/interfaces/json-rpc/JSONUtils.h index 0e1cd1c55d..4414753567 100644 --- a/xbmc/interfaces/json-rpc/JSONUtils.h +++ b/xbmc/interfaces/json-rpc/JSONUtils.h @@ -141,7 +141,7 @@ namespace JSONRPC \return True if the given object contains a member with the given key otherwise false */ - static inline bool IsValueMember(const CVariant &value, std::string key) { return value.isObject() && value.isMember(key); } + static inline bool IsValueMember(const CVariant &value, std::string key) { return value.isMember(key); } /*! \brief Returns the json value of a parameter diff --git a/xbmc/interfaces/json-rpc/PVROperations.cpp b/xbmc/interfaces/json-rpc/PVROperations.cpp index 9d7cde95c1..707d586655 100644 --- a/xbmc/interfaces/json-rpc/PVROperations.cpp +++ b/xbmc/interfaces/json-rpc/PVROperations.cpp @@ -21,6 +21,7 @@ #include "PVROperations.h" #include "messaging/ApplicationMessenger.h" +#include "pvr/PVRGUIActions.h" #include "pvr/PVRManager.h" #include "pvr/channels/PVRChannelGroupsContainer.h" #include "pvr/channels/PVRChannel.h" @@ -227,7 +228,7 @@ JSONRPC_STATUS CPVROperations::Record(const std::string &method, ITransportLayer if (toggle) { - if (!g_PVRManager.ToggleRecordingOnChannel(pChannel->ChannelID())) + if (!CPVRGUIActions::GetInstance().SetRecordingOnChannel(pChannel, pChannel->IsRecording())) return FailedToExecute; } @@ -239,9 +240,7 @@ JSONRPC_STATUS CPVROperations::Scan(const std::string &method, ITransportLayer * if (!g_PVRManager.IsStarted()) return FailedToExecute; - if (!g_PVRManager.IsRunningChannelScan()) - g_PVRManager.StartChannelScan(); - + CPVRGUIActions::GetInstance().StartChannelScan(); return ACK; } @@ -261,7 +260,7 @@ JSONRPC_STATUS CPVROperations::GetPropertyValue(const std::string &property, CVa else if (property == "scanning") { if (started) - result = g_PVRManager.IsRunningChannelScan(); + result = CPVRGUIActions::GetInstance().IsRunningChannelScan(); else result = false; } @@ -345,7 +344,7 @@ JSONRPC_STATUS CPVROperations::AddTimer(const std::string &method, ITransportLay CPVRTimerInfoTagPtr newTimer = CPVRTimerInfoTag::CreateFromEpg(epgTag, parameterObject["timerrule"].asBoolean(false)); if (newTimer) { - if (g_PVRTimers->AddTimer(newTimer)) + if (CPVRGUIActions::GetInstance().AddTimer(newTimer)) return ACK; } return FailedToExecute; @@ -398,7 +397,7 @@ JSONRPC_STATUS CPVROperations::ToggleTimer(const std::string &method, ITransport if (!timer) return InvalidParams; - sentOkay = g_PVRTimers->AddTimer(timer); + sentOkay = CPVRGUIActions::GetInstance().AddTimer(timer); } if (sentOkay) diff --git a/xbmc/interfaces/json-rpc/PlayerOperations.cpp b/xbmc/interfaces/json-rpc/PlayerOperations.cpp index f325ee0df2..e2cb354a6e 100644 --- a/xbmc/interfaces/json-rpc/PlayerOperations.cpp +++ b/xbmc/interfaces/json-rpc/PlayerOperations.cpp @@ -375,11 +375,9 @@ JSONRPC_STATUS CPlayerOperations::Seek(const std::string &method, ITransportLaye return FailedToExecute; const CVariant& value = parameterObject["value"]; - if (IsType(value, NumberValue) || - (value.isObject() && value.isMember("percentage"))) + if (IsType(value, NumberValue) || value.isMember("percentage")) g_application.SeekPercentage(IsType(value, NumberValue) ? value.asFloat() : value["percentage"].asFloat()); - else if (value.isString() || - (value.isObject() && value.isMember("step"))) + else if (value.isString() || value.isMember("step")) { std::string step = value.isString() ? value.asString() : value["step"].asString(); if (step == "smallforward") @@ -393,7 +391,7 @@ JSONRPC_STATUS CPlayerOperations::Seek(const std::string &method, ITransportLaye else return InvalidParams; } - else if (value.isObject() && value.isMember("seconds") && value.size() == 1) + else if (value.isMember("seconds") && value.size() == 1) CSeekHandler::GetInstance().SeekSeconds(static_cast<int>(value["seconds"].asInteger())); else if (value.isObject()) g_application.SeekTime(ParseTimeInSeconds(value.isMember("time") ? value["time"] : value)); @@ -507,7 +505,7 @@ JSONRPC_STATUS CPlayerOperations::Open(const std::string &method, ITransportLaye CVariant optionResume = options["resume"]; CVariant optionPlayer = options["playername"]; - if (parameterObject["item"].isObject() && parameterObject["item"].isMember("playlistid")) + if (parameterObject["item"].isMember("playlistid")) { int playlistid = (int)parameterObject["item"]["playlistid"].asInteger(); @@ -553,7 +551,7 @@ JSONRPC_STATUS CPlayerOperations::Open(const std::string &method, ITransportLaye return ACK; } - else if (parameterObject["item"].isObject() && parameterObject["item"].isMember("path")) + else if (parameterObject["item"].isMember("path")) { bool random = (optionShuffled.isBoolean() && optionShuffled.asBoolean()) || (!optionShuffled.isBoolean() && parameterObject["item"]["random"].asBoolean()); @@ -566,7 +564,7 @@ JSONRPC_STATUS CPlayerOperations::Open(const std::string &method, ITransportLaye CApplicationMessenger::GetInstance().SendMsg(TMSG_EXECUTE_BUILT_IN, -1, -1, nullptr, "playercontrol(partymode(" + parameterObject["item"]["partymode"].asString() + "))"); return ACK; } - else if (parameterObject["item"].isObject() && parameterObject["item"].isMember("channelid")) + else if (parameterObject["item"].isMember("channelid")) { if (!g_PVRManager.IsStarted()) return FailedToExecute; @@ -591,7 +589,7 @@ JSONRPC_STATUS CPlayerOperations::Open(const std::string &method, ITransportLaye return ACK; } - else if (parameterObject["item"].isObject() && parameterObject["item"].isMember("recordingid")) + else if (parameterObject["item"].isMember("recordingid")) { if (!g_PVRManager.IsStarted()) return FailedToExecute; @@ -1759,17 +1757,14 @@ int CPlayerOperations::ParseRepeatState(const CVariant &repeat) double CPlayerOperations::ParseTimeInSeconds(const CVariant &time) { double seconds = 0.0; - if (time.isObject()) - { - if (time.isMember("hours")) - seconds += time["hours"].asInteger() * 60 * 60; - if (time.isMember("minutes")) - seconds += time["minutes"].asInteger() * 60; - if (time.isMember("seconds")) - seconds += time["seconds"].asInteger(); - if (time.isMember("milliseconds")) - seconds += time["milliseconds"].asDouble() / 1000.0; - } + if (time.isMember("hours")) + seconds += time["hours"].asInteger() * 60 * 60; + if (time.isMember("minutes")) + seconds += time["minutes"].asInteger() * 60; + if (time.isMember("seconds")) + seconds += time["seconds"].asInteger(); + if (time.isMember("milliseconds")) + seconds += time["milliseconds"].asDouble() / 1000.0; return seconds; } diff --git a/xbmc/interfaces/json-rpc/SettingsOperations.cpp b/xbmc/interfaces/json-rpc/SettingsOperations.cpp index 8dfe557e3f..c9328ef403 100644 --- a/xbmc/interfaces/json-rpc/SettingsOperations.cpp +++ b/xbmc/interfaces/json-rpc/SettingsOperations.cpp @@ -141,7 +141,7 @@ JSONRPC_STATUS CSettingsOperations::GetSettings(const std::string &method, ITran { SettingLevel level = (SettingLevel)ParseSettingLevel(parameterObject["level"].asString()); const CVariant &filter = parameterObject["filter"]; - bool doFilter = filter.isObject() && filter.isMember("section") && filter.isMember("category"); + bool doFilter = filter.isMember("section") && filter.isMember("category"); std::string strSection, strCategory; if (doFilter) { diff --git a/xbmc/interfaces/legacy/ListItem.cpp b/xbmc/interfaces/legacy/ListItem.cpp index 1f301327c0..99ec1853eb 100644 --- a/xbmc/interfaces/legacy/ListItem.cpp +++ b/xbmc/interfaces/legacy/ListItem.cpp @@ -857,7 +857,7 @@ namespace XBMCAddon for (const auto& el : alt.later()) { if (el.which() == second) - throw WrongTypeException(StringUtils::Format("When using \"%s\" you need to supply a string or list of strings for the value in the dictionary", tag.c_str()).c_str()); + throw WrongTypeException("When using \"%s\" you need to supply a string or list of strings for the value in the dictionary", tag.c_str()); els.emplace_back(el.former()); } return els; diff --git a/xbmc/interfaces/legacy/ModuleXbmc.cpp b/xbmc/interfaces/legacy/ModuleXbmc.cpp index a9c6d06b6f..1032adb81f 100644 --- a/xbmc/interfaces/legacy/ModuleXbmc.cpp +++ b/xbmc/interfaces/legacy/ModuleXbmc.cpp @@ -461,7 +461,7 @@ namespace XBMCAddon else if (strcmpi(mediaType, "music") == 0) result = g_advancedSettings.GetMusicExtensions(); else if (strcmpi(mediaType, "picture") == 0) - result = g_advancedSettings.m_pictureExtensions; + result = g_advancedSettings.GetPictureExtensions(); //! @todo implement // else diff --git a/xbmc/interfaces/python/PythonSwig.cpp.template b/xbmc/interfaces/python/PythonSwig.cpp.template index 1af3ab210c..f473eb55aa 100644 --- a/xbmc/interfaces/python/PythonSwig.cpp.template +++ b/xbmc/interfaces/python/PythonSwig.cpp.template @@ -166,7 +166,7 @@ void doMethod(Node method, MethodType methodType) <% } params.each { %> - ${SwigTypeParser.SwigType_str(SwigTypeParser.convertTypeToLTypeForParam(it.@type))} ${it.@name} ${it.@value != null ? ' = ' + it.@value : ''};<% + ${SwigTypeParser.SwigType_str(SwigTypeParser.convertTypeToLTypeForParam(it.@type))} ${it.@name} ${it.@value != null ? ' = ' + it.@value : SwigTypeParser.SwigType_ispointer(it.@type) ? ' = nullptr' : ''};<% if (!PythonTools.parameterCanBeUsedDirectly(it) && !doAsMappingIndex) { %> PyObject* py${it.@name} = NULL;<% diff --git a/xbmc/linux/OMXClock.cpp b/xbmc/linux/OMXClock.cpp index 0b6dfc3ba0..3764952438 100644 --- a/xbmc/linux/OMXClock.cpp +++ b/xbmc/linux/OMXClock.cpp @@ -25,7 +25,7 @@ #if defined(HAVE_OMXLIB) #include "ServiceBroker.h" -#include "video/VideoReferenceClock.h" +#include "cores/VideoPlayer/VideoReferenceClock.h" #include "settings/Settings.h" #include "OMXClock.h" diff --git a/xbmc/linux/RBP.cpp b/xbmc/linux/RBP.cpp index 356d64b0b1..053c10deaf 100644 --- a/xbmc/linux/RBP.cpp +++ b/xbmc/linux/RBP.cpp @@ -103,7 +103,7 @@ bool CRBP::Initialize() return true; } -void CRBP::LogFirmwareVerison() +void CRBP::LogFirmwareVersion() { char response[1024]; m_DllBcmHost->vc_gencmd(response, sizeof response, "version"); diff --git a/xbmc/linux/RBP.h b/xbmc/linux/RBP.h index eff631d24c..10f5776fd4 100644 --- a/xbmc/linux/RBP.h +++ b/xbmc/linux/RBP.h @@ -61,12 +61,12 @@ public: ~CRBP(); bool Initialize(); - void LogFirmwareVerison(); + void LogFirmwareVersion(); void Deinitialize(); int GetArmMem() { return m_arm_mem; } int GetGpuMem() { return m_gpu_mem; } bool GetCodecMpg2() { return m_codec_mpg2_enabled; } - int RasberryPiVersion() { return g_cpuInfo.getCPUCount() == 1 ? 1 : 2; }; + int RaspberryPiVersion() { return g_cpuInfo.getCPUCount() == 1 ? 1 : 2; }; bool GetCodecWvc1() { return m_codec_wvc1_enabled; } void GetDisplaySize(int &width, int &height); DISPMANX_DISPLAY_HANDLE_T OpenDisplay(uint32_t device); diff --git a/xbmc/messaging/ApplicationMessenger.h b/xbmc/messaging/ApplicationMessenger.h index b54b1c88f9..f3ad2aabde 100644 --- a/xbmc/messaging/ApplicationMessenger.h +++ b/xbmc/messaging/ApplicationMessenger.h @@ -164,6 +164,79 @@ struct ThreadMessageCallback class IMessageTarget; +/*! + * \class CApplicationMessenger ApplicationMessenger.h "messaging/ApplicationMessenger.h" + * \brief This implements a simple message dispatcher/router for Kodi + * + * For most users that wants to send message go to the documentation for these + * \sa CApplicationMessenger::SendMsg + * \sa CApplicationMessenger::PostMsg + * + * For anyone wanting to implement a message receiver, go to the documentation for + * \sa IMessageTarget + * + * IMPLEMENTATION SPECIFIC NOTES - DOCUMENTED HERE FOR THE SOLE PURPOSE OF IMPLEMENTERS OF THIS CLASS + * On a high level this implements two methods for dispatching messages, SendMsg and PostMsg. + * These are roughly modeled on the implementation of SendMessage and PostMessage in Windows. + * + * PostMsg is the preferred method to use as it's non-blocking and does not wait for any response before + * returning to the caller. Messages will be stored in a queue and processed in order. + * + * SendMsg is a blocking version and has a bit more subtleties to it regarding how inter-process + * dispatching is handled. + * + * Calling SendMsg with a message type that doesn't require marshalling will bypass the message queue + * and call the receiver directly + * + * Calling SendMsg with a message type that require marshalling to a specific thread when not on that thread + * will add a message to the queue with a an event, it will then block the calling thread waiting on this event + * to be signaled. + * The message will be processed by the correct thread in it's message pump and the event will be signaled, unblocking + * the calling thread + * + * Calling SendMsg with a message type that require marshalling to a specific thread when already on that thread + * will behave as scenario one, it will bypass the queue and call the receiver directly. + * + * Currently there is a hack implemented in the message dispatcher that releases the graphicslock before dispatching + * a message. This was here before the redesign and removing it will require careful inspection of every call site. + * TODO: add logging if the graphicslock is held during message dispatch + * + * Current design has three different message types + * 1. Normal messages that can be processed on any thread + * 2. GUI messages that require marshalling to the UI thread + * 3. A thread message that will spin up a background thread and wait a specified amount of time before posting the message + * This should probably be removed, it's left for compatibility + * + * Heavy emphasis on current design, the idea is that we can easily add more message types to route messages + * to more threads or other scenarios. + * + * \sa CApplicationMessenger::ProcessMessages() + * handles regular messages that require no marshalling, this can be called from any thread to drive the message + * pump + * + * \sa CApplicationMessenger::ProcessWindowMessages() + * handles GUI messages and currently should only be called on the UI thread + * + * If/When this is expanded upon ProcessMessage() and ProcessWindowMessages() should be combined into a single method + * taking an enum or similar to indicate which message it's interested in. + * + * The above methods are backed by two messages queues, one for each type of message. If more types are added + * this might need to be redesigned to simplify the lookup of the correct message queue but currently they're implemented + * as two member variables + * + * The design is meant to be very encapsulated and easy to extend without altering the public interface. + * e.g. If GUI messages should be handled on another thread, call \sa CApplicationMessenger::ProcessWindowMessage() on that + * thread and nothing else has to change. The callers have no knowledge of how this is implemented. + * + * The design is also meant to be very dependency free to work as a bridge between lower layer functionality without + * having to have knowledge of the GUI or having a dependency on the GUI in any way. This is not the reality currently as + * this depends on \sa CApplication and the graphicslock but should be fixed soon enough. + * + * To keep things simple the current implementation routes messages based on a mask that the receiver provides. + * Any message fitting that mask will be routed to that specific receiver. + * This will likely need to change if many different receivers are added but it should be possible to do it without + * any of the callers being changed. + */ class CApplicationMessenger { public: @@ -175,27 +248,156 @@ public: void Cleanup(); // if a message has to be send to the gui, use MSG_TYPE_WINDOW instead + /*! + * \brief Send a blocking message and wait for a response + * + * If and what the response is depends entirely on the message being sent and + * should be documented on the message. + * + * Under no circumestances shall the caller hold a lock when calling SendMsg as there's + * no guarantee what the receiver will do to answer the request. + * + * \param [in] messageId defined further up in this file + * \return meaning of the return varies based on the message + */ int SendMsg(uint32_t messageId); + + /*! + * \brief Send a blocking message and wait for a response + * + * If and what the response is depends entirely on the message being sent and + * should be documented on the message. + * + * Under no circumestances shall the caller hold a lock when calling SendMsg as there's + * no guarantee what the receiver will do to answer the request. + * + * \param [in] messageId defined further up in this file + * \param [in] param1 value depends on the message being sent + * \param [in] param2 value depends on the message being sent, defaults to -1 + * \param [in] payload this is a void pointer that is meant to send larger objects to the receiver + * what to send depends on the message + * \return meaning of the return varies based on the message + */ int SendMsg(uint32_t messageId, int param1, int param2 = -1, void* payload = nullptr); + + /*! + * \brief Send a blocking message and wait for a response + * + * If and what the response is depends entirely on the message being sent and + * should be documented on the message. + * + * Under no circumestances shall the caller hold a lock when calling SendMsg as there's + * no guarantee what the receiver will do to answer the request. + * + * \param [in] messageId defined further up in this file + * \param [in] param1 value depends on the message being sent + * \param [in] param2 value depends on the message being sent + * \param [in,out] payload this is a void pointer that is meant to send larger objects to the receiver + * what to send depends on the message + * \param [in] strParam value depends on the message being sent, remains for backward compat + * \return meaning of the return varies based on the message + */ int SendMsg(uint32_t messageId, int param1, int param2, void* payload, std::string strParam); + + /*! + * \brief Send a blocking message and wait for a response + * + * If and what the response is depends entirely on the message being sent and + * should be documented on the message. + * + * Under no circumestances shall the caller hold a lock when calling SendMsg as there's + * no guarantee what the receiver will do to answer the request. + * + * \param [in] messageId defined further up in this file + * \param [in] param1 value depends on the message being sent + * \param [in] param2 value depends on the message being sent + * \param [in,out] payload this is a void pointer that is meant to send larger objects to the receiver + * what to send depends on the message + * \param [in] strParam value depends on the message being sent, remains for backward compat + * \param [in] params value depends on the message being sent, kept for backward compatiblity + * \return meaning of the return varies based on the message + */ int SendMsg(uint32_t messageId, int param1, int param2, void* payload, std::string strParam, std::vector<std::string> params); + /*! + * \brief Send a non-blocking message and return immediately + * + * If and what the response is depends entirely on the message being sent and + * should be documented on the message. + * + * \param [in] messageId defined further up in this file + */ void PostMsg(uint32_t messageId); + + /*! + * \brief Send a non-blocking message and return immediately + * + * If and what the response is depends entirely on the message being sent and + * should be documented on the message. + * + * \param [in] messageId defined further up in this file + * \param [in] param1 value depends on the message being sent + * \param [in] param2 value depends on the message being sent + * \param [in,out] payload this is a void pointer that is meant to send larger objects to the receiver + * what to send depends on the message + */ void PostMsg(uint32_t messageId, int param1, int param2 = -1, void* payload = nullptr); + + /*! + * \brief Send a non-blocking message and return immediately + * + * If and what the response is depends entirely on the message being sent and + * should be documented on the message. + * + * \param [in] messageId defined further up in this file + * \param [in] param1 value depends on the message being sent + * \param [in] param2 value depends on the message being sent + * \param [in,out] payload this is a void pointer that is meant to send larger objects to the receiver + * what to send depends on the message + * \param [in] strParam value depends on the message being sent, remains for backward compat + */ void PostMsg(uint32_t messageId, int param1, int param2, void* payload, std::string strParam); + /*! + * \brief Send a non-blocking message and return immediately + * + * If and what the response is depends entirely on the message being sent and + * should be documented on the message. + * + * \param [in] messageId defined further up in this file + * \param [in] param1 value depends on the message being sent + * \param [in] param2 value depends on the message being sent + * \param [in,out] payload this is a void pointer that is meant to send larger objects to the receiver + * what to send depends on the message + * \param [in] strParam value depends on the message being sent, remains for backward compat + * \param [in] params value depends on the message being sent, kept for backward compatiblity + */ void PostMsg(uint32_t messageId, int param1, int param2, void* payload, std::string strParam, std::vector<std::string> params); - void ProcessMessages(); // only call from main thread. + /*! + * \brief Called from any thread to dispatch messages + */ + void ProcessMessages(); + + /*! + * \brief Called from the UI thread to dispatch UI messages + * This is only of value to implementers of the message pump, do not rely on a specific thread + * being used other than that it's appropriate for UI messages + */ void ProcessWindowMessages(); /*! \brief Send a GUIMessage, optionally waiting before it's processed to return. - Should be used to send messages to the GUI from other threads. - \param msg the GUIMessage to send. - \param windowID optional window to send the message to (defaults to no specified window). - \param waitResult whether to wait for the result (defaults to false). + * This is kept for backward compat and is just a convenience wrapper for for SendMsg and PostMsg + * specifically for UI messages + * \param msg the GUIMessage to send. + * \param windowID optional window to send the message to (defaults to no specified window). + * \param waitResult whether to wait for the result (defaults to false). */ void SendGUIMessage(const CGUIMessage &msg, int windowID = WINDOW_INVALID, bool waitResult=false); + /*! + * \brief This should be called any class implementing \sa IMessageTarget before it + * can receive any messages + */ void RegisterReceiver(IMessageTarget* target); private: @@ -208,9 +410,9 @@ private: int SendMsg(ThreadMessage&& msg, bool wait); void ProcessMessage(ThreadMessage *pMsg); - std::queue<ThreadMessage*> m_vecMessages; - std::queue<ThreadMessage*> m_vecWindowMessages; - std::map<int, IMessageTarget*> m_mapTargets; + std::queue<ThreadMessage*> m_vecMessages; /*!< queue for regular messages */ + std::queue<ThreadMessage*> m_vecWindowMessages; /*!< queue for UI messages */ + std::map<int, IMessageTarget*> m_mapTargets; /*!< a map of registered receivers indexed on the message mask*/ CCriticalSection m_critSection; }; } diff --git a/xbmc/messaging/IMessageTarget.h b/xbmc/messaging/IMessageTarget.h index b59f150b54..a67d9adf9f 100644 --- a/xbmc/messaging/IMessageTarget.h +++ b/xbmc/messaging/IMessageTarget.h @@ -25,11 +25,43 @@ namespace MESSAGING { class ThreadMessage; +/*! + * \class IMessageTarget IMessageTarget.h "messaging/IMessageTarget.h" + * \brief A class wishing to receive messages should implement this + * and call \sa CApplicationMessenger::RegisterReceiver + * to start receiving messages + */ class IMessageTarget { public: virtual ~IMessageTarget() { } + /*! + * \brief Should return the message mask that it wishes to receive + * messages for + * + * The message mask is defined in "messaging/ApplicationMessenger.h" + * pick the next one available when creating a new + */ virtual int GetMessageMask() = 0; + + /*! + * \brief This gets called whenever a message matching the registered + * message mask is processed. + * + * There are no ordering guarantees here so implementations should never + * rely on a certain ordering of messages. + * + * Cleaning up any pointers stored in the message payload is not specified + * and is decided by the implementer of the message. + * In general prefer to delete any data in this method to keep the callsites cleaner + * and simpler but if data is to be passed back it's perfectly valid to handle it any way + * that fits the situation as long as it's documented along with the message. + * + * To return a simple value the result parameter of \sa ThreadMessage can be used + * as it will be used as the return value for \sa CApplicationMessenger::SendMsg. + * It is up to the implementer to decide if this is to be used and it should be documented + * along with any new message implemented. + */ virtual void OnApplicationMessage(ThreadMessage* msg) = 0; }; } diff --git a/xbmc/messaging/ThreadMessage.h b/xbmc/messaging/ThreadMessage.h index 86fd4d4741..6471f2ffdc 100644 --- a/xbmc/messaging/ThreadMessage.h +++ b/xbmc/messaging/ThreadMessage.h @@ -125,7 +125,12 @@ public: std::string strParam; std::vector<std::string> params; - void SetResult(int res) + /*! + * \brief set the message return value, will only be returned when + * the message is sent using SendMsg + * \param [in] res the return value or a result status code that is returned to the caller + */ + void SetResult(int res) const { //On posted messages result will be zero, since they can't //retrieve the response we silently ignore this to let message diff --git a/xbmc/music/MusicDatabase.cpp b/xbmc/music/MusicDatabase.cpp index 57b6047c72..0fb70f1b6f 100644 --- a/xbmc/music/MusicDatabase.cpp +++ b/xbmc/music/MusicDatabase.cpp @@ -192,6 +192,10 @@ void CMusicDatabase::CreateTables() CLog::Log(LOGINFO, "create cue table"); m_pDS->exec("CREATE TABLE cue (idPath integer, strFileName text, strCuesheet text)"); + + CLog::Log(LOGINFO, "create versiontagscan table"); + m_pDS->exec("CREATE TABLE versiontagscan (idVersion integer, iNeedsScan integer)"); + m_pDS->exec(PrepareSQL("INSERT INTO versiontagscan (idVersion, iNeedsScan) values(%i, 0)", GetSchemaVersion())); } void CMusicDatabase::CreateAnalytics() @@ -4250,19 +4254,25 @@ bool CMusicDatabase::GetSongsFullByWhere(const std::string &baseDir, const Filte // Count number of songs that satisfy selection criteria total = (int)strtol(GetSingleValue("SELECT COUNT(1) FROM songview " + strSQLExtra, m_pDS).c_str(), NULL, 10); - // Apply the limiting directly here if there's no special sorting but limiting - bool limited = extFilter.limit.empty() && sortDescription.sortBy == SortByNone && + // Apply any limiting directly in SQL if there is either no special sorting or random sort + // When limited, random sort is also applied in SQL + bool limitedInSQL = extFilter.limit.empty() && + (sortDescription.sortBy == SortByNone || sortDescription.sortBy == SortByRandom) && (sortDescription.limitStart > 0 || sortDescription.limitEnd > 0); - if (limited) + if (limitedInSQL) + { + if (sortDescription.sortBy == SortByRandom) + strSQLExtra += PrepareSQL(" ORDER BY RANDOM()"); strSQLExtra += DatabaseUtils::BuildLimitClause(sortDescription.limitEnd, sortDescription.limitStart); + } std::string strSQL; if (artistData) { // Get data from song and song_artist tables to fully populate songs with artists // All songs now have at least one artist so inner join sufficient // Need guaranteed ordering for dataset processing to extract songs - if (limited) - //Apply where clause and limits to songview, then join as multiple records in result set per song + if (limitedInSQL) + //Apply where clause, limits and random order to songview, then join as multiple records in result set per song strSQL = "SELECT sv.*, songartistview.* " "FROM (SELECT songview.* FROM songview " + strSQLExtra + ") AS sv " "JOIN songartistview ON songartistview.idsong = sv.idsong "; @@ -4355,8 +4365,9 @@ bool CMusicDatabase::GetSongsFullByWhere(const std::string &baseDir, const Filte // cleanup m_pDS->close(); - // When have join with songartistview apply sort (and limit) to items rather than dataset - if (artistData && sortDescription.sortBy != SortByNone) + // Finally do any sorting in items list we have not been able to do before in SQL or dataset, + // that is when have join with songartistview and sorting other than random with limit + if (artistData && sortDescription.sortBy != SortByNone && !(limitedInSQL && sortDescription.sortBy == SortByRandom)) items.Sort(sortDescription); if (cueSheetData) @@ -4662,8 +4673,6 @@ void CMusicDatabase::UpdateTables(int version) if (version < 53) { m_pDS->exec("ALTER TABLE song ADD dateAdded text"); - CMediaSettings::GetInstance().SetMusicNeedsUpdate(53); - CServiceBroker::GetSettings().Save(); } if (version < 54) { @@ -4958,17 +4967,78 @@ void CMusicDatabase::UpdateTables(int version) //Remove temp indices, full analytics for database created later m_pDS->exec("DROP INDEX idxSongArtist1 ON song_artist"); m_pDS->exec("DROP INDEX idxAlbumArtist1 ON album_artist"); - - // Prompt for rescan of library to read tags that were not processed by previous versions - // and accomodate changes to the way some tags are processed - CMediaSettings::GetInstance().SetMusicNeedsUpdate(60); - CServiceBroker::GetSettings().Save(); } + if (version < 61) + { + // Create versiontagscan table + m_pDS->exec("CREATE TABLE versiontagscan (idVersion integer, iNeedsScan integer)"); + m_pDS->exec("INSERT INTO versiontagscan (idVersion, iNeedsScan) values(0, 0)"); + } + + // Set the version of tag scanning required. + // Not every schema change requires the tags to be rescanned, set to the highest schema version + // that needs this. Forced rescanning (of music files that have not changed since they were + // previously scanned) also accommodates any changes to the way tags are processed + // e.g. read tags that were not processed by previous versions. + // The original db version when the tags were scanned, and the minimal db version needed are + // later used to determine if a forced rescan should be prompted + + // The last schema change needing forced rescanning was 60. + // Mostly because of the new tags processed by v17 rather than a schema change. + SetMusicNeedsTagScan(60); + + // After all updates, store the original db version. + // This indicates the version of tag processing that was used to populate db + SetMusicTagScanVersion(version); } int CMusicDatabase::GetSchemaVersion() const { - return 60; + return 61; +} + +int CMusicDatabase::GetMusicNeedsTagScan() +{ + try + { + if (NULL == m_pDB.get()) return -1; + if (NULL == m_pDS.get()) return -1; + + std::string sql = "SELECT * FROM versiontagscan"; + if (!m_pDS->query(sql)) return -1; + + if (m_pDS->num_rows() != 1) + { + m_pDS->close(); + return -1; + } + + int idVersion = m_pDS->fv("idVersion").get_asInt(); + int iNeedsScan = m_pDS->fv("iNeedsScan").get_asInt(); + m_pDS->close(); + if (idVersion < iNeedsScan) + return idVersion; + else + return 0; + } + catch (...) + { + CLog::Log(LOGERROR, "%s failed", __FUNCTION__); + } + return -1; +} + +void CMusicDatabase::SetMusicNeedsTagScan(int version) +{ + m_pDS->exec(PrepareSQL("UPDATE versiontagscan SET iNeedsScan=%i", version)); +} + +void CMusicDatabase::SetMusicTagScanVersion(int version /* = 0 */) +{ + if (version == 0) + m_pDS->exec(PrepareSQL("UPDATE versiontagscan SET idVersion=%i", GetSchemaVersion())); + else + m_pDS->exec(PrepareSQL("UPDATE versiontagscan SET idVersion=%i", version)); } unsigned int CMusicDatabase::GetSongIDs(const Filter &filter, std::vector<std::pair<int,int> > &songIDs) diff --git a/xbmc/music/MusicDatabase.h b/xbmc/music/MusicDatabase.h index f51a981a2d..3bc2caa15b 100644 --- a/xbmc/music/MusicDatabase.h +++ b/xbmc/music/MusicDatabase.h @@ -497,6 +497,26 @@ public: */ std::string GetArtistArtForItem(int mediaId, const std::string &mediaType, const std::string &artType); + ///////////////////////////////////////////////// + // Tag Scan Version + ///////////////////////////////////////////////// + /*! \brief Check if music files need all tags rescanning regardless of file being unchanged + because the tag processing has changed (which may happen without db version changes) since they + where last scanned. + \return -1 if an error occured, 0 if no scan is needed, or the version number of tags if not the same as current. + */ + virtual int GetMusicNeedsTagScan(); + + /*! \brief Set minimum version number of db needed when tag data scanned from music files + \param version the version number of db + */ + void SetMusicNeedsTagScan(int version); + + /*! \brief Set the version number of tag data + \param version the version number of db when tags last scanned, 0 (default) means current db version + */ + void SetMusicTagScanVersion(int version = 0); + protected: std::map<std::string, int> m_artistCache; std::map<std::string, int> m_genreCache; diff --git a/xbmc/music/infoscanner/MusicInfoScanner.cpp b/xbmc/music/infoscanner/MusicInfoScanner.cpp index 6bf6628b21..0991c5f76d 100644 --- a/xbmc/music/infoscanner/MusicInfoScanner.cpp +++ b/xbmc/music/infoscanner/MusicInfoScanner.cpp @@ -92,18 +92,6 @@ void CMusicInfoScanner::Process() ANNOUNCEMENT::CAnnouncementManager::GetInstance().Announce(ANNOUNCEMENT::AudioLibrary, "xbmc", "OnScanStarted"); try { - if (m_bClean) - { - CleanDatabase(false); - m_bRunning = false; - - return; - } - - unsigned int tick = XbmcThreads::SystemClockMillis(); - - m_musicDatabase.Open(); - if (m_showDialog && !CServiceBroker::GetSettings().GetBool(CSettings::SETTING_MUSICLIBRARY_BACKGROUNDUPDATE)) { CGUIDialogExtendedProgressBar* dialog = @@ -112,8 +100,18 @@ void CMusicInfoScanner::Process() m_handle = dialog->GetHandle(g_localizeStrings.Get(314)); } - m_bClean = g_advancedSettings.m_bMusicLibraryCleanOnUpdate; + // check if we only need to perform a cleaning + if (m_bClean && m_pathsToScan.empty()) + { + CleanDatabase(false); + m_handle = NULL; + m_bRunning = false; + return; + } + + unsigned int tick = XbmcThreads::SystemClockMillis(); + m_musicDatabase.Open(); m_bCanInterrupt = true; if (m_scanType == 0) // load info from files @@ -287,7 +285,8 @@ void CMusicInfoScanner::Start(const std::string& strDirectory, int flags) } else m_pathsToScan.insert(strDirectory); - m_bClean = false; + + m_bClean = g_advancedSettings.m_bMusicLibraryCleanOnUpdate; m_scanType = 0; Create(); @@ -416,7 +415,7 @@ bool CMusicInfoScanner::IsScanning() void CMusicInfoScanner::Stop(bool wait /* = false*/) { if (m_bCanInterrupt) - m_musicDatabase.Interupt(); + m_musicDatabase.Interrupt(); StopThread(wait); } diff --git a/xbmc/music/windows/GUIWindowMusicBase.cpp b/xbmc/music/windows/GUIWindowMusicBase.cpp index 81e457a04c..6cc1c68039 100644 --- a/xbmc/music/windows/GUIWindowMusicBase.cpp +++ b/xbmc/music/windows/GUIWindowMusicBase.cpp @@ -1308,7 +1308,7 @@ void CGUIWindowMusicBase::OnInitWindow() CGUIMediaWindow::OnInitWindow(); // Prompt for rescan of library to read music file tags that were not processed by previous versions // and accomodate any changes to the way some tags are processed - if (CMediaSettings::GetInstance().GetMusicNeedsUpdate() != 0) + if (m_musicdatabase.GetMusicNeedsTagScan() != 0) { if (g_infoManager.GetLibraryBool(LIBRARY_HAS_MUSIC) && !g_application.IsMusicScanning()) { @@ -1324,15 +1324,13 @@ void CGUIWindowMusicBase::OnInitWindow() if (CServiceBroker::GetSettings().GetBool(CSettings::SETTING_MUSICLIBRARY_BACKGROUNDUPDATE)) flags |= CMusicInfoScanner::SCAN_BACKGROUND; g_application.StartMusicScan("", true, flags); - CMediaSettings::GetInstance().SetMusicNeedsUpdate(0); // once is enough (user may interrupt, but that's up to them) - CServiceBroker::GetSettings().Save(); + m_musicdatabase.SetMusicTagScanVersion(); // once is enough (user may interrupt, but that's up to them) } } else { // no need to force a rescan if there's no music in the library or if a library scan is already active - CMediaSettings::GetInstance().SetMusicNeedsUpdate(0); - CServiceBroker::GetSettings().Save(); + m_musicdatabase.SetMusicTagScanVersion(); } } } diff --git a/xbmc/network/AirTunesServer.cpp b/xbmc/network/AirTunesServer.cpp index 466468539f..2f9e0f796b 100644 --- a/xbmc/network/AirTunesServer.cpp +++ b/xbmc/network/AirTunesServer.cpp @@ -365,7 +365,7 @@ void* CAirTunesServer::AudioOutputFunctions::audio_init(void *cls, int bits, int XFILE::CPipeFile *pipe=(XFILE::CPipeFile *)cls; const CURL pathToUrl(XFILE::PipesManager::GetInstance().GetUniquePipeName()); pipe->OpenForWrite(pathToUrl); - pipe->SetOpenThreashold(300); + pipe->SetOpenThreshold(300); Demux_BXA_FmtHeader header; strncpy(header.fourcc, "BXA ", 4); diff --git a/xbmc/network/cddb.cpp b/xbmc/network/cddb.cpp index 5831a1968d..0cf1caa34b 100644 --- a/xbmc/network/cddb.cpp +++ b/xbmc/network/cddb.cpp @@ -730,7 +730,7 @@ void Xcddb::addInexactListLine(int line_cnt, const char *line, int len) } //------------------------------------------------------------------------------------------------------------------- -void Xcddb::setCDDBIpAdress(const std::string& ip_address) +void Xcddb::setCDDBIpAddress(const std::string& ip_address) { m_cddb_ip_address = ip_address; } diff --git a/xbmc/network/cddb.h b/xbmc/network/cddb.h index ef2dc2ef9c..de8da75eca 100644 --- a/xbmc/network/cddb.h +++ b/xbmc/network/cddb.h @@ -67,7 +67,7 @@ class Xcddb public: Xcddb(); virtual ~Xcddb(); - void setCDDBIpAdress(const std::string& ip_address); + void setCDDBIpAddress(const std::string& ip_address); void setCacheDir(const std::string& pCacheDir ); // int queryCDinfo(int real_track_count, toc cdtoc[]); diff --git a/xbmc/network/upnp/UPnPServer.cpp b/xbmc/network/upnp/UPnPServer.cpp index a2e1f9c869..10d3e9fc29 100644 --- a/xbmc/network/upnp/UPnPServer.cpp +++ b/xbmc/network/upnp/UPnPServer.cpp @@ -677,7 +677,7 @@ CUPnPServer::OnBrowseDirectChildren(PLT_ActionReference& action, // this is the only way to hide unplayable items in the 'files' // view as we cannot tell what context (eg music vs video) the // request came from - std::string supported = g_advancedSettings.m_pictureExtensions + "|" + std::string supported = g_advancedSettings.GetPictureExtensions() + "|" + g_advancedSettings.m_videoExtensions + "|" + g_advancedSettings.GetMusicExtensions() + "|" + g_advancedSettings.m_discStubExtensions; diff --git a/xbmc/network/websocket/WebSocket.h b/xbmc/network/websocket/WebSocket.h index 6e2c4ae954..769156c94c 100644 --- a/xbmc/network/websocket/WebSocket.h +++ b/xbmc/network/websocket/WebSocket.h @@ -69,7 +69,7 @@ public: virtual int8_t GetExtension() const { return m_extension; } virtual WebSocketFrameOpcode GetOpcode() const { return m_opcode; } virtual bool IsControlFrame() const { return (m_valid && (m_opcode & 0x8) == 0x8); } - virtual bool IsMasekd() const { return m_masked; } + virtual bool IsMasked() const { return m_masked; } virtual uint64_t GetLength() const { return m_length; } virtual int32_t GetMask() const { return m_mask; } virtual const char* GetFrameData() const { return m_data; } diff --git a/xbmc/peripherals/Peripherals.cpp b/xbmc/peripherals/Peripherals.cpp index a92ce3c4e3..7d1bbfeb75 100644 --- a/xbmc/peripherals/Peripherals.cpp +++ b/xbmc/peripherals/Peripherals.cpp @@ -69,7 +69,7 @@ #include "bus/virtual/PeripheralBusCEC.h" #endif - +using namespace KODI; using namespace JOYSTICK; using namespace PERIPHERALS; using namespace XFILE; @@ -132,7 +132,7 @@ void CPeripherals::Initialise() m_eventScanner.Start(); m_bInitialised = true; - KODI::MESSAGING::CApplicationMessenger::GetInstance().RegisterReceiver(this); + MESSAGING::CApplicationMessenger::GetInstance().RegisterReceiver(this); } void CPeripherals::Clear() @@ -964,7 +964,7 @@ void CPeripherals::OnSettingAction(const CSetting *setting) TestFeature(FEATURE_RUMBLE); } -void CPeripherals::OnApplicationMessage(KODI::MESSAGING::ThreadMessage* pMsg) +void CPeripherals::OnApplicationMessage(MESSAGING::ThreadMessage* pMsg) { switch (pMsg->dwMessage) { diff --git a/xbmc/peripherals/Peripherals.h b/xbmc/peripherals/Peripherals.h index 6495b5ecba..63d4e91da7 100644 --- a/xbmc/peripherals/Peripherals.h +++ b/xbmc/peripherals/Peripherals.h @@ -39,10 +39,13 @@ class TiXmlElement; class CAction; class CKey; +namespace KODI +{ namespace JOYSTICK { class IButtonMapper; } +} namespace PERIPHERALS { @@ -277,13 +280,13 @@ namespace PERIPHERALS * \ref CPeripheral::RegisterJoystickButtonMapper for what is done to the * mapper after being given to the peripheral. */ - void RegisterJoystickButtonMapper(JOYSTICK::IButtonMapper* mapper); + void RegisterJoystickButtonMapper(KODI::JOYSTICK::IButtonMapper* mapper); /*! * \brief Unregister a button mapper interface * \param mapper The button mapper */ - void UnregisterJoystickButtonMapper(JOYSTICK::IButtonMapper* mapper); + void UnregisterJoystickButtonMapper(KODI::JOYSTICK::IButtonMapper* mapper); virtual void OnSettingChanged(const CSetting *setting) override; virtual void OnSettingAction(const CSetting *setting) override; diff --git a/xbmc/peripherals/addons/AddonButtonMap.cpp b/xbmc/peripherals/addons/AddonButtonMap.cpp index 039c5ba02f..5beb76b80a 100644 --- a/xbmc/peripherals/addons/AddonButtonMap.cpp +++ b/xbmc/peripherals/addons/AddonButtonMap.cpp @@ -28,6 +28,7 @@ #include <assert.h> #include <vector> +using namespace KODI; using namespace JOYSTICK; using namespace PERIPHERALS; diff --git a/xbmc/peripherals/addons/AddonButtonMap.h b/xbmc/peripherals/addons/AddonButtonMap.h index 172d6b275a..eddbaca2cf 100644 --- a/xbmc/peripherals/addons/AddonButtonMap.h +++ b/xbmc/peripherals/addons/AddonButtonMap.h @@ -31,7 +31,7 @@ namespace PERIPHERALS { class CPeripheral; - class CAddonButtonMap : public JOYSTICK::IButtonMap + class CAddonButtonMap : public KODI::JOYSTICK::IButtonMap { public: CAddonButtonMap(CPeripheral* device, const std::weak_ptr<CPeripheralAddon>& addon, const std::string& strControllerId); @@ -50,53 +50,53 @@ namespace PERIPHERALS virtual bool IsEmpty(void) const override; virtual bool GetFeature( - const JOYSTICK::CDriverPrimitive& primitive, - JOYSTICK::FeatureName& feature + const KODI::JOYSTICK::CDriverPrimitive& primitive, + KODI::JOYSTICK::FeatureName& feature ) override; - virtual JOYSTICK::FEATURE_TYPE GetFeatureType( - const JOYSTICK::FeatureName& feature + virtual KODI::JOYSTICK::FEATURE_TYPE GetFeatureType( + const KODI::JOYSTICK::FeatureName& feature ) override; virtual bool GetScalar( - const JOYSTICK::FeatureName& feature, - JOYSTICK::CDriverPrimitive& primitive + const KODI::JOYSTICK::FeatureName& feature, + KODI::JOYSTICK::CDriverPrimitive& primitive ) override; virtual void AddScalar( - const JOYSTICK::FeatureName& feature, - const JOYSTICK::CDriverPrimitive& primitive + const KODI::JOYSTICK::FeatureName& feature, + const KODI::JOYSTICK::CDriverPrimitive& primitive ) override; virtual bool GetAnalogStick( - const JOYSTICK::FeatureName& feature, - JOYSTICK::ANALOG_STICK_DIRECTION direction, - JOYSTICK::CDriverPrimitive& primitive + const KODI::JOYSTICK::FeatureName& feature, + KODI::JOYSTICK::ANALOG_STICK_DIRECTION direction, + KODI::JOYSTICK::CDriverPrimitive& primitive ) override; virtual void AddAnalogStick( - const JOYSTICK::FeatureName& feature, - JOYSTICK::ANALOG_STICK_DIRECTION direction, - const JOYSTICK::CDriverPrimitive& primitive + const KODI::JOYSTICK::FeatureName& feature, + KODI::JOYSTICK::ANALOG_STICK_DIRECTION direction, + const KODI::JOYSTICK::CDriverPrimitive& primitive ) override; virtual bool GetAccelerometer( - const JOYSTICK::FeatureName& feature, - JOYSTICK::CDriverPrimitive& positiveX, - JOYSTICK::CDriverPrimitive& positiveY, - JOYSTICK::CDriverPrimitive& positiveZ + const KODI::JOYSTICK::FeatureName& feature, + KODI::JOYSTICK::CDriverPrimitive& positiveX, + KODI::JOYSTICK::CDriverPrimitive& positiveY, + KODI::JOYSTICK::CDriverPrimitive& positiveZ ) override; virtual void AddAccelerometer( - const JOYSTICK::FeatureName& feature, - const JOYSTICK::CDriverPrimitive& positiveX, - const JOYSTICK::CDriverPrimitive& positiveY, - const JOYSTICK::CDriverPrimitive& positiveZ + const KODI::JOYSTICK::FeatureName& feature, + const KODI::JOYSTICK::CDriverPrimitive& positiveX, + const KODI::JOYSTICK::CDriverPrimitive& positiveY, + const KODI::JOYSTICK::CDriverPrimitive& positiveZ ) override; - virtual void SetIgnoredPrimitives(const std::vector<JOYSTICK::CDriverPrimitive>& primitives) override; + virtual void SetIgnoredPrimitives(const std::vector<KODI::JOYSTICK::CDriverPrimitive>& primitives) override; - virtual bool IsIgnored(const JOYSTICK::CDriverPrimitive& primitive) override; + virtual bool IsIgnored(const KODI::JOYSTICK::CDriverPrimitive& primitive) override; virtual bool GetAxisProperties(unsigned int axisIndex, int& center, unsigned int& range) override; @@ -105,13 +105,13 @@ namespace PERIPHERALS virtual void RevertButtonMap() override; private: - typedef std::map<JOYSTICK::CDriverPrimitive, JOYSTICK::FeatureName> DriverMap; - typedef std::vector<JOYSTICK::CDriverPrimitive> JoystickPrimitiveVector; + typedef std::map<KODI::JOYSTICK::CDriverPrimitive, KODI::JOYSTICK::FeatureName> DriverMap; + typedef std::vector<KODI::JOYSTICK::CDriverPrimitive> JoystickPrimitiveVector; // Utility functions static DriverMap CreateLookupTable(const FeatureMap& features); - static JOYSTICK_FEATURE_PRIMITIVE GetPrimitiveIndex(JOYSTICK::ANALOG_STICK_DIRECTION dir); + static JOYSTICK_FEATURE_PRIMITIVE GetPrimitiveIndex(KODI::JOYSTICK::ANALOG_STICK_DIRECTION dir); CPeripheral* const m_device; std::weak_ptr<CPeripheralAddon> m_addon; diff --git a/xbmc/peripherals/addons/AddonButtonMapping.cpp b/xbmc/peripherals/addons/AddonButtonMapping.cpp index d7c08d0b32..8717033c87 100644 --- a/xbmc/peripherals/addons/AddonButtonMapping.cpp +++ b/xbmc/peripherals/addons/AddonButtonMapping.cpp @@ -25,6 +25,7 @@ #include "peripherals/Peripherals.h" #include "utils/log.h" +using namespace KODI; using namespace JOYSTICK; using namespace PERIPHERALS; diff --git a/xbmc/peripherals/addons/AddonButtonMapping.h b/xbmc/peripherals/addons/AddonButtonMapping.h index fa18d5ca7a..1474ef2a1a 100644 --- a/xbmc/peripherals/addons/AddonButtonMapping.h +++ b/xbmc/peripherals/addons/AddonButtonMapping.h @@ -24,28 +24,31 @@ #include <memory> +namespace KODI +{ namespace JOYSTICK { class CButtonMapping; class IButtonMap; class IButtonMapper; } +} namespace PERIPHERALS { class CPeripheral; - class CAddonButtonMapping : public JOYSTICK::IDriverHandler, - public JOYSTICK::IButtonMapCallback + class CAddonButtonMapping : public KODI::JOYSTICK::IDriverHandler, + public KODI::JOYSTICK::IButtonMapCallback { public: - CAddonButtonMapping(CPeripheral* peripheral, JOYSTICK::IButtonMapper* mapper); + CAddonButtonMapping(CPeripheral* peripheral, KODI::JOYSTICK::IButtonMapper* mapper); virtual ~CAddonButtonMapping(void); // implementation of IDriverHandler virtual bool OnButtonMotion(unsigned int buttonIndex, bool bPressed) override; - virtual bool OnHatMotion(unsigned int hatIndex, JOYSTICK::HAT_STATE state) override; + virtual bool OnHatMotion(unsigned int hatIndex, KODI::JOYSTICK::HAT_STATE state) override; virtual bool OnAxisMotion(unsigned int axisIndex, float position, int center, unsigned int range) override; virtual void ProcessAxisMotions(void) override; @@ -55,7 +58,7 @@ namespace PERIPHERALS virtual void RevertButtonMap() override; private: - std::unique_ptr<JOYSTICK::CButtonMapping> m_buttonMapping; - std::unique_ptr<JOYSTICK::IButtonMap> m_buttonMap; + std::unique_ptr<KODI::JOYSTICK::CButtonMapping> m_buttonMapping; + std::unique_ptr<KODI::JOYSTICK::IButtonMap> m_buttonMap; }; } diff --git a/xbmc/peripherals/addons/AddonInputHandling.cpp b/xbmc/peripherals/addons/AddonInputHandling.cpp index a598fbbafd..cc995ee0b5 100644 --- a/xbmc/peripherals/addons/AddonInputHandling.cpp +++ b/xbmc/peripherals/addons/AddonInputHandling.cpp @@ -28,6 +28,7 @@ #include "peripherals/Peripherals.h" #include "utils/log.h" +using namespace KODI; using namespace JOYSTICK; using namespace PERIPHERALS; diff --git a/xbmc/peripherals/addons/AddonInputHandling.h b/xbmc/peripherals/addons/AddonInputHandling.h index a1c7b2346f..b249792b99 100644 --- a/xbmc/peripherals/addons/AddonInputHandling.h +++ b/xbmc/peripherals/addons/AddonInputHandling.h @@ -24,37 +24,40 @@ #include <memory> +namespace KODI +{ namespace JOYSTICK { class IButtonMap; class IDriverReceiver; class IInputHandler; } +} namespace PERIPHERALS { class CPeripheral; - class CAddonInputHandling : public JOYSTICK::IDriverHandler, - public JOYSTICK::IInputReceiver + class CAddonInputHandling : public KODI::JOYSTICK::IDriverHandler, + public KODI::JOYSTICK::IInputReceiver { public: - CAddonInputHandling(CPeripheral* peripheral, JOYSTICK::IInputHandler* handler, JOYSTICK::IDriverReceiver* receiver); + CAddonInputHandling(CPeripheral* peripheral, KODI::JOYSTICK::IInputHandler* handler, KODI::JOYSTICK::IDriverReceiver* receiver); virtual ~CAddonInputHandling(void); // implementation of IDriverHandler virtual bool OnButtonMotion(unsigned int buttonIndex, bool bPressed) override; - virtual bool OnHatMotion(unsigned int hatIndex, JOYSTICK::HAT_STATE state) override; + virtual bool OnHatMotion(unsigned int hatIndex, KODI::JOYSTICK::HAT_STATE state) override; virtual bool OnAxisMotion(unsigned int axisIndex, float position, int center, unsigned int range) override; virtual void ProcessAxisMotions(void) override; // implementation of IInputReceiver - virtual bool SetRumbleState(const JOYSTICK::FeatureName& feature, float magnitude) override; + virtual bool SetRumbleState(const KODI::JOYSTICK::FeatureName& feature, float magnitude) override; private: - std::unique_ptr<JOYSTICK::IDriverHandler> m_driverHandler; - std::unique_ptr<JOYSTICK::IInputReceiver> m_inputReceiver; - std::unique_ptr<JOYSTICK::IButtonMap> m_buttonMap; + std::unique_ptr<KODI::JOYSTICK::IDriverHandler> m_driverHandler; + std::unique_ptr<KODI::JOYSTICK::IInputReceiver> m_inputReceiver; + std::unique_ptr<KODI::JOYSTICK::IButtonMap> m_buttonMap; }; } diff --git a/xbmc/peripherals/addons/PeripheralAddon.cpp b/xbmc/peripherals/addons/PeripheralAddon.cpp index b070ac7484..2b408fe980 100644 --- a/xbmc/peripherals/addons/PeripheralAddon.cpp +++ b/xbmc/peripherals/addons/PeripheralAddon.cpp @@ -43,6 +43,7 @@ #include <string.h> #include <utility> +using namespace KODI; using namespace JOYSTICK; using namespace PERIPHERALS; using namespace XFILE; diff --git a/xbmc/peripherals/addons/PeripheralAddon.h b/xbmc/peripherals/addons/PeripheralAddon.h index afb5c5760e..016a3fe793 100644 --- a/xbmc/peripherals/addons/PeripheralAddon.h +++ b/xbmc/peripherals/addons/PeripheralAddon.h @@ -30,11 +30,14 @@ #include <memory> #include <vector> +namespace KODI +{ namespace JOYSTICK { class IButtonMap; class IDriverHandler; } +} namespace PERIPHERALS { @@ -42,7 +45,7 @@ namespace PERIPHERALS class CPeripheralJoystick; typedef std::vector<ADDON::DriverPrimitive> PrimitiveVector; - typedef std::map<JOYSTICK::FeatureName, ADDON::JoystickFeature> FeatureMap; + typedef std::map<KODI::JOYSTICK::FeatureName, ADDON::JoystickFeature> FeatureMap; class CPeripheralAddon : public ADDON::CAddonDll { @@ -93,8 +96,8 @@ namespace PERIPHERALS void PowerOffJoystick(unsigned int index); //@} - void RegisterButtonMap(CPeripheral* device, JOYSTICK::IButtonMap* buttonMap); - void UnregisterButtonMap(JOYSTICK::IButtonMap* buttonMap); + void RegisterButtonMap(CPeripheral* device, KODI::JOYSTICK::IButtonMap* buttonMap); + void UnregisterButtonMap(KODI::JOYSTICK::IButtonMap* buttonMap); void RefreshButtonMaps(const std::string& strDeviceName = ""); protected: @@ -149,7 +152,7 @@ namespace PERIPHERALS std::map<unsigned int, PeripheralPtr> m_peripherals; /* @brief Button map observers */ - std::vector<std::pair<CPeripheral*, JOYSTICK::IButtonMap*> > m_buttonMaps; + std::vector<std::pair<CPeripheral*, KODI::JOYSTICK::IButtonMap*> > m_buttonMaps; CCriticalSection m_buttonMapMutex; /* @brief Thread synchronization */ diff --git a/xbmc/peripherals/addons/PeripheralAddonTranslator.cpp b/xbmc/peripherals/addons/PeripheralAddonTranslator.cpp index 3ab40dea6a..4c9725cc84 100644 --- a/xbmc/peripherals/addons/PeripheralAddonTranslator.cpp +++ b/xbmc/peripherals/addons/PeripheralAddonTranslator.cpp @@ -24,6 +24,7 @@ #include <algorithm> #include <iterator> +using namespace KODI; using namespace JOYSTICK; using namespace PERIPHERALS; diff --git a/xbmc/peripherals/addons/PeripheralAddonTranslator.h b/xbmc/peripherals/addons/PeripheralAddonTranslator.h index 88e74dc966..94388641cb 100644 --- a/xbmc/peripherals/addons/PeripheralAddonTranslator.h +++ b/xbmc/peripherals/addons/PeripheralAddonTranslator.h @@ -37,22 +37,22 @@ namespace PERIPHERALS static PeripheralType TranslateType(PERIPHERAL_TYPE type); static PERIPHERAL_TYPE TranslateType(PeripheralType type); - static JOYSTICK::CDriverPrimitive TranslatePrimitive(const ADDON::DriverPrimitive& primitive); - static ADDON::DriverPrimitive TranslatePrimitive(const JOYSTICK::CDriverPrimitive& primitive); + static KODI::JOYSTICK::CDriverPrimitive TranslatePrimitive(const ADDON::DriverPrimitive& primitive); + static ADDON::DriverPrimitive TranslatePrimitive(const KODI::JOYSTICK::CDriverPrimitive& primitive); - static std::vector<JOYSTICK::CDriverPrimitive> TranslatePrimitives(const std::vector<ADDON::DriverPrimitive>& primitives); - static std::vector<ADDON::DriverPrimitive> TranslatePrimitives(const std::vector<JOYSTICK::CDriverPrimitive>& primitives); + static std::vector<KODI::JOYSTICK::CDriverPrimitive> TranslatePrimitives(const std::vector<ADDON::DriverPrimitive>& primitives); + static std::vector<ADDON::DriverPrimitive> TranslatePrimitives(const std::vector<KODI::JOYSTICK::CDriverPrimitive>& primitives); - static JOYSTICK::HAT_DIRECTION TranslateHatDirection(JOYSTICK_DRIVER_HAT_DIRECTION dir); - static JOYSTICK_DRIVER_HAT_DIRECTION TranslateHatDirection(JOYSTICK::HAT_DIRECTION dir); + static KODI::JOYSTICK::HAT_DIRECTION TranslateHatDirection(JOYSTICK_DRIVER_HAT_DIRECTION dir); + static JOYSTICK_DRIVER_HAT_DIRECTION TranslateHatDirection(KODI::JOYSTICK::HAT_DIRECTION dir); - static JOYSTICK::HAT_STATE TranslateHatState(JOYSTICK_STATE_HAT state); + static KODI::JOYSTICK::HAT_STATE TranslateHatState(JOYSTICK_STATE_HAT state); - static JOYSTICK::SEMIAXIS_DIRECTION TranslateSemiAxisDirection(JOYSTICK_DRIVER_SEMIAXIS_DIRECTION dir); - static JOYSTICK_DRIVER_SEMIAXIS_DIRECTION TranslateSemiAxisDirection(JOYSTICK::SEMIAXIS_DIRECTION dir); + static KODI::JOYSTICK::SEMIAXIS_DIRECTION TranslateSemiAxisDirection(JOYSTICK_DRIVER_SEMIAXIS_DIRECTION dir); + static JOYSTICK_DRIVER_SEMIAXIS_DIRECTION TranslateSemiAxisDirection(KODI::JOYSTICK::SEMIAXIS_DIRECTION dir); - static JOYSTICK::FEATURE_TYPE TranslateFeatureType(JOYSTICK_FEATURE_TYPE type); - static JOYSTICK_FEATURE_TYPE TranslateFeatureType(JOYSTICK::FEATURE_TYPE type); + static KODI::JOYSTICK::FEATURE_TYPE TranslateFeatureType(JOYSTICK_FEATURE_TYPE type); + static JOYSTICK_FEATURE_TYPE TranslateFeatureType(KODI::JOYSTICK::FEATURE_TYPE type); static ADDON::DriverPrimitive Opposite(const ADDON::DriverPrimitive& semiaxis); }; diff --git a/xbmc/peripherals/bus/android/PeripheralBusAndroid.cpp b/xbmc/peripherals/bus/android/PeripheralBusAndroid.cpp index efb81a8fb5..56e8436b3d 100644 --- a/xbmc/peripherals/bus/android/PeripheralBusAndroid.cpp +++ b/xbmc/peripherals/bus/android/PeripheralBusAndroid.cpp @@ -31,6 +31,7 @@ #include "utils/log.h" #include "utils/StringUtils.h" +using namespace KODI; using namespace PERIPHERALS; static const std::string DeviceLocationPrefix = "android/inputdevice/"; diff --git a/xbmc/peripherals/bus/virtual/PeripheralBusAddon.cpp b/xbmc/peripherals/bus/virtual/PeripheralBusAddon.cpp index fcd3ff6062..9cc928fe32 100644 --- a/xbmc/peripherals/bus/virtual/PeripheralBusAddon.cpp +++ b/xbmc/peripherals/bus/virtual/PeripheralBusAddon.cpp @@ -31,6 +31,7 @@ #include <algorithm> #include <memory> +using namespace KODI; using namespace PERIPHERALS; CPeripheralBusAddon::CPeripheralBusAddon(CPeripherals *manager) : @@ -494,7 +495,7 @@ void CPeripheralBusAddon::UpdateAddons(void) bool CPeripheralBusAddon::PromptEnableAddons(const ADDON::VECADDONS& disabledAddons) { using namespace ADDON; - using namespace KODI::MESSAGING::HELPERS; + using namespace MESSAGING::HELPERS; // True if the user confirms enabling the disabled peripheral add-on bool bAccepted = false; diff --git a/xbmc/peripherals/devices/Peripheral.cpp b/xbmc/peripherals/devices/Peripheral.cpp index b0cf3de067..12968e3ec0 100644 --- a/xbmc/peripherals/devices/Peripheral.cpp +++ b/xbmc/peripherals/devices/Peripheral.cpp @@ -38,6 +38,7 @@ #include "Util.h" #include "filesystem/File.h" +using namespace KODI; using namespace JOYSTICK; using namespace PERIPHERALS; diff --git a/xbmc/peripherals/devices/Peripheral.h b/xbmc/peripherals/devices/Peripheral.h index f77dfa1910..cc2192c408 100644 --- a/xbmc/peripherals/devices/Peripheral.h +++ b/xbmc/peripherals/devices/Peripheral.h @@ -28,6 +28,8 @@ class TiXmlDocument; class CSetting; +namespace KODI +{ namespace JOYSTICK { class IActionMap; @@ -36,6 +38,7 @@ namespace JOYSTICK class IDriverReceiver; class IInputHandler; } +} namespace PERIPHERALS { @@ -192,18 +195,18 @@ namespace PERIPHERALS virtual bool ErrorOccured(void) const { return m_bError; } - virtual void RegisterJoystickDriverHandler(JOYSTICK::IDriverHandler* handler, bool bPromiscuous) { } - virtual void UnregisterJoystickDriverHandler(JOYSTICK::IDriverHandler* handler) { } + virtual void RegisterJoystickDriverHandler(KODI::JOYSTICK::IDriverHandler* handler, bool bPromiscuous) { } + virtual void UnregisterJoystickDriverHandler(KODI::JOYSTICK::IDriverHandler* handler) { } - virtual void RegisterJoystickInputHandler(JOYSTICK::IInputHandler* handler); - virtual void UnregisterJoystickInputHandler(JOYSTICK::IInputHandler* handler); + virtual void RegisterJoystickInputHandler(KODI::JOYSTICK::IInputHandler* handler); + virtual void UnregisterJoystickInputHandler(KODI::JOYSTICK::IInputHandler* handler); - virtual void RegisterJoystickButtonMapper(JOYSTICK::IButtonMapper* mapper); - virtual void UnregisterJoystickButtonMapper(JOYSTICK::IButtonMapper* mapper); + virtual void RegisterJoystickButtonMapper(KODI::JOYSTICK::IButtonMapper* mapper); + virtual void UnregisterJoystickButtonMapper(KODI::JOYSTICK::IButtonMapper* mapper); - virtual JOYSTICK::IDriverReceiver* GetDriverReceiver() { return nullptr; } + virtual KODI::JOYSTICK::IDriverReceiver* GetDriverReceiver() { return nullptr; } - virtual JOYSTICK::IActionMap* GetActionMap() { return nullptr; } + virtual KODI::JOYSTICK::IActionMap* GetActionMap() { return nullptr; } protected: virtual void ClearSettings(void); @@ -228,7 +231,7 @@ namespace PERIPHERALS std::map<std::string, PeripheralDeviceSetting> m_settings; std::set<std::string> m_changedSettings; CPeripheralBus* m_bus; - std::map<JOYSTICK::IInputHandler*, std::unique_ptr<JOYSTICK::IDriverHandler>> m_inputHandlers; - std::map<JOYSTICK::IButtonMapper*, JOYSTICK::IDriverHandler*> m_buttonMappers; + std::map<KODI::JOYSTICK::IInputHandler*, std::unique_ptr<KODI::JOYSTICK::IDriverHandler>> m_inputHandlers; + std::map<KODI::JOYSTICK::IButtonMapper*, KODI::JOYSTICK::IDriverHandler*> m_buttonMappers; }; } diff --git a/xbmc/peripherals/devices/PeripheralCecAdapter.cpp b/xbmc/peripherals/devices/PeripheralCecAdapter.cpp index 54dc37e751..5b5b38df65 100644 --- a/xbmc/peripherals/devices/PeripheralCecAdapter.cpp +++ b/xbmc/peripherals/devices/PeripheralCecAdapter.cpp @@ -38,7 +38,8 @@ #include <libcec/cec.h> -using namespace KODI::MESSAGING; +using namespace KODI; +using namespace MESSAGING; using namespace PERIPHERALS; using namespace ANNOUNCEMENT; using namespace CEC; diff --git a/xbmc/peripherals/devices/PeripheralJoystick.cpp b/xbmc/peripherals/devices/PeripheralJoystick.cpp index 2f47c09cab..493a261191 100644 --- a/xbmc/peripherals/devices/PeripheralJoystick.cpp +++ b/xbmc/peripherals/devices/PeripheralJoystick.cpp @@ -29,6 +29,7 @@ #include <algorithm> +using namespace KODI; using namespace JOYSTICK; using namespace PERIPHERALS; diff --git a/xbmc/peripherals/devices/PeripheralJoystick.h b/xbmc/peripherals/devices/PeripheralJoystick.h index 7695778f3a..03288c9946 100644 --- a/xbmc/peripherals/devices/PeripheralJoystick.h +++ b/xbmc/peripherals/devices/PeripheralJoystick.h @@ -32,17 +32,20 @@ #define JOYSTICK_PORT_UNKNOWN (-1) +namespace KODI +{ namespace JOYSTICK { class CDeadzoneFilter; class IButtonMap; class IDriverHandler; } +} namespace PERIPHERALS { class CPeripheralJoystick : public CPeripheral, //! @todo extend CPeripheralHID - public JOYSTICK::IDriverReceiver + public KODI::JOYSTICK::IDriverReceiver { public: CPeripheralJoystick(const PeripheralScanResult& scanResult, CPeripheralBus* bus); @@ -53,13 +56,13 @@ namespace PERIPHERALS virtual bool InitialiseFeature(const PeripheralFeature feature) override; virtual void OnUserNotification() override; virtual bool TestFeature(PeripheralFeature feature) override; - virtual void RegisterJoystickDriverHandler(JOYSTICK::IDriverHandler* handler, bool bPromiscuous) override; - virtual void UnregisterJoystickDriverHandler(JOYSTICK::IDriverHandler* handler) override; - virtual JOYSTICK::IDriverReceiver* GetDriverReceiver() override { return this; } - virtual JOYSTICK::IActionMap* GetActionMap() override { return &m_defaultInputHandler; } + virtual void RegisterJoystickDriverHandler(KODI::JOYSTICK::IDriverHandler* handler, bool bPromiscuous) override; + virtual void UnregisterJoystickDriverHandler(KODI::JOYSTICK::IDriverHandler* handler) override; + virtual KODI::JOYSTICK::IDriverReceiver* GetDriverReceiver() override { return this; } + virtual KODI::JOYSTICK::IActionMap* GetActionMap() override { return &m_defaultInputHandler; } bool OnButtonMotion(unsigned int buttonIndex, bool bPressed); - bool OnHatMotion(unsigned int hatIndex, JOYSTICK::HAT_STATE state); + bool OnHatMotion(unsigned int hatIndex, KODI::JOYSTICK::HAT_STATE state); bool OnAxisMotion(unsigned int axisIndex, float position); void ProcessAxisMotions(void); @@ -107,7 +110,7 @@ namespace PERIPHERALS struct DriverHandler { - JOYSTICK::IDriverHandler* handler; + KODI::JOYSTICK::IDriverHandler* handler; bool bPromiscuous; }; @@ -118,10 +121,10 @@ namespace PERIPHERALS unsigned int m_axisCount; unsigned int m_motorCount; bool m_supportsPowerOff; - JOYSTICK::CDefaultJoystick m_defaultInputHandler; - JOYSTICK::CJoystickMonitor m_joystickMonitor; - std::unique_ptr<JOYSTICK::IButtonMap> m_buttonMap; - std::unique_ptr<JOYSTICK::CDeadzoneFilter> m_deadzoneFilter; + KODI::JOYSTICK::CDefaultJoystick m_defaultInputHandler; + KODI::JOYSTICK::CJoystickMonitor m_joystickMonitor; + std::unique_ptr<KODI::JOYSTICK::IButtonMap> m_buttonMap; + std::unique_ptr<KODI::JOYSTICK::CDeadzoneFilter> m_deadzoneFilter; std::vector<DriverHandler> m_driverHandlers; CCriticalSection m_handlerMutex; }; diff --git a/xbmc/peripherals/devices/PeripheralJoystickEmulation.cpp b/xbmc/peripherals/devices/PeripheralJoystickEmulation.cpp index dceadeb478..266949b32b 100644 --- a/xbmc/peripherals/devices/PeripheralJoystickEmulation.cpp +++ b/xbmc/peripherals/devices/PeripheralJoystickEmulation.cpp @@ -25,6 +25,7 @@ #include <sstream> +using namespace KODI; using namespace PERIPHERALS; CPeripheralJoystickEmulation::CPeripheralJoystickEmulation(const PeripheralScanResult& scanResult, CPeripheralBus* bus) : diff --git a/xbmc/peripherals/devices/PeripheralJoystickEmulation.h b/xbmc/peripherals/devices/PeripheralJoystickEmulation.h index 1d22a63e8e..901aedde90 100644 --- a/xbmc/peripherals/devices/PeripheralJoystickEmulation.h +++ b/xbmc/peripherals/devices/PeripheralJoystickEmulation.h @@ -26,7 +26,7 @@ namespace PERIPHERALS { class CPeripheralJoystickEmulation : public CPeripheral, - public KEYBOARD::IKeyboardHandler + public KODI::KEYBOARD::IKeyboardHandler { public: CPeripheralJoystickEmulation(const PeripheralScanResult& scanResult, CPeripheralBus* bus); @@ -35,8 +35,8 @@ namespace PERIPHERALS // implementation of CPeripheral virtual bool InitialiseFeature(const PeripheralFeature feature) override; - virtual void RegisterJoystickDriverHandler(JOYSTICK::IDriverHandler* handler, bool bPromiscuous) override; - virtual void UnregisterJoystickDriverHandler(JOYSTICK::IDriverHandler* handler) override; + virtual void RegisterJoystickDriverHandler(KODI::JOYSTICK::IDriverHandler* handler, bool bPromiscuous) override; + virtual void UnregisterJoystickDriverHandler(KODI::JOYSTICK::IDriverHandler* handler) override; // implementation of IKeyboardHandler virtual bool OnKeyPress(const CKey& key) override; @@ -50,11 +50,11 @@ namespace PERIPHERALS private: struct KeyboardHandle { - KEYBOARD::IKeyboardHandler* handler; + KODI::KEYBOARD::IKeyboardHandler* handler; bool bPromiscuous; }; - typedef std::map<JOYSTICK::IDriverHandler*, KeyboardHandle> KeyboardHandlers; + typedef std::map<KODI::JOYSTICK::IDriverHandler*, KeyboardHandle> KeyboardHandlers; KeyboardHandlers m_keyboardHandlers; CCriticalSection m_mutex; diff --git a/xbmc/pictures/GUIViewStatePictures.cpp b/xbmc/pictures/GUIViewStatePictures.cpp index 226cb8a173..138e3a42c6 100644 --- a/xbmc/pictures/GUIViewStatePictures.cpp +++ b/xbmc/pictures/GUIViewStatePictures.cpp @@ -73,7 +73,7 @@ std::string CGUIViewStateWindowPictures::GetLockType() std::string CGUIViewStateWindowPictures::GetExtensions() { - std::string extensions = g_advancedSettings.m_pictureExtensions; + std::string extensions = g_advancedSettings.GetPictureExtensions(); if (CServiceBroker::GetSettings().GetBool(CSettings::SETTING_PICTURES_SHOWVIDEOS)) extensions += "|" + g_advancedSettings.m_videoExtensions; diff --git a/xbmc/pictures/PictureThumbLoader.cpp b/xbmc/pictures/PictureThumbLoader.cpp index 7f271c31d2..6b2c4ece87 100644 --- a/xbmc/pictures/PictureThumbLoader.cpp +++ b/xbmc/pictures/PictureThumbLoader.cpp @@ -183,7 +183,7 @@ void CPictureThumbLoader::ProcessFoldersAndArchives(CFileItem *pItem) CFileItemList items; - CDirectory::GetDirectory(pathToUrl, items, g_advancedSettings.m_pictureExtensions, DIR_FLAG_NO_FILE_DIRS); + CDirectory::GetDirectory(pathToUrl, items, g_advancedSettings.GetPictureExtensions(), DIR_FLAG_NO_FILE_DIRS); // create the folder thumb by choosing 4 random thumbs within the folder and putting // them into one thumb. @@ -202,7 +202,7 @@ void CPictureThumbLoader::ProcessFoldersAndArchives(CFileItem *pItem) { if (pItem->IsCBZ() || pItem->IsCBR()) { - CDirectory::GetDirectory(pathToUrl, items, g_advancedSettings.m_pictureExtensions, DIR_FLAG_NO_FILE_DIRS); + CDirectory::GetDirectory(pathToUrl, items, g_advancedSettings.GetPictureExtensions(), DIR_FLAG_NO_FILE_DIRS); for (int i=0;i<items.Size();++i) { CFileItemPtr item = items[i]; diff --git a/xbmc/platform/android/activity/XBMCApp.cpp b/xbmc/platform/android/activity/XBMCApp.cpp index 6d2b1ea2dc..46bdfa408a 100644 --- a/xbmc/platform/android/activity/XBMCApp.cpp +++ b/xbmc/platform/android/activity/XBMCApp.cpp @@ -87,7 +87,7 @@ #include "AndroidKey.h" #include "CompileInfo.h" -#include "video/videosync/VideoSyncAndroid.h" +#include "windowing/egl/VideoSyncAndroid.h" #define GIGABYTES 1073741824 diff --git a/xbmc/platform/android/jni/InetAddress.h b/xbmc/platform/android/jni/InetAddress.h index a8fb0f8e78..42119b41f9 100644 --- a/xbmc/platform/android/jni/InetAddress.h +++ b/xbmc/platform/android/jni/InetAddress.h @@ -47,4 +47,4 @@ protected: static const char *m_classname; }; -typedef std::vector<CJNIInetAddress> CJNIInetAddresss; +typedef std::vector<CJNIInetAddress> CJNIInetAddresses; diff --git a/xbmc/platform/darwin/ios/XBMCController.mm b/xbmc/platform/darwin/ios/XBMCController.mm index 380537e944..2d6b85fe56 100644 --- a/xbmc/platform/darwin/ios/XBMCController.mm +++ b/xbmc/platform/darwin/ios/XBMCController.mm @@ -37,7 +37,6 @@ #include "guilib/GUIControl.h" #include "input/Key.h" #include "windowing/WindowingFactory.h" -#include "video/VideoReferenceClock.h" #include "utils/log.h" #include "utils/TimeUtils.h" #include "Util.h" diff --git a/xbmc/platform/xbmc.cpp b/xbmc/platform/xbmc.cpp index 34e5ea67d4..5791e306ff 100644 --- a/xbmc/platform/xbmc.cpp +++ b/xbmc/platform/xbmc.cpp @@ -58,7 +58,7 @@ extern "C" int XBMC_Run(bool renderGUI, CFileItemList &playlist) #ifdef TARGET_RASPBERRY_PI if(!g_RBP.Initialize()) return false; - g_RBP.LogFirmwareVerison(); + g_RBP.LogFirmwareVersion(); #endif if (renderGUI && !g_application.CreateGUI()) diff --git a/xbmc/powermanagement/PowerManager.cpp b/xbmc/powermanagement/PowerManager.cpp index 6ec7cab205..86a7645866 100644 --- a/xbmc/powermanagement/PowerManager.cpp +++ b/xbmc/powermanagement/PowerManager.cpp @@ -278,7 +278,7 @@ void CPowerManager::OnWake() CGUIDialogBusy* dialog = (CGUIDialogBusy*)g_windowManager.GetWindow(WINDOW_DIALOG_BUSY); if (dialog) - dialog->Close(); + dialog->Close(true); // force close. no closing animation, sound etc at this early stage #if defined(HAS_SDL) || defined(TARGET_WINDOWS) if (g_Windowing.IsFullScreen()) diff --git a/xbmc/pvr/CMakeLists.txt b/xbmc/pvr/CMakeLists.txt index 8761e726f0..7b9181adc3 100644 --- a/xbmc/pvr/CMakeLists.txt +++ b/xbmc/pvr/CMakeLists.txt @@ -6,7 +6,8 @@ set(SOURCES PVRActionListener.cpp PVRContextMenus.cpp PVRGUIActions.cpp PVRItem.cpp - PVRChannelNumberInputHandler.cpp) + PVRChannelNumberInputHandler.cpp + PVRJobs.cpp) set(HEADERS PVRActionListener.h PVRDatabase.h @@ -18,6 +19,7 @@ set(HEADERS PVRActionListener.h PVRGUIActions.h PVRItem.h PVRTypes.h - PVRChannelNumberInputHandler.h) + PVRChannelNumberInputHandler.h + PVRJobs.h) core_add_library(pvr) diff --git a/xbmc/pvr/PVRActionListener.cpp b/xbmc/pvr/PVRActionListener.cpp index 9a6a04131c..002d1175a2 100644 --- a/xbmc/pvr/PVRActionListener.cpp +++ b/xbmc/pvr/PVRActionListener.cpp @@ -19,11 +19,15 @@ */ #include "Application.h" +#include "ServiceBroker.h" +#include "dialogs/GUIDialogNumeric.h" #include "guilib/GUIWindowManager.h" #include "input/Key.h" +#include "settings/Settings.h" #include "pvr/PVRGUIActions.h" #include "pvr/PVRManager.h" +#include "pvr/addons/PVRClients.h" #include "pvr/channels/PVRChannel.h" #include "PVRActionListener.h" @@ -31,16 +35,32 @@ namespace PVR { -CPVRActionListener::CPVRActionListener() -{ -} - CPVRActionListener &CPVRActionListener::GetInstance() { static CPVRActionListener instance; return instance; } +void CPVRActionListener::Init() +{ + std::set<std::string> settingSet; + settingSet.insert(CSettings::SETTING_PVRPARENTAL_ENABLED); + settingSet.insert(CSettings::SETTING_PVRMANAGER_RESETDB); + settingSet.insert(CSettings::SETTING_EPG_RESETEPG); + settingSet.insert(CSettings::SETTING_PVRMANAGER_CHANNELMANAGER); + settingSet.insert(CSettings::SETTING_PVRMANAGER_GROUPMANAGER); + settingSet.insert(CSettings::SETTING_PVRMANAGER_CHANNELSCAN); + settingSet.insert(CSettings::SETTING_PVRMENU_SEARCHICONS); + settingSet.insert(CSettings::SETTING_PVRCLIENT_MENUHOOK); + settingSet.insert(CSettings::SETTING_EPG_DAYSTODISPLAY); + CServiceBroker::GetSettings().RegisterCallback(this, settingSet); +} + +void CPVRActionListener::Deinit() +{ + CServiceBroker::GetSettings().UnregisterCallback(this); +} + bool CPVRActionListener::OnAction(const CAction &action) { bool bIsJumpSMS = false; @@ -58,19 +78,20 @@ bool CPVRActionListener::OnAction(const CAction &action) { case ACTION_PVR_PLAY: if (!isPlayingPvr) - g_PVRManager.StartPlayback(PlaybackTypeAny); + CPVRGUIActions::GetInstance().SwitchToChannel(PlaybackTypeAny); break; case ACTION_PVR_PLAY_TV: if (!isPlayingPvr || g_application.CurrentFileItem().GetPVRChannelInfoTag()->IsRadio()) - g_PVRManager.StartPlayback(PlaybackTypeTv); + CPVRGUIActions::GetInstance().SwitchToChannel(PlaybackTypeTV); break; case ACTION_PVR_PLAY_RADIO: if (!isPlayingPvr || !g_application.CurrentFileItem().GetPVRChannelInfoTag()->IsRadio()) - g_PVRManager.StartPlayback(PlaybackTypeRadio); + CPVRGUIActions::GetInstance().SwitchToChannel(PlaybackTypeRadio); break; } return true; } + case ACTION_JUMP_SMS2: case ACTION_JUMP_SMS3: case ACTION_JUMP_SMS4: @@ -111,4 +132,75 @@ bool CPVRActionListener::OnAction(const CAction &action) return false; } +void CPVRActionListener::OnSettingChanged(const CSetting *setting) +{ + if (setting == nullptr) + return; + + const std::string &settingId = setting->GetId(); + if (settingId == CSettings::SETTING_PVRPARENTAL_ENABLED) + { + if (dynamic_cast<const CSettingBool*>(setting)->GetValue() && CServiceBroker::GetSettings().GetString(CSettings::SETTING_PVRPARENTAL_PIN).empty()) + { + std::string newPassword = ""; + // password set... save it + if (CGUIDialogNumeric::ShowAndVerifyNewPassword(newPassword)) + CServiceBroker::GetSettings().SetString(CSettings::SETTING_PVRPARENTAL_PIN, newPassword); + // password not set... disable parental + else + dynamic_cast<CSettingBool*>(const_cast<CSetting*>(setting))->SetValue(false); + } + } +} + +void CPVRActionListener::OnSettingAction(const CSetting *setting) +{ + if (setting == nullptr) + return; + + const std::string &settingId = setting->GetId(); + if (settingId == CSettings::SETTING_PVRMANAGER_RESETDB) + { + CPVRGUIActions::GetInstance().ResetPVRDatabase(false); + } + else if (settingId == CSettings::SETTING_EPG_RESETEPG) + { + CPVRGUIActions::GetInstance().ResetPVRDatabase(true); + } + else if (settingId == CSettings::SETTING_PVRMANAGER_CHANNELMANAGER) + { + if (g_PVRManager.IsStarted()) + { + CGUIDialog *dialog = dynamic_cast<CGUIDialog *>(g_windowManager.GetWindow(WINDOW_DIALOG_PVR_CHANNEL_MANAGER)); + if (dialog) + dialog->Open(); + } + } + else if (settingId == CSettings::SETTING_PVRMANAGER_GROUPMANAGER) + { + if (g_PVRManager.IsStarted()) + { + CGUIDialog *dialog = dynamic_cast<CGUIDialog *>(g_windowManager.GetWindow(WINDOW_DIALOG_PVR_GROUP_MANAGER)); + if (dialog) + dialog->Open(); + } + } + else if (settingId == CSettings::SETTING_PVRMANAGER_CHANNELSCAN) + { + CPVRGUIActions::GetInstance().StartChannelScan(); + } + else if (settingId == CSettings::SETTING_PVRMENU_SEARCHICONS) + { + g_PVRManager.TriggerSearchMissingChannelIcons(); + } + else if (settingId == CSettings::SETTING_PVRCLIENT_MENUHOOK) + { + CPVRGUIActions::GetInstance().ProcessMenuHooks(CFileItemPtr()); + } + else if (settingId == CSettings::SETTING_EPG_DAYSTODISPLAY) + { + g_PVRClients->SetEPGTimeFrame(static_cast<const CSettingInt*>(setting)->GetValue()); + } +} + } // namespace PVR diff --git a/xbmc/pvr/PVRActionListener.h b/xbmc/pvr/PVRActionListener.h index 3bca56d6f7..2bb7bea95d 100644 --- a/xbmc/pvr/PVRActionListener.h +++ b/xbmc/pvr/PVRActionListener.h @@ -21,23 +21,32 @@ */ #include "interfaces/IActionListener.h" +#include "settings/lib/ISettingCallback.h" namespace PVR { -class CPVRActionListener : public IActionListener +class CPVRActionListener : public IActionListener, public ISettingCallback { public: + void Init(); + void Deinit(); + static CPVRActionListener &GetInstance(); - bool OnAction(const CAction &action); + // IActionListener implementation + bool OnAction(const CAction &action) override; + + // ISettingCallback implementation + void OnSettingChanged(const CSetting *setting) override; + void OnSettingAction(const CSetting *setting) override; private: - CPVRActionListener(); - CPVRActionListener(const CPVRActionListener&); - CPVRActionListener& operator=(const CPVRActionListener&); - ~CPVRActionListener() {}; + CPVRActionListener() = default; + ~CPVRActionListener() = default; + CPVRActionListener(const CPVRActionListener&) = delete; + CPVRActionListener& operator=(const CPVRActionListener&) = delete; }; } // namespace PVR diff --git a/xbmc/pvr/PVRChannelNumberInputHandler.cpp b/xbmc/pvr/PVRChannelNumberInputHandler.cpp index 09d0207fbe..87b52a752a 100644 --- a/xbmc/pvr/PVRChannelNumberInputHandler.cpp +++ b/xbmc/pvr/PVRChannelNumberInputHandler.cpp @@ -62,7 +62,7 @@ void CPVRChannelNumberInputHandler::AppendChannelNumberDigit(int iDigit) // recalc channel string m_strChannel.erase(); - if (m_digits.size() != m_iMaxDigits || GetChannelNumber() > 0) + if (m_digits.size() != (size_t)m_iMaxDigits || GetChannelNumber() > 0) { for (int digit : m_digits) m_strChannel.append(StringUtils::Format("%d", digit)); diff --git a/xbmc/pvr/PVRContextMenus.cpp b/xbmc/pvr/PVRContextMenus.cpp index 0a6053aab2..fc77c084de 100644 --- a/xbmc/pvr/PVRContextMenus.cpp +++ b/xbmc/pvr/PVRContextMenus.cpp @@ -499,21 +499,9 @@ namespace PVR bool PVRClientMenuHook::Execute(const CFileItemPtr &item) const { - if (item->IsEPG() && item->GetEPGInfoTag()->HasPVRChannel()) - g_PVRClients->ProcessMenuHooks(item->GetEPGInfoTag()->ChannelTag()->ClientID(), PVR_MENUHOOK_EPG, item.get()); - else if (item->IsPVRChannel()) - g_PVRClients->ProcessMenuHooks(item->GetPVRChannelInfoTag()->ClientID(), PVR_MENUHOOK_CHANNEL, item.get()); - else if (item->IsDeletedPVRRecording()) - g_PVRClients->ProcessMenuHooks(item->GetPVRRecordingInfoTag()->m_iClientId, PVR_MENUHOOK_DELETED_RECORDING, item.get()); - else if (item->IsUsablePVRRecording()) - g_PVRClients->ProcessMenuHooks(item->GetPVRRecordingInfoTag()->m_iClientId, PVR_MENUHOOK_RECORDING, item.get()); - else if (item->IsPVRTimer()) - g_PVRClients->ProcessMenuHooks(item->GetPVRTimerInfoTag()->m_iClientId, PVR_MENUHOOK_TIMER, item.get()); - else - return false; - - return true; + return CPVRGUIActions::GetInstance().ProcessMenuHooks(item);; } + } // namespace CONEXTMENUITEM CPVRContextMenuManager& CPVRContextMenuManager::GetInstance() diff --git a/xbmc/pvr/PVRDatabase.cpp b/xbmc/pvr/PVRDatabase.cpp index 60504489b9..234567d38c 100644 --- a/xbmc/pvr/PVRDatabase.cpp +++ b/xbmc/pvr/PVRDatabase.cpp @@ -62,12 +62,10 @@ void CPVRDatabase::CreateTables() "bIsVirtual bool, " "bEPGEnabled bool, " "sEPGScraper varchar(32), " - "iLastWatched integer," - - //! @todo use mapping table - "iClientId integer, " - - "idEpg integer" + "iLastWatched integer, " + "iClientId integer, " //! @todo use mapping table + "idEpg integer, " + "bWasPlayingOnQuit bool" ")" ); @@ -138,12 +136,13 @@ void CPVRDatabase::UpdateTables(int iVersion) m_pDS->exec("ALTER TABLE channelgroups ADD bIsHidden bool"); if (iVersion < 28) - { m_pDS->exec("DROP TABLE clients"); - } if (iVersion < 29) m_pDS->exec("ALTER TABLE channelgroups ADD iPosition integer"); + + if (iVersion < 30) + m_pDS->exec("ALTER TABLE channels ADD bWasPlayingOnQuit bool"); } /********** Channel methods **********/ @@ -652,6 +651,46 @@ bool CPVRDatabase::Persist(CPVRChannel &channel) return bReturn; } +bool CPVRDatabase::SetWasPlayingOnLastQuit(const CPVRChannel &channel, bool bSet, bool& bWasPlaying) +{ + bool bRet = false; + + // Obtain previous value. + try + { + const std::string strSQL(PrepareSQL("SELECT bWasPlayingOnQuit FROM channels WHERE iUniqueId = %u AND iClientId = %u", + channel.UniqueID(), channel.ClientID())); + m_pDS->query(strSQL); + if (m_pDS->num_rows() > 0) + { + bWasPlaying = m_pDS->fv(0).get_asBool(); + bRet = true; + } + else + { + CLog::Log(LOGERROR, "PVR - %s - couldn't obtain value from channels (no rows)", __FUNCTION__); + } + m_pDS->close(); + } + catch (...) + { + CLog::Log(LOGERROR, "PVR - %s - couldn't obtain value from channels (exception)", __FUNCTION__); + } + + // Set new value. + if (bRet && bSet != bWasPlaying) + bRet = SetWasPlayingOnLastQuit(channel, bSet); + + return bRet; +} + +bool CPVRDatabase::SetWasPlayingOnLastQuit(const CPVRChannel &channel, bool bSet) +{ + const std::string strQuery(PrepareSQL("UPDATE channels SET bWasPlayingOnQuit = %i WHERE iUniqueId = %u AND iClientId = %u", + bSet, channel.UniqueID(), channel.ClientID())); + return ExecuteQuery(strQuery); +} + bool CPVRDatabase::UpdateLastWatched(const CPVRChannel &channel) { std::string strQuery = PrepareSQL("UPDATE channels SET iLastWatched = %d WHERE idChannel = %d", diff --git a/xbmc/pvr/PVRDatabase.h b/xbmc/pvr/PVRDatabase.h index 11be7b469e..5f44d5a756 100644 --- a/xbmc/pvr/PVRDatabase.h +++ b/xbmc/pvr/PVRDatabase.h @@ -56,7 +56,7 @@ namespace PVR * @brief Get the minimal database version that is required to operate correctly. * @return The minimal database version. */ - virtual int GetSchemaVersion() const { return 29; }; + virtual int GetSchemaVersion() const { return 30; }; /*! * @brief Get the default sqlite database filename. @@ -145,6 +145,23 @@ namespace PVR //@{ /*! + * @brief Sets the 'was playing on last app quit' flag for a channel. + * @param channel the channel + * @param bSet True to set the flag, false to reset the flag + * @return True if the operation was successful, false otherwise + */ + bool SetWasPlayingOnLastQuit(const CPVRChannel &channel, bool bSet); + + /*! + * @brief Sets the 'was playing on last app quit' flag for a channel. + * @param channel the channel + * @param bSet True to set the flag, false to reset the flag + * @param bWasPlaying on return contains the previous value of the flag + * @return True if the operation was successful, false otherwise + */ + bool SetWasPlayingOnLastQuit(const CPVRChannel &channel, bool bSet, bool& bWasPlaying); + + /*! * @brief Updates the last watched timestamp for the channel * @param channel the channel * @return whether the update was successful diff --git a/xbmc/pvr/PVRGUIActions.cpp b/xbmc/pvr/PVRGUIActions.cpp index 3265b143b0..8a14690b8e 100644 --- a/xbmc/pvr/PVRGUIActions.cpp +++ b/xbmc/pvr/PVRGUIActions.cpp @@ -20,8 +20,12 @@ #include "Application.h" #include "dialogs/GUIDialogKaiToast.h" +#include "dialogs/GUIDialogNumeric.h" #include "dialogs/GUIDialogOK.h" +#include "dialogs/GUIDialogProgress.h" +#include "dialogs/GUIDialogSelect.h" #include "dialogs/GUIDialogYesNo.h" +#include "epg/EpgContainer.h" #include "epg/EpgInfoTag.h" #include "FileItem.h" #include "filesystem/Directory.h" @@ -31,14 +35,17 @@ #include "guilib/LocalizeStrings.h" #include "input/Key.h" #include "messaging/ApplicationMessenger.h" +#include "pvr/addons/PVRClients.h" #include "pvr/channels/PVRChannelGroupsContainer.h" #include "pvr/dialogs/GUIDialogPVRGuideInfo.h" #include "pvr/dialogs/GUIDialogPVRRecordingInfo.h" #include "pvr/dialogs/GUIDialogPVRTimerSettings.h" +#include "pvr/PVRDatabase.h" #include "pvr/PVRItem.h" #include "pvr/PVRManager.h" #include "pvr/timers/PVRTimers.h" #include "pvr/recordings/PVRRecordings.h" +#include "pvr/recordings/PVRRecordingsPath.h" #include "pvr/windows/GUIWindowPVRSearch.h" #include "ServiceBroker.h" #include "settings/MediaSettings.h" @@ -61,10 +68,15 @@ namespace PVR return instance; } + CPVRGUIActions::CPVRGUIActions() + : m_bChannelScanRunning(false) + { + } + bool CPVRGUIActions::ShowEPGInfo(const CFileItemPtr &item) const { const CPVRChannelPtr channel(CPVRItem(item).GetChannel()); - if (channel && !g_PVRManager.CheckParentalLock(channel)) + if (channel && !CheckParentalLock(channel)) return false; const CEpgInfoTagPtr epgTag(CPVRItem(item).GetEpgInfoTag()); @@ -147,7 +159,7 @@ namespace PVR if (ShowTimerSettings(newTimer)) { /* Add timer to backend */ - return g_PVRTimers->AddTimer(newTimer); + return AddTimer(newTimer); } return false; } @@ -171,7 +183,7 @@ namespace PVR return false; } - if (!g_PVRManager.CheckParentalLock(channel)) + if (!CheckParentalLock(channel)) return false; const CEpgInfoTagPtr epgTag(CPVRItem(item).GetEpgInfoTag()); @@ -205,7 +217,267 @@ namespace PVR return false; } - return g_PVRTimers->AddTimer(newTimer); + return AddTimer(newTimer); + } + + bool CPVRGUIActions::AddTimer(const CPVRTimerInfoTagPtr &item) const + { + if (!item->m_channel && item->GetTimerType() && !item->GetTimerType()->IsEpgBasedTimerRule()) + { + CLog::Log(LOGERROR, "CPVRGUIActions - %s - no channel given", __FUNCTION__); + CGUIDialogOK::ShowAndGetInput(CVariant{19033}, CVariant{19109}); // "Information", "Couldn't save timer. Check the log for more information about this message." + return false; + } + + if (!g_PVRClients->SupportsTimers(item->m_iClientId)) + { + CGUIDialogOK::ShowAndGetInput(CVariant{19033}, CVariant{19215}); // "Information", "The PVR backend does not support timers." + return false; + } + + if (!CheckParentalLock(item->m_channel)) + return false; + + return g_PVRTimers->AddTimer(item); + } + + namespace + { + enum PVRRECORD_INSTANTRECORDACTION + { + NONE = -1, + RECORD_CURRENT_SHOW = 0, + RECORD_INSTANTRECORDTIME = 1, + ASK = 2, + RECORD_30_MINUTES = 3, + RECORD_60_MINUTES = 4, + RECORD_120_MINUTES = 5, + RECORD_NEXT_SHOW = 6 + }; + + class InstantRecordingActionSelector + { + public: + InstantRecordingActionSelector(); + virtual ~InstantRecordingActionSelector() {} + + void AddAction(PVRRECORD_INSTANTRECORDACTION eAction, const std::string &title); + void PreSelectAction(PVRRECORD_INSTANTRECORDACTION eAction); + PVRRECORD_INSTANTRECORDACTION Select(); + + private: + CGUIDialogSelect *m_pDlgSelect; // not owner! + std::map<PVRRECORD_INSTANTRECORDACTION, int> m_actions; + }; + + InstantRecordingActionSelector::InstantRecordingActionSelector() + : m_pDlgSelect(dynamic_cast<CGUIDialogSelect *>(g_windowManager.GetWindow(WINDOW_DIALOG_SELECT))) + { + if (m_pDlgSelect) + { + m_pDlgSelect->SetMultiSelection(false); + m_pDlgSelect->SetHeading(CVariant{19086}); // Instant recording action + } + else + { + CLog::Log(LOGERROR, "InstantRecordingActionSelector - %s - unable to obtain WINDOW_DIALOG_SELECT instance", __FUNCTION__); + } + } + + void InstantRecordingActionSelector::AddAction(PVRRECORD_INSTANTRECORDACTION eAction, const std::string &title) + { + if (m_actions.find(eAction) == m_actions.end()) + { + switch (eAction) + { + case RECORD_INSTANTRECORDTIME: + m_pDlgSelect->Add(StringUtils::Format(g_localizeStrings.Get(19090).c_str(), + CServiceBroker::GetSettings().GetInt(CSettings::SETTING_PVRRECORD_INSTANTRECORDTIME))); // Record next <default duration> minutes + break; + case RECORD_30_MINUTES: + m_pDlgSelect->Add(StringUtils::Format(g_localizeStrings.Get(19090).c_str(), 30)); // Record next 30 minutes + break; + case RECORD_60_MINUTES: + m_pDlgSelect->Add(StringUtils::Format(g_localizeStrings.Get(19090).c_str(), 60)); // Record next 60 minutes + break; + case RECORD_120_MINUTES: + m_pDlgSelect->Add(StringUtils::Format(g_localizeStrings.Get(19090).c_str(), 120)); // Record next 120 minutes + break; + case RECORD_CURRENT_SHOW: + m_pDlgSelect->Add(StringUtils::Format(g_localizeStrings.Get(19091).c_str(), title.c_str())); // Record current show (<title>) + break; + case RECORD_NEXT_SHOW: + m_pDlgSelect->Add(StringUtils::Format(g_localizeStrings.Get(19092).c_str(), title.c_str())); // Record next show (<title>) + break; + case NONE: + case ASK: + default: + return; + } + + m_actions.insert(std::make_pair(eAction, m_actions.size())); + } + } + + void InstantRecordingActionSelector::PreSelectAction(PVRRECORD_INSTANTRECORDACTION eAction) + { + const auto &it = m_actions.find(eAction); + if (it != m_actions.end()) + m_pDlgSelect->SetSelected(it->second); + } + + PVRRECORD_INSTANTRECORDACTION InstantRecordingActionSelector::Select() + { + PVRRECORD_INSTANTRECORDACTION eAction = NONE; + + m_pDlgSelect->Open(); + + if (m_pDlgSelect->IsConfirmed()) + { + int iSelection = m_pDlgSelect->GetSelectedItem(); + for (const auto &action : m_actions) + { + if (action.second == iSelection) + { + eAction = action.first; + break; + } + } + } + + return eAction; + } + + } // unnamed namespace + + bool CPVRGUIActions::SetRecordingOnChannel(const CPVRChannelPtr &channel, bool bOnOff) + { + bool bReturn = false; + + if (!channel) + return bReturn; + + if (!CheckParentalLock(channel)) + return bReturn; + + if (g_PVRClients->HasTimerSupport(channel->ClientID())) + { + /* timers are supported on this channel */ + if (bOnOff && !channel->IsRecording()) + { + CEpgInfoTagPtr epgTag; + int iDuration = CServiceBroker::GetSettings().GetInt(CSettings::SETTING_PVRRECORD_INSTANTRECORDTIME); + + int iAction = CServiceBroker::GetSettings().GetInt(CSettings::SETTING_PVRRECORD_INSTANTRECORDACTION); + switch (iAction) + { + case RECORD_CURRENT_SHOW: + epgTag = channel->GetEPGNow(); + break; + + case RECORD_INSTANTRECORDTIME: + epgTag.reset(); + break; + + case ASK: + { + PVRRECORD_INSTANTRECORDACTION ePreselect = RECORD_INSTANTRECORDTIME; + InstantRecordingActionSelector selector; + CEpgInfoTagPtr epgTagNext; + + // fixed length recordings + selector.AddAction(RECORD_30_MINUTES, ""); + selector.AddAction(RECORD_60_MINUTES, ""); + selector.AddAction(RECORD_120_MINUTES, ""); + + const int iDurationDefault = CServiceBroker::GetSettings().GetInt(CSettings::SETTING_PVRRECORD_INSTANTRECORDTIME); + if (iDurationDefault != 30 && iDurationDefault != 60 && iDurationDefault != 120) + selector.AddAction(RECORD_INSTANTRECORDTIME, ""); + + // epg-based recordings + epgTag = channel->GetEPGNow(); + if (epgTag) + { + // "now" + selector.AddAction(RECORD_CURRENT_SHOW, epgTag->Title()); + ePreselect = RECORD_CURRENT_SHOW; + + // "next" + epgTagNext = channel->GetEPGNext(); + if (epgTagNext) + { + selector.AddAction(RECORD_NEXT_SHOW, epgTagNext->Title()); + + // be smart. if current show is almost over, preselect next show. + if (epgTag->ProgressPercentage() > 90.0f) + ePreselect = RECORD_NEXT_SHOW; + } + } + + selector.PreSelectAction(ePreselect); + + PVRRECORD_INSTANTRECORDACTION eSelected = selector.Select(); + switch (eSelected) + { + case NONE: + return false; // dialog canceled + + case RECORD_30_MINUTES: + iDuration = 30; + epgTag.reset(); + break; + + case RECORD_60_MINUTES: + iDuration = 60; + epgTag.reset(); + break; + + case RECORD_120_MINUTES: + iDuration = 120; + epgTag.reset(); + break; + + case RECORD_INSTANTRECORDTIME: + iDuration = iDurationDefault; + epgTag.reset(); + break; + + case RECORD_CURRENT_SHOW: + break; + + case RECORD_NEXT_SHOW: + epgTag = epgTagNext; + break; + + default: + CLog::Log(LOGERROR, "PVRManager - %s - unknown instant record action selection (%d), defaulting to fixed length recording.", __FUNCTION__, eSelected); + epgTag.reset(); + break; + } + break; + } + + default: + CLog::Log(LOGERROR, "PVRManager - %s - unknown instant record action setting value (%d), defaulting to fixed length recording.", __FUNCTION__, iAction); + break; + } + + const CPVRTimerInfoTagPtr newTimer(epgTag ? CPVRTimerInfoTag::CreateFromEpg(epgTag, false) : CPVRTimerInfoTag::CreateInstantTimerTag(channel, iDuration)); + + if (newTimer) + bReturn = newTimer->AddToClient(); + + if (!bReturn) + CGUIDialogOK::ShowAndGetInput(CVariant{19033}, CVariant{19164}); // "Information", "Can't start recording. Check the log for more information about this message." + } + else if (!bOnOff && channel->IsRecording()) + { + /* delete active timers */ + bReturn = g_PVRTimers->DeleteTimersOnChannel(channel, true, true); + } + } + + return bReturn; } bool CPVRGUIActions::ToggleTimer(const CFileItemPtr &item) const @@ -266,11 +538,11 @@ namespace PVR // end up with one timer missing wrt to the rule defined by the new timer. if (g_PVRTimers->DeleteTimer(timer, timer->IsRecording(), false)) { - if (g_PVRTimers->AddTimer(newTimer)) + if (AddTimer(newTimer)) return true; // rollback. - return g_PVRTimers->AddTimer(timer); + return AddTimer(timer); } } } @@ -419,7 +691,10 @@ namespace PVR return false; if (!g_PVRRecordings->RenameRecording(*item, strNewName)) + { + CGUIDialogOK::ShowAndGetInput(CVariant{257}, CVariant{19111}); // "Error", "PVR backend error. Check the log for more information about this message." return false; + } g_PVRManager.TriggerRecordingsUpdate(); return true; @@ -434,7 +709,10 @@ namespace PVR return false; if (!g_PVRRecordings->Delete(*item)) + { + CGUIDialogOK::ShowAndGetInput(CVariant{257}, CVariant{19111}); // "Error", "PVR backend error. Check the log for more information about this message." return false; + } g_PVRManager.TriggerRecordingsUpdate(); return true; @@ -477,7 +755,10 @@ namespace PVR /* undelete the recording */ if (!g_PVRRecordings->Undelete(*item)) + { + CGUIDialogOK::ShowAndGetInput(CVariant{257}, CVariant{19111}); // "Error", "PVR backend error. Check the log for more information about this message." return false; + } g_PVRManager.TriggerRecordingsUpdate(); return true; @@ -534,9 +815,8 @@ namespace PVR return PlayRecording(item, false); } - void CPVRGUIActions::CheckAndSwitchToFullscreen() const + void CPVRGUIActions::CheckAndSwitchToFullscreen(bool bFullscreen) const { - const bool bFullscreen(CServiceBroker::GetSettings().GetBool(CSettings::SETTING_PVRPLAYBACK_SWITCHTOFULLSCREEN)); CMediaSettings::GetInstance().SetVideoStartWindowed(!bFullscreen); if (bFullscreen) @@ -546,7 +826,7 @@ namespace PVR } } - bool CPVRGUIActions::TryFastChannelSwitch(const CPVRChannelPtr &channel) const + bool CPVRGUIActions::TryFastChannelSwitch(const CPVRChannelPtr &channel, bool bFullscreen) const { bool bSwitchSuccessful(false); @@ -557,16 +837,16 @@ namespace PVR bSwitchSuccessful = g_application.m_pPlayer->SwitchChannel(channel); if (bSwitchSuccessful) - CheckAndSwitchToFullscreen(); + CheckAndSwitchToFullscreen(bFullscreen); } return bSwitchSuccessful; } - void CPVRGUIActions::StartPlayback(CFileItem *item) const + void CPVRGUIActions::StartPlayback(CFileItem *item, bool bFullscreen) const { CApplicationMessenger::GetInstance().PostMsg(TMSG_MEDIA_PLAY, 0, 0, static_cast<void*>(item)); - CheckAndSwitchToFullscreen(); + CheckAndSwitchToFullscreen(bFullscreen); } bool CPVRGUIActions::PlayRecording(const CFileItemPtr &item, bool bCheckResume) const @@ -589,7 +869,7 @@ namespace PVR { CFileItem *itemToPlay = new CFileItem(recording); itemToPlay->m_lStartOffset = item->m_lStartOffset; - StartPlayback(itemToPlay); + StartPlayback(itemToPlay, true); } return true; } @@ -641,13 +921,18 @@ namespace PVR } if (!bCheckResume || CheckResumeRecording(item)) - StartPlayback(new CFileItem(*item)); + StartPlayback(new CFileItem(*item), true); return true; } bool CPVRGUIActions::SwitchToChannel(const CFileItemPtr &item, bool bCheckResume) const { + return SwitchToChannel(item, bCheckResume, CServiceBroker::GetSettings().GetBool(CSettings::SETTING_PVRPLAYBACK_SWITCHTOFULLSCREEN)); + } + + bool CPVRGUIActions::SwitchToChannel(const CFileItemPtr &item, bool bCheckResume, bool bFullscreen) const + { if (item->m_bIsFolder) return false; @@ -663,7 +948,7 @@ namespace PVR // switch to channel or if recording present, ask whether to switch or play recording... bool bSwitchSuccessful(false); - if (channel && g_PVRManager.CheckParentalLock(channel)) + if (channel && CheckParentalLock(channel)) { const CPVRRecordingPtr recording(channel->GetRecording()); if (recording) @@ -688,11 +973,11 @@ namespace PVR } /* optimization: try a fast switch */ - bSwitchSuccessful = TryFastChannelSwitch(channel); + bSwitchSuccessful = TryFastChannelSwitch(channel, bFullscreen); if (!bSwitchSuccessful) { - StartPlayback(new CFileItem(channel)); + StartPlayback(new CFileItem(channel), bFullscreen); return true; } } @@ -711,6 +996,93 @@ namespace PVR return true; } + bool CPVRGUIActions::SwitchToChannel(PlaybackType type) const + { + CFileItemPtr channel; + bool bIsRadio(false); + + // check if the desired PlaybackType is already playing, + // and if not, try to grab the last played channel of this type + switch (type) + { + case PlaybackTypeRadio: + if (g_PVRManager.IsPlayingRadio()) + return true; + + channel = g_PVRChannelGroups->GetGroupAllRadio()->GetLastPlayedChannel(); + bIsRadio = true; + break; + + case PlaybackTypeTV: + if (g_PVRManager.IsPlayingTV()) + return true; + + channel = g_PVRChannelGroups->GetGroupAllTV()->GetLastPlayedChannel(); + break; + + default: + if (g_PVRManager.IsPlaying()) + return true; + + channel = g_PVRChannelGroups->GetLastPlayedChannel(); + break; + } + + // if we have a last played channel, start playback + if (channel && channel->HasPVRChannelInfoTag()) + { + return SwitchToChannel(channel, true); + } + else + { + // if we don't, find the active channel group of the demanded type and play it's first channel + const CPVRChannelGroupPtr channelGroup(g_PVRManager.GetPlayingGroup(bIsRadio)); + if (channelGroup) + { + // try to start playback of first channel in this group + std::vector<PVRChannelGroupMember> groupMembers(channelGroup->GetMembers()); + if (!groupMembers.empty()) + { + return SwitchToChannel(CFileItemPtr(new CFileItem((*groupMembers.begin()).channel)), true); + } + } + } + + CLog::Log(LOGNOTICE, "PVRGUIActions - %s - could not determine %s channel to start playback with. No last played channel found, and first channel of active group could also not be determined.", __FUNCTION__, bIsRadio ? "Radio": "TV"); + + CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Error, + g_localizeStrings.Get(19166), // PVR information + StringUtils::Format(g_localizeStrings.Get(19035).c_str(), + g_localizeStrings.Get(bIsRadio ? 19021 : 19020).c_str())); // Radio/TV could not be played. Check the log for details. + return false; + } + + bool CPVRGUIActions::ContinueLastPlayedChannel() const + { + const CFileItemPtr item(g_PVRChannelGroups->GetLastPlayedChannel()); + const CPVRChannelPtr channel(item ? item->GetPVRChannelInfoTag() : CPVRChannelPtr()); + bool bWasPlaying = false; + if (channel) + { + // Obtain previous 'was playing on last app quit' flag and reset it, then. + channel->SetWasPlayingOnLastQuit(false, bWasPlaying); + } + + int iPlayMode = CServiceBroker::GetSettings().GetInt(CSettings::SETTING_PVRPLAYBACK_STARTLAST); + if (iPlayMode == CONTINUE_LAST_CHANNEL_OFF) + return false; + + // Only switch to the channel if it was playing on last app quit. + if (bWasPlaying) + { + CLog::Log(LOGNOTICE, "PVRGUIActions - %s - continue playback on channel '%s'", __FUNCTION__, channel->ChannelName().c_str()); + g_PVRManager.SetPlayingGroup(g_PVRChannelGroups->GetLastPlayedGroup(channel->ChannelID())); + return SwitchToChannel(item, true, iPlayMode == CONTINUE_LAST_CHANNEL_IN_FOREGROUND); + } + + return false; + } + bool CPVRGUIActions::PlayMedia(const CFileItemPtr &item) const { CFileItemPtr pvrItem(item); @@ -761,6 +1133,333 @@ namespace PVR return true; } + bool CPVRGUIActions::StartChannelScan() + { + if (!g_PVRManager.IsStarted() || IsRunningChannelScan()) + return false; + + PVR_CLIENT scanClient; + std::vector<PVR_CLIENT> possibleScanClients = g_PVRClients->GetClientsSupportingChannelScan(); + m_bChannelScanRunning = true; + + /* multiple clients found */ + if (possibleScanClients.size() > 1) + { + CGUIDialogSelect* pDialog= dynamic_cast<CGUIDialogSelect*>(g_windowManager.GetWindow(WINDOW_DIALOG_SELECT)); + if (!pDialog) + { + CLog::Log(LOGERROR, "CPVRGUIActions - %s - unable to get WINDOW_DIALOG_SELECT!", __FUNCTION__); + m_bChannelScanRunning = false; + return false; + } + + pDialog->Reset(); + pDialog->SetHeading(CVariant{19119}); // "On which backend do you want to search?" + + for (const auto client : possibleScanClients) + pDialog->Add(client->GetFriendlyName()); + + pDialog->Open(); + + int selection = pDialog->GetSelectedItem(); + if (selection >= 0) + scanClient = possibleScanClients[selection]; + } + /* one client found */ + else if (possibleScanClients.size() == 1) + { + scanClient = possibleScanClients[0]; + } + /* no clients found */ + else if (!scanClient) + { + CGUIDialogOK::ShowAndGetInput(CVariant{19033}, // "Information" + CVariant{19192}); // "None of the connected PVR backends supports scanning for channels." + m_bChannelScanRunning = false; + return false; + } + + /* start the channel scan */ + CLog::Log(LOGNOTICE,"CPVRGUIActions - %s - starting to scan for channels on client %s", + __FUNCTION__, scanClient->GetFriendlyName().c_str()); + long perfCnt = XbmcThreads::SystemClockMillis(); + + /* do the scan */ + if (scanClient->StartChannelScan() != PVR_ERROR_NO_ERROR) + CGUIDialogOK::ShowAndGetInput(CVariant{257}, // "Error" + CVariant{19193}); // "The channel scan can't be started. Check the log for more information about this message." + + CLog::Log(LOGNOTICE, "CPVRGUIActions - %s - channel scan finished after %li.%li seconds", + __FUNCTION__, (XbmcThreads::SystemClockMillis() - perfCnt) / 1000, (XbmcThreads::SystemClockMillis() - perfCnt) % 1000); + m_bChannelScanRunning = false; + return true; + } + + bool CPVRGUIActions::ProcessMenuHooks(const CFileItemPtr &item) + { + if (!g_PVRManager.IsStarted()) + return false; + + int iClientID = -1; + PVR_MENUHOOK_CAT menuCategory = PVR_MENUHOOK_SETTING; + + if (item->IsEPG()) + { + if (item->GetEPGInfoTag()->HasPVRChannel()) + { + iClientID = item->GetEPGInfoTag()->ChannelTag()->ClientID(); + menuCategory = PVR_MENUHOOK_EPG; + } + else + return false; + } + else if (item->IsPVRChannel()) + { + iClientID = item->GetPVRChannelInfoTag()->ClientID(); + menuCategory = PVR_MENUHOOK_CHANNEL; + } + else if (item->IsDeletedPVRRecording()) + { + iClientID = item->GetPVRRecordingInfoTag()->m_iClientId; + menuCategory = PVR_MENUHOOK_DELETED_RECORDING; + } + else if (item->IsUsablePVRRecording()) + { + iClientID = item->GetPVRRecordingInfoTag()->m_iClientId; + menuCategory = PVR_MENUHOOK_RECORDING; + } + else if (item->IsPVRTimer()) + { + iClientID = item->GetPVRTimerInfoTag()->m_iClientId; + menuCategory = PVR_MENUHOOK_TIMER; + } + + // get client id + if (iClientID < 0 && menuCategory == PVR_MENUHOOK_SETTING) + { + PVR_CLIENTMAP clients; + g_PVRClients->GetCreatedClients(clients); + + if (clients.size() == 1) + { + iClientID = clients.begin()->first; + } + else if (clients.size() > 1) + { + // have user select client + CGUIDialogSelect* pDialog= dynamic_cast<CGUIDialogSelect*>(g_windowManager.GetWindow(WINDOW_DIALOG_SELECT)); + if (!pDialog) + { + CLog::Log(LOGERROR, "CPVRGUIActions - %s - unable to get WINDOW_DIALOG_SELECT!", __FUNCTION__); + return false; + } + + pDialog->Reset(); + pDialog->SetHeading(CVariant{19196}); // "PVR client specific actions" + + for (const auto client : clients) + { + pDialog->Add(client.second->GetBackendName()); + } + + pDialog->Open(); + + int selection = pDialog->GetSelectedItem(); + if (selection >= 0) + { + auto client = clients.begin(); + std::advance(client, selection); + iClientID = client->first; + } + } + } + + if (iClientID < 0) + iClientID = g_PVRClients->GetPlayingClientID(); + + PVR_CLIENT client; + if (g_PVRClients->GetCreatedClient(iClientID, client) && client->HasMenuHooks(menuCategory)) + { + CGUIDialogSelect* pDialog= dynamic_cast<CGUIDialogSelect*>(g_windowManager.GetWindow(WINDOW_DIALOG_SELECT)); + if (!pDialog) + { + CLog::Log(LOGERROR, "CPVRGUIActions - %s - unable to get WINDOW_DIALOG_SELECT!", __FUNCTION__); + return false; + } + + pDialog->Reset(); + pDialog->SetHeading(CVariant{19196}); // "PVR client specific actions" + + PVR_MENUHOOKS *hooks = client->GetMenuHooks(); + std::vector<int> hookIDs; + int selection = 0; + + for (unsigned int i = 0; i < hooks->size(); ++i) + { + if (hooks->at(i).category == menuCategory || hooks->at(i).category == PVR_MENUHOOK_ALL) + { + pDialog->Add(g_localizeStrings.GetAddonString(client->ID(), hooks->at(i).iLocalizedStringId)); + hookIDs.push_back(i); + } + } + + if (hookIDs.size() > 1) + { + pDialog->Open(); + selection = pDialog->GetSelectedItem(); + } + + if (selection >= 0) + client->CallMenuHook(hooks->at(hookIDs.at(selection)), item.get()); + else + return false; + } + + return true; + } + + bool CPVRGUIActions::ResetPVRDatabase(bool bResetEPGOnly) + { + CLog::Log(LOGNOTICE,"CPVRGUIActions - %s - clearing the PVR database", __FUNCTION__); + + CGUIDialogProgress* pDlgProgress = dynamic_cast<CGUIDialogProgress*>(g_windowManager.GetWindow(WINDOW_DIALOG_PROGRESS)); + if (!pDlgProgress) + { + CLog::Log(LOGERROR, "CPVRGUIActions - %s - unable to get WINDOW_DIALOG_PROGRESS!", __FUNCTION__); + return false; + } + + if (bResetEPGOnly) + { + if (!CGUIDialogYesNo::ShowAndGetInput(CVariant{19098}, // "Warning!" + CVariant{19188})) // "All your guide data will be cleared. Are you sure?" + return false; + } + else + { + if (!CheckParentalPIN() || + !CGUIDialogYesNo::ShowAndGetInput(CVariant{19098}, // "Warning!" + CVariant{19186})) // "All your TV related data (channels, groups, guide) will be cleared. Are you sure?" + return false; + } + + CDateTime::ResetTimezoneBias(); + + g_EpgContainer.Stop(); + + pDlgProgress->SetHeading(CVariant{313}); // "Cleaning database" + pDlgProgress->SetLine(0, CVariant{g_localizeStrings.Get(19187)}); // "Clearing all related data." + pDlgProgress->SetLine(1, CVariant{""}); + pDlgProgress->SetLine(2, CVariant{""}); + + pDlgProgress->Open(); + pDlgProgress->Progress(); + + if (g_PVRManager.IsPlaying()) + { + CLog::Log(LOGNOTICE,"CPVRGUIActions - %s - stopping playback", __FUNCTION__); + CApplicationMessenger::GetInstance().SendMsg(TMSG_MEDIA_STOP); + } + + pDlgProgress->SetPercentage(10); + pDlgProgress->Progress(); + + /* reset the EPG pointers */ + const CPVRDatabasePtr database(g_PVRManager.GetTVDatabase()); + if (database) + database->ResetEPG(); + + /* stop the thread, close database */ + g_PVRManager.Stop(); + + pDlgProgress->SetPercentage(20); + pDlgProgress->Progress(); + + if (database && database->Open()) + { + /* clean the EPG database */ + g_EpgContainer.Reset(); + pDlgProgress->SetPercentage(30); + pDlgProgress->Progress(); + + if (!bResetEPGOnly) + { + database->DeleteChannelGroups(); + pDlgProgress->SetPercentage(50); + pDlgProgress->Progress(); + + /* delete all channels */ + database->DeleteChannels(); + pDlgProgress->SetPercentage(70); + pDlgProgress->Progress(); + + /* delete all channel and recording settings */ + CVideoDatabase videoDatabase; + + if (videoDatabase.Open()) + { + videoDatabase.EraseVideoSettings("pvr://channels/"); + videoDatabase.EraseVideoSettings(CPVRRecordingsPath::PATH_RECORDINGS); + videoDatabase.Close(); + } + + pDlgProgress->SetPercentage(80); + pDlgProgress->Progress(); + + /* delete all client information */ + pDlgProgress->SetPercentage(90); + pDlgProgress->Progress(); + } + + database->Close(); + } + + CLog::Log(LOGNOTICE,"CPVRGUIActions - %s - %s database cleared", __FUNCTION__, bResetEPGOnly ? "EPG" : "PVR and EPG"); + + if (database) + database->Open(); + + CLog::Log(LOGNOTICE,"CPVRGUIActions - %s - restarting the PVRManager", __FUNCTION__); + g_PVRManager.Start(); + + pDlgProgress->SetPercentage(100); + pDlgProgress->Close(); + return true; + } + + bool CPVRGUIActions::CheckParentalLock(const CPVRChannelPtr &channel) const + { + bool bReturn = !g_PVRManager.IsParentalLocked(channel) || CheckParentalPIN(); + + if (!bReturn) + CLog::Log(LOGERROR, "CPVRGUIActions - %s - parental lock verification failed for channel '%s': wrong PIN entered.", __FUNCTION__, channel->ChannelName().c_str()); + + return bReturn; + } + + bool CPVRGUIActions::CheckParentalPIN() const + { + std::string pinCode = CServiceBroker::GetSettings().GetString(CSettings::SETTING_PVRPARENTAL_PIN); + + if (!CServiceBroker::GetSettings().GetBool(CSettings::SETTING_PVRPARENTAL_ENABLED) || pinCode.empty()) + return true; + + // Locked channel. Enter PIN: + bool bValidPIN = CGUIDialogNumeric::ShowAndVerifyInput(pinCode, g_localizeStrings.Get(19262), true); // "Parental control. Enter PIN:" + if (!bValidPIN) + { + // display message: The entered PIN number was incorrect + CGUIDialogOK::ShowAndGetInput(CVariant{19264}, CVariant{19265}); // "Incorrect PIN", "The entered PIN was incorrect." + } + else + { + // restart the parental timer + g_PVRManager.RestartParentalTimer(); + } + + return bValidPIN; + } + CPVRChannelNumberInputHandler &CPVRGUIActions::GetChannelNumberInputHandler() { // window/dialog specific input handler diff --git a/xbmc/pvr/PVRGUIActions.h b/xbmc/pvr/PVRGUIActions.h index eabc2d5df2..43ff28eba0 100644 --- a/xbmc/pvr/PVRGUIActions.h +++ b/xbmc/pvr/PVRGUIActions.h @@ -32,6 +32,13 @@ class CGUIWindow; namespace PVR { + enum PlaybackType + { + PlaybackTypeAny = 0, + PlaybackTypeTV, + PlaybackTypeRadio + }; + class CPVRChannelSwitchingInputHandler : public CPVRChannelNumberInputHandler { public: @@ -91,6 +98,12 @@ namespace PVR bool AddTimer(const CFileItemPtr &item, bool bShowTimerSettings) const; /*! + * @brief Add a timer to the client. Doesn't add the timer to the container. The backend will do this. + * @return True if it was sent correctly, false if not. + */ + bool AddTimer(const CPVRTimerInfoTagPtr &item) const; + + /*! * @brief Create a new timer rule, either interactive or non-interactive. * @param item containing epg data to create a timer rule for. item must be an epg tag or a channel. * @param bShowTimerSettings is used to control whether a settings dialog will be opened prior creating the timer rule. @@ -155,6 +168,14 @@ namespace PVR bool ShowRecordingInfo(const CFileItemPtr &item) const; /*! + * @brief Start or stop recording on a given channel. + * @param channel the channel to start/stop recording. + * @param bOnOff True to start recording, false to stop. + * @return True if the recording was started or stopped successfully, false otherwise. + */ + bool SetRecordingOnChannel(const CPVRChannelPtr &channel, bool bOnOff); + + /*! * @brief Stop a currently active recording, always showing a confirmation dialog. * @param item containing a recording to stop. item must be a timer, an epg tag or a channel. * @return true, if the recording was stopped successfully, false otherwise. @@ -227,6 +248,19 @@ namespace PVR bool PlayMedia(const CFileItemPtr &item) const; /*! + * @brief Start playback of the last played channel, and if there is none, play first channel in the current channelgroup. + * @param type The type of playback to be started (any, radio, tv). See PlaybackType enum + * @return True if playback was started, false otherwise. + */ + bool SwitchToChannel(PlaybackType type) const; + + /*! + * @brief Continue playback of the last played channel. + * @return True if playback was continued, false otherwise. + */ + bool ContinueLastPlayedChannel() const; + + /*! * @brief Hide a channel, always showing a confirmation dialog. * @param item containing a channel or an epg tag. * @return true on success, false otherwise. @@ -234,13 +268,51 @@ namespace PVR bool HideChannel(const CFileItemPtr &item) const; /*! + * @brief Open a selection dialog and start a channel scan on the selected client. + * @return true on success, false otherwise. + */ + bool StartChannelScan(); + + /*! + * @return True when a channel scan is currently running, false otherwise. + */ + bool IsRunningChannelScan() const { return m_bChannelScanRunning; } + + /*! + * @brief Open selection and progress PVR actions. + * @param item The selected file item for which the hook was called. + * @return true on success, false otherwise. + */ + bool ProcessMenuHooks(const CFileItemPtr &item); + + /*! + * @brief Reset the TV database to it's initial state and delete all the data. + * @param bResetEPGOnly True to only reset the EPG database, false to reset both PVR and EPG database. + * @return true on success, false otherwise. + */ + bool ResetPVRDatabase(bool bResetEPGOnly); + + /*! + * @brief Check if channel is parental locked. Ask for PIN if necessary. + * @param channel The channel to do the check for. + * @return True if channel is unlocked (by default or PIN unlocked), false otherwise. + */ + bool CheckParentalLock(const CPVRChannelPtr &channel) const; + + /*! + * @brief Open Numeric dialog to check for parental PIN. + * @return True if entered PIN was correct, false otherwise. + */ + bool CheckParentalPIN() const; + + /*! * @brief Get the currently active channel number input handler. * @return the handler. */ CPVRChannelNumberInputHandler &GetChannelNumberInputHandler(); private: - CPVRGUIActions() = default; + CPVRGUIActions(); CPVRGUIActions(const CPVRGUIActions&) = delete; CPVRGUIActions const& operator=(CPVRGUIActions const&) = delete; virtual ~CPVRGUIActions() {} @@ -310,24 +382,38 @@ namespace PVR /*! * @brief Check "play minimized" settings value and switch to fullscreen if not set. + * @param bFullscreen switch to fullscreen or set windowed playback. */ - void CheckAndSwitchToFullscreen() const; + void CheckAndSwitchToFullscreen(bool bFullscreen) const; + + /*! + * @brief Switch channel. + * @param item containing a channel or an epg tag. + * @param bCheckResume controls resume check in case a recording for the current epg event is present. + * @param bFullscreen start playback fullscreen or not. + * @return true on success, false otherwise. + */ + bool SwitchToChannel(const CFileItemPtr &item, bool bCheckResume, bool bFullscreen) const; /*! * @brief Try a fast Live TV/Radio channel switch. Calls directly into active player instead of using messaging * @param channel the channel to switch to. + * @param bFullscreen start playback fullscreen or not. * @return true if the switch was succesful, false otherwise. */ - bool TryFastChannelSwitch(const CPVRChannelPtr &channel) const; + bool TryFastChannelSwitch(const CPVRChannelPtr &channel, bool bFullscreen) const; /*! * @brief Start playback of the given item. + * @param bFullscreen start playback fullscreen or not. * @param item containing a channel or a recording. */ - void StartPlayback(CFileItem *item) const; + void StartPlayback(CFileItem *item, bool bFullscreen) const; private: CPVRChannelSwitchingInputHandler m_channelNumberInputHandler; + bool m_bChannelScanRunning; + }; } // namespace PVR diff --git a/xbmc/pvr/PVRJobs.cpp b/xbmc/pvr/PVRJobs.cpp new file mode 100644 index 0000000000..135256c516 --- /dev/null +++ b/xbmc/pvr/PVRJobs.cpp @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2012-2015 Team Kodi + * http://kodi.tv + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Kodi; see the file COPYING. If not, see + * <http://www.gnu.org/licenses/>. + * + */ + +#include "PVRJobs.h" + +#include "dialogs/GUIDialogKaiToast.h" +#include "events/EventLog.h" +#include "events/NotificationEvent.h" + +#include "pvr/PVRGUIActions.h" + +namespace PVR +{ + +bool CPVRSetRecordingOnChannelJob::DoWork() +{ + return CPVRGUIActions::GetInstance().SetRecordingOnChannel(m_channel, m_bOnOff); +} + +bool CPVRContinueLastChannelJob::DoWork() +{ + return CPVRGUIActions::GetInstance().ContinueLastPlayedChannel(); +} + +CPVREventlogJob::CPVREventlogJob(bool bNotifyUser, bool bError, const std::string &label, const std::string &msg, const std::string &icon) +{ + AddEvent(bNotifyUser, bError, label, msg, icon); +} + +void CPVREventlogJob::AddEvent(bool bNotifyUser, bool bError, const std::string &label, const std::string &msg, const std::string &icon) +{ + m_events.emplace_back(Event(bNotifyUser, bError, label, msg, icon)); +} + +bool CPVREventlogJob::DoWork() +{ + for (const auto &event : m_events) + { + if (event.m_bNotifyUser) + CGUIDialogKaiToast::QueueNotification( + event.m_bError ? CGUIDialogKaiToast::Error : CGUIDialogKaiToast::Info, event.m_label.c_str(), event.m_msg, 5000, true); + + // Write event log entry. + CEventLog::GetInstance().Add( + EventPtr(new CNotificationEvent(event.m_label, event.m_msg, event.m_icon, event.m_bError ? EventLevel::Error : EventLevel::Information))); + } + return true; +} + +} // namespace PVR diff --git a/xbmc/pvr/PVRJobs.h b/xbmc/pvr/PVRJobs.h new file mode 100644 index 0000000000..4671e1bf46 --- /dev/null +++ b/xbmc/pvr/PVRJobs.h @@ -0,0 +1,81 @@ +#pragma once +/* + * Copyright (C) 2012-2013 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC; see the file COPYING. If not, see + * <http://www.gnu.org/licenses/>. + * + */ + +#include <vector> + +#include "utils/JobManager.h" + +#include "pvr/PVRTypes.h" + +namespace PVR +{ + class CPVRSetRecordingOnChannelJob : public CJob + { + public: + CPVRSetRecordingOnChannelJob(const CPVRChannelPtr &channel, bool bOnOff) + : m_channel(channel), m_bOnOff(bOnOff) {} + virtual ~CPVRSetRecordingOnChannelJob() = default; + const char *GetType() const override { return "pvr-set-recording-on-channel"; } + + bool DoWork() override; + private: + CPVRChannelPtr m_channel; + bool m_bOnOff; + }; + + class CPVRContinueLastChannelJob : public CJob + { + public: + CPVRContinueLastChannelJob() = default; + virtual ~CPVRContinueLastChannelJob() = default; + const char *GetType() const override { return "pvr-continue-last-channel-job"; } + + bool DoWork() override; + }; + + class CPVREventlogJob : public CJob + { + public: + CPVREventlogJob() = default; + CPVREventlogJob(bool bNotifyUser, bool bError, const std::string &label, const std::string &msg, const std::string &icon); + virtual ~CPVREventlogJob() = default; + const char *GetType() const override { return "pvr-eventlog-job"; } + + void AddEvent(bool bNotifyUser, bool bError, const std::string &label, const std::string &msg, const std::string &icon); + + bool DoWork() override; + private: + struct Event + { + bool m_bNotifyUser; + bool m_bError; + std::string m_label; + std::string m_msg; + std::string m_icon; + + Event(bool bNotifyUser, bool bError, const std::string &label, const std::string &msg, const std::string &icon) + : m_bNotifyUser(bNotifyUser), m_bError(bError), m_label(label), m_msg(msg), m_icon(icon) {} + }; + + std::vector<Event> m_events; + }; + +} // namespace PVR diff --git a/xbmc/pvr/PVRManager.cpp b/xbmc/pvr/PVRManager.cpp index 6887349a23..7795c50f73 100644 --- a/xbmc/pvr/PVRManager.cpp +++ b/xbmc/pvr/PVRManager.cpp @@ -26,15 +26,12 @@ #include "Application.h" #include "dialogs/GUIDialogExtendedProgressBar.h" #include "dialogs/GUIDialogKaiToast.h" -#include "dialogs/GUIDialogNumeric.h" -#include "dialogs/GUIDialogOK.h" -#include "dialogs/GUIDialogProgress.h" -#include "dialogs/GUIDialogSelect.h" #include "epg/EpgContainer.h" #include "GUIInfoManager.h" #include "guilib/GUIWindowManager.h" #include "guilib/LocalizeStrings.h" #include "interfaces/AnnouncementManager.h" +#include "input/Key.h" #include "messaging/ApplicationMessenger.h" #include "messaging/helpers/DialogHelper.h" #include "music/tags/MusicInfoTag.h" @@ -44,11 +41,10 @@ #include "pvr/channels/PVRChannel.h" #include "pvr/channels/PVRChannelGroupInternal.h" #include "pvr/channels/PVRChannelGroupsContainer.h" -#include "pvr/dialogs/GUIDialogPVRChannelManager.h" -#include "pvr/dialogs/GUIDialogPVRGroupManager.h" #include "pvr/PVRActionListener.h" #include "pvr/PVRDatabase.h" #include "pvr/PVRGUIInfo.h" +#include "pvr/PVRJobs.h" #include "pvr/recordings/PVRRecordings.h" #include "pvr/recordings/PVRRecordingsPath.h" #include "pvr/timers/PVRTimers.h" @@ -170,7 +166,6 @@ CPVRManager::CPVRManager(void) : CPVRManager::~CPVRManager(void) { - CServiceBroker::GetSettings().UnregisterCallback(this); CAnnouncementManager::GetInstance().RemoveAnnouncer(this); CLog::Log(LOGDEBUG,"PVRManager - destroyed"); } @@ -182,13 +177,21 @@ void CPVRManager::Announce(AnnouncementFlag flag, const char *sender, const char if ((flag & (ANNOUNCEMENT::System))) { - if (strcmp(message, "OnWake") == 0) + if (strcmp(message, "OnQuit") == 0 || + strcmp(message, "OnSleep") == 0) + { + // save the currently playing channel. + const CPVRChannelPtr playingChannel(GetCurrentChannel()); + if (playingChannel) + playingChannel->SetWasPlayingOnLastQuit(true); + } + else if (strcmp(message, "OnWake") == 0) { /* start job to search for missing channel icons */ TriggerSearchMissingChannelIcons(); /* continue last watched channel */ - ContinueLastChannel(); + TriggerContinueLastChannel(); /* trigger PVR data updates */ TriggerChannelGroupsUpdate(); @@ -246,89 +249,6 @@ CPVRClientsPtr CPVRManager::Clients(void) const return m_addons; } -void CPVRManager::OnSettingChanged(const CSetting *setting) -{ - if (setting == NULL) - return; - - const std::string &settingId = setting->GetId(); - if (settingId == CSettings::SETTING_PVRPARENTAL_ENABLED) - { - if (((CSettingBool*)setting)->GetValue() && CServiceBroker::GetSettings().GetString(CSettings::SETTING_PVRPARENTAL_PIN).empty()) - { - std::string newPassword = ""; - // password set... save it - if (CGUIDialogNumeric::ShowAndVerifyNewPassword(newPassword)) - CServiceBroker::GetSettings().SetString(CSettings::SETTING_PVRPARENTAL_PIN, newPassword); - // password not set... disable parental - else - ((CSettingBool*)setting)->SetValue(false); - } - } - else if(settingId == CSettings::SETTING_EPG_DAYSTODISPLAY) - { - m_addons->SetEPGTimeFrame(static_cast<const CSettingInt*>(setting)->GetValue()); - } -} - -void CPVRManager::OnSettingAction(const CSetting *setting) -{ - if (setting == NULL) - return; - - const std::string &settingId = setting->GetId(); - if (settingId == CSettings::SETTING_PVRMENU_SEARCHICONS) - { - if (IsStarted()) - TriggerSearchMissingChannelIcons(); - } - else if (settingId == CSettings::SETTING_PVRMANAGER_RESETDB) - { - if (CheckParentalPIN(g_localizeStrings.Get(19262)) && - HELPERS::ShowYesNoDialogText(CVariant{19098}, CVariant{19186}) == DialogResponse::YES) - { - CDateTime::ResetTimezoneBias(); - ResetDatabase(false); - } - } - else if (settingId == CSettings::SETTING_EPG_RESETEPG) - { - if (HELPERS::ShowYesNoDialogText(CVariant{19098}, CVariant{19188}) == DialogResponse::YES) - { - CDateTime::ResetTimezoneBias(); - ResetDatabase(true); - } - } - else if (settingId == CSettings::SETTING_PVRMANAGER_CHANNELSCAN) - { - if (IsStarted()) - StartChannelScan(); - } - else if (settingId == CSettings::SETTING_PVRMANAGER_CHANNELMANAGER) - { - if (IsStarted()) - { - CGUIDialogPVRChannelManager *dialog = (CGUIDialogPVRChannelManager *)g_windowManager.GetWindow(WINDOW_DIALOG_PVR_CHANNEL_MANAGER); - if (dialog) - dialog->Open(); - } - } - else if (settingId == CSettings::SETTING_PVRMANAGER_GROUPMANAGER) - { - if (IsStarted()) - { - CGUIDialogPVRGroupManager *dialog = (CGUIDialogPVRGroupManager *)g_windowManager.GetWindow(WINDOW_DIALOG_PVR_GROUP_MANAGER); - if (dialog) - dialog->Open(); - } - } - else if (settingId == CSettings::SETTING_PVRCLIENT_MENUHOOK) - { - if (IsStarted()) - m_addons->ProcessMenuHooks(-1, PVR_MENUHOOK_SETTING, NULL); - } -} - void CPVRManager::Clear(void) { g_application.UnregisterActionListener(&CPVRActionListener::GetInstance()); @@ -366,17 +286,8 @@ void CPVRManager::ResetProperties(void) void CPVRManager::Init() { - std::set<std::string> settingSet; - settingSet.insert(CSettings::SETTING_PVRMANAGER_CHANNELMANAGER); - settingSet.insert(CSettings::SETTING_PVRMANAGER_GROUPMANAGER); - settingSet.insert(CSettings::SETTING_PVRMANAGER_CHANNELSCAN); - settingSet.insert(CSettings::SETTING_PVRMANAGER_RESETDB); - settingSet.insert(CSettings::SETTING_PVRCLIENT_MENUHOOK); - settingSet.insert(CSettings::SETTING_PVRMENU_SEARCHICONS); - settingSet.insert(CSettings::SETTING_EPG_RESETEPG); - settingSet.insert(CSettings::SETTING_EPG_DAYSTODISPLAY); - settingSet.insert(CSettings::SETTING_PVRPARENTAL_ENABLED); - CServiceBroker::GetSettings().RegisterCallback(this, settingSet); + // Create and init action listener + CPVRActionListener::GetInstance().Init(); // Note: we're holding the progress bar dialog instance pointer in a member because it is needed by pvr core // components. The latter might run in a different thread than the gui and g_windowManager.GetWindow() @@ -485,6 +396,9 @@ void CPVRManager::Shutdown() // release addons m_addons.reset(); + + // deinit action listener + CPVRActionListener::GetInstance().Deinit(); } CPVRManager::ManagerState CPVRManager::GetState(void) const @@ -587,9 +501,8 @@ void CPVRManager::Process(void) /* start job to search for missing channel icons */ TriggerSearchMissingChannelIcons(); - /* try to continue last watched channel otherwise set group to last played group */ - if (!ContinueLastChannel()) - SetPlayingGroup(m_channelGroups->GetLastPlayedGroup()); + /* try to continue last watched channel */ + TriggerContinueLastChannel(); } /* execute the next pending jobs if there are any */ try @@ -771,108 +684,9 @@ bool CPVRManager::ChannelUpDown(unsigned int *iNewChannelNumber, bool bPreview, return bReturn; } -bool CPVRManager::ContinueLastChannel(void) +void CPVRManager::TriggerContinueLastChannel(void) { - if (CServiceBroker::GetSettings().GetInt(CSettings::SETTING_PVRPLAYBACK_STARTLAST) == CONTINUE_LAST_CHANNEL_OFF) - return false; - - CFileItemPtr channel = m_channelGroups->GetLastPlayedChannel(); - if (channel && channel->HasPVRChannelInfoTag()) - { - CLog::Log(LOGNOTICE, "PVRManager - %s - continue playback on channel '%s'", __FUNCTION__, channel->GetPVRChannelInfoTag()->ChannelName().c_str()); - SetPlayingGroup(m_channelGroups->GetLastPlayedGroup(channel->GetPVRChannelInfoTag()->ChannelID())); - StartPlayback(channel->GetPVRChannelInfoTag(), (CServiceBroker::GetSettings().GetInt(CSettings::SETTING_PVRPLAYBACK_STARTLAST) == CONTINUE_LAST_CHANNEL_IN_BACKGROUND)); - return true; - } - - CLog::Log(LOGDEBUG, "PVRManager - %s - no last played channel to continue playback found", __FUNCTION__); - - return false; -} - -void CPVRManager::ResetDatabase(bool bResetEPGOnly /* = false */) -{ - CLog::Log(LOGNOTICE,"PVRManager - %s - clearing the PVR database", __FUNCTION__); - - g_EpgContainer.Stop(); - - CGUIDialogProgress* pDlgProgress = (CGUIDialogProgress*)g_windowManager.GetWindow(WINDOW_DIALOG_PROGRESS); - pDlgProgress->SetHeading(CVariant{313}); - pDlgProgress->SetLine(0, CVariant{g_localizeStrings.Get(19187)}); // All data in the PVR database is being erased - pDlgProgress->SetLine(1, CVariant{""}); - pDlgProgress->SetLine(2, CVariant{""}); - pDlgProgress->Open(); - pDlgProgress->Progress(); - - if (m_addons->IsPlaying()) - { - CLog::Log(LOGNOTICE,"PVRManager - %s - stopping playback", __FUNCTION__); - CApplicationMessenger::GetInstance().SendMsg(TMSG_MEDIA_STOP); - } - - pDlgProgress->SetPercentage(10); - pDlgProgress->Progress(); - - /* reset the EPG pointers */ - const CPVRDatabasePtr database(GetTVDatabase()); - if (database) - database->ResetEPG(); - - /* stop the thread, close database */ - Stop(); - - pDlgProgress->SetPercentage(20); - pDlgProgress->Progress(); - - if (database && database->Open()) - { - /* clean the EPG database */ - g_EpgContainer.Reset(); - pDlgProgress->SetPercentage(30); - pDlgProgress->Progress(); - - if (!bResetEPGOnly) - { - database->DeleteChannelGroups(); - pDlgProgress->SetPercentage(50); - pDlgProgress->Progress(); - - /* delete all channels */ - database->DeleteChannels(); - pDlgProgress->SetPercentage(70); - pDlgProgress->Progress(); - - /* delete all channel and recording settings */ - CVideoDatabase videoDatabase; - - if (videoDatabase.Open()) - { - videoDatabase.EraseVideoSettings("pvr://channels/"); - videoDatabase.EraseVideoSettings(CPVRRecordingsPath::PATH_RECORDINGS); - videoDatabase.Close(); - } - - pDlgProgress->SetPercentage(80); - pDlgProgress->Progress(); - - /* delete all client information */ - pDlgProgress->SetPercentage(90); - pDlgProgress->Progress(); - } - - database->Close(); - } - - CLog::Log(LOGNOTICE,"PVRManager - %s - %s database cleared", __FUNCTION__, bResetEPGOnly ? "EPG" : "PVR and EPG"); - - if (database) - database->Open(); - - CLog::Log(LOGNOTICE,"PVRManager - %s - restarting the PVRManager", __FUNCTION__); - Start(); - - pDlgProgress->SetPercentage(100); - pDlgProgress->Close(); + CJobManager::GetInstance().AddJob(new CPVRContinueLastChannelJob(), nullptr); } bool CPVRManager::IsPlaying(void) const @@ -938,269 +752,16 @@ void CPVRManager::ResetPlayingTag(void) m_guiInfo->ResetPlayingTag(); } -bool CPVRManager::ToggleRecordingOnChannel(unsigned int iChannelId) -{ - const CPVRChannelPtr channel(m_channelGroups->GetChannelById(iChannelId)); - if (!channel) - return false; - - return SetRecordingOnChannel(channel, !channel->IsRecording()); -} - void CPVRManager::StartRecordingOnPlayingChannel(bool bOnOff) { // can be called from VideoPlayer thread. SetRecordingOnChannel can open a dialog. Thus, execute async. CJobManager::GetInstance().AddJob(new CPVRSetRecordingOnChannelJob(m_addons->GetPlayingChannel(), bOnOff), NULL); } -namespace -{ -enum PVRRECORD_INSTANTRECORDACTION -{ - NONE = -1, - RECORD_CURRENT_SHOW = 0, - RECORD_INSTANTRECORDTIME = 1, - ASK = 2, - RECORD_30_MINUTES = 3, - RECORD_60_MINUTES = 4, - RECORD_120_MINUTES = 5, - RECORD_NEXT_SHOW = 6 -}; - -class InstantRecordingActionSelector -{ -public: - InstantRecordingActionSelector(); - virtual ~InstantRecordingActionSelector() {} - - void AddAction(PVRRECORD_INSTANTRECORDACTION eAction, const std::string &title); - void PreSelectAction(PVRRECORD_INSTANTRECORDACTION eAction); - PVRRECORD_INSTANTRECORDACTION Select(); - -private: - CGUIDialogSelect *m_pDlgSelect; // not owner! - std::map<PVRRECORD_INSTANTRECORDACTION, int> m_actions; -}; - -InstantRecordingActionSelector::InstantRecordingActionSelector() -: m_pDlgSelect(dynamic_cast<CGUIDialogSelect *>(g_windowManager.GetWindow(WINDOW_DIALOG_SELECT))) -{ - if (m_pDlgSelect) - { - m_pDlgSelect->SetMultiSelection(false); - m_pDlgSelect->SetHeading(CVariant{19086}); // Instant recording action - } - else - { - CLog::Log(LOGERROR, "InstantRecordingActionSelector - %s - unable to obtain WINDOW_DIALOG_SELECT instance", __FUNCTION__); - } -} - -void InstantRecordingActionSelector::AddAction(PVRRECORD_INSTANTRECORDACTION eAction, const std::string &title) -{ - if (m_actions.find(eAction) == m_actions.end()) - { - switch (eAction) - { - case RECORD_INSTANTRECORDTIME: - m_pDlgSelect->Add(StringUtils::Format(g_localizeStrings.Get(19090).c_str(), - CServiceBroker::GetSettings().GetInt(CSettings::SETTING_PVRRECORD_INSTANTRECORDTIME))); // Record next <default duration> minutes - break; - case RECORD_30_MINUTES: - m_pDlgSelect->Add(StringUtils::Format(g_localizeStrings.Get(19090).c_str(), 30)); // Record next 30 minutes - break; - case RECORD_60_MINUTES: - m_pDlgSelect->Add(StringUtils::Format(g_localizeStrings.Get(19090).c_str(), 60)); // Record next 60 minutes - break; - case RECORD_120_MINUTES: - m_pDlgSelect->Add(StringUtils::Format(g_localizeStrings.Get(19090).c_str(), 120)); // Record next 120 minutes - break; - case RECORD_CURRENT_SHOW: - m_pDlgSelect->Add(StringUtils::Format(g_localizeStrings.Get(19091).c_str(), title.c_str())); // Record current show (<title>) - break; - case RECORD_NEXT_SHOW: - m_pDlgSelect->Add(StringUtils::Format(g_localizeStrings.Get(19092).c_str(), title.c_str())); // Record next show (<title>) - break; - case NONE: - case ASK: - default: - return; - } - - m_actions.insert(std::make_pair(eAction, m_actions.size())); - } -} - -void InstantRecordingActionSelector::PreSelectAction(PVRRECORD_INSTANTRECORDACTION eAction) -{ - const auto &it = m_actions.find(eAction); - if (it != m_actions.end()) - m_pDlgSelect->SetSelected(it->second); -} - -PVRRECORD_INSTANTRECORDACTION InstantRecordingActionSelector::Select() -{ - PVRRECORD_INSTANTRECORDACTION eAction = NONE; - - m_pDlgSelect->Open(); - - if (m_pDlgSelect->IsConfirmed()) - { - int iSelection = m_pDlgSelect->GetSelectedItem(); - for (const auto &action : m_actions) - { - if (action.second == iSelection) - { - eAction = action.first; - break; - } - } - } - - return eAction; -} - -} // unnamed namespace - -bool CPVRManager::SetRecordingOnChannel(const CPVRChannelPtr &channel, bool bOnOff) -{ - bool bReturn = false; - - if (!channel) - return bReturn; - - if (!g_PVRManager.CheckParentalLock(channel)) - return bReturn; - - if (m_addons->HasTimerSupport(channel->ClientID())) - { - /* timers are supported on this channel */ - if (bOnOff && !channel->IsRecording()) - { - CEpgInfoTagPtr epgTag; - int iDuration = CServiceBroker::GetSettings().GetInt(CSettings::SETTING_PVRRECORD_INSTANTRECORDTIME); - - int iAction = CServiceBroker::GetSettings().GetInt(CSettings::SETTING_PVRRECORD_INSTANTRECORDACTION); - switch (iAction) - { - case RECORD_CURRENT_SHOW: - epgTag = channel->GetEPGNow(); - break; - - case RECORD_INSTANTRECORDTIME: - epgTag.reset(); - break; - - case ASK: - { - PVRRECORD_INSTANTRECORDACTION ePreselect = RECORD_INSTANTRECORDTIME; - InstantRecordingActionSelector selector; - CEpgInfoTagPtr epgTagNext; - - // fixed length recordings - selector.AddAction(RECORD_30_MINUTES, ""); - selector.AddAction(RECORD_60_MINUTES, ""); - selector.AddAction(RECORD_120_MINUTES, ""); - - const int iDurationDefault = CServiceBroker::GetSettings().GetInt(CSettings::SETTING_PVRRECORD_INSTANTRECORDTIME); - if (iDurationDefault != 30 && iDurationDefault != 60 && iDurationDefault != 120) - selector.AddAction(RECORD_INSTANTRECORDTIME, ""); - - // epg-based recordings - epgTag = channel->GetEPGNow(); - if (epgTag) - { - // "now" - selector.AddAction(RECORD_CURRENT_SHOW, epgTag->Title()); - ePreselect = RECORD_CURRENT_SHOW; - - // "next" - epgTagNext = channel->GetEPGNext(); - if (epgTagNext) - { - selector.AddAction(RECORD_NEXT_SHOW, epgTagNext->Title()); - - // be smart. if current show is almost over, preselect next show. - if (epgTag->ProgressPercentage() > 90.0f) - ePreselect = RECORD_NEXT_SHOW; - } - } - - selector.PreSelectAction(ePreselect); - - PVRRECORD_INSTANTRECORDACTION eSelected = selector.Select(); - switch (eSelected) - { - case NONE: - return false; // dialog canceled - - case RECORD_30_MINUTES: - iDuration = 30; - epgTag.reset(); - break; - - case RECORD_60_MINUTES: - iDuration = 60; - epgTag.reset(); - break; - - case RECORD_120_MINUTES: - iDuration = 120; - epgTag.reset(); - break; - - case RECORD_INSTANTRECORDTIME: - iDuration = iDurationDefault; - epgTag.reset(); - break; - - case RECORD_CURRENT_SHOW: - break; - - case RECORD_NEXT_SHOW: - epgTag = epgTagNext; - break; - - default: - CLog::Log(LOGERROR, "PVRManager - %s - unknown instant record action selection (%d), defaulting to fixed length recording.", __FUNCTION__, eSelected); - epgTag.reset(); - break; - } - break; - } - - default: - CLog::Log(LOGERROR, "PVRManager - %s - unknown instant record action setting value (%d), defaulting to fixed length recording.", __FUNCTION__, iAction); - break; - } - - const CPVRTimerInfoTagPtr newTimer(epgTag ? CPVRTimerInfoTag::CreateFromEpg(epgTag, false) : CPVRTimerInfoTag::CreateInstantTimerTag(channel, iDuration)); - - if (newTimer) - bReturn = newTimer->AddToClient(); - - if (!bReturn) - CGUIDialogOK::ShowAndGetInput(CVariant{19033}, CVariant{19164}); - } - else if (!bOnOff && channel->IsRecording()) - { - /* delete active timers */ - bReturn = m_timers->DeleteTimersOnChannel(channel, true, true); - } - } - - return bReturn; -} - -bool CPVRManager::CheckParentalLock(const CPVRChannelPtr &channel) +void CPVRManager::RestartParentalTimer() { - bool bReturn = !IsParentalLocked(channel) || - CheckParentalPIN(); - - if (!bReturn) - CLog::Log(LOGERROR, "PVRManager - %s - parental lock verification failed for channel '%s': wrong PIN entered.", __FUNCTION__, channel->ChannelName().c_str()); - - return bReturn; + if (m_parentalTimer) + m_parentalTimer->StartZero(); } bool CPVRManager::IsParentalLocked(const CPVRChannelPtr &channel) @@ -1226,27 +787,6 @@ bool CPVRManager::IsParentalLocked(const CPVRChannelPtr &channel) return bReturn; } -bool CPVRManager::CheckParentalPIN(const std::string& strTitle /* = "" */) -{ - std::string pinCode = CServiceBroker::GetSettings().GetString(CSettings::SETTING_PVRPARENTAL_PIN); - - if (!CServiceBroker::GetSettings().GetBool(CSettings::SETTING_PVRPARENTAL_ENABLED) || pinCode.empty()) - return true; - - // Locked channel. Enter PIN: - bool bValidPIN = CGUIDialogNumeric::ShowAndVerifyInput(pinCode, !strTitle.empty() ? strTitle : g_localizeStrings.Get(19263), true); - if (!bValidPIN) - // display message: The entered PIN number was incorrect - CGUIDialogOK::ShowAndGetInput(CVariant{19264}, CVariant{19265}); - else if (m_parentalTimer) - { - // reset the timer - m_parentalTimer->StartZero(); - } - - return bValidPIN; -} - void CPVRManager::SetPlayingGroup(const CPVRChannelGroupPtr &group) { if (m_channelGroups && group) @@ -1461,88 +1001,6 @@ bool CPVRManager::UpdateItem(CFileItem& item) return false; } -bool CPVRManager::StartPlayback(const CPVRChannelPtr &channel, bool bMinimised /* = false */) -{ - CMediaSettings::GetInstance().SetVideoStartWindowed(bMinimised); - - CFileItemList *l = new CFileItemList; //don't delete, - l->Add(std::make_shared<CFileItem>(channel)); - CApplicationMessenger::GetInstance().PostMsg(TMSG_MEDIA_PLAY, -1, -1, static_cast<void*>(l)); - - CLog::Log(LOGNOTICE, "PVRManager - %s - started playback on channel '%s'", - __FUNCTION__, channel->ChannelName().c_str()); - return true; -} - -bool CPVRManager::StartPlayback(PlaybackType type /* = PlaybackTypeAny */) -{ - bool bIsRadio(false); - bool bReturn(false); - bool bIsPlaying(false); - CFileItemPtr channel; - - // check if the desired PlaybackType is already playing, - // and if not, try to grab the last played channel of this type - switch (type) - { - case PlaybackTypeRadio: - if (IsPlayingRadio()) - bIsPlaying = true; - else - channel = m_channelGroups->GetGroupAllRadio()->GetLastPlayedChannel(); - bIsRadio = true; - break; - - case PlaybackTypeTv: - if (IsPlayingTV()) - bIsPlaying = true; - else - channel = m_channelGroups->GetGroupAllTV()->GetLastPlayedChannel(); - break; - - default: - if (IsPlaying()) - bIsPlaying = true; - else - channel = m_channelGroups->GetLastPlayedChannel(); - } - - // we're already playing? Then nothing to do - if (bIsPlaying) - return true; - - // if we have a last played channel, start playback - if (channel && channel->HasPVRChannelInfoTag()) - { - bReturn = StartPlayback(channel->GetPVRChannelInfoTag(), false); - } - else - { - // if we don't, find the active channel group of the demanded type and play it's first channel - CPVRChannelGroupPtr channelGroup = GetPlayingGroup(bIsRadio); - if (channelGroup) - { - // try to start playback of first channel in this group - std::vector<PVRChannelGroupMember> groupMembers(channelGroup->GetMembers()); - if (!groupMembers.empty()) - bReturn = StartPlayback((*groupMembers.begin()).channel, false); - } - } - - if (!bReturn) - { - CLog::Log(LOGNOTICE, "PVRManager - %s - could not determine %s channel to start playback with. No last played channel found, and first channel of active group could also not be determined.", __FUNCTION__, bIsRadio ? "radio": "tv"); - - std::string msg = StringUtils::Format(g_localizeStrings.Get(19035).c_str(), g_localizeStrings.Get(bIsRadio ? 19021 : 19020).c_str()); // RADIO/TV could not be played. Check the log for details. - CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Error, - g_localizeStrings.Get(19166), // PVR information - msg); - } - - return bReturn; -} - - bool CPVRManager::PerformChannelSwitch(const CPVRChannelPtr &channel, bool bPreview) { assert(channel.get()); @@ -1866,17 +1324,6 @@ bool CPVRManager::IsPlayingRecording(void) const return IsStarted() && m_addons->IsPlayingRecording(); } -bool CPVRManager::IsRunningChannelScan(void) const -{ - return IsStarted() && m_addons->IsRunningChannelScan(); -} - -void CPVRManager::StartChannelScan(void) -{ - if (IsStarted()) - m_addons->StartChannelScan(); -} - void CPVRManager::SearchMissingChannelIcons(void) { if (IsStarted() && m_channelGroups) @@ -1910,7 +1357,8 @@ void CPVRManager::TriggerChannelGroupsUpdate(void) void CPVRManager::TriggerSearchMissingChannelIcons(void) { - CJobManager::GetInstance().AddJob(new CPVRSearchMissingChannelIconsJob(), NULL); + if (IsStarted()) + CJobManager::GetInstance().AddJob(new CPVRSearchMissingChannelIconsJob(), NULL); } void CPVRManager::ConnectionStateChange(CPVRClient *client, std::string connectString, PVR_CONNECTION_STATE state, std::string message) @@ -1952,12 +1400,6 @@ bool CPVRClientConnectionJob::DoWork(void) return true; } -bool CPVRSetRecordingOnChannelJob::DoWork(void) -{ - g_PVRManager.SetRecordingOnChannel(m_channel, m_bOnOff); - return true; -} - bool CPVRManager::CreateChannelEpgs(void) { if (EpgsCreated()) diff --git a/xbmc/pvr/PVRManager.h b/xbmc/pvr/PVRManager.h index 891c3376fb..3ecface1be 100644 --- a/xbmc/pvr/PVRManager.h +++ b/xbmc/pvr/PVRManager.h @@ -22,7 +22,6 @@ #include "FileItem.h" #include "addons/kodi-addon-dev-kit/include/kodi/xbmc_pvr_types.h" #include "interfaces/IAnnouncer.h" -#include "settings/lib/ISettingCallback.h" #include "threads/Event.h" #include "threads/Thread.h" #include "utils/EventStream.h" @@ -62,13 +61,6 @@ namespace PVR class CPVRDatabase; class CGUIWindowPVRCommon; - enum PlaybackType - { - PlaybackTypeAny = 0, - PlaybackTypeTv, - PlaybackTypeRadio - }; - enum ContinueLastChannelOnStartup { CONTINUE_LAST_CHANNEL_OFF = 0, @@ -102,7 +94,7 @@ namespace PVR bool m_bStopped; }; - class CPVRManager : public ISettingCallback, private CThread, public Observable, public ANNOUNCEMENT::IAnnouncer + class CPVRManager : private CThread, public Observable, public ANNOUNCEMENT::IAnnouncer { friend class CPVRClients; @@ -139,9 +131,6 @@ namespace PVR */ static CPVRManager &GetInstance(); - virtual void OnSettingChanged(const CSetting *setting) override; - virtual void OnSettingAction(const CSetting *setting) override; - /*! * @brief Get the channel groups container. * @return The groups container. @@ -177,6 +166,11 @@ namespace PVR void Reinit(void); /*! + * @brief Start the PVRManager, which loads all PVR data and starts some threads to update the PVR data. + */ + void Start(); + + /*! * @brief Stop PVRManager. */ void Stop(void); @@ -226,12 +220,6 @@ namespace PVR void ShowPlayerInfo(int iTimeout); /*! - * @brief Reset the TV database to it's initial state and delete all the data inside. - * @param bResetEPGOnly True to only reset the EPG database, false to reset both PVR and EPG. - */ - void ResetDatabase(bool bResetEPGOnly = false); - - /*! * @brief Check if a TV channel, radio channel or recording is playing. * @return True if it's playing, false otherwise. */ @@ -347,27 +335,12 @@ namespace PVR bool OpenRecordedStream(const CPVRRecordingPtr &tag); /*! - * @brief Start recording on a given channel if it is not already recording, stop if it is. - * @param channel the channel to start/stop recording. - * @return True if the recording was started or stopped successfully, false otherwise. - */ - bool ToggleRecordingOnChannel(unsigned int iChannelId); - - /*! * @brief Start or stop recording on the channel that is currently being played. * @param bOnOff True to start recording, false to stop. */ void StartRecordingOnPlayingChannel(bool bOnOff); /*! - * @brief Start or stop recording on a given channel. - * @param channel the channel to start/stop recording. - * @param bOnOff True to start recording, false to stop. - * @return True if the recording was started or stopped successfully, false otherwise. - */ - bool SetRecordingOnChannel(const CPVRChannelPtr &channel, bool bOnOff); - - /*! * @brief Check whether there are active recordings. * @return True if there are active recordings, false otherwise. */ @@ -473,21 +446,6 @@ namespace PVR int GetStartTime(void) const; /*! - * @brief Start playback on a channel. - * @param channel The channel to start to play. - * @param bMinimised If true, playback starts minimised, otherwise in fullscreen. - * @return True if playback was started, false otherwise. - */ - bool StartPlayback(const CPVRChannelPtr &channel, bool bMinimised = false); - - /*! - * @brief Start playback of the last used channel, and if it fails use first channel in the current channelgroup. - * @param type The type of playback to be started (any, radio, tv). See PlaybackType enum - * @return True if playback was started, false otherwise. - */ - bool StartPlayback(PlaybackType type = PlaybackTypeAny); - - /*! * @brief Update the current playing file in the guiinfomanager and application. */ void UpdateCurrentFile(void); @@ -516,28 +474,11 @@ namespace PVR bool IsPlayingRecording(void) const; /*! - * @return True when a channel scan is currently running, false otherwise. - */ - bool IsRunningChannelScan(void) const; - - /*! - * @brief Open a selection dialog and start a channel scan on the selected client. - */ - void StartChannelScan(void); - - /*! * @brief Try to find missing channel icons automatically */ void SearchMissingChannelIcons(void); /*! - * @brief Check if channel is parental locked. Ask for PIN if necessary. - * @param channel The channel to open. - * @return True if channel is unlocked (by default or PIN unlocked), false otherwise. - */ - bool CheckParentalLock(const CPVRChannelPtr &channel); - - /*! * @brief Check if parental lock is overridden at the given moment. * @param channel The channel to open. * @return True if parental lock is overridden, false otherwise. @@ -545,11 +486,9 @@ namespace PVR bool IsParentalLocked(const CPVRChannelPtr &channel); /*! - * @brief Open Numeric dialog to check for parental PIN. - * @param strTitle Override the title of the dialog if set. - * @return True if entered PIN was correct, false otherwise. + * @brief Restart the parental timer. */ - bool CheckParentalPIN(const std::string& strTitle = ""); + void RestartParentalTimer(); /*! * @brief Executes "pvrpowermanagement.setwakeupcmd" @@ -613,11 +552,6 @@ namespace PVR protected: /*! - * @brief Start the PVRManager, which loads all PVR data and starts some threads to update the PVR data. - */ - void Start(); - - /*! * @brief PVR update and control thread. */ virtual void Process(void) override; @@ -663,10 +597,9 @@ namespace PVR bool ChannelUpDown(unsigned int *iNewChannelNumber, bool bPreview, bool bUp); /*! - * @brief Continue playback on the last channel if it was stored in the database. - * @return True if playback was continued, false otherwise. + * @brief Continue playback on the last played channel. */ - bool ContinueLastChannel(void); + void TriggerContinueLastChannel(void); enum ManagerState { @@ -719,8 +652,8 @@ namespace PVR class CPVRStartupJob : public CJob { public: - CPVRStartupJob(void) {} - virtual ~CPVRStartupJob() {} + CPVRStartupJob(void) = default; + virtual ~CPVRStartupJob() = default; virtual const char *GetType() const { return "pvr-startup"; } virtual bool DoWork(); @@ -729,8 +662,8 @@ namespace PVR class CPVREpgsCreateJob : public CJob { public: - CPVREpgsCreateJob(void) {} - virtual ~CPVREpgsCreateJob() {} + CPVREpgsCreateJob(void) = default; + virtual ~CPVREpgsCreateJob() = default; virtual const char *GetType() const { return "pvr-create-epgs"; } virtual bool DoWork(); @@ -739,8 +672,8 @@ namespace PVR class CPVRRecordingsUpdateJob : public CJob { public: - CPVRRecordingsUpdateJob(void) {} - virtual ~CPVRRecordingsUpdateJob() {} + CPVRRecordingsUpdateJob(void) = default; + virtual ~CPVRRecordingsUpdateJob() = default; virtual const char *GetType() const { return "pvr-update-recordings"; } virtual bool DoWork(); @@ -749,8 +682,8 @@ namespace PVR class CPVRTimersUpdateJob : public CJob { public: - CPVRTimersUpdateJob(void) {} - virtual ~CPVRTimersUpdateJob() {} + CPVRTimersUpdateJob(void) = default; + virtual ~CPVRTimersUpdateJob() = default; virtual const char *GetType() const { return "pvr-update-timers"; } virtual bool DoWork(); @@ -759,8 +692,8 @@ namespace PVR class CPVRChannelsUpdateJob : public CJob { public: - CPVRChannelsUpdateJob(void) {} - virtual ~CPVRChannelsUpdateJob() {} + CPVRChannelsUpdateJob(void) = default; + virtual ~CPVRChannelsUpdateJob() = default; virtual const char *GetType() const { return "pvr-update-channels"; } virtual bool DoWork(); @@ -769,8 +702,8 @@ namespace PVR class CPVRChannelGroupsUpdateJob : public CJob { public: - CPVRChannelGroupsUpdateJob(void) {} - virtual ~CPVRChannelGroupsUpdateJob() {} + CPVRChannelGroupsUpdateJob(void) = default; + virtual ~CPVRChannelGroupsUpdateJob() = default; virtual const char *GetType() const { return "pvr-update-channelgroups"; } virtual bool DoWork(); @@ -780,7 +713,7 @@ namespace PVR { public: CPVRChannelSwitchJob(const CFileItemPtr &previous, const CFileItemPtr & next) : m_previous(previous), m_next(next) {} - virtual ~CPVRChannelSwitchJob() {} + virtual ~CPVRChannelSwitchJob() = default; virtual const char *GetType() const { return "pvr-channel-switch"; } virtual bool DoWork(); @@ -792,8 +725,8 @@ namespace PVR class CPVRSearchMissingChannelIconsJob : public CJob { public: - CPVRSearchMissingChannelIconsJob(void) {} - virtual ~CPVRSearchMissingChannelIconsJob() {} + CPVRSearchMissingChannelIconsJob(void) = default; + virtual ~CPVRSearchMissingChannelIconsJob() = default; virtual const char *GetType() const { return "pvr-search-missing-channel-icons"; } bool DoWork(); @@ -804,7 +737,7 @@ namespace PVR public: CPVRClientConnectionJob(CPVRClient *client, std::string connectString, PVR_CONNECTION_STATE state, std::string message) : m_client(client), m_connectString(connectString), m_state(state), m_message(message) {} - virtual ~CPVRClientConnectionJob() {} + virtual ~CPVRClientConnectionJob() = default; virtual const char *GetType() const { return "pvr-client-connection"; } virtual bool DoWork(); @@ -814,18 +747,4 @@ namespace PVR PVR_CONNECTION_STATE m_state; std::string m_message; }; - - class CPVRSetRecordingOnChannelJob : public CJob - { - public: - CPVRSetRecordingOnChannelJob(const CPVRChannelPtr &channel, bool bOnOff) : - m_channel(channel), m_bOnOff(bOnOff) {} - virtual ~CPVRSetRecordingOnChannelJob() {} - virtual const char *GetType() const { return "pvr-set-recording-on-channel"; } - - bool DoWork(); - private: - CPVRChannelPtr m_channel; - bool m_bOnOff; - }; } diff --git a/xbmc/pvr/addons/PVRClients.cpp b/xbmc/pvr/addons/PVRClients.cpp index 9bd717a529..1bd94dc84f 100644 --- a/xbmc/pvr/addons/PVRClients.cpp +++ b/xbmc/pvr/addons/PVRClients.cpp @@ -27,21 +27,14 @@ #include "Application.h" #include "ServiceBroker.h" #include "cores/IPlayer.h" -#include "dialogs/GUIDialogOK.h" -#include "dialogs/GUIDialogSelect.h" -#include "dialogs/GUIDialogKaiToast.h" -#include "events/EventLog.h" -#include "events/NotificationEvent.h" -#include "guilib/GUIWindowManager.h" -#include "GUIUserMessages.h" #include "messaging/ApplicationMessenger.h" #include "pvr/channels/PVRChannelGroupInternal.h" #include "pvr/channels/PVRChannelGroups.h" +#include "pvr/PVRJobs.h" #include "pvr/PVRManager.h" #include "pvr/recordings/PVRRecordings.h" #include "pvr/timers/PVRTimers.h" #include "utils/log.h" -#include "utils/Variant.h" using namespace ADDON; using namespace PVR; @@ -54,7 +47,6 @@ using namespace KODI::MESSAGING; #define PVR_CLIENT_AVAHI_SLEEP_TIME_MS (250) CPVRClients::CPVRClients(void) : - m_bChannelScanRunning(false), m_bIsSwitchingChannels(false), m_playingClientId(-EINVAL), m_bIsPlayingLiveTV(false), @@ -153,7 +145,6 @@ void CPVRClients::Unload(void) CSingleLock lock(m_critSection); /* reset class properties */ - m_bChannelScanRunning = false; m_bIsPlayingLiveTV = false; m_bIsPlayingRecording = false; m_strPlayingClientName = ""; @@ -859,80 +850,7 @@ bool CPVRClients::HasMenuHooks(int iClientID, PVR_MENUHOOK_CAT cat) iClientID = GetPlayingClientID(); PVR_CLIENT client; - return (GetCreatedClient(iClientID, client) && - client->HaveMenuHooks(cat)); -} - -void CPVRClients::ProcessMenuHooks(int iClientID, PVR_MENUHOOK_CAT cat, const CFileItem *item) -{ - // get client id - if (iClientID < 0 && cat == PVR_MENUHOOK_SETTING) - { - PVR_CLIENTMAP clients; - GetCreatedClients(clients); - - if (clients.size() == 1) - { - iClientID = clients.begin()->first; - } - else if (clients.size() > 1) - { - // have user select client - CGUIDialogSelect* pDialog = (CGUIDialogSelect*)g_windowManager.GetWindow(WINDOW_DIALOG_SELECT); - pDialog->Reset(); - pDialog->SetHeading(CVariant{19196}); - - for (const auto client : clients) - { - pDialog->Add(client.second->GetBackendName()); - } - pDialog->Open(); - - int selection = pDialog->GetSelectedItem(); - if (selection >= 0) - { - auto client = clients.begin(); - std::advance(client, selection); - iClientID = client->first; - } - } - } - - if (iClientID < 0) - iClientID = GetPlayingClientID(); - - PVR_CLIENT client; - if (GetCreatedClient(iClientID, client) && client->HaveMenuHooks(cat)) - { - PVR_MENUHOOKS *hooks = client->GetMenuHooks(); - std::vector<int> hookIDs; - int selection = 0; - - CGUIDialogSelect* pDialog = (CGUIDialogSelect*)g_windowManager.GetWindow(WINDOW_DIALOG_SELECT); - pDialog->Reset(); - pDialog->SetHeading(CVariant{19196}); - for (unsigned int i = 0; i < hooks->size(); ++i) - { - if (hooks->at(i).category == cat || hooks->at(i).category == PVR_MENUHOOK_ALL) - { - pDialog->Add(g_localizeStrings.GetAddonString(client->ID(), hooks->at(i).iLocalizedStringId)); - hookIDs.push_back(i); - } - } - if (hookIDs.size() > 1) - { - pDialog->Open(); - selection = pDialog->GetSelectedItem(); - } - if (selection >= 0) - client->CallMenuHook(hooks->at(hookIDs.at(selection)), item); - } -} - -bool CPVRClients::IsRunningChannelScan(void) const -{ - CSingleLock lock(m_critSection); - return m_bChannelScanRunning; + return (GetCreatedClient(iClientID, client) && client->HasMenuHooks(cat)); } std::vector<PVR_CLIENT> CPVRClients::GetClientsSupportingChannelScan(void) const @@ -950,57 +868,6 @@ std::vector<PVR_CLIENT> CPVRClients::GetClientsSupportingChannelScan(void) const return possibleScanClients; } -void CPVRClients::StartChannelScan(void) -{ - PVR_CLIENT scanClient; - CSingleLock lock(m_critSection); - std::vector<PVR_CLIENT> possibleScanClients = GetClientsSupportingChannelScan(); - m_bChannelScanRunning = true; - - /* multiple clients found */ - if (possibleScanClients.size() > 1) - { - CGUIDialogSelect* pDialog= (CGUIDialogSelect*)g_windowManager.GetWindow(WINDOW_DIALOG_SELECT); - - pDialog->Reset(); - pDialog->SetHeading(CVariant{19119}); - - for (const auto client : possibleScanClients) - pDialog->Add(client->GetFriendlyName()); - - pDialog->Open(); - - int selection = pDialog->GetSelectedItem(); - if (selection >= 0) - scanClient = possibleScanClients[selection]; - } - /* one client found */ - else if (possibleScanClients.size() == 1) - { - scanClient = possibleScanClients[0]; - } - /* no clients found */ - else if (!scanClient) - { - CGUIDialogOK::ShowAndGetInput(CVariant{19033}, CVariant{19192}); - return; - } - - /* start the channel scan */ - CLog::Log(LOGNOTICE,"PVR - %s - starting to scan for channels on client %s", - __FUNCTION__, scanClient->GetFriendlyName().c_str()); - long perfCnt = XbmcThreads::SystemClockMillis(); - - /* do the scan */ - if (scanClient->StartChannelScan() != PVR_ERROR_NO_ERROR) - /* an error occured */ - CGUIDialogOK::ShowAndGetInput(CVariant{19111}, CVariant{19193}); - - CLog::Log(LOGNOTICE, "PVRManager - %s - channel scan finished after %li.%li seconds", - __FUNCTION__, (XbmcThreads::SystemClockMillis()-perfCnt)/1000, (XbmcThreads::SystemClockMillis()-perfCnt)%1000); - m_bChannelScanRunning = false; -} - std::vector<PVR_CLIENT> CPVRClients::GetClientsSupportingChannelSettings(bool bRadio) const { std::vector<PVR_CLIENT> possibleSettingsClients; @@ -1017,8 +884,7 @@ std::vector<PVR_CLIENT> CPVRClients::GetClientsSupportingChannelSettings(bool bR return possibleSettingsClients; } - -bool CPVRClients::OpenDialogChannelAdd(const CPVRChannelPtr &channel) +PVR_ERROR CPVRClients::OpenDialogChannelAdd(const CPVRChannelPtr &channel) { PVR_ERROR error = PVR_ERROR_UNKNOWN; @@ -1028,16 +894,10 @@ bool CPVRClients::OpenDialogChannelAdd(const CPVRChannelPtr &channel) else CLog::Log(LOGERROR, "PVR - %s - cannot find client %d",__FUNCTION__, channel->ClientID()); - if (error == PVR_ERROR_NOT_IMPLEMENTED) - { - CGUIDialogOK::ShowAndGetInput(CVariant{19033}, CVariant{19038}); - return true; - } - - return error == PVR_ERROR_NO_ERROR; + return error; } -bool CPVRClients::OpenDialogChannelSettings(const CPVRChannelPtr &channel) +PVR_ERROR CPVRClients::OpenDialogChannelSettings(const CPVRChannelPtr &channel) { PVR_ERROR error = PVR_ERROR_UNKNOWN; @@ -1047,16 +907,10 @@ bool CPVRClients::OpenDialogChannelSettings(const CPVRChannelPtr &channel) else CLog::Log(LOGERROR, "PVR - %s - cannot find client %d",__FUNCTION__, channel->ClientID()); - if (error == PVR_ERROR_NOT_IMPLEMENTED) - { - CGUIDialogOK::ShowAndGetInput(CVariant{19033}, CVariant{19038}); - return true; - } - - return error == PVR_ERROR_NO_ERROR; + return error; } -bool CPVRClients::DeleteChannel(const CPVRChannelPtr &channel) +PVR_ERROR CPVRClients::DeleteChannel(const CPVRChannelPtr &channel) { PVR_ERROR error = PVR_ERROR_UNKNOWN; @@ -1066,13 +920,7 @@ bool CPVRClients::DeleteChannel(const CPVRChannelPtr &channel) else CLog::Log(LOGERROR, "PVR - %s - cannot find client %d",__FUNCTION__, channel->ClientID()); - if (error == PVR_ERROR_NOT_IMPLEMENTED) - { - CGUIDialogOK::ShowAndGetInput(CVariant{19033}, CVariant{19038}); - return true; - } - - return error == PVR_ERROR_NO_ERROR; + return error; } bool CPVRClients::RenameChannel(const CPVRChannelPtr &channel) @@ -1142,8 +990,8 @@ void CPVRClients::UpdateAddons(void) CLog::Log(LOGERROR, "%s - failed to create add-on %s, status = %d", __FUNCTION__, addon->Name().c_str(), status); if (status == ADDON_STATUS_PERMANENT_FAILURE) { - CGUIDialogOK::ShowAndGetInput(CVariant{24070}, CVariant{16029}); CAddonMgr::GetInstance().DisableAddon(addon->ID()); + CJobManager::GetInstance().AddJob(new CPVREventlogJob(true, true, addon->Name(), g_localizeStrings.Get(24070), addon->Icon()), nullptr); } } } @@ -1541,13 +1389,7 @@ void CPVRClients::ConnectionStateChange(CPVRClient *client, std::string &strConn strMsg = g_localizeStrings.Get(iMsg); // Notify user. - if (bNotify) - CGUIDialogKaiToast::QueueNotification(bError ? CGUIDialogKaiToast::Error : CGUIDialogKaiToast::Info, client->Name().c_str(), - strMsg, 5000, true); - - // Write event log entry. - CEventLog::GetInstance().Add(EventPtr(new CNotificationEvent(client->Name(), strMsg, client->Icon(), - bError ? EventLevel::Error : EventLevel::Information))); + CJobManager::GetInstance().AddJob(new CPVREventlogJob(bNotify, bError, client->Name(), strMsg, client->Icon()), nullptr); if (newState == PVR_CONNECTION_STATE_CONNECTED) { diff --git a/xbmc/pvr/addons/PVRClients.h b/xbmc/pvr/addons/PVRClients.h index 310d655ee3..39283fe74c 100644 --- a/xbmc/pvr/addons/PVRClients.h +++ b/xbmc/pvr/addons/PVRClients.h @@ -79,15 +79,35 @@ namespace PVR //@{ /*! - * @brief Check whether a client ID points to a valid and connected add-on. + * @brief Check whether a given client ID points to a created pvr client. * @param iClientId The client ID. - * @return True when the client ID is valid and connected, false otherwise. + * @return True if the the client ID represents a created client, false otherwise. */ bool IsCreatedClient(int iClientId) const; + /*! + * @brief Check whether an given addon instance is a created pvr client. + * @param addon The addon. + * @return True if the the addon represents a created client, false otherwise. + */ bool IsCreatedClient(const ADDON::AddonPtr &addon); /*! + * @brief Get the instance of the client, if it's created. + * @param iClientId The id of the client to get. + * @param addon The client. + * @return True on success, false otherwise. + */ + bool GetCreatedClient(int iClientId, PVR_CLIENT &addon) const; + + /*! + * @brief Get all created clients. + * @param clients Store the active clients in this map. + * @return The amount of added clients. + */ + int GetCreatedClients(PVR_CLIENTMAP &clients) const; + + /*! * @brief Restart a single client add-on. * @param addon The add-on to restart. * @param bDataChanged True if the client's data changed, false otherwise (unused). @@ -565,29 +585,12 @@ namespace PVR */ bool HasMenuHooks(int iClientId, PVR_MENUHOOK_CAT cat); - /*! - * @brief Open selection and progress PVR actions. - * @param iClientId The ID of the client to process the menu entries for. Process the menu entries for the active channel if iClientId < 0. - * @param item The selected file item for which the hook was called. - */ - void ProcessMenuHooks(int iClientID, PVR_MENUHOOK_CAT cat, const CFileItem *item); - //@} /*! @name Channel scan methods */ //@{ /*! - * @return True when a channel scan is currently running, false otherwise. - */ - bool IsRunningChannelScan(void) const; - - /*! - * @brief Open a selection dialog and start a channel scan on the selected client. - */ - void StartChannelScan(void); - - /*! * @return All clients that support channel scanning. */ std::vector<PVR_CLIENT> GetClientsSupportingChannelScan(void) const; @@ -605,23 +608,23 @@ namespace PVR /*! * @brief Open addon settings dialog to add a channel * @param channel The channel to edit. - * @return True if the edit was successful, false otherwise. + * @return PVR_ERROR_NO_ERROR if the dialog was opened successfully, the respective error code otherwise. */ - bool OpenDialogChannelAdd(const CPVRChannelPtr &channel); + PVR_ERROR OpenDialogChannelAdd(const CPVRChannelPtr &channel); /*! * @brief Open addon settings dialog to related channel * @param channel The channel to edit. - * @return True if the edit was successful, false otherwise. + * @return PVR_ERROR_NO_ERROR if the dialog was opened successfully, the respective error code otherwise. */ - bool OpenDialogChannelSettings(const CPVRChannelPtr &channel); + PVR_ERROR OpenDialogChannelSettings(const CPVRChannelPtr &channel); /*! * @brief Inform addon to delete channel * @param channel The channel to delete. - * @return True if it was successful, false otherwise. + * @return PVR_ERROR_NO_ERROR if the channel was deleted successfully, the respective error code otherwise. */ - bool DeleteChannel(const CPVRChannelPtr &channel); + PVR_ERROR DeleteChannel(const CPVRChannelPtr &channel); /*! * @brief Request the client to rename given channel @@ -685,21 +688,6 @@ namespace PVR bool GetClient(int iClientId, PVR_CLIENT &addon) const; /*! - * @brief Get the instance of the client, if it's created. - * @param iClientId The id of the client to get. - * @param addon The client. - * @return True if the client is connected, false otherwise. - */ - bool GetCreatedClient(int iClientId, PVR_CLIENT &addon) const; - - /*! - * @brief Get all created clients. - * @param clients Store the active clients in this map. - * @return The amount of added clients. - */ - int GetCreatedClients(PVR_CLIENTMAP &clients) const; - - /*! * @brief Check whether a client is registered. * @param client The client to check. * @return True if this client is registered, false otherwise. @@ -710,7 +698,6 @@ namespace PVR int GetClientId(const ADDON::AddonPtr &client) const; - bool m_bChannelScanRunning; /*!< true when a channel scan is currently running, false otherwise */ bool m_bIsSwitchingChannels; /*!< true while switching channels */ int m_playingClientId; /*!< the ID of the client that is currently playing */ bool m_bIsPlayingLiveTV; diff --git a/xbmc/pvr/channels/PVRChannel.cpp b/xbmc/pvr/channels/PVRChannel.cpp index 8eee72284e..9d687bc120 100644 --- a/xbmc/pvr/channels/PVRChannel.cpp +++ b/xbmc/pvr/channels/PVRChannel.cpp @@ -376,6 +376,24 @@ bool CPVRChannel::SetLastWatched(time_t iLastWatched) return false; } +bool CPVRChannel::SetWasPlayingOnLastQuit(bool bSet) +{ + const CPVRDatabasePtr database(g_PVRManager.GetTVDatabase()); + if (database) + return database->SetWasPlayingOnLastQuit(*this, bSet); + + return false; +} + +bool CPVRChannel::SetWasPlayingOnLastQuit(bool bSet, bool& bWasPlaying) +{ + const CPVRDatabasePtr database(g_PVRManager.GetTVDatabase()); + if (database) + return database->SetWasPlayingOnLastQuit(*this, bSet, bWasPlaying); + + return false; +} + bool CPVRChannel::IsEmpty() const { CSingleLock lock(m_critSection); diff --git a/xbmc/pvr/channels/PVRChannel.h b/xbmc/pvr/channels/PVRChannel.h index 31a172d414..0b4170c9c9 100644 --- a/xbmc/pvr/channels/PVRChannel.h +++ b/xbmc/pvr/channels/PVRChannel.h @@ -230,6 +230,21 @@ namespace PVR bool SetLastWatched(time_t iLastWatched); /*! + * @brief Sets the 'was playing on last app quit' flag for a channel. + * @param bSet True to set the flag, false to reset the flag + * @return True if the operation was successful, false otherwise + */ + bool SetWasPlayingOnLastQuit(bool bSet); + + /*! + * @brief Sets the 'was playing on last app quit' flag for a channel. + * @param bSet True to set the flag, false to reset the flag + * @param bWasPlaying on return contains the previous value of the flag + * @return True if the operation was successful, false otherwise + */ + bool SetWasPlayingOnLastQuit(bool bSet, bool& bWasPlaying); + + /*! * @brief True if this channel has no file or stream name * @return True if this channel has no file or stream name */ diff --git a/xbmc/pvr/channels/PVRChannelGroupsContainer.cpp b/xbmc/pvr/channels/PVRChannelGroupsContainer.cpp index f6acd5e064..e0cd1ff430 100644 --- a/xbmc/pvr/channels/PVRChannelGroupsContainer.cpp +++ b/xbmc/pvr/channels/PVRChannelGroupsContainer.cpp @@ -19,7 +19,6 @@ */ #include "URL.h" -#include "dialogs/GUIDialogOK.h" #include "guilib/LocalizeStrings.h" #include "utils/log.h" #include "utils/StringUtils.h" diff --git a/xbmc/pvr/dialogs/GUIDialogPVRChannelManager.cpp b/xbmc/pvr/dialogs/GUIDialogPVRChannelManager.cpp index e8598956b3..d3277a76c1 100644 --- a/xbmc/pvr/dialogs/GUIDialogPVRChannelManager.cpp +++ b/xbmc/pvr/dialogs/GUIDialogPVRChannelManager.cpp @@ -36,6 +36,7 @@ #include "utils/StringUtils.h" #include "utils/Variant.h" +#include "pvr/PVRGUIActions.h" #include "pvr/PVRManager.h" #include "pvr/addons/PVRClients.h" #include "pvr/channels/PVRChannelGroupsContainer.h" @@ -291,7 +292,7 @@ bool CGUIDialogPVRChannelManager::OnClickButtonRadioParentalLocked(CGUIMessage & bool selected(msg.GetParam1() == 1); // ask for PIN first - if (!g_PVRManager.CheckParentalPIN(g_localizeStrings.Get(19262).c_str())) + if (!CPVRGUIActions::GetInstance().CheckParentalPIN()) { // failed - reset to previous SET_CONTROL_SELECTED(GetID(), RADIOBUTTON_PARENTAL_LOCK, !selected); return false; @@ -469,10 +470,13 @@ bool CGUIDialogPVRChannelManager::OnClickButtonNewChannel() channel->SetEPGEnabled(g_PVRClients->SupportsEPG(iClientID)); channel->SetClientID(iClientID); - if (g_PVRClients->OpenDialogChannelAdd(channel)) + PVR_ERROR ret = g_PVRClients->OpenDialogChannelAdd(channel); + if (ret == PVR_ERROR_NO_ERROR) Update(); + else if (ret == PVR_ERROR_NOT_IMPLEMENTED) + CGUIDialogOK::ShowAndGetInput(CVariant{19033}, CVariant{19038}); // "Information", "Not supported by the PVR backend." else - CGUIDialogOK::ShowAndGetInput(CVariant{2103}, CVariant{16029}); // Add-on error;Check the log file for details. + CGUIDialogOK::ShowAndGetInput(CVariant{2103}, CVariant{16029}); // "Add-on error", "Check the log for more information about this message." } return true; } @@ -598,8 +602,11 @@ bool CGUIDialogPVRChannelManager::OnContextButton(int itemNumber, CONTEXT_BUTTON } else if (button == CONTEXT_BUTTON_SETTINGS) { - if (!g_PVRClients->OpenDialogChannelSettings(pItem->GetPVRChannelInfoTag())) - CGUIDialogOK::ShowAndGetInput(CVariant{2103}, CVariant{16029}); // Add-on error;Check the log file for details. + PVR_ERROR ret = g_PVRClients->OpenDialogChannelSettings(pItem->GetPVRChannelInfoTag()); + if (ret == PVR_ERROR_NOT_IMPLEMENTED) + CGUIDialogOK::ShowAndGetInput(CVariant{19033}, CVariant{19038}); // "Information", "Not supported by the PVR backend." + else if (ret != PVR_ERROR_NO_ERROR) + CGUIDialogOK::ShowAndGetInput(CVariant{2103}, CVariant{16029}); // "Add-on error", "Check the log for more information about this message." } else if (button == CONTEXT_BUTTON_DELETE) { @@ -614,15 +621,18 @@ bool CGUIDialogPVRChannelManager::OnContextButton(int itemNumber, CONTEXT_BUTTON if (pDialog->IsConfirmed()) { CPVRChannelPtr channel = pItem->GetPVRChannelInfoTag(); - if (g_PVRClients->DeleteChannel(channel)) + PVR_ERROR ret = g_PVRClients->DeleteChannel(channel); + if (ret == PVR_ERROR_NO_ERROR) { g_PVRChannelGroups->GetGroupAll(channel->IsRadio())->RemoveFromGroup(channel); m_channelItems->Remove(m_iSelected); m_viewControl.SetItems(*m_channelItems); Renumber(); } + else if (ret == PVR_ERROR_NOT_IMPLEMENTED) + CGUIDialogOK::ShowAndGetInput(CVariant{19033}, CVariant{19038}); // "Information", "Not supported by the PVR backend." else - CGUIDialogOK::ShowAndGetInput(CVariant{2103}, CVariant{16029}); // Add-on error;Check the log file for details. + CGUIDialogOK::ShowAndGetInput(CVariant{2103}, CVariant{16029}); // "Add-on error", "Check the log for more information about this message." } } else if (button == CONTEXT_BUTTON_EDIT_SOURCE) diff --git a/xbmc/pvr/dialogs/GUIDialogPVRTimerSettings.cpp b/xbmc/pvr/dialogs/GUIDialogPVRTimerSettings.cpp index 10445f949b..3d0d8ffa65 100644 --- a/xbmc/pvr/dialogs/GUIDialogPVRTimerSettings.cpp +++ b/xbmc/pvr/dialogs/GUIDialogPVRTimerSettings.cpp @@ -149,7 +149,12 @@ void CGUIDialogPVRTimerSettings::SetTimer(const CPVRTimerInfoTagPtr &timer) m_iPriority = m_timerInfoTag->m_iPriority; m_iLifetime = m_timerInfoTag->m_iLifetime; m_iMaxRecordings = m_timerInfoTag->m_iMaxRecordings; - m_strDirectory = m_timerInfoTag->m_strDirectory; + + if (m_bIsNewTimer && m_timerInfoTag->m_strDirectory.empty() && m_timerType->SupportsRecordingFolders()) + m_strDirectory = m_strTitle; + else + m_strDirectory = m_timerInfoTag->m_strDirectory; + m_iRecordingGroup = m_timerInfoTag->m_iRecordingGroup; InitializeChannelsList(); diff --git a/xbmc/pvr/recordings/PVRRecording.cpp b/xbmc/pvr/recordings/PVRRecording.cpp index e81603455d..d93846c13f 100644 --- a/xbmc/pvr/recordings/PVRRecording.cpp +++ b/xbmc/pvr/recordings/PVRRecording.cpp @@ -226,10 +226,8 @@ bool CPVRRecording::Delete(void) { PVR_ERROR error = g_PVRClients->DeleteRecording(*this); if (error != PVR_ERROR_NO_ERROR) - { - DisplayError(error); return false; - } + OnDelete(); return true; } @@ -252,10 +250,7 @@ bool CPVRRecording::Undelete(void) { PVR_ERROR error = g_PVRClients->UndeleteRecording(*this); if (error != PVR_ERROR_NO_ERROR) - { - DisplayError(error); return false; - } return true; } @@ -265,10 +260,7 @@ bool CPVRRecording::Rename(const std::string &strNewName) m_strTitle = StringUtils::Format("%s", strNewName.c_str()); PVR_ERROR error = g_PVRClients->RenameRecording(*this); if (error != PVR_ERROR_NO_ERROR) - { - DisplayError(error); return false; - } return true; } @@ -278,10 +270,7 @@ bool CPVRRecording::SetPlayCount(int count) PVR_ERROR error; if (g_PVRClients->SupportsRecordingPlayCount(m_iClientId) && !g_PVRClients->SetRecordingPlayCount(*this, count, &error)) - { - DisplayError(error); return false; - } return CVideoInfoTag::SetPlayCount(count); } @@ -291,10 +280,7 @@ bool CPVRRecording::IncrementPlayCount() PVR_ERROR error; if (g_PVRClients->SupportsRecordingPlayCount(m_iClientId) && !g_PVRClients->SetRecordingPlayCount(*this, CVideoInfoTag::GetPlayCount(), &error)) - { - DisplayError(error); return false; - } return CVideoInfoTag::IncrementPlayCount(); } @@ -304,10 +290,7 @@ bool CPVRRecording::SetResumePoint(const CBookmark &resumePoint) PVR_ERROR error; if (g_PVRClients->SupportsLastPlayedPosition(m_iClientId) && !g_PVRClients->SetRecordingLastPlayedPosition(*this, lrint(resumePoint.timeInSeconds), &error)) - { - DisplayError(error); return false; - } return CVideoInfoTag::SetResumePoint(resumePoint); } @@ -317,10 +300,7 @@ bool CPVRRecording::SetResumePoint(double timeInSeconds, double totalTimeInSecon PVR_ERROR error; if (g_PVRClients->SupportsLastPlayedPosition(m_iClientId) && !g_PVRClients->SetRecordingLastPlayedPosition(*this, lrint(timeInSeconds), &error)) - { - DisplayError(error); return false; - } return CVideoInfoTag::SetResumePoint(timeInSeconds, totalTimeInSeconds, playerState); } @@ -330,11 +310,7 @@ CBookmark CPVRRecording::GetResumePoint() const if (g_PVRClients->SupportsLastPlayedPosition(m_iClientId)) { int pos = g_PVRClients->GetRecordingLastPlayedPosition(*this); - if (pos < 0) - { - DisplayError(PVR_ERROR_SERVER_ERROR); - } - else + if (pos >= 0) { CBookmark resumePoint(CVideoInfoTag::GetResumePoint()); resumePoint.timeInSeconds = pos; @@ -374,18 +350,6 @@ std::vector<PVR_EDL_ENTRY> CPVRRecording::GetEdl() const return std::vector<PVR_EDL_ENTRY>(); } -void CPVRRecording::DisplayError(PVR_ERROR err) const -{ - if (err == PVR_ERROR_SERVER_ERROR) - CGUIDialogOK::ShowAndGetInput(CVariant{19033}, CVariant{19111}); /* print info dialog "Server error!" */ - else if (err == PVR_ERROR_REJECTED) - CGUIDialogOK::ShowAndGetInput(CVariant{19033}, CVariant{19068}); /* print info dialog "Couldn't delete recording!" */ - else - CGUIDialogOK::ShowAndGetInput(CVariant{19033}, CVariant{19147}); /* print info dialog "Unknown error!" */ - - return; -} - void CPVRRecording::Update(const CPVRRecording &tag) { m_strRecordingId = tag.m_strRecordingId; diff --git a/xbmc/pvr/recordings/PVRRecording.h b/xbmc/pvr/recordings/PVRRecording.h index b5d8c6bb5d..3267453ca8 100644 --- a/xbmc/pvr/recordings/PVRRecording.h +++ b/xbmc/pvr/recordings/PVRRecording.h @@ -94,7 +94,7 @@ namespace PVR bool operator ==(const CPVRRecording& right) const; bool operator !=(const CPVRRecording& right) const; - virtual void Serialize(CVariant& value) const; + void Serialize(CVariant& value) const override; /*! * @brief Reset this tag to it's initial state. @@ -276,6 +276,5 @@ namespace PVR bool m_bRadio; /*!< radio or tv recording */ void UpdatePath(void); - void DisplayError(PVR_ERROR err) const; }; } diff --git a/xbmc/pvr/timers/PVRTimerInfoTag.cpp b/xbmc/pvr/timers/PVRTimerInfoTag.cpp index 51d7d0a9e9..4bfbf018a0 100644 --- a/xbmc/pvr/timers/PVRTimerInfoTag.cpp +++ b/xbmc/pvr/timers/PVRTimerInfoTag.cpp @@ -19,9 +19,7 @@ */ #include "ServiceBroker.h" -#include "dialogs/GUIDialogKaiToast.h" #include "dialogs/GUIDialogOK.h" -#include "dialogs/GUIDialogYesNo.h" #include "epg/Epg.h" #include "epg/EpgContainer.h" #include "messaging/ApplicationMessenger.h" diff --git a/xbmc/pvr/timers/PVRTimers.cpp b/xbmc/pvr/timers/PVRTimers.cpp index 6b3cc4d9ac..ffba81cfd7 100644 --- a/xbmc/pvr/timers/PVRTimers.cpp +++ b/xbmc/pvr/timers/PVRTimers.cpp @@ -25,21 +25,17 @@ #include <utility> #include "ServiceBroker.h" -#include "dialogs/GUIDialogKaiToast.h" -#include "dialogs/GUIDialogOK.h" #include "epg/EpgContainer.h" -#include "events/EventLog.h" -#include "events/NotificationEvent.h" #include "FileItem.h" #include "pvr/addons/PVRClients.h" #include "pvr/channels/PVRChannelGroupsContainer.h" +#include "pvr/PVRJobs.h" #include "pvr/PVRManager.h" #include "settings/Settings.h" #include "threads/SingleLock.h" #include "utils/log.h" #include "utils/StringUtils.h" #include "utils/URIUtils.h" -#include "utils/Variant.h" using namespace PVR; using namespace EPG; @@ -326,22 +322,27 @@ bool CPVRTimers::UpdateEntries(const CPVRTimers &timers, const std::vector<int> g_PVRManager.SetChanged(); g_PVRManager.NotifyObservers(bAddedOrDeleted ? ObservableMessageTimersReset : ObservableMessageTimers); - if (g_PVRManager.IsStarted()) + if (!timerNotifications.empty() && g_PVRManager.IsStarted()) { + CPVREventlogJob *job = new CPVREventlogJob; + /* queue notifications / fill eventlog */ for (const auto &entry : timerNotifications) { - if (CServiceBroker::GetSettings().GetBool(CSettings::SETTING_PVRRECORD_TIMERNOTIFICATIONS)) - CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Info, g_localizeStrings.Get(19166), entry.second); - std::string strName; g_PVRClients->GetClientAddonName(entry.first, strName); std::string strIcon; g_PVRClients->GetClientAddonIcon(entry.first, strIcon); - CEventLog::GetInstance().Add(EventPtr(new CNotificationEvent(strName, entry.second, strIcon, EventLevel::Information))); + job->AddEvent(CServiceBroker::GetSettings().GetBool(CSettings::SETTING_PVRRECORD_TIMERNOTIFICATIONS), + false, // info, no error + strName, + entry.second, + strIcon); } + + CJobManager::GetInstance().AddJob(job, nullptr); } } @@ -677,22 +678,6 @@ bool CPVRTimers::DeleteTimersOnChannel(const CPVRChannelPtr &channel, bool bDele bool CPVRTimers::AddTimer(const CPVRTimerInfoTagPtr &item) { - if (!item->m_channel && item->GetTimerType() && !item->GetTimerType()->IsEpgBasedTimerRule()) - { - CLog::Log(LOGERROR, "PVRTimers - %s - no channel given", __FUNCTION__); - CGUIDialogOK::ShowAndGetInput(CVariant{19033}, CVariant{19109}); // Couldn't save timer - return false; - } - - if (!g_PVRClients->SupportsTimers(item->m_iClientId)) - { - CGUIDialogOK::ShowAndGetInput(CVariant{19033}, CVariant{19215}); - return false; - } - - if (!g_PVRManager.CheckParentalLock(item->m_channel)) - return false; - return item->AddToClient(); } diff --git a/xbmc/pvr/timers/PVRTimers.h b/xbmc/pvr/timers/PVRTimers.h index 5519f6f541..0ffa7aa747 100644 --- a/xbmc/pvr/timers/PVRTimers.h +++ b/xbmc/pvr/timers/PVRTimers.h @@ -183,26 +183,26 @@ namespace PVR /*! * @brief Add a timer to the client. Doesn't add the timer to the container. The backend will do this. - * @return True if it was sent correctly, false if not. + * @return True if timer add request was sent correctly, false if not. */ - static bool AddTimer(const CPVRTimerInfoTagPtr &item); + static bool AddTimer(const CPVRTimerInfoTagPtr &item); /*! * @brief Delete a timer on the client. Doesn't delete the timer from the container. The backend will do this. * @param bDeleteRule Also delete the timer rule that scheduled the timer instead of single timer only. - * @return True if it was sent correctly, false if not. + * @return True if timer delete request was sent correctly, false if not. */ static bool DeleteTimer(const CPVRTimerInfoTagPtr &tag, bool bForce = false, bool bDeleteRule = false); /*! * @brief Rename a timer on the client. Doesn't update the timer in the container. The backend will do this. - * @return True if it was sent correctly, false if not. + * @return True if timer rename request was sent correctly, false if not. */ static bool RenameTimer(CFileItem &item, const std::string &strNewName); /*! * @brief Update the timer on the client. Doesn't update the timer in the container. The backend will do this. - * @return True if it was sent correctly, false if not. + * @return True if timer update request was sent correctly, false if not. */ static bool UpdateTimer(const CPVRTimerInfoTagPtr &item); diff --git a/xbmc/rendering/dx/RenderSystemDX.cpp b/xbmc/rendering/dx/RenderSystemDX.cpp index 0cd42d1a0c..a2cdc15039 100644 --- a/xbmc/rendering/dx/RenderSystemDX.cpp +++ b/xbmc/rendering/dx/RenderSystemDX.cpp @@ -772,7 +772,7 @@ bool CRenderSystemDX::CreateWindowSizeDependentResources() if (!bNeedRecreate && !bNeedResize) { - CheckInterlasedStereoView(); + CheckInterlacedStereoView(); return true; } @@ -1010,7 +1010,7 @@ bool CRenderSystemDX::CreateWindowSizeDependentResources() CPoint camPoint = { m_nBackBufferWidth * 0.5f, m_nBackBufferHeight * 0.5f }; SetCameraPosition(camPoint, m_nBackBufferWidth, m_nBackBufferHeight); - CheckInterlasedStereoView(); + CheckInterlacedStereoView(); if (bRestoreRTView) m_pContext->OMSetRenderTargets(1, &m_pRenderTargetView, m_depthStencilView); @@ -1025,7 +1025,7 @@ bool CRenderSystemDX::CreateWindowSizeDependentResources() return true; } -void CRenderSystemDX::CheckInterlasedStereoView(void) +void CRenderSystemDX::CheckInterlacedStereoView(void) { RENDER_STEREO_MODE stereoMode = g_graphicsContext.GetStereoMode(); diff --git a/xbmc/rendering/dx/RenderSystemDX.h b/xbmc/rendering/dx/RenderSystemDX.h index e2fcdf54a6..19f5964dba 100644 --- a/xbmc/rendering/dx/RenderSystemDX.h +++ b/xbmc/rendering/dx/RenderSystemDX.h @@ -115,7 +115,7 @@ protected: void OnResize(unsigned int width, unsigned int height); void SetFullScreenInternal(); void GetClosestDisplayModeToCurrent(IDXGIOutput* output, DXGI_MODE_DESC* outCurrentDisplayMode, bool useCached = false); - void CheckInterlasedStereoView(void); + void CheckInterlacedStereoView(void); void SetMaximumFrameLatency(uint8_t latency = -1) const; bool GetStereoEnabled() const; diff --git a/xbmc/settings/AdvancedSettings.cpp b/xbmc/settings/AdvancedSettings.cpp index 5634ed111a..9ce6384c07 100644 --- a/xbmc/settings/AdvancedSettings.cpp +++ b/xbmc/settings/AdvancedSettings.cpp @@ -28,6 +28,7 @@ #include "addons/AudioDecoder.h" #include "addons/BinaryAddonCache.h" #include "addons/IAddon.h" +#include "addons/ImageDecoder.h" #include "Application.h" #include "ServiceBroker.h" #include "filesystem/File.h" @@ -275,6 +276,7 @@ void CAdvancedSettings::Initialize() m_bMusicLibraryAllItemsOnBottom = false; m_bMusicLibraryCleanOnUpdate = false; + m_bMusicLibraryPromptFullTagScan = false; m_iMusicLibraryRecentlyAddedItems = 25; m_strMusicLibraryAlbumFormat = ""; m_prioritiseAPEv2tags = false; @@ -732,6 +734,7 @@ void CAdvancedSettings::ParseSettingsFile(const std::string &file) XMLUtils::GetBoolean(pElement, "prioritiseapetags", m_prioritiseAPEv2tags); XMLUtils::GetBoolean(pElement, "allitemsonbottom", m_bMusicLibraryAllItemsOnBottom); XMLUtils::GetBoolean(pElement, "cleanonupdate", m_bMusicLibraryCleanOnUpdate); + XMLUtils::GetBoolean(pElement, "promptfulltagscan", m_bMusicLibraryPromptFullTagScan); XMLUtils::GetString(pElement, "albumformat", m_strMusicLibraryAlbumFormat); XMLUtils::GetString(pElement, "itemseparator", m_musicItemSeparator); XMLUtils::GetInt(pElement, "dateadded", m_iMusicLibraryDateAdded); @@ -1437,3 +1440,20 @@ std::string CAdvancedSettings::GetMusicExtensions() const return result; } + +std::string CAdvancedSettings::GetPictureExtensions() const +{ + std::string result(m_pictureExtensions); + + VECADDONS codecs; + CBinaryAddonCache &addonCache = CServiceBroker::GetBinaryAddonCache(); + addonCache.GetAddons(codecs, ADDON_IMAGEDECODER); + for (size_t i=0;i<codecs.size();++i) + { + std::shared_ptr<CImageDecoder> dec(std::static_pointer_cast<CImageDecoder>(codecs[i])); + result += '|'; + result += dec->GetExtensions(); + } + + return result; +} diff --git a/xbmc/settings/AdvancedSettings.h b/xbmc/settings/AdvancedSettings.h index 64d42f8bdc..76428eef8d 100644 --- a/xbmc/settings/AdvancedSettings.h +++ b/xbmc/settings/AdvancedSettings.h @@ -256,6 +256,7 @@ class CAdvancedSettings : public ISettingCallback, public ISettingsHandler int m_iMusicLibraryDateAdded; bool m_bMusicLibraryAllItemsOnBottom; bool m_bMusicLibraryCleanOnUpdate; + bool m_bMusicLibraryPromptFullTagScan; std::string m_strMusicLibraryAlbumFormat; bool m_prioritiseAPEv2tags; std::string m_musicItemSeparator; @@ -356,6 +357,9 @@ class CAdvancedSettings : public ISettingCallback, public ISettingsHandler float GetDisplayLatency(float refreshrate); bool m_initialized; + //! \brief Returns a list of picture extension for filtering in the GUI + std::string GetPictureExtensions() const; + //! \brief Returns a list of music extension for filtering in the GUI std::string GetMusicExtensions() const; @@ -365,7 +369,6 @@ class CAdvancedSettings : public ISettingCallback, public ISettingsHandler void ToggleDirtyRegionVisualization() { m_guiVisualizeDirtyRegions = !m_guiVisualizeDirtyRegions; }; // runtime settings which cannot be set from advancedsettings.xml - std::string m_pictureExtensions; std::string m_videoExtensions; std::string m_discStubExtensions; std::string m_subtitlesExtensions; @@ -385,6 +388,7 @@ class CAdvancedSettings : public ISettingCallback, public ISettingsHandler private: std::string m_musicExtensions; + std::string m_pictureExtensions; void setExtraLogLevel(const std::vector<CVariant> &components); }; diff --git a/xbmc/settings/SettingConditions.cpp b/xbmc/settings/SettingConditions.cpp index 6b1f2b6d75..4abfb5c43d 100644 --- a/xbmc/settings/SettingConditions.cpp +++ b/xbmc/settings/SettingConditions.cpp @@ -34,7 +34,7 @@ #include "peripherals/Peripherals.h" #include "peripherals/bus/virtual/PeripheralBusAddon.h" #include "profiles/ProfilesManager.h" -#include "pvr/PVRManager.h" +#include "pvr/PVRGUIActions.h" #include "settings/SettingAddon.h" #if defined(HAS_LIBAMCODEC) #include "utils/AMLUtils.h" @@ -72,7 +72,7 @@ bool CheckMasterLock(const std::string &condition, const std::string &value, con bool CheckPVRParentalPin(const std::string &condition, const std::string &value, const CSetting *setting, void *data) { - return PVR::g_PVRManager.CheckParentalPIN(g_localizeStrings.Get(19262).c_str()); + return PVR::CPVRGUIActions::GetInstance().CheckParentalPIN(); } bool HasPeripherals(const std::string &condition, const std::string &value, const CSetting *setting, void *data) diff --git a/xbmc/settings/Settings.cpp b/xbmc/settings/Settings.cpp index e745aebf57..89f0414803 100644 --- a/xbmc/settings/Settings.cpp +++ b/xbmc/settings/Settings.cpp @@ -728,7 +728,7 @@ bool CSettings::InitializeDefinitions() #elif defined(TARGET_RASPBERRY_PI) if (CFile::Exists(SETTINGS_XML_FOLDER "rbp.xml") && !Initialize(SETTINGS_XML_FOLDER "rbp.xml")) CLog::Log(LOGFATAL, "Unable to load rbp-specific settings definitions"); - if (g_RBP.RasberryPiVersion() > 1 && CFile::Exists(SETTINGS_XML_FOLDER "rbp2.xml") && !Initialize(SETTINGS_XML_FOLDER "rbp2.xml")) + if (g_RBP.RaspberryPiVersion() > 1 && CFile::Exists(SETTINGS_XML_FOLDER "rbp2.xml") && !Initialize(SETTINGS_XML_FOLDER "rbp2.xml")) CLog::Log(LOGFATAL, "Unable to load rbp2-specific settings definitions"); #elif defined(TARGET_FREEBSD) if (CFile::Exists(SETTINGS_XML_FOLDER "freebsd.xml") && !Initialize(SETTINGS_XML_FOLDER "freebsd.xml")) diff --git a/xbmc/settings/dialogs/GUIDialogAudioDSPManager.cpp b/xbmc/settings/dialogs/GUIDialogAudioDSPManager.cpp index b6301e490c..8a39ebbcb3 100644 --- a/xbmc/settings/dialogs/GUIDialogAudioDSPManager.cpp +++ b/xbmc/settings/dialogs/GUIDialogAudioDSPManager.cpp @@ -306,7 +306,7 @@ bool CGUIDialogAudioDSPManager::OnClickListActive(CGUIMessage &message) return false; } -bool CGUIDialogAudioDSPManager::OnClickRadioContinousSaving(CGUIMessage &message) +bool CGUIDialogAudioDSPManager::OnClickRadioContinuousSaving(CGUIMessage &message) { CGUIRadioButtonControl *radioButton = dynamic_cast<CGUIRadioButtonControl*>(GetControl(CONTROL_RADIO_BUTTON_CONTINUOUS_SAVING)); CGUIButtonControl *applyChangesButton = dynamic_cast<CGUIButtonControl*>(GetControl(CONTROL_BUTTON_APPLY_CHANGES)); @@ -383,7 +383,7 @@ bool CGUIDialogAudioDSPManager::OnMessageClick(CGUIMessage &message) case CONTROL_LIST_ACTIVE: return OnClickListActive(message); case CONTROL_RADIO_BUTTON_CONTINUOUS_SAVING: - return OnClickRadioContinousSaving(message); + return OnClickRadioContinuousSaving(message); case CONTROL_BUTTON_CLEAR_ACTIVE_MODES: return OnClickClearActiveModes(message); case CONTROL_BUTTON_APPLY_CHANGES: diff --git a/xbmc/settings/dialogs/GUIDialogAudioDSPManager.h b/xbmc/settings/dialogs/GUIDialogAudioDSPManager.h index 4843c39eea..3e13225969 100644 --- a/xbmc/settings/dialogs/GUIDialogAudioDSPManager.h +++ b/xbmc/settings/dialogs/GUIDialogAudioDSPManager.h @@ -53,7 +53,7 @@ namespace ActiveAE bool OnClickListAvailable(CGUIMessage &message); bool OnClickListActive(CGUIMessage &message); - bool OnClickRadioContinousSaving(CGUIMessage &message); + bool OnClickRadioContinuousSaving(CGUIMessage &message); bool OnClickApplyChanges(CGUIMessage &message); bool OnClickClearActiveModes(CGUIMessage &message); diff --git a/xbmc/utils/BitstreamConverter.cpp b/xbmc/utils/BitstreamConverter.cpp index 7bb100ffb0..84f105f5fe 100644 --- a/xbmc/utils/BitstreamConverter.cpp +++ b/xbmc/utils/BitstreamConverter.cpp @@ -74,6 +74,34 @@ enum { HEVC_NAL_SEI_SUFFIX = 40 }; +enum { + SEI_BUFFERING_PERIOD = 0, + SEI_PIC_TIMING, + SEI_PAN_SCAN_RECT, + SEI_FILLER_PAYLOAD, + SEI_USER_DATA_REGISTERED_ITU_T_T35, + SEI_USER_DATA_UNREGISTERED, + SEI_RECOVERY_POINT, + SEI_DEC_REF_PIC_MARKING_REPETITION, + SEI_SPARE_PIC, + SEI_SCENE_INFO, + SEI_SUB_SEQ_INFO, + SEI_SUB_SEQ_LAYER_CHARACTERISTICS, + SEI_SUB_SEQ_CHARACTERISTICS, + SEI_FULL_FRAME_FREEZE, + SEI_FULL_FRAME_FREEZE_RELEASE, + SEI_FULL_FRAME_SNAPSHOT, + SEI_PROGRESSIVE_REFINEMENT_SEGMENT_START, + SEI_PROGRESSIVE_REFINEMENT_SEGMENT_END, + SEI_MOTION_CONSTRAINED_SLICE_GROUP_SET, + SEI_FILM_GRAIN_CHARACTERISTICS, + SEI_DEBLOCKING_FILTER_DISPLAY_PREFERENCE, + SEI_STEREO_VIDEO_INFO, + SEI_POST_FILTER_HINTS, + SEI_TONE_MAPPING +}; + + //////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////// // GStreamer h264 parser @@ -207,6 +235,34 @@ static const uint8_t* avc_find_startcode(const uint8_t *p, const uint8_t *end) return out; } +static bool has_sei_recovery_point(const uint8_t *p, const uint8_t *end) +{ + int pt(0), ps(0), offset(1); + + do + { + pt = 0; + do { + pt += p[offset]; + } while (p[offset++] == 0xFF); + + ps = 0; + do { + ps += p[offset]; + } while (p[offset++] == 0xFF); + + if (pt == SEI_RECOVERY_POINT) + { + nal_bitstream bs; + nal_bs_init(&bs, p + offset, ps); + return nal_bs_read_ue(&bs) >= 0; + } + offset += ps; + } while(p + offset < end && p[offset] != 0x80); + + return false; +} + //////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////// CBitstreamParser::CBitstreamParser() @@ -217,49 +273,44 @@ CBitstreamParser::~CBitstreamParser() { } -bool CBitstreamParser::FindIdrSlice(const uint8_t *buf, int buf_size) +bool CBitstreamParser::HasKeyframe(const uint8_t *buf, int buf_size) { if (!buf) return false; bool rtn = false; uint32_t state = -1; - const uint8_t *buf_end = buf + buf_size; + const uint8_t *buf_begin, *buf_end = buf + buf_size; - for(;;) + for(;rtn == false;) { buf = find_start_code(buf, buf_end, &state); if (buf >= buf_end) { - //CLog::Log(LOGDEBUG, "FindIdrSlice: buf(%p), buf_end(%p)", buf, buf_end); break; } - --buf; - int src_length = buf_end - buf; switch (state & 0x1f) { - default: - CLog::Log(LOGDEBUG, "FindIdrSlice: found nal_type(%d)", state & 0x1f); - break; case AVC_NAL_SLICE: - CLog::Log(LOGDEBUG, "FindIdrSlice: found NAL_SLICE"); break; case AVC_NAL_IDR_SLICE: - CLog::Log(LOGDEBUG, "FindIdrSlice: found NAL_IDR_SLICE"); rtn = true; break; case AVC_NAL_SEI: - CLog::Log(LOGDEBUG, "FindIdrSlice: found NAL_SEI"); + buf_begin = buf - 1; + buf = find_start_code(buf, buf_end, &state) - 4; + if (has_sei_recovery_point(buf_begin, buf)) + rtn = true; break; case AVC_NAL_SPS: - CLog::Log(LOGDEBUG, "FindIdrSlice: found NAL_SPS"); + rtn = true; break; case AVC_NAL_PPS: - CLog::Log(LOGDEBUG, "FindIdrSlice: found NAL_PPS"); + break; + default: break; } - buf += src_length; } return rtn; @@ -280,6 +331,7 @@ CBitstreamConverter::CBitstreamConverter() m_convert_3byteTo4byteNALSize = false; m_convert_bytestream = false; m_sps_pps_context.sps_pps_data = NULL; + m_has_keyframe = true; } CBitstreamConverter::~CBitstreamConverter() @@ -359,7 +411,7 @@ bool CBitstreamConverter::Open(enum AVCodecID codec, uint8_t *in_extradata, int // are valid, setup to convert 3 byte NAL sizes to 4 byte. in_extradata[4] = 0xFF; m_convert_3byteTo4byteNALSize = true; - + m_extradata = (uint8_t *)av_malloc(in_extrasize); memcpy(m_extradata, in_extradata, in_extrasize); m_extrasize = in_extrasize; @@ -470,7 +522,7 @@ void CBitstreamConverter::Close(void) bool CBitstreamConverter::Convert(uint8_t *pData, int iSize) { if (m_convertBuffer) - { + { av_free(m_convertBuffer); m_convertBuffer = NULL; } @@ -520,7 +572,7 @@ bool CBitstreamConverter::Convert(uint8_t *pData, int iSize) { m_inputSize = iSize; m_inputBuffer = pData; - + if (m_convert_bytestream) { if(m_convertBuffer) @@ -608,6 +660,16 @@ int CBitstreamConverter::GetExtraSize() const return m_extrasize; } +void CBitstreamConverter::ResetKeyframe(void) +{ + m_has_keyframe = false; +} + +bool CBitstreamConverter::HasKeyframe() const +{ + return m_has_keyframe; +} + bool CBitstreamConverter::BitstreamConvertInitAVC(void *in_extradata, int in_extrasize) { // based on h264_mp4toannexb_bsf.c (ffmpeg) @@ -822,7 +884,7 @@ bool CBitstreamConverter::BitstreamConvert(uint8_t* pData, int iSize, uint8_t ** int i; uint8_t *buf = pData; uint32_t buf_size = iSize; - uint8_t unit_type, nal_sps, nal_pps; + uint8_t unit_type, nal_sps, nal_pps, nal_sei; int32_t nal_size; uint32_t cumul_size = 0; const uint8_t *buf_end = buf + buf_size; @@ -832,10 +894,12 @@ bool CBitstreamConverter::BitstreamConvert(uint8_t* pData, int iSize, uint8_t ** case AV_CODEC_ID_H264: nal_sps = AVC_NAL_SPS; nal_pps = AVC_NAL_PPS; + nal_sei = AVC_NAL_SEI; break; case AV_CODEC_ID_HEVC: nal_sps = HEVC_NAL_SPS; nal_pps = HEVC_NAL_PPS; + nal_sei = HEVC_NAL_SEI_PREFIX; break; default: return false; @@ -866,7 +930,10 @@ bool CBitstreamConverter::BitstreamConvert(uint8_t* pData, int iSize, uint8_t ** if (m_sps_pps_context.first_idr && (unit_type == nal_sps || unit_type == nal_pps)) m_sps_pps_context.idr_sps_pps_seen = 1; - // prepend only to the first access unit of an IDR picture, if no sps/pps already present + if (!m_has_keyframe && (unit_type == nal_sps || IsIDR(unit_type) || (unit_type == nal_sei && has_sei_recovery_point(buf, buf + nal_size)))) + m_has_keyframe = true; + + // prepend only to the first access unit of an IDR picture, if no sps/pps already present if (m_sps_pps_context.first_idr && IsIDR(unit_type) && !m_sps_pps_context.idr_sps_pps_seen) { BitstreamAllocAndCopy(poutbuf, poutbuf_size, diff --git a/xbmc/utils/BitstreamConverter.h b/xbmc/utils/BitstreamConverter.h index 81e4037473..bdcc3be630 100644 --- a/xbmc/utils/BitstreamConverter.h +++ b/xbmc/utils/BitstreamConverter.h @@ -87,7 +87,9 @@ public: CBitstreamParser(); ~CBitstreamParser(); - static bool FindIdrSlice(const uint8_t *buf, int buf_size); + static bool Open(){}; + static void Close(){}; + static bool HasKeyframe(const uint8_t *buf, int buf_size); }; class CBitstreamConverter @@ -104,6 +106,8 @@ public: int GetConvertSize() const; uint8_t* GetExtraData(void) const; int GetExtraSize() const; + void ResetKeyframe(void); + bool HasKeyframe() const; static void parseh264_sps(const uint8_t *sps, const uint32_t sps_size, bool *interlaced, int32_t *max_ref_frames); static bool mpeg2_sequence_header(const uint8_t *data, const uint32_t size, mpeg2_sequence *sequence); @@ -144,4 +148,5 @@ protected: bool m_convert_3byteTo4byteNALSize; bool m_convert_bytestream; AVCodecID m_codec; + bool m_has_keyframe; }; diff --git a/xbmc/utils/Mime.cpp b/xbmc/utils/Mime.cpp index 91234c90da..875148f6d8 100644 --- a/xbmc/utils/Mime.cpp +++ b/xbmc/utils/Mime.cpp @@ -55,6 +55,7 @@ std::map<std::string, std::string> fillMimeTypes() mimeTypes.insert(std::pair<std::string, std::string>("arc", "application/octet-stream")); mimeTypes.insert(std::pair<std::string, std::string>("arj", "application/arj")); mimeTypes.insert(std::pair<std::string, std::string>("art", "image/x-jg")); + mimeTypes.insert(std::pair<std::string, std::string>("arw", "image/arw")); mimeTypes.insert(std::pair<std::string, std::string>("asf", "video/x-ms-asf")); mimeTypes.insert(std::pair<std::string, std::string>("asm", "text/x-asm")); mimeTypes.insert(std::pair<std::string, std::string>("asp", "text/asp")); @@ -91,6 +92,7 @@ std::map<std::string, std::string> fillMimeTypes() mimeTypes.insert(std::pair<std::string, std::string>("cpt", "application/x-cpt")); mimeTypes.insert(std::pair<std::string, std::string>("crl", "application/pkcs-crl")); mimeTypes.insert(std::pair<std::string, std::string>("crt", "application/pkix-cert")); + mimeTypes.insert(std::pair<std::string, std::string>("cr2", "image/cr2")); mimeTypes.insert(std::pair<std::string, std::string>("csh", "application/x-csh")); mimeTypes.insert(std::pair<std::string, std::string>("css", "text/css")); mimeTypes.insert(std::pair<std::string, std::string>("cxx", "text/plain")); @@ -102,6 +104,7 @@ std::map<std::string, std::string> fillMimeTypes() mimeTypes.insert(std::pair<std::string, std::string>("dir", "application/x-director")); mimeTypes.insert(std::pair<std::string, std::string>("dl", "video/dl")); mimeTypes.insert(std::pair<std::string, std::string>("divx", "video/x-msvideo")); + mimeTypes.insert(std::pair<std::string, std::string>("dng", "image/dng")); mimeTypes.insert(std::pair<std::string, std::string>("doc", "application/msword")); mimeTypes.insert(std::pair<std::string, std::string>("docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document")); mimeTypes.insert(std::pair<std::string, std::string>("dot", "application/msword")); @@ -268,6 +271,7 @@ std::map<std::string, std::string> fillMimeTypes() mimeTypes.insert(std::pair<std::string, std::string>("naplps", "image/naplps")); mimeTypes.insert(std::pair<std::string, std::string>("nc", "application/x-netcdf")); mimeTypes.insert(std::pair<std::string, std::string>("ncm", "application/vnd.nokia.configuration-message")); + mimeTypes.insert(std::pair<std::string, std::string>("nef", "image/nef")); mimeTypes.insert(std::pair<std::string, std::string>("nfo", "text/xml")); mimeTypes.insert(std::pair<std::string, std::string>("nif", "image/x-niff")); mimeTypes.insert(std::pair<std::string, std::string>("niff", "image/x-niff")); diff --git a/xbmc/utils/URIUtils.cpp b/xbmc/utils/URIUtils.cpp index 06b2068207..76f4c6f750 100644 --- a/xbmc/utils/URIUtils.cpp +++ b/xbmc/utils/URIUtils.cpp @@ -127,7 +127,7 @@ void URIUtils::RemoveExtension(std::string& strFileName) strExtension += "|"; std::string strFileMask; - strFileMask = g_advancedSettings.m_pictureExtensions; + strFileMask = g_advancedSettings.GetPictureExtensions(); strFileMask += "|" + g_advancedSettings.GetMusicExtensions(); strFileMask += "|" + g_advancedSettings.m_videoExtensions; strFileMask += "|" + g_advancedSettings.m_subtitlesExtensions; diff --git a/xbmc/utils/test/TestHttpHeader.cpp b/xbmc/utils/test/TestHttpHeader.cpp index 72a50e1a2f..45c8337858 100644 --- a/xbmc/utils/test/TestHttpHeader.cpp +++ b/xbmc/utils/test/TestHttpHeader.cpp @@ -75,7 +75,7 @@ "\r\n" // local helper function: replace substrings -std::string strReplc(const std::string& str, const std::string& from, const std::string& to) +std::string strReplace(const std::string& str, const std::string& from, const std::string& to) { std::string result; size_t prevPos = 0; @@ -175,14 +175,14 @@ TEST(TestHttpHeader, Parse) EXPECT_STREQ("http://www.Example.Com", testHdr.GetValue("Location").c_str()); // case-sensitive match of value /* check support for '\n' line endings */ - testHdr.Parse(strReplc(CHECK_HEADER_SMPL, "\r\n", "\n")); + testHdr.Parse(strReplace(CHECK_HEADER_SMPL, "\r\n", "\n")); EXPECT_TRUE(testHdr.IsHeaderDone()) << "Completed header has \"parsing not finished\" state"; EXPECT_STRCASEEQ(CHECK_HEADER_SMPL, testHdr.GetHeader().c_str()) << "Parsed header mismatch the original header"; EXPECT_TRUE(testHdr.IsHeaderDone()) << "Completed header has \"parsing not finished\" state"; - testHdr.Parse(strReplc(CHECK_HEADER_L1, "\r\n", "\n")); + testHdr.Parse(strReplace(CHECK_HEADER_L1, "\r\n", "\n")); EXPECT_STRCASEEQ(CHECK_HEADER_L1, testHdr.GetHeader().c_str()) << "Parsed header mismatch the original header"; EXPECT_TRUE(testHdr.IsHeaderDone()) << "Completed header has \"parsing not finished\" state"; - testHdr.Parse(strReplc(CHECK_HEADER_L2, "\r\n", "\n")); + testHdr.Parse(strReplace(CHECK_HEADER_L2, "\r\n", "\n")); EXPECT_STRCASEEQ(CHECK_HEADER_L2, testHdr.GetHeader().c_str()) << "Parsed header mismatch the original header"; EXPECT_TRUE(testHdr.IsHeaderDone()) << "Completed header has \"parsing not finished\" state"; testHdr.Parse(CHECK_PROT_LINE_200 "\n" CHECK_CNT_TYPE_NAME ": " CHECK_CONTENT_TYPE_HTML "\r\n"); // mixed "\n" and "\r\n" @@ -332,7 +332,7 @@ TEST(TestHttpHeader, Parse_Multiline) EXPECT_TRUE(testHdr.IsHeaderDone()) << "Completed header has \"parsing not finished\" state"; EXPECT_GE(strlen("Apache/2.4.7 (Unix) mod_wsgi/3.4 \tPython/2.7.5\t \t \tOpenSSL/1.0.1e"), testHdr.GetValue("Server").length()) << "Length of miltiline value is greater than length of original string"; EXPECT_LE(strlen("Apache/2.4.7 (Unix) mod_wsgi/3.4 Python/2.7.5 OpenSSL/1.0.1e"), testHdr.GetValue("Server").length()) << "Length of miltiline value is less than length of trimmed original string"; - EXPECT_STREQ("Apache/2.4.7(Unix)mod_wsgi/3.4Python/2.7.5OpenSSL/1.0.1e", strReplc(strReplc(testHdr.GetValue("Server"), " ", ""), "\t", "").c_str()) << "Multiline value with removed whitespaces does not match original string with removed whitespaces"; + EXPECT_STREQ("Apache/2.4.7(Unix)mod_wsgi/3.4Python/2.7.5OpenSSL/1.0.1e", strReplace(strReplace(testHdr.GetValue("Server"), " ", ""), "\t", "").c_str()) << "Multiline value with removed whitespaces does not match original string with removed whitespaces"; testHdr.Clear(); testHdr.Parse(CHECK_PROT_LINE_200 "\r\n"); @@ -343,7 +343,7 @@ TEST(TestHttpHeader, Parse_Multiline) EXPECT_TRUE(testHdr.IsHeaderDone()) << "Completed header has \"parsing not finished\" state"; EXPECT_GE(strlen("Apache/2.4.7 (Unix) mod_wsgi/3.4 \tPython/2.7.5\t \t \tOpenSSL/1.0.1e"), testHdr.GetValue("Server").length()) << "Length of miltiline value is greater than length of original string"; EXPECT_LE(strlen("Apache/2.4.7 (Unix) mod_wsgi/3.4 Python/2.7.5 OpenSSL/1.0.1e"), testHdr.GetValue("Server").length()) << "Length of miltiline value is less than length of trimmed original string"; - EXPECT_STREQ("Apache/2.4.7(Unix)mod_wsgi/3.4Python/2.7.5OpenSSL/1.0.1e", strReplc(strReplc(testHdr.GetValue("Server"), " ", ""), "\t", "").c_str()) << "Multiline value with removed whitespaces does not match original string with removed whitespaces"; + EXPECT_STREQ("Apache/2.4.7(Unix)mod_wsgi/3.4Python/2.7.5OpenSSL/1.0.1e", strReplace(strReplace(testHdr.GetValue("Server"), " ", ""), "\t", "").c_str()) << "Multiline value with removed whitespaces does not match original string with removed whitespaces"; } TEST(TestHttpHeader, GetValue) diff --git a/xbmc/utils/test/TestVariant.cpp b/xbmc/utils/test/TestVariant.cpp index 45ee687758..ad9f089907 100644 --- a/xbmc/utils/test/TestVariant.cpp +++ b/xbmc/utils/test/TestVariant.cpp @@ -236,7 +236,7 @@ TEST(TestVariant, swap) EXPECT_TRUE(a.isString()); } -TEST(TestVariant, interator_array) +TEST(TestVariant, iterator_array) { std::vector<std::string> strarray; strarray.push_back("string"); diff --git a/xbmc/video/CMakeLists.txt b/xbmc/video/CMakeLists.txt index 9842fce0aa..c3ee3d7554 100644 --- a/xbmc/video/CMakeLists.txt +++ b/xbmc/video/CMakeLists.txt @@ -9,7 +9,6 @@ set(SOURCES Bookmark.cpp VideoInfoScanner.cpp VideoInfoTag.cpp VideoLibraryQueue.cpp - VideoReferenceClock.cpp VideoThumbLoader.cpp ViewModeSettings.cpp) @@ -26,7 +25,6 @@ set(HEADERS Bookmark.h VideoInfoScanner.h VideoInfoTag.h VideoLibraryQueue.h - VideoReferenceClock.h VideoThumbLoader.h) core_add_library(video) diff --git a/xbmc/video/VideoInfoScanner.cpp b/xbmc/video/VideoInfoScanner.cpp index 5f8dbf85bc..b3bef3e19f 100644 --- a/xbmc/video/VideoInfoScanner.cpp +++ b/xbmc/video/VideoInfoScanner.cpp @@ -126,7 +126,7 @@ namespace VIDEO m_itemCount = -1; // Database operations should not be canceled - // using Interupt() while scanning as it could + // using Interrupt() while scanning as it could // result in unexpected behaviour. m_bCanInterrupt = false; @@ -229,7 +229,7 @@ namespace VIDEO void CVideoInfoScanner::Stop() { if (m_bCanInterrupt) - m_database.Interupt(); + m_database.Interrupt(); m_bStop = true; } diff --git a/xbmc/video/videosync/CMakeLists.txt b/xbmc/video/videosync/CMakeLists.txt deleted file mode 100644 index 82f7169c78..0000000000 --- a/xbmc/video/videosync/CMakeLists.txt +++ /dev/null @@ -1,45 +0,0 @@ -set(HEADERS VideoSync.h) - -if(OPENGL_FOUND) - list(APPEND SOURCES VideoSyncGLX.cpp) - list(APPEND HEADERS VideoSyncGLX.h) -endif() - -if(X_FOUND) - list(APPEND SOURCES VideoSyncDRM.cpp) - list(APPEND HEADERS VideoSyncDRM.h) -endif() - -if(CORE_SYSTEM_NAME STREQUAL windows) - list(APPEND SOURCES VideoSyncD3D.cpp) - list(APPEND HEADERS VideoSyncD3D.h) -endif() - -if(CORE_SYSTEM_NAME STREQUAL rbpi) - list(APPEND SOURCES VideoSyncPi.cpp) - list(APPEND HEADERS VideoSyncPi.h) -endif() - -if(CORE_SYSTEM_NAME STREQUAL osx) - list(APPEND SOURCES VideoSyncOsx.cpp) - list(APPEND HEADERS VideoSyncOsx.h) -endif() - -if(CORE_SYSTEM_NAME STREQUAL ios) - list(APPEND SOURCES VideoSyncIos.cpp) - list(APPEND HEADERS VideoSyncIos.h) -endif() - -if(CORE_SYSTEM_NAME STREQUAL android) - list(APPEND SOURCES VideoSyncAndroid.cpp) - list(APPEND HEADERS VideoSyncAndroid.h) -endif() - -if(IMX_FOUND) - list(APPEND SOURCES VideoSyncIMX.cpp) - list(APPEND HEADERS VideoSyncIMX.h) -endif() - -if(SOURCES AND HEADERS) - core_add_library(video_sync) -endif() diff --git a/xbmc/windowing/CMakeLists.txt b/xbmc/windowing/CMakeLists.txt index 0e0cf87a1e..b8924a3104 100644 --- a/xbmc/windowing/CMakeLists.txt +++ b/xbmc/windowing/CMakeLists.txt @@ -4,7 +4,8 @@ set(SOURCES WinEvents.cpp set(HEADERS WindowingFactory.h WinEvents.h WinSystem.h - XBMC_events.h) + XBMC_events.h + VideoSync.h) if (NOT MIR_FOUND) if(SDL_FOUND AND NOT X_FOUND) diff --git a/xbmc/video/videosync/VideoSync.h b/xbmc/windowing/VideoSync.h index a430cb029f..8db21957ca 100644 --- a/xbmc/video/videosync/VideoSync.h +++ b/xbmc/windowing/VideoSync.h @@ -21,12 +21,12 @@ #include <atomic> class CVideoReferenceClock; -typedef void (*PUPDATECLOCK)(int NrVBlanks, uint64_t time, CVideoReferenceClock *clock); +typedef void (*PUPDATECLOCK)(int NrVBlanks, uint64_t time, void *clock); class CVideoSync { public: - CVideoSync(CVideoReferenceClock *clock) { m_refClock = clock; }; + CVideoSync(void *clock) { m_refClock = clock; }; virtual ~CVideoSync() {}; virtual bool Setup(PUPDATECLOCK func) = 0; virtual void Run(std::atomic<bool>& stop) = 0; @@ -36,5 +36,5 @@ public: protected: PUPDATECLOCK UpdateClock; float m_fps; - CVideoReferenceClock *m_refClock; + void *m_refClock; }; diff --git a/xbmc/windowing/WinSystem.h b/xbmc/windowing/WinSystem.h index d67a2a9298..95676b4358 100644 --- a/xbmc/windowing/WinSystem.h +++ b/xbmc/windowing/WinSystem.h @@ -21,8 +21,10 @@ #ifndef WINDOW_SYSTEM_BASE_H #define WINDOW_SYSTEM_BASE_H +#include "VideoSync.h" #include "WinEvents.h" #include "guilib/Resolution.h" +#include <memory> #include <vector> typedef enum _WindowSystemType @@ -84,6 +86,9 @@ public: virtual bool Hide() { return false; } virtual bool Show(bool raise = true) { return false; } + // videosync + virtual std::unique_ptr<CVideoSync> GetVideoSync(void *clock) { return nullptr; } + // notifications virtual void OnMove(int x, int y) {} diff --git a/xbmc/windowing/X11/CMakeLists.txt b/xbmc/windowing/X11/CMakeLists.txt index 6d2527d563..902dea50a4 100644 --- a/xbmc/windowing/X11/CMakeLists.txt +++ b/xbmc/windowing/X11/CMakeLists.txt @@ -6,6 +6,8 @@ if (X_FOUND) WinSystemX11GLContext.cpp WinSystemX11GLESContext.cpp XRandR.cpp + VideoSyncGLX.cpp + VideoSyncDRM.cpp WinSystemX11.cpp) set(HEADERS GLContext.h @@ -14,6 +16,8 @@ if (X_FOUND) WinSystemX11GLContext.h WinSystemX11GLESContext.h XRandR.h + VideoSyncGLX.h + VideoSyncDRM.h WinSystemX11.h) core_add_library(windowing_X11) diff --git a/xbmc/video/videosync/VideoSyncDRM.cpp b/xbmc/windowing/X11/VideoSyncDRM.cpp index c86a7b771d..f31b349124 100644 --- a/xbmc/video/videosync/VideoSyncDRM.cpp +++ b/xbmc/windowing/X11/VideoSyncDRM.cpp @@ -22,7 +22,7 @@ #if defined(HAVE_X11) -#include "video/videosync/VideoSyncDRM.h" +#include "VideoSyncDRM.h" #include "xf86drm.h" #include <sys/poll.h> #include <sys/time.h> diff --git a/xbmc/video/videosync/VideoSyncDRM.h b/xbmc/windowing/X11/VideoSyncDRM.h index b6807171f3..3f41cc25ee 100644 --- a/xbmc/video/videosync/VideoSyncDRM.h +++ b/xbmc/windowing/X11/VideoSyncDRM.h @@ -19,15 +19,13 @@ * */ -#if defined(HAVE_X11) - -#include "video/videosync/VideoSync.h" +#include "windowing/VideoSync.h" #include "guilib/DispResource.h" class CVideoSyncDRM : public CVideoSync, IDispResource { public: - CVideoSyncDRM(CVideoReferenceClock *clock) : CVideoSync(clock) {}; + CVideoSyncDRM(void *clock) : CVideoSync(clock) {}; virtual bool Setup(PUPDATECLOCK func); virtual void Run(std::atomic<bool>& stop); virtual void Cleanup(); @@ -45,4 +43,3 @@ private: }; }; -#endif diff --git a/xbmc/video/videosync/VideoSyncGLX.cpp b/xbmc/windowing/X11/VideoSyncGLX.cpp index fd28e007e3..a0da423254 100644 --- a/xbmc/video/videosync/VideoSyncGLX.cpp +++ b/xbmc/windowing/X11/VideoSyncGLX.cpp @@ -22,7 +22,7 @@ #if defined(HAS_GLX) -#include "video/videosync/VideoSyncGLX.h" +#include "VideoSyncGLX.h" #include <sstream> #include <X11/extensions/Xrandr.h> #include "windowing/WindowingFactory.h" diff --git a/xbmc/video/videosync/VideoSyncGLX.h b/xbmc/windowing/X11/VideoSyncGLX.h index 7d23c47f03..eb390d6a84 100644 --- a/xbmc/video/videosync/VideoSyncGLX.h +++ b/xbmc/windowing/X11/VideoSyncGLX.h @@ -21,7 +21,7 @@ #if defined(HAS_GLX) -#include "video/videosync/VideoSync.h" +#include "windowing/VideoSync.h" #include "system_gl.h" #include <X11/X.h> #include <X11/Xlib.h> @@ -32,7 +32,7 @@ class CVideoSyncGLX : public CVideoSync, IDispResource { public: - CVideoSyncGLX(CVideoReferenceClock *clock) : CVideoSync(clock) {}; + CVideoSyncGLX(void *clock) : CVideoSync(clock) {}; virtual bool Setup(PUPDATECLOCK func); virtual void Run(std::atomic<bool>& stop); virtual void Cleanup(); diff --git a/xbmc/windowing/X11/WinSystemX11.cpp b/xbmc/windowing/X11/WinSystemX11.cpp index 291bbf6420..ff7abe675d 100644 --- a/xbmc/windowing/X11/WinSystemX11.cpp +++ b/xbmc/windowing/X11/WinSystemX11.cpp @@ -20,8 +20,6 @@ #include "system.h" -#if defined(HAVE_X11) - #include "WinSystemX11.h" #include "ServiceBroker.h" #include "settings/DisplaySettings.h" @@ -1071,4 +1069,4 @@ void CWinSystemX11::UpdateCrtc() g_graphicsContext.SetFPS(fps); } -#endif + diff --git a/xbmc/windowing/X11/WinSystemX11GLContext.cpp b/xbmc/windowing/X11/WinSystemX11GLContext.cpp index 33c5858b8b..c776dbdf96 100644 --- a/xbmc/windowing/X11/WinSystemX11GLContext.cpp +++ b/xbmc/windowing/X11/WinSystemX11GLContext.cpp @@ -19,7 +19,7 @@ */ #include "system.h" -#if defined(HAVE_X11) && defined(HAS_GL) +#if defined(HAS_GL) #include <X11/Xlib.h> #include <X11/Xutil.h> @@ -34,6 +34,8 @@ #include "threads/SingleLock.h" #include <vector> #include "Application.h" +#include "VideoSyncDRM.h" +#include "VideoSyncGLX.h" CWinSystemX11GLContext::CWinSystemX11GLContext() { @@ -219,4 +221,19 @@ bool CWinSystemX11GLContext::RefreshGLContext(bool force) return ret; } +std::unique_ptr<CVideoSync> CWinSystemX11GLContext::GetVideoSync(void *clock) +{ + std::unique_ptr<CVideoSync> pVSync; + + if (dynamic_cast<CGLContextEGL*>(m_pGLContext)) + { + pVSync.reset(new CVideoSyncDRM(clock)); + } + else if (dynamic_cast<CGLContextGLX*>(m_pGLContext)) + { + pVSync.reset(new CVideoSyncGLX(clock)); + } + return pVSync; +} + #endif diff --git a/xbmc/windowing/X11/WinSystemX11GLContext.h b/xbmc/windowing/X11/WinSystemX11GLContext.h index 4e0ca8c62e..b4e7f390d9 100644 --- a/xbmc/windowing/X11/WinSystemX11GLContext.h +++ b/xbmc/windowing/X11/WinSystemX11GLContext.h @@ -43,6 +43,9 @@ public: bool IsExtSupported(const char* extension) override; + // videosync + virtual std::unique_ptr<CVideoSync> GetVideoSync(void *clock) override; + GLXWindow GetWindow() const; GLXContext GetGlxContext() const; EGLDisplay GetEGLDisplay() const; diff --git a/xbmc/windowing/egl/CMakeLists.txt b/xbmc/windowing/egl/CMakeLists.txt index cab9495aab..361de124a5 100644 --- a/xbmc/windowing/egl/CMakeLists.txt +++ b/xbmc/windowing/egl/CMakeLists.txt @@ -16,16 +16,22 @@ endif() if(CORE_SYSTEM_NAME STREQUAL android) list(APPEND SOURCES EGLNativeTypeAndroid.cpp) list(APPEND HEADERS EGLNativeTypeAndroid.h) + list(APPEND SOURCES VideoSyncAndroid.h) + list(APPEND SOURCES VideoSyncAndroid.cpp) endif() if(AML_FOUND) list(APPEND SOURCES EGLNativeTypeAmlogic.cpp) list(APPEND HEADERS EGLNativeTypeAmlogic.h) + list(APPEND SOURCES VideoSyncAML.h) + list(APPEND SOURCES VideoSyncAML.cpp) endif() if(MMAL_FOUND) list(APPEND SOURCES EGLNativeTypeRaspberryPI.cpp) list(APPEND HEADERS EGLNativeTypeRaspberryPI.h) + list(APPEND SOURCES VideoSyncPi.cpp) + list(APPEND HEADERS VideoSyncPi.h) endif() if(IMX_FOUND) diff --git a/xbmc/windowing/egl/VideoSyncAML.cpp b/xbmc/windowing/egl/VideoSyncAML.cpp new file mode 100644 index 0000000000..ebf3fb9546 --- /dev/null +++ b/xbmc/windowing/egl/VideoSyncAML.cpp @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2017 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC; see the file COPYING. If not, see + * <http://www.gnu.org/licenses/>. + * + */ + +#include "system.h" + +#if defined(HAS_LIBAMCODEC) + +#include "VideoSyncAML.h" +#include "guilib/GraphicContext.h" +#include "windowing/WindowingFactory.h" +#include "utils/TimeUtils.h" +#include "utils/log.h" +#include "threads/Thread.h" +#include <sys/poll.h> + +#include <chrono> +#include <thread> + +extern CEvent g_aml_sync_event; + +CVideoSyncAML::CVideoSyncAML(void *clock) +: CVideoSync(clock) +, m_abort(false) +{ +} + +CVideoSyncAML::~CVideoSyncAML() +{ +} + +bool CVideoSyncAML::Setup(PUPDATECLOCK func) +{ + UpdateClock = func; + + m_abort = false; + + g_Windowing.Register(this); + CLog::Log(LOGDEBUG, "CVideoReferenceClock: setting up AML"); + + return true; +} + +void CVideoSyncAML::Run(std::atomic<bool>& stop) +{ + // We use the wall clock for timout handling (no AML h/w, startup) + std::chrono::time_point<std::chrono::system_clock> now(std::chrono::system_clock::now()); + unsigned int waittime (3000 / m_fps); + uint64_t numVBlanks (0); + + while (!stop && !m_abort) + { + int countVSyncs(1); + if( !g_aml_sync_event.WaitMSec(waittime)) + { + std::chrono::milliseconds elapsed(std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() - now).count()); + uint64_t curVBlanks = (m_fps * elapsed.count()) / 1000; + int64_t lastVBlankTime((curVBlanks * 1000) / m_fps); + if (elapsed.count() > lastVBlankTime) + { + lastVBlankTime = (++curVBlanks * 1000) / m_fps; + std::this_thread::sleep_for(std::chrono::milliseconds(lastVBlankTime - elapsed.count())); + } + countVSyncs = curVBlanks - numVBlanks; + numVBlanks = curVBlanks; + } + else + ++numVBlanks; + + uint64_t now = CurrentHostCounter(); + + UpdateClock(countVSyncs, now, m_refClock); + } +} + +void CVideoSyncAML::Cleanup() +{ + CLog::Log(LOGDEBUG, "CVideoReferenceClock: cleaning up AML"); + g_Windowing.Unregister(this); +} + +float CVideoSyncAML::GetFps() +{ + m_fps = g_graphicsContext.GetFPS(); + CLog::Log(LOGDEBUG, "CVideoReferenceClock: fps: %.3f", m_fps); + return m_fps; +} + +void CVideoSyncAML::OnResetDisplay() +{ + m_abort = true; +} + +#endif diff --git a/xbmc/windowing/egl/VideoSyncAML.h b/xbmc/windowing/egl/VideoSyncAML.h new file mode 100644 index 0000000000..8186459f9f --- /dev/null +++ b/xbmc/windowing/egl/VideoSyncAML.h @@ -0,0 +1,41 @@ +#pragma once +/* + * Copyright (C) 2017 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC; see the file COPYING. If not, see + * <http://www.gnu.org/licenses/>. + * + */ + +#if defined(HAS_LIBAMCODEC) + +#include "windowing/VideoSync.h" +#include "guilib/DispResource.h" + +class CVideoSyncAML : public CVideoSync, IDispResource +{ +public: + CVideoSyncAML(void *clock); + virtual ~CVideoSyncAML(); + virtual bool Setup(PUPDATECLOCK func)override; + virtual void Run(std::atomic<bool>& stop)override; + virtual void Cleanup()override; + virtual float GetFps()override; + virtual void OnResetDisplay()override; +private: + volatile bool m_abort; +}; + +#endif diff --git a/xbmc/video/videosync/VideoSyncAndroid.cpp b/xbmc/windowing/egl/VideoSyncAndroid.cpp index 71d7906267..65f48dd17b 100644 --- a/xbmc/video/videosync/VideoSyncAndroid.cpp +++ b/xbmc/windowing/egl/VideoSyncAndroid.cpp @@ -23,7 +23,7 @@ #if defined(TARGET_ANDROID) #include "utils/log.h" #include "VideoSyncAndroid.h" -#include "video/VideoReferenceClock.h" +#include "cores/VideoPlayer/VideoReferenceClock.h" #include "utils/TimeUtils.h" #include "platform/android/activity/XBMCApp.h" #include "windowing/WindowingFactory.h" @@ -35,12 +35,12 @@ bool CVideoSyncAndroid::Setup(PUPDATECLOCK func) { CLog::Log(LOGDEBUG, "CVideoSyncAndroid::%s setting up", __FUNCTION__); - + //init the vblank timestamp m_LastVBlankTime = CurrentHostCounter(); UpdateClock = func; m_abort = false; - + CXBMCApp::InitFrameCallback(this); g_Windowing.Register(this); @@ -79,14 +79,14 @@ void CVideoSyncAndroid::FrameCallback(int64_t frameTimeNanos) int NrVBlanks; double VBlankTime; int64_t nowtime = CurrentHostCounter(); - + //calculate how many vblanks happened VBlankTime = (double)(nowtime - m_LastVBlankTime) / (double)CurrentHostFrequency(); NrVBlanks = MathUtils::round_int(VBlankTime * m_fps); //save the timestamp of this vblank so we can calculate how many happened next time m_LastVBlankTime = nowtime; - + //update the vblank timestamp, update the clock and send a signal that we got a vblank UpdateClock(NrVBlanks, nowtime, m_refClock); } diff --git a/xbmc/video/videosync/VideoSyncAndroid.h b/xbmc/windowing/egl/VideoSyncAndroid.h index 803df561b2..789c6a1c99 100644 --- a/xbmc/video/videosync/VideoSyncAndroid.h +++ b/xbmc/windowing/egl/VideoSyncAndroid.h @@ -20,26 +20,26 @@ */ #if defined(TARGET_ANDROID) -#include "VideoSync.h" +#include "windowing/VideoSync.h" #include "guilib/DispResource.h" class CVideoSyncAndroid : public CVideoSync, IDispResource { public: - CVideoSyncAndroid(CVideoReferenceClock *clock) : CVideoSync(clock), m_LastVBlankTime(0), m_abort(false){} - + CVideoSyncAndroid(void *clock) : CVideoSync(clock), m_LastVBlankTime(0), m_abort(false){} + // CVideoSync interface - virtual bool Setup(PUPDATECLOCK func); - virtual void Run(std::atomic<bool>& stop); - virtual void Cleanup(); - virtual float GetFps(); - + virtual bool Setup(PUPDATECLOCK func) override; + virtual void Run(std::atomic<bool>& stop) override; + virtual void Cleanup() override; + virtual float GetFps() override; + // IDispResource interface - virtual void OnResetDisplay(); + virtual void OnResetDisplay() override; // Choreographer callback void FrameCallback(int64_t frameTimeNanos); - + private: int64_t m_LastVBlankTime; //timestamp of the last vblank, used for calculating how many vblanks happened volatile bool m_abort; diff --git a/xbmc/video/videosync/VideoSyncIMX.cpp b/xbmc/windowing/egl/VideoSyncIMX.cpp index fa7c27c4e5..fa7c27c4e5 100644 --- a/xbmc/video/videosync/VideoSyncIMX.cpp +++ b/xbmc/windowing/egl/VideoSyncIMX.cpp diff --git a/xbmc/video/videosync/VideoSyncIMX.h b/xbmc/windowing/egl/VideoSyncIMX.h index 7220ac60ba..7220ac60ba 100644 --- a/xbmc/video/videosync/VideoSyncIMX.h +++ b/xbmc/windowing/egl/VideoSyncIMX.h diff --git a/xbmc/video/videosync/VideoSyncPi.cpp b/xbmc/windowing/egl/VideoSyncPi.cpp index 0b512d3b0b..d37b3b4c46 100644 --- a/xbmc/video/videosync/VideoSyncPi.cpp +++ b/xbmc/windowing/egl/VideoSyncPi.cpp @@ -22,7 +22,7 @@ #if defined(TARGET_RASPBERRY_PI) -#include "video/videosync/VideoSyncPi.h" +#include "VideoSyncPi.h" #include "guilib/GraphicContext.h" #include "windowing/WindowingFactory.h" #include "utils/TimeUtils.h" @@ -70,4 +70,10 @@ void CVideoSyncPi::OnResetDisplay() m_abort = true; } +void CVideoSyncPi::RefreshChanged() +{ + if (m_fps != g_graphicsContext.GetFPS()) + m_abort = true; +} + #endif diff --git a/xbmc/video/videosync/VideoSyncPi.h b/xbmc/windowing/egl/VideoSyncPi.h index c7c3d12c71..2fa2216cca 100644 --- a/xbmc/video/videosync/VideoSyncPi.h +++ b/xbmc/windowing/egl/VideoSyncPi.h @@ -21,18 +21,19 @@ #if defined(TARGET_RASPBERRY_PI) -#include "video/videosync/VideoSync.h" +#include "windowing/VideoSync.h" #include "guilib/DispResource.h" class CVideoSyncPi : public CVideoSync, IDispResource { public: - CVideoSyncPi(CVideoReferenceClock *clock) : CVideoSync(clock) {}; + CVideoSyncPi(void *clock) : CVideoSync(clock) {}; virtual bool Setup(PUPDATECLOCK func); virtual void Run(std::atomic<bool>& stop); virtual void Cleanup(); virtual float GetFps(); virtual void OnResetDisplay(); + virtual void RefreshChanged(); private: volatile bool m_abort; diff --git a/xbmc/windowing/egl/WinSystemEGL.cpp b/xbmc/windowing/egl/WinSystemEGL.cpp index 815d389fa5..bd72af5f72 100644 --- a/xbmc/windowing/egl/WinSystemEGL.cpp +++ b/xbmc/windowing/egl/WinSystemEGL.cpp @@ -32,6 +32,15 @@ #include "settings/DisplaySettings.h" #include "guilib/DispResource.h" #include "threads/SingleLock.h" + +#if defined(TARGET_RASPBERRY_PI) +#include "VideoSyncPi.h" +#elif defined(TARGET_ANDROID) +#include "VideoSyncAndroid.h" +#elif defined(HAS_LIBAMCODEC) +#include "VideoSyncAML.h" +#endif + #ifdef HAS_IMXVPU // This has to go into another header file #include "cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecIMX.h" @@ -556,4 +565,21 @@ bool CWinSystemEGL::ClampToGUIDisplayLimits(int &width, int &height) return true; } +std::unique_ptr<CVideoSync> CWinSystemEGL::GetVideoSync(void *clock) +{ +#if defined(TARGET_RASPBERRY_PI) + std::unique_ptr<CVideoSync> pVSync(new CVideoSyncPi(clock)); + return pVSync; +#elif defined(TARGET_ANDROID) + std::unique_ptr<CVideoSync> pVSync(new CVideoSyncAndroid(clock)); + return pVSync; +#elif defined(HAS_LIBAMCODEC) + std::unique_ptr<CVideoSync> pVSync(new CVideoSyncAML(clock)); + return pVSync; +#else + return nullptr; +#endif +} + + #endif diff --git a/xbmc/windowing/egl/WinSystemEGL.h b/xbmc/windowing/egl/WinSystemEGL.h index c24bb356b9..c9a5506922 100644 --- a/xbmc/windowing/egl/WinSystemEGL.h +++ b/xbmc/windowing/egl/WinSystemEGL.h @@ -69,6 +69,9 @@ public: EGLDisplay GetEGLDisplay(); EGLContext GetEGLContext(); + + // videosync + virtual std::unique_ptr<CVideoSync> GetVideoSync(void *clock) override; protected: virtual void PresentRenderImpl(bool rendered); virtual void SetVSyncImpl(bool enable); diff --git a/xbmc/windowing/osx/CMakeLists.txt b/xbmc/windowing/osx/CMakeLists.txt index a007c38df2..0191ddefb5 100644 --- a/xbmc/windowing/osx/CMakeLists.txt +++ b/xbmc/windowing/osx/CMakeLists.txt @@ -1,17 +1,21 @@ if(CORE_SYSTEM_NAME STREQUAL osx) set(SOURCES WinEventsOSX.mm WinSystemOSX.mm - WinSystemOSXGL.mm) + WinSystemOSXGL.mm + VideoSyncOsx.cpp) set(HEADERS WinEventsOSX.h WinSystemOSX.h - WinSystemOSXGL.h) + WinSystemOSXGL.h + VideoSyncOsx.h) endif() if(CORE_SYSTEM_NAME STREQUAL ios) set(SOURCES WinEventsIOS.mm - WinSystemIOS.mm) + WinSystemIOS.mm + VideoSyncIos.cpp) set(HEADERS WinEventsIOS.h - WinSystemIOS.h) + WinSystemIOS.h + VideoSyncIos.h) endif() core_add_library(windowing_osx) diff --git a/xbmc/video/videosync/VideoSyncIos.cpp b/xbmc/windowing/osx/VideoSyncIos.cpp index 026dd7ed91..ac23993dd8 100644 --- a/xbmc/video/videosync/VideoSyncIos.cpp +++ b/xbmc/windowing/osx/VideoSyncIos.cpp @@ -24,7 +24,7 @@ #include "utils/log.h" #include "VideoSyncIos.h" #include "utils/MathUtils.h" -#include "video/VideoReferenceClock.h" +#include "cores/VideoPlayer/VideoReferenceClock.h" #include "guilib/GraphicContext.h" #include "windowing/WindowingFactory.h" #include "utils/TimeUtils.h" diff --git a/xbmc/video/videosync/VideoSyncIos.h b/xbmc/windowing/osx/VideoSyncIos.h index bf336b80dd..6d129eb63d 100644 --- a/xbmc/video/videosync/VideoSyncIos.h +++ b/xbmc/windowing/osx/VideoSyncIos.h @@ -20,13 +20,13 @@ */ #if defined(TARGET_DARWIN_IOS) -#include "VideoSync.h" +#include "windowing/VideoSync.h" #include "guilib/DispResource.h" class CVideoSyncIos : public CVideoSync, IDispResource { public: - CVideoSyncIos(CVideoReferenceClock *clock) : CVideoSync(clock), m_LastVBlankTime(0), m_abort(false){} + CVideoSyncIos(void *clock) : CVideoSync(clock), m_LastVBlankTime(0), m_abort(false){} // CVideoSync interface virtual bool Setup(PUPDATECLOCK func) override; diff --git a/xbmc/video/videosync/VideoSyncOsx.cpp b/xbmc/windowing/osx/VideoSyncOsx.cpp index f6320c49b3..9ea7145b33 100644 --- a/xbmc/video/videosync/VideoSyncOsx.cpp +++ b/xbmc/windowing/osx/VideoSyncOsx.cpp @@ -20,11 +20,9 @@ #include "system.h" -#if defined(TARGET_DARWIN_OSX) #include "utils/log.h" #include "VideoSyncOsx.h" #include "utils/MathUtils.h" -#include "video/VideoReferenceClock.h" #include "guilib/GraphicContext.h" #include "utils/TimeUtils.h" #include "windowing/WindowingFactory.h" @@ -159,4 +157,3 @@ void CVideoSyncOsx::DeinitDisplayLink() Cocoa_CVDisplayLinkRelease(); } -#endif//TARGET_DARWIN_OSX diff --git a/xbmc/video/videosync/VideoSyncOsx.h b/xbmc/windowing/osx/VideoSyncOsx.h index 1a2eedcd7e..276c9085a5 100644 --- a/xbmc/video/videosync/VideoSyncOsx.h +++ b/xbmc/windowing/osx/VideoSyncOsx.h @@ -19,8 +19,7 @@ * */ -#if defined(TARGET_DARWIN_OSX) -#include "VideoSync.h" +#include "windowing/VideoSync.h" #include "guilib/DispResource.h" #include "threads/Event.h" @@ -28,7 +27,7 @@ class CVideoSyncOsx : public CVideoSync, IDispResource { public: - CVideoSyncOsx(CVideoReferenceClock *clock) : + CVideoSyncOsx(void *clock) : CVideoSync(clock), m_LastVBlankTime(0), m_displayLost(false), @@ -58,4 +57,3 @@ private: CEvent m_lostEvent; }; -#endif// TARGET_DARWIN_OSX diff --git a/xbmc/windowing/osx/WinSystemIOS.h b/xbmc/windowing/osx/WinSystemIOS.h index 7ecdf672a7..2ee5645b22 100644 --- a/xbmc/windowing/osx/WinSystemIOS.h +++ b/xbmc/windowing/osx/WinSystemIOS.h @@ -72,6 +72,8 @@ public: virtual int GetNumScreens(); virtual int GetCurrentScreen(); + virtual std::unique_ptr<CVideoSync> GetVideoSync(void *clock) override; + bool InitDisplayLink(CVideoSyncIos *syncImpl); void DeinitDisplayLink(void); void OnAppFocusChange(bool focus); diff --git a/xbmc/windowing/osx/WinSystemIOS.mm b/xbmc/windowing/osx/WinSystemIOS.mm index a2e74332a4..84f1770185 100644 --- a/xbmc/windowing/osx/WinSystemIOS.mm +++ b/xbmc/windowing/osx/WinSystemIOS.mm @@ -18,7 +18,6 @@ * */ -#if defined(TARGET_DARWIN_IOS) //hack around problem with xbmc's typedef int BOOL // and obj-c's typedef unsigned char BOOL #define BOOL XBMC_BOOL @@ -26,7 +25,8 @@ #undef BOOL #ifdef HAS_EGL -#define BOOL XBMC_BOOL +#define BOOL XBMC_BOOL +#include "VideoSyncIos.h" #include "WinSystemIOS.h" #include "utils/log.h" #include "filesystem/SpecialProtocol.h" @@ -37,7 +37,7 @@ #include "utils/StringUtils.h" #include "guilib/DispResource.h" #include "threads/SingleLock.h" -#include "video/videosync/VideoSyncIos.h" +#include "VideoSyncIos.h" #include <vector> #undef BOOL @@ -485,6 +485,11 @@ void* CWinSystemIOS::GetEAGLContextObj() return [g_xbmcController getEAGLContextObj]; } -#endif +std::unique_ptr<CVideoSync> CWinSystemIOS::GetVideoSync(void *clock) +{ + std::unique_ptr<CVideoSync> pVSync(new CVideoSyncIos(clock)); + return pVSync; +} #endif + diff --git a/xbmc/windowing/osx/WinSystemOSX.h b/xbmc/windowing/osx/WinSystemOSX.h index c46e27b41e..fe37b26b68 100644 --- a/xbmc/windowing/osx/WinSystemOSX.h +++ b/xbmc/windowing/osx/WinSystemOSX.h @@ -74,6 +74,8 @@ public: virtual int GetNumScreens(); virtual int GetCurrentScreen(); virtual double GetCurrentRefreshrate() { return m_refreshRate; } + + virtual std::unique_ptr<CVideoSync> GetVideoSync(void *clock) override; void WindowChangedScreen(); @@ -88,6 +90,7 @@ public: std::string GetClipboardText(void); + protected: void HandlePossibleRefreshrateChange(); void* CreateWindowedContext(void* shareCtx); diff --git a/xbmc/windowing/osx/WinSystemOSX.mm b/xbmc/windowing/osx/WinSystemOSX.mm index 752e8655a8..365bb0badb 100644 --- a/xbmc/windowing/osx/WinSystemOSX.mm +++ b/xbmc/windowing/osx/WinSystemOSX.mm @@ -18,13 +18,12 @@ * */ -#if defined(TARGET_DARWIN_OSX) - //hack around problem with xbmc's typedef int BOOL // and obj-c's typedef unsigned char BOOL #define BOOL XBMC_BOOL #include "WinSystemOSX.h" #include "WinEventsOSX.h" +#include "VideoSyncOsx.h" #include "Application.h" #include "ServiceBroker.h" #include "messaging/ApplicationMessenger.h" @@ -1798,4 +1797,8 @@ std::string CWinSystemOSX::GetClipboardText(void) return utf8_text; } -#endif +std::unique_ptr<CVideoSync> CWinSystemOSX::GetVideoSync(void *clock) +{ + std::unique_ptr<CVideoSync> pVSync(new CVideoSyncOsx(clock)); + return pVSync; +} diff --git a/xbmc/windowing/windows/CMakeLists.txt b/xbmc/windowing/windows/CMakeLists.txt index 4a1f1b3b5b..76c5293f0b 100644 --- a/xbmc/windowing/windows/CMakeLists.txt +++ b/xbmc/windowing/windows/CMakeLists.txt @@ -1,8 +1,10 @@ -set(SOURCES WinEventsWin32.cpp +set(SOURCES VideoSyncD3D.cpp + WinEventsWin32.cpp WinSystemWin32.cpp WinSystemWin32DX.cpp) -set(HEADERS WinEventsWin32.h +set(HEADERS VideoSyncD3D.h + WinEventsWin32.h WinSystemWin32.h WinSystemWin32DX.h) diff --git a/xbmc/video/videosync/VideoSyncD3D.cpp b/xbmc/windowing/windows/VideoSyncD3D.cpp index e48b91e121..3d9462723b 100644 --- a/xbmc/video/videosync/VideoSyncD3D.cpp +++ b/xbmc/windowing/windows/VideoSyncD3D.cpp @@ -20,13 +20,11 @@ #include "system.h" -#if defined(TARGET_WINDOWS) - #include "utils/log.h" #include "Utils/TimeUtils.h" #include "Utils/MathUtils.h" #include "windowing\WindowingFactory.h" -#include "video/videosync/VideoSyncD3D.h" +#include "VideoSyncD3D.h" #include "guilib/GraphicContext.h" #include "platform/win32/dxerr.h" #include "utils/StringUtils.h" @@ -155,4 +153,3 @@ std::string CVideoSyncD3D::GetErrorDescription(HRESULT hr) return StringUtils::Format("%ls: %ls", error.c_str(), descr.c_str()); } -#endif diff --git a/xbmc/video/videosync/VideoSyncD3D.h b/xbmc/windowing/windows/VideoSyncD3D.h index 486b6206f6..64a28cdc3e 100644 --- a/xbmc/video/videosync/VideoSyncD3D.h +++ b/xbmc/windowing/windows/VideoSyncD3D.h @@ -19,16 +19,14 @@ * */ -#if defined(TARGET_WINDOWS) - -#include "video/videosync/VideoSync.h" +#include "windowing/VideoSync.h" #include "guilib/DispResource.h" #include "threads/Event.h" class CVideoSyncD3D : public CVideoSync, IDispResource { public: - CVideoSyncD3D(CVideoReferenceClock *clock) : CVideoSync(clock) {}; + CVideoSyncD3D(void *clock) : CVideoSync(clock) {}; bool Setup(PUPDATECLOCK func) override; void Run(std::atomic<bool>& stop) override; void Cleanup() override; @@ -47,4 +45,3 @@ private: int64_t m_lastUpdateTime; }; -#endif diff --git a/xbmc/windowing/windows/WinSystemWin32.cpp b/xbmc/windowing/windows/WinSystemWin32.cpp index 1e7edb2337..6989179933 100644 --- a/xbmc/windowing/windows/WinSystemWin32.cpp +++ b/xbmc/windowing/windows/WinSystemWin32.cpp @@ -31,8 +31,8 @@ #include "utils/log.h" #include "utils/CharsetConverter.h" #include "utils/SystemInfo.h" +#include "VideoSyncD3D.h" -#ifdef TARGET_WINDOWS #include <tpcshrd.h> CWinSystemWin32::CWinSystemWin32() @@ -939,4 +939,8 @@ void CWinSystemWin32::SetForegroundWindowInternal(HWND hWnd) } } -#endif +std::unique_ptr<CVideoSync> CWinSystemWin32::GetVideoSync(void *clock) +{ + std::unique_ptr<CVideoSync> pVSync(new CVideoSyncD3D(clock)); + return pVSync; +} diff --git a/xbmc/windowing/windows/WinSystemWin32.h b/xbmc/windowing/windows/WinSystemWin32.h index d5aebef1a4..dc522809ec 100644 --- a/xbmc/windowing/windows/WinSystemWin32.h +++ b/xbmc/windowing/windows/WinSystemWin32.h @@ -154,6 +154,9 @@ public: virtual bool Hide(); virtual bool Show(bool raise = true); + // videosync + virtual std::unique_ptr<CVideoSync> GetVideoSync(void *clock) override; + // CWinSystemWin32 HWND GetHwnd() { return m_hWnd; } bool IsAlteringWindow() { return m_IsAlteringWindow; } |