aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGarrett Brown <garbearucla@gmail.com>2013-09-11 23:17:42 -0700
committerGarrett Brown <themagnificentmrb@gmail.com>2016-12-01 18:08:29 -0800
commit5a3be439dad1ee32d79b2c4fdd85782ee67254df (patch)
tree5705ad46778c8e9f7a4d8f491af74bc4259725a8
parente2563f6529ea0f08fe153d6baa9dff0935ea8d65 (diff)
[retroplayer] RetroPlayer core
Thanks to elpendor for RGB565 support, poisson for RAII improvements, ChrisMyhre for catching a compile error, notspiff for CMake fixes, acmiyaguchi for video and audio codec support, and popcornmix for Raspberry Pi support (PR 62). TODO: Is a call to `g_renderManager.IsStarted()` needed?
-rw-r--r--.gitignore1
-rw-r--r--Kodi.xcodeproj/project.pbxproj44
-rw-r--r--Makefile.in1
-rw-r--r--configure.ac1
-rw-r--r--project/cmake/treedata/common/cores.txt1
-rw-r--r--system/keymaps/gamepad.xml15
-rw-r--r--system/keymaps/joystick.xml29
-rw-r--r--system/keymaps/keyboard.xml25
-rw-r--r--system/keymaps/mouse.xml5
-rw-r--r--system/keymaps/remote.xml14
-rw-r--r--system/keymaps/touchscreen.xml8
-rw-r--r--xbmc/Application.cpp4
-rw-r--r--xbmc/GUIInfoManager.cpp19
-rw-r--r--xbmc/GUIInfoManager.h1
-rw-r--r--xbmc/cores/RetroPlayer/CMakeLists.txt18
-rw-r--r--xbmc/cores/RetroPlayer/IPixelConverter.h61
-rw-r--r--xbmc/cores/RetroPlayer/Makefile.in13
-rw-r--r--xbmc/cores/RetroPlayer/PixelConverter.cpp127
-rw-r--r--xbmc/cores/RetroPlayer/PixelConverter.h48
-rw-r--r--xbmc/cores/RetroPlayer/PixelConverterRBP.cpp237
-rw-r--r--xbmc/cores/RetroPlayer/PixelConverterRBP.h73
-rw-r--r--xbmc/cores/RetroPlayer/RetroPlayer.cpp365
-rw-r--r--xbmc/cores/RetroPlayer/RetroPlayer.h166
-rw-r--r--xbmc/cores/RetroPlayer/RetroPlayerAudio.cpp184
-rw-r--r--xbmc/cores/RetroPlayer/RetroPlayerAudio.h53
-rw-r--r--xbmc/cores/RetroPlayer/RetroPlayerDefines.h23
-rw-r--r--xbmc/cores/RetroPlayer/RetroPlayerVideo.cpp226
-rw-r--r--xbmc/cores/RetroPlayer/RetroPlayerVideo.h74
-rw-r--r--xbmc/cores/playercorefactory/PlayerCoreConfig.h5
-rw-r--r--xbmc/cores/playercorefactory/PlayerCoreFactory.cpp15
-rw-r--r--xbmc/guilib/GUIWindowManager.cpp21
-rw-r--r--xbmc/input/ButtonTranslator.cpp4
-rw-r--r--xbmc/windows/GUIWindowFileManager.cpp2
33 files changed, 1876 insertions, 7 deletions
diff --git a/.gitignore b/.gitignore
index 3a617d0fa4..83895b5878 100644
--- a/.gitignore
+++ b/.gitignore
@@ -442,6 +442,7 @@ lib/cpluff/stamp-h1
/xbmc/cores/playercorefactory/Makefile
/xbmc/cores/Makefile
/xbmc/cores/VideoPlayer/VideoRenderers/Makefile
+/xbmc/cores/RetroPlayer/Makefile
# /xbmc/filesystem/
/xbmc/filesystem/Makefile
diff --git a/Kodi.xcodeproj/project.pbxproj b/Kodi.xcodeproj/project.pbxproj
index 6ad12ab571..7ca98c7295 100644
--- a/Kodi.xcodeproj/project.pbxproj
+++ b/Kodi.xcodeproj/project.pbxproj
@@ -317,6 +317,14 @@
6890C2511DDBDDC900F8F362 /* MouseInputHandling.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6890C24E1DDBDDC900F8F362 /* MouseInputHandling.cpp */; };
6890C2571DDBDDD500F8F362 /* MouseWindowingButtonMap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6890C2551DDBDDD500F8F362 /* MouseWindowingButtonMap.cpp */; };
6890C2581DDBDDD500F8F362 /* MouseWindowingButtonMap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6890C2551DDBDDD500F8F362 /* MouseWindowingButtonMap.cpp */; };
+ 6890C2771DDBDFD900F8F362 /* PixelConverter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6890C26E1DDBDFD900F8F362 /* PixelConverter.cpp */; };
+ 6890C2781DDBDFD900F8F362 /* PixelConverter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6890C26E1DDBDFD900F8F362 /* PixelConverter.cpp */; };
+ 6890C2791DDBDFD900F8F362 /* RetroPlayer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6890C2701DDBDFD900F8F362 /* RetroPlayer.cpp */; };
+ 6890C27A1DDBDFD900F8F362 /* RetroPlayer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6890C2701DDBDFD900F8F362 /* RetroPlayer.cpp */; };
+ 6890C27B1DDBDFD900F8F362 /* RetroPlayerAudio.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6890C2721DDBDFD900F8F362 /* RetroPlayerAudio.cpp */; };
+ 6890C27C1DDBDFD900F8F362 /* RetroPlayerAudio.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6890C2721DDBDFD900F8F362 /* RetroPlayerAudio.cpp */; };
+ 6890C27D1DDBDFD900F8F362 /* RetroPlayerVideo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6890C2751DDBDFD900F8F362 /* RetroPlayerVideo.cpp */; };
+ 6890C27E1DDBDFD900F8F362 /* RetroPlayerVideo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6890C2751DDBDFD900F8F362 /* RetroPlayerVideo.cpp */; };
68AE5BA51C92412900C4D527 /* AddonCallbacksPeripheral.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 68AE5BA31C92412900C4D527 /* AddonCallbacksPeripheral.cpp */; };
68AE5BA61C92412900C4D527 /* AddonCallbacksPeripheral.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 68AE5BA31C92412900C4D527 /* AddonCallbacksPeripheral.cpp */; };
68AE5BBD1C9241DF00C4D527 /* DefaultJoystick.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 68AE5BAC1C9241DF00C4D527 /* DefaultJoystick.cpp */; };
@@ -2919,6 +2927,16 @@
6890C2541DDBDDD500F8F362 /* IMouseInputHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = IMouseInputHandler.h; path = mouse/IMouseInputHandler.h; sourceTree = "<group>"; };
6890C2551DDBDDD500F8F362 /* MouseWindowingButtonMap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = MouseWindowingButtonMap.cpp; path = mouse/MouseWindowingButtonMap.cpp; sourceTree = "<group>"; };
6890C2561DDBDDD500F8F362 /* MouseWindowingButtonMap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MouseWindowingButtonMap.h; path = mouse/MouseWindowingButtonMap.h; sourceTree = "<group>"; };
+ 6890C26D1DDBDFD900F8F362 /* IPixelConverter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = IPixelConverter.h; path = RetroPlayer/IPixelConverter.h; sourceTree = "<group>"; };
+ 6890C26E1DDBDFD900F8F362 /* PixelConverter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PixelConverter.cpp; path = RetroPlayer/PixelConverter.cpp; sourceTree = "<group>"; };
+ 6890C26F1DDBDFD900F8F362 /* PixelConverter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PixelConverter.h; path = RetroPlayer/PixelConverter.h; sourceTree = "<group>"; };
+ 6890C2701DDBDFD900F8F362 /* RetroPlayer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RetroPlayer.cpp; path = RetroPlayer/RetroPlayer.cpp; sourceTree = "<group>"; };
+ 6890C2711DDBDFD900F8F362 /* RetroPlayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RetroPlayer.h; path = RetroPlayer/RetroPlayer.h; sourceTree = "<group>"; };
+ 6890C2721DDBDFD900F8F362 /* RetroPlayerAudio.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RetroPlayerAudio.cpp; path = RetroPlayer/RetroPlayerAudio.cpp; sourceTree = "<group>"; };
+ 6890C2731DDBDFD900F8F362 /* RetroPlayerAudio.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RetroPlayerAudio.h; path = RetroPlayer/RetroPlayerAudio.h; sourceTree = "<group>"; };
+ 6890C2741DDBDFD900F8F362 /* RetroPlayerDefines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RetroPlayerDefines.h; path = RetroPlayer/RetroPlayerDefines.h; sourceTree = "<group>"; };
+ 6890C2751DDBDFD900F8F362 /* RetroPlayerVideo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RetroPlayerVideo.cpp; path = RetroPlayer/RetroPlayerVideo.cpp; sourceTree = "<group>"; };
+ 6890C2761DDBDFD900F8F362 /* RetroPlayerVideo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RetroPlayerVideo.h; path = RetroPlayer/RetroPlayerVideo.h; sourceTree = "<group>"; };
68AE5BA01C923E5300C4D527 /* kodi_vfs_utils.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = kodi_vfs_utils.hpp; path = "kodi-addon-dev-kit/include/kodi/kodi_vfs_utils.hpp"; sourceTree = "<group>"; };
68AE5BA31C92412900C4D527 /* AddonCallbacksPeripheral.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = AddonCallbacksPeripheral.cpp; path = addons/binary/interfaces/api1/Peripheral/AddonCallbacksPeripheral.cpp; sourceTree = "<group>"; };
68AE5BA41C92412900C4D527 /* AddonCallbacksPeripheral.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AddonCallbacksPeripheral.h; path = addons/binary/interfaces/api1/Peripheral/AddonCallbacksPeripheral.h; sourceTree = "<group>"; };
@@ -6443,6 +6461,23 @@
name = generic;
sourceTree = "<group>";
};
+ 6890C26C1DDBDFC100F8F362 /* RetroPlayer */ = {
+ isa = PBXGroup;
+ children = (
+ 6890C26D1DDBDFD900F8F362 /* IPixelConverter.h */,
+ 6890C26E1DDBDFD900F8F362 /* PixelConverter.cpp */,
+ 6890C26F1DDBDFD900F8F362 /* PixelConverter.h */,
+ 6890C2701DDBDFD900F8F362 /* RetroPlayer.cpp */,
+ 6890C2711DDBDFD900F8F362 /* RetroPlayer.h */,
+ 6890C2721DDBDFD900F8F362 /* RetroPlayerAudio.cpp */,
+ 6890C2731DDBDFD900F8F362 /* RetroPlayerAudio.h */,
+ 6890C2741DDBDFD900F8F362 /* RetroPlayerDefines.h */,
+ 6890C2751DDBDFD900F8F362 /* RetroPlayerVideo.cpp */,
+ 6890C2761DDBDFD900F8F362 /* RetroPlayerVideo.h */,
+ );
+ name = RetroPlayer;
+ sourceTree = "<group>";
+ };
68AE5BA21C92410300C4D527 /* Peripheral */ = {
isa = PBXGroup;
children = (
@@ -8292,6 +8327,7 @@
7C5608C30F1754930056433A /* ExternalPlayer */,
E38E15D20D25F9FA00618676 /* paplayer */,
F5E56B11108284E6006E788A /* playercorefactory */,
+ 6890C26C1DDBDFC100F8F362 /* RetroPlayer */,
E38E14F80D25F9F900618676 /* VideoPlayer */,
DF923E5B1A11536A008CDB0C /* DataCacheCore.cpp */,
DF923E5C1A11536A008CDB0C /* DataCacheCore.h */,
@@ -10585,6 +10621,7 @@
6890C1F21DDBDBEA00F8F362 /* GameClientReversiblePlayback.cpp in Sources */,
F592568810FBF2E100D2C91D /* ConvolutionKernels.cpp in Sources */,
F5DC87E2110A287400EE1B15 /* RingBuffer.cpp in Sources */,
+ 6890C2791DDBDFD900F8F362 /* RetroPlayer.cpp in Sources */,
F5F244651110DC6B009126C6 /* FileOperationJob.cpp in Sources */,
6890C24A1DDBDDA400F8F362 /* KeyboardEasterEgg.cpp in Sources */,
DF0E4AC51AD597ED00A75430 /* VideoPlayerRadioRDS.cpp in Sources */,
@@ -10757,6 +10794,7 @@
F5AE40A413415D9E0004BD79 /* PlayerOperations.cpp in Sources */,
F5AE40A513415D9E0004BD79 /* PlaylistOperations.cpp in Sources */,
F5AE40A613415D9E0004BD79 /* SystemOperations.cpp in Sources */,
+ 6890C2771DDBDFD900F8F362 /* PixelConverter.cpp in Sources */,
F5AE40A713415D9E0004BD79 /* VideoLibrary.cpp in Sources */,
F5AE40A813415D9E0004BD79 /* XBMCOperations.cpp in Sources */,
C84BF7341349BB74006D6FC9 /* JSONServiceDescription.cpp in Sources */,
@@ -10960,6 +10998,7 @@
DF1D2DF31B6E85EE002BB9DB /* XbtManager.cpp in Sources */,
DFB25D30163D4743006C4A48 /* AddonCallback.cpp in Sources */,
DFB25D31163D4743006C4A48 /* AddonClass.cpp in Sources */,
+ 6890C27B1DDBDFD900F8F362 /* RetroPlayerAudio.cpp in Sources */,
DFB25D32163D4743006C4A48 /* AddonUtils.cpp in Sources */,
DFB25D33163D4743006C4A48 /* CallbackFunction.cpp in Sources */,
DFB25D34163D4743006C4A48 /* CallbackHandler.cpp in Sources */,
@@ -11262,6 +11301,7 @@
B179BD6B1AD8EA7B00EA8D49 /* InputCodingTableBaiduPY.cpp in Sources */,
DFD7173B1C09FEC60025D964 /* OSXGNUReplacements.c in Sources */,
B179BD6E1AD8EA7B00EA8D49 /* InputCodingTableBasePY.cpp in Sources */,
+ 6890C27D1DDBDFD900F8F362 /* RetroPlayerVideo.cpp in Sources */,
B179BD711AD8EA7B00EA8D49 /* InputCodingTableFactory.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
@@ -11391,6 +11431,7 @@
E49911C9174E5D2500741B6D /* DVDOverlayCodecSSA.cpp in Sources */,
E49911CA174E5D2500741B6D /* DVDOverlayCodecText.cpp in Sources */,
7C8E02471BA35D0B0072E8B2 /* SystemBuiltins.cpp in Sources */,
+ 6890C27A1DDBDFD900F8F362 /* RetroPlayer.cpp in Sources */,
E49911CB174E5D2500741B6D /* DVDOverlayCodecTX3G.cpp in Sources */,
E49911CE174E5D2500741B6D /* DVDVideoCodecFFmpeg.cpp in Sources */,
395C29BD1A94733100EBC7AD /* Key.cpp in Sources */,
@@ -11564,6 +11605,7 @@
E499127F174E5D9900741B6D /* DirectoryNodeAlbumCompilationsSongs.cpp in Sources */,
E4991280174E5D9900741B6D /* DirectoryNodeAlbumRecentlyAdded.cpp in Sources */,
395F6DDE1A8133360088CC74 /* GUIDialogSimpleMenu.cpp in Sources */,
+ 6890C2781DDBDFD900F8F362 /* PixelConverter.cpp in Sources */,
E4991281174E5D9900741B6D /* DirectoryNodeAlbumRecentlyAddedSong.cpp in Sources */,
E4991282174E5D9900741B6D /* DirectoryNodeAlbumRecentlyPlayed.cpp in Sources */,
DFD7175D1C0A031B0025D964 /* IOSExternalTouchController.mm in Sources */,
@@ -11727,6 +11769,7 @@
E4991313174E5DAD00741B6D /* GUISpinControlEx.cpp in Sources */,
E4991314174E5DAD00741B6D /* GUIStaticItem.cpp in Sources */,
E4991315174E5DAD00741B6D /* GUITextBox.cpp in Sources */,
+ 6890C27E1DDBDFD900F8F362 /* RetroPlayerVideo.cpp in Sources */,
E4991316174E5DAD00741B6D /* GUITextLayout.cpp in Sources */,
E4991317174E5DAD00741B6D /* GUITexture.cpp in Sources */,
395C2A121A9F072400EBC7AD /* ResourceDirectory.cpp in Sources */,
@@ -12325,6 +12368,7 @@
7CCDA1B0192753E30074CF51 /* X_MS_MediaReceiverRegistrarSCPD.cpp in Sources */,
7CCDA1BB192753E30074CF51 /* AVTransportSCPD.cpp in Sources */,
7CCDA1C8192753E30074CF51 /* PltMediaController.cpp in Sources */,
+ 6890C27C1DDBDFD900F8F362 /* RetroPlayerAudio.cpp in Sources */,
7CCDA1D1192753E30074CF51 /* PltMediaRenderer.cpp in Sources */,
7CCDA1DC192753E30074CF51 /* RdrConnectionManagerSCPD.cpp in Sources */,
7CCDA1E7192753E30074CF51 /* RenderingControlSCPD.cpp in Sources */,
diff --git a/Makefile.in b/Makefile.in
index f28925e9f2..a8c1f63a8d 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -41,6 +41,7 @@ DIRECTORY_ARCHIVES=$(VideoPlayer_ARCHIVES) \
xbmc/cores/DllLoader/exports/exports.a \
xbmc/cores/DllLoader/exports/util/exports_utils.a \
xbmc/cores/ExternalPlayer/ExternalPlayer.a \
+ xbmc/cores/RetroPlayer/retroplayer.a \
xbmc/cores/VideoPlayer/VideoRenderers/VideoRenderer.a \
xbmc/cores/VideoPlayer/VideoRenderers/VideoShaders/VideoShaders.a \
xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/HwDecRender.a \
diff --git a/configure.ac b/configure.ac
index 1da41576dd..8d1e85e293 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2173,6 +2173,7 @@ OUTPUT_FILES="Makefile \
xbmc/cores/paplayer/Makefile \
xbmc/cores/omxplayer/Makefile \
xbmc/cores/playercorefactory/Makefile \
+ xbmc/cores/RetroPlayer/Makefile \
xbmc/messaging/Makefile \
xbmc/messaging/helpers/Makefile \
xbmc/guilib/Makefile \
diff --git a/project/cmake/treedata/common/cores.txt b/project/cmake/treedata/common/cores.txt
index d23939d314..8d79dd18dc 100644
--- a/project/cmake/treedata/common/cores.txt
+++ b/project/cmake/treedata/common/cores.txt
@@ -6,3 +6,4 @@ xbmc/cores/DllLoader/exports/util cores/dll-loader/exports/util
xbmc/cores/ExternalPlayer cores/externalplayer
xbmc/cores/paplayer cores/paplayer
xbmc/cores/playercorefactory cores/playercorefactory
+xbmc/cores/RetroPlayer cores/RetroPlayer
diff --git a/system/keymaps/gamepad.xml b/system/keymaps/gamepad.xml
index e1767515ba..63140230da 100644
--- a/system/keymaps/gamepad.xml
+++ b/system/keymaps/gamepad.xml
@@ -84,6 +84,21 @@
<dpaddown>ChapterOrBigStepBack</dpaddown>
</gamepad>
</FullscreenVideo>
+ <FullscreenGame>
+ <gamepad>
+ <A>Pause</A>
+ <B>Stop</B>
+ <Y>AspectRatio</Y>
+ <black>CodecInfo</black>
+ <white>Info</white>
+ <back>Seek(-7)</back><!-- Replaces smallstepback -->
+ <start>OSD</start>
+ <leftanalogtrigger>AnalogRewind</leftanalogtrigger>
+ <rightanalogtrigger>AnalogFastForward</rightanalogtrigger>
+ <dpadleft>StepBack</dpadleft>
+ <dpadright>StepForward</dpadright>
+ </gamepad>
+ </FullscreenGame>
<FullscreenLiveTV>
<gamepad>
<dpadleft>StepBack</dpadleft>
diff --git a/system/keymaps/joystick.xml b/system/keymaps/joystick.xml
index 937baf2229..7717c587f1 100644
--- a/system/keymaps/joystick.xml
+++ b/system/keymaps/joystick.xml
@@ -91,6 +91,35 @@
<rightstickdown>VolumeDown</rightstickdown>
</joystick>
</FullscreenVideo>
+ <FullscreenGame>
+ <joystick>
+ <a>noop</a>
+ <b>noop</b>
+ <x>noop</x>
+ <y>noop</y>
+ <start>noop</start>
+ <back>noop</back>
+ <!--<guide>noop</guide>-->
+ <up>noop</up>
+ <down>noop</down>
+ <right>noop</right>
+ <left>noop</left>
+ <leftthumb>noop</leftthumb>
+ <rightthumb>noop</rightthumb>
+ <lefttrigger>noop</lefttrigger>
+ <righttrigger>noop</righttrigger>
+ <leftbumper>noop</leftbumper>
+ <rightbumper>noop</rightbumper>
+ <leftstickleft>noop</leftstickleft>
+ <leftstickright>noop</leftstickright>
+ <leftstickup>noop</leftstickup>
+ <leftstickdown>noop</leftstickdown>
+ <rightstickleft>noop</rightstickleft>
+ <rightstickright>noop</rightstickright>
+ <rightstickup>noop</rightstickup>
+ <rightstickdown>noop</rightstickdown>
+ </joystick>
+ </FullscreenGame>
<FullscreenLiveTV>
<joystick>
<up>ChannelUp</up>
diff --git a/system/keymaps/keyboard.xml b/system/keymaps/keyboard.xml
index d4dffed997..fd91476f56 100644
--- a/system/keymaps/keyboard.xml
+++ b/system/keymaps/keyboard.xml
@@ -373,6 +373,31 @@
<b mod="alt">CreateEpisodeBookmark</b>
</keyboard>
</FullscreenVideo>
+ <FullscreenGame>
+ <keyboard>
+ <f>FastForward</f>
+ <r>Rewind</r>
+ <period>StepForward</period>
+ <comma>StepBack</comma>
+ <backspace>Fullscreen</backspace>
+ <backspace mod="longpress">Stop</backspace>
+ <browser_back>Fullscreen</browser_back>
+ <browser_back mod="longpress">Stop</browser_back>
+ <return>OSD</return>
+ <enter>OSD</enter>
+ <return mod="longpress">PlayPause</return>
+ <enter mod="longpress">PlayPause</enter>
+ <m>OSD</m>
+ <menu>OSD</menu>
+ <i>Info</i>
+ <o>CodecInfo</o>
+ <z>AspectRatio</z>
+ <zoom>AspectRatio</zoom>
+ <left>StepBack</left>
+ <right>StepForward</right>
+ <escape>Fullscreen</escape>
+ </keyboard>
+ </FullscreenGame>
<VideoTimeSeek>
<keyboard>
<return>Select</return>
diff --git a/system/keymaps/mouse.xml b/system/keymaps/mouse.xml
index 9df7a976d5..b4edcd482d 100644
--- a/system/keymaps/mouse.xml
+++ b/system/keymaps/mouse.xml
@@ -53,4 +53,9 @@
<rightclick>Info</rightclick>
</mouse>
</FullscreenVideo>
+ <FullscreenGame>
+ <mouse>
+ <rightclick>Info</rightclick>
+ </mouse>
+ </FullscreenGame>
</keymap>
diff --git a/system/keymaps/remote.xml b/system/keymaps/remote.xml
index 54193b6525..259265ace2 100644
--- a/system/keymaps/remote.xml
+++ b/system/keymaps/remote.xml
@@ -202,6 +202,20 @@
<pageminus>SkipPrevious</pageminus>
</remote>
</FullscreenVideo>
+ <FullscreenGame>
+ <remote>
+ <left>StepBack</left>
+ <right>StepForward</right>
+ <back>Back</back>
+ <menu>OSD</menu>
+ <contentsmenu>OSD</contentsmenu>
+ <rootmenu>OSD</rootmenu>
+ <start>OSD</start>
+ <select>OSD</select>
+ <title>CodecInfo</title>
+ <info>Info</info>
+ </remote>
+ </FullscreenGame>
<VideoTimeSeek>
<remote>
<select>Select</select>
diff --git a/system/keymaps/touchscreen.xml b/system/keymaps/touchscreen.xml
index c3135ae791..fee4eb4ad2 100644
--- a/system/keymaps/touchscreen.xml
+++ b/system/keymaps/touchscreen.xml
@@ -55,6 +55,14 @@
<tap pointers="3">PlayPause</tap>
</touch>
</FullScreenVideo>
+ <FullScreenGame>
+ <touch>
+ <swipe direction="left">StepBack</swipe>
+ <swipe direction="right">StepForward</swipe>
+ <swipe direction="left" pointers="2">Seek(-7)</swipe>
+ <tap pointers="3">PlayPause</tap>
+ </touch>
+ </FullScreenGame>
<PlayerControls>
<touch>
<swipe direction="down" pointers="3">Back</swipe>
diff --git a/xbmc/Application.cpp b/xbmc/Application.cpp
index 23f03ddcbb..ff3e3c192c 100644
--- a/xbmc/Application.cpp
+++ b/xbmc/Application.cpp
@@ -3472,7 +3472,7 @@ PlayBackRet CApplication::PlayFile(CFileItem item, const std::string& player, bo
* This should speed up player startup for files on internet filesystems (eg. webdav) and
* increase performance on low powered systems (Atom/ARM).
*/
- if (item.IsVideo())
+ if (item.IsVideo() || item.IsGame())
{
CJobManager::GetInstance().PauseJobs();
}
@@ -4434,7 +4434,7 @@ bool CApplication::ExecuteXBMCAction(std::string actionStr, const CGUIListItemPt
}
else
#endif
- if (item.IsAudio() || item.IsVideo())
+ if (item.IsAudio() || item.IsVideo() || item.IsGame())
{ // an audio or video file
PlayFile(item, "");
}
diff --git a/xbmc/GUIInfoManager.cpp b/xbmc/GUIInfoManager.cpp
index 169241b2be..2033c32676 100644
--- a/xbmc/GUIInfoManager.cpp
+++ b/xbmc/GUIInfoManager.cpp
@@ -43,6 +43,7 @@
#include "pictures/PictureInfoTag.h"
#include "music/tags/MusicInfoTag.h"
#include "games/addons/savestates/SavestateDefines.h"
+#include "games/tags/GameInfoTag.h"
#include "guilib/IGUIContainer.h"
#include "guilib/GUIWindowManager.h"
#include "PlayListPlayer.h"
@@ -9255,6 +9256,8 @@ void CGUIInfoManager::SetCurrentItemJob(const CFileItemPtr item)
if (item->IsAudio())
SetCurrentSong(*item);
+ else if (item->IsGame())
+ SetCurrentGame(*item);
else
SetCurrentMovie(*item);
@@ -9374,6 +9377,22 @@ void CGUIInfoManager::SetCurrentMovie(CFileItem &item)
m_currentMovieThumb = item.GetArt("thumb");
}
+void CGUIInfoManager::SetCurrentGame(CFileItem &item)
+{
+ CLog::Log(LOGDEBUG,"CGUIInfoManager::SetCurrentGame(%s)", item.GetPath().c_str());
+ *m_currentFile = item;
+
+ m_currentFile->LoadGameTag();
+ if (m_currentFile->GetGameInfoTag()->GetTitle().empty())
+ {
+ // No title in tag, show filename only
+ m_currentFile->GetGameInfoTag()->SetTitle(CUtil::GetTitleFromPath(m_currentFile->GetPath()));
+ }
+ m_currentFile->GetGameInfoTag()->SetLoaded(true);
+
+ m_currentFile->FillInDefaultIcon();
+}
+
std::string CGUIInfoManager::GetSystemHeatInfo(int info)
{
if (CTimeUtils::GetFrameTime() - m_lastSysHeatInfoTime >= SYSHEATUPDATEINTERVAL)
diff --git a/xbmc/GUIInfoManager.h b/xbmc/GUIInfoManager.h
index 48d1c6f282..fc96e73351 100644
--- a/xbmc/GUIInfoManager.h
+++ b/xbmc/GUIInfoManager.h
@@ -171,6 +171,7 @@ public:
void SetCurrentSlide(CFileItem &item);
const CFileItem &GetCurrentSlide() const;
void ResetCurrentSlide();
+ void SetCurrentGame(CFileItem &item);
void SetCurrentSongTag(const MUSIC_INFO::CMusicInfoTag &tag);
void SetCurrentVideoTag(const CVideoInfoTag &tag);
diff --git a/xbmc/cores/RetroPlayer/CMakeLists.txt b/xbmc/cores/RetroPlayer/CMakeLists.txt
new file mode 100644
index 0000000000..d9a8e3ad2a
--- /dev/null
+++ b/xbmc/cores/RetroPlayer/CMakeLists.txt
@@ -0,0 +1,18 @@
+set(SOURCES PixelConverter.cpp
+ RetroPlayer.cpp
+ RetroPlayerAudio.cpp
+ RetroPlayerVideo.cpp)
+
+set(HEADERS IPixelConverter.h
+ PixelConverter.h
+ RetroPlayer.h
+ RetroPlayerAudio.h
+ RetroPlayerDefines.h
+ RetroPlayerVideo.h)
+
+if(CORE_SYSTEM_NAME STREQUAL rbpi)
+ list(APPEND SOURCES PixelConverterRBP.cpp)
+ list(APPEND HEADERS PixelConverterRBP.h)
+endif()
+
+core_add_library(retroplayer)
diff --git a/xbmc/cores/RetroPlayer/IPixelConverter.h b/xbmc/cores/RetroPlayer/IPixelConverter.h
new file mode 100644
index 0000000000..387f454b03
--- /dev/null
+++ b/xbmc/cores/RetroPlayer/IPixelConverter.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2016 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 "libavutil/pixfmt.h"
+
+#include <stdint.h>
+
+struct DVDVideoPicture;
+
+class IPixelConverter
+{
+public:
+ virtual ~IPixelConverter() = default;
+
+ /*!
+ * \brief Open a context for converting pixels
+ * \param pixfmt The source format
+ * \param target The target format
+ * \param with The width of the frame
+ * \param height The height of the frame
+ * \return true if this object is ready to convert pixels
+ */
+ virtual bool Open(AVPixelFormat pixfmt, AVPixelFormat target, unsigned int width, unsigned int height) = 0;
+
+ /*!
+ * \brief Release the resources used by this class
+ */
+ virtual void Dispose() = 0;
+
+ /*!
+ * \brief Send a frame to the pixel converter
+ * \param pData A pointer to the pixel data
+ * \param size The size of the data
+ * \return true if a picture is ready to be read, false otherwise
+ */
+ virtual bool Decode(const uint8_t* pData, unsigned int size) = 0;
+
+ /*!
+ * \brief Get the results of processing the pixels
+ * \param dvdVideoPicture a container for the resulting pixel data
+ */
+ virtual void GetPicture(DVDVideoPicture& dvdVideoPicture) = 0;
+};
diff --git a/xbmc/cores/RetroPlayer/Makefile.in b/xbmc/cores/RetroPlayer/Makefile.in
new file mode 100644
index 0000000000..976b7c7f15
--- /dev/null
+++ b/xbmc/cores/RetroPlayer/Makefile.in
@@ -0,0 +1,13 @@
+SRCS=PixelConverter.cpp \
+ RetroPlayer.cpp \
+ RetroPlayerAudio.cpp \
+ RetroPlayerVideo.cpp
+
+ifeq (@CORE_SYSTEM_NAME@,rbpi)
+ SRCS += PixelConverterRBP.cpp
+endif
+
+LIB=retroplayer.a
+
+include ../../../Makefile.include
+-include $(patsubst %.cpp,%.P,$(patsubst %.c,%.P,$(SRCS)))
diff --git a/xbmc/cores/RetroPlayer/PixelConverter.cpp b/xbmc/cores/RetroPlayer/PixelConverter.cpp
new file mode 100644
index 0000000000..8d8a2dcda2
--- /dev/null
+++ b/xbmc/cores/RetroPlayer/PixelConverter.cpp
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2016 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 "PixelConverter.h"
+#include "cores/VideoPlayer/DVDClock.h"
+#include "cores/VideoPlayer/DVDCodecs/DVDCodecUtils.h"
+#include "utils/log.h"
+
+extern "C"
+{
+ #include "libswscale/swscale.h"
+}
+
+CPixelConverter::CPixelConverter() :
+ m_renderFormat(RENDER_FMT_NONE),
+ m_width(0),
+ m_height(0),
+ m_swsContext(nullptr),
+ m_buf(nullptr)
+{
+}
+
+bool CPixelConverter::Open(AVPixelFormat pixfmt, AVPixelFormat targetfmt, unsigned int width, unsigned int height)
+{
+ if (pixfmt == targetfmt || width == 0 || height == 0)
+ return false;
+
+ m_renderFormat = CDVDCodecUtils::EFormatFromPixfmt(targetfmt);
+ if (m_renderFormat == RENDER_FMT_NONE)
+ {
+ CLog::Log(LOGERROR, "%s: Invalid target pixel format: %d", __FUNCTION__, targetfmt);
+ return false;
+ }
+
+ m_width = width;
+ m_height = height;
+
+ m_swsContext = sws_getContext(width, height, pixfmt,
+ width, height, targetfmt,
+ SWS_FAST_BILINEAR, NULL, NULL, NULL);
+ if (!m_swsContext)
+ {
+ CLog::Log(LOGERROR, "%s: Failed to create swscale context", __FUNCTION__);
+ return false;
+ }
+
+ m_buf = CDVDCodecUtils::AllocatePicture(width, height);
+ if (!m_buf)
+ {
+ CLog::Log(LOGERROR, "%s: Failed to allocate picture of dimensions %dx%d", __FUNCTION__, width, height);
+ return false;
+ }
+
+ return true;
+}
+
+void CPixelConverter::Dispose()
+{
+ if (m_swsContext)
+ {
+ sws_freeContext(m_swsContext);
+ m_swsContext = nullptr;
+ }
+
+ if (m_buf)
+ {
+ CDVDCodecUtils::FreePicture(m_buf);
+ m_buf = nullptr;
+ }
+}
+
+bool CPixelConverter::Decode(const uint8_t* pData, unsigned int size)
+{
+ if (pData == nullptr || size == 0 || m_swsContext == nullptr)
+ return false;
+
+ uint8_t* dataMutable = const_cast<uint8_t*>(pData);
+
+ const int stride = size / m_height;
+
+ uint8_t* src[] = { dataMutable, 0, 0, 0 };
+ int srcStride[] = { stride, 0, 0, 0 };
+ uint8_t* dst[] = { m_buf->data[0], m_buf->data[1], m_buf->data[2], 0 };
+ int dstStride[] = { m_buf->iLineSize[0], m_buf->iLineSize[1], m_buf->iLineSize[2], 0 };
+
+ sws_scale(m_swsContext, src, srcStride, 0, m_height, dst, dstStride);
+
+ return true;
+}
+
+void CPixelConverter::GetPicture(DVDVideoPicture& dvdVideoPicture)
+{
+ dvdVideoPicture.dts = DVD_NOPTS_VALUE;
+ dvdVideoPicture.pts = DVD_NOPTS_VALUE;
+
+ for (int i = 0; i < 4; i++)
+ {
+ dvdVideoPicture.data[i] = m_buf->data[i];
+ dvdVideoPicture.iLineSize[i] = m_buf->iLineSize[i];
+ }
+
+ dvdVideoPicture.iFlags = 0; // *not* DVP_FLAG_ALLOCATED
+ dvdVideoPicture.color_matrix = 4; // CONF_FLAGS_YUVCOEF_BT601
+ dvdVideoPicture.color_range = 0; // *not* CONF_FLAGS_YUV_FULLRANGE
+ dvdVideoPicture.iWidth = m_width;
+ dvdVideoPicture.iHeight = m_height;
+ dvdVideoPicture.iDisplayWidth = m_width; //! @todo: Update if aspect ratio changes
+ dvdVideoPicture.iDisplayHeight = m_height;
+ dvdVideoPicture.format = m_renderFormat;
+}
diff --git a/xbmc/cores/RetroPlayer/PixelConverter.h b/xbmc/cores/RetroPlayer/PixelConverter.h
new file mode 100644
index 0000000000..fd009ae12c
--- /dev/null
+++ b/xbmc/cores/RetroPlayer/PixelConverter.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2016 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 "IPixelConverter.h"
+#include "cores/VideoPlayer/VideoRenderers/RenderFormats.h"
+
+#include <stdint.h>
+
+struct DVDVideoPicture;
+struct SwsContext;
+
+class CPixelConverter : public IPixelConverter
+{
+public:
+ CPixelConverter();
+ virtual ~CPixelConverter() { Dispose(); }
+
+ // implementation of IPixelConverter
+ virtual bool Open(AVPixelFormat pixfmt, AVPixelFormat target, unsigned int width, unsigned int height) override;
+ virtual void Dispose() override;
+ virtual bool Decode(const uint8_t* pData, unsigned int size) override;
+ virtual void GetPicture(DVDVideoPicture& dvdVideoPicture) override;
+
+protected:
+ ERenderFormat m_renderFormat;
+ unsigned int m_width;
+ unsigned int m_height;
+ SwsContext* m_swsContext;
+ DVDVideoPicture* m_buf;
+};
diff --git a/xbmc/cores/RetroPlayer/PixelConverterRBP.cpp b/xbmc/cores/RetroPlayer/PixelConverterRBP.cpp
new file mode 100644
index 0000000000..4d159ca91b
--- /dev/null
+++ b/xbmc/cores/RetroPlayer/PixelConverterRBP.cpp
@@ -0,0 +1,237 @@
+/*
+ * Copyright (C) 2016 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 "PixelConverterRBP.h"
+#include "cores/VideoPlayer/DVDClock.h"
+#include "cores/VideoPlayer/VideoRenderers/HwDecRender/MMALRenderer.h"
+#include "linux/RBP.h"
+#include "utils/log.h"
+
+extern "C"
+{
+ #include "libavutil/imgutils.h"
+ #include "libswscale/swscale.h"
+}
+
+std::vector<CPixelConverterRBP::PixelFormatTargetTable> CPixelConverterRBP::pixfmt_target_table =
+{
+ { AV_PIX_FMT_BGR0, AV_PIX_FMT_BGR0 },
+ { AV_PIX_FMT_RGB565LE, AV_PIX_FMT_RGB565LE },
+};
+
+std::vector<CPixelConverterRBP::MMALEncodingTable> CPixelConverterRBP::mmal_encoding_table =
+{
+ { AV_PIX_FMT_YUV420P, MMAL_ENCODING_I420 },
+ { AV_PIX_FMT_ARGB, MMAL_ENCODING_ARGB },
+ { AV_PIX_FMT_RGBA, MMAL_ENCODING_RGBA },
+ { AV_PIX_FMT_ABGR, MMAL_ENCODING_ABGR },
+ { AV_PIX_FMT_BGRA, MMAL_ENCODING_ABGR },
+ { AV_PIX_FMT_BGR0, MMAL_ENCODING_BGRA },
+ { AV_PIX_FMT_RGB24, MMAL_ENCODING_RGB24 },
+ { AV_PIX_FMT_BGR24, MMAL_ENCODING_BGR24 },
+ { AV_PIX_FMT_RGB565, MMAL_ENCODING_RGB16 },
+ { AV_PIX_FMT_RGB565LE, MMAL_ENCODING_RGB16 },
+ { AV_PIX_FMT_BGR565, MMAL_ENCODING_BGR16 },
+};
+
+CPixelConverterRBP::CPixelConverterRBP() :
+ m_mmal_format(MMAL_ENCODING_UNKNOWN)
+{
+}
+
+bool CPixelConverterRBP::Open(AVPixelFormat pixfmt, AVPixelFormat targetfmt, unsigned int width, unsigned int height)
+{
+ if (width == 0 || height == 0)
+ return false;
+
+ targetfmt = TranslateTargetFormat(pixfmt);
+
+ CLog::Log(LOGDEBUG, "CPixelConverter::%s: pixfmt:%d(%s) targetfmt:%d(%s) %dx%d", __FUNCTION__, pixfmt, av_get_pix_fmt_name(pixfmt), targetfmt, av_get_pix_fmt_name(targetfmt), width, height);
+
+ if (targetfmt == AV_PIX_FMT_NONE)
+ {
+ CLog::Log(LOGERROR, "%s: Invalid target pixel format: %d", __FUNCTION__, targetfmt);
+ return false;
+ }
+
+ m_renderFormat = RENDER_FMT_MMAL;
+ m_width = width;
+ m_height = height;
+ m_swsContext = sws_getContext(width, height, pixfmt,
+ width, height, targetfmt,
+ SWS_FAST_BILINEAR, NULL, NULL, NULL);
+ if (!m_swsContext)
+ {
+ CLog::Log(LOGERROR, "%s: Failed to create swscale context", __FUNCTION__);
+ return false;
+ }
+
+ m_mmal_format = TranslateFormat(targetfmt);
+
+ if (m_mmal_format == MMAL_ENCODING_UNKNOWN)
+ return false;
+
+ /* Create dummy component with attached pool */
+ m_pool = std::make_shared<CMMALPool>(MMAL_COMPONENT_DEFAULT_VIDEO_DECODER, false, MMAL_NUM_OUTPUT_BUFFERS, 0, MMAL_ENCODING_I420, MMALStateFFDec);
+
+ return true;
+}
+
+void CPixelConverterRBP::Dispose()
+{
+ m_pool->Close();
+ m_pool = nullptr;
+
+ CPixelConverter::Dispose();
+}
+
+bool CPixelConverterRBP::Decode(const uint8_t* pData, unsigned int size)
+{
+ if (pData == nullptr || size == 0 || m_swsContext == nullptr)
+ return false;
+
+ if (m_buf)
+ FreePicture(m_buf);
+
+ m_buf = AllocatePicture(m_width, m_height);
+ if (!m_buf)
+ {
+ CLog::Log(LOGERROR, "%s: Failed to allocate picture of dimensions %dx%d", __FUNCTION__, m_width, m_height);
+ return false;
+ }
+
+ uint8_t* dataMutable = const_cast<uint8_t*>(pData);
+
+ int bpp;
+ if (m_mmal_format == MMAL_ENCODING_ARGB ||
+ m_mmal_format == MMAL_ENCODING_RGBA ||
+ m_mmal_format == MMAL_ENCODING_ABGR ||
+ m_mmal_format == MMAL_ENCODING_BGRA)
+ bpp = 4;
+ else if (m_mmal_format == MMAL_ENCODING_RGB24 ||
+ m_mmal_format == MMAL_ENCODING_BGR24)
+ bpp = 4;
+ else if (m_mmal_format == MMAL_ENCODING_RGB16 ||
+ m_mmal_format == MMAL_ENCODING_BGR16)
+ bpp = 2;
+ else
+ {
+ CLog::Log(LOGERROR, "CPixelConverter::AllocatePicture, unknown format:%.4s", (char *)&m_mmal_format);
+ return false;
+ }
+
+ MMAL::CMMALYUVBuffer *omvb = (MMAL::CMMALYUVBuffer *)m_buf->MMALBuffer;
+
+ const int stride = size / m_height;
+
+ uint8_t* src[] = { dataMutable, 0, 0, 0 };
+ int srcStride[] = { stride, 0, 0, 0 };
+ uint8_t* dst[] = { (uint8_t *)omvb->gmem->m_arm, 0, 0, 0 };
+ int dstStride[] = { (int)omvb->m_aligned_width * bpp, 0, 0, 0 };
+
+ sws_scale(m_swsContext, src, srcStride, 0, m_height, dst, dstStride);
+
+ return true;
+}
+
+void CPixelConverterRBP::GetPicture(DVDVideoPicture& dvdVideoPicture)
+{
+ CPixelConverter::GetPicture(dvdVideoPicture);
+
+ dvdVideoPicture.MMALBuffer = m_buf->MMALBuffer;
+
+ MMAL::CMMALYUVBuffer *omvb = (MMAL::CMMALYUVBuffer *)m_buf->MMALBuffer;
+
+ // need to flush ARM cache so GPU can see it
+ omvb->gmem->Flush();
+}
+
+DVDVideoPicture* CPixelConverterRBP::AllocatePicture(int iWidth, int iHeight)
+{
+ MMAL::CMMALYUVBuffer *omvb = nullptr;
+ DVDVideoPicture* pPicture = new DVDVideoPicture;
+
+ // gpu requirements
+ int w = (iWidth + 31) & ~31;
+ int h = (iHeight + 15) & ~15;
+ if (pPicture && m_pool)
+ {
+ m_pool->SetFormat(m_mmal_format, iWidth, iHeight, w, h, 0, nullptr);
+
+ omvb = dynamic_cast<MMAL::CMMALYUVBuffer *>(m_pool->GetBuffer(500));
+ if (!omvb ||
+ !omvb->mmal_buffer ||
+ !omvb->gmem ||
+ !omvb->gmem->m_arm)
+ {
+ CLog::Log(LOGERROR, "CPixelConverterRBP::AllocatePicture, unable to allocate new video picture, out of memory.");
+ delete pPicture;
+ pPicture = nullptr;
+ }
+
+ CGPUMEM *gmem = omvb->gmem;
+ omvb->mmal_buffer->data = (uint8_t *)gmem->m_vc_handle;
+ omvb->mmal_buffer->alloc_size = omvb->mmal_buffer->length = gmem->m_numbytes;
+ }
+ else
+ CLog::Log(LOGERROR, "CPixelConverterRBP::AllocatePicture invalid picture:%p pool:%p", pPicture, m_pool.get());
+
+ if (pPicture)
+ {
+ pPicture->MMALBuffer = omvb;
+ pPicture->iWidth = iWidth;
+ pPicture->iHeight = iHeight;
+ }
+
+ return pPicture;
+}
+
+void CPixelConverterRBP::FreePicture(DVDVideoPicture* pPicture)
+{
+ if (pPicture)
+ {
+ if (pPicture->MMALBuffer)
+ pPicture->MMALBuffer->Release();
+
+ delete pPicture;
+ }
+ else
+ CLog::Log(LOGERROR, "CPixelConverterRBP::FreePicture invalid picture:%p", pPicture);
+}
+
+AVPixelFormat CPixelConverterRBP::TranslateTargetFormat(AVPixelFormat pixfmt)
+{
+ for (const auto& entry : pixfmt_target_table)
+ {
+ if (entry.pixfmt == pixfmt)
+ return entry.targetfmt;
+ }
+ return AV_PIX_FMT_NONE;
+}
+
+uint32_t CPixelConverterRBP::TranslateFormat(AVPixelFormat pixfmt)
+{
+ for (const auto& entry : mmal_encoding_table)
+ {
+ if (entry.pixfmt == pixfmt)
+ return entry.encoding;
+ }
+ return MMAL_ENCODING_UNKNOWN;
+}
diff --git a/xbmc/cores/RetroPlayer/PixelConverterRBP.h b/xbmc/cores/RetroPlayer/PixelConverterRBP.h
new file mode 100644
index 0000000000..9924ec6d48
--- /dev/null
+++ b/xbmc/cores/RetroPlayer/PixelConverterRBP.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2016 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 "PixelConverter.h"
+
+#include <stdint.h>
+#include <vector>
+
+class CMMALPool;
+struct DVDVideoPicture;
+
+class CPixelConverterRBP : public CPixelConverter
+{
+public:
+ CPixelConverterRBP();
+ virtual ~CPixelConverterRBP() { Dispose(); }
+
+ // implementation of IPixelConverter
+ virtual bool Open(AVPixelFormat pixfmt, AVPixelFormat target, unsigned int width, unsigned int height) override;
+ virtual void Dispose() override;
+ virtual bool Decode(const uint8_t* pData, unsigned int size) override;
+ virtual void GetPicture(DVDVideoPicture& dvdVideoPicture) override;
+
+private:
+ /*!
+ * \brief Allocate a new picture (AV_PIX_FMT_YUV420P)
+ */
+ DVDVideoPicture* AllocatePicture(int iWidth, int iHeight);
+
+ /*!
+ * \brief Free an allocated picture
+ */
+ void FreePicture(DVDVideoPicture* pPicture);
+
+ struct PixelFormatTargetTable
+ {
+ AVPixelFormat pixfmt;
+ AVPixelFormat targetfmt;
+ };
+
+ struct MMALEncodingTable
+ {
+ AVPixelFormat pixfmt;
+ uint32_t encoding;
+ };
+
+ static std::vector<PixelFormatTargetTable> pixfmt_target_table;
+ static std::vector<MMALEncodingTable> mmal_encoding_table;
+
+ static AVPixelFormat TranslateTargetFormat(AVPixelFormat pixfmt);
+ static uint32_t TranslateFormat(AVPixelFormat pixfmt);
+
+ std::shared_ptr<CMMALPool> m_pool;
+ uint32_t m_mmal_format;
+};
diff --git a/xbmc/cores/RetroPlayer/RetroPlayer.cpp b/xbmc/cores/RetroPlayer/RetroPlayer.cpp
new file mode 100644
index 0000000000..89960db88a
--- /dev/null
+++ b/xbmc/cores/RetroPlayer/RetroPlayer.cpp
@@ -0,0 +1,365 @@
+/*
+ * Copyright (C) 2012-2016 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 "RetroPlayer.h"
+#include "RetroPlayerAudio.h"
+#include "RetroPlayerVideo.h"
+#include "cores/VideoPlayer/Process/ProcessInfo.h"
+#include "games/addons/playback/IGameClientPlayback.h"
+#include "games/addons/GameClient.h"
+#include "games/tags/GameInfoTag.h"
+#include "games/GameUtils.h"
+#include "threads/SingleLock.h"
+#include "utils/log.h"
+#include "utils/MathUtils.h"
+#include "utils/StringUtils.h"
+#include "windowing/WindowingFactory.h"
+#include "FileItem.h"
+#include "URL.h"
+
+using namespace GAME;
+
+CRetroPlayer::CRetroPlayer(IPlayerCallback& callback) :
+ IPlayer(callback),
+ m_renderManager(m_clock, this),
+ m_processInfo(CProcessInfo::CreateInstance())
+{
+ g_Windowing.Register(this);
+}
+
+CRetroPlayer::~CRetroPlayer()
+{
+ CloseFile();
+}
+
+bool CRetroPlayer::OpenFile(const CFileItem& file, const CPlayerOptions& options)
+{
+ std::string redactedPath = CURL::GetRedacted(file.GetPath());
+ CLog::Log(LOGINFO, "RetroPlayer: Opening: %s", redactedPath.c_str());
+
+ CSingleLock lock(m_mutex);
+
+ if (IsPlaying())
+ CloseFile();
+
+ PrintGameInfo(file);
+
+ bool bSuccess = false;
+
+ m_gameClient = CGameUtils::OpenGameClient(file);
+ if (m_gameClient)
+ {
+ if (m_gameClient->Initialize())
+ {
+ m_audio.reset(new CRetroPlayerAudio(*m_processInfo));
+ m_video.reset(new CRetroPlayerVideo(m_clock, m_renderManager, *m_processInfo));
+ if (m_gameClient->OpenFile(file, m_audio.get(), m_video.get()))
+ {
+ CLog::Log(LOGDEBUG, "RetroPlayer: Using game client %s", m_gameClient->ID().c_str());
+ bSuccess = true;
+ }
+ else
+ CLog::Log(LOGERROR, "RetroPlayer: Failed to open file using %s", m_gameClient->ID().c_str());
+ }
+ else
+ CLog::Log(LOGERROR, "RetroPlayer: Failed to initialize %s", m_gameClient->ID().c_str());
+ }
+ else
+ CLog::Log(LOGERROR, "RetroPlayer: Can't find add-on for game file");
+
+ if (bSuccess)
+ {
+ if (file.m_lStartOffset == STARTOFFSET_RESUME && file.HasGameInfoTag())
+ {
+ std::string redactedSavestatePath = CURL::GetRedacted(file.GetGameInfoTag()->GetSavestate());
+ CLog::Log(LOGDEBUG, "RetroPlayer: Loading savestate %s", redactedSavestatePath.c_str());
+
+ if (!SetPlayerState(file.GetGameInfoTag()->GetSavestate()))
+ CLog::Log(LOGERROR, "RetroPlayer: Failed to load savestate");
+ }
+
+ SetSpeed(1);
+
+ m_callback.OnPlayBackStarted();
+ }
+ else
+ {
+ m_gameClient.reset();
+ m_audio.reset();
+ m_video.reset();
+ }
+
+ return bSuccess;
+}
+
+bool CRetroPlayer::CloseFile(bool reopen /* = false */)
+{
+ CLog::Log(LOGDEBUG, "RetroPlayer: Closing file");
+
+ CSingleLock lock(m_mutex);
+
+ if (m_gameClient)
+ {
+ m_gameClient->CloseFile();
+ m_gameClient->Unload();
+ m_gameClient.reset();
+ m_callback.OnPlayBackEnded();
+ }
+
+ m_audio.reset();
+ m_video.reset();
+
+ return true;
+}
+
+bool CRetroPlayer::IsPlaying() const
+{
+ if (m_gameClient)
+ return m_gameClient->IsPlaying();
+ return false;
+}
+
+bool CRetroPlayer::CanPause()
+{
+ if (m_gameClient)
+ return m_gameClient->GetPlayback()->CanPause();
+ return false;
+}
+
+void CRetroPlayer::Pause()
+{
+ if (!CanPause())
+ return;
+
+ if (m_gameClient)
+ {
+ m_gameClient->GetPlayback()->PauseUnpause();
+ m_audio->Enable(m_gameClient->GetPlayback()->GetSpeed() == 1.0);
+ }
+}
+
+bool CRetroPlayer::CanSeek()
+{
+ if (m_gameClient)
+ return m_gameClient->GetPlayback()->CanSeek();
+ return false;
+}
+
+void CRetroPlayer::Seek(bool bPlus /* = true */,
+ bool bLargeStep /* = false */,
+ bool bChapterOverride /* = false */)
+{
+ if (!CanSeek())
+ return;
+
+ if (m_gameClient)
+ {
+ //! @todo
+ /*
+ if (bPlus)
+ {
+ if (bLargeStep)
+ m_gameClient->GetPlayback()->BigSkipForward();
+ else
+ m_gameClient->GetPlayback()->SmallSkipForward();
+ }
+ else
+ {
+ if (bLargeStep)
+ m_gameClient->GetPlayback()->BigSkipBackward();
+ else
+ m_gameClient->GetPlayback()->SmallSkipBackward();
+ }
+ */
+ }
+}
+
+void CRetroPlayer::SeekPercentage(float fPercent /* = 0 */)
+{
+ if (!CanSeek())
+ return;
+
+ if (fPercent < 0.0f )
+ fPercent = 0.0f;
+ else if (fPercent > 100.0f)
+ fPercent = 100.0f;
+
+ int64_t totalTime = GetTotalTime();
+ if (totalTime != 0)
+ SeekTime(static_cast<int64_t>(totalTime * fPercent / 100.0f));
+}
+
+float CRetroPlayer::GetPercentage()
+{
+ if (m_gameClient)
+ {
+ const float timeMs = static_cast<float>(m_gameClient->GetPlayback()->GetTimeMs());
+ const float totalMs = static_cast<float>(m_gameClient->GetPlayback()->GetTotalTimeMs());
+
+ if (totalMs != 0.0f)
+ return timeMs / totalMs * 100.0f;
+ }
+
+ return 0.0f;
+}
+
+float CRetroPlayer::GetCachePercentage()
+{
+ if (m_gameClient)
+ {
+ const float cacheMs = static_cast<float>(m_gameClient->GetPlayback()->GetCacheTimeMs());
+ const float totalMs = static_cast<float>(m_gameClient->GetPlayback()->GetTotalTimeMs());
+
+ if (totalMs != 0.0f)
+ return cacheMs / totalMs * 100.0f;
+ }
+ return 0.0f;
+}
+
+void CRetroPlayer::SetMute(bool bOnOff)
+{
+ if (m_audio)
+ m_audio->Enable(!bOnOff);
+}
+
+void CRetroPlayer::SeekTime(int64_t iTime /* = 0 */)
+{
+ if (!CanSeek())
+ return;
+
+ if (m_gameClient)
+ {
+ m_gameClient->GetPlayback()->SeekTimeMs(static_cast<unsigned int>(iTime));
+ m_audio->Enable(m_gameClient->GetPlayback()->GetSpeed() == 1.0);
+ }
+}
+
+bool CRetroPlayer::SeekTimeRelative(int64_t iTime)
+{
+ if (!CanSeek())
+ return false;
+
+ SeekTime(GetTime() + iTime);
+
+ return true;
+}
+
+int64_t CRetroPlayer::GetTime()
+{
+ if (m_gameClient)
+ return m_gameClient->GetPlayback()->GetTimeMs();
+ return 0;
+}
+
+int64_t CRetroPlayer::GetTotalTime()
+{
+ if (m_gameClient)
+ return m_gameClient->GetPlayback()->GetTotalTimeMs();
+ return 0;
+}
+
+bool CRetroPlayer::GetStreamDetails(CStreamDetails &details)
+{
+ //! @todo
+ return false;
+}
+
+void CRetroPlayer::SetSpeed(float speed)
+{
+ if (m_gameClient)
+ {
+ if (m_gameClient->GetPlayback()->GetSpeed() != speed)
+ {
+ if (speed == 1.0f)
+ m_callback.OnPlayBackResumed();
+ else if (speed == 0.0f)
+ m_callback.OnPlayBackPaused();
+ }
+
+ m_gameClient->GetPlayback()->SetSpeed(speed);
+ m_audio->Enable(m_gameClient->GetPlayback()->GetSpeed() == 1.0);
+ }
+}
+
+float CRetroPlayer::GetSpeed()
+{
+ if (m_gameClient)
+ return static_cast<float>(m_gameClient->GetPlayback()->GetSpeed());
+ return 0;
+}
+
+std::string CRetroPlayer::GetPlayerState()
+{
+ if (m_gameClient)
+ return m_gameClient->GetPlayback()->CreateManualSavestate();
+ return "";
+}
+
+bool CRetroPlayer::SetPlayerState(const std::string& state)
+{
+ if (m_gameClient)
+ return m_gameClient->GetPlayback()->LoadSavestate(state);
+ return false;
+}
+
+bool CRetroPlayer::Supports(EINTERLACEMETHOD method)
+{
+ return m_processInfo->Supports(method);
+}
+
+EINTERLACEMETHOD CRetroPlayer::GetDeinterlacingMethodDefault()
+{
+ return m_processInfo->GetDeinterlacingMethodDefault();
+}
+
+void CRetroPlayer::UpdateClockSync(bool enabled)
+{
+ m_processInfo->SetRenderClockSync(enabled);
+}
+
+void CRetroPlayer::UpdateRenderInfo(CRenderInfo &info)
+{
+ m_processInfo->UpdateRenderInfo(info);
+}
+
+void CRetroPlayer::PrintGameInfo(const CFileItem &file) const
+{
+ const CGameInfoTag *tag = file.GetGameInfoTag();
+ if (tag)
+ {
+ CLog::Log(LOGDEBUG, "RetroPlayer: ---------------------------------------");
+ CLog::Log(LOGDEBUG, "RetroPlayer: Game tag loaded");
+ CLog::Log(LOGDEBUG, "RetroPlayer: URL: %s", tag->GetURL().c_str());
+ CLog::Log(LOGDEBUG, "RetroPlayer: Title: %s", tag->GetTitle().c_str());
+ CLog::Log(LOGDEBUG, "RetroPlayer: Platform: %s", tag->GetPlatform().c_str());
+ CLog::Log(LOGDEBUG, "RetroPlayer: Genres: %s", StringUtils::Join(tag->GetGenres(), ", ").c_str());
+ CLog::Log(LOGDEBUG, "RetroPlayer: Developer: %s", tag->GetDeveloper().c_str());
+ if (tag->GetYear() > 0)
+ CLog::Log(LOGDEBUG, "RetroPlayer: Year: %u", tag->GetYear());
+ CLog::Log(LOGDEBUG, "RetroPlayer: Game Code: %s", tag->GetID().c_str());
+ CLog::Log(LOGDEBUG, "RetroPlayer: Region: %s", tag->GetRegion().c_str());
+ CLog::Log(LOGDEBUG, "RetroPlayer: Publisher: %s", tag->GetPublisher().c_str());
+ CLog::Log(LOGDEBUG, "RetroPlayer: Format: %s", tag->GetFormat().c_str());
+ CLog::Log(LOGDEBUG, "RetroPlayer: Cartridge type: %s", tag->GetCartridgeType().c_str());
+ CLog::Log(LOGDEBUG, "RetroPlayer: Save state: %s", tag->GetSavestate().c_str());
+ CLog::Log(LOGDEBUG, "RetroPlayer: Game client: %s", tag->GetGameClient().c_str());
+ CLog::Log(LOGDEBUG, "RetroPlayer: ---------------------------------------");
+ }
+}
diff --git a/xbmc/cores/RetroPlayer/RetroPlayer.h b/xbmc/cores/RetroPlayer/RetroPlayer.h
new file mode 100644
index 0000000000..f4081b89c3
--- /dev/null
+++ b/xbmc/cores/RetroPlayer/RetroPlayer.h
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2012-2016 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 "cores/IPlayer.h"
+#include "cores/VideoPlayer/VideoRenderers/RenderManager.h"
+#include "cores/VideoPlayer/DVDClock.h"
+#include "games/GameTypes.h"
+#include "guilib/DispResource.h"
+#include "threads/CriticalSection.h"
+
+#include <memory>
+
+class CProcessInfo;
+
+namespace GAME
+{
+ class CRetroPlayerAudio;
+ class CRetroPlayerVideo;
+
+ class CRetroPlayer : public IPlayer,
+ public IRenderMsg,
+ public IDispResource
+ {
+ public:
+ CRetroPlayer(IPlayerCallback& callback);
+ virtual ~CRetroPlayer();
+
+ // implementation of IPlayer
+ //virtual bool Initialize(TiXmlElement* pConfig) override { return true; }
+ virtual bool OpenFile(const CFileItem& file, const CPlayerOptions& options) override;
+ //virtual bool QueueNextFile(const CFileItem &file) override { return false; }
+ //virtual void OnNothingToQueueNotify() override { }
+ virtual bool CloseFile(bool reopen = false) override;
+ virtual bool IsPlaying() const override;
+ virtual bool CanPause() override;
+ virtual void Pause() override;
+ virtual bool HasVideo() const override { return true; }
+ virtual bool HasAudio() const override { return true; }
+ virtual bool HasGame() const override { return true; }
+ //virtual bool HasRDS() const override { return false; }
+ //virtual bool IsPassthrough() const override { return false;}
+ virtual bool CanSeek() override;
+ virtual void Seek(bool bPlus = true, bool bLargeStep = false, bool bChapterOverride = false) override;
+ //virtual bool SeekScene(bool bPlus = true) override { return false; }
+ virtual void SeekPercentage(float fPercent = 0) override;
+ virtual float GetPercentage() override;
+ virtual float GetCachePercentage() override;
+ virtual void SetMute(bool bOnOff) override;
+ //virtual void SetVolume(float volume) override { }
+ //virtual void SetDynamicRangeCompression(long drc) override { }
+ //virtual bool CanRecord() override { return false; }
+ //virtual bool IsRecording() override { return false; }
+ //virtual bool Record(bool bOnOff) override { return false; }
+ //virtual void SetAVDelay(float fValue = 0.0f) override { return; }
+ //virtual float GetAVDelay() override { return 0.0f; }
+ //virtual void SetSubTitleDelay(float fValue = 0.0f) override { }
+ //virtual float GetSubTitleDelay() override { return 0.0f; }
+ //virtual int GetSubtitleCount() override { return 0; }
+ //virtual int GetSubtitle() override { return -1; }
+ //virtual void GetSubtitleStreamInfo(int index, SPlayerSubtitleStreamInfo &info) override { }
+ //virtual void SetSubtitle(int iStream) override { }
+ //virtual bool GetSubtitleVisible() override { return false; }
+ //virtual void SetSubtitleVisible(bool bVisible) override { }
+ //virtual void AddSubtitle(const std::string& strSubPath) override { }
+ //virtual int GetAudioStreamCount() override { return 0; }
+ //virtual int GetAudioStream() override { return -1; }
+ //virtual void SetAudioStream(int iStream) override { }
+ //virtual void GetAudioStreamInfo(int index, SPlayerAudioStreamInfo &info) override { }
+ //virtual int GetVideoStream() const override { return -1; }
+ //virtual int GetVideoStreamCount() const override { return 0; }
+ //virtual void GetVideoStreamInfo(int streamId, SPlayerVideoStreamInfo &info) override { }
+ //virtual void SetVideoStream(int iStream) override { }
+ //virtual TextCacheStruct_t* GetTeletextCache() override { return NULL; }
+ //virtual void LoadPage(int p, int sp, unsigned char* buffer) override { }
+ //virtual std::string GetRadioText(unsigned int line) override { return ""; }
+ //virtual int GetChapterCount() override { return 0; }
+ //virtual int GetChapter() override { return -1; }
+ //virtual void GetChapterName(std::string& strChapterName, int chapterIdx = -1) override { return; }
+ //virtual int64_t GetChapterPos(int chapterIdx = -1) override { return 0; }
+ //virtual int SeekChapter(int iChapter) override { return -1; }
+ //virtual float GetActualFPS() override { return 0.0f; }
+ virtual void SeekTime(int64_t iTime = 0) override;
+ virtual bool SeekTimeRelative(int64_t iTime) override;
+ virtual int64_t GetTime() override;
+ //virtual void SetTime(int64_t time) override { } // Only used by Air Tunes Server
+ virtual int64_t GetTotalTime() override;
+ //virtual void SetTotalTime(int64_t time) override { } // Only used by Air Tunes Server
+ //virtual int GetSourceBitrate() override { return 0; }
+ virtual bool GetStreamDetails(CStreamDetails &details) override;
+ virtual void SetSpeed(float speed) override;
+ virtual float GetSpeed() override;
+ //virtual bool SkipNext() override { return false; }
+ //virtual bool IsCaching() const override { return false; }
+ //virtual int GetCacheLevel() const override { return -1; }
+ //virtual bool IsInMenu() const override { return false; }
+ //virtual bool HasMenu() const override { return false; }
+ //virtual void DoAudioWork() override { }
+ //virtual bool OnAction(const CAction &action) override { return false; }
+ virtual std::string GetPlayerState() override;
+ virtual bool SetPlayerState(const std::string& state) override;
+ //virtual std::string GetPlayingTitle() override { return ""; }
+ //virtual bool SwitchChannel(const PVR::CPVRChannelPtr &channel) override { return false; }
+ //virtual void GetAudioCapabilities(std::vector<int> &audioCaps) override { audioCaps.assign(1,IPC_AUD_ALL); }
+ //virtual void GetSubtitleCapabilities(std::vector<int> &subCaps) override { subCaps.assign(1,IPC_SUBS_ALL); }
+ virtual void FrameMove() override { m_renderManager.FrameMove(); }
+ virtual void Render(bool clear, uint32_t alpha = 255, bool gui = true) override { m_renderManager.Render(clear, 0, alpha, gui); }
+ virtual void FlushRenderer() override { m_renderManager.Flush(); }
+ virtual void SetRenderViewMode(int mode) override { m_renderManager.SetViewMode(mode); }
+ virtual float GetRenderAspectRatio() override { return m_renderManager.GetAspectRatio(); }
+ virtual void TriggerUpdateResolution() override { m_renderManager.TriggerUpdateResolution(0.0f, 0, 0); }
+ virtual bool IsRenderingVideo() override { return m_renderManager.IsConfigured(); }
+ virtual bool IsRenderingGuiLayer() override { return m_renderManager.IsGuiLayer(); }
+ virtual bool IsRenderingVideoLayer() override { return m_renderManager.IsVideoLayer(); }
+ virtual bool Supports(EINTERLACEMETHOD method) override;
+ virtual EINTERLACEMETHOD GetDeinterlacingMethodDefault() override;
+ virtual bool Supports(ESCALINGMETHOD method) override { return m_renderManager.Supports(method); }
+ virtual bool Supports(ERENDERFEATURE feature) override { return m_renderManager.Supports(feature); }
+ virtual unsigned int RenderCaptureAlloc() override { return m_renderManager.AllocRenderCapture(); }
+ virtual void RenderCaptureRelease(unsigned int captureId) override { m_renderManager.ReleaseRenderCapture(captureId); }
+ virtual void RenderCapture(unsigned int captureId, unsigned int width, unsigned int height, int flags) override { m_renderManager.StartRenderCapture(captureId, width, height, flags); }
+ virtual bool RenderCaptureGetPixels(unsigned int captureId, unsigned int millis, uint8_t *buffer, unsigned int size) override { return m_renderManager.RenderCaptureGetPixels(captureId, millis, buffer, size); }
+
+ // implementation of IRenderMsg
+ virtual void VideoParamsChange() override { }
+ virtual void GetDebugInfo(std::string &audio, std::string &video, std::string &general) override { }
+ virtual void UpdateClockSync(bool enabled) override;
+ virtual void UpdateRenderInfo(CRenderInfo &info) override;
+
+ // implementation of IDispResource
+ //virtual void OnLostDisplay() override { }
+ //virtual void OnResetDisplay() override { }
+ //virtual void OnAppFocusChange(bool focus) override { }
+
+ private:
+ /**
+ * \brief Dump game information (if any) to the debug log.
+ */
+ void PrintGameInfo(const CFileItem &file) const;
+
+ CDVDClock m_clock;
+ CRenderManager m_renderManager;
+ std::unique_ptr<CProcessInfo> m_processInfo;
+ std::unique_ptr<CRetroPlayerAudio> m_audio;
+ std::unique_ptr<CRetroPlayerVideo> m_video;
+ GameClientPtr m_gameClient;
+ CCriticalSection m_mutex;
+ };
+}
diff --git a/xbmc/cores/RetroPlayer/RetroPlayerAudio.cpp b/xbmc/cores/RetroPlayer/RetroPlayerAudio.cpp
new file mode 100644
index 0000000000..8679b5c790
--- /dev/null
+++ b/xbmc/cores/RetroPlayer/RetroPlayerAudio.cpp
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2012-2016 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 "RetroPlayerAudio.h"
+#include "RetroPlayerDefines.h"
+#include "cores/AudioEngine/AEFactory.h"
+#include "cores/AudioEngine/Interfaces/AEStream.h"
+#include "cores/AudioEngine/Utils/AEChannelInfo.h"
+#include "cores/AudioEngine/Utils/AEUtil.h"
+#include "cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodec.h"
+#include "cores/VideoPlayer/DVDCodecs/DVDFactoryCodec.h"
+#include "cores/VideoPlayer/DVDDemuxers/DVDDemux.h"
+#include "cores/VideoPlayer/DVDClock.h"
+#include "cores/VideoPlayer/DVDStreamInfo.h"
+#include "cores/VideoPlayer/Process/ProcessInfo.h"
+#include "threads/Thread.h"
+#include "utils/log.h"
+
+using namespace GAME;
+
+CRetroPlayerAudio::CRetroPlayerAudio(CProcessInfo& processInfo) :
+ m_processInfo(processInfo),
+ m_pAudioStream(nullptr),
+ m_bAudioEnabled(true)
+{
+}
+
+CRetroPlayerAudio::~CRetroPlayerAudio()
+{
+ CloseStream();
+}
+
+unsigned int CRetroPlayerAudio::NormalizeSamplerate(unsigned int samplerate) const
+{
+ //! @todo List comes from AESinkALSA.cpp many moons ago
+ static unsigned int sampleRateList[] = { 5512, 8000, 11025, 16000, 22050, 32000, 44100, 48000, 0 };
+
+ for (unsigned int *rate = sampleRateList; ; rate++)
+ {
+ const unsigned int thisValue = *rate;
+ const unsigned int nextValue = *(rate + 1);
+
+ if (nextValue == 0)
+ {
+ // Reached the end of our list
+ return thisValue;
+ }
+
+ if (samplerate < (thisValue + nextValue) / 2)
+ {
+ // samplerate is between this rate and the next, so use this rate
+ return thisValue;
+ }
+ }
+
+ return samplerate; // Shouldn't happen
+}
+
+bool CRetroPlayerAudio::OpenPCMStream(AEDataFormat format, unsigned int samplerate, const CAEChannelInfo& channelLayout)
+{
+ if (m_pAudioStream != nullptr)
+ CloseStream();
+
+ CLog::Log(LOGINFO, "RetroPlayerAudio: Creating audio stream, sample rate = %d", samplerate);
+
+ // Resampling is not supported
+ if (NormalizeSamplerate(samplerate) != samplerate)
+ {
+ CLog::Log(LOGERROR, "RetroPlayerAudio: Resampling to %d not supported", NormalizeSamplerate(samplerate));
+ return false;
+ }
+
+ AEAudioFormat audioFormat;
+ audioFormat.m_dataFormat = format;
+ audioFormat.m_sampleRate = samplerate;
+ audioFormat.m_channelLayout = channelLayout;
+ m_pAudioStream = CAEFactory::MakeStream(audioFormat);
+
+ if (!m_pAudioStream)
+ {
+ CLog::Log(LOGERROR, "RetroPlayerAudio: Failed to create audio stream");
+ return false;
+ }
+
+ return true;
+}
+
+bool CRetroPlayerAudio::OpenEncodedStream(AVCodecID codec, unsigned int samplerate, const CAEChannelInfo& channelLayout)
+{
+ CDemuxStreamAudio audioStream;
+
+ // Stream
+ audioStream.uniqueId = GAME_STREAM_AUDIO_ID;
+ audioStream.codec = codec;
+ audioStream.type = STREAM_AUDIO;
+ audioStream.source = STREAM_SOURCE_DEMUX;
+ audioStream.realtime = true;
+
+ // Audio
+ audioStream.iChannels = channelLayout.Count();
+ audioStream.iSampleRate = samplerate;
+ audioStream.iChannelLayout = CAEUtil::GetAVChannelLayout(channelLayout);
+
+ CDVDStreamInfo hint(audioStream);
+ m_pAudioCodec.reset(CDVDFactoryCodec::CreateAudioCodec(hint, m_processInfo, false));
+
+ if (!m_pAudioCodec)
+ {
+ CLog::Log(LOGERROR, "RetroPlayerAudio: Failed to create audio codec (codec=%d, samplerate=%u)", codec, samplerate);
+ return false;
+ }
+
+ return true;
+}
+
+void CRetroPlayerAudio::AddData(const uint8_t* data, unsigned int size)
+{
+ if (m_bAudioEnabled)
+ {
+ if (m_pAudioCodec)
+ {
+ int consumed = m_pAudioCodec->Decode(const_cast<uint8_t*>(data), size, DVD_NOPTS_VALUE, DVD_NOPTS_VALUE);
+ if (consumed < 0)
+ {
+ CLog::Log(LOGERROR, "CRretroPlayerAudio::AddData - Decode Error (%d)", consumed);
+ m_pAudioCodec.reset();
+ return;
+ }
+
+ DVDAudioFrame audioframe;
+ m_pAudioCodec->GetData(audioframe);
+
+ if (audioframe.nb_frames != 0)
+ {
+ // Open audio stream if not already open
+ if (!m_pAudioStream)
+ {
+ const AEAudioFormat& format = audioframe.format;
+ if (!OpenPCMStream(format.m_dataFormat, format.m_sampleRate, format.m_channelLayout))
+ m_pAudioCodec.reset();
+ }
+
+ if (m_pAudioStream)
+ m_pAudioStream->AddData(audioframe.data, 0, audioframe.nb_frames);
+ }
+ }
+ else if (m_pAudioStream)
+ {
+ const unsigned int frameSize = m_pAudioStream->GetChannelCount() * (CAEUtil::DataFormatToBits(m_pAudioStream->GetDataFormat()) >> 3);
+ m_pAudioStream->AddData(&data, 0, size / frameSize);
+ }
+ }
+}
+
+void CRetroPlayerAudio::CloseStream()
+{
+ if (m_pAudioCodec)
+ {
+ m_pAudioCodec->Dispose();
+ m_pAudioCodec.reset();
+ }
+ if (m_pAudioStream)
+ {
+ CAEFactory::FreeStream(m_pAudioStream);
+ m_pAudioStream = nullptr;
+ }
+}
diff --git a/xbmc/cores/RetroPlayer/RetroPlayerAudio.h b/xbmc/cores/RetroPlayer/RetroPlayerAudio.h
new file mode 100644
index 0000000000..c7913e292b
--- /dev/null
+++ b/xbmc/cores/RetroPlayer/RetroPlayerAudio.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2012-2016 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 "games/addons/GameClientCallbacks.h"
+
+#include <memory>
+
+class CDVDAudioCodec;
+class CProcessInfo;
+class IAEStream;
+
+namespace GAME
+{
+ class CRetroPlayerAudio : public IGameAudioCallback
+ {
+ public:
+ CRetroPlayerAudio(CProcessInfo& processInfo);
+ virtual ~CRetroPlayerAudio();
+
+ // implementation of IGameAudioCallback
+ virtual unsigned int NormalizeSamplerate(unsigned int samplerate) const override;
+ virtual bool OpenPCMStream(AEDataFormat format, unsigned int samplerate, const CAEChannelInfo& channelLayout) override;
+ virtual bool OpenEncodedStream(AVCodecID codec, unsigned int samplerate, const CAEChannelInfo& channelLayout) override;
+ virtual void AddData(const uint8_t* data, unsigned int size) override;
+ virtual void CloseStream() override;
+
+ void Enable(bool bEnabled) { m_bAudioEnabled = bEnabled; }
+
+ private:
+ CProcessInfo& m_processInfo;
+ IAEStream* m_pAudioStream;
+ std::unique_ptr<CDVDAudioCodec> m_pAudioCodec;
+ bool m_bAudioEnabled;
+ };
+}
diff --git a/xbmc/cores/RetroPlayer/RetroPlayerDefines.h b/xbmc/cores/RetroPlayer/RetroPlayerDefines.h
new file mode 100644
index 0000000000..092aa24816
--- /dev/null
+++ b/xbmc/cores/RetroPlayer/RetroPlayerDefines.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2016 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
+
+#define GAME_STREAM_VIDEO_ID 1
+#define GAME_STREAM_AUDIO_ID 2
diff --git a/xbmc/cores/RetroPlayer/RetroPlayerVideo.cpp b/xbmc/cores/RetroPlayer/RetroPlayerVideo.cpp
new file mode 100644
index 0000000000..0eff2b078e
--- /dev/null
+++ b/xbmc/cores/RetroPlayer/RetroPlayerVideo.cpp
@@ -0,0 +1,226 @@
+/*
+ * Copyright (C) 2012-2016 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 "RetroPlayerVideo.h"
+#include "RetroPlayerDefines.h"
+#include "PixelConverter.h"
+#include "PixelConverterRBP.h"
+#include "cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodec.h"
+#include "cores/VideoPlayer/DVDCodecs/DVDCodecUtils.h"
+#include "cores/VideoPlayer/DVDCodecs/DVDFactoryCodec.h"
+#include "cores/VideoPlayer/DVDDemuxers/DVDDemux.h"
+#include "cores/VideoPlayer/VideoRenderers/RenderFlags.h"
+#include "cores/VideoPlayer/VideoRenderers/RenderManager.h"
+#include "cores/VideoPlayer/DVDStreamInfo.h"
+#include "utils/log.h"
+
+#include <atomic> //! @todo
+
+using namespace GAME;
+
+CRetroPlayerVideo::CRetroPlayerVideo(CDVDClock& clock, CRenderManager& renderManager, CProcessInfo& processInfo) :
+ //CThread("RetroPlayerVideo"),
+ m_clock(clock),
+ m_renderManager(renderManager),
+ m_processInfo(processInfo),
+ m_framerate(0.0),
+ m_orientation(0),
+ m_bConfigured(false),
+ m_droppedFrames(0)
+{
+ m_renderManager.PreInit();
+}
+
+CRetroPlayerVideo::~CRetroPlayerVideo()
+{
+ CloseStream();
+ m_renderManager.UnInit();
+}
+
+bool CRetroPlayerVideo::OpenPixelStream(AVPixelFormat pixfmt, unsigned int width, unsigned int height, double framerate, unsigned int orientationDeg)
+{
+ CLog::Log(LOGINFO, "RetroPlayerVideo: Creating video stream with pixel format: %i, %dx%d", pixfmt, width, height);
+
+ m_framerate = framerate;
+ m_orientation = orientationDeg;
+ m_bConfigured = false;
+ m_droppedFrames = 0;
+
+#ifdef TARGET_RASPBERRY_PI
+ m_pixelConverter.reset(new CPixelConverterRBP);
+#else
+ m_pixelConverter.reset(new CPixelConverter);
+#endif
+
+ if (m_pixelConverter->Open(pixfmt, AV_PIX_FMT_YUV420P, width, height))
+ {
+ //! @todo
+ //m_processInfo.SetVideoPixelFormat(CDVDVideoCodecFFmpeg::GetPixelFormatName(pixfmt));
+ m_processInfo.SetVideoDimensions(width, height);
+ m_processInfo.SetVideoFps(static_cast<float>(framerate));
+ return true;
+ }
+
+ m_pixelConverter.reset();
+
+ return false;
+}
+
+bool CRetroPlayerVideo::OpenEncodedStream(AVCodecID codec)
+{
+ CDemuxStreamVideo videoStream;
+
+ // Stream
+ videoStream.uniqueId = GAME_STREAM_VIDEO_ID;
+ videoStream.codec = codec;
+ videoStream.type = STREAM_VIDEO;
+ videoStream.source = STREAM_SOURCE_DEMUX;
+ videoStream.realtime = true;
+
+ // Video
+ //! @todo Needed?
+ /*
+ videoStream.iFpsScale = 1000;
+ videoStream.iFpsRate = static_cast<int>(framerate * 1000);
+ videoStream.iHeight = height;
+ videoStream.iWidth = width;
+ videoStream.fAspect = static_cast<float>(width) / static_cast<float>(height);
+ videoStream.iOrientation = orientationDeg;
+ */
+
+ CDVDStreamInfo hint(videoStream);
+ m_pVideoCodec.reset(CDVDFactoryCodec::CreateVideoCodec(hint, m_processInfo, m_renderManager.GetRenderInfo()));
+
+ return m_pVideoCodec.get() != nullptr;
+}
+
+void CRetroPlayerVideo::AddData(const uint8_t* data, unsigned int size)
+{
+ DVDVideoPicture picture = { };
+
+ if (GetPicture(data, size, picture))
+ {
+ if (!Configure(picture))
+ {
+ CLog::Log(LOGERROR, "RetroPlayerVideo: Failed to configure renderer");
+ CloseStream();
+ }
+ else
+ {
+ SendPicture(picture);
+ }
+ }
+}
+
+void CRetroPlayerVideo::CloseStream()
+{
+ m_renderManager.Flush();
+ m_pixelConverter.reset();
+ m_pVideoCodec.reset();
+}
+
+bool CRetroPlayerVideo::Configure(DVDVideoPicture& picture)
+{
+ if (!m_bConfigured)
+ {
+ // Determine RenderManager flags
+ unsigned int flags = CONF_FLAGS_YUVCOEF_BT601 | // color_matrix = 4
+ CONF_FLAGS_FULLSCREEN; // Allow fullscreen
+
+ const int buffers = 1; //! @todo
+
+ m_bConfigured = m_renderManager.Configure(picture, static_cast<float>(m_framerate), flags, m_orientation, buffers);
+
+ if (m_bConfigured)
+ {
+ // Update process info
+ AVPixelFormat pixfmt = static_cast<AVPixelFormat>(CDVDCodecUtils::PixfmtFromEFormat(picture.format));
+ if (pixfmt != AV_PIX_FMT_NONE)
+ {
+ //! @todo
+ //m_processInfo.SetVideoPixelFormat(CDVDVideoCodecFFmpeg::GetPixelFormatName(pixfmt));
+ }
+ m_processInfo.SetVideoDimensions(picture.iWidth, picture.iHeight);
+ m_processInfo.SetVideoFps(static_cast<float>(m_framerate));
+ }
+ }
+
+ return m_bConfigured;
+}
+
+bool CRetroPlayerVideo::GetPicture(const uint8_t* data, unsigned int size, DVDVideoPicture& picture)
+{
+ bool bHasPicture = false;
+
+ if (m_pixelConverter)
+ {
+ int lateframes;
+ double renderPts;
+ int queued, discard;
+ m_renderManager.GetStats(lateframes, renderPts, queued, discard);
+
+ // Drop frame if another is queued
+ const bool bDropped = (queued > 0);
+
+ if (!bDropped)
+ {
+ if (m_pixelConverter->Decode(data, size))
+ {
+ m_pixelConverter->GetPicture(picture);
+ bHasPicture = true;
+ }
+ }
+ }
+ else if (m_pVideoCodec)
+ {
+ int iDecoderState = m_pVideoCodec->Decode(const_cast<uint8_t*>(data), size, DVD_NOPTS_VALUE, DVD_NOPTS_VALUE);
+ if (iDecoderState & VC_PICTURE)
+ {
+ m_pVideoCodec->ClearPicture(&picture);
+
+ if (m_pVideoCodec->GetPicture(&picture))
+ {
+ // Drop frame if requested by the decoder
+ const bool bDropped = (picture.iFlags & DVP_FLAG_DROPPED) != 0;
+
+ if (!bDropped)
+ bHasPicture = true;
+ }
+ }
+ }
+
+ return bHasPicture;
+}
+
+void CRetroPlayerVideo::SendPicture(DVDVideoPicture& picture)
+{
+ std::atomic_bool bAbortOutput(false); //! @todo
+
+ int index = m_renderManager.AddVideoPicture(picture);
+ if (index < 0)
+ {
+ // Video device might not be done yet, drop the frame
+ m_droppedFrames++;
+ }
+ else
+ {
+ m_renderManager.FlipPage(bAbortOutput, 0.0, VS_INTERLACEMETHOD_NONE, FS_NONE, false);
+ }
+}
diff --git a/xbmc/cores/RetroPlayer/RetroPlayerVideo.h b/xbmc/cores/RetroPlayer/RetroPlayerVideo.h
new file mode 100644
index 0000000000..f9dc3ea94a
--- /dev/null
+++ b/xbmc/cores/RetroPlayer/RetroPlayerVideo.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2012-2016 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 "games/addons/GameClientCallbacks.h"
+//#include "threads/Thread.h"
+
+#include <memory>
+
+class CDVDClock;
+class CDVDVideoCodec;
+class CPixelConverter;
+class CProcessInfo;
+class CRenderManager;
+struct DVDVideoPicture;
+
+namespace GAME
+{
+ class CRetroPlayerVideo : public IGameVideoCallback
+ //protected CThread
+ {
+ public:
+ CRetroPlayerVideo(CDVDClock& m_clock, CRenderManager& m_renderManager, CProcessInfo& m_processInfo);
+
+ virtual ~CRetroPlayerVideo();
+
+ // implementation of IGameVideoCallback
+ virtual bool OpenPixelStream(AVPixelFormat pixfmt, unsigned int width, unsigned int height, double framerate, unsigned int orientationDeg) override;
+ virtual bool OpenEncodedStream(AVCodecID codec) override;
+ virtual void AddData(const uint8_t* data, unsigned int size) override;
+ virtual void CloseStream() override;
+
+ /*
+ protected:
+ // implementation of CThread
+ virtual void Process(void);
+ */
+
+ private:
+ bool Configure(DVDVideoPicture& picture);
+ bool GetPicture(const uint8_t* data, unsigned int size, DVDVideoPicture& picture);
+ void SendPicture(DVDVideoPicture& picture);
+
+ // Construction parameters
+ CDVDClock& m_clock;
+ CRenderManager& m_renderManager;
+ CProcessInfo& m_processInfo;
+
+ // Stream properties
+ double m_framerate;
+ unsigned int m_orientation; // Degrees counter-clockwise
+ bool m_bConfigured; // Need first picture to configure the render manager
+ unsigned int m_droppedFrames;
+ std::unique_ptr<CPixelConverter> m_pixelConverter;
+ std::unique_ptr<CDVDVideoCodec> m_pVideoCodec;
+ };
+}
diff --git a/xbmc/cores/playercorefactory/PlayerCoreConfig.h b/xbmc/cores/playercorefactory/PlayerCoreConfig.h
index 15a6570a27..69b14eda13 100644
--- a/xbmc/cores/playercorefactory/PlayerCoreConfig.h
+++ b/xbmc/cores/playercorefactory/PlayerCoreConfig.h
@@ -24,6 +24,7 @@
#include "PlayerCoreFactory.h"
#include "cores/VideoPlayer/VideoPlayer.h"
#include "cores/paplayer/PAPlayer.h"
+#include "cores/RetroPlayer/RetroPlayer.h"
#include "cores/ExternalPlayer/ExternalPlayer.h"
#ifdef HAS_UPNP
#include "network/upnp/UPnPPlayer.h"
@@ -93,6 +94,10 @@ public:
{
pPlayer = new PAPlayer(callback);
}
+ else if (m_type.compare("game") == 0)
+ {
+ pPlayer = new GAME::CRetroPlayer(callback);
+ }
else if (m_type.compare("external") == 0)
{
pPlayer = new CExternalPlayer(callback);
diff --git a/xbmc/cores/playercorefactory/PlayerCoreFactory.cpp b/xbmc/cores/playercorefactory/PlayerCoreFactory.cpp
index 896b865895..9abf1cbd76 100644
--- a/xbmc/cores/playercorefactory/PlayerCoreFactory.cpp
+++ b/xbmc/cores/playercorefactory/PlayerCoreFactory.cpp
@@ -116,9 +116,9 @@ void CPlayerCoreFactory::GetPlayers(const CFileItem& item, std::vector<std::stri
// Process defaults
- // Set video default player. Check whether it's video first (overrule audio check)
- // Also push these players in case it is NOT audio either
- if (item.IsVideo() || !item.IsAudio())
+ // Set video default player. Check whether it's video first (overrule audio and
+ // game check). Also push these players in case it is NOT audio or game either.
+ if (item.IsVideo() || (!item.IsAudio() && !item.IsGame()))
{
int idx = GetPlayerIndex("videodefaultplayer");
if (idx > -1)
@@ -146,6 +146,12 @@ void CPlayerCoreFactory::GetPlayers(const CFileItem& item, std::vector<std::stri
GetPlayers(players, true, true); // Audio & video players
}
+ if (item.IsGame())
+ {
+ CLog::Log(LOGDEBUG, "CPlayerCoreFactory::GetPlayers: adding retroplayer");
+ players.push_back("RetroPlayer");
+ }
+
CLog::Log(LOGDEBUG, "CPlayerCoreFactory::GetPlayers: added %" PRIuS" players", players.size());
}
@@ -323,6 +329,9 @@ bool CPlayerCoreFactory::LoadConfiguration(const std::string &file, bool clear)
CPlayerCoreConfig* paplayer = new CPlayerCoreConfig("PAPlayer", "music", nullptr);
paplayer->m_bPlaysAudio = true;
m_vecPlayerConfigs.push_back(paplayer);
+
+ CPlayerCoreConfig* retroPlayer = new CPlayerCoreConfig("RetroPlayer", "game", nullptr);
+ m_vecPlayerConfigs.push_back(retroPlayer);
}
if (!pConfig || strcmpi(pConfig->Value(), "playercorefactory") != 0)
diff --git a/xbmc/guilib/GUIWindowManager.cpp b/xbmc/guilib/GUIWindowManager.cpp
index d1ffc1f736..53aec7e604 100644
--- a/xbmc/guilib/GUIWindowManager.cpp
+++ b/xbmc/guilib/GUIWindowManager.cpp
@@ -678,6 +678,15 @@ void CGUIWindowManager::PreviousWindow()
// ok to go to the previous window now
+ // pause game when leaving fullscreen or resume game when entering fullscreen
+ if (g_application.m_pPlayer->IsPlayingGame())
+ {
+ if (previousWindow == WINDOW_FULLSCREEN_VIDEO && g_application.m_pPlayer->IsPaused())
+ g_application.OnAction(ACTION_PAUSE);
+ else if (currentWindow == WINDOW_FULLSCREEN_VIDEO && !g_application.m_pPlayer->IsPaused())
+ g_application.OnAction(ACTION_PAUSE);
+ }
+
// tell our info manager which window we are going to
g_infoManager.SetNextWindow(previousWindow);
@@ -790,6 +799,15 @@ void CGUIWindowManager::ActivateWindow_Internal(int iWindowID, const std::vector
return;
}
+ // pause game when leaving fullscreen or resume game when entering fullscreen
+ if (g_application.m_pPlayer->IsPlayingGame())
+ {
+ if (GetActiveWindow() == WINDOW_FULLSCREEN_VIDEO && !g_application.m_pPlayer->IsPaused())
+ g_application.OnAction(ACTION_PAUSE);
+ else if (iWindowID == WINDOW_FULLSCREEN_VIDEO && g_application.m_pPlayer->IsPaused())
+ g_application.OnAction(ACTION_PAUSE);
+ }
+
g_infoManager.SetNextWindow(iWindowID);
// deactivate any window
@@ -1406,6 +1424,9 @@ int CGUIWindowManager::GetActiveWindowID()
// special casing for numeric seek
else if (CSeekHandler::GetInstance().HasTimeCode())
iWin = WINDOW_VIDEO_TIME_SEEK;
+ // check if a game is playing
+ else if (g_application.m_pPlayer->IsPlayingGame())
+ iWin = WINDOW_FULLSCREEN_GAME;
}
if (iWin == WINDOW_VISUALISATION)
{
diff --git a/xbmc/input/ButtonTranslator.cpp b/xbmc/input/ButtonTranslator.cpp
index e882c2a73c..06a0ec3ab1 100644
--- a/xbmc/input/ButtonTranslator.cpp
+++ b/xbmc/input/ButtonTranslator.cpp
@@ -391,6 +391,7 @@ static const ActionMapping windows[] =
{ "fullscreenvideo" , WINDOW_FULLSCREEN_VIDEO },
{ "fullscreenlivetv" , WINDOW_FULLSCREEN_LIVETV }, // virtual window/keymap section for PVR specific bindings in fullscreen playback (which internally uses WINDOW_FULLSCREEN_VIDEO)
{ "fullscreenradio" , WINDOW_FULLSCREEN_RADIO }, // virtual window for fullscreen radio, uses WINDOW_VISUALISATION as fallback
+ { "fullscreengame" , WINDOW_FULLSCREEN_GAME }, // virtual window for fullscreen games, uses WINDOW_FULLSCREEN_VIDEO as fallback
{ "visualisation" , WINDOW_VISUALISATION },
{ "slideshow" , WINDOW_SLIDESHOW },
{ "weather" , WINDOW_WEATHER },
@@ -444,7 +445,8 @@ static const ActionMapping touchcommands[] =
static const WindowMapping fallbackWindows[] =
{
{ WINDOW_FULLSCREEN_LIVETV , WINDOW_FULLSCREEN_VIDEO },
- { WINDOW_FULLSCREEN_RADIO , WINDOW_VISUALISATION }
+ { WINDOW_FULLSCREEN_RADIO , WINDOW_VISUALISATION },
+ { WINDOW_FULLSCREEN_GAME , WINDOW_FULLSCREEN_VIDEO }
};
#ifdef TARGET_WINDOWS
diff --git a/xbmc/windows/GUIWindowFileManager.cpp b/xbmc/windows/GUIWindowFileManager.cpp
index 547507fbfb..20ac6f9bf7 100644
--- a/xbmc/windows/GUIWindowFileManager.cpp
+++ b/xbmc/windows/GUIWindowFileManager.cpp
@@ -617,7 +617,7 @@ void CGUIWindowFileManager::OnStart(CFileItem *pItem, const std::string &player)
g_application.ProcessAndStartPlaylist(strPlayList, *pPlayList, PLAYLIST_MUSIC);
return;
}
- if (pItem->IsAudio() || pItem->IsVideo())
+ if (pItem->IsAudio() || pItem->IsVideo() || pItem->IsGame())
{
g_application.PlayFile(*pItem, player);
return ;