xbmc/xbmc — pull request #3335 by garbear (2013-09-26 22:18:00+00:00)
Title: RetroPlayer proof-of-concept

RetroPlayer is a new player core that allows xbmc to play retro arcade games. RetroPlayer is a frontend for libretro (https://github.com/libretro/RetroArch/blob/master/libretro.h), an API created so that the hassle of porting X emulators to Y systems can be consolidated via a single interface (the reference front-end, RetroArch, supports virtually every console and OS, including Android). This PR only includes Linux and Win32 support.

**The PR is broken down as follows:**
* 1. https://github.com/xbmc/xbmc/pull/2370 (Joystick API) abstracts joystick handling, and adds Linux Joystick API and Microsoft XInput support. This PR is a work-in-progress. More work is needed until the API reaches the quality of the Settings API and the Network Manager PR.
* 2. Game Info Tags solve the problem of extension clashes with AV files (.bin, .iso, etc). In the future, this will be accomplished by a python-based info loader I wrote named [PyRomInfo](https://github.com/garbear/pyrominfo). ROMs for most platforms contain magic words, which will PyRomInfo can sniff to determine the platform. Most ROMs also include the game title, publisher, unique game ID, etc embedded in the data, which PyRomInfo is able to extract. Game scraper sites, such as http://thegamesdb.net, can use the game ID to return 1:1 matches and avoid fuzzy title-based guesswork.
* 3. Game clients - these are libretro emulator binaries. RetroPlayer is capable of directly loading unmodified RetroArch game clients from https://github.com/libretro. The libretro API has serveral limitations. For example, as RetroArch is written in C, there is no context support, so all callbacks must be static functions and thus only 1 game client can be loaded at once. (Also, a call is needed to query the number of controllers, among other things.) Before this is merged, I recommend collaborating on a v2 of the libretro API that addresses these limitations.
* 4. RetroPlayer - libretro is essentially some functions for passing rendered 16-bit audio and RGB data to the front-end. Drawing inspiration from DVDPlayer, I wrote a new core to render this AV data in a quasi-similar manner. One thing to note is the single class for both audio and video buffers, which encapsulates the thread-safety, accompanying frame metadata, and memory management in a single class. RetroPlayer provides just-in-time game client installation -- more on this later.
* 5. RetroPlayerInput - Handles the input. I broke this out into a separate commit so that the hooks added throughout the code can be easily viewed. See libretro.h for more info on input devices.
* 6. Game Add-ons - for now only scripts are supported (I think). As a portion of libretro cores can load files from memory, eventually plugins can provide public domain ROMs ([see thread](http://forum.xbmc.org/showthread.php?tid=173355)) directly over http.
* 7. MyGames window - modeled after MyVideos window, root node contains Game Sources and Game Add-ons. In the future, game library items (platform, title, publisher, player count) will show up under the root node.

**Overview/features, in no particular order:**
* 1. Just-in-time emulator installation drastically reduces the setup time. Simply add a source, hit enter on a ROM, and RetroPlayer will guide the user through the installation process. In order to recognize games by extension, RetroPlayer generates the extension mask from the add-ons listed in remote repos (extensions are listed in addon.xml). When enter is hit on a ROM, a list of compatible emulators (see next bullet) is presented to the user if none are installed. The user can then go to the add-on manager, or install an emulator. If an emulator is installed, the game is then launched using that emulator. If the user goes to the add-on manager, and installs a compatible emulator from there, RetroPlayer will intelligently ask the user if they would like to continue launching the ROM.
* 2. ROM compatibility is determined by several factors. Most emulators list extensions and/or supported platforms in their addon.xml. The extension and game info tag platform is screened against these. Some emulators support loading files from memory (VFS), while others require an absolute (possibly local) path and implement their own file input mechanism. Ideally, most emulators should be patched to short-circuit the file loading and support load-from-vfs. Furthermore, some emulators can load ZIPs, yet others that support loading from memory must load the game *within* the zip when the zip when the zip is "played". The entire loading/compatibility logic is contained within a separate class, GameFileLoader.
* 3. Real-time rewind (also known as Baid-style) is supported for some emulators. This works by the emulator reporting a serialized state of the game at each frame. The states are then XORed together for space efficiency, and buffered over 60 seconds. As a result, the user can use the seek bar to rewind an arbitrary number of seconds, or hit the rewind key on the remote to roll back history. In my development branch (not included in this PR) is a save-state manager based on snapshots of these serialized states (includes auto-save functionality). A quick guess, from the OS's resource manager, showed that 60 seconds of a SNES emulator's history (at 60fps) used a little over 100MB of RAM.
* 4. Fast-forward is implemented by progressing through frames as fast as possible (my core i7 can do 4x on some emulators). 32x will need a *really* fast computer. Frame skipping is not supported, nor is it currently possible with the libretro API.
* 5. Some emulators require a "system directory" for things like BIOSes, etc. If the emulator asks for a system directory, RetroPlayer will prompt the user on game load. Once set, the system directory can be changed in the emulator's add-on settings.
* 6. Libretro allows per-emulator settings, which RetroPlayer hasn't implemented (yet). HACK: Because any emulator can ask for a system directory, I dynamically add this setting in LoadSettings() (so that identical settings.xml files can be avoided for every emulator).
* 7. Key maps can be configured by the standard XML process. Because the keyboard X is mapped to a gamepad button, games can be quit using backspace.
* 8. Emulator repositories are hosted at https://github.com/garbear/repository.libretro. Linux comes with only 64-bit emus, but the 32-bit repo can be installed from within the add-on manager (requires a restart). I expect this hackjob to go away with binary add-ons.
* 9. Loading ROMs can sometimes be a crapshoot. Not all emulators in the repos work (and some segfault under certain conditions). Reports of broken/working emus can be found in the [RetroPlayer Subforum](http://forum.xbmc.org/forumdisplay.php?fid=194).
* 10. As a final note, the last refactor might have changes the game client DLL manager. Some emulators are registered twice (harmless), and I received one report on the forum about a NULL game client DLL shared pointer. This might need some inspection.

Much more info can be found in the [RetroPlayer Subforum](http://forum.xbmc.org/forumdisplay.php?fid=194).