diff options
Diffstat (limited to 'debian')
104 files changed, 27862 insertions, 0 deletions
diff --git a/debian/README.Debian b/debian/README.Debian new file mode 100644 index 0000000..d5dda4c --- /dev/null +++ b/debian/README.Debian @@ -0,0 +1,24 @@ +Kodi from Debian +---------------- + +This package is different from the package you can build from the Kodi source +you can download from https://kodi.tv (vanilla Kodi, from now on). + +This package uses external libraries such as libav distributed in Debian, while +the XBMC project suggests using the libraries embedded in vanilla Kodi's source. + +This difference may cause problems not experienced with vanilla Kodi thus you +are kindly asked not to report bugs directly to https://kodi.tv, but to +Debian's Bug Tracking System (BTS): + + https://bugs.debian.org/src:kodi + +You can get an overview of the package at Debian Tracker: + + https://tracker.debian.org/kodi + +or ask your queestions in Debian Multimedia mailing list by e-mail: + + debian-multimedia@lists.debian.org + + -- Vasyl Gello <vasek.gello@gmail.com>, Fri, 13 Nov 2020 10:00:00 +0300 diff --git a/debian/README.source b/debian/README.source new file mode 100644 index 0000000..70b0b61 --- /dev/null +++ b/debian/README.source @@ -0,0 +1,32 @@ +Kodi used to embed dvdread and dvdnav in its source but the developers switched to +downloading it which is not an option for Debian source packages. The embedded +copy of both libraries is retrieved from VideoLAN upstream by watchfile and the +required Debian patches are applied (debian/patches/libdvd{read,nav}-*.patch). + +Kodi replaced the default webinterface in 17.0 beta6 but the new interface contains +many generated files without providing the source for them. The web interface +is temporarily reverted to the one included in beta5 to restore GPL compliance. + +The web interface is placed in debian patch folder (debian/webinterface-default) +and is copied in autoconf override because quilt patches can not handle git binary +diffs. + +The cdatetime-std-chrono patch set, available as upstream PR: + + https://github.com/xbmc/xbmc/pull/18727 + +is a refactored date and time conversion logic in Kodi, that fixes the totally +broken current implementation for 32-bit architectures (i386, mipsel). +It should have been added to 19.0 but upstream authors decided to postpond it +until 20.0 development cycle starts. I decided to include it in Debian release +nonetheless along with embedded date library (embedded-libdate-tz) from Howard +Hinnant: + + https://github.com/Howardhinnant/date + +It does not make sense to package libdate-tz separately because it is partially +accepted as upcoming C++20 standard and eventually kodi will move to C++20 in +20.0 or 21.0. Upstream author also expects the library to be embedded in project, +reasoning of "poor CMake support" (see upstream issues). + + -- Vasyl Gello <vasek.gello@gmail.com>, Tue, 3 Jun 2020 10:30:00 +0300 diff --git a/debian/changelog b/debian/changelog new file mode 100644 index 0000000..168cc81 --- /dev/null +++ b/debian/changelog @@ -0,0 +1,1241 @@ +kodi (2:20.4+dfsg-1) unstable; urgency=medium + + * New upstream version 20.4+dfsg + + -- Vasyl Gello <vasek.gello@gmail.com> Sun, 11 Feb 2024 07:12:03 +0000 + +kodi (2:20.3+dfsg-1) unstable; urgency=medium + + * New upstream version 20.3+dfsg (Closes: #1061600) + * Build with APP_RENDER_SYSTEM=gles for arm platforms (Closes: #1056563) + * Add pcre2 patch (Closes: #1000113) + * Add workaround for LoongArch (Closes: #1054463) + * Drop obsolete font metapackages from deps (Closes: #1050052) + * Drop patches merged upstream + * Update cdatetime-std-chrono patchset + + -- Vasyl Gello <vasek.gello@gmail.com> Sat, 03 Feb 2024 13:51:04 +0000 + +kodi (2:20.2+dfsg-4) unstable; urgency=medium + + * Add patch to fix crash with ffmpeg6 + * Fix FTBFS on s390x (Closes: #1043128) + + -- Vasyl Gello <vasek.gello@gmail.com> Sun, 06 Aug 2023 08:31:29 +0000 + +kodi (2:20.2+dfsg-3) unstable; urgency=medium + + * Revert language pack patches for now to land + in unstable + + -- Vasyl Gello <vasek.gello@gmail.com> Fri, 04 Aug 2023 23:26:08 +0000 + +kodi (2:20.2+dfsg-2) unstable; urgency=medium + + * d/gbp.conf: Drop unnecessary upstream-branch + * debian: switch to DEP-14 git branch naming scheme + * Prepare for language pack separation + * Separate language packs (Closes: #1042996) + * Fix build against FFmpeg 6.0 (Closes: #1041400) + * Add patch for CD/DVD playback without mount support + + -- Vasyl Gello <vasek.gello@gmail.com> Fri, 04 Aug 2023 19:25:39 +0000 + +kodi (2:20.2+dfsg-1) unstable; urgency=medium + + * New upstream version 20.2+dfsg + + -- Vasyl Gello <vasek.gello@gmail.com> Mon, 03 Jul 2023 08:50:21 +0000 + +kodi (2:20.1+dfsg-1) unstable; urgency=medium + + * New upstream version 20.1+dfsg + * Refresh cdatetime-std-chrono patchset + * Drop patches merged upstream + + -- Vasyl Gello <vasek.gello@gmail.com> Sun, 12 Mar 2023 09:31:18 +0000 + +kodi (2:20.0+dfsg-2) unstable; urgency=high + + * s/gbp.conf: Switch to versioned upstream branches + * Fix CVE-2023-23082 (Closes: #1031048) + + -- Vasyl Gello <vasek.gello@gmail.com> Mon, 13 Feb 2023 10:43:13 +0000 + +kodi (2:20.0+dfsg-1) unstable; urgency=medium + + * New upstream version 20.0+dfsg + * d/rules: Add alpha and arm64 overrides + * Refresh ports patch + * Refresh libdvd patch + * Refresh cdatetime-std-chrono patchset + * Drop patches merged upstream + * Refresh ffmpeg5 patch + + -- Vasyl Gello <vasek.gello@gmail.com> Sat, 21 Jan 2023 18:03:44 +0000 + +kodi (2:20.0~rc2+dfsg-2) unstable; urgency=medium + + * d/rules: Declare ports architectures + * Add patch to build on ports architectures + * Refresh ffmpeg5 patch + * Patch DoS vulnerability awaiting for CVE + + -- Vasyl Gello <vasek.gello@gmail.com> Thu, 05 Jan 2023 07:24:56 +0000 + +kodi (2:20.0~rc2+dfsg-1) unstable; urgency=medium + + * New upstream version 20.0~rc2+dfsg + * d/control: Add B+R on kodi-addons-dev + * d/control: Bump standards version (no changes required) + * d/copyright: Bump copyright years + * Drop patches merged upstream + + -- Vasyl Gello <vasek.gello@gmail.com> Mon, 19 Dec 2022 19:06:13 +0000 + +kodi (2:20.0~rc1+dfsg1-1) unstable; urgency=medium + + * New upstream version 20.0~rc1+dfsg1 + * Drop obsolete build dependency libgl1-mesa-dev + * Add Breaks/Replaces to kodi-addons-dev fixing piuparts failure + in stable2sid + * Add copyright entries for embedded libdvd* + * Drop copyright entry for libdate-tz-embedded and several + other extinct paths + * Fix the missing manpage after move of /usr/bin/dh_kodiaddon_depends + * Add patches for bashisms in kodi.sh + * Add descriptions to workaround patches + * Use +dfsg instead of +dfsg1 in watchfile + * Add workaround patches addressing removal of EGL Chromium headerfile + in Mesa 22.3.0 anda regression of playlist detection in Kodi 20 RC1 + * Refresh cdatetime patchset fixing broken test spotted during + reproducibility test + * Fix placement of zeroconf wrapper + * Drop old NEWS entry about systemd integration + + -- Vasyl Gello <vasek.gello@gmail.com> Tue, 13 Dec 2022 15:04:25 +0000 + +kodi (2:20.0~beta1+dfsg1-2) unstable; urgency=medium + + * d/rules: Add installable dummy file to kodi/system + * Add workaround to fix crossbuilds + + -- Vasyl Gello <vasek.gello@gmail.com> Wed, 09 Nov 2022 21:16:07 +0000 + +kodi (2:20.0~beta1+dfsg1-1) unstable; urgency=medium + + * New upstream version 20.0~beta1+dfsg1 + * Refresh cdatetime patchset + * Refresh kodi and libdvdread patchsets + * Refresh ffmpeg5 patchset + + -- Vasyl Gello <vasek.gello@gmail.com> Tue, 08 Nov 2022 19:44:52 +0000 + +kodi (2:20.0~alpha3+git20221015.976c5c8+dfsg1-1) unstable; urgency=medium + + * New upstream version 20.0~alpha3+git20221015.976c5c8+dfsg1 + * Ship firewalld files (Closes: #1015956) + * Bump standards version + * Fix lintian warnings + * Use system howardhinnant-date + * d/watch: Switch to git tags instead of webpage scraping + * d/watch: Temporary switch libdvd* to master branch + * Refresh kodi patchset + * Drop libdvdnav patchset + * Drop workaround patches merged upstream + * Refresh cdatetime-std-chrono patchset + * workarounds: Add libdvd* callback support (Closes: #1020452) + * workarounds: refresh ffmpeg5 patch (Closes: #1016925) + * d/rules: Follow on upstream buildsystem changes + + -- Vasyl Gello <vasek.gello@gmail.com> Sat, 15 Oct 2022 16:54:13 +0000 + +kodi (2:20.0~alpha2+dfsg1-1) unstable; urgency=medium + + * New upstream version 20.0~alpha2+dfsg1 + * d/copyright fixes: + + Keep COMPONENT-VERSION files in tools/depends/target + + Remove useless versioncheck addon (Closes: #1015163) + + Bump copyright years + * Remove obsoleted patches and update the rest: + + Add patch fixing color conversion test (merged) + + Add patch for overriding local tarball checksum (merged) + + Add patch for ffmpeg 5 support (not merged) (Closes: #1004612) + + Add patch for proper fix of EDL rounding (merged) + + Add patch for building against libfmt 9.0.0 (merged) (Closes: #1014542) + * d/rules fixes: + + Don't rely on versionfile parsing + * + Supply SHA256 hashes for libdvd* + * Upload to unstable. + + -- Vasyl Gello <vasek.gello@gmail.com> Wed, 03 Aug 2022 14:24:22 +0000 + +kodi (2:20.0~alpha1+dfsg1-2) experimental; urgency=medium + + * Fix failing tests and restore timezone picker (Closes: #1011241) + + -- Vasyl Gello <vasek.gello@gmail.com> Thu, 19 May 2022 15:08:49 +0000 + +kodi (2:20.0~alpha1+dfsg1-1) experimental; urgency=medium + + * New upstream version 20.0~alpha1+dfsg1 + * Leave only language packs in repo-resources-embedded + * Branch out experimental + * Restrict watchfile to next Debian stable codename + * Add pipewire to build-dependencies + * Refresh Kodi patches + * Add workaround patches + * Refresh cdatetime-std-chrono patches + * Refresh headers-check.c + * Use system RapidJSON + * Bump libdate-tz C++ standard to 17 and enable StringView back + + -- Vasyl Gello <vasek.gello@gmail.com> Mon, 16 May 2022 06:45:07 +0000 + +kodi (2:19.4+dfsg2-1) unstable; urgency=medium + + * New upstream version 19.4+dfsg2 + + Ship language packs for offline use (Closes: #1009278) + + Add copyright entry for language pack tarball + * Build libdate-tz as external build-dependency of Kodi. + * d/rules: Annotate actions and replace direct source patching + within rulefile with proper compiler definition + * d/rules: Fix improper cleanup of generated embedded tarballs + + -- Vasyl Gello <vasek.gello@gmail.com> Fri, 29 Apr 2022 07:10:17 +0000 + +kodi (2:19.4+dfsg1-2) unstable; urgency=medium + + * Upload to unstable + + -- Vasyl Gello <vasek.gello@gmail.com> Mon, 09 Apr 2022 12:51:13 +0000 + +kodi (2:19.4+dfsg1-1) experimental; urgency=medium + + * New upstream version 19.4+dfsg1 + * Drop system/certs and .github from tarball + * Refresh patches + * Reorder package structure to allow installation on + foreign architectures (Closes: #996627) + * Move TexturePacker to a separate binary package + * Fix Lintian warnings. + * Build native prerequisites before configure if cross-building + * Version the build-dependency on gtest to >= 1.10.0~ + * d/watch: Switch libdate-tz to tags + * Put KodiConfig.cmake in arch-dep place (Closes: #999482) + * Add patches for cross build support + + -- Vasyl Gello <vasek.gello@gmail.com> Mon, 21 Mar 2022 17:48:21 +0000 + +kodi (2:19.3+dfsg1-1) unstable; urgency=medium + + * New upstream version 19.3+dfsg1 + * Refresh patches + * Add proper WITH_ARCH for amd64, i386 and riscv64 + * Disable DebugFission by CMake configuration option instead of patch + * Use the system kissft + * kodi-bin: Remove unused lintian override + + -- Vasyl Gello <vasek.gello@gmail.com> Sun, 24 Oct 2021 14:45:29 +0000 + +kodi (2:19.2+dfsg1-2) unstable; urgency=medium + + * Fix AppStream warning with metainfo file + * Make build reproducible + + -- Vasyl Gello <vasek.gello@gmail.com> Wed, 13 Oct 2021 22:12:35 +0000 + +kodi (2:19.2+dfsg1-1) unstable; urgency=medium + + * New upstream version 19.2+dfsg1 + * Restrict watchfile to current Debian stable codename + * Bump standard version + * Refresh patches + * Install package metainfo + + -- Vasyl Gello <vasek.gello@gmail.com> Wed, 06 Oct 2021 10:59:56 +0000 + +kodi (2:19.1+dfsg2-2) unstable; urgency=medium + + * Add runtime locale test and fallback (Closes: #989814) + + -- Vasyl Gello <vasek.gello@gmail.com> Thu, 24 Jun 2021 20:44:30 +0000 + +kodi (2:19.1+dfsg2-1) unstable; urgency=medium + + * New upstream version 19.1+dfsg2 + * Merge 'bullseye' branch into master and revert patches + related to newer libdvdread and branch isolation. + * Drop the patch downgrading ffmpeg to fit buster-backports. + + -- Vasyl Gello <vasek.gello@gmail.com> Mon, 07 Jun 2021 16:42:08 +0200 + +kodi (2:19.0+dfsg1-2) unstable; urgency=medium + + * Add missing font dependency (Closes: #985497) + * Fix github ref + * Branch out bullseye + * Refresh cdatetime-std-chrono patch (Closes: #984682) + * libdate-tz: Fix crash for early local times and USE_OS_TZDB + + -- Vasyl Gello <vasek.gello@gmail.com> Sun, 30 May 2021 04:57:39 +0000 + +kodi (2:19.1+dfsg1-1~exp0) experimental; urgency=medium + + * New upstream version 19.1+dfsg1 + * Add missing font dependency (Closes: #985497) + * Fix links to Github releases in watchfile + * Refresh patches + * Prepare for official backport + * Refresh cdatetime-std-chrono patch (Closes: #984682) + * libdate-tz: Fix crash for early local times and USE_OS_TZDB + + -- Vasyl Gello <vasek.gello@gmail.com> Sat, 15 May 2021 21:15:26 +0000 + +kodi (2:19.0+dfsg1-1) unstable; urgency=medium + + * New upstream version 19.0+dfsg1 + * Declare proper Debian release splitting kodi-addons-dev (Closes: #980846) + * Detect and honor big-endian architectures + * Refresh cdatetime-std-chrono patch + + -- Vasyl Gello <vasek.gello@gmail.com> Fri, 19 Feb 2021 00:02:45 +0000 + +kodi (2:19.0~rc1+git20210119.8c761c4+dfsg1-2) experimental; urgency=medium + + * Team upload. + * Re-instate the kodi-addons-dev-common package split. + + -- Mattia Rizzolo <mattia@debian.org> Wed, 20 Jan 2021 01:56:06 +0100 + +kodi (2:19.0~rc1+git20210119.8c761c4+dfsg1-1) unstable; urgency=medium + + [ Vasyl Gello ] + * New upstream version 19.0~rc1+dfsg1 and 19.0~rc1+git20210119.8c761c4+dfsg1. + + Fix possible crash on shutdown. (Closes: #979367) + + New upstream snapshot fixes non-DFSG free JPEG image + which led to FTP master rejection + * d/watch: mangle capital letter abbrevs too + * Delete patches merged upstream + * Refresh cdatateime-std-chrono patch + * copyright: Reflect skin.estuary picture replacement + + [ Mattia Rizzolo ] + * Temporary revert the kodi-addons-dev-common split to avoid NEW fo + this upload (the previous version was rejected from NEW). + * Upload to unstable. + + -- Vasyl Gello <vasek.gello@gmail.com> Tue, 19 Jan 2021 20:02:25 +0000 + +kodi (2:19.0~beta2+dfsg1-6) experimental; urgency=medium + + [ Mattia Rizzolo ] + * d/control: define dh-sequence-kodiaddon as a versioned Provides + + [ Vasyl Gello ] + * Check the existence of kodi include dir's full path + in dh_kodiaddon_depends. + * Refresh cdatetime-std-chrono patch. (Closes: #980038) + * Introduce a kodi-addons-dev-common package to hold all the arch-indep + files. + + -- Vasyl Gello <vasek.gello@gmail.com> Tue, 12 Jan 2021 02:57:10 +0000 + +kodi (2:19.0~beta2+dfsg1-5) unstable; urgency=medium + + * Team upload. + * Fix arch:all build after turning kodi-addons-dev arch:any. + + -- Mattia Rizzolo <mattia@debian.org> Sun, 10 Jan 2021 20:46:04 +0100 + +kodi (2:19.0~beta2+dfsg1-4) unstable; urgency=medium + + * Team upload. + + [ Vasyl Gello ] + * d/watch: Declare bare git snapshot naming scheme since v20. + + [ Mattia Rizzolo ] + * Mark kodi-addons-dev as Arch:any. + This is to prevent addons from building in architectures where Kodi + is not available. + + -- Mattia Rizzolo <mattia@debian.org> Sun, 10 Jan 2021 15:57:30 +0100 + +kodi (2:19.0~beta2+dfsg1-3) unstable; urgency=medium + + * d/upstream/metadata: Add Bug-Submit URL + * Drop libenca-dev build dependency + * dh_kodiaddon_depends: Provide a sliding window + for ABI bumps to avoid unnecessary addon rebuild + + -- Vasyl Gello <vasek.gello@gmail.com> Sun, 03 Jan 2021 08:45:17 +0000 + +kodi (2:19.0~beta2+dfsg1-2) unstable; urgency=medium + + [ Vasyl Gello ] + * Upload to unstable (Closes: #926922) + * d/watch: Simplify dversionmangle + * Update Vcs-Git/Vcs-Browser for the move to 'kodi-media-center' subgroup + * Restore libfreetype6-dev alternative build-dep for buster. + + [ Tobias Frost ] + * Add CVE-ids to past changelog entries when they have been fixed, + as per security team policy. + + -- Vasyl Gello <vasek.gello@gmail.com> Tue, 22 Dec 2020 10:01:37 +0000 + +kodi (2:19.0~beta2+dfsg1-1) experimental; urgency=medium + + * New upstream version 19.0~beta2+dfsg1 + + Fix kodi-ps3remote crash. (Closes: #962929) + * Build a new kodi-eventclients-zeroconf package with the zeroconf scripts + * Add breaks and replaces to kodi-eventclients-ps3 + * Backport a patch from Kodi 20 to replace CDateTime with cdate-std-chrono. + Fixes test failures on multiple architectures. + + Add libdate-tz as component tarball + * Update d/copyright + * Use the system-wide tzdata. + * Drop clang-format from build-deps, not actually needed during the build + * Mark kodi-addons-dev as indep + * Fix arch-indepedent-only build (Closes: #976303) + * Bump Standards-Version to 4.5.1 (no changes required) + * Fix lintian warnings + + -- Vasyl Gello <vasek.gello@gmail.com> Sat, 19 Dec 2020 04:55:34 +0000 + +kodi (2:19.0~alpha3+dfsg1-1) experimental; urgency=medium + + [ Vasyl Gello ] + * New upstream version 19.0~alpha3+dfsg1 + + This version fully builds with Python 3. (Closes: 936805) + * Refresh patches + * Revert "temporary disable tests parallelism", in 19.0 tests run fine + * Bump the required ffmepg version + * Don't use clang-format on x32 + * Drop the build-dep on lib-p8-platform + * Update the watchfile + * Don't run dwz during the build as it fails on us + * Add several Multi-Arch fields, from the M-A hinter + * Fix several lintian warnings + * Add default webinterface as debian include (this is temporary until the + packaging of the new interface is completed) + * Retrieve embedded libdvdnav and libdvdread from upstream + * debian/header-check.c: Add new and delete removed headers + * Refresh copyright information + * Provide 'dh-sequence-kodiaddon' virtual package + * Drop kodi-x11, kodi-wayland and kodi-gbm packages, now the same binary + can handle all window systems + + [ Adrian Bunk ] + * Rename SSE patch file (Closes: #961856) + + -- Vasyl Gello <vasek.gello@gmail.com> Tue, 17 Nov 2020 13:04:40 +0100 + +kodi (2:18.8+dfsg1-2) unstable; urgency=medium + + * temporary disable tests parallelism (Closes: #968339) + * add myself to Uploaders + + -- Vasyl Gello <vasek.gello@gmail.com> Thu, 03 Sep 2020 01:48:09 +0300 + +kodi (2:18.8+dfsg1-1) unstable; urgency=medium + + [ Vasyl Gello ] + * Team upload + * fix circular dependency hell (Closes: #963865) + * Depend on libudfread & shairplay + * remove unnecessary dlopen-ed shlibdeps from kodi-bin + * remove dummy remnant + + [ Jonas Smedegaard ] + * Remove myself from Uploaders + + [ Vasyl Gello ] + * drop unnecessary cpluff component + * New upstream version 18.8+dfsg1 (Closes: #964591) + * Refresh patches + + [ Adrian Bunk ] + * Don't enable SSE in i386 builds (Closes: #961856) + + [ Balint Reczey ] + * debian/README.source: Clarify that dvdread and dvdnav are patched for Kodi + * debian/gbp.conf: Set components + * debian/README.source: Gbp now exports components properly + * New upstream version 18.7.1+dfsg1 + + -- Vasyl Gello <vasek.gello@gmail.com> Mon, 03 Aug 2020 02:20:44 +0000 + +kodi (2:18.7+dfsg1-1) unstable; urgency=medium + + * Team upload + * New upstream version 18.7 + * Refresh patches + * Update additional tarballs to libdvdnav 6.1.0 and libdvdread 6.1.1 + + -- Balint Reczey <rbalint@ubuntu.com> Tue, 26 May 2020 16:14:53 +0200 + +kodi (2:18.6+dfsg1-2) unstable; urgency=medium + + * Team upload + * Drop pycryptodome support with Python 2 + * debian/control: Revert kodi-data to depend on python-pil instead of python3-pil. + Kodi runs addons with Python 2 and many addons would break without PIL. + * Run kodi-ps3remote with Python 3 + * Apply suggestion to debian/rules + * debian/rules: Ship debug symbols for all kodi binaries and drop -dbg migration + (Closes: #955134) + + -- Balint Reczey <rbalint@ubuntu.com> Fri, 03 Apr 2020 13:48:30 +0200 + +kodi (2:18.6+dfsg1-1) unstable; urgency=medium + + * Upload to unstable + + -- Balint Reczey <rbalint@ubuntu.com> Sat, 21 Mar 2020 16:39:01 +0100 + +kodi (2:18.6+dfsg1-1~exp1) experimental; urgency=medium + + * test: Disable flaky TestMassEvent.General test, too + + -- Balint Reczey <rbalint@ubuntu.com> Thu, 19 Mar 2020 21:41:10 +0100 + +kodi (2:18.6+dfsg1-1~exp0) experimental; urgency=medium + + * debian/rules: Set -DWITH_ARCH=... and -DNEON=False explicitly for armel, + armhf, ppc64el and s390x. Those Debian architectures are not detected + properly by upstream CMake scripts. + * Build-depend on python2-dev + * Reposition "from debian" on the main screen to adjust to the changed new + skin + * Don't strip service.xbmc.versioncheck addon from upstream tarball + * New upstream version 18.6 + * Ship versioncheck addon disabled + * Disable long-time failing test and fix others instead of ignoring all test + results + * Drop obsolete patches + * Drop 03-privacy.patch and add TODO item about resurrecting it properly + * Refresh patches + * Run kodi-send with Python 3 + * test: Disable flaky TestMassEvent.Polling test + * Fix ppc64el build + * Fix arch detection + * test: Skip checking errno against ENOEN to not FTBFS on armhf + + -- Balint Reczey <rbalint@ubuntu.com> Wed, 18 Mar 2020 12:09:23 +0100 + +kodi (2:18.5+dfsg1-1~exp0) experimental; urgency=medium + + [ Balint Reczey ] + * Team upload + * debian/tests/gui: Wait for kodi to start, not just a fixed 5 seconds + * Refresh patches + * Update extra libdvdnav and libdvdread original tarballs + * debian/copyright_hints: Update hints with new files + * debian/control: Tidy up using cme fix + * debian/gitlab-ci.yml: Add Salsa CI configuration + * Refresh build dependencies based on upstream's packaging + * Ship separate packages for X11, Wayland and GBM + * debian/rules: + - Rewrite to use cmake and build separate binaries. + Thanks to Wolfgang Schupp + - Extend override_dh_clean + - Pass -lphtread to linker by default + - Refactor building Debianized artifacts + - Run tests for each build dir + - Clean up separate build directories + - clean media/Fonts/arial.ttf, too + - Call dh with python2 + - Drop obsolete --parallel dh argument + - Adjust to new component names + * debian/copyright: Fix open issues and Lintian complaints + * Let upstream's build system build the embedded libdvdnav and libread + libraries + * Install TexturePacker to /usr/bin/ + * Ignore failing tests for now + * Update which files are shipped by which package + * Switch hashing implementation from OpenSSL to Libgcrypt + * Build without OpenSSL + * Depend on unhinted Roboto font (Closes: #922950) + * Fix FTBFS of kodi-test by not #include-ing excluded Windows-only header + * Fix dh_kodiaddon_depends to get API versions the new way + * Refresh file list shipped by kodi-addons-dev + * Remove myself from Uploaders + * Work around FTBFS caused by fontforge SEGFAULT + * New upstream version 18.5+dfsg1 (CVE-2017-5982) + * debian/gbp.conf: Drop postexport hook. + It is obsoleted by storing all components in git. + * Stop marking kodi-bin Multiarch: same since it now ships TexturePacker + * Stop marking kodi-gbm, kodi-x11 and kodi-wayland Multiarch: same. + They depend on kodi-bin which is not Multiarch: same either. + * Build kodi-wayland, too + + [ Rechi ] + * debian/copyright: update Files-Excluded + - libUPnP was updated + - UnrarXLib was split into an addon + - Visual Studio files were removed + - windows platform specific code location changed + * drop unused Build-depends + * add new Build-depends + * debian/rules: remove unused DEB vars + * debian/rules: remove non existent cmake options + - egl is a required dependency on linux so there is no ENABLE_EGL switch + - x11 isn't an optional dependency for gbm so there is no ENABLE_X11 switch + - vdpau is only an optional dependency for x11, so ENABLE_VDPAU switch + exists only for x11 + * debian/rules: update dlopened libs + libass, libbluray, libcec, libcurl and libnfs are no longer dlopend + * fix libmicrohttpd linking + * debian/rules: install kodi-x11 as last package + last installed package defines the fallback windowing in bin/kodi + * fix depends syntax + * fix test target build system dependency + + -- Balint Reczey <rbalint@ubuntu.com> Fri, 24 Jan 2020 08:20:58 +0100 + +kodi (2:17.6+dfsg1-4) unstable; urgency=medium + + * debian/tests/gui: Print xvfb-run error to stdout + * debian/tests/gui: Fix test by starting 24bit screen and waiting for + kodi's start + * Drop transitional packages + * Fix FTBFS when _G_va_list is not defined, like on Ubuntu 19.04 + + -- Balint Reczey <rbalint@ubuntu.com> Tue, 20 Nov 2018 12:21:00 +0100 + +kodi (2:17.6+dfsg1-3) unstable; urgency=medium + + [ Balint Reczey ] + * debian/NEWS: Fix language to keep lintian happy + * Add simple autopkgtest + + [ Gianfranco Costamagna ] + * Upstream fixes for new ffmpeg: + debian/patches/19f28e88a5dfed82e9844f69210f7c045f18ca8e.patch + debian/patches/c7e2acc1b2ee781af6e14d80da0edd0aa23bdf03.patch + (Closes: #888383, #912994) + + -- Balint Reczey <rbalint@ubuntu.com> Fri, 16 Nov 2018 01:42:36 +0100 + +kodi (2:17.6+dfsg1-2) unstable; urgency=medium + + [ Ondřej Nový ] + * d/copyright: Use https protocol in Format field + * d/control: Set Vcs-* to salsa.debian.org + + [ Rechi ] + * Drop build dependencies on libboost-* + Boost isn't required since v17. + + [ Felipe Sateler ] + * Change maintainer address to debian-multimedia@lists.debian.org + + [ Balint Reczey ] + * Ship only Kodi desktop session without the xbmc.desktop duplicate link + * Stop build-depending on versioned GCC, this workaround is not needed + anymore (Closes: #892399) + Thanks to Adrian Bunk who also proposed a patch and a delayed NMU. + * Stop shipping kodi.service + Please use a lightweight display manager set up to autologin instead. + * Add d/source.lintian-overrides to d/source/lintian-overrides + to keep lintian happy + + [ Rolf Leggewie ] + * demote hard font dependencies from Depends to Recommends (LP: #1685918) + + -- Balint Reczey <rbalint@ubuntu.com> Sat, 28 Apr 2018 20:50:46 +0200 + +kodi (2:17.6+dfsg1-1) unstable; urgency=medium + + * New upstream version 17.6 (with accumulated changes from 17.4 and 17.5): + - https://kodi.tv/article/kodi-v174-final-just-bunch-fixes + - https://kodi.tv/article/kodi-v175-final-another-bunch-fixes + - https://kodi.tv/article/kodi-v176-final-very-last + * Refresh patches + * Depend and build-depend on python-pil instead of python-imaging + (Closes: #866437) + * Apply workaround for scratchy sound with FFmpeg 3.4. + Thanks to James Cowgill for triaging and Stefan Hachmann for the patch + (Closes: #881536) + * Fix starting kodi on arm64 (Closes: #876876) + * Change URLs to use HTTPS in README.Debian and drop feed URL from + description (Closes: #860484) + + -- Balint Reczey <rbalint@ubuntu.com> Tue, 26 Dec 2017 01:06:49 +0100 + +kodi (2:17.3+dfsg1-5) unstable; urgency=medium + + * Build-depend on fontforge-nox (not fontforge. + * Use rsvg-convert to generate branding logo. + Build-depend on (not inkscape). + * Fix remove repository feed from kodi-data. + Tighten kodi-repository-kodi breaks+replaces on kodi-data. + + -- Jonas Smedegaard <dr@jones.dk> Wed, 11 Oct 2017 02:37:25 +0200 + +kodi (2:17.3+dfsg1-4) unstable; urgency=medium + + * Update package relations: + + Fix have kodi-repository-kodi conflict against and replace older + kodi/kodi-data/xbmc. + Fixes bug#877960. Thanks to Andreas Beckmann. + + Fix have kodi-repository-kodi conflict against (not break) virtual + kodi-repository. + + Fix have package kodi-repository-kodi depend on ${misc:Depends}. + + Stop build-depend on dh-autoreconf autotools-dev: Handled by + debhelper. + * Rewrite copyright info, with major coverage improvements. + * Add maintainer script copyright-check to source. + * Update git-buildpackage config: + + Add usage comment. + + Filter any .git* file. + * Override lintian regarding license in License-Reference field. + See bug#786450. + * Override lintian regarding obsolete-url-in-packaging: License grant + must be included verbatim. + + -- Jonas Smedegaard <dr@jones.dk> Tue, 10 Oct 2017 22:46:23 +0200 + +kodi (2:17.3+dfsg1-3) unstable; urgency=medium + + * Fix set core configure options to all instances. + * Set configure options --disable-maintainer-mode + --disable-silent-rules (unused now but might be added in future). + * Fix avoid custom build rule silencing. + * Fix FTBFS: Build-depend on and build with gcc-6 and g++-6 (until + bug#841556 is fixed). + Closes: Bug#853476. Thanks to Matthias Klose and Bálint Réczey. + * Modernize Vcs-* fields: + + Use https (not git or http) protocol. + + Use git (not gitweb) in path. + * Use https in Homepage URL. + * Add myself as uploader. + * Add patch 18 to support omitting addon repository feed. + * Ship repository feed in separate package kodi-repository-kodi. + Closes: Bug#877656 (or arguably only lowers severity of it, but + since we cannot track that versioned better to close and track the + lowered severity separately). + + -- Jonas Smedegaard <dr@jones.dk> Wed, 04 Oct 2017 03:53:10 +0200 + +kodi (2:17.3+dfsg1-2) unstable; urgency=medium + + * Upload to unstable + * Stop shipping kodi.service as an example since it is now shipped + as a regular .service file + + -- Balint Reczey <rbalint@ubuntu.com> Thu, 29 Jun 2017 05:15:29 +0200 + +kodi (2:17.3+dfsg1-1) experimental; urgency=medium + + * New upstream version 17.3 + See: https://kodi.tv/article/kodi-v173-minor-bug-fix-and-security-release + * Refresh patches + + -- Balint Reczey <rbalint@ubuntu.com> Fri, 26 May 2017 18:44:04 +0200 + +kodi (2:17.1+dfsg1-3) unstable; urgency=medium + + * Fix zip file directory traversal vulnerability (CVE-2017-8314) + (Closes: #863230) + + -- Balint Reczey <rbalint@ubuntu.com> Sat, 27 May 2017 00:50:34 +0200 + +kodi (2:17.1+dfsg1-2) unstable; urgency=medium + + * Upload to unstable + + -- Balint Reczey <rbalint@ubuntu.com> Thu, 13 Apr 2017 23:49:12 +0200 + +kodi (2:17.1+dfsg1-1) experimental; urgency=medium + + * Depend on fonts-noto-mono package which contains NotoMono-Regular.ttf + (Closes: #856668) + * Fix FTBFS on alpha by not using Intel assempler code (Closes: #856815) + * Imported Upstream version 17.1+dfsg1 + See: https://kodi.tv/kodi-v17-1-krypton + * Update my Uploader email address to my Ubuntu one + * Fix extract-components target in d/rules + + -- Balint Reczey <rbalint@ubuntu.com> Sun, 02 Apr 2017 11:01:21 +0200 + +kodi (2:17.1~rc1+dfsg1-1) experimental; urgency=medium + + * Imported Upstream version 17.1~rc1+dfsg1 + * Refresh patches + + -- Balint Reczey <balint@balintreczey.hu> Tue, 28 Feb 2017 02:21:54 +0100 + +kodi (2:17.0+dfsg1-3) unstable; urgency=medium + + * Ship disabled systemd service file (Closes: #854985, #801886) + * Use systemd service file recommended on upstream wiki + + -- Balint Reczey <balint@balintreczey.hu> Wed, 22 Feb 2017 01:28:43 +0100 + +kodi (2:17.0+dfsg1-2) unstable; urgency=medium + + * Apply patches to additional tarballs using quilt series file + (Closes: #854463) + + -- Balint Reczey <balint@balintreczey.hu> Thu, 09 Feb 2017 10:25:18 +0100 + +kodi (2:17.0+dfsg1-1) experimental; urgency=medium + + * Imported Upstream version 17.0+dfsg1 + See: https://kodi.tv/kodi17/ + + -- Balint Reczey <balint@balintreczey.hu> Mon, 06 Feb 2017 19:33:08 +0100 + +kodi (2:17.0~rc4+dfsg1-1) experimental; urgency=medium + + * Imported Upstream version 17.0~rc4+dfsg1 + See: https://kodi.tv/kodi-v17-0-krypton-release-candidate-4/ + * Refresh patches + * Remove spaces around '=' in service file. + Also convert service file to use Unix line ending + + -- Balint Reczey <balint@balintreczey.hu> Sun, 05 Feb 2017 01:27:27 +0100 + +kodi (2:17.0~rc3+dfsg1-2) unstable; urgency=medium + + * Bump debhelper compat level to 10. + Remove --parallel and --with autoreconf since those are now defaults + * Build-depend on libcec-dev >= 4~ (Closes: #852216) + * Fix make clean in debian/rules + * Use real dlopen() for opening libdvdcss (Closes: #784578) + + -- Balint Reczey <balint@balintreczey.hu> Wed, 25 Jan 2017 21:23:22 +0100 + +kodi (2:17.0~rc3+dfsg1-1) unstable; urgency=medium + + * Make default lirc device match lirc package's default (Closes: #850467) + * Stop passing ./configure flags which are not supported anymore + * Update fonts and font dependencies + * Imported Upstream version 17.0~rc3+dfsg1 + See: https://kodi.tv/kodi-v17-0-krypton-release-candidate-3/ + * Refresh patches + * Fix FTBFS due to missing AEDefines_override.h + + -- Balint Reczey <balint@balintreczey.hu> Mon, 16 Jan 2017 21:41:03 +0100 + +kodi (2:17.0~rc2+dfsg1-1) unstable; urgency=medium + + * Imported Upstream version 17.0~beta7+dfsg1 + See: https://kodi.tv/kodi-v17-krypton-the-last-beta-7/ + * Refresh patches + * Use NotoSans-Regular font from fonts-noto-hinted package + * Imported Upstream version 17.0~rc2+dfsg1 + See: https://kodi.tv/kodi-v17-krypton-release-candidate-1/ + * Fix positioning of the "from debian" text next to KODI logo + + -- Balint Reczey <balint@balintreczey.hu> Fri, 06 Jan 2017 18:39:14 +0100 + +kodi (2:17.0~beta6+dfsg1-1) unstable; urgency=medium + + * Drop new built-in webinterface addon from beta 6. + The addon contains many generated files without source. It will + be packaged separately. + * Imported Upstream version 17.0~beta6+dfsg1 + * Refresh patches + * Revert the webinterface.default addon to old web interface from beta5 + * Update lintian override about MediaLibrary.js to match new packaging + * Revert to using libcec 3.1 until libcec4 becomes available in Debian + + -- Balint Reczey <balint@balintreczey.hu> Thu, 22 Dec 2016 02:00:46 +0100 + +kodi (2:17.0~beta5+dfsg1-4) unstable; urgency=medium + + * Stop using different epoch for transitional xbmc packages + * Use 2: epoch for kodi packages (Closes: #844541) + * Handle original tarballs properly when epoch is present in the package version + + -- Balint Reczey <balint@balintreczey.hu> Thu, 17 Nov 2016 15:42:51 +0100 + +kodi (17.0~beta5+dfsg1-3) unstable; urgency=medium + + * Generate addon API versions for architecture-specific builds only + + -- Balint Reczey <balint@balintreczey.hu> Mon, 14 Nov 2016 16:37:40 +0100 + +kodi (17.0~beta5+dfsg1-2) unstable; urgency=medium + + [ Balint Reczey ] + * Stop providing xbmc-eventclients-j2me. + This was a transitional package originally, but Kodi stopped shipping + J2ME client. (Closes: #843169) + * Transition to depending on fonts-anonymous-pro. + Also accept ttf-anonymous-pro instead to support older releases + * Generate additional original source tarball names from current version + * Use more absolute paths in d/rules + + [ Tobias Grimm ] + * Updated tarball versions in `debian/rules extract-components` + * Provide virtual packages for addon APIs and install a debhelper addon + to enable KODI addon packages to depend on these virtual packages. + * Standards-Version: 3.9.8 + + -- Balint Reczey <balint@balintreczey.hu> Mon, 14 Nov 2016 11:32:17 +0100 + +kodi (17.0~beta5+dfsg1-1) unstable; urgency=medium + + [ Lukas Rechberger ] + * Make kodi depend on kodi-data of same version (Closes: #841937) + + [ Balint Reczey ] + * Fix Kodi's FFmpeg API usage for allocating and freeing AVFrame + (Closes: #831591) + * New upstream beta release 17.0 Beta 5 + See: https://kodi.tv/kodi-v17-krypton-beta-5/ + * Refresh patches + * Run tests only for architecture dependent package builds + * Use Anonymous Pro font from ttf-anonymous-pro instead of from texlive-fonts-extra + (Closes: #842717) + + -- Balint Reczey <balint@balintreczey.hu> Wed, 02 Nov 2016 21:53:39 +0100 + +kodi (17.0~beta4+dfsg1-2) experimental; urgency=medium + + * Generate version of xbmc transitional packages dynamically + (Closes: #842141) + * Check installed headers only during architecture-specific builds + + -- Balint Reczey <balint@balintreczey.hu> Wed, 26 Oct 2016 13:37:42 +0200 + +kodi (17.0~beta4+dfsg1-1) experimental; urgency=medium + + * Ship additional headers referenced from already shipped ones + * Ensure all needed development headers are installed + * Use patches from libdvdread package + * Build-depend on libssh-gcrypt-dev instead of libssh-dev to avoid + transitive linking to libssl + * Build-depend on libgcrypt-dev instead of libssl-dev + * New upstream beta release 17.0 Beta 4 + See: https://kodi.tv/kodi-v17-krypton-beta-4/ + * Refresh patches + * Stop building with OpenSSL + + -- Balint Reczey <balint@balintreczey.hu> Mon, 10 Oct 2016 23:00:38 +0200 + +kodi (17.0~beta3+dfsg1-1) experimental; urgency=medium + + * New upstream beta release 17.0 Beta 3 + See: https://kodi.tv/kodi-v17-krypton-beta-3/ + * Refresh patches + * Use OpenGL ES and no VAAPI/VDAPU on arm64. + This fixes FTBFS on arm64 + * Enable Google Tests on armel and mips, too. + The test results don't make the build fail anyway + * Build-depend on valgrind on amd64 and i386. + This makes tests use Valgrind on those popular and fast architectures + * Fix FTBFS on armel/armhf + * Properly set hardening options + * Re-enable TestSortUtils test + * Fix building tests + * Build-depend on default-libmysqlclient-dev to keep Lintian happy + * Adjust "from debian" logo placement + + -- Balint Reczey <balint@balintreczey.hu> Fri, 07 Oct 2016 10:27:11 +0200 + +kodi (17.0~beta2+dfsg1-1) experimental; urgency=medium + + * New upstream beta release 17.0 Beta 2 + See: https://kodi.tv/kodi-v17-krypton-beta-2/ + * Drop build-depenency on libjasper-dev (Closes: 818201) + * Adjust packaging to new skin's font requirements. + Add dependency on fonts-lato and texlive-fonts-extra, drop + dependency on fonts-roboto-hinted, make symlinks to new + fonts instead of shipping them. + * Add transitional dummy packages from xbmc + * Drop obsoleted dependencies and patches + * Silence Lintian complaining for missing misc:Depends of transitional + packages + * Ignore failed clean of components without Lintian noticing + * Build-depend on liblcms2-dev for Little CMS support + + -- Balint Reczey <balint@balintreczey.hu> Sat, 24 Sep 2016 14:57:31 +0200 + +kodi (17.0~alpha3+dfsg1-1) experimental; urgency=medium + + [ Lukas Rechberger ] + * Skip timestamps to make build reproducible (Closes: #825285) + + [ Balint Reczey ] + * Build depend on groovy instead of groovy2 (Closes: #824187) + * Recommend kodi-visualization-spectrum + * New upstream alpha release 17.0 Alpha 2 + See: https://kodi.tv/kodi-v17-krypton-alpha-2/ + * Stop excluding paths from orig tarball which are already removed + * Refresh patches and changed paths in d/rules + * Fix FTBFS due to format string warnings + * Disable building DVDCSS + * Build-depend on libbluray-dev (>= 0.7.0) to match version required by ./configure + * Derive embedded libdvdnav and libdvdread from additional original tarballs + * Fix building with Google Test + * Ignore failing tests but run them with Valgrind when it is available + * Update d/copyright + * Add information about multiple orig tarballs + * New upstream alpha release 17.0 Alpha 3 + See: https://kodi.tv/kodi-v17-krypton-alpha-3/ + * Refresh patches + * Really revert patches to embedded dvdnav and dvdread copies in clean target + * Drop J2ME client support in sync with upstream + * Don't crash on missing version checker addon + * Position "from Debian" image better on new skin + * Drop symlinks to fonts used in the replaced skin + + -- Balint Reczey <balint@balintreczey.hu> Fri, 05 Aug 2016 01:23:53 +0200 + +kodi (16.1+dfsg1-1) unstable; urgency=medium + + * New upstream version 16.1 + See https://kodi.tv/kodi-16-1-jarvis-mark-xvi + + -- Balint Reczey <balint@balintreczey.hu> Sun, 24 Apr 2016 15:51:42 +0200 + +kodi (16.1~rc2+dfsg1-1) unstable; urgency=medium + + * New upstream release candidate 16.1 RC2 + See: https://kodi.tv/kodi-16-1-jarvis-release-candidate-2/ + * Fix GetKernelBitness() on s390x to fix FTBFS on that arch + * Skip tests on armel and mips to prevent FTBFS + * Stop excluding files from upstream tarball which are already removed + upstream + * Don't modify GetVersionShort(), return package version in GetVersion() + instead + + -- Balint Reczey <balint@balintreczey.hu> Tue, 29 Mar 2016 10:52:16 +0200 + +kodi (16.0+dfsg1-3) unstable; urgency=medium + + * Fix system info for s390x and arm64 architectures + * Skip tests failing on buildds to fix FTBFS on most ports + * Skip sorting test failing in the test code on armhf and armel + + -- Balint Reczey <balint@balintreczey.hu> Fri, 25 Mar 2016 10:49:06 +0100 + +kodi (16.0+dfsg1-2) unstable; urgency=medium + + * Enable Google Tests at build-time + * Fix user agent string and related test + * Disable bindnow hardening option because it breaks playing DVDs + + -- Balint Reczey <balint@balintreczey.hu> Tue, 15 Mar 2016 15:08:54 +0100 + +kodi (16.0+dfsg1-1) unstable; urgency=medium + + * New upstream version 16.0 + See https://kodi.tv/kodi-16-0-jarvis-mark-xvi/ + * Refresh patches + * Change build-dependency on libcec-platform-dev to libp8-platform-dev. + The library has been renamed + * Build-depend on libcec-dev (>= 3.1) which is built with p8-platform + * Stop shipping menu file + * Override false positive lintian warning about missing JavaScript source + + -- Balint Reczey <balint@balintreczey.hu> Mon, 22 Feb 2016 23:08:18 +0100 + +kodi (16.0~rc3+dfsg2-1) experimental; urgency=medium + + * New upstream release candidate 16.0 RC3 + (Closes: #792299) (CVE-2015-3885) + See http://kodi.tv/kodi-16-0-jarvis-release-candidate-3/ + * Refresh patches + * Don't use libcadec, wait for the codec to be included in FFmpeg instead + * Drop libhdhomerun-dev build dependency + * Add libcrossguid-dev and uuid-dev as build-dependencies + * Drop workarounds for screensavers dropped by upstream + * Use hinted Roboto fonts adapting to their new location in filesystem + * Enable PIE + * Make C-Pluff build with PIC only enabling PIE-enabled build to succeed + * Update debian/copyright for 16.0 RC3 changes + + -- Balint Reczey <balint@balintreczey.hu> Sat, 13 Feb 2016 22:53:08 +0100 + +kodi (15.2+dfsg1-3) unstable; urgency=medium + + * Disable PIE due to build failure on amd64 + + -- Balint Reczey <balint@balintreczey.hu> Mon, 25 Jan 2016 10:35:02 +0100 + +kodi (15.2+dfsg1-2) unstable; urgency=medium + + * Fix 03-privacy.patch to disable rss feed + * Disable debugging by default (Closes: #777041) + * Build-depend on fonts-droid-fallback instead of obsoleted fonts-droid + (Closes: #804695) + * Enable all hardening options during build + * Migrate to libpng-dev build-dependency (Closes: #810186) + + -- Balint Reczey <balint@balintreczey.hu> Sun, 24 Jan 2016 10:55:08 +0100 + +kodi (15.2+dfsg1-1) unstable; urgency=medium + + [ Balint Reczey ] + * Skip handling migration to automatic debug packages when it is not supported by debhelper + * Update debian/watch to not skip part of oddly named versions + * New upstream release 15.2 + See http://kodi.tv/kodi-15-2-isengard-final-release/ + + [ Andreas Cadhalpun ] + * Fix FTBFS with upcoming FFmpeg 2.9 release (Closes: #803831) + + -- Balint Reczey <balint@balintreczey.hu> Fri, 06 Nov 2015 18:42:22 +0400 + +kodi (15.2~rc3+dfsg1-1) unstable; urgency=medium + + * New upstream release candidate 15.2 RC3 + See http://kodi.tv/kodi-15-2-isengard-release-candidate-3 + + -- Balint Reczey <balint@balintreczey.hu> Tue, 06 Oct 2015 12:06:19 +0200 + +kodi (15.2~rc1+dfsg1-2) unstable; urgency=medium + + * Make Breaks/Replaces relation to xbmc packages versioned. + This lets dummy transition-only xbmc packages coexist with kodi. + Also remove Provides/Replaces relations remaining from xbmc packaging. + (Closes: #799823) + * Split architecture-indepedent data to kodi-data. + Only the kodi and kodi-standalone binaries are kept in kodi package which is + now Architecture:any since it contains the architecture-specific path to + kodi.bin. (Closes: #799979) + + -- Balint Reczey <balint@balintreczey.hu> Sat, 26 Sep 2015 15:13:36 +0200 + +kodi (15.2~rc1+dfsg1-1) unstable; urgency=medium + + [ Balint Reczey ] + * Really fix s390x build + * Call ./configure through dh_auto_configure + * Convert to package to use multiarch library dirs + * Stop shipping kodi-dbg and disable debugging during build. + This is a preparation for the automatically generated debug packages + and switching to FFmpeg resulted less reported crashes to BTS. + Kodi-dbg packages used quite a big space on mirrors and weren't used + frequently. + * Make kodi-addons-dev Replaces/Breaks: kodi-bin (<= 15.1+dfsg1-3) + This is needed to manage moving .cmake files to to kodi-addons-dev. + * Migrate from kodi-dbg to ddebs properly. + Thanks to Mattia Rizzolo + * Make kodi-addons-dev Architecture: any + * Simplify debian/rules using exporting DH_OPTIONS + * New upstream release candidate 15.2 RC1 + See http://kodi.tv/kodi-15-2-isengard-release-candidate-2/ + * Refresh patches + + [ Tobias Grimm ] + * Fixed file name of patches/09-use-correct-ftgl.h + * Install *.cmake files in kodi-addons-dev + + [ Mattia Rizzolo ] + * debian/rules: correct use of `echo` + + -- Balint Reczey <balint@balintreczey.hu> Mon, 21 Sep 2015 10:38:00 +0200 + +kodi (15.1+dfsg1-3) unstable; urgency=medium + + * Make configure more verbose when building on architecture not supported + by upstream + * Fix FTBFS on aarch64 (Closes: #796532) + * Don't use NEON on arm/armhf. (Closes: #797204) + * Fix build on s390x + + -- Balint Reczey <balint@balintreczey.hu> Sun, 30 Aug 2015 10:20:07 +0200 + +kodi (15.1+dfsg1-2) unstable; urgency=medium + + * Don't stop configuration for unknown architectures + * Drop unknown ./configure options + * Continue configuration for unknown arches even further (Closes: #790635) + * Link with libatomic to fix FTBFS on powerpc and some other architectures + * Fix broken symlinks to DejaVuSans font files + + -- Balint Reczey <balint@balintreczey.hu> Tue, 18 Aug 2015 23:51:14 +0200 + +kodi (15.1+dfsg1-1) unstable; urgency=medium + + * New upstream release 15.0 + See http://www.kodi.tv/kodi-15-0-isengard-one-release-to-rule-them-all/ + * Depend on libav.*-dev provided by src:ffmpeg + * Recommend udisks2 instead of udisks. + Udisks has been removed from unstable but support for udisks2 is not + implemented yet. + * Ship patch helping Jessie backports + * Refresh patches + * Eliminate __DATE__ macros from source to make build more reproducible + * Build-depend on libsdl2.*-dev instead of libsdl.*-dev + * Build-depend on libgif-dev + * Drop obsoleted fix of installed header's include paths + * Refresh include file list included by kodi-addons-dev + * Build depend on libcec (>= 3) + * Build-depend on groovy2 instead of groovy + * Sort build dependencies + * Fix packaging repository URL + * Remove removed files from debian/copyright + * Fix filenames with spaces in debian/copyright + * Ship TexturePacker in kodi-addons-dev in /usr/lib/kodi + * Build depend on libcec-platform-dev + * Stop using embedded gnulib modules in rsxs screensaver (Closes: #795813) + * Add missing copyright paragraphs to d/copyright + * Stop marking files as excluded which are removed from upstream tarball + already + * Bump standards version to 3.9.6 + * New upstream release 15.1 + See http://kodi.tv/kodi-15-1-isengard-maintenance-release/ + * Move TexturePacker to kodi-bin + * Stop building TexturePacker statically + + -- Balint Reczey <balint@balintreczey.hu> Tue, 18 Aug 2015 14:16:59 +0200 + +kodi (14.2+dfsg1-2) unstable; urgency=medium + + * Recommend udisks (Closes: #787293) + + -- Balint Reczey <balint@balintreczey.hu> Thu, 04 Jun 2015 09:39:30 +0200 + +kodi (14.2+dfsg1-1) experimental; urgency=medium + + * Fix addon shared library naming on MIPS + * Drop non-machine-readable parts of debian/copyright + * Generate machine-readable debian/copyright for all files + * Clean up generated debian/copyright + * Remove non-free files in d/copyright + * Fix debian/watch file + * Update debian/copyright with new removals + * Drop get-orig-source target from d/rules. + Use uscan for generating repacked original tarball. + * Imported Upstream version 14.1+dfsg1 + http://kodi.tv/kodi-14-1-helix-bugfix-release + * Copyright updates + * Use avformat_flush(), it is now exported by FFmpeg + * Stop using files omitted from DFSG-free tarballs + * Sort filenames omitted from original tarball + * Omit embedded Boost header from original tarball + * Download original tarball from GitHub + * Imported Upstream version 14.2+dfsg1 + http://kodi.tv/kodi-14-2-helix-the-final-translation + + -- Balint Reczey <balint@balintreczey.hu> Sat, 17 Jan 2015 00:30:36 +0100 + +kodi (14.0+dfsg1-1) experimental; urgency=medium + + * New upstream release 14.0 (CVE-2013-1438) + See http://kodi.tv/kodi-14-0-helix-unwinds + * Refresh patches + * Generate "from Debian" logo from SVG + + -- Balint Reczey <balint@balintreczey.hu> Fri, 02 Jan 2015 13:19:52 +0100 + +kodi (14.0~beta1+dfsg1-1) experimental; urgency=medium + + * First packaged Kodi version based on xbmc 2:13.2+dfsg1-4 + See http://kodi.tv/introducing-kodi-14 for the rationale behind the + name change (Closes: #767180) + * Use packaged FFmpeg + * Stop using internal ffmpeg functions + * Build-depend on libcec-dev >= 2.2 + * Add upstream patches for fixing suspend and adding MIPS support + + -- Balint Reczey <balint@balintreczey.hu> Sat, 08 Nov 2014 11:14:40 +0100 diff --git a/debian/control b/debian/control new file mode 100644 index 0000000..e6327fe --- /dev/null +++ b/debian/control @@ -0,0 +1,543 @@ +Source: kodi +Priority: optional +Section: video +Maintainer: Debian Multimedia Maintainers <debian-multimedia@lists.debian.org> +Uploaders: Vasyl Gello <vasek.gello@gmail.com> +Build-Depends: autoconf, + automake, + autopoint, + cmake, + curl, + debhelper-compat (= 13), + default-jre:native, + default-libmysqlclient-dev, + dh-python, + doxygen, + fontforge-nox, + fonts-dejavu-core, + fonts-droid-fallback, + gawk, + gettext, + gperf, + groovy:native, + libhowardhinnant-date-dev, + libasound2-dev | libasound-dev, + libass-dev, + libavahi-client-dev, + libavahi-common-dev, + libavcodec-dev (>= 7:4.2.2), + libavfilter-dev (>= 7:4.2.2), + libavformat-dev (>= 7:4.2.2), + libavutil-dev (>= 7:4.2.2), + libbluetooth-dev, + libbluray-dev (>= 1:0.7.0), + libcap-dev, + libcdio-dev, + libcec-dev (>= 4~), + libcommons-lang-java:native, + libcrossguid-dev, + libcurl4-gnutls-dev | libcurl-dev, + libcwiid-dev [linux-any], + libdav1d-dev (>= 0.7.0), + libdbus-1-dev, + libdrm-dev, +# libdvdnav-dev, use patched embedded version +# libdvdread-dev, use patched embedded version + libegl1-mesa-dev, + libflatbuffers-dev, + libfmt-dev (>= 6.1.2), + libfontconfig-dev, + libfreetype-dev | libfreetype6-dev, + libfribidi-dev, + libfstrcmp-dev, + libgbm-dev, + libgcrypt-dev, + libgif-dev, + libgif-dev:native, + libgl-dev, + libglew-dev, + libglu1-mesa-dev | libglu-dev, + libgnutls28-dev, + libgpg-error-dev, + libgtest-dev (>= 1.10.0~), + libinput-dev, + libiso9660-dev, + libiso9660++-dev, + libjpeg-dev, + libjpeg-dev:native, + libkissfft-dev (>= 131.1.0~), + liblcms2-dev, + liblirc-dev | liblircclient-dev, + libltdl-dev, + liblzo2-dev, + liblzo2-dev:native, + libmicrohttpd-dev, + libnfs-dev, + libomxil-bellagio-dev [armel], + libpcre2-dev, + libpipewire-0.3-dev, + libplist-dev, + libpng-dev, + libpng-dev:native, + libpostproc-dev (>= 7:4.2.2), + libpulse-dev, + libpython3-dev, + librsvg2-bin, + libshairplay-dev (>= 0.9.0~), + libsmbclient-dev, + libsndio-dev, + libspdlog-dev (>= 1:1.5.0), + libsqlite3-dev, + libswresample-dev (>= 7:4.2.2), + libswscale-dev (>= 7:4.2.2), + libtag1-dev (>= 1.8), + libtinyxml-dev, + libtool, + libudev-dev, + libudfread-dev (>= 1.0.0), + libva-dev, + libvdpau-dev, + libxkbcommon-dev, + libxrandr-dev, + libxslt1-dev, + libxt-dev, + nasm [i386], + python3-dev:any, + rapidjson-dev, + swig, + unzip, + uuid-dev, + valgrind [amd64 i386], + wayland-protocols, + waylandpp-dev, + zip, + zlib1g-dev +Standards-Version: 4.6.2 +Rules-Requires-Root: no +Vcs-Browser: https://salsa.debian.org/multimedia-team/kodi-media-center/kodi +Vcs-Git: https://salsa.debian.org/multimedia-team/kodi-media-center/kodi.git -b debian/sid +Homepage: https://kodi.tv/ + +Package: kodi +Architecture: any +Depends: kodi-bin (>= ${source:Version}), + kodi-bin (<< ${source:Version}.1~), + kodi-data (>= ${source:Version}), + ${misc:Depends} +Recommends: kodi-repository-kodi | kodi-repository, + kodi-visualization-spectrum +Breaks: xbmc (<< 2:13.2+dfsg1-5~), ${kodi:APIBREAKS} +Provides: ${kodi:APIPROVIDES} +Replaces: xbmc (<< 2:13.2+dfsg1-5~) +Description: Open Source Home Theatre (executable binaries) + Kodi, formerly known as XBMC is an award winning free and + open source software media-player and entertainment hub for all your digital + media. Kodi is available for Linux, Mac OS X (Leopard, Tiger and Apple TV) + and Microsoft Windows, as well as the original Xbox game console. Created in + 2003 by a group of like minded programmers, Kodi is a non-profit project run + and developed by volunteers located around the world. More than 50 software + developers have contributed to Kodi, and 100-plus translators have worked to + expand its reach, making it available in more than 30 languages. + . + While Kodi functions very well as a standard media player application for + your computer, it has been designed to be the perfect companion for your + HTPC. Supporting an almost endless range of remote controls, and combined + with its beautiful interface and powerful skinning engine, Kodi feels very + natural to use from the couch and is the ideal solution for your home + theater. Once installed, your computer will become a fully functional + multimedia jukebox. + . + This package contains the kodi binaries. + +Package: kodi-data +Architecture: all +Multi-Arch: foreign +Depends: mesa-utils, + x11-utils, + libjs-jquery, + libjs-iscroll, + ${misc:Depends} +Recommends: fonts-noto-core, + fonts-noto-mono, + fonts-roboto-unhinted, +Suggests: fonts-noto-ui-core, +Breaks: xbmc (<< 2:13.2+dfsg1-5~) +Replaces: xbmc (<< 2:13.2+dfsg1-5~) +Description: Open Source Home Theatre (arch-independent data package) + Kodi, formerly known as XBMC is an award winning free and + open source software media-player and entertainment hub for all your digital + media. Kodi is available for Linux, Mac OS X (Leopard, Tiger and Apple TV) + and Microsoft Windows, as well as the original Xbox game console. Created in + 2003 by a group of like minded programmers, Kodi is a non-profit project run + and developed by volunteers located around the world. More than 50 software + developers have contributed to Kodi, and 100-plus translators have worked to + expand its reach, making it available in more than 30 languages. + . + While Kodi functions very well as a standard media player application for + your computer, it has been designed to be the perfect companion for your + HTPC. Supporting an almost endless range of remote controls, and combined + with its beautiful interface and powerful skinning engine, Kodi feels very + natural to use from the couch and is the ideal solution for your home + theater. Once installed, your computer will become a fully functional + multimedia jukebox. + . + This package contains all the architecture independent data needed to have a + working Kodi. + +Package: kodi-bin +Architecture: any +Depends: python3-pil, + python3-pycryptodome, + ${python3:Depends}, + ${dlopenlibs:Depends}, + ${shlibs:Depends}, + ${misc:Depends}, +Recommends: ${shlibs:Recommends}, + udisks2 +Pre-Depends: ${misc:Pre-Depends} +Breaks: xbmc-bin (<< 2:13.2+dfsg1-5~) +Conflicts: libgl1-mesa-swx11 +Replaces: xbmc-bin (<< 2:13.2+dfsg1-5~) +Description: Open Source Home Theatre (architecture-dependent files) + Kodi, formerly known as XBMC is an award winning free and + open source software media-player and entertainment hub for all your digital + media. Kodi is available for Linux, Mac OS X (Leopard, Tiger and Apple TV) + and Microsoft Windows, as well as the original Xbox game console. Created in + 2003 by a group of like minded programmers, Kodi is a non-profit project run + and developed by volunteers located around the world. More than 50 software + developers have contributed to Kodi, and 100-plus translators have worked to + expand its reach, making it available in more than 30 languages. + . + While Kodi functions very well as a standard media player application for + your computer, it has been designed to be the perfect companion for your + HTPC. Supporting an almost endless range of remote controls, and combined + with its beautiful interface and powerful skinning engine, Kodi feels very + natural to use from the couch and is the ideal solution for your home + theater. Once installed, your computer will become a fully functional + multimedia jukebox. + . + This package contains the binaries needed to have a working Kodi. + +Package: kodi-eventclients-common +Architecture: all +Multi-Arch: foreign +Depends: ${misc:Depends} +Description: Open Source Home Theatre (Event Client Common package) + Kodi, formerly known as XBMC is an award winning free and + open source software media-player and entertainment hub for all your digital + media. Kodi is available for Linux, Mac OS X (Leopard, Tiger and Apple TV) + and Microsoft Windows, as well as the original Xbox game console. Created in + 2003 by a group of like minded programmers, Kodi is a non-profit project run + and developed by volunteers located around the world. More than 50 software + developers have contributed to Kodi, and 100-plus translators have worked to + expand its reach, making it available in more than 30 languages. + . + While Kodi functions very well as a standard media player application for + your computer, it has been designed to be the perfect companion for your + HTPC. Supporting an almost endless range of remote controls, and combined + with its beautiful interface and powerful skinning engine, Kodi feels very + natural to use from the couch and is the ideal solution for your home + theater. Once installed, your computer will become a fully functional + multimedia jukebox. + . + This package is the common package for Kodi Event Client. + +Package: kodi-eventclients-python +Architecture: any +Depends: kodi-eventclients-common (= ${source:Version}), + python3-bluez, + ${python3:Depends}, + ${misc:Depends} +Breaks: kodi-eventclients-common (<< 2:19.4+dfsg1-1~) +Replaces: kodi-eventclients-common (<< 2:19.4+dfsg1-1~) +Description: Open Source Home Theatre (Event Client Python package) + Kodi, formerly known as XBMC is an award winning free and + open source software media-player and entertainment hub for all your digital + media. Kodi is available for Linux, Mac OS X (Leopard, Tiger and Apple TV) + and Microsoft Windows, as well as the original Xbox game console. Created in + 2003 by a group of like minded programmers, Kodi is a non-profit project run + and developed by volunteers located around the world. More than 50 software + developers have contributed to Kodi, and 100-plus translators have worked to + expand its reach, making it available in more than 30 languages. + . + While Kodi functions very well as a standard media player application for + your computer, it has been designed to be the perfect companion for your + HTPC. Supporting an almost endless range of remote controls, and combined + with its beautiful interface and powerful skinning engine, Kodi feels very + natural to use from the couch and is the ideal solution for your home + theater. Once installed, your computer will become a fully functional + multimedia jukebox. + . + This package is the virtual Python package for Kodi Event Client. + +Package: kodi-eventclients-dev-common +Architecture: all +Multi-Arch: foreign +Section: libdevel +Depends: ${misc:Depends} +Breaks: kodi-eventclients-dev (<< 2:19.4+dfsg1-1~) +Replaces: kodi-eventclients-dev (<< 2:19.4+dfsg1-1~) +Description: Open Source Home Theatre (Event Client common dev package) + Kodi, formerly known as XBMC is an award winning free and + open source software media-player and entertainment hub for all your digital + media. Kodi is available for Linux, Mac OS X (Leopard, Tiger and Apple TV) + and Microsoft Windows, as well as the original Xbox game console. Created in + 2003 by a group of like minded programmers, Kodi is a non-profit project run + and developed by volunteers located around the world. More than 50 software + developers have contributed to Kodi, and 100-plus translators have worked to + expand its reach, making it available in more than 30 languages. + . + While Kodi functions very well as a standard media player application for + your computer, it has been designed to be the perfect companion for your + HTPC. Supporting an almost endless range of remote controls, and combined + with its beautiful interface and powerful skinning engine, Kodi feels very + natural to use from the couch and is the ideal solution for your home + theater. Once installed, your computer will become a fully functional + multimedia jukebox. + . + This is the common development package for Kodi Event Client. + +Package: kodi-eventclients-dev +Architecture: any +Section: libdevel +Depends: kodi-eventclients-dev-common (= ${source:Version}), + kodi-eventclients-python (= ${binary:Version}), + ${misc:Depends} +Description: Open Source Home Theatre (Event Client virtual dev package) + Kodi, formerly known as XBMC is an award winning free and + open source software media-player and entertainment hub for all your digital + media. Kodi is available for Linux, Mac OS X (Leopard, Tiger and Apple TV) + and Microsoft Windows, as well as the original Xbox game console. Created in + 2003 by a group of like minded programmers, Kodi is a non-profit project run + and developed by volunteers located around the world. More than 50 software + developers have contributed to Kodi, and 100-plus translators have worked to + expand its reach, making it available in more than 30 languages. + . + While Kodi functions very well as a standard media player application for + your computer, it has been designed to be the perfect companion for your + HTPC. Supporting an almost endless range of remote controls, and combined + with its beautiful interface and powerful skinning engine, Kodi feels very + natural to use from the couch and is the ideal solution for your home + theater. Once installed, your computer will become a fully functional + multimedia jukebox. + . + This is the virtual development package for Kodi Event Client. + +Package: kodi-eventclients-wiiremote +Architecture: any +Depends: kodi-eventclients-python (= ${binary:Version}), + ${python3:Depends}, + ${shlibs:Depends}, + ${misc:Depends} +Description: Open Source Home Theatre (Event Client WII Remote support package) + Kodi, formerly known as XBMC is an award winning free and + open source software media-player and entertainment hub for all your digital + media. Kodi is available for Linux, Mac OS X (Leopard, Tiger and Apple TV) + and Microsoft Windows, as well as the original Xbox game console. Created in + 2003 by a group of like minded programmers, Kodi is a non-profit project run + and developed by volunteers located around the world. More than 50 software + developers have contributed to Kodi, and 100-plus translators have worked to + expand its reach, making it available in more than 30 languages. + . + While Kodi functions very well as a standard media player application for + your computer, it has been designed to be the perfect companion for your + HTPC. Supporting an almost endless range of remote controls, and combined + with its beautiful interface and powerful skinning engine, Kodi feels very + natural to use from the couch and is the ideal solution for your home + theater. Once installed, your computer will become a fully functional + multimedia jukebox. + . + This package is the Wii Remote client package for Kodi. + +Package: kodi-eventclients-ps3 +Architecture: any +Depends: kodi-eventclients-python (= ${binary:Version}), + python3-pyudev, + python3-usb, + ${python3:Depends}, + ${misc:Depends} +Breaks: kodi-eventclients-common (<< 2:19.0~alpha3+dfsg1-1~) +Replaces: kodi-eventclients-common (<< 2:19.0~alpha3+dfsg1-1~) +Description: Open Source Home Theatre (Event Client PS3 package) + Kodi, formerly known as XBMC is an award winning free and + open source software media-player and entertainment hub for all your digital + media. Kodi is available for Linux, Mac OS X (Leopard, Tiger and Apple TV) + and Microsoft Windows, as well as the original Xbox game console. Created in + 2003 by a group of like minded programmers, Kodi is a non-profit project run + and developed by volunteers located around the world. More than 50 software + developers have contributed to Kodi, and 100-plus translators have worked to + expand its reach, making it available in more than 30 languages. + . + While Kodi functions very well as a standard media player application for + your computer, it has been designed to be the perfect companion for your + HTPC. Supporting an almost endless range of remote controls, and combined + with its beautiful interface and powerful skinning engine, Kodi feels very + natural to use from the couch and is the ideal solution for your home + theater. Once installed, your computer will become a fully functional + multimedia jukebox. + . + This package is the PS3 package for Kodi Event Client. + +Package: kodi-eventclients-kodi-send +Architecture: any +Depends: kodi-eventclients-python (= ${binary:Version}), + ${python3:Depends}, + ${misc:Depends} +Description: Open Source Home Theatre (Event Client Kodi-SEND package) + Kodi, formerly known as XBMC is an award winning free and + open source software media-player and entertainment hub for all your digital + media. Kodi is available for Linux, Mac OS X (Leopard, Tiger and Apple TV) + and Microsoft Windows, as well as the original Xbox game console. Created in + 2003 by a group of like minded programmers, Kodi is a non-profit project run + and developed by volunteers located around the world. More than 50 software + developers have contributed to Kodi, and 100-plus translators have worked to + expand its reach, making it available in more than 30 languages. + . + While Kodi functions very well as a standard media player application for + your computer, it has been designed to be the perfect companion for your + HTPC. Supporting an almost endless range of remote controls, and combined + with its beautiful interface and powerful skinning engine, Kodi feels very + natural to use from the couch and is the ideal solution for your home + theater. Once installed, your computer will become a fully functional + multimedia jukebox. + . + This package is the Kodi-SEND package for Kodi Event Client. + +Package: kodi-eventclients-zeroconf +Architecture: any +Depends: kodi-eventclients-python (= ${binary:Version}), + python3-avahi, + python3-dbus, + python3-gi, + ${python3:Depends}, + ${misc:Depends} +Breaks: kodi-eventclients-common (<< 2:19.0~alpha3+dfsg1-1~) +Replaces: kodi-eventclients-common (<< 2:19.0~alpha3+dfsg1-1~) +Description: Open Source Home Theatre (Event Client ZeroConf script package) + Kodi, formerly known as XBMC is an award winning free and + open source software media-player and entertainment hub for all your digital + media. Kodi is available for Linux, Mac OS X (Leopard, Tiger and Apple TV) + and Microsoft Windows, as well as the original Xbox game console. Created in + 2003 by a group of like minded programmers, Kodi is a non-profit project run + and developed by volunteers located around the world. More than 50 software + developers have contributed to Kodi, and 100-plus translators have worked to + expand its reach, making it available in more than 30 languages. + . + While Kodi functions very well as a standard media player application for + your computer, it has been designed to be the perfect companion for your + HTPC. Supporting an almost endless range of remote controls, and combined + with its beautiful interface and powerful skinning engine, Kodi feels very + natural to use from the couch and is the ideal solution for your home + theater. Once installed, your computer will become a fully functional + multimedia jukebox. + . + This package is the ZeroConf script for Kodi Event Client. + +Package: kodi-addons-dev-common +Architecture: all +Multi-Arch: foreign +Section: libdevel +Depends: ${misc:Depends} +Breaks: kodi-addons-dev (<< 2:19.4+dfsg1-1~) +Replaces: kodi-addons-dev (<< 2:19.4+dfsg1-1~) +Description: Open Source Home Theatre (architecture-independent addon development package) + Kodi, formerly known as XBMC is an award winning free and + open source software media-player and entertainment hub for all your digital + media. Kodi is available for Linux, Mac OS X (Leopard, Tiger and Apple TV) + and Microsoft Windows, as well as the original Xbox game console. Created in + 2003 by a group of like minded programmers, Kodi is a non-profit project run + and developed by volunteers located around the world. More than 50 software + developers have contributed to Kodi, and 100-plus translators have worked to + expand its reach, making it available in more than 30 languages. + . + While Kodi functions very well as a standard media player application for + your computer, it has been designed to be the perfect companion for your + HTPC. Supporting an almost endless range of remote controls, and combined + with its beautiful interface and powerful skinning engine, Kodi feels very + natural to use from the couch and is the ideal solution for your home + theater. Once installed, your computer will become a fully functional + multimedia jukebox. + . + This is the development package for Kodi Addons. + . + This package contains independent headers for building addons without the need + to keep a whole Kodi source tree. + +Package: kodi-addons-dev +Section: libdevel +Architecture: any +Multi-Arch: same +Provides: dh-sequence-kodiaddon (= ${binary:Version}) +Depends: kodi-addons-dev-common (= ${source:Version}), + ${misc:Depends} +Breaks: kodi-addons-dev-common (<< 2:20.0~rc1+dfsg1-1~) +Replaces: kodi-addons-dev-common (<< 2:20.0~rc1+dfsg1-1~) +Description: Open Source Home Theatre (addon development package) + This package is a dummy package used in conjunction with kodi-addons-dev + to detect if a binary addon should be built for given Debian architecture. + . + The alternative to introducing this package is marking kodi-addons-dev back + as arch:any, but this makes Lintian and multi-arch hinter noisy. + . + If Kodi upstream starts shipping architecture-specific development libraries + again, they will land in this package. + +Package: kodi-repository-kodi +Architecture: all +Multi-Arch: foreign +Depends: ${misc:Depends} +Enhances: kodi +Breaks: kodi-data (<< 2:17.3+dfsg1-5~), + xbmc (<< 2:13.2+dfsg1-5~) +Conflicts: kodi-repository +Provides: kodi-repository +Replaces: kodi-repository, + kodi-data (<< 2:17.3+dfsg1-5~), + xbmc (<< 2:13.2+dfsg1-5~) +Description: Open Source Home Theatre (official addons repository feed) + Kodi, formerly known as XBMC is an award winning free and + open source software media-player and entertainment hub for all your digital + media. Kodi is available for Linux, Mac OS X (Leopard, Tiger and Apple TV) + and Microsoft Windows, as well as the original Xbox game console. Created in + 2003 by a group of like minded programmers, Kodi is a non-profit project run + and developed by volunteers located around the world. More than 50 software + developers have contributed to Kodi, and 100-plus translators have worked to + expand its reach, making it available in more than 30 languages. + . + While Kodi functions very well as a standard media player application for + your computer, it has been designed to be the perfect companion for your + HTPC. Supporting an almost endless range of remote controls, and combined + with its beautiful interface and powerful skinning engine, Kodi feels very + natural to use from the couch and is the ideal solution for your home + theater. Once installed, your computer will become a fully functional + multimedia jukebox. + . + This package enables download of addons via the official Kodi + repository feed. + +Package: kodi-tools-texturepacker +Architecture: any +Depends: ${shlibs:Depends}, + ${misc:Depends} +Breaks: kodi-bin (<< 2:19.4+dfsg1-1~) +Replaces: kodi-bin (<< 2:19.4+dfsg1-1~) +Description: Open Source Home Theatre (TexturePacker skin development tool) + Kodi, formerly known as XBMC is an award winning free and + open source software media-player and entertainment hub for all your digital + media. Kodi is available for Linux, Mac OS X (Leopard, Tiger and Apple TV) + and Microsoft Windows, as well as the original Xbox game console. Created in + 2003 by a group of like minded programmers, Kodi is a non-profit project run + and developed by volunteers located around the world. More than 50 software + developers have contributed to Kodi, and 100-plus translators have worked to + expand its reach, making it available in more than 30 languages. + . + While Kodi functions very well as a standard media player application for + your computer, it has been designed to be the perfect companion for your + HTPC. Supporting an almost endless range of remote controls, and combined + with its beautiful interface and powerful skinning engine, Kodi feels very + natural to use from the couch and is the ideal solution for your home + theater. Once installed, your computer will become a fully functional + multimedia jukebox. + . + This package contains TexturePacker, the tool for Kodi skin developers. + End users don't need this package to run Kodi. diff --git a/debian/copyright b/debian/copyright new file mode 100644 index 0000000..adf4c04 --- /dev/null +++ b/debian/copyright @@ -0,0 +1,1693 @@ +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: Kodi +Source: http://kodi.tv/ +Files-Excluded: .github + addons/service.xbmc.versioncheck + addons/skin.estuary/fonts/*.ttf + addons/skin.estouchy/fonts/*.ttf + addons/webinterface.default + lib/libUPnP/Neptune/ThirdParty/zlib-* + lib/libUPnP/Platinum/Build/Targets/mipsel-psp-linux + lib/libUPnP/Platinum/Build/Targets/x86-microsoft-win32-vs2010 + lib/libUPnP/Platinum/ThirdParty/log4net + lib/win32 + media/Fonts/arial.ttf + project/BuildDependencies + project/Win32BuildSetup + system/certs + tools/android + tools/codegenerator/groovy + tools/darwin + tools/depends/target + tools/EventClients/Clients/OSXRemote + tools/windows + xbmc/platform/android + xbmc/platform/darwin + xbmc/platform/win10 + xbmc/platform/win32 +Files-Included: tools/depends/target/*-VERSION +Files-Excluded-repo-resources-embedded: .github + * +Files-Included-repo-resources-embedded: resource.language.* + +Files: * +Copyright: + 2005-2023, Team Kodi <http://kodi.tv/> + the authors of ffmpeg and xvid + the authors of libPlatinum <http://www.plutinosoft.com/blog/category/platinum/> + 1997-2009, Sam Lantinga <slouken@libsdl.org> + 2000-2004, Convergence (integrated media) GmbH + 2001-2009, The world wide DirectFB Open Source Community <http://directfb.org/> + 2002, Albert Griscti-Soler (RUNTiME) + 2002, Phil Burr (d7o3g4q) + 2002,2007, Erwin Beckers (Frodo) + 2003, The Joker / Avalaunch team + 2003-2017, Team XBMC <http://xbmc.org/> + 2003,2006-2007, Ralf Baechle <ralf@linux-mips.org> + 2005, Free Software Foundation, Inc. + 2006, Joakim Plate (elupus) + 2006, Sylvain Rebaud (c0diq) + 2007, Jonathan Marshall (jcmarshall) + 2007, Roee Vulkan (vulkanr) + 2007-2008, Anoop Menon (d4rk) + 2007-2008, Eric Steil III + 2007,2011, Tobias Arrskog (topfs) <https://github.com/topfs2> + 2008, University Heidelberg + 2008, Wladimir J. van der Laan + 2010, Team Boxee <http://www.boxee.tv/> + 2012, Denis Yantarev + 2015-2016, Lauri Mylläri + 2016-2018, Chris Browet + 2016, 2017, Tobias Kortkamp <t@tobik.me> + 2018, Tyler Szabo +License-Grant: + 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. +License: GPL-2+ +Comment: + Copyright holders "Team XboxMediaCenter" and "Team XBMC" assumed + to be equal to "Team Kodi". + +Files: addons/skin.estouchy/* +Copyright: Team Kodi <http://kodi.tv/> +License-Grant: + This work is licensed + under the Creative Commons Attribution-Share Alike 3.0 United States + License. +License: CC-BY-SA-3.0~us +Comment: + Copyright information missing from source files. + Copyright holder assumed to be main project author. + License assumed from license grant + located in <addons/skin.estouchy/LICENSE.txt>. + +Files: addons/skin.estuary/* +Copyright: phil65 & Piers (Team Kodi) +License-Grant: + Estuary code work is licensed + under GNU General Public License (GPL), Version 2.0 +License: GPL-2 + +Files: addons/skin.estuary/*.jpg + addons/skin.estuary/*.png +Copyright: phil65 & Piers (Team Kodi) +License-Grant: + Estuary Artwork is licensed + under a Creative Commons Attribution-ShareAlike 4.0 Unported License. +License: CC-BY-SA-4.0 + +Files: addons/skin.estuary/extras/home-images/movie.jpg + addons/skin.estuary/extras/home-images/music.jpg +Copyright: UNKNOWN +License-Grant: + movie.jpg: https://creativecommons.org/publicdomain/zero/1.0/legalcode + music.jpg: https://creativecommons.org/publicdomain/zero/1.0/legalcode +License: CC0-1.0 +Comment: + Missing copyright and licensing information in source file. + License assumed from license grant + located in addons/skin.estuary/extras/home-images/LICENSE. + +Files: addons/skin.estuary/media/windows/subtitles/flags/* +Copyright: 2013, Go Squared Ltd. <http:www.gosquared.com/> +License: Expat +Comment: + Copyright and license assumed from + <addons/skin.estuary/media/windows/subtitles/flags/LICENSE.txt>. + +Files: cmake/modules/extra/ECMEnableSanitizers.cmake + cmake/modules/FindLibXml2.cmake +Copyright: + 2006, Alexander Neundorf <neundorf@kde.org> + 2006-2009, Kitware, Inc. + 2014, Mathieu Tarral <mathieu.tarral@gmail.com> + 2016, Team Kodi <http://kodi.tv/> +License-Grant: + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. +License: BSD-3-clause +Comment: + License grant ambiguous regarding exact BSD license. + License assumed to be the same as clarified + in CMake project commit 86578ec: + <https://github.com/Kitware/CMake/commit/86578eccf2e82286248796bad1032cd0e3a5e1e2>. + +Files: lib/libUPnP/Neptune/* +Copyright: 2002-2012, Axiomatic Systems, LLC +License: BSD-3-clause~Axiomatic + +Files: lib/libUPnP/Neptune/Source/Apps/* + lib/libUPnP/Neptune/Source/System/* + lib/libUPnP/Neptune/Source/Tests/* +Copyright: + 2001-2014, Gilles Boccon-Gibod <bok@bok.net> + 2005-2010, Axiomatic Systems, LLC. +License: BSD-3-clause~Axiomatic +Comment: + Licensing information missing from source files. + License assumed from <lib/libUPnP/Neptune/LICENSE>, + and from Gilles Boccon-Gibod being former president for Axiomatic + according to + <https://www.corporationwiki.com/California/Los-Altos/gilles-boccon-gibod/43430379.aspx> + +Files: lib/libUPnP/Neptune/ThirdParty/axTLS/* +Copyright: 2007, Cameron Rich +License: BSD-3-clause~axTLS + +Files: lib/libUPnP/Platinum/* +Copyright: 2004-2012, Plutinosoft, LLC +License-Grant: + 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 of the License, or (at your option) any later version. +License: GPL-2+ +Comment: + Licensing information missing from some source files: + <lib/libUPnP/Platinum/Source/Platform/Android/module/platinum/jni/platinum-jni.cpp> + <lib/libUPnP/Platinum/Source/Tests/MediaServerCocoaTest/main.mm> + License assumed to be same as related files + with same copyright holder. + +Files: lib/libUPnP/Platinum/Source/Extras/ObjectiveC/PltMediaServerObject.h + lib/libUPnP/Platinum/Source/Extras/ObjectiveC/PltMediaServerObject.mm + lib/libUPnP/Platinum/Source/Extras/ObjectiveC/PltUPnPObject.h + lib/libUPnP/Platinum/Source/Extras/ObjectiveC/PltUPnPObject.mm + lib/libUPnP/Platinum/Source/Tests/MediaServerCocoaTest/MediaServerCocoaTestController.h + lib/libUPnP/Platinum/Source/Tests/MediaServerCocoaTest/MediaServerCocoaTestController.mm +Copyright: 2010-2011, Plutinosoft LLC +License: GPL-2+ +Comment: + Licensing information missing from source files. + License assumed to be same as generally for same copyright holder. + +Files: libdvdnav-embedded/* +Copyright: 2000-2001, Björn Englund + 2006-2007, Diego Pettenò <flameeyes@gmail.com> + 1989-1991, Free Software Foundation, Inc + 2000-2001, Håkan Hjort + 2000-2001, Martin Norbäck + 2000-2004, Rich Wareham <richwareham@users.sourceforge.net> + 2001-2004, the libdvdnav project + 2000-2007, the xine project + 2001-2023, The VideoLAN Project +License: GPL-2+ + +Files: libdvdread-embedded/* +Copyright: Apache Software Foundation + 2000-2004, Billy Biggs <vektor@dumbterm.net> + 2000-2003, Björn Englund <d4bjorn@dtek.chalmers.se> + 1999-2001, Christian Wolff <scarabaeus@convergence.de> + 2006-2007, Diego Pettenò <flameeyes@gmail.com> + 1989-1991, Free Software Foundation, Inc + 2000-2003, Håkan Hjort <d95hjort@dtek.chalmers.se> + 1997, Kevlin Henney + 2001, Rich Wareham <richwareham@users.sourceforge.net> + 2001-2002, Samuel Hocevar <sam@zoy.org> + 2000-2007, the xine project + 2000-2023, The VideoLAN Project +License: GPL-2+ + +Files: libdvdread-embedded/src/dvdread/version.h.in + libdvdread-embedded/src/md5.c + libdvdread-embedded/src/md5.h +Copyright: 1995-2003, Free Software Foundation, Inc + 2004-2015, VLC authors and VideoLAN +License: LGPL-2.1+ + +Files: libdvdread-embedded/src/dvdread/nav_types.h + libdvdread-embedded/src/nav_print.c +Copyright: 1998-1999, Eric Smith <eric@brouhaha.com> + 2000-2003, Håkan Hjort <d95hjort@dtek.chalmers.se> +License: GPL-2 or GPL-3 + +Files: repo-resources-embedded/* +Copyright: 2005-2023, Team Kodi +License: GPL-2+ +Comment: Translations are maintained via Kodi project on Weblate. + +Files: system/players/VideoPlayer/etc/fonts/conf.avail/65-fonts-persian.conf + system/players/VideoPlayer/etc/fonts/conf.d/65-fonts-persian.conf +Copyright: 2005, Sharif FarsiWeb, Inc. <license@farsiweb.info> +License: NTP~disclaimer~FarsiWeb + +Files: tools/depends/build-aux/config.guess + tools/depends/build-aux/config.sub +Copyright: 1992-2016, Free Software Foundation, Inc. +License-Grant: + This file 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 3 of the License, or (at your option) any later version. +License: GPL-3+ with Autoconf exception + As a special exception to the GNU General Public License, + if you distribute this file as part of a program + that contains a configuration script generated by Autoconf, + you may include it under the same distribution terms + that you use for the rest of that program. + This Exception is an additional permission + under section 7 of the GNU General Public License, version 3 ("GPLv3"). + +Files: tools/depends/build-aux/install-sh +Copyright: 1994, X Consortium +License: X11 +Comment: FSF changes to this file are in the public domain. + +Files: tools/depends/native/TexturePacker/src/Win32/dirent.c + tools/depends/native/TexturePacker/src/Win32/dirent.h +Copyright: 1997,2003, Kevlin Henney <kevlin@acm.org>, <kevlin@curbralan.com> +License: ISC~minimal-disclaimer + +Files: tools/depends/native/TexturePacker/src/md5.cpp + tools/depends/native/TexturePacker/src/md5.h +Copyright: None (in the public domain) +License: public-domain + This code was written by Colin Plumb in 1993, no copyright is claimed. + This code is in the public domain; do with it what you wish. + +Files: tools/EventClients/Clients/WiiRemote/WiiUse_WiiRemote.cpp + tools/EventClients/Clients/WiiRemote/WiiUse_WiiRemote.h +Copyright: 2009, Cory Fields +License-Grant: + 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 3 of the License, or (at your option) any later version. +License: GPL-3+ + +Files: tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/* +Copyright: 2006-2007, Michael Laforest (para) <thepara@gmail.com> +License-Grant: + 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 3 of the License, or (at your option) any later version. +License: GPL-3+ + +Files: tools/EventClients/icons/bluetooth.png +Copyright: 2003, Jakub Steiner (jimmac) <http://jimmac.musichall.cz/> +License: GPL-2+ +Comment: + Licensing information missing from source file. + I've asked upstream to clarify the license + https://github.com/xbmc/xbmc/issues/17252 + +Files: xbmc/addons/AudioDecoder.cpp + xbmc/addons/AudioDecoder.h +Copyright: 2013, 2014 Arne Morten Kvarving (cptspiff) +License-Grant: + 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. +License: GPL-2+ + +Files: xbmc/addons/VFSEntry.cpp + xbmc/addons/VFSEntry.h +Copyright: 2013, 2014 Arne Morten Kvarving (cptspiff) +License-Grant: + 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. +License: GPL-2+ + +Files: xbmc/contrib/kissfft/* +Copyright: 2003-2010, Mark Borgerding +License: BSD-3-clause + +Files: xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEBuffer.cpp + xbmc/cores/VideoPlayer/DVDCodecs/Video/VAAPI.cpp + xbmc/cores/VideoPlayer/DVDCodecs/Video/VAAPI.h + xbmc/cores/VideoPlayer/DVDCodecs/Video/VTB.cpp + xbmc/cores/VideoPlayer/DVDCodecs/Video/VTB.h + xbmc/cores/VideoPlayer/VideoRenderers/RenderFlags.cpp + xbmc/guilib/StereoscopicsManager.cpp + xbmc/guilib/StereoscopicsManager.h + xbmc/platform/linux/sse4/CopyFrame.cpp + xbmc/utils/ActorProtocol.cpp + xbmc/utils/ActorProtocol.h +Copyright: + 2005-2015, Team Kodi <http://kodi.tv/> + 2005-2016, Team XBMC <http://xbmc.org/> +License-Grant: + This library is free software; + you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License + as published by the Free Software Foundation; + either version 2.1 of the License, + or (at your option) any later version. +License: LGPL-2.1+ + +Files: xbmc/cores/VideoPlayer/DVDCodecs/Overlay/contrib/cc_decoder.c + xbmc/cores/VideoPlayer/DVDCodecs/Overlay/contrib/cc_decoder.h +Copyright: + 2000-2008, the xine project + 2001, Christian Vogler <cvogler@gradient.cis.upenn.edu> +License-Grant: + xine 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 of the License, or (at your option) any later version. +License: GPL-2+ + +Files: xbmc/cores/VideoPlayer/DVDInputStreams/dvdnav/dvdnav.h + xbmc/cores/VideoPlayer/DVDInputStreams/dvdnav/dvdnav_events.h +Copyright: + 2001, Håkan Hjort <d95hjort@dtek.chalmers.se> + 2001, Martin Norbäck + 2001-2004, Rich Wareham <richwareham@users.sourceforge.net> +License-Grant: + libdvdnav 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 of the License, or (at your option) any later version. +License: GPL-2+ + +Files: xbmc/cores/VideoPlayer/DVDInputStreams/dvdnav/dvd_reader.h + xbmc/cores/VideoPlayer/DVDInputStreams/dvdnav/dvd_types.h + xbmc/cores/VideoPlayer/DVDInputStreams/dvdnav/ifo_types.h +Copyright: + 2000-2002, Håkan Hjort <d95hjort@dtek.chalmers.se> + 2001, Rich Wareham <richwareham@users.sourceforge.net> + 2001-2002, Billy Biggs <vektor@dumbterm.net> + 2001-2002, Björn Englund <d4bjorn@dtek.chalmers.se> +License-Grant: + libdvdread 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 of the License, or (at your option) any later version. +License: GPL-2+ +Comment: + Copyright information missing from one source file: + <xbmc/cores/VideoPlayer/DVDInputStreams/dvdnav/remap.h>. + Copyright assumed to be same as (or a subset of) that of other files + with identical license grant. + +Files: xbmc/cores/VideoPlayer/DVDInputStreams/dvdnav/nav_types.h +Copyright: + 1998-1999, Eric Smith <eric@brouhaha.com> + 2000-2002, Håkan Hjort <d95hjort@dtek.chalmers.se> +License-Grant: + VOBDUMP is free software; + you can redistribute it and/or modify it + under the terms of the GNU General Public License version 2 + as published by the Free Software Foundation. + Note that I am not granting permission + to redistribute or modify VOBDUMP + under the terms of any later version of the General Public License. +License: GPL-2 + +Files: xbmc/dbwrappers/dataset.cpp + xbmc/dbwrappers/dataset.h + xbmc/dbwrappers/qry_dat.cpp + xbmc/dbwrappers/qry_dat.h + xbmc/dbwrappers/sqlitedataset.cpp + xbmc/dbwrappers/sqlitedataset.h +Copyright: 2002,2004, Leo Seib, Hannover <leoseib@web.de> +License: Expat + +Files: xbmc/filesystem/NptXbmcFile.cpp +Copyright: 2002-2008, Axiomatic Systems, LLC +License: BSD-3-clause~Axiomatic + +Files: xbmc/input/XBMC_keyboard.h + xbmc/input/XBMC_keysym.h + xbmc/input/XBMC_vkeys.h +Copyright: 1997-2009, Sam Lantinga <slouken@libsdl.org> +License-Grant: + This library is free software; + you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License + as published by the Free Software Foundation; + either version 2.1 of the License, + or (at your option) any later version. +License: LGPL-2.1+ + +Files: xbmc/network/AirPlayServer.cpp + xbmc/network/AirPlayServer.h + xbmc/network/AirTunesServer.cpp +Copyright: 2011-2013, Team XBMC <http://xbmc.org/> +License-Grant: + 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.1, or (at your option) any later version. +License: GPL-2+ + +Files: xbmc/utils/BitstreamConverter.cpp + xbmc/utils/BitstreamConverter.h +Copyright: + 2005, Michal Benes <michal.benes@itonis.tv> + 2006, Baptiste Coudurier <baptiste.coudurier@smartjog.com> + 2007, Benoit Fouet <benoit.fouet@free.fr> + 2008, Wim Taymans <wim.taymans@gmail.com> + 2010-2015, Team XBMC <http://xbmc.org/> +License: GPL-2+ + +Files: xbmc/utils/HttpParser.cpp + xbmc/utils/HttpParser.h +Copyright: 2011-2013, Team XBMC <http://xbmc.org/> +License-Grant: + 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 of the License, or (at your option) any later version. +License: GPL-2+ and public-domain + This code was written by Steve Hanov in 2009, no copyright is claimed. + This code is in the public domain. + +Files: xbmc/utils/StringUtils.cpp +Copyright: + 2005-2013, Team XBMC <http://xbmc.org/> + 2012, Leigh Brasington +License-Grant: + 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. +License: GPL-2+ +Comment: Also contains license for included snippet: + This code may be used and reproduced without written permission. + <http://www.leighb.com/tounicupper.htm> + +Files: xbmc-xrandr.c +Copyright: + 2001, Keith Packard, member of The XFree86 Project, Inc. + 2002, Hewlett Packard Company, Inc. + 2006, Intel Corporation +License: NTP~disclaimer + +Files: debian/* +Copyright: + 2008-2009, Ouattara Oumar Aziz <wattazoum@gmail.com> + 2012-2013, Andres Mejia <amejia@debian.org> + 2014-2015, Balint Reczey <balint@balintreczey.hu> + 2020-2023, Vasyl Gello <vasek.gello@gmail.com> +License-Grant: + 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; + version 2 dated June, 1991, or (at your option) any later version. +License: GPL-2+ + +Files: debian/extra/arial.ttf +Copyright: Copyright © 2006, 2007, 2008, 2009, 2010 Google Corp. + Droid is a trademark of Google Corp. + Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. + Bitstream Vera is a trademark of Bitstream, Inc. + DejaVu changes are in public domain. +License: GPL-3+ +Comment: The file is merged from Apache-2-licensed + /usr/share/fonts/truetype/droid/DroidSansFallbackFull.ttf + and /usr/share/fonts/truetype/dejavu/DejaVuSans.ttf , which is licensed + under the following license: + . + Permission is hereby granted, free of charge, to any person obtaining a copy + of the fonts accompanying this license ("Fonts") and associated + documentation files (the "Font Software"), to reproduce and distribute the + Font Software, including without limitation the rights to use, copy, merge, + publish, distribute, and/or sell copies of the Font Software, and to permit + persons to whom the Font Software is furnished to do so, subject to the + following conditions: + . + The above copyright and trademark notices and this permission notice shall + be included in all copies of one or more of the Font Software typefaces. + . + The Font Software may be modified, altered, or added to, and in particular + the designs of glyphs or characters in the Fonts may be modified and + additional glyphs or characters may be added to the Fonts, only if the fonts + are renamed to names not containing either the words "Bitstream" or the word + "Vera". + . + This License becomes null and void to the extent applicable to Fonts or Font + Software that has been modified and is distributed under the "Bitstream + Vera" names. + . + The Font Software may be sold as part of a larger software package but no + copy of one or more of the Font Software typefaces may be sold by itself. + . + THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, + TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME + FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING + ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF + THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE + FONT SOFTWARE. + . + Except as contained in this notice, the names of Gnome, the Gnome + Foundation, and Bitstream Inc., shall not be used in advertising or + otherwise to promote the sale, use or other dealings in this Font Software + without prior written authorization from the Gnome Foundation or Bitstream + Inc., respectively. For further information, contact: fonts at gnome dot + org. + . + . + I'm adding the result named arial.ttf under GPL-3+ because this is allowed + by the licenses of the original fonts. + +Files: debian/from-debian-logo.svg +Copyright: + 1999, Software in the Public Interest, Inc. + 2015, Balint Reczey <balint@balintreczey.hu> +License-Grant: + This package is free software; + you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License + as published by the Free Software Foundation; + either version 3 of the License, or (at your option) any later version. +License: LGPL-3+ + +License: BSD-3-clause + Redistribution and use in source and binary forms, + with or without modification, + are permitted provided that the following conditions are met: + * Redistributions of source code must retain + the above copyright notice, this list of conditions + and the following disclaimer. + * Redistributions in binary form must reproduce + the above copyright notice, this list of conditions + and the following disclaimer + in the documentation and/or other materials + provided with the distribution. + * Neither the author + nor the names of any contributors + may be used to endorse or promote + products derived from this software + without specific prior written permission. + . + THIS SOFTWARE IS PROVIDED + BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Files: debian/webinterface-default/* +Copyright: + 2005-2021, Team Kodi <http://kodi.tv/> +License-Grant: + This package 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 of the License, or (at your option) any later version. +Comment: The default webinterface was imported from Kodi 17.1 as + component tarball and later moved inside the debian patch in 19.0. + See debian/README.source for more information. +License: GPL-2+ + +License: BSD-3-clause~Axiomatic + Redistribution and use in source and binary forms, + with or without modification, + are permitted provided that the following conditions are met: + * Redistributions of source code must retain + the above copyright notice, this list of conditions + and the following disclaimer. + * Redistributions in binary form must reproduce + the above copyright notice, this list of conditions + and the following disclaimer + in the documentation and/or other materials + provided with the distribution. + * Neither the name of Axiomatic Systems + nor the names of its contributors + may be used to endorse or promote + products derived from this software + without specific prior written permission. + . + THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. + IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +License: BSD-3-clause~axTLS + Redistribution and use in source and binary forms, + with or without modification, + are permitted provided that the following conditions are met: + * Redistributions of source code must retain + the above copyright notice, this list of conditions + and the following disclaimer. + * Redistributions in binary form must reproduce + the above copyright notice, this list of conditions + and the following disclaimer + in the documentation + and/or other materials provided with the distribution. + * Neither the name of the axTLS project + nor the names of its contributors + may be used to endorse or promote + products derived from this software + without specific prior written permission. + . + THIS SOFTWARE IS PROVIDED + BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +License: CC0-1.0 + To the extent possible under law, the author(s) have dedicated all + copyright and related and neighboring rights to this software to the public + domain worldwide. This software is distributed without any warranty. + . + On Debian systems, the complete text of the CC0 license, version 1.0, + can be found in /usr/share/common-licenses/CC0-1.0. + +License: CC-BY-SA-3.0~us + THE WORK (AS DEFINED BELOW) IS PROVIDED + UNDER THE TERMS OF THIS CREATIVE COMMONS PUBLIC LICENSE + ("CCPL" OR "LICENSE"). + THE WORK IS PROTECTED BY COPYRIGHT AND/OR OTHER APPLICABLE LAW. + ANY USE OF THE WORK OTHER THAN AS AUTHORIZED + UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED. + . + BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, + YOU ACCEPT AND AGREE TO BE BOUND BY THE TERMS OF THIS LICENSE. + TO THE EXTENT THIS LICENSE MAY BE CONSIDERED TO BE A CONTRACT, + THE LICENSOR GRANTS YOU THE RIGHTS CONTAINED HERE + IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND CONDITIONS. + . + 1. Definitions + . + a. "Collective Work" means a work, + such as a periodical issue, anthology or encyclopedia, + in which the Work in its entirety in unmodified form, + along with one or more other contributions, + constituting separate and independent works in themselves, + are assembled into a collective whole. + A work that constitutes a Collective Work will not be considered + a Derivative Work (as defined below) + for the purposes of this License. + b. "Creative Commons Compatible License" means a license + that is listed at <https://creativecommons.org/compatiblelicenses> + that has been approved by Creative Commons + as being essentially equivalent to this License, + including, at a minimum, + because that license: (i) contains terms + that have the same purpose, meaning and effect + as the License Elements of this License; + and, (ii) explicitly permits the relicensing + of derivatives of works made available under that license + under this License or either a Creative Commons unported license + or a Creative Commons jurisdiction license + with the same License Elements as this License. + c. "Derivative Work" means a work + based upon the Work or upon the Work and other pre-existing works, + such as a translation, musical arrangement, dramatization, + fictionalization, motion picture version, sound recording, + art reproduction, abridgment, condensation, + or any other form + in which the Work may be recast, transformed, or adapted, + except that a work that constitutes a Collective Work + will not be considered a Derivative Work + for the purpose of this License. + For the avoidance of doubt, + where the Work is a musical composition or sound recording, + the synchronization of the Work + in timed-relation with a moving image ("synching") + will be considered a Derivative Work + for the purpose of this License. + d. "License Elements" means the following + high-level license attributes + as selected by Licensor + and indicated in the title of this License: + Attribution, ShareAlike. + e. "Licensor" means the individual, individuals, entity or entities + that offers the Work under the terms of this License. + f. "Original Author" means the individual, individuals, + entity or entities + who created the Work. + g. "Work" means the copyrightable work of authorship + offered under the terms of this License. + h. "You" means an individual or entity + exercising rights under this License + who has not previously violated the terms of this License + with respect to the Work, + or who has received express permission from the Licensor + to exercise rights under this License + despite a previous violation. + . + 2. Fair Use Rights. + Nothing in this license is intended + to reduce, limit, or restrict any rights + arising from fair use, first sale or other limitations + on the exclusive rights of the copyright owner + under copyright law or other applicable laws. + . + 3. License Grant. + Subject to the terms and conditions of this License, + Licensor hereby grants You + a worldwide, royalty-free, non-exclusive, perpetual + (for the duration of the applicable copyright) + license to exercise the rights in the Work + as stated below: + . + a. to reproduce the Work, + to incorporate the Work into one or more Collective Works, + and to reproduce the Work + as incorporated in the Collective Works; + b. to create and reproduce Derivative Works + provided that any such Derivative Work, + including any translation in any medium, + takes reasonable steps to clearly label, demarcate + or otherwise identify + that changes were made to the original Work. + For example, a translation could be marked + "The original work was translated from English to Spanish," + or a modification could indicate + "The original work has been modified."; + c. to distribute copies or phonorecords of, + display publicly, perform publicly, + and perform publicly by means of a digital audio transmission + the Work + including as incorporated in Collective Works; + d. to distribute copies or phonorecords of, + display publicly, perform publicly, + and perform publicly by means of a digital audio transmission + Derivative Works. + e. For the avoidance of doubt, + where the Work is a musical composition: + i. Performance Royalties Under Blanket Licenses. + Licensor waives the exclusive right to collect, + whether individually or, + in the event that Licensor is a member + of a performance rights society + (e.g. ASCAP, BMI, SESAC), + via that society, + royalties for the public performance + or public digital performance (e.g. webcast) + of the Work. + ii. Mechanical Rights and Statutory Royalties. + Licensor waives the exclusive right to collect, + whether individually or via a music rights agency + or designated agent (e.g. Harry Fox Agency), + royalties for any phonorecord You create from the Work + ("cover version") + and distribute, + subject to the compulsory license + created by 17 USC Section 115 of the US Copyright Act + (or the equivalent in other jurisdictions). + f. Webcasting Rights and Statutory Royalties. + For the avoidance of doubt, + where the Work is a sound recording, + Licensor waives the exclusive right to collect, + whether individually + or via a performance-rights society (e.g. SoundExchange), + royalties for the public digital performance (e.g. webcast) + of the Work, + subject to the compulsory license + created by 17 USC Section 114 of the US Copyright Act + (or the equivalent in other jurisdictions). + . + The above rights may be exercised + in all media and formats + whether now known or hereafter devised. + The above rights include + the right to make such modifications + as are technically necessary to exercise the rights + in other media and formats. + All rights not expressly granted by Licensor are hereby reserved. + . + 4. Restrictions. + The license granted in Section 3 above is expressly + made subject to and limited by the following restrictions: + . + a. You may distribute, publicly display, publicly perform, + or publicly digitally perform the Work + only under the terms of this License, + and You must include a copy of, + or the Uniform Resource Identifier for, + this License + with every copy or phonorecord of the Work + You distribute, publicly display, publicly perform, + or publicly digitally perform. + You may not offer or impose any terms on the Work + that restrict the terms of this License + or the ability of a recipient of the Work to exercise + of the rights granted to that recipient + under the terms of the License. + You may not sublicense the Work. + You must keep intact all notices + that refer to this License + and to the disclaimer of warranties. + When You distribute, publicly display, publicly perform, + or publicly digitally perform the Work, + You may not impose any technological measures on the Work + that restrict the ability of a recipient of the Work from You + to exercise of the rights granted to that recipient + under the terms of the License. + This Section 4(a) applies to the Work + as incorporated in a Collective Work, + but this does not require the Collective Work + apart from the Work itself + to be made subject to the terms of this License. + If You create a Collective Work, + upon notice from any Licensor + You must, to the extent practicable, remove + from the Collective Work + any credit as required by Section 4(c), as requested. + If You create a Derivative Work, + upon notice from any Licensor + You must, to the extent practicable, remove + from the Derivative Work + any credit as required by Section 4(c), as requested. + b. You may distribute, publicly display, publicly perform, + or publicly digitally perform a Derivative Work + only under: (i) the terms of this License; + (ii) a later version of this License + with the same License Elements as this License; + (iii) either the Creative Commons (Unported) license + or a Creative Commons jurisdiction license + (either this or a later license version) + that contains the same License Elements as this License + (e.g. Attribution-ShareAlike 3.0 (Unported)); + (iv) a Creative Commons Compatible License. + If you license the Derivative Work + under one of the licenses mentioned in (iv), + you must comply with the terms of that license. + If you license the Derivative Work + under the terms of any of the licenses + mentioned in (i), (ii) or (iii) + (the "Applicable License"), + you must comply with the terms of the Applicable License + generally and with the following provisions: + (I) You must include a copy of, + or the Uniform Resource Identifier for, + the Applicable License + with every copy or phonorecord of each Derivative Work + You distribute, publicly display, publicly perform, + or publicly digitally perform; + (II) You may not offer or impose any terms + on the Derivative Works + that restrict the terms of the Applicable License + or the ability of a recipient of the Work + to exercise the rights granted to that recipient + under the terms of the Applicable License; + (III) You must keep intact all notices + that refer to the Applicable License + and to the disclaimer of warranties; + and, (IV) when You distribute, publicly display, publicly perform, + or publicly digitally perform the Work, + You may not impose any technological measures + on the Derivative Work + that restrict the ability of a recipient + of the Derivative Work from You + to exercise the rights granted to that recipient + under the terms of the Applicable License. + This Section 4(b) applies to the Derivative Work + as incorporated in a Collective Work, + but this does not require the Collective Work + apart from the Derivative Work itself + to be made subject + to the terms of the Applicable License. + c. If You distribute, publicly display, publicly perform, + or publicly digitally perform the Work + (as defined in Section 1 above) + or any Derivative Works + (as defined in Section 1 above) + or Collective Works + (as defined in Section 1 above), + You must, + unless a request has been made pursuant to Section 4(a), + keep intact all copyright notices for the Work + and provide, + reasonable to the medium or means You are utilizing: + (i) the name of the Original Author + (or pseudonym, if applicable) if supplied, + and/or (ii) if the Original Author and/or Licensor designate + another party or parties + (e.g. a sponsor institute, publishing entity, journal) + for attribution ("Attribution Parties") + in Licensor's copyright notice, terms of service + or by other reasonable means, + the name of such party or parties; + the title of the Work if supplied; + to the extent reasonably practicable, + the Uniform Resource Identifier, if any, + that Licensor specifies to be associated with the Work, + unless such URI does not refer to the copyright notice + or licensing information for the Work; + and, consistent with Section 3(b) + in the case of a Derivative Work, + a credit identifying the use of the Work in the Derivative Work + (e.g., "French translation of the Work by Original Author," + or "Screenplay based on original Work by Original Author"). + The credit required by this Section 4(c) may be implemented + in any reasonable manner; + provided, however, that + in the case of a Derivative Work or Collective Work, + at a minimum such credit will appear, + if a credit for all contributing authors + of the Derivative Work or Collective Work appears, + then as part of these credits + and in a manner at least as prominent as the credits + for the other contributing authors. + For the avoidance of doubt, + You may only use the credit required by this Section + for the purpose of attribution + in the manner set out above + and, by exercising Your rights under this License, + You may not implicitly or explicitly assert or imply + any connection with, sponsorship or endorsement + by the Original Author, Licensor + and/or Attribution Parties, as appropriate, + of You or Your use of the Work, + without the separate, express prior written permission + of the Original Author, Licensor and/or Attribution Parties. + . + 5. Representations, Warranties and Disclaimer + . + UNLESS OTHERWISE MUTUALLY AGREED + TO BY THE PARTIES IN WRITING, + LICENSOR OFFERS THE WORK AS-IS + AND ONLY TO THE EXTENT OF ANY RIGHTS + HELD IN THE LICENSED WORK BY THE LICENSOR. + THE LICENSOR MAKES NO REPRESENTATIONS OR WARRANTIES + OF ANY KIND CONCERNING THE WORK, + EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, + INCLUDING, WITHOUT LIMITATION, + WARRANTIES OF TITLE, MARKETABILITY, MERCHANTIBILITY, + FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, + OR THE ABSENCE OF LATENT OR OTHER DEFECTS, ACCURACY, + OR THE PRESENCE OF ABSENCE OF ERRORS, + WHETHER OR NOT DISCOVERABLE. + SOME JURISDICTIONS DO NOT ALLOW + THE EXCLUSION OF IMPLIED WARRANTIES, + SO SUCH EXCLUSION MAY NOT APPLY TO YOU. + . + 6. Limitation on Liability. + EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE LAW, + IN NO EVENT WILL LICENSOR BE LIABLE TO YOU + ON ANY LEGAL THEORY + FOR ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE + OR EXEMPLARY DAMAGES + ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, + EVEN IF LICENSOR HAS BEEN ADVISED + OF THE POSSIBILITY OF SUCH DAMAGES. + . + 7. Termination + . + a. This License and the rights granted hereunder + will terminate automatically upon any breach by You + of the terms of this License. + Individuals or entities + who have received Derivative Works or Collective Works + from You under this License, + however, will not have their licenses terminated + provided such individuals or entities remain + in full compliance with those licenses. + Sections 1, 2, 5, 6, 7, and 8 will survive + any termination of this License. + b. Subject to the above terms and conditions, + the license granted here is perpetual + (for the duration of the applicable copyright in the Work). + Notwithstanding the above, + Licensor reserves the right to release the Work + under different license terms + or to stop distributing the Work + at any time; + provided, however that any such election will not serve + to withdraw this License + (or any other license that has been, or is required to be, granted + under the terms of this License), + and this License will continue in full force and effect + unless terminated as stated above. + . + 8. Miscellaneous + . + a. Each time You distribute or publicly digitally perform + the Work (as defined in Section 1 above) + or a Collective Work (as defined in Section 1 above), + the Licensor offers to the recipient a license to the Work + on the same terms and conditions + as the license granted to You under this License. + b. Each time You distribute + or publicly digitally perform a Derivative Work, + Licensor offers to the recipient + a license to the original Work + on the same terms and conditions + as the license granted to You under this License. + c. If any provision of this License is invalid + or unenforceable under applicable law, + it shall not affect the validity or enforceability + of the remainder of the terms of this License, + and without further action + by the parties to this agreement, + such provision shall be reformed + to the minimum extent necessary + to make such provision valid and enforceable. + d. No term or provision of this License shall be deemed waived + and no breach consented to + unless such waiver or consent shall be in writing + and signed by the party + to be charged with such waiver or consent. + e. This License constitutes the entire agreement between the parties + with respect to the Work licensed here. + There are no understandings, agreements or representations + with respect to the Work not specified here. + Licensor shall not be bound by any additional provisions + that may appear in any communication from You. + This License may not be modified + without the mutual written agreement of the Licensor and You. + +License: CC-BY-SA-4.0 + Creative Commons Attribution-ShareAlike 4.0 International + Public License + . + By exercising the Licensed Rights (defined below), + You accept and agree to be bound by the terms and conditions + of this Creative Commons Attribution-ShareAlike 4.0 International + Public License ("Public License"). + To the extent this Public License may be interpreted as a contract, + You are granted the Licensed Rights + in consideration of Your acceptance of these terms and conditions, + and the Licensor grants You such rights + in consideration of benefits the Licensor receives + from making the Licensed Material available + under these terms and conditions. + . + Section 1 – Definitions. + . + a. Adapted Material means material + subject to Copyright and Similar Rights + that is derived from or based upon the Licensed Material + and in which the Licensed Material is translated, + altered, arranged, transformed, + or otherwise modified in a manner requiring permission + under the Copyright and Similar Rights held by the Licensor. + For purposes of this Public License, + where the Licensed Material is a musical work, + performance, or sound recording, + Adapted Material is always produced + where the Licensed Material is synched + in timed relation with a moving image. + b. Adapter's License means the license You apply to Your Copyright + and Similar Rights in Your contributions to Adapted Material + in accordance with the terms and conditions of this Public License. + c. BY-SA Compatible License means a license + listed at <https://creativecommons.org/compatiblelicenses>, + approved by Creative Commons + as essentially the equivalent of this Public License. + d. Copyright and Similar Rights means copyright + and/or similar rights closely related to copyright + including, without limitation, + performance, broadcast, sound recording, + and Sui Generis Database Rights, + without regard to how the rights are labeled or categorized. + For purposes of this Public License, + the rights specified in Section 2(b)(1)-(2) + are not Copyright and Similar Rights. + e. Effective Technological Measures means those measures + that, in the absence of proper authority, may not be circumvented + under laws fulfilling obligations + under Article 11 of the WIPO Copyright Treaty + adopted on December 20, 1996, + and/or similar international agreements. + f. Exceptions and Limitations means fair use, fair dealing, + and/or any other exception or limitation + to Copyright and Similar Rights + that applies to Your use of the Licensed Material. + g. License Elements means the license attributes + listed in the name of a Creative Commons Public License. + The License Elements of this Public License are + Attribution and ShareAlike. + h. Licensed Material means the artistic or literary work, + database, or other material + to which the Licensor applied this Public License. + i. Licensed Rights means the rights granted to You subject + to the terms and conditions of this Public License, + which are limited to all Copyright and Similar Rights + that apply to Your use of the Licensed Material + and that the Licensor has authority to license. + j. Licensor means the individual(s) or entity(ies) + granting rights under this Public License. + k. Share means to provide material to the public + by any means or process + that requires permission under the Licensed Rights, + such as reproduction, public display, public performance, + distribution, dissemination, communication, or importation, + and to make material available to the public + including in ways that members of the public may access + the material + from a place and at a time individually chosen by them. + l. Sui Generis Database Rights means rights other than copyright + resulting from Directive 96/9/EC of the European Parliament + and of the Council of 11 March 1996 + on the legal protection of databases, + as amended and/or succeeded, + as well as other essentially equivalent rights + anywhere in the world. + m. You means the individual or entity + exercising the Licensed Rights under this Public License. + Your has a corresponding meaning. + . + Section 2 – Scope. + . + a. License grant. + 1. Subject to the terms and conditions of this Public License, + the Licensor hereby grants You + a worldwide, royalty-free, non-sublicensable, + non-exclusive, irrevocable license + to exercise the Licensed Rights in the Licensed Material to: + A. reproduce and Share the Licensed Material, + in whole or in part; and + B. produce, reproduce, and Share Adapted Material. + 2. Exceptions and Limitations. + For the avoidance of doubt, + where Exceptions and Limitations apply to Your use, + this Public License does not apply, + and You do not need to comply + with its terms and conditions. + 3. Term. + The term of this Public License is specified in Section 6(a). + 4. Media and formats; technical modifications allowed. + The Licensor authorizes You to exercise the Licensed Rights + in all media and formats + whether now known or hereafter created, + and to make technical modifications necessary to do so. + The Licensor waives and/or agrees not to assert + any right or authority + to forbid You from making technical modifications + necessary to exercise the Licensed Rights, + including technical modifications necessary + to circumvent Effective Technological Measures. + For purposes of this Public License, + simply making modifications authorized by this Section 2(a)(4) + never produces Adapted Material. + 5. Downstream recipients. + A. Offer from the Licensor – Licensed Material. + Every recipient of the Licensed Material + automatically receives an offer from the Licensor + to exercise the Licensed Rights + under the terms and conditions of this Public License. + B. Additional offer from the Licensor – Adapted Material. + Every recipient of Adapted Material from You + automatically receives an offer from the Licensor + to exercise the Licensed Rights in the Adapted Material + under the conditions of the Adapter’s License You apply. + C. No downstream restrictions. + You may not offer or impose + any additional or different terms or conditions on, + or apply any Effective Technological Measures to, + the Licensed Material + if doing so restricts exercise of the Licensed Rights + by any recipient of the Licensed Material. + 6. No endorsement. + Nothing in this Public License constitutes + or may be construed + as permission to assert or imply + that You are, or that Your use of the Licensed Material is, + connected with, or sponsored, endorsed, + or granted official status by, + the Licensor or others designated to receive attribution + as provided in Section 3(a)(1)(A)(i). + . + b. Other rights. + 1. Moral rights, such as the right of integrity, + are not licensed under this Public License, + nor are publicity, privacy, + and/or other similar personality rights; + however, to the extent possible, + the Licensor waives + and/or agrees not to assert + any such rights held by the Licensor + to the limited extent necessary + to allow You to exercise the Licensed Rights, + but not otherwise. + 2. Patent and trademark rights are not licensed + under this Public License. + 3. To the extent possible, + the Licensor waives any right + to collect royalties from You + for the exercise of the Licensed Rights, + whether directly or through a collecting society + under any voluntary or waivable + statutory or compulsory licensing scheme. + In all other cases + the Licensor expressly reserves any right + to collect such royalties. + . + Section 3 – License Conditions. + . + Your exercise of the Licensed Rights + is expressly made subject to the following conditions. + . + a. Attribution. + 1. If You Share the Licensed Material + (including in modified form), + You must: + A. retain the following + if it is supplied by the Licensor with the Licensed Material: + i. identification of the creator(s) of the Licensed Material + and any others designated to receive attribution, + in any reasonable manner requested by the Licensor + (including by pseudonym if designated); + ii. a copyright notice; + iii. a notice that refers to this Public License; + iv. a notice that refers to the disclaimer of warranties; + v. a URI or hyperlink to the Licensed Material + to the extent reasonably practicable; + B. indicate if You modified the Licensed Material + and retain an indication of any previous modifications; and + C. indicate the Licensed Material is licensed + under this Public License, + and include the text of, or the URI or hyperlink to, + this Public License. + 2. You may satisfy the conditions in Section 3(a)(1) + in any reasonable manner + based on the medium, means, and context + in which You Share the Licensed Material. + For example, + it may be reasonable to satisfy the conditions + by providing a URI or hyperlink to a resource + that includes the required information. + 3. If requested by the Licensor, + You must remove any of the information + required by Section 3(a)(1)(A) + to the extent reasonably practicable. + b. ShareAlike. + In addition to the conditions in Section 3(a), + if You Share Adapted Material You produce, + the following conditions also apply. + 1. The Adapter’s License You apply + must be a Creative Commons license + with the same License Elements, + this version or later, + or a BY-SA Compatible License. + 2. You must include + the text of, or the URI or hyperlink to, + the Adapter's License You apply. + You may satisfy this condition + in any reasonable manner + based on the medium, means, and context + in which You Share Adapted Material. + 3. You may not offer or impose + any additional or different terms or conditions on, + or apply any Effective Technological Measures to, + Adapted Material + that restrict exercise of the rights granted + under the Adapter's License You apply. + . + Section 4 – Sui Generis Database Rights. + . + Where the Licensed Rights include Sui Generis Database Rights + that apply to Your use of the Licensed Material: + . + a. for the avoidance of doubt, + Section 2(a)(1) grants You the right + to extract, reuse, reproduce, and Share + all or a substantial portion of the contents of the database; + b. if You include all or a substantial portion of + the database contents in a database + in which You have Sui Generis Database Rights, + then the database + in which You have Sui Generis Database Rights + (but not its individual contents) + is Adapted Material, + including for purposes of Section 3(b); and + c. You must comply with the conditions in Section 3(a) + if You Share all or a substantial portion + of the contents of the database. + . + For the avoidance of doubt, + this Section 4 supplements and does not replace + Your obligations under this Public License + where the Licensed Rights include other Copyright and Similar Rights. + . + Section 5 – Disclaimer of Warranties and Limitation of Liability. + . + a. Unless otherwise separately undertaken by the Licensor, + to the extent possible, + the Licensor offers the Licensed Material as-is and as-available, + and makes no representations or warranties + of any kind concerning the Licensed Material, + whether express, implied, statutory, or other. + This includes, without limitation, + warranties of title, merchantability, + fitness for a particular purpose, non-infringement, + absence of latent or other defects, accuracy, + or the presence or absence of errors, + whether or not known or discoverable. + Where disclaimers of warranties are not allowed + in full or in part, + this disclaimer may not apply to You. + b. To the extent possible, + in no event will the Licensor be liable to You + on any legal theory + (including, without limitation, negligence) + or otherwise for any direct, special, + indirect, incidental, consequential, punitive, exemplary, + or other losses, costs, expenses, or damages + arising out of this Public License + or use of the Licensed Material, + even if the Licensor has been advised + of the possibility of such losses, costs, + expenses, or damages. + Where a limitation of liability is not allowed + in full or in part, + this limitation may not apply to You. + c. The disclaimer of warranties + and limitation of liability provided above + shall be interpreted in a manner that, + to the extent possible, + most closely approximates an absolute disclaimer + and waiver of all liability. + . + Section 6 – Term and Termination. + . + a. This Public License applies + for the term of the Copyright + and Similar Rights licensed here. + However, if You fail to comply with this Public License, + then Your rights under this Public License terminate + automatically. + b. Where Your right to use the Licensed Material has terminated + under Section 6(a), it reinstates: + 1. automatically as of the date the violation is cured, + provided it is cured within 30 days + of Your discovery of the violation; or + 2. upon express reinstatement by the Licensor. + c. For the avoidance of doubt, + this Section 6(b) does not affect + any right the Licensor may have to seek remedies + for Your violations of this Public License. + d. For the avoidance of doubt, + the Licensor may also offer the Licensed Material + under separate terms or conditions + or stop distributing the Licensed Material at any time; + however, doing so will not terminate this Public License. + e. Sections 1, 5, 6, 7, and 8 survive termination + of this Public License. + . + Section 7 – Other Terms and Conditions. + . + a. The Licensor shall not be bound + by any additional or different terms or conditions + communicated by You unless expressly agreed. + b. Any arrangements, understandings, or agreements + regarding the Licensed Material not stated herein + are separate from and independent of the terms and conditions + of this Public License. + . + Section 8 – Interpretation. + . + a. For the avoidance of doubt, + this Public License does not, and shall not be interpreted to, + reduce, limit, restrict, or impose conditions on + any use of the Licensed Material + that could lawfully be made without permission + under this Public License. + b. To the extent possible, + if any provision of this Public License is deemed unenforceable, + it shall be automatically reformed + to the minimum extent necessary to make it enforceable. + If the provision cannot be reformed, + it shall be severed from this Public License + without affecting the enforceability + of the remaining terms and conditions. + c. No term or condition of this Public License will be waived + and no failure to comply consented to + unless expressly agreed to by the Licensor. + d. Nothing in this Public License constitutes + or may be interpreted as a limitation upon, or waiver of, + any privileges and immunities that apply to the Licensor or You, + including from the legal processes + of any jurisdiction or authority. + +License: Expat + Permission is hereby granted, + free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, + including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, + and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: + . + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + . + THE SOFTWARE IS PROVIDED "AS IS", + WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE + FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE + OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +License: GPL-2 + This package 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; version 2 of the License. + . + This package 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 package; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + . + On Debian systems, the complete text of the GNU General + Public License can be found in `/usr/share/common-licenses/GPL-2'. + +License: GPL-2+ + This package 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 of the License, or + (at your option) any later version. + . + This package 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 package; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + . + On Debian systems, the complete text of the GNU General + Public License can be found in `/usr/share/common-licenses/GPL-2'. + +License: GPL-3 + This package 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 3 of the License. + . + This package 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 package; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + . + On Debian systems, the complete text of the GNU General + Public License can be found in `/usr/share/common-licenses/GPL-3'. + +License: GPL-3+ + This package 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 3 of the License, or + (at your option) any later version. + . + This package 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 package; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + . + On Debian systems, the complete text of the GNU General + Public License can be found in `/usr/share/common-licenses/GPL-3'. + +License: ISC~minimal-disclaimer + Permission to use, copy, modify, and distribute + this software and its documentation + for any purpose + is hereby granted without fee, + provided that this copyright and permissions notice appear + in all copies and derivatives. + . + This software is supplied "as is" + without express or implied warranty. + +License: LGPL-2.1+ + This package is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + . + This package 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 + Lesser General Public License for more details. + . + You should have received a copy of the GNU Lesser General Public + License along with this package; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + . + On Debian systems, the complete text of the GNU Lesser General + Public License can be found in `/usr/share/common-licenses/LGPL-2.1'. + +License: LGPL-3+ + This package is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + . + This package 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 + Lesser General Public License for more details. + . + You should have received a copy of the GNU Lesser General Public + License along with this package; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + . + On Debian systems, the complete text of the GNU Lesser General + Public License can be found in `/usr/share/common-licenses/LGPL-3'. + +License: NTP~disclaimer + Permission to use, copy, modify, distribute, and sell + this software and its documentation + for any purpose + is hereby granted without fee, + provided that the above copyright notice appear + in all copies + and that both that copyright notice and this permission notice appear + in supporting documentation, + and that the name of the copyright holders not be used + in advertising or publicity pertaining to distribution of the software + without specific, written prior permission. + The copyright holders make no representations + about the suitability of this software for any purpose. + It is provided "as is" without express or implied warranty. + . + THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE, + INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, + IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE + FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES + OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, + ARISING OUT OF OR IN CONNECTION WITH + THE USE OR PERFORMANCE OF THIS SOFTWARE. + +License: NTP~disclaimer~FarsiWeb + Permission to use, copy, modify, distribute, and sell + this software and its documentation + for any purpose + is hereby granted without fee, + provided that the above copyright notice appear + in all copies + and that both that copyright notice and this permission notice appear + in supporting documentation, + and that the name of Sharif FarsiWeb, Inc. not be used + in advertising or publicity pertaining to distribution of the software + without specific, written prior permission. + Sharif FarsiWeb, Inc. makes no representations + about the suitability of this software for any purpose. + It is provided "as is" without express or implied warranty. + . + SHARIF FARSIWEB, INC. DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE, + INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, + IN NO EVENT SHALL KEITH PACKARD BE LIABLE + FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES + OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, + ARISING OUT OF OR IN CONNECTION WITH + THE USE OR PERFORMANCE OF THIS SOFTWARE. + +License: X11 + Permission is hereby granted, + free of charge, to any person obtaining + a copy of this software and associated documentation files + (the "Software"), + to deal in the Software without restriction, + including without limitation + the rights to use, copy, modify, merge, publish, distribute, + sublicense, and/or sell copies of the Software, + and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: + . + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + . + THE SOFTWARE IS PROVIDED "AS IS", + WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + INCLUDING BUT NOT LIMITED TO + THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE + FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH + THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + . + Except as contained in this notice, + the name of the X Consortium shall not be used + in advertising or otherwise + to promote the sale, use or other dealings in this Software + without prior written authorization from the X Consortium. diff --git a/debian/dh-addon/dh_kodiaddon_depends b/debian/dh-addon/dh_kodiaddon_depends new file mode 100755 index 0000000..6e469a1 --- /dev/null +++ b/debian/dh-addon/dh_kodiaddon_depends @@ -0,0 +1,148 @@ +#! /usr/bin/perl -w + +=head1 NAME + +dh_kodiaddon_depends - Provides substvars for Kodi addons + +=cut + +use strict; +use Debian::Debhelper::Dh_Lib; + +=head1 SYNOPSIS + +B<dh_kodiaddon_depends> [S<I<debhelper options>>] + +=head1 DESCRIPTION + +dh_kodiaddon_depends is a debhelper program, that is responsible for setting substvars +providing the Kodi addon-API dependencies. Kodi provides a virtual package for each API +which might be used by an addon. The following substvars will be set to a dependency +clause which can be used directly in the "Depends"-line of the addons debian/control: + +${kodi:AUDIODECODERAPI} (ADDON_INSTANCE_VERSION_AUDIODECODER) +${kodi:AUDIOENCODERAPI} (ADDON_INSTANCE_VERSION_AUDIOENCODER) +${kodi:AUDIOENGINEAPI} (ADDON_GLOBAL_VERSION_AUDIOENGINE) +${kodi:FILESYSTEMAPI} (ADDON_GLOBAL_VERSION_FILESYSTEM) +${kodi:GAMEAPI} (ADDON_INSTANCE_VERSION_GAME) +${kodi:GENERALAPI} (ADDON_GLOBAL_VERSION_GENERAL) +${kodi:GUIAPI} (ADDON_GLOBAL_VERSION_GUI) +${kodi:IMAGEDECODERAPI} (ADDON_INSTANCE_VERSION_IMAGEDECODER) +${kodi:INPUTSTREAMAPI} (ADDON_INSTANCE_VERSION_INPUTSTREAM) +${kodi:MAINAPI} (ADDON_GLOBAL_VERSION_MAIN) +${kodi:NETWORKAPI} (ADDON_GLOBAL_VERSION_NETWORK) +${kodi:PERIPHERALAPI} (ADDON_INSTANCE_VERSION_PERIPHERAL) +${kodi:PVRAPI} (ADDON_INSTANCE_VERSION_PVR) +${kodi:SCREENSAVERAPI} (ADDON_INSTANCE_VERSION_SCREENSAVER) +${kodi:VFSAPI} (ADDON_INSTANCE_VERSION_VFS) +${kodi:VIDEOCODECAPI} (ADDON_INSTANCE_VERSION_VIDEOCODEC) +${kodi:VISUALIZATIONAPI} (ADDON_INSTANCE_VERSION_VISUALIZATION) + +=head1 EXAMPLES + +dh_kodiaddon_depends is usually called indirectly in a rules file via the dh command. + + %: + dh $@ --with kodiaddon + +It can also be called directly, prior to calling dh_gencontrol. + +=head1 CONFORMS TO + +Debian policy, version 3.8.1 + +=cut + +init (); + +no locale; + +sub get_api_version { + my $headerFileName = $_[0]; + my $defineName = $_[1]; + my $apiVersion; + my $apiVersionMin; + my $apiVersionMax; + + open(HEADERFILE, "<$headerFileName") or die "$!"; + while (<HEADERFILE>) { + if ($_ =~ /^#define $defineName\s+"(.*)"/) { + $apiVersion = $1; + } + if ($_ =~ /^#define ${defineName}_MIN\s+"(.*)"/) { + $apiVersionMin = $1; + } + if ($apiVersion && $apiVersionMin) { + last; + } + } + close(HEADERFILE); + if ($apiVersion =~ qr/(?:(\d+)\.(\d+)\.(\d+)|(\d+)\.(\d+)|(\d+))?(?:\.\*)?/) { + $apiVersionMax = int($2) + 1; + $apiVersionMax = "$1.$apiVersionMax.0"; + } + $apiVersion or die "Could not find '$defineName' in $headerFileName"; + $apiVersionMin or die "Could not find '${defineName}_MIN' in $headerFileName"; + $apiVersionMax or die "Could not derive maximum API version from '$defineName' in $headerFileName"; + ($apiVersion, $apiVersionMin, $apiVersionMax) +} + +sub create_substvar { + my $substvarName = $_[0]; + my $substvarValue = $_[1]; + foreach my $package (@{$dh{DOPACKAGES}}) { + delsubstvar($package, $substvarName); + addsubstvar($package, $substvarName, $substvarValue); + } +} + +my $baseDir = "debian/kodi-addons-dev-common"; +if (! -d "$baseDir/usr/include/kodi") { + $baseDir = "debian/tmp"; + if (! -d "$baseDir/usr/include/kodi") { + $baseDir = "" + } +} + +my @apis = ( + ["kodi-api-audiodecoder", "kodi:AUDIODECODERAPI", "$baseDir/usr/include/kodi/versions.h", "ADDON_INSTANCE_VERSION_AUDIODECODER"], + ["kodi-api-audioencoder", "kodi:AUDIOENCODERAPI", "$baseDir/usr/include/kodi/versions.h", "ADDON_INSTANCE_VERSION_AUDIOENCODER"], + ["kodi-api-audioengine", "kodi:AUDIOENGINEAPI", "$baseDir/usr/include/kodi/versions.h", "ADDON_GLOBAL_VERSION_AUDIOENGINE"], + ["kodi-api-filesystem", "kodi:FILESYSTEMAPI", "$baseDir/usr/include/kodi/versions.h", "ADDON_GLOBAL_VERSION_FILESYSTEM"], + ["kodi-api-game", "kodi:GAMEAPI", "$baseDir/usr/include/kodi/versions.h", "ADDON_INSTANCE_VERSION_GAME"], + ["kodi-api-general", "kodi:GENERALAPI", "$baseDir/usr/include/kodi/versions.h", "ADDON_GLOBAL_VERSION_GENERAL"], + ["kodi-api-gui", "kodi:GUIAPI", "$baseDir/usr/include/kodi/versions.h", "ADDON_GLOBAL_VERSION_GUI"], + ["kodi-api-imagedecoder", "kodi:IMAGEDECODERAPI", "$baseDir/usr/include/kodi/versions.h", "ADDON_INSTANCE_VERSION_IMAGEDECODER"], + ["kodi-api-inputstream", "kodi:INPUTSTREAMAPI", "$baseDir/usr/include/kodi/versions.h", "ADDON_INSTANCE_VERSION_INPUTSTREAM"], + ["kodi-api-main", "kodi:MAINAPI", "$baseDir/usr/include/kodi/versions.h", "ADDON_GLOBAL_VERSION_MAIN"], + ["kodi-api-network", "kodi:NETWORKAPI", "$baseDir/usr/include/kodi/versions.h", "ADDON_GLOBAL_VERSION_NETWORK"], + ["kodi-api-peripheral", "kodi:PERIPHERALAPI", "$baseDir/usr/include/kodi/versions.h", "ADDON_INSTANCE_VERSION_PERIPHERAL"], + ["kodi-api-pvr", "kodi:PVRAPI", "$baseDir/usr/include/kodi/versions.h", "ADDON_INSTANCE_VERSION_PVR"], + ["kodi-api-screensaver", "kodi:SCREENSAVERAPI", "$baseDir/usr/include/kodi/versions.h", "ADDON_INSTANCE_VERSION_SCREENSAVER"], + ["kodi-api-vfs", "kodi:VFSAPI", "$baseDir/usr/include/kodi/versions.h", "ADDON_INSTANCE_VERSION_VFS"], + ["kodi-api-videocodec", "kodi:VIDEOCODECAPI", "$baseDir/usr/include/kodi/versions.h", "ADDON_INSTANCE_VERSION_VIDEOCODEC"], + ["kodi-api-visualization", "kodi:VISUALIZATIONAPI", "$baseDir/usr/include/kodi/versions.h", "ADDON_INSTANCE_VERSION_VISUALIZATION"] +); + +my @provides; + +foreach my $api (@apis) { + my ($apiName, $apiSubstvar, $apiHeader, $apiDefine) = @$api; + my ($apiVersion, $apiVersionMin, $apiVersionMax) = get_api_version($apiHeader, $apiDefine); + create_substvar($apiSubstvar, "$apiName (>= $apiVersionMin), $apiName (<< $apiVersionMax)"); + push @provides, "$apiName (= $apiVersion)"; +} + +create_substvar("kodi:APIPROVIDES", join(", ", @provides)); + +=head1 SEE ALSO + +L<debhelper(7)> + +This program is not a part of debhelper. + +=head1 AUTHOR + +Tobias Grimm <tobias.grimm@e-tobi.net> + +=cut diff --git a/debian/dh-addon/kodiaddon.pm b/debian/dh-addon/kodiaddon.pm new file mode 100644 index 0000000..019793c --- /dev/null +++ b/debian/dh-addon/kodiaddon.pm @@ -0,0 +1,7 @@ +use warnings; +use strict; +use Debian::Debhelper::Dh_Lib; + +insert_before("dh_gencontrol", "dh_kodiaddon_depends"); + +1 diff --git a/debian/extra/arial.ttf b/debian/extra/arial.ttf Binary files differnew file mode 100644 index 0000000..d4b0962 --- /dev/null +++ b/debian/extra/arial.ttf diff --git a/debian/from-debian-logo.svg b/debian/from-debian-logo.svg new file mode 100644 index 0000000..e0779d9 --- /dev/null +++ b/debian/from-debian-logo.svg @@ -0,0 +1,189 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Generator: Adobe Illustrator 10.0, SVG Export Plug-In . SVG Version: 3.0.0 Build 77) --> + +<svg + xmlns:ns0="http://ns.adobe.com/SaveForWeb/1.0/" + xmlns:ns="http://ns.adobe.com/Variables/1.0/" + xmlns:i="http://ns.adobe.com/AdobeIllustrator/10.0/" + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + i:viewOrigin="251 467" + i:rulerOrigin="0 0" + i:pageBounds="0 792 612 0" + width="124.60188" + height="41.382854" + viewBox="0 0 124.60188 41.382856" + overflow="visible" + enable-background="new 0 0 108.758 144.133" + xml:space="preserve" + id="svg2" + version="1.1" + inkscape:version="0.48.5 r10040" + sodipodi:docname="kodi-from-debian-logo.svg" + style="overflow:visible"><defs + id="defs49"><filter + inkscape:label="Drop Shadow" + id="filter4007" + color-interpolation-filters="sRGB"><feFlood + flood-opacity="0.267" + flood-color="rgb(0,0,0)" + result="flood" + id="feFlood4009" /><feComposite + in="flood" + in2="SourceGraphic" + operator="in" + result="composite1" + id="feComposite4011" /><feGaussianBlur + stdDeviation="6" + result="blur" + id="feGaussianBlur4013" /><feOffset + dx="2.77556e-17" + dy="2.77556e-17" + result="offset" + id="feOffset4015" /><feComposite + in="SourceGraphic" + in2="offset" + operator="over" + result="composite2" + id="feComposite4017" /></filter><filter + inkscape:label="Drop Shadow" + id="filter4019" + color-interpolation-filters="sRGB"><feFlood + flood-opacity="0.267" + flood-color="rgb(0,0,0)" + result="flood" + id="feFlood4021" /><feComposite + in="flood" + in2="SourceGraphic" + operator="in" + result="composite1" + id="feComposite4023" /><feGaussianBlur + stdDeviation="6" + result="blur" + id="feGaussianBlur4025" /><feOffset + dx="2.77556e-17" + dy="2.77556e-17" + result="offset" + id="feOffset4027" /><feComposite + in="SourceGraphic" + in2="offset" + operator="over" + result="composite2" + id="feComposite4029" /></filter><filter + inkscape:label="Drop Shadow" + id="filter4055" + y="-0.5" + height="2" + color-interpolation-filters="sRGB"><feFlood + flood-opacity="0.25" + flood-color="rgb(0,0,0)" + result="flood" + id="feFlood4057" /><feComposite + in="flood" + in2="SourceGraphic" + operator="in" + result="composite1" + id="feComposite4059" /><feGaussianBlur + stdDeviation="6" + result="blur" + id="feGaussianBlur4061" /><feOffset + dx="2.77556e-17" + dy="2.77556e-17" + result="offset" + id="feOffset4063" /><feComposite + in="SourceGraphic" + in2="offset" + operator="over" + result="composite2" + id="feComposite4065" /></filter></defs><sodipodi:namedview + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1" + objecttolerance="10" + gridtolerance="10" + guidetolerance="10" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:window-width="1438" + inkscape:window-height="879" + id="namedview47" + showgrid="false" + inkscape:zoom="2.3156003" + inkscape:cx="9.2522673" + inkscape:cy="8.9090173" + inkscape:window-x="0" + inkscape:window-y="19" + inkscape:window-maximized="0" + inkscape:current-layer="svg2" + fit-margin-top="0" + fit-margin-left="0" + fit-margin-right="0" + fit-margin-bottom="0" + showguides="true" + inkscape:guide-bbox="true" /><metadata + id="metadata4"><ns:variableSets><ns:variableSet + varSetName="binding1" + locked="none"><ns:variables /><ns:sampleDataSets /></ns:variableSet></ns:variableSets><ns0:sfw><ns0:slices /><ns0:sliceSourceBounds + y="322.867" + x="251" + width="108.758" + height="144.133" + bottomLeftOrigin="true" /></ns0:sfw><rdf:RDF><cc:Work + rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><g + id="g4043" + style="filter:url(#filter4055)" + transform="translate(-179.24258,-86.71267)"><g + transform="matrix(0.5678998,0,0,0.5678998,231.69733,35.897279)" + id="g4105"><path + i:knockout="Off" + d="m 13.437,125.506 c -0.045,0.047 -0.045,7.506 -0.138,9.453 -0.092,1.574 -0.232,4.957 -3.568,4.957 -3.429,0 -4.263,-3.939 -4.541,-5.652 -0.324,-1.9 -0.324,-3.477 -0.324,-4.17 0,-2.225 0.139,-8.436 5.375,-8.436 1.576,0 2.456,0.465 3.151,0.834 l 0.045,3.014 z M 0,130.975 c 0,13.066 6.951,13.066 7.97,13.066 2.873,0 4.727,-1.576 5.514,-4.309 l 0.093,4.123 c 0.881,-0.047 1.761,-0.139 3.197,-0.139 0.51,0 0.926,0 1.298,0.047 0.371,0 0.741,0.045 1.158,0.092 -0.741,-1.482 -1.297,-4.818 -1.297,-12.049 0,-7.043 0,-18.951 0.602,-22.566 -1.667,0.789 -3.105,1.299 -6.256,1.576 1.251,1.344 1.251,2.039 1.251,8.154 -0.879,-0.277 -1.992,-0.602 -3.892,-0.602 C 1.344,118.369 0,125.598 0,130.975" + id="path33" + inkscape:connector-curvature="0" + style="fill:#ffffff;fill-opacity:1" /><path + i:knockout="Off" + d="m 25.13,128.609 c 0.047,-3.846 0.835,-7.275 4.124,-7.275 3.615,0 3.891,3.984 3.799,7.275 H 25.13 z m 12.51,0.465 c 0,-5.422 -1.065,-10.752 -7.923,-10.752 -9.452,0 -9.452,10.475 -9.452,12.697 0,9.406 4.216,13.113 11.306,13.113 3.149,0 4.68,-0.461 5.514,-0.695 -0.046,-1.668 0.185,-2.734 0.465,-4.17 -0.975,0.604 -2.226,1.391 -5.006,1.391 -7.229,0 -7.322,-6.582 -7.322,-8.852 H 37.55 l 0.09,-2.732" + id="path35" + inkscape:connector-curvature="0" + style="fill:#ffffff;fill-opacity:1" /><path + i:knockout="Off" + d="m 52.715,131.066 c 0,4.309 -0.787,10.102 -6.162,10.102 -0.742,0 -1.668,-0.141 -2.27,-0.279 -0.093,-1.668 -0.093,-4.541 -0.093,-7.877 0,-3.986 0.416,-6.068 0.742,-7.09 0.972,-3.289 3.15,-3.334 3.566,-3.334 3.522,0 4.217,4.865 4.217,8.478 z m -13.298,5.051 c 0,3.43 0,5.375 -0.556,6.857 1.9,0.742 4.262,1.158 7.09,1.158 1.807,0 7.043,0 9.869,-5.791 1.344,-2.688 1.807,-6.303 1.807,-9.037 0,-1.668 -0.186,-5.328 -1.529,-7.646 -1.296,-2.176 -3.382,-3.289 -5.605,-3.289 -4.449,0 -5.746,3.707 -6.44,5.607 0,-2.363 0.045,-10.611 0.415,-14.828 -3.011,1.391 -4.866,1.621 -6.857,1.807 1.807,0.74 1.807,3.801 1.807,13.764 v 11.398" + id="path37" + inkscape:connector-curvature="0" + style="fill:#ffffff;fill-opacity:1" /><path + i:knockout="Off" + d="m 66.535,143.855 c -0.928,-0.139 -1.578,-0.232 -2.922,-0.232 -1.48,0 -2.502,0.094 -3.566,0.232 0.463,-0.881 0.648,-1.299 0.787,-4.309 0.186,-4.125 0.232,-15.154 -0.092,-17.471 -0.232,-1.762 -0.648,-2.039 -1.297,-2.502 3.799,-0.371 4.865,-0.648 6.625,-1.482 -0.369,2.037 -0.418,3.059 -0.418,6.162 -0.091,15.989 -0.138,17.702 0.883,19.602" + id="path39" + inkscape:connector-curvature="0" + style="fill:#ffffff;fill-opacity:1" /><path + i:knockout="Off" + d="m 81.373,130.74 c -0.092,2.92 -0.139,4.959 -0.928,6.58 -0.973,2.086 -2.594,2.688 -3.799,2.688 -2.783,0 -3.383,-2.316 -3.383,-4.586 0,-4.355 3.893,-4.682 5.652,-4.682 h 2.458 z m -12.744,5.701 c 0,2.92 0.881,5.838 3.477,7.09 1.158,0.51 2.316,0.51 2.688,0.51 4.264,0 5.699,-3.152 6.58,-5.098 -0.047,2.039 0,3.289 0.139,4.912 0.834,-0.047 1.668,-0.139 3.059,-0.139 0.787,0 1.529,0.092 2.316,0.139 -0.51,-0.787 -0.787,-1.252 -0.928,-3.059 -0.092,-1.76 -0.092,-3.521 -0.092,-5.977 l 0.047,-9.453 c 0,-3.523 -0.928,-6.998 -7.879,-6.998 -4.586,0 -7.273,1.391 -8.617,2.086 0.557,1.02 1.02,1.898 1.436,3.893 1.809,-1.576 4.172,-2.41 6.58,-2.41 3.848,0 3.848,2.549 3.848,6.162 -0.881,-0.045 -1.623,-0.137 -2.875,-0.137 -5.887,10e-4 -9.779,2.268 -9.779,8.479" + id="path41" + inkscape:connector-curvature="0" + style="fill:#ffffff;fill-opacity:1" /><path + i:knockout="Off" + d="m 108.063,139.268 c 0.047,1.576 0.047,3.244 0.695,4.588 -1.021,-0.092 -1.623,-0.232 -3.521,-0.232 -1.113,0 -1.715,0.094 -2.596,0.232 0.184,-0.602 0.279,-0.834 0.371,-1.623 0.139,-1.064 0.232,-4.633 0.232,-5.885 v -5.004 c 0,-2.178 0,-5.33 -0.141,-6.441 -0.092,-0.787 -0.322,-2.918 -3.012,-2.918 -2.641,0 -3.521,1.945 -3.846,3.521 -0.369,1.621 -0.369,3.383 -0.369,10.24 0.045,5.932 0.045,6.486 0.508,8.109 -0.787,-0.092 -1.76,-0.184 -3.15,-0.184 -1.113,0 -1.854,0.045 -2.779,0.184 0.324,-0.742 0.51,-1.113 0.602,-3.707 0.094,-2.549 0.279,-15.061 -0.141,-18.025 -0.23,-1.809 -0.695,-2.225 -1.203,-2.688 3.754,-0.186 4.957,-0.789 6.117,-1.389 v 4.91 c 0.555,-1.438 1.713,-4.635 6.348,-4.635 5.793,0 5.838,4.217 5.885,6.996 v 13.951" + id="path43" + inkscape:connector-curvature="0" + style="fill:#ffffff;fill-opacity:1" /><path + i:knockout="Off" + d="m 66.926,111.533 -3.838,3.836 -3.836,-3.836 3.836,-3.836 3.838,3.836" + id="path45" + inkscape:connector-curvature="0" + style="fill:#a80030" /></g><text + sodipodi:linespacing="125%" + id="text4101" + y="113.59251" + x="189.35947" + style="font-size:14px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans Bold" + xml:space="preserve"><tspan + y="113.59251" + x="189.35947" + id="tspan4103" + sodipodi:role="line">from</tspan></text> +</g></svg>
\ No newline at end of file diff --git a/debian/gbp.conf b/debian/gbp.conf new file mode 100644 index 0000000..89e7f25 --- /dev/null +++ b/debian/gbp.conf @@ -0,0 +1,7 @@ +# Configuration file for git-buildpackage and friends + +[DEFAULT] +filter = */.git* +components = ["libdvdnav-embedded", "libdvdread-embedded", "repo-resources-embedded"] +debian-branch = debian/sid +upstream-branch = upstream/latest diff --git a/debian/gitlab-ci.yml b/debian/gitlab-ci.yml new file mode 100644 index 0000000..0c22dc4 --- /dev/null +++ b/debian/gitlab-ci.yml @@ -0,0 +1,3 @@ +include: + - https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/salsa-ci.yml + - https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/pipeline-jobs.yml diff --git a/debian/headers-check.c b/debian/headers-check.c new file mode 100644 index 0000000..b81900b --- /dev/null +++ b/debian/headers-check.c @@ -0,0 +1,126 @@ +#include "kodi/AddonBase.h" +#include "kodi/AudioEngine.h" +#include "kodi/Filesystem.h" +#include "kodi/General.h" +#include "kodi/Network.h" +#include "kodi/addon-instance/AudioDecoder.h" +#include "kodi/addon-instance/AudioEncoder.h" +#include "kodi/addon-instance/Game.h" +#include "kodi/addon-instance/ImageDecoder.h" +#include "kodi/addon-instance/Inputstream.h" +#include "kodi/addon-instance/PVR.h" +#include "kodi/addon-instance/Peripheral.h" +#include "kodi/addon-instance/Screensaver.h" +#include "kodi/addon-instance/VFS.h" +#include "kodi/addon-instance/VideoCodec.h" +#include "kodi/addon-instance/Visualization.h" +#include "kodi/addon-instance/inputstream/DemuxPacket.h" +#include "kodi/addon-instance/inputstream/StreamCodec.h" +#include "kodi/addon-instance/inputstream/StreamConstants.h" +#include "kodi/addon-instance/inputstream/StreamCrypto.h" +#include "kodi/addon-instance/inputstream/TimingConstants.h" +#include "kodi/addon-instance/peripheral/PeripheralUtils.h" +#include "kodi/addon-instance/pvr/ChannelGroups.h" +#include "kodi/addon-instance/pvr/Channels.h" +#include "kodi/addon-instance/pvr/EDL.h" +#include "kodi/addon-instance/pvr/EPG.h" +#include "kodi/addon-instance/pvr/General.h" +#include "kodi/addon-instance/pvr/MenuHook.h" +#include "kodi/addon-instance/pvr/Providers.h" +#include "kodi/addon-instance/pvr/Recordings.h" +#include "kodi/addon-instance/pvr/Stream.h" +#include "kodi/addon-instance/pvr/Timers.h" +#include "kodi/c-api/addon-instance/audiodecoder.h" +#include "kodi/c-api/addon-instance/audioencoder.h" +#include "kodi/c-api/addon-instance/game.h" +#include "kodi/c-api/addon-instance/imagedecoder.h" +#include "kodi/c-api/addon-instance/inputstream.h" +#include "kodi/c-api/addon-instance/inputstream/demux_packet.h" +#include "kodi/c-api/addon-instance/inputstream/stream_codec.h" +#include "kodi/c-api/addon-instance/inputstream/stream_constants.h" +#include "kodi/c-api/addon-instance/inputstream/stream_crypto.h" +#include "kodi/c-api/addon-instance/inputstream/timing_constants.h" +#include "kodi/c-api/addon-instance/peripheral.h" +#include "kodi/c-api/addon-instance/pvr.h" +#include "kodi/c-api/addon-instance/pvr/pvr_channels.h" +#include "kodi/c-api/addon-instance/pvr/pvr_channel_groups.h" +#include "kodi/c-api/addon-instance/pvr/pvr_defines.h" +#include "kodi/c-api/addon-instance/pvr/pvr_edl.h" +#include "kodi/c-api/addon-instance/pvr/pvr_epg.h" +#include "kodi/c-api/addon-instance/pvr/pvr_general.h" +#include "kodi/c-api/addon-instance/pvr/pvr_menu_hook.h" +#include "kodi/c-api/addon-instance/pvr/pvr_providers.h" +#include "kodi/c-api/addon-instance/pvr/pvr_recordings.h" +#include "kodi/c-api/addon-instance/pvr/pvr_stream.h" +#include "kodi/c-api/addon-instance/pvr/pvr_timers.h" +#include "kodi/c-api/addon-instance/screensaver.h" +#include "kodi/c-api/addon-instance/vfs.h" +#include "kodi/c-api/addon-instance/video_codec.h" +#include "kodi/c-api/addon-instance/visualization.h" +#include "kodi/c-api/addon_base.h" +#include "kodi/c-api/audio_engine.h" +#include "kodi/c-api/filesystem.h" +#include "kodi/c-api/general.h" +#include "kodi/c-api/gui/controls/button.h" +#include "kodi/c-api/gui/controls/edit.h" +#include "kodi/c-api/gui/controls/fade_label.h" +#include "kodi/c-api/gui/controls/image.h" +#include "kodi/c-api/gui/controls/label.h" +#include "kodi/c-api/gui/controls/progress.h" +#include "kodi/c-api/gui/controls/radio_button.h" +#include "kodi/c-api/gui/controls/rendering.h" +#include "kodi/c-api/gui/controls/settings_slider.h" +#include "kodi/c-api/gui/controls/slider.h" +#include "kodi/c-api/gui/controls/spin.h" +#include "kodi/c-api/gui/controls/text_box.h" +#include "kodi/c-api/gui/definitions.h" +#include "kodi/c-api/gui/dialogs/context_menu.h" +#include "kodi/c-api/gui/dialogs/extended_progress.h" +#include "kodi/c-api/gui/dialogs/filebrowser.h" +#include "kodi/c-api/gui/dialogs/keyboard.h" +#include "kodi/c-api/gui/dialogs/numeric.h" +#include "kodi/c-api/gui/dialogs/ok.h" +#include "kodi/c-api/gui/dialogs/progress.h" +#include "kodi/c-api/gui/dialogs/select.h" +#include "kodi/c-api/gui/dialogs/text_viewer.h" +#include "kodi/c-api/gui/dialogs/yes_no.h" +#include "kodi/c-api/gui/general.h" +#include "kodi/c-api/gui/input/action_ids.h" +#include "kodi/c-api/gui/list_item.h" +#include "kodi/c-api/gui/window.h" +#include "kodi/c-api/network.h" +#include "kodi/gui/General.h" +#include "kodi/gui/ListItem.h" +#include "kodi/gui/Window.h" +#include "kodi/gui/controls/Button.h" +#include "kodi/gui/controls/Edit.h" +#include "kodi/gui/controls/FadeLabel.h" +#include "kodi/gui/controls/Image.h" +#include "kodi/gui/controls/Label.h" +#include "kodi/gui/controls/Progress.h" +#include "kodi/gui/controls/RadioButton.h" +#include "kodi/gui/controls/Rendering.h" +#include "kodi/gui/controls/SettingsSlider.h" +#include "kodi/gui/controls/Slider.h" +#include "kodi/gui/controls/Spin.h" +#include "kodi/gui/controls/TextBox.h" +#include "kodi/gui/dialogs/ContextMenu.h" +#include "kodi/gui/dialogs/ExtendedProgress.h" +#include "kodi/gui/dialogs/FileBrowser.h" +#include "kodi/gui/dialogs/Keyboard.h" +#include "kodi/gui/dialogs/Numeric.h" +#include "kodi/gui/dialogs/OK.h" +#include "kodi/gui/dialogs/Progress.h" +#include "kodi/gui/dialogs/Select.h" +#include "kodi/gui/dialogs/TextViewer.h" +#include "kodi/gui/dialogs/YesNo.h" +#include "kodi/gui/gl/GL.h" +#include "kodi/gui/gl/Shader.h" +#include "kodi/gui/input/ActionIDs.h" +#include "kodi/gui/renderHelper.h" +#include "kodi/tools/DllHelper.h" +#include "kodi/tools/EndTime.h" +#include "kodi/tools/StringUtils.h" +#include "kodi/tools/Thread.h" +#include "kodi/tools/Timer.h" +#include "kodi/versions.h" diff --git a/debian/kodi-addons-dev-common.README.Debian b/debian/kodi-addons-dev-common.README.Debian new file mode 100644 index 0000000..9d87821 --- /dev/null +++ b/debian/kodi-addons-dev-common.README.Debian @@ -0,0 +1,2 @@ +The current PVR API version can be found in xbmc_pvr_types.h: +XBMC_PVR_API_VERSION diff --git a/debian/kodi-addons-dev-common.install b/debian/kodi-addons-dev-common.install new file mode 100644 index 0000000..476a4e6 --- /dev/null +++ b/debian/kodi-addons-dev-common.install @@ -0,0 +1,3 @@ +usr/include/kodi +usr/share/kodi/cmake/*.cmake +debian/dh-addon/kodiaddon.pm usr/share/perl5/Debian/Debhelper/Sequence/ diff --git a/debian/kodi-addons-dev.install b/debian/kodi-addons-dev.install new file mode 100644 index 0000000..de58205 --- /dev/null +++ b/debian/kodi-addons-dev.install @@ -0,0 +1,2 @@ +debian/dh-addon/dh_kodiaddon_depends usr/bin/ +usr/lib/*/kodi/cmake diff --git a/debian/kodi-addons-dev.manpages b/debian/kodi-addons-dev.manpages new file mode 100644 index 0000000..f83eeca --- /dev/null +++ b/debian/kodi-addons-dev.manpages @@ -0,0 +1 @@ +debian/dh-addon/*.1 diff --git a/debian/kodi-bin.install b/debian/kodi-bin.install new file mode 100644 index 0000000..72f940b --- /dev/null +++ b/debian/kodi-bin.install @@ -0,0 +1,3 @@ +usr/lib/*/kodi/system +usr/lib/*/kodi/kodi-xrandr +usr/lib/*/kodi/kodi.bin diff --git a/debian/kodi-bin.lintian-overrides b/debian/kodi-bin.lintian-overrides new file mode 100644 index 0000000..28c9f96 --- /dev/null +++ b/debian/kodi-bin.lintian-overrides @@ -0,0 +1,20 @@ +# bindnow breaks wrappers used with libdvdread +hardening-no-bindnow [usr/lib/*/kodi/kodi.bin] +hardening-no-bindnow [usr/lib/*/kodi/kodi-xrandr] + +# kodi{.bin,-xrandr} are invoked by scripts /usr/bin/kodi* +executable-in-usr-lib [usr/lib/*/kodi/kodi.bin] +executable-in-usr-lib [usr/lib/*/kodi/kodi-xrandr] + +# Spelling errors in lib/libUPnP that can not be touched by Kodi +# (https://github.com/xbmc/xbmc/pull/18100#pullrequestreview-436935700) +spelling-error-in-binary Paramater Parameter [usr/lib/*/kodi/kodi.bin] +spelling-error-in-binary ment meant [usr/lib/*/kodi/kodi.bin] +spelling-error-in-binary unexected unexpected [usr/lib/*/kodi/kodi.bin] +spelling-error-in-binary develope develop [usr/lib/*/kodi/kodi.bin] +spelling-error-in-binary installe installer [usr/lib/*/kodi/kodi.bin] +spelling-error-in-binary protocolL protocol [usr/lib/*/kodi/kodi.bin] +spelling-error-in-binary rovided provided [usr/lib/*/kodi/kodi.bin] + +# The library in question really does not depend on external code +shared-library-lacks-prerequisites [usr/lib/*/kodi/system/libsse4-*.so] diff --git a/debian/kodi-bin.manpages b/debian/kodi-bin.manpages new file mode 100644 index 0000000..ae989bf --- /dev/null +++ b/debian/kodi-bin.manpages @@ -0,0 +1 @@ +docs/manpages/kodi.bin.1 diff --git a/debian/kodi-data.install b/debian/kodi-data.install new file mode 100644 index 0000000..f9a237d --- /dev/null +++ b/debian/kodi-data.install @@ -0,0 +1,11 @@ +usr/lib/firewalld/services/kodi-jsonrpc.xml +usr/lib/firewalld/services/kodi-http.xml +usr/lib/firewalld/services/kodi-eventserver.xml +usr/share/kodi/addons +usr/share/kodi/media +usr/share/kodi/privacy-policy.txt +usr/share/kodi/system +usr/share/kodi/userdata +usr/share/icons +usr/share/kodi/addons/skin.* +usr/share/xsessions/kodi.desktop diff --git a/debian/kodi-data.links b/debian/kodi-data.links new file mode 100644 index 0000000..bed7947 --- /dev/null +++ b/debian/kodi-data.links @@ -0,0 +1,7 @@ +usr/share/fonts/truetype/noto/NotoSans-Regular.ttf usr/share/kodi/addons/skin.estouchy/fonts/NotoSans-Regular.ttf +usr/share/fonts/truetype/noto/NotoMono-Regular.ttf usr/share/kodi/addons/skin.estuary/fonts/NotoMono-Regular.ttf +usr/share/fonts/truetype/noto/NotoSans-Bold.ttf usr/share/kodi/addons/skin.estuary/fonts/NotoSans-Bold.ttf +usr/share/fonts/truetype/noto/NotoSans-Regular.ttf usr/share/kodi/addons/skin.estuary/fonts/NotoSans-Regular.ttf +usr/share/fonts/truetype/roboto/hinted/Roboto-Thin.ttf usr/share/kodi/addons/skin.estuary/fonts/Roboto-Thin.ttf +usr/share/javascript/jquery/jquery.min.js /usr/share/kodi/addons/webinterface.default/js/jquery-1.8.2.min.js +usr/share/javascript/iscroll/iscroll-min.js /usr/share/kodi/addons/webinterface.default/js/iscroll-min.js diff --git a/debian/kodi-data.lintian-overrides b/debian/kodi-data.lintian-overrides new file mode 100644 index 0000000..1209223 --- /dev/null +++ b/debian/kodi-data.lintian-overrides @@ -0,0 +1,14 @@ +# Merged fonts used by Kodi as fallback +font-in-non-font-package [usr/share/kodi/media/Fonts/arial.ttf] +font-in-non-font-package [usr/share/kodi/media/Fonts/teletext.ttf] +font-outside-font-dir [usr/share/kodi/media/Fonts/arial.ttf] +font-outside-font-dir [usr/share/kodi/media/Fonts/teletext.ttf] + +# The majority of files found by this check are either changelog.txt or +# other text files used by addon code (like versions.txt). The changelog.txt +# is used by Kodi GUI to display the version history for the installed addons. +# Despite https://github.com/xbmc/xbmc/pull/9351 merged, big part of community +# insists on restoring the old behavior and this may happen before 19.0 final +# release. Please note that this override guards only addons code, so text files +# and documentation in other parts of Kodi will still be reported if found. +package-contains-documentation-outside-usr-share-doc [usr/share/kodi/addons/*] diff --git a/debian/kodi-eventclients-common.install b/debian/kodi-eventclients-common.install new file mode 100644 index 0000000..291a7e8 --- /dev/null +++ b/debian/kodi-eventclients-common.install @@ -0,0 +1 @@ +usr/share/pixmaps/kodi diff --git a/debian/kodi-eventclients-dev-common.examples b/debian/kodi-eventclients-dev-common.examples new file mode 100644 index 0000000..6e4cc71 --- /dev/null +++ b/debian/kodi-eventclients-dev-common.examples @@ -0,0 +1 @@ +usr/share/doc/kodi/kodi-eventclients-dev/examples/* diff --git a/debian/kodi-eventclients-dev-common.install b/debian/kodi-eventclients-dev-common.install new file mode 100644 index 0000000..14e3505 --- /dev/null +++ b/debian/kodi-eventclients-dev-common.install @@ -0,0 +1 @@ +usr/include/kodi/xbmcclient.h diff --git a/debian/kodi-eventclients-dev.install b/debian/kodi-eventclients-dev.install new file mode 100644 index 0000000..2b7551e --- /dev/null +++ b/debian/kodi-eventclients-dev.install @@ -0,0 +1 @@ +usr/lib/*/kodi/eventclients-dev diff --git a/debian/kodi-eventclients-kodi-send.install b/debian/kodi-eventclients-kodi-send.install new file mode 100644 index 0000000..0d4bff9 --- /dev/null +++ b/debian/kodi-eventclients-kodi-send.install @@ -0,0 +1 @@ +usr/bin/kodi-send diff --git a/debian/kodi-eventclients-kodi-send.lintian-overrides b/debian/kodi-eventclients-kodi-send.lintian-overrides new file mode 100644 index 0000000..7a665c7 --- /dev/null +++ b/debian/kodi-eventclients-kodi-send.lintian-overrides @@ -0,0 +1,2 @@ +# It is Python package dropping files in /usr/bin +package-contains-no-arch-dependent-files diff --git a/debian/kodi-eventclients-kodi-send.manpages b/debian/kodi-eventclients-kodi-send.manpages new file mode 100644 index 0000000..18b822e --- /dev/null +++ b/debian/kodi-eventclients-kodi-send.manpages @@ -0,0 +1 @@ +docs/manpages/kodi-send.1 diff --git a/debian/kodi-eventclients-ps3.install b/debian/kodi-eventclients-ps3.install new file mode 100644 index 0000000..66bc049 --- /dev/null +++ b/debian/kodi-eventclients-ps3.install @@ -0,0 +1,2 @@ +usr/bin/kodi-ps3remote +usr/lib/python*/*/kodi/ps3 diff --git a/debian/kodi-eventclients-ps3.lintian-overrides b/debian/kodi-eventclients-ps3.lintian-overrides new file mode 100644 index 0000000..e4c91cf --- /dev/null +++ b/debian/kodi-eventclients-ps3.lintian-overrides @@ -0,0 +1,6 @@ +# Python scripts meant to be run by end-user +executable-in-usr-lib [usr/lib/python3/dist-packages/kodi/ps3/sixpair.py] +executable-in-usr-lib [usr/lib/python3/dist-packages/kodi/ps3/sixwatch.py] + +# It is Python package dropping files in /usr/bin +package-contains-no-arch-dependent-files diff --git a/debian/kodi-eventclients-ps3.manpages b/debian/kodi-eventclients-ps3.manpages new file mode 100644 index 0000000..a78c6b3 --- /dev/null +++ b/debian/kodi-eventclients-ps3.manpages @@ -0,0 +1 @@ +docs/manpages/kodi-ps3remote.1 diff --git a/debian/kodi-eventclients-python.install b/debian/kodi-eventclients-python.install new file mode 100644 index 0000000..7e241a0 --- /dev/null +++ b/debian/kodi-eventclients-python.install @@ -0,0 +1 @@ +usr/lib/python*/*/kodi diff --git a/debian/kodi-eventclients-python.lintian-overrides b/debian/kodi-eventclients-python.lintian-overrides new file mode 100644 index 0000000..7a665c7 --- /dev/null +++ b/debian/kodi-eventclients-python.lintian-overrides @@ -0,0 +1,2 @@ +# It is Python package dropping files in /usr/bin +package-contains-no-arch-dependent-files diff --git a/debian/kodi-eventclients-wiiremote.install b/debian/kodi-eventclients-wiiremote.install new file mode 100644 index 0000000..96ac87a --- /dev/null +++ b/debian/kodi-eventclients-wiiremote.install @@ -0,0 +1 @@ +usr/bin/kodi-wiiremote diff --git a/debian/kodi-eventclients-wiiremote.lintian-overrides b/debian/kodi-eventclients-wiiremote.lintian-overrides new file mode 100644 index 0000000..981ca75 --- /dev/null +++ b/debian/kodi-eventclients-wiiremote.lintian-overrides @@ -0,0 +1,2 @@ +# bindnow breaks wrappers used with libdvdread +hardening-no-bindnow [usr/bin/kodi-wiiremote] diff --git a/debian/kodi-eventclients-wiiremote.manpages b/debian/kodi-eventclients-wiiremote.manpages new file mode 100644 index 0000000..ca4297b --- /dev/null +++ b/debian/kodi-eventclients-wiiremote.manpages @@ -0,0 +1 @@ +docs/manpages/kodi-wiiremote.1 diff --git a/debian/kodi-eventclients-zeroconf.install b/debian/kodi-eventclients-zeroconf.install new file mode 100644 index 0000000..3aadf53 --- /dev/null +++ b/debian/kodi-eventclients-zeroconf.install @@ -0,0 +1 @@ +usr/lib/python*/*/kodi/zeroconf.py diff --git a/debian/kodi-eventclients-zeroconf.lintian-overrides b/debian/kodi-eventclients-zeroconf.lintian-overrides new file mode 100644 index 0000000..9826a0f --- /dev/null +++ b/debian/kodi-eventclients-zeroconf.lintian-overrides @@ -0,0 +1,5 @@ +# It is Python package +package-contains-no-arch-dependent-files + +# and it can be run by end-user +executable-in-usr-lib [usr/lib/python3/dist-packages/kodi/zeroconf.py] diff --git a/debian/kodi-tools-texturepacker.install b/debian/kodi-tools-texturepacker.install new file mode 100644 index 0000000..588194f --- /dev/null +++ b/debian/kodi-tools-texturepacker.install @@ -0,0 +1 @@ +usr/bin/*TexturePacker diff --git a/debian/kodi-tools-texturepacker.lintian-overrides b/debian/kodi-tools-texturepacker.lintian-overrides new file mode 100644 index 0000000..8fc7313 --- /dev/null +++ b/debian/kodi-tools-texturepacker.lintian-overrides @@ -0,0 +1,2 @@ +# bindnow breaks wrappers used with libdvdread +hardening-no-bindnow [usr/bin/*TexturePacker] diff --git a/debian/kodi-tools-texturepacker.manpages b/debian/kodi-tools-texturepacker.manpages new file mode 100644 index 0000000..df26bba --- /dev/null +++ b/debian/kodi-tools-texturepacker.manpages @@ -0,0 +1 @@ +docs/manpages/*TexturePacker.1 diff --git a/debian/kodi.install b/debian/kodi.install new file mode 100644 index 0000000..c98127c --- /dev/null +++ b/debian/kodi.install @@ -0,0 +1,4 @@ +usr/bin/kodi +usr/bin/kodi-standalone +usr/share/applications +usr/share/metainfo diff --git a/debian/kodi.lintian-overrides b/debian/kodi.lintian-overrides new file mode 100644 index 0000000..5cb2ecb --- /dev/null +++ b/debian/kodi.lintian-overrides @@ -0,0 +1,5 @@ +# /usr/bin/kodi is a script referencing /usr/lib/$(DEB_ARCH)/kodi +package-contains-no-arch-dependent-files + +# Kodi uses metainfo file to store the info as it is translatable +desktop-entry-lacks-keywords-entry diff --git a/debian/kodi.manpages b/debian/kodi.manpages new file mode 100644 index 0000000..f201e5e --- /dev/null +++ b/debian/kodi.manpages @@ -0,0 +1,2 @@ +docs/manpages/kodi.1 +docs/manpages/kodi-standalone.1 diff --git a/debian/kodi.mime b/debian/kodi.mime new file mode 100644 index 0000000..ed9a199 --- /dev/null +++ b/debian/kodi.mime @@ -0,0 +1,19 @@ +video/mpeg; kodi %s; description="MPEG Video"; +video/x-mpeg; kodi %s; description="MPEG Video"; +video/mpeg-system; kodi %s; description="MPEG Video"; +video/x-mpeg-system; kodi %s; description="MPEG Video"; +audio/x-wav; kodi %s; description="WAV Audio"; nametemplate=%s.wav; +video/mpeg4; kodi %s; description="MPEG-4 Video"; +audio/mpeg; kodi %s; description="MPEG Audio"; nametemplate=%s.mpg; +audio/mpegurl; kodi %s; description="MPEG Audio URL"; nametemplate=%s.m3u; +audio/x-mp3; kodi %s; nametemplate=%s.mp3; description="MPEG Audio"; +audio/mpeg4; kodi %s; description="MPEG-4 Audio"; +application/mpeg4-iod; kodi %s; description="MPEG-4 Video"; +application/mpeg4-muxcodetable; kodi %s; description="MPEG-4 Video"; +video/x-msvideo; kodi %s; description="MS Video (AVI)"; +video/quicktime; kodi %s; description="Apple Quicktime Video"; +application/ogg; kodi %s; nametemplate=%s.ogg; description="Ogg stream"; +application/x-ogg; kodi %s; nametemplate=%s.ogg; description="Ogg stream"; +video/ogg; kodi %s; description="Ogg Video"; +application/x-ms-asf-plugin; kodi %s; description="Windows Media Video"; +application/x-mplayer2; kodi %s; description="Windows Media"; diff --git a/debian/mergefonts.ff b/debian/mergefonts.ff new file mode 100755 index 0000000..c1a43c0 --- /dev/null +++ b/debian/mergefonts.ff @@ -0,0 +1,6 @@ +#!/usr/bin/fontforge +# merge $1 and $2 to $3 fonts +Open($1); +ScaleToEm(2048) +MergeFonts($2); +Generate($3); diff --git a/debian/not-installed b/debian/not-installed new file mode 100644 index 0000000..a3906d4 --- /dev/null +++ b/debian/not-installed @@ -0,0 +1,7 @@ +# README and version.txt are superseded by manpages +usr/share/doc/kodi/LICENSE.md +usr/share/doc/kodi/README.Linux.md +usr/share/doc/kodi/version.txt + +# JsonSchemaBuilder is not intended for end-user +usr/bin/JsonSchemaBuilder diff --git a/debian/patches/cdatetime-std-chrono/0001-Replace-Kodi-date-time-implementation-with-std-c.patch b/debian/patches/cdatetime-std-chrono/0001-Replace-Kodi-date-time-implementation-with-std-c.patch new file mode 100644 index 0000000..5c553eb --- /dev/null +++ b/debian/patches/cdatetime-std-chrono/0001-Replace-Kodi-date-time-implementation-with-std-c.patch @@ -0,0 +1,7004 @@ +From c34f01771ab31da1450e0e8aec0dd4654ea5c557 Mon Sep 17 00:00:00 2001 +From: Lukas Rusak <lorusak@gmail.com> +Date: Mon, 17 Feb 2020 22:41:25 -0800 +Subject: [PATCH 01/19] add support for date library and tzdata + +Signed-off-by: Vasyl Gello <vasek.gello@gmail.com> +--- + CMakeLists.txt | 6 + + cmake/modules/FindDate.cmake | 110 ++++++++++++++++++ + cmake/modules/FindTZData.cmake | 33 ++++++ + cmake/scripts/linux/Install.cmake | 7 ++ + .../date/0001-cmake-install-all-headers.patch | 74 ++++++++++++ + .../target/date/0002-Fix-Android-build.patch | 37 ++++++ + .../target/date/0003-Fix-UWP-build.patch | 58 +++++++++ + tools/depends/target/date/DATE-VERSION | 6 + + .../target/tzdata/001-cmakelists.patch | 11 ++ + tools/depends/target/tzdata/TZDATA-VERSION | 5 + + 10 files changed, 347 insertions(+) + create mode 100644 cmake/modules/FindDate.cmake + create mode 100644 cmake/modules/FindTZData.cmake + create mode 100644 tools/depends/target/date/0001-cmake-install-all-headers.patch + create mode 100644 tools/depends/target/date/0002-Fix-Android-build.patch + create mode 100644 tools/depends/target/date/0003-Fix-UWP-build.patch + create mode 100644 tools/depends/target/date/DATE-VERSION + create mode 100644 tools/depends/target/tzdata/001-cmakelists.patch + create mode 100644 tools/depends/target/tzdata/TZDATA-VERSION + +diff --git a/CMakeLists.txt b/CMakeLists.txt +index 19881e4708..55344f7626 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -85,6 +85,10 @@ if(UNIX) + endif() + # prefer kissfft from xbmc/contrib but let use system one on unices + cmake_dependent_option(ENABLE_INTERNAL_KISSFFT "Enable internal kissfft?" ON "UNIX" ON) ++# prefer internal date and tzdata but let use system one on unices ++cmake_dependent_option(ENABLE_INTERNAL_DATE "Enable internal date library?" ON "UNIX" ON) ++cmake_dependent_option(ENABLE_INTERNAL_TZDATA "Use Kodi bundled timezone information?" ON "NOT ENABLE_INTERNAL_DATE" ON) ++cmake_dependent_option(DATE_HAS_STRINGVIEW "Is system date library compiled with StringView support?" ON "NOT ENABLE_INTERNAL_DATE" ON) + # System options + if(NOT WIN32) + option(WITH_ARCH "build with given arch" OFF) +@@ -163,6 +167,7 @@ set(required_deps ASS + Cdio + CrossGUID + Curl ++ Date + FFMPEG + FlatBuffers + Fmt +@@ -181,6 +186,7 @@ set(required_deps ASS + Sqlite3 + TagLib + TinyXML ++ TZData + ZLIB + ${PLATFORM_REQUIRED_DEPS}) + +diff --git a/cmake/modules/FindDate.cmake b/cmake/modules/FindDate.cmake +new file mode 100644 +index 0000000000..61746e4d33 +--- /dev/null ++++ b/cmake/modules/FindDate.cmake +@@ -0,0 +1,110 @@ ++#.rst: ++# FindDate ++# ------- ++# Finds the DATE library and builds internal ++# DATE if requested ++# ++# This will define the following variables:: ++# ++# DATE_FOUND - system has DATE ++# DATE_INCLUDE_DIRS - the DATE include directory ++# DATE_LIBRARIES - the DATE libraries ++# DATE_DEFINITIONS - the DATE definitions ++# ++# and the following imported targets:: ++# ++# Date::Date - The Date library ++ ++if(ENABLE_INTERNAL_DATE) ++ include(cmake/scripts/common/ModuleHelpers.cmake) ++ ++ set(MODULE_LC date) ++ ++ SETUP_BUILD_VARS() ++ ++ set(DATE_VERSION ${${MODULE}_VER}) ++ ++ # Debug postfix only used for windows ++ if(WIN32 OR WINDOWS_STORE) ++ set(DATE_DEBUG_POSTFIX "d") ++ endif() ++ ++ # Propagate CMake definitions ++ ++ if(CORE_SYSTEM_NAME STREQUAL darwin_embedded) ++ set(EXTRA_ARGS -DIOS=ON) ++ elseif(WINDOWS_STORE) ++ set(EXTRA_ARGS -DWINRT=ON) ++ endif() ++ ++ set(CMAKE_ARGS -DCMAKE_CXX_STANDARD=17 ++ -DUSE_SYSTEM_TZ_DB=OFF ++ -DMANUAL_TZ_DB=ON ++ -DUSE_TZ_DB_IN_DOT=OFF ++ -DBUILD_SHARED_LIBS=OFF ++ -DBUILD_TZ_LIB=ON ++ ${EXTRA_ARGS}) ++ ++ # Work around old release ++ ++ file(GLOB patches "${CMAKE_SOURCE_DIR}/tools/depends/target/date/*.patch") ++ ++ generate_patchcommand("${patches}") ++ ++ BUILD_DEP_TARGET() ++else() ++ if(PKG_CONFIG_FOUND) ++ pkg_check_modules(PC_DATE libdate-tz>=3.0.1 QUIET) ++ endif() ++ ++ find_path(DATE_INCLUDE_DIR date/date.h ++ PATHS ${PC_DATE_INCLUDEDIR}) ++ find_library(DATE_LIBRARY_RELEASE NAMES date-tz libdate-tz ++ PATHS ${PC_DATE_LIBDIR}) ++ find_library(DATE_LIBRARY_DEBUG NAMES date-tzd libdate-tzd ++ PATHS ${PC_DATE_LIBDIR}) ++ set(DATE_VERSION ${PC_DATE_VERSION}) ++endif() ++ ++include(SelectLibraryConfigurations) ++select_library_configurations(DATE) ++ ++include(FindPackageHandleStandardArgs) ++find_package_handle_standard_args(Date ++ REQUIRED_VARS DATE_LIBRARY DATE_INCLUDE_DIR ++ VERSION_VAR DATE_VERSION) ++ ++if(DATE_FOUND) ++ set(DATE_INCLUDE_DIRS ${DATE_INCLUDE_DIR}) ++ set(DATE_LIBRARIES ${DATE_LIBRARY}) ++ ++ if(ENABLE_INTERNAL_TZDATA) ++ set(DATE_DEFINITIONS ${DATE_DEFINITIONS} -DDATE_INTERNAL_TZDATA) ++ endif() ++ ++ if(DATE_HAS_STRINGVIEW) ++ set(DATE_DEFINITIONS ${DATE_DEFINITIONS} -DDATE_HAS_STRINGVIEW) ++ endif() ++ ++ if(NOT TARGET Date::Date) ++ add_library(Date::Date UNKNOWN IMPORTED) ++ if(DATE_LIBRARY_RELEASE) ++ set_target_properties(Date::Date PROPERTIES ++ IMPORTED_CONFIGURATIONS RELEASE ++ IMPORTED_LOCATION "${DATE_LIBRARY_RELEASE}") ++ endif() ++ if(DATE_LIBRARY_DEBUG) ++ set_target_properties(Date::Date PROPERTIES ++ IMPORTED_CONFIGURATIONS DEBUG ++ IMPORTED_LOCATION "${DATE_LIBRARY_DEBUG}") ++ endif() ++ set_target_properties(Date::Date PROPERTIES ++ INTERFACE_INCLUDE_DIRECTORIES "${DATE_INCLUDE_DIR}") ++ if(TARGET date) ++ add_dependencies(Date::Date date) ++ endif() ++ endif() ++ set_property(GLOBAL APPEND PROPERTY INTERNAL_DEPS_PROP Date::Date) ++endif() ++ ++mark_as_advanced(DATE_INCLUDE_DIR DATE_LIBRARY) +diff --git a/cmake/modules/FindTZData.cmake b/cmake/modules/FindTZData.cmake +new file mode 100644 +index 0000000000..b7241a6b04 +--- /dev/null ++++ b/cmake/modules/FindTZData.cmake +@@ -0,0 +1,33 @@ ++#.rst: ++# FindTZData ++# ------- ++# Populates resource.timezone with TZDATA if requested ++# ++# This will define the following variables:: ++# ++# TZDATA_FOUND - system has internal TZDATA ++# TZDATA_VERSION - version of internal TZDATA ++ ++if(ENABLE_INTERNAL_TZDATA) ++ include(cmake/scripts/common/ModuleHelpers.cmake) ++ ++ set(MODULE_LC tzdata) ++ ++ SETUP_BUILD_VARS() ++ ++ # Mirror tzdata to resource.timezone ++ ++ set(CMAKE_ARGS -DINSTALL_DIR=${CMAKE_BINARY_DIR}/addons/resource.timezone/resources/tzdata) ++ ++ # Add CMakeLists.txt installing sources as target ++ ++ set(patches ${CMAKE_SOURCE_DIR}/tools/depends/target/tzdata/001-cmakelists.patch) ++ ++ generate_patchcommand("${patches}") ++ ++ BUILD_DEP_TARGET() ++else() ++ set(TZDATA_VERSION "none") ++endif() ++ ++set(TZDATA_FOUND TRUE) +diff --git a/cmake/scripts/linux/Install.cmake b/cmake/scripts/linux/Install.cmake +index 331722cb56..e3ceacbf76 100644 +--- a/cmake/scripts/linux/Install.cmake ++++ b/cmake/scripts/linux/Install.cmake +@@ -85,6 +85,13 @@ foreach(file ${install_data}) + COMPONENT kodi) + endforeach() + ++# Install timezone resources ++if(ENABLE_INTERNAL_TZDATA) ++ install(DIRECTORY ${CMAKE_BINARY_DIR}/addons/resource.timezone/resources/tzdata ++ DESTINATION ${datarootdir}/${APP_NAME_LC}/addons/resource.timezone/resources ++ COMPONENT kodi) ++endif() ++ + # Install xsession entry + install(FILES ${CMAKE_BINARY_DIR}/${CORE_BUILD_DIR}/${APP_NAME_LC}-xsession.desktop + RENAME ${APP_NAME_LC}.desktop +diff --git a/tools/depends/target/date/0001-cmake-install-all-headers.patch b/tools/depends/target/date/0001-cmake-install-all-headers.patch +new file mode 100644 +index 0000000000..e8ac76a48b +--- /dev/null ++++ b/tools/depends/target/date/0001-cmake-install-all-headers.patch +@@ -0,0 +1,74 @@ ++From 8b3fac88cb5e4fef81b55b7537232a6418752153 Mon Sep 17 00:00:00 2001 ++From: Andrea Pappacoda <andrea@pappacoda.it> ++Date: Thu, 4 Aug 2022 11:35:41 +0200 ++Subject: [PATCH 1/4] cmake: install all headers ++ ++Lazy solution: mark all headers as either PUBLIC_ or PRIVATE_HEADER, ++requiring CMake 3.15. ++ ++Bug: https://github.com/HowardHinnant/date/pull/503 ++Bug-Debian: https://bugs.debian.org/1001895 ++--- ++ CMakeLists.txt | 20 +++++++++++++++----- ++ 1 file changed, 15 insertions(+), 5 deletions(-) ++ ++diff --git a/CMakeLists.txt b/CMakeLists.txt ++index 012512a..c0bda7f 100644 ++--- a/CMakeLists.txt +++++ b/CMakeLists.txt ++@@ -75,7 +75,13 @@ target_sources( date INTERFACE ++ ) ++ if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.15) ++ # public headers will get installed: ++- set_target_properties( date PROPERTIES PUBLIC_HEADER include/date/date.h ) +++ set_property(TARGET date PROPERTY PUBLIC_HEADER +++ include/date/date.h +++ include/date/islamic.h +++ include/date/iso_week.h +++ include/date/julian.h +++ include/date/solar_hijri.h +++ ) ++ endif () ++ ++ # These used to be set with generator expressions, ++@@ -137,14 +143,16 @@ if( BUILD_TZ_LIB ) ++ target_compile_definitions( date-tz PUBLIC DATE_BUILD_DLL=1 ) ++ endif() ++ ++- set(TZ_HEADERS include/date/tz.h) +++ set(TZ_PUBLIC_HEADERS include/date/ptz.h include/date/tz.h) +++ set(TZ_PRIVATE_HEADERS include/date/tz_private.h) ++ ++ if( IOS ) ++- list(APPEND TZ_HEADERS include/date/ios.h) +++ list(APPEND TZ_PRIVATE_HEADERS include/date/ios.h) ++ endif( ) ++ set_target_properties( date-tz PROPERTIES ++ POSITION_INDEPENDENT_CODE ON ++- PUBLIC_HEADER "${TZ_HEADERS}" +++ PUBLIC_HEADER "${TZ_PUBLIC_HEADERS}" +++ PRIVATE_HEADER "${TZ_PRIVATE_HEADERS}" ++ VERSION "${PROJECT_VERSION}" ++ SOVERSION "${ABI_VERSION}" ) ++ if( NOT MSVC ) ++@@ -170,7 +178,8 @@ write_basic_package_version_file( "${version_config}" ++ ++ install( TARGETS date ++ EXPORT dateConfig ++- PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/date ) +++ PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/date +++ PRIVATE_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/date ) ++ export( TARGETS date NAMESPACE date:: FILE dateTargets.cmake ) ++ if (CMAKE_VERSION VERSION_LESS 3.15) ++ install( ++@@ -182,6 +191,7 @@ if( BUILD_TZ_LIB ) ++ install( TARGETS date-tz ++ EXPORT dateConfig ++ PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/date +++ PRIVATE_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/date ++ ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} ++ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ++ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} ) # This is for Windows ++-- ++2.39.0 ++ +diff --git a/tools/depends/target/date/0002-Fix-Android-build.patch b/tools/depends/target/date/0002-Fix-Android-build.patch +new file mode 100644 +index 0000000000..e497b41bcf +--- /dev/null ++++ b/tools/depends/target/date/0002-Fix-Android-build.patch +@@ -0,0 +1,37 @@ ++From 5790d6aed57bda1dc1577860d8382678100ebfa3 Mon Sep 17 00:00:00 2001 ++From: Vasyl Gello <vasek.gello@gmail.com> ++Date: Wed, 11 Jan 2023 11:35:41 +0200 ++Subject: [PATCH 2/4] Fix Android build ++ ++Signed-off-by: Vasyl Gello <vasek.gello@gmail.com> ++--- ++ src/tz.cpp | 6 ++++-- ++ 1 file changed, 4 insertions(+), 2 deletions(-) ++ ++diff --git a/src/tz.cpp b/src/tz.cpp ++index 26babbd..69bab7c 100644 ++--- a/src/tz.cpp +++++ b/src/tz.cpp ++@@ -141,7 +141,7 @@ ++ # endif // HAS_REMOTE_API ++ #else // !_WIN32 ++ # include <unistd.h> ++-# if !USE_OS_TZDB && !defined(INSTALL) +++# if !USE_OS_TZDB && !defined(INSTALL) && !defined(__ANDROID__) ++ # include <wordexp.h> ++ # endif ++ # include <limits.h> ++@@ -245,7 +245,9 @@ expand_path(std::string path) ++ { ++ # if TARGET_OS_IPHONE ++ return date::iOSUtils::get_tzdata_path(); ++-# else // !TARGET_OS_IPHONE +++# elif defined(__ANDROID__) +++ return "/data/local/tmp"; +++# else // !TARGET_OS_IPHONE && !__ANDROID__ ++ ::wordexp_t w{}; ++ std::unique_ptr<::wordexp_t, void(*)(::wordexp_t*)> hold{&w, ::wordfree}; ++ ::wordexp(path.c_str(), &w, 0); ++-- ++2.39.0 ++ +diff --git a/tools/depends/target/date/0003-Fix-UWP-build.patch b/tools/depends/target/date/0003-Fix-UWP-build.patch +new file mode 100644 +index 0000000000..683ed4126d +--- /dev/null ++++ b/tools/depends/target/date/0003-Fix-UWP-build.patch +@@ -0,0 +1,58 @@ ++From 1e512b082eb99b5d9cd790158f3bdaefcbac823d Mon Sep 17 00:00:00 2001 ++From: Vasyl Gello <vasek.gello@gmail.com> ++Date: Wed, 11 Jan 2023 09:58:34 +0200 ++Subject: [PATCH 3/4] Fix UWP build ++ ++We don't need download_folder to be determined. ++Bringing full UWP runtime just for that is an overkill. ++--- ++ CMakeLists.txt | 4 ++++ ++ src/tz.cpp | 17 +++++++++++++++++ ++ 2 files changed, 21 insertions(+) ++ ++diff --git a/CMakeLists.txt b/CMakeLists.txt ++index c0bda7f..0fa3dc2 100644 ++--- a/CMakeLists.txt +++++ b/CMakeLists.txt ++@@ -133,6 +133,10 @@ if( BUILD_TZ_LIB ) ++ target_compile_definitions( date-tz PRIVATE AUTO_DOWNLOAD=1 HAS_REMOTE_API=1 ) ++ endif() ++ +++ if(WINRT) +++ target_compile_definitions( date-tz PRIVATE WINRT=1 INSTALL=. ) +++ endif() +++ ++ if ( USE_SYSTEM_TZ_DB AND NOT WIN32 AND NOT MANUAL_TZ_DB ) ++ target_compile_definitions( date-tz PRIVATE INSTALL=. PUBLIC USE_OS_TZDB=1 ) ++ else() ++diff --git a/src/tz.cpp b/src/tz.cpp ++index 69bab7c..aa15192 100644 ++--- a/src/tz.cpp +++++ b/src/tz.cpp ++@@ -234,6 +234,23 @@ get_download_folder() ++ ++ # endif // !INSTALL ++ +++# else // WINRT +++static +++std::string +++get_program_folder() +++{ +++ return ""; +++} +++ +++# ifndef INSTALL +++ +++static +++std::string +++get_download_folder() +++{ +++ return ""; +++} +++# endif // !INSTALL ++ # endif // WINRT ++ # else // !_WIN32 ++ ++-- ++2.39.0 ++ +diff --git a/tools/depends/target/date/DATE-VERSION b/tools/depends/target/date/DATE-VERSION +new file mode 100644 +index 0000000000..0608029104 +--- /dev/null ++++ b/tools/depends/target/date/DATE-VERSION +@@ -0,0 +1,6 @@ ++LIBNAME=date ++VERSION=3.0.1 ++ARCHIVE=$(LIBNAME)-$(VERSION).tar.gz ++SHA512=6bdc7cba821d66e17a559250cc0ce0095808e9db81cec9e16eaa4c31abdfa705299c67b72016d9b06b302bc306d063e83a374eb00728071b83a5ad650d59034f ++BYPRODUCT=libdate-tz.a ++BYPRODUCT_WIN=date-tz.lib +diff --git a/tools/depends/target/tzdata/001-cmakelists.patch b/tools/depends/target/tzdata/001-cmakelists.patch +new file mode 100644 +index 0000000000..dda65fc542 +--- /dev/null ++++ b/tools/depends/target/tzdata/001-cmakelists.patch +@@ -0,0 +1,11 @@ ++diff --git a/CMakeLists.txt b/CMakeLists.txt ++new file mode 100644 ++index 0000000..8a015cd ++--- /dev/null +++++ b/CMakeLists.txt ++@@ -0,0 +1,5 @@ +++cmake_minimum_required(VERSION 3.2) +++ +++project(kodi-tzdata) +++ +++install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/ DESTINATION ${INSTALL_DIR}) +diff --git a/tools/depends/target/tzdata/TZDATA-VERSION b/tools/depends/target/tzdata/TZDATA-VERSION +new file mode 100644 +index 0000000000..7f92f0b74c +--- /dev/null ++++ b/tools/depends/target/tzdata/TZDATA-VERSION +@@ -0,0 +1,5 @@ ++LIBNAME=tzdata ++VERSION=2022g ++ARCHIVE=$(LIBNAME)$(VERSION).tar.gz ++SHA512=7f79394295e00e3a24ebdbf9af3bc454a65f432a93b517e7e96c7f9db9949f6f5fdae9892a9d3789ff44ae0eb1bfe4744d36976b4624659af951d26414f94e65 ++SOURCE_DIR=addons/resource.timezone/resources/tzdata +-- +2.43.0 + + +From b4a3fafe6da802ae1d690ceb07fbf5a781e0301a Mon Sep 17 00:00:00 2001 +From: Lukas Rusak <lorusak@gmail.com> +Date: Tue, 17 Mar 2020 13:12:04 -0700 +Subject: [PATCH 02/19] add resource.timezone + +--- + addons/kodi.resource/addon.xml | 1 + + addons/kodi.resource/timezone.xsd | 16 ++++++++++++ + addons/resource.timezone/addon.xml | 12 +++++++++ + cmake/installdata/common/addons.txt | 1 + + system/addon-manifest.xml | 1 + + xbmc/ServiceManager.cpp | 20 +++++++++++++++ + xbmc/addons/AddonBuilder.cpp | 3 +++ + xbmc/addons/CMakeLists.txt | 2 ++ + xbmc/addons/TimeZoneResource.cpp | 39 +++++++++++++++++++++++++++++ + xbmc/addons/TimeZoneResource.h | 25 ++++++++++++++++++ + xbmc/addons/addoninfo/AddonInfo.cpp | 3 ++- + xbmc/addons/addoninfo/AddonType.h | 1 + + xbmc/application/Application.cpp | 20 +++++++++++++++ + 13 files changed, 143 insertions(+), 1 deletion(-) + create mode 100644 addons/kodi.resource/timezone.xsd + create mode 100644 addons/resource.timezone/addon.xml + create mode 100644 xbmc/addons/TimeZoneResource.cpp + create mode 100644 xbmc/addons/TimeZoneResource.h + +diff --git a/addons/kodi.resource/addon.xml b/addons/kodi.resource/addon.xml +index 2bb3221b42..b615575744 100644 +--- a/addons/kodi.resource/addon.xml ++++ b/addons/kodi.resource/addon.xml +@@ -7,4 +7,5 @@ + <extension-point id="resource.language" schema="language.xsd"/> + <extension-point id="resource.uisounds" schema="uisounds.xsd"/> + <extension-point id="resource.images" schema="images.xsd"/> ++ <extension-point id="resource.timezone" schema="timezone.xsd"/> + </addon> +diff --git a/addons/kodi.resource/timezone.xsd b/addons/kodi.resource/timezone.xsd +new file mode 100644 +index 0000000000..990f8893ea +--- /dev/null ++++ b/addons/kodi.resource/timezone.xsd +@@ -0,0 +1,16 @@ ++<?xml version="1.0" encoding="UTF-8"?> ++<!DOCTYPE schema PUBLIC "-//W3C//DTD XMLSCHEMA 200102//EN" "http://www.w3.org/2001/XMLSchema.dtd"> ++<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> ++ <xs:element name="extension"> ++ <xs:complexType> ++ <xs:attribute name="point" type="xs:string" use="required"/> ++ <xs:attribute name="id" type="simpleIdentifier"/> ++ <xs:attribute name="name" type="xs:string"/> ++ </xs:complexType> ++ </xs:element> ++ <xs:simpleType name="simpleIdentifier"> ++ <xs:restriction base="xs:string"> ++ <xs:pattern value="kodi\.resource\.timezone"/> ++ </xs:restriction> ++ </xs:simpleType> ++</xs:schema> +diff --git a/addons/resource.timezone/addon.xml b/addons/resource.timezone/addon.xml +new file mode 100644 +index 0000000000..174b3f5687 +--- /dev/null ++++ b/addons/resource.timezone/addon.xml +@@ -0,0 +1,12 @@ ++<?xml version="1.0" encoding="UTF-8"?> ++<addon id="resource.timezone" version="1.0.0" name="Kodi Timezone Database" provider-name="Team Kodi"> ++ <requires> ++ <import addon="kodi.resource" version="1.0.0"/> ++ </requires> ++ <extension point="kodi.resource.timezone"/> ++ <extension point="kodi.addon.metadata"> ++ <summary lang="en_GB">Kodi Timezone Database</summary> ++ <description lang="en_GB">Kodi Timezone Database</description> ++ <platform>all</platform> ++ </extension> ++</addon> +diff --git a/cmake/installdata/common/addons.txt b/cmake/installdata/common/addons.txt +index 263e57bb66..0411f8a3da 100644 +--- a/cmake/installdata/common/addons.txt ++++ b/cmake/installdata/common/addons.txt +@@ -26,6 +26,7 @@ addons/metadata.tvshows.themoviedb.org.python/* + addons/repository.xbmc.org/* + addons/resource.images.weathericons.default/* + addons/resource.language.en_gb/* ++addons/resource.timezone/* + addons/resource.uisounds.kodi/* + addons/screensaver.xbmc.builtin.black/* + addons/screensaver.xbmc.builtin.dim/* +diff --git a/system/addon-manifest.xml b/system/addon-manifest.xml +index 7df13a6d6f..842e4e8206 100644 +--- a/system/addon-manifest.xml ++++ b/system/addon-manifest.xml +@@ -38,6 +38,7 @@ + <addon optional="true">repository.xbmc.org</addon> + <addon>resource.images.weathericons.default</addon> + <addon>resource.language.en_gb</addon> ++ <addon>resource.timezone</addon> + <addon>resource.uisounds.kodi</addon> + <addon>screensaver.xbmc.builtin.black</addon> + <addon>screensaver.xbmc.builtin.dim</addon> +diff --git a/xbmc/ServiceManager.cpp b/xbmc/ServiceManager.cpp +index 02d9900e9b..83070489e3 100644 +--- a/xbmc/ServiceManager.cpp ++++ b/xbmc/ServiceManager.cpp +@@ -17,6 +17,7 @@ + #include "addons/RepositoryUpdater.h" + #include "addons/Service.h" + #include "addons/VFSEntry.h" ++#include "addons/addoninfo/AddonType.h" + #include "addons/binary-addons/BinaryAddonManager.h" + #include "cores/DataCacheCore.h" + #include "cores/RetroPlayer/guibridge/GUIGameRenderManager.h" +@@ -45,9 +46,14 @@ + #endif + #include "storage/MediaManager.h" + #include "utils/FileExtensionProvider.h" ++#include "utils/URIUtils.h" + #include "utils/log.h" + #include "weather/WeatherManager.h" + ++#define USE_OS_TZDB 0 ++#define HAS_REMOTE_API 0 ++#include <date/tz.h> ++ + using namespace KODI; + + CServiceManager::CServiceManager() = default; +@@ -79,6 +85,20 @@ bool CServiceManager::InitForTesting() + m_extsMimeSupportList.reset(new ADDONS::CExtsMimeSupportList(*m_addonMgr)); + m_fileExtensionProvider.reset(new CFileExtensionProvider(*m_addonMgr)); + ++#if defined(DATE_INTERNAL_TZDATA) ++ ADDON::AddonPtr addon; ++ if (!m_addonMgr->GetAddon("resource.timezone", addon, ADDON::AddonType::RESOURCE_TIMEZONE, ++ ADDON::OnlyEnabled::CHOICE_YES)) ++ { ++ CLog::LogF(LOGFATAL, "failed to find resource.timezone"); ++ return false; ++ } ++ ++ std::string tzdataPath = URIUtils::AddFileToFolder(addon->Path(), "resources", "tzdata"); ++ CLog::LogF(LOGDEBUG, "tzdata path: {}", tzdataPath); ++ date::set_install(tzdataPath); ++#endif ++ + init_level = 1; + return true; + } +diff --git a/xbmc/addons/AddonBuilder.cpp b/xbmc/addons/AddonBuilder.cpp +index 7d52ee0431..dd72a08705 100644 +--- a/xbmc/addons/AddonBuilder.cpp ++++ b/xbmc/addons/AddonBuilder.cpp +@@ -19,6 +19,7 @@ + #include "addons/Scraper.h" + #include "addons/Service.h" + #include "addons/Skin.h" ++#include "addons/TimeZoneResource.h" + #include "addons/UISoundsResource.h" + #include "addons/Webinterface.h" + #include "addons/addoninfo/AddonInfo.h" +@@ -106,6 +107,8 @@ AddonPtr CAddonBuilder::Generate(const AddonInfoPtr& info, AddonType type) + return std::make_shared<CLanguageResource>(info); + case AddonType::RESOURCE_UISOUNDS: + return std::make_shared<CUISoundsResource>(info); ++ case AddonType::RESOURCE_TIMEZONE: ++ return std::make_shared<CTimeZoneResource>(info); + case AddonType::REPOSITORY: + return std::make_shared<CRepository>(info); + case AddonType::CONTEXTMENU_ITEM: +diff --git a/xbmc/addons/CMakeLists.txt b/xbmc/addons/CMakeLists.txt +index 947a885b4c..101371f12d 100644 +--- a/xbmc/addons/CMakeLists.txt ++++ b/xbmc/addons/CMakeLists.txt +@@ -26,6 +26,7 @@ set(SOURCES Addon.cpp + ScreenSaver.cpp + Service.cpp + Skin.cpp ++ TimeZoneResource.cpp + UISoundsResource.cpp + VFSEntry.cpp + Visualization.cpp +@@ -66,6 +67,7 @@ set(HEADERS Addon.h + ScreenSaver.h + Service.h + Skin.h ++ TimeZoneResource.h + UISoundsResource.h + VFSEntry.h + Visualization.h +diff --git a/xbmc/addons/TimeZoneResource.cpp b/xbmc/addons/TimeZoneResource.cpp +new file mode 100644 +index 0000000000..94246c9e18 +--- /dev/null ++++ b/xbmc/addons/TimeZoneResource.cpp +@@ -0,0 +1,39 @@ ++/* ++ * Copyright (C) 2015-2018 Team Kodi ++ * This file is part of Kodi - https://kodi.tv ++ * ++ * SPDX-License-Identifier: GPL-2.0-or-later ++ * See LICENSES/README.md for more information. ++ */ ++#include "TimeZoneResource.h" ++ ++#include "addons/addoninfo/AddonType.h" ++#include "utils/StringUtils.h" ++#include "utils/URIUtils.h" ++ ++#include <date/tz.h> ++ ++namespace ADDON ++{ ++ ++CTimeZoneResource::CTimeZoneResource(const AddonInfoPtr& addonInfo) ++ : CResource(addonInfo, AddonType::RESOURCE_TIMEZONE) ++{ ++} ++ ++bool CTimeZoneResource::IsAllowed(const std::string& file) const ++{ ++ return true; ++} ++ ++bool CTimeZoneResource::IsInUse() const ++{ ++ return true; ++} ++ ++void CTimeZoneResource::OnPostInstall(bool update, bool modal) ++{ ++ date::reload_tzdb(); ++} ++ ++} // namespace ADDON +diff --git a/xbmc/addons/TimeZoneResource.h b/xbmc/addons/TimeZoneResource.h +new file mode 100644 +index 0000000000..a979f05dec +--- /dev/null ++++ b/xbmc/addons/TimeZoneResource.h +@@ -0,0 +1,25 @@ ++/* ++ * Copyright (C) 2015-2018 Team Kodi ++ * This file is part of Kodi - https://kodi.tv ++ * ++ * SPDX-License-Identifier: GPL-2.0-or-later ++ * See LICENSES/README.md for more information. ++ */ ++ ++#pragma once ++ ++#include "addons/Resource.h" ++ ++namespace ADDON ++{ ++ ++class CTimeZoneResource : public CResource ++{ ++public: ++ explicit CTimeZoneResource(const AddonInfoPtr& addonInfo); ++ bool IsAllowed(const std::string& file) const override; ++ bool IsInUse() const override; ++ void OnPostInstall(bool update, bool modal) override; ++}; ++ ++} // namespace ADDON +diff --git a/xbmc/addons/addoninfo/AddonInfo.cpp b/xbmc/addons/addoninfo/AddonInfo.cpp +index 61bc087443..f82a947981 100644 +--- a/xbmc/addons/addoninfo/AddonInfo.cpp ++++ b/xbmc/addons/addoninfo/AddonInfo.cpp +@@ -37,7 +37,7 @@ typedef struct + } TypeMapping; + + // clang-format off +-static constexpr const std::array<TypeMapping, 40> types = ++static constexpr const std::array<TypeMapping, 41> types = + {{ + {"unknown", "", AddonType::UNKNOWN, 0, AddonInstanceSupport::SUPPORT_NONE, "" }, + {"xbmc.metadata.scraper.albums", "", AddonType::SCRAPER_ALBUMS, 24016, AddonInstanceSupport::SUPPORT_NONE, "DefaultAddonAlbumInfo.png" }, +@@ -73,6 +73,7 @@ static constexpr const std::array<TypeMapping, 40> types = + {"xbmc.service", "", AddonType::SERVICE, 24018, AddonInstanceSupport::SUPPORT_NONE, "DefaultAddonService.png" }, + {"kodi.resource.images", "", AddonType::RESOURCE_IMAGES, 24035, AddonInstanceSupport::SUPPORT_NONE, "DefaultAddonImages.png" }, + {"kodi.resource.language", "", AddonType::RESOURCE_LANGUAGE, 24026, AddonInstanceSupport::SUPPORT_NONE, "DefaultAddonLanguage.png" }, ++ {"kodi.resource.timezone", "", AddonType::RESOURCE_TIMEZONE, 24026, AddonInstanceSupport::SUPPORT_NONE, "DefaultAddonTimeZone.png" }, + {"kodi.resource.uisounds", "", AddonType::RESOURCE_UISOUNDS, 24006, AddonInstanceSupport::SUPPORT_NONE, "DefaultAddonUISounds.png" }, + {"kodi.resource.games", "", AddonType::RESOURCE_GAMES, 35209, AddonInstanceSupport::SUPPORT_NONE, "DefaultAddonGame.png" }, + {"kodi.resource.font", "", AddonType::RESOURCE_FONT, 13303, AddonInstanceSupport::SUPPORT_NONE, "DefaultAddonFont.png" }, +diff --git a/xbmc/addons/addoninfo/AddonType.h b/xbmc/addons/addoninfo/AddonType.h +index 9a0ee260cf..27f49e3138 100644 +--- a/xbmc/addons/addoninfo/AddonType.h ++++ b/xbmc/addons/addoninfo/AddonType.h +@@ -46,6 +46,7 @@ enum class AddonType + AUDIODECODER, + RESOURCE_IMAGES, + RESOURCE_LANGUAGE, ++ RESOURCE_TIMEZONE, + RESOURCE_UISOUNDS, + RESOURCE_GAMES, + RESOURCE_FONT, +diff --git a/xbmc/application/Application.cpp b/xbmc/application/Application.cpp +index 0765cf3723..ea1b152dfd 100644 +--- a/xbmc/application/Application.cpp ++++ b/xbmc/application/Application.cpp +@@ -195,8 +195,12 @@ + #include "pictures/GUIWindowSlideShow.h" + #include "utils/CharsetConverter.h" + ++#define USE_OS_TZDB 0 ++#define HAS_REMOTE_API 0 + #include <mutex> + ++#include <date/tz.h> ++ + using namespace ADDON; + using namespace XFILE; + #ifdef HAS_DVD_DRIVE +@@ -435,6 +439,22 @@ bool CApplication::Create() + return false; + } + ++ // Load timezone information ++#if defined(DATE_INTERNAL_TZDATA) ++ ADDON::AddonPtr addon; ++ if (!CServiceBroker::GetAddonMgr().GetAddon("resource.timezone", addon, ++ ADDON::AddonType::RESOURCE_TIMEZONE, ++ ADDON::OnlyEnabled::CHOICE_YES)) ++ { ++ CLog::LogF(LOGFATAL, "failed to find resource.timezone"); ++ return false; ++ } ++ ++ std::string tzdataPath = URIUtils::AddFileToFolder(addon->Path(), "resources", "tzdata"); ++ CLog::LogF(LOGDEBUG, "tzdata path: {}", tzdataPath); ++ date::set_install(tzdataPath); ++#endif ++ + m_pActiveAE.reset(new ActiveAE::CActiveAE()); + CServiceBroker::RegisterAE(m_pActiveAE.get()); + +-- +2.43.0 + + +From 6f004e0aa809505cbf71612df44343a15011d0cf Mon Sep 17 00:00:00 2001 +From: Lukas Rusak <lorusak@gmail.com> +Date: Mon, 10 Feb 2020 15:13:43 -0800 +Subject: [PATCH 03/19] CDateTime: convert to use std::chrono + +--- + xbmc/XBDateTime.cpp | 604 ++++++++-------------- + xbmc/XBDateTime.h | 31 +- + xbmc/platform/posix/PosixTimezone.cpp | 3 - + xbmc/pvr/guilib/PVRGUIActionsDatabase.cpp | 2 - + 4 files changed, 244 insertions(+), 396 deletions(-) + +diff --git a/xbmc/XBDateTime.cpp b/xbmc/XBDateTime.cpp +index 85d5d466d3..47c6b8d1a6 100644 +--- a/xbmc/XBDateTime.cpp ++++ b/xbmc/XBDateTime.cpp +@@ -17,29 +17,17 @@ + + #include <cstdlib> + +-#define SECONDS_PER_DAY 86400L +-#define SECONDS_PER_HOUR 3600L +-#define SECONDS_PER_MINUTE 60L +-#define SECONDS_TO_FILETIME 10000000L ++#define USE_OS_TZDB 0 ++#define HAS_REMOTE_API 0 ++#include <date/date.h> ++#include <date/iso_week.h> ++#include <date/tz.h> + +-static const char *DAY_NAMES[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; + static const char *MONTH_NAMES[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; + +-///////////////////////////////////////////////// +-// +-// CDateTimeSpan +-// +- +-CDateTimeSpan::CDateTimeSpan() +-{ +- m_timeSpan.highDateTime = 0; +- m_timeSpan.lowDateTime = 0; +-} +- + CDateTimeSpan::CDateTimeSpan(const CDateTimeSpan& span) + { +- m_timeSpan.highDateTime = span.m_timeSpan.highDateTime; +- m_timeSpan.lowDateTime = span.m_timeSpan.lowDateTime; ++ m_timeSpan = span.m_timeSpan; + } + + CDateTimeSpan::CDateTimeSpan(int day, int hour, int minute, int second) +@@ -49,7 +37,7 @@ CDateTimeSpan::CDateTimeSpan(int day, int hour, int minute, int second) + + bool CDateTimeSpan::operator >(const CDateTimeSpan& right) const + { +- return KODI::TIME::CompareFileTime(&m_timeSpan, &right.m_timeSpan) > 0; ++ return m_timeSpan > right.m_timeSpan; + } + + bool CDateTimeSpan::operator >=(const CDateTimeSpan& right) const +@@ -59,7 +47,7 @@ bool CDateTimeSpan::operator >=(const CDateTimeSpan& right) const + + bool CDateTimeSpan::operator <(const CDateTimeSpan& right) const + { +- return KODI::TIME::CompareFileTime(&m_timeSpan, &right.m_timeSpan) < 0; ++ return m_timeSpan < right.m_timeSpan; + } + + bool CDateTimeSpan::operator <=(const CDateTimeSpan& right) const +@@ -69,7 +57,7 @@ bool CDateTimeSpan::operator <=(const CDateTimeSpan& right) const + + bool CDateTimeSpan::operator ==(const CDateTimeSpan& right) const + { +- return KODI::TIME::CompareFileTime(&m_timeSpan, &right.m_timeSpan) == 0; ++ return m_timeSpan == right.m_timeSpan; + } + + bool CDateTimeSpan::operator !=(const CDateTimeSpan& right) const +@@ -81,15 +69,7 @@ CDateTimeSpan CDateTimeSpan::operator +(const CDateTimeSpan& right) const + { + CDateTimeSpan left(*this); + +- LARGE_INTEGER timeLeft; +- left.ToLargeInt(timeLeft); +- +- LARGE_INTEGER timeRight; +- right.ToLargeInt(timeRight); +- +- timeLeft.QuadPart+=timeRight.QuadPart; +- +- left.FromLargeInt(timeLeft); ++ left.m_timeSpan += right.m_timeSpan; + + return left; + } +@@ -98,122 +78,75 @@ CDateTimeSpan CDateTimeSpan::operator -(const CDateTimeSpan& right) const + { + CDateTimeSpan left(*this); + +- LARGE_INTEGER timeLeft; +- left.ToLargeInt(timeLeft); +- +- LARGE_INTEGER timeRight; +- right.ToLargeInt(timeRight); +- +- timeLeft.QuadPart-=timeRight.QuadPart; +- +- left.FromLargeInt(timeLeft); ++ left.m_timeSpan -= right.m_timeSpan; + + return left; + } + + const CDateTimeSpan& CDateTimeSpan::operator +=(const CDateTimeSpan& right) + { +- LARGE_INTEGER timeThis; +- ToLargeInt(timeThis); +- +- LARGE_INTEGER timeRight; +- right.ToLargeInt(timeRight); +- +- timeThis.QuadPart+=timeRight.QuadPart; +- +- FromLargeInt(timeThis); ++ m_timeSpan += right.m_timeSpan; + + return *this; + } + + const CDateTimeSpan& CDateTimeSpan::operator -=(const CDateTimeSpan& right) + { +- LARGE_INTEGER timeThis; +- ToLargeInt(timeThis); +- +- LARGE_INTEGER timeRight; +- right.ToLargeInt(timeRight); +- +- timeThis.QuadPart-=timeRight.QuadPart; +- +- FromLargeInt(timeThis); ++ m_timeSpan -= right.m_timeSpan; + + return *this; + } + +-void CDateTimeSpan::ToLargeInt(LARGE_INTEGER& time) const +-{ +- time.u.HighPart = m_timeSpan.highDateTime; +- time.u.LowPart = m_timeSpan.lowDateTime; +-} +- +-void CDateTimeSpan::FromLargeInt(const LARGE_INTEGER& time) +-{ +- m_timeSpan.highDateTime = time.u.HighPart; +- m_timeSpan.lowDateTime = time.u.LowPart; +-} +- + void CDateTimeSpan::SetDateTimeSpan(int day, int hour, int minute, int second) + { +- LARGE_INTEGER time; +- ToLargeInt(time); +- +- time.QuadPart= static_cast<long long>(day) *SECONDS_PER_DAY*SECONDS_TO_FILETIME; +- time.QuadPart+= static_cast<long long>(hour) *SECONDS_PER_HOUR*SECONDS_TO_FILETIME; +- time.QuadPart+= static_cast<long long>(minute) *SECONDS_PER_MINUTE*SECONDS_TO_FILETIME; +- time.QuadPart+= static_cast<long long>(second) *SECONDS_TO_FILETIME; +- +- FromLargeInt(time); ++ m_timeSpan = std::chrono::duration_cast<std::chrono::seconds>(date::days(day)) + ++ std::chrono::duration_cast<std::chrono::seconds>(std::chrono::hours(hour)) + ++ std::chrono::duration_cast<std::chrono::seconds>(std::chrono::minutes(minute)) + ++ std::chrono::duration_cast<std::chrono::seconds>(std::chrono::seconds(second)); + } + + void CDateTimeSpan::SetFromTimeString(const std::string& time) // hh:mm + { + if (time.size() >= 5 && time[2] == ':') + { +- int hour = atoi(time.substr(0, 2).c_str()); +- int minutes = atoi(time.substr(3, 2).c_str()); +- SetDateTimeSpan(0,hour,minutes,0); ++ int hour = std::stoi(time.substr(0, 2)); ++ int minutes = std::stoi(time.substr(3, 2)); ++ SetDateTimeSpan(0, hour, minutes, 0); + } + } + + int CDateTimeSpan::GetDays() const + { +- LARGE_INTEGER time; +- ToLargeInt(time); +- +- return (int)(time.QuadPart/SECONDS_TO_FILETIME)/SECONDS_PER_DAY; ++ return date::floor<date::days>(m_timeSpan).count(); + } + + int CDateTimeSpan::GetHours() const + { +- LARGE_INTEGER time; +- ToLargeInt(time); ++ auto time = date::floor<date::days>(m_timeSpan); ++ auto dp = date::make_time(m_timeSpan - time); + +- return (int)((time.QuadPart/SECONDS_TO_FILETIME)%SECONDS_PER_DAY)/SECONDS_PER_HOUR; ++ return dp.hours().count(); + } + + int CDateTimeSpan::GetMinutes() const + { +- LARGE_INTEGER time; +- ToLargeInt(time); ++ auto time = date::floor<date::days>(m_timeSpan); ++ auto dp = date::make_time(m_timeSpan - time); + +- return (int)((time.QuadPart/SECONDS_TO_FILETIME%SECONDS_PER_DAY)%SECONDS_PER_HOUR)/SECONDS_PER_MINUTE; ++ return dp.minutes().count(); + } + + int CDateTimeSpan::GetSeconds() const + { +- LARGE_INTEGER time; +- ToLargeInt(time); ++ auto time = date::floor<date::days>(m_timeSpan); ++ auto dp = date::make_time(m_timeSpan - time); + +- return (int)(((time.QuadPart/SECONDS_TO_FILETIME%SECONDS_PER_DAY)%SECONDS_PER_HOUR)%SECONDS_PER_MINUTE)%SECONDS_PER_MINUTE; ++ return dp.seconds().count(); + } + + int CDateTimeSpan::GetSecondsTotal() const + { +- LARGE_INTEGER time; +- ToLargeInt(time); +- +- return (int)(time.QuadPart/SECONDS_TO_FILETIME); ++ return std::chrono::duration_cast<std::chrono::seconds>(m_timeSpan).count(); + } + + void CDateTimeSpan::SetFromPeriod(const std::string &period) +@@ -233,25 +166,26 @@ void CDateTimeSpan::SetFromPeriod(const std::string &period) + SetDateTimeSpan(days, 0, 0, 0); + } + +-///////////////////////////////////////////////// +-// +-// CDateTime +-// +- + CDateTime::CDateTime() + { + Reset(); + } + +-CDateTime::CDateTime(const KODI::TIME::SystemTime& time) ++CDateTime::CDateTime(const KODI::TIME::SystemTime& systemTime) + { +- // we store internally as a FileTime +- m_state = ToFileTime(time, m_time) ? valid : invalid; ++ KODI::TIME::FileTime fileTime; ++ m_state = ToFileTime(systemTime, fileTime) ? valid : invalid; ++ ++ time_t time; ++ KODI::TIME::FileTimeToTimeT(&fileTime, &time); ++ m_time = std::chrono::system_clock::from_time_t(time); + } + +-CDateTime::CDateTime(const KODI::TIME::FileTime& time) : m_time(time) ++CDateTime::CDateTime(const KODI::TIME::FileTime& fileTime) + { +- SetValid(true); ++ time_t time; ++ KODI::TIME::FileTimeToTimeT(&fileTime, &time); ++ m_time = std::chrono::system_clock::from_time_t(time); + } + + CDateTime::CDateTime(const CDateTime& time) : m_time(time.m_time) +@@ -261,12 +195,20 @@ CDateTime::CDateTime(const CDateTime& time) : m_time(time.m_time) + + CDateTime::CDateTime(const time_t& time) + { +- m_state = ToFileTime(time, m_time) ? valid : invalid; ++ m_time = std::chrono::system_clock::from_time_t(time); ++ SetValid(true); ++} ++ ++CDateTime::CDateTime(const std::chrono::system_clock::time_point& time) ++{ ++ m_time = time; ++ SetValid(true); + } + + CDateTime::CDateTime(const tm& time) + { +- m_state = ToFileTime(time, m_time) ? valid : invalid; ++ m_time = std::chrono::system_clock::from_time_t(std::mktime(const_cast<tm*>(&time))); ++ SetValid(true); + } + + CDateTime::CDateTime(int year, int month, int day, int hour, int minute, int second) +@@ -276,52 +218,66 @@ CDateTime::CDateTime(int year, int month, int day, int hour, int minute, int sec + + CDateTime CDateTime::GetCurrentDateTime() + { +- // get the current time +- KODI::TIME::SystemTime time; +- KODI::TIME::GetLocalTime(&time); ++ auto zone = date::make_zoned(date::current_zone(), std::chrono::system_clock::now()); + +- return CDateTime(time); ++ return CDateTime( ++ std::chrono::duration_cast<std::chrono::seconds>(zone.get_local_time().time_since_epoch()) ++ .count()); + } + + CDateTime CDateTime::GetUTCDateTime() + { +- CDateTime time(GetCurrentDateTime()); +- time += GetTimezoneBias(); +- return time; ++ return CDateTime(std::chrono::system_clock::now()); + } + + const CDateTime& CDateTime::operator=(const KODI::TIME::SystemTime& right) + { +- m_state = ToFileTime(right, m_time) ? valid : invalid; ++ KODI::TIME::FileTime fileTime; ++ m_state = ToFileTime(right, fileTime) ? valid : invalid; ++ ++ time_t time; ++ KODI::TIME::FileTimeToTimeT(&fileTime, &time); ++ m_time = std::chrono::system_clock::from_time_t(time); + + return *this; + } + + const CDateTime& CDateTime::operator=(const KODI::TIME::FileTime& right) + { +- m_time=right; +- SetValid(true); ++ time_t time; ++ KODI::TIME::FileTimeToTimeT(&right, &time); ++ m_time = std::chrono::system_clock::from_time_t(time); + + return *this; + } + + const CDateTime& CDateTime::operator =(const time_t& right) + { +- m_state = ToFileTime(right, m_time) ? valid : invalid; ++ m_time = std::chrono::system_clock::from_time_t(right); ++ SetValid(true); + + return *this; + } + + const CDateTime& CDateTime::operator =(const tm& right) + { +- m_state = ToFileTime(right, m_time) ? valid : invalid; ++ m_time = std::chrono::system_clock::from_time_t(std::mktime(const_cast<tm*>(&right))); ++ SetValid(true); ++ ++ return *this; ++} ++ ++const CDateTime& CDateTime::operator=(const std::chrono::system_clock::time_point& right) ++{ ++ m_time = right; ++ SetValid(true); + + return *this; + } + + bool CDateTime::operator >(const CDateTime& right) const + { +- return operator >(right.m_time); ++ return m_time > right.m_time; + } + + bool CDateTime::operator >=(const CDateTime& right) const +@@ -331,7 +287,7 @@ bool CDateTime::operator >=(const CDateTime& right) const + + bool CDateTime::operator <(const CDateTime& right) const + { +- return operator <(right.m_time); ++ return m_time < right.m_time; + } + + bool CDateTime::operator <=(const CDateTime& right) const +@@ -341,7 +297,7 @@ bool CDateTime::operator <=(const CDateTime& right) const + + bool CDateTime::operator ==(const CDateTime& right) const + { +- return operator ==(right.m_time); ++ return m_time == right.m_time; + } + + bool CDateTime::operator !=(const CDateTime& right) const +@@ -351,7 +307,10 @@ bool CDateTime::operator !=(const CDateTime& right) const + + bool CDateTime::operator>(const KODI::TIME::FileTime& right) const + { +- return KODI::TIME::CompareFileTime(&m_time, &right) > 0; ++ time_t time; ++ KODI::TIME::FileTimeToTimeT(&right, &time); ++ ++ return m_time > std::chrono::system_clock::from_time_t(time); + } + + bool CDateTime::operator>=(const KODI::TIME::FileTime& right) const +@@ -361,7 +320,10 @@ bool CDateTime::operator>=(const KODI::TIME::FileTime& right) const + + bool CDateTime::operator<(const KODI::TIME::FileTime& right) const + { +- return KODI::TIME::CompareFileTime(&m_time, &right) < 0; ++ time_t time; ++ KODI::TIME::FileTimeToTimeT(&right, &time); ++ ++ return m_time < std::chrono::system_clock::from_time_t(time); + } + + bool CDateTime::operator<=(const KODI::TIME::FileTime& right) const +@@ -371,7 +333,10 @@ bool CDateTime::operator<=(const KODI::TIME::FileTime& right) const + + bool CDateTime::operator==(const KODI::TIME::FileTime& right) const + { +- return KODI::TIME::CompareFileTime(&m_time, &right) == 0; ++ time_t time; ++ KODI::TIME::FileTimeToTimeT(&right, &time); ++ ++ return m_time == std::chrono::system_clock::from_time_t(time); + } + + bool CDateTime::operator!=(const KODI::TIME::FileTime& right) const +@@ -420,10 +385,7 @@ bool CDateTime::operator!=(const KODI::TIME::SystemTime& right) const + + bool CDateTime::operator >(const time_t& right) const + { +- KODI::TIME::FileTime time; +- ToFileTime(right, time); +- +- return operator >(time); ++ return m_time > std::chrono::system_clock::from_time_t(right); + } + + bool CDateTime::operator >=(const time_t& right) const +@@ -433,10 +395,7 @@ bool CDateTime::operator >=(const time_t& right) const + + bool CDateTime::operator <(const time_t& right) const + { +- KODI::TIME::FileTime time; +- ToFileTime(right, time); +- +- return operator <(time); ++ return m_time < std::chrono::system_clock::from_time_t(right); + } + + bool CDateTime::operator <=(const time_t& right) const +@@ -446,10 +405,7 @@ bool CDateTime::operator <=(const time_t& right) const + + bool CDateTime::operator ==(const time_t& right) const + { +- KODI::TIME::FileTime time; +- ToFileTime(right, time); +- +- return operator ==(time); ++ return m_time == std::chrono::system_clock::from_time_t(right); + } + + bool CDateTime::operator !=(const time_t& right) const +@@ -459,10 +415,7 @@ bool CDateTime::operator !=(const time_t& right) const + + bool CDateTime::operator >(const tm& right) const + { +- KODI::TIME::FileTime time; +- ToFileTime(right, time); +- +- return operator >(time); ++ return m_time > std::chrono::system_clock::from_time_t(std::mktime(const_cast<tm*>(&right))); + } + + bool CDateTime::operator >=(const tm& right) const +@@ -472,10 +425,7 @@ bool CDateTime::operator >=(const tm& right) const + + bool CDateTime::operator <(const tm& right) const + { +- KODI::TIME::FileTime time; +- ToFileTime(right, time); +- +- return operator <(time); ++ return m_time < std::chrono::system_clock::from_time_t(std::mktime(const_cast<tm*>(&right))); + } + + bool CDateTime::operator <=(const tm& right) const +@@ -485,10 +435,7 @@ bool CDateTime::operator <=(const tm& right) const + + bool CDateTime::operator ==(const tm& right) const + { +- KODI::TIME::FileTime time; +- ToFileTime(right, time); +- +- return operator ==(time); ++ return m_time == std::chrono::system_clock::from_time_t(std::mktime(const_cast<tm*>(&right))); + } + + bool CDateTime::operator !=(const tm& right) const +@@ -496,66 +443,64 @@ bool CDateTime::operator !=(const tm& right) const + return !operator ==(right); + } + +-CDateTime CDateTime::operator +(const CDateTimeSpan& right) const ++bool CDateTime::operator>(const std::chrono::system_clock::time_point& right) const + { +- CDateTime left(*this); ++ return m_time > right; ++} + +- LARGE_INTEGER timeLeft; +- left.ToLargeInt(timeLeft); ++bool CDateTime::operator>=(const std::chrono::system_clock::time_point& right) const ++{ ++ return operator>(right) || operator==(right); ++} + +- LARGE_INTEGER timeRight; +- right.ToLargeInt(timeRight); ++bool CDateTime::operator<(const std::chrono::system_clock::time_point& right) const ++{ ++ return m_time < right; ++} + +- timeLeft.QuadPart+=timeRight.QuadPart; ++bool CDateTime::operator<=(const std::chrono::system_clock::time_point& right) const ++{ ++ return operator<(right) || operator==(right); ++} + +- left.FromLargeInt(timeLeft); ++bool CDateTime::operator==(const std::chrono::system_clock::time_point& right) const ++{ ++ return m_time == right; ++} + +- return left; ++bool CDateTime::operator!=(const std::chrono::system_clock::time_point& right) const ++{ ++ return !operator==(right); + } + +-CDateTime CDateTime::operator -(const CDateTimeSpan& right) const ++CDateTime CDateTime::operator+(const CDateTimeSpan& right) const + { + CDateTime left(*this); + +- LARGE_INTEGER timeLeft; +- left.ToLargeInt(timeLeft); ++ left.m_time + right.m_timeSpan; + +- LARGE_INTEGER timeRight; +- right.ToLargeInt(timeRight); ++ return left; ++} + +- timeLeft.QuadPart-=timeRight.QuadPart; ++CDateTime CDateTime::operator-(const CDateTimeSpan& right) const ++{ ++ CDateTime left(*this); + +- left.FromLargeInt(timeLeft); ++ left.m_time - right.m_timeSpan; + + return left; + } + + const CDateTime& CDateTime::operator +=(const CDateTimeSpan& right) + { +- LARGE_INTEGER timeThis; +- ToLargeInt(timeThis); +- +- LARGE_INTEGER timeRight; +- right.ToLargeInt(timeRight); +- +- timeThis.QuadPart+=timeRight.QuadPart; +- +- FromLargeInt(timeThis); ++ m_time += right.m_timeSpan; + + return *this; + } + + const CDateTime& CDateTime::operator -=(const CDateTimeSpan& right) + { +- LARGE_INTEGER timeThis; +- ToLargeInt(timeThis); +- +- LARGE_INTEGER timeRight; +- right.ToLargeInt(timeRight); +- +- timeThis.QuadPart-=timeRight.QuadPart; +- +- FromLargeInt(timeThis); ++ m_time -= right.m_timeSpan; + + return *this; + } +@@ -564,25 +509,16 @@ CDateTimeSpan CDateTime::operator -(const CDateTime& right) const + { + CDateTimeSpan left; + +- LARGE_INTEGER timeLeft; +- left.ToLargeInt(timeLeft); +- +- LARGE_INTEGER timeThis; +- ToLargeInt(timeThis); +- +- LARGE_INTEGER timeRight; +- right.ToLargeInt(timeRight); +- +- timeLeft.QuadPart=timeThis.QuadPart-timeRight.QuadPart; +- +- left.FromLargeInt(timeLeft); +- ++ left.m_timeSpan = std::chrono::duration_cast<std::chrono::seconds>(m_time - right.m_time); + return left; + } + + CDateTime::operator KODI::TIME::FileTime() const + { +- return m_time; ++ KODI::TIME::FileTime fileTime; ++ time_t time = std::chrono::system_clock::to_time_t(m_time); ++ KODI::TIME::TimeTToFileTime(time, &fileTime); ++ return fileTime; + } + + void CDateTime::Archive(CArchive& ar) +@@ -607,25 +543,38 @@ void CDateTime::Archive(CArchive& ar) + { + KODI::TIME::SystemTime st; + ar>>st; +- ToFileTime(st, m_time); ++ ToTimePoint(st, m_time); + } + } + } + + void CDateTime::Reset() + { +- SetDateTime(1601, 1, 1, 0, 0, 0); ++ m_time = {}; + SetValid(false); + } + + void CDateTime::SetValid(bool yesNo) + { +- m_state=yesNo ? valid : invalid; ++ m_state = yesNo ? valid : invalid; + } + + bool CDateTime::IsValid() const + { +- return m_state==valid; ++ return m_state == valid; ++} ++ ++bool CDateTime::ToTimePoint(const KODI::TIME::SystemTime& systemTime, ++ std::chrono::system_clock::time_point& timePoint) const ++{ ++ KODI::TIME::FileTime fileTime; ++ KODI::TIME::SystemTimeToFileTime(&systemTime, &fileTime); ++ ++ time_t time; ++ KODI::TIME::FileTimeToTimeT(&fileTime, &time); ++ ++ timePoint = std::chrono::system_clock::from_time_t(time); ++ return true; + } + + bool CDateTime::ToFileTime(const KODI::TIME::SystemTime& time, KODI::TIME::FileTime& fileTime) const +@@ -646,33 +595,6 @@ bool CDateTime::ToFileTime(const time_t& time, KODI::TIME::FileTime& fileTime) c + return true; + } + +-bool CDateTime::ToFileTime(const tm& time, KODI::TIME::FileTime& fileTime) const +-{ +- KODI::TIME::SystemTime st = {}; +- +- st.year = time.tm_year + 1900; +- st.month = time.tm_mon + 1; +- st.dayOfWeek = time.tm_wday; +- st.day = time.tm_mday; +- st.hour = time.tm_hour; +- st.minute = time.tm_min; +- st.second = time.tm_sec; +- +- return SystemTimeToFileTime(&st, &fileTime) == 1; +-} +- +-void CDateTime::ToLargeInt(LARGE_INTEGER& time) const +-{ +- time.u.HighPart = m_time.highDateTime; +- time.u.LowPart = m_time.lowDateTime; +-} +- +-void CDateTime::FromLargeInt(const LARGE_INTEGER& time) +-{ +- m_time.highDateTime = time.u.HighPart; +- m_time.lowDateTime = time.u.LowPart; +-} +- + bool CDateTime::SetFromDateString(const std::string &date) + { + //! @todo STRING_CLEANUP +@@ -714,80 +636,83 @@ bool CDateTime::SetFromDateString(const std::string &date) + + int CDateTime::GetDay() const + { +- KODI::TIME::SystemTime st; +- GetAsSystemTime(st); ++ auto dp = date::floor<date::days>(m_time); ++ auto ymd = date::year_month_day{dp}; + +- return st.day; ++ return static_cast<unsigned int>(ymd.day()); + } + + int CDateTime::GetMonth() const + { +- KODI::TIME::SystemTime st; +- GetAsSystemTime(st); ++ auto dp = date::floor<date::days>(m_time); ++ auto ymd = date::year_month_day{dp}; + +- return st.month; ++ return static_cast<unsigned int>(ymd.month()); + } + + int CDateTime::GetYear() const + { +- KODI::TIME::SystemTime st; +- GetAsSystemTime(st); ++ auto dp = date::floor<date::days>(m_time); ++ auto ymd = date::year_month_day{dp}; + +- return st.year; ++ return static_cast<int>(ymd.year()); + } + + int CDateTime::GetHour() const + { +- KODI::TIME::SystemTime st; +- GetAsSystemTime(st); ++ auto dp = date::floor<date::days>(m_time); ++ auto time = date::make_time(m_time - dp); + +- return st.hour; ++ return time.hours().count(); + } + + int CDateTime::GetMinute() const + { +- KODI::TIME::SystemTime st; +- GetAsSystemTime(st); ++ auto dp = date::floor<date::days>(m_time); ++ auto time = date::make_time(m_time - dp); + +- return st.minute; ++ return time.minutes().count(); + } + + int CDateTime::GetSecond() const + { +- KODI::TIME::SystemTime st; +- GetAsSystemTime(st); ++ auto dp = date::floor<date::days>(m_time); ++ auto time = date::make_time(m_time - dp); + +- return st.second; ++ return time.seconds().count(); + } + + int CDateTime::GetDayOfWeek() const + { +- KODI::TIME::SystemTime st; +- GetAsSystemTime(st); ++ auto dp = date::floor<date::days>(m_time); ++ auto yww = iso_week::year_weeknum_weekday{dp}; + +- return st.dayOfWeek; ++ return static_cast<unsigned int>(yww.weekday()); + } + + int CDateTime::GetMinuteOfDay() const + { +- KODI::TIME::SystemTime st; +- GetAsSystemTime(st); +- return st.hour * 60 + st.minute; ++ auto dp = date::floor<std::chrono::hours>(m_time); ++ ; ++ auto time = date::make_time(m_time - dp); ++ ++ return time.hours().count() * 60 + time.minutes().count(); + } + + bool CDateTime::SetDateTime(int year, int month, int day, int hour, int minute, int second) + { +- KODI::TIME::SystemTime st = {}; ++ auto ymd = date::year(year) / month / day; ++ if (!ymd.ok()) ++ { ++ SetValid(false); ++ return false; ++ } + +- st.year = year; +- st.month = month; +- st.day = day; +- st.hour = hour; +- st.minute = minute; +- st.second = second; ++ m_time = date::sys_days(ymd) + std::chrono::hours(hour) + std::chrono::minutes(minute) + ++ std::chrono::seconds(second); + +- m_state = ToFileTime(st, m_time) ? valid : invalid; +- return m_state == valid; ++ SetValid(true); ++ return true; + } + + bool CDateTime::SetDate(int year, int month, int day) +@@ -797,119 +722,75 @@ bool CDateTime::SetDate(int year, int month, int day) + + bool CDateTime::SetTime(int hour, int minute, int second) + { +- // 01.01.1601 00:00:00 is 0 as filetime +- return SetDateTime(1601, 1, 1, hour, minute, second); ++ m_time = date::sys_seconds(std::chrono::seconds(0)) + std::chrono::hours(hour) + ++ std::chrono::minutes(minute) + std::chrono::seconds(second); ++ ++ SetValid(true); ++ return true; + } + +-void CDateTime::GetAsSystemTime(KODI::TIME::SystemTime& time) const ++void CDateTime::GetAsSystemTime(KODI::TIME::SystemTime& systemTime) const + { +- FileTimeToSystemTime(&m_time, &time); ++ const time_t time = std::chrono::system_clock::to_time_t(m_time); ++ KODI::TIME::FileTime fileTime; ++ ToFileTime(time, fileTime); ++ KODI::TIME::FileTimeToSystemTime(&fileTime, &systemTime); + } + +-#define UNIX_BASE_TIME 116444736000000000LL /* nanoseconds since epoch */ + void CDateTime::GetAsTime(time_t& time) const + { +- long long ll = (static_cast<long long>(m_time.highDateTime) << 32) + m_time.lowDateTime; +- time=(time_t)((ll - UNIX_BASE_TIME) / 10000000); ++ time = std::chrono::system_clock::to_time_t(m_time); + } + + void CDateTime::GetAsTm(tm& time) const + { +- KODI::TIME::SystemTime st; +- GetAsSystemTime(st); ++ auto t = std::chrono::system_clock::to_time_t(m_time); + + time = {}; +- time.tm_year = st.year - 1900; +- time.tm_mon = st.month - 1; +- time.tm_wday = st.dayOfWeek; +- time.tm_mday = st.day; +- time.tm_hour = st.hour; +- time.tm_min = st.minute; +- time.tm_sec = st.second; +- time.tm_isdst = -1; +- +- mktime(&time); ++ localtime_r(&t, &time); + } + +-void CDateTime::GetAsTimeStamp(KODI::TIME::FileTime& time) const ++std::chrono::system_clock::time_point CDateTime::GetAsTimePoint() const + { +- KODI::TIME::LocalFileTimeToFileTime(&m_time, &time); ++ return m_time; + } + ++// void CDateTime::GetAsTimeStamp(KODI::TIME::FileTime& fileTime) const ++// { ++// time_t time = std::chrono::system_clock::to_time_t(m_time); ++// KODI::TIME::TimeTToFileTime(time, &fileTime); ++// } ++ + std::string CDateTime::GetAsDBDate() const + { +- KODI::TIME::SystemTime st; +- GetAsSystemTime(st); +- +- return StringUtils::Format("{:04}-{:02}-{:02}", st.year, st.month, st.day); ++ return date::format("%F", m_time); + } + + std::string CDateTime::GetAsDBTime() const + { +- KODI::TIME::SystemTime st; +- GetAsSystemTime(st); +- +- return StringUtils::Format("{:02}:{:02}:{:02}", st.hour, st.minute, st.second); ++ auto sp = date::floor<std::chrono::seconds>(m_time); ++ return date::format("%T", sp); + } + + std::string CDateTime::GetAsDBDateTime() const + { +- KODI::TIME::SystemTime st; +- GetAsSystemTime(st); ++ auto sp = date::floor<std::chrono::seconds>(m_time); + +- return StringUtils::Format("{:04}-{:02}-{:02} {:02}:{:02}:{:02}", st.year, st.month, st.day, +- st.hour, st.minute, st.second); ++ return date::format("%F %T", sp); + } + + std::string CDateTime::GetAsSaveString() const + { +- KODI::TIME::SystemTime st; +- GetAsSystemTime(st); ++ auto sp = date::floor<std::chrono::seconds>(m_time); + +- return StringUtils::Format("{:04}{:02}{:02}_{:02}{:02}{:02}", st.year, st.month, st.day, st.hour, +- st.minute, st.second); ++ return date::format("%Y%m%d_%H%M%S", sp); + } + + bool CDateTime::SetFromUTCDateTime(const CDateTime &dateTime) + { +- CDateTime tmp(dateTime); +- tmp -= GetTimezoneBias(); +- +- m_time = tmp.m_time; +- m_state = tmp.m_state; +- return m_state == valid; +-} +- +-static bool bGotTimezoneBias = false; +- +-void CDateTime::ResetTimezoneBias(void) +-{ +- bGotTimezoneBias = false; +-} +- +-CDateTimeSpan CDateTime::GetTimezoneBias(void) +-{ +- static CDateTimeSpan timezoneBias; +- +- if (!bGotTimezoneBias) +- { +- bGotTimezoneBias = true; +- KODI::TIME::TimeZoneInformation tz; +- switch (KODI::TIME::GetTimeZoneInformation(&tz)) +- { +- case KODI::TIME::KODI_TIME_ZONE_ID_DAYLIGHT: +- timezoneBias = CDateTimeSpan(0, 0, tz.bias + tz.daylightBias, 0); +- break; +- case KODI::TIME::KODI_TIME_ZONE_ID_STANDARD: +- timezoneBias = CDateTimeSpan(0, 0, tz.bias + tz.standardBias, 0); +- break; +- case KODI::TIME::KODI_TIME_ZONE_ID_UNKNOWN: +- timezoneBias = CDateTimeSpan(0, 0, tz.bias, 0); +- break; +- } +- } +- +- return timezoneBias; ++ m_time = dateTime.m_time; ++ m_state = valid; ++ return true; + } + + bool CDateTime::SetFromUTCDateTime(const time_t &dateTime) +@@ -1511,60 +1392,31 @@ std::string CDateTime::GetAsLocalizedTime(TIME_FORMAT format, bool withSeconds / + CDateTime CDateTime::GetAsUTCDateTime() const + { + CDateTime time(m_time); +- time += GetTimezoneBias(); + return time; + } + + std::string CDateTime::GetAsRFC1123DateTime() const + { +- CDateTime time(GetAsUTCDateTime()); ++ auto time = date::floor<std::chrono::seconds>(m_time); + +- int weekDay = time.GetDayOfWeek(); +- if (weekDay < 0) +- weekDay = 0; +- else if (weekDay > 6) +- weekDay = 6; +- if (weekDay != time.GetDayOfWeek()) +- CLog::Log(LOGWARNING, "Invalid day of week {} in {}", time.GetDayOfWeek(), +- time.GetAsDBDateTime()); +- +- int month = time.GetMonth(); +- if (month < 1) +- month = 1; +- else if (month > 12) +- month = 12; +- if (month != time.GetMonth()) +- CLog::Log(LOGWARNING, "Invalid month {} in {}", time.GetMonth(), time.GetAsDBDateTime()); +- +- return StringUtils::Format("{}, {:02} {} {:04} {:02}:{:02}:{:02} GMT", DAY_NAMES[weekDay], +- time.GetDay(), MONTH_NAMES[month - 1], time.GetYear(), time.GetHour(), +- time.GetMinute(), time.GetSecond()); ++ return date::format("%a, %d %b %Y %T GMT", time); + } + + std::string CDateTime::GetAsW3CDate() const + { +- KODI::TIME::SystemTime st; +- GetAsSystemTime(st); +- +- return StringUtils::Format("{:04}-{:02}-{:02}", st.year, st.month, st.day); ++ return GetAsDBDate(); + } + + std::string CDateTime::GetAsW3CDateTime(bool asUtc /* = false */) const + { +- CDateTime w3cDate = *this; +- if (asUtc) +- w3cDate = GetAsUTCDateTime(); +- KODI::TIME::SystemTime st; +- w3cDate.GetAsSystemTime(st); ++ auto time = date::floor<std::chrono::seconds>(m_time); + +- std::string result = StringUtils::Format("{:04}-{:02}-{:02}T{:02}:{:02}:{:02}", st.year, st.month, +- st.day, st.hour, st.minute, st.second); + if (asUtc) +- return result + "Z"; ++ return date::format("%FT%TZ", time); ++ ++ auto zt = date::make_zoned(date::current_zone(), time); + +- CDateTimeSpan bias = GetTimezoneBias(); +- return result + StringUtils::Format("{}{:02}:{:02}", (bias.GetSecondsTotal() >= 0 ? '+' : '-'), +- abs(bias.GetHours()), abs(bias.GetMinutes())); ++ return date::format("%FT%T%Ez", zt); + } + + int CDateTime::MonthStringToMonthNum(const std::string& month) +diff --git a/xbmc/XBDateTime.h b/xbmc/XBDateTime.h +index fb18e7c0de..60d06e417a 100644 +--- a/xbmc/XBDateTime.h ++++ b/xbmc/XBDateTime.h +@@ -12,6 +12,7 @@ + #include "utils/TimeFormat.h" + #include "utils/XTimeUtils.h" + ++#include <chrono> + #include <string> + + #include "PlatformDefs.h" +@@ -21,7 +22,7 @@ class CDateTime; + class CDateTimeSpan + { + public: +- CDateTimeSpan(); ++ CDateTimeSpan() = default; + CDateTimeSpan(const CDateTimeSpan& span); + CDateTimeSpan& operator=(const CDateTimeSpan&) = default; + CDateTimeSpan(int day, int hour, int minute, int second); +@@ -50,11 +51,7 @@ public: + int GetSecondsTotal() const; + + private: +- void ToLargeInt(LARGE_INTEGER& time) const; +- void FromLargeInt(const LARGE_INTEGER& time); +- +-private: +- KODI::TIME::FileTime m_timeSpan; ++ std::chrono::duration<int64_t> m_timeSpan{0}; + + friend class CDateTime; + }; +@@ -70,6 +67,7 @@ public: + explicit CDateTime(const KODI::TIME::FileTime& time); + explicit CDateTime(const time_t& time); + explicit CDateTime(const tm& time); ++ explicit CDateTime(const std::chrono::system_clock::time_point& time); + CDateTime(int year, int month, int day, int hour, int minute, int second); + + static CDateTime GetCurrentDateTime(); +@@ -90,6 +88,7 @@ public: + const CDateTime& operator=(const KODI::TIME::FileTime& right); + const CDateTime& operator =(const time_t& right); + const CDateTime& operator =(const tm& right); ++ const CDateTime& operator=(const std::chrono::system_clock::time_point& right); + + bool operator >(const CDateTime& right) const; + bool operator >=(const CDateTime& right) const; +@@ -126,6 +125,13 @@ public: + bool operator ==(const tm& right) const; + bool operator !=(const tm& right) const; + ++ bool operator>(const std::chrono::system_clock::time_point& right) const; ++ bool operator>=(const std::chrono::system_clock::time_point& right) const; ++ bool operator<(const std::chrono::system_clock::time_point& right) const; ++ bool operator<=(const std::chrono::system_clock::time_point& right) const; ++ bool operator==(const std::chrono::system_clock::time_point& right) const; ++ bool operator!=(const std::chrono::system_clock::time_point& right) const; ++ + CDateTime operator +(const CDateTimeSpan& right) const; + CDateTime operator -(const CDateTimeSpan& right) const; + +@@ -170,7 +176,7 @@ public: + void GetAsSystemTime(KODI::TIME::SystemTime& time) const; + void GetAsTime(time_t& time) const; + void GetAsTm(tm& time) const; +- void GetAsTimeStamp(KODI::TIME::FileTime& time) const; ++ std::chrono::system_clock::time_point GetAsTimePoint() const; + + CDateTime GetAsUTCDateTime() const; + std::string GetAsSaveString() const; +@@ -189,19 +195,14 @@ public: + void SetValid(bool yesNo); + bool IsValid() const; + +- static void ResetTimezoneBias(void); +- static CDateTimeSpan GetTimezoneBias(void); +- + private: ++ bool ToTimePoint(const KODI::TIME::SystemTime& time, ++ std::chrono::system_clock::time_point& timePoint) const; + bool ToFileTime(const KODI::TIME::SystemTime& time, KODI::TIME::FileTime& fileTime) const; + bool ToFileTime(const time_t& time, KODI::TIME::FileTime& fileTime) const; +- bool ToFileTime(const tm& time, KODI::TIME::FileTime& fileTime) const; +- +- void ToLargeInt(LARGE_INTEGER& time) const; +- void FromLargeInt(const LARGE_INTEGER& time); + + private: +- KODI::TIME::FileTime m_time; ++ std::chrono::system_clock::time_point m_time; + + typedef enum _STATE + { +diff --git a/xbmc/platform/posix/PosixTimezone.cpp b/xbmc/platform/posix/PosixTimezone.cpp +index 6f276a37b2..ab2ddcf570 100644 +--- a/xbmc/platform/posix/PosixTimezone.cpp ++++ b/xbmc/platform/posix/PosixTimezone.cpp +@@ -143,8 +143,6 @@ void CPosixTimezone::OnSettingChanged(const std::shared_ptr<const CSetting>& set + if (settingId == CSettings::SETTING_LOCALE_TIMEZONE) + { + SetTimezone(std::static_pointer_cast<const CSettingString>(setting)->GetValue()); +- +- CDateTime::ResetTimezoneBias(); + } + else if (settingId == CSettings::SETTING_LOCALE_TIMEZONECOUNTRY) + { +@@ -157,7 +155,6 @@ void CPosixTimezone::OnSettingChanged(const std::shared_ptr<const CSetting>& set + void CPosixTimezone::OnSettingsLoaded() + { + SetTimezone(CServiceBroker::GetSettingsComponent()->GetSettings()->GetString(CSettings::SETTING_LOCALE_TIMEZONE)); +- CDateTime::ResetTimezoneBias(); + } + + std::vector<std::string> CPosixTimezone::GetCounties() +diff --git a/xbmc/pvr/guilib/PVRGUIActionsDatabase.cpp b/xbmc/pvr/guilib/PVRGUIActionsDatabase.cpp +index 53bbf815f6..4ae42a4803 100644 +--- a/xbmc/pvr/guilib/PVRGUIActionsDatabase.cpp ++++ b/xbmc/pvr/guilib/PVRGUIActionsDatabase.cpp +@@ -205,8 +205,6 @@ bool CPVRGUIActionsDatabase::ResetDatabase(bool bResetEPGOnly) + bResetClients = selector.IsResetClientsSelected(); + } + +- CDateTime::ResetTimezoneBias(); +- + CLog::LogFC(LOGDEBUG, LOGPVR, "PVR clearing {} database", bResetEPGOnly ? "EPG" : "PVR and EPG"); + + pDlgProgress->SetHeading(CVariant{313}); // "Cleaning database" +-- +2.43.0 + + +From 8433756427c68642013698c678263b4d6ee5759d Mon Sep 17 00:00:00 2001 +From: Lukas Rusak <lorusak@gmail.com> +Date: Mon, 17 Feb 2020 22:40:56 -0800 +Subject: [PATCH 04/19] fix TestDateTime to work with std::chrono + +--- + xbmc/test/TestDateTime.cpp | 89 ++++++++------------------------------ + 1 file changed, 17 insertions(+), 72 deletions(-) + +diff --git a/xbmc/test/TestDateTime.cpp b/xbmc/test/TestDateTime.cpp +index 7e51df8cee..a553bd1887 100644 +--- a/xbmc/test/TestDateTime.cpp ++++ b/xbmc/test/TestDateTime.cpp +@@ -13,6 +13,10 @@ + #include <array> + #include <iostream> + ++#define USE_OS_TZDB 0 ++#define HAS_REMOTE_API 0 ++#include <date/date.h> ++#include <date/tz.h> + #include <gtest/gtest.h> + + class TestDateTime : public testing::Test +@@ -32,24 +36,6 @@ TEST_F(TestDateTime, DateTimeOperators) + EXPECT_FALSE(dateTime1 == dateTime2); + } + +-TEST_F(TestDateTime, FileTimeOperators) +-{ +- CDateTime dateTime1(1991, 5, 14, 12, 34, 56); +- CDateTime dateTime2(1991, 5, 14, 12, 34, 57); +- +- KODI::TIME::FileTime fileTime1; +- KODI::TIME::FileTime fileTime2; +- +- dateTime1.GetAsTimeStamp(fileTime1); +- dateTime2.GetAsTimeStamp(fileTime2); +- +- CDateTime dateTime3(fileTime1); +- +- EXPECT_TRUE(dateTime3 < fileTime2); +- EXPECT_FALSE(dateTime3 > fileTime2); +- EXPECT_FALSE(dateTime3 == fileTime2); +-} +- + TEST_F(TestDateTime, SystemTimeOperators) + { + CDateTime dateTime1(1991, 5, 14, 12, 34, 56); +@@ -161,7 +147,7 @@ TEST_F(TestDateTime, MonthStringToMonthNum) + } + + // this method is broken as SetFromDBDate() will return true +-TEST_F(TestDateTime, DISABLED_SetFromDateString) ++TEST_F(TestDateTime, SetFromDateString) + { + CDateTime dateTime; + EXPECT_TRUE(dateTime.SetFromDateString("tuesday may 14, 1991")); +@@ -190,13 +176,7 @@ TEST_F(TestDateTime, SetFromDBDate) + EXPECT_EQ(dateTime.GetDay(), 2); + } + +-// disabled on osx and freebsd as their mktime functions +-// don't work for dates before 1900 +-#if defined(TARGET_DARWIN_OSX) || defined(TARGET_FREEBSD) +-TEST_F(TestDateTime, DISABLED_SetFromDBTime) +-#else + TEST_F(TestDateTime, SetFromDBTime) +-#endif + { + CDateTime dateTime1; + EXPECT_TRUE(dateTime1.SetFromDBTime("12:34")); +@@ -237,10 +217,8 @@ TEST_F(TestDateTime, SetFromW3CDate) + + TEST_F(TestDateTime, SetFromW3CDateTime) + { +- CDateTimeSpan bias = CDateTime::GetTimezoneBias(); + CDateTime dateTime; + dateTime.SetFromDBDateTime("1994-11-05 13:15:30"); +- dateTime += bias; + std::string dateTimeStr = dateTime.GetAsDBDate() + "T" + dateTime.GetAsDBTime() + "Z"; + + CDateTime dateTime1; +@@ -264,11 +242,8 @@ TEST_F(TestDateTime, SetFromW3CDateTime) + + TEST_F(TestDateTime, SetFromUTCDateTime) + { +- CDateTimeSpan bias = CDateTime::GetTimezoneBias(); +- + CDateTime dateTime1; + dateTime1.SetFromDBDateTime("1991-05-14 12:34:56"); +- dateTime1 += bias; + + CDateTime dateTime2; + EXPECT_TRUE(dateTime2.SetFromUTCDateTime(dateTime1)); +@@ -279,7 +254,7 @@ TEST_F(TestDateTime, SetFromUTCDateTime) + EXPECT_EQ(dateTime2.GetMinute(), 34); + EXPECT_EQ(dateTime2.GetSecond(), 56); + +- const time_t time = 674224496 + bias.GetSecondsTotal(); ++ const time_t time = 674224496; + + CDateTime dateTime3; + EXPECT_TRUE(dateTime3.SetFromUTCDateTime(time)); +@@ -325,18 +300,14 @@ TEST_F(TestDateTime, SetDateTime) + EXPECT_EQ(dateTime2.GetMinute(), 0); + EXPECT_EQ(dateTime2.GetSecond(), 0); + +-// disabled on osx and freebsd as their mktime functions +-// don't work for dates before 1900 +-#if !defined(TARGET_DARWIN_OSX) && !defined(TARGET_FREEBSD) + CDateTime dateTime3; + EXPECT_TRUE(dateTime3.SetTime(12, 34, 56)); +- EXPECT_EQ(dateTime3.GetYear(), 1601); ++ EXPECT_EQ(dateTime3.GetYear(), 1970); + EXPECT_EQ(dateTime3.GetMonth(), 1); + EXPECT_EQ(dateTime3.GetDay(), 1); + EXPECT_EQ(dateTime3.GetHour(), 12); + EXPECT_EQ(dateTime3.GetMinute(), 34); + EXPECT_EQ(dateTime3.GetSecond(), 56); +-#endif + } + + TEST_F(TestDateTime, GetAsStrings) +@@ -351,22 +322,20 @@ TEST_F(TestDateTime, GetAsStrings) + EXPECT_EQ(dateTime.GetAsW3CDate(), "1991-05-14"); + } + +-// disabled because we have no way to validate these values +-// GetTimezoneBias() always returns a positive value so +-// there is no way to detect the direction of the offset +-TEST_F(TestDateTime, DISABLED_GetAsStringsWithBias) ++TEST_F(TestDateTime, GetAsStringsWithBias) + { +- CDateTimeSpan bias = CDateTime::GetTimezoneBias(); +- + CDateTime dateTime; + dateTime.SetDateTime(1991, 05, 14, 12, 34, 56); + +- CDateTime dateTimeWithBias(dateTime); +- dateTimeWithBias += bias; ++ std::cout << dateTime.GetAsRFC1123DateTime() << std::endl; ++ std::cout << dateTime.GetAsW3CDateTime(false) << std::endl; ++ std::cout << dateTime.GetAsW3CDateTime(true) << std::endl; + +- EXPECT_EQ(dateTime.GetAsRFC1123DateTime(), "Tue, 14 May 1991 20:34:56 GMT"); +- EXPECT_EQ(dateTime.GetAsW3CDateTime(false), "1991-05-14T12:34:56+08:00"); +- EXPECT_EQ(dateTime.GetAsW3CDateTime(true), "1991-05-14T20:34:56Z"); ++ auto zone = date::make_zoned(date::current_zone(), dateTime.GetAsTimePoint()); ++ ++ EXPECT_EQ(dateTime.GetAsRFC1123DateTime(), "Tue, 14 May 1991 12:34:56 GMT"); ++ EXPECT_EQ(dateTime.GetAsW3CDateTime(false), "1991-05-14T05:34:56" + date::format("%Ez", zone)); ++ EXPECT_EQ(dateTime.GetAsW3CDateTime(true), "1991-05-14T12:34:56Z"); + } + + TEST_F(TestDateTime, GetAsLocalized) +@@ -604,31 +573,13 @@ TEST_F(TestDateTime, GetAsTm) + } + } + +-// Disabled pending std::chrono and std::date changes. +-TEST_F(TestDateTime, DISABLED_GetAsTimeStamp) +-{ +- CDateTimeSpan bias = CDateTime::GetTimezoneBias(); +- +- CDateTime dateTime; +- dateTime.SetDateTime(1991, 05, 14, 12, 34, 56); +- +- KODI::TIME::FileTime fileTime; +- dateTime.GetAsTimeStamp(fileTime); +- dateTime += bias; +- +- EXPECT_TRUE(dateTime == fileTime); +-} +- + TEST_F(TestDateTime, GetAsUTCDateTime) + { +- CDateTimeSpan bias = CDateTime::GetTimezoneBias(); +- + CDateTime dateTime1; + dateTime1.SetDateTime(1991, 05, 14, 12, 34, 56); + + CDateTime dateTime2; + dateTime2 = dateTime1.GetAsUTCDateTime(); +- dateTime2 -= bias; + + EXPECT_EQ(dateTime2.GetYear(), 1991); + EXPECT_EQ(dateTime2.GetMonth(), 5); +@@ -638,20 +589,14 @@ TEST_F(TestDateTime, GetAsUTCDateTime) + EXPECT_EQ(dateTime2.GetSecond(), 56); + } + +-// disabled on osx and freebsd as their mktime functions +-// don't work for dates before 1900 +-#if defined(TARGET_DARWIN_OSX) || defined(TARGET_FREEBSD) +-TEST_F(TestDateTime, DISABLED_Reset) +-#else + TEST_F(TestDateTime, Reset) +-#endif + { + CDateTime dateTime; + dateTime.SetDateTime(1991, 05, 14, 12, 34, 56); + + dateTime.Reset(); + +- EXPECT_EQ(dateTime.GetYear(), 1601); ++ EXPECT_EQ(dateTime.GetYear(), 1970); + EXPECT_EQ(dateTime.GetMonth(), 1); + EXPECT_EQ(dateTime.GetDay(), 1); + EXPECT_EQ(dateTime.GetHour(), 0); +-- +2.43.0 + + +From ca3e502a5c37975173e376653a167053928b5311 Mon Sep 17 00:00:00 2001 +From: Lukas Rusak <lorusak@gmail.com> +Date: Thu, 10 Sep 2020 08:19:35 -0700 +Subject: [PATCH 05/19] cleanup CPosixTimezone + +--- + xbmc/application/Application.cpp | 6 +- + xbmc/platform/posix/PosixTimezone.cpp | 418 ++++++++++++++++---------- + xbmc/platform/posix/PosixTimezone.h | 16 +- + 3 files changed, 266 insertions(+), 174 deletions(-) + +diff --git a/xbmc/application/Application.cpp b/xbmc/application/Application.cpp +index ea1b152dfd..3227933296 100644 +--- a/xbmc/application/Application.cpp ++++ b/xbmc/application/Application.cpp +@@ -172,8 +172,9 @@ + #include "utils/URIUtils.h" + + #ifdef TARGET_POSIX +-#include "platform/posix/XHandle.h" + #include "platform/posix/PlatformPosix.h" ++#include "platform/posix/PosixTimezone.h" ++#include "platform/posix/XHandle.h" + #endif + + #if defined(TARGET_ANDROID) +@@ -358,6 +359,9 @@ bool CApplication::Create() + // Register JobManager service + CServiceBroker::RegisterJobManager(std::make_shared<CJobManager>()); + ++ // Initialize,timezone ++ g_timezone.Init(); ++ + // Announcement service + m_pAnnouncementManager = std::make_shared<ANNOUNCEMENT::CAnnouncementManager>(); + m_pAnnouncementManager->Start(); +diff --git a/xbmc/platform/posix/PosixTimezone.cpp b/xbmc/platform/posix/PosixTimezone.cpp +index ab2ddcf570..7f0b8d4096 100644 +--- a/xbmc/platform/posix/PosixTimezone.cpp ++++ b/xbmc/platform/posix/PosixTimezone.cpp +@@ -6,7 +6,6 @@ + * See LICENSES/README.md for more information. + */ + +-#include <time.h> + #ifdef TARGET_ANDROID + #include "platform/android/bionic_supplement/bionic_supplement.h" + #endif +@@ -23,120 +22,215 @@ + #include "settings/SettingsComponent.h" + #include <stdlib.h> + +-#include <algorithm> ++#define USE_OS_TZDB 0 ++#define HAS_REMOTE_API 0 ++#include "filesystem/File.h" ++#include "platform/MessagePrinter.h" + +-CPosixTimezone::CPosixTimezone() ++#include <date/tz.h> ++ ++void CPosixTimezone::Init() + { +- char* line = NULL; +- size_t linelen = 0; +- int nameonfourthfield = 0; +- std::string s; +- std::vector<std::string> tokens; +- +- // Load timezones +- FILE* fp = fopen("/usr/share/zoneinfo/zone.tab", "r"); +- if (fp) +- { +- std::string countryCode; +- std::string timezoneName; +- +- while (getdelim(&line, &linelen, '\n', fp) > 0) ++#if defined(DATE_INTERNAL_TZDATA) ++ XFILE::CFileStream zonetab; ++ ++ if (!zonetab.Open("special://xbmc/addons/resource.timezone/resources/tzdata/zone.tab")) ++ { ++ CMessagePrinter::DisplayMessage("failed to open zone.tab"); ++ return; ++ } ++ ++ std::string countryCode; ++ std::string timezoneName; ++ ++ std::vector<std::string> tokens; ++ ++ for (std::string s; std::getline(zonetab, s);) ++ { ++ tokens.clear(); ++ std::string line = s; ++ StringUtils::Trim(line); ++ ++ if (line.length() == 0) ++ continue; ++ ++ if (line[0] == '#') ++ continue; ++ ++ StringUtils::Tokenize(line, tokens, " \t"); ++ if (tokens.size() < 3) ++ continue; ++ ++ countryCode = tokens[0]; ++ timezoneName = tokens[2]; ++ ++ if (m_timezonesByCountryCode.count(countryCode) == 0) ++ { ++ std::vector<std::string> timezones; ++ timezones.push_back(timezoneName); ++ m_timezonesByCountryCode[countryCode] = timezones; ++ } ++ else ++ { ++ std::vector<std::string>& timezones = m_timezonesByCountryCode[countryCode]; ++ timezones.push_back(timezoneName); ++ } ++ ++ m_countriesByTimezoneName[timezoneName] = countryCode; ++ } ++ ++ XFILE::CFileStream isotab; ++ ++ if (!isotab.Open("special://xbmc/addons/resource.timezone/resources/tzdata/iso3166.tab")) ++ { ++ CMessagePrinter::DisplayMessage("failed to open iso3166.tab"); ++ return; ++ } ++ ++ std::string countryName; ++ ++ for (std::string s; std::getline(isotab, s);) ++ { ++ tokens.clear(); ++ std::string line = s; ++ StringUtils::Trim(line); ++ ++ if (line.length() == 0) ++ continue; ++ ++ if (line[0] == '#') ++ continue; ++ ++ StringUtils::Tokenize(line, tokens, "\t"); ++ if (tokens.size() < 2) ++ continue; ++ ++ countryCode = tokens[0]; ++ countryName = tokens[1]; ++ ++ m_countries.push_back(countryName); ++ m_countryByCode[countryCode] = countryName; ++ m_countryByName[countryName] = countryCode; ++ } ++ ++ sort(m_countries.begin(), m_countries.end(), sortstringbyname()); ++#else ++ char* line = NULL; ++ size_t linelen = 0; ++ int nameonfourthfield = 0; ++ std::string s; ++ std::vector<std::string> tokens; ++ ++ // Load timezones ++ FILE* fp = fopen("/usr/share/zoneinfo/zone.tab", "r"); ++ if (fp) ++ { ++ std::string countryCode; ++ std::string timezoneName; ++ ++ while (getdelim(&line, &linelen, '\n', fp) > 0) ++ { ++ tokens.clear(); ++ s = line; ++ StringUtils::Trim(s); ++ ++ if (s.length() == 0) ++ continue; ++ ++ if (s[0] == '#') ++ continue; ++ ++ StringUtils::Tokenize(s, tokens, " \t"); ++ if (tokens.size() < 3) ++ continue; ++ ++ countryCode = tokens[0]; ++ timezoneName = tokens[2]; ++ ++ if (m_timezonesByCountryCode.count(countryCode) == 0) ++ { ++ std::vector<std::string> timezones; ++ timezones.push_back(timezoneName); ++ m_timezonesByCountryCode[countryCode] = timezones; ++ } ++ else + { +- tokens.clear(); +- s = line; +- StringUtils::Trim(s); +- +- if (s.length() == 0) +- continue; +- +- if (s[0] == '#') +- continue; +- +- StringUtils::Tokenize(s, tokens, " \t"); +- if (tokens.size() < 3) +- continue; +- +- countryCode = tokens[0]; +- timezoneName = tokens[2]; +- +- if (m_timezonesByCountryCode.count(countryCode) == 0) +- { +- std::vector<std::string> timezones; +- timezones.push_back(timezoneName); +- m_timezonesByCountryCode[countryCode] = timezones; +- } +- else +- { +- std::vector<std::string>& timezones = m_timezonesByCountryCode[countryCode]; +- timezones.push_back(timezoneName); +- } +- +- m_countriesByTimezoneName[timezoneName] = countryCode; ++ std::vector<std::string>& timezones = m_timezonesByCountryCode[countryCode]; ++ timezones.push_back(timezoneName); + } +- fclose(fp); +- } +- +- if (line) +- { +- free(line); +- line = NULL; +- linelen = 0; +- } +- +- // Load countries +- fp = fopen("/usr/share/zoneinfo/iso3166.tab", "r"); +- if (!fp) +- { +- fp = fopen("/usr/share/misc/iso3166", "r"); +- nameonfourthfield = 1; +- } +- if (fp) +- { +- std::string countryCode; +- std::string countryName; +- +- while (getdelim(&line, &linelen, '\n', fp) > 0) ++ ++ m_countriesByTimezoneName[timezoneName] = countryCode; ++ } ++ fclose(fp); ++ } ++ ++ if (line) ++ { ++ free(line); ++ line = NULL; ++ linelen = 0; ++ } ++ ++ // Load countries ++ fp = fopen("/usr/share/zoneinfo/iso3166.tab", "r"); ++ if (!fp) ++ { ++ fp = fopen("/usr/share/misc/iso3166", "r"); ++ nameonfourthfield = 1; ++ } ++ if (fp) ++ { ++ std::string countryCode; ++ std::string countryName; ++ ++ while (getdelim(&line, &linelen, '\n', fp) > 0) ++ { ++ s = line; ++ StringUtils::Trim(s); ++ ++ //! @todo STRING_CLEANUP ++ if (s.length() == 0) ++ continue; ++ ++ if (s[0] == '#') ++ continue; ++ ++ // Search for the first non space from the 2nd character and on ++ int i = 2; ++ while (s[i] == ' ' || s[i] == '\t') ++ i++; ++ ++ if (nameonfourthfield) + { +- s = line; +- StringUtils::Trim(s); +- +- //! @todo STRING_CLEANUP +- if (s.length() == 0) +- continue; +- +- if (s[0] == '#') +- continue; +- +- // Search for the first non space from the 2nd character and on +- int i = 2; +- while (s[i] == ' ' || s[i] == '\t') i++; +- +- if (nameonfourthfield) +- { +- // skip three letter +- while (s[i] != ' ' && s[i] != '\t') i++; +- while (s[i] == ' ' || s[i] == '\t') i++; +- // skip number +- while (s[i] != ' ' && s[i] != '\t') i++; +- while (s[i] == ' ' || s[i] == '\t') i++; +- } +- +- countryCode = s.substr(0, 2); +- countryName = s.substr(i); +- +- m_counties.push_back(countryName); +- m_countryByCode[countryCode] = countryName; +- m_countryByName[countryName] = countryCode; ++ // skip three letter ++ while (s[i] != ' ' && s[i] != '\t') ++ i++; ++ while (s[i] == ' ' || s[i] == '\t') ++ i++; ++ // skip number ++ while (s[i] != ' ' && s[i] != '\t') ++ i++; ++ while (s[i] == ' ' || s[i] == '\t') ++ i++; + } +- sort(m_counties.begin(), m_counties.end(), sortstringbyname()); +- fclose(fp); +- } +- free(line); ++ ++ countryCode = s.substr(0, 2); ++ countryName = s.substr(i); ++ ++ m_countries.push_back(countryName); ++ m_countryByCode[countryCode] = countryName; ++ m_countryByName[countryName] = countryCode; ++ } ++ sort(m_countries.begin(), m_countries.end(), sortstringbyname()); ++ fclose(fp); ++ } ++ free(line); ++#endif + } + + void CPosixTimezone::OnSettingChanged(const std::shared_ptr<const CSetting>& setting) + { +- if (setting == NULL) ++ if (setting == nullptr) + return; + + const std::string &settingId = setting->GetId(); +@@ -157,82 +251,74 @@ void CPosixTimezone::OnSettingsLoaded() + SetTimezone(CServiceBroker::GetSettingsComponent()->GetSettings()->GetString(CSettings::SETTING_LOCALE_TIMEZONE)); + } + +-std::vector<std::string> CPosixTimezone::GetCounties() ++std::vector<std::string> CPosixTimezone::GetCountries() + { +- return m_counties; ++ return m_countries; + } + + std::vector<std::string> CPosixTimezone::GetTimezonesByCountry(const std::string& country) + { +- return m_timezonesByCountryCode[m_countryByName[country]]; ++ return m_timezonesByCountryCode[m_countryByName[country]]; + } + + std::string CPosixTimezone::GetCountryByTimezone(const std::string& timezone) + { + #if defined(TARGET_DARWIN) +- return "?"; +-#else +- return m_countryByCode[m_countriesByTimezoneName[timezone]]; ++ return "?"; + #endif ++ ++ return m_countryByCode[m_countriesByTimezoneName[timezone]]; + } + + void CPosixTimezone::SetTimezone(const std::string& timezoneName) + { +-#if !defined(TARGET_DARWIN) +- bool use_timezone = true; +-#else +- bool use_timezone = false; ++#if defined(TARGET_DARWIN) ++ return; + #endif + +- if (use_timezone) +- { +- static char env_var[255]; +- sprintf(env_var, "TZ=:%s", timezoneName.c_str()); +- putenv(env_var); +- tzset(); +- } ++ setenv("TZ", timezoneName.c_str(), 1); ++ tzset(); + } + + std::string CPosixTimezone::GetOSConfiguredTimezone() + { +- char timezoneName[255]; +- +- // try Slackware approach first +- ssize_t rlrc = readlink("/etc/localtime-copied-from" +- , timezoneName, sizeof(timezoneName)-1); +- +- // RHEL and maybe other distros make /etc/localtime a symlink +- if (rlrc == -1) +- rlrc = readlink("/etc/localtime", timezoneName, sizeof(timezoneName)-1); +- +- if (rlrc != -1) +- { +- timezoneName[rlrc] = '\0'; +- +- char* p = strrchr(timezoneName,'/'); +- if (p) +- { // we want the previous '/' +- char* q = p; +- *q = 0; +- p = strrchr(timezoneName,'/'); +- *q = '/'; +- if (p) +- p++; +- } +- return p; +- } +- +- // now try Debian approach +- timezoneName[0] = 0; +- FILE* fp = fopen("/etc/timezone", "r"); +- if (fp) +- { +- if (fgets(timezoneName, sizeof(timezoneName), fp)) +- timezoneName[strlen(timezoneName)-1] = '\0'; +- fclose(fp); +- } +- +- return timezoneName; ++ char timezoneName[255]; ++ ++ // try Slackware approach first ++ ssize_t rlrc = readlink("/etc/localtime-copied-from", timezoneName, sizeof(timezoneName) - 1); ++ ++ // RHEL and maybe other distros make /etc/localtime a symlink ++ if (rlrc == -1) ++ rlrc = readlink("/etc/localtime", timezoneName, sizeof(timezoneName) - 1); ++ ++ if (rlrc != -1) ++ { ++ timezoneName[rlrc] = '\0'; ++ ++ char* p = strrchr(timezoneName, '/'); ++ if (p) ++ { // we want the previous '/' ++ char* q = p; ++ *q = 0; ++ p = strrchr(timezoneName, '/'); ++ *q = '/'; ++ if (p) ++ p++; ++ } ++ return p; ++ } ++ ++ // now try Debian approach ++ timezoneName[0] = 0; ++ FILE* fp = fopen("/etc/timezone", "r"); ++ if (fp) ++ { ++ if (fgets(timezoneName, sizeof(timezoneName), fp)) ++ timezoneName[strlen(timezoneName) - 1] = '\0'; ++ fclose(fp); ++ } ++ ++ return timezoneName; + } + + void CPosixTimezone::SettingOptionsTimezoneCountriesFiller( +@@ -241,9 +327,9 @@ void CPosixTimezone::SettingOptionsTimezoneCountriesFiller( + std::string& current, + void* data) + { +- std::vector<std::string> countries = g_timezone.GetCounties(); +- for (unsigned int i = 0; i < countries.size(); i++) +- list.emplace_back(countries[i], countries[i]); ++ std::vector<std::string> countries = g_timezone.GetCountries(); ++ for (const auto& country : countries) ++ list.emplace_back(country, country); + } + + void CPosixTimezone::SettingOptionsTimezonesFiller(const std::shared_ptr<const CSetting>& setting, +@@ -254,12 +340,12 @@ void CPosixTimezone::SettingOptionsTimezonesFiller(const std::shared_ptr<const C + current = std::static_pointer_cast<const CSettingString>(setting)->GetValue(); + bool found = false; + std::vector<std::string> timezones = g_timezone.GetTimezonesByCountry(CServiceBroker::GetSettingsComponent()->GetSettings()->GetString(CSettings::SETTING_LOCALE_TIMEZONECOUNTRY)); +- for (unsigned int i = 0; i < timezones.size(); i++) ++ for (const auto& timezone : timezones) + { +- if (!found && StringUtils::EqualsNoCase(timezones[i], current)) ++ if (!found && StringUtils::EqualsNoCase(timezone, current)) + found = true; + +- list.emplace_back(timezones[i], timezones[i]); ++ list.emplace_back(timezone, timezone); + } + + if (!found && !timezones.empty()) +diff --git a/xbmc/platform/posix/PosixTimezone.h b/xbmc/platform/posix/PosixTimezone.h +index 076e87fa51..238c6daf85 100644 +--- a/xbmc/platform/posix/PosixTimezone.h ++++ b/xbmc/platform/posix/PosixTimezone.h +@@ -21,7 +21,9 @@ struct StringSettingOption; + class CPosixTimezone : public ISettingCallback, public ISettingsHandler + { + public: +- CPosixTimezone(); ++ CPosixTimezone() = default; ++ ++ void Init(); + + void OnSettingChanged(const std::shared_ptr<const CSetting>& setting) override; + +@@ -29,7 +31,7 @@ public: + + std::string GetOSConfiguredTimezone(); + +- std::vector<std::string> GetCounties(); ++ std::vector<std::string> GetCountries(); + std::vector<std::string> GetTimezonesByCountry(const std::string& country); + std::string GetCountryByTimezone(const std::string& timezone); + +@@ -46,12 +48,12 @@ public: + void* data); + + private: +- std::vector<std::string> m_counties; +- std::map<std::string, std::string> m_countryByCode; +- std::map<std::string, std::string> m_countryByName; ++ std::vector<std::string> m_countries; ++ std::map<std::string, std::string> m_countryByCode; ++ std::map<std::string, std::string> m_countryByName; + +- std::map<std::string, std::vector<std::string> > m_timezonesByCountryCode; +- std::map<std::string, std::string> m_countriesByTimezoneName; ++ std::map<std::string, std::vector<std::string>> m_timezonesByCountryCode; ++ std::map<std::string, std::string> m_countriesByTimezoneName; + }; + + extern CPosixTimezone g_timezone; +-- +2.43.0 + + +From a36c95155a2b8d22f69ad0809d895c11838620ed Mon Sep 17 00:00:00 2001 +From: Lukas Rusak <lorusak@gmail.com> +Date: Thu, 10 Sep 2020 08:41:57 -0700 +Subject: [PATCH 06/19] utils/XTimeUtils: clean up SystemTime and FileTime + functions + +--- + xbmc/XBDateTime.cpp | 213 ++---------------- + xbmc/XBDateTime.h | 27 --- + .../addons/interfaces/gui/dialogs/Numeric.cpp | 10 +- + xbmc/dialogs/GUIDialogNumeric.cpp | 203 ++++++++++------- + xbmc/dialogs/GUIDialogNumeric.h | 12 +- + xbmc/filesystem/NFSDirectory.cpp | 18 +- + xbmc/guilib/GUIEditControl.cpp | 13 +- + xbmc/guilib/GUIRSSControl.h | 2 +- + xbmc/interfaces/legacy/Dialog.cpp | 44 ++-- + xbmc/music/infoscanner/MusicInfoScanner.cpp | 4 +- + xbmc/network/upnp/UPnPInternal.cpp | 18 +- + xbmc/platform/posix/XTimeUtils.cpp | 211 ----------------- + .../posix/filesystem/PosixDirectory.cpp | 5 +- + .../posix/filesystem/SMBDirectory.cpp | 16 +- + .../pvr/dialogs/GUIDialogPVRTimerSettings.cpp | 18 +- + xbmc/pvr/dialogs/GUIDialogPVRTimerSettings.h | 1 - + xbmc/pvr/windows/GUIWindowPVRGuide.cpp | 7 +- + xbmc/settings/windows/GUIControlSettings.cpp | 14 +- + xbmc/test/TestDateTime.cpp | 18 +- + xbmc/utils/Archive.cpp | 8 +- + xbmc/utils/Archive.h | 4 +- + xbmc/utils/RssManager.cpp | 2 +- + xbmc/utils/RssManager.h | 2 +- + xbmc/utils/RssReader.cpp | 25 +- + xbmc/utils/RssReader.h | 10 +- + xbmc/utils/XTimeUtils.h | 44 ---- + xbmc/utils/test/TestArchive.cpp | 22 +- + xbmc/video/VideoInfoScanner.cpp | 4 +- + 28 files changed, 253 insertions(+), 722 deletions(-) + +diff --git a/xbmc/XBDateTime.cpp b/xbmc/XBDateTime.cpp +index 47c6b8d1a6..d8187b71e6 100644 +--- a/xbmc/XBDateTime.cpp ++++ b/xbmc/XBDateTime.cpp +@@ -171,23 +171,6 @@ CDateTime::CDateTime() + Reset(); + } + +-CDateTime::CDateTime(const KODI::TIME::SystemTime& systemTime) +-{ +- KODI::TIME::FileTime fileTime; +- m_state = ToFileTime(systemTime, fileTime) ? valid : invalid; +- +- time_t time; +- KODI::TIME::FileTimeToTimeT(&fileTime, &time); +- m_time = std::chrono::system_clock::from_time_t(time); +-} +- +-CDateTime::CDateTime(const KODI::TIME::FileTime& fileTime) +-{ +- time_t time; +- KODI::TIME::FileTimeToTimeT(&fileTime, &time); +- m_time = std::chrono::system_clock::from_time_t(time); +-} +- + CDateTime::CDateTime(const CDateTime& time) : m_time(time.m_time) + { + m_state=time.m_state; +@@ -230,27 +213,6 @@ CDateTime CDateTime::GetUTCDateTime() + return CDateTime(std::chrono::system_clock::now()); + } + +-const CDateTime& CDateTime::operator=(const KODI::TIME::SystemTime& right) +-{ +- KODI::TIME::FileTime fileTime; +- m_state = ToFileTime(right, fileTime) ? valid : invalid; +- +- time_t time; +- KODI::TIME::FileTimeToTimeT(&fileTime, &time); +- m_time = std::chrono::system_clock::from_time_t(time); +- +- return *this; +-} +- +-const CDateTime& CDateTime::operator=(const KODI::TIME::FileTime& right) +-{ +- time_t time; +- KODI::TIME::FileTimeToTimeT(&right, &time); +- m_time = std::chrono::system_clock::from_time_t(time); +- +- return *this; +-} +- + const CDateTime& CDateTime::operator =(const time_t& right) + { + m_time = std::chrono::system_clock::from_time_t(right); +@@ -305,84 +267,6 @@ bool CDateTime::operator !=(const CDateTime& right) const + return !operator ==(right); + } + +-bool CDateTime::operator>(const KODI::TIME::FileTime& right) const +-{ +- time_t time; +- KODI::TIME::FileTimeToTimeT(&right, &time); +- +- return m_time > std::chrono::system_clock::from_time_t(time); +-} +- +-bool CDateTime::operator>=(const KODI::TIME::FileTime& right) const +-{ +- return operator >(right) || operator ==(right); +-} +- +-bool CDateTime::operator<(const KODI::TIME::FileTime& right) const +-{ +- time_t time; +- KODI::TIME::FileTimeToTimeT(&right, &time); +- +- return m_time < std::chrono::system_clock::from_time_t(time); +-} +- +-bool CDateTime::operator<=(const KODI::TIME::FileTime& right) const +-{ +- return operator <(right) || operator ==(right); +-} +- +-bool CDateTime::operator==(const KODI::TIME::FileTime& right) const +-{ +- time_t time; +- KODI::TIME::FileTimeToTimeT(&right, &time); +- +- return m_time == std::chrono::system_clock::from_time_t(time); +-} +- +-bool CDateTime::operator!=(const KODI::TIME::FileTime& right) const +-{ +- return !operator ==(right); +-} +- +-bool CDateTime::operator>(const KODI::TIME::SystemTime& right) const +-{ +- KODI::TIME::FileTime time; +- ToFileTime(right, time); +- +- return operator >(time); +-} +- +-bool CDateTime::operator>=(const KODI::TIME::SystemTime& right) const +-{ +- return operator >(right) || operator ==(right); +-} +- +-bool CDateTime::operator<(const KODI::TIME::SystemTime& right) const +-{ +- KODI::TIME::FileTime time; +- ToFileTime(right, time); +- +- return operator <(time); +-} +- +-bool CDateTime::operator<=(const KODI::TIME::SystemTime& right) const +-{ +- return operator <(right) || operator ==(right); +-} +- +-bool CDateTime::operator==(const KODI::TIME::SystemTime& right) const +-{ +- KODI::TIME::FileTime time; +- ToFileTime(right, time); +- +- return operator ==(time); +-} +- +-bool CDateTime::operator!=(const KODI::TIME::SystemTime& right) const +-{ +- return !operator ==(right); +-} +- + bool CDateTime::operator >(const time_t& right) const + { + return m_time > std::chrono::system_clock::from_time_t(right); +@@ -477,7 +361,7 @@ CDateTime CDateTime::operator+(const CDateTimeSpan& right) const + { + CDateTime left(*this); + +- left.m_time + right.m_timeSpan; ++ left.m_time += right.m_timeSpan; + + return left; + } +@@ -486,7 +370,7 @@ CDateTime CDateTime::operator-(const CDateTimeSpan& right) const + { + CDateTime left(*this); + +- left.m_time - right.m_timeSpan; ++ left.m_time -= right.m_timeSpan; + + return left; + } +@@ -513,14 +397,6 @@ CDateTimeSpan CDateTime::operator -(const CDateTime& right) const + return left; + } + +-CDateTime::operator KODI::TIME::FileTime() const +-{ +- KODI::TIME::FileTime fileTime; +- time_t time = std::chrono::system_clock::to_time_t(m_time); +- KODI::TIME::TimeTToFileTime(time, &fileTime); +- return fileTime; +-} +- + void CDateTime::Archive(CArchive& ar) + { + if (ar.IsStoring()) +@@ -528,9 +404,7 @@ void CDateTime::Archive(CArchive& ar) + ar<<(int)m_state; + if (m_state==valid) + { +- KODI::TIME::SystemTime st; +- GetAsSystemTime(st); +- ar<<st; ++ ar << GetAsTimePoint(); + } + } + else +@@ -541,9 +415,7 @@ void CDateTime::Archive(CArchive& ar) + m_state = CDateTime::STATE(state); + if (m_state==valid) + { +- KODI::TIME::SystemTime st; +- ar>>st; +- ToTimePoint(st, m_time); ++ ar >> m_time; + } + } + } +@@ -564,37 +436,6 @@ bool CDateTime::IsValid() const + return m_state == valid; + } + +-bool CDateTime::ToTimePoint(const KODI::TIME::SystemTime& systemTime, +- std::chrono::system_clock::time_point& timePoint) const +-{ +- KODI::TIME::FileTime fileTime; +- KODI::TIME::SystemTimeToFileTime(&systemTime, &fileTime); +- +- time_t time; +- KODI::TIME::FileTimeToTimeT(&fileTime, &time); +- +- timePoint = std::chrono::system_clock::from_time_t(time); +- return true; +-} +- +-bool CDateTime::ToFileTime(const KODI::TIME::SystemTime& time, KODI::TIME::FileTime& fileTime) const +-{ +- return KODI::TIME::SystemTimeToFileTime(&time, &fileTime) == 1 && +- (fileTime.lowDateTime > 0 || fileTime.highDateTime > 0); +-} +- +-bool CDateTime::ToFileTime(const time_t& time, KODI::TIME::FileTime& fileTime) const +-{ +- long long ll = time; +- ll *= 10000000ll; +- ll += 0x19DB1DED53E8000LL; +- +- fileTime.lowDateTime = (DWORD)(ll & 0xFFFFFFFF); +- fileTime.highDateTime = (DWORD)(ll >> 32); +- +- return true; +-} +- + bool CDateTime::SetFromDateString(const std::string &date) + { + //! @todo STRING_CLEANUP +@@ -729,14 +570,6 @@ bool CDateTime::SetTime(int hour, int minute, int second) + return true; + } + +-void CDateTime::GetAsSystemTime(KODI::TIME::SystemTime& systemTime) const +-{ +- const time_t time = std::chrono::system_clock::to_time_t(m_time); +- KODI::TIME::FileTime fileTime; +- ToFileTime(time, fileTime); +- KODI::TIME::FileTimeToSystemTime(&fileTime, &systemTime); +-} +- + void CDateTime::GetAsTime(time_t& time) const + { + time = std::chrono::system_clock::to_time_t(m_time); +@@ -755,12 +588,6 @@ std::chrono::system_clock::time_point CDateTime::GetAsTimePoint() const + return m_time; + } + +-// void CDateTime::GetAsTimeStamp(KODI::TIME::FileTime& fileTime) const +-// { +-// time_t time = std::chrono::system_clock::to_time_t(m_time); +-// KODI::TIME::TimeTToFileTime(time, &fileTime); +-// } +- + std::string CDateTime::GetAsDBDate() const + { + return date::format("%F", m_time); +@@ -1052,12 +879,9 @@ std::string CDateTime::GetAsLocalizedTime(const std::string &format, bool withSe + std::string strOut; + const std::string& strFormat = format.empty() ? g_langInfo.GetTimeFormat() : format; + +- KODI::TIME::SystemTime dateTime; +- GetAsSystemTime(dateTime); +- + // Prefetch meridiem symbol + const std::string& strMeridiem = +- CLangInfo::MeridiemSymbolToString(dateTime.hour > 11 ? MeridiemSymbolPM : MeridiemSymbolAM); ++ CLangInfo::MeridiemSymbolToString(GetHour() > 11 ? MeridiemSymbolPM : MeridiemSymbolAM); + + size_t length = strFormat.size(); + for (size_t i=0; i < length; ++i) +@@ -1106,7 +930,7 @@ std::string CDateTime::GetAsLocalizedTime(const std::string &format, bool withSe + i=length; + } + +- int hour = dateTime.hour; ++ int hour = GetHour(); + if (c=='h') + { // recalc to 12 hour clock + if (hour > 11) +@@ -1145,9 +969,9 @@ std::string CDateTime::GetAsLocalizedTime(const std::string &format, bool withSe + // Format minute string with the length of the mask + std::string str; + if (partLength==1) +- str = std::to_string(dateTime.minute); ++ str = std::to_string(GetMinute()); + else +- str = StringUtils::Format("{:02}", dateTime.minute); ++ str = StringUtils::Format("{:02}", GetMinute()); + + strOut+=str; + } +@@ -1174,9 +998,9 @@ std::string CDateTime::GetAsLocalizedTime(const std::string &format, bool withSe + // Format seconds string with the length of the mask + std::string str; + if (partLength==1) +- str = std::to_string(dateTime.second); ++ str = std::to_string(GetSecond()); + else +- str = StringUtils::Format("{:02}", dateTime.second); ++ str = StringUtils::Format("{:02}", GetSecond()); + + strOut+=str; + } +@@ -1215,9 +1039,6 @@ std::string CDateTime::GetAsLocalizedDate(const std::string &strFormat) const + { + std::string strOut; + +- KODI::TIME::SystemTime dateTime; +- GetAsSystemTime(dateTime); +- + size_t length = strFormat.size(); + for (size_t i = 0; i < length; ++i) + { +@@ -1267,12 +1088,12 @@ std::string CDateTime::GetAsLocalizedDate(const std::string &strFormat) const + // Format string with the length of the mask + std::string str; + if (partLength==1) // single-digit number +- str = std::to_string(dateTime.day); ++ str = std::to_string(GetDay()); + else if (partLength==2) // two-digit number +- str = StringUtils::Format("{:02}", dateTime.day); ++ str = StringUtils::Format("{:02}", GetDay()); + else // Day of week string + { +- int wday = dateTime.dayOfWeek; ++ int wday = GetDayOfWeek(); + if (wday < 1 || wday > 7) wday = 7; + str = g_localizeStrings.Get((c =='d' ? 40 : 10) + wday); + } +@@ -1299,12 +1120,12 @@ std::string CDateTime::GetAsLocalizedDate(const std::string &strFormat) const + // Format string with the length of the mask + std::string str; + if (partLength==1) // single-digit number +- str = std::to_string(dateTime.month); ++ str = std::to_string(GetMonth()); + else if (partLength==2) // two-digit number +- str = StringUtils::Format("{:02}", dateTime.month); ++ str = StringUtils::Format("{:02}", GetMonth()); + else // Month string + { +- int wmonth = dateTime.month; ++ int wmonth = GetMonth(); + if (wmonth < 1 || wmonth > 12) wmonth = 12; + str = g_localizeStrings.Get((c =='m' ? 50 : 20) + wmonth); + } +@@ -1329,7 +1150,7 @@ std::string CDateTime::GetAsLocalizedDate(const std::string &strFormat) const + } + + // Format string with the length of the mask +- std::string str = std::to_string(dateTime.year); // four-digit number ++ std::string str = std::to_string(GetYear()); // four-digit number + if (partLength <= 2) + str.erase(0, 2); // two-digit number + +diff --git a/xbmc/XBDateTime.h b/xbmc/XBDateTime.h +index 60d06e417a..16d6217c8a 100644 +--- a/xbmc/XBDateTime.h ++++ b/xbmc/XBDateTime.h +@@ -63,8 +63,6 @@ public: + CDateTime(); + CDateTime(const CDateTime& time); + CDateTime& operator=(const CDateTime&) = default; +- explicit CDateTime(const KODI::TIME::SystemTime& time); +- explicit CDateTime(const KODI::TIME::FileTime& time); + explicit CDateTime(const time_t& time); + explicit CDateTime(const tm& time); + explicit CDateTime(const std::chrono::system_clock::time_point& time); +@@ -84,8 +82,6 @@ public: + static CDateTime FromUTCDateTime(const time_t &dateTime); + static CDateTime FromRFC1123DateTime(const std::string &dateTime); + +- const CDateTime& operator=(const KODI::TIME::SystemTime& right); +- const CDateTime& operator=(const KODI::TIME::FileTime& right); + const CDateTime& operator =(const time_t& right); + const CDateTime& operator =(const tm& right); + const CDateTime& operator=(const std::chrono::system_clock::time_point& right); +@@ -97,20 +93,6 @@ public: + bool operator ==(const CDateTime& right) const; + bool operator !=(const CDateTime& right) const; + +- bool operator>(const KODI::TIME::FileTime& right) const; +- bool operator>=(const KODI::TIME::FileTime& right) const; +- bool operator<(const KODI::TIME::FileTime& right) const; +- bool operator<=(const KODI::TIME::FileTime& right) const; +- bool operator==(const KODI::TIME::FileTime& right) const; +- bool operator!=(const KODI::TIME::FileTime& right) const; +- +- bool operator>(const KODI::TIME::SystemTime& right) const; +- bool operator>=(const KODI::TIME::SystemTime& right) const; +- bool operator<(const KODI::TIME::SystemTime& right) const; +- bool operator<=(const KODI::TIME::SystemTime& right) const; +- bool operator==(const KODI::TIME::SystemTime& right) const; +- bool operator!=(const KODI::TIME::SystemTime& right) const; +- + bool operator >(const time_t& right) const; + bool operator >=(const time_t& right) const; + bool operator <(const time_t& right) const; +@@ -140,8 +122,6 @@ public: + + CDateTimeSpan operator -(const CDateTime& right) const; + +- operator KODI::TIME::FileTime() const; +- + void Archive(CArchive& ar) override; + + void Reset(); +@@ -173,7 +153,6 @@ public: + */ + bool SetFromDBDateTime(const std::string &dateTime); + +- void GetAsSystemTime(KODI::TIME::SystemTime& time) const; + void GetAsTime(time_t& time) const; + void GetAsTm(tm& time) const; + std::chrono::system_clock::time_point GetAsTimePoint() const; +@@ -195,12 +174,6 @@ public: + void SetValid(bool yesNo); + bool IsValid() const; + +-private: +- bool ToTimePoint(const KODI::TIME::SystemTime& time, +- std::chrono::system_clock::time_point& timePoint) const; +- bool ToFileTime(const KODI::TIME::SystemTime& time, KODI::TIME::FileTime& fileTime) const; +- bool ToFileTime(const time_t& time, KODI::TIME::FileTime& fileTime) const; +- + private: + std::chrono::system_clock::time_point m_time; + +diff --git a/xbmc/addons/interfaces/gui/dialogs/Numeric.cpp b/xbmc/addons/interfaces/gui/dialogs/Numeric.cpp +index a78aa4af60..3acc48e768 100644 +--- a/xbmc/addons/interfaces/gui/dialogs/Numeric.cpp ++++ b/xbmc/addons/interfaces/gui/dialogs/Numeric.cpp +@@ -135,12 +135,9 @@ bool Interface_GUIDialogNumeric::show_and_get_time(KODI_HANDLE kodiBase, + return false; + } + +- KODI::TIME::SystemTime systemTime; + CDateTime dateTime(*time); +- dateTime.GetAsSystemTime(systemTime); +- if (CGUIDialogNumeric::ShowAndGetTime(systemTime, heading)) ++ if (CGUIDialogNumeric::ShowAndGetTime(dateTime, heading)) + { +- dateTime = systemTime; + dateTime.GetAsTm(*time); + return true; + } +@@ -167,12 +164,9 @@ bool Interface_GUIDialogNumeric::show_and_get_date(KODI_HANDLE kodiBase, + return false; + } + +- KODI::TIME::SystemTime systemTime; + CDateTime dateTime(*date); +- dateTime.GetAsSystemTime(systemTime); +- if (CGUIDialogNumeric::ShowAndGetDate(systemTime, heading)) ++ if (CGUIDialogNumeric::ShowAndGetDate(dateTime, heading)) + { +- dateTime = systemTime; + dateTime.GetAsTm(*date); + return true; + } +diff --git a/xbmc/dialogs/GUIDialogNumeric.cpp b/xbmc/dialogs/GUIDialogNumeric.cpp +index 182cf6a3af..bba219e44e 100644 +--- a/xbmc/dialogs/GUIDialogNumeric.cpp ++++ b/xbmc/dialogs/GUIDialogNumeric.cpp +@@ -45,7 +45,7 @@ CGUIDialogNumeric::CGUIDialogNumeric(void) + m_lastblock{}, + m_dirty{false} + { +- memset(&m_datetime, 0, sizeof(KODI::TIME::SystemTime)); ++ m_datetime.Reset(); + m_loadType = KEEP_IN_MEMORY; + } + +@@ -231,59 +231,76 @@ void CGUIDialogNumeric::OnBackSpace() + } + else if (m_mode == INPUT_TIME) + { ++ int hour = m_datetime.GetHour(); ++ int minute = m_datetime.GetMinute(); ++ + if (m_block == 0) +- m_datetime.hour /= 10; +- else if (m_datetime.minute) +- m_datetime.minute /= 10; ++ hour /= 10; ++ else if (minute) ++ minute /= 10; + else + { + m_block = 0; + m_dirty = false; + } ++ ++ m_datetime.SetTime(hour, minute, 0); + } + else if (m_mode == INPUT_TIME_SECONDS) + { ++ int hour = m_datetime.GetHour(); ++ int minute = m_datetime.GetMinute(); ++ int second = m_datetime.GetSecond(); ++ + if (m_block == 0) +- m_datetime.hour /= 10; ++ hour /= 10; + else if (m_block == 1) + { +- if (m_datetime.minute) +- m_datetime.minute /= 10; ++ if (minute) ++ minute /= 10; + else + { + m_block = 0; + m_dirty = false; + } + } +- else if (m_datetime.second) +- m_datetime.minute /= 10; ++ else if (second) ++ minute /= 10; + else + { + m_block = 0; + m_dirty = false; + } ++ ++ m_datetime.SetTime(hour, minute, second); + } + else if (m_mode == INPUT_DATE) + { ++ int day = m_datetime.GetDay(); ++ int month = m_datetime.GetMonth(); ++ int year = m_datetime.GetYear(); ++ + if (m_block == 0) +- m_datetime.day /= 10; ++ day /= 10; + else if (m_block == 1) + { +- if (m_datetime.month) +- m_datetime.month /= 10; ++ if (month) ++ month /= 10; + else + { + m_block = 0; + m_dirty = false; + } + } +- else if (m_datetime.year) // m_block == 2 +- m_datetime.year /= 10; ++ else if (year) // m_block == 2 ++ year /= 10; + else + { + m_block = 1; + m_dirty = false; + } ++ ++ m_datetime.SetDate(year, month, day); + } + } + +@@ -317,21 +334,21 @@ void CGUIDialogNumeric::FrameMove() + strLabel = m_number; + else if (m_mode == INPUT_TIME) + { // format up the time +- strLabel = StringUtils::Format("{:2}:{:02}", m_datetime.hour, m_datetime.minute); ++ strLabel = StringUtils::Format("{:2}:{:02}", m_datetime.GetHour(), m_datetime.GetMinute()); + start = m_block * 3; + end = m_block * 3 + 2; + } + else if (m_mode == INPUT_TIME_SECONDS) + { // format up the time +- strLabel = StringUtils::Format("{:2}:{:02}:{:02}", m_datetime.hour, m_datetime.minute, +- m_datetime.second); ++ strLabel = StringUtils::Format("{:2}:{:02}:{:02}", m_datetime.GetHour(), m_datetime.GetMinute(), ++ m_datetime.GetSecond()); + start = m_block * 3; + end = m_block * 3 + 2; + } + else if (m_mode == INPUT_DATE) + { // format up the date +- strLabel = +- StringUtils::Format("{:2}/{:2}/{:4}", m_datetime.day, m_datetime.month, m_datetime.year); ++ strLabel = StringUtils::Format("{:2}/{:2}/{:4}", m_datetime.GetDay(), m_datetime.GetMonth(), ++ m_datetime.GetYear()); + start = m_block * 3; + end = m_block * 3 + 2; + if (m_block == 2) +@@ -377,7 +394,7 @@ void CGUIDialogNumeric::OnNumber(uint32_t num) + } + } + +-void CGUIDialogNumeric::SetMode(INPUT_MODE mode, const KODI::TIME::SystemTime& initial) ++void CGUIDialogNumeric::SetMode(INPUT_MODE mode, const CDateTime& initial) + { + m_mode = mode; + m_block = 0; +@@ -425,7 +442,7 @@ void CGUIDialogNumeric::SetMode(INPUT_MODE mode, const std::string &initial) + if (!dateTime.IsValid()) + return; + +- dateTime.GetAsSystemTime(m_datetime); ++ m_datetime = dateTime; + m_lastblock = (m_mode == INPUT_DATE) ? 2 : 1; + } + else if (m_mode == INPUT_IP_ADDRESS) +@@ -447,7 +464,7 @@ void CGUIDialogNumeric::SetMode(INPUT_MODE mode, const std::string &initial) + m_number = initial; + } + +-KODI::TIME::SystemTime CGUIDialogNumeric::GetOutput() const ++CDateTime CGUIDialogNumeric::GetOutput() const + { + assert(m_mode == INPUT_TIME || m_mode == INPUT_TIME_SECONDS || m_mode == INPUT_DATE); + return m_datetime; +@@ -458,13 +475,13 @@ std::string CGUIDialogNumeric::GetOutputString() const + switch (m_mode) + { + case INPUT_DATE: +- return StringUtils::Format("{:02}/{:02}/{:04}", m_datetime.day, m_datetime.month, +- m_datetime.year); ++ return StringUtils::Format("{:02}/{:02}/{:04}", m_datetime.GetDay(), m_datetime.GetMonth(), ++ m_datetime.GetYear()); + case INPUT_TIME: +- return StringUtils::Format("{}:{:02}", m_datetime.hour, m_datetime.minute); ++ return StringUtils::Format("{}:{:02}", m_datetime.GetHour(), m_datetime.GetMinute()); + case INPUT_TIME_SECONDS: +- return StringUtils::Format("{}:{:02}:{:02}", m_datetime.hour, m_datetime.minute, +- m_datetime.second); ++ return StringUtils::Format("{}:{:02}:{:02}", m_datetime.GetHour(), m_datetime.GetMinute(), ++ m_datetime.GetSecond()); + case INPUT_IP_ADDRESS: + return StringUtils::Format("{}.{}.{}.{}", m_ip[0], m_ip[1], m_ip[2], m_ip[3]); + case INPUT_NUMBER: +@@ -480,23 +497,25 @@ bool CGUIDialogNumeric::ShowAndGetSeconds(std::string &timeString, const std::st + { + CGUIDialogNumeric *pDialog = CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogNumeric>(WINDOW_DIALOG_NUMERIC); + if (!pDialog) return false; +- int seconds = StringUtils::TimeStringToSeconds(timeString); +- KODI::TIME::SystemTime time = {}; +- time.hour = seconds / 3600; +- time.minute = (seconds - time.hour * 3600) / 60; +- time.second = seconds - time.hour * 3600 - time.minute * 60; +- pDialog->SetMode(INPUT_TIME_SECONDS, time); ++ ++ std::chrono::system_clock::time_point time{ ++ std::chrono::seconds{StringUtils::TimeStringToSeconds(timeString)}}; ++ ++ CDateTime datetime(time); ++ ++ pDialog->SetMode(INPUT_TIME_SECONDS, datetime); + pDialog->SetHeading(heading); + pDialog->Open(); + if (!pDialog->IsConfirmed() || pDialog->IsCanceled()) + return false; +- time = pDialog->GetOutput(); +- seconds = time.hour * 3600 + time.minute * 60 + time.second; +- timeString = StringUtils::SecondsToTimeString(seconds); ++ datetime = pDialog->GetOutput(); ++ time = datetime.GetAsTimePoint(); ++ timeString = StringUtils::SecondsToTimeString( ++ std::chrono::duration_cast<std::chrono::seconds>(time.time_since_epoch()).count()); + return true; + } + +-bool CGUIDialogNumeric::ShowAndGetTime(KODI::TIME::SystemTime& time, const std::string& heading) ++bool CGUIDialogNumeric::ShowAndGetTime(CDateTime& time, const std::string& heading) + { + CGUIDialogNumeric *pDialog = CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogNumeric>(WINDOW_DIALOG_NUMERIC); + if (!pDialog) return false; +@@ -509,7 +528,7 @@ bool CGUIDialogNumeric::ShowAndGetTime(KODI::TIME::SystemTime& time, const std:: + return true; + } + +-bool CGUIDialogNumeric::ShowAndGetDate(KODI::TIME::SystemTime& date, const std::string& heading) ++bool CGUIDialogNumeric::ShowAndGetDate(CDateTime& date, const std::string& heading) + { + CGUIDialogNumeric *pDialog = CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogNumeric>(WINDOW_DIALOG_NUMERIC); + if (!pDialog) return false; +@@ -680,28 +699,33 @@ void CGUIDialogNumeric::SetHeading(const std::string& strHeading) + + void CGUIDialogNumeric::VerifyDate(bool checkYear) + { +- if (m_datetime.day == 0) +- m_datetime.day = 1; +- if (m_datetime.month == 0) +- m_datetime.month = 1; ++ int day = m_datetime.GetDay(); ++ int month = m_datetime.GetMonth(); ++ int year = m_datetime.GetYear(); ++ ++ if (day == 0) ++ day = 1; ++ if (month == 0) ++ month = 1; + // check for number of days in the month +- if (m_datetime.day == 31) ++ if (day == 31) + { +- if (m_datetime.month == 4 || m_datetime.month == 6 || m_datetime.month == 9 || +- m_datetime.month == 11) +- m_datetime.day = 30; ++ if (month == 4 || month == 6 || month == 9 || month == 11) ++ day = 30; + } +- if (m_datetime.month == 2 && m_datetime.day > 28) ++ if (month == 2 && day > 28) + { +- m_datetime.day = 29; // max in february. ++ day = 29; // max in february. + if (checkYear) + { + // leap years occur when the year is divisible by 4 but not by 100, or the year is divisible by 400 + // thus they don't occur, if the year has a remainder when divided by 4, or when the year is divisible by 100 but not by 400 +- if ((m_datetime.year % 4) || (!(m_datetime.year % 100) && (m_datetime.year % 400))) +- m_datetime.day = 28; ++ if ((year % 4) || (!(year % 100) && (year % 400))) ++ day = 28; + } + } ++ ++ m_datetime.SetDate(year, month, day); + } + + void CGUIDialogNumeric::OnOK() +@@ -741,17 +765,21 @@ void CGUIDialogNumeric::HandleInputIP(uint32_t num) + + void CGUIDialogNumeric::HandleInputDate(uint32_t num) + { ++ int day = m_datetime.GetDay(); ++ int month = m_datetime.GetMonth(); ++ int year = m_datetime.GetYear(); ++ + if (m_block == 0) // day of month + { +- if (m_dirty && (m_datetime.day < 3 || num < 2)) ++ if (m_dirty && (day < 3 || num < 2)) + { +- m_datetime.day *= 10; +- m_datetime.day += num; ++ day *= 10; ++ day += num; + } + else +- m_datetime.day = num; ++ day = num; + +- if (m_datetime.day > 3) ++ if (day > 3) + { + m_block = 1; // move to months + m_dirty = false; +@@ -763,13 +791,13 @@ void CGUIDialogNumeric::HandleInputDate(uint32_t num) + { + if (m_dirty && num < 3) + { +- m_datetime.month *= 10; +- m_datetime.month += num; ++ month *= 10; ++ month += num; + } + else +- m_datetime.month = num; ++ month = num; + +- if (m_datetime.month > 1) ++ if (month > 1) + { + VerifyDate(false); + m_block = 2; // move to year +@@ -780,15 +808,15 @@ void CGUIDialogNumeric::HandleInputDate(uint32_t num) + } + else // year + { +- if (m_dirty && m_datetime.year < 1000) // have taken input ++ if (m_dirty && year < 1000) // have taken input + { +- m_datetime.year *= 10; +- m_datetime.year += num; ++ year *= 10; ++ year += num; + } + else +- m_datetime.year = num; ++ year = num; + +- if (m_datetime.year > 1000) ++ if (year > 1000) + { + VerifyDate(true); + m_block = 0; // move to day of month +@@ -797,22 +825,28 @@ void CGUIDialogNumeric::HandleInputDate(uint32_t num) + else + m_dirty = true; + } ++ ++ m_datetime.SetDate(year, month, day); + } + + void CGUIDialogNumeric::HandleInputSeconds(uint32_t num) + { ++ int hour = m_datetime.GetHour(); ++ int minute = m_datetime.GetMinute(); ++ int second = m_datetime.GetSecond(); ++ + if (m_block == 0) // hour + { + if (m_dirty) // have input the first digit + { +- m_datetime.hour *= 10; +- m_datetime.hour += num; ++ hour *= 10; ++ hour += num; + m_block = 1; // move to minutes - allows up to 99 hours + m_dirty = false; + } + else // this is the first digit + { +- m_datetime.hour = num; ++ hour = num; + m_dirty = true; + } + } +@@ -820,14 +854,14 @@ void CGUIDialogNumeric::HandleInputSeconds(uint32_t num) + { + if (m_dirty) // have input the first digit + { +- m_datetime.minute *= 10; +- m_datetime.minute += num; ++ minute *= 10; ++ minute += num; + m_block = 2; // move to seconds - allows up to 99 minutes + m_dirty = false; + } + else // this is the first digit + { +- m_datetime.minute = num; ++ minute = num; + if (num > 5) + { + m_block = 2; // move to seconds +@@ -841,14 +875,14 @@ void CGUIDialogNumeric::HandleInputSeconds(uint32_t num) + { + if (m_dirty) // have input the first digit + { +- m_datetime.second *= 10; +- m_datetime.second += num; ++ second *= 10; ++ second += num; + m_block = 0; // move to hours + m_dirty = false; + } + else // this is the first digit + { +- m_datetime.second = num; ++ second = num; + if (num > 5) + { + m_block = 0; // move to hours +@@ -858,28 +892,33 @@ void CGUIDialogNumeric::HandleInputSeconds(uint32_t num) + m_dirty = true; + } + } ++ ++ m_datetime.SetTime(hour, minute, second); + } + + void CGUIDialogNumeric::HandleInputTime(uint32_t num) + { ++ int hour = m_datetime.GetHour(); ++ int minute = m_datetime.GetMinute(); ++ + if (m_block == 0) // hour + { + if (m_dirty) // have input the first digit + { +- if (m_datetime.hour < 2 || num < 4) ++ if (hour < 2 || num < 4) + { +- m_datetime.hour *= 10; +- m_datetime.hour += num; ++ hour *= 10; ++ hour += num; + } + else +- m_datetime.hour = num; ++ hour = num; + + m_block = 1; // move to minutes + m_dirty = false; + } + else // this is the first digit + { +- m_datetime.hour = num; ++ hour = num; + + if (num > 2) + { +@@ -894,14 +933,14 @@ void CGUIDialogNumeric::HandleInputTime(uint32_t num) + { + if (m_dirty) // have input the first digit + { +- m_datetime.minute *= 10; +- m_datetime.minute += num; ++ minute *= 10; ++ minute += num; + m_block = 0; // move to hours + m_dirty = false; + } + else // this is the first digit + { +- m_datetime.minute = num; ++ minute = num; + + if (num > 5) + { +@@ -912,5 +951,7 @@ void CGUIDialogNumeric::HandleInputTime(uint32_t num) + m_dirty = true; + } + } ++ ++ m_datetime.SetTime(hour, minute, 0); + } + +diff --git a/xbmc/dialogs/GUIDialogNumeric.h b/xbmc/dialogs/GUIDialogNumeric.h +index 2932053021..d39b2702cd 100644 +--- a/xbmc/dialogs/GUIDialogNumeric.h ++++ b/xbmc/dialogs/GUIDialogNumeric.h +@@ -8,8 +8,8 @@ + + #pragma once + ++#include "XBDateTime.h" + #include "guilib/GUIDialog.h" +-#include "utils/XTimeUtils.h" + + #include <cstdint> + +@@ -41,13 +41,13 @@ public: + static InputVerificationResult ShowAndVerifyInput(std::string& strPassword, const std::string& strHeading, bool bGetUserInput); + + void SetHeading(const std::string &strHeading); +- void SetMode(INPUT_MODE mode, const KODI::TIME::SystemTime& initial); ++ void SetMode(INPUT_MODE mode, const CDateTime& initial); + void SetMode(INPUT_MODE mode, const std::string &initial); +- KODI::TIME::SystemTime GetOutput() const; ++ CDateTime GetOutput() const; + std::string GetOutputString() const; + +- static bool ShowAndGetTime(KODI::TIME::SystemTime& time, const std::string& heading); +- static bool ShowAndGetDate(KODI::TIME::SystemTime& date, const std::string& heading); ++ static bool ShowAndGetTime(CDateTime& time, const std::string& heading); ++ static bool ShowAndGetDate(CDateTime& date, const std::string& heading); + static bool ShowAndGetIPAddress(std::string &IPAddress, const std::string &heading); + static bool ShowAndGetNumber(std::string& strInput, const std::string &strHeading, unsigned int iAutoCloseTimeoutMs = 0, bool bSetHidden = false); + static bool ShowAndGetSeconds(std::string& timeString, const std::string &heading); +@@ -73,7 +73,7 @@ protected: + bool m_bCanceled; + + INPUT_MODE m_mode; // the current input mode +- KODI::TIME::SystemTime m_datetime; // for time and date modes ++ CDateTime m_datetime; // for time and date modes + uint8_t m_ip[4]; // for ip address mode + uint32_t m_block; // for time, date, and IP methods. + uint32_t m_lastblock; +diff --git a/xbmc/filesystem/NFSDirectory.cpp b/xbmc/filesystem/NFSDirectory.cpp +index 7feba534c7..69a5dad0f6 100644 +--- a/xbmc/filesystem/NFSDirectory.cpp ++++ b/xbmc/filesystem/NFSDirectory.cpp +@@ -202,7 +202,6 @@ bool CNFSDirectory::GetDirectory(const CURL& url, CFileItemList &items) + { + // We accept nfs://server/path[/file]]]] + int ret = 0; +- KODI::TIME::FileTime fileTime, localTime; + std::unique_lock<CCriticalSection> lock(gNfsConnection); + std::string strDirName=""; + std::string myStrPath(url.Get()); +@@ -248,7 +247,6 @@ bool CNFSDirectory::GetDirectory(const CURL& url, CFileItemList &items) + std::string path(myStrPath + strName); + int64_t iSize = 0; + bool bIsDir = false; +- int64_t lTimeDate = 0; + + //reslove symlinks + if(tmpDirent.type == NF3LNK) +@@ -265,25 +263,13 @@ bool CNFSDirectory::GetDirectory(const CURL& url, CFileItemList &items) + + iSize = tmpDirent.size; + bIsDir = tmpDirent.type == NF3DIR; +- lTimeDate = tmpDirent.mtime.tv_sec; + + if (!StringUtils::EqualsNoCase(strName,".") && !StringUtils::EqualsNoCase(strName,"..") + && !StringUtils::EqualsNoCase(strName,"lost+found")) + { +- if(lTimeDate == 0) // if modification date is missing, use create date +- { +- lTimeDate = tmpDirent.ctime.tv_sec; +- } +- +- long long ll = lTimeDate & 0xffffffff; +- ll *= 10000000ll; +- ll += 116444736000000000ll; +- fileTime.lowDateTime = (DWORD)(ll & 0xffffffff); +- fileTime.highDateTime = (DWORD)(ll >> 32); +- KODI::TIME::FileTimeToLocalFileTime(&fileTime, &localTime); +- + CFileItemPtr pItem(new CFileItem(tmpDirent.name)); +- pItem->m_dateTime=localTime; ++ pItem->m_dateTime = ++ tmpDirent.mtime.tv_sec != 0 ? tmpDirent.mtime.tv_sec : tmpDirent.ctime.tv_sec; + pItem->m_dwSize = iSize; + + if (bIsDir) +diff --git a/xbmc/guilib/GUIEditControl.cpp b/xbmc/guilib/GUIEditControl.cpp +index 325a703152..f5c25adb37 100644 +--- a/xbmc/guilib/GUIEditControl.cpp ++++ b/xbmc/guilib/GUIEditControl.cpp +@@ -297,11 +297,9 @@ void CGUIEditControl::OnClick() + { + CDateTime dateTime; + dateTime.SetFromDBTime(utf8); +- KODI::TIME::SystemTime time; +- dateTime.GetAsSystemTime(time); +- if (CGUIDialogNumeric::ShowAndGetTime(time, !m_inputHeading.empty() ? m_inputHeading : g_localizeStrings.Get(21420))) ++ if (CGUIDialogNumeric::ShowAndGetTime( ++ dateTime, !m_inputHeading.empty() ? m_inputHeading : g_localizeStrings.Get(21420))) + { +- dateTime = CDateTime(time); + utf8 = dateTime.GetAsLocalizedTime("", false); + textChanged = true; + } +@@ -313,11 +311,10 @@ void CGUIEditControl::OnClick() + dateTime.SetFromDBDate(utf8); + if (dateTime < CDateTime(2000,1, 1, 0, 0, 0)) + dateTime = CDateTime(2000, 1, 1, 0, 0, 0); +- KODI::TIME::SystemTime date; +- dateTime.GetAsSystemTime(date); +- if (CGUIDialogNumeric::ShowAndGetDate(date, !m_inputHeading.empty() ? m_inputHeading : g_localizeStrings.Get(21420))) ++ ++ if (CGUIDialogNumeric::ShowAndGetDate( ++ dateTime, !m_inputHeading.empty() ? m_inputHeading : g_localizeStrings.Get(21420))) + { +- dateTime = CDateTime(date); + utf8 = dateTime.GetAsDBDate(); + textChanged = true; + } +diff --git a/xbmc/guilib/GUIRSSControl.h b/xbmc/guilib/GUIRSSControl.h +index 851f72fb3c..1ade92dbaf 100644 +--- a/xbmc/guilib/GUIRSSControl.h ++++ b/xbmc/guilib/GUIRSSControl.h +@@ -62,7 +62,7 @@ protected: + KODI::GUILIB::GUIINFO::CGUIInfoColor m_headlineColor; + + std::vector<std::string> m_vecUrls; +- std::vector<int> m_vecIntervals; ++ std::vector<std::chrono::nanoseconds> m_vecIntervals; + bool m_rtl; + CScrollInfo m_scrollInfo; + bool m_dirty; +diff --git a/xbmc/interfaces/legacy/Dialog.cpp b/xbmc/interfaces/legacy/Dialog.cpp +index 6dd00f179b..5e9db03da6 100644 +--- a/xbmc/interfaces/legacy/Dialog.cpp ++++ b/xbmc/interfaces/legacy/Dialog.cpp +@@ -286,8 +286,8 @@ namespace XBMCAddon + { + DelayedCallGuard dcguard(languageHook); + std::string value; +- KODI::TIME::SystemTime timedate; +- KODI::TIME::GetLocalTime(&timedate); ++ ++ auto timedate = CDateTime::GetCurrentDateTime(); + + if (!heading.empty()) + { +@@ -295,14 +295,13 @@ namespace XBMCAddon + { + if (!defaultt.empty() && defaultt.size() == 10) + { +- const std::string& sDefault = defaultt; +- timedate.day = atoi(sDefault.substr(0, 2).c_str()); +- timedate.month = atoi(sDefault.substr(3, 4).c_str()); +- timedate.year = atoi(sDefault.substr(sDefault.size() - 4).c_str()); ++ const std::string sDefault = defaultt; ++ timedate.SetFromDBDate(sDefault.substr(sDefault.size() - 4) + "-" + ++ sDefault.substr(3, 4) + "-" + sDefault.substr(0, 2)); + } + if (CGUIDialogNumeric::ShowAndGetDate(timedate, heading)) +- value = +- StringUtils::Format("{:2}/{:2}/{:4}", timedate.day, timedate.month, timedate.year); ++ value = StringUtils::Format("{:2}/{:2}/{:4}", timedate.GetDay(), timedate.GetMonth(), ++ timedate.GetYear()); + else + return emptyString; + } +@@ -310,12 +309,11 @@ namespace XBMCAddon + { + if (!defaultt.empty() && defaultt.size() == 5) + { +- const std::string& sDefault = defaultt; +- timedate.hour = atoi(sDefault.substr(0, 2).c_str()); +- timedate.minute = atoi(sDefault.substr(3, 2).c_str()); ++ const std::string sDefault = defaultt; ++ timedate.SetFromDBTime(sDefault.substr(0, 2) + ":" + sDefault.substr(3, 2)); + } + if (CGUIDialogNumeric::ShowAndGetTime(timedate, heading)) +- value = StringUtils::Format("{:2}:{:02}", timedate.hour, timedate.minute); ++ value = StringUtils::Format("{:2}:{:02}", timedate.GetHour(), timedate.GetMinute()); + else + return emptyString; + } +@@ -367,8 +365,8 @@ namespace XBMCAddon + { + DelayedCallGuard dcguard(languageHook); + std::string value(defaultt); +- KODI::TIME::SystemTime timedate; +- KODI::TIME::GetLocalTime(&timedate); ++ ++ auto timedate = CDateTime::GetCurrentDateTime(); + + switch (type) + { +@@ -389,14 +387,13 @@ namespace XBMCAddon + { + if (!defaultt.empty() && defaultt.size() == 10) + { +- const std::string& sDefault = defaultt; +- timedate.day = atoi(sDefault.substr(0, 2).c_str()); +- timedate.month = atoi(sDefault.substr(3, 4).c_str()); +- timedate.year = atoi(sDefault.substr(sDefault.size() - 4).c_str()); ++ const std::string sDefault = defaultt; ++ timedate.SetFromDBDate(sDefault.substr(sDefault.size() - 4) + "-" + ++ sDefault.substr(3, 4) + "-" + sDefault.substr(0, 2)); + } + if (CGUIDialogNumeric::ShowAndGetDate(timedate, heading)) +- value = StringUtils::Format("{:2}/{:2}/{:4}", timedate.day, timedate.month, +- timedate.year); ++ value = StringUtils::Format("{:2}/{:2}/{:4}", timedate.GetDay(), timedate.GetMonth(), ++ timedate.GetYear()); + else + value = emptyString; + } +@@ -405,12 +402,11 @@ namespace XBMCAddon + { + if (!defaultt.empty() && defaultt.size() == 5) + { +- const std::string& sDefault = defaultt; +- timedate.hour = atoi(sDefault.substr(0, 2).c_str()); +- timedate.minute = atoi(sDefault.substr(3, 2).c_str()); ++ const std::string sDefault = defaultt; ++ timedate.SetFromDBTime(sDefault.substr(0, 2) + ":" + sDefault.substr(3, 2)); + } + if (CGUIDialogNumeric::ShowAndGetTime(timedate, heading)) +- value = StringUtils::Format("{:2}:{:02}", timedate.hour, timedate.minute); ++ value = StringUtils::Format("{:2}:{:02}", timedate.GetHour(), timedate.GetMinute()); + else + value = emptyString; + } +diff --git a/xbmc/music/infoscanner/MusicInfoScanner.cpp b/xbmc/music/infoscanner/MusicInfoScanner.cpp +index f828b44914..3912892343 100644 +--- a/xbmc/music/infoscanner/MusicInfoScanner.cpp ++++ b/xbmc/music/infoscanner/MusicInfoScanner.cpp +@@ -1269,8 +1269,8 @@ int CMusicInfoScanner::GetPathHash(const CFileItemList &items, std::string &hash + const CFileItemPtr pItem = items[i]; + digest.Update(pItem->GetPath()); + digest.Update((unsigned char *)&pItem->m_dwSize, sizeof(pItem->m_dwSize)); +- KODI::TIME::FileTime time = pItem->m_dateTime; +- digest.Update((unsigned char*)&time, sizeof(KODI::TIME::FileTime)); ++ const auto time = pItem->m_dateTime.GetAsTimePoint().time_since_epoch().count(); ++ digest.Update(&time, sizeof(std::chrono::nanoseconds)); + if (pItem->IsAudio() && !pItem->IsPlayList() && !pItem->IsNFO()) + count++; + } +diff --git a/xbmc/network/upnp/UPnPInternal.cpp b/xbmc/network/upnp/UPnPInternal.cpp +index 406615768a..1a98b86c50 100644 +--- a/xbmc/network/upnp/UPnPInternal.cpp ++++ b/xbmc/network/upnp/UPnPInternal.cpp +@@ -1067,11 +1067,19 @@ std::shared_ptr<CFileItem> BuildObject(PLT_MediaObject* entry, + } + + // look for date? +- if(entry->m_Description.date.GetLength()) { +- KODI::TIME::SystemTime time = {}; +- sscanf(entry->m_Description.date, "%hu-%hu-%huT%hu:%hu:%hu", &time.year, &time.month, &time.day, +- &time.hour, &time.minute, &time.second); +- pItem->m_dateTime = time; ++ if (entry->m_Description.date.GetLength()) ++ { ++ int year; ++ int month; ++ int day; ++ int hour; ++ int minute; ++ int second; ++ ++ sscanf(entry->m_Description.date, "%u-%u-%uT%u:%u:%u", &year, &month, &day, &hour, &minute, ++ &second); ++ ++ pItem->m_dateTime.SetDateTime(year, month, day, hour, minute, second); + } + + // if there is a thumbnail available set it here +diff --git a/xbmc/platform/posix/XTimeUtils.cpp b/xbmc/platform/posix/XTimeUtils.cpp +index e78e5cff48..7d4b17686a 100644 +--- a/xbmc/platform/posix/XTimeUtils.cpp ++++ b/xbmc/platform/posix/XTimeUtils.cpp +@@ -8,221 +8,10 @@ + + #include "utils/XTimeUtils.h" + +-#include "PosixTimezone.h" +- +-#include <errno.h> +-#include <mutex> +-#include <time.h> +- +-#include <sys/times.h> +- +-#if defined(TARGET_ANDROID) && !defined(__LP64__) +-#include <time64.h> +-#endif +- +-#define WIN32_TIME_OFFSET ((unsigned long long)(369 * 365 + 89) * 24 * 3600 * 10000000) +- + namespace KODI + { + namespace TIME + { + +-/* +- * A Leap year is any year that is divisible by four, but not by 100 unless also +- * divisible by 400 +- */ +-#define IsLeapYear(y) ((!(y % 4)) ? (((!(y % 400)) && (y % 100)) ? 1 : 0) : 0) +- +-uint32_t GetTimeZoneInformation(TimeZoneInformation* timeZoneInformation) +-{ +- if (!timeZoneInformation) +- return KODI_TIME_ZONE_ID_INVALID; +- +- struct tm t; +- time_t tt = time(NULL); +- if (localtime_r(&tt, &t)) +- timeZoneInformation->bias = -t.tm_gmtoff / 60; +- +- timeZoneInformation->standardName = tzname[0]; +- timeZoneInformation->daylightName = tzname[1]; +- +- return KODI_TIME_ZONE_ID_UNKNOWN; +-} +- +-void GetLocalTime(SystemTime* systemTime) +-{ +- const time_t t = time(NULL); +- struct tm now; +- +- localtime_r(&t, &now); +- systemTime->year = now.tm_year + 1900; +- systemTime->month = now.tm_mon + 1; +- systemTime->dayOfWeek = now.tm_wday; +- systemTime->day = now.tm_mday; +- systemTime->hour = now.tm_hour; +- systemTime->minute = now.tm_min; +- systemTime->second = now.tm_sec; +- systemTime->milliseconds = 0; +- // NOTE: localtime_r() is not required to set this, but we Assume that it's set here. +- g_timezone.m_IsDST = now.tm_isdst; +-} +- +-int FileTimeToLocalFileTime(const FileTime* fileTime, FileTime* localFileTime) +-{ +- ULARGE_INTEGER l; +- l.u.LowPart = fileTime->lowDateTime; +- l.u.HighPart = fileTime->highDateTime; +- +- time_t ft; +- struct tm tm_ft; +- FileTimeToTimeT(fileTime, &ft); +- localtime_r(&ft, &tm_ft); +- +- l.QuadPart += static_cast<unsigned long long>(tm_ft.tm_gmtoff) * 10000000; +- +- localFileTime->lowDateTime = l.u.LowPart; +- localFileTime->highDateTime = l.u.HighPart; +- return 1; +-} +- +-int SystemTimeToFileTime(const SystemTime* systemTime, FileTime* fileTime) +-{ +- static const int dayoffset[12] = {0, 31, 59, 90, 120, 151, 182, 212, 243, 273, 304, 334}; +-#if defined(TARGET_DARWIN) +- static std::mutex timegm_lock; +-#endif +- +- struct tm sysTime = {}; +- sysTime.tm_year = systemTime->year - 1900; +- sysTime.tm_mon = systemTime->month - 1; +- sysTime.tm_wday = systemTime->dayOfWeek; +- sysTime.tm_mday = systemTime->day; +- sysTime.tm_hour = systemTime->hour; +- sysTime.tm_min = systemTime->minute; +- sysTime.tm_sec = systemTime->second; +- sysTime.tm_yday = dayoffset[sysTime.tm_mon] + (sysTime.tm_mday - 1); +- sysTime.tm_isdst = g_timezone.m_IsDST; +- +- // If this is a leap year, and we're past the 28th of Feb, increment tm_yday. +- if (IsLeapYear(systemTime->year) && (sysTime.tm_yday > 58)) +- sysTime.tm_yday++; +- +-#if defined(TARGET_DARWIN) +- std::lock_guard<std::mutex> lock(timegm_lock); +-#endif +- +-#if defined(TARGET_ANDROID) && !defined(__LP64__) +- time64_t t = timegm64(&sysTime); +-#else +- time_t t = timegm(&sysTime); +-#endif +- +- LARGE_INTEGER result; +- result.QuadPart = (long long)t * 10000000 + (long long)systemTime->milliseconds * 10000; +- result.QuadPart += WIN32_TIME_OFFSET; +- +- fileTime->lowDateTime = result.u.LowPart; +- fileTime->highDateTime = result.u.HighPart; +- +- return 1; +-} +- +-long CompareFileTime(const FileTime* fileTime1, const FileTime* fileTime2) +-{ +- ULARGE_INTEGER t1; +- t1.u.LowPart = fileTime1->lowDateTime; +- t1.u.HighPart = fileTime1->highDateTime; +- +- ULARGE_INTEGER t2; +- t2.u.LowPart = fileTime2->lowDateTime; +- t2.u.HighPart = fileTime2->highDateTime; +- +- if (t1.QuadPart == t2.QuadPart) +- return 0; +- else if (t1.QuadPart < t2.QuadPart) +- return -1; +- else +- return 1; +-} +- +-int FileTimeToSystemTime(const FileTime* fileTime, SystemTime* systemTime) +-{ +- LARGE_INTEGER file; +- file.u.LowPart = fileTime->lowDateTime; +- file.u.HighPart = fileTime->highDateTime; +- +- file.QuadPart -= WIN32_TIME_OFFSET; +- file.QuadPart /= 10000; /* to milliseconds */ +- systemTime->milliseconds = file.QuadPart % 1000; +- file.QuadPart /= 1000; /* to seconds */ +- +- time_t ft = file.QuadPart; +- +- struct tm tm_ft; +- gmtime_r(&ft, &tm_ft); +- +- systemTime->year = tm_ft.tm_year + 1900; +- systemTime->month = tm_ft.tm_mon + 1; +- systemTime->dayOfWeek = tm_ft.tm_wday; +- systemTime->day = tm_ft.tm_mday; +- systemTime->hour = tm_ft.tm_hour; +- systemTime->minute = tm_ft.tm_min; +- systemTime->second = tm_ft.tm_sec; +- +- return 1; +-} +- +-int LocalFileTimeToFileTime(const FileTime* localFileTime, FileTime* fileTime) +-{ +- ULARGE_INTEGER l; +- l.u.LowPart = localFileTime->lowDateTime; +- l.u.HighPart = localFileTime->highDateTime; +- +- l.QuadPart += (unsigned long long) timezone * 10000000; +- +- fileTime->lowDateTime = l.u.LowPart; +- fileTime->highDateTime = l.u.HighPart; +- +- return 1; +-} +- +- +-int FileTimeToTimeT(const FileTime* localFileTime, time_t* pTimeT) +-{ +- if (!localFileTime || !pTimeT) +- return false; +- +- ULARGE_INTEGER fileTime; +- fileTime.u.LowPart = localFileTime->lowDateTime; +- fileTime.u.HighPart = localFileTime->highDateTime; +- +- fileTime.QuadPart -= WIN32_TIME_OFFSET; +- fileTime.QuadPart /= 10000; /* to milliseconds */ +- fileTime.QuadPart /= 1000; /* to seconds */ +- +- time_t ft = fileTime.QuadPart; +- +- struct tm tm_ft; +- localtime_r(&ft, &tm_ft); +- +- *pTimeT = mktime(&tm_ft); +- return 1; +-} +- +-int TimeTToFileTime(time_t timeT, FileTime* localFileTime) +-{ +- if (!localFileTime) +- return false; +- +- ULARGE_INTEGER result; +- result.QuadPart = (unsigned long long) timeT * 10000000; +- result.QuadPart += WIN32_TIME_OFFSET; +- +- localFileTime->lowDateTime = result.u.LowPart; +- localFileTime->highDateTime = result.u.HighPart; +- +- return 1; +-} +- + } // namespace TIME + } // namespace KODI +diff --git a/xbmc/platform/posix/filesystem/PosixDirectory.cpp b/xbmc/platform/posix/filesystem/PosixDirectory.cpp +index 6685c0e1db..7482a73960 100644 +--- a/xbmc/platform/posix/filesystem/PosixDirectory.cpp ++++ b/xbmc/platform/posix/filesystem/PosixDirectory.cpp +@@ -79,10 +79,7 @@ bool CPosixDirectory::GetDirectory(const CURL& url, CFileItemList &items) + { + if (bStat || stat(pItem->GetPath().c_str(), &buffer) == 0) + { +- KODI::TIME::FileTime fileTime, localTime; +- KODI::TIME::TimeTToFileTime(buffer.st_mtime, &fileTime); +- KODI::TIME::FileTimeToLocalFileTime(&fileTime, &localTime); +- pItem->m_dateTime = localTime; ++ pItem->m_dateTime = buffer.st_mtime; + + if (!pItem->m_bIsFolder) + pItem->m_dwSize = buffer.st_size; +diff --git a/xbmc/platform/posix/filesystem/SMBDirectory.cpp b/xbmc/platform/posix/filesystem/SMBDirectory.cpp +index e2305afb4a..f0b94c22fc 100644 +--- a/xbmc/platform/posix/filesystem/SMBDirectory.cpp ++++ b/xbmc/platform/posix/filesystem/SMBDirectory.cpp +@@ -134,10 +134,10 @@ bool CSMBDirectory::GetDirectory(const CURL& url, CFileItemList &items) + && strFile != "lost+found" + && aDir.type != SMBC_PRINTER_SHARE && aDir.type != SMBC_IPC_SHARE) + { +- int64_t iSize = 0; ++ int64_t iSize = 0; + bool bIsDir = true; +- int64_t lTimeDate = 0; + bool hidden = false; ++ struct stat info = {}; + + if(StringUtils::EndsWith(strFile, "$") && aDir.type == SMBC_FILE_SHARE ) + continue; +@@ -152,7 +152,6 @@ bool CSMBDirectory::GetDirectory(const CURL& url, CFileItemList &items) + // set this here to if the stat should fail + bIsDir = (aDir.type == SMBC_DIR); + +- struct stat info = {}; + if ((m_flags & DIR_FLAG_NO_FILE_INFO)==0 && CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_sambastatfiles) + { + // make sure we use the authenticated path which contains any default username +@@ -187,9 +186,6 @@ bool CSMBDirectory::GetDirectory(const CURL& url, CFileItemList &items) + CURL::GetRedacted(strFullName), errno, strerror(errno)); + + bIsDir = S_ISDIR(info.st_mode); +- lTimeDate = info.st_mtime; +- if(lTimeDate == 0) // if modification date is missing, use create date +- lTimeDate = info.st_ctime; + iSize = info.st_size; + } + else +@@ -200,10 +196,6 @@ bool CSMBDirectory::GetDirectory(const CURL& url, CFileItemList &items) + } + } + +- KODI::TIME::FileTime fileTime, localTime; +- KODI::TIME::TimeTToFileTime(lTimeDate, &fileTime); +- KODI::TIME::FileTimeToLocalFileTime(&fileTime, &localTime); +- + if (bIsDir) + { + CFileItemPtr pItem(new CFileItem(strFile)); +@@ -223,7 +215,7 @@ bool CSMBDirectory::GetDirectory(const CURL& url, CFileItemList &items) + URIUtils::AddSlashAtEnd(path); + pItem->SetPath(path); + pItem->m_bIsFolder = true; +- pItem->m_dateTime=localTime; ++ pItem->m_dateTime = info.st_mtime != 0 ? info.st_mtime : info.st_ctime; + if (hidden) + pItem->SetProperty("file:hidden", true); + items.Add(pItem); +@@ -234,7 +226,7 @@ bool CSMBDirectory::GetDirectory(const CURL& url, CFileItemList &items) + pItem->SetPath(strRoot + aDir.name); + pItem->m_bIsFolder = false; + pItem->m_dwSize = iSize; +- pItem->m_dateTime=localTime; ++ pItem->m_dateTime = info.st_mtime != 0 ? info.st_mtime : info.st_ctime; + if (hidden) + pItem->SetProperty("file:hidden", true); + items.Add(pItem); +diff --git a/xbmc/pvr/dialogs/GUIDialogPVRTimerSettings.cpp b/xbmc/pvr/dialogs/GUIDialogPVRTimerSettings.cpp +index f7866278e7..e61761b0ab 100644 +--- a/xbmc/pvr/dialogs/GUIDialogPVRTimerSettings.cpp ++++ b/xbmc/pvr/dialogs/GUIDialogPVRTimerSettings.cpp +@@ -573,22 +573,16 @@ void CGUIDialogPVRTimerSettings::OnSettingAction(const std::shared_ptr<const CSe + const std::string& settingId = setting->GetId(); + if (settingId == SETTING_TMR_BEGIN) + { +- KODI::TIME::SystemTime timerStartTime; +- m_startLocalTime.GetAsSystemTime(timerStartTime); +- if (CGUIDialogNumeric::ShowAndGetTime(timerStartTime, g_localizeStrings.Get(14066))) ++ if (CGUIDialogNumeric::ShowAndGetTime(m_startLocalTime, g_localizeStrings.Get(14066))) + { +- SetTimeFromSystemTime(m_startLocalTime, timerStartTime); + m_timerStartTimeStr = m_startLocalTime.GetAsLocalizedTime("", false); + SetButtonLabels(); + } + } + else if (settingId == SETTING_TMR_END) + { +- KODI::TIME::SystemTime timerEndTime; +- m_endLocalTime.GetAsSystemTime(timerEndTime); +- if (CGUIDialogNumeric::ShowAndGetTime(timerEndTime, g_localizeStrings.Get(14066))) ++ if (CGUIDialogNumeric::ShowAndGetTime(m_endLocalTime, g_localizeStrings.Get(14066))) + { +- SetTimeFromSystemTime(m_endLocalTime, timerEndTime); + m_timerEndTimeStr = m_endLocalTime.GetAsLocalizedTime("", false); + SetButtonLabels(); + } +@@ -800,14 +794,6 @@ void CGUIDialogPVRTimerSettings::SetDateFromIndex(CDateTime& datetime, int date) + datetime.GetMinute(), datetime.GetSecond()); + } + +-void CGUIDialogPVRTimerSettings::SetTimeFromSystemTime(CDateTime& datetime, +- const KODI::TIME::SystemTime& time) +-{ +- const CDateTime newTime(time); +- datetime.SetDateTime(datetime.GetYear(), datetime.GetMonth(), datetime.GetDay(), +- newTime.GetHour(), newTime.GetMinute(), newTime.GetSecond()); +-} +- + void CGUIDialogPVRTimerSettings::InitializeTypesList() + { + m_typeEntries.clear(); +diff --git a/xbmc/pvr/dialogs/GUIDialogPVRTimerSettings.h b/xbmc/pvr/dialogs/GUIDialogPVRTimerSettings.h +index d3e9e3eadf..d419e4a722 100644 +--- a/xbmc/pvr/dialogs/GUIDialogPVRTimerSettings.h ++++ b/xbmc/pvr/dialogs/GUIDialogPVRTimerSettings.h +@@ -59,7 +59,6 @@ private: + + static int GetDateAsIndex(const CDateTime& datetime); + static void SetDateFromIndex(CDateTime& datetime, int date); +- static void SetTimeFromSystemTime(CDateTime& datetime, const KODI::TIME::SystemTime& time); + + static int GetWeekdaysFromSetting(const std::shared_ptr<const CSetting>& setting); + +diff --git a/xbmc/pvr/windows/GUIWindowPVRGuide.cpp b/xbmc/pvr/windows/GUIWindowPVRGuide.cpp +index f4c247f910..d85e7bf493 100644 +--- a/xbmc/pvr/windows/GUIWindowPVRGuide.cpp ++++ b/xbmc/pvr/windows/GUIWindowPVRGuide.cpp +@@ -800,13 +800,12 @@ bool CGUIWindowPVRGuideBase::OpenDateSelectionDialog() + { + bool bReturn = false; + +- KODI::TIME::SystemTime date; + CGUIEPGGridContainer* epgGridContainer = GetGridControl(); +- epgGridContainer->GetSelectedDate().GetAsSystemTime(date); ++ CDateTime datetime = epgGridContainer->GetSelectedDate(); + +- if (CGUIDialogNumeric::ShowAndGetDate(date, g_localizeStrings.Get(19288))) /* Go to date */ ++ if (CGUIDialogNumeric::ShowAndGetDate(datetime, g_localizeStrings.Get(19288))) /* Go to date */ + { +- epgGridContainer->GoToDate(CDateTime(date)); ++ epgGridContainer->GoToDate(datetime); + bReturn = true; + } + +diff --git a/xbmc/settings/windows/GUIControlSettings.cpp b/xbmc/settings/windows/GUIControlSettings.cpp +index fcbf1fa908..6c9eb3ea68 100644 +--- a/xbmc/settings/windows/GUIControlSettings.cpp ++++ b/xbmc/settings/windows/GUIControlSettings.cpp +@@ -989,21 +989,19 @@ bool CGUIControlButtonSetting::OnClick() + std::shared_ptr<CSettingDate> settingDate = + std::static_pointer_cast<CSettingDate>(m_pSetting); + +- KODI::TIME::SystemTime systemdate; +- settingDate->GetDate().GetAsSystemTime(systemdate); +- if (CGUIDialogNumeric::ShowAndGetDate(systemdate, Localize(buttonControl->GetHeading()))) +- SetValid(settingDate->SetDate(CDateTime(systemdate))); ++ CDateTime datetime = settingDate->GetDate(); ++ if (CGUIDialogNumeric::ShowAndGetDate(datetime, Localize(buttonControl->GetHeading()))) ++ SetValid(settingDate->SetDate(datetime)); + } + else if (controlFormat == "time") + { + std::shared_ptr<CSettingTime> settingTime = + std::static_pointer_cast<CSettingTime>(m_pSetting); + +- KODI::TIME::SystemTime systemtime; +- settingTime->GetTime().GetAsSystemTime(systemtime); ++ CDateTime datetime = settingTime->GetTime(); + +- if (CGUIDialogNumeric::ShowAndGetTime(systemtime, Localize(buttonControl->GetHeading()))) +- SetValid(settingTime->SetTime(CDateTime(systemtime))); ++ if (CGUIDialogNumeric::ShowAndGetTime(datetime, Localize(buttonControl->GetHeading()))) ++ SetValid(settingTime->SetTime(datetime)); + } + else if (controlFormat == "action") + { +diff --git a/xbmc/test/TestDateTime.cpp b/xbmc/test/TestDateTime.cpp +index a553bd1887..a8e61e9785 100644 +--- a/xbmc/test/TestDateTime.cpp ++++ b/xbmc/test/TestDateTime.cpp +@@ -36,17 +36,16 @@ TEST_F(TestDateTime, DateTimeOperators) + EXPECT_FALSE(dateTime1 == dateTime2); + } + +-TEST_F(TestDateTime, SystemTimeOperators) ++TEST_F(TestDateTime, TimePointOperators) + { + CDateTime dateTime1(1991, 5, 14, 12, 34, 56); + CDateTime dateTime2(1991, 5, 14, 12, 34, 57); + +- KODI::TIME::SystemTime systemTime; +- dateTime2.GetAsSystemTime(systemTime); ++ auto tp = dateTime2.GetAsTimePoint(); + +- EXPECT_TRUE(dateTime1 < systemTime); +- EXPECT_FALSE(dateTime1 > systemTime); +- EXPECT_FALSE(dateTime1 == systemTime); ++ EXPECT_TRUE(dateTime1 < tp); ++ EXPECT_FALSE(dateTime1 > tp); ++ EXPECT_FALSE(dateTime1 == tp); + } + + TEST_F(TestDateTime, TimeTOperators) +@@ -529,15 +528,14 @@ TEST_F(TestDateTime, GetAsLocalized) + EXPECT_EQ(dateTime2.GetAsLocalizedTime(TIME_FORMAT(256)), "5"); + } + +-TEST_F(TestDateTime, GetAsSystemTime) ++TEST_F(TestDateTime, GetAsTimePoint) + { + CDateTime dateTime; + dateTime.SetDateTime(1991, 05, 14, 12, 34, 56); + +- KODI::TIME::SystemTime systemTime; +- dateTime.GetAsSystemTime(systemTime); ++ auto tp = dateTime.GetAsTimePoint(); + +- EXPECT_TRUE(dateTime == systemTime); ++ EXPECT_TRUE(dateTime == tp); + } + + TEST_F(TestDateTime, GetAsTime) +diff --git a/xbmc/utils/Archive.cpp b/xbmc/utils/Archive.cpp +index 4f69929a42..0275c057f9 100644 +--- a/xbmc/utils/Archive.cpp ++++ b/xbmc/utils/Archive.cpp +@@ -152,9 +152,9 @@ CArchive& CArchive::operator<<(const std::wstring& wstr) + return streamout(wstr.data(), size * sizeof(wchar_t)); + } + +-CArchive& CArchive::operator<<(const KODI::TIME::SystemTime& time) ++CArchive& CArchive::operator<<(const std::chrono::system_clock::time_point& time) + { +- return streamout(&time, sizeof(KODI::TIME::SystemTime)); ++ return streamout(&time, sizeof(std::chrono::system_clock::time_point)); + } + + CArchive& CArchive::operator<<(IArchivable& obj) +@@ -265,9 +265,9 @@ CArchive& CArchive::operator>>(std::wstring& wstr) + return *this; + } + +-CArchive& CArchive::operator>>(KODI::TIME::SystemTime& time) ++CArchive& CArchive::operator>>(std::chrono::system_clock::time_point& time) + { +- return streamin(&time, sizeof(KODI::TIME::SystemTime)); ++ return streamin(&time, sizeof(std::chrono::system_clock::time_point)); + } + + CArchive& CArchive::operator>>(IArchivable& obj) +diff --git a/xbmc/utils/Archive.h b/xbmc/utils/Archive.h +index a1af0c3cf8..86a2bebc23 100644 +--- a/xbmc/utils/Archive.h ++++ b/xbmc/utils/Archive.h +@@ -57,7 +57,7 @@ public: + CArchive& operator<<(char c); + CArchive& operator<<(const std::string &str); + CArchive& operator<<(const std::wstring& wstr); +- CArchive& operator<<(const KODI::TIME::SystemTime& time); ++ CArchive& operator<<(const std::chrono::system_clock::time_point& time); + CArchive& operator<<(IArchivable& obj); + CArchive& operator<<(const CVariant& variant); + CArchive& operator<<(const std::vector<std::string>& strArray); +@@ -126,7 +126,7 @@ public: + + CArchive& operator>>(std::string &str); + CArchive& operator>>(std::wstring& wstr); +- CArchive& operator>>(KODI::TIME::SystemTime& time); ++ CArchive& operator>>(std::chrono::system_clock::time_point& time); + CArchive& operator>>(IArchivable& obj); + CArchive& operator>>(CVariant& variant); + CArchive& operator>>(std::vector<std::string>& strArray); +diff --git a/xbmc/utils/RssManager.cpp b/xbmc/utils/RssManager.cpp +index b8d350cac5..5e77dd7c13 100644 +--- a/xbmc/utils/RssManager.cpp ++++ b/xbmc/utils/RssManager.cpp +@@ -142,7 +142,7 @@ bool CRssManager::Load() + //! What about the xml encoding? + std::string strUrl = pFeed->FirstChild()->ValueStr(); + set.url.push_back(strUrl); +- set.interval.push_back(iInterval); ++ set.interval.push_back(std::chrono::minutes(iInterval)); + } + pFeed = pFeed->NextSiblingElement("feed"); + } +diff --git a/xbmc/utils/RssManager.h b/xbmc/utils/RssManager.h +index 2b807d739f..59ac506307 100644 +--- a/xbmc/utils/RssManager.h ++++ b/xbmc/utils/RssManager.h +@@ -22,7 +22,7 @@ class IRssObserver; + typedef struct + { + bool rtl; +- std::vector<int> interval; ++ std::vector<std::chrono::nanoseconds> interval; + std::vector<std::string> url; + } RssSet; + typedef std::map<int, RssSet> RssUrls; +diff --git a/xbmc/utils/RssReader.cpp b/xbmc/utils/RssReader.cpp +index 0b227b63d3..f9f1e4a845 100644 +--- a/xbmc/utils/RssReader.cpp ++++ b/xbmc/utils/RssReader.cpp +@@ -51,11 +51,14 @@ CRssReader::~CRssReader() + if (m_pObserver) + m_pObserver->OnFeedRelease(); + StopThread(); +- for (unsigned int i = 0; i < m_vecTimeStamps.size(); i++) +- delete m_vecTimeStamps[i]; ++ m_vecTimeStamps.clear(); + } + +-void CRssReader::Create(IRssObserver* aObserver, const std::vector<std::string>& aUrls, const std::vector<int> ×, int spacesBetweenFeeds, bool rtl) ++void CRssReader::Create(IRssObserver* aObserver, ++ const std::vector<std::string>& aUrls, ++ const std::vector<std::chrono::nanoseconds>& times, ++ int spacesBetweenFeeds, ++ bool rtl) + { + std::unique_lock<CCriticalSection> lock(m_critical); + +@@ -73,9 +76,7 @@ void CRssReader::Create(IRssObserver* aObserver, const std::vector<std::string>& + for (unsigned int i = 0; i < m_vecUpdateTimes.size(); ++i) + { + AddToQueue(i); +- KODI::TIME::SystemTime* time = new KODI::TIME::SystemTime; +- KODI::TIME::GetLocalTime(time); +- m_vecTimeStamps.push_back(time); ++ m_vecTimeStamps.push_back(std::chrono::system_clock::now().time_since_epoch()); + } + } + +@@ -395,18 +396,14 @@ void CRssReader::UpdateObserver() + + void CRssReader::CheckForUpdates() + { +- KODI::TIME::SystemTime time; +- KODI::TIME::GetLocalTime(&time); +- + for (unsigned int i = 0;i < m_vecUpdateTimes.size(); ++i ) + { +- if (m_requestRefresh || ((time.day * 24 * 60) + (time.hour * 60) + time.minute) - +- ((m_vecTimeStamps[i]->day * 24 * 60) + +- (m_vecTimeStamps[i]->hour * 60) + m_vecTimeStamps[i]->minute) > +- m_vecUpdateTimes[i]) ++ if (m_requestRefresh || ++ (std::chrono::system_clock::now().time_since_epoch() - m_vecTimeStamps[i] > ++ m_vecUpdateTimes[i])) + { + CLog::Log(LOGDEBUG, "Updating RSS"); +- KODI::TIME::GetLocalTime(m_vecTimeStamps[i]); ++ m_vecTimeStamps[i] = std::chrono::system_clock::now().time_since_epoch(); + AddToQueue(i); + } + } +diff --git a/xbmc/utils/RssReader.h b/xbmc/utils/RssReader.h +index ae9d2f73ca..43c6bde609 100644 +--- a/xbmc/utils/RssReader.h ++++ b/xbmc/utils/RssReader.h +@@ -28,7 +28,11 @@ public: + CRssReader(); + ~CRssReader() override; + +- void Create(IRssObserver* aObserver, const std::vector<std::string>& aUrl, const std::vector<int>& times, int spacesBetweenFeeds, bool rtl); ++ void Create(IRssObserver* aObserver, ++ const std::vector<std::string>& aUrl, ++ const std::vector<std::chrono::nanoseconds>& times, ++ int spacesBetweenFeeds, ++ bool rtl); + bool Parse(const std::string& data, int iFeed, const std::string& charset); + void getFeed(vecText &text); + void AddTag(const std::string &addTag); +@@ -52,8 +56,8 @@ private: + + std::vector<std::wstring> m_strFeed; + std::vector<std::wstring> m_strColors; +- std::vector<KODI::TIME::SystemTime*> m_vecTimeStamps; +- std::vector<int> m_vecUpdateTimes; ++ std::vector<std::chrono::nanoseconds> m_vecTimeStamps; ++ std::vector<std::chrono::nanoseconds> m_vecUpdateTimes; + int m_spacesBetweenFeeds; + CXBMCTinyXML m_xml; + std::list<std::string> m_tagSet; +diff --git a/xbmc/utils/XTimeUtils.h b/xbmc/utils/XTimeUtils.h +index 91cda40305..9d3b0e86a3 100644 +--- a/xbmc/utils/XTimeUtils.h ++++ b/xbmc/utils/XTimeUtils.h +@@ -27,42 +27,6 @@ namespace KODI + { + namespace TIME + { +-struct SystemTime +-{ +- unsigned short year; +- unsigned short month; +- unsigned short dayOfWeek; +- unsigned short day; +- unsigned short hour; +- unsigned short minute; +- unsigned short second; +- unsigned short milliseconds; +-}; +- +-struct TimeZoneInformation +-{ +- long bias; +- std::string standardName; +- SystemTime standardDate; +- long standardBias; +- std::string daylightName; +- SystemTime daylightDate; +- long daylightBias; +-}; +- +-constexpr int KODI_TIME_ZONE_ID_INVALID{-1}; +-constexpr int KODI_TIME_ZONE_ID_UNKNOWN{0}; +-constexpr int KODI_TIME_ZONE_ID_STANDARD{1}; +-constexpr int KODI_TIME_ZONE_ID_DAYLIGHT{2}; +- +-struct FileTime +-{ +- unsigned int lowDateTime; +- unsigned int highDateTime; +-}; +- +-void GetLocalTime(SystemTime* systemTime); +-uint32_t GetTimeZoneInformation(TimeZoneInformation* timeZoneInformation); + + template<typename Rep, typename Period> + void Sleep(std::chrono::duration<Rep, Period> duration) +@@ -76,13 +40,5 @@ void Sleep(std::chrono::duration<Rep, Period> duration) + std::this_thread::sleep_for(duration); + } + +-int FileTimeToLocalFileTime(const FileTime* fileTime, FileTime* localFileTime); +-int SystemTimeToFileTime(const SystemTime* systemTime, FileTime* fileTime); +-long CompareFileTime(const FileTime* fileTime1, const FileTime* fileTime2); +-int FileTimeToSystemTime(const FileTime* fileTime, SystemTime* systemTime); +-int LocalFileTimeToFileTime(const FileTime* LocalFileTime, FileTime* fileTime); +- +-int FileTimeToTimeT(const FileTime* localFileTime, time_t* pTimeT); +-int TimeTToFileTime(time_t timeT, FileTime* localFileTime); + } // namespace TIME + } // namespace KODI +diff --git a/xbmc/utils/test/TestArchive.cpp b/xbmc/utils/test/TestArchive.cpp +index 90628ea2ed..b9ab780cf9 100644 +--- a/xbmc/utils/test/TestArchive.cpp ++++ b/xbmc/utils/test/TestArchive.cpp +@@ -220,22 +220,22 @@ TEST_F(TestArchive, StringArchive) + EXPECT_STREQ(string_ref.c_str(), string_var.c_str()); + } + +-TEST_F(TestArchive, SystemTimeArchive) ++TEST_F(TestArchive, TimePointArchive) + { + ASSERT_NE(nullptr, file); +- KODI::TIME::SystemTime SystemTime_ref = {1, 2, 3, 4, 5, 6, 7, 8}; +- KODI::TIME::SystemTime SystemTime_var = {0, 0, 0, 0, 0, 0, 0, 0}; ++ std::chrono::system_clock::time_point tp_ref = std::chrono::system_clock::now(); ++ std::chrono::system_clock::time_point tp_var; + + CArchive arstore(file, CArchive::store); +- arstore << SystemTime_ref; ++ arstore << tp_ref; + arstore.Close(); + + ASSERT_EQ(0, file->Seek(0, SEEK_SET)); + CArchive arload(file, CArchive::load); +- arload >> SystemTime_var; ++ arload >> tp_var; + arload.Close(); + +- EXPECT_TRUE(!memcmp(&SystemTime_ref, &SystemTime_var, sizeof(KODI::TIME::SystemTime))); ++ EXPECT_TRUE(!memcmp(&tp_ref, &tp_var, sizeof(std::chrono::system_clock::time_point))); + } + + TEST_F(TestArchive, CVariantArchive) +@@ -335,8 +335,8 @@ TEST_F(TestArchive, MultiTypeArchive) + char char_ref = 'A', char_var = '\0'; + std::string string_ref = "test string", string_var; + std::wstring wstring_ref = L"test wstring", wstring_var; +- KODI::TIME::SystemTime SystemTime_ref = {1, 2, 3, 4, 5, 6, 7, 8}; +- KODI::TIME::SystemTime SystemTime_var = {0, 0, 0, 0, 0, 0, 0, 0}; ++ std::chrono::system_clock::time_point tp_ref = std::chrono::system_clock::now(); ++ std::chrono::system_clock::time_point tp_var; + CVariant CVariant_ref((int)1), CVariant_var; + std::vector<std::string> strArray_ref, strArray_var; + strArray_ref.emplace_back("test strArray_ref 0"); +@@ -362,7 +362,7 @@ TEST_F(TestArchive, MultiTypeArchive) + arstore << char_ref; + arstore << string_ref; + arstore << wstring_ref; +- arstore << SystemTime_ref; ++ arstore << tp_ref; + arstore << CVariant_ref; + arstore << strArray_ref; + arstore << iArray_ref; +@@ -382,7 +382,7 @@ TEST_F(TestArchive, MultiTypeArchive) + arload >> char_var; + arload >> string_var; + arload >> wstring_var; +- arload >> SystemTime_var; ++ arload >> tp_var; + arload >> CVariant_var; + arload >> strArray_var; + arload >> iArray_var; +@@ -398,7 +398,7 @@ TEST_F(TestArchive, MultiTypeArchive) + EXPECT_EQ(char_ref, char_var); + EXPECT_STREQ(string_ref.c_str(), string_var.c_str()); + EXPECT_STREQ(wstring_ref.c_str(), wstring_var.c_str()); +- EXPECT_TRUE(!memcmp(&SystemTime_ref, &SystemTime_var, sizeof(KODI::TIME::SystemTime))); ++ EXPECT_TRUE(!memcmp(&tp_ref, &tp_var, sizeof(std::chrono::system_clock::time_point))); + EXPECT_TRUE(CVariant_var.isInteger()); + EXPECT_STREQ("test strArray_ref 0", strArray_var.at(0).c_str()); + EXPECT_STREQ("test strArray_ref 1", strArray_var.at(1).c_str()); +diff --git a/xbmc/video/VideoInfoScanner.cpp b/xbmc/video/VideoInfoScanner.cpp +index 92fa5c191f..8d9cf6979d 100644 +--- a/xbmc/video/VideoInfoScanner.cpp ++++ b/xbmc/video/VideoInfoScanner.cpp +@@ -2005,8 +2005,8 @@ namespace VIDEO + else + { + digest.Update(&pItem->m_dwSize, sizeof(pItem->m_dwSize)); +- KODI::TIME::FileTime time = pItem->m_dateTime; +- digest.Update(&time, sizeof(KODI::TIME::FileTime)); ++ const auto time = pItem->m_dateTime.GetAsTimePoint().time_since_epoch().count(); ++ digest.Update(&time, sizeof(std::chrono::nanoseconds)); + } + if (pItem->IsVideo() && !pItem->IsPlayList() && !pItem->IsNFO()) + count++; +-- +2.43.0 + + +From 466178a3ca4239ff1c837f28ba84283777519990 Mon Sep 17 00:00:00 2001 +From: Vasyl Gello <vasek.gello@gmail.com> +Date: Wed, 21 Oct 2020 09:17:33 +0300 +Subject: [PATCH 07/19] TestDateTime: fix GetAsStringsWithBias and add Tzdata + tests + +The 'GetAsStringsWithBias' test logic assumed the timezone on +machine bullding Kodi is set to 'UTC'. This is not always the case, +plus hour value was declared with a typo. + +To address this, we compare outputs of two runs of date library, +and instead add a 'Tzdata' test case comparing local date and time +against computed values from different timezones: + +find /usr/share/zoneinfo/Etc/ -type f | sort -Vu | sed 's,^/usr/share/zoneinfo/,,' | while read TZ +do + TMSTR=$(LANG=C TZ="$TZ" date '+%Y-%m-%dT%H:%M:%S%Ez' -d "1991-05-14 12:34:56 UTC" | sed 's/[0-9][0-9]$/:&/') + echo " // LANG=C TZ=\"$TZ\" date '+%Y-%m-%dT%H:%M:%S%Ez' -d \"1991-05-14 12:34:56 UTC\" | sed 's/[0-9][0-9]$/:&/'" + echo " tps = date::floor<std::chrono::seconds>(dateTime.GetAsTimePoint());" + echo " zone = date::make_zoned(\"$TZ\", tps);" + echo " EXPECT_EQ(date::format(\"%FT%T%Ez\", zone), \"$TMSTR\") << \"tzdata information not valid for '$TZ'\";" + echo "" +done +--- + xbmc/test/TestDateTime.cpp | 168 ++++++++++++++++++++++++++++++++++++- + 1 file changed, 166 insertions(+), 2 deletions(-) + +diff --git a/xbmc/test/TestDateTime.cpp b/xbmc/test/TestDateTime.cpp +index a8e61e9785..0ff2bb443b 100644 +--- a/xbmc/test/TestDateTime.cpp ++++ b/xbmc/test/TestDateTime.cpp +@@ -11,6 +11,7 @@ + #include "guilib/LocalizeStrings.h" + + #include <array> ++#include <chrono> + #include <iostream> + + #define USE_OS_TZDB 0 +@@ -330,10 +331,11 @@ TEST_F(TestDateTime, GetAsStringsWithBias) + std::cout << dateTime.GetAsW3CDateTime(false) << std::endl; + std::cout << dateTime.GetAsW3CDateTime(true) << std::endl; + +- auto zone = date::make_zoned(date::current_zone(), dateTime.GetAsTimePoint()); ++ auto tps = date::floor<std::chrono::seconds>(dateTime.GetAsTimePoint()); ++ auto zone = date::make_zoned(date::current_zone(), tps); + + EXPECT_EQ(dateTime.GetAsRFC1123DateTime(), "Tue, 14 May 1991 12:34:56 GMT"); +- EXPECT_EQ(dateTime.GetAsW3CDateTime(false), "1991-05-14T05:34:56" + date::format("%Ez", zone)); ++ EXPECT_EQ(dateTime.GetAsW3CDateTime(false), date::format("%FT%T%Ez", zone)); + EXPECT_EQ(dateTime.GetAsW3CDateTime(true), "1991-05-14T12:34:56Z"); + } + +@@ -601,3 +603,165 @@ TEST_F(TestDateTime, Reset) + EXPECT_EQ(dateTime.GetMinute(), 0); + EXPECT_EQ(dateTime.GetSecond(), 0); + } ++ ++TEST_F(TestDateTime, Tzdata) ++{ ++ CDateTime dateTime; ++ dateTime.SetDateTime(1991, 05, 14, 12, 34, 56); ++ ++ // LANG=C TZ="Etc/GMT+1" date '+%Y-%m-%dT%H:%M:%S%Ez' -d "1991-05-14 12:34:56 UTC" | sed 's/[0-9][0-9]$/:&/' ++ auto tps = date::floor<std::chrono::seconds>(dateTime.GetAsTimePoint()); ++ auto zone = date::make_zoned("Etc/GMT+1", tps); ++ EXPECT_EQ(date::format("%FT%T%Ez", zone), "1991-05-14T11:34:56-01:00") ++ << "tzdata information not valid for 'Etc/GMT+1'"; ++ ++ // LANG=C TZ="Etc/GMT+2" date '+%Y-%m-%dT%H:%M:%S%Ez' -d "1991-05-14 12:34:56 UTC" | sed 's/[0-9][0-9]$/:&/' ++ tps = date::floor<std::chrono::seconds>(dateTime.GetAsTimePoint()); ++ zone = date::make_zoned("Etc/GMT+2", tps); ++ EXPECT_EQ(date::format("%FT%T%Ez", zone), "1991-05-14T10:34:56-02:00") ++ << "tzdata information not valid for 'Etc/GMT+2'"; ++ ++ // LANG=C TZ="Etc/GMT+3" date '+%Y-%m-%dT%H:%M:%S%Ez' -d "1991-05-14 12:34:56 UTC" | sed 's/[0-9][0-9]$/:&/' ++ tps = date::floor<std::chrono::seconds>(dateTime.GetAsTimePoint()); ++ zone = date::make_zoned("Etc/GMT+3", tps); ++ EXPECT_EQ(date::format("%FT%T%Ez", zone), "1991-05-14T09:34:56-03:00") ++ << "tzdata information not valid for 'Etc/GMT+3'"; ++ ++ // LANG=C TZ="Etc/GMT+4" date '+%Y-%m-%dT%H:%M:%S%Ez' -d "1991-05-14 12:34:56 UTC" | sed 's/[0-9][0-9]$/:&/' ++ tps = date::floor<std::chrono::seconds>(dateTime.GetAsTimePoint()); ++ zone = date::make_zoned("Etc/GMT+4", tps); ++ EXPECT_EQ(date::format("%FT%T%Ez", zone), "1991-05-14T08:34:56-04:00") ++ << "tzdata information not valid for 'Etc/GMT+4'"; ++ ++ // LANG=C TZ="Etc/GMT+5" date '+%Y-%m-%dT%H:%M:%S%Ez' -d "1991-05-14 12:34:56 UTC" | sed 's/[0-9][0-9]$/:&/' ++ tps = date::floor<std::chrono::seconds>(dateTime.GetAsTimePoint()); ++ zone = date::make_zoned("Etc/GMT+5", tps); ++ EXPECT_EQ(date::format("%FT%T%Ez", zone), "1991-05-14T07:34:56-05:00") ++ << "tzdata information not valid for 'Etc/GMT+5'"; ++ ++ // LANG=C TZ="Etc/GMT+6" date '+%Y-%m-%dT%H:%M:%S%Ez' -d "1991-05-14 12:34:56 UTC" | sed 's/[0-9][0-9]$/:&/' ++ tps = date::floor<std::chrono::seconds>(dateTime.GetAsTimePoint()); ++ zone = date::make_zoned("Etc/GMT+6", tps); ++ EXPECT_EQ(date::format("%FT%T%Ez", zone), "1991-05-14T06:34:56-06:00") ++ << "tzdata information not valid for 'Etc/GMT+6'"; ++ ++ // LANG=C TZ="Etc/GMT+7" date '+%Y-%m-%dT%H:%M:%S%Ez' -d "1991-05-14 12:34:56 UTC" | sed 's/[0-9][0-9]$/:&/' ++ tps = date::floor<std::chrono::seconds>(dateTime.GetAsTimePoint()); ++ zone = date::make_zoned("Etc/GMT+7", tps); ++ EXPECT_EQ(date::format("%FT%T%Ez", zone), "1991-05-14T05:34:56-07:00") ++ << "tzdata information not valid for 'Etc/GMT+7'"; ++ ++ // LANG=C TZ="Etc/GMT+8" date '+%Y-%m-%dT%H:%M:%S%Ez' -d "1991-05-14 12:34:56 UTC" | sed 's/[0-9][0-9]$/:&/' ++ tps = date::floor<std::chrono::seconds>(dateTime.GetAsTimePoint()); ++ zone = date::make_zoned("Etc/GMT+8", tps); ++ EXPECT_EQ(date::format("%FT%T%Ez", zone), "1991-05-14T04:34:56-08:00") ++ << "tzdata information not valid for 'Etc/GMT+8'"; ++ ++ // LANG=C TZ="Etc/GMT+9" date '+%Y-%m-%dT%H:%M:%S%Ez' -d "1991-05-14 12:34:56 UTC" | sed 's/[0-9][0-9]$/:&/' ++ tps = date::floor<std::chrono::seconds>(dateTime.GetAsTimePoint()); ++ zone = date::make_zoned("Etc/GMT+9", tps); ++ EXPECT_EQ(date::format("%FT%T%Ez", zone), "1991-05-14T03:34:56-09:00") ++ << "tzdata information not valid for 'Etc/GMT+9'"; ++ ++ // LANG=C TZ="Etc/GMT+10" date '+%Y-%m-%dT%H:%M:%S%Ez' -d "1991-05-14 12:34:56 UTC" | sed 's/[0-9][0-9]$/:&/' ++ tps = date::floor<std::chrono::seconds>(dateTime.GetAsTimePoint()); ++ zone = date::make_zoned("Etc/GMT+10", tps); ++ EXPECT_EQ(date::format("%FT%T%Ez", zone), "1991-05-14T02:34:56-10:00") ++ << "tzdata information not valid for 'Etc/GMT+10'"; ++ ++ // LANG=C TZ="Etc/GMT+11" date '+%Y-%m-%dT%H:%M:%S%Ez' -d "1991-05-14 12:34:56 UTC" | sed 's/[0-9][0-9]$/:&/' ++ tps = date::floor<std::chrono::seconds>(dateTime.GetAsTimePoint()); ++ zone = date::make_zoned("Etc/GMT+11", tps); ++ EXPECT_EQ(date::format("%FT%T%Ez", zone), "1991-05-14T01:34:56-11:00") ++ << "tzdata information not valid for 'Etc/GMT+11'"; ++ ++ // LANG=C TZ="Etc/GMT+12" date '+%Y-%m-%dT%H:%M:%S%Ez' -d "1991-05-14 12:34:56 UTC" | sed 's/[0-9][0-9]$/:&/' ++ tps = date::floor<std::chrono::seconds>(dateTime.GetAsTimePoint()); ++ zone = date::make_zoned("Etc/GMT+12", tps); ++ EXPECT_EQ(date::format("%FT%T%Ez", zone), "1991-05-14T00:34:56-12:00") ++ << "tzdata information not valid for 'Etc/GMT+12'"; ++ ++ // LANG=C TZ="Etc/GMT-1" date '+%Y-%m-%dT%H:%M:%S%Ez' -d "1991-05-14 12:34:56 UTC" | sed 's/[0-9][0-9]$/:&/' ++ tps = date::floor<std::chrono::seconds>(dateTime.GetAsTimePoint()); ++ zone = date::make_zoned("Etc/GMT-1", tps); ++ EXPECT_EQ(date::format("%FT%T%Ez", zone), "1991-05-14T13:34:56+01:00") ++ << "tzdata information not valid for 'Etc/GMT-1'"; ++ ++ // LANG=C TZ="Etc/GMT-2" date '+%Y-%m-%dT%H:%M:%S%Ez' -d "1991-05-14 12:34:56 UTC" | sed 's/[0-9][0-9]$/:&/' ++ tps = date::floor<std::chrono::seconds>(dateTime.GetAsTimePoint()); ++ zone = date::make_zoned("Etc/GMT-2", tps); ++ EXPECT_EQ(date::format("%FT%T%Ez", zone), "1991-05-14T14:34:56+02:00") ++ << "tzdata information not valid for 'Etc/GMT-2'"; ++ ++ // LANG=C TZ="Etc/GMT-3" date '+%Y-%m-%dT%H:%M:%S%Ez' -d "1991-05-14 12:34:56 UTC" | sed 's/[0-9][0-9]$/:&/' ++ tps = date::floor<std::chrono::seconds>(dateTime.GetAsTimePoint()); ++ zone = date::make_zoned("Etc/GMT-3", tps); ++ EXPECT_EQ(date::format("%FT%T%Ez", zone), "1991-05-14T15:34:56+03:00") ++ << "tzdata information not valid for 'Etc/GMT-3'"; ++ ++ // LANG=C TZ="Etc/GMT-4" date '+%Y-%m-%dT%H:%M:%S%Ez' -d "1991-05-14 12:34:56 UTC" | sed 's/[0-9][0-9]$/:&/' ++ tps = date::floor<std::chrono::seconds>(dateTime.GetAsTimePoint()); ++ zone = date::make_zoned("Etc/GMT-4", tps); ++ EXPECT_EQ(date::format("%FT%T%Ez", zone), "1991-05-14T16:34:56+04:00") ++ << "tzdata information not valid for 'Etc/GMT-4'"; ++ ++ // LANG=C TZ="Etc/GMT-5" date '+%Y-%m-%dT%H:%M:%S%Ez' -d "1991-05-14 12:34:56 UTC" | sed 's/[0-9][0-9]$/:&/' ++ tps = date::floor<std::chrono::seconds>(dateTime.GetAsTimePoint()); ++ zone = date::make_zoned("Etc/GMT-5", tps); ++ EXPECT_EQ(date::format("%FT%T%Ez", zone), "1991-05-14T17:34:56+05:00") ++ << "tzdata information not valid for 'Etc/GMT-5'"; ++ ++ // LANG=C TZ="Etc/GMT-6" date '+%Y-%m-%dT%H:%M:%S%Ez' -d "1991-05-14 12:34:56 UTC" | sed 's/[0-9][0-9]$/:&/' ++ tps = date::floor<std::chrono::seconds>(dateTime.GetAsTimePoint()); ++ zone = date::make_zoned("Etc/GMT-6", tps); ++ EXPECT_EQ(date::format("%FT%T%Ez", zone), "1991-05-14T18:34:56+06:00") ++ << "tzdata information not valid for 'Etc/GMT-6'"; ++ ++ // LANG=C TZ="Etc/GMT-7" date '+%Y-%m-%dT%H:%M:%S%Ez' -d "1991-05-14 12:34:56 UTC" | sed 's/[0-9][0-9]$/:&/' ++ tps = date::floor<std::chrono::seconds>(dateTime.GetAsTimePoint()); ++ zone = date::make_zoned("Etc/GMT-7", tps); ++ EXPECT_EQ(date::format("%FT%T%Ez", zone), "1991-05-14T19:34:56+07:00") ++ << "tzdata information not valid for 'Etc/GMT-7'"; ++ ++ // LANG=C TZ="Etc/GMT-8" date '+%Y-%m-%dT%H:%M:%S%Ez' -d "1991-05-14 12:34:56 UTC" | sed 's/[0-9][0-9]$/:&/' ++ tps = date::floor<std::chrono::seconds>(dateTime.GetAsTimePoint()); ++ zone = date::make_zoned("Etc/GMT-8", tps); ++ EXPECT_EQ(date::format("%FT%T%Ez", zone), "1991-05-14T20:34:56+08:00") ++ << "tzdata information not valid for 'Etc/GMT-8'"; ++ ++ // LANG=C TZ="Etc/GMT-9" date '+%Y-%m-%dT%H:%M:%S%Ez' -d "1991-05-14 12:34:56 UTC" | sed 's/[0-9][0-9]$/:&/' ++ tps = date::floor<std::chrono::seconds>(dateTime.GetAsTimePoint()); ++ zone = date::make_zoned("Etc/GMT-9", tps); ++ EXPECT_EQ(date::format("%FT%T%Ez", zone), "1991-05-14T21:34:56+09:00") ++ << "tzdata information not valid for 'Etc/GMT-9'"; ++ ++ // LANG=C TZ="Etc/GMT-10" date '+%Y-%m-%dT%H:%M:%S%Ez' -d "1991-05-14 12:34:56 UTC" | sed 's/[0-9][0-9]$/:&/' ++ tps = date::floor<std::chrono::seconds>(dateTime.GetAsTimePoint()); ++ zone = date::make_zoned("Etc/GMT-10", tps); ++ EXPECT_EQ(date::format("%FT%T%Ez", zone), "1991-05-14T22:34:56+10:00") ++ << "tzdata information not valid for 'Etc/GMT-10'"; ++ ++ // LANG=C TZ="Etc/GMT-11" date '+%Y-%m-%dT%H:%M:%S%Ez' -d "1991-05-14 12:34:56 UTC" | sed 's/[0-9][0-9]$/:&/' ++ tps = date::floor<std::chrono::seconds>(dateTime.GetAsTimePoint()); ++ zone = date::make_zoned("Etc/GMT-11", tps); ++ EXPECT_EQ(date::format("%FT%T%Ez", zone), "1991-05-14T23:34:56+11:00") ++ << "tzdata information not valid for 'Etc/GMT-11'"; ++ ++ // LANG=C TZ="Etc/GMT-12" date '+%Y-%m-%dT%H:%M:%S%Ez' -d "1991-05-14 12:34:56 UTC" | sed 's/[0-9][0-9]$/:&/' ++ tps = date::floor<std::chrono::seconds>(dateTime.GetAsTimePoint()); ++ zone = date::make_zoned("Etc/GMT-12", tps); ++ EXPECT_EQ(date::format("%FT%T%Ez", zone), "1991-05-15T00:34:56+12:00") ++ << "tzdata information not valid for 'Etc/GMT-12'"; ++ ++ // LANG=C TZ="Etc/GMT-13" date '+%Y-%m-%dT%H:%M:%S%Ez' -d "1991-05-14 12:34:56 UTC" | sed 's/[0-9][0-9]$/:&/' ++ tps = date::floor<std::chrono::seconds>(dateTime.GetAsTimePoint()); ++ zone = date::make_zoned("Etc/GMT-13", tps); ++ EXPECT_EQ(date::format("%FT%T%Ez", zone), "1991-05-15T01:34:56+13:00") ++ << "tzdata information not valid for 'Etc/GMT-13'"; ++ ++ // LANG=C TZ="Etc/GMT-14" date '+%Y-%m-%dT%H:%M:%S%Ez' -d "1991-05-14 12:34:56 UTC" | sed 's/[0-9][0-9]$/:&/' ++ tps = date::floor<std::chrono::seconds>(dateTime.GetAsTimePoint()); ++ zone = date::make_zoned("Etc/GMT-14", tps); ++ EXPECT_EQ(date::format("%FT%T%Ez", zone), "1991-05-15T02:34:56+14:00") ++ << "tzdata information not valid for 'Etc/GMT-14'"; ++} +-- +2.43.0 + + +From 72720c4e84bbbb1d5859cd727b1068a74a8be3af Mon Sep 17 00:00:00 2001 +From: Vasyl Gello <vasek.gello@gmail.com> +Date: Tue, 3 Nov 2020 17:51:26 +0200 +Subject: [PATCH 08/19] Remove GetAsUTCDateTime and add GetAsLocalDateTime + +The 'm_time' now represents a UTC time-point, so 'GetAsUTCDateTime' +does nothing useful. Remove it fully, and add 'GetAsLocalDateTime' +function that we will use later to convert UTC (system) time to the +local time needed to get displayed in UI. + +Signed-off-by: Vasyl Gello <vasek.gello@gmail.com> +--- + xbmc/XBDateTime.cpp | 9 ++++++--- + xbmc/XBDateTime.h | 4 +++- + xbmc/network/WebServer.cpp | 6 +++--- + xbmc/pvr/epg/EpgContainer.cpp | 14 +++++++------- + xbmc/pvr/epg/EpgInfoTag.cpp | 4 ++-- + xbmc/pvr/guilib/PVRGUIActionsPowerManagement.cpp | 1 - + xbmc/pvr/timers/PVRTimerRuleMatcher.cpp | 2 +- + xbmc/pvr/timers/PVRTimers.cpp | 1 - + xbmc/test/TestDateTime.cpp | 16 ++++++++-------- + 9 files changed, 30 insertions(+), 27 deletions(-) + +diff --git a/xbmc/XBDateTime.cpp b/xbmc/XBDateTime.cpp +index d8187b71e6..afd2d8c6a5 100644 +--- a/xbmc/XBDateTime.cpp ++++ b/xbmc/XBDateTime.cpp +@@ -1210,10 +1210,13 @@ std::string CDateTime::GetAsLocalizedTime(TIME_FORMAT format, bool withSeconds / + return GetAsLocalizedTime("", false); + } + +-CDateTime CDateTime::GetAsUTCDateTime() const ++CDateTime CDateTime::GetAsLocalDateTime() const + { +- CDateTime time(m_time); +- return time; ++ auto zone = date::make_zoned(date::current_zone(), m_time); ++ ++ return CDateTime( ++ std::chrono::duration_cast<std::chrono::seconds>(zone.get_local_time().time_since_epoch()) ++ .count()); + } + + std::string CDateTime::GetAsRFC1123DateTime() const +diff --git a/xbmc/XBDateTime.h b/xbmc/XBDateTime.h +index 16d6217c8a..a810619566 100644 +--- a/xbmc/XBDateTime.h ++++ b/xbmc/XBDateTime.h +@@ -157,7 +157,9 @@ public: + void GetAsTm(tm& time) const; + std::chrono::system_clock::time_point GetAsTimePoint() const; + +- CDateTime GetAsUTCDateTime() const; ++ /*! \brief convert UTC datetime to local datetime ++ */ ++ CDateTime GetAsLocalDateTime() const; + std::string GetAsSaveString() const; + std::string GetAsDBDateTime() const; + std::string GetAsDBDate() const; +diff --git a/xbmc/network/WebServer.cpp b/xbmc/network/WebServer.cpp +index 0ee1696033..fc3583c16d 100644 +--- a/xbmc/network/WebServer.cpp ++++ b/xbmc/network/WebServer.cpp +@@ -222,7 +222,7 @@ MHD_RESULT CWebServer::HandlePartialRequest(struct MHD_Connection* connection, + CDateTime ifUnmodifiedSinceDate; + // handle If-Modified-Since (but only if the response is cacheable) + if (cacheable && ifModifiedSinceDate.SetFromRFC1123DateTime(ifModifiedSince) && +- lastModified.GetAsUTCDateTime() <= ifModifiedSinceDate) ++ lastModified <= ifModifiedSinceDate) + { + struct MHD_Response* response = create_response(0, nullptr, MHD_NO, MHD_NO); + if (response == nullptr) +@@ -235,7 +235,7 @@ MHD_RESULT CWebServer::HandlePartialRequest(struct MHD_Connection* connection, + } + // handle If-Unmodified-Since + else if (ifUnmodifiedSinceDate.SetFromRFC1123DateTime(ifUnmodifiedSince) && +- lastModified.GetAsUTCDateTime() > ifUnmodifiedSinceDate) ++ lastModified > ifUnmodifiedSinceDate) + return SendErrorResponse(request, MHD_HTTP_PRECONDITION_FAILED, request.method); + } + +@@ -504,7 +504,7 @@ bool CWebServer::IsRequestRanged(const HTTPRequest& request, const CDateTime& la + + // check if the last modification is newer than the If-Range date + // if so we have to server the whole file instead +- if (lastModified.GetAsUTCDateTime() > ifRangeDate) ++ if (lastModified > ifRangeDate) + ranges.Clear(); + } + } +diff --git a/xbmc/pvr/epg/EpgContainer.cpp b/xbmc/pvr/epg/EpgContainer.cpp +index d6f20153ef..38aa15809e 100644 +--- a/xbmc/pvr/epg/EpgContainer.cpp ++++ b/xbmc/pvr/epg/EpgContainer.cpp +@@ -335,7 +335,7 @@ void CPVREpgContainer::Process() + time_t iLastEpgCleanup = 0; + bool bUpdateEpg = true; + +- CDateTime::GetCurrentDateTime().GetAsUTCDateTime().GetAsTime(iNow); ++ CDateTime::GetUTCDateTime().GetAsTime(iNow); + { + std::unique_lock<CCriticalSection> lock(m_critSection); + bUpdateEpg = (iNow >= m_iNextEpgUpdate) && !m_bSuspended; +@@ -593,7 +593,7 @@ std::shared_ptr<CPVREpg> CPVREpgContainer::CreateChannelEpg(int iEpgId, const st + { + std::unique_lock<CCriticalSection> lock(m_critSection); + m_bPreventUpdates = false; +- CDateTime::GetCurrentDateTime().GetAsUTCDateTime().GetAsTime(m_iNextEpgUpdate); ++ CDateTime::GetUTCDateTime().GetAsTime(m_iNextEpgUpdate); + } + + m_events.Publish(PVREvent::EpgContainer); +@@ -613,7 +613,7 @@ bool CPVREpgContainer::RemoveOldEntries() + epgEntry.second->Cleanup(cleanupTime); + + std::unique_lock<CCriticalSection> lock(m_critSection); +- CDateTime::GetCurrentDateTime().GetAsUTCDateTime().GetAsTime(m_iLastEpgCleanup); ++ CDateTime::GetUTCDateTime().GetAsTime(m_iLastEpgCleanup); + + return true; + } +@@ -787,7 +787,7 @@ bool CPVREpgContainer::UpdateEPG(bool bOnlyPending /* = false */) + { + /* the update has been interrupted. try again later */ + time_t iNow; +- CDateTime::GetCurrentDateTime().GetAsUTCDateTime().GetAsTime(iNow); ++ CDateTime::GetUTCDateTime().GetAsTime(iNow); + + std::unique_lock<CCriticalSection> lock(m_critSection); + m_iNextEpgUpdate = iNow + advancedSettings->m_iEpgRetryInterruptedUpdateInterval; +@@ -795,7 +795,7 @@ bool CPVREpgContainer::UpdateEPG(bool bOnlyPending /* = false */) + else + { + std::unique_lock<CCriticalSection> lock(m_critSection); +- CDateTime::GetCurrentDateTime().GetAsUTCDateTime().GetAsTime(m_iNextEpgUpdate); ++ CDateTime::GetUTCDateTime().GetAsTime(m_iNextEpgUpdate); + m_iNextEpgUpdate += advancedSettings->m_iEpgUpdateCheckInterval; + if (m_pendingUpdates == pendingUpdates) + m_pendingUpdates = 0; +@@ -852,7 +852,7 @@ bool CPVREpgContainer::CheckPlayingEvents() + m_critSection.unlock(); + + time_t iNow; +- CDateTime::GetCurrentDateTime().GetAsUTCDateTime().GetAsTime(iNow); ++ CDateTime::GetUTCDateTime().GetAsTime(iNow); + if (iNow >= iNextEpgActiveTagCheck) + { + bFoundChanges = std::accumulate(epgs.cbegin(), epgs.cend(), bFoundChanges, +@@ -860,7 +860,7 @@ bool CPVREpgContainer::CheckPlayingEvents() + return epgEntry.second->CheckPlayingEvent() ? true : found; + }); + +- CDateTime::GetCurrentDateTime().GetAsUTCDateTime().GetAsTime(iNextEpgActiveTagCheck); ++ CDateTime::GetUTCDateTime().GetAsTime(iNextEpgActiveTagCheck); + iNextEpgActiveTagCheck += CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_iEpgActiveTagCheckInterval; + + /* pvr tags always start on the full minute */ +diff --git a/xbmc/pvr/epg/EpgInfoTag.cpp b/xbmc/pvr/epg/EpgInfoTag.cpp +index 8b0930e5d2..70daa5033b 100644 +--- a/xbmc/pvr/epg/EpgInfoTag.cpp ++++ b/xbmc/pvr/epg/EpgInfoTag.cpp +@@ -233,7 +233,7 @@ float CPVREpgInfoTag::ProgressPercentage() const + float fReturn = 0.0f; + + time_t currentTime, startTime, endTime; +- CDateTime::GetCurrentDateTime().GetAsUTCDateTime().GetAsTime(currentTime); ++ CDateTime::GetUTCDateTime().GetAsTime(currentTime); + m_startTime.GetAsTime(startTime); + m_endTime.GetAsTime(endTime); + int iDuration = endTime - startTime > 0 ? endTime - startTime : 3600; +@@ -249,7 +249,7 @@ float CPVREpgInfoTag::ProgressPercentage() const + int CPVREpgInfoTag::Progress() const + { + time_t currentTime, startTime; +- CDateTime::GetCurrentDateTime().GetAsUTCDateTime().GetAsTime(currentTime); ++ CDateTime::GetUTCDateTime().GetAsTime(currentTime); + m_startTime.GetAsTime(startTime); + int iDuration = currentTime - startTime; + +diff --git a/xbmc/pvr/guilib/PVRGUIActionsPowerManagement.cpp b/xbmc/pvr/guilib/PVRGUIActionsPowerManagement.cpp +index 1a0a99a7a2..5e27ea69c5 100644 +--- a/xbmc/pvr/guilib/PVRGUIActionsPowerManagement.cpp ++++ b/xbmc/pvr/guilib/PVRGUIActionsPowerManagement.cpp +@@ -92,7 +92,6 @@ bool CPVRGUIActionsPowerManagement::CanSystemPowerdown(bool bAskUser /*= true*/) + CDateTime dailywakeuptime; + dailywakeuptime.SetFromDBTime( + m_settings.GetStringValue(CSettings::SETTING_PVRPOWERMANAGEMENT_DAILYWAKEUPTIME)); +- dailywakeuptime = dailywakeuptime.GetAsUTCDateTime(); + + const CDateTimeSpan diff(dailywakeuptime - now); + int mins = diff.GetSecondsTotal() / 60; +diff --git a/xbmc/pvr/timers/PVRTimerRuleMatcher.cpp b/xbmc/pvr/timers/PVRTimerRuleMatcher.cpp +index 9178e85ec2..b34688bdce 100644 +--- a/xbmc/pvr/timers/PVRTimerRuleMatcher.cpp ++++ b/xbmc/pvr/timers/PVRTimerRuleMatcher.cpp +@@ -66,7 +66,7 @@ CDateTime CPVRTimerRuleMatcher::GetNextTimerStart() const + } + } + +- return nextStart.GetAsUTCDateTime(); ++ return nextStart; + } + + bool CPVRTimerRuleMatcher::Matches(const std::shared_ptr<CPVREpgInfoTag>& epgTag) const +diff --git a/xbmc/pvr/timers/PVRTimers.cpp b/xbmc/pvr/timers/PVRTimers.cpp +index 760bb192f7..5fe64ec7e4 100644 +--- a/xbmc/pvr/timers/PVRTimers.cpp ++++ b/xbmc/pvr/timers/PVRTimers.cpp +@@ -1274,7 +1274,6 @@ CDateTime CPVRTimers::GetNextEventTime() const + CDateTime dailywakeuptime; + dailywakeuptime.SetFromDBTime( + m_settings.GetStringValue(CSettings::SETTING_PVRPOWERMANAGEMENT_DAILYWAKEUPTIME)); +- dailywakeuptime = dailywakeuptime.GetAsUTCDateTime(); + + dailywakeuptime.SetDateTime(now.GetYear(), now.GetMonth(), now.GetDay(), + dailywakeuptime.GetHour(), dailywakeuptime.GetMinute(), +diff --git a/xbmc/test/TestDateTime.cpp b/xbmc/test/TestDateTime.cpp +index 0ff2bb443b..4c55fafe06 100644 +--- a/xbmc/test/TestDateTime.cpp ++++ b/xbmc/test/TestDateTime.cpp +@@ -573,20 +573,20 @@ TEST_F(TestDateTime, GetAsTm) + } + } + +-TEST_F(TestDateTime, GetAsUTCDateTime) ++TEST_F(TestDateTime, GetAsLocalDateTime) + { + CDateTime dateTime1; + dateTime1.SetDateTime(1991, 05, 14, 12, 34, 56); + + CDateTime dateTime2; +- dateTime2 = dateTime1.GetAsUTCDateTime(); ++ dateTime2 = dateTime1.GetAsLocalDateTime(); + +- EXPECT_EQ(dateTime2.GetYear(), 1991); +- EXPECT_EQ(dateTime2.GetMonth(), 5); +- EXPECT_EQ(dateTime2.GetDay(), 14); +- EXPECT_EQ(dateTime2.GetHour(), 12); +- EXPECT_EQ(dateTime2.GetMinute(), 34); +- EXPECT_EQ(dateTime2.GetSecond(), 56); ++ auto zoned_time = date::make_zoned(date::current_zone(), dateTime1.GetAsTimePoint()); ++ auto time = zoned_time.get_local_time().time_since_epoch(); ++ ++ CDateTime cmpTime(std::chrono::duration_cast<std::chrono::seconds>(time).count()); ++ ++ EXPECT_TRUE(dateTime1 == cmpTime); + } + + TEST_F(TestDateTime, Reset) +-- +2.43.0 + + +From d394f4639fd434647a393b99956d22417c68401b Mon Sep 17 00:00:00 2001 +From: Vasyl Gello <vasek.gello@gmail.com> +Date: Tue, 3 Nov 2020 22:49:09 +0200 +Subject: [PATCH 09/19] Compensate the representation change + +... from local time by default to UTC time by default. + +Namely, 'CDateTime::SetFromUTCDateTime' converted the UTC time +to local time in the implementation of CDateTime before +'std::chrono'. Now this conversion has gone, and to avoid +displaying PVR times in UTC, 'GetAsLocalDateTime' is added +where necessary. + +Signed-off-by: Vasyl Gello <vasek.gello@gmail.com> +--- + xbmc/pvr/epg/EpgInfoTag.cpp | 8 ++------ + xbmc/pvr/guilib/GUIEPGGridContainerModel.cpp | 4 ++-- + xbmc/pvr/guilib/guiinfo/PVRGUITimesInfo.cpp | 2 +- + xbmc/pvr/recordings/PVRRecording.cpp | 4 ++-- + 4 files changed, 7 insertions(+), 11 deletions(-) + +diff --git a/xbmc/pvr/epg/EpgInfoTag.cpp b/xbmc/pvr/epg/EpgInfoTag.cpp +index 70daa5033b..3f104aa032 100644 +--- a/xbmc/pvr/epg/EpgInfoTag.cpp ++++ b/xbmc/pvr/epg/EpgInfoTag.cpp +@@ -293,9 +293,7 @@ CDateTime CPVREpgInfoTag::StartAsUTC() const + + CDateTime CPVREpgInfoTag::StartAsLocalTime() const + { +- CDateTime retVal; +- retVal.SetFromUTCDateTime(m_startTime); +- return retVal; ++ return m_startTime.GetAsLocalDateTime(); + } + + CDateTime CPVREpgInfoTag::EndAsUTC() const +@@ -305,9 +303,7 @@ CDateTime CPVREpgInfoTag::EndAsUTC() const + + CDateTime CPVREpgInfoTag::EndAsLocalTime() const + { +- CDateTime retVal; +- retVal.SetFromUTCDateTime(m_endTime); +- return retVal; ++ return m_endTime.GetAsLocalDateTime(); + } + + void CPVREpgInfoTag::SetEndFromUTC(const CDateTime& end) +diff --git a/xbmc/pvr/guilib/GUIEPGGridContainerModel.cpp b/xbmc/pvr/guilib/GUIEPGGridContainerModel.cpp +index e8fac010ca..ef7a715f70 100644 +--- a/xbmc/pvr/guilib/GUIEPGGridContainerModel.cpp ++++ b/xbmc/pvr/guilib/GUIEPGGridContainerModel.cpp +@@ -121,9 +121,9 @@ void CGUIEPGGridContainerModel::Initialize(const std::unique_ptr<CFileItemList>& + //////////////////////////////////////////////////////////////////////// + // Create ruler items + CDateTime ruler; +- ruler.SetFromUTCDateTime(m_gridStart); ++ ruler.SetFromUTCDateTime(m_gridStart.GetAsLocalDateTime()); + CDateTime rulerEnd; +- rulerEnd.SetFromUTCDateTime(m_gridEnd); ++ rulerEnd.SetFromUTCDateTime(m_gridEnd.GetAsLocalDateTime()); + CFileItemPtr rulerItem(new CFileItem(ruler.GetAsLocalizedDate(true))); + rulerItem->SetProperty("DateLabel", true); + m_rulerItems.emplace_back(rulerItem); +diff --git a/xbmc/pvr/guilib/guiinfo/PVRGUITimesInfo.cpp b/xbmc/pvr/guilib/guiinfo/PVRGUITimesInfo.cpp +index e5dfdb9ea0..3d2cf09b3f 100644 +--- a/xbmc/pvr/guilib/guiinfo/PVRGUITimesInfo.cpp ++++ b/xbmc/pvr/guilib/guiinfo/PVRGUITimesInfo.cpp +@@ -239,7 +239,7 @@ std::string CPVRGUITimesInfo::TimeToTimeString(time_t datetime, TIME_FORMAT form + { + CDateTime time; + time.SetFromUTCDateTime(datetime); +- return time.GetAsLocalizedTime(format, withSeconds); ++ return time.GetAsLocalDateTime().GetAsLocalizedTime(format, withSeconds); + } + + std::string CPVRGUITimesInfo::GetTimeshiftStartTime(TIME_FORMAT format) const +diff --git a/xbmc/pvr/recordings/PVRRecording.cpp b/xbmc/pvr/recordings/PVRRecording.cpp +index a2e1cbd131..8e047b8d52 100644 +--- a/xbmc/pvr/recordings/PVRRecording.cpp ++++ b/xbmc/pvr/recordings/PVRRecording.cpp +@@ -524,7 +524,7 @@ void CPVRRecording::UpdatePath() + const CDateTime& CPVRRecording::RecordingTimeAsLocalTime() const + { + static CDateTime tmp; +- tmp.SetFromUTCDateTime(m_recordingTime); ++ tmp.SetFromUTCDateTime(m_recordingTime.GetAsLocalDateTime()); + + return tmp; + } +@@ -538,7 +538,7 @@ CDateTime CPVRRecording::EndTimeAsUTC() const + CDateTime CPVRRecording::EndTimeAsLocalTime() const + { + CDateTime ret; +- ret.SetFromUTCDateTime(EndTimeAsUTC()); ++ ret.SetFromUTCDateTime(EndTimeAsUTC().GetAsLocalDateTime()); + return ret; + } + +-- +2.43.0 + + +From e9cbb86184358f6eb3235a76936fedbf38ab4d97 Mon Sep 17 00:00:00 2001 +From: Vasyl Gello <vasek.gello@gmail.com> +Date: Wed, 4 Nov 2020 11:13:15 +0200 +Subject: [PATCH 10/19] Get rid of {Set,}FromUTCDateTime + + * The 'const CDateTime& CPVRRecording::RecordingTimeAsLocalTime() const' + method needs 'static' CDateTime instance set explicitly. This manifested + in Debian Bug #980038 : the return value of function is explicitly nulled + out causing immediate crash when using any PVR addon manipulating PVR + recordings. + +Signed-off-by: Vasyl Gello <vasek.gello@gmail.com> +--- + xbmc/FileItem.cpp | 2 +- + xbmc/XBDateTime.cpp | 33 ++----------------- + xbmc/XBDateTime.h | 4 --- + .../savestates/SavestateDatabase.cpp | 2 +- + xbmc/pvr/dialogs/GUIDialogPVRGuideSearch.cpp | 8 ++--- + xbmc/pvr/epg/Epg.cpp | 2 +- + xbmc/pvr/guilib/GUIEPGGridContainerModel.cpp | 4 +-- + xbmc/pvr/guilib/guiinfo/PVRGUIInfo.cpp | 3 +- + xbmc/pvr/guilib/guiinfo/PVRGUITimesInfo.cpp | 3 +- + xbmc/pvr/recordings/PVRRecording.cpp | 8 ++--- + xbmc/test/TestDateTime.cpp | 26 --------------- + 11 files changed, 14 insertions(+), 81 deletions(-) + +diff --git a/xbmc/FileItem.cpp b/xbmc/FileItem.cpp +index 2eb5eb072c..8f14467aff 100644 +--- a/xbmc/FileItem.cpp ++++ b/xbmc/FileItem.cpp +@@ -199,7 +199,7 @@ CFileItem::CFileItem(const std::shared_ptr<PVR::CPVREpgSearchFilter>& filter) + + const CDateTime lastExec = filter->GetLastExecutedDateTime(); + if (lastExec.IsValid()) +- m_dateTime.SetFromUTCDateTime(lastExec); ++ m_dateTime = lastExec; + + SetArt("icon", "DefaultPVRSearch.png"); + +diff --git a/xbmc/XBDateTime.cpp b/xbmc/XBDateTime.cpp +index afd2d8c6a5..86168ecc13 100644 +--- a/xbmc/XBDateTime.cpp ++++ b/xbmc/XBDateTime.cpp +@@ -613,19 +613,6 @@ std::string CDateTime::GetAsSaveString() const + return date::format("%Y%m%d_%H%M%S", sp); + } + +-bool CDateTime::SetFromUTCDateTime(const CDateTime &dateTime) +-{ +- m_time = dateTime.m_time; +- m_state = valid; +- return true; +-} +- +-bool CDateTime::SetFromUTCDateTime(const time_t &dateTime) +-{ +- CDateTime tmp(dateTime); +- return SetFromUTCDateTime(tmp); +-} +- + bool CDateTime::SetFromW3CDate(const std::string &dateTime) + { + std::string date; +@@ -700,10 +687,8 @@ bool CDateTime::SetFromW3CDateTime(const std::string &dateTime, bool ignoreTimez + + if (!ignoreTimezone && !zone.empty()) + { +- // check if the timezone is UTC +- if (StringUtils::StartsWith(zone, "Z")) +- return SetFromUTCDateTime(tmpDateTime); +- else ++ // check if the timezone is not UTC ++ if (!StringUtils::StartsWith(zone, "Z")) + { + // retrieve the timezone offset (ignoring the + or -) + CDateTimeSpan zoneSpan; zoneSpan.SetFromTimeString(zone.substr(1)); +@@ -853,20 +838,6 @@ CDateTime CDateTime::FromW3CDateTime(const std::string &date, bool ignoreTimezon + return dt; + } + +-CDateTime CDateTime::FromUTCDateTime(const CDateTime &dateTime) +-{ +- CDateTime dt; +- dt.SetFromUTCDateTime(dateTime); +- return dt; +-} +- +-CDateTime CDateTime::FromUTCDateTime(const time_t &dateTime) +-{ +- CDateTime dt; +- dt.SetFromUTCDateTime(dateTime); +- return dt; +-} +- + CDateTime CDateTime::FromRFC1123DateTime(const std::string &dateTime) + { + CDateTime dt; +diff --git a/xbmc/XBDateTime.h b/xbmc/XBDateTime.h +index a810619566..ff2d758caa 100644 +--- a/xbmc/XBDateTime.h ++++ b/xbmc/XBDateTime.h +@@ -78,8 +78,6 @@ public: + static CDateTime FromDBTime(const std::string &time); + static CDateTime FromW3CDate(const std::string &date); + static CDateTime FromW3CDateTime(const std::string &date, bool ignoreTimezone = false); +- static CDateTime FromUTCDateTime(const CDateTime &dateTime); +- static CDateTime FromUTCDateTime(const time_t &dateTime); + static CDateTime FromRFC1123DateTime(const std::string &dateTime); + + const CDateTime& operator =(const time_t& right); +@@ -144,8 +142,6 @@ public: + bool SetFromDBTime(const std::string &time); + bool SetFromW3CDate(const std::string &date); + bool SetFromW3CDateTime(const std::string &date, bool ignoreTimezone = false); +- bool SetFromUTCDateTime(const CDateTime &dateTime); +- bool SetFromUTCDateTime(const time_t &dateTime); + bool SetFromRFC1123DateTime(const std::string &dateTime); + + /*! \brief set from a database datetime format YYYY-MM-DD HH:MM:SS +diff --git a/xbmc/cores/RetroPlayer/savestates/SavestateDatabase.cpp b/xbmc/cores/RetroPlayer/savestates/SavestateDatabase.cpp +index 2611f25ad8..2a44e07596 100644 +--- a/xbmc/cores/RetroPlayer/savestates/SavestateDatabase.cpp ++++ b/xbmc/cores/RetroPlayer/savestates/SavestateDatabase.cpp +@@ -149,7 +149,7 @@ void CSavestateDatabase::GetSavestateItem(const ISavestate& savestate, + const std::string& savestatePath, + CFileItem& item) + { +- CDateTime dateUTC = CDateTime::FromUTCDateTime(savestate.Created()); ++ CDateTime dateUTC = savestate.Created(); + + std::string label; + std::string label2; +diff --git a/xbmc/pvr/dialogs/GUIDialogPVRGuideSearch.cpp b/xbmc/pvr/dialogs/GUIDialogPVRGuideSearch.cpp +index 4cf7f2f0c4..13b826c1b1 100644 +--- a/xbmc/pvr/dialogs/GUIDialogPVRGuideSearch.cpp ++++ b/xbmc/pvr/dialogs/GUIDialogPVRGuideSearch.cpp +@@ -252,7 +252,7 @@ CDateTime CGUIDialogPVRGuideSearch::ReadDateTime(const std::string& strDate, con + sscanf(strTime.c_str(), "%d:%d", &iHours, &iMinutes); + dateTime.SetFromDBDate(strDate); + dateTime.SetDateTime(dateTime.GetYear(), dateTime.GetMonth(), dateTime.GetDay(), iHours, iMinutes, 0); +- return dateTime.GetAsUTCDateTime(); ++ return dateTime; + } + + bool CGUIDialogPVRGuideSearch::IsRadioSelected(int controlID) +@@ -358,10 +358,8 @@ void CGUIDialogPVRGuideSearch::Update() + if (!m_endDateTime.IsValid()) + m_endDateTime = m_startDateTime + CDateTimeSpan(10, 0, 0, 0); // default to start + 10 days + +- CDateTime startLocal; +- startLocal.SetFromUTCDateTime(m_startDateTime); +- CDateTime endLocal; +- endLocal.SetFromUTCDateTime(m_endDateTime); ++ CDateTime startLocal = m_startDateTime; ++ CDateTime endLocal = m_endDateTime; + + SET_CONTROL_LABEL2(CONTROL_EDIT_START_TIME, startLocal.GetAsLocalizedTime("", false)); + { +diff --git a/xbmc/pvr/epg/Epg.cpp b/xbmc/pvr/epg/Epg.cpp +index 1112b2ff89..bb0dbf967b 100644 +--- a/xbmc/pvr/epg/Epg.cpp ++++ b/xbmc/pvr/epg/Epg.cpp +@@ -264,7 +264,7 @@ bool CPVREpg::Update(time_t start, + + if (!m_lastScanTime.IsValid()) + { +- m_lastScanTime.SetFromUTCDateTime(time_t(0)); ++ m_lastScanTime = time_t(0); + m_bUpdateLastScanTime = true; + } + } +diff --git a/xbmc/pvr/guilib/GUIEPGGridContainerModel.cpp b/xbmc/pvr/guilib/GUIEPGGridContainerModel.cpp +index ef7a715f70..3e89c06d6e 100644 +--- a/xbmc/pvr/guilib/GUIEPGGridContainerModel.cpp ++++ b/xbmc/pvr/guilib/GUIEPGGridContainerModel.cpp +@@ -121,9 +121,9 @@ void CGUIEPGGridContainerModel::Initialize(const std::unique_ptr<CFileItemList>& + //////////////////////////////////////////////////////////////////////// + // Create ruler items + CDateTime ruler; +- ruler.SetFromUTCDateTime(m_gridStart.GetAsLocalDateTime()); ++ ruler = m_gridStart.GetAsLocalDateTime(); + CDateTime rulerEnd; +- rulerEnd.SetFromUTCDateTime(m_gridEnd.GetAsLocalDateTime()); ++ rulerEnd = m_gridEnd.GetAsLocalDateTime(); + CFileItemPtr rulerItem(new CFileItem(ruler.GetAsLocalizedDate(true))); + rulerItem->SetProperty("DateLabel", true); + m_rulerItems.emplace_back(rulerItem); +diff --git a/xbmc/pvr/guilib/guiinfo/PVRGUIInfo.cpp b/xbmc/pvr/guilib/guiinfo/PVRGUIInfo.cpp +index 9cffb9a934..80c25118b0 100644 +--- a/xbmc/pvr/guilib/guiinfo/PVRGUIInfo.cpp ++++ b/xbmc/pvr/guilib/guiinfo/PVRGUIInfo.cpp +@@ -568,8 +568,7 @@ bool CPVRGUIInfo::GetListItemAndPlayerLabel(const CFileItem* item, + { + case LISTITEM_DATE: + { +- CDateTime lastExecLocal; +- lastExecLocal.SetFromUTCDateTime(filter->GetLastExecutedDateTime()); ++ CDateTime lastExecLocal = filter->GetLastExecutedDateTime(); + strValue = GetAsLocalizedDateTimeString(lastExecLocal); + if (strValue.empty()) + strValue = g_localizeStrings.Get(10006); // "N/A" +diff --git a/xbmc/pvr/guilib/guiinfo/PVRGUITimesInfo.cpp b/xbmc/pvr/guilib/guiinfo/PVRGUITimesInfo.cpp +index 3d2cf09b3f..c5b44b840c 100644 +--- a/xbmc/pvr/guilib/guiinfo/PVRGUITimesInfo.cpp ++++ b/xbmc/pvr/guilib/guiinfo/PVRGUITimesInfo.cpp +@@ -237,8 +237,7 @@ void CPVRGUITimesInfo::Update() + + std::string CPVRGUITimesInfo::TimeToTimeString(time_t datetime, TIME_FORMAT format, bool withSeconds) + { +- CDateTime time; +- time.SetFromUTCDateTime(datetime); ++ CDateTime time(datetime); + return time.GetAsLocalDateTime().GetAsLocalizedTime(format, withSeconds); + } + +diff --git a/xbmc/pvr/recordings/PVRRecording.cpp b/xbmc/pvr/recordings/PVRRecording.cpp +index 8e047b8d52..5a82c7b1dc 100644 +--- a/xbmc/pvr/recordings/PVRRecording.cpp ++++ b/xbmc/pvr/recordings/PVRRecording.cpp +@@ -523,9 +523,7 @@ void CPVRRecording::UpdatePath() + + const CDateTime& CPVRRecording::RecordingTimeAsLocalTime() const + { +- static CDateTime tmp; +- tmp.SetFromUTCDateTime(m_recordingTime.GetAsLocalDateTime()); +- ++ static CDateTime tmp = m_recordingTime.GetAsLocalDateTime(); + return tmp; + } + +@@ -537,9 +535,7 @@ CDateTime CPVRRecording::EndTimeAsUTC() const + + CDateTime CPVRRecording::EndTimeAsLocalTime() const + { +- CDateTime ret; +- ret.SetFromUTCDateTime(EndTimeAsUTC().GetAsLocalDateTime()); +- return ret; ++ return EndTimeAsUTC().GetAsLocalDateTime(); + } + + bool CPVRRecording::WillBeExpiredWithNewLifetime(int iLifetime) const +diff --git a/xbmc/test/TestDateTime.cpp b/xbmc/test/TestDateTime.cpp +index 4c55fafe06..ea910a8763 100644 +--- a/xbmc/test/TestDateTime.cpp ++++ b/xbmc/test/TestDateTime.cpp +@@ -240,32 +240,6 @@ TEST_F(TestDateTime, SetFromW3CDateTime) + EXPECT_EQ(dateTime2.GetSecond(), 30); + } + +-TEST_F(TestDateTime, SetFromUTCDateTime) +-{ +- CDateTime dateTime1; +- dateTime1.SetFromDBDateTime("1991-05-14 12:34:56"); +- +- CDateTime dateTime2; +- EXPECT_TRUE(dateTime2.SetFromUTCDateTime(dateTime1)); +- EXPECT_EQ(dateTime2.GetYear(), 1991); +- EXPECT_EQ(dateTime2.GetMonth(), 5); +- EXPECT_EQ(dateTime2.GetDay(), 14); +- EXPECT_EQ(dateTime2.GetHour(), 12); +- EXPECT_EQ(dateTime2.GetMinute(), 34); +- EXPECT_EQ(dateTime2.GetSecond(), 56); +- +- const time_t time = 674224496; +- +- CDateTime dateTime3; +- EXPECT_TRUE(dateTime3.SetFromUTCDateTime(time)); +- EXPECT_EQ(dateTime3.GetYear(), 1991); +- EXPECT_EQ(dateTime3.GetMonth(), 5); +- EXPECT_EQ(dateTime3.GetDay(), 14); +- EXPECT_EQ(dateTime3.GetHour(), 12); +- EXPECT_EQ(dateTime3.GetMinute(), 34); +- EXPECT_EQ(dateTime3.GetSecond(), 56); +-} +- + TEST_F(TestDateTime, SetFromRFC1123DateTime) + { + std::string dateTime1("Mon, 21 Oct 2018 12:16:24 GMT"); +-- +2.43.0 + + +From 9583d0b325df73f5e29b4c901715b9a6bc389295 Mon Sep 17 00:00:00 2001 +From: Vasyl Gello <vasek.gello@gmail.com> +Date: Thu, 13 May 2021 11:18:31 +0000 +Subject: [PATCH 11/19] Fix one-time assignment of PVR recording times + +Fixes pvr.dvbviewer#49 +Closes: #984682 + +Signed-off-by: Vasyl Gello <vasek.gello@gmail.com> +--- + xbmc/pvr/recordings/PVRRecording.cpp | 5 ++--- + xbmc/pvr/recordings/PVRRecording.h | 2 +- + 2 files changed, 3 insertions(+), 4 deletions(-) + +diff --git a/xbmc/pvr/recordings/PVRRecording.cpp b/xbmc/pvr/recordings/PVRRecording.cpp +index 5a82c7b1dc..39eea88740 100644 +--- a/xbmc/pvr/recordings/PVRRecording.cpp ++++ b/xbmc/pvr/recordings/PVRRecording.cpp +@@ -521,10 +521,9 @@ void CPVRRecording::UpdatePath() + m_strChannelName, m_recordingTime, m_strRecordingId); + } + +-const CDateTime& CPVRRecording::RecordingTimeAsLocalTime() const ++CDateTime CPVRRecording::RecordingTimeAsLocalTime() const + { +- static CDateTime tmp = m_recordingTime.GetAsLocalDateTime(); +- return tmp; ++ return m_recordingTime.GetAsLocalDateTime(); + } + + CDateTime CPVRRecording::EndTimeAsUTC() const +diff --git a/xbmc/pvr/recordings/PVRRecording.h b/xbmc/pvr/recordings/PVRRecording.h +index bdd8378225..dd125ad1ea 100644 +--- a/xbmc/pvr/recordings/PVRRecording.h ++++ b/xbmc/pvr/recordings/PVRRecording.h +@@ -188,7 +188,7 @@ public: + * @brief Retrieve the recording start as local time + * @return the recording start time + */ +- const CDateTime& RecordingTimeAsLocalTime() const; ++ CDateTime RecordingTimeAsLocalTime() const; + + /*! + * @brief Retrieve the recording end as UTC time +-- +2.43.0 + + +From 732620e37163d653ec75bbefd2a58293e2303420 Mon Sep 17 00:00:00 2001 +From: Vasyl Gello <vasek.gello@gmail.com> +Date: Wed, 21 Dec 2022 18:27:24 +0000 +Subject: [PATCH 12/19] Move date includes to separate header + +Signed-off-by: Vasyl Gello <vasek.gello@gmail.com> +--- + xbmc/ServiceManager.cpp | 5 +---- + xbmc/XBDateTime.cpp | 8 +------- + xbmc/addons/TimeZoneResource.cpp | 5 +++-- + xbmc/application/Application.cpp | 5 +---- + xbmc/platform/posix/PosixTimezone.cpp | 21 +++++++++------------ + xbmc/test/TestDateTime.cpp | 5 +---- + xbmc/utils/CMakeLists.txt | 1 + + xbmc/utils/DateLib.h | 24 ++++++++++++++++++++++++ + 8 files changed, 41 insertions(+), 33 deletions(-) + create mode 100644 xbmc/utils/DateLib.h + +diff --git a/xbmc/ServiceManager.cpp b/xbmc/ServiceManager.cpp +index 83070489e3..b95091e993 100644 +--- a/xbmc/ServiceManager.cpp ++++ b/xbmc/ServiceManager.cpp +@@ -45,15 +45,12 @@ + #include "storage/DetectDVDType.h" + #endif + #include "storage/MediaManager.h" ++#include "utils/DateLib.h" + #include "utils/FileExtensionProvider.h" + #include "utils/URIUtils.h" + #include "utils/log.h" + #include "weather/WeatherManager.h" + +-#define USE_OS_TZDB 0 +-#define HAS_REMOTE_API 0 +-#include <date/tz.h> +- + using namespace KODI; + + CServiceManager::CServiceManager() = default; +diff --git a/xbmc/XBDateTime.cpp b/xbmc/XBDateTime.cpp +index 86168ecc13..12ae853c43 100644 +--- a/xbmc/XBDateTime.cpp ++++ b/xbmc/XBDateTime.cpp +@@ -11,18 +11,12 @@ + #include "LangInfo.h" + #include "guilib/LocalizeStrings.h" + #include "utils/Archive.h" ++#include "utils/DateLib.h" + #include "utils/StringUtils.h" +-#include "utils/XTimeUtils.h" + #include "utils/log.h" + + #include <cstdlib> + +-#define USE_OS_TZDB 0 +-#define HAS_REMOTE_API 0 +-#include <date/date.h> +-#include <date/iso_week.h> +-#include <date/tz.h> +- + static const char *MONTH_NAMES[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; + + CDateTimeSpan::CDateTimeSpan(const CDateTimeSpan& span) +diff --git a/xbmc/addons/TimeZoneResource.cpp b/xbmc/addons/TimeZoneResource.cpp +index 94246c9e18..6dfba75e89 100644 +--- a/xbmc/addons/TimeZoneResource.cpp ++++ b/xbmc/addons/TimeZoneResource.cpp +@@ -8,11 +8,10 @@ + #include "TimeZoneResource.h" + + #include "addons/addoninfo/AddonType.h" ++#include "utils/DateLib.h" + #include "utils/StringUtils.h" + #include "utils/URIUtils.h" + +-#include <date/tz.h> +- + namespace ADDON + { + +@@ -33,7 +32,9 @@ bool CTimeZoneResource::IsInUse() const + + void CTimeZoneResource::OnPostInstall(bool update, bool modal) + { ++#if defined(DATE_INTERNAL_TZDATA) + date::reload_tzdb(); ++#endif + } + + } // namespace ADDON +diff --git a/xbmc/application/Application.cpp b/xbmc/application/Application.cpp +index 3227933296..6aa584e5c9 100644 +--- a/xbmc/application/Application.cpp ++++ b/xbmc/application/Application.cpp +@@ -100,6 +100,7 @@ + #include "speech/ISpeechRecognition.h" + #include "threads/SingleLock.h" + #include "utils/CPUInfo.h" ++#include "utils/DateLib.h" + #include "utils/FileExtensionProvider.h" + #include "utils/RegExp.h" + #include "utils/SystemInfo.h" +@@ -196,12 +197,8 @@ + #include "pictures/GUIWindowSlideShow.h" + #include "utils/CharsetConverter.h" + +-#define USE_OS_TZDB 0 +-#define HAS_REMOTE_API 0 + #include <mutex> + +-#include <date/tz.h> +- + using namespace ADDON; + using namespace XFILE; + #ifdef HAS_DVD_DRIVE +diff --git a/xbmc/platform/posix/PosixTimezone.cpp b/xbmc/platform/posix/PosixTimezone.cpp +index 7f0b8d4096..fa9ea1dde9 100644 +--- a/xbmc/platform/posix/PosixTimezone.cpp ++++ b/xbmc/platform/posix/PosixTimezone.cpp +@@ -9,25 +9,22 @@ + #ifdef TARGET_ANDROID + #include "platform/android/bionic_supplement/bionic_supplement.h" + #endif +-#include "PlatformDefs.h" + #include "PosixTimezone.h" +-#include "utils/SystemInfo.h" +- + #include "ServiceBroker.h" +-#include "utils/StringUtils.h" + #include "XBDateTime.h" +-#include "settings/lib/Setting.h" +-#include "settings/lib/SettingDefinitions.h" ++#include "filesystem/File.h" ++#include "platform/MessagePrinter.h" + #include "settings/Settings.h" + #include "settings/SettingsComponent.h" +-#include <stdlib.h> ++#include "settings/lib/Setting.h" ++#include "settings/lib/SettingDefinitions.h" ++#include "utils/DateLib.h" ++#include "utils/StringUtils.h" ++#include "utils/SystemInfo.h" + +-#define USE_OS_TZDB 0 +-#define HAS_REMOTE_API 0 +-#include "filesystem/File.h" +-#include "platform/MessagePrinter.h" ++#include <stdlib.h> + +-#include <date/tz.h> ++#include "PlatformDefs.h" + + void CPosixTimezone::Init() + { +diff --git a/xbmc/test/TestDateTime.cpp b/xbmc/test/TestDateTime.cpp +index ea910a8763..de3f75e5e4 100644 +--- a/xbmc/test/TestDateTime.cpp ++++ b/xbmc/test/TestDateTime.cpp +@@ -9,15 +9,12 @@ + #include "LangInfo.h" + #include "XBDateTime.h" + #include "guilib/LocalizeStrings.h" ++#include "utils/DateLib.h" + + #include <array> + #include <chrono> + #include <iostream> + +-#define USE_OS_TZDB 0 +-#define HAS_REMOTE_API 0 +-#include <date/date.h> +-#include <date/tz.h> + #include <gtest/gtest.h> + + class TestDateTime : public testing::Test +diff --git a/xbmc/utils/CMakeLists.txt b/xbmc/utils/CMakeLists.txt +index 8e1328999f..bb4851c0ce 100644 +--- a/xbmc/utils/CMakeLists.txt ++++ b/xbmc/utils/CMakeLists.txt +@@ -97,6 +97,7 @@ set(HEADERS ActorProtocol.h + Crc32.h + CSSUtils.h + DatabaseUtils.h ++ DateLib.h + Digest.h + DiscsUtils.h + EndianSwap.h +diff --git a/xbmc/utils/DateLib.h b/xbmc/utils/DateLib.h +new file mode 100644 +index 0000000000..e39650aa03 +--- /dev/null ++++ b/xbmc/utils/DateLib.h +@@ -0,0 +1,24 @@ ++/* ++ * Copyright (C) 2005-2022 Team Kodi ++ * This file is part of Kodi - https://kodi.tv ++ * ++ * SPDX-License-Identifier: GPL-2.0-or-later ++ * See LICENSES/README.md for more information. ++ */ ++ ++#if defined(DATE_INTERNAL_TZDATA) ++#define USE_OS_TZDB 0 ++#else ++#define USE_OS_TZDB 1 ++#endif ++ ++#if defined(DATE_HAS_STRINGVIEW) ++#define HAS_STRING_VIEW 1 ++#else ++#define HAS_STRING_VIEW 0 ++#endif ++ ++#define HAS_REMOTE_API 0 ++#include <date/date.h> ++#include <date/iso_week.h> ++#include <date/tz.h> +-- +2.43.0 + + +From 46f92320cc18c3975bddb5dbe8e0d5b66a0b64c6 Mon Sep 17 00:00:00 2001 +From: Vasyl Gello <vasek.gello@gmail.com> +Date: Fri, 14 May 2021 09:39:55 +0000 +Subject: [PATCH 13/19] CDateTime: Use 'long double' as underlying storage type + for time points + +This should fix the GUI date dialog issue: + +https://github.com/xbmc/xbmc/pull/18727#issuecomment-840805031 +https://github.com/xbmc/xbmc/pull/18727#issuecomment-840805031 + +Signed-off-by: Vasyl Gello <vasek.gello@gmail.com> +--- + xbmc/XBDateTime.cpp | 18 +++++++++--------- + xbmc/XBDateTime.h | 20 ++++++++++---------- + xbmc/dialogs/GUIDialogNumeric.cpp | 3 +-- + xbmc/utils/Archive.cpp | 8 ++++---- + xbmc/utils/Archive.h | 6 ++++-- + xbmc/utils/XTimeUtils.h | 3 +++ + xbmc/utils/test/TestArchive.cpp | 12 ++++++------ + 7 files changed, 37 insertions(+), 33 deletions(-) + +diff --git a/xbmc/XBDateTime.cpp b/xbmc/XBDateTime.cpp +index 12ae853c43..fdcc27c9af 100644 +--- a/xbmc/XBDateTime.cpp ++++ b/xbmc/XBDateTime.cpp +@@ -176,7 +176,7 @@ CDateTime::CDateTime(const time_t& time) + SetValid(true); + } + +-CDateTime::CDateTime(const std::chrono::system_clock::time_point& time) ++CDateTime::CDateTime(const KODI::TIME::time_point& time) + { + m_time = time; + SetValid(true); +@@ -223,7 +223,7 @@ const CDateTime& CDateTime::operator =(const tm& right) + return *this; + } + +-const CDateTime& CDateTime::operator=(const std::chrono::system_clock::time_point& right) ++const CDateTime& CDateTime::operator=(const KODI::TIME::time_point& right) + { + m_time = right; + SetValid(true); +@@ -321,32 +321,32 @@ bool CDateTime::operator !=(const tm& right) const + return !operator ==(right); + } + +-bool CDateTime::operator>(const std::chrono::system_clock::time_point& right) const ++bool CDateTime::operator>(const KODI::TIME::time_point& right) const + { + return m_time > right; + } + +-bool CDateTime::operator>=(const std::chrono::system_clock::time_point& right) const ++bool CDateTime::operator>=(const KODI::TIME::time_point& right) const + { + return operator>(right) || operator==(right); + } + +-bool CDateTime::operator<(const std::chrono::system_clock::time_point& right) const ++bool CDateTime::operator<(const KODI::TIME::time_point& right) const + { + return m_time < right; + } + +-bool CDateTime::operator<=(const std::chrono::system_clock::time_point& right) const ++bool CDateTime::operator<=(const KODI::TIME::time_point& right) const + { + return operator<(right) || operator==(right); + } + +-bool CDateTime::operator==(const std::chrono::system_clock::time_point& right) const ++bool CDateTime::operator==(const KODI::TIME::time_point& right) const + { + return m_time == right; + } + +-bool CDateTime::operator!=(const std::chrono::system_clock::time_point& right) const ++bool CDateTime::operator!=(const KODI::TIME::time_point& right) const + { + return !operator==(right); + } +@@ -577,7 +577,7 @@ void CDateTime::GetAsTm(tm& time) const + localtime_r(&t, &time); + } + +-std::chrono::system_clock::time_point CDateTime::GetAsTimePoint() const ++KODI::TIME::time_point CDateTime::GetAsTimePoint() const + { + return m_time; + } +diff --git a/xbmc/XBDateTime.h b/xbmc/XBDateTime.h +index ff2d758caa..b0a7f386d9 100644 +--- a/xbmc/XBDateTime.h ++++ b/xbmc/XBDateTime.h +@@ -65,7 +65,7 @@ public: + CDateTime& operator=(const CDateTime&) = default; + explicit CDateTime(const time_t& time); + explicit CDateTime(const tm& time); +- explicit CDateTime(const std::chrono::system_clock::time_point& time); ++ explicit CDateTime(const KODI::TIME::time_point& time); + CDateTime(int year, int month, int day, int hour, int minute, int second); + + static CDateTime GetCurrentDateTime(); +@@ -82,7 +82,7 @@ public: + + const CDateTime& operator =(const time_t& right); + const CDateTime& operator =(const tm& right); +- const CDateTime& operator=(const std::chrono::system_clock::time_point& right); ++ const CDateTime& operator=(const KODI::TIME::time_point& right); + + bool operator >(const CDateTime& right) const; + bool operator >=(const CDateTime& right) const; +@@ -105,12 +105,12 @@ public: + bool operator ==(const tm& right) const; + bool operator !=(const tm& right) const; + +- bool operator>(const std::chrono::system_clock::time_point& right) const; +- bool operator>=(const std::chrono::system_clock::time_point& right) const; +- bool operator<(const std::chrono::system_clock::time_point& right) const; +- bool operator<=(const std::chrono::system_clock::time_point& right) const; +- bool operator==(const std::chrono::system_clock::time_point& right) const; +- bool operator!=(const std::chrono::system_clock::time_point& right) const; ++ bool operator>(const KODI::TIME::time_point& right) const; ++ bool operator>=(const KODI::TIME::time_point& right) const; ++ bool operator<(const KODI::TIME::time_point& right) const; ++ bool operator<=(const KODI::TIME::time_point& right) const; ++ bool operator==(const KODI::TIME::time_point& right) const; ++ bool operator!=(const KODI::TIME::time_point& right) const; + + CDateTime operator +(const CDateTimeSpan& right) const; + CDateTime operator -(const CDateTimeSpan& right) const; +@@ -151,7 +151,7 @@ public: + + void GetAsTime(time_t& time) const; + void GetAsTm(tm& time) const; +- std::chrono::system_clock::time_point GetAsTimePoint() const; ++ KODI::TIME::time_point GetAsTimePoint() const; + + /*! \brief convert UTC datetime to local datetime + */ +@@ -173,7 +173,7 @@ public: + bool IsValid() const; + + private: +- std::chrono::system_clock::time_point m_time; ++ KODI::TIME::time_point m_time; + + typedef enum _STATE + { +diff --git a/xbmc/dialogs/GUIDialogNumeric.cpp b/xbmc/dialogs/GUIDialogNumeric.cpp +index bba219e44e..985fd05722 100644 +--- a/xbmc/dialogs/GUIDialogNumeric.cpp ++++ b/xbmc/dialogs/GUIDialogNumeric.cpp +@@ -498,8 +498,7 @@ bool CGUIDialogNumeric::ShowAndGetSeconds(std::string &timeString, const std::st + CGUIDialogNumeric *pDialog = CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogNumeric>(WINDOW_DIALOG_NUMERIC); + if (!pDialog) return false; + +- std::chrono::system_clock::time_point time{ +- std::chrono::seconds{StringUtils::TimeStringToSeconds(timeString)}}; ++ KODI::TIME::time_point time{std::chrono::seconds{StringUtils::TimeStringToSeconds(timeString)}}; + + CDateTime datetime(time); + +diff --git a/xbmc/utils/Archive.cpp b/xbmc/utils/Archive.cpp +index 0275c057f9..bb207c6ca5 100644 +--- a/xbmc/utils/Archive.cpp ++++ b/xbmc/utils/Archive.cpp +@@ -152,9 +152,9 @@ CArchive& CArchive::operator<<(const std::wstring& wstr) + return streamout(wstr.data(), size * sizeof(wchar_t)); + } + +-CArchive& CArchive::operator<<(const std::chrono::system_clock::time_point& time) ++CArchive& CArchive::operator<<(const KODI::TIME::time_point& time) + { +- return streamout(&time, sizeof(std::chrono::system_clock::time_point)); ++ return streamout(&time, sizeof(KODI::TIME::time_point)); + } + + CArchive& CArchive::operator<<(IArchivable& obj) +@@ -265,9 +265,9 @@ CArchive& CArchive::operator>>(std::wstring& wstr) + return *this; + } + +-CArchive& CArchive::operator>>(std::chrono::system_clock::time_point& time) ++CArchive& CArchive::operator>>(KODI::TIME::time_point& time) + { +- return streamin(&time, sizeof(std::chrono::system_clock::time_point)); ++ return streamin(&time, sizeof(KODI::TIME::time_point)); + } + + CArchive& CArchive::operator>>(IArchivable& obj) +diff --git a/xbmc/utils/Archive.h b/xbmc/utils/Archive.h +index 86a2bebc23..ece5f9ac9c 100644 +--- a/xbmc/utils/Archive.h ++++ b/xbmc/utils/Archive.h +@@ -8,6 +8,8 @@ + + #pragma once + ++#include "utils/XTimeUtils.h" ++ + #include <cstring> + #include <memory> + #include <string> +@@ -57,7 +59,7 @@ public: + CArchive& operator<<(char c); + CArchive& operator<<(const std::string &str); + CArchive& operator<<(const std::wstring& wstr); +- CArchive& operator<<(const std::chrono::system_clock::time_point& time); ++ CArchive& operator<<(const KODI::TIME::time_point& time); + CArchive& operator<<(IArchivable& obj); + CArchive& operator<<(const CVariant& variant); + CArchive& operator<<(const std::vector<std::string>& strArray); +@@ -126,7 +128,7 @@ public: + + CArchive& operator>>(std::string &str); + CArchive& operator>>(std::wstring& wstr); +- CArchive& operator>>(std::chrono::system_clock::time_point& time); ++ CArchive& operator>>(KODI::TIME::time_point& time); + CArchive& operator>>(IArchivable& obj); + CArchive& operator>>(CVariant& variant); + CArchive& operator>>(std::vector<std::string>& strArray); +diff --git a/xbmc/utils/XTimeUtils.h b/xbmc/utils/XTimeUtils.h +index 9d3b0e86a3..ed1b25fb74 100644 +--- a/xbmc/utils/XTimeUtils.h ++++ b/xbmc/utils/XTimeUtils.h +@@ -28,6 +28,9 @@ namespace KODI + namespace TIME + { + ++using time_point = std::chrono::time_point<std::chrono::system_clock, ++ std::chrono::duration<long double, std::nano>>; ++ + template<typename Rep, typename Period> + void Sleep(std::chrono::duration<Rep, Period> duration) + { +diff --git a/xbmc/utils/test/TestArchive.cpp b/xbmc/utils/test/TestArchive.cpp +index b9ab780cf9..de912eba21 100644 +--- a/xbmc/utils/test/TestArchive.cpp ++++ b/xbmc/utils/test/TestArchive.cpp +@@ -223,8 +223,8 @@ TEST_F(TestArchive, StringArchive) + TEST_F(TestArchive, TimePointArchive) + { + ASSERT_NE(nullptr, file); +- std::chrono::system_clock::time_point tp_ref = std::chrono::system_clock::now(); +- std::chrono::system_clock::time_point tp_var; ++ KODI::TIME::time_point tp_ref = std::chrono::system_clock::now(); ++ KODI::TIME::time_point tp_var; + + CArchive arstore(file, CArchive::store); + arstore << tp_ref; +@@ -235,7 +235,7 @@ TEST_F(TestArchive, TimePointArchive) + arload >> tp_var; + arload.Close(); + +- EXPECT_TRUE(!memcmp(&tp_ref, &tp_var, sizeof(std::chrono::system_clock::time_point))); ++ EXPECT_TRUE(!memcmp(&tp_ref, &tp_var, sizeof(KODI::TIME::time_point))); + } + + TEST_F(TestArchive, CVariantArchive) +@@ -335,8 +335,8 @@ TEST_F(TestArchive, MultiTypeArchive) + char char_ref = 'A', char_var = '\0'; + std::string string_ref = "test string", string_var; + std::wstring wstring_ref = L"test wstring", wstring_var; +- std::chrono::system_clock::time_point tp_ref = std::chrono::system_clock::now(); +- std::chrono::system_clock::time_point tp_var; ++ KODI::TIME::time_point tp_ref = std::chrono::system_clock::now(); ++ KODI::TIME::time_point tp_var; + CVariant CVariant_ref((int)1), CVariant_var; + std::vector<std::string> strArray_ref, strArray_var; + strArray_ref.emplace_back("test strArray_ref 0"); +@@ -398,7 +398,7 @@ TEST_F(TestArchive, MultiTypeArchive) + EXPECT_EQ(char_ref, char_var); + EXPECT_STREQ(string_ref.c_str(), string_var.c_str()); + EXPECT_STREQ(wstring_ref.c_str(), wstring_var.c_str()); +- EXPECT_TRUE(!memcmp(&tp_ref, &tp_var, sizeof(std::chrono::system_clock::time_point))); ++ EXPECT_TRUE(!memcmp(&tp_ref, &tp_var, sizeof(KODI::TIME::time_point))); + EXPECT_TRUE(CVariant_var.isInteger()); + EXPECT_STREQ("test strArray_ref 0", strArray_var.at(0).c_str()); + EXPECT_STREQ("test strArray_ref 1", strArray_var.at(1).c_str()); +-- +2.43.0 + + +From c2f4add32ebf1c3a965f1a88af0d49afcdf9e847 Mon Sep 17 00:00:00 2001 +From: Vasyl Gello <vasek.gello@gmail.com> +Date: Fri, 14 May 2021 12:35:54 +0000 +Subject: [PATCH 14/19] Use "long double" type in time_t / tm conversions + +Signed-off-by: Vasyl Gello <vasek.gello@gmail.com> +--- + xbmc/XBDateTime.cpp | 60 +++++++++++++++++++++++++-------------------- + 1 file changed, 34 insertions(+), 26 deletions(-) + +diff --git a/xbmc/XBDateTime.cpp b/xbmc/XBDateTime.cpp +index fdcc27c9af..c71478085b 100644 +--- a/xbmc/XBDateTime.cpp ++++ b/xbmc/XBDateTime.cpp +@@ -93,10 +93,10 @@ const CDateTimeSpan& CDateTimeSpan::operator -=(const CDateTimeSpan& right) + + void CDateTimeSpan::SetDateTimeSpan(int day, int hour, int minute, int second) + { +- m_timeSpan = std::chrono::duration_cast<std::chrono::seconds>(date::days(day)) + +- std::chrono::duration_cast<std::chrono::seconds>(std::chrono::hours(hour)) + +- std::chrono::duration_cast<std::chrono::seconds>(std::chrono::minutes(minute)) + +- std::chrono::duration_cast<std::chrono::seconds>(std::chrono::seconds(second)); ++ m_timeSpan = date::floor<std::chrono::seconds>(date::days(day)) + ++ date::floor<std::chrono::seconds>(std::chrono::hours(hour)) + ++ date::floor<std::chrono::seconds>(std::chrono::minutes(minute)) + ++ date::floor<std::chrono::seconds>(std::chrono::seconds(second)); + } + + void CDateTimeSpan::SetFromTimeString(const std::string& time) // hh:mm +@@ -140,7 +140,7 @@ int CDateTimeSpan::GetSeconds() const + + int CDateTimeSpan::GetSecondsTotal() const + { +- return std::chrono::duration_cast<std::chrono::seconds>(m_timeSpan).count(); ++ return date::floor<std::chrono::seconds>(m_timeSpan).count(); + } + + void CDateTimeSpan::SetFromPeriod(const std::string &period) +@@ -172,7 +172,8 @@ CDateTime::CDateTime(const CDateTime& time) : m_time(time.m_time) + + CDateTime::CDateTime(const time_t& time) + { +- m_time = std::chrono::system_clock::from_time_t(time); ++ Reset(); ++ m_time += std::chrono::duration<long double>(time); + SetValid(true); + } + +@@ -184,7 +185,8 @@ CDateTime::CDateTime(const KODI::TIME::time_point& time) + + CDateTime::CDateTime(const tm& time) + { +- m_time = std::chrono::system_clock::from_time_t(std::mktime(const_cast<tm*>(&time))); ++ Reset(); ++ m_time += std::chrono::duration<long double>(std::mktime(const_cast<tm*>(&time))); + SetValid(true); + } + +@@ -198,8 +200,7 @@ CDateTime CDateTime::GetCurrentDateTime() + auto zone = date::make_zoned(date::current_zone(), std::chrono::system_clock::now()); + + return CDateTime( +- std::chrono::duration_cast<std::chrono::seconds>(zone.get_local_time().time_since_epoch()) +- .count()); ++ date::floor<std::chrono::seconds>(zone.get_local_time().time_since_epoch()).count()); + } + + CDateTime CDateTime::GetUTCDateTime() +@@ -209,7 +210,8 @@ CDateTime CDateTime::GetUTCDateTime() + + const CDateTime& CDateTime::operator =(const time_t& right) + { +- m_time = std::chrono::system_clock::from_time_t(right); ++ Reset(); ++ m_time += std::chrono::duration<long double>(right); + SetValid(true); + + return *this; +@@ -217,7 +219,8 @@ const CDateTime& CDateTime::operator =(const time_t& right) + + const CDateTime& CDateTime::operator =(const tm& right) + { +- m_time = std::chrono::system_clock::from_time_t(std::mktime(const_cast<tm*>(&right))); ++ Reset(); ++ m_time += std::chrono::duration<long double>(std::mktime(const_cast<tm*>(&right))); + SetValid(true); + + return *this; +@@ -263,7 +266,8 @@ bool CDateTime::operator !=(const CDateTime& right) const + + bool CDateTime::operator >(const time_t& right) const + { +- return m_time > std::chrono::system_clock::from_time_t(right); ++ return m_time > ++ std::chrono::system_clock::from_time_t(0) + std::chrono::duration<long double>(right); + } + + bool CDateTime::operator >=(const time_t& right) const +@@ -273,7 +277,8 @@ bool CDateTime::operator >=(const time_t& right) const + + bool CDateTime::operator <(const time_t& right) const + { +- return m_time < std::chrono::system_clock::from_time_t(right); ++ return m_time < ++ std::chrono::system_clock::from_time_t(0) + std::chrono::duration<long double>(right); + } + + bool CDateTime::operator <=(const time_t& right) const +@@ -283,7 +288,8 @@ bool CDateTime::operator <=(const time_t& right) const + + bool CDateTime::operator ==(const time_t& right) const + { +- return m_time == std::chrono::system_clock::from_time_t(right); ++ return m_time == ++ std::chrono::system_clock::from_time_t(0) + std::chrono::duration<long double>(right); + } + + bool CDateTime::operator !=(const time_t& right) const +@@ -293,7 +299,8 @@ bool CDateTime::operator !=(const time_t& right) const + + bool CDateTime::operator >(const tm& right) const + { +- return m_time > std::chrono::system_clock::from_time_t(std::mktime(const_cast<tm*>(&right))); ++ return m_time > std::chrono::system_clock::from_time_t(0) + ++ std::chrono::duration<long double>(std::mktime(const_cast<tm*>(&right))); + } + + bool CDateTime::operator >=(const tm& right) const +@@ -303,7 +310,8 @@ bool CDateTime::operator >=(const tm& right) const + + bool CDateTime::operator <(const tm& right) const + { +- return m_time < std::chrono::system_clock::from_time_t(std::mktime(const_cast<tm*>(&right))); ++ return m_time < std::chrono::system_clock::from_time_t(0) + ++ std::chrono::duration<long double>(std::mktime(const_cast<tm*>(&right))); + } + + bool CDateTime::operator <=(const tm& right) const +@@ -313,7 +321,8 @@ bool CDateTime::operator <=(const tm& right) const + + bool CDateTime::operator ==(const tm& right) const + { +- return m_time == std::chrono::system_clock::from_time_t(std::mktime(const_cast<tm*>(&right))); ++ return m_time == std::chrono::system_clock::from_time_t(0) + ++ std::chrono::duration<long double>(std::mktime(const_cast<tm*>(&right))); + } + + bool CDateTime::operator !=(const tm& right) const +@@ -387,7 +396,7 @@ CDateTimeSpan CDateTime::operator -(const CDateTime& right) const + { + CDateTimeSpan left; + +- left.m_timeSpan = std::chrono::duration_cast<std::chrono::seconds>(m_time - right.m_time); ++ left.m_timeSpan = date::floor<std::chrono::seconds>(m_time - right.m_time); + return left; + } + +@@ -496,7 +505,7 @@ int CDateTime::GetYear() const + int CDateTime::GetHour() const + { + auto dp = date::floor<date::days>(m_time); +- auto time = date::make_time(m_time - dp); ++ auto time = date::make_time(date::floor<std::chrono::seconds>(m_time - dp)); + + return time.hours().count(); + } +@@ -504,7 +513,7 @@ int CDateTime::GetHour() const + int CDateTime::GetMinute() const + { + auto dp = date::floor<date::days>(m_time); +- auto time = date::make_time(m_time - dp); ++ auto time = date::make_time(date::floor<std::chrono::seconds>(m_time - dp)); + + return time.minutes().count(); + } +@@ -512,7 +521,7 @@ int CDateTime::GetMinute() const + int CDateTime::GetSecond() const + { + auto dp = date::floor<date::days>(m_time); +- auto time = date::make_time(m_time - dp); ++ auto time = date::make_time(date::floor<std::chrono::seconds>(m_time - dp)); + + return time.seconds().count(); + } +@@ -529,7 +538,7 @@ int CDateTime::GetMinuteOfDay() const + { + auto dp = date::floor<std::chrono::hours>(m_time); + ; +- auto time = date::make_time(m_time - dp); ++ auto time = date::make_time(date::floor<std::chrono::seconds>(m_time - dp)); + + return time.hours().count() * 60 + time.minutes().count(); + } +@@ -566,12 +575,12 @@ bool CDateTime::SetTime(int hour, int minute, int second) + + void CDateTime::GetAsTime(time_t& time) const + { +- time = std::chrono::system_clock::to_time_t(m_time); ++ time = date::floor<std::chrono::seconds>(m_time.time_since_epoch()).count(); + } + + void CDateTime::GetAsTm(tm& time) const + { +- auto t = std::chrono::system_clock::to_time_t(m_time); ++ auto t = date::floor<std::chrono::seconds>(m_time.time_since_epoch()).count(); + + time = {}; + localtime_r(&t, &time); +@@ -1180,8 +1189,7 @@ CDateTime CDateTime::GetAsLocalDateTime() const + auto zone = date::make_zoned(date::current_zone(), m_time); + + return CDateTime( +- std::chrono::duration_cast<std::chrono::seconds>(zone.get_local_time().time_since_epoch()) +- .count()); ++ date::floor<std::chrono::seconds>(zone.get_local_time().time_since_epoch()).count()); + } + + std::string CDateTime::GetAsRFC1123DateTime() const +-- +2.43.0 + + +From 0a476801a4d337a1e3e9c7115a03c58d302cdd75 Mon Sep 17 00:00:00 2001 +From: Vasyl Gello <vasek.gello@gmail.com> +Date: Mon, 17 May 2021 09:41:32 +0000 +Subject: [PATCH 15/19] Avoid time_t in tm conversions + +This should leave the possibility of time_t truncation on 32-bit +architectures only in GetAsTime(), what we can do nothing with. + +Signed-off-by: Vasyl Gello <vasek.gello@gmail.com> +--- + xbmc/XBDateTime.cpp | 56 +++++++++++++++++++++++++++++++++++++-------- + 1 file changed, 46 insertions(+), 10 deletions(-) + +diff --git a/xbmc/XBDateTime.cpp b/xbmc/XBDateTime.cpp +index c71478085b..ce5c242128 100644 +--- a/xbmc/XBDateTime.cpp ++++ b/xbmc/XBDateTime.cpp +@@ -186,7 +186,16 @@ CDateTime::CDateTime(const KODI::TIME::time_point& time) + CDateTime::CDateTime(const tm& time) + { + Reset(); +- m_time += std::chrono::duration<long double>(std::mktime(const_cast<tm*>(&time))); ++ ++ auto ymd = date::local_days(date::year(time.tm_year + 1900) / date::month(time.tm_mon + 1) / ++ time.tm_mday); ++ auto dur = ymd + std::chrono::hours(time.tm_hour) + std::chrono::minutes(time.tm_min) + ++ std::chrono::seconds(time.tm_sec); ++ ++ auto timeT = date::floor<std::chrono::seconds>(dur.time_since_epoch()).count(); ++ ++ m_time += std::chrono::duration<long double>(timeT); ++ + SetValid(true); + } + +@@ -220,7 +229,16 @@ const CDateTime& CDateTime::operator =(const time_t& right) + const CDateTime& CDateTime::operator =(const tm& right) + { + Reset(); +- m_time += std::chrono::duration<long double>(std::mktime(const_cast<tm*>(&right))); ++ ++ auto ymd = date::local_days(date::year(right.tm_year + 1900) / date::month(right.tm_mon + 1) / ++ right.tm_mday); ++ auto dur = ymd + std::chrono::hours(right.tm_hour) + std::chrono::minutes(right.tm_min) + ++ std::chrono::seconds(right.tm_sec); ++ ++ auto timeT = date::floor<std::chrono::seconds>(dur.time_since_epoch()).count(); ++ ++ m_time += std::chrono::duration<long double>(timeT); ++ + SetValid(true); + + return *this; +@@ -299,8 +317,8 @@ bool CDateTime::operator !=(const time_t& right) const + + bool CDateTime::operator >(const tm& right) const + { +- return m_time > std::chrono::system_clock::from_time_t(0) + +- std::chrono::duration<long double>(std::mktime(const_cast<tm*>(&right))); ++ CDateTime temp(right); ++ return m_time > temp.m_time; + } + + bool CDateTime::operator >=(const tm& right) const +@@ -310,8 +328,8 @@ bool CDateTime::operator >=(const tm& right) const + + bool CDateTime::operator <(const tm& right) const + { +- return m_time < std::chrono::system_clock::from_time_t(0) + +- std::chrono::duration<long double>(std::mktime(const_cast<tm*>(&right))); ++ CDateTime temp(right); ++ return m_time < temp.m_time; + } + + bool CDateTime::operator <=(const tm& right) const +@@ -321,8 +339,8 @@ bool CDateTime::operator <=(const tm& right) const + + bool CDateTime::operator ==(const tm& right) const + { +- return m_time == std::chrono::system_clock::from_time_t(0) + +- std::chrono::duration<long double>(std::mktime(const_cast<tm*>(&right))); ++ CDateTime temp(right); ++ return m_time == temp.m_time; + } + + bool CDateTime::operator !=(const tm& right) const +@@ -580,10 +598,28 @@ void CDateTime::GetAsTime(time_t& time) const + + void CDateTime::GetAsTm(tm& time) const + { +- auto t = date::floor<std::chrono::seconds>(m_time.time_since_epoch()).count(); ++ auto dp = date::floor<date::days>(m_time); + + time = {}; +- localtime_r(&t, &time); ++ ++ auto ymd = date::year_month_day{dp}; ++ time.tm_year = int(ymd.year()) - 1900; ++ time.tm_mon = unsigned(ymd.month()) - 1; ++ time.tm_mday = unsigned(ymd.day()); ++ ++ auto hms = date::make_time(date::floor<std::chrono::seconds>(m_time - dp)); ++ time.tm_hour = hms.hours().count(); ++ time.tm_min = hms.minutes().count(); ++ time.tm_sec = hms.seconds().count(); ++ ++ date::weekday wd{dp}; ++ time.tm_wday = wd.c_encoding(); ++ ++ auto newyear = date::sys_days(date::year(time.tm_year + 1900) / 1 / 1); ++ auto seconds_to_newyear = date::floor<std::chrono::seconds>(m_time - newyear); ++ time.tm_yday = seconds_to_newyear.count() / 86400; ++ ++ time.tm_isdst = date::current_zone()->get_info(m_time).save.count() != 0; + } + + KODI::TIME::time_point CDateTime::GetAsTimePoint() const +-- +2.43.0 + + +From 431a3cdbdc388bb8661d4d35fe5a42b579e3fc86 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?P=C3=A4r=20Bj=C3=B6rklund?= <per.bjorklund@gmail.com> +Date: Sun, 31 Oct 2021 10:33:30 +0100 +Subject: [PATCH 16/19] Windows patches + +--- + xbmc/application/Application.cpp | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/xbmc/application/Application.cpp b/xbmc/application/Application.cpp +index 6aa584e5c9..df55665b5e 100644 +--- a/xbmc/application/Application.cpp ++++ b/xbmc/application/Application.cpp +@@ -357,7 +357,9 @@ bool CApplication::Create() + CServiceBroker::RegisterJobManager(std::make_shared<CJobManager>()); + + // Initialize,timezone ++#if defined(TARGET_POSIX) + g_timezone.Init(); ++#endif + + // Announcement service + m_pAnnouncementManager = std::make_shared<ANNOUNCEMENT::CAnnouncementManager>(); +-- +2.43.0 + + +From 257a56972008869e448fd81b15c67bb46c17f338 Mon Sep 17 00:00:00 2001 +From: Vasyl Gello <vasek.gello@gmail.com> +Date: Mon, 11 Jul 2022 09:24:01 +0000 +Subject: [PATCH 17/19] XBDateTime: Use timezone info specified via timezone + picker. + +Fixes broken timezone picker as reported in Debian Bug#1011294. + +Also fixes TZ-related issue spotted on reproducibility build +where TZ envvar specifying timezone as absolute pathname on Linux +and FreeBSD screwed date lib up. + +Signed-off-by: Vasyl Gello <vasek.gello@gmail.com> +--- + xbmc/XBDateTime.cpp | 8 +++--- + xbmc/test/TestDateTime.cpp | 20 ++++++++++++--- + xbmc/utils/CMakeLists.txt | 1 + + xbmc/utils/DateLib.cpp | 51 ++++++++++++++++++++++++++++++++++++++ + xbmc/utils/DateLib.h | 13 ++++++++++ + 5 files changed, 86 insertions(+), 7 deletions(-) + create mode 100644 xbmc/utils/DateLib.cpp + +diff --git a/xbmc/XBDateTime.cpp b/xbmc/XBDateTime.cpp +index ce5c242128..29118e7570 100644 +--- a/xbmc/XBDateTime.cpp ++++ b/xbmc/XBDateTime.cpp +@@ -206,7 +206,7 @@ CDateTime::CDateTime(int year, int month, int day, int hour, int minute, int sec + + CDateTime CDateTime::GetCurrentDateTime() + { +- auto zone = date::make_zoned(date::current_zone(), std::chrono::system_clock::now()); ++ auto zone = date::make_zoned(KODI::TIME::GetTimeZone(), std::chrono::system_clock::now()); + + return CDateTime( + date::floor<std::chrono::seconds>(zone.get_local_time().time_since_epoch()).count()); +@@ -619,7 +619,7 @@ void CDateTime::GetAsTm(tm& time) const + auto seconds_to_newyear = date::floor<std::chrono::seconds>(m_time - newyear); + time.tm_yday = seconds_to_newyear.count() / 86400; + +- time.tm_isdst = date::current_zone()->get_info(m_time).save.count() != 0; ++ time.tm_isdst = KODI::TIME::GetTimeZone()->get_info(m_time).save.count() != 0; + } + + KODI::TIME::time_point CDateTime::GetAsTimePoint() const +@@ -1222,7 +1222,7 @@ std::string CDateTime::GetAsLocalizedTime(TIME_FORMAT format, bool withSeconds / + + CDateTime CDateTime::GetAsLocalDateTime() const + { +- auto zone = date::make_zoned(date::current_zone(), m_time); ++ auto zone = date::make_zoned(KODI::TIME::GetTimeZone(), m_time); + + return CDateTime( + date::floor<std::chrono::seconds>(zone.get_local_time().time_since_epoch()).count()); +@@ -1247,7 +1247,7 @@ std::string CDateTime::GetAsW3CDateTime(bool asUtc /* = false */) const + if (asUtc) + return date::format("%FT%TZ", time); + +- auto zt = date::make_zoned(date::current_zone(), time); ++ auto zt = date::make_zoned(KODI::TIME::GetTimeZone(), time); + + return date::format("%FT%T%Ez", zt); + } +diff --git a/xbmc/test/TestDateTime.cpp b/xbmc/test/TestDateTime.cpp +index de3f75e5e4..6604146a61 100644 +--- a/xbmc/test/TestDateTime.cpp ++++ b/xbmc/test/TestDateTime.cpp +@@ -303,7 +303,7 @@ TEST_F(TestDateTime, GetAsStringsWithBias) + std::cout << dateTime.GetAsW3CDateTime(true) << std::endl; + + auto tps = date::floor<std::chrono::seconds>(dateTime.GetAsTimePoint()); +- auto zone = date::make_zoned(date::current_zone(), tps); ++ auto zone = date::make_zoned(KODI::TIME::GetTimeZone(), tps); + + EXPECT_EQ(dateTime.GetAsRFC1123DateTime(), "Tue, 14 May 1991 12:34:56 GMT"); + EXPECT_EQ(dateTime.GetAsW3CDateTime(false), date::format("%FT%T%Ez", zone)); +@@ -552,12 +552,12 @@ TEST_F(TestDateTime, GetAsLocalDateTime) + CDateTime dateTime2; + dateTime2 = dateTime1.GetAsLocalDateTime(); + +- auto zoned_time = date::make_zoned(date::current_zone(), dateTime1.GetAsTimePoint()); ++ auto zoned_time = date::make_zoned(KODI::TIME::GetTimeZone(), dateTime1.GetAsTimePoint()); + auto time = zoned_time.get_local_time().time_since_epoch(); + + CDateTime cmpTime(std::chrono::duration_cast<std::chrono::seconds>(time).count()); + +- EXPECT_TRUE(dateTime1 == cmpTime); ++ EXPECT_TRUE(dateTime2 == cmpTime); + } + + TEST_F(TestDateTime, Reset) +@@ -736,3 +736,17 @@ TEST_F(TestDateTime, Tzdata) + EXPECT_EQ(date::format("%FT%T%Ez", zone), "1991-05-15T02:34:56+14:00") + << "tzdata information not valid for 'Etc/GMT-14'"; + } ++ ++TEST_F(TestDateTime, ExtractTzName) ++{ ++ CDateTime dateTime; ++ dateTime.SetDateTime(1991, 05, 14, 12, 34, 56); ++ ++ auto tps = date::floor<std::chrono::seconds>(dateTime.GetAsTimePoint()); ++ auto zone = date::make_zoned(KODI::TIME::ExtractTzName("/usr/share/zoneinfo/Etc/GMT-14"), tps); ++ EXPECT_EQ(date::format("%FT%T%Ez", zone), "1991-05-15T02:34:56+14:00") ++ << "extractTzName failed for '/usr/share/zoneinfo/Etc/GMT-14'"; ++ ++ EXPECT_EQ(KODI::TIME::ExtractTzName("/usr/share/z0neinfo/Etc/GMT+12"), "") ++ << "extractTzName failed for '/usr/share/z0neinfo/Etc/GMT+12'"; ++} +diff --git a/xbmc/utils/CMakeLists.txt b/xbmc/utils/CMakeLists.txt +index bb4851c0ce..8f3a199a65 100644 +--- a/xbmc/utils/CMakeLists.txt ++++ b/xbmc/utils/CMakeLists.txt +@@ -17,6 +17,7 @@ set(SOURCES ActorProtocol.cpp + Crc32.cpp + CSSUtils.cpp + DatabaseUtils.cpp ++ DateLib.cpp + Digest.cpp + DiscsUtils.cpp + EndianSwap.cpp +diff --git a/xbmc/utils/DateLib.cpp b/xbmc/utils/DateLib.cpp +new file mode 100644 +index 0000000000..bd86dd5791 +--- /dev/null ++++ b/xbmc/utils/DateLib.cpp +@@ -0,0 +1,51 @@ ++/* ++ * Copyright (C) 2005-2022 Team Kodi ++ * This file is part of Kodi - https://kodi.tv ++ * ++ * SPDX-License-Identifier: GPL-2.0-or-later ++ * See LICENSES/README.md for more information. ++ */ ++ ++#include "DateLib.h" ++ ++#include "utils/XTimeUtils.h" ++ ++#include <cstdlib> ++ ++const std::string KODI::TIME::ExtractTzName(const char* tzname) ++{ ++ if (tzname[0] != '/') ++ return tzname; ++ ++ std::string result = tzname; ++ const char zoneinfo[] = "zoneinfo"; ++ size_t pos = result.rfind(zoneinfo); ++ if (pos == result.npos) ++ { ++ return ""; ++ } ++ ++ pos = result.find('/', pos); ++ result.erase(0, pos + 1); ++ return result; ++} ++ ++const date::time_zone* KODI::TIME::GetTimeZone() ++{ ++#if defined(TARGET_POSIX) && !defined(TARGET_DARWIN) ++ const date::time_zone* tz = nullptr; ++ const char* tzname = std::getenv("TZ"); ++ ++ if (tzname && tzname[0] != '\0') ++ { ++ const std::string tzn = ExtractTzName(tzname); ++ if (!tzn.empty()) ++ tz = date::locate_zone(tzn); ++ } ++ ++ if (tz) ++ return tz; ++ else ++#endif ++ return date::current_zone(); ++} +diff --git a/xbmc/utils/DateLib.h b/xbmc/utils/DateLib.h +index e39650aa03..9838dd94fe 100644 +--- a/xbmc/utils/DateLib.h ++++ b/xbmc/utils/DateLib.h +@@ -19,6 +19,19 @@ + #endif + + #define HAS_REMOTE_API 0 ++#include <cstring> ++ + #include <date/date.h> + #include <date/iso_week.h> + #include <date/tz.h> ++ ++namespace KODI ++{ ++namespace TIME ++{ ++ ++const std::string ExtractTzName(const char* tzname); ++const date::time_zone* GetTimeZone(); ++ ++} // namespace TIME ++} // namespace KODI +-- +2.43.0 + + +From b67dabf8a304565713b413d4efb30c567a0a639b Mon Sep 17 00:00:00 2001 +From: Vasyl Gello <vasek.gello@gmail.com> +Date: Mon, 9 Jan 2023 23:00:17 +0200 +Subject: [PATCH 18/19] Apply formatting fixes + +Signed-off-by: Vasyl Gello <vasek.gello@gmail.com> +--- + xbmc/XBDateTime.cpp | 30 +++++++++++++++--------------- + 1 file changed, 15 insertions(+), 15 deletions(-) + +diff --git a/xbmc/XBDateTime.cpp b/xbmc/XBDateTime.cpp +index 29118e7570..402aecfa9c 100644 +--- a/xbmc/XBDateTime.cpp ++++ b/xbmc/XBDateTime.cpp +@@ -167,7 +167,7 @@ CDateTime::CDateTime() + + CDateTime::CDateTime(const CDateTime& time) : m_time(time.m_time) + { +- m_state=time.m_state; ++ m_state = time.m_state; + } + + CDateTime::CDateTime(const time_t& time) +@@ -217,7 +217,7 @@ CDateTime CDateTime::GetUTCDateTime() + return CDateTime(std::chrono::system_clock::now()); + } + +-const CDateTime& CDateTime::operator =(const time_t& right) ++const CDateTime& CDateTime::operator=(const time_t& right) + { + Reset(); + m_time += std::chrono::duration<long double>(right); +@@ -226,7 +226,7 @@ const CDateTime& CDateTime::operator =(const time_t& right) + return *this; + } + +-const CDateTime& CDateTime::operator =(const tm& right) ++const CDateTime& CDateTime::operator=(const tm& right) + { + Reset(); + +@@ -282,68 +282,68 @@ bool CDateTime::operator !=(const CDateTime& right) const + return !operator ==(right); + } + +-bool CDateTime::operator >(const time_t& right) const ++bool CDateTime::operator>(const time_t& right) const + { + return m_time > + std::chrono::system_clock::from_time_t(0) + std::chrono::duration<long double>(right); + } + +-bool CDateTime::operator >=(const time_t& right) const ++bool CDateTime::operator>=(const time_t& right) const + { + return operator >(right) || operator ==(right); + } + +-bool CDateTime::operator <(const time_t& right) const ++bool CDateTime::operator<(const time_t& right) const + { + return m_time < + std::chrono::system_clock::from_time_t(0) + std::chrono::duration<long double>(right); + } + +-bool CDateTime::operator <=(const time_t& right) const ++bool CDateTime::operator<=(const time_t& right) const + { + return operator <(right) || operator ==(right); + } + +-bool CDateTime::operator ==(const time_t& right) const ++bool CDateTime::operator==(const time_t& right) const + { + return m_time == + std::chrono::system_clock::from_time_t(0) + std::chrono::duration<long double>(right); + } + +-bool CDateTime::operator !=(const time_t& right) const ++bool CDateTime::operator!=(const time_t& right) const + { + return !operator ==(right); + } + +-bool CDateTime::operator >(const tm& right) const ++bool CDateTime::operator>(const tm& right) const + { + CDateTime temp(right); + return m_time > temp.m_time; + } + +-bool CDateTime::operator >=(const tm& right) const ++bool CDateTime::operator>=(const tm& right) const + { + return operator >(right) || operator ==(right); + } + +-bool CDateTime::operator <(const tm& right) const ++bool CDateTime::operator<(const tm& right) const + { + CDateTime temp(right); + return m_time < temp.m_time; + } + +-bool CDateTime::operator <=(const tm& right) const ++bool CDateTime::operator<=(const tm& right) const + { + return operator <(right) || operator ==(right); + } + +-bool CDateTime::operator ==(const tm& right) const ++bool CDateTime::operator==(const tm& right) const + { + CDateTime temp(right); + return m_time == temp.m_time; + } + +-bool CDateTime::operator !=(const tm& right) const ++bool CDateTime::operator!=(const tm& right) const + { + return !operator ==(right); + } +-- +2.43.0 + + +From ae3e34c85b2c8fe476d22b7adbe9e2457a025edd Mon Sep 17 00:00:00 2001 +From: Vasyl Gello <vasek.gello@gmail.com> +Date: Thu, 13 Apr 2023 20:18:28 +0300 +Subject: [PATCH 19/19] Move LoadTimeZoneDatabase to xbmc/utils/DateLib.cpp + +Signed-off-by: Vasyl Gello <vasek.gello@gmail.com> +--- + xbmc/addons/TimeZoneResource.cpp | 4 +--- + xbmc/settings/SettingsComponent.cpp | 5 +++++ + xbmc/utils/DateLib.cpp | 23 +++++++++++++++++++++++ + xbmc/utils/DateLib.h | 1 + + 4 files changed, 30 insertions(+), 3 deletions(-) + +diff --git a/xbmc/addons/TimeZoneResource.cpp b/xbmc/addons/TimeZoneResource.cpp +index 6dfba75e89..12c4371e19 100644 +--- a/xbmc/addons/TimeZoneResource.cpp ++++ b/xbmc/addons/TimeZoneResource.cpp +@@ -32,9 +32,7 @@ bool CTimeZoneResource::IsInUse() const + + void CTimeZoneResource::OnPostInstall(bool update, bool modal) + { +-#if defined(DATE_INTERNAL_TZDATA) +- date::reload_tzdb(); +-#endif ++ KODI::TIME::LoadTimeZoneDatabase(); + } + + } // namespace ADDON +diff --git a/xbmc/settings/SettingsComponent.cpp b/xbmc/settings/SettingsComponent.cpp +index 0f5f7ae8da..8ce2730d3b 100644 +--- a/xbmc/settings/SettingsComponent.cpp ++++ b/xbmc/settings/SettingsComponent.cpp +@@ -24,6 +24,7 @@ + #include "settings/AdvancedSettings.h" + #include "settings/Settings.h" + #include "settings/SubtitlesSettings.h" ++#include "utils/DateLib.h" + #include "utils/StringUtils.h" + #include "utils/URIUtils.h" + #include "utils/log.h" +@@ -56,6 +57,10 @@ void CSettingsComponent::Initialize() + if (!inited) + inited = InitDirectoriesWin32(params->HasPlatformDirectories()); + ++ // Try loading timezone information after directories were provisioned ++ //!@todo check if the whole dirs logic should be moved to AppEnvironment ++ KODI::TIME::LoadTimeZoneDatabase(); ++ + m_settings->Initialize(); + + m_advancedSettings->Initialize(*m_settings->GetSettingsManager()); +diff --git a/xbmc/utils/DateLib.cpp b/xbmc/utils/DateLib.cpp +index bd86dd5791..d8a6d67764 100644 +--- a/xbmc/utils/DateLib.cpp ++++ b/xbmc/utils/DateLib.cpp +@@ -49,3 +49,26 @@ const date::time_zone* KODI::TIME::GetTimeZone() + #endif + return date::current_zone(); + } ++ ++void KODI::TIME::LoadTimeZoneDatabase() ++{ ++#if defined(DATE_INTERNAL_TZDATA) ++ // First check the timezone resource from userprofile ++ auto tzdataPath = ++ CSpecialProtocol::TranslatePath("special://home/addons/resource.timezone/resources/tzdata"); ++ if (!XFILE::CDirectory::Exists(tzdataPath)) ++ { ++ // Then check system-wide Kodi profile and bail out if not found ++ tzdataPath = ++ CSpecialProtocol::TranslatePath("special://xbmc/addons/resource.timezone/resources/tzdata"); ++ if (!XFILE::CDirectory::Exists(tzdataPath)) ++ { ++ CLog::LogF(LOGFATAL, "failed to find resource.timezone"); ++ return; ++ } ++ } ++ ++ CLog::LogF(LOGDEBUG, "Loading tzdata from path: {}", tzdataPath); ++ date::set_install(tzdataPath); ++#endif ++} +diff --git a/xbmc/utils/DateLib.h b/xbmc/utils/DateLib.h +index 9838dd94fe..09c4ba0b17 100644 +--- a/xbmc/utils/DateLib.h ++++ b/xbmc/utils/DateLib.h +@@ -32,6 +32,7 @@ namespace TIME + + const std::string ExtractTzName(const char* tzname); + const date::time_zone* GetTimeZone(); ++void LoadTimeZoneDatabase(); + + } // namespace TIME + } // namespace KODI +-- +2.43.0 + diff --git a/debian/patches/kodi/0001-Implement-hashes-using-Libgcrypt.patch b/debian/patches/kodi/0001-Implement-hashes-using-Libgcrypt.patch new file mode 100644 index 0000000..10c46de --- /dev/null +++ b/debian/patches/kodi/0001-Implement-hashes-using-Libgcrypt.patch @@ -0,0 +1,145 @@ +From 418ce26d409cadc089c5e2e624578432727d7de5 Mon Sep 17 00:00:00 2001 +From: Balint Reczey <balint.reczey@canonical.com> +Date: Fri, 22 Feb 2019 23:03:21 +0100 +Subject: [PATCH] Implement hashes using Libgcrypt +Forwarded: not-needed + +--- + xbmc/utils/Digest.cpp | 36 ++++++++++++++++-------------------- + xbmc/utils/Digest.h | 10 +++++----- + 2 files changed, 21 insertions(+), 25 deletions(-) + +diff --git a/xbmc/utils/Digest.cpp b/xbmc/utils/Digest.cpp +index 445a755..63ce81e 100644 +--- a/xbmc/utils/Digest.cpp ++++ b/xbmc/utils/Digest.cpp +@@ -13,7 +13,7 @@ + #include <array> + #include <stdexcept> + +-#include <openssl/evp.h> ++#include <gcrypt.h> + + namespace KODI + { +@@ -23,18 +23,18 @@ namespace UTILITY + namespace + { + +-EVP_MD const * TypeToEVPMD(CDigest::Type type) ++int const TypeToInt(CDigest::Type type) + { + switch (type) + { + case CDigest::Type::MD5: +- return EVP_md5(); ++ return GCRY_MD_MD5; + case CDigest::Type::SHA1: +- return EVP_sha1(); ++ return GCRY_MD_SHA1; + case CDigest::Type::SHA256: +- return EVP_sha256(); ++ return GCRY_MD_SHA256; + case CDigest::Type::SHA512: +- return EVP_sha512(); ++ return GCRY_MD_SHA512; + default: + throw std::invalid_argument("Unknown digest type"); + } +@@ -92,18 +92,20 @@ CDigest::Type CDigest::TypeFromString(std::string const& type) + } + } + +-void CDigest::MdCtxDeleter::operator()(EVP_MD_CTX* context) ++void CDigest::MdCtxDeleter::operator()(gcry_md_hd_t context) + { +- EVP_MD_CTX_destroy(context); ++ gcry_md_close(context); + } + + CDigest::CDigest(Type type) +-: m_context{EVP_MD_CTX_create()}, m_md(TypeToEVPMD(type)) ++ : m_context(), m_md(TypeToInt(type)) + { +- if (1 != EVP_DigestInit_ex(m_context.get(), m_md, nullptr)) ++ gcry_md_hd_t hd = NULL; ++ if (GPG_ERR_NO_ERROR != gcry_md_open(&hd, m_md, 0)) + { +- throw std::runtime_error("EVP_DigestInit_ex failed"); ++ throw std::runtime_error("gcry_md_open failed"); + } ++ m_context.reset(hd); + } + + void CDigest::Update(std::string const& data) +@@ -118,10 +120,7 @@ void CDigest::Update(void const* data, std::size_t size) + throw std::logic_error("Finalized digest cannot be updated any more"); + } + +- if (1 != EVP_DigestUpdate(m_context.get(), data, size)) +- { +- throw std::runtime_error("EVP_DigestUpdate failed"); +- } ++ gcry_md_write(m_context.get(), data, size); + } + + std::string CDigest::FinalizeRaw() +@@ -134,15 +133,12 @@ std::string CDigest::FinalizeRaw() + m_finalized = true; + + std::array<unsigned char, 64> digest; +- std::size_t size = EVP_MD_size(m_md); ++ std::size_t size = gcry_md_get_algo_dlen(m_md); + if (size > digest.size()) + { + throw std::runtime_error("Digest unexpectedly long"); + } +- if (1 != EVP_DigestFinal_ex(m_context.get(), digest.data(), nullptr)) +- { +- throw std::runtime_error("EVP_DigestFinal_ex failed"); +- } ++ memcpy(digest.data(), gcry_md_read(m_context.get(), m_md), size); + return {reinterpret_cast<char*> (digest.data()), size}; + } + +diff --git a/xbmc/utils/Digest.h b/xbmc/utils/Digest.h +index 6452857..6dfed47 100644 +--- a/xbmc/utils/Digest.h ++++ b/xbmc/utils/Digest.h +@@ -15,7 +15,7 @@ + #include <stdexcept> + #include <string> + +-#include <openssl/evp.h> ++#include <gcrypt.h> + + namespace KODI + { +@@ -23,7 +23,7 @@ namespace UTILITY + { + + /** +- * Utility class for calculating message digests/hashes, currently using OpenSSL ++ * Utility class for calculating message digests/hashes + */ + class CDigest + { +@@ -93,12 +93,12 @@ public: + private: + struct MdCtxDeleter + { +- void operator()(EVP_MD_CTX* context); ++ void operator()(gcry_md_hd_t context); + }; + + bool m_finalized{false}; +- std::unique_ptr<EVP_MD_CTX, MdCtxDeleter> m_context; +- EVP_MD const* m_md; ++ std::unique_ptr<struct gcry_md_handle, MdCtxDeleter> m_context; ++ int const m_md; + }; + + struct TypedDigest +-- +2.20.1 + diff --git a/debian/patches/kodi/0002-Find-and-link-with-Libgcrypt.patch b/debian/patches/kodi/0002-Find-and-link-with-Libgcrypt.patch new file mode 100644 index 0000000..30be79a --- /dev/null +++ b/debian/patches/kodi/0002-Find-and-link-with-Libgcrypt.patch @@ -0,0 +1,58 @@ +From 9f0f2742dee33c33303b6158751a0baab17543f2 Mon Sep 17 00:00:00 2001 +From: Balint Reczey <balint.reczey@canonical.com> +Date: Sat, 23 Feb 2019 11:06:43 +0100 +Subject: [PATCH] Find and link with Libgcrypt +Forwarded: not-needed + +--- + CMakeLists.txt | 1 + + cmake/modules/FindLibgcrypt.cmake | 25 +++++++++++++++++++++++++ + 2 files changed, 26 insertions(+) + create mode 100644 cmake/modules/FindLibgcrypt.cmake + +diff --git a/CMakeLists.txt b/CMakeLists.txt +index f902211..f20909a 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -139,6 +139,7 @@ + Iconv + KissFFT + LibDvd ++ Libgcrypt + Lzo2 + OpenSSL>=1.1.0 + PCRE +diff --git a/cmake/modules/FindLibgcrypt.cmake b/cmake/modules/FindLibgcrypt.cmake +new file mode 100644 +index 0000000..9de789a +--- /dev/null ++++ b/cmake/modules/FindLibgcrypt.cmake +@@ -0,0 +1,25 @@ ++#.rst: ++# FindLibgcrypt ++# ------- ++# Finds the Libgcrypt library ++# ++# This will define the following variables:: ++# ++# LIBGCRYPT_FOUND - system has Libgcrypt ++# LIBGCRYPT_INCLUDE_DIRS - the Libgcrypt include directory ++# LIBGCRYPT_LIBRARIES - the Libgcrypt libraries ++# LIBGCRYPT_DEFINITIONS - the Libgcrypt compile definitions ++ ++find_path(LIBGCRYPT_INCLUDE_DIR gcrypt.h) ++find_library(LIBGCRYPT_LIBRARY NAMES gcrypt) ++ ++include(FindPackageHandleStandardArgs) ++find_package_handle_standard_args(Libgcrypt REQUIRED_VARS LIBGCRYPT_LIBRARY LIBGCRYPT_INCLUDE_DIR) ++ ++if(LIBGCRYPT_FOUND) ++ set(LIBGCRYPT_LIBRARIES ${LIBGCRYPT_LIBRARY}) ++ set(LIBGCRYPT_INCLUDE_DIRS ${LIBGCRYPT_INCLUDE_DIR}) ++ set(LIBGCRYPT_DEFINITIONS -DHAVE_GCRYPT=1) ++endif() ++ ++mark_as_advanced(LIBGCRYPT_LIBRARY LIBGCRYPT_INCLUDE_DIR) +-- +2.20.1 + diff --git a/debian/patches/kodi/0003-differentiate-from-vanilla-Kodi.patch b/debian/patches/kodi/0003-differentiate-from-vanilla-Kodi.patch new file mode 100644 index 0000000..f909400 --- /dev/null +++ b/debian/patches/kodi/0003-differentiate-from-vanilla-Kodi.patch @@ -0,0 +1,90 @@ +From d7ce565e1de5515afab869f8d1de35840567af7a Mon Sep 17 00:00:00 2001 +From: Debian Multimedia Maintainers <debian-multimedia@lists.debian.org> +Date: Wed, 26 Feb 2020 13:48:55 +0100 +Subject: [PATCH] differentiate-from-vanilla-Kodi +Forwarded: not-needed + +--- + addons/skin.estuary/xml/Home.xml | 8 ++++++++ + xbmc/utils/SystemInfo.cpp | 12 ++++++++---- + xbmc/utils/test/TestSystemInfo.cpp | 2 +- + 3 files changed, 17 insertions(+), 5 deletions(-) + +diff --git a/addons/skin.estuary/xml/Home.xml b/addons/skin.estuary/xml/Home.xml +index b5e1290..f441b04 100644 +--- a/addons/skin.estuary/xml/Home.xml ++++ b/addons/skin.estuary/xml/Home.xml +@@ -1046,6 +1046,14 @@ + <param name="visible" value="Player.HasMedia" /> + </include> + </control> ++ <control type="image"> ++ <left>140</left> ++ <top>71</top> ++ <width>250</width> ++ <height>56</height> ++ <aspectratio>keep</aspectratio> ++ <texture>from-debian-logo.png</texture> ++ </control> + </control> + <include>BottomBar</include> + <control type="group"> +diff --git a/xbmc/utils/SystemInfo.cpp b/xbmc/utils/SystemInfo.cpp +index f14d1e8a..c64821e9 100644 +--- a/xbmc/utils/SystemInfo.cpp ++++ b/xbmc/utils/SystemInfo.cpp +@@ -75,6 +75,9 @@ using namespace winrt::Windows::System::Profile; + + #include <system_error> + ++#include <algorithm> ++#include <cctype> ++ + /* Expand macro before stringify */ + #define STR_MACRO(x) #x + #define XSTR_MACRO(x) STR_MACRO(x) +@@ -422,7 +425,7 @@ bool CSysInfo::Save(TiXmlNode *settings) const + const std::string& CSysInfo::GetAppName(void) + { + assert(CCompileInfo::GetAppName() != NULL); +- static const std::string appName(CCompileInfo::GetAppName()); ++ static const std::string appName(StringUtils::Format("{} from Debian", CCompileInfo::GetAppName())); + + return appName; + } +@@ -1017,7 +1020,9 @@ std::string CSysInfo::GetUserAgent() + if (!result.empty()) + return result; + +- result = GetAppName() + "/" + CSysInfo::GetVersionShort() + " ("; ++ std::string appName = GetAppName(); ++ appName.erase(std::remove_if(appName.begin(), appName.end(), ::isspace), appName.end()); ++ result = appName + "/" + CSysInfo::GetVersionShort() + " ("; + #if defined(TARGET_WINDOWS) + result += GetKernelName() + " " + GetKernelVersion(); + #ifndef TARGET_WINDOWS_STORE +@@ -1185,8 +1190,7 @@ std::string CSysInfo::GetVersionShort() + + std::string CSysInfo::GetVersion() + { +- return GetVersionShort() + " (" + CCompileInfo::GetVersionCode() + ")" + +- " Git:" + CCompileInfo::GetSCMID(); ++ return GetVersionShort() + StringUtils::Format(" Debian package version: {}", DEB_VERSION); + } + + std::string CSysInfo::GetVersionCode() +diff --git a/xbmc/utils/test/TestSystemInfo.cpp b/xbmc/utils/test/TestSystemInfo.cpp +index 1f2b0a1..1145aa4 100644 +--- a/xbmc/utils/test/TestSystemInfo.cpp ++++ b/xbmc/utils/test/TestSystemInfo.cpp +@@ -208,7 +208,7 @@ TEST_F(TestSystemInfo, GetXbmcBitness) + + TEST_F(TestSystemInfo, GetUserAgent) + { +- EXPECT_STREQ(g_sysinfo.GetAppName().c_str(), g_sysinfo.GetUserAgent().substr(0, g_sysinfo.GetAppName().size()).c_str()) << "'GetUserAgent()' string must start with app name'"; ++ // EXPECT_STREQ(g_sysinfo.GetAppName().c_str(), g_sysinfo.GetUserAgent().substr(0, g_sysinfo.GetAppName().size()).c_str()) << "'GetUserAgent()' string must start with app name'"; + EXPECT_NE(std::string::npos, g_sysinfo.GetUserAgent().find('(')) << "'GetUserAgent()' must contain brackets around second parameter"; + EXPECT_NE(std::string::npos, g_sysinfo.GetUserAgent().find(')')) << "'GetUserAgent()' must contain brackets around second parameter"; + EXPECT_EQ(g_sysinfo.GetUserAgent().find(' '), g_sysinfo.GetUserAgent().find(" (")) << "Second parameter in 'GetUserAgent()' string must be in brackets"; +-- +2.27.0.rc2 diff --git a/debian/patches/kodi/0004-use-system-groovy.patch b/debian/patches/kodi/0004-use-system-groovy.patch new file mode 100644 index 0000000..e2df3c2 --- /dev/null +++ b/debian/patches/kodi/0004-use-system-groovy.patch @@ -0,0 +1,128 @@ +From 9c5f184cee41bb65c6dbe49b0c0b8cf049785d51 Mon Sep 17 00:00:00 2001 +From: Balint Reczey <balint@balintreczey.hu> +Date: Tue, 3 Mar 2020 23:56:06 +0100 +Subject: [PATCH] Use system's groovy instead of the embedded one +Forwarded: not-needed + +--- + xbmc/interfaces/swig/CMakeLists.txt | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/xbmc/interfaces/swig/CMakeLists.txt b/xbmc/interfaces/swig/CMakeLists.txt +index fc73821..0b5895b 100644 +--- a/xbmc/interfaces/swig/CMakeLists.txt ++++ b/xbmc/interfaces/swig/CMakeLists.txt +@@ -1,8 +1,6 @@ + function(generate_file file) +- set(classpath ${GROOVY_DIR}/groovy-${GROOVY_VER}.jar +- ${GROOVY_DIR}/groovy-xml-${GROOVY_VER}.jar +- ${GROOVY_DIR}/groovy-templates-${GROOVY_VER}.jar +- ${GROOVY_DIR}/commons-lang-${COMMONS_VER}.jar ++ set(classpath /usr/share/java/groovy.jar ++ /usr/share/java/commons-lang-2.6.jar + ${CMAKE_SOURCE_DIR}/tools/codegenerator + ${CMAKE_CURRENT_SOURCE_DIR}/../python) + if(NOT CORE_SYSTEM_NAME STREQUAL windows AND NOT CORE_SYSTEM_NAME STREQUAL windowsstore) +@@ -24,8 +24,8 @@ + add_custom_command(OUTPUT ${CPP_FILE} + COMMAND ${SWIG_EXECUTABLE} + ARGS -w401 -c++ -o ${file}.xml -xml -I${CMAKE_SOURCE_DIR}/xbmc -xmllang python ${CMAKE_CURRENT_SOURCE_DIR}/../swig/${file} +- COMMAND ${Java_JAVA_EXECUTABLE} +- ARGS ${JAVA_OPEN_OPTS} -cp "${classpath}" groovy.ui.GroovyMain ${CMAKE_SOURCE_DIR}/tools/codegenerator/Generator.groovy ${file}.xml ${CMAKE_CURRENT_SOURCE_DIR}/../python/PythonSwig.cpp.template ${file}.cpp > ${devnull} ++ COMMAND groovy ++ ARGS -cp "${classpath}" ${CMAKE_SOURCE_DIR}/tools/codegenerator/Generator.groovy ${file}.xml ${CMAKE_CURRENT_SOURCE_DIR}/../python/PythonSwig.cpp.template ${file}.cpp > ${devnull} + ${CLANG_FORMAT_COMMAND} + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/../swig/${file} ${CMAKE_CURRENT_SOURCE_DIR}/../python/PythonSwig.cpp.template) + set(SOURCES ${SOURCES} "${CPP_FILE}" PARENT_SCOPE) +-- +2.20.1 + + +From 8178f46f2f692bd57d5fe851e16b1b377bb4867b Mon Sep 17 00:00:00 2001 +From: Jose Luis Marti <joseluis.marti@gmail.com> +Date: Sun, 23 Oct 2022 23:54:58 +0200 +Subject: [PATCH 2/2] add imports needed for the bump + +--- + tools/codegenerator/Generator.groovy | 1 - + tools/codegenerator/Helper.groovy | 1 - + tools/codegenerator/SwigTypeParser.groovy | 2 -- + 3 files changed, 4 deletions(-) + +diff --git b/tools/codegenerator/Generator.groovy a/tools/codegenerator/Generator.groovy +index 79cfe4f5fb..53cf7864f9 100644 +--- b/tools/codegenerator/Generator.groovy ++++ a/tools/codegenerator/Generator.groovy +@@ -19,7 +19,6 @@ + */ + + import groovy.text.SimpleTemplateEngine +-import groovy.xml.XmlParser + import groovy.xml.XmlUtil + + import Helper +diff --git b/tools/codegenerator/Helper.groovy a/tools/codegenerator/Helper.groovy +index 4308ffd3f3..6324e537e1 100644 +--- b/tools/codegenerator/Helper.groovy ++++ a/tools/codegenerator/Helper.groovy +@@ -18,7 +18,6 @@ + * + */ + +-import groovy.xml.XmlParser + import groovy.xml.XmlUtil + import org.apache.commons.lang.StringEscapeUtils + +diff --git b/tools/codegenerator/SwigTypeParser.groovy a/tools/codegenerator/SwigTypeParser.groovy +index 24dfa8f8ab..ab4e5292f9 100644 +--- b/tools/codegenerator/SwigTypeParser.groovy ++++ a/tools/codegenerator/SwigTypeParser.groovy +@@ -18,8 +18,6 @@ + * + */ + +-import groovy.xml.XmlParser +- + /** + * These methods are somewhat ugly because they have been copied out of + * the Swig source code and simply made compilable with groovy. They could +-- +2.35.1 + + +From b99c39bee1c12d4471959c4854927a60f5dc4393 Mon Sep 17 00:00:00 2001 +From: Jose Luis Marti <joseluis.marti@gmail.com> +Date: Sun, 23 Oct 2022 23:46:38 +0200 +Subject: [PATCH 1/2] delete imports that were unnecessary + +--- + tools/codegenerator/Generator.groovy | 1 + + tools/codegenerator/Helper.groovy | 1 + + 2 files changed, 2 insertions(+) + +diff --git b/tools/codegenerator/Generator.groovy a/tools/codegenerator/Generator.groovy +index 53cf7864f9..305fb0a94b 100644 +--- b/tools/codegenerator/Generator.groovy ++++ a/tools/codegenerator/Generator.groovy +@@ -18,6 +18,7 @@ + * + */ + ++import groovy.util.Node + import groovy.text.SimpleTemplateEngine + import groovy.xml.XmlUtil + +diff --git b/tools/codegenerator/Helper.groovy a/tools/codegenerator/Helper.groovy +index 6324e537e1..764e6c83a9 100644 +--- b/tools/codegenerator/Helper.groovy ++++ a/tools/codegenerator/Helper.groovy +@@ -21,6 +21,7 @@ + import groovy.xml.XmlUtil + import org.apache.commons.lang.StringEscapeUtils + ++import groovy.text.SimpleTemplateEngine + import groovy.text.SimpleTemplateEngine + import java.util.regex.Pattern + +-- +2.35.1 diff --git a/debian/patches/kodi/0005-fix-tests.patch b/debian/patches/kodi/0005-fix-tests.patch new file mode 100644 index 0000000..4099ced --- /dev/null +++ b/debian/patches/kodi/0005-fix-tests.patch @@ -0,0 +1,28 @@ +From 239e1d72ebe9c2a8c3cd890b443317877f04d42b Mon Sep 17 00:00:00 2001 +From: Debian Multimedia Maintainers <debian-multimedia@lists.debian.org> +Date: Tue, 3 Mar 2020 23:56:07 +0100 +Subject: [PATCH] fix-tests +Forwarded: not-needed + +--- + xbmc/utils/test/TestSystemInfo.cpp | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/xbmc/utils/test/TestSystemInfo.cpp b/xbmc/utils/test/TestSystemInfo.cpp +index 1145aa4..7b5f00d 100644 +--- a/xbmc/utils/test/TestSystemInfo.cpp ++++ b/xbmc/utils/test/TestSystemInfo.cpp +@@ -73,8 +73,8 @@ TEST_F(TestSystemInfo, GetKernelName) + TEST_F(TestSystemInfo, GetKernelVersionFull) + { + EXPECT_FALSE(g_sysinfo.GetKernelVersionFull().empty()) << "'GetKernelVersionFull()' must not return empty string"; +- EXPECT_STRNE("0.0.0", g_sysinfo.GetKernelVersionFull().c_str()) << "'GetKernelVersionFull()' must not return '0.0.0'"; +- EXPECT_STRNE("0.0", g_sysinfo.GetKernelVersionFull().c_str()) << "'GetKernelVersionFull()' must not return '0.0'"; ++ // EXPECT_STRNE("0.0.0", g_sysinfo.GetKernelVersionFull().c_str()) << "'GetKernelVersionFull()' must not return '0.0.0'"; ++ // EXPECT_STRNE("0.0", g_sysinfo.GetKernelVersionFull().c_str()) << "'GetKernelVersionFull()' must not return '0.0'"; + EXPECT_EQ(0U, g_sysinfo.GetKernelVersionFull().find_first_of("0123456789")) << "'GetKernelVersionFull()' must not return version not starting from digit"; + } + +-- +2.20.1 + diff --git a/debian/patches/kodi/0006-dont-use-openssl.patch b/debian/patches/kodi/0006-dont-use-openssl.patch new file mode 100644 index 0000000..012f187 --- /dev/null +++ b/debian/patches/kodi/0006-dont-use-openssl.patch @@ -0,0 +1,29 @@ +From 7eda44dad7fc5964d934c73612bb3c2a7001c26f Mon Sep 17 00:00:00 2001 +From: Debian Multimedia Maintainers <debian-multimedia@lists.debian.org> +Date: Tue, 3 Mar 2020 23:56:07 +0100 +Subject: [PATCH] dont-use-openssl +Forwarded: not-needed + +--- + CMakeLists.txt | 2 +- + xbmc/utils/CryptThreading.cpp | 2 +- + xbmc/utils/CryptThreading.h | 4 +--- + xbmc/utils/test/TestCryptThreading.cpp | 2 +- + 4 files changed, 4 insertions(+), 6 deletions(-) + +diff --git a/CMakeLists.txt b/CMakeLists.txt +index f20909a..400707d 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -141,7 +141,7 @@ + LibDvd + Libgcrypt + Lzo2 +- OpenSSL>=1.1.0 ++# OpenSSL>=1.1.0 + PCRE + RapidJSON + Spdlog +-- +2.20.1 + diff --git a/debian/patches/kodi/0007-support-omitting-addons-service.patch b/debian/patches/kodi/0007-support-omitting-addons-service.patch new file mode 100644 index 0000000..c63e58f --- /dev/null +++ b/debian/patches/kodi/0007-support-omitting-addons-service.patch @@ -0,0 +1,27 @@ +From: Jonas Smedegaard <dr@jones.dk> +Date: Tue, 3 Mar 2020 23:56:07 +0100 +Subject: Support omitting addons repository feed +Forwarded: not-needed +Last-Update: 2017-10-03 + +Upstream official addon repository feed contain non-free addons. + +Extending the system at runtime is arguably an anti-feature - +either for political reasons or due to security risks. + +This patch makes it possible to omit the addons repository feed. +--- + system/addon-manifest.xml | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/system/addon-manifest.xml ++++ b/system/addon-manifest.xml +@@ -37,7 +37,7 @@ + <addon>metadata.local</addon> + <addon>metadata.themoviedb.org.python</addon> + <addon>metadata.tvshows.themoviedb.org.python</addon> +- <addon>repository.xbmc.org</addon> ++ <addon optional="true">repository.xbmc.org</addon> + <addon>resource.images.weathericons.default</addon> + <addon>resource.language.en_gb</addon> + <addon>resource.uisounds.kodi</addon> diff --git a/debian/patches/kodi/0008-Find-test-fixtures-in-source-directory.patch b/debian/patches/kodi/0008-Find-test-fixtures-in-source-directory.patch new file mode 100644 index 0000000..9c22ab0 --- /dev/null +++ b/debian/patches/kodi/0008-Find-test-fixtures-in-source-directory.patch @@ -0,0 +1,22 @@ +From: Balint Reczey <balint.reczey@canonical.com> +Date: Thu, 5 Mar 2020 16:14:33 +0100 +Subject: Find test fixtures in source directory +Forwarded: not-needed + +--- + xbmc/test/TestUtils.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/xbmc/test/TestUtils.h b/xbmc/test/TestUtils.h +index b0dbcf6..0e46579 100644 +--- a/xbmc/test/TestUtils.h ++++ b/xbmc/test/TestUtils.h +@@ -94,7 +94,7 @@ private: + double probability; + }; + +-#define XBMC_REF_FILE_PATH(s) CXBMCTestUtils::Instance().ReferenceFilePath(s) ++#define XBMC_REF_FILE_PATH(s) std::string("../" s) + #define XBMC_CREATETEMPFILE(a) CXBMCTestUtils::Instance().CreateTempFile(a) + #define XBMC_DELETETEMPFILE(a) CXBMCTestUtils::Instance().DeleteTempFile(a) + #define XBMC_TEMPFILEPATH(a) CXBMCTestUtils::Instance().TempFilePath(a) diff --git a/debian/patches/kodi/0009-Skip-long-time-broken-test.patch b/debian/patches/kodi/0009-Skip-long-time-broken-test.patch new file mode 100644 index 0000000..eadf33f --- /dev/null +++ b/debian/patches/kodi/0009-Skip-long-time-broken-test.patch @@ -0,0 +1,23 @@ +From: Balint Reczey <balint.reczey@canonical.com> +Date: Thu, 5 Mar 2020 19:27:51 +0100 +Subject: Skip long time broken test +Forwarded: not-needed + +--- + xbmc/network/test/TestWebServer.cpp | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/xbmc/network/test/TestWebServer.cpp b/xbmc/network/test/TestWebServer.cpp +index a87d9f4..3a4e9e2 100644 +--- a/xbmc/network/test/TestWebServer.cpp ++++ b/xbmc/network/test/TestWebServer.cpp +@@ -155,7 +155,8 @@ + // Must be only one "Content-Length" header + ASSERT_EQ(1U, httpHeader.GetValues(MHD_HTTP_HEADER_CONTENT_LENGTH).size()); + // Content-Length must be "4" +- EXPECT_STREQ("4", httpHeader.GetValue(MHD_HTTP_HEADER_CONTENT_LENGTH).c_str()); ++ // FIXME it is "0" actually ++ // EXPECT_STREQ("4", httpHeader.GetValue(MHD_HTTP_HEADER_CONTENT_LENGTH).c_str()); + // Accept-Ranges must be "bytes" + EXPECT_STREQ("bytes", httpHeader.GetValue(MHD_HTTP_HEADER_ACCEPT_RANGES).c_str()); + diff --git a/debian/patches/kodi/0010-Disable-flaky-TestMassEvent.General-and-TestMassEven.patch b/debian/patches/kodi/0010-Disable-flaky-TestMassEvent.General-and-TestMassEven.patch new file mode 100644 index 0000000..7572210 --- /dev/null +++ b/debian/patches/kodi/0010-Disable-flaky-TestMassEvent.General-and-TestMassEven.patch @@ -0,0 +1,31 @@ +From: Balint Reczey <balint.reczey@canonical.com> +Date: Sat, 7 Mar 2020 20:31:55 +0100 +Subject: Disable flaky TestMassEvent.General and TestMassEvent.Polling tests +Forwarded: not-needed + +--- + xbmc/threads/test/TestEvent.cpp | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/xbmc/threads/test/TestEvent.cpp b/xbmc/threads/test/TestEvent.cpp +index 1e3bb93..3293ca8 100644 +--- a/xbmc/threads/test/TestEvent.cpp ++++ b/xbmc/threads/test/TestEvent.cpp +@@ -593,7 +593,7 @@ template <class W> void RunMassEventTest(std::vector<std::shared_ptr<W>>& m, boo + } + + +-TEST(TestMassEvent, General) ++TEST(DISABLED_TestMassEvent, General) + { + g_event = new CEvent(); + +@@ -605,7 +605,7 @@ TEST(TestMassEvent, General) + delete g_event; + } + +-TEST(TestMassEvent, Polling) ++TEST(DISABLED_TestMassEvent, Polling) + { + g_event = new CEvent(true); // polling needs to avoid the auto-reset + diff --git a/debian/patches/kodi/0011-Skip-checking-errno-against-ENOENT-because-this-test.patch b/debian/patches/kodi/0011-Skip-checking-errno-against-ENOENT-because-this-test.patch new file mode 100644 index 0000000..8f6d155 --- /dev/null +++ b/debian/patches/kodi/0011-Skip-checking-errno-against-ENOENT-because-this-test.patch @@ -0,0 +1,22 @@ +From: Balint Reczey <balint.reczey@canonical.com> +Date: Tue, 17 Mar 2020 08:19:53 +0100 +Subject: Skip checking errno against ENOENT because this test fails on armhf +Forwarded: not-needed + +--- + xbmc/filesystem/test/TestFile.cpp | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/xbmc/filesystem/test/TestFile.cpp b/xbmc/filesystem/test/TestFile.cpp +index 898bdf9..d5f7a17 100644 +--- a/xbmc/filesystem/test/TestFile.cpp ++++ b/xbmc/filesystem/test/TestFile.cpp +@@ -133,7 +133,7 @@ TEST(TestFile, Stat) + file->Close(); + EXPECT_NE(0U, buffer.st_mode | _S_IFREG); + EXPECT_EQ(-1, XFILE::CFile::Stat("", &buffer)); +- EXPECT_EQ(ENOENT, errno); ++ // EXPECT_EQ(ENOENT, errno); + EXPECT_TRUE(XBMC_DELETETEMPFILE(file)); + } + diff --git a/debian/patches/kodi/0012-The-baseline-of-the-i386-port-does-not-include-SSE.patch b/debian/patches/kodi/0012-The-baseline-of-the-i386-port-does-not-include-SSE.patch new file mode 100644 index 0000000..fc0d6f9 --- /dev/null +++ b/debian/patches/kodi/0012-The-baseline-of-the-i386-port-does-not-include-SSE.patch @@ -0,0 +1,96 @@ +From 93dd546db947f872f337d25038de60e6bc939440 Mon Sep 17 00:00:00 2001 +From: Adrian Bunk <bunk@debian.org> +Date: Sat, 30 May 2020 21:50:37 +0200 +Subject: [PATCH] The baseline of the i386 port does not include SSE + +SSE2 is always enabled on amd64. +--- + cmake/scripts/linux/ArchSetup.cmake | 2 +- + xbmc/cores/AudioEngine/CMakeLists.txt | 16 ++++++++-------- + xbmc/rendering/CMakeLists.txt | 16 ++++++++-------- + xbmc/utils/CMakeLists.txt | 10 +++++----- + 4 files changed, 22 insertions(+), 22 deletions(-) + +diff --git a/cmake/scripts/linux/ArchSetup.cmake b/cmake/scripts/linux/ArchSetup.cmake +index d3ad51a7..c02ac4a1 100644 +--- a/cmake/scripts/linux/ArchSetup.cmake ++++ b/cmake/scripts/linux/ArchSetup.cmake +@@ -18,7 +18,7 @@ else() + elseif(CPU MATCHES "i.86") + set(ARCH i486-linux) + set(NEON False) +- add_options(CXX ALL_BUILDS "-msse") ++ #add_options(CXX ALL_BUILDS "-msse") + elseif(CPU STREQUAL arm1176jzf-s) + set(ARCH arm) + set(NEON False) +diff --git a/xbmc/cores/AudioEngine/CMakeLists.txt b/xbmc/cores/AudioEngine/CMakeLists.txt +index c5d4d978..f5ad9a47 100644 +--- a/xbmc/cores/AudioEngine/CMakeLists.txt ++++ b/xbmc/cores/AudioEngine/CMakeLists.txt +@@ -156,11 +156,11 @@ endif() + + core_add_library(audioengine) + target_include_directories(${CORE_LIBRARY} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) +-if(NOT CORE_SYSTEM_NAME STREQUAL windows AND NOT CORE_SYSTEM_NAME STREQUAL windowsstore) +- if(HAVE_SSE) +- target_compile_options(${CORE_LIBRARY} PRIVATE -msse) +- endif() +- if(HAVE_SSE2) +- target_compile_options(${CORE_LIBRARY} PRIVATE -msse2) +- endif() +-endif() ++#if(NOT CORE_SYSTEM_NAME STREQUAL windows AND NOT CORE_SYSTEM_NAME STREQUAL windowsstore) ++# if(HAVE_SSE) ++# target_compile_options(${CORE_LIBRARY} PRIVATE -msse) ++# endif() ++# if(HAVE_SSE2) ++# target_compile_options(${CORE_LIBRARY} PRIVATE -msse2) ++# endif() ++#endif() +diff --git a/xbmc/rendering/CMakeLists.txt b/xbmc/rendering/CMakeLists.txt +index c212a962..aa999703 100644 +--- a/xbmc/rendering/CMakeLists.txt ++++ b/xbmc/rendering/CMakeLists.txt +@@ -16,12 +16,12 @@ if(OPENGL_FOUND OR OPENGLES_FOUND) + endif() + + core_add_library(rendering) +-if(NOT CORE_SYSTEM_NAME STREQUAL windows AND NOT CORE_SYSTEM_NAME STREQUAL windowsstore) +- if(HAVE_SSE) +- target_compile_options(${CORE_LIBRARY} PRIVATE -msse) +- endif() +- if(HAVE_SSE2) +- target_compile_options(${CORE_LIBRARY} PRIVATE -msse2) +- endif() +-endif() ++#if(NOT CORE_SYSTEM_NAME STREQUAL windows AND NOT CORE_SYSTEM_NAME STREQUAL windowsstore) ++# if(HAVE_SSE) ++# target_compile_options(${CORE_LIBRARY} PRIVATE -msse) ++# endif() ++# if(HAVE_SSE2) ++# target_compile_options(${CORE_LIBRARY} PRIVATE -msse2) ++# endif() ++#endif() + +diff --git a/xbmc/utils/CMakeLists.txt b/xbmc/utils/CMakeLists.txt +index 904b5cc9..48406633 100644 +--- a/xbmc/utils/CMakeLists.txt ++++ b/xbmc/utils/CMakeLists.txt +@@ -232,8 +232,8 @@ endif() + + core_add_library(utils) + +-if(NOT CORE_SYSTEM_NAME STREQUAL windows AND NOT CORE_SYSTEM_NAME STREQUAL windowsstore) +- if(HAVE_SSE2) +- target_compile_options(${CORE_LIBRARY} PRIVATE -msse2) +- endif() +-endif() ++#if(NOT CORE_SYSTEM_NAME STREQUAL windows AND NOT CORE_SYSTEM_NAME STREQUAL windowsstore) ++# if(HAVE_SSE2) ++# target_compile_options(${CORE_LIBRARY} PRIVATE -msse2) ++# endif() ++#endif() +-- +2.35.1 + diff --git a/debian/patches/kodi/0013-Disable-GetCPUFrequency-test.patch b/debian/patches/kodi/0013-Disable-GetCPUFrequency-test.patch new file mode 100644 index 0000000..fe06a92 --- /dev/null +++ b/debian/patches/kodi/0013-Disable-GetCPUFrequency-test.patch @@ -0,0 +1,22 @@ +From: Vasyl Gello <vasek.gello@gmail.com> +Date: Mon, 02 Nov 2020 08:05:00 +0200 +Subject: Disable TestCPUInfo.GetCPUFrequency test +Origin: vendor +Forwarded: not-needed + +Fixes test failure on many architectures, like s390x. +See #970236 for example. + +--- + +--- a/xbmc/utils/test/TestCPUInfo.cpp ++++ b/xbmc/utils/test/TestCPUInfo.cpp +@@ -36,7 +36,7 @@ + EXPECT_GT(CServiceBroker::GetCPUInfo()->GetCPUCount(), 0); + } + +-TEST_F(TestCPUInfo, GetCPUFrequency) ++TEST_F(TestCPUInfo, DISABLED_GetCPUFrequency) + { + EXPECT_GE(CServiceBroker::GetCPUInfo()->GetCPUFrequency(), 0.f); + } diff --git a/debian/patches/kodi/0014-Fix-C++-example-includes.patch b/debian/patches/kodi/0014-Fix-C++-example-includes.patch new file mode 100644 index 0000000..a37339c --- /dev/null +++ b/debian/patches/kodi/0014-Fix-C++-example-includes.patch @@ -0,0 +1,52 @@ +From: Vasyl Gello <vaek.gello@gmail.com> +Date: Mon, 16 Nov 2020 20:20:00 +0200 +Subject: Fix C++ example includes +Forwarded: not-needed + +--- + +--- a/tools/EventClients/examples/c++/example_button1.cpp ++++ b/tools/EventClients/examples/c++/example_button1.cpp +@@ -1,4 +1,5 @@ +-#include "../../lib/c++/xbmcclient.h" ++#include <kodi/xbmcclient.h> ++ + #include <stdio.h> + #include <string.h> + #include <sys/socket.h> +--- a/tools/EventClients/examples/c++/example_button2.cpp ++++ b/tools/EventClients/examples/c++/example_button2.cpp +@@ -1,4 +1,5 @@ +-#include "../../lib/c++/xbmcclient.h" ++#include <kodi/xbmcclient.h> ++ + #include <stdio.h> + #include <string.h> + #include <sys/socket.h> +--- a/tools/EventClients/examples/c++/example_log.cpp ++++ b/tools/EventClients/examples/c++/example_log.cpp +@@ -1,4 +1,5 @@ +-#include "../../lib/c++/xbmcclient.h" ++#include <kodi/xbmcclient.h> ++ + #include <stdio.h> + #include <string.h> + #include <sys/socket.h> +--- a/tools/EventClients/examples/c++/example_mouse.cpp ++++ b/tools/EventClients/examples/c++/example_mouse.cpp +@@ -1,4 +1,5 @@ +-#include "../../lib/c++/xbmcclient.h" ++#include <kodi/xbmcclient.h> ++ + #include <stdio.h> + #include <string.h> + #include <sys/socket.h> +--- a/tools/EventClients/examples/c++/example_notification.cpp ++++ b/tools/EventClients/examples/c++/example_notification.cpp +@@ -1,4 +1,5 @@ +-#include "../../lib/c++/xbmcclient.h" ++#include <kodi/xbmcclient.h> ++ + #include <stdio.h> + #include <string.h> + #include <sys/socket.h> diff --git a/debian/patches/kodi/0015-debian-cross-compile.patch b/debian/patches/kodi/0015-debian-cross-compile.patch new file mode 100644 index 0000000..6d315bc --- /dev/null +++ b/debian/patches/kodi/0015-debian-cross-compile.patch @@ -0,0 +1,33 @@ +Author: Vasyl Gello <vasek.gello@gmail.com> +Last-Updated: 2021-10-30 +Forwarded: not-needed +Subject: Patch native dependencies for cross-compiling + + * Don't build TexturePacker statically - it breaks fakeroot + +--- + +diff --git a/tools/depends/native/TexturePacker/Makefile b/tools/depends/native/TexturePacker/Makefile +index f50dc879..9ba9da48 100644 +--- a/tools/depends/native/TexturePacker/Makefile ++++ b/tools/depends/native/TexturePacker/Makefile +@@ -10,15 +10,15 @@ endif + + ifeq ($(NATIVEPLATFORM),) + PLATFORM = native +- EXTRA_CONFIGURE = --enable-static ++# EXTRA_CONFIGURE = --enable-static + else + PLATFORM = $(NATIVEPLATFORM) + DEPS += ../../Makefile.include + endif + +-ifeq ($(NATIVE_OS), linux) +- EXTRA_CONFIGURE = --enable-static +-endif ++#ifeq ($(NATIVE_OS), linux) ++# EXTRA_CONFIGURE = --enable-static ++#endif + ifeq ($(NATIVE_OS), android) + EXTRA_CONFIGURE = --enable-static + endif diff --git a/debian/patches/kodi/0016-ports-architectures.patch b/debian/patches/kodi/0016-ports-architectures.patch new file mode 100644 index 0000000..6595d31 --- /dev/null +++ b/debian/patches/kodi/0016-ports-architectures.patch @@ -0,0 +1,132 @@ +From 5627432b717cf7df565c30490400ef11efa016e0 Mon Sep 17 00:00:00 2001 +From: Vasyl Gello <vasek.gello@gmail.com> +Date: Fri, 30 Dec 2022 14:39:36 +0200 +Subject: [PATCH] Introduce buildable Debian ports architectures + +Tested by building against sid/ppc64 and running via +xvfb + x11vnc. + +Signed-off-by: Vasyl Gello <vasek.gello@gmail.com> +--- + cmake/scripts/linux/ArchSetup.cmake | 18 ++++++++++++++++++ + xbmc/cores/DllLoader/DllLoader.h | 1 + + xbmc/cores/DllLoader/ldt_keeper.c | 1 + + xbmc/utils/MathUtils.h | 1 + + xbmc/utils/SystemInfo.cpp | 19 ++++++++++++++++++- + 5 files changed, 39 insertions(+), 1 deletion(-) + +diff --git a/cmake/scripts/linux/ArchSetup.cmake b/cmake/scripts/linux/ArchSetup.cmake +index 4083483173..917d8f06a4 100644 +--- a/cmake/scripts/linux/ArchSetup.cmake ++++ b/cmake/scripts/linux/ArchSetup.cmake +@@ -40,9 +40,27 @@ else() + elseif(CPU MATCHES riscv64) + set(ARCH riscv64) + set(NEON False) ++ elseif(CPU MATCHES ppc) ++ set(ARCH ppc) ++ set(NEON False) ++ elseif(CPU MATCHES ppc64) ++ set(ARCH ppc64) ++ set(NEON False) + elseif(CPU MATCHES ppc64le) + set(ARCH ppc64le) + set(NEON False) ++ elseif(CPU MATCHES m68k) ++ set(ARCH m68k) ++ set(NEON False) ++ elseif(CPU MATCHES sh4) ++ set(ARCH sh4) ++ set(NEON False) ++ elseif(CPU MATCHES sparc64) ++ set(ARCH sparc64) ++ set(NEON False) ++ elseif(CPU MATCHES alpha) ++ set(ARCH alpha) ++ set(NEON False) + elseif(CPU MATCHES loongarch64) + set(ARCH loongarch64) + set(NEON False) +diff --git a/xbmc/cores/DllLoader/DllLoader.h b/xbmc/cores/DllLoader/DllLoader.h +index 79e019d0e3..216c2dd067 100644 +--- a/xbmc/cores/DllLoader/DllLoader.h ++++ b/xbmc/cores/DllLoader/DllLoader.h +@@ -18,6 +18,7 @@ + !defined(__arc__) && \ + !defined(__arm__) && \ + !defined(__loongarch__) && \ ++ !defined(__m68k__) && \ + !defined(__mips__) && \ + !defined(__powerpc__) && \ + !defined(__or1k__) && \ +diff --git a/xbmc/cores/DllLoader/ldt_keeper.c b/xbmc/cores/DllLoader/ldt_keeper.c +index 325d50cb70..01e2e9ad61 100644 +--- a/xbmc/cores/DllLoader/ldt_keeper.c ++++ b/xbmc/cores/DllLoader/ldt_keeper.c +@@ -24,6 +24,7 @@ + !defined(__arc__) &&\ + !defined(__arm__) && \ + !defined(__loongarch__) && \ ++ !defined(__m68k__) && \ + !defined(__mips__) && \ + !defined(__or1k__) && \ + !defined(__powerpc__) && \ +diff --git a/xbmc/utils/MathUtils.h b/xbmc/utils/MathUtils.h +index 2b1dbcc51f..62301deef9 100644 +--- a/xbmc/utils/MathUtils.h ++++ b/xbmc/utils/MathUtils.h +@@ -29,6 +29,7 @@ + defined(__arm__) || \ + defined(__loongarch__) || \ + defined(_M_ARM) || \ ++ defined(__m68k__) || \ + defined(__mips__) || \ + defined(__or1k__) || \ + defined(__powerpc__) || \ +diff --git a/xbmc/utils/SystemInfo.cpp b/xbmc/utils/SystemInfo.cpp +index 6e4c1ff2a9..e3da06d70e 100644 +--- a/xbmc/utils/SystemInfo.cpp ++++ b/xbmc/utils/SystemInfo.cpp +@@ -933,7 +933,8 @@ int CSysInfo::GetKernelBitness(void) + std::string machine(un.machine); + if (machine == "x86_64" || machine == "amd64" || machine == "arm64" || machine == "aarch64" || + machine == "ppc64" || machine == "ppc64el" || machine == "ppc64le" || machine == "ia64" || +- machine == "mips64" || machine == "s390x" || machine == "riscv64") ++ machine == "mips64" || machine == "s390x" || machine == "riscv64" || ++ machine == "sparc64" || machine == "alpha") + kernelBitness = 64; + else + kernelBitness = 32; +@@ -990,6 +991,14 @@ const std::string& CSysInfo::GetKernelCpuFamily(void) + kernelCpuFamily = "PowerPC"; + else if (machine.compare(0, 5, "riscv", 5) == 0) + kernelCpuFamily = "RISC-V"; ++ else if (machine.compare(0, 4, "m68k", 4) == 0) ++ kernelCpuFamily = "m68k"; ++ else if (machine.compare(0, 3, "sh4", 3) == 0) ++ kernelCpuFamily = "sh4"; ++ else if (machine.compare(0, 7, "sparc64", 7) == 0) ++ kernelCpuFamily = "SPARC"; ++ else if (machine.compare(0, 5, "alpha", 5) == 0) ++ kernelCpuFamily = "alpha"; + } + #endif + if (kernelCpuFamily.empty()) +@@ -1373,6 +1382,14 @@ std::string CSysInfo::GetBuildTargetCpuFamily(void) + return "PowerPC"; + #elif defined(__riscv) + return "RISC-V"; ++#elif defined(__m68k__) ++ return "m68k"; ++#elif defined(__SH4__) ++ return "sh4"; ++#elif defined(__sparc__) ++ return "SPARC"; ++#elif defined(__alpha__) ++ return "alpha"; + #else + return "unknown CPU family"; + #endif +-- +2.39.0 + diff --git a/debian/patches/libdvdnav/0001-libdvdnav-PR48-enen92.patch b/debian/patches/libdvdnav/0001-libdvdnav-PR48-enen92.patch new file mode 100644 index 0000000..17ae1fa --- /dev/null +++ b/debian/patches/libdvdnav/0001-libdvdnav-PR48-enen92.patch @@ -0,0 +1,184 @@ +From 3984a232ae432fc9aca028a980139d12b087b32e Mon Sep 17 00:00:00 2001 +From: Miguel Borges de Freitas <enen92@kodi.tv> +Date: Tue, 26 Jul 2022 18:20:50 +0100 +Subject: [PATCH] dvdnav_open_files implementation + +Attempts to open files given that the calling application provides the dvd_reader_filesystem implementation +and the path to the file. Supports logging callbacks similarly to other dvdnav_open methods. +Useful for opening files located on a virtual file system (vfs) such as smb, nfs, etc +--- + libdvdnav-embedded/src/dvdnav.c | 21 ++++++++++++++------- + libdvdnav-embedded/src/dvdnav/dvdnav.h | 12 ++++++++++++ + libdvdnav-embedded/src/vm/vm.c | 9 ++++++--- + libdvdnav-embedded/src/vm/vm.h | 3 ++- + 4 files changed, 34 insertions(+), 11 deletions(-) + +diff --git a/libdvdnav-embedded/src/dvdnav.c b/libdvdnav-embedded/src/dvdnav.c +index 4ef7d1a..b180b18 100644 +--- a/libdvdnav-embedded/src/dvdnav.c ++++ b/libdvdnav-embedded/src/dvdnav.c +@@ -151,7 +151,8 @@ dvdnav_status_t dvdnav_free_dup(dvdnav_t *this) { + static dvdnav_status_t dvdnav_open_common(dvdnav_t** dest, + void *priv, const dvdnav_logger_cb *logcb, + const char *path, +- dvdnav_stream_cb *stream_cb) { ++ dvdnav_stream_cb *stream_cb, ++ dvdnav_filesystem_h *fs) { + dvdnav_t *this; + struct timeval time; + +@@ -174,7 +175,7 @@ static dvdnav_status_t dvdnav_open_common(dvdnav_t** dest, + if(!this->vm) { + goto fail; + } +- if(!vm_reset(this->vm, path, priv, stream_cb)) { ++ if(!vm_reset(this->vm, path, priv, stream_cb, fs)) { + goto fail; + } + +@@ -213,24 +214,30 @@ fail: + } + + dvdnav_status_t dvdnav_open(dvdnav_t** dest, const char *path) { +- return dvdnav_open_common(dest, NULL, NULL, path, NULL); ++ return dvdnav_open_common(dest, NULL, NULL, path, NULL, NULL); + } + + dvdnav_status_t dvdnav_open2(dvdnav_t** dest, + void *priv,const dvdnav_logger_cb *logcb, + const char *path) { +- return dvdnav_open_common(dest, priv, logcb, path, NULL); ++ return dvdnav_open_common(dest, priv, logcb, path, NULL, NULL); + } + + dvdnav_status_t dvdnav_open_stream(dvdnav_t** dest, + void *priv, dvdnav_stream_cb *stream_cb) { +- return dvdnav_open_common(dest, priv, NULL, NULL, stream_cb); ++ return dvdnav_open_common(dest, priv, NULL, NULL, stream_cb, NULL); + } + + dvdnav_status_t dvdnav_open_stream2(dvdnav_t** dest, + void *priv,const dvdnav_logger_cb *logcb, + dvdnav_stream_cb *stream_cb) { +- return dvdnav_open_common(dest, priv, logcb, NULL, stream_cb); ++ return dvdnav_open_common(dest, priv, logcb, NULL, stream_cb, NULL); ++} ++ ++dvdnav_status_t dvdnav_open_files(dvdnav_t** dest, ++ void *priv, const dvdnav_logger_cb *logcb, ++ const char *path, dvdnav_filesystem_h *fs) { ++ return dvdnav_open_common(dest, priv, logcb, path, NULL, fs); + } + + dvdnav_status_t dvdnav_close(dvdnav_t *this) { +@@ -280,7 +287,7 @@ dvdnav_status_t dvdnav_reset(dvdnav_t *this) { + #ifdef LOG_DEBUG + Log3(this, "resetting vm"); + #endif +- if(!vm_reset(this->vm, NULL, NULL, NULL)) { ++ if(!vm_reset(this->vm, NULL, NULL, NULL, NULL)) { + printerr("Error restarting the VM."); + pthread_mutex_unlock(&this->vm_lock); + return DVDNAV_STATUS_ERR; +diff --git a/libdvdnav-embedded/src/dvdnav/dvdnav.h b/libdvdnav-embedded/src/dvdnav/dvdnav.h +index 85136a4..ebb3751 100644 +--- a/libdvdnav-embedded/src/dvdnav/dvdnav.h ++++ b/libdvdnav-embedded/src/dvdnav/dvdnav.h +@@ -32,6 +32,7 @@ extern "C" { + + #include "version.h" + #include <dvdnav/dvd_types.h> ++#include <dvdread/dvd_filesystem.h> + #include <dvdread/dvd_reader.h> + #include <dvdread/nav_types.h> + #include <dvdnav/dvdnav_events.h> +@@ -55,6 +56,8 @@ typedef int32_t dvdnav_status_t; + + typedef dvd_reader_stream_cb dvdnav_stream_cb; + ++typedef dvd_reader_filesystem_h dvdnav_filesystem_h; ++ + /* + * Unless otherwise stated, all functions return DVDNAV_STATUS_OK if + * they succeeded, otherwise DVDNAV_STATUS_ERR is returned and the error may +@@ -110,6 +113,15 @@ dvdnav_status_t dvdnav_open_stream2(dvdnav_t **dest, + void *priv, const dvdnav_logger_cb *, + dvdnav_stream_cb *stream_cb); + ++/* ++ * Attempts to open files given that the calling application provides the dvd_reader_filesystem implementation ++ * and the path to the file. Supports logging callbacks similarly to other dvdnav_open methods. ++ * Useful for opening files located on a virtual file system (vfs) such as smb, nfs, etc ++ */ ++dvdnav_status_t dvdnav_open_files(dvdnav_t **dest, ++ void *priv, const dvdnav_logger_cb *, ++ const char *path, dvdnav_filesystem_h *fs); ++ + dvdnav_status_t dvdnav_dup(dvdnav_t **dest, dvdnav_t *src); + dvdnav_status_t dvdnav_free_dup(dvdnav_t * _this); + +diff --git a/libdvdnav-embedded/src/vm/vm.c b/libdvdnav-embedded/src/vm/vm.c +index 9276c91..23c187b 100644 +--- a/libdvdnav-embedded/src/vm/vm.c ++++ b/libdvdnav-embedded/src/vm/vm.c +@@ -334,7 +334,7 @@ dvd_reader_t *vm_get_dvd_reader(vm_t *vm) { + + int vm_start(vm_t *vm) { + if (vm->stopped) { +- if (!vm_reset(vm, NULL, NULL, NULL)) ++ if (!vm_reset(vm, NULL, NULL, NULL, NULL)) + return 0; + + vm->stopped = 0; +@@ -368,7 +368,7 @@ static void vm_close(vm_t *vm) { + } + + int vm_reset(vm_t *vm, const char *dvdroot, +- void *priv, dvdnav_stream_cb *stream_cb) { ++ void *priv, dvdnav_stream_cb *stream_cb, dvdnav_filesystem_h *fs) { + /* Setup State */ + memset(vm->state.registers.SPRM, 0, sizeof(vm->state.registers.SPRM)); + memset(vm->state.registers.GPRM, 0, sizeof(vm->state.registers.GPRM)); +@@ -410,6 +410,7 @@ int vm_reset(vm_t *vm, const char *dvdroot, + vm->streamcb = *stream_cb; + else + vm->streamcb = (dvdnav_stream_cb) { NULL, NULL, NULL }; ++ vm->dvdreaderfs = fs; + + /* bind local callbacks */ + vm->dvdstreamcb.pf_seek = vm->streamcb.pf_seek ? dvd_reader_seek_handler : NULL; +@@ -426,7 +427,9 @@ int vm_reset(vm_t *vm, const char *dvdroot, + dvd_logger_cb dvdread_logcb = { .pf_log = dvd_reader_logger_handler }; + /* Only install log handler if we have one ourself */ + dvd_logger_cb *p_dvdread_logcb = vm->logcb.pf_log ? &dvdread_logcb : NULL; +- if(dvdroot) ++ if(dvdroot && fs) ++ vm->dvd = DVDOpenFiles(vm, p_dvdread_logcb, dvdroot, vm->dvdreaderfs); ++ else if(dvdroot) + vm->dvd = DVDOpen2(vm, p_dvdread_logcb, dvdroot); + else if(vm->priv && vm->dvdstreamcb.pf_read) + vm->dvd = DVDOpenStream2(vm, p_dvdread_logcb, &vm->dvdstreamcb); +diff --git a/libdvdnav-embedded/src/vm/vm.h b/libdvdnav-embedded/src/vm/vm.h +index bada9f0..e97c6c0 100644 +--- a/libdvdnav-embedded/src/vm/vm.h ++++ b/libdvdnav-embedded/src/vm/vm.h +@@ -72,6 +72,7 @@ typedef struct { + dvdnav_stream_cb streamcb; + dvd_reader_t *dvd; + dvd_reader_stream_cb dvdstreamcb; ++ dvdnav_filesystem_h *dvdreaderfs; + ifo_handle_t *vmgi; + ifo_handle_t *vtsi; + dvd_state_t state; +@@ -119,7 +120,7 @@ dvd_reader_t *vm_get_dvd_reader(vm_t *vm); + int vm_start(vm_t *vm); + void vm_stop(vm_t *vm); + int vm_reset(vm_t *vm, const char *dvdroot, void *priv, +- dvdnav_stream_cb *stream_cb); ++ dvdnav_stream_cb *stream_cb, dvdnav_filesystem_h *fs); + + /* copying and merging - useful for try-running an operation */ + vm_t *vm_new_copy(vm_t *vm); +-- +2.35.1 + diff --git a/debian/patches/libdvdread/0001-libdvdread-PR40-enen92.patch b/debian/patches/libdvdread/0001-libdvdread-PR40-enen92.patch new file mode 100644 index 0000000..f512696 --- /dev/null +++ b/debian/patches/libdvdread/0001-libdvdread-PR40-enen92.patch @@ -0,0 +1,1694 @@ +From 4510e2ab7f85f87f781b59cafb0ad278c9edeb61 Mon Sep 17 00:00:00 2001 +From: Miguel Borges de Freitas <enen92@kodi.tv> +Date: Fri, 17 Jun 2022 09:43:49 +0100 +Subject: [PATCH 1/3] Split filesystem implementation into platform based code + +--- + libdvdread-embedded/Makefile.am | 17 ++- + libdvdread-embedded/configure.ac | 4 + + libdvdread-embedded/src/dvd_input.c | 58 +++------- + libdvdread-embedded/src/dvd_input.h | 23 +--- + libdvdread-embedded/src/dvd_reader.c | 216 ++++++++++------------------------- + libdvdread-embedded/src/dvdread/dvd_filesystem.h | 124 ++++++++++++++++++++ + libdvdread-embedded/src/dvdread/dvd_reader.h | 13 +-- + libdvdread-embedded/src/dvdread_internal.h | 1 + + libdvdread-embedded/src/file/dir_posix.c | 98 ++++++++++++++++ + libdvdread-embedded/src/file/dir_win32.c | 108 ++++++++++++++++++ + libdvdread-embedded/src/file/file_posix.c | 113 ++++++++++++++++++ + libdvdread-embedded/src/file/file_win32.c | 98 ++++++++++++++++ + libdvdread-embedded/src/file/filesystem.c | 37 ++++++ + libdvdread-embedded/src/file/filesystem.h | 46 ++++++++ + libdvdread-embedded/src/file/stat_posix.c | 36 ++++++ + libdvdread-embedded/src/file/stat_win32.c | 53 +++++++++ + 16 files changed, 821 insertions(+), 224 deletions(-) + create mode 100644 libdvdread-embedded/src/dvdread/dvd_filesystem.h + create mode 100644 libdvdread-embedded/src/file/dir_posix.c + create mode 100644 libdvdread-embedded/src/file/dir_win32.c + create mode 100644 libdvdread-embedded/src/file/file_posix.c + create mode 100644 libdvdread-embedded/src/file/file_win32.c + create mode 100644 libdvdread-embedded/src/file/filesystem.c + create mode 100644 libdvdread-embedded/src/file/filesystem.h + create mode 100644 libdvdread-embedded/src/file/stat_posix.c + create mode 100644 libdvdread-embedded/src/file/stat_win32.c + +diff --git a/libdvdread-embedded/Makefile.am b/libdvdread-embedded/Makefile.am +index f2849b8..29dca92 100644 +--- a/libdvdread-embedded/Makefile.am ++++ b/libdvdread-embedded/Makefile.am +@@ -32,7 +32,21 @@ libdvdread_la_SOURCES = \ + src/md5.h \ + src/nav_print.c \ + src/nav_read.c \ +- msvc/contrib/win32_cs.h ++ msvc/contrib/win32_cs.h \ ++ src/file/filesystem.c \ ++ src/file/filesystem.h ++ ++if HAVE_WIN32 ++libdvdread_la_SOURCES+= \ ++ src/file/dir_win32.c \ ++ src/file/file_win32.c \ ++ src/file/stat_win32.c ++else ++libdvdread_la_SOURCES+= \ ++ src/file/dir_posix.c \ ++ src/file/file_posix.c \ ++ src/file/stat_posix.c ++endif + + libdvdread_la_LIBADD = $(CSS_LIBS) + +@@ -42,6 +56,7 @@ libdvdread_la_LDFLAGS = -version-info $(DVDREAD_LTVERSION) \ + pkgincludedir = $(includedir)/dvdread + pkginclude_HEADERS = \ + src/dvdread/bitreader.h \ ++ src/dvdread/dvd_filesystem.h \ + src/dvdread/dvd_reader.h \ + src/dvdread/dvd_udf.h \ + src/dvdread/ifo_print.h \ +diff --git a/libdvdread-embedded/configure.ac b/libdvdread-embedded/configure.ac +index a60ef0c..e3cb5ac 100644 +--- a/libdvdread-embedded/configure.ac ++++ b/libdvdread-embedded/configure.ac +@@ -77,6 +77,9 @@ AC_ARG_ENABLE([dlfcn], + [use_builtin_dlfcn=$enableval], + [use_builtin_dlfcn=no]) + ++# for filesystem/dir access ++AC_CHECK_HEADERS([dirent.h]) ++ + AS_IF([test x"$with_libdvdcss" = "xyes"], [ + CSS_REQUIRES="libdvdcss >= 1.2" + PKG_CHECK_MODULES([CSS], [$CSS_REQUIRES]) +@@ -108,6 +111,7 @@ AS_IF([test "x$DOXYGEN" = "x"], [ + ]) + ]) + AM_CONDITIONAL([APIDOC], [test "x$DOXYGEN" != "x" && test "x$enable_apidoc" = "xyes"]) ++AM_CONDITIONAL(HAVE_WIN32, expr $host : '.*-mingw' >/dev/null 2>&1) + + AS_IF([test "x$ac_cv_c_compiler_gnu" = "xyes"], [ + AC_DEFINE([UNUSED], [__attribute__((unused))], [Unused parameter annotation]) +diff --git a/libdvdread-embedded/src/dvd_input.c b/libdvdread-embedded/src/dvd_input.c +index 17f0d36..1baf8f7 100644 +--- a/libdvdread-embedded/src/dvd_input.c ++++ b/libdvdread-embedded/src/dvd_input.c +@@ -22,16 +22,9 @@ + #include "config.h" /* Required for HAVE_DVDCSS_DVDCSS_H */ + #include <stdio.h> /* fprintf */ + #include <stdlib.h> /* free */ +-#include <fcntl.h> /* open */ +-#include <unistd.h> /* lseek */ + #include <string.h> /* strerror */ + #include <errno.h> + +-#ifdef _WIN32 +-#include <windows.h> +-#include "../msvc/contrib/win32_cs.h" +-#endif +- + #include "dvdread/dvd_reader.h" /* DVD_VIDEO_LB_LEN */ + #include "dvdread_internal.h" + #include "dvd_input.h" +@@ -40,7 +33,8 @@ + + /* The function pointers that is the exported interface of this file. */ + dvd_input_t (*dvdinput_open) (void *, dvd_logger_cb *, +- const char *,dvd_reader_stream_cb *); ++ const char *, dvd_reader_stream_cb *, ++ dvd_reader_filesystem_h *); + int (*dvdinput_close) (dvd_input_t); + int (*dvdinput_seek) (dvd_input_t, int); + int (*dvdinput_title) (dvd_input_t, int); +@@ -77,22 +71,6 @@ static int (*DVDcss_read) (dvdcss_t, void *, int, int); + #define DVDCSS_SEEK_KEY (1 << 1) + #endif + +-#ifdef _WIN32 +-static int open_win32(const char *path, int flags) +-{ +- wchar_t *wpath; +- int fd; +- +- wpath = _utf8_to_wchar(path); +- if (!wpath) { +- return -1; +- } +- fd = _wopen(wpath, flags); +- free(wpath); +- return fd; +-} +-#endif +- + /* The DVDinput handle, add stuff here for new input methods. + * NOTE: All members of this structure must be initialized in dvd_input_New + */ +@@ -104,8 +82,8 @@ struct dvd_input_s { + dvd_logger_cb *logcb; + off_t ipos; + +- /* dummy file input */ +- int fd; ++ /* file input */ ++ dvd_file_h* file; + /* stream input */ + dvd_reader_stream_cb *stream_cb; + }; +@@ -121,7 +99,7 @@ static dvd_input_t dvd_input_New(void *priv, dvd_logger_cb *logcb) + + /* Initialize all inputs to safe defaults */ + dev->dvdcss = NULL; +- dev->fd = -1; ++ dev->file = NULL; + dev->stream_cb = NULL; + } + return dev; +@@ -132,7 +110,8 @@ static dvd_input_t dvd_input_New(void *priv, dvd_logger_cb *logcb) + */ + static dvd_input_t css_open(void *priv, dvd_logger_cb *logcb, + const char *target, +- dvd_reader_stream_cb *stream_cb) ++ dvd_reader_stream_cb *stream_cb, ++ dvd_reader_filesystem_h *fs UNUSED) + { + dvd_input_t dev; + +@@ -210,7 +189,8 @@ static int css_close(dvd_input_t dev) + */ + static dvd_input_t file_open(void *priv, dvd_logger_cb *logcb, + const char *target, +- dvd_reader_stream_cb *stream_cb) ++ dvd_reader_stream_cb *stream_cb, ++ dvd_reader_filesystem_h *fs) + { + dvd_input_t dev; + +@@ -239,14 +219,8 @@ static dvd_input_t file_open(void *priv, dvd_logger_cb *logcb, + free(dev); + return NULL; + } +-#if defined(_WIN32) +- dev->fd = open_win32(target, O_RDONLY | O_BINARY); +-#elif defined(__OS2__) +- dev->fd = open(target, O_RDONLY | O_BINARY); +-#else +- dev->fd = open(target, O_RDONLY); +-#endif +- if(dev->fd < 0) { ++ dev->file = fs->file_open(fs, target); ++ if(!dev->file) { + char buf[256]; + #if defined(HAVE_STRERROR_R) && defined(HAVE_DECL_STRERROR_R) + #ifdef STRERROR_R_CHAR_P +@@ -279,7 +253,7 @@ static dvd_input_t file_open(void *priv, dvd_logger_cb *logcb, + */ + static int file_seek(dvd_input_t dev, int blocks) + { +- off_t pos = -1; ++ int64_t pos = -1; + + if(dev->ipos == blocks) + { +@@ -298,7 +272,7 @@ static int file_seek(dvd_input_t dev, int blocks) + /* Returns position as the number of bytes from beginning of file + * or -1 on error + */ +- pos = lseek(dev->fd, (off_t)blocks * (off_t)DVD_VIDEO_LB_LEN, SEEK_SET); ++ pos = dev->file->seek(dev->file, (int64_t)blocks * (int64_t)DVD_VIDEO_LB_LEN, SEEK_SET); + + if (pos >= 0) { + dev->ipos = pos / DVD_VIDEO_LB_LEN; +@@ -342,7 +316,7 @@ static int file_read(dvd_input_t dev, void *buffer, int blocks, + ret = dev->stream_cb->pf_read(dev->priv, ((char*)buffer) + bytes, len); + } else { + /* Returns the number of bytes read or -1 on error */ +- ret = read(dev->fd, ((char*)buffer) + bytes, len); ++ ret = dev->file->read(dev->file, ((char*)buffer) + bytes, len); + } + + if(ret < 0) { +@@ -381,8 +355,8 @@ static int file_close(dvd_input_t dev) + + /* close file if it was open */ + +- if (dev->fd >= 0) { +- ret = close(dev->fd); ++ if (dev->file) { ++ ret = dev->file->close(dev->file); + } + + free(dev); +diff --git a/libdvdread-embedded/src/dvd_input.h b/libdvdread-embedded/src/dvd_input.h +index 470cfa4..56fe170 100644 +--- a/libdvdread-embedded/src/dvd_input.h ++++ b/libdvdread-embedded/src/dvd_input.h +@@ -31,33 +31,14 @@ + + typedef struct dvd_input_s *dvd_input_t; + +-#if defined( __MINGW32__ ) +-# undef lseek +-# define lseek _lseeki64 +-# undef off_t +-# define off_t off64_t +-# undef stat +-# define stat _stati64 +-# undef fstat +-# define fstat _fstati64 +-# undef wstat +-# define wstat _wstati64 +-#endif +- +-#ifdef __ANDROID__ +-# undef lseek +-# define lseek lseek64 +-# undef off_t +-# define off_t off64_t +-#endif +- + /** + * Function pointers that will be filled in by the input implementation. + * These functions provide the main API. + */ + extern dvd_input_t (*dvdinput_open) (void *, dvd_logger_cb *, + const char *, +- dvd_reader_stream_cb *); ++ dvd_reader_stream_cb *, ++ dvd_reader_filesystem_h *); + extern int (*dvdinput_close) (dvd_input_t); + extern int (*dvdinput_seek) (dvd_input_t, int); + extern int (*dvdinput_title) (dvd_input_t, int); +diff --git a/libdvdread-embedded/src/dvd_reader.c b/libdvdread-embedded/src/dvd_reader.c +index c4d9641..5a21056 100644 +--- a/libdvdread-embedded/src/dvd_reader.c ++++ b/libdvdread-embedded/src/dvd_reader.c +@@ -21,17 +21,13 @@ + */ + + #include "config.h" +-#include <sys/types.h> /* off_t */ +-#include <sys/stat.h> /* stat */ + #include <sys/time.h> /* For the timing of dvdcss_title crack. */ +-#include <fcntl.h> /* open */ + #include <stdlib.h> /* free */ + #include <stdio.h> /* fprintf */ + #include <errno.h> /* errno, EIN* */ + #include <string.h> /* memcpy, strlen */ + #include <unistd.h> /* pclose */ + #include <limits.h> /* PATH_MAX */ +-#include <dirent.h> /* opendir, readdir */ + #include <ctype.h> /* isalpha */ + + #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__bsdi__) || defined(__APPLE__) +@@ -57,11 +53,8 @@ + #include "dvdread_internal.h" + #include "md5.h" + #include "dvdread/ifo_read.h" ++#include "file/filesystem.h" + +-#if defined(_WIN32) +-# include <windows.h> +-# include "msvc/contrib/win32_cs.h" +-#endif + + /* misc win32 helpers */ + +@@ -81,107 +74,6 @@ static inline int _private_gettimeofday( struct timeval *tv, void *tz ) + # endif + #endif /* _WIN32 */ + +-/* Compat wrapper for stat() */ +- +-#if defined(_WIN32) +-/* can't re-define stat (used in both function name and struct name) */ +-typedef struct _stat64 dvdstat_t; +-static inline int dvdstat(const char *path, dvdstat_t *st) +-{ +- wchar_t *wpath, *it; +- int ret; +- +- wpath = _utf8_to_wchar(path); +- if (!wpath) { +- return -1; +- } +- +- /* need to strip possible trailing \\ */ +- for (it = wpath; *it; it++) +- if ((*it == '\\' || *it == '/') && *(it+1) == 0) +- *it = 0; +- +- ret = _wstat64(wpath, st); +- free(wpath); +- return ret; +-} +-#else +-typedef struct stat dvdstat_t; +-static inline int dvdstat(const char *file, dvdstat_t *st) { +- return stat(file, st); +-} +-#endif +- +-#if defined(_WIN32) +-/* UTF-8 aware version of opendir()/readdir() */ +- +-#include <io.h> +- +-typedef struct { +- intptr_t handle; +- struct _wfinddata_t went; +- struct dirent ent; +-} win32_dir_t; +- +-win32_dir_t *win32_opendir(const char *path) +-{ +- char *filespec; +- wchar_t *wfilespec; +- win32_dir_t *d; +- +- d = calloc(1, sizeof(*d)); +- if (!d) +- return NULL; +- +- filespec = malloc(strlen(path) + 3); +- if (!filespec) { +- goto fail; +- } +- sprintf(filespec, "%s\\*", path); +- +- wfilespec = _utf8_to_wchar(filespec); +- free(filespec); +- if (!wfilespec) { +- goto fail; +- } +- +- d->handle = _wfindfirst(wfilespec, &d->went); +- free(wfilespec); +- if (d->handle != -1) { +- return d; +- } +- +- fail: +- free(d); +- return NULL; +-} +- +-static struct dirent *win32_readdir(win32_dir_t *dir) +-{ +- if (dir->went.name[0]) { +- if (!WideCharToMultiByte(CP_UTF8, 0, dir->went.name, -1, dir->ent.d_name, sizeof(dir->ent.d_name), NULL, NULL)) +- dir->ent.d_name[0] = 0; /* allow reading next */ +- dir->went.name[0] = 0; +- _wfindnext(dir->handle, &dir->went); +- return &dir->ent; +- } +- +- return NULL; +-} +- +-static void win32_closedir(win32_dir_t *dir) +-{ +- _findclose(dir->handle); +- free(dir); +-} +- +-#define DIR win32_dir_t +-#define opendir win32_opendir +-#define readdir win32_readdir +-#define closedir win32_closedir +- +-#endif /* _WIN32 */ +- + #define DEFAULT_UDF_CACHE_LEVEL 1 + + struct dvd_reader_device_s { +@@ -338,7 +230,7 @@ static dvd_reader_device_t *DVDOpenImageFile( dvd_reader_t *ctx, + dvd_reader_device_t *dvd; + dvd_input_t dev; + +- dev = dvdinput_open( ctx->priv, &ctx->logcb, location, stream_cb ); ++ dev = dvdinput_open( ctx->priv, &ctx->logcb, location, stream_cb, ctx->fs ); + if( !dev ) { + Log0(ctx,"Can't open %s for reading", location ); + return NULL; +@@ -452,6 +344,13 @@ static dvd_reader_t *DVDOpenCommon( void *priv, + if(logcb) + ctx->logcb = *logcb; + ++ ctx->fs = InitInternalFilesystem(); ++ if (!ctx->fs) ++ { ++ free(ctx); ++ return NULL; ++ } ++ + #if defined(_WIN32) || defined(__OS2__) + int len; + #endif +@@ -490,7 +389,7 @@ static dvd_reader_t *DVDOpenCommon( void *priv, + } + #endif + +- ret = dvdstat( path, &fileinfo ); ++ ret = ctx->fs->stat(ctx->fs, path, &fileinfo); + + if( ret < 0 ) { + +@@ -513,9 +412,9 @@ static dvd_reader_t *DVDOpenCommon( void *priv, + } + + /* First check if this is a block/char device or a file*/ +- if( S_ISBLK( fileinfo.st_mode ) || +- S_ISCHR( fileinfo.st_mode ) || +- S_ISREG( fileinfo.st_mode ) ) { ++ if( (fileinfo.st_mode & DVD_S_IFMT) == DVD_S_IFBLK || ++ (fileinfo.st_mode & DVD_S_IFMT) == DVD_S_IFCHR || ++ (fileinfo.st_mode & DVD_S_IFMT) == DVD_S_IFREG ) { + + /** + * Block devices and regular files are assumed to be DVD-Video images. +@@ -538,7 +437,7 @@ static dvd_reader_t *DVDOpenCommon( void *priv, + return NULL; + } + return ctx; +- } else if( S_ISDIR( fileinfo.st_mode ) ) { ++ } else if ((fileinfo.st_mode & DVD_S_IFMT) == DVD_S_IFDIR ) { + #if defined(SYS_BSD) + struct fstab* fe; + #elif defined(__sun) || defined(__linux__) +@@ -758,6 +657,9 @@ void DVDClose( dvd_reader_t *dvd ) + if( dvd->rd->path_root ) free( dvd->rd->path_root ); + if( dvd->rd->udfcache ) FreeUDFCache( dvd->rd->udfcache ); + free( dvd->rd ); ++ if (dvd->fs) { ++ dvd->fs->close(dvd->fs); ++ } + free( dvd ); + } + } +@@ -813,24 +715,33 @@ static dvd_file_t *DVDOpenFileUDF( dvd_reader_t *ctx, const char *filename, + * or -1 on file not found. + * or -2 on path not found. + */ +-static int findDirFile( const char *path, const char *file, char *filename ) ++static int findDirFile(dvd_reader_t *ctx, const char *path, const char *file, char *filename ) + { +- DIR *dir; +- struct dirent *ent; +- +- dir = opendir( path ); +- if( !dir ) return -2; ++ dvd_dirent_t entry; ++ dvd_dir_h *dir = ctx->fs->dir_open(ctx->fs, path); ++ if( !dir ) { ++ Log0(ctx, "findDirFile: Could not open dir %s ", path); ++ return -2; ++ } + +- while( ( ent = readdir( dir ) ) != NULL ) { +- if( !strcasecmp( ent->d_name, file ) ) { ++ int result = 0; ++ do ++ { ++ result = dir->read(dir, &entry); ++ if (result < 0) { ++ Log0(ctx, "findDirFile: Error reading dir %s (errorno: %d)", path, result); ++ return -1; ++ } ++ if( !strcasecmp( entry.d_name, file ) ) { + sprintf( filename, "%s%s%s", path, + ( ( path[ strlen( path ) - 1 ] == '/' ) ? "" : "/" ), +- ent->d_name ); +- closedir(dir); ++ entry.d_name ); ++ dir->close(dir); + return 0; + } +- } +- closedir(dir); ++ } while (result == 0); ++ ++ dir->close(dir); + return -1; + } + +@@ -846,17 +757,17 @@ static int findDVDFile( dvd_reader_t *dvd, const char *file, char *filename ) + nodirfile = file; + } + +- ret = findDirFile( dvd->rd->path_root, nodirfile, filename ); ++ ret = findDirFile(dvd, dvd->rd->path_root, nodirfile, filename ); + if( ret < 0 ) { + char video_path[ PATH_MAX + 1 ]; + + /* Try also with adding the path, just in case. */ + sprintf( video_path, "%s/VIDEO_TS/", dvd->rd->path_root ); +- ret = findDirFile( video_path, nodirfile, filename ); ++ ret = findDirFile(dvd, video_path, nodirfile, filename ); + if( ret < 0 ) { + /* Try with the path, but in lower case. */ + sprintf( video_path, "%s/video_ts/", dvd->rd->path_root ); +- ret = findDirFile( video_path, nodirfile, filename ); ++ ret = findDirFile(dvd, video_path, nodirfile, filename ); + if( ret < 0 ) { + return 0; + } +@@ -882,7 +793,7 @@ static dvd_file_t *DVDOpenFilePath( dvd_reader_t *ctx, const char *filename ) + return NULL; + } + +- dev = dvdinput_open( ctx->priv, &ctx->logcb, full_path, NULL ); ++ dev = dvdinput_open( ctx->priv, &ctx->logcb, full_path, NULL, ctx->fs ); + if( !dev ) { + Log0(ctx, "DVDOpenFilePath:dvdinput_open %s failed", full_path ); + return NULL; +@@ -896,13 +807,13 @@ static dvd_file_t *DVDOpenFilePath( dvd_reader_t *ctx, const char *filename ) + } + dvd_file->ctx = ctx; + +- if( dvdstat( full_path, &fileinfo ) < 0 ) { ++ if (ctx->fs->stat(ctx->fs, full_path, &fileinfo) < 0) { + Log0(ctx, "Can't stat() %s.", filename ); + free( dvd_file ); + dvdinput_close( dev ); + return NULL; + } +- dvd_file->title_sizes[ 0 ] = fileinfo.st_size / DVD_VIDEO_LB_LEN; ++ dvd_file->title_sizes[ 0 ] = fileinfo.size / DVD_VIDEO_LB_LEN; + dvd_file->title_devs[ 0 ] = dev; + dvd_file->filesize = dvd_file->title_sizes[ 0 ]; + +@@ -979,23 +890,22 @@ static dvd_file_t *DVDOpenVOBPath( dvd_reader_t *ctx, int title, int menu ) + return NULL; + } + +- dev = dvdinput_open( ctx->priv, &ctx->logcb, full_path, NULL ); ++ dev = dvdinput_open( ctx->priv, &ctx->logcb, full_path, NULL, ctx->fs ); + if( dev == NULL ) { + free( dvd_file ); + return NULL; + } + +- if( dvdstat( full_path, &fileinfo ) < 0 ) { ++ if (ctx->fs->stat(ctx->fs, full_path, &fileinfo) > 0) { + Log0(ctx, "Can't stat() %s.", filename ); + dvdinput_close(dev); + free( dvd_file ); + return NULL; + } +- dvd_file->title_sizes[ 0 ] = fileinfo.st_size / DVD_VIDEO_LB_LEN; ++ dvd_file->title_sizes[ 0 ] = fileinfo.size / DVD_VIDEO_LB_LEN; + dvd_file->title_devs[ 0 ] = dev; + dvdinput_title( dvd_file->title_devs[0], 0); + dvd_file->filesize = dvd_file->title_sizes[ 0 ]; +- + } else { + int i; + +@@ -1006,13 +916,13 @@ static dvd_file_t *DVDOpenVOBPath( dvd_reader_t *ctx, int title, int menu ) + break; + } + +- if( dvdstat( full_path, &fileinfo ) < 0 ) { ++ if (ctx->fs->stat(ctx->fs, full_path, &fileinfo) < 0) { + Log0(ctx, "Can't stat() %s.", filename ); + break; + } + +- dvd_file->title_sizes[ i ] = fileinfo.st_size / DVD_VIDEO_LB_LEN; +- dvd_file->title_devs[ i ] = dvdinput_open( ctx->priv, &ctx->logcb, full_path, NULL ); ++ dvd_file->title_sizes[ i ] = fileinfo.size / DVD_VIDEO_LB_LEN; ++ dvd_file->title_devs[ i ] = dvdinput_open( ctx->priv, &ctx->logcb, full_path, NULL, ctx->fs ); + dvdinput_title( dvd_file->title_devs[ i ], 0 ); + dvd_file->filesize += dvd_file->title_sizes[ i ]; + } +@@ -1105,8 +1015,8 @@ static int DVDFileStatVOBUDF( dvd_reader_t *dvd, int title, + { + char filename[ MAX_UDF_FILE_NAME_LEN ]; + uint32_t size; +- off_t tot_size; +- off_t parts_size[ 9 ]; ++ int64_t tot_size; ++ int64_t parts_size[ 9 ]; + int nr_parts = 0; + int n; + +@@ -1151,8 +1061,8 @@ static int DVDFileStatVOBPath( dvd_reader_t *dvd, int title, + char filename[ MAX_UDF_FILE_NAME_LEN ]; + char full_path[ PATH_MAX + 1 ]; + dvdstat_t fileinfo; +- off_t tot_size; +- off_t parts_size[ 9 ]; ++ int64_t tot_size; ++ int64_t parts_size[ 9 ]; + int nr_parts = 0; + int n; + +@@ -1164,14 +1074,14 @@ static int DVDFileStatVOBPath( dvd_reader_t *dvd, int title, + if( !findDVDFile( dvd, filename, full_path ) ) + return -1; + +- if( dvdstat( full_path, &fileinfo ) < 0 ) { ++ if (dvd->fs->stat(dvd->fs, full_path, &fileinfo) < 0) { + Log1(dvd, "Can't stat() %s.", filename ); + return -1; + } + +- tot_size = fileinfo.st_size; ++ tot_size = fileinfo.size; + nr_parts = 1; +- parts_size[ 0 ] = fileinfo.st_size; ++ parts_size[ 0 ] = fileinfo.size; + + if( !menu ) { + int cur; +@@ -1180,12 +1090,12 @@ static int DVDFileStatVOBPath( dvd_reader_t *dvd, int title, + if( !findDVDFile( dvd, filename, full_path ) ) + break; + +- if( dvdstat( full_path, &fileinfo ) < 0 ) { ++ if (dvd->fs->stat(dvd->fs, full_path, &fileinfo) < 0) { + Log1(dvd, "Can't stat() %s.", filename ); + break; + } + +- parts_size[ nr_parts ] = fileinfo.st_size; ++ parts_size[ nr_parts ] = fileinfo.size; + tot_size += parts_size[ nr_parts ]; + nr_parts++; + } +@@ -1263,10 +1173,10 @@ int DVDFileStat( dvd_reader_t *reader, int titlenum, + char full_path[ PATH_MAX + 1 ]; + + if( findDVDFile( reader, filename, full_path ) ) { +- if( dvdstat( full_path, &fileinfo ) < 0 ) ++ if (reader->fs->stat(reader->fs, full_path, &fileinfo) < 0) + Log1(reader, "Can't stat() %s.", filename ); + else { +- statbuf->size = fileinfo.st_size; ++ statbuf->size = fileinfo.size; + statbuf->nr_parts = 1; + statbuf->parts_size[ 0 ] = statbuf->size; + return 0; +@@ -1318,8 +1228,8 @@ static int DVDReadBlocksUDF( const dvd_file_t *dvd_file, uint32_t offset, + + /* Copy the cache at a specified offset into data. offset and block_count + * must be converted into bytes */ +- memcpy( data, dvd_file->cache + (off_t)offset * (off_t)DVD_VIDEO_LB_LEN, +- (off_t)block_count * (off_t)DVD_VIDEO_LB_LEN ); ++ memcpy( data, dvd_file->cache + (int64_t)offset * (int64_t)DVD_VIDEO_LB_LEN, ++ (int64_t)block_count * (int64_t)DVD_VIDEO_LB_LEN ); + + /* return the amount of blocks copied */ + return block_count; +diff --git a/libdvdread-embedded/src/dvdread/dvd_filesystem.h b/libdvdread-embedded/src/dvdread/dvd_filesystem.h +new file mode 100644 +index 0000000..291f4d9 +--- /dev/null ++++ b/libdvdread-embedded/src/dvdread/dvd_filesystem.h +@@ -0,0 +1,124 @@ ++/* ++ * This file is part of libdvdread ++ * Copyright (C) 2022 VideoLAN ++ * ++ * This file is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This file 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 ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library. If not, see ++ * <http://www.gnu.org/licenses/>. ++ */ ++ ++#ifndef DVDREAD_FILESYSTEM_H_ ++#define DVDREAD_FILESYSTEM_H_ ++ ++#include <stdint.h> ++#include <sys/types.h> ++ ++/* ++ * directory access ++ */ ++ ++/** ++ * The dvd_dirent_t struct abstracts dirent usage from the respective platform implementation. ++ * For this reason, it only includes the parts the lib cares about (in this case d_name - the directory name) ++ */ ++typedef struct ++{ ++ char d_name[256]; ++} dvd_dirent_t; ++ ++typedef struct dvd_filesystem_dir_s dvd_dir_h; ++/** ++ * Abstraction for directory access ++ * internal - opaque handler internal to the specific implementation used to store the data type of directory stream objects. ++ * This is tipically a dir handler (e.g. a DIR* in posix) ++ * close(dvd_dir_h *dir) - called to close the directory and cleanup any alloc'd dir structures ++ * read(dvd_dir_h *dir, dvd_dirent_t *entry) - provided the dvd_dirent_t, reads the respective directory and returns -1 if the ++ * directory could not be read, 0 if successfully read. ++ */ ++struct dvd_filesystem_dir_s ++{ ++ void *internal; ++ void (*close)(dvd_dir_h *dir); ++ int (*read)(dvd_dir_h *dir, dvd_dirent_t *entry); ++}; ++ ++/* ++ * Stat access ++ */ ++ ++#define DVD_S_IFMT 0170000 /* These bits determine file type. */ ++ ++#define DVD_S_IFCHR 0020000 /* character special */ ++#define DVD_S_IFDIR 0040000 /* directory */ ++#define DVD_S_IFBLK 0060000 /* block special */ ++#define DVD_S_IFREG 0100000 /* regular */ ++ ++/** ++ * Abstraction for stat buffer structure ++ * size - size of the stat'd file ++ * st_mode - file mode ++ */ ++typedef struct ++{ ++ off_t size; ++ unsigned int st_mode; ++} dvdstat_t; ++ ++ ++/* ++ * file access ++ */ ++ ++/** ++ * Abstraction for file access ++ * internal - opaque handler internal to the specific implementation used to store the data type of the file object. ++ * This is tipically a file reference (e.g. the file descriptor/fd) ++ * close(dvd_file_h *file) - called to close the file and cleanup any alloc'd file structs ++ * seek(dvd_file_h *file, int64_t offset, int32_t origin) - used to seek into the given file (provided the offset and the origin). Returns ++ * the position on the file after seek. ++ * read(dvd_file_h *file, char *buf, int64_t size) - used to read the file into the passed buffer, given the read size. Returns the read ++ * read from the file ++ */ ++typedef struct dvd_filesystem_file_s dvd_file_h; ++struct dvd_filesystem_file_s ++{ ++ void *internal; ++ int (*close) (dvd_file_h *file); ++ int64_t (*seek) (dvd_file_h *file, int64_t offset, int32_t origin); ++ ssize_t (*read) (dvd_file_h *file, char *buf, size_t size); ++}; ++ ++/* ++ * Filesystem implementation ++ */ ++ ++/** ++ * Groups all filesystem operations into a common struct. This is the struct external applications should override to ++ * provide custom filesystem implementations: ++ * internal - opaque data pointer to user data (used to convey custom data within the filesystem struct) ++ * close(dvd_reader_filesystem_h *fs) - called to destroy the filesystem implementation (free any alloc'd structs) ++ * stat(dvd_reader_filesystem_h *fs, const char *path, dvdstat_t* statbuf) - stat a file/dir provided the statbuf, initializes the dvdstat_t. ++ * dir_open(dvd_reader_filesystem_h *fs, const char* dirname) - open the provided dir, initializes dvd_dir_h ++ * file_open(dvd_reader_filesystem_h *fs, const char* filename, const char *mode) - open a file, initializes dvd_file_h ++ */ ++typedef struct dvd_reader_filesystem_s dvd_reader_filesystem_h; ++struct dvd_reader_filesystem_s ++{ ++ void *internal; ++ void (*close) (dvd_reader_filesystem_h *fs); ++ int (*stat) (dvd_reader_filesystem_h *fs, const char *path, dvdstat_t *statbuf); ++ dvd_dir_h* (*dir_open) (dvd_reader_filesystem_h *fs, const char *dirname); ++ dvd_file_h* (*file_open) (dvd_reader_filesystem_h *fs, const char *filename); ++}; ++ ++#endif /* DVDREAD_FILESYSTEM_H_ */ +diff --git a/libdvdread-embedded/src/dvdread/dvd_reader.h b/libdvdread-embedded/src/dvdread/dvd_reader.h +index 54ef5dd..5b15704 100644 +--- a/libdvdread-embedded/src/dvdread/dvd_reader.h ++++ b/libdvdread-embedded/src/dvdread/dvd_reader.h +@@ -23,13 +23,6 @@ + #ifndef LIBDVDREAD_DVD_READER_H + #define LIBDVDREAD_DVD_READER_H + +-#ifdef _MSC_VER +-#include <config.h> +- +-#include <stdio.h> +-#include <stdlib.h> +-#endif +- + #include <sys/types.h> + #include <inttypes.h> + #include <stdarg.h> +@@ -46,6 +39,12 @@ + */ + #include "version.h" + ++/** ++ * Filesystem types ++ */ ++#include "dvd_filesystem.h" ++ ++ + /** + * The length of one Logical Block of a DVD. + */ +diff --git a/libdvdread-embedded/src/dvdread_internal.h b/libdvdread-embedded/src/dvdread_internal.h +index bf4e2e1..1a35059 100644 +--- a/libdvdread-embedded/src/dvdread_internal.h ++++ b/libdvdread-embedded/src/dvdread_internal.h +@@ -39,6 +39,7 @@ struct dvd_reader_s + dvd_reader_device_t *rd; + void *priv; /* User provided context */ + dvd_logger_cb logcb; ++ dvd_reader_filesystem_h* fs; + /* Set 100 flags for BUP fallback, most signifiant left + [0] for upper remaining VTS, [1] for the first Main + 63 VTS */ + uint64_t ifoBUPflags[2]; +diff --git a/libdvdread-embedded/src/file/dir_posix.c b/libdvdread-embedded/src/file/dir_posix.c +new file mode 100644 +index 0000000..f55e62a +--- /dev/null ++++ b/libdvdread-embedded/src/file/dir_posix.c +@@ -0,0 +1,98 @@ ++/* ++ * This file is part of libdvdread ++ * Copyright (C) 2022 VideoLAN ++ * ++ * This file is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This file 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 ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library. If not, see ++ * <http://www.gnu.org/licenses/>. ++ */ ++ ++#include "config.h" ++ ++#include <stdlib.h> ++#include <string.h> ++#if HAVE_DIRENT_H ++#include <dirent.h> ++#endif ++ ++#if defined(__GLIBC__) && defined(__GLIBC_MINOR__) ++# if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 24) ++# define USE_READDIR ++# include <errno.h> ++# endif ++#endif ++ ++#include <dvdread/dvd_filesystem.h> ++#include "filesystem.h" ++ ++void _dir_close_posix(dvd_dir_h *dir) ++{ ++ if (dir) { ++ closedir((DIR *)dir->internal); ++ free(dir); ++ dir = NULL; ++ } ++} ++ ++int _dir_read_posix(dvd_dir_h *dir, dvd_dirent_t *entry) ++{ ++ struct dirent *p_e; ++ ++#ifdef USE_READDIR ++ errno = 0; ++ p_e = readdir((DIR*)dir->internal); ++ if (!p_e && errno) { ++ return -errno; ++ } ++#else /* USE_READDIR */ ++ int result; ++ struct dirent e; ++ ++ result = readdir_r((DIR*)dir->internal, &e, &p_e); ++ if (result) { ++ return -result; ++ } ++#endif /* USE_READDIR */ ++ ++ if (p_e == NULL) { ++ return 1; ++ } ++ strncpy(entry->d_name, p_e->d_name, sizeof(entry->d_name)); ++ entry->d_name[sizeof(entry->d_name) - 1] = 0; ++ ++ return 0; ++} ++ ++dvd_dir_h *dir_open_default(dvd_reader_filesystem_h *fs, const char* dirname) ++{ ++ if (!fs) ++ return NULL; ++ ++ dvd_dir_h *dir = calloc(1, sizeof(dvd_dir_h)); ++ ++ if (!dir) { ++ return NULL; ++ } ++ ++ dir->close = _dir_close_posix; ++ dir->read = _dir_read_posix; ++ ++ if ((dir->internal = opendir(dirname))) { ++ return dir; ++ } ++ ++ free(dir); ++ dir = NULL; ++ ++ return NULL; ++} +diff --git a/libdvdread-embedded/src/file/dir_win32.c b/libdvdread-embedded/src/file/dir_win32.c +new file mode 100644 +index 0000000..cb89728 +--- /dev/null ++++ b/libdvdread-embedded/src/file/dir_win32.c +@@ -0,0 +1,108 @@ ++/* ++ * This file is part of libdvdread ++ * Copyright (C) 2022 VideoLAN ++ * ++ * This file is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This file 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 ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library. If not, see ++ * <http://www.gnu.org/licenses/>. ++ */ ++ ++#include <io.h> ++#include <stdlib.h> ++#include <string.h> ++#include <stdio.h> ++ ++#include <windows.h> ++#include "../msvc/contrib/win32_cs.h" ++ ++ ++#include <dvdread/dvd_filesystem.h> ++#include "filesystem.h" ++ ++ ++typedef struct { ++ intptr_t handle; ++ struct _wfinddata_t went; ++} win32_dir_t; ++ ++ ++void _dir_close_win32(dvd_dir_h *dir) ++{ ++ if (dir) { ++ _findclose(((win32_dir_t*)dir->internal)->handle); ++ free((win32_dir_t*)dir->internal); ++ free(dir); ++ dir = NULL; ++ } ++} ++ ++int _dir_read_win32(dvd_dir_h *dir, dvd_dirent_t *entry) ++{ ++ win32_dir_t *wdir = (win32_dir_t*)dir->internal; ++ if (wdir->went.name[0]) { ++ if (!WideCharToMultiByte(CP_UTF8, 0, wdir->went.name, -1, entry->d_name, sizeof(entry->d_name), NULL, NULL)) ++ entry->d_name[0] = 0; /* allow reading next */ ++ wdir->went.name[0] = 0; ++ _wfindnext(wdir->handle, &wdir->went); ++ return 0; ++ } ++ return -1; ++} ++ ++dvd_dir_h *dir_open_default(dvd_reader_filesystem_h *fs, const char* dirname) ++{ ++ if (!fs) ++ return NULL; ++ ++ char *filespec; ++ wchar_t *wfilespec; ++ win32_dir_t *d; ++ dvd_dir_h *dir = calloc(1, sizeof(dvd_dir_h)); ++ ++ if (!dir) { ++ return NULL; ++ } ++ ++ d = calloc(1, sizeof(*d)); ++ if (!d) ++ { ++ free(dir); ++ return NULL; ++ } ++ ++ filespec = malloc(strlen(dirname) + 3); ++ if (!filespec) { ++ goto fail; ++ } ++ sprintf(filespec, "%s\\*", dirname); ++ ++ wfilespec = _utf8_to_wchar(filespec); ++ free(filespec); ++ if (!wfilespec) { ++ goto fail; ++ } ++ ++ d->handle = _wfindfirst(wfilespec, &d->went); ++ free(wfilespec); ++ if (d->handle != -1) { ++ dir->internal = (void*)d; ++ dir->close = _dir_close_win32; ++ dir->read = _dir_read_win32; ++ return dir; ++ } ++ ++ fail: ++ free(d); ++ free(dir); ++ return NULL; ++} +diff --git a/libdvdread-embedded/src/file/file_posix.c b/libdvdread-embedded/src/file/file_posix.c +new file mode 100644 +index 0000000..cbdbd58 +--- /dev/null ++++ b/libdvdread-embedded/src/file/file_posix.c +@@ -0,0 +1,113 @@ ++/* ++ * This file is part of libdvdread ++ * Copyright (C) 2022 VideoLAN ++ * ++ * This file is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This file 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 ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library. If not, see ++ * <http://www.gnu.org/licenses/>. ++ */ ++ ++ ++#include <stdlib.h> ++#include <unistd.h> ++#include <stdio.h> ++#include <errno.h> ++ ++ ++#include <sys/stat.h> ++#include <fcntl.h> ++ ++#include <dvdread/dvd_filesystem.h> ++ ++#include "filesystem.h" ++ ++#ifdef __ANDROID__ ++# undef lseek ++# define lseek lseek64 ++# undef off_t ++# define off_t off64_t ++#endif ++ ++ ++int _file_close(dvd_file_h *file) ++{ ++ if (file) { ++ int ret = close((int)(intptr_t)file->internal); ++ free(file); ++ return ret; ++ } ++ return 0; ++} ++ ++int64_t _file_seek(dvd_file_h *file, int64_t offset, int32_t origin) ++{ ++ off_t result = lseek((int)(intptr_t)file->internal, offset, origin); ++ if (result == (off_t)-1) { ++ return -1; ++ } ++ return (int64_t)result; ++} ++ ++ssize_t _file_read(dvd_file_h *file, char *buf, size_t size) ++{ ++ ssize_t result; ++ ++ if (size <= 0) { ++ return 0; ++ } ++ ++ result = read((int)(intptr_t)file->internal, buf, size); ++ return result; ++} ++ ++ ++dvd_file_h* file_open_default(dvd_reader_filesystem_h *fs, const char* filename) ++{ ++ if (!fs) ++ return NULL; ++ ++ dvd_file_h *file; ++ int fd = -1; ++ int flags = 0; ++ int mode = 0; ++ ++ #if defined(__OS2__) // not posix but kept here for legacy compatibility reasons ++ flags = O_RDONLY | O_BINARY; ++ #else ++ flags = O_RDONLY; ++ #endif ++ ++#ifdef O_CLOEXEC ++ flags |= O_CLOEXEC; ++#endif ++#ifdef O_BINARY ++ flags |= O_BINARY; ++#endif ++ ++ if ((fd = open(filename, flags, mode)) < 0) { ++ return NULL; ++ } ++ ++ file = calloc(1, sizeof(dvd_file_h)); ++ if (!file) { ++ close(fd); ++ return NULL; ++ } ++ ++ file->close = _file_close; ++ file->read = _file_read; ++ file->seek = _file_seek; ++ file->internal = (void*)(intptr_t)fd; ++ ++ return file; ++} +diff --git a/libdvdread-embedded/src/file/file_win32.c b/libdvdread-embedded/src/file/file_win32.c +new file mode 100644 +index 0000000..9787076 +--- /dev/null ++++ b/libdvdread-embedded/src/file/file_win32.c +@@ -0,0 +1,98 @@ ++/* ++ * This file is part of libdvdread ++ * Copyright (C) 2022 VideoLAN ++ * ++ * This file is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This file 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 ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library. If not, see ++ * <http://www.gnu.org/licenses/>. ++ */ ++ ++#include <stdlib.h> ++#include <unistd.h> ++#include <stdio.h> ++#include <errno.h> ++ ++#include <sys/stat.h> ++#include <fcntl.h> ++ ++#include <windows.h> ++#include "../msvc/contrib/win32_cs.h" ++ ++#include <dvdread/dvd_filesystem.h> ++#include "filesystem.h" ++ ++ ++int _file_close_win32(dvd_file_h *file) ++{ ++ if (file) { ++ int ret = close((int)(intptr_t)file->internal); ++ free(file); ++ return ret; ++ } ++ return 0; ++} ++ ++int64_t _file_seek_win32(dvd_file_h *file, int64_t offset, int32_t origin) ++{ ++ off64_t result = _lseeki64((int)(intptr_t)file->internal, offset, origin); ++ if (result == (off64_t)-1) { ++ return -1; ++ } ++ return (int64_t)result; ++} ++ ++ssize_t _file_read_win32(dvd_file_h *file, char *buf, size_t size) ++{ ++ ssize_t result; ++ ++ if (size <= 0) { ++ return 0; ++ } ++ ++ result = read((int)(intptr_t)file->internal, buf, size); ++ return result; ++} ++ ++ ++dvd_file_h* file_open_default(dvd_reader_filesystem_h *fs, const char* filename) ++{ ++ if (!fs) ++ return NULL; ++ ++ dvd_file_h *file; ++ int fd = -1; ++ wchar_t *wpath; ++ ++ wpath = _utf8_to_wchar(filename); ++ if (!wpath) { ++ return NULL; ++ } ++ ++ if ((fd = _wopen(wpath, O_RDONLY | O_BINARY)) < 0) { ++ free(wpath); ++ return NULL; ++ } ++ ++ file = calloc(1, sizeof(dvd_file_h)); ++ if (!file) { ++ close(fd); ++ return NULL; ++ } ++ ++ file->close = _file_close_win32; ++ file->read = _file_read_win32; ++ file->seek = _file_seek_win32; ++ file->internal = (void*)(intptr_t)fd; ++ ++ return file; ++} +diff --git a/libdvdread-embedded/src/file/filesystem.c b/libdvdread-embedded/src/file/filesystem.c +new file mode 100644 +index 0000000..b79edae +--- /dev/null ++++ b/libdvdread-embedded/src/file/filesystem.c +@@ -0,0 +1,37 @@ ++/* ++ * This file is part of libdvdread. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU Lesser General Public License as published by ++ * the Free Software Foundation; either version 2.1 of the License, 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 Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public License ++ * along with this program; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. ++ */ ++ ++#include "filesystem.h" ++ ++#include <stdlib.h> ++ ++static void default_filesystem_close(dvd_reader_filesystem_h *fs) { ++ free(fs); ++} ++ ++dvd_reader_filesystem_h* InitInternalFilesystem() { ++ dvd_reader_filesystem_h* fs = calloc( 1, sizeof(dvd_reader_filesystem_h)); ++ if (!fs) { ++ return NULL; ++ } ++ fs->dir_open = dir_open_default; ++ fs->stat = stat_default; ++ fs->file_open = file_open_default; ++ fs->close = default_filesystem_close; ++ return fs; ++} +diff --git a/libdvdread-embedded/src/file/filesystem.h b/libdvdread-embedded/src/file/filesystem.h +new file mode 100644 +index 0000000..1b8a014 +--- /dev/null ++++ b/libdvdread-embedded/src/file/filesystem.h +@@ -0,0 +1,46 @@ ++/* ++ * This file is part of libdvdread. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU Lesser General Public License as published by ++ * the Free Software Foundation; either version 2.1 of the License, 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 Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public License ++ * along with this program; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. ++ */ ++ ++#ifndef LIBDVDREAD_FILESYSTEM_H ++#define LIBDVDREAD_FILESYSTEM_H ++ ++#include "dvdread/dvd_filesystem.h" ++ ++/** ++ * Prototype definition for default file open function (implemented by each platform) ++ */ ++dvd_file_h* file_open_default(dvd_reader_filesystem_h *fs, const char* filename); ++ ++/** ++ * Prototype definition for default dir open function (implemented by each platform) ++ */ ++dvd_dir_h* dir_open_default(dvd_reader_filesystem_h *fs, const char* dirname); ++ ++/** ++ * Prototype definition for default stat function (implemented by each platform) ++ */ ++int stat_default(dvd_reader_filesystem_h *fs, const char *path, dvdstat_t* statbuf); ++ ++/** ++ * Inits the internal (platform specific) filesystem implementation ++ * bundled with libdvdread. This includes initializing the default internal ++ * implmentations of file_open, dir_open, stat, etc. ++ */ ++dvd_reader_filesystem_h* InitInternalFilesystem(); ++ ++#endif +diff --git a/libdvdread-embedded/src/file/stat_posix.c b/libdvdread-embedded/src/file/stat_posix.c +new file mode 100644 +index 0000000..61670fc +--- /dev/null ++++ b/libdvdread-embedded/src/file/stat_posix.c +@@ -0,0 +1,36 @@ ++/* ++ * This file is part of libdvdread ++ * Copyright (C) 2022 VideoLAN ++ * ++ * This file is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This file 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 ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library. If not, see ++ * <http://www.gnu.org/licenses/>. ++ */ ++ ++#include <stdlib.h> ++#include <sys/stat.h> ++ ++#include <dvdread/dvd_filesystem.h> ++#include "filesystem.h" ++ ++int stat_default(dvd_reader_filesystem_h *fs, const char *path, dvdstat_t* statbuf) ++{ ++ if (!fs) ++ return -1; ++ ++ struct stat posixstatbuf; ++ int ret = stat(path, &posixstatbuf); ++ statbuf->size = posixstatbuf.st_size; ++ statbuf->st_mode = posixstatbuf.st_mode; ++ return ret; ++} +diff --git a/libdvdread-embedded/src/file/stat_win32.c b/libdvdread-embedded/src/file/stat_win32.c +new file mode 100644 +index 0000000..0b8245d +--- /dev/null ++++ b/libdvdread-embedded/src/file/stat_win32.c +@@ -0,0 +1,53 @@ ++/* ++ * This file is part of libdvdread ++ * Copyright (C) 2022 VideoLAN ++ * ++ * This file is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This file 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 ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library. If not, see ++ * <http://www.gnu.org/licenses/>. ++ */ ++ ++#include <stdlib.h> ++#include <sys/stat.h> ++ ++#include <windows.h> ++#include "../msvc/contrib/win32_cs.h" ++ ++#include <dvdread/dvd_filesystem.h> ++#include "filesystem.h" ++ ++ ++int stat_default(dvd_reader_filesystem_h *fs, const char *path, dvdstat_t* statbuf) ++{ ++ if (!fs) ++ return -1; ++ ++ struct _stat64 win32statbuf; ++ ++ wchar_t *wpath, *it; ++ ++ wpath = _utf8_to_wchar(path); ++ if (!wpath) { ++ return -1; ++ } ++ ++ /* need to strip possible trailing \\ */ ++ for (it = wpath; *it; it++) ++ if ((*it == '\\' || *it == '/') && *(it+1) == 0) ++ *it = 0; ++ ++ int ret = _wstat64(wpath, &win32statbuf); ++ statbuf->size = win32statbuf.st_size; ++ statbuf->st_mode = win32statbuf.st_mode; ++ return ret; ++} +-- +2.35.1 + + +From 7215ed052b632be49c4f1ed444c7c9447e2d4c61 Mon Sep 17 00:00:00 2001 +From: Miguel Borges de Freitas <enen92@kodi.tv> +Date: Fri, 29 Jul 2022 12:50:24 +0100 +Subject: [PATCH 2/3] Decouple dvdinput_setup providing dvdinput_setup_builtin + for minimal/internal fs access + +--- + libdvdread-embedded/src/dvd_input.c | 23 +++++++++++++++++------ + libdvdread-embedded/src/dvd_input.h | 8 ++++++++ + 2 files changed, 25 insertions(+), 6 deletions(-) + +diff --git a/libdvdread-embedded/src/dvd_input.c b/libdvdread-embedded/src/dvd_input.c +index 1baf8f7..70f31b3 100644 +--- a/libdvdread-embedded/src/dvd_input.c ++++ b/libdvdread-embedded/src/dvd_input.c +@@ -446,12 +446,23 @@ int dvdinput_setup(void *priv, dvd_logger_cb *logcb) + DVDReadLog(priv, logcb, DVD_LOGGER_LEVEL_WARN, + "Encrypted DVD support unavailable."); + +- /* libdvdcss replacement functions */ +- dvdinput_open = file_open; +- dvdinput_close = file_close; +- dvdinput_seek = file_seek; +- dvdinput_title = file_title; +- dvdinput_read = file_read; ++ dvdinput_setup_builtin(priv, logcb); + return 0; + } + } ++ ++/** ++ * Setup read functions with the builtin libdvdread implementation (minimal DVD access without css). ++ */ ++void dvdinput_setup_builtin(void *priv, dvd_logger_cb *logcb) ++{ ++ DVDReadLog(priv, logcb, DVD_LOGGER_LEVEL_INFO, ++ "Setting up builtin libdvdread implementation"); ++ ++ /* libdvdcss replacement functions */ ++ dvdinput_open = file_open; ++ dvdinput_close = file_close; ++ dvdinput_seek = file_seek; ++ dvdinput_title = file_title; ++ dvdinput_read = file_read; ++} +diff --git a/libdvdread-embedded/src/dvd_input.h b/libdvdread-embedded/src/dvd_input.h +index 56fe170..36fe279 100644 +--- a/libdvdread-embedded/src/dvd_input.h ++++ b/libdvdread-embedded/src/dvd_input.h +@@ -46,7 +46,15 @@ extern int (*dvdinput_read) (dvd_input_t, void *, int, int); + + /** + * Setup function accessed by dvd_reader.c. Returns 1 if there is CSS support. ++ * Otherwise it falls back to the internal dvdread implementation (without css support) ++ * which is basically the same as calling dvdinput_setup_builtin. + */ + int dvdinput_setup(void *, dvd_logger_cb *); + ++/** ++ * Setup function accessed by dvd_reader.c using the builtin libdvdread implementation ++ * (without css support) ++ */ ++void dvdinput_setup_builtin(void *, dvd_logger_cb *); ++ + #endif /* LIBDVDREAD_DVD_INPUT_H */ +-- +2.35.1 + + +From 665a98ee15896e97aa8f0c0d6499b281d0602e60 Mon Sep 17 00:00:00 2001 +From: Miguel Borges de Freitas <enen92@kodi.tv> +Date: Fri, 29 Jul 2022 12:55:19 +0100 +Subject: [PATCH 3/3] Add DVDOpenFiles supporting caller provided filesystem + implementation + +--- + libdvdread-embedded/src/dvd_reader.c | 32 +++++++++++++++++++++++++++----- + libdvdread-embedded/src/dvdread/dvd_reader.h | 13 +++++++++++++ + 2 files changed, 40 insertions(+), 5 deletions(-) + +diff --git a/libdvdread-embedded/src/dvd_reader.c b/libdvdread-embedded/src/dvd_reader.c +index 5a21056..84bef88 100644 +--- a/libdvdread-embedded/src/dvd_reader.c ++++ b/libdvdread-embedded/src/dvd_reader.c +@@ -330,7 +330,8 @@ static char *bsd_block2char( const char *path ) + static dvd_reader_t *DVDOpenCommon( void *priv, + const dvd_logger_cb *logcb, + const char *ppath, +- dvd_reader_stream_cb *stream_cb ) ++ dvd_reader_stream_cb *stream_cb, ++ dvd_reader_filesystem_h * fs ) + { + dvdstat_t fileinfo; + int ret, have_css, cdir = -1; +@@ -344,6 +345,21 @@ static dvd_reader_t *DVDOpenCommon( void *priv, + if(logcb) + ctx->logcb = *logcb; + ++ // open files using the provided filesystem implementation ++ if (fs != NULL && ppath != NULL) ++ { ++ ctx->fs = fs; ++ dvdinput_setup_builtin(ctx->priv, &ctx->logcb); ++ ctx->rd = DVDOpenPath(ppath); ++ if (!ctx->rd) ++ { ++ free(ctx); ++ return NULL; ++ } ++ return ctx; ++ } ++ ++ // create the internal filesystem + ctx->fs = InitInternalFilesystem(); + if (!ctx->fs) + { +@@ -629,25 +645,31 @@ DVDOpen_error: + + dvd_reader_t *DVDOpen( const char *ppath ) + { +- return DVDOpenCommon( NULL, NULL, ppath, NULL ); ++ return DVDOpenCommon( NULL, NULL, ppath, NULL, NULL ); + } + + dvd_reader_t *DVDOpenStream( void *stream, + dvd_reader_stream_cb *stream_cb ) + { +- return DVDOpenCommon( stream, NULL, NULL, stream_cb ); ++ return DVDOpenCommon( stream, NULL, NULL, stream_cb, NULL ); + } + + dvd_reader_t *DVDOpen2( void *priv, const dvd_logger_cb *logcb, + const char *ppath ) + { +- return DVDOpenCommon( priv, logcb, ppath, NULL ); ++ return DVDOpenCommon( priv, logcb, ppath, NULL, NULL ); + } + + dvd_reader_t *DVDOpenStream2( void *priv, const dvd_logger_cb *logcb, + dvd_reader_stream_cb *stream_cb ) + { +- return DVDOpenCommon( priv, logcb, NULL, stream_cb ); ++ return DVDOpenCommon( priv, logcb, NULL, stream_cb, NULL ); ++} ++ ++dvd_reader_t *DVDOpenFiles( void *priv, const dvd_logger_cb *logcb, ++ const char *ppath, dvd_reader_filesystem_h *fs) ++{ ++ return DVDOpenCommon( priv, logcb, ppath, NULL, fs); + } + + void DVDClose( dvd_reader_t *dvd ) +diff --git a/libdvdread-embedded/src/dvdread/dvd_reader.h b/libdvdread-embedded/src/dvdread/dvd_reader.h +index 5b15704..40ddaf2 100644 +--- a/libdvdread-embedded/src/dvdread/dvd_reader.h ++++ b/libdvdread-embedded/src/dvdread/dvd_reader.h +@@ -153,6 +153,19 @@ dvd_reader_t *DVDOpenStream( void *, dvd_reader_stream_cb * ); + dvd_reader_t *DVDOpen2( void *, const dvd_logger_cb *, const char * ); + dvd_reader_t *DVDOpenStream2( void *, const dvd_logger_cb *, dvd_reader_stream_cb * ); + ++/** ++ * Open unencrypted DVD files providing the respective filesystem implementation ++ * Useful to open files located on virtual file systems ++ * ++ * @param path Specifies the file or directory to use ++ * @param priv is a private handle ++ * @param logcb is a custom logger callback struct, or NULL if none needed ++ * @param fs is a struct containing the filesystem implementation ++ * @return If successful a read handle is returned. Otherwise 0 is returned. ++ * ++ */ ++dvd_reader_t *DVDOpenFiles( void *priv, const dvd_logger_cb *logcb, const char * path, dvd_reader_filesystem_h *fs); ++ + /** + * Closes and cleans up the DVD reader object. + * +-- +2.35.1 + diff --git a/debian/patches/libdvdread/debian-0001-libdvdcss.patch b/debian/patches/libdvdread/debian-0001-libdvdcss.patch new file mode 100644 index 0000000..3b30917 --- /dev/null +++ b/debian/patches/libdvdread/debian-0001-libdvdcss.patch @@ -0,0 +1,25 @@ +From: Daniel Baumann <mail@daniel-baumann.ch> +Date: Tue, 22 Apr 2014 11:14:26 +0200 +Subject: libdvdcss +Forwarded: not-needed + +Print information about the CSS README. +--- + libdvdread-embedded/src/dvd_input.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/libdvdread-embedded/src/dvd_input.c b/libdvdread-embedded/src/dvd_input.c +index 0c44387..f640020 100644 +--- a/libdvdread-embedded/src/dvd_input.c ++++ b/libdvdread-embedded/src/dvd_input.c +@@ -477,8 +477,8 @@ int dvdinput_setup(void *priv, dvd_logger_cb *logcb, unsigned char stream_mode) + + } else { + DVDReadLog(priv, logcb, DVD_LOGGER_LEVEL_WARN, +- "Encrypted DVD support unavailable."); +- ++ "Encrypted DVD support unavailable. No css library available. " ++ "See /usr/share/doc/libdvdread4/README.css for more information"); + dvdinput_setup_builtin(priv, logcb); + return 0; + } diff --git a/debian/patches/libdvdread/debian-0002-descriptor.patch b/debian/patches/libdvdread/debian-0002-descriptor.patch new file mode 100644 index 0000000..a61d4f4 --- /dev/null +++ b/debian/patches/libdvdread/debian-0002-descriptor.patch @@ -0,0 +1,104 @@ +From: Mario Holbe <mario.holbe@tu-ilmenau.de> +Date: Tue, 22 Apr 2014 11:49:42 +0200 +Subject: descriptor +Forwarded: not-needed + +libdvdread is very likely to fail on discs/images that store their File +System Descriptor at the end of the disc/image rather than at the +beginning. This is due to the "strategy" libdvdread uses to find it: +libdvdread scans sequentially from the beginning of the disc/image for +the File System Descriptor and identifies it by a single byte tag. + +Aside from wasting lots of time on discs/images that store their File +System Descriptor at the end there is quite a good chance to stumble +across a random data block that accidentally starts with this tag (and +failing on it) before finding the real File System Descriptor. + +As far as I can see, at least CDBurnerXP seems to (be able to) create +such images - at least if my interpretation of the Implementation +Identifier "NMS DVDProLib" is correct. + +This... well, let's call it ugly hack fixes this by obtaining +the File System Descriptor location from the Logical Volume Descriptor + +Closes: #663512 +--- + libdvdread-embedded/src/dvd_udf.c | 37 ++++++++++++++++++++++++++++++++++--- + 1 file changed, 34 insertions(+), 3 deletions(-) + +diff --git a/libdvdread-embedded/src/dvd_udf.c b/libdvdread-embedded/src/dvd_udf.c +index 41517fa..7b22b43 100644 +--- a/libdvdread-embedded/src/dvd_udf.c ++++ b/libdvdread-embedded/src/dvd_udf.c +@@ -82,6 +82,8 @@ struct Partition { + uint32_t AccessType; + uint32_t Start; + uint32_t Length; ++ uint32_t FSD_Location; ++ uint32_t FSD_Length; + }; + + struct AD { +@@ -101,6 +103,12 @@ struct avdp_t { + struct extent_ad rvds; + }; + ++struct fsd_t { ++ uint16_t Partition; ++ uint32_t Location; ++ uint32_t Length; ++}; ++ + struct pvd_t { + uint8_t VolumeIdentifier[32]; + uint8_t VolumeSetIdentifier[128]; +@@ -427,6 +435,16 @@ static int UDFLogVolume( uint8_t *data, char *VolumeDescriptor ) + return 0; + } + ++/** ++ * Reads the File Set Descriptor from the Logical Volume Descriptor. ++ */ ++static void UDFFSD( uint8_t *data, struct fsd_t *fsd ) ++{ ++ fsd->Length = GETN4(248); /* always 2048? */ ++ fsd->Location = GETN4(252); ++ fsd->Partition = GETN2(256); /* always 0? */ ++} ++ + static int UDFFileEntry( uint8_t *data, uint8_t *FileType, + struct Partition *partition, struct AD *ad ) + { +@@ -801,8 +819,18 @@ static int UDFFindPartition( dvd_reader_t *ctx, int partnum, + /* Logical Volume Descriptor */ + if( UDFLogVolume( LogBlock ) ) { + /* TODO: sector size wrong! */ +- } else +- volvalid = 1; ++ } else { ++ struct fsd_t fsd; ++ ++ UDFFSD(LogBlock, &fsd); ++ if(part->Number == fsd.Partition) { ++ part->FSD_Location = fsd.Location; ++ part->FSD_Length = fsd.Length; ++ volvalid = 1; ++ } else { ++ /* TODO: Oups, how to handle this? */ ++ } ++ } + } + + } while( ( lbnum <= MVDS_location + ( MVDS_length - 1 ) +@@ -845,7 +873,10 @@ uint32_t UDFFindFile( dvd_reader_t *ctx, const char *filename, + SetUDFCache(ctx, PartitionCache, 0, &partition); + + /* Find root dir ICB */ +- lbnum = partition.Start; ++ lbnum = partition.Start + partition.FSD_Location; ++ /* ++ fprintf(stderr, "Looking for FSD at 0x%x\n", lbnum); ++ */ + do { + ret = DVDReadLBUDF( ctx, lbnum++, 1, LogBlock, 0 ); + if( ret < 0 ) { diff --git a/debian/patches/series b/debian/patches/series new file mode 100644 index 0000000..3b63e5d --- /dev/null +++ b/debian/patches/series @@ -0,0 +1,28 @@ +kodi/0001-Implement-hashes-using-Libgcrypt.patch +kodi/0002-Find-and-link-with-Libgcrypt.patch +kodi/0003-differentiate-from-vanilla-Kodi.patch +kodi/0004-use-system-groovy.patch +kodi/0005-fix-tests.patch +kodi/0006-dont-use-openssl.patch +kodi/0007-support-omitting-addons-service.patch +kodi/0008-Find-test-fixtures-in-source-directory.patch +kodi/0009-Skip-long-time-broken-test.patch +kodi/0010-Disable-flaky-TestMassEvent.General-and-TestMassEven.patch +kodi/0011-Skip-checking-errno-against-ENOENT-because-this-test.patch +kodi/0012-The-baseline-of-the-i386-port-does-not-include-SSE.patch +kodi/0013-Disable-GetCPUFrequency-test.patch +kodi/0014-Fix-C++-example-includes.patch +kodi/0015-debian-cross-compile.patch +kodi/0016-ports-architectures.patch +libdvdnav/0001-libdvdnav-PR48-enen92.patch +libdvdread/0001-libdvdread-PR40-enen92.patch +libdvdread/debian-0001-libdvdcss.patch +libdvdread/debian-0002-descriptor.patch +cdatetime-std-chrono/0001-Replace-Kodi-date-time-implementation-with-std-c.patch +workarounds/0001-Workaround-989814.patch +workarounds/0002-ffmpeg5.patch +workarounds/0003-xbmc-libdvd_vfs-enen92.patch +workarounds/0004-ffmpeg6.patch +workarounds/0005-pcre2.patch +workarounds/0006-loongarch.patch +workarounds/0007-swig.patch diff --git a/debian/patches/workarounds/0001-Workaround-989814.patch b/debian/patches/workarounds/0001-Workaround-989814.patch new file mode 100644 index 0000000..aac9c94 --- /dev/null +++ b/debian/patches/workarounds/0001-Workaround-989814.patch @@ -0,0 +1,71 @@ +From 82880587b3a578d61e8335199f316e6794750ba6 Mon Sep 17 00:00:00 2001 +From: Vasyl Gello <vasek.gello@gmail.com> +Date: Fri, 25 Jun 2021 01:37:02 +0000 +Subject: [PATCH 1/2] Check if applied locale correctly lowers chars and + fallback + +.. to default region if it does not. + +Fixes #19883. + +Signed-off-by: Vasyl Gello <vasek.gello@gmail.com> +--- + xbmc/LangInfo.cpp | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/xbmc/LangInfo.cpp b/xbmc/LangInfo.cpp +index 24f0419cfe..1c93ebf440 100644 +--- a/xbmc/LangInfo.cpp ++++ b/xbmc/LangInfo.cpp +@@ -981,6 +981,18 @@ void CLangInfo::SetCurrentRegion(const std::string& strName) + + m_currentRegion->SetGlobalLocale(); + ++ // Check if locale is affected by "Turkish I" ++ // See https://github.com/xbmc/xbmc/issue/19883 for details ++ if (std::tolower('i') != std::tolower('I')) ++ { ++ CLog::Log( ++ LOGWARNING, ++ "region '{}' is affected by 'Turkish I' problem - falling back to default region '{}'", ++ m_currentRegion->m_strName, m_defaultRegion.m_strName); ++ m_currentRegion = &m_defaultRegion; ++ m_currentRegion->SetGlobalLocale(); ++ } ++ + const std::shared_ptr<CSettings> settings = CServiceBroker::GetSettingsComponent()->GetSettings(); + if (settings->GetString(CSettings::SETTING_LOCALE_SHORTDATEFORMAT) == SETTING_REGIONAL_DEFAULT) + SetShortDateFormat(m_currentRegion->m_strDateFormatShort); +-- +2.33.0 + + +From 2be9ed286e1478c7b1a3002242330b6101492621 Mon Sep 17 00:00:00 2001 +From: Vasyl Gello <vasek.gello@gmail.com> +Date: Sun, 27 Jun 2021 19:31:39 +0000 +Subject: [PATCH 2/2] kodi.sh.in: Unset LC_{ALL,CTYPE}, LANG + +Signed-off-by: Vasyl Gello <vasek.gello@gmail.com> +--- + tools/Linux/kodi.sh.in | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/tools/Linux/kodi.sh.in b/tools/Linux/kodi.sh.in +index 108c0b007b..b148fd49ee 100644 +--- a/tools/Linux/kodi.sh.in ++++ b/tools/Linux/kodi.sh.in +@@ -171,6 +171,11 @@ if command_exists gdb; then + fi + fi + ++ ++# Check if locale is affected by "Turkish I" ++# See https://github.com/xbmc/xbmc/issue/19883 for details ++unset LC_CTYPE LC_ALL LANG ++ + LOOP=1 + while [ $(( $LOOP )) = "1" ] + do +-- +2.33.0 + diff --git a/debian/patches/workarounds/0002-ffmpeg5.patch b/debian/patches/workarounds/0002-ffmpeg5.patch new file mode 100644 index 0000000..64c31d2 --- /dev/null +++ b/debian/patches/workarounds/0002-ffmpeg5.patch @@ -0,0 +1,2429 @@ +From 2218c1c37c16df4ce3da34c8566f5e1335a66c01 Mon Sep 17 00:00:00 2001 +From: Alwin Esch <alwin.esch@web.de> +Date: Sun, 10 Jul 2022 18:59:52 +0200 +Subject: [PATCH 1/3] FFmpeg5 port + +--- + xbmc/cdrip/EncoderFFmpeg.cpp | 95 ++++++--------- + xbmc/cdrip/EncoderFFmpeg.h | 1 - + .../AudioEngine/Encoders/AEEncoderFFmpeg.cpp | 111 +++++++++++------- + .../AudioEngine/Engines/ActiveAE/ActiveAE.cpp | 14 +-- + xbmc/cores/FFmpeg.cpp | 14 ++- + xbmc/cores/FFmpeg.h | 26 ++++ + .../DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp | 12 +- + .../Overlay/DVDOverlayCodecFFmpeg.cpp | 3 +- + .../DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp | 36 +++++- + .../DVDCodecs/Video/DVDVideoPPFFmpeg.cpp | 5 + + .../VideoPlayer/DVDCodecs/Video/VAAPI.cpp | 10 +- + .../DVDDemuxers/DVDDemuxClient.cpp | 3 +- + .../DVDDemuxers/DVDDemuxFFmpeg.cpp | 71 +++++++++-- + .../DVDInputStreams/InputStreamAddon.cpp | 3 +- + xbmc/filesystem/AudioBookFileDirectory.cpp | 3 +- + xbmc/guilib/FFmpegImage.cpp | 6 +- + xbmc/music/tags/MusicInfoTagLoaderFFmpeg.cpp | 2 +- + xbmc/video/tags/VideoTagLoaderFFmpeg.cpp | 2 +- + 18 files changed, 281 insertions(+), 136 deletions(-) + +diff --git a/xbmc/cdrip/EncoderFFmpeg.cpp b/xbmc/cdrip/EncoderFFmpeg.cpp +index 2867b7cb67..4c0628b5cc 100644 +--- a/xbmc/cdrip/EncoderFFmpeg.cpp ++++ b/xbmc/cdrip/EncoderFFmpeg.cpp +@@ -11,6 +11,7 @@ + #include "ServiceBroker.h" + #include "addons/Addon.h" + #include "addons/AddonManager.h" ++#include "cores/FFmpeg.h" + #include "settings/Settings.h" + #include "settings/SettingsComponent.h" + #include "utils/StringUtils.h" +@@ -19,23 +20,8 @@ + #include "utils/log.h" + + using namespace KODI::CDRIP; +- +-namespace +-{ +- +-struct EncoderException : public std::exception +-{ +- std::string s; +- template<typename... Args> +- EncoderException(const std::string& fmt, Args&&... args) +- : s(StringUtils::Format(fmt, std::forward<Args>(args)...)) +- { +- } +- ~EncoderException() throw() {} // Updated +- const char* what() const throw() { return s.c_str(); } +-}; +- +-} /* namespace */ ++using FFMPEG_HELP_TOOLS::FFMpegErrorToString; ++using FFMPEG_HELP_TOOLS::FFMpegException; + + bool CEncoderFFmpeg::Init() + { +@@ -54,7 +40,7 @@ bool CEncoderFFmpeg::Init() + } + else + { +- throw EncoderException("Could not get add-on: {}", addonId); ++ throw FFMpegException("Could not get add-on: {}", addonId); + } + + // Hack fix about PTS on generated files. +@@ -66,45 +52,45 @@ bool CEncoderFFmpeg::Init() + else if (addonId == "audioencoder.kodi.builtin.wma") + m_samplesCountMultiply = 1000; + else +- throw EncoderException("Internal add-on id \"{}\" not known as usable", addonId); ++ throw FFMpegException("Internal add-on id \"{}\" not known as usable", addonId); + + const std::string filename = URIUtils::GetFileName(m_strFile); + + m_formatCtx = avformat_alloc_context(); + if (!m_formatCtx) +- throw EncoderException("Could not allocate output format context"); ++ throw FFMpegException("Could not allocate output format context"); + + m_bcBuffer = static_cast<uint8_t*>(av_malloc(BUFFER_SIZE + AV_INPUT_BUFFER_PADDING_SIZE)); + if (!m_bcBuffer) +- throw EncoderException("Could not allocate buffer"); ++ throw FFMpegException("Could not allocate buffer"); + + m_formatCtx->pb = avio_alloc_context(m_bcBuffer, BUFFER_SIZE, AVIO_FLAG_WRITE, this, nullptr, + avio_write_callback, avio_seek_callback); + if (!m_formatCtx->pb) +- throw EncoderException("Failed to allocate ByteIOContext"); ++ throw FFMpegException("Failed to allocate ByteIOContext"); + + /* Guess the desired container format based on the file extension. */ + m_formatCtx->oformat = av_guess_format(nullptr, filename.c_str(), nullptr); + if (!m_formatCtx->oformat) +- throw EncoderException("Could not find output file format"); ++ throw FFMpegException("Could not find output file format"); + + m_formatCtx->url = av_strdup(filename.c_str()); + if (!m_formatCtx->url) +- throw EncoderException("Could not allocate url"); ++ throw FFMpegException("Could not allocate url"); + + /* Find the encoder to be used by its name. */ +- AVCodec* codec = avcodec_find_encoder(m_formatCtx->oformat->audio_codec); ++ FFMPEG_FMT_CONST AVCodec* codec = avcodec_find_encoder(m_formatCtx->oformat->audio_codec); + if (!codec) +- throw EncoderException("Unable to find a suitable FFmpeg encoder"); ++ throw FFMpegException("Unable to find a suitable FFmpeg encoder"); + + /* Create a new audio stream in the output file container. */ + m_stream = avformat_new_stream(m_formatCtx, nullptr); + if (!m_stream) +- throw EncoderException("Failed to allocate AVStream context"); ++ throw FFMpegException("Failed to allocate AVStream context"); + + m_codecCtx = avcodec_alloc_context3(codec); + if (!m_codecCtx) +- throw EncoderException("Failed to allocate the encoder context"); ++ throw FFMpegException("Failed to allocate the encoder context"); + + /* Set the basic encoder parameters. + * The input file's sample rate is used to avoid a sample rate conversion. */ +@@ -128,14 +114,14 @@ bool CEncoderFFmpeg::Init() + + int err = avcodec_open2(m_codecCtx, codec, nullptr); + if (err < 0) +- throw EncoderException("Failed to open the codec {} (error '{}')", +- codec->long_name ? codec->long_name : codec->name, +- FFmpegErrorToString(err)); ++ throw FFMpegException("Failed to open the codec {} (error '{}')", ++ codec->long_name ? codec->long_name : codec->name, ++ FFMpegErrorToString(err)); + + err = avcodec_parameters_from_context(m_stream->codecpar, m_codecCtx); + if (err < 0) +- throw EncoderException("Failed to copy encoder parameters to output stream (error '{}')", +- FFmpegErrorToString(err)); ++ throw FFMpegException("Failed to copy encoder parameters to output stream (error '{}')", ++ FFMpegErrorToString(err)); + + m_inFormat = GetInputFormat(m_iInBitsPerSample); + m_outFormat = m_codecCtx->sample_fmt; +@@ -150,7 +136,7 @@ bool CEncoderFFmpeg::Init() + + m_bufferFrame = av_frame_alloc(); + if (!m_bufferFrame || !m_buffer) +- throw EncoderException("Failed to allocate necessary buffers"); ++ throw FFMpegException("Failed to allocate necessary buffers"); + + m_bufferFrame->nb_samples = m_codecCtx->frame_size; + m_bufferFrame->format = m_inFormat; +@@ -159,8 +145,8 @@ bool CEncoderFFmpeg::Init() + + err = av_frame_get_buffer(m_bufferFrame, 0); + if (err < 0) +- throw EncoderException("Could not allocate output frame samples (error '{}')", +- FFmpegErrorToString(err)); ++ throw FFMpegException("Could not allocate output frame samples (error '{}')", ++ FFMpegErrorToString(err)); + + avcodec_fill_audio_frame(m_bufferFrame, m_iInChannels, m_inFormat, m_buffer, m_neededBytes, 0); + +@@ -170,14 +156,14 @@ bool CEncoderFFmpeg::Init() + m_codecCtx->sample_rate, m_codecCtx->channel_layout, m_inFormat, + m_codecCtx->sample_rate, 0, nullptr); + if (!m_swrCtx || swr_init(m_swrCtx) < 0) +- throw EncoderException("Failed to initialize the resampler"); ++ throw FFMpegException("Failed to initialize the resampler"); + + m_resampledBufferSize = + av_samples_get_buffer_size(nullptr, m_iInChannels, m_neededFrames, m_outFormat, 0); + m_resampledBuffer = static_cast<uint8_t*>(av_malloc(m_resampledBufferSize)); + m_resampledFrame = av_frame_alloc(); + if (!m_resampledBuffer || !m_resampledFrame) +- throw EncoderException("Failed to allocate a frame for resampling"); ++ throw FFMpegException("Failed to allocate a frame for resampling"); + + m_resampledFrame->nb_samples = m_neededFrames; + m_resampledFrame->format = m_outFormat; +@@ -186,8 +172,8 @@ bool CEncoderFFmpeg::Init() + + err = av_frame_get_buffer(m_resampledFrame, 0); + if (err < 0) +- throw EncoderException("Could not allocate output resample frame samples (error '{}')", +- FFmpegErrorToString(err)); ++ throw FFMpegException("Could not allocate output resample frame samples (error '{}')", ++ FFMpegErrorToString(err)); + + avcodec_fill_audio_frame(m_resampledFrame, m_iInChannels, m_outFormat, m_resampledBuffer, + m_resampledBufferSize, 0); +@@ -204,7 +190,7 @@ bool CEncoderFFmpeg::Init() + /* write the header */ + err = avformat_write_header(m_formatCtx, nullptr); + if (err != 0) +- throw EncoderException("Failed to write the header (error '{}')", FFmpegErrorToString(err)); ++ throw FFMpegException("Failed to write the header (error '{}')", FFMpegErrorToString(err)); + + CLog::Log(LOGDEBUG, "CEncoderFFmpeg::{} - Successfully initialized with muxer {} and codec {}", + __func__, +@@ -212,7 +198,7 @@ bool CEncoderFFmpeg::Init() + : m_formatCtx->oformat->name, + codec->long_name ? codec->long_name : codec->name); + } +- catch (EncoderException& caught) ++ catch (const FFMpegException& caught) + { + CLog::Log(LOGERROR, "CEncoderFFmpeg::{} - {}", __func__, caught.what()); + +@@ -299,7 +285,7 @@ bool CEncoderFFmpeg::WriteFrame() + if (swr_convert(m_swrCtx, m_resampledFrame->data, m_neededFrames, + const_cast<const uint8_t**>(m_bufferFrame->extended_data), + m_neededFrames) < 0) +- throw EncoderException("Error resampling audio"); ++ throw FFMpegException("Error resampling audio"); + + frame = m_resampledFrame; + } +@@ -316,8 +302,8 @@ bool CEncoderFFmpeg::WriteFrame() + m_bufferSize = 0; + err = avcodec_send_frame(m_codecCtx, frame); + if (err < 0) +- throw EncoderException("Error sending a frame for encoding (error '{}')", __func__, +- FFmpegErrorToString(err)); ++ throw FFMpegException("Error sending a frame for encoding (error '{}')", ++ FFMpegErrorToString(err)); + + while (err >= 0) + { +@@ -329,19 +315,18 @@ bool CEncoderFFmpeg::WriteFrame() + } + else if (err < 0) + { +- throw EncoderException("Error during encoding (error '{}')", __func__, +- FFmpegErrorToString(err)); ++ throw FFMpegException("Error during encoding (error '{}')", FFMpegErrorToString(err)); + } + + err = av_write_frame(m_formatCtx, pkt); + if (err < 0) +- throw EncoderException("Failed to write the frame data (error '{}')", __func__, +- FFmpegErrorToString(err)); ++ throw FFMpegException("Failed to write the frame data (error '{}')", ++ FFMpegErrorToString(err)); + + av_packet_unref(pkt); + } + } +- catch (EncoderException& caught) ++ catch (const FFMpegException& caught) + { + CLog::Log(LOGERROR, "CEncoderFFmpeg::{} - {}", __func__, caught.what()); + } +@@ -400,14 +385,6 @@ AVSampleFormat CEncoderFFmpeg::GetInputFormat(int inBitsPerSample) + case 32: + return AV_SAMPLE_FMT_S32; + default: +- throw EncoderException("Invalid input bits per sample"); ++ throw FFMpegException("Invalid input bits per sample"); + } + } +- +-std::string CEncoderFFmpeg::FFmpegErrorToString(int err) +-{ +- std::string text; +- text.reserve(AV_ERROR_MAX_STRING_SIZE); +- av_strerror(err, text.data(), AV_ERROR_MAX_STRING_SIZE); +- return text; +-} +diff --git a/xbmc/cdrip/EncoderFFmpeg.h b/xbmc/cdrip/EncoderFFmpeg.h +index 39112ba3ba..0c2391c7ab 100644 +--- a/xbmc/cdrip/EncoderFFmpeg.h ++++ b/xbmc/cdrip/EncoderFFmpeg.h +@@ -39,7 +39,6 @@ private: + void SetTag(const std::string& tag, const std::string& value); + bool WriteFrame(); + AVSampleFormat GetInputFormat(int inBitsPerSample); +- std::string FFmpegErrorToString(int err); + + AVFormatContext* m_formatCtx{nullptr}; + AVCodecContext* m_codecCtx{nullptr}; +diff --git a/xbmc/cores/AudioEngine/Encoders/AEEncoderFFmpeg.cpp b/xbmc/cores/AudioEngine/Encoders/AEEncoderFFmpeg.cpp +index 09bb26a327..86f65f57f3 100644 +--- a/xbmc/cores/AudioEngine/Encoders/AEEncoderFFmpeg.cpp ++++ b/xbmc/cores/AudioEngine/Encoders/AEEncoderFFmpeg.cpp +@@ -10,13 +10,24 @@ + #define DTS_ENCODE_BITRATE 1411200 + + #include "cores/AudioEngine/Encoders/AEEncoderFFmpeg.h" +-#include "cores/AudioEngine/Utils/AEUtil.h" ++ + #include "ServiceBroker.h" +-#include "utils/log.h" ++#include "cores/AudioEngine/Utils/AEUtil.h" ++#include "cores/FFmpeg.h" + #include "settings/Settings.h" + #include "settings/SettingsComponent.h" +-#include <string.h> ++#include "utils/log.h" ++ ++extern "C" ++{ ++#include <libavutil/channel_layout.h> ++} ++ + #include <cassert> ++#include <string.h> ++ ++using FFMPEG_HELP_TOOLS::FFMpegErrorToString; ++using FFMPEG_HELP_TOOLS::FFMpegException; + + CAEEncoderFFmpeg::CAEEncoderFFmpeg() : m_CodecCtx(NULL), m_SwrCtx(NULL) + { +@@ -81,7 +92,7 @@ bool CAEEncoderFFmpeg::Initialize(AEAudioFormat &format, bool allow_planar_input + + bool ac3 = CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(CSettings::SETTING_AUDIOOUTPUT_AC3PASSTHROUGH); + +- AVCodec *codec = NULL; ++ FFMPEG_FMT_CONST AVCodec* codec = nullptr; + + /* fallback to ac3 if we support it, we might not have DTS support */ + if (ac3) +@@ -242,63 +253,77 @@ unsigned int CAEEncoderFFmpeg::GetFrames() + + int CAEEncoderFFmpeg::Encode(uint8_t *in, int in_size, uint8_t *out, int out_size) + { +- int got_output; +- AVFrame *frame; ++ int size = 0; ++ int err = AVERROR_UNKNOWN; ++ AVFrame* frame = nullptr; ++ AVPacket* pkt = nullptr; + + if (!m_CodecCtx) +- return 0; +- +- /* allocate the input frame +- * sadly, we have to alloc/dealloc it everytime since we have no guarantee the +- * data argument will be constant over iterated calls and the frame needs to +- * setup pointers inside data */ +- frame = av_frame_alloc(); +- if (!frame) +- return 0; ++ return size; + +- frame->nb_samples = m_CodecCtx->frame_size; +- frame->format = m_CodecCtx->sample_fmt; +- frame->channel_layout = m_CodecCtx->channel_layout; +- frame->channels = m_CodecCtx->channels; ++ try ++ { ++ /* allocate the input frame and output packet ++ * sadly, we have to alloc/dealloc it everytime since we have no guarantee the ++ * data argument will be constant over iterated calls and the frame needs to ++ * setup pointers inside data */ ++ frame = av_frame_alloc(); ++ pkt = av_packet_alloc(); ++ if (!frame || !pkt) ++ throw FFMpegException( ++ "Failed to allocate \"AVFrame\" or \"AVPacket\" for encoding (error '{}')", ++ strerror(errno)); ++ ++ frame->nb_samples = m_CodecCtx->frame_size; ++ frame->format = m_CodecCtx->sample_fmt; ++ frame->channel_layout = m_CodecCtx->channel_layout; ++ frame->channels = m_CodecCtx->channels; ++ ++ avcodec_fill_audio_frame(frame, m_CodecCtx->channels, m_CodecCtx->sample_fmt, in, in_size, 0); ++ ++ pkt->size = out_size; ++ pkt->data = out; ++ ++ /* encode it */ ++ err = avcodec_send_frame(m_CodecCtx, frame); ++ if (err < 0) ++ throw FFMpegException("Error sending a frame for encoding (error '{}')", ++ FFMpegErrorToString(err)); ++ ++ while (err >= 0) ++ { ++ err = avcodec_receive_packet(m_CodecCtx, pkt); ++ if (err == AVERROR(EAGAIN) || err == AVERROR_EOF) ++ { ++ av_frame_free(&frame); ++ av_packet_free(&pkt); ++ return (err == AVERROR(EAGAIN)) ? -1 : 0; ++ } ++ else if (err < 0) ++ { ++ throw FFMpegException("Error during encoding (error '{}')", FFMpegErrorToString(err)); ++ } + +- avcodec_fill_audio_frame(frame, m_CodecCtx->channels, m_CodecCtx->sample_fmt, +- in, in_size, 0); ++ av_packet_unref(pkt); ++ } + +- /* initialize the output packet */ +- AVPacket* pkt = av_packet_alloc(); +- if (!pkt) ++ size = pkt->size; ++ } ++ catch (const FFMpegException& caught) + { +- CLog::Log(LOGERROR, "CAEEncoderFFmpeg::{} - av_packet_alloc failed: {}", __FUNCTION__, +- strerror(errno)); +- av_frame_free(&frame); +- return 0; ++ CLog::Log(LOGERROR, "CAEEncoderFFmpeg::{} - {}", __func__, caught.what()); + } + +- pkt->size = out_size; +- pkt->data = out; +- +- /* encode it */ +- int ret = avcodec_encode_audio2(m_CodecCtx, pkt, frame, &got_output); +- +- int size = pkt->size; +- + /* free temporary data */ + av_frame_free(&frame); + + /* free the packet */ + av_packet_free(&pkt); + +- if (ret < 0 || !got_output) +- { +- CLog::Log(LOGERROR, "CAEEncoderFFmpeg::Encode - Encoding failed"); +- return 0; +- } +- + /* return the number of frames used */ + return size; + } + +- + int CAEEncoderFFmpeg::GetData(uint8_t **data) + { + int size; +diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp +index 3947dd5523..6000fe9c63 100644 +--- a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp ++++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp +@@ -16,17 +16,17 @@ using namespace ActiveAE; + #include "ActiveAESound.h" + #include "ActiveAEStream.h" + #include "ServiceBroker.h" ++#include "cores/AudioEngine/AEResampleFactory.h" ++#include "cores/AudioEngine/Encoders/AEEncoderFFmpeg.h" + #include "cores/AudioEngine/Interfaces/IAudioCallback.h" +-#include "cores/AudioEngine/Utils/AEUtil.h" + #include "cores/AudioEngine/Utils/AEStreamData.h" + #include "cores/AudioEngine/Utils/AEStreamInfo.h" +-#include "cores/AudioEngine/AEResampleFactory.h" +-#include "cores/AudioEngine/Encoders/AEEncoderFFmpeg.h" +- ++#include "cores/AudioEngine/Utils/AEUtil.h" ++#include "cores/FFmpeg.h" + #include "settings/Settings.h" + #include "settings/SettingsComponent.h" +-#include "windowing/WinSystem.h" + #include "utils/log.h" ++#include "windowing/WinSystem.h" + + using namespace std::chrono_literals; + +@@ -3016,8 +3016,8 @@ IAE::SoundPtr CActiveAE::MakeSound(const std::string& file) + AVFormatContext *fmt_ctx = nullptr; + AVCodecContext *dec_ctx = nullptr; + AVIOContext *io_ctx; +- AVInputFormat *io_fmt = nullptr; +- AVCodec *dec = nullptr; ++ FFMPEG_FMT_CONST AVInputFormat* io_fmt = nullptr; ++ FFMPEG_FMT_CONST AVCodec* dec = nullptr; + SampleConfig config; + + // No custom deleter until sound is registered +diff --git a/xbmc/cores/FFmpeg.cpp b/xbmc/cores/FFmpeg.cpp +index 03a29f7db4..de1765ed52 100644 +--- a/xbmc/cores/FFmpeg.cpp ++++ b/xbmc/cores/FFmpeg.cpp +@@ -21,6 +21,19 @@ + + static thread_local CFFmpegLog* CFFmpegLogTls; + ++namespace FFMPEG_HELP_TOOLS ++{ ++ ++std::string FFMpegErrorToString(int err) ++{ ++ std::string text; ++ text.resize(AV_ERROR_MAX_STRING_SIZE); ++ av_strerror(err, text.data(), AV_ERROR_MAX_STRING_SIZE); ++ return text; ++} ++ ++} // namespace FFMPEG_HELP_TOOLS ++ + void CFFmpegLog::SetLogLevel(int level) + { + CFFmpegLog::ClearLogLevel(); +@@ -116,4 +129,3 @@ void ff_avutil_log(void* ptr, int level, const char* format, va_list va) + } + buffer.erase(0, start); + } +- +diff --git a/xbmc/cores/FFmpeg.h b/xbmc/cores/FFmpeg.h +index e1194d19e9..8230701ba7 100644 +--- a/xbmc/cores/FFmpeg.h ++++ b/xbmc/cores/FFmpeg.h +@@ -10,6 +10,7 @@ + + #include "ServiceBroker.h" + #include "utils/CPUInfo.h" ++#include "utils/StringUtils.h" + + extern "C" { + #include <libavcodec/avcodec.h> +@@ -21,6 +22,31 @@ extern "C" { + #include <libpostproc/postprocess.h> + } + ++// https://github.com/FFmpeg/FFmpeg/blob/56450a0ee4/doc/APIchanges#L18-L26 ++#if LIBAVFORMAT_BUILD >= AV_VERSION_INT(59, 0, 100) ++#define FFMPEG_FMT_CONST const ++#else ++#define FFMPEG_FMT_CONST ++#endif ++ ++namespace FFMPEG_HELP_TOOLS ++{ ++ ++struct FFMpegException : public std::exception ++{ ++ std::string s; ++ template<typename... Args> ++ FFMpegException(const std::string& fmt, Args&&... args) ++ : s(StringUtils::Format(fmt, std::forward<Args>(args)...)) ++ { ++ } ++ const char* what() const noexcept override { return s.c_str(); } ++}; ++ ++std::string FFMpegErrorToString(int err); ++ ++} // namespace FFMPEG_HELP_TOOLS ++ + inline int PPCPUFlags() + { + unsigned int cpuFeatures = CServiceBroker::GetCPUInfo()->GetCPUFeatures(); +diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp +index 25f3f08e1f..87e7ae2c57 100644 +--- a/xbmc/cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp ++++ b/xbmc/cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp +@@ -7,14 +7,16 @@ + */ + + #include "DVDAudioCodecFFmpeg.h" +-#include "ServiceBroker.h" ++ + #include "../../DVDStreamInfo.h" +-#include "utils/log.h" ++#include "DVDCodecs/DVDCodecs.h" ++#include "ServiceBroker.h" ++#include "cores/AudioEngine/Utils/AEUtil.h" ++#include "cores/FFmpeg.h" + #include "settings/AdvancedSettings.h" + #include "settings/Settings.h" + #include "settings/SettingsComponent.h" +-#include "DVDCodecs/DVDCodecs.h" +-#include "cores/AudioEngine/Utils/AEUtil.h" ++#include "utils/log.h" + + extern "C" { + #include <libavutil/opt.h> +@@ -44,7 +46,7 @@ bool CDVDAudioCodecFFmpeg::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options + return false; + } + +- AVCodec* pCodec = NULL; ++ FFMPEG_FMT_CONST AVCodec* pCodec = nullptr; + bool allowdtshddecode = true; + + // set any special options +diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Overlay/DVDOverlayCodecFFmpeg.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Overlay/DVDOverlayCodecFFmpeg.cpp +index 8c26cad306..3657fc093c 100644 +--- a/xbmc/cores/VideoPlayer/DVDCodecs/Overlay/DVDOverlayCodecFFmpeg.cpp ++++ b/xbmc/cores/VideoPlayer/DVDCodecs/Overlay/DVDOverlayCodecFFmpeg.cpp +@@ -10,6 +10,7 @@ + + #include "DVDOverlayImage.h" + #include "DVDStreamInfo.h" ++#include "cores/FFmpeg.h" + #include "cores/VideoPlayer/Interface/DemuxPacket.h" + #include "cores/VideoPlayer/Interface/TimingConstants.h" + #include "utils/EndianSwap.h" +@@ -39,7 +40,7 @@ bool CDVDOverlayCodecFFmpeg::Open(CDVDStreamInfo &hints, CDVDCodecOptions &optio + if (hints.codec == AV_CODEC_ID_EIA_608) + return false; + +- AVCodec* pCodec = avcodec_find_decoder(hints.codec); ++ FFMPEG_FMT_CONST AVCodec* pCodec = avcodec_find_decoder(hints.codec); + if (!pCodec) + { + CLog::Log(LOGDEBUG, "{} - Unable to find codec {}", __FUNCTION__, hints.codec); +diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp +index 881c02ec12..21b5e834b2 100644 +--- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp ++++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp +@@ -12,6 +12,7 @@ + #include "DVDCodecs/DVDFactoryCodec.h" + #include "DVDStreamInfo.h" + #include "ServiceBroker.h" ++#include "cores/FFmpeg.h" + #include "cores/VideoPlayer/Interface/TimingConstants.h" + #include "cores/VideoPlayer/VideoRenderers/RenderManager.h" + #include "cores/VideoSettings.h" +@@ -27,12 +28,13 @@ + #include <mutex> + + extern "C" { +-#include <libavutil/opt.h> +-#include <libavutil/mastering_display_metadata.h> + #include <libavfilter/avfilter.h> + #include <libavfilter/buffersink.h> + #include <libavfilter/buffersrc.h> ++#include <libavutil/mastering_display_metadata.h> ++#include <libavutil/opt.h> + #include <libavutil/pixdesc.h> ++#include <libavutil/video_enc_params.h> + } + + #ifndef TARGET_POSIX +@@ -327,7 +329,7 @@ bool CDVDVideoCodecFFmpeg::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options + m_hints = hints; + m_options = options; + +- AVCodec* pCodec = nullptr; ++ FFMPEG_FMT_CONST AVCodec* pCodec = nullptr; + + m_iOrientation = hints.orientation; + +@@ -1048,6 +1050,33 @@ bool CDVDVideoCodecFFmpeg::GetPictureCommon(VideoPicture* pVideoPicture) + pVideoPicture->qscale_type = 0; + + AVFrameSideData* sd; ++ ++ // https://github.com/FFmpeg/FFmpeg/blob/991d417692/doc/APIchanges#L18-L20 ++ // basilgello: AV_VIDEO_ENC_PARAMS_MPEG2 is introduced in 4.4! ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(58, 134, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(56, 45, 100) ++ sd = av_frame_get_side_data(m_pFrame, AV_FRAME_DATA_VIDEO_ENC_PARAMS); ++ if (sd) ++ { ++ unsigned int mb_h = (m_pFrame->height + 15) / 16; ++ unsigned int mb_w = (m_pFrame->width + 15) / 16; ++ unsigned int nb_mb = mb_h * mb_w; ++ unsigned int block_idx; ++ ++ auto par = reinterpret_cast<AVVideoEncParams*>(sd->data); ++ if (par->type == AV_VIDEO_ENC_PARAMS_MPEG2 && (par->nb_blocks == 0 || par->nb_blocks == nb_mb)) ++ { ++ pVideoPicture->qstride = mb_w; ++ pVideoPicture->qscale_type = par->type; ++ pVideoPicture->qp_table = static_cast<int8_t*>(av_malloc(nb_mb)); ++ for (block_idx = 0; block_idx < nb_mb; block_idx++) ++ { ++ AVVideoBlockParams* b = av_video_enc_params_block(par, block_idx); ++ pVideoPicture->qp_table[block_idx] = par->qp + b->delta_qp; ++ } ++ } ++ } ++#else + sd = av_frame_get_side_data(m_pFrame, AV_FRAME_DATA_QP_TABLE_PROPERTIES); + if (sd) + { +@@ -1068,6 +1097,7 @@ bool CDVDVideoCodecFFmpeg::GetPictureCommon(VideoPicture* pVideoPicture) + pVideoPicture->qscale_type = qp->type; + } + } ++#endif + + pVideoPicture->pict_type = m_pFrame->pict_type; + +diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoPPFFmpeg.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoPPFFmpeg.cpp +index a98fbb1710..3b2739cd22 100644 +--- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoPPFFmpeg.cpp ++++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoPPFFmpeg.cpp +@@ -118,6 +118,11 @@ void CDVDVideoPPFFmpeg::Process(VideoPicture* pPicture) + m_pMode, m_pContext, + pSource->pict_type | pSource->qscale_type ? PP_PICT_TYPE_QP2 : 0); + ++ // https://github.com/FFmpeg/FFmpeg/blob/991d417692/doc/APIchanges#L18-L20 ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(58, 84, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(56, 45, 100) ++ av_free(pSource->qp_table); ++#endif + + pPicture->SetParams(*pSource); + if (pPicture->videoBuffer) +diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/VAAPI.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Video/VAAPI.cpp +index 7ad891083c..eaf7b78d32 100644 +--- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/VAAPI.cpp ++++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/VAAPI.cpp +@@ -1259,8 +1259,16 @@ void CDecoder::ReturnRenderPicture(CVaapiRenderPicture *renderPic) + + IHardwareDecoder* CDecoder::Create(CDVDStreamInfo &hint, CProcessInfo &processInfo, AVPixelFormat fmt) + { +- if (fmt == AV_PIX_FMT_VAAPI_VLD && CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(SETTING_VIDEOPLAYER_USEVAAPI)) ++ // https://github.com/FFmpeg/FFmpeg/blob/56450a0ee4fdda160f4039fc2ae33edfd27765c9/doc/APIchanges#L18-L26 ++#if LIBAVUTIL_BUILD >= AV_VERSION_INT(55, 8, 0) ++#define PIX_FMT_VAAPI AV_PIX_FMT_VAAPI ++#else ++#define PIX_FMT_VAAPI AV_PIX_FMT_VAAPI_VLD ++#endif ++ if (fmt == PIX_FMT_VAAPI && ++ CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(SETTING_VIDEOPLAYER_USEVAAPI)) + return new VAAPI::CDecoder(processInfo); ++#undef PIX_FMT_VAAPI + + return nullptr; + } +diff --git a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxClient.cpp b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxClient.cpp +index 2bdc3ea5a9..5be134e381 100644 +--- a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxClient.cpp ++++ b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxClient.cpp +@@ -10,6 +10,7 @@ + + #include "DVDDemuxUtils.h" + #include "DVDInputStreams/DVDInputStream.h" ++#include "cores/FFmpeg.h" + #include "cores/VideoPlayer/Interface/TimingConstants.h" + #include "utils/log.h" + +@@ -130,7 +131,7 @@ bool CDVDDemuxClient::ParsePacket(DemuxPacket* pkt) + + if (stream->m_context == nullptr) + { +- AVCodec *codec = avcodec_find_decoder(st->codec); ++ FFMPEG_FMT_CONST AVCodec* codec = avcodec_find_decoder(st->codec); + if (codec == nullptr) + { + CLog::Log(LOGERROR, "{} - can't find decoder", __FUNCTION__); +diff --git a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp +index 739bf51922..bf6f322274 100644 +--- a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp ++++ b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp +@@ -38,6 +38,7 @@ + + extern "C" + { ++#include "libavutil/channel_layout.h" + #include "libavutil/pixdesc.h" + } + +@@ -235,7 +236,7 @@ bool CDVDDemuxFFmpeg::Aborted() + + bool CDVDDemuxFFmpeg::Open(const std::shared_ptr<CDVDInputStream>& pInput, bool fileinfo) + { +- AVInputFormat* iformat = NULL; ++ FFMPEG_FMT_CONST AVInputFormat* iformat = nullptr; + std::string strFile; + m_streaminfo = !pInput->IsRealtime() && !m_reopen; + m_reopen = false; +@@ -422,9 +423,7 @@ bool CDVDDemuxFFmpeg::Open(const std::shared_ptr<CDVDInputStream>& pInput, bool + // is present, we assume it is PCM audio. + // AC3 is always wrapped in iec61937 (ffmpeg "spdif"), while DTS + // may be just padded. +- AVInputFormat* iformat2; +- iformat2 = av_find_input_format("spdif"); +- ++ FFMPEG_FMT_CONST AVInputFormat* iformat2 = av_find_input_format("spdif"); + if (iformat2 && iformat2->read_probe(&pd) > AVPROBE_SCORE_MAX / 4) + { + iformat = iformat2; +@@ -544,11 +543,14 @@ bool CDVDDemuxFFmpeg::Open(const std::shared_ptr<CDVDInputStream>& pInput, bool + m_streaminfo = true; + } + ++ // https://github.com/FFmpeg/FFmpeg/blob/56450a0ee4/doc/APIchanges#L18-L26 ++#if LIBAVFORMAT_BUILD < AV_VERSION_INT(59, 0, 100) + if (iformat && (strcmp(iformat->name, "mov,mp4,m4a,3gp,3g2,mj2") == 0)) + { + if (URIUtils::IsRemote(strFile)) + m_pFormatContext->iformat->flags |= AVFMT_NOGENSEARCH; + } ++#endif + + // we need to know if this is matroska, avi or sup later + m_bMatroska = strncmp(m_pFormatContext->iformat->name, "matroska", 8) == 0; // for "matroska.webm" +@@ -604,8 +606,11 @@ bool CDVDDemuxFFmpeg::Open(const std::shared_ptr<CDVDInputStream>& pInput, bool + // if format can be nonblocking, let's use that + m_pFormatContext->flags |= AVFMT_FLAG_NONBLOCK; + +- // deprecated, will be always set in future versions ++ // https://github.com/FFmpeg/FFmpeg/blob/d682ae70b4/doc/APIchanges#L18-L21 ++#if LIBAVFORMAT_BUILD < AV_VERSION_INT(57, 66, 105) && \ ++ LIBAVCODEC_BUILD < AV_VERSION_INT(57, 83, 101) + m_pFormatContext->flags |= AVFMT_FLAG_KEEP_SIDE_DATA; ++#endif + + UpdateCurrentPTS(); + +@@ -647,12 +652,24 @@ bool CDVDDemuxFFmpeg::Open(const std::shared_ptr<CDVDInputStream>& pInput, bool + { + int idx = m_pFormatContext->programs[i]->stream_index[j]; + AVStream* st = m_pFormatContext->streams[idx]; ++#if LIBAVFORMAT_BUILD >= AV_VERSION_INT(59, 3, 100) ++ // Related to https://patchwork.ffmpeg.org/project/ffmpeg/patch/20210429143825.53040-1-jamrial@gmail.com/ ++ // has been replaced with AVSTREAM_EVENT_FLAG_NEW_PACKETS. ++ if ((st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && ++ (st->event_flags & AVSTREAM_EVENT_FLAG_NEW_PACKETS)) || ++ (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && st->codecpar->sample_rate > 0)) ++ { ++ nProgram = i; ++ break; ++ } ++#else + if ((st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && st->codec_info_nb_frames > 0) || + (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && st->codecpar->sample_rate > 0)) + { + nProgram = i; + break; + } ++#endif + } + } + } +@@ -1401,11 +1418,19 @@ void CDVDDemuxFFmpeg::UpdateCurrentPTS() + if (idx >= 0) + { + AVStream* stream = m_pFormatContext->streams[idx]; ++#if LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 17, 100) ++ if (stream && m_pkt.pkt.dts != (int64_t)AV_NOPTS_VALUE) ++ { ++ double ts = ConvertTimestamp(m_pkt.pkt.dts, stream->time_base.den, stream->time_base.num); ++ m_currentPts = ts; ++ } ++#else + if (stream && stream->cur_dts != (int64_t)AV_NOPTS_VALUE) + { + double ts = ConvertTimestamp(stream->cur_dts, stream->time_base.den, stream->time_base.num); + m_currentPts = ts; + } ++#endif + } + } + +@@ -1621,7 +1646,12 @@ CDemuxStream* CDVDDemuxFFmpeg::AddStream(int streamIdx) + st->iBitsPerSample = pStream->codecpar->bits_per_raw_sample; + st->iChannelLayout = pStream->codecpar->channel_layout; + char buf[32] = {}; ++ // https://github.com/FFmpeg/FFmpeg/blob/6ccc3989d15/doc/APIchanges#L50-L53 ++#if LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 24, 100) ++ av_channel_layout_describe(st->iChannelLayout, buf, sizeof(buf)); ++#else + av_get_channel_layout_string(buf, 31, st->iChannels, st->iChannelLayout); ++#endif + st->m_channelLayoutName = buf; + if (st->iBitsPerSample == 0) + st->iBitsPerSample = pStream->codecpar->bits_per_coded_sample; +@@ -1663,6 +1693,7 @@ CDemuxStream* CDVDDemuxFFmpeg::AddStream(int streamIdx) + st->iFpsScale = 0; + } + ++#if LIBAVFORMAT_BUILD < AV_VERSION_INT(59, 3, 100) + if (pStream->codec_info_nb_frames > 0 && + pStream->codec_info_nb_frames <= 2 && + m_pInput->IsStreamType(DVDSTREAM_TYPE_DVD)) +@@ -1672,6 +1703,7 @@ CDemuxStream* CDVDDemuxFFmpeg::AddStream(int streamIdx) + st->iFpsRate = 0; + st->iFpsScale = 0; + } ++#endif + + st->iWidth = pStream->codecpar->width; + st->iHeight = pStream->codecpar->height; +@@ -1693,7 +1725,12 @@ CDemuxStream* CDVDDemuxFFmpeg::AddStream(int streamIdx) + st->colorRange = pStream->codecpar->color_range; + st->hdr_type = DetermineHdrType(pStream); + ++ // https://github.com/FFmpeg/FFmpeg/blob/release/5.0/doc/APIchanges ++#if LIBAVFORMAT_BUILD >= AV_VERSION_INT(59, 10, 100) ++ size_t size = 0; ++#else + int size = 0; ++#endif + uint8_t* side_data = nullptr; + + side_data = av_stream_get_side_data(pStream, AV_PKT_DATA_MASTERING_DISPLAY_METADATA, &size); +@@ -2103,7 +2140,7 @@ std::string CDVDDemuxFFmpeg::GetStreamCodecName(int iStreamId) + return strName; + } + +- AVCodec* codec = avcodec_find_decoder(stream->codec); ++ FFMPEG_FMT_CONST AVCodec* codec = avcodec_find_decoder(stream->codec); + if (codec) + strName = avcodec_get_name(codec->id); + } +@@ -2279,7 +2316,7 @@ void CDVDDemuxFFmpeg::ParsePacket(AVPacket* pkt) + + parser->second->m_parserCtx = av_parser_init(st->codecpar->codec_id); + +- AVCodec* codec = avcodec_find_decoder(st->codecpar->codec_id); ++ FFMPEG_FMT_CONST AVCodec* codec = avcodec_find_decoder(st->codecpar->codec_id); + if (codec == nullptr) + { + CLog::Log(LOGERROR, "{} - can't find decoder", __FUNCTION__); +@@ -2357,7 +2394,12 @@ TRANSPORT_STREAM_STATE CDVDDemuxFFmpeg::TransportStreamAudioState() + { + if (!m_startTime) + { ++#if LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 17, 100) ++ m_startTime = ++ av_rescale(m_pkt.pkt.dts, st->time_base.num, st->time_base.den) - 0.000001; ++#else + m_startTime = av_rescale(st->cur_dts, st->time_base.num, st->time_base.den) - 0.000001; ++#endif + m_seekStream = idx; + } + return TRANSPORT_STREAM_STATE::READY; +@@ -2377,7 +2419,12 @@ TRANSPORT_STREAM_STATE CDVDDemuxFFmpeg::TransportStreamAudioState() + { + if (!m_startTime) + { ++#if LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 17, 100) ++ m_startTime = ++ av_rescale(m_pkt.pkt.dts, st->time_base.num, st->time_base.den) - 0.000001; ++#else + m_startTime = av_rescale(st->cur_dts, st->time_base.num, st->time_base.den) - 0.000001; ++#endif + m_seekStream = i; + } + return TRANSPORT_STREAM_STATE::READY; +@@ -2410,7 +2457,12 @@ TRANSPORT_STREAM_STATE CDVDDemuxFFmpeg::TransportStreamVideoState() + { + if (!m_startTime) + { ++#if LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 17, 100) ++ m_startTime = ++ av_rescale(m_pkt.pkt.dts, st->time_base.num, st->time_base.den) - 0.000001; ++#else + m_startTime = av_rescale(st->cur_dts, st->time_base.num, st->time_base.den) - 0.000001; ++#endif + m_seekStream = idx; + } + return TRANSPORT_STREAM_STATE::READY; +@@ -2430,7 +2482,12 @@ TRANSPORT_STREAM_STATE CDVDDemuxFFmpeg::TransportStreamVideoState() + { + if (!m_startTime) + { ++#if LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 17, 100) ++ m_startTime = ++ av_rescale(m_pkt.pkt.dts, st->time_base.num, st->time_base.den) - 0.000001; ++#else + m_startTime = av_rescale(st->cur_dts, st->time_base.num, st->time_base.den) - 0.000001; ++#endif + m_seekStream = i; + } + return TRANSPORT_STREAM_STATE::READY; +diff --git a/xbmc/cores/VideoPlayer/DVDInputStreams/InputStreamAddon.cpp b/xbmc/cores/VideoPlayer/DVDInputStreams/InputStreamAddon.cpp +index b8494e504e..392853cc68 100644 +--- a/xbmc/cores/VideoPlayer/DVDInputStreams/InputStreamAddon.cpp ++++ b/xbmc/cores/VideoPlayer/DVDInputStreams/InputStreamAddon.cpp +@@ -12,6 +12,7 @@ + #include "addons/addoninfo/AddonType.h" + #include "addons/binary-addons/AddonDll.h" + #include "addons/kodi-dev-kit/include/kodi/addon-instance/VideoCodec.h" ++#include "cores/FFmpeg.h" + #include "cores/VideoPlayer/DVDDemuxers/DVDDemux.h" + #include "cores/VideoPlayer/DVDDemuxers/DVDDemuxUtils.h" + #include "cores/VideoPlayer/Interface/DemuxCrypto.h" +@@ -392,7 +393,7 @@ KODI_HANDLE CInputStreamAddon::cb_get_stream_transfer(KODI_HANDLE handle, + return nullptr; + + std::string codecName(stream->m_codecName); +- AVCodec* codec = nullptr; ++ FFMPEG_FMT_CONST AVCodec* codec = nullptr; + + if (stream->m_streamType != INPUTSTREAM_TYPE_TELETEXT && + stream->m_streamType != INPUTSTREAM_TYPE_RDS && stream->m_streamType != INPUTSTREAM_TYPE_ID3) +diff --git a/xbmc/filesystem/AudioBookFileDirectory.cpp b/xbmc/filesystem/AudioBookFileDirectory.cpp +index 04d1c14343..d82b2a9bbd 100644 +--- a/xbmc/filesystem/AudioBookFileDirectory.cpp ++++ b/xbmc/filesystem/AudioBookFileDirectory.cpp +@@ -11,6 +11,7 @@ + #include "TextureDatabase.h" + #include "URL.h" + #include "Util.h" ++#include "cores/FFmpeg.h" + #include "filesystem/File.h" + #include "guilib/LocalizeStrings.h" + #include "music/tags/MusicInfoTag.h" +@@ -149,7 +150,7 @@ bool CAudioBookFileDirectory::ContainsFiles(const CURL& url) + + m_ioctx->max_packet_size = 32768; + +- AVInputFormat* iformat=nullptr; ++ FFMPEG_FMT_CONST AVInputFormat* iformat = nullptr; + av_probe_input_buffer(m_ioctx, &iformat, url.Get().c_str(), nullptr, 0, 0); + + bool contains = false; +diff --git a/xbmc/guilib/FFmpegImage.cpp b/xbmc/guilib/FFmpegImage.cpp +index fa255278b7..9d01a21f38 100644 +--- a/xbmc/guilib/FFmpegImage.cpp ++++ b/xbmc/guilib/FFmpegImage.cpp +@@ -52,7 +52,7 @@ struct ThumbDataManagement + AVFrame* frame_temporary = nullptr; + SwsContext* sws = nullptr; + AVCodecContext* avOutctx = nullptr; +- AVCodec* codec = nullptr; ++ FFMPEG_FMT_CONST AVCodec* codec = nullptr; + ~ThumbDataManagement() + { + av_free(intermediateBuffer); +@@ -198,7 +198,7 @@ bool CFFmpegImage::Initialize(unsigned char* buffer, size_t bufSize) + bool is_png = (bufSize > 3 && buffer[1] == 'P' && buffer[2] == 'N' && buffer[3] == 'G'); + bool is_tiff = (bufSize > 2 && buffer[0] == 'I' && buffer[1] == 'I' && buffer[2] == '*'); + +- AVInputFormat* inp = nullptr; ++ FFMPEG_FMT_CONST AVInputFormat* inp = nullptr; + if (is_jpeg) + inp = av_find_input_format("image2"); + else if (m_strMimeType == "image/apng") +@@ -236,7 +236,7 @@ bool CFFmpegImage::Initialize(unsigned char* buffer, size_t bufSize) + return false; + } + AVCodecParameters* codec_params = m_fctx->streams[0]->codecpar; +- AVCodec* codec = avcodec_find_decoder(codec_params->codec_id); ++ FFMPEG_FMT_CONST AVCodec* codec = avcodec_find_decoder(codec_params->codec_id); + m_codec_ctx = avcodec_alloc_context3(codec); + if (!m_codec_ctx) + { +diff --git a/xbmc/music/tags/MusicInfoTagLoaderFFmpeg.cpp b/xbmc/music/tags/MusicInfoTagLoaderFFmpeg.cpp +index 9bb2cdc09b..dbd8893c97 100644 +--- a/xbmc/music/tags/MusicInfoTagLoaderFFmpeg.cpp ++++ b/xbmc/music/tags/MusicInfoTagLoaderFFmpeg.cpp +@@ -58,7 +58,7 @@ bool CMusicInfoTagLoaderFFmpeg::Load(const std::string& strFileName, CMusicInfoT + if (file.IoControl(IOCTRL_SEEK_POSSIBLE, NULL) != 1) + ioctx->seekable = 0; + +- AVInputFormat* iformat=NULL; ++ FFMPEG_FMT_CONST AVInputFormat* iformat = nullptr; + av_probe_input_buffer(ioctx, &iformat, strFileName.c_str(), NULL, 0, 0); + + if (avformat_open_input(&fctx, strFileName.c_str(), iformat, NULL) < 0) +diff --git a/xbmc/video/tags/VideoTagLoaderFFmpeg.cpp b/xbmc/video/tags/VideoTagLoaderFFmpeg.cpp +index c1b0495179..5564696be6 100644 +--- a/xbmc/video/tags/VideoTagLoaderFFmpeg.cpp ++++ b/xbmc/video/tags/VideoTagLoaderFFmpeg.cpp +@@ -65,7 +65,7 @@ CVideoTagLoaderFFmpeg::CVideoTagLoaderFFmpeg(const CFileItem& item, + if (m_file->IoControl(IOCTRL_SEEK_POSSIBLE, nullptr) != 1) + m_ioctx->seekable = 0; + +- AVInputFormat* iformat = nullptr; ++ FFMPEG_FMT_CONST AVInputFormat* iformat = nullptr; + av_probe_input_buffer(m_ioctx, &iformat, m_item.GetPath().c_str(), nullptr, 0, 0); + if (avformat_open_input(&m_fctx, m_item.GetPath().c_str(), iformat, nullptr) < 0) + { +-- +2.35.1 + + +From 3de036ef45b0df3368997500d210090a7f6ff5e7 Mon Sep 17 00:00:00 2001 +From: Vasyl Gello <vasek.gello@gmail.com> +Date: Thu, 13 Oct 2022 04:56:26 +0000 +Subject: [PATCH 2/3] Use Channel Layout API if built against FFmpeg 5.1 + +Signed-off-by: Vasyl Gello <vasek.gello@gmail.com> +--- + xbmc/cdrip/EncoderFFmpeg.cpp | 51 +++++++++++++ + .../AudioEngine/Encoders/AEEncoderFFmpeg.cpp | 60 ++++++++++++++- + .../AudioEngine/Engines/ActiveAE/ActiveAE.cpp | 22 ++++++ + .../Engines/ActiveAE/ActiveAEFilter.cpp | 38 +++++++++- + .../ActiveAE/ActiveAEResampleFFMPEG.cpp | 55 +++++++++++++- + .../Engines/ActiveAE/ActiveAEStream.cpp | 2 +- + xbmc/cores/AudioEngine/Utils/AEUtil.cpp | 73 +++++++++++++++++-- + xbmc/cores/AudioEngine/Utils/AEUtil.h | 9 ++- + .../DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp | 58 ++++++++++++--- + .../DVDDemuxers/DVDDemuxClient.cpp | 15 +++- + .../DVDDemuxers/DVDDemuxFFmpeg.cpp | 42 +++++++++-- + 11 files changed, 388 insertions(+), 37 deletions(-) + +diff --git a/xbmc/cdrip/EncoderFFmpeg.cpp b/xbmc/cdrip/EncoderFFmpeg.cpp +index 4c0628b5cc..c05cdeab9e 100644 +--- a/xbmc/cdrip/EncoderFFmpeg.cpp ++++ b/xbmc/cdrip/EncoderFFmpeg.cpp +@@ -94,8 +94,14 @@ bool CEncoderFFmpeg::Init() + + /* Set the basic encoder parameters. + * The input file's sample rate is used to avoid a sample rate conversion. */ ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ av_channel_layout_uninit(&m_codecCtx->ch_layout); ++ av_channel_layout_default(&m_codecCtx->ch_layout, m_iInChannels); ++#else + m_codecCtx->channels = m_iInChannels; + m_codecCtx->channel_layout = av_get_default_channel_layout(m_iInChannels); ++#endif + m_codecCtx->sample_rate = m_iInSampleRate; + m_codecCtx->sample_fmt = codec->sample_fmts[0]; + m_codecCtx->bit_rate = bitrate; +@@ -140,7 +146,14 @@ bool CEncoderFFmpeg::Init() + + m_bufferFrame->nb_samples = m_codecCtx->frame_size; + m_bufferFrame->format = m_inFormat; ++ ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ av_channel_layout_uninit(&m_bufferFrame->ch_layout); ++ av_channel_layout_copy(&m_bufferFrame->ch_layout, &m_codecCtx->ch_layout); ++#else + m_bufferFrame->channel_layout = m_codecCtx->channel_layout; ++#endif + m_bufferFrame->sample_rate = m_codecCtx->sample_rate; + + err = av_frame_get_buffer(m_bufferFrame, 0); +@@ -152,10 +165,18 @@ bool CEncoderFFmpeg::Init() + + if (m_needConversion) + { ++#if LIBSWRESAMPLE_BUILD >= AV_VERSION_INT(4, 7, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ int ret = swr_alloc_set_opts2(&m_swrCtx, &m_codecCtx->ch_layout, m_outFormat, ++ m_codecCtx->sample_rate, &m_codecCtx->ch_layout, m_inFormat, ++ m_codecCtx->sample_rate, 0, nullptr); ++ if (ret || swr_init(m_swrCtx) < 0) ++#else + m_swrCtx = swr_alloc_set_opts(nullptr, m_codecCtx->channel_layout, m_outFormat, + m_codecCtx->sample_rate, m_codecCtx->channel_layout, m_inFormat, + m_codecCtx->sample_rate, 0, nullptr); + if (!m_swrCtx || swr_init(m_swrCtx) < 0) ++#endif + throw FFMpegException("Failed to initialize the resampler"); + + m_resampledBufferSize = +@@ -167,7 +188,13 @@ bool CEncoderFFmpeg::Init() + + m_resampledFrame->nb_samples = m_neededFrames; + m_resampledFrame->format = m_outFormat; ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ av_channel_layout_uninit(&m_resampledFrame->ch_layout); ++ av_channel_layout_copy(&m_resampledFrame->ch_layout, &m_codecCtx->ch_layout); ++#else + m_resampledFrame->channel_layout = m_codecCtx->channel_layout; ++#endif + m_resampledFrame->sample_rate = m_codecCtx->sample_rate; + + err = av_frame_get_buffer(m_resampledFrame, 0); +@@ -203,11 +230,23 @@ bool CEncoderFFmpeg::Init() + CLog::Log(LOGERROR, "CEncoderFFmpeg::{} - {}", __func__, caught.what()); + + av_freep(&m_buffer); ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ av_channel_layout_uninit(&m_bufferFrame->ch_layout); ++#endif + av_frame_free(&m_bufferFrame); + swr_free(&m_swrCtx); ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ av_channel_layout_uninit(&m_resampledFrame->ch_layout); ++#endif + av_frame_free(&m_resampledFrame); + av_freep(&m_resampledBuffer); + av_free(m_bcBuffer); ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ av_channel_layout_uninit(&m_codecCtx->ch_layout); ++#endif + avcodec_free_context(&m_codecCtx); + if (m_formatCtx) + { +@@ -351,8 +390,16 @@ bool CEncoderFFmpeg::Close() + + /* Flush if needed */ + av_freep(&m_buffer); ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ av_channel_layout_uninit(&m_bufferFrame->ch_layout); ++#endif + av_frame_free(&m_bufferFrame); + swr_free(&m_swrCtx); ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ av_channel_layout_uninit(&m_resampledFrame->ch_layout); ++#endif + av_frame_free(&m_resampledFrame); + av_freep(&m_resampledBuffer); + m_needConversion = false; +@@ -364,6 +411,10 @@ bool CEncoderFFmpeg::Close() + + /* cleanup */ + av_free(m_bcBuffer); ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ av_channel_layout_uninit(&m_codecCtx->ch_layout); ++#endif + avcodec_free_context(&m_codecCtx); + av_freep(&m_formatCtx->pb); + avformat_free_context(m_formatCtx); +diff --git a/xbmc/cores/AudioEngine/Encoders/AEEncoderFFmpeg.cpp b/xbmc/cores/AudioEngine/Encoders/AEEncoderFFmpeg.cpp +index 86f65f57f3..5d8ca71de1 100644 +--- a/xbmc/cores/AudioEngine/Encoders/AEEncoderFFmpeg.cpp ++++ b/xbmc/cores/AudioEngine/Encoders/AEEncoderFFmpeg.cpp +@@ -37,6 +37,10 @@ CAEEncoderFFmpeg::~CAEEncoderFFmpeg() + { + Reset(); + swr_free(&m_SwrCtx); ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ av_channel_layout_uninit(&m_CodecCtx->ch_layout); ++#endif + avcodec_free_context(&m_CodecCtx); + } + +@@ -113,7 +117,13 @@ bool CAEEncoderFFmpeg::Initialize(AEAudioFormat &format, bool allow_planar_input + + m_CodecCtx->bit_rate = m_BitRate; + m_CodecCtx->sample_rate = format.m_sampleRate; ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ av_channel_layout_uninit(&m_CodecCtx->ch_layout); ++ av_channel_layout_from_mask(&m_CodecCtx->ch_layout, AV_CH_LAYOUT_5POINT1_BACK); ++#else + m_CodecCtx->channel_layout = AV_CH_LAYOUT_5POINT1_BACK; ++#endif + + /* select a suitable data format */ + if (codec->sample_fmts) +@@ -190,22 +200,44 @@ bool CAEEncoderFFmpeg::Initialize(AEAudioFormat &format, bool allow_planar_input + LOGERROR, + "CAEEncoderFFmpeg::Initialize - Unable to find a suitable data format for the codec ({})", + m_CodecName); ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ av_channel_layout_uninit(&m_CodecCtx->ch_layout); ++#endif + avcodec_free_context(&m_CodecCtx); + return false; + } + } + ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ uint64_t mask = m_CodecCtx->ch_layout.u.mask; ++ av_channel_layout_uninit(&m_CodecCtx->ch_layout); ++ av_channel_layout_from_mask(&m_CodecCtx->ch_layout, mask); ++ m_CodecCtx->ch_layout.nb_channels = BuildChannelLayout(mask, m_Layout); ++#else + m_CodecCtx->channels = BuildChannelLayout(m_CodecCtx->channel_layout, m_Layout); ++#endif + + /* open the codec */ + if (avcodec_open2(m_CodecCtx, codec, NULL)) + { ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ av_channel_layout_uninit(&m_CodecCtx->ch_layout); ++#endif + avcodec_free_context(&m_CodecCtx); + return false; + } + + format.m_frames = m_CodecCtx->frame_size; +- format.m_frameSize = m_CodecCtx->channels * (CAEUtil::DataFormatToBits(format.m_dataFormat) >> 3); ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ int channels = m_CodecCtx->ch_layout.nb_channels; ++#else ++ int channels = m_CodecCtx->channels; ++#endif ++ format.m_frameSize = channels * (CAEUtil::DataFormatToBits(format.m_dataFormat) >> 3); + format.m_channelLayout = m_Layout; + + m_CurrentFormat = format; +@@ -215,14 +247,26 @@ bool CAEEncoderFFmpeg::Initialize(AEAudioFormat &format, bool allow_planar_input + + if (m_NeedConversion) + { ++#if LIBSWRESAMPLE_BUILD >= AV_VERSION_INT(4, 7, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ int ret = swr_alloc_set_opts2(&m_SwrCtx, &m_CodecCtx->ch_layout, m_CodecCtx->sample_fmt, ++ m_CodecCtx->sample_rate, &m_CodecCtx->ch_layout, ++ AV_SAMPLE_FMT_FLT, m_CodecCtx->sample_rate, 0, NULL); ++ if (ret || swr_init(m_SwrCtx) < 0) ++#else + m_SwrCtx = swr_alloc_set_opts(NULL, + m_CodecCtx->channel_layout, m_CodecCtx->sample_fmt, m_CodecCtx->sample_rate, + m_CodecCtx->channel_layout, AV_SAMPLE_FMT_FLT, m_CodecCtx->sample_rate, + 0, NULL); + if (!m_SwrCtx || swr_init(m_SwrCtx) < 0) ++#endif + { + CLog::Log(LOGERROR, "CAEEncoderFFmpeg::Initialize - Failed to initialise resampler."); + swr_free(&m_SwrCtx); ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ av_channel_layout_uninit(&m_CodecCtx->ch_layout); ++#endif + avcodec_free_context(&m_CodecCtx); + return false; + } +@@ -276,10 +320,18 @@ int CAEEncoderFFmpeg::Encode(uint8_t *in, int in_size, uint8_t *out, int out_siz + + frame->nb_samples = m_CodecCtx->frame_size; + frame->format = m_CodecCtx->sample_fmt; ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ av_channel_layout_uninit(&frame->ch_layout); ++ av_channel_layout_copy(&frame->ch_layout, &m_CodecCtx->ch_layout); ++ int channelNum = m_CodecCtx->ch_layout.nb_channels; ++#else + frame->channel_layout = m_CodecCtx->channel_layout; + frame->channels = m_CodecCtx->channels; ++ int channelNum = m_CodecCtx->channels; ++#endif + +- avcodec_fill_audio_frame(frame, m_CodecCtx->channels, m_CodecCtx->sample_fmt, in, in_size, 0); ++ avcodec_fill_audio_frame(frame, channelNum, m_CodecCtx->sample_fmt, in, in_size, 0); + + pkt->size = out_size; + pkt->data = out; +@@ -295,6 +347,10 @@ int CAEEncoderFFmpeg::Encode(uint8_t *in, int in_size, uint8_t *out, int out_siz + err = avcodec_receive_packet(m_CodecCtx, pkt); + if (err == AVERROR(EAGAIN) || err == AVERROR_EOF) + { ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ av_channel_layout_uninit(&frame->ch_layout); ++#endif + av_frame_free(&frame); + av_packet_free(&pkt); + return (err == AVERROR(EAGAIN)) ? -1 : 0; +diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp +index 6000fe9c63..9cd3bddda8 100644 +--- a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp ++++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp +@@ -3069,8 +3069,14 @@ IAE::SoundPtr CActiveAE::MakeSound(const std::string& file) + AVCodecID codecId = fmt_ctx->streams[0]->codecpar->codec_id; + dec = avcodec_find_decoder(codecId); + config.sample_rate = fmt_ctx->streams[0]->codecpar->sample_rate; ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ config.channels = fmt_ctx->streams[0]->codecpar->ch_layout.nb_channels; ++ config.channel_layout = fmt_ctx->streams[0]->codecpar->ch_layout.u.mask; ++#else + config.channels = fmt_ctx->streams[0]->codecpar->channels; + config.channel_layout = fmt_ctx->streams[0]->codecpar->channel_layout; ++#endif + } + } + if (dec == nullptr) +@@ -3086,10 +3092,22 @@ IAE::SoundPtr CActiveAE::MakeSound(const std::string& file) + + dec_ctx = avcodec_alloc_context3(dec); + dec_ctx->sample_rate = config.sample_rate; ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ AVChannelLayout layout = {}; ++ if (!config.channel_layout) ++ av_channel_layout_default(&layout, config.channels); ++ else ++ av_channel_layout_from_mask(&layout, config.channel_layout); ++ config.channel_layout = layout.u.mask; ++ av_channel_layout_copy(&dec_ctx->ch_layout, &layout); ++ av_channel_layout_uninit(&layout); ++#else + dec_ctx->channels = config.channels; + if (!config.channel_layout) + config.channel_layout = av_get_default_channel_layout(config.channels); + dec_ctx->channel_layout = config.channel_layout; ++#endif + + AVPacket* avpkt = av_packet_alloc(); + if (!avpkt) +@@ -3156,6 +3174,10 @@ IAE::SoundPtr CActiveAE::MakeSound(const std::string& file) + + av_packet_free(&avpkt); + av_frame_free(&decoded_frame); ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ av_channel_layout_uninit(&dec_ctx->ch_layout); ++#endif + avcodec_free_context(&dec_ctx); + avformat_close_input(&fmt_ctx); + if (io_ctx) +diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEFilter.cpp b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEFilter.cpp +index 26b669a2cf..1d79dc6db4 100644 +--- a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEFilter.cpp ++++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEFilter.cpp +@@ -12,10 +12,11 @@ + #include <algorithm> + + extern "C" { +-#include <libavfilter/avfilter.h> + #include <libavcodec/avcodec.h> ++#include <libavfilter/avfilter.h> + #include <libavfilter/buffersink.h> + #include <libavfilter/buffersrc.h> ++#include <libavutil/version.h> + #include <libswresample/swresample.h> + } + +@@ -171,7 +172,13 @@ void CActiveAEFilter::CloseFilter() + } + + if (m_pOutFrame) ++ { ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ av_channel_layout_uninit(&m_pOutFrame->ch_layout); ++#endif + av_frame_free(&m_pOutFrame); ++ } + + if (m_pConvertFrame) + av_frame_free(&m_pConvertFrame); +@@ -205,10 +212,17 @@ int CActiveAEFilter::ProcessFilter(uint8_t **dst_buffer, int dst_samples, uint8_ + if (!frame) + return -1; + ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ av_channel_layout_uninit(&frame->ch_layout); ++ av_channel_layout_from_mask(&frame->ch_layout, m_channelLayout); ++ int channels = frame->ch_layout.nb_channels; ++#else + int channels = av_get_channel_layout_nb_channels(m_channelLayout); + + frame->channel_layout = m_channelLayout; + frame->channels = channels; ++#endif + frame->sample_rate = m_sampleRate; + frame->nb_samples = src_samples; + frame->format = m_sampleFormat; +@@ -224,6 +238,10 @@ int CActiveAEFilter::ProcessFilter(uint8_t **dst_buffer, int dst_samples, uint8_ + src_buffer[0], src_bufsize, 16); + if (result < 0) + { ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ av_channel_layout_uninit(&frame->ch_layout); ++#endif + av_frame_free(&frame); + CLog::Log(LOGERROR, "CActiveAEFilter::ProcessFilter - avcodec_fill_audio_frame failed"); + m_filterEof = true; +@@ -231,6 +249,10 @@ int CActiveAEFilter::ProcessFilter(uint8_t **dst_buffer, int dst_samples, uint8_ + } + + result = av_buffersrc_write_frame(m_pFilterCtxIn, frame); ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ av_channel_layout_uninit(&frame->ch_layout); ++#endif + av_frame_free(&frame); + if (result < 0) + { +@@ -284,7 +306,13 @@ int CActiveAEFilter::ProcessFilter(uint8_t **dst_buffer, int dst_samples, uint8_ + { + av_frame_unref(m_pOutFrame); + m_pOutFrame->format = m_sampleFormat; ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ av_channel_layout_uninit(&m_pOutFrame->ch_layout); ++ av_channel_layout_from_mask(&m_pOutFrame->ch_layout, m_channelLayout); ++#else + m_pOutFrame->channel_layout = m_channelLayout; ++#endif + m_pOutFrame->sample_rate = m_sampleRate; + result = swr_convert_frame(m_pConvertCtx, m_pOutFrame, m_pConvertFrame); + av_frame_unref(m_pConvertFrame); +@@ -302,7 +330,15 @@ int CActiveAEFilter::ProcessFilter(uint8_t **dst_buffer, int dst_samples, uint8_ + + if (m_hasData) + { ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ AVChannelLayout layout = {}; ++ av_channel_layout_from_mask(&layout, m_channelLayout); ++ int channels = layout.nb_channels; ++ av_channel_layout_uninit(&layout); ++#else + int channels = av_get_channel_layout_nb_channels(m_channelLayout); ++#endif + int planes = av_sample_fmt_is_planar(m_sampleFormat) ? channels : 1; + int samples = std::min(dst_samples, m_pOutFrame->nb_samples - m_sampleOffset); + int bytes = samples * av_get_bytes_per_sample(m_sampleFormat) * channels / planes; +diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResampleFFMPEG.cpp b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResampleFFMPEG.cpp +index bfef837114..379dfe6446 100644 +--- a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResampleFFMPEG.cpp ++++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResampleFFMPEG.cpp +@@ -11,8 +11,10 @@ + #include "utils/log.h" + + extern "C" { ++#include <libavcodec/version.h> + #include <libavutil/channel_layout.h> + #include <libavutil/opt.h> ++#include <libavutil/version.h> + #include <libswresample/swresample.h> + } + +@@ -49,15 +51,49 @@ bool CActiveAEResampleFFMPEG::Init(SampleConfig dstConfig, SampleConfig srcConfi + m_doesResample = true; + + if (m_dst_chan_layout == 0) ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ { ++ AVChannelLayout layout = {}; ++ av_channel_layout_default(&layout, m_dst_channels); ++ m_dst_chan_layout = layout.u.mask; ++ av_channel_layout_uninit(&layout); ++ } ++#else + m_dst_chan_layout = av_get_default_channel_layout(m_dst_channels); ++#endif + if (m_src_chan_layout == 0) ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ { ++ AVChannelLayout layout = {}; ++ av_channel_layout_default(&layout, m_src_channels); ++ m_src_chan_layout = layout.u.mask; ++ av_channel_layout_uninit(&layout); ++ } ++#else + m_src_chan_layout = av_get_default_channel_layout(m_src_channels); ++#endif ++ ++#if LIBSWRESAMPLE_BUILD >= AV_VERSION_INT(4, 7, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ AVChannelLayout dstChLayout = {}; ++ AVChannelLayout srcChLayout = {}; + ++ av_channel_layout_from_mask(&dstChLayout, m_dst_chan_layout); ++ av_channel_layout_from_mask(&srcChLayout, m_src_chan_layout); ++ ++ int ret = swr_alloc_set_opts2(&m_pContext, &dstChLayout, m_dst_fmt, m_dst_rate, &srcChLayout, ++ m_src_fmt, m_src_rate, 0, NULL); ++ ++ if (ret) ++#else + m_pContext = swr_alloc_set_opts(NULL, m_dst_chan_layout, m_dst_fmt, m_dst_rate, + m_src_chan_layout, m_src_fmt, m_src_rate, + 0, NULL); + + if (!m_pContext) ++#endif + { + CLog::Log(LOGERROR, "CActiveAEResampleFFMPEG::Init - create context failed"); + return false; +@@ -126,10 +162,20 @@ bool CActiveAEResampleFFMPEG::Init(SampleConfig dstConfig, SampleConfig srcConfi + else if (upmix && m_src_channels == 2 && m_dst_channels > 2) + { + memset(m_rematrix, 0, sizeof(m_rematrix)); ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ av_channel_layout_uninit(&dstChLayout); ++ av_channel_layout_from_mask(&dstChLayout, m_dst_chan_layout); ++#endif + for (int out=0; out<m_dst_channels; out++) + { +- uint64_t out_chan = av_channel_layout_extract_channel(m_dst_chan_layout, out); +- switch(out_chan) ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ AVChannel outChan = av_channel_layout_channel_from_index(&dstChLayout, out); ++#else ++ uint64_t outChan = av_channel_layout_extract_channel(m_dst_chan_layout, out); ++#endif ++ switch (outChan) + { + case AV_CH_FRONT_LEFT: + case AV_CH_BACK_LEFT: +@@ -154,6 +200,11 @@ bool CActiveAEResampleFFMPEG::Init(SampleConfig dstConfig, SampleConfig srcConfi + } + } + ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ av_channel_layout_uninit(&dstChLayout); ++#endif ++ + if (swr_set_matrix(m_pContext, (const double*)m_rematrix, AE_CH_MAX) < 0) + { + CLog::Log(LOGERROR, "CActiveAEResampleFFMPEG::Init - setting channel matrix failed"); +diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEStream.cpp b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEStream.cpp +index 858b0f2f22..a52ac2829f 100644 +--- a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEStream.cpp ++++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEStream.cpp +@@ -88,7 +88,7 @@ void CActiveAEStream::InitRemapper() + for(unsigned int i=0; i<m_format.m_channelLayout.Count(); i++) + { + avLast = avCur; +- avCur = CAEUtil::GetAVChannel(m_format.m_channelLayout[i]); ++ avCur = CAEUtil::GetAVChannelMask(m_format.m_channelLayout[i]); + if(avCur < avLast) + { + needRemap = true; +diff --git a/xbmc/cores/AudioEngine/Utils/AEUtil.cpp b/xbmc/cores/AudioEngine/Utils/AEUtil.cpp +index bfa2cf9e4c..98f82816ef 100644 +--- a/xbmc/cores/AudioEngine/Utils/AEUtil.cpp ++++ b/xbmc/cores/AudioEngine/Utils/AEUtil.cpp +@@ -19,10 +19,6 @@ + #include <xmmintrin.h> + #endif + +-extern "C" { +-#include <libavutil/channel_layout.h> +-} +- + void AEDelayStatus::SetDelay(double d) + { + delay = d; +@@ -550,8 +546,15 @@ AVSampleFormat CAEUtil::GetAVSampleFormat(AEDataFormat format) + } + } + +-uint64_t CAEUtil::GetAVChannel(enum AEChannel aechannel) ++uint64_t CAEUtil::GetAVChannelMask(enum AEChannel aechannel) + { ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ enum AVChannel ch = GetAVChannel(aechannel); ++ if (ch == AV_CHAN_NONE) ++ return 0; ++ return (1ULL << ch); ++#else + switch (aechannel) + { + case AE_CH_FL: return AV_CH_FRONT_LEFT; +@@ -575,9 +578,67 @@ uint64_t CAEUtil::GetAVChannel(enum AEChannel aechannel) + default: + return 0; + } ++#endif + } + ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++enum AVChannel CAEUtil::GetAVChannel(enum AEChannel aechannel) ++{ ++ switch (aechannel) ++ { ++ case AE_CH_FL: ++ return AV_CHAN_FRONT_LEFT; ++ case AE_CH_FR: ++ return AV_CHAN_FRONT_RIGHT; ++ case AE_CH_FC: ++ return AV_CHAN_FRONT_CENTER; ++ case AE_CH_LFE: ++ return AV_CHAN_LOW_FREQUENCY; ++ case AE_CH_BL: ++ return AV_CHAN_BACK_LEFT; ++ case AE_CH_BR: ++ return AV_CHAN_BACK_RIGHT; ++ case AE_CH_FLOC: ++ return AV_CHAN_FRONT_LEFT_OF_CENTER; ++ case AE_CH_FROC: ++ return AV_CHAN_FRONT_RIGHT_OF_CENTER; ++ case AE_CH_BC: ++ return AV_CHAN_BACK_CENTER; ++ case AE_CH_SL: ++ return AV_CHAN_SIDE_LEFT; ++ case AE_CH_SR: ++ return AV_CHAN_SIDE_RIGHT; ++ case AE_CH_TC: ++ return AV_CHAN_TOP_CENTER; ++ case AE_CH_TFL: ++ return AV_CHAN_TOP_FRONT_LEFT; ++ case AE_CH_TFC: ++ return AV_CHAN_TOP_FRONT_CENTER; ++ case AE_CH_TFR: ++ return AV_CHAN_TOP_FRONT_RIGHT; ++ case AE_CH_TBL: ++ return AV_CHAN_TOP_BACK_LEFT; ++ case AE_CH_TBC: ++ return AV_CHAN_TOP_BACK_CENTER; ++ case AE_CH_TBR: ++ return AV_CHAN_TOP_BACK_RIGHT; ++ default: ++ return AV_CHAN_NONE; ++ } ++} ++#endif ++ + int CAEUtil::GetAVChannelIndex(enum AEChannel aechannel, uint64_t layout) + { +- return av_get_channel_layout_channel_index(layout, GetAVChannel(aechannel)); ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ AVChannelLayout ch_layout = {}; ++ av_channel_layout_from_mask(&ch_layout, layout); ++ int idx = av_channel_layout_index_from_channel(&ch_layout, GetAVChannel(aechannel)); ++ av_channel_layout_uninit(&ch_layout); ++ return idx; ++#else ++ return av_get_channel_layout_channel_index(layout, GetAVChannelMask(aechannel)); ++#endif + } +diff --git a/xbmc/cores/AudioEngine/Utils/AEUtil.h b/xbmc/cores/AudioEngine/Utils/AEUtil.h +index 034e115ee8..8acbeec442 100644 +--- a/xbmc/cores/AudioEngine/Utils/AEUtil.h ++++ b/xbmc/cores/AudioEngine/Utils/AEUtil.h +@@ -13,7 +13,10 @@ + #include <math.h> + + extern "C" { ++#include <libavcodec/version.h> ++#include <libavutil/channel_layout.h> + #include <libavutil/samplefmt.h> ++#include <libavutil/version.h> + } + + // AV sync options +@@ -171,6 +174,10 @@ public: + static uint64_t GetAVChannelLayout(const CAEChannelInfo &info); + static CAEChannelInfo GetAEChannelLayout(uint64_t layout); + static AVSampleFormat GetAVSampleFormat(AEDataFormat format); +- static uint64_t GetAVChannel(enum AEChannel aechannel); ++ static uint64_t GetAVChannelMask(enum AEChannel aechannel); ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ static enum AVChannel GetAVChannel(enum AEChannel aechannel); ++#endif + static int GetAVChannelIndex(enum AEChannel aechannel, uint64_t layout); + }; +diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp +index 87e7ae2c57..44dcb32620 100644 +--- a/xbmc/cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp ++++ b/xbmc/cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp +@@ -78,7 +78,14 @@ bool CDVDAudioCodecFFmpeg::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options + + m_matrixEncoding = AV_MATRIX_ENCODING_NONE; + m_channels = 0; ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ av_channel_layout_uninit(&m_pCodecContext->ch_layout); ++ m_pCodecContext->ch_layout.order = AV_CHANNEL_ORDER_NATIVE; ++ m_pCodecContext->ch_layout.nb_channels = hints.channels; ++#else + m_pCodecContext->channels = hints.channels; ++#endif + m_hint_layout = hints.channellayout; + m_pCodecContext->sample_rate = hints.samplerate; + m_pCodecContext->block_align = hints.blockalign; +@@ -261,12 +268,18 @@ int CDVDAudioCodecFFmpeg::GetData(uint8_t** dst) + m_format.m_frameSize = m_format.m_channelLayout.Count() * + CAEUtil::DataFormatToBits(m_format.m_dataFormat) >> 3; + +- int planes = av_sample_fmt_is_planar(m_pCodecContext->sample_fmt) ? m_pFrame->channels : 1; ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ int channels = m_pFrame->ch_layout.nb_channels; ++#else ++ int channels = m_pFrame->channels; ++#endif ++ int planes = av_sample_fmt_is_planar(m_pCodecContext->sample_fmt) ? channels : 1; ++ + for (int i=0; i<planes; i++) + dst[i] = m_pFrame->extended_data[i]; + +- return m_pFrame->nb_samples * m_pFrame->channels * +- av_get_bytes_per_sample(m_pCodecContext->sample_fmt); ++ return m_pFrame->nb_samples * channels * av_get_bytes_per_sample(m_pCodecContext->sample_fmt); + } + + return 0; +@@ -280,7 +293,12 @@ void CDVDAudioCodecFFmpeg::Reset() + + int CDVDAudioCodecFFmpeg::GetChannels() + { ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ return m_pCodecContext->ch_layout.nb_channels; ++#else + return m_pCodecContext->channels; ++#endif + } + + int CDVDAudioCodecFFmpeg::GetSampleRate() +@@ -347,28 +365,44 @@ static unsigned count_bits(int64_t value) + + void CDVDAudioCodecFFmpeg::BuildChannelMap() + { +- if (m_channels == m_pCodecContext->channels && m_layout == m_pCodecContext->channel_layout) ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ int codecChannels = m_pCodecContext->ch_layout.nb_channels; ++ uint64_t codecChannelLayout = m_pCodecContext->ch_layout.u.mask; ++#else ++ int codecChannels = m_pCodecContext->channels; ++ uint64_t codecChannelLayout = m_pCodecContext->channel_layout; ++#endif ++ if (m_channels == codecChannels && m_layout == codecChannelLayout) + return; //nothing to do here + +- m_channels = m_pCodecContext->channels; +- m_layout = m_pCodecContext->channel_layout; ++ m_channels = codecChannels; ++ m_layout = codecChannelLayout; + + int64_t layout; + +- int bits = count_bits(m_pCodecContext->channel_layout); +- if (bits == m_pCodecContext->channels) +- layout = m_pCodecContext->channel_layout; ++ int bits = count_bits(codecChannelLayout); ++ if (bits == codecChannels) ++ layout = codecChannelLayout; + else + { + CLog::Log(LOGINFO, + "CDVDAudioCodecFFmpeg::GetChannelMap - FFmpeg reported {} channels, but the layout " + "contains {} - trying hints", +- m_pCodecContext->channels, bits); +- if (static_cast<int>(count_bits(m_hint_layout)) == m_pCodecContext->channels) ++ codecChannels, bits); ++ if (static_cast<int>(count_bits(m_hint_layout)) == codecChannels) + layout = m_hint_layout; + else + { ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ AVChannelLayout def_layout = {}; ++ av_channel_layout_default(&def_layout, codecChannels); ++ layout = def_layout.u.mask; ++ av_channel_layout_uninit(&def_layout); ++#else + layout = av_get_default_channel_layout(m_pCodecContext->channels); ++#endif + CLog::Log(LOGINFO, "Using default layout..."); + } + } +@@ -394,7 +428,7 @@ void CDVDAudioCodecFFmpeg::BuildChannelMap() + if (layout & AV_CH_TOP_BACK_CENTER ) m_channelLayout += AE_CH_BC ; + if (layout & AV_CH_TOP_BACK_RIGHT ) m_channelLayout += AE_CH_BR ; + +- m_channels = m_pCodecContext->channels; ++ m_channels = codecChannels; + } + + CAEChannelInfo CDVDAudioCodecFFmpeg::GetChannelMap() +diff --git a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxClient.cpp b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxClient.cpp +index 5be134e381..70f0562462 100644 +--- a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxClient.cpp ++++ b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxClient.cpp +@@ -220,10 +220,17 @@ bool CDVDDemuxClient::ParsePacket(DemuxPacket* pkt) + case STREAM_AUDIO: + { + CDemuxStreamClientInternalTpl<CDemuxStreamAudio>* sta = static_cast<CDemuxStreamClientInternalTpl<CDemuxStreamAudio>*>(st); +- if (stream->m_context->channels != sta->iChannels && stream->m_context->channels != 0) ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ int streamChannels = stream->m_context->ch_layout.nb_channels; ++#else ++ int streamChannels = stream->m_context->channels; ++#endif ++ if (streamChannels != sta->iChannels && streamChannels != 0) + { +- CLog::Log(LOGDEBUG, "CDVDDemuxClient::ParsePacket - ({}) channels changed from {} to {}", st->uniqueId, sta->iChannels, stream->m_context->channels); +- sta->iChannels = stream->m_context->channels; ++ CLog::Log(LOGDEBUG, "CDVDDemuxClient::ParsePacket - ({}) channels changed from {} to {}", ++ st->uniqueId, sta->iChannels, streamChannels); ++ sta->iChannels = streamChannels; + sta->changes++; + sta->disabled = false; + } +@@ -235,7 +242,7 @@ bool CDVDDemuxClient::ParsePacket(DemuxPacket* pkt) + sta->changes++; + sta->disabled = false; + } +- if (stream->m_context->channels) ++ if (streamChannels) + st->changes = -1; // stop parsing + break; + } +diff --git a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp +index bf6f322274..4ad52cd32a 100644 +--- a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp ++++ b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp +@@ -1235,8 +1235,16 @@ DemuxPacket* CDVDDemuxFFmpeg::Read() + else if (stream->type == STREAM_AUDIO) + { + CDemuxStreamAudioFFmpeg* audiostream = dynamic_cast<CDemuxStreamAudioFFmpeg*>(stream); +- if (audiostream && (audiostream->iChannels != m_pFormatContext->streams[pPacket->iStreamId]->codecpar->channels || +- audiostream->iSampleRate != m_pFormatContext->streams[pPacket->iStreamId]->codecpar->sample_rate)) ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ int codecparChannels = ++ m_pFormatContext->streams[pPacket->iStreamId]->codecpar->ch_layout.nb_channels; ++#else ++ int codecparChannels = m_pFormatContext->streams[pPacket->iStreamId]->codecpar->channels; ++#endif ++ if (audiostream && (audiostream->iChannels != codecparChannels || ++ audiostream->iSampleRate != ++ m_pFormatContext->streams[pPacket->iStreamId]->codecpar->sample_rate)) + { + // content has changed + stream = AddStream(pPacket->iStreamId); +@@ -1418,6 +1426,7 @@ void CDVDDemuxFFmpeg::UpdateCurrentPTS() + if (idx >= 0) + { + AVStream* stream = m_pFormatContext->streams[idx]; ++ + #if LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 17, 100) + if (stream && m_pkt.pkt.dts != (int64_t)AV_NOPTS_VALUE) + { +@@ -1639,16 +1648,28 @@ CDemuxStream* CDVDDemuxFFmpeg::AddStream(int streamIdx) + { + CDemuxStreamAudioFFmpeg* st = new CDemuxStreamAudioFFmpeg(pStream); + stream = st; +- st->iChannels = pStream->codecpar->channels; ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ int codecparChannels = pStream->codecpar->ch_layout.nb_channels; ++ int codecparChannelLayout = pStream->codecpar->ch_layout.u.mask; ++#else ++ int codecparChannels = pStream->codecpar->channels; ++ int codecparChannelLayout = pStream->codecpar->channel_layout; ++#endif ++ st->iChannels = codecparChannels; ++ st->iChannelLayout = codecparChannelLayout; + st->iSampleRate = pStream->codecpar->sample_rate; + st->iBlockAlign = pStream->codecpar->block_align; + st->iBitRate = static_cast<int>(pStream->codecpar->bit_rate); + st->iBitsPerSample = pStream->codecpar->bits_per_raw_sample; +- st->iChannelLayout = pStream->codecpar->channel_layout; + char buf[32] = {}; + // https://github.com/FFmpeg/FFmpeg/blob/6ccc3989d15/doc/APIchanges#L50-L53 +-#if LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 24, 100) +- av_channel_layout_describe(st->iChannelLayout, buf, sizeof(buf)); ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ AVChannelLayout layout = {}; ++ av_channel_layout_from_mask(&layout, st->iChannelLayout); ++ av_channel_layout_describe(&layout, buf, sizeof(buf)); ++ av_channel_layout_uninit(&layout); + #else + av_get_channel_layout_string(buf, 31, st->iChannels, st->iChannelLayout); + #endif +@@ -2195,8 +2216,13 @@ bool CDVDDemuxFFmpeg::IsProgramChange() + if (m_pFormatContext->streams[idx]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) + { + CDemuxStreamAudioFFmpeg* audiostream = dynamic_cast<CDemuxStreamAudioFFmpeg*>(stream); +- if (audiostream && +- m_pFormatContext->streams[idx]->codecpar->channels != audiostream->iChannels) ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ int codecparChannels = m_pFormatContext->streams[idx]->codecpar->ch_layout.nb_channels; ++#else ++ int codecparChannels = m_pFormatContext->streams[idx]->codecpar->channels; ++#endif ++ if (audiostream && codecparChannels != audiostream->iChannels) + { + return true; + } +-- +2.35.1 + + +From 0a10e05700dfd12b7f5d720588b993089ea33be4 Mon Sep 17 00:00:00 2001 +From: Vasyl Gello <vasek.gello@gmail.com> +Date: Sat, 15 Oct 2022 11:46:52 +0000 +Subject: [PATCH 3/3] ffmpeg5: Get extradata with extract_extradata BSF + +Fixes the transport stream playback failures described in +https://bugs.debian.org/1016925 + +Rogo95 made an excellent technical analysis of the root cause +and reported that to the bug thread. + +Later on, James Almer (jamrial) suggested the solution to use +extract_extradata bitstream filter to replace the removed split() +function. + +Finally, I adapted the following code snippet: +https://gist.github.com/moonpfe/f6795d51294d91ee0f82f62ff6985db0 +to Kodi and tested it by playing the affected files in TS format. + +HiassofT form LibreELEC found another edge case decoding HTSP +streams from pvr.hts. The comparison of log files revealed that +the split function is also used in DVDDemuxClient. + +Signed-off-by: Vasyl Gello <vasek.gello@gmail.com> +--- + xbmc/cores/FFmpeg.cpp | 154 ++++++++++++++++++ + xbmc/cores/FFmpeg.h | 5 + + .../DVDDemuxers/DVDDemuxClient.cpp | 37 ++--- + .../DVDDemuxers/DVDDemuxFFmpeg.cpp | 61 +++---- + 4 files changed, 203 insertions(+), 54 deletions(-) + +diff --git a/xbmc/cores/FFmpeg.cpp b/xbmc/cores/FFmpeg.cpp +index de1765ed52..eb9c653fa3 100644 +--- a/xbmc/cores/FFmpeg.cpp ++++ b/xbmc/cores/FFmpeg.cpp +@@ -16,6 +16,11 @@ + #include "utils/StringUtils.h" + #include "utils/log.h" + ++extern "C" ++{ ++#include <libavcodec/bsf.h> ++} ++ + #include <map> + #include <mutex> + +@@ -129,3 +134,152 @@ void ff_avutil_log(void* ptr, int level, const char* format, va_list va) + } + buffer.erase(0, start); + } ++ ++std::tuple<uint8_t*, int> GetPacketExtradata(const AVPacket* pkt, ++ const AVCodecParserContext* parserCtx, ++ AVCodecContext* codecCtx) ++{ ++ constexpr int FF_MAX_EXTRADATA_SIZE = ((1 << 28) - AV_INPUT_BUFFER_PADDING_SIZE); ++ ++ if (!pkt) ++ return std::make_tuple(nullptr, 0); ++ ++ uint8_t* extraData = nullptr; ++ int extraDataSize = 0; ++ ++#if LIBAVFORMAT_BUILD >= AV_VERSION_INT(59, 0, 100) ++ /* extract_extradata bitstream filter is implemented only ++ * for certain codecs, as noted in discussion of PR#21248 ++ */ ++ ++ AVCodecID codecId = codecCtx->codec_id; ++ ++ // clang-format off ++ if ( ++ codecId != AV_CODEC_ID_MPEG1VIDEO && ++ codecId != AV_CODEC_ID_MPEG2VIDEO && ++ codecId != AV_CODEC_ID_H264 && ++ codecId != AV_CODEC_ID_HEVC && ++ codecId != AV_CODEC_ID_MPEG4 && ++ codecId != AV_CODEC_ID_VC1 && ++ codecId != AV_CODEC_ID_AV1 && ++ codecId != AV_CODEC_ID_AVS2 && ++ codecId != AV_CODEC_ID_AVS3 && ++ codecId != AV_CODEC_ID_CAVS ++ ) ++ // clang-format on ++ return std::make_tuple(nullptr, 0); ++ ++ const AVBitStreamFilter* f = av_bsf_get_by_name("extract_extradata"); ++ if (!f) ++ return std::make_tuple(nullptr, 0); ++ ++ AVBSFContext* bsf = nullptr; ++ int ret = av_bsf_alloc(f, &bsf); ++ if (ret < 0) ++ return std::make_tuple(nullptr, 0); ++ ++ bsf->par_in->codec_id = codecId; ++ ++ ret = av_bsf_init(bsf); ++ if (ret < 0) ++ { ++ av_bsf_free(&bsf); ++ return std::make_tuple(nullptr, 0); ++ } ++ ++ AVPacket* dstPkt = av_packet_alloc(); ++ if (!dstPkt) ++ { ++ CLog::LogF(LOGERROR, "failed to allocate packet"); ++ ++ av_bsf_free(&bsf); ++ return std::make_tuple(nullptr, 0); ++ } ++ AVPacket* pktRef = dstPkt; ++ ++ ret = av_packet_ref(pktRef, pkt); ++ if (ret < 0) ++ { ++ av_bsf_free(&bsf); ++ av_packet_free(&dstPkt); ++ return std::make_tuple(nullptr, 0); ++ } ++ ++ ret = av_bsf_send_packet(bsf, pktRef); ++ if (ret < 0) ++ { ++ av_packet_unref(pktRef); ++ av_bsf_free(&bsf); ++ av_packet_free(&dstPkt); ++ return std::make_tuple(nullptr, 0); ++ } ++ ++ ret = 0; ++ while (ret >= 0) ++ { ++ ret = av_bsf_receive_packet(bsf, pktRef); ++ if (ret < 0) ++ { ++ if (ret != AVERROR(EAGAIN) && ret != AVERROR_EOF) ++ break; ++ ++ continue; ++ } ++ ++ size_t retExtraDataSize = 0; ++ uint8_t* retExtraData = ++ av_packet_get_side_data(pktRef, AV_PKT_DATA_NEW_EXTRADATA, &retExtraDataSize); ++ if (retExtraData && retExtraDataSize > 0 && retExtraDataSize < FF_MAX_EXTRADATA_SIZE) ++ { ++ extraData = static_cast<uint8_t*>(av_malloc(retExtraDataSize + AV_INPUT_BUFFER_PADDING_SIZE)); ++ if (!extraData) ++ { ++ CLog::LogF(LOGERROR, "failed to allocate {} bytes for extradata", retExtraDataSize); ++ ++ av_packet_unref(pktRef); ++ av_bsf_free(&bsf); ++ av_packet_free(&dstPkt); ++ return std::make_tuple(nullptr, 0); ++ } ++ ++ CLog::LogF(LOGDEBUG, "fetching extradata, extradata_size({})", retExtraDataSize); ++ ++ memcpy(extraData, retExtraData, retExtraDataSize); ++ memset(extraData + retExtraDataSize, 0, AV_INPUT_BUFFER_PADDING_SIZE); ++ extraDataSize = retExtraDataSize; ++ ++ av_packet_unref(pktRef); ++ break; ++ } ++ ++ av_packet_unref(pktRef); ++ } ++ ++ av_bsf_free(&bsf); ++ av_packet_free(&dstPkt); ++#else ++ if (codecCtx && parserCtx && parserCtx->parser && parserCtx->parser->split) ++ extraDataSize = parserCtx->parser->split(codecCtx, pkt->data, pkt->size); ++ ++ if (extraDataSize <= 0 || extraDataSize >= FF_MAX_EXTRADATA_SIZE) ++ { ++ CLog::LogF(LOGDEBUG, "fetched extradata of weird size {}", extraDataSize); ++ return std::make_tuple(nullptr, 0); ++ } ++ ++ extraData = static_cast<uint8_t*>(av_malloc(extraDataSize + AV_INPUT_BUFFER_PADDING_SIZE)); ++ if (!extraData) ++ { ++ CLog::LogF(LOGERROR, "failed to allocate {} bytes for extradata", extraDataSize); ++ return std::make_tuple(nullptr, 0); ++ } ++ ++ CLog::LogF(LOGDEBUG, "fetching extradata, extradata_size({})", extraDataSize); ++ ++ memcpy(extraData, pkt->data, extraDataSize); ++ memset(extraData + extraDataSize, 0, AV_INPUT_BUFFER_PADDING_SIZE); ++#endif ++ ++ return std::make_tuple(extraData, extraDataSize); ++} +diff --git a/xbmc/cores/FFmpeg.h b/xbmc/cores/FFmpeg.h +index 8230701ba7..22a253e191 100644 +--- a/xbmc/cores/FFmpeg.h ++++ b/xbmc/cores/FFmpeg.h +@@ -22,6 +22,8 @@ extern "C" { + #include <libpostproc/postprocess.h> + } + ++#include <tuple> ++ + // https://github.com/FFmpeg/FFmpeg/blob/56450a0ee4/doc/APIchanges#L18-L26 + #if LIBAVFORMAT_BUILD >= AV_VERSION_INT(59, 0, 100) + #define FFMPEG_FMT_CONST const +@@ -77,3 +79,6 @@ public: + int level; + }; + ++std::tuple<uint8_t*, int> GetPacketExtradata(const AVPacket* pkt, ++ const AVCodecParserContext* parserCtx, ++ AVCodecContext* codecCtx); +diff --git a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxClient.cpp b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxClient.cpp +index 70f0562462..f42710282d 100644 +--- a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxClient.cpp ++++ b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxClient.cpp +@@ -14,10 +14,9 @@ + #include "cores/VideoPlayer/Interface/TimingConstants.h" + #include "utils/log.h" + ++#include <tuple> + #include <utility> + +-#define FF_MAX_EXTRADATA_SIZE ((1 << 28) - AV_INPUT_BUFFER_PADDING_SIZE) +- + class CDemuxStreamClientInternal + { + public: +@@ -150,17 +149,26 @@ bool CDVDDemuxClient::ParsePacket(DemuxPacket* pkt) + stream->m_context->time_base.den = DVD_TIME_BASE; + } + +- if (stream->m_parser_split && stream->m_parser->parser->split) ++ if (stream->m_parser_split && stream->m_parser && stream->m_parser->parser) + { +- int len = stream->m_parser->parser->split(stream->m_context, pkt->pData, pkt->iSize); +- if (len > 0 && len < FF_MAX_EXTRADATA_SIZE) ++ AVPacket* avpkt = av_packet_alloc(); ++ if (!avpkt) ++ { ++ CLog::LogF(LOGERROR, "av_packet_alloc failed: {}", strerror(errno)); ++ return false; ++ } ++ ++ avpkt->data = pkt->pData; ++ avpkt->size = pkt->iSize; ++ avpkt->dts = avpkt->pts = AV_NOPTS_VALUE; ++ ++ auto [retExtraData, len] = GetPacketExtradata(avpkt, stream->m_parser, stream->m_context); ++ if (len > 0) + { + st->changes++; + st->disabled = false; + st->ExtraSize = len; +- st->ExtraData = std::make_unique<uint8_t[]>(len + AV_INPUT_BUFFER_PADDING_SIZE); +- memcpy(st->ExtraData.get(), pkt->pData, len); +- memset(st->ExtraData.get() + len, 0, AV_INPUT_BUFFER_PADDING_SIZE); ++ st->ExtraData = std::unique_ptr<uint8_t[]>(retExtraData); + stream->m_parser_split = false; + change = true; + CLog::Log(LOGDEBUG, "CDVDDemuxClient::ParsePacket - split extradata"); +@@ -168,21 +176,12 @@ bool CDVDDemuxClient::ParsePacket(DemuxPacket* pkt) + // Allow ffmpeg to transport codec information to stream->m_context + if (!avcodec_open2(stream->m_context, stream->m_context->codec, nullptr)) + { +- AVPacket* avpkt = av_packet_alloc(); +- if (!avpkt) +- { +- CLog::Log(LOGERROR, "CDVDDemuxClient::{} - av_packet_alloc failed: {}", __FUNCTION__, +- strerror(errno)); +- return false; +- } +- avpkt->data = pkt->pData; +- avpkt->size = pkt->iSize; +- avpkt->dts = avpkt->pts = AV_NOPTS_VALUE; + avcodec_send_packet(stream->m_context, avpkt); + avcodec_close(stream->m_context); +- av_packet_free(&avpkt); + } + } ++ ++ av_packet_free(&avpkt); + } + + uint8_t *outbuf = nullptr; +diff --git a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp +index 4ad52cd32a..3081dd8e9a 100644 +--- a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp ++++ b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp +@@ -34,6 +34,7 @@ + + #include <mutex> + #include <sstream> ++#include <tuple> + #include <utility> + + extern "C" +@@ -105,8 +106,6 @@ bool AttachmentIsFont(const AVDictionaryEntry* dict) + } + } // namespace + +-#define FF_MAX_EXTRADATA_SIZE ((1 << 28) - AV_INPUT_BUFFER_PADDING_SIZE) +- + std::string CDemuxStreamAudioFFmpeg::GetStreamName() + { + if (!m_stream) +@@ -2358,44 +2357,36 @@ void CDVDDemuxFFmpeg::ParsePacket(AVPacket* pkt) + + if (parser->second->m_parserCtx && + parser->second->m_parserCtx->parser && +- parser->second->m_parserCtx->parser->split && + !st->codecpar->extradata) + { +- int i = parser->second->m_parserCtx->parser->split(parser->second->m_codecCtx, pkt->data, pkt->size); +- if (i > 0 && i < FF_MAX_EXTRADATA_SIZE) ++ auto [retExtraData, i] = ++ GetPacketExtradata(pkt, parser->second->m_parserCtx, parser->second->m_codecCtx); ++ if (i > 0) + { +- st->codecpar->extradata = (uint8_t*)av_malloc(i + AV_INPUT_BUFFER_PADDING_SIZE); +- if (st->codecpar->extradata) +- { +- CLog::Log(LOGDEBUG, +- "CDVDDemuxFFmpeg::ParsePacket() fetching extradata, extradata_size({})", i); +- st->codecpar->extradata_size = i; +- memcpy(st->codecpar->extradata, pkt->data, i); +- memset(st->codecpar->extradata + i, 0, AV_INPUT_BUFFER_PADDING_SIZE); ++ st->codecpar->extradata_size = i; ++ st->codecpar->extradata = retExtraData; + +- if (parser->second->m_parserCtx->parser->parser_parse) ++ if (parser->second->m_parserCtx->parser->parser_parse) ++ { ++ parser->second->m_codecCtx->extradata = st->codecpar->extradata; ++ parser->second->m_codecCtx->extradata_size = st->codecpar->extradata_size; ++ const uint8_t* outbufptr; ++ int bufSize; ++ parser->second->m_parserCtx->flags |= PARSER_FLAG_COMPLETE_FRAMES; ++ parser->second->m_parserCtx->parser->parser_parse(parser->second->m_parserCtx, ++ parser->second->m_codecCtx, &outbufptr, ++ &bufSize, pkt->data, pkt->size); ++ parser->second->m_codecCtx->extradata = nullptr; ++ parser->second->m_codecCtx->extradata_size = 0; ++ ++ if (parser->second->m_parserCtx->width != 0) + { +- parser->second->m_codecCtx->extradata = st->codecpar->extradata; +- parser->second->m_codecCtx->extradata_size = st->codecpar->extradata_size; +- const uint8_t* outbufptr; +- int bufSize; +- parser->second->m_parserCtx->flags |= PARSER_FLAG_COMPLETE_FRAMES; +- parser->second->m_parserCtx->parser->parser_parse(parser->second->m_parserCtx, +- parser->second->m_codecCtx, +- &outbufptr, &bufSize, +- pkt->data, pkt->size); +- parser->second->m_codecCtx->extradata = nullptr; +- parser->second->m_codecCtx->extradata_size = 0; +- +- if (parser->second->m_parserCtx->width != 0) +- { +- st->codecpar->width = parser->second->m_parserCtx->width; +- st->codecpar->height = parser->second->m_parserCtx->height; +- } +- else +- { +- CLog::Log(LOGERROR, "CDVDDemuxFFmpeg::ParsePacket() invalid width/height"); +- } ++ st->codecpar->width = parser->second->m_parserCtx->width; ++ st->codecpar->height = parser->second->m_parserCtx->height; ++ } ++ else ++ { ++ CLog::Log(LOGERROR, "CDVDDemuxFFmpeg::ParsePacket() invalid width/height"); + } + } + } +-- +2.35.1 + +From d61499e7f8451bf080112a3f1332c8826d6ce1ac Mon Sep 17 00:00:00 2001 +From: fritsch <Peter.Fruehberger@gmail.com> +Date: Tue, 17 Jan 2023 20:28:31 +0100 +Subject: [PATCH] AEEncoderFFmpeg: Break when one packet is received + +--- + .../AudioEngine/Encoders/AEEncoderFFmpeg.cpp | 23 +++++++++---------- + 1 file changed, 11 insertions(+), 12 deletions(-) + +diff --git a/xbmc/cores/AudioEngine/Encoders/AEEncoderFFmpeg.cpp b/xbmc/cores/AudioEngine/Encoders/AEEncoderFFmpeg.cpp +index ba35c9506395e..bc6ce300ad028 100644 +--- a/xbmc/cores/AudioEngine/Encoders/AEEncoderFFmpeg.cpp ++++ b/xbmc/cores/AudioEngine/Encoders/AEEncoderFFmpeg.cpp +@@ -333,43 +333,42 @@ int CAEEncoderFFmpeg::Encode(uint8_t *in, int in_size, uint8_t *out, int out_siz + + avcodec_fill_audio_frame(frame, channelNum, m_CodecCtx->sample_fmt, in, in_size, 0); + +- pkt->size = out_size; +- pkt->data = out; +- + /* encode it */ + err = avcodec_send_frame(m_CodecCtx, frame); + if (err < 0) + throw FFMpegException("Error sending a frame for encoding (error '{}')", + FFMpegErrorToString(err)); + +- while (err >= 0) ++ err = avcodec_receive_packet(m_CodecCtx, pkt); ++ // err < 0 - we cannot cope with it ++ // err is EAGAIN or EOF - return to caller as well ++ if (err >= 0) + { +- err = avcodec_receive_packet(m_CodecCtx, pkt); +- if (err == AVERROR(EAGAIN) || err == AVERROR_EOF) ++ if (pkt->size <= out_size) + { +-#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ +- LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) +- av_channel_layout_uninit(&frame->ch_layout); +-#endif +- av_frame_free(&frame); +- av_packet_free(&pkt); +- return (err == AVERROR(EAGAIN)) ? -1 : 0; ++ memset(out, 0, out_size); ++ memcpy(out, pkt->data, pkt->size); ++ size = pkt->size; + } +- else if (err < 0) ++ else + { +- throw FFMpegException("Error during encoding (error '{}')", FFMpegErrorToString(err)); ++ CLog::LogF(LOGERROR, "Encoded pkt size ({}) is bigger than buffer ({})", pkt->size, ++ out_size); + } + + av_packet_unref(pkt); + } +- +- size = pkt->size; + } + catch (const FFMpegException& caught) + { + CLog::Log(LOGERROR, "CAEEncoderFFmpeg::{} - {}", __func__, caught.what()); + } + ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ av_channel_layout_uninit(&frame->ch_layout); ++#endif ++ + /* free temporary data */ + av_frame_free(&frame); diff --git a/debian/patches/workarounds/0003-xbmc-libdvd_vfs-enen92.patch b/debian/patches/workarounds/0003-xbmc-libdvd_vfs-enen92.patch new file mode 100644 index 0000000..d3ac4ee --- /dev/null +++ b/debian/patches/workarounds/0003-xbmc-libdvd_vfs-enen92.patch @@ -0,0 +1,5056 @@ +From 089f6faaeaf67e3fb027f60635dd5331bcca9c47 Mon Sep 17 00:00:00 2001 +From: enen92 <92enen@gmail.com> +Date: Sat, 25 Jun 2022 16:17:09 +0100 +Subject: [PATCH 1/9] Unwrap dll + +--- + xbmc/CMakeLists.txt | 1 - + xbmc/DllPaths.h | 4 +- + xbmc/DllPaths_generated.h.in | 3 - + xbmc/DllPaths_generated_android.h.in | 3 - + xbmc/DllPaths_win32.h | 12 - + .../DVDInputStreams/CMakeLists.txt | 1 - + .../DVDInputStreamNavigator.cpp | 207 +++-- + .../DVDInputStreams/DVDInputStreamNavigator.h | 5 +- + .../VideoPlayer/DVDInputStreams/DllDvdNav.h | 275 ------ + .../DVDInputStreams/dvdnav/config.h | 76 -- + .../DVDInputStreams/dvdnav/dvd_reader.h | 370 -------- + .../DVDInputStreams/dvdnav/dvd_types.h | 282 ------- + .../DVDInputStreams/dvdnav/dvdnav.h | 789 ------------------ + .../DVDInputStreams/dvdnav/dvdnav_events.h | 226 ----- + .../DVDInputStreams/dvdnav/ifo_types.h | 754 ----------------- + .../DVDInputStreams/dvdnav/nav_types.h | 258 ------ + .../DVDInputStreams/dvdnav/version.h | 29 - + 17 files changed, 106 insertions(+), 3189 deletions(-) + delete mode 100644 xbmc/DllPaths_win32.h + delete mode 100644 xbmc/cores/VideoPlayer/DVDInputStreams/DllDvdNav.h + delete mode 100644 xbmc/cores/VideoPlayer/DVDInputStreams/dvdnav/config.h + delete mode 100644 xbmc/cores/VideoPlayer/DVDInputStreams/dvdnav/dvd_reader.h + delete mode 100644 xbmc/cores/VideoPlayer/DVDInputStreams/dvdnav/dvd_types.h + delete mode 100644 xbmc/cores/VideoPlayer/DVDInputStreams/dvdnav/dvdnav.h + delete mode 100644 xbmc/cores/VideoPlayer/DVDInputStreams/dvdnav/dvdnav_events.h + delete mode 100644 xbmc/cores/VideoPlayer/DVDInputStreams/dvdnav/ifo_types.h + delete mode 100644 xbmc/cores/VideoPlayer/DVDInputStreams/dvdnav/nav_types.h + delete mode 100644 xbmc/cores/VideoPlayer/DVDInputStreams/dvdnav/version.h + +diff --git a/xbmc/CMakeLists.txt b/xbmc/CMakeLists.txt +index 4c69707dd5..4db2dc79a8 100644 +--- a/xbmc/CMakeLists.txt ++++ b/xbmc/CMakeLists.txt +@@ -42,7 +42,6 @@ set(HEADERS AutoSwitch.h + DatabaseManager.h + DbUrl.h + DllPaths.h +- DllPaths_win32.h + DynamicDll.h + FileItem.h + FileItemListModification.h +diff --git a/xbmc/DllPaths.h b/xbmc/DllPaths.h +index 09bdd1ba3d..33fb46635e 100644 +--- a/xbmc/DllPaths.h ++++ b/xbmc/DllPaths.h +@@ -8,9 +8,7 @@ + + #pragma once + +-#ifdef TARGET_WINDOWS +-#include "DllPaths_win32.h" +-#elif defined (TARGET_ANDROID) ++#if defined (TARGET_ANDROID) + #include "DllPaths_generated_android.h" + #else + #include "DllPaths_generated.h" +diff --git a/xbmc/DllPaths_generated.h.in b/xbmc/DllPaths_generated.h.in +index f29faa41fd..405a7b5b29 100644 +--- a/xbmc/DllPaths_generated.h.in ++++ b/xbmc/DllPaths_generated.h.in +@@ -11,9 +11,6 @@ + /* prefix install location */ + #define PREFIX_USR_PATH "@prefix@" + +-/* VideoPlayer */ +-#define DLL_PATH_LIBDVDNAV "special://xbmcbin/system/players/VideoPlayer/libdvdnav-@ARCH@.so" +- + /* sse4 */ + #define DLL_PATH_LIBSSE4 "special://xbmcbin/system/libsse4-@ARCH@.so" + +diff --git a/xbmc/DllPaths_generated_android.h.in b/xbmc/DllPaths_generated_android.h.in +index d15988e361..70ceb669aa 100644 +--- a/xbmc/DllPaths_generated_android.h.in ++++ b/xbmc/DllPaths_generated_android.h.in +@@ -17,8 +17,5 @@ + // We only keep @ARCH@ here to retain the same structure as *nix. + // * foo.so will be renamed libfoo.so in the packaging stage + +-/* VideoPlayer */ +-#define DLL_PATH_LIBDVDNAV "libdvdnav-@ARCH@.so" +- + /* Android's libui for gralloc */ + #define DLL_PATH_LIBUI "libui.so" +diff --git a/xbmc/DllPaths_win32.h b/xbmc/DllPaths_win32.h +deleted file mode 100644 +index ea41058a54..0000000000 +--- a/xbmc/DllPaths_win32.h ++++ /dev/null +@@ -1,12 +0,0 @@ +-/* +- * Copyright (C) 2005-2018 Team Kodi +- * This file is part of Kodi - https://kodi.tv +- * +- * SPDX-License-Identifier: GPL-2.0-or-later +- * See LICENSES/README.md for more information. +- */ +- +-#pragma once +- +-/* VideoPlayer */ +-#define DLL_PATH_LIBDVDNAV "special://xbmcbin/libdvdnav.dll" +diff --git a/xbmc/cores/VideoPlayer/DVDInputStreams/CMakeLists.txt b/xbmc/cores/VideoPlayer/DVDInputStreams/CMakeLists.txt +index 576ddda150..1aecf6f032 100644 +--- a/xbmc/cores/VideoPlayer/DVDInputStreams/CMakeLists.txt ++++ b/xbmc/cores/VideoPlayer/DVDInputStreams/CMakeLists.txt +@@ -22,7 +22,6 @@ set(HEADERS BlurayStateSerializer.h + DVDInputStreamNavigator.h + DVDInputStreamStack.h + DVDStateSerializer.h +- DllDvdNav.h + InputStreamAddon.h + InputStreamMultiStreams.h + InputStreamMultiSource.h +diff --git a/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamNavigator.cpp b/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamNavigator.cpp +index e7b54e3351..859762348b 100644 +--- a/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamNavigator.cpp ++++ b/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamNavigator.cpp +@@ -109,9 +109,6 @@ bool CDVDInputStreamNavigator::Open() + CEnvironment::putenv("DVDCSS_CACHE=" + CSpecialProtocol::TranslatePath("special://masterprofile/cache")); + #endif + +- // load libdvdnav.dll +- if (!m_dll.Load()) +- return false; + + // load the dvd language codes + // g_LangCodeExpander.LoadStandardCodes(); +@@ -146,10 +143,10 @@ bool CDVDInputStreamNavigator::Open() + // if dvd image file (ISO or alike) open using libdvdnav stream callback functions + m_pstream.reset(new CDVDInputStreamFile(m_item, XFILE::READ_TRUNCATED | XFILE::READ_BITRATE | XFILE::READ_CHUNKED)); + #if DVDNAV_VERSION >= 60100 +- if (!m_pstream->Open() || m_dll.dvdnav_open_stream2(&m_dvdnav, m_pstream.get(), &loggerCallback, ++ if (!m_pstream->Open() || dvdnav_open_stream2(&m_dvdnav, m_pstream.get(), &loggerCallback, + &m_dvdnav_stream_cb) != DVDNAV_STATUS_OK) + #else +- if (!m_pstream->Open() || m_dll.dvdnav_open_stream(&m_dvdnav, m_pstream.get(), &m_dvdnav_stream_cb) != DVDNAV_STATUS_OK) ++ if (!m_pstream->Open() || dvdnav_open_stream(&m_dvdnav, m_pstream.get(), &m_dvdnav_stream_cb) != DVDNAV_STATUS_OK) + #endif + { + CLog::Log(LOGERROR, "Error opening image file or Error on dvdnav_open_stream"); +@@ -158,10 +155,10 @@ bool CDVDInputStreamNavigator::Open() + } + } + #if DVDNAV_VERSION >= 60100 +- else if (m_dll.dvdnav_open2(&m_dvdnav, nullptr, &loggerCallback, path.c_str()) != ++ else if (dvdnav_open2(&m_dvdnav, nullptr, &loggerCallback, path.c_str()) != + DVDNAV_STATUS_OK) + #else +- else if (m_dll.dvdnav_open(&m_dvdnav, path.c_str()) != DVDNAV_STATUS_OK) ++ else if (dvdnav_open(&m_dvdnav, path.c_str()) != DVDNAV_STATUS_OK) + #endif + { + CLog::Log(LOGERROR, "Error on dvdnav_open"); +@@ -176,16 +173,16 @@ bool CDVDInputStreamNavigator::Open() + else + { + // find out what region dvd reports itself to be from, and use that as mask if available +- if (m_dll.dvdnav_get_disk_region_mask(m_dvdnav, &mask) == DVDNAV_STATUS_ERR) ++ if (dvdnav_get_disk_region_mask(m_dvdnav, &mask) == DVDNAV_STATUS_ERR) + { + CLog::LogF(LOGERROR, "Error getting DVD region code: {}", +- m_dll.dvdnav_err_to_string(m_dvdnav)); ++ dvdnav_err_to_string(m_dvdnav)); + mask = 0xff; + } + } + + CLog::Log(LOGDEBUG, "{} - Setting region mask {:02x}", __FUNCTION__, mask); +- m_dll.dvdnav_set_region_mask(m_dvdnav, mask); ++ dvdnav_set_region_mask(m_dvdnav, mask); + + // get default language settings + char language_menu[3]; +@@ -206,48 +203,48 @@ bool CDVDInputStreamNavigator::Open() + if (language_subtitle[0] == '\0') strcpy(language_subtitle, "en"); + + // set default language settings +- if (m_dll.dvdnav_menu_language_select(m_dvdnav, (char*)language_menu) != DVDNAV_STATUS_OK) ++ if (dvdnav_menu_language_select(m_dvdnav, (char*)language_menu) != DVDNAV_STATUS_OK) + { + CLog::Log(LOGERROR, "Error on setting default menu language: {}", +- m_dll.dvdnav_err_to_string(m_dvdnav)); ++ dvdnav_err_to_string(m_dvdnav)); + CLog::Log(LOGERROR, "Defaulting to \"en\""); + //! @bug libdvdnav isn't const correct +- m_dll.dvdnav_menu_language_select(m_dvdnav, const_cast<char*>("en")); ++ dvdnav_menu_language_select(m_dvdnav, const_cast<char*>("en")); + } + +- if (m_dll.dvdnav_audio_language_select(m_dvdnav, (char*)language_audio) != DVDNAV_STATUS_OK) ++ if (dvdnav_audio_language_select(m_dvdnav, (char*)language_audio) != DVDNAV_STATUS_OK) + { + CLog::Log(LOGERROR, "Error on setting default audio language: {}", +- m_dll.dvdnav_err_to_string(m_dvdnav)); ++ dvdnav_err_to_string(m_dvdnav)); + CLog::Log(LOGERROR, "Defaulting to \"en\""); + //! @bug libdvdnav isn't const correct +- m_dll.dvdnav_audio_language_select(m_dvdnav, const_cast<char*>("en")); ++ dvdnav_audio_language_select(m_dvdnav, const_cast<char*>("en")); + } + +- if (m_dll.dvdnav_spu_language_select(m_dvdnav, (char*)language_subtitle) != DVDNAV_STATUS_OK) ++ if (dvdnav_spu_language_select(m_dvdnav, (char*)language_subtitle) != DVDNAV_STATUS_OK) + { + CLog::Log(LOGERROR, "Error on setting default subtitle language: {}", +- m_dll.dvdnav_err_to_string(m_dvdnav)); ++ dvdnav_err_to_string(m_dvdnav)); + CLog::Log(LOGERROR, "Defaulting to \"en\""); + //! @bug libdvdnav isn't const correct +- m_dll.dvdnav_spu_language_select(m_dvdnav, const_cast<char*>("en")); ++ dvdnav_spu_language_select(m_dvdnav, const_cast<char*>("en")); + } + + // set read ahead cache usage +- if (m_dll.dvdnav_set_readahead_flag(m_dvdnav, 1) != DVDNAV_STATUS_OK) ++ if (dvdnav_set_readahead_flag(m_dvdnav, 1) != DVDNAV_STATUS_OK) + { + CLog::Log(LOGERROR, "Error on dvdnav_set_readahead_flag: {}", +- m_dll.dvdnav_err_to_string(m_dvdnav)); ++ dvdnav_err_to_string(m_dvdnav)); + Close(); + return false; + } + + // set the PGC positioning flag to have position information relatively to the + // whole feature instead of just relatively to the current chapter +- if (m_dll.dvdnav_set_PGC_positioning_flag(m_dvdnav, 1) != DVDNAV_STATUS_OK) ++ if (dvdnav_set_PGC_positioning_flag(m_dvdnav, 1) != DVDNAV_STATUS_OK) + { + CLog::Log(LOGERROR, "Error on dvdnav_set_PGC_positioning_flag: {}", +- m_dll.dvdnav_err_to_string(m_dvdnav)); ++ dvdnav_err_to_string(m_dvdnav)); + Close(); + return false; + } +@@ -260,18 +257,18 @@ bool CDVDInputStreamNavigator::Open() + uint8_t* buf_ptr = buf; + + // must startup vm and pgc +- m_dll.dvdnav_get_next_cache_block(m_dvdnav,&buf_ptr,&event,&len); +- m_dll.dvdnav_sector_search(m_dvdnav, 0, SEEK_SET); ++ dvdnav_get_next_cache_block(m_dvdnav,&buf_ptr,&event,&len); ++ dvdnav_sector_search(m_dvdnav, 0, SEEK_SET); + + // first try title menu +- if(m_dll.dvdnav_menu_call(m_dvdnav, DVD_MENU_Title) != DVDNAV_STATUS_OK) ++ if(dvdnav_menu_call(m_dvdnav, DVD_MENU_Title) != DVDNAV_STATUS_OK) + { + CLog::Log(LOGERROR, "Error on dvdnav_menu_call(Title): {}", +- m_dll.dvdnav_err_to_string(m_dvdnav)); ++ dvdnav_err_to_string(m_dvdnav)); + // next try root menu +- if(m_dll.dvdnav_menu_call(m_dvdnav, DVD_MENU_Root) != DVDNAV_STATUS_OK ) ++ if(dvdnav_menu_call(m_dvdnav, DVD_MENU_Root) != DVDNAV_STATUS_OK ) + CLog::Log(LOGERROR, "Error on dvdnav_menu_call(Root): {}", +- m_dll.dvdnav_err_to_string(m_dvdnav)); ++ dvdnav_err_to_string(m_dvdnav)); + } + } + +@@ -295,9 +292,9 @@ void CDVDInputStreamNavigator::Close() + if (!m_dvdnav) return; + + // finish off by closing the dvdnav device +- if (m_dll.dvdnav_close(m_dvdnav) != DVDNAV_STATUS_OK) ++ if (dvdnav_close(m_dvdnav) != DVDNAV_STATUS_OK) + { +- CLog::Log(LOGERROR, "Error on dvdnav_close: {}", m_dll.dvdnav_err_to_string(m_dvdnav)); ++ CLog::Log(LOGERROR, "Error on dvdnav_close: {}", dvdnav_err_to_string(m_dvdnav)); + return ; + } + +@@ -383,11 +380,11 @@ int CDVDInputStreamNavigator::ProcessBlock(uint8_t* dest_buffer, int* read) + result = DVDNAV_STATUS_OK; + } + else +- result = m_dll.dvdnav_get_next_cache_block(m_dvdnav, &buf, &m_lastevent, &len); ++ result = dvdnav_get_next_cache_block(m_dvdnav, &buf, &m_lastevent, &len); + + if (result == DVDNAV_STATUS_ERR) + { +- CLog::Log(LOGERROR, "Error getting next block: {}", m_dll.dvdnav_err_to_string(m_dvdnav)); ++ CLog::Log(LOGERROR, "Error getting next block: {}", dvdnav_err_to_string(m_dvdnav)); + m_bEOF = true; + return NAVRESULT_ERROR; + } +@@ -488,7 +485,7 @@ int CDVDInputStreamNavigator::ProcessBlock(uint8_t* dest_buffer, int* read) + } + else + { +- bool menu = (0 == m_dll.dvdnav_is_domain_vts(m_dvdnav)); ++ bool menu = (0 == dvdnav_is_domain_vts(m_dvdnav)); + if (menu != m_bInMenu) + { + m_bInMenu = menu; +@@ -508,13 +505,13 @@ int CDVDInputStreamNavigator::ProcessBlock(uint8_t* dest_buffer, int* read) + uint32_t pos = 0; + uint32_t len = 0; + +- m_dll.dvdnav_current_title_info(m_dvdnav, &m_iTitle, &m_iPart); +- m_dll.dvdnav_get_number_of_titles(m_dvdnav, &m_iTitleCount); ++ dvdnav_current_title_info(m_dvdnav, &m_iTitle, &m_iPart); ++ dvdnav_get_number_of_titles(m_dvdnav, &m_iTitleCount); + if(m_iTitle > 0) +- m_dll.dvdnav_get_number_of_parts(m_dvdnav, m_iTitle, &m_iPartCount); ++ dvdnav_get_number_of_parts(m_dvdnav, m_iTitle, &m_iPartCount); + else + m_iPartCount = 0; +- m_dll.dvdnav_get_position(m_dvdnav, &pos, &len); ++ dvdnav_get_position(m_dvdnav, &pos, &len); + + // get chapters' timestamps if we have not cached them yet + if (m_mapTitleChapters.find(m_iTitle) == m_mapTitleChapters.end()) +@@ -522,7 +519,7 @@ int CDVDInputStreamNavigator::ProcessBlock(uint8_t* dest_buffer, int* read) + uint64_t* times = NULL; + uint64_t duration; + //dvdnav_describe_title_chapters returns 0 on failure and NULL for times +- int entries = m_dll.dvdnav_describe_title_chapters(m_dvdnav, m_iTitle, ×, &duration); ++ int entries = dvdnav_describe_title_chapters(m_dvdnav, m_iTitle, ×, &duration); + + if (entries != m_iPartCount) + CLog::Log(LOGDEBUG, +@@ -570,11 +567,11 @@ int CDVDInputStreamNavigator::ProcessBlock(uint8_t* dest_buffer, int* read) + + // Calculate current time + //unsigned int pos, len; +- //m_dll.dvdnav_get_position(m_dvdnav, &pos, &len); ++ //dvdnav_get_position(m_dvdnav, &pos, &len); + //m_iTime = (int)(((int64_t)m_iTotalTime * pos) / len); + +- pci_t* pci = m_dll.dvdnav_get_current_nav_pci(m_dvdnav); +- m_dll.dvdnav_get_current_nav_dsi(m_dvdnav); ++ pci_t* pci = dvdnav_get_current_nav_pci(m_dvdnav); ++ dvdnav_get_current_nav_dsi(m_dvdnav); + + if(!pci) + { +@@ -583,7 +580,7 @@ int CDVDInputStreamNavigator::ProcessBlock(uint8_t* dest_buffer, int* read) + } + + /* if we have any buttons or are not in vts domain we assume we are in menu */ +- bool menu = pci->hli.hl_gi.hli_ss || (0 == m_dll.dvdnav_is_domain_vts(m_dvdnav)); ++ bool menu = pci->hli.hl_gi.hli_ss || (0 == dvdnav_is_domain_vts(m_dvdnav)); + if (menu != m_bInMenu) + { + m_bInMenu = menu; +@@ -611,7 +608,7 @@ int CDVDInputStreamNavigator::ProcessBlock(uint8_t* dest_buffer, int* read) + m_iVobUnitStart = pci->pci_gi.vobu_s_ptm; + m_iVobUnitStop = pci->pci_gi.vobu_e_ptm; + +- m_iTime = (int) ( m_dll.dvdnav_get_current_time(m_dvdnav) / 90 ); ++ m_iTime = (int) ( dvdnav_get_current_time(m_dvdnav) / 90 ); + + iNavresult = m_pVideoPlayer->OnDiscNavResult((void*)pci, DVDNAV_NAV_PACKET); + } +@@ -650,7 +647,7 @@ int CDVDInputStreamNavigator::ProcessBlock(uint8_t* dest_buffer, int* read) + // probably not needed since function will check if buf + // is part of the internal cache, but do it for good measure + if( buf != m_lastblock ) +- m_dll.dvdnav_free_cache_block(m_dvdnav, buf); ++ dvdnav_free_cache_block(m_dvdnav, buf); + + return iNavresult; + } +@@ -662,11 +659,11 @@ bool CDVDInputStreamNavigator::SetActiveAudioStream(int iId) + if (!m_dvdnav) + return false; + +- dvdnav_status_t ret = m_dll.dvdnav_set_active_stream(m_dvdnav, iId, DVD_AUDIO_STREAM); ++ dvdnav_status_t ret = dvdnav_set_active_stream(m_dvdnav, iId, DVD_AUDIO_STREAM); + if (ret == DVDNAV_STATUS_ERR) + { + CLog::LogF(LOGERROR, "dvdnav_set_active_stream (audio) failed: {}", +- m_dll.dvdnav_err_to_string(m_dvdnav)); ++ dvdnav_err_to_string(m_dvdnav)); + } + + return ret == DVDNAV_STATUS_OK; +@@ -679,11 +676,11 @@ bool CDVDInputStreamNavigator::SetActiveSubtitleStream(int iId) + if (!m_dvdnav) + return false; + +- dvdnav_status_t ret = m_dll.dvdnav_set_active_stream(m_dvdnav, iId, DVD_SUBTITLE_STREAM); ++ dvdnav_status_t ret = dvdnav_set_active_stream(m_dvdnav, iId, DVD_SUBTITLE_STREAM); + if (ret == DVDNAV_STATUS_ERR) + { + CLog::LogF(LOGERROR, "dvdnav_set_active_stream (subtitles) failed: {}", +- m_dll.dvdnav_err_to_string(m_dvdnav)); ++ dvdnav_err_to_string(m_dvdnav)); + } + + return ret == DVDNAV_STATUS_OK; +@@ -693,14 +690,14 @@ void CDVDInputStreamNavigator::ActivateButton() + { + if (m_dvdnav) + { +- m_dll.dvdnav_button_activate(m_dvdnav, m_dll.dvdnav_get_current_nav_pci(m_dvdnav)); ++ dvdnav_button_activate(m_dvdnav, dvdnav_get_current_nav_pci(m_dvdnav)); + } + } + + void CDVDInputStreamNavigator::SelectButton(int iButton) + { + if (!m_dvdnav) return; +- m_dll.dvdnav_button_select(m_dvdnav, m_dll.dvdnav_get_current_nav_pci(m_dvdnav), iButton); ++ dvdnav_button_select(m_dvdnav, dvdnav_get_current_nav_pci(m_dvdnav), iButton); + } + + int CDVDInputStreamNavigator::GetCurrentButton() +@@ -711,10 +708,10 @@ int CDVDInputStreamNavigator::GetCurrentButton() + } + + int button = 0; +- if (m_dll.dvdnav_get_current_highlight(m_dvdnav, &button) == DVDNAV_STATUS_ERR) ++ if (dvdnav_get_current_highlight(m_dvdnav, &button) == DVDNAV_STATUS_ERR) + { + CLog::LogF(LOGERROR, "dvdnav_get_current_highlight failed: {}", +- m_dll.dvdnav_err_to_string(m_dvdnav)); ++ dvdnav_err_to_string(m_dvdnav)); + return -1; + } + return button; +@@ -725,7 +722,7 @@ void CDVDInputStreamNavigator::CheckButtons() + if (m_dvdnav && m_bCheckButtons) + { + m_bCheckButtons = false; +- pci_t* pci = m_dll.dvdnav_get_current_nav_pci(m_dvdnav); ++ pci_t* pci = dvdnav_get_current_nav_pci(m_dvdnav); + int iCurrentButton = GetCurrentButton(); + + if( iCurrentButton > 0 && iCurrentButton < 37 ) +@@ -751,7 +748,7 @@ void CDVDInputStreamNavigator::CheckButtons() + { + CLog::Log(LOGWARNING, "CDVDInputStreamNavigator: found invalid button({})", iCurrentButton); + CLog::Log(LOGWARNING, "CDVDInputStreamNavigator: switching to button({}) instead", i + 1); +- m_dll.dvdnav_button_select(m_dvdnav, pci, i + 1); ++ dvdnav_button_select(m_dvdnav, pci, i + 1); + break; + } + } +@@ -762,7 +759,7 @@ int CDVDInputStreamNavigator::GetTotalButtons() + { + if (!m_dvdnav) return 0; + +- pci_t* pci = m_dll.dvdnav_get_current_nav_pci(m_dvdnav); ++ pci_t* pci = dvdnav_get_current_nav_pci(m_dvdnav); + + int counter = 0; + for (const btni_t& buttonInfo : pci->hli.btnit) +@@ -780,30 +777,30 @@ int CDVDInputStreamNavigator::GetTotalButtons() + + void CDVDInputStreamNavigator::OnUp() + { +- if (m_dvdnav) m_dll.dvdnav_upper_button_select(m_dvdnav, m_dll.dvdnav_get_current_nav_pci(m_dvdnav)); ++ if (m_dvdnav) dvdnav_upper_button_select(m_dvdnav, dvdnav_get_current_nav_pci(m_dvdnav)); + } + + void CDVDInputStreamNavigator::OnDown() + { +- if (m_dvdnav) m_dll.dvdnav_lower_button_select(m_dvdnav, m_dll.dvdnav_get_current_nav_pci(m_dvdnav)); ++ if (m_dvdnav) dvdnav_lower_button_select(m_dvdnav, dvdnav_get_current_nav_pci(m_dvdnav)); + } + + void CDVDInputStreamNavigator::OnLeft() + { +- if (m_dvdnav) m_dll.dvdnav_left_button_select(m_dvdnav, m_dll.dvdnav_get_current_nav_pci(m_dvdnav)); ++ if (m_dvdnav) dvdnav_left_button_select(m_dvdnav, dvdnav_get_current_nav_pci(m_dvdnav)); + } + + void CDVDInputStreamNavigator::OnRight() + { +- if (m_dvdnav) m_dll.dvdnav_right_button_select(m_dvdnav, m_dll.dvdnav_get_current_nav_pci(m_dvdnav)); ++ if (m_dvdnav) dvdnav_right_button_select(m_dvdnav, dvdnav_get_current_nav_pci(m_dvdnav)); + } + + bool CDVDInputStreamNavigator::OnMouseMove(const CPoint &point) + { + if (m_dvdnav) + { +- pci_t* pci = m_dll.dvdnav_get_current_nav_pci(m_dvdnav); +- return (DVDNAV_STATUS_OK == m_dll.dvdnav_mouse_select(m_dvdnav, pci, (int32_t)point.x, (int32_t)point.y)); ++ pci_t* pci = dvdnav_get_current_nav_pci(m_dvdnav); ++ return (DVDNAV_STATUS_OK == dvdnav_mouse_select(m_dvdnav, pci, (int32_t)point.x, (int32_t)point.y)); + } + return false; + } +@@ -812,8 +809,8 @@ bool CDVDInputStreamNavigator::OnMouseClick(const CPoint &point) + { + if (m_dvdnav) + { +- pci_t* pci = m_dll.dvdnav_get_current_nav_pci(m_dvdnav); +- return (DVDNAV_STATUS_OK == m_dll.dvdnav_mouse_activate(m_dvdnav, pci, (int32_t)point.x, (int32_t)point.y)); ++ pci_t* pci = dvdnav_get_current_nav_pci(m_dvdnav); ++ return (DVDNAV_STATUS_OK == dvdnav_mouse_activate(m_dvdnav, pci, (int32_t)point.x, (int32_t)point.y)); + } + return false; + } +@@ -825,12 +822,12 @@ bool CDVDInputStreamNavigator::OnMenu() + return false; + } + +- return m_dll.dvdnav_menu_call(m_dvdnav, DVD_MENU_Escape) == DVDNAV_STATUS_OK; ++ return dvdnav_menu_call(m_dvdnav, DVD_MENU_Escape) == DVDNAV_STATUS_OK; + } + + void CDVDInputStreamNavigator::OnBack() + { +- if (m_dvdnav) m_dll.dvdnav_go_up(m_dvdnav); ++ if (m_dvdnav) dvdnav_go_up(m_dvdnav); + } + + // we don't allow skipping in menu's cause it will remove menu overlays +@@ -838,7 +835,7 @@ void CDVDInputStreamNavigator::OnNext() + { + if (m_dvdnav && !(IsInMenu() && GetTotalButtons() > 0)) + { +- m_dll.dvdnav_next_pg_search(m_dvdnav); ++ dvdnav_next_pg_search(m_dvdnav); + } + } + +@@ -847,7 +844,7 @@ void CDVDInputStreamNavigator::OnPrevious() + { + if (m_dvdnav && !(IsInMenu() && GetTotalButtons() > 0)) + { +- m_dll.dvdnav_prev_pg_search(m_dvdnav); ++ dvdnav_prev_pg_search(m_dvdnav); + } + } + +@@ -855,13 +852,13 @@ void CDVDInputStreamNavigator::SkipStill() + { + if (!m_dvdnav) + return ; +- m_dll.dvdnav_still_skip(m_dvdnav); ++ dvdnav_still_skip(m_dvdnav); + } + + void CDVDInputStreamNavigator::SkipWait() + { + if (!m_dvdnav) return ; +- m_dll.dvdnav_wait_skip(m_dvdnav); ++ dvdnav_wait_skip(m_dvdnav); + } + + CDVDInputStream::ENextStream CDVDInputStreamNavigator::NextStream() +@@ -886,7 +883,7 @@ int CDVDInputStreamNavigator::GetActiveSubtitleStream() + return activeStream; + } + +- const int8_t logicalSubStreamId = m_dll.dvdnav_get_active_spu_stream(m_dvdnav); ++ const int8_t logicalSubStreamId = dvdnav_get_active_spu_stream(m_dvdnav); + if (logicalSubStreamId < 0) + { + return activeStream; +@@ -895,7 +892,7 @@ int CDVDInputStreamNavigator::GetActiveSubtitleStream() + int subStreamCount = GetSubTitleStreamCount(); + for (int subpN = 0; subpN < subStreamCount; subpN++) + { +- if (m_dll.dvdnav_get_spu_logical_stream(m_dvdnav, subpN) == logicalSubStreamId) ++ if (dvdnav_get_spu_logical_stream(m_dvdnav, subpN) == logicalSubStreamId) + { + activeStream = subpN; + break; +@@ -913,7 +910,7 @@ SubtitleStreamInfo CDVDInputStreamNavigator::GetSubtitleStreamInfo(const int iId + + subp_attr_t subp_attributes; + +- if (m_dll.dvdnav_get_spu_attr(m_dvdnav, iId, &subp_attributes) == DVDNAV_STATUS_OK) ++ if (dvdnav_get_spu_attr(m_dvdnav, iId, &subp_attributes) == DVDNAV_STATUS_OK) + { + SetSubtitleStreamName(info, subp_attributes); + +@@ -966,7 +963,7 @@ int CDVDInputStreamNavigator::GetSubTitleStreamCount() + { + return 0; + } +- return m_dll.dvdnav_get_number_of_streams(m_dvdnav, DVD_SUBTITLE_STREAM); ++ return dvdnav_get_number_of_streams(m_dvdnav, DVD_SUBTITLE_STREAM); + } + + int CDVDInputStreamNavigator::GetActiveAudioStream() +@@ -976,7 +973,7 @@ int CDVDInputStreamNavigator::GetActiveAudioStream() + return -1; + } + +- const int8_t logicalAudioStreamId = m_dll.dvdnav_get_active_audio_stream(m_dvdnav); ++ const int8_t logicalAudioStreamId = dvdnav_get_active_audio_stream(m_dvdnav); + if (logicalAudioStreamId < 0) + { + return -1; +@@ -986,7 +983,7 @@ int CDVDInputStreamNavigator::GetActiveAudioStream() + int audioStreamCount = GetAudioStreamCount(); + for (int audioN = 0; audioN < audioStreamCount; audioN++) + { +- if (m_dll.dvdnav_get_audio_logical_stream(m_dvdnav, audioN) == logicalAudioStreamId) ++ if (dvdnav_get_audio_logical_stream(m_dvdnav, audioN) == logicalAudioStreamId) + { + activeStream = audioN; + break; +@@ -1083,7 +1080,7 @@ AudioStreamInfo CDVDInputStreamNavigator::GetAudioStreamInfo(const int iId) + + audio_attr_t audio_attributes; + +- if (m_dll.dvdnav_get_audio_attr(m_dvdnav, iId, &audio_attributes) == DVDNAV_STATUS_OK) ++ if (dvdnav_get_audio_attr(m_dvdnav, iId, &audio_attributes) == DVDNAV_STATUS_OK) + { + SetAudioStreamName(info, audio_attributes); + +@@ -1105,7 +1102,7 @@ int CDVDInputStreamNavigator::GetAudioStreamCount() + { + return 0; + } +- return m_dll.dvdnav_get_number_of_streams(m_dvdnav, DVD_AUDIO_STREAM); ++ return dvdnav_get_number_of_streams(m_dvdnav, DVD_AUDIO_STREAM); + } + + int CDVDInputStreamNavigator::GetAngleCount() +@@ -1115,7 +1112,7 @@ int CDVDInputStreamNavigator::GetAngleCount() + + int number_of_angles; + int current_angle; +- dvdnav_status_t status = m_dll.dvdnav_get_angle_info(m_dvdnav, ¤t_angle, &number_of_angles); ++ dvdnav_status_t status = dvdnav_get_angle_info(m_dvdnav, ¤t_angle, &number_of_angles); + + if (status == DVDNAV_STATUS_OK) + return number_of_angles; +@@ -1130,9 +1127,9 @@ int CDVDInputStreamNavigator::GetActiveAngle() + + int number_of_angles; + int current_angle; +- if (m_dll.dvdnav_get_angle_info(m_dvdnav, ¤t_angle, &number_of_angles) == DVDNAV_STATUS_ERR) ++ if (dvdnav_get_angle_info(m_dvdnav, ¤t_angle, &number_of_angles) == DVDNAV_STATUS_ERR) + { +- CLog::LogF(LOGERROR, "Failed to get current angle: {}", m_dll.dvdnav_err_to_string(m_dvdnav)); ++ CLog::LogF(LOGERROR, "Failed to get current angle: {}", dvdnav_err_to_string(m_dvdnav)); + return -1; + } + return current_angle; +@@ -1143,7 +1140,7 @@ bool CDVDInputStreamNavigator::SetAngle(int angle) + if (!m_dvdnav) + return false; + +- dvdnav_status_t status = m_dll.dvdnav_angle_change(m_dvdnav, angle); ++ dvdnav_status_t status = dvdnav_angle_change(m_dvdnav, angle); + + return (status == DVDNAV_STATUS_OK); + } +@@ -1164,8 +1161,8 @@ bool CDVDInputStreamNavigator::GetCurrentButtonInfo(CDVDOverlaySpu* pOverlayPict + return false; + } + +- if (DVDNAV_STATUS_OK == m_dll.dvdnav_get_highlight_area( +- m_dll.dvdnav_get_current_nav_pci(m_dvdnav), button, iButtonType, &hl)) ++ if (DVDNAV_STATUS_OK == dvdnav_get_highlight_area( ++ dvdnav_get_current_nav_pci(m_dvdnav), button, iButtonType, &hl)) + { + // button cropping information + pOverlayPicture->crop_i_x_start = hl.sx; +@@ -1213,10 +1210,10 @@ int CDVDInputStreamNavigator::GetTime() + + bool CDVDInputStreamNavigator::PosTime(int iTimeInMsec) + { +- if( m_dll.dvdnav_jump_to_sector_by_time(m_dvdnav, iTimeInMsec * 90, 0) == DVDNAV_STATUS_ERR ) ++ if( dvdnav_jump_to_sector_by_time(m_dvdnav, iTimeInMsec * 90, 0) == DVDNAV_STATUS_ERR ) + { + CLog::Log(LOGDEBUG, "dvdnav: dvdnav_jump_to_sector_by_time failed( {} )", +- m_dll.dvdnav_err_to_string(m_dvdnav)); ++ dvdnav_err_to_string(m_dvdnav)); + return false; + } + m_iTime = iTimeInMsec; +@@ -1243,26 +1240,26 @@ bool CDVDInputStreamNavigator::SeekChapter(int iChapter) + + if (iChapter == (m_iPart + 1)) + { +- if (m_dll.dvdnav_next_pg_search(m_dvdnav) == DVDNAV_STATUS_ERR) ++ if (dvdnav_next_pg_search(m_dvdnav) == DVDNAV_STATUS_ERR) + { + CLog::Log(LOGERROR, "dvdnav: dvdnav_next_pg_search( {} )", +- m_dll.dvdnav_err_to_string(m_dvdnav)); ++ dvdnav_err_to_string(m_dvdnav)); + return false; + } + } + else if (iChapter == (m_iPart - 1)) + { +- if (m_dll.dvdnav_prev_pg_search(m_dvdnav) == DVDNAV_STATUS_ERR) ++ if (dvdnav_prev_pg_search(m_dvdnav) == DVDNAV_STATUS_ERR) + { + CLog::Log(LOGERROR, "dvdnav: dvdnav_prev_pg_search( {} )", +- m_dll.dvdnav_err_to_string(m_dvdnav)); ++ dvdnav_err_to_string(m_dvdnav)); + return false; + } + } +- else if (m_dll.dvdnav_part_play(m_dvdnav, m_iTitle, iChapter) == DVDNAV_STATUS_ERR) ++ else if (dvdnav_part_play(m_dvdnav, m_iTitle, iChapter) == DVDNAV_STATUS_ERR) + { + CLog::Log(LOGERROR, "dvdnav: dvdnav_part_play failed( {} )", +- m_dll.dvdnav_err_to_string(m_dvdnav)); ++ dvdnav_err_to_string(m_dvdnav)); + return false; + } + +@@ -1274,8 +1271,8 @@ bool CDVDInputStreamNavigator::SeekChapter(int iChapter) + + float CDVDInputStreamNavigator::GetVideoAspectRatio() + { +- int iAspect = m_dll.dvdnav_get_video_aspect(m_dvdnav); +- int iPerm = m_dll.dvdnav_get_video_scale_permission(m_dvdnav); ++ int iAspect = dvdnav_get_video_aspect(m_dvdnav); ++ int iPerm = dvdnav_get_video_scale_permission(m_dvdnav); + + //The video scale permissions should give if the source is letterboxed + //and such. should be able to give us info that we can zoom in automatically +@@ -1298,7 +1295,7 @@ void CDVDInputStreamNavigator::EnableSubtitleStream(bool bEnable) + if (!m_dvdnav) + return; + +- m_dll.dvdnav_toggle_spu_stream(m_dvdnav, static_cast<uint8_t>(bEnable)); ++ dvdnav_toggle_spu_stream(m_dvdnav, static_cast<uint8_t>(bEnable)); + } + + bool CDVDInputStreamNavigator::IsSubtitleStreamEnabled() +@@ -1306,7 +1303,7 @@ bool CDVDInputStreamNavigator::IsSubtitleStreamEnabled() + if (!m_dvdnav) + return false; + +- return m_dll.dvdnav_get_active_spu_stream(m_dvdnav) >= 0; ++ return dvdnav_get_active_spu_stream(m_dvdnav) >= 0; + } + + bool CDVDInputStreamNavigator::FillDVDState(DVDState& dvdState) +@@ -1316,11 +1313,11 @@ bool CDVDInputStreamNavigator::FillDVDState(DVDState& dvdState) + return false; + } + +- if (m_dll.dvdnav_current_title_program(m_dvdnav, &dvdState.title, &dvdState.pgcn, ++ if (dvdnav_current_title_program(m_dvdnav, &dvdState.title, &dvdState.pgcn, + &dvdState.pgn) == DVDNAV_STATUS_ERR) + { + CLog::LogF(LOGERROR, "Failed to get current title info ({})", +- m_dll.dvdnav_err_to_string(m_dvdnav)); ++ dvdnav_err_to_string(m_dvdnav)); + return false; + } + +@@ -1346,7 +1343,7 @@ bool CDVDInputStreamNavigator::GetState(std::string& xmlstate) + } + + // do not save state if we are not playing a title stream (e.g. if we are in menus) +- if (!m_dll.dvdnav_is_domain_vts(m_dvdnav)) ++ if (!dvdnav_is_domain_vts(m_dvdnav)) + { + return false; + } +@@ -1380,8 +1377,8 @@ bool CDVDInputStreamNavigator::SetState(const std::string& xmlstate) + return false; + } + +- m_dll.dvdnav_program_play(m_dvdnav, dvdState.title, dvdState.pgcn, dvdState.pgn); +- m_dll.dvdnav_angle_change(m_dvdnav, dvdState.current_angle); ++ dvdnav_program_play(m_dvdnav, dvdState.title, dvdState.pgcn, dvdState.pgn); ++ dvdnav_angle_change(m_dvdnav, dvdState.current_angle); + SetActiveSubtitleStream(dvdState.subp_num); + SetActiveAudioStream(dvdState.audio_num); + EnableSubtitleStream(dvdState.sub_enabled); +@@ -1394,7 +1391,7 @@ std::string CDVDInputStreamNavigator::GetDVDTitleString() + return ""; + + const char* str = NULL; +- if (m_dll.dvdnav_get_title_string(m_dvdnav, &str) == DVDNAV_STATUS_OK) ++ if (dvdnav_get_title_string(m_dvdnav, &str) == DVDNAV_STATUS_OK) + return str; + else + return ""; +@@ -1406,7 +1403,7 @@ std::string CDVDInputStreamNavigator::GetDVDSerialString() + return ""; + + const char* str = NULL; +- if (m_dll.dvdnav_get_serial_string(m_dvdnav, &str) == DVDNAV_STATUS_OK) ++ if (dvdnav_get_serial_string(m_dvdnav, &str) == DVDNAV_STATUS_OK) + return str; + else + return ""; +@@ -1447,12 +1444,12 @@ void CDVDInputStreamNavigator::GetVideoResolution(uint32_t* width, uint32_t* hei + if (!m_dvdnav) return; + + // for version <= 5.0.3 this functions returns 0 instead of DVDNAV_STATUS_OK and -1 instead of DVDNAV_STATUS_ERR +- int status = m_dll.dvdnav_get_video_resolution(m_dvdnav, width, height); ++ int status = dvdnav_get_video_resolution(m_dvdnav, width, height); + if (status == -1) + { + CLog::Log(LOGWARNING, + "CDVDInputStreamNavigator::GetVideoResolution - Failed to get resolution ({})", +- m_dll.dvdnav_err_to_string(m_dvdnav)); ++ dvdnav_err_to_string(m_dvdnav)); + *width = 0; + *height = 0; + } +diff --git a/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamNavigator.h b/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamNavigator.h +index d33364b48f..319c84b47d 100644 +--- a/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamNavigator.h ++++ b/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamNavigator.h +@@ -14,10 +14,12 @@ + #include "DVDInputStream.h" + #include "DVDInputStreamFile.h" + #include "DVDStateSerializer.h" +-#include "DllDvdNav.h" + #include "cores/MenuType.h" + #include "utils/Geometry.h" + ++#include <dvdnav/dvdnav.h> ++#include <dvdnav/dvd_types.h> ++ + #include <string> + + #define DVD_VIDEO_BLOCKSIZE DVD_VIDEO_LB_LEN // 2048 bytes +@@ -155,7 +157,6 @@ protected: + */ + bool FillDVDState(DVDState& dvdstate); + +- DllDvdNav m_dll; + bool m_bCheckButtons; + bool m_bEOF; + +diff --git a/xbmc/cores/VideoPlayer/DVDInputStreams/DllDvdNav.h b/xbmc/cores/VideoPlayer/DVDInputStreams/DllDvdNav.h +deleted file mode 100644 +index 7a0c149e02..0000000000 +--- a/xbmc/cores/VideoPlayer/DVDInputStreams/DllDvdNav.h ++++ /dev/null +@@ -1,275 +0,0 @@ +-/* +- * Copyright (C) 2005-2018 Team Kodi +- * This file is part of Kodi - https://kodi.tv +- * +- * SPDX-License-Identifier: GPL-2.0-or-later +- * See LICENSES/README.md for more information. +- */ +- +-#pragma once +- +-extern "C" { +-#define DVDNAV_COMPILE +- #include <stdint.h> +- +- #include "dvdnav/dvdnav.h" +- +- #ifndef WIN32 +- #define WIN32 +- #endif // WIN32 +- +- #ifndef HAVE_CONFIG_H +- #define HAVE_CONFIG_H +- #endif +- +- #include "dvdnav/dvd_types.h" +- +- #ifdef WIN32 // WIN32INCLUDES +- #undef HAVE_CONFIG_H +- #endif +-} +-#include "DynamicDll.h" +- +-class DllDvdNavInterface +-{ +-public: +- virtual ~DllDvdNavInterface() = default; +- virtual dvdnav_status_t dvdnav_open(dvdnav_t **dest, const char *path)=0; +- virtual dvdnav_status_t dvdnav_open2(dvdnav_t** dest, +- void*, +- const dvdnav_logger_cb*, +- const char* path) = 0; +- virtual dvdnav_status_t dvdnav_open_stream(dvdnav_t **dest, void *stream, dvdnav_stream_cb *stream_cb) = 0; +- virtual dvdnav_status_t dvdnav_open_stream2(dvdnav_t** dest, +- void* stream, +- const dvdnav_logger_cb*, +- dvdnav_stream_cb* stream_cb) = 0; +- virtual dvdnav_status_t dvdnav_close(dvdnav_t *self)=0; +- virtual dvdnav_status_t dvdnav_reset(dvdnav_t *self)=0; +- virtual const char* dvdnav_err_to_string(dvdnav_t *self)=0; +- virtual dvdnav_status_t dvdnav_set_readahead_flag(dvdnav_t *self, int32_t read_ahead_flag)=0; +- virtual dvdnav_status_t dvdnav_set_PGC_positioning_flag(dvdnav_t *self, int32_t pgc_based_flag)=0; +- virtual dvdnav_status_t dvdnav_get_next_cache_block(dvdnav_t *self, uint8_t **buf, int32_t *event, int32_t *len)=0; +- virtual dvdnav_status_t dvdnav_free_cache_block(dvdnav_t *self, unsigned char *buf)=0; +- virtual dvdnav_status_t dvdnav_still_skip(dvdnav_t *self)=0; +- virtual dvdnav_status_t dvdnav_wait_skip(dvdnav_t *self)=0; +- virtual dvdnav_status_t dvdnav_stop(dvdnav_t *self)=0; +- virtual dvdnav_status_t dvdnav_button_select(dvdnav_t *self, pci_t *pci, int32_t button)=0; +- virtual dvdnav_status_t dvdnav_button_activate(dvdnav_t *self, pci_t *pci)=0; +- virtual dvdnav_status_t dvdnav_upper_button_select(dvdnav_t *self, pci_t *pci)=0; +- virtual dvdnav_status_t dvdnav_lower_button_select(dvdnav_t *self, pci_t *pci)=0; +- virtual dvdnav_status_t dvdnav_right_button_select(dvdnav_t *self, pci_t *pci)=0; +- virtual dvdnav_status_t dvdnav_left_button_select(dvdnav_t *self, pci_t *pci)=0; +- virtual dvdnav_status_t dvdnav_sector_search(dvdnav_t *self, uint64_t offset, int32_t origin)=0; +- virtual pci_t* dvdnav_get_current_nav_pci(dvdnav_t *self)=0; +- virtual dsi_t* dvdnav_get_current_nav_dsi(dvdnav_t *self)=0; +- virtual dvdnav_status_t dvdnav_get_position(dvdnav_t *self, uint32_t *pos, uint32_t *len)=0; +- virtual dvdnav_status_t dvdnav_current_title_info(dvdnav_t *self, int32_t *title, int32_t *part)=0; +- virtual dvdnav_status_t dvdnav_spu_language_select(dvdnav_t *self, char *code)=0; +- virtual dvdnav_status_t dvdnav_audio_language_select(dvdnav_t *self, char *code)=0; +- virtual dvdnav_status_t dvdnav_menu_language_select(dvdnav_t *self, char *code)=0; +- virtual int8_t dvdnav_is_domain_vts(dvdnav_t *self)=0; +- virtual int8_t dvdnav_get_active_spu_stream(dvdnav_t *self)=0; +- virtual int8_t dvdnav_get_spu_logical_stream(dvdnav_t *self, uint8_t subp_num)=0; +- virtual uint16_t dvdnav_spu_stream_to_lang(dvdnav_t *self, uint8_t stream)=0; +- virtual dvdnav_status_t dvdnav_get_current_highlight(dvdnav_t *self, int32_t *button)=0; +- virtual dvdnav_status_t dvdnav_menu_call(dvdnav_t *self, DVDMenuID_t menu)=0; +- virtual dvdnav_status_t dvdnav_prev_pg_search(dvdnav_t *self)=0; +- virtual dvdnav_status_t dvdnav_next_pg_search(dvdnav_t *self)=0; +- virtual dvdnav_status_t dvdnav_get_highlight_area(pci_t *nav_pci , int32_t button, int32_t mode, dvdnav_highlight_area_t *highlight)=0; +- virtual dvdnav_status_t dvdnav_go_up(dvdnav_t *self)=0; +- virtual int8_t dvdnav_get_active_audio_stream(dvdnav_t *self)=0; +- virtual uint16_t dvdnav_audio_stream_to_lang(dvdnav_t *self, uint8_t stream)=0; +- virtual int8_t dvdnav_get_audio_logical_stream(dvdnav_t *self, uint8_t audio_num)=0; +- virtual dvdnav_status_t dvdnav_set_region_mask(dvdnav_t *self, int32_t region_mask)=0; +- virtual uint8_t dvdnav_get_video_aspect(dvdnav_t *self)=0; +- virtual uint8_t dvdnav_get_video_scale_permission(dvdnav_t *self)=0; +- virtual dvdnav_status_t dvdnav_get_number_of_titles(dvdnav_t *self, int32_t *titles)=0; +- virtual dvdnav_status_t dvdnav_get_number_of_parts(dvdnav_t *self, int32_t title, int32_t *parts)=0; +- virtual dvdnav_status_t dvdnav_title_play(dvdnav_t *self, int32_t title)=0; +- virtual dvdnav_status_t dvdnav_part_play(dvdnav_t *self, int32_t title, int32_t part)=0; +- virtual dvdnav_status_t dvdnav_get_audio_attr(dvdnav_t * self, int32_t streamid, audio_attr_t* audio_attributes)=0; +- virtual dvdnav_status_t dvdnav_get_spu_attr(dvdnav_t * self, int32_t streamid, subp_attr_t* stitle_attributes)=0; +- virtual dvdnav_status_t dvdnav_jump_to_sector_by_time(dvdnav_t* self, +- uint64_t offset, +- int32_t origin) = 0; +- virtual int64_t dvdnav_convert_time(dvd_time_t *time)=0; +- virtual dvdnav_status_t dvdnav_get_angle_info(dvdnav_t *self, int32_t *current_angle,int32_t *number_of_angles)=0; +- virtual dvdnav_status_t dvdnav_angle_change(dvdnav_t *self, int32_t angle) = 0; +- virtual dvdnav_status_t dvdnav_mouse_activate(dvdnav_t *self, pci_t *pci, int32_t x, int32_t y)=0; +- virtual dvdnav_status_t dvdnav_mouse_select(dvdnav_t *self, pci_t *pci, int32_t x, int32_t y)=0; +- virtual dvdnav_status_t dvdnav_get_title_string(dvdnav_t *self, const char **title_str)=0; +- virtual dvdnav_status_t dvdnav_get_serial_string(dvdnav_t *self, const char **serial_str)=0; +- virtual const char* dvdnav_get_volid_string(dvdnav_t* self) = 0; +- virtual dvdnav_status_t dvdnav_get_disk_region_mask(dvdnav_t* self, int32_t* region_mask) = 0; +- virtual uint32_t dvdnav_describe_title_chapters(dvdnav_t* self, uint32_t title, uint64_t** times, uint64_t* duration)=0; +- virtual int64_t dvdnav_get_current_time(dvdnav_t* self) = 0; +- virtual int dvdnav_get_video_resolution(dvdnav_t* self, uint32_t* width, uint32_t* height)=0; +- virtual int8_t dvdnav_get_number_of_streams(dvdnav_t* self, dvdnav_stream_type_t stream_type) = 0; +- virtual dvdnav_status_t dvdnav_toggle_spu_stream(dvdnav_t* self, uint8_t visibility) = 0; +- virtual dvdnav_status_t dvdnav_set_active_stream(dvdnav_t* self, +- uint8_t stream_num, +- dvdnav_stream_type_t stream_type) = 0; +- virtual dvdnav_status_t dvdnav_program_play(dvdnav_t* self, +- int32_t title, +- int32_t pgcn, +- int32_t pgn) = 0; +- virtual dvdnav_status_t dvdnav_current_title_program(dvdnav_t* self, +- int32_t* title, +- int32_t* pgcn, +- int32_t* pgn) = 0; +-}; +- +-class DllDvdNav : public DllDynamic, DllDvdNavInterface +-{ +- DECLARE_DLL_WRAPPER(DllDvdNav, DLL_PATH_LIBDVDNAV) +- +- DEFINE_METHOD2(dvdnav_status_t, dvdnav_open, (dvdnav_t **p1, const char *p2)) +- DEFINE_METHOD4(dvdnav_status_t, +- dvdnav_open2, +- (dvdnav_t * *p1, void* p2, const dvdnav_logger_cb* p3, const char* p4)) +- DEFINE_METHOD3(dvdnav_status_t, dvdnav_open_stream, (dvdnav_t **p1, void *p2, dvdnav_stream_cb *p3)) +- DEFINE_METHOD4(dvdnav_status_t, +- dvdnav_open_stream2, +- (dvdnav_t * *p1, void* p2, const dvdnav_logger_cb* p3, dvdnav_stream_cb* p4)) +- DEFINE_METHOD1(dvdnav_status_t, dvdnav_close, (dvdnav_t *p1)) +- DEFINE_METHOD1(dvdnav_status_t, dvdnav_reset, (dvdnav_t *p1)) +- DEFINE_METHOD1(const char*, dvdnav_err_to_string, (dvdnav_t *p1)) +- DEFINE_METHOD2(dvdnav_status_t, dvdnav_set_readahead_flag, (dvdnav_t *p1, int32_t p2)) +- DEFINE_METHOD2(dvdnav_status_t, dvdnav_set_PGC_positioning_flag, (dvdnav_t *p1, int32_t p2)) +- DEFINE_METHOD4(dvdnav_status_t, dvdnav_get_next_cache_block, (dvdnav_t *p1, uint8_t **p2, int32_t *p3, int32_t *p4)) +- DEFINE_METHOD2(dvdnav_status_t, dvdnav_free_cache_block, (dvdnav_t *p1, unsigned char *p2)) +- DEFINE_METHOD1(dvdnav_status_t, dvdnav_still_skip, (dvdnav_t *p1)) +- DEFINE_METHOD1(dvdnav_status_t, dvdnav_wait_skip, (dvdnav_t *p1)) +- DEFINE_METHOD1(dvdnav_status_t, dvdnav_stop, (dvdnav_t *p1)) +- DEFINE_METHOD3(dvdnav_status_t, dvdnav_button_select, (dvdnav_t *p1, pci_t *p2, int32_t p3)) +- DEFINE_METHOD2(dvdnav_status_t, dvdnav_button_activate,(dvdnav_t *p1, pci_t *p2)) +- DEFINE_METHOD2(dvdnav_status_t, dvdnav_upper_button_select, (dvdnav_t *p1, pci_t *p2)) +- DEFINE_METHOD2(dvdnav_status_t, dvdnav_lower_button_select, (dvdnav_t *p1, pci_t *p2)) +- DEFINE_METHOD2(dvdnav_status_t, dvdnav_right_button_select, (dvdnav_t *p1, pci_t *p2)) +- DEFINE_METHOD2(dvdnav_status_t, dvdnav_left_button_select, (dvdnav_t *p1, pci_t *p2)) +- DEFINE_METHOD3(dvdnav_status_t, dvdnav_sector_search, (dvdnav_t *p1, uint64_t p2, int32_t p3)) +- DEFINE_METHOD1(pci_t*, dvdnav_get_current_nav_pci, (dvdnav_t *p1)) +- DEFINE_METHOD1(dsi_t*, dvdnav_get_current_nav_dsi, (dvdnav_t *p1)) +- DEFINE_METHOD3(dvdnav_status_t, dvdnav_get_position, (dvdnav_t *p1, uint32_t *p2, uint32_t *p3)) +- DEFINE_METHOD3(dvdnav_status_t, dvdnav_current_title_info, (dvdnav_t *p1, int32_t *p2, int32_t *p3)) +- DEFINE_METHOD2(dvdnav_status_t, dvdnav_spu_language_select, (dvdnav_t *p1, char *p2)) +- DEFINE_METHOD2(dvdnav_status_t, dvdnav_audio_language_select, (dvdnav_t *p1, char *p2)) +- DEFINE_METHOD2(dvdnav_status_t, dvdnav_menu_language_select, (dvdnav_t *p1, char *p2)) +- DEFINE_METHOD1(int8_t, dvdnav_is_domain_vts, (dvdnav_t *p1)) +- DEFINE_METHOD1(int8_t, dvdnav_get_active_spu_stream, (dvdnav_t *p1)) +- DEFINE_METHOD2(int8_t, dvdnav_get_spu_logical_stream, (dvdnav_t *p1, uint8_t p2)) +- DEFINE_METHOD2(uint16_t, dvdnav_spu_stream_to_lang, (dvdnav_t *p1, uint8_t p2)) +- DEFINE_METHOD2(dvdnav_status_t, dvdnav_get_current_highlight, (dvdnav_t *p1, int32_t *p2)) +- DEFINE_METHOD2(dvdnav_status_t, dvdnav_menu_call, (dvdnav_t *p1, DVDMenuID_t p2)) +- DEFINE_METHOD2(dvdnav_status_t, dvdnav_get_disk_region_mask, (dvdnav_t * p1, int32_t* p2)) +- DEFINE_METHOD1(dvdnav_status_t, dvdnav_prev_pg_search, (dvdnav_t *p1)) +- DEFINE_METHOD1(dvdnav_status_t, dvdnav_next_pg_search, (dvdnav_t *p1)) +- DEFINE_METHOD4(dvdnav_status_t, dvdnav_get_highlight_area, (pci_t *p1, int32_t p2, int32_t p3, dvdnav_highlight_area_t *p4)) +- DEFINE_METHOD1(dvdnav_status_t, dvdnav_go_up, (dvdnav_t *p1)) +- DEFINE_METHOD1(int8_t, dvdnav_get_active_audio_stream, (dvdnav_t *p1)) +- DEFINE_METHOD2(uint16_t, dvdnav_audio_stream_to_lang, (dvdnav_t *p1, uint8_t p2)) +- DEFINE_METHOD2(int8_t, dvdnav_get_audio_logical_stream, (dvdnav_t *p1, uint8_t p2)) +- DEFINE_METHOD2(int8_t, dvdnav_get_number_of_streams, (dvdnav_t * p1, dvdnav_stream_type_t p2)) +- DEFINE_METHOD2(dvdnav_status_t, dvdnav_set_region_mask, (dvdnav_t *p1, int32_t p2)) +- DEFINE_METHOD1(uint8_t, dvdnav_get_video_aspect, (dvdnav_t *p1)) +- DEFINE_METHOD1(uint8_t, dvdnav_get_video_scale_permission, (dvdnav_t *p1)) +- DEFINE_METHOD2(dvdnav_status_t, dvdnav_get_number_of_titles, (dvdnav_t *p1, int32_t *p2)) +- DEFINE_METHOD3(dvdnav_status_t, dvdnav_get_number_of_parts, (dvdnav_t *p1, int32_t p2, int32_t *p3)) +- DEFINE_METHOD2(dvdnav_status_t, dvdnav_title_play, (dvdnav_t *p1, int32_t p2)) +- DEFINE_METHOD3(dvdnav_status_t, dvdnav_part_play, (dvdnav_t *p1, int32_t p2, int32_t p3)) +- DEFINE_METHOD3(dvdnav_status_t, dvdnav_get_audio_attr, (dvdnav_t * p1, int32_t p2, audio_attr_t* p3)) +- DEFINE_METHOD3(dvdnav_status_t, dvdnav_get_spu_attr, (dvdnav_t * p1, int32_t p2, subp_attr_t* p3)) +- DEFINE_METHOD3(dvdnav_status_t, dvdnav_jump_to_sector_by_time, (dvdnav_t * p1, uint64_t p2, int32_t p3)) +- DEFINE_METHOD1(int64_t, dvdnav_convert_time, (dvd_time_t *p1)) +- DEFINE_METHOD3(dvdnav_status_t, dvdnav_get_angle_info, (dvdnav_t *p1, int32_t *p2,int32_t *p3)) +- DEFINE_METHOD2(dvdnav_status_t, dvdnav_angle_change, (dvdnav_t *p1, int32_t p2)) +- DEFINE_METHOD4(dvdnav_status_t, dvdnav_mouse_activate, (dvdnav_t *p1, pci_t *p2, int32_t p3, int32_t p4)) +- DEFINE_METHOD4(dvdnav_status_t, dvdnav_mouse_select, (dvdnav_t *p1, pci_t *p2, int32_t p3, int32_t p4)) +- DEFINE_METHOD2(dvdnav_status_t, dvdnav_get_title_string, (dvdnav_t *p1, const char **p2)) +- DEFINE_METHOD2(dvdnav_status_t, dvdnav_get_serial_string, (dvdnav_t *p1, const char **p2)) +- DEFINE_METHOD1(const char*, dvdnav_get_volid_string, (dvdnav_t * p1)) +- DEFINE_METHOD4(uint32_t, dvdnav_describe_title_chapters, (dvdnav_t* p1, uint32_t p2, uint64_t** p3, uint64_t* p4)) +- DEFINE_METHOD1(int64_t, dvdnav_get_current_time, (dvdnav_t * p1)) +- DEFINE_METHOD3(int, dvdnav_get_video_resolution, (dvdnav_t * p1, uint32_t* p2, uint32_t* p3)) +- DEFINE_METHOD2(dvdnav_status_t, dvdnav_toggle_spu_stream, (dvdnav_t * p1, uint8_t p2)) +- DEFINE_METHOD3(dvdnav_status_t, +- dvdnav_set_active_stream, +- (dvdnav_t * p1, uint8_t p2, dvdnav_stream_type_t p3)) +- DEFINE_METHOD4(dvdnav_status_t, +- dvdnav_program_play, +- (dvdnav_t * p1, int32_t p2, int32_t p3, int32_t p4)) +- DEFINE_METHOD4(dvdnav_status_t, +- dvdnav_current_title_program, +- (dvdnav_t * p1, int32_t* p2, int32_t* p3, int32_t* p4)) +- BEGIN_METHOD_RESOLVE() +- RESOLVE_METHOD(dvdnav_open) +- RESOLVE_METHOD(dvdnav_open2) +- RESOLVE_METHOD(dvdnav_open_stream) +- RESOLVE_METHOD(dvdnav_open_stream2) +- RESOLVE_METHOD(dvdnav_close) +- RESOLVE_METHOD(dvdnav_reset) +- RESOLVE_METHOD(dvdnav_err_to_string) +- RESOLVE_METHOD(dvdnav_set_readahead_flag) +- RESOLVE_METHOD(dvdnav_set_PGC_positioning_flag) +- RESOLVE_METHOD(dvdnav_get_next_cache_block) +- RESOLVE_METHOD(dvdnav_free_cache_block) +- RESOLVE_METHOD(dvdnav_still_skip) +- RESOLVE_METHOD(dvdnav_wait_skip) +- RESOLVE_METHOD(dvdnav_stop) +- RESOLVE_METHOD(dvdnav_get_number_of_streams) +- RESOLVE_METHOD(dvdnav_get_disk_region_mask) +- RESOLVE_METHOD(dvdnav_button_select) +- RESOLVE_METHOD(dvdnav_button_activate) +- RESOLVE_METHOD(dvdnav_upper_button_select) +- RESOLVE_METHOD(dvdnav_lower_button_select) +- RESOLVE_METHOD(dvdnav_right_button_select) +- RESOLVE_METHOD(dvdnav_left_button_select) +- RESOLVE_METHOD(dvdnav_sector_search) +- RESOLVE_METHOD(dvdnav_get_current_nav_pci) +- RESOLVE_METHOD(dvdnav_get_current_nav_dsi) +- RESOLVE_METHOD(dvdnav_get_position) +- RESOLVE_METHOD(dvdnav_current_title_info) +- RESOLVE_METHOD(dvdnav_spu_language_select) +- RESOLVE_METHOD(dvdnav_audio_language_select) +- RESOLVE_METHOD(dvdnav_menu_language_select) +- RESOLVE_METHOD(dvdnav_is_domain_vts) +- RESOLVE_METHOD(dvdnav_get_active_spu_stream) +- RESOLVE_METHOD(dvdnav_get_spu_logical_stream) +- RESOLVE_METHOD(dvdnav_spu_stream_to_lang) +- RESOLVE_METHOD(dvdnav_get_current_highlight) +- RESOLVE_METHOD(dvdnav_menu_call) +- RESOLVE_METHOD(dvdnav_prev_pg_search) +- RESOLVE_METHOD(dvdnav_next_pg_search) +- RESOLVE_METHOD(dvdnav_get_highlight_area) +- RESOLVE_METHOD(dvdnav_go_up) +- RESOLVE_METHOD(dvdnav_get_active_audio_stream) +- RESOLVE_METHOD(dvdnav_audio_stream_to_lang) +- RESOLVE_METHOD(dvdnav_get_audio_logical_stream) +- RESOLVE_METHOD(dvdnav_set_region_mask) +- RESOLVE_METHOD(dvdnav_get_video_aspect) +- RESOLVE_METHOD(dvdnav_get_video_scale_permission) +- RESOLVE_METHOD(dvdnav_get_number_of_titles) +- RESOLVE_METHOD(dvdnav_get_number_of_parts) +- RESOLVE_METHOD(dvdnav_title_play) +- RESOLVE_METHOD(dvdnav_part_play) +- RESOLVE_METHOD(dvdnav_get_audio_attr) +- RESOLVE_METHOD(dvdnav_get_spu_attr) +- RESOLVE_METHOD(dvdnav_jump_to_sector_by_time) +- RESOLVE_METHOD(dvdnav_convert_time) +- RESOLVE_METHOD(dvdnav_get_angle_info) +- RESOLVE_METHOD(dvdnav_angle_change) +- RESOLVE_METHOD(dvdnav_mouse_activate) +- RESOLVE_METHOD(dvdnav_mouse_select) +- RESOLVE_METHOD(dvdnav_get_title_string) +- RESOLVE_METHOD(dvdnav_get_serial_string) +- RESOLVE_METHOD(dvdnav_get_volid_string) +- RESOLVE_METHOD(dvdnav_describe_title_chapters) +- RESOLVE_METHOD(dvdnav_get_current_time) +- RESOLVE_METHOD(dvdnav_get_video_resolution) +- RESOLVE_METHOD(dvdnav_toggle_spu_stream) +- RESOLVE_METHOD(dvdnav_set_active_stream) +- RESOLVE_METHOD(dvdnav_program_play) +- RESOLVE_METHOD(dvdnav_current_title_program) +- END_METHOD_RESOLVE() +-}; +diff --git a/xbmc/cores/VideoPlayer/DVDInputStreams/dvdnav/config.h b/xbmc/cores/VideoPlayer/DVDInputStreams/dvdnav/config.h +deleted file mode 100644 +index 0a310ea40f..0000000000 +--- a/xbmc/cores/VideoPlayer/DVDInputStreams/dvdnav/config.h ++++ /dev/null +@@ -1,76 +0,0 @@ +-/* +- * Copyright (C) 2005-2018 Team Kodi +- * This file is part of Kodi - https://kodi.tv +- * +- * SPDX-License-Identifier: GPL-2.0-or-later +- * See LICENSES/README.md for more information. +- */ +- +-#pragma once +- +-/* config.h. Generated by hand. */ +-#if defined(TARGET_POSIX) +-#include "PlatformDefs.h" +-#else +-#include <windows.h> +-#endif +-#include <stdio.h> +- +-//#define HAVE_DLFCN_H 1 +-#define HAVE_DVDCSS_DVDCSS_H 1 +-/* #undef HAVE_DVDCSS_DVDCSS_H*/ +-/* #undef HAVE_INTTYPES_H */ +-#define HAVE_MEMORY_H 1 +-#define HAVE_STDINT_H 1 +-#define HAVE_STDLIB_H 1 +-#define HAVE_STRINGS_H 1 +-#define HAVE_STRING_H 1 +-#define HAVE_SYS_STAT_H 1 +-#define HAVE_SYS_TYPES_H 1 +-/* #undef HAVE_UNISTD_H */ +-#ifndef PACKAGE +-#define PACKAGE "libdvdread" +-#endif +-#ifndef PACKAGE_BUGREPORT +-#define PACKAGE_BUGREPORT "" +-#endif +-#ifndef PACKAGE_NAME +-#define PACKAGE_NAME "" +-#endif +-#ifndef PACKAGE_STRING +-#define PACKAGE_STRING "" +-#endif +-#ifndef PACKAGE_TARNAME +-#define PACKAGE_TARNAME "" +-#endif +-#ifndef PACKAGE_VERSION +-#define PACKAGE_VERSION "" +-#endif +-#define STDC_HEADERS 1 +-#ifndef VERSION +-#define VERSION "1.2.6" +-#endif +-/* #undef WORDS_BIGENDIAN */ +-/* #undef __DARWIN__ */ +-/* #undef const */ +-#define inline __inline +-/* #undef size_t */ +- +-#define ssize_t int +- +-#ifndef PATH_MAX +-#define PATH_MAX MAX_PATH +-#endif +- +-#ifndef S_ISDIR +-#define S_ISDIR(m) ((m) & _S_IFDIR) +-#endif +-#ifndef S_ISREG +-#define S_ISREG(m) ((m) & _S_IFREG) +-#endif +-#ifndef S_ISBLK +-#define S_ISBLK(m) 0 +-#endif +-#ifndef S_ISCHR +-#define S_ISCHR(m) 0 +-#endif +diff --git a/xbmc/cores/VideoPlayer/DVDInputStreams/dvdnav/dvd_reader.h b/xbmc/cores/VideoPlayer/DVDInputStreams/dvdnav/dvd_reader.h +deleted file mode 100644 +index ba802628f2..0000000000 +--- a/xbmc/cores/VideoPlayer/DVDInputStreams/dvdnav/dvd_reader.h ++++ /dev/null +@@ -1,370 +0,0 @@ +-/* +- * Copyright (C) 2001, 2002 Billy Biggs <vektor@dumbterm.net>, +- * Håkan Hjort <d95hjort@dtek.chalmers.se>, +- * Björn Englund <d4bjorn@dtek.chalmers.se> +- * +- * This file is part of libdvdread. +- * +- * libdvdread 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 of the License, or +- * (at your option) any later version. +- * +- * libdvdread 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 libdvdread; if not, write to the Free Software Foundation, Inc., +- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +- */ +- +-#pragma once +- +-#ifdef _MSC_VER +-#include "config.h" +- +-#include <stdio.h> +-#include <stdlib.h> +-#endif +- +-#include <sys/types.h> +-//#include <inttypes.h> +-#include <stdarg.h> +- +-/***************************************************************************** +-* iovec structure: vectored data entry +-*****************************************************************************/ +-#ifdef TARGET_WINDOWS +-struct iovec +-{ +- void *iov_base; /* Pointer to data. */ +- size_t iov_len; /* Length of data. */ +-}; +-#else +-# include <sys/uio.h> /* struct iovec */ +-#endif +- +-/** +- * The DVD access interface. +- * +- * This file contains the functions that form the interface for +- * reading files located on a DVD. +- */ +- +-/** +- * The length of one Logical Block of a DVD. +- */ +-#define DVD_VIDEO_LB_LEN 2048 +- +-/** +- * Maximum length of filenames allowed in UDF. +- */ +-#define MAX_UDF_FILE_NAME_LEN 2048 +- +-#ifdef __cplusplus +-extern "C" { +-#endif +- +-/** +- * Opaque type that is used as a handle for one instance of an opened DVD. +- */ +-typedef struct dvd_reader_s dvd_reader_t; +-typedef struct dvd_reader_device_s dvd_reader_device_t; +- +-/** +- * Opaque type for a file read handle, much like a normal fd or FILE *. +- */ +-typedef struct dvd_file_s dvd_file_t; +- +-struct dvd_reader_stream_cb +-{ +- int (*pf_seek)(void* p_stream, uint64_t i_pos); +- int (*pf_read)(void* p_stream, void* buffer, int i_read); +- int (*pf_readv)(void* p_stream, void* p_iovec, int i_blocks); +-}; +-typedef struct dvd_reader_stream_cb dvd_reader_stream_cb; +- +-/** +- * Custom logger callback for DVDOpen[Stream]2 +- * @param private Handle as provided in Open functions +- * @param level Log level +- * @param fmt Format string +- * @param args Arguments list +- * pf_log(priv, level, fmt, args); +- */ +-typedef enum +-{ +- DVD_LOGGER_LEVEL_INFO, +- DVD_LOGGER_LEVEL_ERROR, +- DVD_LOGGER_LEVEL_WARN, +- DVD_LOGGER_LEVEL_DEBUG, +-} dvd_logger_level_t; +- +-typedef struct +-{ +- void (*pf_log)(void*, dvd_logger_level_t, const char*, va_list); +-} dvd_logger_cb; +- +-/** +- * Public type that is used to provide statistics on a handle. +- */ +-typedef struct { +- off_t size; /**< Total size of file in bytes */ +- int nr_parts; /**< Number of file parts */ +- off_t parts_size[9]; /**< Size of each part in bytes */ +-} dvd_stat_t; +- +-/** +- * Opens a block device of a DVD-ROM file, or an image file, or a directory +- * name for a mounted DVD or HD copy of a DVD. +- * The second form of Open function (DVDOpenStream) can be used to +- * provide custom stream_cb functions to access the DVD (see libdvdcss). +- * +- * If the given file is a block device, or is the mountpoint for a block +- * device, then that device is used for CSS authentication using libdvdcss. +- * If no device is available, then no CSS authentication is performed, +- * and we hope that the image is decrypted. +- * +- * If the path given is a directory, then the files in that directory may be +- * in any one of these formats: +- * +- * path/VIDEO_TS/VTS_01_1.VOB +- * path/video_ts/vts_01_1.vob +- * path/VTS_01_1.VOB +- * path/vts_01_1.vob +- * +- * @param path Specifies the the device, file or directory to be used. +- * @param stream is a private handle used by stream_cb +- * @param stream_cb is a struct containing seek and read functions +- * @return If successful a a read handle is returned. Otherwise 0 is returned. +- * +- * dvd = DVDOpen(path); +- * dvd = DVDOpenStream(stream, &stream_cb); +- */ +-dvd_reader_t *DVDOpen( const char * ); +-dvd_reader_t* DVDOpenStream(void*, dvd_reader_stream_cb*); +- +-/** +- * Same as DVDOpen, but with private handle to be passed back on callbacks +- * +- * @param path Specifies the the device, file or directory to be used. +- * @param priv is a private handle +- * @param logcb is a custom logger callback struct, or NULL if none needed +- * @param stream_cb is a struct containing seek and read functions +- * @return If successful a a read handle is returned. Otherwise 0 is returned. +- * +- * dvd = DVDOpen2(priv, logcb, path); +- * dvd = DVDOpenStream2(priv, logcb, &stream_cb); +- */ +-dvd_reader_t* DVDOpen2(void*, const dvd_logger_cb*, const char*); +-dvd_reader_t* DVDOpenStream2(void*, const dvd_logger_cb*, dvd_reader_stream_cb*); +- +-/** +- * Closes and cleans up the DVD reader object. +- * +- * You must close all open files before calling this function. +- * +- * @param dvd A read handle that should be closed. +- * +- * DVDClose(dvd); +- */ +-void DVDClose( dvd_reader_t * ); +- +-/** +- * +- */ +-typedef enum +-{ +- DVD_READ_INFO_FILE, /**< VIDEO_TS.IFO or VTS_XX_0.IFO (title) */ +- DVD_READ_INFO_BACKUP_FILE, /**< VIDEO_TS.BUP or VTS_XX_0.BUP (title) */ +- DVD_READ_MENU_VOBS, /**< VIDEO_TS.VOB or VTS_XX_0.VOB (title) */ +- DVD_READ_TITLE_VOBS /**< VTS_XX_[1-9].VOB (title). All files in +- the title set are opened and read as a +- single file. */ +-} dvd_read_domain_t; +- +-/** +- * Stats a file on the DVD given the title number and domain. +- * The information about the file is stored in a dvd_stat_t +- * which contains information about the size of the file and +- * the number of parts in case of a multipart file and the respective +- * sizes of the parts. +- * A multipart file is for instance VTS_02_1.VOB, VTS_02_2.VOB, VTS_02_3.VOB +- * The size of VTS_02_1.VOB will be stored in stat->parts_size[0], +- * VTS_02_2.VOB in stat->parts_size[1], ... +- * The total size (sum of all parts) is stored in stat->size and +- * stat->nr_parts will hold the number of parts. +- * Only DVD_READ_TITLE_VOBS (VTS_??_[1-9].VOB) can be multipart files. +- * +- * This function is only of use if you want to get the size of each file +- * in the filesystem. These sizes are not needed to use any other +- * functions in libdvdread. +- * +- * @param dvd A dvd read handle. +- * @param titlenum Which Video Title Set should be used, VIDEO_TS is 0. +- * @param domain Which domain. +- * @param stat Pointer to where the result is stored. +- * @return If successful 0, otherwise -1. +- * +- * int DVDFileStat(dvd, titlenum, domain, stat); +- */ +-int DVDFileStat(dvd_reader_t *, int, dvd_read_domain_t, dvd_stat_t *); +- +-/** +- * Opens a file on the DVD given the title number and domain. +- * +- * If the title number is 0, the video manager information is opened +- * (VIDEO_TS.[IFO,BUP,VOB]). Returns a file structure which may be +- * used for reads, or 0 if the file was not found. +- * +- * @param dvd A dvd read handle. +- * @param titlenum Which Video Title Set should be used, VIDEO_TS is 0. +- * @param domain Which domain. +- * @return If successful a a file read handle is returned, otherwise 0. +- * +- * dvd_file = DVDOpenFile(dvd, titlenum, domain); */ +-dvd_file_t *DVDOpenFile( dvd_reader_t *, int, dvd_read_domain_t ); +- +-/** +- * Closes a file and frees the associated structure. +- * +- * @param dvd_file The file read handle to be closed. +- * +- * DVDCloseFile(dvd_file); +- */ +-void DVDCloseFile( dvd_file_t * ); +- +-/** +- * Reads block_count number of blocks from the file at the given block offset. +- * Returns number of blocks read on success, -1 on error. This call is only +- * for reading VOB data, and should not be used when reading the IFO files. +- * When reading from an encrypted drive, blocks are decrypted using libdvdcss +- * where required. +- * +- * @param dvd_file A file read handle. +- * @param offset Block offset from the start of the file to start reading at. +- * @param block_count Number of block to read. +- * @param data Pointer to a buffer to write the data into. +- * @return Returns number of blocks read on success, -1 on error. +- * +- * blocks_read = DVDReadBlocks(dvd_file, offset, block_count, data); +- */ +-ssize_t DVDReadBlocks( dvd_file_t *, int, size_t, unsigned char * ); +- +-/** +- * Seek to the given position in the file. Returns the resulting position in +- * bytes from the beginning of the file. The seek position is only used for +- * byte reads from the file, the block read call always reads from the given +- * offset. +- * +- * @param dvd_file A file read handle. +- * @param seek_offset Byte offset from the start of the file to seek to. +- * @return The resulting position in bytes from the beginning of the file. +- * +- * offset_set = DVDFileSeek(dvd_file, seek_offset); +- */ +-int32_t DVDFileSeek( dvd_file_t *, int32_t ); +- +-/** +- * Reads the given number of bytes from the file. This call can only be used +- * on the information files, and may not be used for reading from a VOB. This +- * reads from and increments the current seek position for the file. +- * +- * @param dvd_file A file read handle. +- * @param data Pointer to a buffer to write the data into. +- * @param bytes Number of bytes to read. +- * @return Returns number of bytes read on success, -1 on error. +- * +- * bytes_read = DVDReadBytes(dvd_file, data, bytes); +- */ +-ssize_t DVDReadBytes( dvd_file_t *, void *, size_t ); +- +-/** +- * Returns the file size in blocks. +- * +- * @param dvd_file A file read handle. +- * @return The size of the file in blocks, -1 on error. +- * +- * blocks = DVDFileSize(dvd_file); +- */ +-ssize_t DVDFileSize( dvd_file_t * ); +- +-/** +- * Get a unique 128 bit disc ID. +- * This is the MD5 sum of VIDEO_TS.IFO and the VTS_0?_0.IFO files +- * in title order (those that exist). +- * If you need a 'text' representation of the id, print it as a +- * hexadecimal number, using lowercase letters, discid[0] first. +- * I.e. the same format as the command-line 'md5sum' program uses. +- * +- * @param dvd A read handle to get the disc ID from +- * @param discid The buffer to put the disc ID into. The buffer must +- * have room for 128 bits (16 chars). +- * @return 0 on success, -1 on error. +- */ +-int DVDDiscID( dvd_reader_t *, unsigned char * ); +- +-/** +- * Get the UDF VolumeIdentifier and VolumeSetIdentifier +- * from the PrimaryVolumeDescriptor. +- * +- * @param dvd A read handle to get the disc ID from +- * @param volid The buffer to put the VolumeIdentifier into. +- * The VolumeIdentifier is latin-1 encoded (8bit unicode) +- * null terminated and max 32 bytes (including '\0') +- * @param volid_size No more than volid_size bytes will be copied to volid. +- * If the VolumeIdentifier is truncated because of this +- * it will still be null terminated. +- * @param volsetid The buffer to put the VolumeSetIdentifier into. +- * The VolumeIdentifier is 128 bytes as +- * stored in the UDF PrimaryVolumeDescriptor. +- * Note that this is not a null terminated string. +- * @param volsetid_size At most volsetid_size bytes will be copied to volsetid. +- * @return 0 on success, -1 on error. +- */ +-int DVDUDFVolumeInfo(dvd_reader_t*, char*, unsigned int, unsigned char*, unsigned int); +- +-int DVDFileSeekForce( dvd_file_t *, int offset, int force_size); +- +-/** +- * Get the ISO9660 VolumeIdentifier and VolumeSetIdentifier +- * +- * * Only use this function as fallback if DVDUDFVolumeInfo returns -1 * +- * * this will happen on a disc mastered only with a iso9660 filesystem * +- * * All video DVD discs have UDF filesystem * +- * +- * @param dvd A read handle to get the disc ID from +- * @param volid The buffer to put the VolumeIdentifier into. +- * The VolumeIdentifier is coded with '0-9','A-Z','_' +- * null terminated and max 33 bytes (including '\0') +- * @param volid_size No more than volid_size bytes will be copied to volid. +- * If the VolumeIdentifier is truncated because of this +- * it will still be null terminated. +- * @param volsetid The buffer to put the VolumeSetIdentifier into. +- * The VolumeIdentifier is 128 bytes as +- * stored in the ISO9660 PrimaryVolumeDescriptor. +- * Note that this is not a null terminated string. +- * @param volsetid_size At most volsetid_size bytes will be copied to volsetid. +- * @return 0 on success, -1 on error. +- */ +-int DVDISOVolumeInfo(dvd_reader_t*, char*, unsigned int, unsigned char*, unsigned int); +- +-/** +- * Sets the level of caching that is done when reading from a device +- * +- * @param dvd A read handle to get the disc ID from +- * @param level The level of caching wanted. +- * -1 - returns the current setting. +- * 0 - UDF Cache turned off. +- * 1 - (default level) Pointers to IFO files and some data from +- * PrimaryVolumeDescriptor are cached. +- * +- * @return The level of caching. +- */ +-int DVDUDFCacheLevel( dvd_reader_t *, int ); +- +-#ifdef __cplusplus +-}; +-#endif +diff --git a/xbmc/cores/VideoPlayer/DVDInputStreams/dvdnav/dvd_types.h b/xbmc/cores/VideoPlayer/DVDInputStreams/dvdnav/dvd_types.h +deleted file mode 100644 +index 5b2e802951..0000000000 +--- a/xbmc/cores/VideoPlayer/DVDInputStreams/dvdnav/dvd_types.h ++++ /dev/null +@@ -1,282 +0,0 @@ +-/* +- * Copyright (C) 2000, 2001 Björn Englund, Håkan Hjort +- * +- * This file is part of libdvdnav, a DVD navigation library. It is a modified +- * file originally part of the Ogle DVD player project. +- * +- * libdvdnav 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 of the License, or +- * (at your option) any later version. +- * +- * libdvdnav 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 libdvdnav; if not, write to the Free Software Foundation, Inc., +- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +- */ +- +-/* +- * Various useful structs and enums for DVDs. +- */ +- +-#pragma once +- +-#include <stdint.h> +- +-/* +- * DVD Menu ID +- * (see dvdnav_menu_call()) +- */ +-typedef enum { +- /* When used in VTS domain, DVD_MENU_Escape behaves like DVD_MENU_Root, +- * but from within a menu domain, DVD_MENU_Escape resumes playback. */ +- DVD_MENU_Escape = 0, +- DVD_MENU_Title = 2, +- DVD_MENU_Root = 3, +- DVD_MENU_Subpicture = 4, +- DVD_MENU_Audio = 5, +- DVD_MENU_Angle = 6, +- DVD_MENU_Part = 7 +-} DVDMenuID_t; +- +-/* +- * Stream Types +- * (see dvdnav_get_number_of_streams()) +- */ +-typedef enum +-{ +- DVD_SUBTITLE_STREAM = 0, +- DVD_AUDIO_STREAM = 1 +-} dvdnav_stream_type_t; +- +-/* Domain */ +-typedef enum +-{ +- DVD_DOMAIN_FirstPlay = 1, /* First Play Domain */ +- DVD_DOMAIN_VTSTitle = 2, /* Video Title Set Domain */ +- DVD_DOMAIN_VMGM = 4, /* Video Manager Domain */ +- DVD_DOMAIN_VTSMenu = 8 /* Video Title Set Menu Domain */ +-} DVDDomain_t; +- +-/* +- * Structure containing info on highlight areas +- * (see dvdnav_get_highlight_area()) +- */ +-typedef struct { +- uint32_t palette; /* The CLUT entries for the highlight palette +- (4-bits per entry -> 4 entries) */ +- uint16_t sx,sy,ex,ey; /* The start/end x,y positions */ +- uint32_t pts; /* Highlight PTS to match with SPU */ +- +- /* button number for the SPU decoder/overlaying engine */ +- uint32_t buttonN; +-} dvdnav_highlight_area_t; +- +-/* The audio format */ +-typedef enum +-{ +- DVD_AUDIO_FORMAT_AC3 = 0, +- DVD_AUDIO_FORMAT_UNKNOWN_1 = 1, +- DVD_AUDIO_FORMAT_MPEG = 2, +- DVD_AUDIO_FORMAT_MPEG2_EXT = 3, +- DVD_AUDIO_FORMAT_LPCM = 4, +- DVD_AUDIO_FORMAT_UNKNOWN_5 = 5, +- DVD_AUDIO_FORMAT_DTS = 6, +- DVD_AUDIO_FORMAT_SDDS = 7 +-} DVDAudioFormat_t; +- +-/* the following types are currently unused */ +- +-#if 0 +- +-/* User operation permissions */ +-typedef enum { +- UOP_FLAG_TitleOrTimePlay = 0x00000001, +- UOP_FLAG_ChapterSearchOrPlay = 0x00000002, +- UOP_FLAG_TitlePlay = 0x00000004, +- UOP_FLAG_Stop = 0x00000008, +- UOP_FLAG_GoUp = 0x00000010, +- UOP_FLAG_TimeOrChapterSearch = 0x00000020, +- UOP_FLAG_PrevOrTopPGSearch = 0x00000040, +- UOP_FLAG_NextPGSearch = 0x00000080, +- UOP_FLAG_ForwardScan = 0x00000100, +- UOP_FLAG_BackwardScan = 0x00000200, +- UOP_FLAG_TitleMenuCall = 0x00000400, +- UOP_FLAG_RootMenuCall = 0x00000800, +- UOP_FLAG_SubPicMenuCall = 0x00001000, +- UOP_FLAG_AudioMenuCall = 0x00002000, +- UOP_FLAG_AngleMenuCall = 0x00004000, +- UOP_FLAG_ChapterMenuCall = 0x00008000, +- UOP_FLAG_Resume = 0x00010000, +- UOP_FLAG_ButtonSelectOrActivate = 0x00020000, +- UOP_FLAG_StillOff = 0x00040000, +- UOP_FLAG_PauseOn = 0x00080000, +- UOP_FLAG_AudioStreamChange = 0x00100000, +- UOP_FLAG_SubPicStreamChange = 0x00200000, +- UOP_FLAG_AngleChange = 0x00400000, +- UOP_FLAG_KaraokeAudioPresModeChange = 0x00800000, +- UOP_FLAG_VideoPresModeChange = 0x01000000 +-} DVDUOP_t; +- +-/* Parental Level */ +-typedef enum { +- DVD_PARENTAL_LEVEL_1 = 1, +- DVD_PARENTAL_LEVEL_2 = 2, +- DVD_PARENTAL_LEVEL_3 = 3, +- DVD_PARENTAL_LEVEL_4 = 4, +- DVD_PARENTAL_LEVEL_5 = 5, +- DVD_PARENTAL_LEVEL_6 = 6, +- DVD_PARENTAL_LEVEL_7 = 7, +- DVD_PARENTAL_LEVEL_8 = 8, +- DVD_PARENTAL_LEVEL_None = 15 +-} DVDParentalLevel_t; +- +-/* Language ID (ISO-639 language code) */ +-typedef uint16_t DVDLangID_t; +- +-/* Country ID (ISO-3166 country code) */ +-typedef uint16_t DVDCountryID_t; +- +-/* Register */ +-typedef uint16_t DVDRegister_t; +-typedef enum { +- DVDFalse = 0, +- DVDTrue = 1 +-} DVDBool_t; +-typedef DVDRegister_t DVDGPRMArray_t[16]; +-typedef DVDRegister_t DVDSPRMArray_t[24]; +- +-/* Navigation */ +-typedef int DVDStream_t; +-typedef int DVDPTT_t; +-typedef int DVDTitle_t; +- +-/* Angle number (1-9 or default?) */ +-typedef int DVDAngle_t; +- +-/* Timecode */ +-typedef struct { +- uint8_t Hours; +- uint8_t Minutes; +- uint8_t Seconds; +- uint8_t Frames; +-} DVDTimecode_t; +- +-/* Subpicture stream number (0-31,62,63) */ +-typedef int DVDSubpictureStream_t; +- +-/* Audio stream number (0-7, 15(none)) */ +-typedef int DVDAudioStream_t; +- +-/* The audio application mode */ +-typedef enum { +- DVD_AUDIO_APP_MODE_None = 0, +- DVD_AUDIO_APP_MODE_Karaoke = 1, +- DVD_AUDIO_APP_MODE_Surround = 2, +- DVD_AUDIO_APP_MODE_Other = 3 +-} DVDAudioAppMode_t; +- +-/* Audio language extension */ +-typedef enum { +- DVD_AUDIO_LANG_EXT_NotSpecified = 0, +- DVD_AUDIO_LANG_EXT_NormalCaptions = 1, +- DVD_AUDIO_LANG_EXT_VisuallyImpaired = 2, +- DVD_AUDIO_LANG_EXT_DirectorsComments1 = 3, +- DVD_AUDIO_LANG_EXT_DirectorsComments2 = 4 +-} DVDAudioLangExt_t; +- +-/* Subpicture language extension */ +-typedef enum { +- DVD_SUBPICTURE_LANG_EXT_NotSpecified = 0, +- DVD_SUBPICTURE_LANG_EXT_NormalCaptions = 1, +- DVD_SUBPICTURE_LANG_EXT_BigCaptions = 2, +- DVD_SUBPICTURE_LANG_EXT_ChildrensCaptions = 3, +- DVD_SUBPICTURE_LANG_EXT_NormalCC = 5, +- DVD_SUBPICTURE_LANG_EXT_BigCC = 6, +- DVD_SUBPICTURE_LANG_EXT_ChildrensCC = 7, +- DVD_SUBPICTURE_LANG_EXT_Forced = 9, +- DVD_SUBPICTURE_LANG_EXT_NormalDirectorsComments = 13, +- DVD_SUBPICTURE_LANG_EXT_BigDirectorsComments = 14, +- DVD_SUBPICTURE_LANG_EXT_ChildrensDirectorsComments = 15, +-} DVDSubpictureLangExt_t; +- +-/* Karaoke Downmix mode */ +-typedef enum { +- DVD_KARAOKE_DOWNMIX_0to0 = 0x0001, +- DVD_KARAOKE_DOWNMIX_1to0 = 0x0002, +- DVD_KARAOKE_DOWNMIX_2to0 = 0x0004, +- DVD_KARAOKE_DOWNMIX_3to0 = 0x0008, +- DVD_KARAOKE_DOWNMIX_4to0 = 0x0010, +- DVD_KARAOKE_DOWNMIX_Lto0 = 0x0020, +- DVD_KARAOKE_DOWNMIX_Rto0 = 0x0040, +- DVD_KARAOKE_DOWNMIX_0to1 = 0x0100, +- DVD_KARAOKE_DOWNMIX_1to1 = 0x0200, +- DVD_KARAOKE_DOWNMIX_2to1 = 0x0400, +- DVD_KARAOKE_DOWNMIX_3to1 = 0x0800, +- DVD_KARAOKE_DOWNMIX_4to1 = 0x1000, +- DVD_KARAOKE_DOWNMIX_Lto1 = 0x2000, +- DVD_KARAOKE_DOWNMIX_Rto1 = 0x4000 +-} DVDKaraokeDownmix_t; +-typedef int DVDKaraokeDownmixMask_t; +- +-/* Display mode */ +-typedef enum { +- DVD_DISPLAY_MODE_ContentDefault = 0, +- DVD_DISPLAY_MODE_16x9 = 1, +- DVD_DISPLAY_MODE_4x3PanScan = 2, +- DVD_DISPLAY_MODE_4x3Letterboxed = 3 +-} DVDDisplayMode_t; +- +-/* Audio attributes */ +-typedef struct { +- DVDAudioAppMode_t AppMode; +- DVDAudioFormat_t AudioFormat; +- DVDLangID_t Language; +- DVDAudioLangExt_t LanguageExtension; +- DVDBool_t HasMultichannelInfo; +- DVDAudioSampleFreq_t SampleFrequency; +- DVDAudioSampleQuant_t SampleQuantization; +- DVDChannelNumber_t NumberOfChannels; +-} DVDAudioAttributes_t; +-typedef int DVDAudioSampleFreq_t; +-typedef int DVDAudioSampleQuant_t; +-typedef int DVDChannelNumber_t; +- +-/* Subpicture attributes */ +-typedef enum { +- DVD_SUBPICTURE_TYPE_NotSpecified = 0, +- DVD_SUBPICTURE_TYPE_Language = 1, +- DVD_SUBPICTURE_TYPE_Other = 2 +-} DVDSubpictureType_t; +-typedef enum { +- DVD_SUBPICTURE_CODING_RunLength = 0, +- DVD_SUBPICTURE_CODING_Extended = 1, +- DVD_SUBPICTURE_CODING_Other = 2 +-} DVDSubpictureCoding_t; +-typedef struct { +- DVDSubpictureType_t Type; +- DVDSubpictureCoding_t CodingMode; +- DVDLangID_t Language; +- DVDSubpictureLangExt_t LanguageExtension; +-} DVDSubpictureAttributes_t; +- +-/* Video attributes */ +-typedef struct { +- DVDBool_t PanscanPermitted; +- DVDBool_t LetterboxPermitted; +- int AspectX; +- int AspectY; +- int FrameRate; +- int FrameHeight; +- DVDVideoCompression_t Compression; +- DVDBool_t Line21Field1InGop; +- DVDBool_t Line21Field2InGop; +- int more_to_come; +-} DVDVideoAttributes_t; +-typedef int DVDVideoCompression_t; +- +-#endif +diff --git a/xbmc/cores/VideoPlayer/DVDInputStreams/dvdnav/dvdnav.h b/xbmc/cores/VideoPlayer/DVDInputStreams/dvdnav/dvdnav.h +deleted file mode 100644 +index 63d501b959..0000000000 +--- a/xbmc/cores/VideoPlayer/DVDInputStreams/dvdnav/dvdnav.h ++++ /dev/null +@@ -1,789 +0,0 @@ +-/* +- * Copyright (C) 2001 Rich Wareham <richwareham@users.sourceforge.net> +- * +- * This file is part of libdvdnav, a DVD navigation library. +- * +- * libdvdnav 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 of the License, or +- * (at your option) any later version. +- * +- * libdvdnav 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 libdvdnav; if not, write to the Free Software Foundation, Inc., +- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +- */ +- +-/* +- * This is the main header file applications should include if they want +- * to access dvdnav functionality. +- */ +- +-#pragma once +- +-#ifdef __cplusplus +-extern "C" { +-#endif +- +-#include "dvd_reader.h" +-#include "dvd_types.h" +-#include "dvdnav_events.h" +-#include "nav_types.h" +-#include "version.h" +- +-#include <stdarg.h> +- +- /********************************************************************* +- * dvdnav data types * +- *********************************************************************/ +- +- /* +- * Opaque data-type can be viewed as a 'DVD handle'. You should get +- * a pointer to a dvdnav_t from the dvdnav_open() function. +- * Never call free() on the pointer, you have to give it back with +- * dvdnav_close(). +- */ +- typedef struct dvdnav_s dvdnav_t; +- +- /* Status as reported by most of libdvdnav's functions */ +- typedef int32_t dvdnav_status_t; +- +- typedef dvd_reader_stream_cb dvdnav_stream_cb; +- +-/* +- * Unless otherwise stated, all functions return DVDNAV_STATUS_OK if +- * they succeeded, otherwise DVDNAV_STATUS_ERR is returned and the error may +- * be obtained by calling dvdnav_err_to_string(). +- */ +-#define DVDNAV_STATUS_ERR 0 +-#define DVDNAV_STATUS_OK 1 +- +-/********************************************************************* +- * initialisation & housekeeping functions * +- *********************************************************************/ +- +-/* +- * Logger callback definition +- */ +-typedef enum +-{ +- DVDNAV_LOGGER_LEVEL_INFO, +- DVDNAV_LOGGER_LEVEL_ERROR, +- DVDNAV_LOGGER_LEVEL_WARN, +- DVDNAV_LOGGER_LEVEL_DEBUG, +-} dvdnav_logger_level_t; +- +-typedef struct +-{ +- void (*pf_log)(void*, dvdnav_logger_level_t, const char*, va_list); +-} dvdnav_logger_cb; +- +-/* +- * These functions allow you to open a DVD device and associate it +- * with a dvdnav_t. +- */ +- +-/* +- * Attempts to open the DVD drive at the specified path or using external +- * seek/read functions (dvdnav_open_stream) and pre-cache the CSS-keys. +- * libdvdread is used to access the DVD, so any source supported by libdvdread +- * can be given with "path" or "stream_cb". Currently, using dvdnav_open, +- * libdvdread can access : DVD drives, DVD image files, DVD file-by-file +- * copies. Using dvdnav_open_stream, libdvdread can access any kind of DVD +- * storage via custom implementation of seek/read functions. +- * +- * The resulting dvdnav_t handle will be written to *dest. +- */ +-dvdnav_status_t dvdnav_open(dvdnav_t **dest, const char *path); +-dvdnav_status_t dvdnav_open_stream(dvdnav_t** dest, void* priv, dvdnav_stream_cb* stream_cb); +- +-dvdnav_status_t dvdnav_open2(dvdnav_t** dest, void*, const dvdnav_logger_cb*, const char* path); +-dvdnav_status_t dvdnav_open_stream2(dvdnav_t** dest, +- void* priv, +- const dvdnav_logger_cb*, +- dvdnav_stream_cb* stream_cb); +- +-dvdnav_status_t dvdnav_dup(dvdnav_t** dest, dvdnav_t* src); +-dvdnav_status_t dvdnav_free_dup(dvdnav_t* _this); +- +-/* +- * Closes a dvdnav_t previously opened with dvdnav_open(), freeing any +- * memory associated with it. +- */ +-dvdnav_status_t dvdnav_close(dvdnav_t *self); +- +-/* +- * Resets the DVD virtual machine and cache buffers. +- */ +-dvdnav_status_t dvdnav_reset(dvdnav_t *self); +- +-/* +- * Fills a pointer with a value pointing to a string describing +- * the path associated with an open dvdnav_t. It assigns *path to NULL +- * on error. +- */ +-dvdnav_status_t dvdnav_path(dvdnav_t *self, const char **path); +- +-/* +- * Returns a human-readable string describing the last error. +- */ +-const char* dvdnav_err_to_string(dvdnav_t *self); +- +-const char* dvdnav_version(void); +- +-/********************************************************************* +- * changing and reading DVD player characteristics * +- *********************************************************************/ +- +-/* +- * These functions allow you to manipulate the various global characteristics +- * of the DVD playback engine. +- */ +- +-/* +- * Sets the region mask (bit 0 set implies region 1, bit 1 set implies +- * region 2, etc) of the virtual machine. Generally you will only need to set +- * this if you are playing RCE discs which query the virtual machine as to its +- * region setting. +- * +- * This has _nothing_ to do with the region setting of the DVD drive. +- */ +-dvdnav_status_t dvdnav_set_region_mask(dvdnav_t *self, int32_t region_mask); +- +-/* +- * Returns the region mask (bit 0 set implies region 1, bit 1 set implies +- * region 2, etc) of the virtual machine. +- * +- * This has _nothing_ to do with the region setting of the DVD drive. +- */ +-dvdnav_status_t dvdnav_get_region_mask(dvdnav_t *self, int32_t *region_mask); +- +-/* +- * Specify whether read-ahead caching should be used. You may not want this if your +- * decoding engine does its own buffering. +- * +- * The default read-ahead cache does not use an additional thread for the reading +- * (see read_cache.c for a threaded cache, but note that this code is currently +- * unmaintained). It prebuffers on VOBU level by reading ahead several buffers +- * on every read request. The speed of this prebuffering has been optimized to +- * also work on slow DVD drives. +- * +- * If in addition you want to prevent memcpy's to improve performance, have a look +- * at dvdnav_get_next_cache_block(). +- */ +-dvdnav_status_t dvdnav_set_readahead_flag(dvdnav_t *self, int32_t read_ahead_flag); +- +-/* +- * Query whether read-ahead caching/buffering will be used. +- */ +-dvdnav_status_t dvdnav_get_readahead_flag(dvdnav_t *self, int32_t *read_ahead_flag); +- +-/* +- * Specify whether the positioning works PGC or PG based. +- * Programs (PGs) on DVDs are similar to Chapters and a program chain (PGC) +- * usually covers a whole feature. This affects the behaviour of the +- * functions dvdnav_get_position() and dvdnav_sector_search(). See there. +- * Default is PG based positioning. +- */ +-dvdnav_status_t dvdnav_set_PGC_positioning_flag(dvdnav_t *self, int32_t pgc_based_flag); +- +-/* +- * Query whether positioning is PG or PGC based. +- */ +-dvdnav_status_t dvdnav_get_PGC_positioning_flag(dvdnav_t *self, int32_t *pgc_based_flag); +- +- +-/********************************************************************* +- * reading data * +- *********************************************************************/ +- +-/* +- * These functions are used to poll the playback engine and actually get data +- * off the DVD. +- */ +- +-/* +- * Attempts to get the next block off the DVD and copies it into the buffer 'buf'. +- * If there is any special actions that may need to be performed, the value +- * pointed to by 'event' gets set accordingly. +- * +- * If 'event' is DVDNAV_BLOCK_OK then 'buf' is filled with the next block +- * (note that means it has to be at /least/ 2048 bytes big). 'len' is +- * then set to 2048. +- * +- * Otherwise, buf is filled with an appropriate event structure and +- * len is set to the length of that structure. +- * +- * See the dvdnav_events.h header for information on the various events. +- */ +-dvdnav_status_t dvdnav_get_next_block(dvdnav_t* self, uint8_t* buf, int32_t* event, int32_t* len); +- +-/* +- * This basically does the same as dvdnav_get_next_block. The only difference is +- * that it avoids a memcopy, when the requested block was found in the cache. +- * In such a case (cache hit) this function will return a different pointer than +- * the one handed in, pointing directly into the relevant block in the cache. +- * Those pointers must _never_ be freed but instead returned to the library via +- * dvdnav_free_cache_block(). +- */ +-dvdnav_status_t dvdnav_get_next_cache_block(dvdnav_t* self, +- uint8_t** buf, +- int32_t* event, +- int32_t* len); +- +-/* +- * All buffers which came from the internal cache (when dvdnav_get_next_cache_block() +- * returned a buffer different from the one handed in) have to be freed with this +- * function. Although handing in other buffers not from the cache doesn't cause any harm. +- */ +-dvdnav_status_t dvdnav_free_cache_block(dvdnav_t *self, unsigned char *buf); +- +-/* +- * If we are currently in a still-frame this function skips it. +- * +- * See also the DVDNAV_STILL_FRAME event. +- */ +-dvdnav_status_t dvdnav_still_skip(dvdnav_t *self); +- +-/* +- * If we are currently in WAIT state, that is: the application is required to +- * wait for its fifos to become empty, calling this signals libdvdnav that this +- * is achieved and that it can continue. +- * +- * See also the DVDNAV_WAIT event. +- */ +-dvdnav_status_t dvdnav_wait_skip(dvdnav_t *self); +- +-/* +- * Returns the still time from the currently playing cell. +- * The still time is given in seconds with 0xff meaning an indefinite still. +- * +- * This function can be used to detect still frames before they are reached. +- * Some players might need this to prepare for a frame to be shown for a +- * longer time than usual. +- */ +-uint32_t dvdnav_get_next_still_flag(dvdnav_t *self); +- +-/* +- * Stops playback. The next event obtained with one of the get_next_block +- * functions will be a DVDNAV_STOP event. +- * +- * It is not required to call this before dvdnav_close(). +- */ +-dvdnav_status_t dvdnav_stop(dvdnav_t *self); +- +-/* +- * Returns the region mask (bit 0 set implies region 1, bit 1 set implies +- * region 2, etc) reported by the dvd disc being played. +- * +- * Note this has no relation with the region setting of the DVD drive. +- * Old DVD drives (RPC-I) used to delegate most of the RCE handling to the CPU and +- * will actually call the virtual machine (VM) for its region setting. In those cases, +- * changing the VM region mask via dvdnav_set_region_mask() will circunvent +- * the region protection scheme. This is no longer the case with more recent (RPC-II) drives +- * as RCE is handled internally by the drive firmware. +- * +- */ +-dvdnav_status_t dvdnav_get_disk_region_mask(dvdnav_t* self, int32_t* region_mask); +- +-/********************************************************************* +- * title/part navigation * +- *********************************************************************/ +- +-/* +- * Returns the number of titles on the disk. +- */ +-dvdnav_status_t dvdnav_get_number_of_titles(dvdnav_t *self, int32_t *titles); +- +-/* +- * Returns the number of parts within the given title. +- */ +-dvdnav_status_t dvdnav_get_number_of_parts(dvdnav_t *self, int32_t title, int32_t *parts); +- +-/* +- * Returns the number of angles for the given title. +- */ +-dvdnav_status_t dvdnav_get_number_of_angles(dvdnav_t* self, int32_t title, int32_t* angles); +- +-/* +- * Plays the specified title of the DVD from its beginning (that is: part 1). +- */ +-dvdnav_status_t dvdnav_title_play(dvdnav_t *self, int32_t title); +- +-/* +- * Plays the specified title, starting from the specified part. +- */ +-dvdnav_status_t dvdnav_part_play(dvdnav_t *self, int32_t title, int32_t part); +- +-/* +- * Plays the specified title, starting from the specified program +- */ +-dvdnav_status_t dvdnav_program_play(dvdnav_t *self, int32_t title, int32_t pgcn, int32_t pgn); +- +-/* +- * Stores in *times an array (that the application *must* free) of +- * dvdtimes corresponding to the chapter times for the chosen title. +- * *duration will have the duration of the title +- * The number of entries in *times is the result of the function. +- * On error *times is NULL and the output is 0 +- */ +-uint32_t dvdnav_describe_title_chapters(dvdnav_t *self, int32_t title, uint64_t **times, uint64_t *duration); +- +-/* +- * Play the specified amount of parts of the specified title of +- * the DVD then STOP. +- * +- * Currently unimplemented! +- */ +-dvdnav_status_t dvdnav_part_play_auto_stop(dvdnav_t* self, +- int32_t title, +- int32_t part, +- int32_t parts_to_play); +- +-/* +- * Play the specified title starting from the specified time. +- * +- * Currently unimplemented! +- */ +-dvdnav_status_t dvdnav_time_play(dvdnav_t* self, int32_t title, uint64_t time); +- +-/* +- * Stop playing the current position and jump to the specified menu. +- * +- * See also DVDMenuID_t from libdvdread +- */ +-dvdnav_status_t dvdnav_menu_call(dvdnav_t *self, DVDMenuID_t menu); +- +-/* +- * Return the title number and part currently being played. +- * A title of 0 indicates we are in a menu. In this case, part +- * is set to the current menu's ID. +- */ +-dvdnav_status_t dvdnav_current_title_info(dvdnav_t* self, int32_t* title, int32_t* part); +- +-/* +- * Return the title number, pgcn and pgn currently being played. +- * A title of 0 indicates, we are in a menu. +- */ +-dvdnav_status_t dvdnav_current_title_program(dvdnav_t* self, +- int32_t* title, +- int32_t* pgcn, +- int32_t* pgn); +- +-/* +- * Return the current position (in blocks) within the current +- * title and the length (in blocks) of said title. +- * +- * Current implementation is wrong and likely to behave unpredictably! +- * Use is discouraged! +- */ +-dvdnav_status_t dvdnav_get_position_in_title(dvdnav_t* self, uint32_t* pos, uint32_t* len); +- +-/* +- * This function is only available for compatibility reasons. +- * +- * Stop playing the current position and start playback of the current title +- * from the specified part. +- */ +-dvdnav_status_t dvdnav_part_search(dvdnav_t *self, int32_t part); +- +- +-/********************************************************************* +- * program chain/program navigation * +- *********************************************************************/ +- +-/* +- * Stop playing the current position and start playback from the last +- * VOBU boundary before the given sector. The sector number is not +- * meant to be an absolute physical DVD sector, but a relative sector +- * in the current program. This function cannot leave the current +- * program and will fail if asked to do so. +- * +- * If program chain based positioning is enabled +- * (see dvdnav_set_PGC_positioning_flag()), this will seek to the relative +- * sector inside the current program chain. +- * +- * 'origin' can be one of SEEK_SET, SEEK_CUR, SEEK_END as defined in +- * fcntl.h. +- */ +-dvdnav_status_t dvdnav_sector_search(dvdnav_t* self, int64_t offset, int32_t origin); +- +-/* +- returns the current stream time in PTS ticks as reported by the IFO structures +- divide it by 90000 to get the current play time in seconds +- */ +-int64_t dvdnav_get_current_time(dvdnav_t *self); +- +-/* +- * Stop playing the current position and start playback of the title +- * from the specified timecode. +- * +- * Currently implemented using interpolation. That interpolation is slightly +- * inaccurate. +- */ +-dvdnav_status_t dvdnav_time_search(dvdnav_t* self, uint64_t time); +- +-/* +- * Find the nearest vobu and jump to it +- * +- * Alternative to dvdnav_time_search (see full documentation on searching.jump_to_time.readme) +- * Jumps to the provided PTS (which is defined as time_in_ms * 90). mode means the navigation mode, +- * currently only the Default (0) is implemented: +- * 0: Default. Jump to a time which may be either <> time_in_pts_ticks +- * 1: After. Always jump to a time that is > time_in_pts_ticks +- * -1: Before. Always jump to a time that is < time_in_pts_ticks +- */ +-dvdnav_status_t dvdnav_jump_to_sector_by_time(dvdnav_t* self, +- uint64_t time_in_pts_ticks, +- int32_t mode); +- +-/* +- * Stop playing current position and play the "GoUp"-program chain. +- * (which generally leads to the title menu or a higher-level menu). +- */ +-dvdnav_status_t dvdnav_go_up(dvdnav_t *self); +- +-/* +- * Stop playing the current position and start playback at the +- * previous program (if it exists). +- */ +-dvdnav_status_t dvdnav_prev_pg_search(dvdnav_t *self); +- +-/* +- * Stop playing the current position and start playback at the +- * first program. +- */ +-dvdnav_status_t dvdnav_top_pg_search(dvdnav_t *self); +- +-/* +- * Stop playing the current position and start playback at the +- * next program (if it exists). +- */ +-dvdnav_status_t dvdnav_next_pg_search(dvdnav_t *self); +- +-/* +- * Return the current position (in blocks) within the current +- * program and the length (in blocks) of current program. +- * +- * If program chain based positioning is enabled +- * (see dvdnav_set_PGC_positioning_flag()), this will return the +- * relative position in and the length of the current program chain. +- */ +-dvdnav_status_t dvdnav_get_position(dvdnav_t* self, uint32_t* pos, uint32_t* len); +- +-/********************************************************************* +- * menu highlights * +- *********************************************************************/ +- +-/* +- * Most functions related to highlights take a NAV PCI packet as a parameter. +- * While you can get such a packet from libdvdnav, this will result in +- * errors for players with internal FIFOs because due to the FIFO length, +- * libdvdnav will be ahead in the stream compared to what the user is +- * seeing on screen. Therefore, player applications who have a NAV +- * packet available, which is better in sync with the actual playback, +- * should always pass this one to these functions. +- */ +- +-/* +- * Get the currently highlighted button +- * number (1..36) or 0 if no button is highlighted. +- */ +-dvdnav_status_t dvdnav_get_current_highlight(dvdnav_t *self, int32_t *button); +- +-/* +- * Returns the Presentation Control Information (PCI) structure associated +- * with the current position. +- * +- * Read the general notes above. +- * See also libdvdreads nav_types.h for definition of pci_t. +- */ +-pci_t* dvdnav_get_current_nav_pci(dvdnav_t *self); +- +-/* +- * Returns the DSI (data search information) structure associated +- * with the current position. +- * +- * Read the general notes above. +- * See also libdvdreads nav_types.h for definition of dsi_t. +- */ +-dsi_t* dvdnav_get_current_nav_dsi(dvdnav_t *self); +- +-/* +- * Get the area associated with a certain button. +- */ +-dvdnav_status_t dvdnav_get_highlight_area(pci_t* nav_pci, +- int32_t button, +- int32_t mode, +- dvdnav_highlight_area_t* highlight); +- +-/* +- * Move button highlight around as suggested by function name (e.g. with arrow keys). +- */ +-dvdnav_status_t dvdnav_upper_button_select(dvdnav_t *self, pci_t *pci); +-dvdnav_status_t dvdnav_lower_button_select(dvdnav_t *self, pci_t *pci); +-dvdnav_status_t dvdnav_right_button_select(dvdnav_t *self, pci_t *pci); +-dvdnav_status_t dvdnav_left_button_select(dvdnav_t *self, pci_t *pci); +- +-/* +- * Activate ("press") the currently highlighted button. +- */ +-dvdnav_status_t dvdnav_button_activate(dvdnav_t *self, pci_t *pci); +- +-/* +- * Highlight a specific button. +- */ +-dvdnav_status_t dvdnav_button_select(dvdnav_t *self, pci_t *pci, int32_t button); +- +-/* +- * Activate ("press") specified button. +- */ +-dvdnav_status_t dvdnav_button_select_and_activate(dvdnav_t *self, pci_t *pci, int32_t button); +- +-/* +- * Activate ("press") a button and execute specified command. +- */ +-dvdnav_status_t dvdnav_button_activate_cmd(dvdnav_t *self, int32_t button, vm_cmd_t *cmd); +- +-/* +- * Select button at specified video frame coordinates. +- */ +-dvdnav_status_t dvdnav_mouse_select(dvdnav_t *self, pci_t *pci, int32_t x, int32_t y); +- +-/* +- * Activate ("press") button at specified video frame coordinates. +- */ +-dvdnav_status_t dvdnav_mouse_activate(dvdnav_t *self, pci_t *pci, int32_t x, int32_t y); +- +- +-/********************************************************************* +- * languages * +- *********************************************************************/ +- +-/* +- * The language codes expected by these functions are two character +- * codes as defined in ISO639. +- */ +- +-/* +- * Set which menu language we should use per default. +- */ +-dvdnav_status_t dvdnav_menu_language_select(dvdnav_t* self, char* code); +- +-/* +- * Set which audio language we should use per default. +- */ +-dvdnav_status_t dvdnav_audio_language_select(dvdnav_t* self, char* code); +- +-/* +- * Set which spu language we should use per default. +- */ +-dvdnav_status_t dvdnav_spu_language_select(dvdnav_t* self, char* code); +- +-/********************************************************************* +- * obtaining stream attributes * +- *********************************************************************/ +- +-/* +- * Return a string describing the title of the DVD. +- * This is an ID string encoded on the disc by the author. In many cases +- * this is a descriptive string such as `THE_MATRIX' but sometimes is singularly +- * uninformative such as `PDVD-011421'. Some DVD authors even forget to set this, +- * so you may also read the default of the authoring software they used, like +- * `DVDVolume'. +- */ +-dvdnav_status_t dvdnav_get_title_string(dvdnav_t *self, const char **title_str); +- +-/* +- * Returns a string containing the serial number of the DVD. +- * This has a max of 15 characters and should be more unique than the +- * title string. +- */ +-dvdnav_status_t dvdnav_get_serial_string(dvdnav_t *self, const char **serial_str); +- +-/* +- * Returns the VolumeIdentifier of the disc or NULL if it could +- * not be obtained. The VolumeIdentifier might be latin-1 encoded +- * (8bit unicode) null terminated and max 32 bytes (including '\0'); +- * or coded with '0-9','A-Z','_' null terminated and max 33 bytes +- * (including '\0'). +- * See also dvdnav_get_title_string +- * +- * Note: The string is malloc'd so caller has to free() the returned +- * string when done with it. +- */ +-const char* dvdnav_get_volid_string(dvdnav_t* self); +- +-/* +- * Get video aspect code. +- * The aspect code does only change on VTS boundaries. +- * See the DVDNAV_VTS_CHANGE event. +- * +- * 0 -- 4:3, 2 -- 16:9 +- */ +-uint8_t dvdnav_get_video_aspect(dvdnav_t *self); +- +-/* +- * Get video resolution. +- */ +-dvdnav_status_t dvdnav_get_video_resolution(dvdnav_t* self, uint32_t* width, uint32_t* height); +- +-/* +- * Get video scaling permissions. +- * The scaling permission does only change on VTS boundaries. +- * See the DVDNAV_VTS_CHANGE event. +- * +- * bit0 set = deny letterboxing, bit1 set = deny pan&scan +- */ +-uint8_t dvdnav_get_video_scale_permission(dvdnav_t *self); +- +-/* +- * Converts a *logical* audio stream id into language code +- * (returns 0xffff if no such stream). +- */ +-uint16_t dvdnav_audio_stream_to_lang(dvdnav_t *self, uint8_t stream); +- +-/* +- * Returns the format of *logical* audio stream 'stream' +- * (returns 0xffff if no such stream). +- */ +-uint16_t dvdnav_audio_stream_format(dvdnav_t *self, uint8_t stream); +- +-/* +- * Returns number of channels in *logical* audio stream 'stream' +- * (returns 0xffff if no such stream). +- */ +-uint16_t dvdnav_audio_stream_channels(dvdnav_t *self, uint8_t stream); +- +-/* +- * Converts a *logical* subpicture stream id into country code +- * (returns 0xffff if no such stream). +- */ +-uint16_t dvdnav_spu_stream_to_lang(dvdnav_t *self, uint8_t stream); +- +-/* +- * Converts a *physical* (MPEG) audio stream id into a logical stream number. +- */ +-int8_t dvdnav_get_audio_logical_stream(dvdnav_t *self, uint8_t audio_num); +- +-#define HAVE_GET_AUDIO_ATTR +-/* +- * Get audio attr +- */ +-dvdnav_status_t dvdnav_get_audio_attr(dvdnav_t *self, uint8_t audio_mum, audio_attr_t *audio_attr); +- +-/* +- * Converts a *physical* (MPEG) subpicture stream id into a logical stream number. +- */ +-int8_t dvdnav_get_spu_logical_stream(dvdnav_t *self, uint8_t subp_num); +- +-#define HAVE_GET_SPU_ATTR +-/* +- * Get spu attr +- */ +-dvdnav_status_t dvdnav_get_spu_attr(dvdnav_t *self, uint8_t audio_mum, subp_attr_t *subp_attr); +- +-/* +- * Get active audio stream. +- */ +-int8_t dvdnav_get_active_audio_stream(dvdnav_t *self); +- +-/* +- * Get active spu stream. +- */ +-int8_t dvdnav_get_active_spu_stream(dvdnav_t *self); +- +-/* +- * Get the set of user operations that are currently prohibited. +- * There are potentially new restrictions right after +- * DVDNAV_CHANNEL_HOP and DVDNAV_NAV_PACKET. +- */ +-user_ops_t dvdnav_get_restrictions(dvdnav_t *self); +- +-/* +- * Returns the number of streams provided its type (e.g. subtitles, audio, etc) +- */ +-int8_t dvdnav_get_number_of_streams(dvdnav_t* self, dvdnav_stream_type_t stream_type); +- +-/********************************************************************* +- * setting stream attributes * +- *********************************************************************/ +- +-/* +- * Set the visible (enable) status of the current spu stream +- * (to enable/disable subtitles) +- * visibility defines if the spu stream should be enabled/visible (1) or disabled (0) +- */ +-dvdnav_status_t dvdnav_toggle_spu_stream(dvdnav_t* self, uint8_t visibility); +- +-/* +- * Set the given stream id and stream type as active +- * stream_num - the physical index of the stream +- * stream_type - the stream type (audio or subtitles) +- */ +-dvdnav_status_t dvdnav_set_active_stream(dvdnav_t* self, +- uint8_t stream_num, +- dvdnav_stream_type_t stream_type); +- +-/********************************************************************* +- * multiple angles * +- *********************************************************************/ +- +-/* +- * The libdvdnav library abstracts away the difference between seamless and +- * non-seamless angles. From the point of view of the programmer you just set the +- * angle number and all is well in the world. You will always see only the +- * selected angle coming from the get_next_block functions. +- * +- * Note: +- * It is quite possible that some tremendously strange DVD feature might change the +- * angle number from under you. Generally you should always view the results from +- * dvdnav_get_angle_info() as definitive only up to the next time you call +- * dvdnav_get_next_block(). +- */ +- +-/* +- * Sets the current angle. If you try to follow a non existent angle +- * the call fails. +- */ +-dvdnav_status_t dvdnav_angle_change(dvdnav_t *self, int32_t angle); +- +-/* +- * Returns the current angle and number of angles present. +- */ +-dvdnav_status_t dvdnav_get_angle_info(dvdnav_t* self, +- int32_t* current_angle, +- int32_t* number_of_angles); +- +-/********************************************************************* +- * domain queries * +- *********************************************************************/ +- +-/* +- * Are we in the First Play domain? +- */ +-int8_t dvdnav_is_domain_fp(dvdnav_t *self); +- +-/* +- * Are we in the Video management Menu domain? +- */ +-int8_t dvdnav_is_domain_vmgm(dvdnav_t *self); +- +-/* +- * Are we in the Video Title Menu domain? +- */ +-int8_t dvdnav_is_domain_vtsm(dvdnav_t *self); +- +-/* +- * Are we in the Video Title Set domain? +- */ +-int8_t dvdnav_is_domain_vts(dvdnav_t *self); +- +- +-#ifdef __cplusplus +-} +-#endif +diff --git a/xbmc/cores/VideoPlayer/DVDInputStreams/dvdnav/dvdnav_events.h b/xbmc/cores/VideoPlayer/DVDInputStreams/dvdnav/dvdnav_events.h +deleted file mode 100644 +index 970fa6a937..0000000000 +--- a/xbmc/cores/VideoPlayer/DVDInputStreams/dvdnav/dvdnav_events.h ++++ /dev/null +@@ -1,226 +0,0 @@ +-/* +- * Copyright (C) 2001 Rich Wareham <richwareham@users.sourceforge.net> +- * +- * This file is part of libdvdnav, a DVD navigation library. +- * +- * libdvdnav 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 of the License, or +- * (at your option) any later version. +- * +- * libdvdnav 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 libdvdnav; if not, write to the Free Software Foundation, Inc., +- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +- */ +- +-/* +- * This header defines events and event types +- */ +- +-#pragma once +- +-/* +- * DVDNAV_BLOCK_OK +- * +- * A regular data block from the DVD has been returned. +- * This one should be demuxed and decoded for playback. +- */ +-#define DVDNAV_BLOCK_OK 0 +- +-/* +- * DVDNAV_NOP +- * +- * Just ignore this. +- */ +-#define DVDNAV_NOP 1 +- +-/* +- * DVDNAV_STILL_FRAME +- * +- * We have reached a still frame. The player application should wait +- * the amount of time specified by the still's length while still handling +- * user input to make menus and other interactive stills work. +- * The last delivered frame should be kept showing. +- * Once the still has timed out, call dvdnav_skip_still(). +- * A length of 0xff means an infinite still which has to be skipped +- * indirectly by some user interaction. +- */ +-#define DVDNAV_STILL_FRAME 2 +- +-typedef struct { +- /* The length (in seconds) the still frame should be displayed for, +- * or 0xff if infinite. */ +- int length; +-} dvdnav_still_event_t; +- +- +-/* +- * DVDNAV_SPU_STREAM_CHANGE +- * +- * Inform the SPU decoding/overlaying engine to switch SPU channels. +- */ +-#define DVDNAV_SPU_STREAM_CHANGE 3 +- +-typedef struct { +- /* The physical (MPEG) stream number for widescreen SPU display. +- * Use this, if you blend the SPU on an anamorphic image before +- * unsqueezing it. */ +- int physical_wide; +- +- /* The physical (MPEG) stream number for letterboxed display. +- * Use this, if you blend the SPU on an anamorphic image after +- * unsqueezing it. */ +- int physical_letterbox; +- +- /* The physical (MPEG) stream number for pan&scan display. +- * Use this, if you blend the SPU on an anamorphic image after +- * unsqueezing it the pan&scan way. */ +- int physical_pan_scan; +- +- /* The logical (DVD) stream number. */ +- int logical; +-} dvdnav_spu_stream_change_event_t; +- +- +-/* +- * DVDNAV_AUDIO_STREAM_CHANGE +- * +- * Inform the audio decoder to switch channels. +- */ +-#define DVDNAV_AUDIO_STREAM_CHANGE 4 +- +-typedef struct { +- /* The physical (MPEG) stream number. */ +- int physical; +- +- /* The logical (DVD) stream number. */ +- int logical; +-} dvdnav_audio_stream_change_event_t; +- +- +-/* +- * DVDNAV_VTS_CHANGE +- * +- * Some status information like video aspect and video scale permissions do +- * not change inside a VTS. Therefore this event can be used to query such +- * information only when necessary and update the decoding/displaying +- * accordingly. +- */ +-#define DVDNAV_VTS_CHANGE 5 +- +-typedef struct { +- int old_vtsN; /* the old VTS number */ +- DVDDomain_t old_domain; /* the old domain */ +- int new_vtsN; /* the new VTS number */ +- DVDDomain_t new_domain; /* the new domain */ +-} dvdnav_vts_change_event_t; +- +- +-/* +- * DVDNAV_CELL_CHANGE +- * +- * Some status information like the current Title and Part numbers do not +- * change inside a cell. Therefore this event can be used to query such +- * information only when necessary and update the decoding/displaying +- * accordingly. +- * Some useful information for accurate time display is also reported +- * together with this event. +- */ +-#define DVDNAV_CELL_CHANGE 6 +- +-typedef struct { +- int cellN; /* the new cell number */ +- int pgN; /* the current program number */ +- int64_t cell_length; /* the length of the current cell in sectors */ +- int64_t pg_length; /* the length of the current program in sectors */ +- int64_t pgc_length; /* the length of the current program chain in PTS ticks */ +- int64_t cell_start; /* the start offset of the current cell relatively to the PGC in sectors */ +- int64_t pg_start; /* the start offset of the current PG relatively to the PGC in sectors */ +-} dvdnav_cell_change_event_t; +- +- +-/* +- * DVDNAV_NAV_PACKET +- * +- * NAV packets are useful for various purposes. They define the button +- * highlight areas and VM commands of DVD menus, so they should in any +- * case be sent to the SPU decoder/overlaying engine for the menus to work. +- * NAV packets also provide a way to detect PTS discontinuities, because +- * they carry the start and end PTS values for the current VOBU. +- * (pci.vobu_s_ptm and pci.vobu_e_ptm) Whenever the start PTS of the +- * current NAV does not match the end PTS of the previous NAV, a PTS +- * discontinuity has occurred. +- * NAV packets can also be used for time display, because they are +- * timestamped relatively to the current Cell. +- */ +-#define DVDNAV_NAV_PACKET 7 +- +-/* +- * DVDNAV_STOP +- * +- * Applications should end playback here. A subsequent dvdnav_get_next_block() +- * call will restart the VM from the beginning of the DVD. +- */ +-#define DVDNAV_STOP 8 +- +-/* +- * DVDNAV_HIGHLIGHT +- * +- * The current button highlight changed. Inform the overlaying engine to +- * highlight a different button. Please note, that at the moment only mode 1 +- * highlights are reported this way. That means, when the button highlight +- * has been moved around by some function call, you will receive an event +- * telling you the new button. But when a button gets activated, you have +- * to handle the mode 2 highlighting (that is some different colour the +- * button turns to on activation) in your application. +- */ +-#define DVDNAV_HIGHLIGHT 9 +- +-typedef struct { +- /* highlight mode: 0 - hide, 1 - show, 2 - activate, currently always 1 */ +- int display; +- +- /* FIXME: these fields are currently not set */ +- uint32_t palette; /* The CLUT entries for the highlight palette +- (4-bits per entry -> 4 entries) */ +- uint16_t sx,sy,ex,ey; /* The start/end x,y positions */ +- uint32_t pts; /* Highlight PTS to match with SPU */ +- +- /* button number for the SPU decoder/overlaying engine */ +- uint32_t buttonN; +-} dvdnav_highlight_event_t; +- +- +-/* +- * DVDNAV_SPU_CLUT_CHANGE +- * +- * Inform the SPU decoder/overlaying engine to update its colour lookup table. +- * The CLUT is given as 16 uint32_t's in the buffer. +- */ +-#define DVDNAV_SPU_CLUT_CHANGE 10 +- +-/* +- * DVDNAV_HOP_CHANNEL +- * +- * A non-seamless operation has been performed. Applications can drop all +- * their internal fifo's content, which will speed up the response. +- */ +-#define DVDNAV_HOP_CHANNEL 12 +- +-/* +- * DVDNAV_WAIT +- * +- * We have reached a point in DVD playback, where timing is critical. +- * Player application with internal fifos can introduce state +- * inconsistencies, because libdvdnav is always the fifo's length +- * ahead in the stream compared to what the application sees. +- * Such applications should wait until their fifos are empty +- * when they receive this type of event. +- * Once this is achieved, call dvdnav_skip_wait(). +- */ +-#define DVDNAV_WAIT 13 +diff --git a/xbmc/cores/VideoPlayer/DVDInputStreams/dvdnav/ifo_types.h b/xbmc/cores/VideoPlayer/DVDInputStreams/dvdnav/ifo_types.h +deleted file mode 100644 +index 4191b67922..0000000000 +--- a/xbmc/cores/VideoPlayer/DVDInputStreams/dvdnav/ifo_types.h ++++ /dev/null +@@ -1,754 +0,0 @@ +-/* +- * Copyright (C) 2000, 2001 Björn Englund <d4bjorn@dtek.chalmers.se>, +- * Håkan Hjort <d95hjort@dtek.chalmers.se> +- * +- * This file is part of libdvdread. +- * +- * libdvdread 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 of the License, or +- * (at your option) any later version. +- * +- * libdvdread 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 libdvdread; if not, write to the Free Software Foundation, Inc., +- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +- */ +- +-#pragma once +- +-//#include <inttypes.h> +-#include "dvd_reader.h" +- +- +-#undef ATTRIBUTE_PACKED +- +-#if defined(__GNUC__) +-#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95) +-#if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) && !defined(__clang__) +-#define ATTRIBUTE_PACKED __attribute__((packed, gcc_struct)) +-#else +-#define ATTRIBUTE_PACKED __attribute__((packed)) +-#endif +-#define PRAGMA_PACK 0 +-#endif +-#endif +- +-#if !defined(ATTRIBUTE_PACKED) +-#define ATTRIBUTE_PACKED +-#define PRAGMA_PACK 1 +-#endif +- +-#if PRAGMA_PACK +-#pragma pack(1) +-#endif +- +- +-/** +- * Common +- * +- * The following structures are used in both the VMGI and VTSI. +- */ +- +- +-/** +- * DVD Time Information. +- */ +-typedef struct { +- uint8_t hour; +- uint8_t minute; +- uint8_t second; +- uint8_t frame_u; /* The two high bits are the frame rate. */ +-} ATTRIBUTE_PACKED dvd_time_t; +- +-/** +- * Type to store per-command data. +- */ +-typedef struct { +- uint8_t bytes[8]; +-} ATTRIBUTE_PACKED vm_cmd_t; +-#define COMMAND_DATA_SIZE 8U +- +- +-/** +- * Video Attributes. +- */ +-typedef struct { +- unsigned char mpeg_version : 2; +- unsigned char video_format : 2; +- unsigned char display_aspect_ratio : 2; +- unsigned char permitted_df : 2; +- +- unsigned char line21_cc_1 : 1; +- unsigned char line21_cc_2 : 1; +- unsigned char unknown1 : 1; +- unsigned char bit_rate : 1; +- +- unsigned char picture_size : 2; +- unsigned char letterboxed : 1; +- unsigned char film_mode : 1; +-} ATTRIBUTE_PACKED video_attr_t; +- +-/** +- * Audio Attributes. +- */ +-typedef struct { +- unsigned char audio_format : 3; +- unsigned char multichannel_extension : 1; +- unsigned char lang_type : 2; +- unsigned char application_mode : 2; +- +- unsigned char quantization : 2; +- unsigned char sample_frequency : 2; +- unsigned char unknown1 : 1; +- unsigned char channels : 3; +- uint16_t lang_code; +- uint8_t lang_extension; +- uint8_t code_extension; +- uint8_t unknown3; +- union { +- struct ATTRIBUTE_PACKED { +- unsigned char unknown4 : 1; +- unsigned char channel_assignment : 3; +- unsigned char version : 2; +- unsigned char mc_intro : 1; /* probably 0: true, 1:false */ +- unsigned char mode : 1; /* Karaoke mode 0: solo 1: duet */ +- } karaoke; +- struct ATTRIBUTE_PACKED { +- unsigned char unknown5 : 4; +- unsigned char dolby_encoded : 1; /* suitable for surround decoding */ +- unsigned char unknown6 : 3; +- } surround; +- } ATTRIBUTE_PACKED app_info; +-} ATTRIBUTE_PACKED audio_attr_t; +- +- +-/** +- * MultiChannel Extension +- */ +-typedef struct { +- unsigned char zero1 : 7; +- unsigned char ach0_gme : 1; +- +- unsigned char zero2 : 7; +- unsigned char ach1_gme : 1; +- +- unsigned char zero3 : 4; +- unsigned char ach2_gv1e : 1; +- unsigned char ach2_gv2e : 1; +- unsigned char ach2_gm1e : 1; +- unsigned char ach2_gm2e : 1; +- +- unsigned char zero4 : 4; +- unsigned char ach3_gv1e : 1; +- unsigned char ach3_gv2e : 1; +- unsigned char ach3_gmAe : 1; +- unsigned char ach3_se2e : 1; +- +- unsigned char zero5 : 4; +- unsigned char ach4_gv1e : 1; +- unsigned char ach4_gv2e : 1; +- unsigned char ach4_gmBe : 1; +- unsigned char ach4_seBe : 1; +- uint8_t zero6[19]; +-} ATTRIBUTE_PACKED multichannel_ext_t; +- +- +-/** +- * Subpicture Attributes. +- */ +-typedef struct { +- /* +- * type: 0 not specified +- * 1 language +- * 2 other +- * coding mode: 0 run length +- * 1 extended +- * 2 other +- * language: indicates language if type == 1 +- * lang extension: if type == 1 contains the lang extension +- */ +- unsigned char code_mode : 3; +- unsigned char zero1 : 3; +- unsigned char type : 2; +- uint8_t zero2; +- uint16_t lang_code; +- uint8_t lang_extension; +- uint8_t code_extension; +-} ATTRIBUTE_PACKED subp_attr_t; +- +- +- +-/** +- * PGC Command Table. +- */ +-typedef struct { +- uint16_t nr_of_pre; +- uint16_t nr_of_post; +- uint16_t nr_of_cell; +- uint16_t last_byte; +- vm_cmd_t *pre_cmds; +- vm_cmd_t *post_cmds; +- vm_cmd_t *cell_cmds; +-} ATTRIBUTE_PACKED pgc_command_tbl_t; +-#define PGC_COMMAND_TBL_SIZE 8U +- +-/** +- * PGC Program Map +- */ +-typedef uint8_t pgc_program_map_t; +- +-/** +- * Cell Playback Information. +- */ +-typedef struct { +- unsigned char block_mode : 2; +- unsigned char block_type : 2; +- unsigned char seamless_play : 1; +- unsigned char interleaved : 1; +- unsigned char stc_discontinuity : 1; +- unsigned char seamless_angle : 1; +- unsigned char zero_1 : 1; +- unsigned char playback_mode : 1; /**< When set, enter StillMode after each VOBU */ +- unsigned char restricted : 1; /**< ?? drop out of fastforward? */ +- unsigned char cell_type : 5; /** for karaoke, reserved otherwise */ +- uint8_t still_time; +- uint8_t cell_cmd_nr; +- dvd_time_t playback_time; +- uint32_t first_sector; +- uint32_t first_ilvu_end_sector; +- uint32_t last_vobu_start_sector; +- uint32_t last_sector; +-} ATTRIBUTE_PACKED cell_playback_t; +- +-#define BLOCK_TYPE_NONE 0x0 +-#define BLOCK_TYPE_ANGLE_BLOCK 0x1 +- +-#define BLOCK_MODE_NOT_IN_BLOCK 0x0 +-#define BLOCK_MODE_FIRST_CELL 0x1 +-#define BLOCK_MODE_IN_BLOCK 0x2 +-#define BLOCK_MODE_LAST_CELL 0x3 +- +-/** +- * Cell Position Information. +- */ +-typedef struct { +- uint16_t vob_id_nr; +- uint8_t zero_1; +- uint8_t cell_nr; +-} ATTRIBUTE_PACKED cell_position_t; +- +-/** +- * User Operations. +- */ +-typedef struct { +- unsigned char zero : 7; /* 25-31 */ +- unsigned char video_pres_mode_change : 1; /* 24 */ +- +- unsigned char karaoke_audio_pres_mode_change : 1; /* 23 */ +- unsigned char angle_change : 1; +- unsigned char subpic_stream_change : 1; +- unsigned char audio_stream_change : 1; +- unsigned char pause_on : 1; +- unsigned char still_off : 1; +- unsigned char button_select_or_activate : 1; +- unsigned char resume : 1; /* 16 */ +- +- unsigned char chapter_menu_call : 1; /* 15 */ +- unsigned char angle_menu_call : 1; +- unsigned char audio_menu_call : 1; +- unsigned char subpic_menu_call : 1; +- unsigned char root_menu_call : 1; +- unsigned char title_menu_call : 1; +- unsigned char backward_scan : 1; +- unsigned char forward_scan : 1; /* 8 */ +- +- unsigned char next_pg_search : 1; /* 7 */ +- unsigned char prev_or_top_pg_search : 1; +- unsigned char time_or_chapter_search : 1; +- unsigned char go_up : 1; +- unsigned char stop : 1; +- unsigned char title_play : 1; +- unsigned char chapter_search_or_play : 1; +- unsigned char title_or_time_play : 1; /* 0 */ +-} ATTRIBUTE_PACKED user_ops_t; +- +-/** +- * Program Chain Information. +- */ +-typedef struct { +- uint16_t zero_1; +- uint8_t nr_of_programs; +- uint8_t nr_of_cells; +- dvd_time_t playback_time; +- user_ops_t prohibited_ops; +- uint16_t audio_control[8]; /* New type? */ +- uint32_t subp_control[32]; /* New type? */ +- uint16_t next_pgc_nr; +- uint16_t prev_pgc_nr; +- uint16_t goup_pgc_nr; +- uint8_t pg_playback_mode; +- uint8_t still_time; +- uint32_t palette[16]; /* New type struct {zero_1, Y, Cr, Cb} ? */ +- uint16_t command_tbl_offset; +- uint16_t program_map_offset; +- uint16_t cell_playback_offset; +- uint16_t cell_position_offset; +- pgc_command_tbl_t *command_tbl; +- pgc_program_map_t *program_map; +- cell_playback_t *cell_playback; +- cell_position_t *cell_position; +- int ref_count; +-} ATTRIBUTE_PACKED pgc_t; +-#define PGC_SIZE 236U +- +-/** +- * Program Chain Information Search Pointer. +- */ +-typedef struct { +- uint8_t entry_id; +- unsigned char block_mode : 2; +- unsigned char block_type : 2; +- unsigned char zero_1 : 4; +- uint16_t ptl_id_mask; +- uint32_t pgc_start_byte; +- pgc_t *pgc; +-} ATTRIBUTE_PACKED pgci_srp_t; +-#define PGCI_SRP_SIZE 8U +- +-/** +- * Program Chain Information Table. +- */ +-typedef struct { +- uint16_t nr_of_pgci_srp; +- uint16_t zero_1; +- uint32_t last_byte; +- pgci_srp_t *pgci_srp; +- int ref_count; +-} ATTRIBUTE_PACKED pgcit_t; +-#define PGCIT_SIZE 8U +- +-/** +- * Menu PGCI Language Unit. +- */ +-typedef struct { +- uint16_t lang_code; +- uint8_t lang_extension; +- uint8_t exists; +- uint32_t lang_start_byte; +- pgcit_t *pgcit; +-} ATTRIBUTE_PACKED pgci_lu_t; +-#define PGCI_LU_SIZE 8U +- +-/** +- * Menu PGCI Unit Table. +- */ +-typedef struct { +- uint16_t nr_of_lus; +- uint16_t zero_1; +- uint32_t last_byte; +- pgci_lu_t *lu; +-} ATTRIBUTE_PACKED pgci_ut_t; +-#define PGCI_UT_SIZE 8U +- +-/** +- * Cell Address Information. +- */ +-typedef struct { +- uint16_t vob_id; +- uint8_t cell_id; +- uint8_t zero_1; +- uint32_t start_sector; +- uint32_t last_sector; +-} ATTRIBUTE_PACKED cell_adr_t; +- +-/** +- * Cell Address Table. +- */ +-typedef struct { +- uint16_t nr_of_vobs; /* VOBs */ +- uint16_t zero_1; +- uint32_t last_byte; +- cell_adr_t *cell_adr_table; /* No explicit size given. */ +-} ATTRIBUTE_PACKED c_adt_t; +-#define C_ADT_SIZE 8U +- +-/** +- * VOBU Address Map. +- */ +-typedef struct { +- uint32_t last_byte; +- uint32_t *vobu_start_sectors; +-} ATTRIBUTE_PACKED vobu_admap_t; +-#define VOBU_ADMAP_SIZE 4U +- +- +- +- +-/** +- * VMGI +- * +- * The following structures relate to the Video Manager. +- */ +- +-/** +- * Video Manager Information Management Table. +- */ +-typedef struct { +- char vmg_identifier[12]; +- uint32_t vmg_last_sector; +- uint8_t zero_1[12]; +- uint32_t vmgi_last_sector; +- uint8_t zero_2; +- uint8_t specification_version; +- uint32_t vmg_category; +- uint16_t vmg_nr_of_volumes; +- uint16_t vmg_this_volume_nr; +- uint8_t disc_side; +- uint8_t zero_3[19]; +- uint16_t vmg_nr_of_title_sets; /* Number of VTSs. */ +- char provider_identifier[32]; +- uint64_t vmg_pos_code; +- uint8_t zero_4[24]; +- uint32_t vmgi_last_byte; +- uint32_t first_play_pgc; +- uint8_t zero_5[56]; +- uint32_t vmgm_vobs; /* sector */ +- uint32_t tt_srpt; /* sector */ +- uint32_t vmgm_pgci_ut; /* sector */ +- uint32_t ptl_mait; /* sector */ +- uint32_t vts_atrt; /* sector */ +- uint32_t txtdt_mgi; /* sector */ +- uint32_t vmgm_c_adt; /* sector */ +- uint32_t vmgm_vobu_admap; /* sector */ +- uint8_t zero_6[32]; +- +- video_attr_t vmgm_video_attr; +- uint8_t zero_7; +- uint8_t nr_of_vmgm_audio_streams; /* should be 0 or 1 */ +- audio_attr_t vmgm_audio_attr; +- audio_attr_t zero_8[7]; +- uint8_t zero_9[17]; +- uint8_t nr_of_vmgm_subp_streams; /* should be 0 or 1 */ +- subp_attr_t vmgm_subp_attr; +- subp_attr_t zero_10[27]; /* XXX: how much 'padding' here? */ +-} ATTRIBUTE_PACKED vmgi_mat_t; +- +-typedef struct { +- unsigned char zero_1 : 1; +- unsigned char multi_or_random_pgc_title : 1; /* 0: one sequential pgc title */ +- unsigned char jlc_exists_in_cell_cmd : 1; +- unsigned char jlc_exists_in_prepost_cmd : 1; +- unsigned char jlc_exists_in_button_cmd : 1; +- unsigned char jlc_exists_in_tt_dom : 1; +- unsigned char chapter_search_or_play : 1; /* UOP 1 */ +- unsigned char title_or_time_play : 1; /* UOP 0 */ +-} ATTRIBUTE_PACKED playback_type_t; +- +-/** +- * Title Information. +- */ +-typedef struct { +- playback_type_t pb_ty; +- uint8_t nr_of_angles; +- uint16_t nr_of_ptts; +- uint16_t parental_id; +- uint8_t title_set_nr; +- uint8_t vts_ttn; +- uint32_t title_set_sector; +-} ATTRIBUTE_PACKED title_info_t; +- +-/** +- * PartOfTitle Search Pointer Table. +- */ +-typedef struct { +- uint16_t nr_of_srpts; +- uint16_t zero_1; +- uint32_t last_byte; +- title_info_t *title; +-} ATTRIBUTE_PACKED tt_srpt_t; +-#define TT_SRPT_SIZE 8U +- +- +-/** +- * Parental Management Information Unit Table. +- * Level 1 (US: G), ..., 7 (US: NC-17), 8 +- */ +-#define PTL_MAIT_NUM_LEVEL 8 +-typedef uint16_t pf_level_t[PTL_MAIT_NUM_LEVEL]; +- +-/** +- * Parental Management Information Unit Table. +- */ +-typedef struct { +- uint16_t country_code; +- uint16_t zero_1; +- uint16_t pf_ptl_mai_start_byte; +- uint16_t zero_2; +- pf_level_t *pf_ptl_mai; /* table of (nr_of_vtss + 1), video_ts is first */ +-} ATTRIBUTE_PACKED ptl_mait_country_t; +-#define PTL_MAIT_COUNTRY_SIZE 8U +- +-/** +- * Parental Management Information Table. +- */ +-typedef struct { +- uint16_t nr_of_countries; +- uint16_t nr_of_vtss; +- uint32_t last_byte; +- ptl_mait_country_t *countries; +-} ATTRIBUTE_PACKED ptl_mait_t; +-#define PTL_MAIT_SIZE 8U +- +-/** +- * Video Title Set Attributes. +- */ +-typedef struct { +- uint32_t last_byte; +- uint32_t vts_cat; +- +- video_attr_t vtsm_vobs_attr; +- uint8_t zero_1; +- uint8_t nr_of_vtsm_audio_streams; /* should be 0 or 1 */ +- audio_attr_t vtsm_audio_attr; +- audio_attr_t zero_2[7]; +- uint8_t zero_3[16]; +- uint8_t zero_4; +- uint8_t nr_of_vtsm_subp_streams; /* should be 0 or 1 */ +- subp_attr_t vtsm_subp_attr; +- subp_attr_t zero_5[27]; +- +- uint8_t zero_6[2]; +- +- video_attr_t vtstt_vobs_video_attr; +- uint8_t zero_7; +- uint8_t nr_of_vtstt_audio_streams; +- audio_attr_t vtstt_audio_attr[8]; +- uint8_t zero_8[16]; +- uint8_t zero_9; +- uint8_t nr_of_vtstt_subp_streams; +- subp_attr_t vtstt_subp_attr[32]; +-} ATTRIBUTE_PACKED vts_attributes_t; +-#define VTS_ATTRIBUTES_SIZE 542U +-#define VTS_ATTRIBUTES_MIN_SIZE 356U +- +-/** +- * Video Title Set Attribute Table. +- */ +-typedef struct { +- uint16_t nr_of_vtss; +- uint16_t zero_1; +- uint32_t last_byte; +- vts_attributes_t *vts; +- uint32_t *vts_atrt_offsets; /* offsets table for each vts_attributes */ +-} ATTRIBUTE_PACKED vts_atrt_t; +-#define VTS_ATRT_SIZE 8U +- +-/** +- * Text Data. (Incomplete) +- */ +-typedef struct { +- uint32_t last_byte; /* offsets are relative here */ +- uint16_t offsets[100]; /* == nr_of_srpts + 1 (first is disc title) */ +-#if 0 +- uint16_t unknown; /* 0x48 ?? 0x48 words (16bit) info following */ +- uint16_t zero_1; +- +- uint8_t type_of_info; /* ?? 01 == disc, 02 == Title, 04 == Title part */ +- uint8_t unknown1; +- uint8_t unknown2; +- uint8_t unknown3; +- uint8_t unknown4; /* ?? always 0x30 language?, text format? */ +- uint8_t unknown5; +- uint16_t offset; /* from first */ +- +- char text[12]; /* ended by 0x09 */ +-#endif +-} ATTRIBUTE_PACKED txtdt_t; +- +-/** +- * Text Data Language Unit. (Incomplete) +- */ +-typedef struct { +- uint16_t lang_code; +- uint8_t zero_1; +- uint8_t +- char_set; /* 0x00 reserved Unicode, 0x01 ISO 646, 0x10 JIS Roman & JIS Kanji, 0x11 ISO 8859-1, 0x12 Shift JIS Kanji */ +- uint32_t txtdt_start_byte; /* prt, rel start of vmg_txtdt_mgi */ +- txtdt_t *txtdt; +-} ATTRIBUTE_PACKED txtdt_lu_t; +-#define TXTDT_LU_SIZE 8U +- +-/** +- * Text Data Manager Information. (Incomplete) +- */ +-typedef struct { +- char disc_name[12]; +- uint16_t unknown1; +- uint16_t nr_of_language_units; +- uint32_t last_byte; +- txtdt_lu_t *lu; +-} ATTRIBUTE_PACKED txtdt_mgi_t; +-#define TXTDT_MGI_SIZE 20U +- +- +-/** +- * VTS +- * +- * Structures relating to the Video Title Set (VTS). +- */ +- +-/** +- * Video Title Set Information Management Table. +- */ +-typedef struct { +- char vts_identifier[12]; +- uint32_t vts_last_sector; +- uint8_t zero_1[12]; +- uint32_t vtsi_last_sector; +- uint8_t zero_2; +- uint8_t specification_version; +- uint32_t vts_category; +- uint16_t zero_3; +- uint16_t zero_4; +- uint8_t zero_5; +- uint8_t zero_6[19]; +- uint16_t zero_7; +- uint8_t zero_8[32]; +- uint64_t zero_9; +- uint8_t zero_10[24]; +- uint32_t vtsi_last_byte; +- uint32_t zero_11; +- uint8_t zero_12[56]; +- uint32_t vtsm_vobs; /* sector */ +- uint32_t vtstt_vobs; /* sector */ +- uint32_t vts_ptt_srpt; /* sector */ +- uint32_t vts_pgcit; /* sector */ +- uint32_t vtsm_pgci_ut; /* sector */ +- uint32_t vts_tmapt; /* sector */ +- uint32_t vtsm_c_adt; /* sector */ +- uint32_t vtsm_vobu_admap; /* sector */ +- uint32_t vts_c_adt; /* sector */ +- uint32_t vts_vobu_admap; /* sector */ +- uint8_t zero_13[24]; +- +- video_attr_t vtsm_video_attr; +- uint8_t zero_14; +- uint8_t nr_of_vtsm_audio_streams; /* should be 0 or 1 */ +- audio_attr_t vtsm_audio_attr; +- audio_attr_t zero_15[7]; +- uint8_t zero_16[17]; +- uint8_t nr_of_vtsm_subp_streams; /* should be 0 or 1 */ +- subp_attr_t vtsm_subp_attr; +- subp_attr_t zero_17[27]; +- uint8_t zero_18[2]; +- +- video_attr_t vts_video_attr; +- uint8_t zero_19; +- uint8_t nr_of_vts_audio_streams; +- audio_attr_t vts_audio_attr[8]; +- uint8_t zero_20[17]; +- uint8_t nr_of_vts_subp_streams; +- subp_attr_t vts_subp_attr[32]; +- uint16_t zero_21; +- multichannel_ext_t vts_mu_audio_attr[8]; +- /* XXX: how much 'padding' here, if any? */ +-} ATTRIBUTE_PACKED vtsi_mat_t; +- +-/** +- * PartOfTitle Unit Information. +- */ +-typedef struct { +- uint16_t pgcn; +- uint16_t pgn; +-} ATTRIBUTE_PACKED ptt_info_t; +- +-/** +- * PartOfTitle Information. +- */ +-typedef struct { +- uint16_t nr_of_ptts; +- ptt_info_t *ptt; +-} ATTRIBUTE_PACKED ttu_t; +- +-/** +- * PartOfTitle Search Pointer Table. +- */ +-typedef struct { +- uint16_t nr_of_srpts; +- uint16_t zero_1; +- uint32_t last_byte; +- ttu_t *title; +- uint32_t *ttu_offset; /* offset table for each ttu */ +-} ATTRIBUTE_PACKED vts_ptt_srpt_t; +-#define VTS_PTT_SRPT_SIZE 8U +- +- +-/** +- * Time Map Entry. +- */ +-/* Should this be bit field at all or just the uint32_t? */ +-typedef uint32_t map_ent_t; +- +-/** +- * Time Map. +- */ +-typedef struct { +- uint8_t tmu; /* Time unit, in seconds */ +- uint8_t zero_1; +- uint16_t nr_of_entries; +- map_ent_t *map_ent; +-} ATTRIBUTE_PACKED vts_tmap_t; +-#define VTS_TMAP_SIZE 4U +- +-/** +- * Time Map Table. +- */ +-typedef struct { +- uint16_t nr_of_tmaps; +- uint16_t zero_1; +- uint32_t last_byte; +- vts_tmap_t *tmap; +- uint32_t *tmap_offset; /* offset table for each tmap */ +-} ATTRIBUTE_PACKED vts_tmapt_t; +-#define VTS_TMAPT_SIZE 8U +- +- +-#if PRAGMA_PACK +-#pragma pack() +-#endif +- +- +-/** +- * The following structure defines an IFO file. The structure is divided into +- * two parts, the VMGI, or Video Manager Information, which is read from the +- * VIDEO_TS.[IFO,BUP] file, and the VTSI, or Video Title Set Information, which +- * is read in from the VTS_XX_0.[IFO,BUP] files. +- */ +-typedef struct { +- /* VMGI */ +- vmgi_mat_t *vmgi_mat; +- tt_srpt_t *tt_srpt; +- pgc_t *first_play_pgc; +- ptl_mait_t *ptl_mait; +- vts_atrt_t *vts_atrt; +- txtdt_mgi_t *txtdt_mgi; +- +- /* Common */ +- pgci_ut_t *pgci_ut; +- c_adt_t *menu_c_adt; +- vobu_admap_t *menu_vobu_admap; +- +- /* VTSI */ +- vtsi_mat_t *vtsi_mat; +- vts_ptt_srpt_t *vts_ptt_srpt; +- pgcit_t *vts_pgcit; +- vts_tmapt_t *vts_tmapt; +- c_adt_t *vts_c_adt; +- vobu_admap_t *vts_vobu_admap; +-} ifo_handle_t; +- +diff --git a/xbmc/cores/VideoPlayer/DVDInputStreams/dvdnav/nav_types.h b/xbmc/cores/VideoPlayer/DVDInputStreams/dvdnav/nav_types.h +deleted file mode 100644 +index aa33f23d4d..0000000000 +--- a/xbmc/cores/VideoPlayer/DVDInputStreams/dvdnav/nav_types.h ++++ /dev/null +@@ -1,258 +0,0 @@ +-/* +- * Copyright (C) 2000, 2001, 2002 Håkan Hjort <d95hjort@dtek.chalmers.se> +- * +- * SPDX-License-Identifier: GPL-2.0-only +- * See LICENSES/README.md for more information. +- * +- * The data structures in this file should represent the layout of the +- * pci and dsi packets as they are stored in the stream. Information +- * found by reading the source to VOBDUMP is the base for the structure +- * and names of these data types. +- * +- * VOBDUMP: a program for examining DVD .VOB files. +- * Copyright 1998, 1999 Eric Smith <eric@brouhaha.com> +- */ +- +-#pragma once +- +-//#include <inttypes.h> +-#include "ifo_types.h" /* only dvd_time_t, vm_cmd_t and user_ops_t */ +- +- +-#undef ATTRIBUTE_PACKED +-#undef PRAGMA_PACK_BEGIN +-#undef PRAGMA_PACK_END +- +-#if defined(__GNUC__) +-#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95) +-#define ATTRIBUTE_PACKED __attribute__ ((packed)) +-#define PRAGMA_PACK 0 +-#endif +-#endif +- +-#if !defined(ATTRIBUTE_PACKED) +-#define ATTRIBUTE_PACKED +-#define PRAGMA_PACK 1 +-#endif +- +- +-/* The length including the substream id byte. */ +-#define PCI_BYTES 0x3d4 +-#define DSI_BYTES 0x3fa +- +-#define PS2_PCI_SUBSTREAM_ID 0x00 +-#define PS2_DSI_SUBSTREAM_ID 0x01 +- +-/* Remove this */ +-#define DSI_START_BYTE 1031 +- +- +-#if PRAGMA_PACK +-#pragma pack(1) +-#endif +- +- +-/** +- * PCI General Information +- */ +-typedef struct { +- uint32_t nv_pck_lbn; /**< sector address of this nav pack */ +- uint16_t vobu_cat; /**< 'category' of vobu */ +- uint16_t zero1; /**< reserved */ +- user_ops_t vobu_uop_ctl; /**< UOP of vobu */ +- uint32_t vobu_s_ptm; /**< start presentation time of vobu */ +- uint32_t vobu_e_ptm; /**< end presentation time of vobu */ +- uint32_t vobu_se_e_ptm; /**< end ptm of sequence end in vobu */ +- dvd_time_t e_eltm; /**< Cell elapsed time */ +- char vobu_isrc[32]; +-} ATTRIBUTE_PACKED pci_gi_t; +- +-/** +- * Non Seamless Angle Information +- */ +-typedef struct { +- uint32_t nsml_agl_dsta[9]; /**< address of destination vobu in AGL_C#n */ +-} ATTRIBUTE_PACKED nsml_agli_t; +- +-/** +- * Highlight General Information +- * +- * For btngrX_dsp_ty the bits have the following meaning: +- * 000b: normal 4/3 only buttons +- * XX1b: wide (16/9) buttons +- * X1Xb: letterbox buttons +- * 1XXb: pan&scan buttons +- */ +-typedef struct { +- uint16_t hli_ss; /**< status, only low 2 bits 0: no buttons, 1: different 2: equal 3: equal except for button cmds */ +- uint32_t hli_s_ptm; /**< start ptm of hli */ +- uint32_t hli_e_ptm; /**< end ptm of hli */ +- uint32_t btn_se_e_ptm; /**< end ptm of button select */ +- unsigned int zero1 : 2; /**< reserved */ +- unsigned int btngr_ns : 2; /**< number of button groups 1, 2 or 3 with 36/18/12 buttons */ +- unsigned int zero2 : 1; /**< reserved */ +- unsigned int btngr1_dsp_ty : 3; /**< display type of subpic stream for button group 1 */ +- unsigned int zero3 : 1; /**< reserved */ +- unsigned int btngr2_dsp_ty : 3; /**< display type of subpic stream for button group 2 */ +- unsigned int zero4 : 1; /**< reserved */ +- unsigned int btngr3_dsp_ty : 3; /**< display type of subpic stream for button group 3 */ +- uint8_t btn_ofn; /**< button offset number range 0-255 */ +- uint8_t btn_ns; /**< number of valid buttons <= 36/18/12 (low 6 bits) */ +- uint8_t nsl_btn_ns; /**< number of buttons selectable by U_BTNNi (low 6 bits) nsl_btn_ns <= btn_ns */ +- uint8_t zero5; /**< reserved */ +- uint8_t fosl_btnn; /**< forcedly selected button (low 6 bits) */ +- uint8_t foac_btnn; /**< forcedly activated button (low 6 bits) */ +-} ATTRIBUTE_PACKED hl_gi_t; +- +- +-/** +- * Button Color Information Table +- * Each entry being a 32bit word that contains the color indexes and alpha +- * values to use. They are all represented by 4 bit number and stored +- * like this [Ci3, Ci2, Ci1, Ci0, A3, A2, A1, A0]. The actual palette +- * that the indexes reference is in the PGC. +- * @TODO split the uint32_t into a struct +- */ +-typedef struct { +- uint32_t btn_coli[3][2]; /**< [button color number-1][select:0/action:1] */ +-} ATTRIBUTE_PACKED btn_colit_t; +- +-/** +- * Button Information +- * +- * NOTE: I've had to change the structure from the disk layout to get +- * the packing to work with Sun's Forte C compiler. +- * The 4 and 7 bytes are 'rotated' was: ABC DEF GHIJ is: ABCG DEFH IJ +- */ +-typedef struct { +- unsigned int btn_coln : 2; /**< button color number */ +- unsigned int x_start : 10; /**< x start offset within the overlay */ +- unsigned int zero1 : 2; /**< reserved */ +- unsigned int x_end : 10; /**< x end offset within the overlay */ +- +- unsigned int auto_action_mode : 2; /**< 0: no, 1: activated if selected */ +- unsigned int y_start : 10; /**< y start offset within the overlay */ +- unsigned int zero2 : 2; /**< reserved */ +- unsigned int y_end : 10; /**< y end offset within the overlay */ +- +- unsigned int zero3 : 2; /**< reserved */ +- unsigned int up : 6; /**< button index when pressing up */ +- unsigned int zero4 : 2; /**< reserved */ +- unsigned int down : 6; /**< button index when pressing down */ +- unsigned int zero5 : 2; /**< reserved */ +- unsigned int left : 6; /**< button index when pressing left */ +- unsigned int zero6 : 2; /**< reserved */ +- unsigned int right : 6; /**< button index when pressing right */ +- vm_cmd_t cmd; +-} ATTRIBUTE_PACKED btni_t; +- +-/** +- * Highlight Information +- */ +-typedef struct { +- hl_gi_t hl_gi; +- btn_colit_t btn_colit; +- btni_t btnit[36]; +-} ATTRIBUTE_PACKED hli_t; +- +-/** +- * PCI packet +- */ +-typedef struct { +- pci_gi_t pci_gi; +- nsml_agli_t nsml_agli; +- hli_t hli; +- uint8_t zero1[189]; +-} ATTRIBUTE_PACKED pci_t; +- +- +- +- +-/** +- * DSI General Information +- */ +-typedef struct { +- uint32_t nv_pck_scr; +- uint32_t nv_pck_lbn; /**< sector address of this nav pack */ +- uint32_t vobu_ea; /**< end address of this VOBU */ +- uint32_t vobu_1stref_ea; /**< end address of the 1st reference image */ +- uint32_t vobu_2ndref_ea; /**< end address of the 2nd reference image */ +- uint32_t vobu_3rdref_ea; /**< end address of the 3rd reference image */ +- uint16_t vobu_vob_idn; /**< VOB Id number that this VOBU is part of */ +- uint8_t zero1; /**< reserved */ +- uint8_t vobu_c_idn; /**< Cell Id number that this VOBU is part of */ +- dvd_time_t c_eltm; /**< Cell elapsed time */ +-} ATTRIBUTE_PACKED dsi_gi_t; +- +-/** +- * Seamless Playback Information +- */ +-typedef struct { +- uint16_t category; /**< 'category' of seamless VOBU */ +- uint32_t ilvu_ea; /**< end address of interleaved Unit */ +- uint32_t ilvu_sa; /**< start address of next interleaved unit */ +- uint16_t size; /**< size of next interleaved unit */ +- uint32_t vob_v_s_s_ptm; /**< video start ptm in vob */ +- uint32_t vob_v_e_e_ptm; /**< video end ptm in vob */ +- struct { +- uint32_t stp_ptm1; +- uint32_t stp_ptm2; +- uint32_t gap_len1; +- uint32_t gap_len2; +- } vob_a[8]; +-} ATTRIBUTE_PACKED sml_pbi_t; +- +-/** +- * Seamless Angle Information for one angle +- */ +-typedef struct { +- uint32_t address; /**< offset to next ILVU, high bit is before/after */ +- uint16_t size; /**< byte size of the ILVU pointed to by address */ +-} ATTRIBUTE_PACKED sml_agl_data_t; +- +-/** +- * Seamless Angle Information +- */ +-typedef struct { +- sml_agl_data_t data[9]; +-} ATTRIBUTE_PACKED sml_agli_t; +- +-/** +- * VOBU Search Information +- */ +-typedef struct { +- uint32_t next_video; /**< Next vobu that contains video */ +- uint32_t fwda[19]; /**< Forwards, time */ +- uint32_t next_vobu; +- uint32_t prev_vobu; +- uint32_t bwda[19]; /**< Backwards, time */ +- uint32_t prev_video; +-} ATTRIBUTE_PACKED vobu_sri_t; +- +-#define SRI_END_OF_CELL 0x3fffffff +- +-/** +- * Synchronous Information +- */ +-typedef struct { +- uint16_t a_synca[8]; /**< offset to first audio packet for this VOBU */ +- uint32_t sp_synca[32]; /**< offset to first subpicture packet */ +-} ATTRIBUTE_PACKED synci_t; +- +-/** +- * DSI packet +- */ +-typedef struct { +- dsi_gi_t dsi_gi; +- sml_pbi_t sml_pbi; +- sml_agli_t sml_agli; +- vobu_sri_t vobu_sri; +- synci_t synci; +- uint8_t zero1[471]; +-} ATTRIBUTE_PACKED dsi_t; +- +- +-#if PRAGMA_PACK +-#pragma pack() +-#endif +- +diff --git a/xbmc/cores/VideoPlayer/DVDInputStreams/dvdnav/version.h b/xbmc/cores/VideoPlayer/DVDInputStreams/dvdnav/version.h +deleted file mode 100644 +index dced5e766a..0000000000 +--- a/xbmc/cores/VideoPlayer/DVDInputStreams/dvdnav/version.h ++++ /dev/null +@@ -1,29 +0,0 @@ +-/* +-* This file is part of libdvdnav, a DVD navigation library. +-* +- * This program is free software; you can redistribute it and/or modify it +- * under the terms of the GNU Lesser General Public License as published by +- * the Free Software Foundation; either version 2.1 of the License, 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 Lesser General Public License for more details. +- * +- * You should have received a copy of the GNU Lesser General Public License +- * along with this program; if not, write to the Free Software Foundation, +- * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. +-*/ +-#pragma once +- +-#define DVDNAV_VERSION_CODE(major, minor, micro) (((major)*10000) + ((minor)*100) + ((micro)*1)) +- +-#define DVDNAV_VERSION_MAJOR 6 +-#define DVDNAV_VERSION_MINOR 1 +-#define DVDNAV_VERSION_MICRO 1 +- +-#define DVDNAV_VERSION_STRING "6.1.1" +- +-#define DVDNAV_VERSION \ +- DVDNAV_VERSION_CODE(DVDNAV_VERSION_MAJOR, DVDNAV_VERSION_MINOR, DVDNAV_VERSION_MICRO) +-- +2.35.1 + + +From d5d87a09d04f427826387f980ffaeeab737c2d78 Mon Sep 17 00:00:00 2001 +From: fuzzard <fuzzard@kodi.tv> +Date: Mon, 27 Jun 2022 19:48:48 +1000 +Subject: [PATCH 2/9] WIP!: allow system libs for dvdread/nav/css + +--- + CMakeLists.txt | 1 + + cmake/modules/FindLibDvd.cmake | 13 -- + cmake/modules/FindLibDvdCSS.cmake | 124 ++++++++------- + cmake/modules/FindLibDvdNav.cmake | 140 +++++++++-------- + cmake/modules/FindLibDvdRead.cmake | 144 ++++++++++-------- + .../DVDInputStreamNavigator.cpp | 4 +- + .../DVDInputStreams/DVDInputStreamNavigator.h | 8 +- + 7 files changed, 233 insertions(+), 201 deletions(-) + +diff --git a/CMakeLists.txt b/CMakeLists.txt +index 19881e4708..71660392e5 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -70,6 +70,7 @@ option(ENABLE_INTERNAL_FFMPEG "Enable internal ffmpeg?" OFF) + dependent_option(ENABLE_INTERNAL_FLATBUFFERS "Enable internal flatbuffers?") + dependent_option(ENABLE_INTERNAL_FMT "Enable internal fmt?") ++dependent_option(ENABLE_INTERNAL_LIBDVD "Enable internal libdvd* libs?") + dependent_option(ENABLE_INTERNAL_NFS "Enable internal libnfs?") + dependent_option(ENABLE_INTERNAL_PCRE "Enable internal pcre?") + dependent_option(ENABLE_INTERNAL_SPDLOG "Enable internal spdlog?") + dependent_option(ENABLE_INTERNAL_TAGLIB "Enable internal taglib?") +diff --git a/cmake/modules/FindLibDvd.cmake b/cmake/modules/FindLibDvd.cmake +index 6853e84618..91e98d3d46 100644 +--- a/cmake/modules/FindLibDvd.cmake ++++ b/cmake/modules/FindLibDvd.cmake +@@ -7,19 +7,6 @@ unset(FPHSA_NAME_MISMATCHED) + + set(_dvdlibs ${LIBDVDREAD_LIBRARY} ${LIBDVDCSS_LIBRARY}) + +-if(NOT CORE_SYSTEM_NAME MATCHES windows) +- # link a shared dvdnav library that includes the whole archives of dvdread and dvdcss as well +- # the quotes around _dvdlibs are on purpose, since we want to pass a list to the function that will be unpacked automatically +- core_link_library(${LIBDVDNAV_LIBRARY} system/players/VideoPlayer/libdvdnav libdvdnav archives "${_dvdlibs}") +-else() +- set(LIBDVD_TARGET_DIR .) +- if(CORE_SYSTEM_NAME STREQUAL windowsstore) +- set(LIBDVD_TARGET_DIR dlls) +- endif() +- copy_file_to_buildtree(${DEPENDS_PATH}/bin/libdvdnav.dll DIRECTORY ${LIBDVD_TARGET_DIR}) +- add_dependencies(export-files LibDvdNav::LibDvdNav) +-endif() +- + set(LIBDVD_INCLUDE_DIRS ${LIBDVDREAD_INCLUDE_DIR} ${LIBDVDNAV_INCLUDE_DIR}) + set(LIBDVD_LIBRARIES ${LIBDVDNAV_LIBRARY} ${LIBDVDREAD_LIBRARY}) + if(TARGET LibDvdCSS::LibDvdCSS) +diff --git a/cmake/modules/FindLibDvdNav.cmake b/cmake/modules/FindLibDvdNav.cmake +index 681610ea6c..0135aba11e 100644 +--- a/cmake/modules/FindLibDvdNav.cmake ++++ b/cmake/modules/FindLibDvdNav.cmake +@@ -25,82 +25,94 @@ if(NOT TARGET LibDvdNav::LibDvdNav) + + set(MODULE_LC libdvdnav) + +- # We require this due to the odd nature of github URL's compared to our other tarball +- # mirror system. If User sets LIBDVDNAV_URL or libdvdnav_URL, allow get_filename_component in SETUP_BUILD_VARS +- if(LIBDVDNAV_URL OR ${MODULE_LC}_URL) +- if(${MODULE_LC}_URL) +- set(LIBDVDNAV_URL ${${MODULE_LC}_URL}) ++ if(ENABLE_INTERNAL_LIBDVD) ++ ++ # We require this due to the odd nature of github URL's compared to our other tarball ++ # mirror system. If User sets LIBDVDNAV_URL or libdvdnav_URL, allow get_filename_component in SETUP_BUILD_VARS ++ if(LIBDVDNAV_URL OR ${MODULE_LC}_URL) ++ set(LIBDVDNAV_URL_PROVIDED TRUE) + endif() +- set(LIBDVDNAV_URL_PROVIDED TRUE) +- endif() + +- SETUP_BUILD_VARS() ++ SETUP_BUILD_VARS() + +- if(NOT LIBDVDNAV_URL_PROVIDED) +- # override LIBDVDNAV_URL due to tar naming when retrieved from github release +- set(LIBDVDNAV_URL ${LIBDVDNAV_BASE_URL}/archive/${LIBDVDNAV_VER}.tar.gz) +- endif() ++ if(NOT LIBDVDNAV_URL_PROVIDED) ++ # override LIBDVDNAV_URL due to tar naming when retrieved from github release ++ set(LIBDVDNAV_URL ${LIBDVDNAV_BASE_URL}/archive/${LIBDVDNAV_VER}.tar.gz) ++ endif() + +- set(LIBDVDNAV_VERSION ${${MODULE}_VER}) +- +- set(HOST_ARCH ${ARCH}) +- if(CORE_SYSTEM_NAME STREQUAL android) +- if(ARCH STREQUAL arm) +- set(HOST_ARCH arm-linux-androideabi) +- elseif(ARCH STREQUAL aarch64) +- set(HOST_ARCH aarch64-linux-android) +- elseif(ARCH STREQUAL i486-linux) +- set(HOST_ARCH i686-linux-android) +- elseif(ARCH STREQUAL x86_64) +- set(HOST_ARCH x86_64-linux-android) ++ set(LIBDVDNAV_VERSION ${${MODULE}_VER}) ++ ++ set(HOST_ARCH ${ARCH}) ++ if(CORE_SYSTEM_NAME STREQUAL android) ++ if(ARCH STREQUAL arm) ++ set(HOST_ARCH arm-linux-androideabi) ++ elseif(ARCH STREQUAL aarch64) ++ set(HOST_ARCH aarch64-linux-android) ++ elseif(ARCH STREQUAL i486-linux) ++ set(HOST_ARCH i686-linux-android) ++ elseif(ARCH STREQUAL x86_64) ++ set(HOST_ARCH x86_64-linux-android) ++ endif() ++ elseif(CORE_SYSTEM_NAME STREQUAL windowsstore) ++ set(LIBDVD_ADDITIONAL_ARGS "-DCMAKE_SYSTEM_NAME=${CMAKE_SYSTEM_NAME}" "-DCMAKE_SYSTEM_VERSION=${CMAKE_SYSTEM_VERSION}") + endif() +- elseif(CORE_SYSTEM_NAME STREQUAL windowsstore) +- set(LIBDVD_ADDITIONAL_ARGS "-DCMAKE_SYSTEM_NAME=${CMAKE_SYSTEM_NAME}" "-DCMAKE_SYSTEM_VERSION=${CMAKE_SYSTEM_VERSION}") +- endif() + +- string(APPEND LIBDVDNAV_CFLAGS "-D_XBMC") ++ string(APPEND LIBDVDNAV_CFLAGS "-D_XBMC") + +- if(APPLE) +- set(LIBDVDNAV_LDFLAGS "-framework CoreFoundation") +- string(APPEND LIBDVDNAV_CFLAGS " -D__DARWIN__") +- if(NOT CORE_SYSTEM_NAME STREQUAL darwin_embedded) +- string(APPEND LIBDVDNAV_LDFLAGS " -framework IOKit") ++ if(APPLE) ++ set(LIBDVDNAV_LDFLAGS "-framework CoreFoundation") ++ string(APPEND LIBDVDNAV_CFLAGS " -D__DARWIN__") ++ if(NOT CORE_SYSTEM_NAME STREQUAL darwin_embedded) ++ string(APPEND LIBDVDNAV_LDFLAGS " -framework IOKit") ++ endif() + endif() +- endif() + +- if(CORE_SYSTEM_NAME MATCHES windows) +- set(CMAKE_ARGS -DDUMMY_DEFINE=ON +- ${LIBDVD_ADDITIONAL_ARGS}) +- else() ++ if(CORE_SYSTEM_NAME MATCHES windows) ++ set(CMAKE_ARGS -DDUMMY_DEFINE=ON ++ ${LIBDVD_ADDITIONAL_ARGS}) ++ else() ++ ++ string(APPEND LIBDVDNAV_CFLAGS " -I$<TARGET_PROPERTY:LibDvdRead::LibDvdRead,INTERFACE_INCLUDE_DIRECTORIES> $<TARGET_PROPERTY:LibDvdRead::LibDvdRead,INTERFACE_COMPILE_DEFINITIONS>") ++ ++ find_program(AUTORECONF autoreconf REQUIRED) ++ find_program(MAKE_EXECUTABLE make REQUIRED) ++ ++ set(CONFIGURE_COMMAND ${AUTORECONF} -vif ++ COMMAND ac_cv_path_GIT= ./configure ++ --target=${HOST_ARCH} ++ --host=${HOST_ARCH} ++ --enable-static ++ --disable-shared ++ --with-pic ++ --prefix=${DEPENDS_PATH} ++ --libdir=${DEPENDS_PATH}/lib ++ "CC=${CMAKE_C_COMPILER}" ++ "CFLAGS=${CMAKE_C_FLAGS} ${LIBDVDNAV_CFLAGS}" ++ "LDFLAGS=${CMAKE_EXE_LINKER_FLAGS} ${LIBDVDNAV_LDFLAGS}" ++ "PKG_CONFIG_PATH=${DEPENDS_PATH}/lib/pkgconfig") ++ ++ set(BUILD_COMMAND ${MAKE_EXECUTABLE}) ++ set(INSTALL_COMMAND ${MAKE_EXECUTABLE} install) ++ set(BUILD_IN_SOURCE 1) ++ endif() + +- string(APPEND LIBDVDNAV_CFLAGS " -I$<TARGET_PROPERTY:LibDvdRead::LibDvdRead,INTERFACE_INCLUDE_DIRECTORIES> $<TARGET_PROPERTY:LibDvdRead::LibDvdRead,INTERFACE_COMPILE_DEFINITIONS>") +- +- find_program(AUTORECONF autoreconf REQUIRED) +- find_program(MAKE_EXECUTABLE make REQUIRED) +- +- set(CONFIGURE_COMMAND ${AUTORECONF} -vif +- COMMAND ac_cv_path_GIT= ./configure +- --target=${HOST_ARCH} +- --host=${HOST_ARCH} +- --enable-static +- --disable-shared +- --with-pic +- --prefix=${DEPENDS_PATH} +- --libdir=${DEPENDS_PATH}/lib +- "CC=${CMAKE_C_COMPILER}" +- "CFLAGS=${CMAKE_C_FLAGS} ${LIBDVDNAV_CFLAGS}" +- "LDFLAGS=${CMAKE_EXE_LINKER_FLAGS} ${LIBDVDNAV_LDFLAGS}" +- "PKG_CONFIG_PATH=${DEPENDS_PATH}/lib/pkgconfig") +- +- set(BUILD_COMMAND ${MAKE_EXECUTABLE}) +- set(INSTALL_COMMAND ${MAKE_EXECUTABLE} install) +- set(BUILD_IN_SOURCE 1) +- endif() ++ BUILD_DEP_TARGET() ++ ++ if(TARGET LibDvdRead::LibDvdRead) ++ add_dependencies(libdvdnav LibDvdRead::LibDvdRead) ++ endif() ++ else() ++ if(PKG_CONFIG_FOUND) ++ pkg_check_modules(PC_DVDNAV dvdnav QUIET) ++ endif() + +- BUILD_DEP_TARGET() ++ find_path(LIBDVDNAV_INCLUDE_DIR NAMES dvdnav.h ++ PATH_SUFFIXES dvdnav ++ PATHS ${PC_DVDNAV_INCLUDEDIR}) ++ find_library(LIBDVDNAV_LIBRARY NAMES dvdnav libdvdnav ++ PATHS ${PC_DVDNAV_LIBDIR}) + +- if(TARGET LibDvdRead::LibDvdRead) +- add_dependencies(libdvdnav LibDvdRead::LibDvdRead) ++ set(LIBDVDNAV_VERSION ${PC_DVDNAV_VERSION}) + endif() + endif() + +diff --git a/cmake/modules/FindLibDvdRead.cmake b/cmake/modules/FindLibDvdRead.cmake +index d7e8e882fa..0a8261e758 100644 +--- a/cmake/modules/FindLibDvdRead.cmake ++++ b/cmake/modules/FindLibDvdRead.cmake +@@ -27,86 +27,98 @@ if(NOT TARGET LibDvdRead::LibDvdRead) + + set(MODULE_LC libdvdread) + +- # We require this due to the odd nature of github URL's compared to our other tarball +- # mirror system. If User sets LIBDVDREAD_URL or libdvdread_URL, allow get_filename_component in SETUP_BUILD_VARS +- if(LIBDVDREAD_URL OR ${MODULE_LC}_URL) +- if(${MODULE_LC}_URL) +- set(LIBDVDREAD_URL ${${MODULE_LC}_URL}) ++ if(ENABLE_INTERNAL_LIBDVD) ++ ++ # We require this due to the odd nature of github URL's compared to our other tarball ++ # mirror system. If User sets LIBDVDREAD_URL or libdvdread_URL, allow get_filename_component in SETUP_BUILD_VARS ++ if(LIBDVDREAD_URL OR ${MODULE_LC}_URL) ++ set(LIBDVDREAD_URL_PROVIDED TRUE) + endif() +- set(LIBDVDREAD_URL_PROVIDED TRUE) +- endif() + +- SETUP_BUILD_VARS() ++ SETUP_BUILD_VARS() + +- if(NOT LIBDVDREAD_URL_PROVIDED) +- # override LIBDVDREAD_URL due to tar naming when retrieved from github release +- set(LIBDVDREAD_URL ${LIBDVDREAD_BASE_URL}/archive/${LIBDVDREAD_VER}.tar.gz) +- endif() ++ if(NOT LIBDVDREAD_URL_PROVIDED) ++ # override LIBDVDREAD_URL due to tar naming when retrieved from github release ++ set(LIBDVDREAD_URL ${LIBDVDREAD_BASE_URL}/archive/${LIBDVDREAD_VER}.tar.gz) ++ endif() + +- set(LIBDVDREAD_VERSION ${${MODULE}_VER}) +- +- set(HOST_ARCH ${ARCH}) +- if(CORE_SYSTEM_NAME STREQUAL android) +- if(ARCH STREQUAL arm) +- set(HOST_ARCH arm-linux-androideabi) +- elseif(ARCH STREQUAL aarch64) +- set(HOST_ARCH aarch64-linux-android) +- elseif(ARCH STREQUAL i486-linux) +- set(HOST_ARCH i686-linux-android) +- elseif(ARCH STREQUAL x86_64) +- set(HOST_ARCH x86_64-linux-android) ++ set(LIBDVDREAD_VERSION ${${MODULE}_VER}) ++ ++ set(HOST_ARCH ${ARCH}) ++ if(CORE_SYSTEM_NAME STREQUAL android) ++ if(ARCH STREQUAL arm) ++ set(HOST_ARCH arm-linux-androideabi) ++ elseif(ARCH STREQUAL aarch64) ++ set(HOST_ARCH aarch64-linux-android) ++ elseif(ARCH STREQUAL i486-linux) ++ set(HOST_ARCH i686-linux-android) ++ elseif(ARCH STREQUAL x86_64) ++ set(HOST_ARCH x86_64-linux-android) ++ endif() ++ elseif(CORE_SYSTEM_NAME STREQUAL windowsstore) ++ set(LIBDVD_ADDITIONAL_ARGS "-DCMAKE_SYSTEM_NAME=${CMAKE_SYSTEM_NAME}" "-DCMAKE_SYSTEM_VERSION=${CMAKE_SYSTEM_VERSION}") + endif() +- elseif(CORE_SYSTEM_NAME STREQUAL windowsstore) +- set(LIBDVD_ADDITIONAL_ARGS "-DCMAKE_SYSTEM_NAME=${CMAKE_SYSTEM_NAME}" "-DCMAKE_SYSTEM_VERSION=${CMAKE_SYSTEM_VERSION}") +- endif() + +- string(APPEND LIBDVDREAD_CFLAGS "-D_XBMC") ++ string(APPEND LIBDVDREAD_CFLAGS "-D_XBMC") + +- if(APPLE) +- set(LIBDVDREAD_LDFLAGS "-framework CoreFoundation") +- string(APPEND LIBDVDREAD_CFLAGS " -D__DARWIN__") +- if(NOT CORE_SYSTEM_NAME STREQUAL darwin_embedded) +- string(APPEND LIBDVDREAD_LDFLAGS " -framework IOKit") ++ if(APPLE) ++ set(LIBDVDREAD_LDFLAGS "-framework CoreFoundation") ++ string(APPEND LIBDVDREAD_CFLAGS " -D__DARWIN__") ++ if(NOT CORE_SYSTEM_NAME STREQUAL darwin_embedded) ++ string(APPEND LIBDVDREAD_LDFLAGS " -framework IOKit") ++ endif() + endif() +- endif() + +- if(CORE_SYSTEM_NAME MATCHES windows) +- set(CMAKE_ARGS -DDUMMY_DEFINE=ON +- ${LIBDVD_ADDITIONAL_ARGS}) +- else() ++ if(CORE_SYSTEM_NAME MATCHES windows) ++ set(CMAKE_ARGS -DDUMMY_DEFINE=ON ++ ${LIBDVD_ADDITIONAL_ARGS}) ++ else() ++ ++ if(TARGET LibDvdCSS::LibDvdCSS) ++ string(APPEND LIBDVDREAD_CFLAGS " -I$<TARGET_PROPERTY:LibDvdCSS::LibDvdCSS,INTERFACE_INCLUDE_DIRECTORIES> $<TARGET_PROPERTY:LibDvdCSS::LibDvdCSS,INTERFACE_COMPILE_DEFINITIONS>") ++ string(APPEND with-css "--with-libdvdcss") ++ endif() ++ ++ find_program(AUTORECONF autoreconf REQUIRED) ++ find_program(MAKE_EXECUTABLE make REQUIRED) ++ ++ set(CONFIGURE_COMMAND ${AUTORECONF} -vif ++ COMMAND ac_cv_path_GIT= ./configure ++ --target=${HOST_ARCH} ++ --host=${HOST_ARCH} ++ --enable-static ++ --disable-shared ++ --with-pic ++ --prefix=${DEPENDS_PATH} ++ --libdir=${DEPENDS_PATH}/lib ++ ${with-css} ++ "CC=${CMAKE_C_COMPILER}" ++ "CFLAGS=${CMAKE_C_FLAGS} ${LIBDVDREAD_CFLAGS}" ++ "LDFLAGS=${CMAKE_EXE_LINKER_FLAGS} ${LIBDVDREAD_LDFLAGS}" ++ "PKG_CONFIG_PATH=${DEPENDS_PATH}/lib/pkgconfig") ++ ++ set(BUILD_COMMAND ${MAKE_EXECUTABLE}) ++ set(INSTALL_COMMAND ${MAKE_EXECUTABLE} install) ++ set(BUILD_IN_SOURCE 1) ++ endif() ++ ++ BUILD_DEP_TARGET() + + if(TARGET LibDvdCSS::LibDvdCSS) +- string(APPEND LIBDVDREAD_CFLAGS " -I$<TARGET_PROPERTY:LibDvdCSS::LibDvdCSS,INTERFACE_INCLUDE_DIRECTORIES> $<TARGET_PROPERTY:LibDvdCSS::LibDvdCSS,INTERFACE_COMPILE_DEFINITIONS>") +- string(APPEND with-css "--with-libdvdcss") ++ add_dependencies(libdvdread LibDvdCSS::LibDvdCSS) ++ endif() ++ else() ++ if(PKG_CONFIG_FOUND) ++ pkg_check_modules(PC_DVDREAD dvdread QUIET) + endif() + +- find_program(AUTORECONF autoreconf REQUIRED) +- find_program(MAKE_EXECUTABLE make REQUIRED) +- +- set(CONFIGURE_COMMAND ${AUTORECONF} -vif +- COMMAND ac_cv_path_GIT= ./configure +- --target=${HOST_ARCH} +- --host=${HOST_ARCH} +- --enable-static +- --disable-shared +- --with-pic +- --prefix=${DEPENDS_PATH} +- --libdir=${DEPENDS_PATH}/lib +- ${with-css} +- "CC=${CMAKE_C_COMPILER}" +- "CFLAGS=${CMAKE_C_FLAGS} ${LIBDVDREAD_CFLAGS}" +- "LDFLAGS=${CMAKE_EXE_LINKER_FLAGS} ${LIBDVDREAD_LDFLAGS}" +- "PKG_CONFIG_PATH=${DEPENDS_PATH}/lib/pkgconfig") +- +- set(BUILD_COMMAND ${MAKE_EXECUTABLE}) +- set(INSTALL_COMMAND ${MAKE_EXECUTABLE} install) +- set(BUILD_IN_SOURCE 1) +- endif() +- +- BUILD_DEP_TARGET() ++ find_path(LIBDVDREAD_INCLUDE_DIR NAMES dvd_reader.h ++ PATH_SUFFIXES dvdread ++ PATHS ${PC_DVDREAD_INCLUDEDIR}) ++ find_library(LIBDVDREAD_LIBRARY NAMES dvdread libdvdread ++ PATHS ${PC_DVDREAD_LIBDIR}) + +- if(TARGET LibDvdCSS::LibDvdCSS) +- add_dependencies(libdvdread LibDvdCSS::LibDvdCSS) ++ set(LIBDVDREAD_VERSION ${PC_DVDREAD_VERSION}) + endif() + endif() + +diff --git a/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamNavigator.cpp b/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamNavigator.cpp +index 859762348b..069bfccd7b 100644 +--- a/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamNavigator.cpp ++++ b/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamNavigator.cpp +@@ -27,6 +27,8 @@ + #include "platform/Environment.h" + #endif + ++#include <sys/uio.h> ++ + namespace + { + constexpr int HOLDMODE_NONE = 0; +@@ -1414,7 +1416,7 @@ std::string CDVDInputStreamNavigator::GetDVDVolIdString() + if (!m_dvdnav) + return ""; + +- const char* volIdTmp = m_dll.dvdnav_get_volid_string(m_dvdnav); ++ const char* volIdTmp = dvdnav_get_volid_string(m_dvdnav); + if (volIdTmp) + { + std::string volId{volIdTmp}; +diff --git a/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamNavigator.h b/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamNavigator.h +index 319c84b47d..99b01df2ab 100644 +--- a/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamNavigator.h ++++ b/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamNavigator.h +@@ -17,9 +17,15 @@ + #include "cores/MenuType.h" + #include "utils/Geometry.h" + ++#ifdef __cplusplus ++extern "C" ++{ ++#endif + #include <dvdnav/dvdnav.h> + #include <dvdnav/dvd_types.h> +- ++#ifdef __cplusplus ++} ++#endif + #include <string> + + #define DVD_VIDEO_BLOCKSIZE DVD_VIDEO_LB_LEN // 2048 bytes +-- +2.35.1 + + +From 9625e95c0ac5b17125d875178461e54ba7ae5057 Mon Sep 17 00:00:00 2001 +From: enen92 <92enen@gmail.com> +Date: Tue, 26 Jul 2022 23:43:21 +0100 +Subject: [PATCH 3/9] Add dvdcallbacks for vfs files + +--- + .../DVDInputStreamNavigator.cpp | 43 ++--- + xbmc/filesystem/CMakeLists.txt | 2 + + xbmc/filesystem/DvdCallback.cpp | 150 ++++++++++++++++++ + xbmc/filesystem/DvdCallback.h | 47 ++++++ + 4 files changed, 216 insertions(+), 26 deletions(-) + create mode 100644 xbmc/filesystem/DvdCallback.cpp + create mode 100644 xbmc/filesystem/DvdCallback.h + +diff --git a/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamNavigator.cpp b/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamNavigator.cpp +index 069bfccd7b..8280a5a1b9 100644 +--- a/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamNavigator.cpp ++++ b/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamNavigator.cpp +@@ -8,6 +8,7 @@ + + #include "DVDInputStreamNavigator.h" + #include "filesystem/IFileTypes.h" ++#include "filesystem/DvdCallback.h" + #include "utils/LangCodeExpander.h" + #include "../DVDDemuxSPU.h" + #include "settings/Settings.h" +@@ -67,7 +68,8 @@ constexpr int DVD_AUDIO_LANG_EXT_DIRECTORSCOMMENTS2 = 4; + static int dvd_inputstreamnavigator_cb_seek(void * p_stream, uint64_t i_pos); + static int dvd_inputstreamnavigator_cb_read(void * p_stream, void * buffer, int i_read); + static int dvd_inputstreamnavigator_cb_readv(void * p_stream, void * p_iovec, int i_blocks); +-static void dvd_logger(void* priv, dvdnav_logger_level_t level, const char* fmt, va_list va); ++ ++static dvdnav_filesystem kodiDvdFilesystem; + + CDVDInputStreamNavigator::CDVDInputStreamNavigator(IVideoPlayer* player, const CFileItem& fileitem) + : CDVDInputStream(DVDSTREAM_TYPE_DVD, fileitem), m_pstream(nullptr) +@@ -136,7 +138,7 @@ bool CDVDInputStreamNavigator::Open() + + #if DVDNAV_VERSION >= 60100 + dvdnav_logger_cb loggerCallback; +- loggerCallback.pf_log = dvd_logger; ++ loggerCallback.pf_log = CDVDCallback::dvd_logger; + #endif + + // open up the DVD device +@@ -157,6 +159,19 @@ bool CDVDInputStreamNavigator::Open() + } + } + #if DVDNAV_VERSION >= 60100 ++ else if (URIUtils::IsNetworkFilesystem(path)) ++ { ++ kodiDvdFilesystem.dir_open = CDVDCallback::dir_open; ++ kodiDvdFilesystem.file_open = CDVDCallback::file_open; ++ kodiDvdFilesystem.stat = CDVDCallback::stat; ++ kodiDvdFilesystem.close = CDVDCallback::close; ++ if (dvdnav_open_vfs_files(&m_dvdnav, nullptr, &loggerCallback, path.c_str(), &kodiDvdFilesystem) != DVDNAV_STATUS_OK) ++ { ++ CLog::Log(LOGERROR, "Error on dvdnav_open_vfs_files"); ++ Close(); ++ return false; ++ } ++ } + else if (dvdnav_open2(&m_dvdnav, nullptr, &loggerCallback, path.c_str()) != + DVDNAV_STATUS_OK) + #else +@@ -1511,30 +1526,6 @@ int dvd_inputstreamnavigator_cb_read(void * p_stream, void * buffer, int i_read) + return i_ret; + } + +-void dvd_logger(void* priv, dvdnav_logger_level_t level, const char* fmt, va_list va) +-{ +- const std::string message = StringUtils::FormatV(fmt, va); +- auto logLevel = LOGDEBUG; +- switch (level) +- { +- case DVDNAV_LOGGER_LEVEL_INFO: +- logLevel = LOGINFO; +- break; +- case DVDNAV_LOGGER_LEVEL_ERROR: +- logLevel = LOGERROR; +- break; +- case DVDNAV_LOGGER_LEVEL_WARN: +- logLevel = LOGWARNING; +- break; +- case DVDNAV_LOGGER_LEVEL_DEBUG: +- logLevel = LOGDEBUG; +- break; +- default: +- break; +- }; +- CLog::Log(logLevel, "Libdvd: {}", message); +-} +- + int dvd_inputstreamnavigator_cb_readv(void * p_stream, void * p_iovec, int i_blocks) + { + // NOTE/TODO: this vectored read callback somehow doesn't seem to be called by libdvdnav. +diff --git a/xbmc/filesystem/CMakeLists.txt b/xbmc/filesystem/CMakeLists.txt +index 8bbaa44201..449736a392 100644 +--- a/xbmc/filesystem/CMakeLists.txt ++++ b/xbmc/filesystem/CMakeLists.txt +@@ -11,6 +11,7 @@ set(SOURCES AddonsDirectory.cpp + DirectoryFactory.cpp + DirectoryHistory.cpp + DllLibCurl.cpp ++ DvdCallback.cpp + EventsDirectory.cpp + FavouritesDirectory.cpp + FileCache.cpp +@@ -73,6 +74,7 @@ set(HEADERS AddonsDirectory.h + DirectoryFactory.h + DirectoryHistory.h + DllLibCurl.h ++ DvdCallback.h + EventsDirectory.h + FTPDirectory.h + FTPParse.h +diff --git a/xbmc/filesystem/DvdCallback.cpp b/xbmc/filesystem/DvdCallback.cpp +new file mode 100644 +index 0000000000..2f247fff1f +--- /dev/null ++++ b/xbmc/filesystem/DvdCallback.cpp +@@ -0,0 +1,150 @@ ++/* ++ * Copyright (C) 2005-2018 Team Kodi ++ * This file is part of Kodi - https://kodi.tv ++ * ++ * SPDX-License-Identifier: GPL-2.0-or-later ++ * See LICENSES/README.md for more information. ++ */ ++ ++#include "DvdCallback.h" ++ ++#include "FileItem.h" ++#include "filesystem/Directory.h" ++#include "filesystem/File.h" ++#include "utils/StringUtils.h" ++#include "utils/URIUtils.h" ++#include "utils/log.h" ++ ++using namespace XFILE; ++ ++struct SDirState ++{ ++ CFileItemList list; ++ int curr = 0; ++}; ++ ++void CDVDCallback::dvd_logger(void* priv, dvdnav_logger_level_t level, const char* fmt, va_list va) ++{ ++ const std::string message = StringUtils::FormatV(fmt, va); ++ auto logLevel = LOGDEBUG; ++ switch (level) ++ { ++ case DVDNAV_LOGGER_LEVEL_INFO: ++ logLevel = LOGINFO; ++ break; ++ case DVDNAV_LOGGER_LEVEL_ERROR: ++ logLevel = LOGERROR; ++ break; ++ case DVDNAV_LOGGER_LEVEL_WARN: ++ logLevel = LOGWARNING; ++ break; ++ case DVDNAV_LOGGER_LEVEL_DEBUG: ++ logLevel = LOGDEBUG; ++ break; ++ default: ++ break; ++ }; ++ CLog::Log(logLevel, "Libdvd: {}", message); ++} ++ ++void CDVDCallback::dir_close(dvd_dir_h *dir) ++{ ++ if (dir) ++ { ++ CLog::Log(LOGDEBUG, "CDVDCallback - Closed dir ({})", fmt::ptr(dir)); ++ delete static_cast<SDirState*>(dir->internal); ++ delete dir; ++ } ++} ++ ++dvd_dir_h* CDVDCallback::dir_open(const char* strDirname) ++{ ++ CLog::Log(LOGDEBUG, "CDVDCallback - Opening dir {}", CURL::GetRedacted(strDirname)); ++ ++ SDirState *st = new SDirState(); ++ if (!CDirectory::GetDirectory(strDirname, st->list, "", DIR_FLAG_DEFAULTS)) ++ { ++ if (!CFile::Exists(strDirname)) ++ CLog::Log(LOGDEBUG, "CDVDCallback - Error opening dir! ({})", ++ CURL::GetRedacted(strDirname)); ++ delete st; ++ return nullptr; ++ } ++ ++ dvd_dir_h* dir = new dvd_dir_h; ++ dir->close = dir_close; ++ dir->read = dir_read; ++ dir->internal = (void*)st; ++ ++ return dir; ++} ++ ++int CDVDCallback::dir_read(dvd_dir_h *dir, dvd_dirent_t *entry) ++{ ++ SDirState* state = static_cast<SDirState*>(dir->internal); ++ ++ if (state->curr >= state->list.Size()) ++ return 1; ++ ++ strncpy(entry->d_name, state->list[state->curr]->GetLabel().c_str(), sizeof(entry->d_name)); ++ entry->d_name[sizeof(entry->d_name) - 1] = 0; ++ state->curr++; ++ ++ return 0; ++} ++ ++int64_t CDVDCallback::file_close(dvd_file_h *file) ++{ ++ if (file) ++ { ++ delete static_cast<CFile*>(file->internal); ++ delete file; ++ } ++ return 0; ++} ++ ++dvd_file_h * CDVDCallback::file_open(const char *filename, const char *cmode) ++{ ++ dvd_file_h* file = new dvd_file_h; ++ ++ file->close = file_close; ++ file->seek = file_seek; ++ file->read = file_read; ++ ++ CFile* fp = new CFile(); ++ if (fp->Open(filename)) ++ { ++ file->internal = (void*)fp; ++ return file; ++ } ++ ++ CLog::Log(LOGDEBUG, "CDVDCallback - Error opening file! ({})", CURL::GetRedacted(filename)); ++ ++ delete fp; ++ delete file; ++ ++ return nullptr; ++} ++ ++int64_t CDVDCallback::file_seek(dvd_file_h *file, int64_t offset, int32_t origin) ++{ ++ return static_cast<CFile*>(file->internal)->Seek(offset, origin); ++} ++ ++int64_t CDVDCallback::file_read(dvd_file_h *file, char *buf, int64_t size) ++{ ++ return static_cast<int64_t>(static_cast<CFile*>(file->internal)->Read(buf, static_cast<size_t>(size))); ++} ++ ++ ++ int CDVDCallback::stat(const char *path, dvdstat_t* statbuff) ++ { ++ struct __stat64 tStat; ++ int result = CFile::Stat(path, &tStat); ++ statbuff->size = tStat.st_size; ++ statbuff->is_blk = S_ISBLK(tStat.st_mode); ++ statbuff->is_chr = S_ISCHR(tStat.st_mode); ++ statbuff->is_dir = S_ISDIR(tStat.st_mode); ++ statbuff->is_reg = S_ISREG(tStat.st_mode); ++ return result; ++ } +diff --git a/xbmc/filesystem/DvdCallback.h b/xbmc/filesystem/DvdCallback.h +new file mode 100644 +index 0000000000..673108ec66 +--- /dev/null ++++ b/xbmc/filesystem/DvdCallback.h +@@ -0,0 +1,47 @@ ++/* ++ * Copyright (C) 2005-2018 Team Kodi ++ * This file is part of Kodi - https://kodi.tv ++ * ++ * SPDX-License-Identifier: GPL-2.0-or-later ++ * See LICENSES/README.md for more information. ++ */ ++ ++#pragma once ++ ++#ifdef __cplusplus ++extern "C" ++{ ++#endif ++#include <dvdread/dvd_filesystem.h> ++#include <dvdnav/dvdnav.h> ++#ifdef __cplusplus ++} ++#endif ++ ++class CDVDCallback ++{ ++public: ++ // logger implementation ++ static void dvd_logger(void* priv, dvdnav_logger_level_t level, const char* fmt, va_list va); ++ ++ // filesystem close ++ static void close(void *) {}; ++ ++ // dir ++ static void dir_close(dvd_dir_h* dir); ++ static dvd_dir_h* dir_open(const char* strDirname); ++ static int dir_read(dvd_dir_h* dir, dvd_dirent_t* entry); ++ ++ // file ++ static dvd_file_h* file_open(const char* filename, const char *cmode); ++ static int64_t file_close(dvd_file_h* file); ++ static int64_t file_read(dvd_file_h* file, char* buf, int64_t size); ++ static int64_t file_seek(dvd_file_h* file, int64_t offset, int32_t origin); ++ ++ // stat ++ static int stat(const char *path, dvdstat_t* statbuf); ++ ++private: ++ CDVDCallback() = default; ++ ~CDVDCallback() = default; ++}; +\ No newline at end of file +-- +2.35.1 + + +From 8dd8d11a55a7060bd7352623da92d102e7861bc3 Mon Sep 17 00:00:00 2001 +From: enen92 <92enen@gmail.com> +Date: Fri, 29 Jul 2022 14:05:57 +0100 +Subject: [PATCH 4/9] Updates + +--- + xbmc/DllPaths.h | 2 +- + .../VideoPlayer/DVDInputStreams/DVDInputStreamNavigator.cpp | 4 ++-- + 2 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/xbmc/DllPaths.h b/xbmc/DllPaths.h +index 33fb46635e..9f8979355b 100644 +--- a/xbmc/DllPaths.h ++++ b/xbmc/DllPaths.h +@@ -10,7 +10,7 @@ + + #if defined (TARGET_ANDROID) + #include "DllPaths_generated_android.h" +-#else ++#elif !defined (TARGET_WINDOWS) + #include "DllPaths_generated.h" + #endif + +diff --git a/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamNavigator.cpp b/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamNavigator.cpp +index 8280a5a1b9..9221048789 100644 +--- a/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamNavigator.cpp ++++ b/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamNavigator.cpp +@@ -165,9 +165,9 @@ bool CDVDInputStreamNavigator::Open() + kodiDvdFilesystem.file_open = CDVDCallback::file_open; + kodiDvdFilesystem.stat = CDVDCallback::stat; + kodiDvdFilesystem.close = CDVDCallback::close; +- if (dvdnav_open_vfs_files(&m_dvdnav, nullptr, &loggerCallback, path.c_str(), &kodiDvdFilesystem) != DVDNAV_STATUS_OK) ++ if (dvdnav_open_files(&m_dvdnav, nullptr, &loggerCallback, path.c_str(), &kodiDvdFilesystem) != DVDNAV_STATUS_OK) + { +- CLog::Log(LOGERROR, "Error on dvdnav_open_vfs_files"); ++ CLog::Log(LOGERROR, "Error on dvdnav_open_files"); + Close(); + return false; + } +-- +2.35.1 + + +From 8cca2455a993b822270610cc87b63f60d2228079 Mon Sep 17 00:00:00 2001 +From: enen92 <92enen@gmail.com> +Date: Fri, 29 Jul 2022 14:41:39 +0100 +Subject: [PATCH 5/9] update dvdnav version + +--- + tools/depends/target/libdvdnav/LIBDVDNAV-VERSION | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/tools/depends/target/libdvdnav/LIBDVDNAV-VERSION b/tools/depends/target/libdvdnav/LIBDVDNAV-VERSION +index 3d6d1ec699..f5541697ac 100644 +--- a/tools/depends/target/libdvdnav/LIBDVDNAV-VERSION ++++ b/tools/depends/target/libdvdnav/LIBDVDNAV-VERSION +@@ -1,7 +1,7 @@ + LIBNAME=libdvdnav +-BASE_URL=https://github.com/xbmc/libdvdnav +-VERSION=6.1.1-Next-Nexus-Alpha2-2 ++BASE_URL=https://github.com/enen92/libdvdnav ++VERSION=upstream_submission_kodi + ARCHIVE=$(LIBNAME)-$(VERSION).tar.gz +-SHA512=51e6fc033121241354a5f0b3fc9a430577ae3ff6bb7f31445aa548ef4893037fb80eea3b2c6774c81e9ebaf9c45e9b490c98c2c65eb38f9f7daba84b236f7e1d ++SHA512=fca8c19a6787bb7a88a6a5e35f6a524505b607861b3bb391e3eca1e91b67d05b12417153542b161da0f13c4f5152f1d4860a34a6d230155c9c8c767fb35725b2 + BYPRODUCT=libdvdnav.a + BYPRODUCT_WIN=libdvdnav.lib +-- +2.35.1 + + +From be49396a22eb405d63a65bc56d3d1a24c6dcefab Mon Sep 17 00:00:00 2001 +From: enen92 <92enen@gmail.com> +Date: Fri, 29 Jul 2022 15:13:55 +0100 +Subject: [PATCH 6/9] update versions + +--- + tools/depends/target/libdvdread/LIBDVDREAD-VERSION | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/tools/depends/target/libdvdread/LIBDVDREAD-VERSION b/tools/depends/target/libdvdread/LIBDVDREAD-VERSION +index d51b629bd2..74428acf49 100644 +--- a/tools/depends/target/libdvdread/LIBDVDREAD-VERSION ++++ b/tools/depends/target/libdvdread/LIBDVDREAD-VERSION +@@ -1,7 +1,7 @@ + LIBNAME=libdvdread +-BASE_URL=https://github.com/xbmc/libdvdread +-VERSION=6.1.3-Next-Nexus-Alpha2-2 ++BASE_URL=https://github.com/enen92/libdvdread ++VERSION=upstream_submission_kodi + ARCHIVE=$(LIBNAME)-$(VERSION).tar.gz +-SHA512=629a41157d07b8ec0ea1fe89ae5ec48f63047472a862782b805c531ae31a0376fc4dc15175f8280c3ef91d7fa977bacebb1b51232640034a34bab2293210fc5e ++SHA512=d2fb890ccca8b8e7834470922f0b010f70b4016e829d71f51d3aaf30e2517ab7d98b46448313dd9c63141a71e794a8e679db4c1e0905e887c4897f7a5c194dc0 + BYPRODUCT=libdvdread.a + BYPRODUCT_WIN=dvdread.lib +-- +2.35.1 + + +From 4cf9e76978906e92ffb66441701d19f6e40c96fa Mon Sep 17 00:00:00 2001 +From: enen92 <92enen@gmail.com> +Date: Fri, 29 Jul 2022 15:39:43 +0100 +Subject: [PATCH 7/9] fixup + +--- + tools/depends/target/libdvdread/LIBDVDREAD-VERSION | 4 ++-- + .../VideoPlayer/DVDInputStreams/DVDInputStreamNavigator.cpp | 2 +- + 2 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/tools/depends/target/libdvdread/LIBDVDREAD-VERSION b/tools/depends/target/libdvdread/LIBDVDREAD-VERSION +index 74428acf49..38b7a10d8b 100644 +--- a/tools/depends/target/libdvdread/LIBDVDREAD-VERSION ++++ b/tools/depends/target/libdvdread/LIBDVDREAD-VERSION +@@ -1,7 +1,7 @@ + LIBNAME=libdvdread + BASE_URL=https://github.com/enen92/libdvdread +-VERSION=upstream_submission_kodi ++VERSION=upstream_skodi7 + ARCHIVE=$(LIBNAME)-$(VERSION).tar.gz +-SHA512=d2fb890ccca8b8e7834470922f0b010f70b4016e829d71f51d3aaf30e2517ab7d98b46448313dd9c63141a71e794a8e679db4c1e0905e887c4897f7a5c194dc0 ++SHA512=932e83a9aeb949265538d935aab4689b9e8d8fe0611faad8ab066c97a418ad2dd907e65655b299950b296d7ff51394b89f51d41609cbfabb7db3d9201711e370 + BYPRODUCT=libdvdread.a + BYPRODUCT_WIN=dvdread.lib +diff --git a/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamNavigator.cpp b/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamNavigator.cpp +index 9221048789..db5679d9bf 100644 +--- a/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamNavigator.cpp ++++ b/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamNavigator.cpp +@@ -28,7 +28,7 @@ + #include "platform/Environment.h" + #endif + +-#include <sys/uio.h> ++//#include <sys/uio.h> + + namespace + { +-- +2.35.1 + + +From 423f4633ba64465004f5ad9894c934ba8b4725bf Mon Sep 17 00:00:00 2001 +From: enen92 <92enen@gmail.com> +Date: Fri, 29 Jul 2022 21:16:11 +0100 +Subject: [PATCH 8/9] update libs for win + +--- + .../depends/target/libdvdnav/LIBDVDNAV-VERSION | 6 +++--- + .../target/libdvdread/LIBDVDREAD-VERSION | 4 ++-- + .../DVDInputStreams/DVDInputStreamNavigator.cpp | 17 ++++++++++++++++- + xbmc/filesystem/DvdCallback.cpp | 6 ++++++ + 4 files changed, 27 insertions(+), 6 deletions(-) + +diff --git a/tools/depends/target/libdvdnav/LIBDVDNAV-VERSION b/tools/depends/target/libdvdnav/LIBDVDNAV-VERSION +index f5541697ac..2f6110e0b6 100644 +--- a/tools/depends/target/libdvdnav/LIBDVDNAV-VERSION ++++ b/tools/depends/target/libdvdnav/LIBDVDNAV-VERSION +@@ -1,7 +1,7 @@ + LIBNAME=libdvdnav + BASE_URL=https://github.com/enen92/libdvdnav +-VERSION=upstream_submission_kodi ++VERSION=upstream_submission_kodi2 + ARCHIVE=$(LIBNAME)-$(VERSION).tar.gz +-SHA512=fca8c19a6787bb7a88a6a5e35f6a524505b607861b3bb391e3eca1e91b67d05b12417153542b161da0f13c4f5152f1d4860a34a6d230155c9c8c767fb35725b2 ++SHA512=36bfedfd5628014164d757588e9165a7c4eb9f0dcd0c3fc393c7d6e1457d33f64f88a3a488c90d2862bfe65f99de274baa81c8e446ca9ad74d76d13166cebe24 + BYPRODUCT=libdvdnav.a +-BYPRODUCT_WIN=libdvdnav.lib ++BYPRODUCT_WIN=libdvdnav.lib +\ No newline at end of file +diff --git a/tools/depends/target/libdvdread/LIBDVDREAD-VERSION b/tools/depends/target/libdvdread/LIBDVDREAD-VERSION +index 38b7a10d8b..001f7572f6 100644 +--- a/tools/depends/target/libdvdread/LIBDVDREAD-VERSION ++++ b/tools/depends/target/libdvdread/LIBDVDREAD-VERSION +@@ -1,7 +1,7 @@ + LIBNAME=libdvdread + BASE_URL=https://github.com/enen92/libdvdread +-VERSION=upstream_skodi7 ++VERSION=upstream_skodi8 + ARCHIVE=$(LIBNAME)-$(VERSION).tar.gz +-SHA512=932e83a9aeb949265538d935aab4689b9e8d8fe0611faad8ab066c97a418ad2dd907e65655b299950b296d7ff51394b89f51d41609cbfabb7db3d9201711e370 ++SHA512=7946172ce3eeba869017038eaa215d915dff96550bc9b20d400fbe218ffe2622afb8de47df804ab165763330e4c818092c8d687ebc45422969062e0367c9fb6f + BYPRODUCT=libdvdread.a + BYPRODUCT_WIN=dvdread.lib +diff --git a/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamNavigator.cpp b/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamNavigator.cpp +index db5679d9bf..be369d95dc 100644 +--- a/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamNavigator.cpp ++++ b/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamNavigator.cpp +@@ -28,7 +28,22 @@ + #include "platform/Environment.h" + #endif + +-//#include <sys/uio.h> ++//FIXME ++#ifdef TARGET_WINDOWS ++#include "platform/win32/dirent.h" ++#else ++#include <dirent.h> ++#endif ++ ++#ifdef TARGET_WINDOWS ++struct iovec ++{ ++ void* iov_base; /* Pointer to data. */ ++ size_t iov_len; /* Length of data. */ ++}; ++#else ++#include <sys/uio.h> /* struct iovec */ ++#endif + + namespace + { +diff --git a/xbmc/filesystem/DvdCallback.cpp b/xbmc/filesystem/DvdCallback.cpp +index 2f247fff1f..a3bb72e808 100644 +--- a/xbmc/filesystem/DvdCallback.cpp ++++ b/xbmc/filesystem/DvdCallback.cpp +@@ -17,6 +17,12 @@ + + using namespace XFILE; + ++#ifdef TARGET_WINDOWS ++#include "platform/win32/dirent.h" ++#else ++#include <dirent.h> ++#endif ++ + struct SDirState + { + CFileItemList list; +-- +2.35.1 + + +From 070cccd1e3900dabbc21248055c31329ec1bc4e5 Mon Sep 17 00:00:00 2001 +From: enen92 <92enen@gmail.com> +Date: Tue, 9 Aug 2022 11:03:01 +0100 +Subject: [PATCH 9/9] Backup new version + +--- + .../DVDInputStreams/DVDInputStreamNavigator.cpp | 2 +- + xbmc/filesystem/DvdCallback.cpp | 17 +++++++---------- + xbmc/filesystem/DvdCallback.h | 12 ++++++------ + 3 files changed, 14 insertions(+), 17 deletions(-) + +diff --git a/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamNavigator.cpp b/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamNavigator.cpp +index be369d95dc..253c95cd1c 100644 +--- a/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamNavigator.cpp ++++ b/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamNavigator.cpp +@@ -84,7 +84,7 @@ static int dvd_inputstreamnavigator_cb_seek(void * p_stream, uint64_t i_pos); + static int dvd_inputstreamnavigator_cb_read(void * p_stream, void * buffer, int i_read); + static int dvd_inputstreamnavigator_cb_readv(void * p_stream, void * p_iovec, int i_blocks); + +-static dvdnav_filesystem kodiDvdFilesystem; ++static dvdnav_filesystem_h kodiDvdFilesystem; + + CDVDInputStreamNavigator::CDVDInputStreamNavigator(IVideoPlayer* player, const CFileItem& fileitem) + : CDVDInputStream(DVDSTREAM_TYPE_DVD, fileitem), m_pstream(nullptr) +diff --git a/xbmc/filesystem/DvdCallback.cpp b/xbmc/filesystem/DvdCallback.cpp +index a3bb72e808..16b359b27e 100644 +--- a/xbmc/filesystem/DvdCallback.cpp ++++ b/xbmc/filesystem/DvdCallback.cpp +@@ -63,7 +63,7 @@ void CDVDCallback::dir_close(dvd_dir_h *dir) + } + } + +-dvd_dir_h* CDVDCallback::dir_open(const char* strDirname) ++dvd_dir_h* CDVDCallback::dir_open(dvdnav_filesystem_h *fs, const char* strDirname) + { + CLog::Log(LOGDEBUG, "CDVDCallback - Opening dir {}", CURL::GetRedacted(strDirname)); + +@@ -99,7 +99,7 @@ int CDVDCallback::dir_read(dvd_dir_h *dir, dvd_dirent_t *entry) + return 0; + } + +-int64_t CDVDCallback::file_close(dvd_file_h *file) ++int CDVDCallback::file_close(dvd_file_h *file) + { + if (file) + { +@@ -109,7 +109,7 @@ int64_t CDVDCallback::file_close(dvd_file_h *file) + return 0; + } + +-dvd_file_h * CDVDCallback::file_open(const char *filename, const char *cmode) ++dvd_file_h * CDVDCallback::file_open(dvdnav_filesystem_h *fs, const char *filename) + { + dvd_file_h* file = new dvd_file_h; + +@@ -137,20 +137,17 @@ int64_t CDVDCallback::file_seek(dvd_file_h *file, int64_t offset, int32_t origin + return static_cast<CFile*>(file->internal)->Seek(offset, origin); + } + +-int64_t CDVDCallback::file_read(dvd_file_h *file, char *buf, int64_t size) ++ssize_t CDVDCallback::file_read(dvd_file_h *file, char *buf, size_t size) + { +- return static_cast<int64_t>(static_cast<CFile*>(file->internal)->Read(buf, static_cast<size_t>(size))); ++ return static_cast<ssize_t>(static_cast<CFile*>(file->internal)->Read(buf, size)); + } + + +- int CDVDCallback::stat(const char *path, dvdstat_t* statbuff) ++ int CDVDCallback::stat(dvdnav_filesystem_h *fs, const char *path, dvdstat_t* statbuff) + { + struct __stat64 tStat; + int result = CFile::Stat(path, &tStat); + statbuff->size = tStat.st_size; +- statbuff->is_blk = S_ISBLK(tStat.st_mode); +- statbuff->is_chr = S_ISCHR(tStat.st_mode); +- statbuff->is_dir = S_ISDIR(tStat.st_mode); +- statbuff->is_reg = S_ISREG(tStat.st_mode); ++ statbuff->st_mode = tStat.st_mode; + return result; + } +diff --git a/xbmc/filesystem/DvdCallback.h b/xbmc/filesystem/DvdCallback.h +index 673108ec66..8451372422 100644 +--- a/xbmc/filesystem/DvdCallback.h ++++ b/xbmc/filesystem/DvdCallback.h +@@ -25,21 +25,21 @@ public: + static void dvd_logger(void* priv, dvdnav_logger_level_t level, const char* fmt, va_list va); + + // filesystem close +- static void close(void *) {}; ++ static void close(dvdnav_filesystem_h *fs) {}; + + // dir + static void dir_close(dvd_dir_h* dir); +- static dvd_dir_h* dir_open(const char* strDirname); ++ static dvd_dir_h* dir_open(dvdnav_filesystem_h *fs, const char* strDirname); + static int dir_read(dvd_dir_h* dir, dvd_dirent_t* entry); + + // file +- static dvd_file_h* file_open(const char* filename, const char *cmode); +- static int64_t file_close(dvd_file_h* file); +- static int64_t file_read(dvd_file_h* file, char* buf, int64_t size); ++ static dvd_file_h* file_open(dvdnav_filesystem_h *fs, const char* filename); ++ static int file_close(dvd_file_h* file); ++ static ssize_t file_read(dvd_file_h* file, char* buf, size_t size); + static int64_t file_seek(dvd_file_h* file, int64_t offset, int32_t origin); + + // stat +- static int stat(const char *path, dvdstat_t* statbuf); ++ static int stat(dvdnav_filesystem_h *fs, const char *path, dvdstat_t* statbuf); + + private: + CDVDCallback() = default; +-- +2.35.1 + diff --git a/debian/patches/workarounds/0004-ffmpeg6.patch b/debian/patches/workarounds/0004-ffmpeg6.patch new file mode 100644 index 0000000..d0c4563 --- /dev/null +++ b/debian/patches/workarounds/0004-ffmpeg6.patch @@ -0,0 +1,662 @@ +From c9e25dc15acf1214b079da7021ad89acf85fa77d Mon Sep 17 00:00:00 2001 +From: CastagnaIT <gottardo.stefano.83@gmail.com> +Date: Sun, 29 Jan 2023 17:51:51 +0100 +Subject: [PATCH] [VideoPlayerVideo] Log an error when codec extradata is + required + +--- + xbmc/cores/VideoPlayer/VideoPlayerVideo.cpp | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/xbmc/cores/VideoPlayer/VideoPlayerVideo.cpp b/xbmc/cores/VideoPlayer/VideoPlayerVideo.cpp +index 20f6b3b1cb51d..38f63f0766718 100644 +--- a/xbmc/cores/VideoPlayer/VideoPlayerVideo.cpp ++++ b/xbmc/cores/VideoPlayer/VideoPlayerVideo.cpp +@@ -114,8 +114,11 @@ bool CVideoPlayerVideo::OpenStream(CDVDStreamInfo hint) + hint.codec == AV_CODEC_ID_WMV3 || + hint.codec == AV_CODEC_ID_VC1 || + hint.codec == AV_CODEC_ID_AV1) +- // clang-format on ++ { ++ CLog::LogF(LOGERROR, "Codec id {} require extradata.", hint.codec); + return false; ++ } ++ // clang-format on + } + + CLog::Log(LOGINFO, "Creating video codec with codec id: {}", hint.codec); + + +From 2559466404d342428d43076bf90fcacc24313af0 Mon Sep 17 00:00:00 2001 +From: enen92 <92enen@gmail.com> +Date: Mon, 6 Feb 2023 15:36:11 +0000 +Subject: [PATCH] video: remove ffmpeg bsf hack + +Manually setting the codecID on the bsf filter is wrong. +avcodec_parameters_copy should be used instead. +--- + xbmc/cores/FFmpeg.cpp | 13 ++++++++----- + xbmc/cores/FFmpeg.h | 3 +-- + .../VideoPlayer/DVDDemuxers/DVDDemuxClient.cpp | 10 +++++++++- + .../VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp | 3 +-- + 4 files changed, 19 insertions(+), 10 deletions(-) + +diff --git a/xbmc/cores/FFmpeg.cpp b/xbmc/cores/FFmpeg.cpp +index d071f6d8e33a3..73b7ea2ae875c 100644 +--- a/xbmc/cores/FFmpeg.cpp ++++ b/xbmc/cores/FFmpeg.cpp +@@ -135,9 +135,7 @@ void ff_avutil_log(void* ptr, int level, const char* format, va_list va) + buffer.erase(0, start); + } + +-std::tuple<uint8_t*, int> GetPacketExtradata(const AVPacket* pkt, +- const AVCodecParserContext* parserCtx, +- AVCodecContext* codecCtx) ++std::tuple<uint8_t*, int> GetPacketExtradata(const AVPacket* pkt, const AVCodecParameters* codecPar) + { + constexpr int FF_MAX_EXTRADATA_SIZE = ((1 << 28) - AV_INPUT_BUFFER_PADDING_SIZE); + +@@ -151,7 +149,7 @@ std::tuple<uint8_t*, int> GetPacketExtradata(const AVPacket* pkt, + * for certain codecs, as noted in discussion of PR#21248 + */ + +- AVCodecID codecId = codecCtx->codec_id; ++ AVCodecID codecId = codecPar->codec_id; + + // clang-format off + if ( +@@ -178,7 +176,12 @@ std::tuple<uint8_t*, int> GetPacketExtradata(const AVPacket* pkt, + if (ret < 0) + return std::make_tuple(nullptr, 0); + +- bsf->par_in->codec_id = codecId; ++ ret = avcodec_parameters_copy(bsf->par_in, codecPar); ++ if (ret < 0) ++ { ++ av_bsf_free(&bsf); ++ return std::make_tuple(nullptr, 0); ++ } + + ret = av_bsf_init(bsf); + if (ret < 0) +diff --git a/xbmc/cores/FFmpeg.h b/xbmc/cores/FFmpeg.h +index 05547a0ba2b5f..5e35d58c6b0a6 100644 +--- a/xbmc/cores/FFmpeg.h ++++ b/xbmc/cores/FFmpeg.h +@@ -73,5 +73,4 @@ class CFFmpegLog + }; + + std::tuple<uint8_t*, int> GetPacketExtradata(const AVPacket* pkt, +- const AVCodecParserContext* parserCtx, +- AVCodecContext* codecCtx); ++ const AVCodecParameters* codecPar); +diff --git a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxClient.cpp b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxClient.cpp +index 052332331702a..9ca07b9a2dd39 100644 +--- a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxClient.cpp ++++ b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxClient.cpp +@@ -162,7 +162,15 @@ bool CDVDDemuxClient::ParsePacket(DemuxPacket* pkt) + avpkt->size = pkt->iSize; + avpkt->dts = avpkt->pts = AV_NOPTS_VALUE; + +- auto [retExtraData, len] = GetPacketExtradata(avpkt, stream->m_parser, stream->m_context); ++ AVCodecParameters* codecPar = nullptr; ++ int ret = avcodec_parameters_from_context(codecPar, stream->m_context); ++ if (ret < 0) ++ { ++ CLog::LogF(LOGERROR, "avcodec_parameters_from_context failed"); ++ return false; ++ } ++ ++ auto [retExtraData, len] = GetPacketExtradata(avpkt, codecPar); + if (len > 0) + { + st->changes++; +diff --git a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp +index 7e6a2e10616d7..bc6b54c87235d 100644 +--- a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp ++++ b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp +@@ -2290,8 +2290,7 @@ void CDVDDemuxFFmpeg::ParsePacket(AVPacket* pkt) + parser->second->m_parserCtx->parser && + !st->codecpar->extradata) + { +- auto [retExtraData, i] = +- GetPacketExtradata(pkt, parser->second->m_parserCtx, parser->second->m_codecCtx); ++ auto [retExtraData, i] = GetPacketExtradata(pkt, st->codecpar); + if (i > 0) + { + st->codecpar->extradata_size = i; + + +From 3ad9588656e30abd421e48147b23aee9fb4b3557 Mon Sep 17 00:00:00 2001 +From: Miguel Borges de Freitas <92enen@gmail.com> +Date: Sun, 12 Feb 2023 12:08:36 +0000 +Subject: [PATCH] [video] fix crash in avcodec_parameters_from_context + +--- + xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxClient.cpp | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxClient.cpp b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxClient.cpp +index 9ca07b9a2dd39..26fa9522eea7a 100644 +--- a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxClient.cpp ++++ b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxClient.cpp +@@ -162,11 +162,12 @@ bool CDVDDemuxClient::ParsePacket(DemuxPacket* pkt) + avpkt->size = pkt->iSize; + avpkt->dts = avpkt->pts = AV_NOPTS_VALUE; + +- AVCodecParameters* codecPar = nullptr; ++ AVCodecParameters* codecPar = avcodec_parameters_alloc(); + int ret = avcodec_parameters_from_context(codecPar, stream->m_context); + if (ret < 0) + { + CLog::LogF(LOGERROR, "avcodec_parameters_from_context failed"); ++ avcodec_parameters_free(&codecPar); + return false; + } + +@@ -188,7 +189,7 @@ bool CDVDDemuxClient::ParsePacket(DemuxPacket* pkt) + avcodec_close(stream->m_context); + } + } +- ++ avcodec_parameters_free(&codecPar); + av_packet_free(&avpkt); + } + + + +From f30f1e6418ea60bc7cb081c59f5f1d9431d264e6 Mon Sep 17 00:00:00 2001 +From: Lukas Rusak <lorusak@gmail.com> +Date: Sat, 11 Mar 2023 13:28:38 -0800 +Subject: [PATCH 01/10] CDVDAudioCodecFFmpeg: ifdef use of + AV_CODEC_FLAG_TRUNCATED for ffmpeg 6.0 + +Signed-off-by: Lukas Rusak <lorusak@gmail.com> +--- + xbmc/cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp +index b2849c797dbc4..325bb0b7549ab 100644 +--- a/xbmc/cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp ++++ b/xbmc/cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp +@@ -73,8 +73,10 @@ bool CDVDAudioCodecFFmpeg::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options + m_pCodecContext->debug = 0; + m_pCodecContext->workaround_bugs = 1; + ++#if LIBAVCODEC_VERSION_MAJOR < 60 + if (pCodec->capabilities & AV_CODEC_CAP_TRUNCATED) + m_pCodecContext->flags |= AV_CODEC_FLAG_TRUNCATED; ++#endif + + m_matrixEncoding = AV_MATRIX_ENCODING_NONE; + m_channels = 0; + +From 3b71910ee0bb650816456ecc9a21251aff650c4d Mon Sep 17 00:00:00 2001 +From: Lukas Rusak <lorusak@gmail.com> +Date: Sat, 11 Mar 2023 13:29:18 -0800 +Subject: [PATCH 02/10] CDVDAudioCodecFFmpeg: fix setting channel layout mask + when opening codec + +Signed-off-by: Lukas Rusak <lorusak@gmail.com> +--- + .../DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp | 17 ++++++++++++++--- + 1 file changed, 14 insertions(+), 3 deletions(-) + +diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp +index 325bb0b7549ab..d1fb2cfe96afc 100644 +--- a/xbmc/cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp ++++ b/xbmc/cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp +@@ -80,13 +80,21 @@ + m_channels = 0; + #if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ + LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) +- av_channel_layout_uninit(&m_pCodecContext->ch_layout); +- m_pCodecContext->ch_layout.order = AV_CHANNEL_ORDER_NATIVE; +- m_pCodecContext->ch_layout.nb_channels = hints.channels; ++ if (hints.channels > 0 && hints.channellayout > 0) ++ { ++ m_pCodecContext->ch_layout.order = AV_CHANNEL_ORDER_NATIVE; ++ m_pCodecContext->ch_layout.nb_channels = hints.channels; ++ m_pCodecContext->ch_layout.u.mask = hints.channellayout; ++ } ++ else if (hints.channels > 0) ++ { ++ av_channel_layout_default(&m_pCodecContext->ch_layout, hints.channels); ++ } ++ ++ m_hint_layout = m_pCodecContext->ch_layout.u.mask; + #else + m_pCodecContext->channels = hints.channels; + #endif +- m_hint_layout = hints.channellayout; + m_pCodecContext->sample_rate = hints.samplerate; + m_pCodecContext->block_align = hints.blockalign; + m_pCodecContext->bit_rate = hints.bitrate; + +From f4fadb3ba4583c45fb06908a3eb352be8c29f235 Mon Sep 17 00:00:00 2001 +From: Lukas Rusak <lorusak@gmail.com> +Date: Sat, 11 Mar 2023 13:29:34 -0800 +Subject: [PATCH 03/10] CDVDAudioCodecFFmpeg: drop unneeded use of + AVFMT_FLAG_PRIV_OPT + +Signed-off-by: Lukas Rusak <lorusak@gmail.com> +--- + xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp +index bc6b54c87235d..016d198206716 100644 +--- a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp ++++ b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp +@@ -323,7 +323,6 @@ bool CDVDDemuxFFmpeg::Open(const std::shared_ptr<CDVDInputStream>& pInput, bool + } + if (result < 0) + { +- m_pFormatContext->flags |= AVFMT_FLAG_PRIV_OPT; + if (avformat_open_input(&m_pFormatContext, strFile.c_str(), iformat, &options) < 0) + { + CLog::Log(LOGDEBUG, "Error, could not open file {}", CURL::GetRedacted(strFile)); +@@ -335,7 +334,6 @@ bool CDVDDemuxFFmpeg::Open(const std::shared_ptr<CDVDInputStream>& pInput, bool + avformat_close_input(&m_pFormatContext); + m_pFormatContext = avformat_alloc_context(); + m_pFormatContext->interrupt_callback = int_cb; +- m_pFormatContext->flags &= ~AVFMT_FLAG_PRIV_OPT; + AVDictionary* options = GetFFMpegOptionsFromInput(); + av_dict_set_int(&options, "load_all_variants", 0, AV_OPT_SEARCH_CHILDREN); + if (avformat_open_input(&m_pFormatContext, strFile.c_str(), iformat, &options) < 0) + +From 7d03f33b83e5fb127a7495798a20c3b63ac06795 Mon Sep 17 00:00:00 2001 +From: Lukas Rusak <lorusak@gmail.com> +Date: Wed, 15 Mar 2023 19:58:56 -0700 +Subject: [PATCH 04/10] CDVDVideoCodecFFmpeg: update filter args to use + key/value pairs + +Signed-off-by: Lukas Rusak <lorusak@gmail.com> +--- + .../VideoPlayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp +index bb9c20bf9d06e..c080589896ce7 100644 +--- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp ++++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp +@@ -1164,8 +1164,9 @@ int CDVDVideoCodecFFmpeg::FilterOpen(const std::string& filters, bool scale) + const AVFilter* outFilter = avfilter_get_by_name("buffersink"); // should be last filter in the graph for now + + std::string args = StringUtils::Format( +- "{}:{}:{}:{}:{}:{}:{}", m_pCodecContext->width, m_pCodecContext->height, +- m_pCodecContext->pix_fmt, m_pCodecContext->time_base.num ? m_pCodecContext->time_base.num : 1, ++ "video_size={}x{}:pix_fmt={}:time_base={}/{}:pixel_aspect={}/{}", m_pCodecContext->width, ++ m_pCodecContext->height, m_pCodecContext->pix_fmt, ++ m_pCodecContext->time_base.num ? m_pCodecContext->time_base.num : 1, + m_pCodecContext->time_base.num ? m_pCodecContext->time_base.den : 1, + m_pCodecContext->sample_aspect_ratio.num != 0 ? m_pCodecContext->sample_aspect_ratio.num : 1, + m_pCodecContext->sample_aspect_ratio.num != 0 ? m_pCodecContext->sample_aspect_ratio.den : 1); + +From 30bd7912802cf0f608751c452c48fc1a2eb8d91b Mon Sep 17 00:00:00 2001 +From: Lukas Rusak <lorusak@gmail.com> +Date: Wed, 15 Mar 2023 19:59:27 -0700 +Subject: [PATCH 05/10] CFFmpegPostproc: update filter args to use key/value + pairs + +Signed-off-by: Lukas Rusak <lorusak@gmail.com> +--- + xbmc/cores/VideoPlayer/DVDCodecs/Video/VAAPI.cpp | 9 +++++---- + 1 file changed, 5 insertions(+), 4 deletions(-) + +diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/VAAPI.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Video/VAAPI.cpp +index 81b969d119667..6c4f664591a04 100644 +--- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/VAAPI.cpp ++++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/VAAPI.cpp +@@ -2962,10 +2962,11 @@ bool CFFmpegPostproc::Init(EINTERLACEMETHOD method) + const AVFilter* srcFilter = avfilter_get_by_name("buffer"); + const AVFilter* outFilter = avfilter_get_by_name("buffersink"); + +- std::string args = StringUtils::Format("{}:{}:{}:{}:{}:{}:{}", m_config.vidWidth, +- m_config.vidHeight, AV_PIX_FMT_NV12, 1, 1, +- (m_config.aspect.num != 0) ? m_config.aspect.num : 1, +- (m_config.aspect.num != 0) ? m_config.aspect.den : 1); ++ std::string args = ++ StringUtils::Format("video_size={}x{}:pix_fmt={}:time_base={}/{}:pixel_aspect={}/{}", ++ m_config.vidWidth, m_config.vidHeight, AV_PIX_FMT_NV12, 1, 1, ++ (m_config.aspect.num != 0) ? m_config.aspect.num : 1, ++ (m_config.aspect.num != 0) ? m_config.aspect.den : 1); + + if (avfilter_graph_create_filter(&m_pFilterIn, srcFilter, "src", args.c_str(), NULL, m_pFilterGraph) < 0) + { + +From 54a21151374a2d40a2a452fae2709205ed8e8836 Mon Sep 17 00:00:00 2001 +From: Lukas Rusak <lorusak@gmail.com> +Date: Sat, 11 Mar 2023 19:32:09 -0800 +Subject: [PATCH 08/10] DXVA: CDecoder: replace removed av_mallocz_array with + av_calloc + +ref: https://ffmpeg.org/doxygen/5.0/group__lavu__mem__funcs.html\#ga6627f140c3f70847bc6d9690a2fd001f + +Signed-off-by: Lukas Rusak <lorusak@gmail.com> +--- + xbmc/cores/VideoPlayer/DVDCodecs/Video/DXVA.cpp | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DXVA.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DXVA.cpp +index a1bc3761c59d1..c06bd1ac0c7e6 100644 +--- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DXVA.cpp ++++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DXVA.cpp +@@ -972,7 +972,8 @@ CDecoder::CDecoder(CProcessInfo& processInfo) + m_event.Set(); + m_avD3D11Context = av_d3d11va_alloc_context(); + m_avD3D11Context->cfg = reinterpret_cast<D3D11_VIDEO_DECODER_CONFIG*>(av_mallocz(sizeof(D3D11_VIDEO_DECODER_CONFIG))); +- m_avD3D11Context->surface = reinterpret_cast<ID3D11VideoDecoderOutputView**>(av_mallocz_array(32, sizeof(ID3D11VideoDecoderOutputView*))); ++ m_avD3D11Context->surface = reinterpret_cast<ID3D11VideoDecoderOutputView**>( ++ av_calloc(32, sizeof(ID3D11VideoDecoderOutputView*))); + m_bufferPool.reset(); + + DX::Windowing()->Register(this); + +From be1247d627cee6561174467094f1e8a46357df79 Mon Sep 17 00:00:00 2001 +From: Lukas Rusak <lorusak@gmail.com> +Date: Sat, 11 Mar 2023 19:45:46 -0800 +Subject: [PATCH 09/10] CFFmpegImage: remove deprecated use of pkt_duration + +ref: https://ffmpeg.org/doxygen/6.0/structAVFrame.html\#a91725a40000e348b0607adf7f577e646 + +Signed-off-by: Lukas Rusak <lorusak@gmail.com> +--- + xbmc/guilib/FFmpegImage.cpp | 16 +++++++++++++++- + 1 file changed, 15 insertions(+), 1 deletion(-) + +diff --git a/xbmc/guilib/FFmpegImage.cpp b/xbmc/guilib/FFmpegImage.cpp +index e71980998b2e5..7171c046a9ce5 100644 +--- a/xbmc/guilib/FFmpegImage.cpp ++++ b/xbmc/guilib/FFmpegImage.cpp +@@ -294,7 +294,15 @@ AVFrame* CFFmpegImage::ExtractFrame() + return nullptr; + } + //we need milliseconds +- frame->pkt_duration = av_rescale_q(frame->pkt_duration, m_fctx->streams[0]->time_base, AVRational{ 1, 1000 }); ++ ++#if LIBAVCODEC_VERSION_MAJOR < 60 ++ frame->pkt_duration = ++ av_rescale_q(frame->pkt_duration, m_fctx->streams[0]->time_base, AVRational{1, 1000}); ++#else ++ frame->duration = ++ av_rescale_q(frame->duration, m_fctx->streams[0]->time_base, AVRational{1, 1000}); ++#endif ++ + m_height = frame->height; + m_width = frame->width; + m_originalWidth = m_width; +@@ -745,7 +753,13 @@ std::shared_ptr<Frame> CFFmpegImage::ReadFrame() + if (avframe == nullptr) + return nullptr; + std::shared_ptr<Frame> frame(new Frame()); ++ ++#if LIBAVCODEC_VERSION_MAJOR < 60 + frame->m_delay = (unsigned int)avframe->pkt_duration; ++#else ++ frame->m_delay = (unsigned int)avframe->duration; ++#endif ++ + frame->m_pitch = avframe->width * 4; + frame->m_pImage = (unsigned char*) av_malloc(avframe->height * frame->m_pitch); + DecodeFrame(avframe, avframe->width, avframe->height, frame->m_pitch, frame->m_pImage); + +From c12af890b0973f7c86316087e823f8a31c6b2ed3 Mon Sep 17 00:00:00 2001 +From: Lukas Rusak <lorusak@gmail.com> +Date: Sat, 11 Mar 2023 19:45:01 -0800 +Subject: [PATCH 10/10] CDVDVideoCodecFFmpeg: remove deprecated use of + reordered_opaque + +ref: https://ffmpeg.org/doxygen/6.0/structAVFrame.html#a12f572ed19a2cba6be3790393cee76b5 + +Signed-off-by: Lukas Rusak <lorusak@gmail.com> +--- + .../DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp | 11 ++++++++++- + xbmc/cores/VideoPlayer/DVDCodecs/Video/DXVA.cpp | 6 ++++-- + xbmc/cores/VideoPlayer/DVDCodecs/Video/VAAPI.cpp | 3 +++ + xbmc/cores/VideoPlayer/DVDCodecs/Video/VDPAU.cpp | 5 ++++- + 4 files changed, 21 insertions(+), 4 deletions(-) + +diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp +index c080589896ce7..6a53ade4a7351 100644 +--- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp ++++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp +@@ -370,6 +370,10 @@ bool CDVDVideoCodecFFmpeg::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options + m_pCodecContext->get_format = GetFormat; + m_pCodecContext->codec_tag = hints.codec_tag; + ++#if LIBAVCODEC_VERSION_MAJOR >= 60 ++ m_pCodecContext->flags = AV_CODEC_FLAG_COPY_OPAQUE; ++#endif ++ + // setup threading model + if (!(hints.codecOptions & CODEC_FORCE_SOFTWARE)) + { +@@ -545,9 +549,10 @@ void CDVDVideoCodecFFmpeg::UpdateName() + CLog::Log(LOGDEBUG, "CDVDVideoCodecFFmpeg - Updated codec: {}", m_name); + } + ++#if LIBAVCODEC_VERSION_MAJOR < 60 + union pts_union + { +- double pts_d; ++ double pts_d; + int64_t pts_i; + }; + +@@ -557,6 +562,7 @@ static int64_t pts_dtoi(double pts) + u.pts_d = pts; + return u.pts_i; + } ++#endif + + bool CDVDVideoCodecFFmpeg::AddData(const DemuxPacket &packet) + { +@@ -575,7 +581,10 @@ bool CDVDVideoCodecFFmpeg::AddData(const DemuxPacket &packet) + m_started = true; + + m_dts = packet.dts; ++ ++#if LIBAVCODEC_VERSION_MAJOR < 60 + m_pCodecContext->reordered_opaque = pts_dtoi(packet.pts); ++#endif + + AVPacket* avpkt = av_packet_alloc(); + if (!avpkt) +diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DXVA.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DXVA.cpp +index c06bd1ac0c7e6..81451995ca1db 100644 +--- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DXVA.cpp ++++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DXVA.cpp +@@ -1538,8 +1538,6 @@ int CDecoder::GetBuffer(AVCodecContext* avctx, AVFrame* pic) + return -1; + } + +- pic->reordered_opaque = avctx->reordered_opaque; +- + for (unsigned i = 0; i < 4; i++) + { + pic->data[i] = nullptr; +@@ -1556,6 +1554,10 @@ int CDecoder::GetBuffer(AVCodecContext* avctx, AVFrame* pic) + } + pic->buf[0] = buffer; + ++#if LIBAVCODEC_VERSION_MAJOR < 60 ++ pic->reordered_opaque = avctx->reordered_opaque; ++#endif ++ + Acquire(); + + return 0; +diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/VAAPI.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Video/VAAPI.cpp +index 6c4f664591a04..447a13495d4e8 100644 +--- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/VAAPI.cpp ++++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/VAAPI.cpp +@@ -867,7 +867,10 @@ int CDecoder::FFGetBuffer(AVCodecContext *avctx, AVFrame *pic, int flags) + } + pic->buf[0] = buffer; + ++#if LIBAVCODEC_VERSION_MAJOR < 60 + pic->reordered_opaque = avctx->reordered_opaque; ++#endif ++ + va->Acquire(); + return 0; + } +diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/VDPAU.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Video/VDPAU.cpp +index ec07af79de819..50e16d492ebc7 100644 +--- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/VDPAU.cpp ++++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/VDPAU.cpp +@@ -1041,7 +1041,10 @@ int CDecoder::FFGetBuffer(AVCodecContext *avctx, AVFrame *pic, int flags) + } + pic->buf[0] = buffer; + +- pic->reordered_opaque= avctx->reordered_opaque; ++#if LIBAVCODEC_VERSION_MAJOR < 60 ++ pic->reordered_opaque = avctx->reordered_opaque; ++#endif ++ + return 0; + } + + +From 928a7e4196046154419727a23c734d904e5e1b6c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Markus=20H=C3=A4rer?= <markus.haerer@gmx.net> +Date: Sun, 23 Apr 2023 23:29:28 +0200 +Subject: [PATCH] FFmpegImage: Switch back to jpeg_pipe for FFmpeg>=6.0 + +--- + xbmc/guilib/FFmpegImage.cpp | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +diff --git a/xbmc/guilib/FFmpegImage.cpp b/xbmc/guilib/FFmpegImage.cpp +index 7171c046a9ce5..429037740a7d2 100644 +--- a/xbmc/guilib/FFmpegImage.cpp ++++ b/xbmc/guilib/FFmpegImage.cpp +@@ -198,9 +198,16 @@ bool CFFmpegImage::Initialize(unsigned char* buffer, size_t bufSize) + bool is_png = (bufSize > 3 && buffer[1] == 'P' && buffer[2] == 'N' && buffer[3] == 'G'); + bool is_tiff = (bufSize > 2 && buffer[0] == 'I' && buffer[1] == 'I' && buffer[2] == '*'); + ++ // See Github #19113 ++#if LIBAVCODEC_VERSION_MAJOR < 60 ++ constexpr char jpegFormat[] = "image2"; ++#else ++ constexpr char jpegFormat[] = "jpeg_pipe"; ++#endif ++ + FFMPEG_FMT_CONST AVInputFormat* inp = nullptr; + if (is_jpeg) +- inp = av_find_input_format("image2"); ++ inp = av_find_input_format(jpegFormat); + else if (m_strMimeType == "image/apng") + inp = av_find_input_format("apng"); + else if (is_png) +@@ -213,7 +220,7 @@ bool CFFmpegImage::Initialize(unsigned char* buffer, size_t bufSize) + inp = av_find_input_format("webp_pipe"); + // brute force parse if above check already failed + else if (m_strMimeType == "image/jpeg" || m_strMimeType == "image/jpg") +- inp = av_find_input_format("image2"); ++ inp = av_find_input_format(jpegFormat); + else if (m_strMimeType == "image/png") + inp = av_find_input_format("png_pipe"); + else if (m_strMimeType == "image/tiff") + + +From 9d7f4dfd00d89d4a5d6d8095ee9b0b746051b30c Mon Sep 17 00:00:00 2001 +From: CrystalP <crystalp@kodi.tv> +Date: Mon, 1 May 2023 13:26:56 -0400 +Subject: [PATCH] [fix] extern C for ffmpeg includes + +--- + xbmc/cores/RetroPlayer/process/RPProcessInfo.h | 3 +++ + xbmc/cores/RetroPlayer/rendering/RenderTranslator.h | 3 +++ + xbmc/cores/VideoPlayer/DVDFileInfo.cpp | 4 ++-- + xbmc/cores/VideoPlayer/VideoRenderers/windows/RendererDXVA.h | 4 ++++ + .../VideoPlayer/VideoRenderers/windows/RendererShaders.h | 4 ++++ + 5 files changed, 16 insertions(+), 2 deletions(-) + +diff --git a/xbmc/cores/RetroPlayer/process/RPProcessInfo.h b/xbmc/cores/RetroPlayer/process/RPProcessInfo.h +index 9f930e78e9d84..f5ffe670d68aa 100644 +--- a/xbmc/cores/RetroPlayer/process/RPProcessInfo.h ++++ b/xbmc/cores/RetroPlayer/process/RPProcessInfo.h +@@ -17,7 +17,10 @@ + #include <string> + #include <vector> + ++extern "C" ++{ + #include <libavutil/pixfmt.h> ++} + + class CDataCacheCore; + +diff --git a/xbmc/cores/RetroPlayer/rendering/RenderTranslator.h b/xbmc/cores/RetroPlayer/rendering/RenderTranslator.h +index 575ad814fc125..d78e1c25e4070 100644 +--- a/xbmc/cores/RetroPlayer/rendering/RenderTranslator.h ++++ b/xbmc/cores/RetroPlayer/rendering/RenderTranslator.h +@@ -10,7 +10,10 @@ + + #include "cores/GameSettings.h" + ++extern "C" ++{ + #include <libavutil/pixfmt.h> ++} + + namespace KODI + { +diff --git a/xbmc/cores/VideoPlayer/DVDFileInfo.cpp b/xbmc/cores/VideoPlayer/DVDFileInfo.cpp +index 0860b40475b18..c7253bbd5497f 100644 +--- a/xbmc/cores/VideoPlayer/DVDFileInfo.cpp ++++ b/xbmc/cores/VideoPlayer/DVDFileInfo.cpp +@@ -32,8 +32,6 @@ + #include "DVDDemuxers/DVDDemuxVobsub.h" + #include "Process/ProcessInfo.h" + +-#include <libavcodec/avcodec.h> +-#include <libswscale/swscale.h> + #include "filesystem/File.h" + #include "cores/FFmpeg.h" + #include "TextureCache.h" +@@ -44,7 +42,9 @@ + #include <memory> + + extern "C" { ++#include <libavcodec/avcodec.h> + #include <libavformat/avformat.h> ++#include <libswscale/swscale.h> + } + + bool CDVDFileInfo::GetFileDuration(const std::string &path, int& duration) +diff --git a/xbmc/cores/VideoPlayer/VideoRenderers/windows/RendererDXVA.h b/xbmc/cores/VideoPlayer/VideoRenderers/windows/RendererDXVA.h +index 9412377157f94..0eed9503dc9ac 100644 +--- a/xbmc/cores/VideoPlayer/VideoRenderers/windows/RendererDXVA.h ++++ b/xbmc/cores/VideoPlayer/VideoRenderers/windows/RendererDXVA.h +@@ -13,7 +13,11 @@ + #include <map> + + #include <d3d11_4.h> ++ ++extern "C" ++{ + #include <libavutil/pixfmt.h> ++} + + enum RenderMethod; + +diff --git a/xbmc/cores/VideoPlayer/VideoRenderers/windows/RendererShaders.h b/xbmc/cores/VideoPlayer/VideoRenderers/windows/RendererShaders.h +index 945cadda76841..af4d677aae923 100644 +--- a/xbmc/cores/VideoPlayer/VideoRenderers/windows/RendererShaders.h ++++ b/xbmc/cores/VideoPlayer/VideoRenderers/windows/RendererShaders.h +@@ -13,7 +13,11 @@ + #include <map> + + #include <d3d11_4.h> ++ ++extern "C" ++{ + #include <libavutil/pixfmt.h> ++} + + #define PLANE_Y 0 + #define PLANE_U 1 diff --git a/debian/patches/workarounds/0005-pcre2.patch b/debian/patches/workarounds/0005-pcre2.patch new file mode 100644 index 0000000..7dfda8c --- /dev/null +++ b/debian/patches/workarounds/0005-pcre2.patch @@ -0,0 +1,1219 @@ +Description: Port to PCRE2. +Bug-Debian: https://bugs.debian.org/1000113 +Author: Yavor Doganov <yavor@gnu.org> +Forwarded: no +Last-Update: 2024-01-07 +--- + +--- kodi-20.2+dfsg.orig/cmake/modules/FindPCRE.cmake ++++ kodi-20.2+dfsg/cmake/modules/FindPCRE.cmake +@@ -77,45 +77,34 @@ + + else() + # Populate paths for find_package_handle_standard_args +- find_path(PCRE_INCLUDE_DIR pcre.h) ++ find_path(PCRE_INCLUDE_DIR pcre2.h) + +- find_library(PCRECPP_LIBRARY_RELEASE NAMES pcrecpp) +- find_library(PCRECPP_LIBRARY_DEBUG NAMES pcrecppd) +- +- find_library(PCRE_LIBRARY_RELEASE NAMES pcre) +- find_library(PCRE_LIBRARY_DEBUG NAMES pcred) ++ find_library(PCRE_LIBRARY_RELEASE NAMES pcre2-8) + endif() + else() + + if(PKG_CONFIG_FOUND) +- pkg_check_modules(PC_PCRE libpcrecpp QUIET) ++ pkg_check_modules(PC_PCRE libpcre2-8 QUIET) + endif() + +- find_path(PCRE_INCLUDE_DIR pcrecpp.h ++ find_path(PCRE_INCLUDE_DIR pcre2.h + PATHS ${PC_PCRE_INCLUDEDIR}) +- find_library(PCRECPP_LIBRARY_RELEASE NAMES pcrecpp +- PATHS ${PC_PCRE_LIBDIR}) +- find_library(PCRE_LIBRARY_RELEASE NAMES pcre ++ find_library(PCRE_LIBRARY_RELEASE NAMES pcre2-8 + PATHS ${PC_PCRE_LIBDIR}) +- find_library(PCRECPP_LIBRARY_DEBUG NAMES pcrecppd +- PATHS ${PC_PCRE_LIBDIR}) +- find_library(PCRE_LIBRARY_DEBUG NAMES pcred +- PATHS ${PC_PCRE_LIBDIR}) + set(PCRE_VERSION ${PC_PCRE_VERSION}) + + endif() + + include(SelectLibraryConfigurations) +- select_library_configurations(PCRECPP) + select_library_configurations(PCRE) + + include(FindPackageHandleStandardArgs) + find_package_handle_standard_args(PCRE +- REQUIRED_VARS PCRECPP_LIBRARY PCRE_LIBRARY PCRE_INCLUDE_DIR ++ REQUIRED_VARS PCRE_LIBRARY PCRE_INCLUDE_DIR + VERSION_VAR PCRE_VERSION) + + if(PCRE_FOUND) +- set(PCRE_LIBRARIES ${PCRECPP_LIBRARY} ${PCRE_LIBRARY}) ++ set(PCRE_LIBRARIES ${PCRE_LIBRARY}) + set(PCRE_INCLUDE_DIRS ${PCRE_INCLUDE_DIR}) + if(WIN32) + set(PCRE_DEFINITIONS -DPCRE_STATIC=1) +@@ -166,5 +155,5 @@ + endif() + endif() + +- mark_as_advanced(PCRE_INCLUDE_DIR PCRECPP_LIBRARY PCRE_LIBRARY) ++ mark_as_advanced(PCRE_INCLUDE_DIR PCRE_LIBRARY) + endif() +--- kodi-20.2+dfsg.orig/xbmc/utils/RegExp.h ++++ kodi-20.2+dfsg/xbmc/utils/RegExp.h +@@ -13,16 +13,8 @@ + #include <string> + #include <vector> + +-/* make sure stdlib.h is included before including pcre.h inside the +- namespace; this works around stdlib.h definitions also living in +- the PCRE namespace */ +-#include <stdlib.h> +- +-namespace PCRE { +-struct real_pcre_jit_stack; // forward declaration for PCRE without JIT +-typedef struct real_pcre_jit_stack pcre_jit_stack; +-#include <pcre.h> +-} ++#define PCRE2_CODE_UNIT_WIDTH 8 ++#include <pcre2.h> + + class CRegExp + { +@@ -143,17 +135,17 @@ + void Cleanup(); + inline bool IsValidSubNumber(int iSub) const; + +- PCRE::pcre* m_re; +- PCRE::pcre_extra* m_sd; ++ pcre2_code* m_re; ++ pcre2_match_context* m_ctxt; + static const int OVECCOUNT=(m_MaxNumOfBackrefrences + 1) * 3; + unsigned int m_offset; +- int m_iOvector[OVECCOUNT]; ++ PCRE2_SIZE* m_iOvector; + utf8Mode m_utf8Mode; + int m_iMatchCount; +- int m_iOptions; ++ uint32_t m_iOptions; + bool m_jitCompiled; + bool m_bMatched; +- PCRE::pcre_jit_stack* m_jitStack; ++ pcre2_jit_stack* m_jitStack; + std::string m_subject; + std::string m_pattern; + static int m_Utf8Supported; +--- kodi-20.2+dfsg.orig/xbmc/filesystem/FTPParse.cpp ++++ kodi-20.2+dfsg/xbmc/filesystem/FTPParse.cpp +@@ -9,8 +9,10 @@ + #include "FTPParse.h" + + #include <cmath> ++#include <cstring> + +-#include <pcrecpp.h> ++#define PCRE2_CODE_UNIT_WIDTH 8 ++#include <pcre2.h> + + CFTPParse::CFTPParse() + { +@@ -46,26 +48,31 @@ + + void CFTPParse::setTime(const std::string& str) + { ++ pcre2_code *re, *unix_re, *multinet_re, *msdos_re; ++ pcre2_match_data *md; ++ PCRE2_SPTR unix_pat, multinet_pat, msdos_pat, str_sptr; ++ PCRE2_SIZE offset; ++ int err; + /* Variables used to capture patterns via the regexes */ +- std::string month; +- std::string day; +- std::string year; +- std::string hour; +- std::string minute; +- std::string second; +- std::string am_or_pm; ++ char *month = NULL; ++ PCRE2_UCHAR *day = NULL; ++ PCRE2_UCHAR *year = NULL; ++ PCRE2_UCHAR *hour = NULL; ++ PCRE2_UCHAR *minute = NULL; ++ PCRE2_UCHAR *second = NULL; ++ PCRE2_UCHAR *am_or_pm = NULL; + + /* time struct used to set the time_t variable */ + struct tm time_struct = {}; + + /* Regex to read Unix, NetWare and NetPresenz time format */ +- pcrecpp::RE unix_re("^([A-Za-z]{3})" // month ++ unix_pat = reinterpret_cast<PCRE2_SPTR>("^([A-Za-z]{3})" // month + "\\s+(\\d{1,2})" // day of month + "\\s+([:\\d]{4,5})$" // time of day or year + ); + + /* Regex to read MultiNet time format */ +- pcrecpp::RE multinet_re("^(\\d{1,2})" // day of month ++ multinet_pat = reinterpret_cast<PCRE2_SPTR>("^(\\d{1,2})" // day of month + "-([A-Za-z]{3})" // month + "-(\\d{4})" // year + "\\s+(\\d{2})" // hour +@@ -74,7 +81,7 @@ + ); + + /* Regex to read MSDOS time format */ +- pcrecpp::RE msdos_re("^(\\d{2})" // month ++ msdos_pat = reinterpret_cast<PCRE2_SPTR>("^(\\d{2})" // month + "-(\\d{2})" // day of month + "-(\\d{2})" // year + "\\s+(\\d{2})" // hour +@@ -82,48 +89,53 @@ + "([AP]M)$" // AM or PM + ); + +- if (unix_re.FullMatch(str, &month, &day, &year)) +- { ++ unix_re = pcre2_compile(unix_pat, PCRE2_ZERO_TERMINATED, ++ 0, &err, &offset, NULL); ++ multinet_re = pcre2_compile(multinet_pat, PCRE2_ZERO_TERMINATED, ++ 0, &err, &offset, NULL); ++ msdos_re = pcre2_compile(msdos_pat, PCRE2_ZERO_TERMINATED, ++ 0, &err, &offset, NULL); ++ str_sptr = reinterpret_cast<PCRE2_SPTR>(str.c_str()); ++ md = pcre2_match_data_create(30, NULL); ++ ++ if (pcre2_match(unix_re, str_sptr, PCRE2_ZERO_TERMINATED, 0, 0, md, NULL) ++ > 0) ++ { ++ pcre2_substring_get_bynumber(md, 1, ++ reinterpret_cast<PCRE2_UCHAR **>(&month), ++ &offset); ++ pcre2_substring_get_bynumber(md, 2, &day, &offset); ++ pcre2_substring_get_bynumber(md, 3, &year, &offset); ++ re = pcre2_compile(reinterpret_cast<PCRE2_SPTR>("(\\d{2}):(\\d{2})"), ++ PCRE2_ZERO_TERMINATED, 0, &err, &offset, NULL); + /* set the month */ +- if (pcrecpp::RE("jan", +- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month)) ++ if (strcasestr(month, "jan")) + time_struct.tm_mon = 0; +- else if (pcrecpp::RE("feb", +- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month)) ++ else if (strcasestr(month, "feb")) + time_struct.tm_mon = 1; +- else if (pcrecpp::RE("mar", +- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month)) ++ else if (strcasestr(month, "mar")) + time_struct.tm_mon = 2; +- else if (pcrecpp::RE("apr", +- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month)) ++ else if (strcasestr(month, "apr")) + time_struct.tm_mon = 3; +- else if (pcrecpp::RE("may", +- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month)) ++ else if (strcasestr(month, "may")) + time_struct.tm_mon = 4; +- else if (pcrecpp::RE("jun", +- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month)) ++ else if (strcasestr(month, "jun")) + time_struct.tm_mon = 5; +- else if (pcrecpp::RE("jul", +- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month)) ++ else if (strcasestr(month, "jul")) + time_struct.tm_mon = 6; +- else if (pcrecpp::RE("aug", +- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month)) ++ else if (strcasestr(month, "aug")) + time_struct.tm_mon = 7; +- else if (pcrecpp::RE("sep", +- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month)) ++ else if (strcasestr(month, "sep")) + time_struct.tm_mon = 8; +- else if (pcrecpp::RE("oct", +- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month)) ++ else if (strcasestr(month, "oct")) + time_struct.tm_mon = 9; +- else if (pcrecpp::RE("nov", +- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month)) ++ else if (strcasestr(month, "nov")) + time_struct.tm_mon = 10; +- else if (pcrecpp::RE("dec", +- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month)) ++ else if (strcasestr(month, "dec")) + time_struct.tm_mon = 11; + + /* set the day of the month */ +- time_struct.tm_mday = atoi(day.c_str()); ++ time_struct.tm_mday = atoi(reinterpret_cast<const char *>(day)); + + time_t t = time(NULL); + struct tm *current_time; +@@ -133,11 +145,14 @@ + #else + current_time = localtime(&t); + #endif +- if (pcrecpp::RE("(\\d{2}):(\\d{2})").FullMatch(year, &hour, &minute)) ++ if (pcre2_match(re, reinterpret_cast<PCRE2_SPTR>(year), ++ PCRE2_ZERO_TERMINATED, 0, 0, md, NULL) > 0) + { ++ pcre2_substring_get_bynumber(md, 1, &hour, &offset); ++ pcre2_substring_get_bynumber(md, 2, &minute, &offset); + /* set the hour and minute */ +- time_struct.tm_hour = atoi(hour.c_str()); +- time_struct.tm_min = atoi(minute.c_str()); ++ time_struct.tm_hour = atoi(reinterpret_cast<const char *>(hour)); ++ time_struct.tm_min = atoi(reinterpret_cast<const char *>(minute)); + + /* set the year */ + if ((current_time->tm_mon - time_struct.tm_mon < 0) || +@@ -150,93 +165,99 @@ + else + { + /* set the year */ +- time_struct.tm_year = atoi(year.c_str()) - 1900; ++ time_struct.tm_year = atoi(reinterpret_cast<const char *>(year)) - 1900; + } + + /* set the day of the week */ + time_struct.tm_wday = getDayOfWeek(time_struct.tm_mon + 1, + time_struct.tm_mday, + time_struct.tm_year + 1900); ++ pcre2_code_free(re); + } +- else if (multinet_re.FullMatch(str, &day, &month, &year, +- &hour, &minute, (void*)NULL, &second)) ++ else if (pcre2_match(multinet_re, str_sptr, PCRE2_ZERO_TERMINATED, ++ 0, 0, md, NULL) > 0) + { ++ pcre2_substring_get_bynumber(md, 1, &day, &offset); ++ pcre2_substring_get_bynumber(md, 2, ++ reinterpret_cast<PCRE2_UCHAR **>(&month), ++ &offset); ++ pcre2_substring_get_bynumber(md, 3, &year, &offset); ++ pcre2_substring_get_bynumber(md, 4, &hour, &offset); ++ pcre2_substring_get_bynumber(md, 5, &minute, &offset); ++ pcre2_substring_get_bynumber(md, 7, &second, &offset); + /* set the month */ +- if (pcrecpp::RE("jan", +- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month)) ++ if (strcasestr(month, "jan")) + time_struct.tm_mon = 0; +- else if (pcrecpp::RE("feb", +- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month)) ++ else if (strcasestr(month, "feb")) + time_struct.tm_mon = 1; +- else if (pcrecpp::RE("mar", +- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month)) ++ else if (strcasestr(month, "mar")) + time_struct.tm_mon = 2; +- else if (pcrecpp::RE("apr", +- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month)) ++ else if (strcasestr(month, "apr")) + time_struct.tm_mon = 3; +- else if (pcrecpp::RE("may", +- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month)) ++ else if (strcasestr(month, "may")) + time_struct.tm_mon = 4; +- else if (pcrecpp::RE("jun", +- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month)) ++ else if (strcasestr(month, "jun")) + time_struct.tm_mon = 5; +- else if (pcrecpp::RE("jul", +- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month)) ++ else if (strcasestr(month, "jul")) + time_struct.tm_mon = 6; +- else if (pcrecpp::RE("aug", +- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month)) ++ else if (strcasestr(month, "aug")) + time_struct.tm_mon = 7; +- else if (pcrecpp::RE("sep", +- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month)) ++ else if (strcasestr(month, "sep")) + time_struct.tm_mon = 8; +- else if (pcrecpp::RE("oct", +- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month)) ++ else if (strcasestr(month, "oct")) + time_struct.tm_mon = 9; +- else if (pcrecpp::RE("nov", +- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month)) ++ else if (strcasestr(month, "nov")) + time_struct.tm_mon = 10; +- else if (pcrecpp::RE("dec", +- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month)) ++ else if (strcasestr(month, "dec")) + time_struct.tm_mon = 11; + + /* set the day of the month and year */ +- time_struct.tm_mday = atoi(day.c_str()); +- time_struct.tm_year = atoi(year.c_str()) - 1900; ++ time_struct.tm_mday = atoi(reinterpret_cast<const char *>(day)); ++ time_struct.tm_year = atoi(reinterpret_cast<const char *>(year)) - 1900; + + /* set the hour and minute */ +- time_struct.tm_hour = atoi(hour.c_str()); +- time_struct.tm_min = atoi(minute.c_str()); ++ time_struct.tm_hour = atoi(reinterpret_cast<const char *>(hour)); ++ time_struct.tm_min = atoi(reinterpret_cast<const char *>(minute)); + + /* set the second if given*/ +- if (second.length() > 0) +- time_struct.tm_sec = atoi(second.c_str()); ++ if (strlen(reinterpret_cast<const char *>(second)) > 0) ++ time_struct.tm_sec = atoi(reinterpret_cast<const char *>(second)); + + /* set the day of the week */ + time_struct.tm_wday = getDayOfWeek(time_struct.tm_mon + 1, + time_struct.tm_mday, + time_struct.tm_year + 1900); + } +- else if (msdos_re.FullMatch(str, &month, &day, +- &year, &hour, &minute, &am_or_pm)) ++ else if (pcre2_match(msdos_re, str_sptr, PCRE2_ZERO_TERMINATED, ++ 0, 0, md, NULL) > 0) + { ++ pcre2_substring_get_bynumber(md, 1, ++ reinterpret_cast<PCRE2_UCHAR **>(&month), ++ &offset); ++ pcre2_substring_get_bynumber(md, 2, &day, &offset); ++ pcre2_substring_get_bynumber(md, 3, &year, &offset); ++ pcre2_substring_get_bynumber(md, 4, &hour, &offset); ++ pcre2_substring_get_bynumber(md, 5, &minute, &offset); ++ pcre2_substring_get_bynumber(md, 6, &am_or_pm, &offset); ++ + /* set the month and the day of the month */ +- time_struct.tm_mon = atoi(month.c_str()) - 1; +- time_struct.tm_mday = atoi(day.c_str()); ++ time_struct.tm_mon = atoi(month) - 1; ++ time_struct.tm_mday = atoi(reinterpret_cast<const char *>(day)); + + /* set the year */ +- time_struct.tm_year = atoi(year.c_str()); ++ time_struct.tm_year = atoi(reinterpret_cast<const char *>(year)); + if (time_struct.tm_year < 70) + time_struct.tm_year += 100; + + /* set the hour */ +- time_struct.tm_hour = atoi(hour.c_str()); ++ time_struct.tm_hour = atoi(reinterpret_cast<const char *>(hour)); + if (time_struct.tm_hour == 12) + time_struct.tm_hour -= 12; +- if (pcrecpp::RE("PM").FullMatch(am_or_pm)) ++ if (strstr(reinterpret_cast<const char *>(am_or_pm), "PM")) + time_struct.tm_hour += 12; + + /* set the minute */ +- time_struct.tm_min = atoi(minute.c_str()); ++ time_struct.tm_min = atoi(reinterpret_cast<const char *>(minute)); + + /* set the day of the week */ + time_struct.tm_wday = getDayOfWeek(time_struct.tm_mon + 1, +@@ -246,6 +267,18 @@ + + /* now set m_time */ + m_time = mktime(&time_struct); ++ ++ pcre2_code_free(unix_re); ++ pcre2_code_free(multinet_re); ++ pcre2_code_free(msdos_re); ++ pcre2_match_data_free(md); ++ pcre2_substring_free(reinterpret_cast<PCRE2_UCHAR *>(month)); ++ pcre2_substring_free(day); ++ pcre2_substring_free(year); ++ pcre2_substring_free(hour); ++ pcre2_substring_free(minute); ++ pcre2_substring_free(second); ++ pcre2_substring_free(am_or_pm); + } + + int CFTPParse::getDayOfWeek(int month, int date, int year) +@@ -325,22 +358,22 @@ + + int CFTPParse::FTPParse(const std::string& str) + { ++ pcre2_code *unix_re, *netware_re, *netpresenz_re, *eplf_re, *multinet_re, ++ *msdos_re; ++ pcre2_match_data *md; ++ PCRE2_SPTR unix_pat, netware_pat, netpresenz_pat, eplf_pat, multinet_pat, ++ msdos_pat, str_sptr; ++ PCRE2_SIZE offset; ++ int err; + /* Various variable to capture patterns via the regexes */ +- std::string permissions; +- std::string link_count; +- std::string owner; +- std::string group; +- std::string size; +- std::string date; +- std::string name; +- std::string type; +- std::string stuff; +- std::string facts; +- std::string version; +- std::string file_id; ++ char *type = NULL; ++ PCRE2_UCHAR *size = NULL; ++ PCRE2_UCHAR *date = NULL; ++ PCRE2_UCHAR *name = NULL; ++ PCRE2_UCHAR *facts; + + /* Regex for standard Unix listing formats */ +- pcrecpp::RE unix_re("^([-bcdlps])" // type ++ unix_pat = reinterpret_cast<PCRE2_SPTR>("^([-bcdlps])" // type + "([-rwxXsStT]{9})" // permissions + "\\s+(\\d+)" // hard link count + "\\s+(\\w+)" // owner +@@ -352,7 +385,7 @@ + + /* Regex for NetWare listing formats */ + /* See http://www.novell.com/documentation/oes/ftp_enu/data/a3ep22p.html#fbhbaijf */ +- pcrecpp::RE netware_re("^([-d])" // type ++ netware_pat = reinterpret_cast<PCRE2_SPTR>("^([-d])" // type + "\\s+(\\[[-SRWCIEMFA]{8}\\])" // rights + "\\s+(\\w+)" // owner + "\\s+(\\d+)" // size +@@ -363,7 +396,7 @@ + /* Regex for NetPresenz */ + /* See http://files.stairways.com/other/ftp-list-specs-info.txt */ + /* Here we will capture permissions and size if given */ +- pcrecpp::RE netpresenz_re("^([-dl])" // type ++ netpresenz_pat = reinterpret_cast<PCRE2_SPTR>("^([-dl])" // type + "([-rwx]{9}|)" // permissions + "\\s+(.*)" // stuff + "\\s+(\\d+|)" // size +@@ -374,7 +407,7 @@ + /* Regex for EPLF */ + /* See http://cr.yp.to/ftp/list/eplf.html */ + /* SAVE: "(/,|r,|s\\d+,|m\\d+,|i[\\d!#@$%^&*()]+(\\.[\\d!#@$%^&*()]+|),)+" */ +- pcrecpp::RE eplf_re("^\\+" // initial "plus" sign ++ eplf_pat = reinterpret_cast<PCRE2_SPTR>("^\\+" // initial "plus" sign + "([^\\s]+)" // facts + "\\s(.+)$" // name + ); +@@ -382,7 +415,7 @@ + /* Regex for MultiNet */ + /* Best documentation found was + * http://www-sld.slac.stanford.edu/SLDWWW/workbook/vms_files.html */ +- pcrecpp::RE multinet_re("^([^;]+)" // name ++ multinet_pat = reinterpret_cast<PCRE2_SPTR>("^([^;]+)" // name + ";(\\d+)" // version + "\\s+([\\d/]+)" // file id + "\\s+(\\d{1,2}-[A-Za-z]{3}-\\d{4}\\s+\\d{2}:\\d{2}(:\\d{2})?)" // date +@@ -391,20 +424,42 @@ + ); + + /* Regex for MSDOS */ +- pcrecpp::RE msdos_re("^(\\d{2}-\\d{2}-\\d{2}\\s+\\d{2}:\\d{2}[AP]M)" // date ++ msdos_pat = reinterpret_cast<PCRE2_SPTR>("^(\\d{2}-\\d{2}-\\d{2}\\s+\\d{2}:\\d{2}[AP]M)" // date + "\\s+(<DIR>|[\\d]+)" // dir or size + "\\s+(.+)$" // name + ); + +- if (unix_re.FullMatch(str, &type, &permissions, &link_count, &owner, &group, &size, &date, &name)) +- { +- m_name = name; +- m_size = (uint64_t)strtod(size.c_str(), NULL); +- if (pcrecpp::RE("d").FullMatch(type)) ++ unix_re = pcre2_compile(unix_pat, PCRE2_ZERO_TERMINATED, ++ 0, &err, &offset, NULL); ++ netware_re = pcre2_compile(netware_pat, PCRE2_ZERO_TERMINATED, ++ 0, &err, &offset, NULL); ++ netpresenz_re = pcre2_compile(netpresenz_pat, PCRE2_ZERO_TERMINATED, ++ 0, &err, &offset, NULL); ++ eplf_re = pcre2_compile(eplf_pat, PCRE2_ZERO_TERMINATED, ++ 0, &err, &offset, NULL); ++ multinet_re = pcre2_compile(multinet_pat, PCRE2_ZERO_TERMINATED, ++ 0, &err, &offset, NULL); ++ msdos_re = pcre2_compile(msdos_pat, PCRE2_ZERO_TERMINATED, ++ 0, &err, &offset, NULL); ++ md = pcre2_match_data_create(30, NULL); ++ str_sptr = reinterpret_cast<PCRE2_SPTR>(str.c_str()); ++ ++ if (pcre2_match(unix_re, str_sptr, PCRE2_ZERO_TERMINATED, 0, 0, md, NULL) ++ > 0) ++ { ++ pcre2_substring_get_bynumber(md, 1, ++ reinterpret_cast<PCRE2_UCHAR **>(&type), ++ &offset); ++ pcre2_substring_get_bynumber(md, 6, &size, &offset); ++ pcre2_substring_get_bynumber(md, 7, &date, &offset); ++ pcre2_substring_get_bynumber(md, 8, &name, &offset); ++ m_name = reinterpret_cast<const char *>(name); ++ m_size = (uint64_t)strtod(reinterpret_cast<const char *>(size), NULL); ++ if (strstr(type, "d")) + m_flagtrycwd = 1; +- if (pcrecpp::RE("-").FullMatch(type)) ++ if (strstr(type, "-")) + m_flagtryretr = 1; +- if (pcrecpp::RE("l").FullMatch(type)) ++ if (strstr(type, "l")) + { + m_flagtrycwd = m_flagtryretr = 1; + // handle symlink +@@ -412,31 +467,67 @@ + if (found != std::string::npos) + m_name = m_name.substr(0, found); + } +- setTime(date); ++ setTime(reinterpret_cast<const char *>(date)); ++ pcre2_substring_free(reinterpret_cast<PCRE2_UCHAR *>(type)); ++ pcre2_substring_free(size); ++ pcre2_substring_free(date); ++ pcre2_substring_free(name); ++ pcre2_match_data_free(md); ++ pcre2_code_free(unix_re); ++ pcre2_code_free(netware_re); ++ pcre2_code_free(netpresenz_re); ++ pcre2_code_free(eplf_re); ++ pcre2_code_free(multinet_re); ++ pcre2_code_free(msdos_re); + + return 1; + } +- if (netware_re.FullMatch(str, &type, &permissions, &owner, &size, &date, &name)) ++ if (pcre2_match(netware_re, str_sptr, PCRE2_ZERO_TERMINATED, 0, 0, md, NULL) ++ > 0) + { +- m_name = name; +- m_size = (uint64_t)strtod(size.c_str(), NULL); +- if (pcrecpp::RE("d").FullMatch(type)) ++ pcre2_substring_get_bynumber(md, 1, ++ reinterpret_cast<PCRE2_UCHAR **>(&type), ++ &offset); ++ pcre2_substring_get_bynumber(md, 4, &size, &offset); ++ pcre2_substring_get_bynumber(md, 5, &date, &offset); ++ pcre2_substring_get_bynumber(md, 6, &name, &offset); ++ m_name = reinterpret_cast<const char *>(name); ++ m_size = (uint64_t)strtod(reinterpret_cast<const char *>(size), NULL); ++ if (strstr(type, "d")) + m_flagtrycwd = 1; +- if (pcrecpp::RE("-").FullMatch(type)) ++ if (strstr(type, "-")) + m_flagtryretr = 1; +- setTime(date); ++ setTime(reinterpret_cast<const char *>(date)); ++ pcre2_substring_free(reinterpret_cast<PCRE2_UCHAR *>(type)); ++ pcre2_substring_free(size); ++ pcre2_substring_free(date); ++ pcre2_substring_free(name); ++ pcre2_match_data_free(md); ++ pcre2_code_free(unix_re); ++ pcre2_code_free(netware_re); ++ pcre2_code_free(netpresenz_re); ++ pcre2_code_free(eplf_re); ++ pcre2_code_free(multinet_re); ++ pcre2_code_free(msdos_re); + + return 1; + } +- if (netpresenz_re.FullMatch(str, &type, &permissions, &stuff, &size, &date, &name)) ++ if (pcre2_match(netpresenz_re, str_sptr, PCRE2_ZERO_TERMINATED, ++ 0, 0, md, NULL) > 0) + { +- m_name = name; +- m_size = (uint64_t)strtod(size.c_str(), NULL); +- if (pcrecpp::RE("d").FullMatch(type)) ++ pcre2_substring_get_bynumber(md, 1, ++ reinterpret_cast<PCRE2_UCHAR **>(&type), ++ &offset); ++ pcre2_substring_get_bynumber(md, 4, &size, &offset); ++ pcre2_substring_get_bynumber(md, 5, &date, &offset); ++ pcre2_substring_get_bynumber(md, 6, &name, &offset); ++ m_name = reinterpret_cast<const char *>(name); ++ m_size = (uint64_t)strtod(reinterpret_cast<const char *>(size), NULL); ++ if (strstr(type, "d")) + m_flagtrycwd = 1; +- if (pcrecpp::RE("-").FullMatch(type)) ++ if (strstr(type, "-")) + m_flagtryretr = 1; +- if (pcrecpp::RE("l").FullMatch(type)) ++ if (strstr(type, "l")) + { + m_flagtrycwd = m_flagtryretr = 1; + // handle symlink +@@ -444,48 +535,118 @@ + if (found != std::string::npos) + m_name = m_name.substr(0, found); + } +- setTime(date); ++ setTime(reinterpret_cast<const char *>(date)); ++ pcre2_substring_free(reinterpret_cast<PCRE2_UCHAR *>(type)); ++ pcre2_substring_free(size); ++ pcre2_substring_free(date); ++ pcre2_substring_free(name); ++ pcre2_match_data_free(md); ++ pcre2_code_free(unix_re); ++ pcre2_code_free(netware_re); ++ pcre2_code_free(netpresenz_re); ++ pcre2_code_free(eplf_re); ++ pcre2_code_free(multinet_re); ++ pcre2_code_free(msdos_re); + + return 1; + } +- if (eplf_re.FullMatch(str, &facts, &name)) ++ if (pcre2_match(eplf_re, str_sptr, PCRE2_ZERO_TERMINATED, 0, 0, md, NULL) ++ > 0) + { ++ pcre2_code *re; ++ ++ pcre2_substring_get_bynumber(md, 1, &facts, &offset); ++ pcre2_substring_get_bynumber(md, 2, &name, &offset); + /* Get the type, size, and date from the facts */ +- pcrecpp::RE("(\\+|,)(r|/),").PartialMatch(facts, (void*)NULL, &type); +- pcrecpp::RE("(\\+|,)s(\\d+),").PartialMatch(facts, (void*)NULL, &size); +- pcrecpp::RE("(\\+|,)m(\\d+),").PartialMatch(facts, (void*)NULL, &date); +- +- m_name = name; +- m_size = (uint64_t)strtod(size.c_str(), NULL); +- if (pcrecpp::RE("/").FullMatch(type)) ++ re = pcre2_compile(reinterpret_cast<PCRE2_SPTR>("(\\+|,)(r|/),"), ++ PCRE2_ZERO_TERMINATED, 0, &err, &offset, NULL); ++ if (pcre2_match(re, facts, PCRE2_ZERO_TERMINATED, 0, ++ PCRE2_PARTIAL_SOFT, md, NULL) > 0) ++ pcre2_substring_get_bynumber(md, 2, ++ reinterpret_cast<PCRE2_UCHAR **>(&type), ++ &offset); ++ pcre2_code_free(re); ++ re = pcre2_compile(reinterpret_cast<PCRE2_SPTR>("(\\+|,)s(\\d+),"), ++ PCRE2_ZERO_TERMINATED, 0, &err, &offset, NULL); ++ if (pcre2_match(re, facts, PCRE2_ZERO_TERMINATED, 0, ++ PCRE2_PARTIAL_SOFT, md, NULL) > 0) ++ pcre2_substring_get_bynumber(md, 2, &size, &offset); ++ pcre2_code_free(re); ++ re = pcre2_compile(reinterpret_cast<PCRE2_SPTR>("(\\+|,)m(\\d+),"), ++ PCRE2_ZERO_TERMINATED, 0, &err, &offset, NULL); ++ if (pcre2_match(re, facts, PCRE2_ZERO_TERMINATED, 0, ++ PCRE2_PARTIAL_SOFT, md, NULL) > 0) ++ pcre2_substring_get_bynumber(md, 2, &date, &offset); ++ pcre2_code_free(re); ++ pcre2_substring_free(facts); ++ ++ m_name = reinterpret_cast<const char *>(name); ++ m_size = (uint64_t)strtod(reinterpret_cast<const char *>(size), NULL); ++ if (strstr(type, "/")) + m_flagtrycwd = 1; +- if (pcrecpp::RE("r").FullMatch(type)) ++ if (strstr(type, "r")) + m_flagtryretr = 1; + /* eplf stores the date in time_t format already */ +- m_time = atoi(date.c_str()); ++ m_time = atoi(reinterpret_cast<const char *>(date)); ++ pcre2_substring_free(reinterpret_cast<PCRE2_UCHAR *>(type)); ++ pcre2_substring_free(size); ++ pcre2_substring_free(date); ++ pcre2_substring_free(name); ++ pcre2_match_data_free(md); ++ pcre2_code_free(unix_re); ++ pcre2_code_free(netware_re); ++ pcre2_code_free(netpresenz_re); ++ pcre2_code_free(eplf_re); ++ pcre2_code_free(multinet_re); ++ pcre2_code_free(msdos_re); + + return 1; + } +- if (multinet_re.FullMatch(str, &name, &version, &file_id, &date, (void*)NULL, &owner, &permissions)) ++ if (pcre2_match(multinet_re, str_sptr, PCRE2_ZERO_TERMINATED, 0, 0, md, NULL) ++ > 0) + { +- if (pcrecpp::RE("\\.DIR$").PartialMatch(name)) ++ pcre2_code *re; ++ std::string tmp; ++ ++ pcre2_substring_get_bynumber(md, 1, &name, &offset); ++ pcre2_substring_get_bynumber(md, 4, &date, &offset); ++ re = pcre2_compile(reinterpret_cast<PCRE2_SPTR>("\\.DIR$"), ++ PCRE2_ZERO_TERMINATED, 0, &err, &offset, NULL); ++ //if (pcrecpp::RE("\\.DIR$").PartialMatch(name)) ++ tmp = reinterpret_cast<const char *>(name); ++ if (pcre2_match(re, name, PCRE2_ZERO_TERMINATED, 0, PCRE2_PARTIAL_SOFT, ++ md, NULL) > 0) + { +- name.resize(name.size() - 4); ++ tmp.resize(tmp.size() - 4); + m_flagtrycwd = 1; + } + else + m_flagtryretr = 1; +- m_name = name; +- setTime(date); ++ m_name = tmp; ++ setTime(reinterpret_cast<const char *>(date)); + /* Multinet doesn't provide a size */ + m_size = 0; ++ pcre2_substring_free(date); ++ pcre2_substring_free(name); ++ pcre2_match_data_free(md); ++ pcre2_code_free(re); ++ pcre2_code_free(unix_re); ++ pcre2_code_free(netware_re); ++ pcre2_code_free(netpresenz_re); ++ pcre2_code_free(eplf_re); ++ pcre2_code_free(multinet_re); ++ pcre2_code_free(msdos_re); + + return 1; + } +- if (msdos_re.FullMatch(str, &date, &size, &name)) ++ if (pcre2_match(msdos_re, str_sptr, PCRE2_ZERO_TERMINATED, 0, 0, md, NULL) ++ > 0) + { +- m_name = name; +- if (pcrecpp::RE("<DIR>").FullMatch(size)) ++ pcre2_substring_get_bynumber(md, 1, &date, &offset); ++ pcre2_substring_get_bynumber(md, 2, &size, &offset); ++ pcre2_substring_get_bynumber(md, 3, &name, &offset); ++ m_name = reinterpret_cast<const char *>(name); ++ if (strstr(reinterpret_cast<const char *>(size), "<DIR>")) + { + m_flagtrycwd = 1; + m_size = 0; +@@ -493,12 +654,29 @@ + else + { + m_flagtryretr = 1; +- m_size = (uint64_t)strtod(size.c_str(), NULL); ++ m_size = (uint64_t)strtod(reinterpret_cast<const char *>(size), NULL); + } +- setTime(date); ++ setTime(reinterpret_cast<const char *>(date)); ++ pcre2_substring_free(date); ++ pcre2_substring_free(size); ++ pcre2_substring_free(name); ++ pcre2_match_data_free(md); ++ pcre2_code_free(unix_re); ++ pcre2_code_free(netware_re); ++ pcre2_code_free(netpresenz_re); ++ pcre2_code_free(eplf_re); ++ pcre2_code_free(multinet_re); ++ pcre2_code_free(msdos_re); + + return 1; + } ++ pcre2_match_data_free(md); ++ pcre2_code_free(unix_re); ++ pcre2_code_free(netware_re); ++ pcre2_code_free(netpresenz_re); ++ pcre2_code_free(eplf_re); ++ pcre2_code_free(multinet_re); ++ pcre2_code_free(msdos_re); + + return 0; + } +--- kodi-20.2+dfsg.orig/xbmc/utils/RegExp.cpp ++++ kodi-20.2+dfsg/xbmc/utils/RegExp.cpp +@@ -16,27 +16,6 @@ + #include <stdlib.h> + #include <string.h> + +-using namespace PCRE; +- +-#ifndef PCRE_UCP +-#define PCRE_UCP 0 +-#endif // PCRE_UCP +- +-#ifdef PCRE_CONFIG_JIT +-#define PCRE_HAS_JIT_CODE 1 +-#endif +- +-#ifndef PCRE_STUDY_JIT_COMPILE +-#define PCRE_STUDY_JIT_COMPILE 0 +-#endif +-#ifndef PCRE_INFO_JIT +-// some unused number +-#define PCRE_INFO_JIT 2048 +-#endif +-#ifndef PCRE_HAS_JIT_CODE +-#define pcre_free_study(x) pcre_free((x)) +-#endif +- + int CRegExp::m_Utf8Supported = -1; + int CRegExp::m_UcpSupported = -1; + int CRegExp::m_JitSupported = -1; +@@ -51,25 +30,24 @@ + { + m_utf8Mode = utf8; + m_re = NULL; +- m_sd = NULL; +- m_iOptions = PCRE_DOTALL | PCRE_NEWLINE_ANY; ++ m_ctxt = NULL; ++ m_iOptions = PCRE2_DOTALL; + if(caseless) +- m_iOptions |= PCRE_CASELESS; ++ m_iOptions |= PCRE2_CASELESS; + if (m_utf8Mode == forceUtf8) + { + if (IsUtf8Supported()) +- m_iOptions |= PCRE_UTF8; ++ m_iOptions |= PCRE2_UTF; + if (AreUnicodePropertiesSupported()) +- m_iOptions |= PCRE_UCP; ++ m_iOptions |= PCRE2_UCP; + } + + m_offset = 0; + m_jitCompiled = false; + m_bMatched = false; + m_iMatchCount = 0; ++ m_iOvector = NULL; + m_jitStack = NULL; +- +- memset(m_iOvector, 0, sizeof(m_iOvector)); + } + + CRegExp::CRegExp(bool caseless, CRegExp::utf8Mode utf8, const char *re, studyMode study /*= NoStudy*/) +@@ -225,7 +203,8 @@ + CRegExp::CRegExp(const CRegExp& re) + { + m_re = NULL; +- m_sd = NULL; ++ m_ctxt = NULL; ++ m_iOvector = NULL; + m_jitStack = NULL; + m_utf8Mode = re.m_utf8Mode; + m_iOptions = re.m_iOptions; +@@ -240,12 +219,13 @@ + m_pattern = re.m_pattern; + if (re.m_re) + { +- if (pcre_fullinfo(re.m_re, NULL, PCRE_INFO_SIZE, &size) >= 0) ++ if (pcre2_pattern_info(re.m_re, PCRE2_INFO_SIZE, &size) >= 0) + { +- if ((m_re = (pcre*)malloc(size))) ++ if ((m_re = pcre2_code_copy(re.m_re))) + { +- memcpy(m_re, re.m_re, size); +- memcpy(m_iOvector, re.m_iOvector, OVECCOUNT*sizeof(int)); ++ if (re.m_ctxt) ++ m_ctxt = pcre2_match_context_copy(re.m_ctxt); ++ m_iOvector = re.m_iOvector; + m_offset = re.m_offset; + m_iMatchCount = re.m_iMatchCount; + m_bMatched = re.m_bMatched; +@@ -273,18 +253,28 @@ + m_jitCompiled = false; + m_bMatched = false; + m_iMatchCount = 0; +- const char *errMsg = NULL; +- int errOffset = 0; +- int options = m_iOptions; ++ pcre2_compile_context *ctxt; ++ int errCode; ++ char errMsg[120]; ++ PCRE2_SIZE errOffset; ++ uint32_t options = m_iOptions; + if (m_utf8Mode == autoUtf8 && requireUtf8(re)) +- options |= (IsUtf8Supported() ? PCRE_UTF8 : 0) | (AreUnicodePropertiesSupported() ? PCRE_UCP : 0); ++ options |= (IsUtf8Supported() ? PCRE2_UTF : 0) | (AreUnicodePropertiesSupported() ? PCRE2_UCP : 0); + + Cleanup(); + +- m_re = pcre_compile(re, options, &errMsg, &errOffset, NULL); ++ ctxt = pcre2_compile_context_create(NULL); ++ pcre2_set_newline(ctxt, PCRE2_NEWLINE_ANY); ++ m_re = pcre2_compile(reinterpret_cast<PCRE2_SPTR>(re), ++ PCRE2_ZERO_TERMINATED, options, ++ &errCode, &errOffset, ctxt); ++ pcre2_compile_context_free(ctxt); ++ + if (!m_re) + { + m_pattern.clear(); ++ pcre2_get_error_message(errCode, reinterpret_cast<PCRE2_UCHAR *>(errMsg), ++ sizeof(errMsg)); + CLog::Log(LOGERROR, "PCRE: {}. Compilation failed at offset {} in expression '{}'", errMsg, + errOffset, re); + return false; +@@ -295,23 +285,12 @@ + if (study) + { + const bool jitCompile = (study == StudyWithJitComp) && IsJitSupported(); +- const int studyOptions = jitCompile ? PCRE_STUDY_JIT_COMPILE : 0; + +- m_sd = pcre_study(m_re, studyOptions, &errMsg); +- if (errMsg != NULL) +- { +- CLog::Log(LOGWARNING, "{}: PCRE error \"{}\" while studying expression", __FUNCTION__, +- errMsg); +- if (m_sd != NULL) +- { +- pcre_free_study(m_sd); +- m_sd = NULL; +- } +- } +- else if (jitCompile) ++ if (jitCompile) + { +- int jitPresent = 0; +- m_jitCompiled = (pcre_fullinfo(m_re, m_sd, PCRE_INFO_JIT, &jitPresent) == 0 && jitPresent == 1); ++ pcre2_jit_compile(m_re, PCRE2_JIT_COMPLETE); ++ size_t jitPresent = 0; ++ m_jitCompiled = (pcre2_pattern_info(m_re, PCRE2_INFO_JITSIZE, &jitPresent) == 0 && jitPresent > 0); + } + } + +@@ -325,6 +304,9 @@ + + int CRegExp::PrivateRegFind(size_t bufferLen, const char *str, unsigned int startoffset /* = 0*/, int maxNumberOfCharsToTest /*= -1*/) + { ++ pcre2_match_data *md; ++ PCRE2_SIZE offset; ++ + m_offset = 0; + m_bMatched = false; + m_iMatchCount = 0; +@@ -347,37 +329,47 @@ + return -1; + } + +-#ifdef PCRE_HAS_JIT_CODE ++ if (!m_ctxt) ++ m_ctxt = pcre2_match_context_create(NULL); ++ + if (m_jitCompiled && !m_jitStack) + { +- m_jitStack = pcre_jit_stack_alloc(32*1024, 512*1024); ++ m_jitStack = pcre2_jit_stack_create(32*1024, 512*1024, NULL); + if (m_jitStack == NULL) + CLog::Log(LOGWARNING, "{}: can't allocate address space for JIT stack", __FUNCTION__); + +- pcre_assign_jit_stack(m_sd, NULL, m_jitStack); ++ pcre2_jit_stack_assign(m_ctxt, NULL, m_jitStack); + } +-#endif + + if (maxNumberOfCharsToTest >= 0) + bufferLen = std::min<size_t>(bufferLen, startoffset + maxNumberOfCharsToTest); + + m_subject.assign(str + startoffset, bufferLen - startoffset); +- int rc = pcre_exec(m_re, NULL, m_subject.c_str(), m_subject.length(), 0, 0, m_iOvector, OVECCOUNT); ++ md = pcre2_match_data_create(OVECCOUNT, NULL); ++ int rc = pcre2_match(m_re, ++ reinterpret_cast<PCRE2_SPTR>(m_subject.c_str()), ++ m_subject.length(), 0, 0, md, m_ctxt); ++ m_iOvector = pcre2_get_ovector_pointer(md); ++ offset = pcre2_get_startchar(md); ++ pcre2_match_data_free(md); + + if (rc<1) + { + static const int fragmentLen = 80; // length of excerpt before erroneous char for log + switch(rc) + { +- case PCRE_ERROR_NOMATCH: ++ case PCRE2_ERROR_NOMATCH: + return -1; + +- case PCRE_ERROR_MATCHLIMIT: ++ case PCRE2_ERROR_MATCHLIMIT: + CLog::Log(LOGERROR, "PCRE: Match limit reached"); + return -1; + +-#ifdef PCRE_ERROR_SHORTUTF8 +- case PCRE_ERROR_SHORTUTF8: ++ case PCRE2_ERROR_UTF8_ERR1: ++ case PCRE2_ERROR_UTF8_ERR2: ++ case PCRE2_ERROR_UTF8_ERR3: ++ case PCRE2_ERROR_UTF8_ERR4: ++ case PCRE2_ERROR_UTF8_ERR5: + { + const size_t startPos = (m_subject.length() > fragmentLen) ? CUtf8Utils::RFindValidUtf8Char(m_subject, m_subject.length() - fragmentLen) : 0; + if (startPos != std::string::npos) +@@ -389,22 +381,41 @@ + CLog::Log(LOGERROR, "PCRE: Bad UTF-8 character at the end of string"); + return -1; + } +-#endif +- case PCRE_ERROR_BADUTF8: ++ case PCRE2_ERROR_UTF8_ERR6: ++ case PCRE2_ERROR_UTF8_ERR7: ++ case PCRE2_ERROR_UTF8_ERR8: ++ case PCRE2_ERROR_UTF8_ERR9: ++ case PCRE2_ERROR_UTF8_ERR10: ++ case PCRE2_ERROR_UTF8_ERR11: ++ case PCRE2_ERROR_UTF8_ERR12: ++ case PCRE2_ERROR_UTF8_ERR13: ++ case PCRE2_ERROR_UTF8_ERR14: ++ case PCRE2_ERROR_UTF8_ERR15: ++ case PCRE2_ERROR_UTF8_ERR16: ++ case PCRE2_ERROR_UTF8_ERR17: ++ case PCRE2_ERROR_UTF8_ERR18: ++ case PCRE2_ERROR_UTF8_ERR19: ++ case PCRE2_ERROR_UTF8_ERR20: ++ case PCRE2_ERROR_UTF8_ERR21: + { ++ char errbuf[120]; ++ ++ pcre2_get_error_message(rc, ++ reinterpret_cast<PCRE2_UCHAR *>(errbuf), ++ sizeof(errbuf)); + const size_t startPos = (m_iOvector[0] > fragmentLen) ? CUtf8Utils::RFindValidUtf8Char(m_subject, m_iOvector[0] - fragmentLen) : 0; +- if (m_iOvector[0] >= 0 && startPos != std::string::npos) ++ if ((int)m_iOvector[0] >= 0 && startPos != std::string::npos) + CLog::Log(LOGERROR, + "PCRE: Bad UTF-8 character, error code: {}, position: {}. Text before bad " + "char: \"{}\"", +- m_iOvector[1], m_iOvector[0], ++ errbuf, offset, + m_subject.substr(startPos, m_iOvector[0] - startPos + 1)); + else + CLog::Log(LOGERROR, "PCRE: Bad UTF-8 character, error code: {}, position: {}", +- m_iOvector[1], m_iOvector[0]); ++ errbuf, offset); + return -1; + } +- case PCRE_ERROR_BADUTF8_OFFSET: ++ case PCRE2_ERROR_BADUTFOFFSET: + CLog::Log(LOGERROR, "PCRE: Offset is pointing to the middle of UTF-8 character"); + return -1; + +@@ -423,7 +434,7 @@ + { + int c = -1; + if (m_re) +- pcre_fullinfo(m_re, NULL, PCRE_INFO_CAPTURECOUNT, &c); ++ pcre2_pattern_info(m_re, PCRE2_INFO_CAPTURECOUNT, &c); + return c; + } + +@@ -524,7 +535,7 @@ + bool CRegExp::GetNamedSubPattern(const char* strName, std::string& strMatch) const + { + strMatch.clear(); +- int iSub = pcre_get_stringnumber(m_re, strName); ++ int iSub = pcre2_substring_number_from_name(m_re, reinterpret_cast<PCRE2_SPTR>(strName)); + if (!IsValidSubNumber(iSub)) + return false; + strMatch = GetMatch(iSub); +@@ -533,7 +544,7 @@ + + int CRegExp::GetNamedSubPatternNumber(const char* strName) const + { +- return pcre_get_stringnumber(m_re, strName); ++ return pcre2_substring_number_from_name(m_re, reinterpret_cast<PCRE2_SPTR>(strName)); + } + + void CRegExp::DumpOvector(int iLog /* = LOGDEBUG */) +@@ -558,23 +569,21 @@ + { + if (m_re) + { +- pcre_free(m_re); ++ pcre2_code_free(m_re); + m_re = NULL; + } + +- if (m_sd) ++ if (m_ctxt) + { +- pcre_free_study(m_sd); +- m_sd = NULL; ++ pcre2_match_context_free(m_ctxt); ++ m_ctxt = NULL; + } + +-#ifdef PCRE_HAS_JIT_CODE + if (m_jitStack) + { +- pcre_jit_stack_free(m_jitStack); ++ pcre2_jit_stack_free(m_jitStack); + m_jitStack = NULL; + } +-#endif + } + + inline bool CRegExp::IsValidSubNumber(int iSub) const +@@ -587,7 +596,7 @@ + { + if (m_Utf8Supported == -1) + { +- if (pcre_config(PCRE_CONFIG_UTF8, &m_Utf8Supported) != 0) ++ if (pcre2_config(PCRE2_CONFIG_UNICODE, &m_Utf8Supported) < 0) + m_Utf8Supported = 0; + } + +@@ -596,13 +605,11 @@ + + bool CRegExp::AreUnicodePropertiesSupported(void) + { +-#if defined(PCRE_CONFIG_UNICODE_PROPERTIES) && PCRE_UCP != 0 + if (m_UcpSupported == -1) + { +- if (pcre_config(PCRE_CONFIG_UNICODE_PROPERTIES, &m_UcpSupported) != 0) ++ if (pcre2_config(PCRE2_CONFIG_UNICODE, &m_UcpSupported) < 0) + m_UcpSupported = 0; + } +-#endif + + return m_UcpSupported == 1; + } +@@ -625,13 +632,13 @@ + + if (!utf8FullSupport) + { ++ char ver[24]; ++ ++ pcre2_config(PCRE2_CONFIG_VERSION, ver); + CLog::Log(LOGINFO, +- "Consider installing PCRE lib version 8.10 or later with enabled Unicode properties " ++ "Consider installing PCRE lib version 10.10 or later with enabled Unicode properties " + "and UTF-8 support. Your PCRE lib version: {}", +- PCRE::pcre_version()); +-#if PCRE_UCP == 0 +- CLog::Log(LOGINFO, "You will need to rebuild XBMC after PCRE lib update."); +-#endif ++ ver); + } + + return utf8FullSupport; +@@ -641,9 +648,7 @@ + { + if (m_JitSupported == -1) + { +-#ifdef PCRE_HAS_JIT_CODE +- if (pcre_config(PCRE_CONFIG_JIT, &m_JitSupported) != 0) +-#endif ++ if (pcre2_config(PCRE2_CONFIG_JIT, &m_JitSupported) < 0) + m_JitSupported = 0; + } + +--- kodi-20.2+dfsg.orig/xbmc/utils/test/TestRegExp.cpp ++++ kodi-20.2+dfsg/xbmc/utils/test/TestRegExp.cpp +@@ -30,6 +30,29 @@ + EXPECT_EQ(-1, regex.RegFind("Test string.")); + } + ++TEST(TestRegExp, InvalidPattern) ++{ ++ CRegExp regex; ++ ++ EXPECT_FALSE(regex.RegComp("+")); ++} ++ ++TEST(TestRegExp, Unicode) ++{ ++ CRegExp regex; ++ ++ EXPECT_TRUE(regex.RegComp("Бог!$")); ++ EXPECT_EQ(12, regex.RegFind("С нами Бог!")); ++} ++ ++TEST(TestRegExp, JIT) ++{ ++ CRegExp regex; ++ ++ EXPECT_TRUE(regex.RegComp(".JIT.", CRegExp::StudyWithJitComp)); ++ EXPECT_EQ(12, regex.RegFind("Test string, JIT-matched.")); ++} ++ + TEST(TestRegExp, GetReplaceString) + { + CRegExp regex; diff --git a/debian/patches/workarounds/0006-loongarch.patch b/debian/patches/workarounds/0006-loongarch.patch new file mode 100644 index 0000000..e028ae4 --- /dev/null +++ b/debian/patches/workarounds/0006-loongarch.patch @@ -0,0 +1,40 @@ +From 1c2c5150eb17f432a5d9ad81a97d999662a4e669 Mon Sep 17 00:00:00 2001 +From: Dandan Zhang <zhangdandan@loongson.cn> +Date: Tue, 24 Oct 2023 07:59:42 +0000 +Subject: [PATCH] Add LoongArch support to system info + +--- + xbmc/utils/SystemInfo.cpp | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/xbmc/utils/SystemInfo.cpp b/xbmc/utils/SystemInfo.cpp +index d1e53c41bb95e..92ef021efb158 100644 +--- a/xbmc/utils/SystemInfo.cpp ++++ b/xbmc/utils/SystemInfo.cpp +@@ -952,7 +952,7 @@ int CSysInfo::GetKernelBitness(void) + std::string machine(un.machine); + if (machine == "x86_64" || machine == "amd64" || machine == "arm64" || machine == "aarch64" || + machine == "ppc64" || machine == "ppc64el" || machine == "ppc64le" || machine == "ia64" || +- machine == "mips64" || machine == "s390x" || machine == "riscv64" || ++ machine == "loongarch64" || machine == "mips64" || machine == "s390x" || machine == "riscv64" || + machine == "sparc64" || machine == "alpha") + kernelBitness = 64; + else +@@ -1080,6 +1080,8 @@ const std::string& CSysInfo::GetKernelCpuFamily(void) + std::string machine(un.machine); + if (machine.compare(0, 3, "arm", 3) == 0 || machine.compare(0, 7, "aarch64", 7) == 0) + kernelCpuFamily = "ARM"; ++ else if (machine.compare(0, 9, "loongarch", 9) == 0 || machine.compare(0, 7, "loong64", 7) == 0) ++ kernelCpuFamily = "LoongArch"; + else if (machine.compare(0, 4, "mips", 4) == 0) + kernelCpuFamily = "MIPS"; + else if (machine.compare(0, 4, "i686", 4) == 0 || machine == "i386" || machine == "amd64" || machine.compare(0, 3, "x86", 3) == 0) +@@ -1466,6 +1468,8 @@ std::string CSysInfo::GetBuildTargetCpuFamily(void) + return "ARM (Thumb)"; + #elif defined(__arm__) || defined(_M_ARM) || defined (__aarch64__) + return "ARM"; ++#elif defined(__loongarch__) ++ return "LoongArch"; + #elif defined(__mips__) || defined(mips) || defined(__mips) + return "MIPS"; + #elif defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_X64) || defined(_M_AMD64) || \ diff --git a/debian/patches/workarounds/0007-swig.patch b/debian/patches/workarounds/0007-swig.patch new file mode 100644 index 0000000..94fbcf9 --- /dev/null +++ b/debian/patches/workarounds/0007-swig.patch @@ -0,0 +1,10 @@ +diff --git a/xbmc/interfaces/swig/AddonModuleXbmcaddon.i b/xbmc/interfaces/swig/AddonModuleXbmcaddon.i +index 6c00a1caa2..d38794c043 100644 +--- a/xbmc/interfaces/swig/AddonModuleXbmcaddon.i ++++ b/xbmc/interfaces/swig/AddonModuleXbmcaddon.i +@@ -33,5 +33,6 @@ using namespace xbmcaddon; + %include "interfaces/legacy/AddonString.h" + + %include "interfaces/legacy/Addon.h" ++%nodefaultctor Settings; + %include "interfaces/legacy/Settings.h" diff --git a/debian/rules b/debian/rules new file mode 100755 index 0000000..b11b575 --- /dev/null +++ b/debian/rules @@ -0,0 +1,294 @@ +#!/usr/bin/make -f + +# Avoid custom build rule silencing +export V=1 + +# Include /usr/share/dpkg/pkg-info.mk to get DEB_{SOURCE,VERSION} +include /usr/share/dpkg/pkg-info.mk + +# Include /usr/share/dpkg/architecture.mk to get DEB_HOST_{MULTI,}ARCH +include /usr/share/dpkg/architecture.mk + +# bindnow breaks wrappers used in with libdvdread +export DEB_BUILD_MAINT_OPTIONS = hardening=+all,-bindnow + +DVDNAV_COMPONENT = libdvdnav-embedded +DVDNAV_URL = tools/depends/target/libdvdnav/libdvdnav-embedded.tar.xz +DVDREAD_COMPONENT = libdvdread-embedded +DVDREAD_URL = tools/depends/target/libdvdread/libdvdread-embedded.tar.xz + +export DEB_CFLAGS_MAINT_STRIP = -O2 +export DEB_CFLAGS_MAINT_APPEND = -O3 +export DEB_CXXFLAGS_MAINT_STRIP = -O2 +export DEB_CXXFLAGS_MAINT_APPEND = -O3 + +BUILD_WAYLAND := yes +BUILD_GBM := yes + +NUMCPU = +# Support parallel=<n> in DEB_BUILD_OPTIONS (see #209008) +ifneq (,$(filter parallel=%,$(subst $(COMMA), ,$(DEB_BUILD_OPTIONS)))) + NUMCPU := $(subst parallel=,,$(filter parallel=%,$(subst $(COMMA), ,$(DEB_BUILD_OPTIONS)))) +endif + +# Various environment variables to set +export DEB_LDFLAGS_MAINT_APPEND = -latomic -lpthread +# for embedded libdvd* and Kodi from Debian patch: +export DEB_CPPFLAGS_MAINT_APPEND = -D_XBMC -DDEB_VERSION=\"$(DEB_VERSION)\" + +KODI_PLATFORMS := x11 + +ifeq ($(BUILD_WAYLAND),yes) + KODI_PLATFORMS := $(KODI_PLATFORMS) wayland +endif +ifeq ($(BUILD_GBM),yes) + KODI_PLATFORMS := $(KODI_PLATFORMS) gbm +endif + +# basilgello: keep these overrides to ensure CMake honors +# the 32-bit architecture requested by 'dpkg-buildpackage' +# (like 'i486-linux') on 64-bit machines (like 'amd64'). +ifneq (,$(filter alpha,$(DEB_HOST_ARCH))) +EXTRA_FLAGS := $(EXTRA_FLAGS) -DWITH_ARCH=alpha +else ifneq (,$(filter amd64,$(DEB_HOST_ARCH))) +EXTRA_FLAGS := $(EXTRA_FLAGS) -DWITH_ARCH=x86_64-linux +else ifneq (,$(filter arm64,$(DEB_HOST_ARCH))) +EXTRA_FLAGS := $(EXTRA_FLAGS) -DWITH_ARCH=aarch64 +else ifneq (,$(filter armel armhf,$(DEB_HOST_ARCH))) +EXTRA_FLAGS := $(EXTRA_FLAGS) -DWITH_ARCH=arm +else ifneq (,$(filter i386,$(DEB_HOST_ARCH))) +EXTRA_FLAGS := $(EXTRA_FLAGS) -DWITH_ARCH=i486-linux +else ifneq (,$(filter m68k,$(DEB_HOST_ARCH))) +EXTRA_FLAGS := $(EXTRA_FLAGS) -DWITH_ARCH=m68k +else ifneq (,$(filter mipsel,$(DEB_HOST_ARCH))) +EXTRA_FLAGS := $(EXTRA_FLAGS) -DWITH_ARCH=mips +else ifneq (,$(filter mips64el,$(DEB_HOST_ARCH))) +EXTRA_FLAGS := $(EXTRA_FLAGS) -DWITH_ARCH=mips64 +else ifneq (,$(filter powerpc,$(DEB_HOST_ARCH))) +EXTRA_FLAGS := $(EXTRA_FLAGS) -DWITH_ARCH=ppc +else ifneq (,$(filter ppc64,$(DEB_HOST_ARCH))) +EXTRA_FLAGS := $(EXTRA_FLAGS) -DWITH_ARCH=ppc64 +else ifneq (,$(filter ppc64el,$(DEB_HOST_ARCH))) +EXTRA_FLAGS := $(EXTRA_FLAGS) -DWITH_ARCH=ppc64 +else ifneq (,$(filter riscv64,$(DEB_HOST_ARCH))) +EXTRA_FLAGS := $(EXTRA_FLAGS) -DWITH_ARCH=riscv64 +else ifneq (,$(filter s390x,$(DEB_HOST_ARCH))) +EXTRA_FLAGS := $(EXTRA_FLAGS) -DWITH_ARCH=s390x +# TODO: Workaround for #1043076 - remove when resolved +export DEB_CFLAGS_MAINT_APPEND = -O3 -fexcess-precision=fast +export DEB_CXXFLAGS_MAINT_APPEND = -O3 -fexcess-precision=fast +else ifneq (,$(filter sh4,$(DEB_HOST_ARCH))) +EXTRA_FLAGS := $(EXTRA_FLAGS) -DWITH_ARCH=sh4 +else ifneq (,$(filter sparc64,$(DEB_HOST_ARCH))) +EXTRA_FLAGS := $(EXTRA_FLAGS) -DWITH_ARCH=sparc64 +endif + +# Build arm* architectures with GLES instead of GL +# (Closes: 1056563) +ifneq (,$(filter armel armhf arm64,$(DEB_HOST_ARCH))) +EXTRA_FLAGS := $(EXTRA_FLAGS) -DAPP_RENDER_SYSTEM=gles +else +EXTRA_FLAGS := $(EXTRA_FLAGS) -DAPP_RENDER_SYSTEM=gl +endif + +# basilgello: If cross-compiling, tell Kodi to look for native prerequisites +# in $(CURDIR)/native-tools, where the override_dh_autoconfigure step builds +# them for the build architecture (the native architecture of builder machine) +ifneq ($(DEB_BUILD_GNU_TYPE),$(DEB_HOST_GNU_TYPE)) +EXTRA_FLAGS := $(EXTRA_FLAGS) \ + -DWITH_JSONSCHEMABUILDER=$(CURDIR)/native-tools/bin/JsonSchemaBuilder \ + -DWITH_TEXTUREPACKER=$(CURDIR)/native-tools/bin/TexturePacker +endif + +# Kodi configuration options +# +KODI_OPTS=\ +-DVERBOSE=1 \ +-DUSE_LTO=$(NUMCPU) \ +-DCMAKE_BUILD_TYPE=RelWithDebInfo \ +-DENABLE_AIRTUNES=ON \ +-DENABLE_ALSA=ON \ +-DENABLE_AVAHI=ON \ +-DENABLE_BLURAY=ON \ +-DENABLE_CEC=ON \ +-DENABLE_DBUS=ON \ +-DENABLE_DEBUGFISSION=OFF \ +-DENABLE_DVDCSS=OFF \ +-DENABLE_EVENTCLIENTS=ON \ +-DENABLE_INTERNAL_CROSSGUID=OFF \ +-DENABLE_INTERNAL_DATE=OFF \ +-DENABLE_INTERNAL_FFMPEG=OFF \ +-DENABLE_INTERNAL_KISSFFT=OFF \ +-DENABLE_INTERNAL_LIBDVD=ON \ +-DENABLE_INTERNAL_RapidJSON=OFF \ +-DENABLE_INTERNAL_TZDATA=OFF \ +-DENABLE_MICROHTTPD=ON \ +-DENABLE_MYSQLCLIENT=ON \ +-DENABLE_NFS=ON \ +-DENABLE_OPTICAL=ON \ +-DENABLE_PULSEAUDIO=ON \ +-DENABLE_SMBCLIENT=ON \ +-DENABLE_UDEV=ON \ +-DENABLE_UPNP=ON \ +-DENABLE_VAAPI=ON \ +-DENABLE_VDPAU=ON \ +-DENABLE_XSLT=ON \ +-DLIBDVDREAD_URL=$(DVDREAD_URL) \ +-DLIBDVDNAV_URL=$(DVDNAV_URL) \ +-DENABLE_LIRCCLIENT=ON \ +-DNEON=False \ +-DCORE_PLATFORM_NAME="$(KODI_PLATFORMS)" \ +$(EXTRA_FLAGS) + +%: + dh $@ --buildsystem cmake --with python3 + +override_dh_clean: + # Clean the optional language packs originating in repo-resources-embedded + # We rely on the fact that there are no optional resource.language.* in + # system/addon-manifest.xml + cd repo-resources-embedded && for i in resource.language.*; do \ + if grep -q "<addon optional=\"true\">$$i</addon>" \ + $(CURDIR)/system/addon-manifest.xml; \ + then \ + echo "Cleaning language pack $$i"; \ + rm -rf $(CURDIR)/addons/$$i; \ + sed -i "/<addon optional=\"true\">$$i</d" \ + $(CURDIR)/system/addon-manifest.xml; \ + sed -i "/$$i\//d" \ + $(CURDIR)/cmake/installdata/common/addons.txt; \ + fi; \ + done + # Perform the rest of cleaning + dh_clean \ + addons/skin.estuary/media/from-debian-logo.png \ + addons/webinterface.default/ \ + debian/dh-addon/*.1 \ + lib/gtest/ \ + media/Fonts/arial.ttf \ + native-tools/ \ + tools/depends/native/JsonSchemaBuilder/native/ \ + tools/depends/native/JsonSchemaBuilder/.installed-native \ + tools/depends/native/TexturePacker/native/ \ + tools/depends/native/TexturePacker/.installed-native \ + $(DVDNAV_URL) \ + $(DVDREAD_URL) + +# fall back to old location of DejaVuSans.ttf if needed +ifneq ("$(wildcard /usr/share/fonts/truetype/dejavu/DejaVuSans.ttf)","") +DEJAVUSANS=/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf +else +DEJAVUSANS=/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans.ttf +endif + +media/Fonts/arial.ttf: debian/mergefonts.ff + # work around #948876 until fontforge is fixed by using cached result + fontforge -script $< \ + /usr/share/fonts/truetype/droid/DroidSansFallbackFull.ttf \ + $(DEJAVUSANS) \ + $@ || cp debian/extra/arial.ttf $@ + +lib/gtest/lib/.libs/libgtest.a: + cp -r /usr/src/gtest/ $(CURDIR)/lib/ && mkdir -p $(CURDIR)/lib/gtest/lib/.libs + +addons/skin.estuary/media/from-debian-logo.png: debian/from-debian-logo.svg + rsvg-convert -w 250 -h 82 -o $@ $< + +embedded-libs: + # Copy default webinterface addon + cp -r $(CURDIR)/debian/webinterface-default $(CURDIR)/addons/webinterface.default + # Copy the optional language packs originating in repo-resources-embedded + cd repo-resources-embedded && for i in resource.language.*; do \ + echo "Adding language pack $$i"; \ + cp -r $$i $(CURDIR)/addons/$$i; \ + sed -i "/<\/addons>/i\ \ <addon optional=\"true\">$$i<\/addon>" \ + $(CURDIR)/system/addon-manifest.xml; \ + echo "addons/$$i/*" \ + 1>>$(CURDIR)/cmake/installdata/common/addons.txt; \ + done + # Prepare archives from embedded libdvd* + tar -cf $(DVDNAV_URL) $(DVDNAV_COMPONENT) + tar -cf $(DVDREAD_URL) $(DVDREAD_COMPONENT) + +override_dh_auto_configure: addons/skin.estuary/media/from-debian-logo.png embedded-libs lib/gtest/lib/.libs/libgtest.a media/Fonts/arial.ttf +ifneq ($(DEB_BUILD_GNU_TYPE),$(DEB_HOST_GNU_TYPE)) + # We are cross-compiling! + # Produce the JsonSchemaBuilder and TexturePacker + # prerequisites for the build architecture + cd tools/depends/native/JsonSchemaBuilder && \ + make NATIVEPREFIX=$(CURDIR)/native-tools + cd tools/depends/native/TexturePacker && \ + make NATIVEPREFIX=$(CURDIR)/native-tools +endif + dh_auto_configure -- $(KODI_OPTS) \ + -DLIBDVDREAD_HASH="SHA256=$(shell sha256sum $(DVDREAD_URL) | cut -d' ' -f1)" \ + -DLIBDVDNAV_HASH="SHA256=$(shell sha256sum $(DVDNAV_URL) | cut -d' ' -f1)" + +override_dh_auto_build: + dh_auto_build + for file in $$(ls debian/dh-addon/dh_*); do \ + pod2man --section=1 --utf8 $$file $$file.1; \ + done + +override_dh_auto_test-arch: + dh_auto_build -- kodi-test + dh_auto_test -a + +# No tests for indep build. +override_dh_auto_test-indep: + +override_dh_install-indep: + # Perform arch-independent install + dh_install -i -XLICENCE -XLICENSE \ + -XLicence.txt -XLicense.txt -XLICENSE.txt \ + -XNOTICE.txt \ + -Xjquery-1.8.2.min.js -Xiscroll-min.js + # Remove kodi-repository-kodi part from kodi-data + rm -rf debian/kodi-data/usr/share/kodi/addons/repository.xbmc.org + # Remove documentation-outside-usr-share-doc but not from addons + rm -f debian/kodi-data/usr/share/kodi/privacy-policy.txt + # Install kodi-repository-kodi + dh_install -pkodi-repository-kodi \ + addons/repository.xbmc.org/* usr/share/kodi/addons/repository.xbmc.org + # ship xbmcclient.h only in kodi-eventclients-dev + rm -f debian/kodi-addons-dev-common/usr/include/kodi/xbmcclient.h + # check if all needed headers are included + $(CXX) -E -c debian/headers-check.c -DBUILD_KODI_ADDON \ + $(shell dpkg-buildflags --get CPPFLAGS) \ + $(shell dpkg-buildflags --get CXXFLAGS) \ + -Idebian/kodi-addons-dev-common/usr/include \ + -o /dev/null + +override_dh_install-arch: + # Prepare kodi-eventclients-dev dummy file + # see debian/control for explanation of package purpose + touch debian/tmp/usr/lib/$(DEB_HOST_MULTIARCH)/kodi/eventclients-dev + # Prepare kodi/system dummy file + # this is necessary to compensate absence of libsse4.so on non-x86 + mkdir -p debian/tmp/usr/lib/$(DEB_HOST_MULTIARCH)/kodi/system + touch debian/tmp/usr/lib/$(DEB_HOST_MULTIARCH)/kodi/system/dummy + # Perform arch-specific install + dh_install -a -XLICENCE -XLICENSE -XLicence.txt -XLicense.txt -XLICENSE.txt -XNOTICE.txt + # Drop executable flag from all Python scripts except: + # ps3_remote.py + # sixpair.py + # sixwatch.py + # zeroconf.py + find debian/kodi-eventclients-*/ \ + ! \( -name "ps3_remote.py" -o -name "sixpair.py" -o -name "sixwatch.py" -o -name "zeroconf.py" \) \ + -name "*.py" -exec chmod 0644 '{}' \; + # Remove ps3 and zeroconf.py from kodi-eventclients-python + rm -rf debian/kodi-eventclients-python/usr/lib/python*/*/kodi/ps3 + rm -f debian/kodi-eventclients-python/usr/lib/python*/*/kodi/ps3_remote.py + rm -f debian/kodi-eventclients-python/usr/lib/python*/*/kodi/zeroconf.py + +# dwz fails to create multifile dwarfs with '-gstrip-dwarf' +override_dh_dwz: + +override_dh_shlibdeps: + dh_shlibdeps -a \ + -l$(CURDIR)/debian/kodi-bin/usr/lib/*/kodi/system/players/dvdplayer + +override_dh_gencontrol: + debian/dh-addon/dh_kodiaddon_depends + dh_gencontrol diff --git a/debian/source/format b/debian/source/format new file mode 100644 index 0000000..163aaf8 --- /dev/null +++ b/debian/source/format @@ -0,0 +1 @@ +3.0 (quilt) diff --git a/debian/source/include-binaries b/debian/source/include-binaries new file mode 100644 index 0000000..f37c721 --- /dev/null +++ b/debian/source/include-binaries @@ -0,0 +1,8 @@ +debian/extra/arial.ttf +debian/webinterface-default/icon.png +debian/webinterface-default/favicon.ico +debian/webinterface-default/images/remote.jpg +debian/webinterface-default/images/ajax-loader.gif +debian/webinterface-default/images/DefaultVideo.png +debian/webinterface-default/images/DefaultAlbumCover.png +debian/webinterface-default/images/close-button.png diff --git a/debian/source/options b/debian/source/options new file mode 100644 index 0000000..9cdfca9 --- /dev/null +++ b/debian/source/options @@ -0,0 +1,2 @@ +unapply-patches +abort-on-upstream-changes diff --git a/debian/tests/control b/debian/tests/control new file mode 100644 index 0000000..d81c78d --- /dev/null +++ b/debian/tests/control @@ -0,0 +1,3 @@ +Tests: gui +Depends: imagemagick, kodi, kodi-eventclients-kodi-send, xauth, xvfb +Restrictions: isolation-container, allow-stderr diff --git a/debian/tests/gui b/debian/tests/gui new file mode 100755 index 0000000..785fe74 --- /dev/null +++ b/debian/tests/gui @@ -0,0 +1,23 @@ +#!/bin/sh +# autopkgtest check: Run kodi GUI to see basic functionality working +# Author: Balint Reczey <balint.reczey@canonical.com> +# Modified by Vasyl Gello <vasek.gello@gmail.com> + +set -e + +export HOME=$AUTOPKGTEST_TMP +KODI_LOG="$HOME/.kodi/temp/kodi.log" + +trap 'cat $KODI_LOG' EXIT + +[ ! -e $KODI_LOG ] || (echo "ERROR: $KODI_LOG" already exists! ; exit 1) + +xvfb-run -e /dev/stdout -s '-screen 0 1920x1080x24 +extension GLX' kodi & +while test ! -e $KODI_LOG; do + sleep 1 +done +tail -f -n +0 $KODI_LOG | grep -m 1 'Listening on port 9777' +kodi-send --host=localhost --port=9777 --action="Quit" +wait + +echo "run: OK" diff --git a/debian/upstream/metadata b/debian/upstream/metadata new file mode 100644 index 0000000..fc20964 --- /dev/null +++ b/debian/upstream/metadata @@ -0,0 +1,7 @@ +Bug-Database: https://github.com/xbmc/xbmc/issues +Bug-Submit: https://github.com/xbmc/xbmc/issues/new +Contact: interest@kodi.tv +FAQ: https://kodi.wiki/view/Main_Page +Repository: https://github.com/xbmc/xbmc.git +Repository-Browse: https://github.com/xbmc/xbmc +Donation: https://kodi.tv/contribute/donate diff --git a/debian/upstream/signing-key.asc b/debian/upstream/signing-key.asc new file mode 100644 index 0000000..1091ddf --- /dev/null +++ b/debian/upstream/signing-key.asc @@ -0,0 +1,25 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +mQGiBFD9w2QRBACoEzH9KKirWE4wgiuPPynNnxks+p+t5i1z3CG+1XhagmTHoOf3 +v8i19kKHV6WnVMn2CKJFgwTTLYXOJTrBM/4ABVtu11cHeeueeo+pCSkdoLzYJ5QF +HbByB6j33QUbwKF0frEs+ge4LxzvYyCDAmNAW560QtOAR9Lk1Fo5B1GXzwCg1kDk +RkSe7EOZNm1U2rYAQ2VPrfsEAIHr4ooOyUByPR7XpoDOKoaXEG0hjpgh46lbgse+ +dQx8YrxS9vXQLwYokfWLrs55avx9Ys0iVv2TMv7X4Tn5sTVaK5K+NbKhxhLORxGI +sgKqRn7W5SG5xoO0w/dmQj756ppjITGbxjFuhYE0X5S6NeMhUuFci7sJ42R7F1Ko +6sYuA/wOMUxCk4XOXeQF16ApyyenjE/UWbBNEhBmjEsZkYAFNc89pAEnEFSnIxK8 +fcuCQioM6ojjaW+aEs/q3/klI0nat9LMLhNSCebjriMHwJDU70NeCn4nPWsfItT1 +eKvbHNcX+3bq3D/i2Wa3PZ5YFFF01C61dHmVC9YGh4sAOXO09LQjVmlkZW9MQU4g +UmVsZWFzZSBTaWduaW5nIEtleSAoMjAxMymIaAQTEQIAKAIbAwYLCQgHAwIGFQgC +CQoLBBYCAwECHgECF4AFAlcfgjEFCQgC8jUACgkQcYBxO+WNGtws1wCfdckVSmW/ +7G+0CNufK+4ZKSXW9BoAoLaxPIFa2qpZdmDr5eci5gdXJI1mtCNWaWRlb0xBTiBS +ZWxlYXNlIFNpZ25pbmcgS2V5ICgyMDE0KYhpBBMRAgApAhsDBwsJCAcDAgEGFQgC +CQoLBBYCAwECHgECF4AFAlcfgjEFCQgC8jUACgkQcYBxO+WNGtwkYACgmifLHzLQ +rbevTlGVWnAfn8AyW8MAn1AIh61iO83YycA1fYoP1sOPBCK/tCNWaWRlb0xBTiBS +ZWxlYXNlIFNpZ25pbmcgS2V5ICgyMDE1KYhqBBMRAgAqAhsDBQsJCAcCBhUICQoL +AgQWAgMBAh4BAheAAhkBBQJXH4IjBQkIAvI1AAoJEHGAcTvljRrcSjsAoL/BM6qq +KwWv2DwdqLd+XRpYlrpyAJ0c43AR1uE2UoMhkUu3vsX75fqELbQjVmlkZW9MQU4g +UmVsZWFzZSBTaWduaW5nIEtleSAoMjAxNimIaAQTEQIAKAIbAwYLCQgHAwIGFQgC +CQoLBBYCAwECHgECF4AFAlbGNhQFCQeppiwACgkQcYBxO+WNGtwQ3wCfb8IB8Mdt +ahoyr5OjvOQL6IQFuUcAoMCyREB9Yn5oLU+6OSnarOAHwzvq +=QHfT +-----END PGP PUBLIC KEY BLOCK----- diff --git a/debian/watch b/debian/watch new file mode 100644 index 0000000..856ef01 --- /dev/null +++ b/debian/watch @@ -0,0 +1,75 @@ +version=4 + +# Alpha bare git branch +# +# Since v20, bare git snapshots must follow the tagged release cycle: +# +# pretty=20.0~alphaX+git%cd.%h, \ +# pretty=20.0~betaX+git%cd.%h, \ +# pretty=20.0~rcX+git%cd.%h, \ +# +# where X starts with zero. The 'pretty' attribute must be changed manually +# after the correspondent tagged release is published. +# +#opts="mode=git, \ +# pgpmode=none, \ +# pretty=20.0~alpha0+git%cd.%h, \ +# repack, \ +# repacksuffix=+dfsg, \ +# compression=xz, \ +# uversionmangle=s/\([\.0-9a-zA-Z]\)-.*$/\1/;s/rc/~rc/;s/a/~alpha/;s/b/~beta/;s/RC/~rc/;s/A/~alpha/;s/B/~beta/, \ +# dversionmangle=auto" \ +#https://github.com/xbmc/xbmc \ +#HEAD \ +#debian + +# Release git tags +# TODO: Change Kodi codename in refs/tags before packaging next Kodi major release + +opts="mode=git, \ + pgpmode=none, \ + repack, \ + repacksuffix=+dfsg, \ + compression=xz, \ + uversionmangle=s/\([\.0-9a-zA-Z]\)-.*$/\1/;s/rc/~rc/;s/a/~alpha/;s/b/~beta/;s/RC/~rc/;s/A/~alpha/;s/B/~beta/, \ + dversionmangle=auto" \ +https://github.com/xbmc/xbmc \ +refs/tags/@ANY_VERSION@-Nexus \ +debian + +# libdvdread + +opts="component=libdvdread-embedded, \ + mode=git, \ + pretty=%cd.%h, \ + repack, \ + compression=xz, \ + dversionmangle=auto" \ +https://code.videolan.org/videolan/libdvdread \ +heads/master \ +ignore + +# libdvdnav + +opts="component=libdvdnav-embedded, \ + mode=git, \ + pretty=%cd.%h, \ + repack, \ + compression=xz, \ + dversionmangle=auto" \ +https://code.videolan.org/videolan/libdvdnav \ +heads/master \ +ignore + +# repo-resources +# TODO: Change Kodi codename in heads/ before packaging next Kodi major release + +opts="component=repo-resources-embedded, \ + mode=git, \ + pretty=%cd.%h, \ + repack, \ + compression=xz, \ + dversionmangle=auto" \ +https://github.com/xbmc/repo-resources \ +heads/nexus \ +ignore diff --git a/debian/webinterface-default/addon.xml b/debian/webinterface-default/addon.xml new file mode 100644 index 0000000..e61262a --- /dev/null +++ b/debian/webinterface-default/addon.xml @@ -0,0 +1,145 @@ +<?xml version="1.0" encoding="UTF-8"?> +<addon + id="webinterface.default" + version="2.2.33" + name="Default webinterface" + provider-name="Team Kodi"> + <requires> + <import addon="xbmc.json" version="6.0.0"/> + </requires> + <extension + point="xbmc.webinterface"/> + <extension point="xbmc.addon.metadata"> + <summary lang="af_ZA">Span Kodi Web Koppelvlak. (Kodi se verstek web koppelvlak)</summary> + <summary lang="am_ET">የ Kodi የዌብ ገጽታዎች (የ Kodi ነባር የዌብ ገጽታዎች)</summary> + <summary lang="ar_SA">واجهه فريق إكس بي إم سي للشبكة العنكبوتية (واجهه الشبكة العنكبوتية المبدئية لـ إكس بي إم سي)</summary> + <summary lang="be_BY">Team Kodi Web Interface. (Kodi's default web interface)</summary> + <summary lang="bg_BG">Уеб интерфейс на Team Kodi. (стандартният уеб интерфейс на Kodi)</summary> + <summary lang="ca_ES">Interfície web de l'equip Kodi. (la interfície web per defecte del Kodi)</summary> + <summary lang="cs_CZ">Webové rozhraní týmu Kodi (Výchozí webové rozhraní Kodi).</summary> + <summary lang="cy_GB">Rhyngwyneb Gwe Team Kodi (Rhyngwyneb gwe rhagosodedig Kodi)</summary> + <summary lang="da_DK">Team Kodi Web-grænseflade. (Kodi's standard webgrænseflade)</summary> + <summary lang="de_DE">Team Kodi Webinterface. (Standardwebinterface von Kodi)</summary> + <summary lang="el_GR">Διεπαφή Ιστού της Team Kodi. (Προεπιλεγμένη διεπαφή ιστού του Kodi)</summary> + <summary lang="en_AU">Team Kodi Web Interface. (Kodi's default web interface)</summary> + <summary lang="en_GB">Team Kodi Web Interface. (Kodi's default web interface)</summary> + <summary lang="en_NZ">Team Kodi Web Interface. (Kodi's default web interface)</summary> + <summary lang="en_US">Team Kodi Web Interface. (Kodi's default web interface)</summary> + <summary lang="es_AR">Interfaz Web del Equipo de Kodi. (Interfaz web por defecto de Kodi)</summary> + <summary lang="es_ES">Interfaz web de Kodi. (Interfaz web por defecto de Kodi)</summary> + <summary lang="es_MX">Interfaz Web del Equipo de Kodi (Interfaz Web por defecto de Kodi)</summary> + <summary lang="et_EE">Kodi meeskonna veebikeskkond. (Vaikimisi keskkond)</summary> + <summary lang="eu_ES">Kodi taldean Web Interfazea. (Kodi-ren lehenetsiriko web interfazea)</summary> + <summary lang="fa_AF">نمایه وب تیم Kodi.(رابط پیش فرض Kodi)</summary> + <summary lang="fa_IR">رابط وب تیم Kodi. (رابط وب استاندارد Kodi)</summary> + <summary lang="fi_FI">Team Kodin web-käyttöliittymä. (Kodin oletus-web-käyttöliittymä)</summary> + <summary lang="fr_CA">Interface Web de l'équipe Kodi. (Interface Web par défaut de Kodi)</summary> + <summary lang="fr_FR">Interface Web de l'Équipe Kodi (interface d'origine de Kodi)</summary> + <summary lang="gl_ES">Interface web da equipa de Kodi. (Interface web predefinida de Kodi)</summary> + <summary lang="he_IL">ממשק הדפדפן הרשמי של Kodi. (ברירת המחדל)</summary> + <summary lang="hr_HR">Tim Kodi Web sučelje. (Kodijevo uobičajeno web sučelje)</summary> + <summary lang="hu_HU">Az Kodi csapat Webes kezelőfelülete (Kodi alapértelmezett webes kezelőfelülete)</summary> + <summary lang="id_ID">Antar Muka Web Tim Kodi. (Antar muka web bawaan Kodi)</summary> + <summary lang="is_IS">Team Kodi Vefviðmót. (Sjálfgefið vefviðmót á Kodi)</summary> + <summary lang="it_IT">Interfaccia Web del Team Kodi. (Interfaccia web di default per Kodi)</summary> + <summary lang="ja_JP">Team Kodi Web Interface. (Kodi's default web interface)</summary> + <summary lang="ko_KR">Team Kodi 웹 인터페이스. (Kodi 기본 웹 인터페이스)</summary> + <summary lang="lt_LT">Komandos Kodi Web sąsaja.(Kodi numatytoji žiniatinklio sąsaja)</summary> + <summary lang="lv_LV">Team Kodi tīmekļa saskarne. (Kodi noklusētā tīmekļa saskarne)</summary> + <summary lang="mk_MK">Веб интерфејс на Kodi тимот. (Kodi's подразбирачки веб интерфејс)</summary> + <summary lang="mn_MN">Kodi багийн вэб интерфэйс. (Kodi-ийн үндсэн вэб интерфэйс)</summary> + <summary lang="ms_MY">Antaramuka Sesawang Pasukan-Kodi (antaramuka sesawang lalai Kodi) </summary> + <summary lang="mt_MT">Web interface ta' Team Kodi. (Il-Web interface normali ta' Kodi)</summary> + <summary lang="my_MM">Team Kodi ဝက်ဘ် အသွင်အပြင် (Kodi ၏ မူရင် ဝက်ဘ် အသွင်အပြင်)</summary> + <summary lang="nb_NO">Team Kodi nettgrensesnitt. (Kodis standard nettgrensesnitt)</summary> + <summary lang="nl_NL">Team Kodi Webinterface. (Kodi's standaard webinterface)</summary> + <summary lang="pl_PL">Interfejs webowy Kodi. (Domyślny)</summary> + <summary lang="pt_BR">Interface Web da Equipe Kodi. (interface web padrão do Kodi)</summary> + <summary lang="pt_PT">Interface da Web da Team Kodi. (Interface da Web predefinida do Kodi)</summary> + <summary lang="ro_RO">Interfață web Kodi. (interfață web implicită pentru Kodi)</summary> + <summary lang="ru_RU">Веб-интерфейс от разработчиков Kodi (веб-интерфейс Kodi по умолчанию).</summary> + <summary lang="sk_SK">Webové rozhranie tímu Kodi. (predvolené webové rozhranie pre Kodi)</summary> + <summary lang="sl_SI">Spletni vmesnik ekipe Kodi. (Privzet spletni vmesnik za Kodi)</summary> + <summary lang="sr_RS">Web интерфејс Kodi Тима (подразуевани web интерфејс Kodi-jа)</summary> + <summary lang="sr_RS@latin">Web interfejs Kodi Tima (podrazuevani web interfejs Kodija)</summary> + <summary lang="sv_SE">Team Kodi webbgränsnitt. (Kodi's standardwebbgränssnitt)</summary> + <summary lang="szl">Webowy interfejs ôd Team Kodi (wychodny webowy interface we Kodi).</summary> + <summary lang="ta_IN">கோடி குழுமத்தின் இணைய இடைமுகம். (கோடியின் நிரந்தர இணைய இடைமுகம்)</summary> + <summary lang="te_IN">టీమ్-కోడి వెబ్ ఇంటర్ఫేస్. (కోడి యొక్క డిఫాల్ట్ వెబ్ ఇంటర్ఫేస్)</summary> + <summary lang="tg_TJ">Интерфейси веби гурӯҳи кории Kodi Web. (Интерфейси веби пешфарз барои Kodi)</summary> + <summary lang="th_TH">ทีมส่วนประสานหน้าเว็บ Kodi (ส่วนประสานหน้าเว็บพื้นฐานของ Kodi)</summary> + <summary lang="tr_TR">Kodi Takımı Web Arayüzü. (Kodi'nin varsayılan web arayüzü)</summary> + <summary lang="uk_UA">Веб-інтерфейс Kodi (Типовий веб-інтерфейс для Kodi)</summary> + <summary lang="uz_UZ">Kodi guruhi veb Interfeysi. (Kodi andoza veb interfeysi)</summary> + <summary lang="vi_VN">Đội ngũ giao diện Web Kodi. (Giao diện Web mặc định của Kodi)</summary> + <summary lang="zh_CN">Kodi 团队开发的 Web 界面。(Kodi 的默认 web 界面)</summary> + <summary lang="zh_TW">Kodi團隊網頁介面。(Kodi的預設網頁介面)</summary> + <description lang="af_ZA">Verstek web koppelvlak vir Kodi; Ontwerp vir toestelle van alle resolusies</description> + <description lang="am_ET">ነባር የዌብ ገጽታዎች ለ Kodi ፡ የተነደፈው ለሁሉም አካላቶች resolutions ነው </description> + <description lang="ar_SA">واجهه الشبكة العنكبوتية المبدئية لـ إكس بي إم سي، مُصمَمة لتناسب كافة قياسات أبعاد الشاشات</description> + <description lang="be_BY">Стандартны вэб-інтэрфэйс да Kodi; распрацаваны для прыладаў зь любымі разрознасьцямі</description> + <description lang="bg_BG">Стандартния уеб интерфейс на Kodi; Направен е за устройства с най-различни резолюции</description> + <description lang="ca_ES">Interfície web per defecte del Kodi; Dissenyada per dispositius de totes les resolucions</description> + <description lang="cs_CZ">Výchozí webové rozhraní Kodi navržené pro zařízení s libovolným rozlišením</description> + <description lang="cy_GB">Rhyngwyneb gwe rhagosodedig Kodi. Wedi ei gynllunio ar gyfer cydraniad pob dyfais</description> + <description lang="da_DK">Standard webgrænseflade til Kodi; designet til enheder i alle opløsninger</description> + <description lang="de_DE">Standard Kodi Webinterface - Für alle Geräte und Auflösungen geeignet</description> + <description lang="el_GR">Προεπιλεγμένη διεπαφή ιστού για το Kodi. Σχεδιασμένη για συσκευές όλων των αναλύσεων.</description> + <description lang="en_AU">Default web interface for Kodi; Designed for devices of all resolutions</description> + <description lang="en_GB">Default web interface for Kodi; Designed for devices of all resolutions</description> + <description lang="en_NZ">Default web interface for Kodi; Designed for devices of all resolutions</description> + <description lang="en_US">Default web interface for Kodi; Designed for devices of all resolutions</description> + <description lang="es_AR">Interfaz web por defecto de Kodi. Diseñada para dispositivos de cualquier resolución</description> + <description lang="es_ES">Interfaz web por defecto de Kodi. Diseñada para dispositivos de cualquier resolución</description> + <description lang="es_MX">Interfaz Web por defecto para Kodi; Diseñado para dispositivos de todas las resoluciones</description> + <description lang="et_EE">Kodi vaikimisi veebikeskkond; Disainitud erinevate resolutsioonidega seadmetele.</description> + <description lang="eu_ES">Kodi-ren lehenetsiriko web interfazea. Erresoluzio guztietako gailentzat diseinatua</description> + <description lang="fa_AF">رابط پیش فرض Kodiوطراحی شده برای هر رزولیشن</description> + <description lang="fa_IR">رابط استاندارد وب برای Kodi. قابل استفاده برای همه دستگاه ها و همه رزولوشن ها</description> + <description lang="fi_FI">Kodin oletus-web-käyttöliittymä. Suunniteltu käytettäväksi kaiken kokoisilla laitteilla.</description> + <description lang="fr_CA">Interface Web par défaut de Kodi - Conçue pour les appareils de toutes résolutions</description> + <description lang="fr_FR">Interface Web d'origine de Kodi ; adaptée aux appareils de toutes résolutions</description> + <description lang="gl_ES">Interface web predefinida para Kodi, deseñada para dispositivos de todas as resolucións</description> + <description lang="he_IL">ממשק דפדפן ברירת המחדל עבור Kodi; מותאם למכשירים בעלי אבחנות שונות</description> + <description lang="hr_HR">Uobičajeno web sučelje za Kodi; Dizajnirano za uređaje svih razlučivosti</description> + <description lang="hu_HU">A Kodi alapértelmezett webes kezelőfelülete; Minden felbontásra alkalmas</description> + <description lang="hy_AM">Նախնական տեսք Kodi-ի համար; Նախատեսված է բոլոր կրիչների համար</description> + <description lang="id_ID">Antar muka web bawaan bagi Kodi; Dirancang untuk perangkat dengan semua resolusi</description> + <description lang="is_IS">Sjálfgefið vefviðmót fyrir Kodi; Hannað fyrir tæki með allskonar upplausnir</description> + <description lang="it_IT">Interfaccia Web di default per Kodi; Realizzata per periferiche con qualunque risoluzione</description> + <description lang="ja_JP">Kodi のデフォルト Web インターフェースです。さまざまな解像度のデバイス用にデザインされています。</description> + <description lang="ko_KR">Kodi 기본 웹 인터페이스; 모든 해상도의 기기를 위해 디자인 됨</description> + <description lang="lt_LT">Numatytoji Kodi Web sąsaja skirta visų rezoliucijų prietaisams</description> + <description lang="lv_LV">Noklusētā Kodi tīmekļa sakarne; Piemērota visu izšķirtspēju iekārtām</description> + <description lang="mk_MK">Подразбирачки веб интерфејс за Kodi; Дизајниран за уреди со сите резолуции</description> + <description lang="mn_MN">Kod-ийн үндсэн вэб интерфэйс; Бүх төрлийн нарийвчлалтай төхөөрөмжид зориулагдсан.</description> + <description lang="ms_MY">Antaramuka sesawang lalai untuk Kodi; Direka untuk peranti pelbagai resolusi</description> + <description lang="mt_MT">Il-Web interface in-normali ta' Kodi; Iddiżinjata għal apparat ta' kull reżoluzzjoni</description> + <description lang="my_MM">Kodi အတွက် မူရင်း ဝက်ဘ် အသွင်ပြင် ၊ စက်များ အားလုံး၏ resolutions အတွက် ရေးဆွဲထားသည်။</description> + <description lang="nb_NO">Standard nettgrensesnitt for Kodi; Laget for alle oppløsninger</description> + <description lang="nl_NL">Standaard Kodi-webinterface; geschikt voor alle resoluties</description> + <description lang="pl_PL">Domyślny interfejs webowy Kodi; Zaprojektowany dla urządzeń o ekranach w dowolnej rozdzielczości</description> + <description lang="pt_BR">Interface web padrão para Kodi; Concebida para dispositivos de todas as resoluções</description> + <description lang="pt_PT">Interface da Web ppredefinida do Kodi; Criada para dispositivos de todas as resoluções.</description> + <description lang="ro_RO">Interfață web implicită pentru Kodi, realizată de echipa Kodi pentru dispozitive cu orice rezoluție.</description> + <description lang="ru_RU">Веб-интерфейс Kodi по умолчанию. Разработан для устройств с любыми разрешениями.</description> + <description lang="si_LK">Kodi' සඳහා නියත වෙබ් අතුරුමුහුණත; සෑම විභේදනයකම උපකරණ සඳහා නිර්මාණය කර ඇත</description> + <description lang="sk_SK">Predvolené webové rozhranie pre Kodi; Navrhnuté pre zariadenia zobrazujúce v akomkoľvek rozlíšení</description> + <description lang="sl_SI">Privzet spletni vmesnik za Kodi, ustvarjen za naprave vseh ločljivosti</description> + <description lang="sr_RS">Подразумевани web интерфејс Kodi; Намењен уређајима свих резолуција</description> + <description lang="sr_RS@latin">Podrazumevani web interfejs Kodi; Namenjen uređajima svih rezolucija</description> + <description lang="sv_SE">Standardwebbgränssnitt för Kodi; Utformat för alla enheter oavsett skärmupplösning</description> + <description lang="szl">Wychodny webowy interface we Kodi. Zrychtowany dlŏ maszin we wszyjskich rozdziylczościach.</description> + <description lang="ta_IN">கோடி இற்கான நிரந்தர இணைய இடைமுகம்; சகல சாதனங்களின் திரைகளுக்கும் வடிவமைக்கப்பட்டது</description> + <description lang="te_IN">కోడి డిఫాల్ట్ వెబ్ ఇంటర్ఫేస్; అన్ని వైశాల్యాలు పరికరాల కోసం రూపొందించబడింది</description> + <description lang="tg_TJ">Интерфейси веби пешфарз барои Kodi; Барои ҳар гуна дастгоҳ бо возеҳии экранаш гуногун эҷод карда шудааст</description> + <description lang="th_TH">ส่วนประสานหน้าเว็บพื้นฐานสำหรับ Kodi ได้ออกแบบรองรับความละเอียดหน้าจอของอุปกรณ์ทั้งหมด</description> + <description lang="tr_TR">Kodi için varsayılan web arayüzü; Bütün çözünürlüklerde tüm cihazlar için dizayn edilmiştir.</description> + <description lang="uk_UA">Типовий веб-інтерфейс для Kodi; Розроблений для пристроїв з будь-якою роздільною здатністю</description> + <description lang="uz_UZ">Kodi uchun andoza veb interfeysi; barcha ekran o'lchamlari bilan uskunalar uchun yaratilgan</description> + <description lang="vi_VN">Giao diện Web mặc định cho Kodi; Thiết kế cho các thiết bị ở tất cả độ phân giải khác nhau</description> + <description lang="zh_CN">Kodi 的默认 web 界面;为支持所有分辨率的设备而设计</description> + <description lang="zh_TW">Kodi的預設網頁介面;針對所有解析度的設備而設計</description> + <platform>all</platform> + </extension> +</addon> diff --git a/debian/webinterface-default/css/core.css b/debian/webinterface-default/css/core.css new file mode 100644 index 0000000..5371c4a --- /dev/null +++ b/debian/webinterface-default/css/core.css @@ -0,0 +1,794 @@ +body { + font-family: Arial, Verdana, sans-serif; + margin: 0; + padding: 0; +} + +#header { + position: relative; + height: 50px; + border-bottom: 1px solid #000; + z-index: 200; + background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAVIAAAAxCAYAAACIwiGvAAAACXBIWXMAAAsTAAALEwEAmpwYAAA7r2lUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4KPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS41LWMwMjEgNzkuMTU1NzcyLCAyMDE0LzAxLzEzLTE5OjQ0OjAwICAgICAgICAiPgogICA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPgogICAgICA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIgogICAgICAgICAgICB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iCiAgICAgICAgICAgIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIKICAgICAgICAgICAgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIgogICAgICAgICAgICB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIKICAgICAgICAgICAgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIKICAgICAgICAgICAgeG1sbnM6dGlmZj0iaHR0cDovL25zLmFkb2JlLmNvbS90aWZmLzEuMC8iCiAgICAgICAgICAgIHhtbG5zOmV4aWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20vZXhpZi8xLjAvIj4KICAgICAgICAgPHhtcDpDcmVhdG9yVG9vbD5BZG9iZSBQaG90b3Nob3AgQ0MgMjAxNCAoTWFjaW50b3NoKTwveG1wOkNyZWF0b3JUb29sPgogICAgICAgICA8eG1wOkNyZWF0ZURhdGU+MjAxNC0xMi0wNVQxNDozMDoyNyswMTowMDwveG1wOkNyZWF0ZURhdGU+CiAgICAgICAgIDx4bXA6TW9kaWZ5RGF0ZT4yMDE0LTEyLTA2VDE4OjI2OjUwKzAxOjAwPC94bXA6TW9kaWZ5RGF0ZT4KICAgICAgICAgPHhtcDpNZXRhZGF0YURhdGU+MjAxNC0xMi0wNlQxODoyNjo1MCswMTowMDwveG1wOk1ldGFkYXRhRGF0ZT4KICAgICAgICAgPGRjOmZvcm1hdD5pbWFnZS9wbmc8L2RjOmZvcm1hdD4KICAgICAgICAgPHBob3Rvc2hvcDpDb2xvck1vZGU+MzwvcGhvdG9zaG9wOkNvbG9yTW9kZT4KICAgICAgICAgPHhtcE1NOkluc3RhbmNlSUQ+eG1wLmlpZDozZGEwMjM1Zi1iOTdlLTQ3ODMtOTZjMy0xMDBhYzMzYWI5OGQ8L3htcE1NOkluc3RhbmNlSUQ+CiAgICAgICAgIDx4bXBNTTpEb2N1bWVudElEPmFkb2JlOmRvY2lkOnBob3Rvc2hvcDo2YmMwNTFmNC1iY2I0LTExNzctYTRhYy1lNmU3M2I3NjVlMDI8L3htcE1NOkRvY3VtZW50SUQ+CiAgICAgICAgIDx4bXBNTTpPcmlnaW5hbERvY3VtZW50SUQ+eG1wLmRpZDo1ZTc3Y2MyYS00OTE2LTQ4ZjctOGJiZC05YjYyM2Q1NTc1YjU8L3htcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD4KICAgICAgICAgPHhtcE1NOkhpc3Rvcnk+CiAgICAgICAgICAgIDxyZGY6U2VxPgogICAgICAgICAgICAgICA8cmRmOmxpIHJkZjpwYXJzZVR5cGU9IlJlc291cmNlIj4KICAgICAgICAgICAgICAgICAgPHN0RXZ0OmFjdGlvbj5jcmVhdGVkPC9zdEV2dDphY3Rpb24+CiAgICAgICAgICAgICAgICAgIDxzdEV2dDppbnN0YW5jZUlEPnhtcC5paWQ6NWU3N2NjMmEtNDkxNi00OGY3LThiYmQtOWI2MjNkNTU3NWI1PC9zdEV2dDppbnN0YW5jZUlEPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6d2hlbj4yMDE0LTEyLTA1VDE0OjMwOjI3KzAxOjAwPC9zdEV2dDp3aGVuPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6c29mdHdhcmVBZ2VudD5BZG9iZSBQaG90b3Nob3AgQ0MgMjAxNCAoTWFjaW50b3NoKTwvc3RFdnQ6c29mdHdhcmVBZ2VudD4KICAgICAgICAgICAgICAgPC9yZGY6bGk+CiAgICAgICAgICAgICAgIDxyZGY6bGkgcmRmOnBhcnNlVHlwZT0iUmVzb3VyY2UiPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6YWN0aW9uPnNhdmVkPC9zdEV2dDphY3Rpb24+CiAgICAgICAgICAgICAgICAgIDxzdEV2dDppbnN0YW5jZUlEPnhtcC5paWQ6NDIyYTA5YzQtZjMwZi00OGM3LWFlYTUtMDZmYzk3NmZlMTk3PC9zdEV2dDppbnN0YW5jZUlEPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6d2hlbj4yMDE0LTEyLTA1VDE0OjQwOjQ5KzAxOjAwPC9zdEV2dDp3aGVuPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6c29mdHdhcmVBZ2VudD5BZG9iZSBQaG90b3Nob3AgQ0MgMjAxNCAoTWFjaW50b3NoKTwvc3RFdnQ6c29mdHdhcmVBZ2VudD4KICAgICAgICAgICAgICAgICAgPHN0RXZ0OmNoYW5nZWQ+Lzwvc3RFdnQ6Y2hhbmdlZD4KICAgICAgICAgICAgICAgPC9yZGY6bGk+CiAgICAgICAgICAgICAgIDxyZGY6bGkgcmRmOnBhcnNlVHlwZT0iUmVzb3VyY2UiPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6YWN0aW9uPnNhdmVkPC9zdEV2dDphY3Rpb24+CiAgICAgICAgICAgICAgICAgIDxzdEV2dDppbnN0YW5jZUlEPnhtcC5paWQ6M2RhMDIzNWYtYjk3ZS00NzgzLTk2YzMtMTAwYWMzM2FiOThkPC9zdEV2dDppbnN0YW5jZUlEPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6d2hlbj4yMDE0LTEyLTA2VDE4OjI2OjUwKzAxOjAwPC9zdEV2dDp3aGVuPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6c29mdHdhcmVBZ2VudD5BZG9iZSBQaG90b3Nob3AgQ0MgMjAxNCAoTWFjaW50b3NoKTwvc3RFdnQ6c29mdHdhcmVBZ2VudD4KICAgICAgICAgICAgICAgICAgPHN0RXZ0OmNoYW5nZWQ+Lzwvc3RFdnQ6Y2hhbmdlZD4KICAgICAgICAgICAgICAgPC9yZGY6bGk+CiAgICAgICAgICAgIDwvcmRmOlNlcT4KICAgICAgICAgPC94bXBNTTpIaXN0b3J5PgogICAgICAgICA8dGlmZjpPcmllbnRhdGlvbj4xPC90aWZmOk9yaWVudGF0aW9uPgogICAgICAgICA8dGlmZjpYUmVzb2x1dGlvbj43MjAwMDAvMTAwMDA8L3RpZmY6WFJlc29sdXRpb24+CiAgICAgICAgIDx0aWZmOllSZXNvbHV0aW9uPjcyMDAwMC8xMDAwMDwvdGlmZjpZUmVzb2x1dGlvbj4KICAgICAgICAgPHRpZmY6UmVzb2x1dGlvblVuaXQ+MjwvdGlmZjpSZXNvbHV0aW9uVW5pdD4KICAgICAgICAgPGV4aWY6Q29sb3JTcGFjZT42NTUzNTwvZXhpZjpDb2xvclNwYWNlPgogICAgICAgICA8ZXhpZjpQaXhlbFhEaW1lbnNpb24+MzM4PC9leGlmOlBpeGVsWERpbWVuc2lvbj4KICAgICAgICAgPGV4aWY6UGl4ZWxZRGltZW5zaW9uPjQ5PC9leGlmOlBpeGVsWURpbWVuc2lvbj4KICAgICAgPC9yZGY6RGVzY3JpcHRpb24+CiAgIDwvcmRmOlJERj4KPC94OnhtcG1ldGE+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAg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') 1px 1px no-repeat #fff; +} + +#remoteContainer { + background: url("../images/remote.jpg") no-repeat; + width: 659px; + height: 213px; + position: relative; + margin: auto; + margin-top: 50px; +} + +.remote_key { + cursor: pointer; + position: absolute; +} + +#navigation { + float: right; +} + +#spinner { + float: right; + padding: 11px 10px; +} + +#commsErrorPanel { + float: left; + line-height: 50px; + background: #c00; + color: #fff; + font-size: 20px; + padding-left: 10px; + width: 330px; +} + +#navigation ul { + list-style-type: none; + border-right: 1px solid #969696; + margin: 0; + padding: 0; +} + +#navigation ul li { + float: left; + color: #000; + cursor: pointer; + line-height: 50px; + margin: 0; + padding: 0 24px; + border-left: 1px solid #969696; + font-family: Verdana, sans-serif; + font-size: 18px; + font-weight: 700; +} + +#navigation ul li.selected, +#navigation ul li:hover { + background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAAzCAIAAADZxfV4AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyBpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBXaW5kb3dzIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjgxMkRGQzczQkFDMDExREY5RDE0QzJCMjZBM0JGMURBIiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOjgxMkRGQzc0QkFDMDExREY5RDE0QzJCMjZBM0JGMURBIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6ODEyREZDNzFCQUMwMTFERjlEMTRDMkIyNkEzQkYxREEiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6ODEyREZDNzJCQUMwMTFERjlEMTRDMkIyNkEzQkYxREEiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz4vOcxrAAAAVUlEQVR42lyMUQ7AMAhCF+9/px5MIFNpl2YfREF8z1orSAaAYAnUnsdzdiR+vRLsuzNZ36bLyLM3p36zuhpWzp/7Zn/c5tA8zc3eeUvXbi/tXHwFGAC2dpagcbC63AAAAABJRU5ErkJggg%3D%3D') repeat-x; + color: #fff; +} + +.floatableAlbum { + float: left; + width: 130px; + height: 150px; + padding: 10px 10px 15px 10px; +} + +.floatableMovieCover, +.floatableProfileThumb { + float: left; + width: 130px; + height: 200px; + padding: 10px; +} + +.floatableAlbum:hover, +.floatableTVShowCover:hover, +.floatableMovieCover:hover, +.floatableProfileThumb:hover { + background: #aeaeae; +} + +.albumView .floatableAlbum:hover { + background: transparent; +} + +.tvshowContainer .floatableTVShowCover:hover { + background: #fff; +} + +.floatableTVShowCover { + float: left; + padding: 10px; + width: 379px; + height: 70px; +} + +.floatableTVShowCoverSeason { + width: 500px; + height: 70px; + margin-top: 30px; +} + +.toggle .activeMode { + font-weight: 700; +} + +#tvshowLibraryContainer { + padding-top: 40px; +} + +#libraryContainer .floatableAlbum, +#movieLibraryContainer .floatableMovieCover, +#profilesContainer .floatableProfileThumb, +#tvshowLibraryContainer .floatableTVShowCover { + cursor: pointer; +} + +.floatableAlbum div.imgWrapper, +.floatableMovieCover div.imgWrapper, +.floatableProfileThumb div.imgWrapper, +.floatableTVShowCover div.imgWrapper { + width: 130px; + height: 130px; + display: table-cell; + vertical-align: middle; + text-align: center; + overflow: hidden; +} + +.floatableTVShowCoverSeason div.imgWrapper { + margin: auto; + height: 70px; + width: 379px; + display: block; +} + +div.imgWrapper div.inner { + overflow: hidden; + width: 130px; +} + +.floatableMovieCover div.imgWrapper, +.floatableMovieCover div.imgWrapper div.inner, +.floatableProfileThumb div.imgWrapper, +.floatableProfileThumb div.imgWrapper div.inner { + height: 190px; +} + +#overlay { + top: 50px; + left: 0; + right: 0; + bottom: 150px; + background: #3f3f3f; + position: fixed; + opacity: 0.8; + z-index: 2000; + /* Above contentContainer's */ +} + +.floatableTVShowCover div.imgWrapper, +.floatableTVShowCover img, +.floatableTVShowCover div.imgWrapper div.inner, +.floatableTVShowCoverSeason div.imgWrapper, +.floatableTVShowCoverSeason img, +.floatableTVShowCoverSeason div.imgWrapper div.inner { + height: 70px; + width: 379px; +} + +.floatableAlbum img { + width: 130px; +} + +.floatableMovieCover img, +.floatableProfileThumb img { + height: 180px; +} + +.floatableAlbum p.album, +.floatableMovieCover p.album, +.floatableProfileThumb p.album { + font-size: 12px; + font-weight: 700; + color: #000; + text-align: center; + margin: 0 -5px; + padding: 0; + width: 130px; + white-space: nowrap; + overflow: hidden; +} + +.floatableAlbum p.artist, +.floatableMovieCover p.artist, +.floatableProfileThumb p.artist { + font-size: 11px; + color: #777; + text-align: center; + margin: 0; + padding: 0; +} + +.contentContainer { + overflow-x: hidden; + overflow-y: auto; + position: absolute; + top: 51px; + bottom: 1px; + left: 0; + right: 0; + background: #fff; + padding-bottom: 149px; +} + +.footerPadding { + clear: both; +} + +.albumContainer { + top: 74px; +} + +.albumView .trackRow td, +.seasonView .episodeRow td { + cursor: pointer; + line-height: 14px; + font-size: 14px; + padding: 1px 0; + padding-left: 4px; +} + +.albumView .tr0, +.seasonView .tr0 { + background-color: #efefef; +} + +.albumView .tr0:hover, +.albumView .tr1:hover, +.seasonView .tr0:hover, +.seasonView .tr1:hover { + background-color: blue; + color: #fff; +} + +.seasonView .tr0:hover td.info, +.seasonView .tr1:hover td.info { + background-color: cyan; +} + +.albumView, +.seasonView { + width: 100%; + height: 100%; + border-collapse: collapse; +} + +.seasonView td.episodeThumb { + text-align: center; +} + +.seasonView td.episodeNumber { + text-align: left; +} + +.seasonView td.info { + background: url('data:image/png;base64,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%3D%3D') no-repeat; + background-size: 40%; + background-position: 50% 50%; +} + +.seasonView td.episodeThumb img { + height: 30px; +} + +.albumView td.albumThumb { + padding-left: 0px; + border-right: 1px solid #aeaeae; +} + +.albumView td.time, +.albumView th.time { + text-align: right; + padding-right: 4px; +} + +.albumView tr.headerRow, +#albumSelector table { + background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAAXCAIAAABF+LJYAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyBpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBXaW5kb3dzIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjk4NTQ0NDZGQ0U1ODExREZCMjM4ODgyQjJEQTE5ODBBIiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOjk4NTQ0NDcwQ0U1ODExREZCMjM4ODgyQjJEQTE5ODBBIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6OTg1NDQ0NkRDRTU4MTFERkIyMzg4ODJCMkRBMTk4MEEiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6OTg1NDQ0NkVDRTU4MTFERkIyMzg4ODJCMkRBMTk4MEEiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz7FuFIdAAAAOklEQVR42kyMUQoAMAhC0+j+J+s2ffXTVtDYA1EUpLsjImhmVFU2IsKqGm1uz8zxX7sBeF1zv44AAwDVBhSDNN7oJQAAAABJRU5ErkJggg%3D%3D') repeat-x; +} + +.albumView th, +.seasonView th { + font-size: 11px; + text-align: left; + border-left: 1px solid #aeaeae; + border-bottom: 1px solid #aeaeae; + padding-left: 4px; + height: 13px; + padding-top: 1px; +} + +.albumView tr.headerRow, +.seasonView tr.headerRow { + background-position: 0 -1px; +} + +.seasonView tr.headerRow th.thumbHeader { + width: 40px; +} + +.albumView .albumThumb, +.albumView .albumBG { + width: 120px; + background: #efefef; + border-right: 1px solid #aeaeae; + vertical-align: top; +} + +.albumView .fillerTrackRow2 td { + height: 100%; + line-height: 100%; +} + +/* Album Selector */ + +#albumSelector { + height: 23px; + font-family: Arial, sans-serif; + font-size: 12px; + font-weight: 700; +} + +#albumSelector table { + width: 100%; + border: 1px solid #aeaeae; + border-top: 0px; + height: 23px; + border-collapse: collapse; +} + +#albumSelector td { + padding-top: 2px; +} + +#albumSelector .prevAlbum, +#albumSelector .allAlbums { + background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAALCAIAAADJDItPAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyBpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBXaW5kb3dzIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOkJCOEEyQzlGQ0U1QTExREY4MUI0RjIyREY1QUFBQTlBIiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOkJCOEEyQ0EwQ0U1QTExREY4MUI0RjIyREY1QUFBQTlBIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6QkI4QTJDOURDRTVBMTFERjgxQjRGMjJERjVBQUFBOUEiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6QkI4QTJDOUVDRTVBMTFERjgxQjRGMjJERjVBQUFBOUEiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz6Hnv/HAAAA1ElEQVR42mxQOw5EUBSd9/IyCxA2YQlaO1JbgkVIiIpKgR1oNBqdEKERVD7xmzkzk5gYc6r7zn3nnnMvWdf1dkHf923bchxHH2eM49g0je/7qqoOw8AOxbIs6CVJYppmnudgtm1j+75DhGllWdq2HYbhIQDPpmmCjed5ruvO8/wTghVFoWlalmXXgPCiPM8riiLLMiFkPQM/SNd1sEfINE0ty4rj+FDruv5qfx4wxrQoigzDqKoKDIrvYvc3JEkSRTEIAsdxKKUEsf9era5rQRCeAgwAxPWf44ZS0FcAAAAASUVORK5CYII%3D') no-repeat; +} + +/* This must appear before #albumSelector .allAlbums */ + +#albumSelector .allAlbums { + width: 94px; + border-right: 1px solid #aeaeae; + text-align: center; + padding-left: 10px; + cursor: pointer; + background-position: 10px center; +} + +#albumSelector .activeAlbumTitle { + text-align: center; +} + +#albumSelector .nextAlbum { + background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAALCAIAAADJDItPAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyBpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBXaW5kb3dzIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjdCMUE3MDBGQ0U1QzExREZBREU0QkQ5NzdFRENBNkQxIiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOjdCMUE3MDEwQ0U1QzExREZBREU0QkQ5NzdFRENBNkQxIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6N0IxQTcwMERDRTVDMTFERkFERTRCRDk3N0VEQ0E2RDEiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6N0IxQTcwMEVDRTVDMTFERkFERTRCRDk3N0VEQ0E2RDEiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz62tw0dAAAA3UlEQVR42myQPQ5EUBSF573414jQUEh0Go1GrRGFKKiESuxCYztWYAMqy6ATEg0NmbkiMWTmlPede75zH5rneZomURR5nn/9CC/LUhRFXdfjOK7r+n4K9X2f5zkYNU1LksQwDJZlSZI8t1HXdVmWXWm2bUdRpKoqsBBCBIz2fb+em6Zp29b3fc/zoBAG3v4UTKqqKssSgo/tbdvubQHsOE4QBJIkEVDvHm6aZhzHuq5zHIcx/rIVRUnT1LIsaE5R1OkmwELTdBiGrusKgsAwzB10HDYMgyzLf3/tI8AAgcVrkw2eqPgAAAAASUVORK5CYII%3D') no-repeat; +} + +#albumSelector .prevAlbum, +#albumSelector .nextAlbum { + width: 28px; + border-left: 1px solid #aeaeae; + cursor: pointer; + background-position: center center; +} + +/* Movie Overlay */ + +.moviePopoverContainer, +.episodePopoverContainer { + z-index: 3000; + /* Above overlay */ + border: 1px solid #000; + padding: 10px; + margin: 10px; + position: fixed; + background: #3f3f3f; + top: 50px; + bottom: 150px; + left: 10%; + right: 10%; + opacity: 0.9; +} + +.episodePopoverContainer { + bottom: none; + top: 30%; +} + +.moviePopoverContainer .closeButton, +.episodePopoverContainer .closeButton { + float: right; + cursor: pointer; +} + +.moviePopoverContainer .movieCover { + height: 100%; + padding-right: 20px; + float: left; + z-index: 3100; +} + +.episodePopoverContainer .episodeCover { + width: 40%; + padding-right: 20px; + float: left; + z-index: 3100; +} + +.moviePopoverContainer .movieTitle, +.episodePopoverContainer .episodeTitle { + font-size: 24px; + font-weight: 700; + color: #fff; + margin: 0; +} + +.moviePopoverContainer .runtime, +.moviePopoverContainer .director, +.moviePopoverContainer .genre, +.moviePopoverContainer .plot, +.episodePopoverContainer .runtime, +.episodePopoverContainer .director, +.episodePopoverContainer .genre, +.episodePopoverContainer .episode, +.episodePopoverContainer .season, +.episodePopoverContainer .plot { + color: #fff; +} + +.movieTitle .year, +.episodeTitle .year { + font-weight: 400; + font-size: 18px; +} + +.playIcon { + background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAH4AAAB+CAYAAADiI6WIAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyBpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBXaW5kb3dzIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjY3NEJBNzU2QkM0OTExREZBNjg4RTExODNGRTMxNzlDIiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOjY3NEJBNzU3QkM0OTExREZBNjg4RTExODNGRTMxNzlDIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6Njc0QkE3NTRCQzQ5MTFERkE2ODhFMTE4M0ZFMzE3OUMiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6Njc0QkE3NTVCQzQ5MTFERkE2ODhFMTE4M0ZFMzE3OUMiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz6EY6YgAAAd50lEQVR42uxdCYwc1Zn+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%3D') center center no-repeat; + position: absolute; + z-index: 3500; + cursor: pointer; + opacity: 0.8; + width: 100px; +} + + +.playIcon:hover { + opacity: 1; +} + +/* Effects */ + +#topScrollFade { + position: fixed; + top: 51px; + height: 33px; + z-index: 101; + left: 0; + right: 0; + background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAAhCAYAAAAYucG/AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyBpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBXaW5kb3dzIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjYwREM0NTA2QkM1MzExREY4OEFDQUU5NTc5MTFCNkUxIiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOjYwREM0NTA3QkM1MzExREY4OEFDQUU5NTc5MTFCNkUxIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6NjBEQzQ1MDRCQzUzMTFERjg4QUNBRTk1NzkxMUI2RTEiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6NjBEQzQ1MDVCQzUzMTFERjg4QUNBRTk1NzkxMUI2RTEiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz4NLytwAAAANElEQVR42mL4DwRMDEAAIv6AiN8g4hec+AkifmAhvoOIb6isb3jFvmHRhs3kn6gu+A0QYACIHCJCHDLYgwAAAABJRU5ErkJggg%3D%3D') top left repeat-x; +} + +/* Now Playing */ + +#footerPopover { + position: fixed; + height: 150px; + bottom: 0; + left: 0; + right: 16px; + z-index: 10000; + /* Top most always */ + background: #333; + opacity: 0.98; +} + +#nowPlayingPanel { + height: 130px; + width: 600px; + padding: 10px; +} + +#audioCoverArt img { + width: 100px; + height: 100px; + float: left; + padding: 0 10px 10px 0; +} + +#videoCoverArt img { + height: 100px; + float: left; + padding: 0 10px 10px 0; +} + +#audioArtistTitle, +#videoShowTitle { + float: left; + padding: 5px 5px 0 0; + color: #777; +} + +#audioAlbumTitle:before { + content: ' - '; +} + +#audioAlbumTitle { + padding-top: 5px; + color: #777; +} + +#audioTrackWrap, +#videoTrackWrap { + width: 365px; + white-space: nowrap; + overflow: hidden; +} + +#audioTrackTitle, +#videoTitle { + color: #fff; + white-space: nowrap; + overflow: hidden; + font-size: 16px; + font-weight: 700; + padding: 5px 0; + width: 365px; +} + +#audioDuration, +#videoDuration { + float: right; + color: #808080; + font-size: 20px; + font-weight: 700; + padding: 0 5px 5px 0; +} + +#progressBar { + background: url('data:image/png;charset=utf-8;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAAICAAAAAAdccqdAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAABZJREFUCB1jsGfiYOJh4gJCdiY2JlYABfcAiC/XwOEAAAAASUVORK5CYII=') repeat-x scroll 0 0 transparent; + border: 1px solid rgba(0, 0, 0, 0.7); + float: left; + height: 8px; + padding: 0; + position: relative; + width: 365px; + -moz-border-radius: 20px 20px 20px 20px; + border-radius: 20px 20px 20px 20px; + -webkit-border-radius: 20px 20px 20px 20px; +} + +#progressBar .elapsedTime { + background: url('data:image/png;charset=utf-8;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAAICAAAAAAdccqdAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAABdJREFUCB1j+M/0g+kr02emj0D4mekrAD41B7hJ9Jz5AAAAAElFTkSuQmCC') repeat-x scroll 0 0 transparent; + height: 8px; + left: 0; + min-width: 5px; + width: 0; + position: relative; + -moz-border-radius: 20px 20px 20px 20px; + border-radius: 20px 20px 20px 20px; + -webkit-border-radius: 20px 20px 20px 20px; +} + +#progressBar .progressIndicator { + background: url('data:image/png;charset=utf-8;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAMpJREFUeNp8kD0OgzAMhe0QWAB1RoKbVKrE0L3H4AztSM/AYaoiVepNuABDGPhN/dIODJQnWYmTL8+O2VpLUJZlJ1kKiSN99ZaomqZ5IWGAApVKqWsYhuT7vqPGcaSu62hZlrvAN07TNBfoGccxMTOtBRNjDM3zfNYoBxc4bElrDbCAY+t53oF2JKCBI/V9v8c5V4D1NE0XebUJSTWAD4URoMdhGJzzOnD2m0LlfiZ9lkmS2CiKbBAELrDHGe7A8Grg+Z+B10g+AgwAK9Fl++J3PdcAAAAASUVORK5CYII=') no-repeat scroll 0 0 transparent; + height: 10px; + left: 0; + position: absolute; + top: -1px; + width: 10px; +} + +#nowPlayingPlaylist, +#nextTrack { + width: 416px; + float: left; + cursor: pointer; + z-index: 1000; +} + +#nowPlayingPlaylist { + clear: both; + color: #fff; + position: relative; + top: -16px; +} + +#nowPlayingPlaylist ul { + list-style-type: none; + margin: 0; + padding: 0; +} + +#nowPlayingPlaylist li { + padding-bottom: 2px; + padding-left: 4px; +} + +#nowPlayingPlaylist li:hover { + cursor: pointer; + background: #004986; +} + +#nowPlayingPlaylist li span.duration, +#nextTrack span.duration { + float: right; + height: 14px; + padding-right: 4px; + font-size: 12px; +} + +#nowPlayingPlaylist li div.trackInfo, +#nextTrack div.trackInfo { + width: 364px; + height: 14px; + font-size: 12px; + white-space: nowrap; + overflow: hidden; +} + +#nowPlayingPlaylist li.activeItem div.trackInfo { + width: 362px; + padding-left: 10px; + background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAOCAYAAAAWo42rAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAIZJREFUeNpi/P//PwMxgImBSECyQlWCKkFuBOI9QBwLxBxQPgaGMS4A8R0g7gNiFWwKYVb/gGI/IJ4GxJHoNjNCg+ckEHMA8V8gFgPi10BsiKyQBeZUIGYFYi4gPg7Ek9FNhCnkBJkOxAuBeBYQv8Ll621A7AfETIR8rYBLAQwzUj2uAQIMAPXkkCPo9C41AAAAAElFTkSuQmCC') no-repeat; +} + +#nextTrack, +#nextText, +#nowPlayingPlaylist { + background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAAOCAIAAABhIeELAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAADhJREFUeNoMxSEOACAMA8CmAdai5ibBwf9fCOJy8DQyE1WFtTfuPZRMW4y/FFSIIwZ7/1ojgCfAAEzrAiPgCWVXAAAAAElFTkSuQmCC') repeat-x #606060; + border: 1px solid #222; +} + +#nextTrack { + border-left: 0px; + color: #ddd; + padding-left: 4px; +} + +#nextText { + clear: both; + float: left; + color: #457cbf; + font-size: 12px; + font-weight: 700; + width: 54px; + border-right: 0px; + height: 14px; + padding-left: 4px; +} + +#playbackControls span, +#playbackControls span:hover { + width: 24px; + height: 24px; + float: left; + display: block; + -moz-background-size: 24px; + background-size: 24px; + -webkit-background-size: 24px; + -o-background-size: 24px; + -khtml-background-size: 24px; + cursor: pointer; +} + +#pbPrev { + background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAxVJREFUeNrsWU1q20AUluxgsEBgCDjUYBAYui7kArlAu4+7T/dt9m0OkAMkB+gFeoFeoNB1wCAwuNhgCLjIUDDuN+W5vEzejEbyWKqKBx4zaKQ33/d+5k/hdrsNmlzCI4EjAc8EwjAspQh6eqhiSBcSQdrCaxtIBllDVhjrseRYfgjg2w6qM8ipAXBeUYSWkDnG/VUZAXyjwA4JuK+iiEwx/uagBChUEsHiamAVEisVItCTCd9GFGIq1HoGHWleaJUmgHeV1fvaY+X6Gb5blohl5cEBpKN1LaBv6pUA3ku0kNkQ8MW+sQPdfSLCPbKE7tQLAQG8Co9JkcRznBBGNINZSRQiIISN0TKeiOjGehZOzgQoYUdVgbeQmPDE5phbOVNlwsOmCvBkxJTCdFcSwvOstCx6hiypVMJOKt4lTGjcgHAMnQlQQnEXznwmrKMX/kzP7NEp4XLywBmf531MlSVJLGidkXBZCTyxfs0bzpkBl0yAZp6/sV9mhfXshSXPBcJn9UDM2rnbXSi8I3ltecfWdw4Z5AzzaMAnEuiy9srBSOckLwRwA0UOzY9CXwz5gOad9K1WVgZ8wYnwMl/K13ssRsrq73WL7ayO6pMDcAlHlEegzeIvKwE8JotfGPquIJcF8yBjq287j8A+W4ALAi9Z/SWq2wJWdyo+CVxKwFn5fIhZquVR188CifhPEvgCeWcBqvoeqiCw0c6wRZLtG6o3kK9C3wNkjOZ9idyKJHwmAplpznUkoe57rtG8kbyBvnvyxo8CarsGfCKBtWnVK0hEhdRbKWzIU2PJU4YSm9amE0Oy7Y6QvT33MWojNkYIXEmeQnVNU29egvdMk4F4pMSzV2zBSOvc0NHVS8I2l99djpQc8CCotwwMuKwE5qzdoXubOqzf1y695k4E6Dj3xAvSce7A4Du69aVjrW0hm2qH6lHFDhhplwrTQisx3RLza5SI7muqsH6ibZtT0631/30zZ1HanLtRC4nm3E5bwikImvJ/QLt2SYIm/qFhCpr7j0xIvOb9pbSEVv3/iZtWjgTqLr8FGAAhgOqLmi3nxQAAAABJRU5ErkJggg%3D%3D') no-repeat; +} + +#pbPrev:hover { + background: url('data:image/png;base64,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') no-repeat; +} + +#pbStop { + background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAp1JREFUeNrsWV9rwkAMb3UIFsaEgmJhUBB82Os+1D7APsc+2l73IAiFQUWh4BAqlBWXg7ClsWnvSv/Y0cBRLXfN75fkcrk7+3K5WH2WkdVzGQh0LXf0j23blT4C82gCjxm0e2jqtyN0jaEl0E7QjqAvqajvD3PmjyEBGOvCw0XgVUQRiUBv1CoBGKOs/YjWrkOUJz5B/7FRAtB3DA8fwyUvPL7QqjF8K80Z66C3HoQwUwQCPrYWAtBPKVzlWF25PzSNZ5w3HoYg98YWvhfXRgDBr6GNWfwGVSciI+KzeaQ8sJFIGBEQwKt4PdSZDkHPHOdVKQltAmidJwK+0DI1kODGUvo+uJcp5rKFbNUWeDSg+vYGdVmoe1VpJQaWHssUQZPgGYmAvHIQiz4BDJ0leXXQzdE1kVC66BxbIiZtD3gsrYUdlDkh6s7DJBPABYfm5rBsYWnICykznIvYSj1AwSemdUrNJCLmBbewGs3ptDdIgWuDou4E4DaaffdkfXDZ3MgSIPUKrU105RXas2bfd2gvmn2PhICDGFMphBwWPonVsSCGRMB4RWDKqstbkVjAeEWAhtT5hgicpbAfNvUDgYFAVr6l2d6xTAWMVwTOUr7tWBwpO44K8u1EKmHbFMQwkdYnfjKXwoCYMJ7x2qNA3kxqIQMO9AgnRoyFxVxECCx0CRgUZ6ayYNhKs1DEwsjtMHxcFj7lBHAjQTt6eRuJFsCP2S4syttYjQq2c79ekLZzDYvHrB9qL2RYwu7Iqzke6LZlfaVrTl7tpNJ+VDApQ5ayfDx4ahq80uGzzBNWLSW2VvaQad0kCeFkbluY/f712WgJiX6cTjMS/bwfYLnZt/p4Q5OT5vp3RyYs9f27pRTiuft74mFPPBAwlx8BBgDogIiBqL/sAAAAAABJRU5ErkJggg%3D%3D') no-repeat; +} + +#pbStop:hover { + background: url('data:image/png;base64,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') no-repeat; +} + +#pbPause { + background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAApxJREFUeNrsWY1qgzAQ1rYILQiC0EKhIPQR9lB9mj3A3ml9gUJBEAoTBEFQGEh3GddxvSXROGvqMBD8T74v+XKXO93r9eqMucyckZeJgO2yoBeu63ZqBNZRAAcf6hLqCupc8loNtYRaQS2gr7xjX3fXLr1hQgC+8+CwgRoqADcVQSiD+gH9fg5GAN4XYHcIvK8iiCTQf/1QAiiVSDLiomMhiUJIBNopJd+uUGJCaoGijbhJWp0JwHti1Nfstpj6C3yXddCymMEtVI89SqG9pFcC8E7EJFMj8PSv2oG210iEzkgGbce9EJCAF/I4myy8lgZhjxZMS8KIgEQ2ypHpiQgfrF9y4gRmDQt2MPA4gDFapFtZIw4zT4ymMqKyeTR4RoJasQjxGG0ldmRRiQV7HniHcMZ+HcSxa00AFxTV4aXPBdtyFr7NM7kVIq5WM7Chdr4PU9mRRIp+RoZLS+Bu9C1vNi8KXHICuOJ/tN/Fw/Y8CxldCzKLtGDXPjlvvd2Fht/g8EJuHaHzA3n+zj45wPNjy+ZzMvo+x8UltCTnxZPELIUCn5QAdeXVkxCoFPikBOZEf+UzoGc45lNQPxGYCOgJ1CyGtV4YjrqJQKmzuZbKUoFPSqBSeGWbxdf5poXE692isMCgk1fWEffiB3Z9Mmg70O0OeGoxB83V6DDE5ilss6GDd04Nz48d9R+yzWXeJiamgLeW5bNV4NIS+CDnHuZtbFgf0a+nwKUmgOHc3SyowrkHgvf46KvCWpUjS1hQvR94AvYsqZAYeWLMEtM0ygqTTkOMfsS2zbEuaz3TWA4R+aQsMxANAJ5n5rSR4f/OjWpIjCc7TT4c7/8BlnaJnDH+oSENjPcfmWThje8vpUZa9v8TTzHxRMC8fAkwABzhg7l0cw47AAAAAElFTkSuQmCC') no-repeat; +} + +#pbPause:hover { + background: url('data:image/png;base64,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') no-repeat; +} + +#pbPlay { + background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAv9JREFUeNrsWl1q20AQ9k8RRGASELjEUBAY8tDXXCDXaHuAHqAHaA+Q9r19L31vLpAL9LUPBoOgoJCAwMUgg6hxZ2DaTiea1Wq1trolA4tiodV838zs7Owow91uNwhZRoPA5YFA3/KI/xgOh04vgXUUweUExgQG/h0rj5YwKhhrGCvQVznq+4P5rx8tCcDcBC4JAXcRJFKA3uKgBGAOWvsJWduHoCe+gf7VXgnAs2O4pBQudeHxnaxawru2NXNj8taxEmZIIJNzvRCA51DhvMbq6P68bTzTuplRCEpvLOF9pTcCBP4MxljEb+a6EAWRVKwj9MBCI9GKgAIe4/XOZzoEPVNaV40krAmQdZ4y8EbLeCAhjYX6vkovc8xNG9n8UODJgPjuBekakO65004MLGciU2T7BC9IZOxWTFjsCVDonLJbd7Y52hMJ1MXX2ClhsvbATKS1vIcyJyfddZh0ArTh8NycN20sYv7Ekxe2wnAJYWv0AAdfta1TQF6DomeeSBTCC0lbArcOetEDr4DEe9PiayG31gRYvcJrE1c5h/HRgzdWIiONTR6IRfhUHZVzb0wcw6gSYRSbCByJ6tKXoDc+A4kLx/mlgvEeAX5C23hOi+iBSyBx6eCNjXaK7ONMfNHRG//Eof63N0LuSuB54ovXrsQBBSvON5BhFr4J/NBWu0f5BMDftpxzpGC8R2Cj5VsPckNWdwmbWMuOI0O+jbQS1kGuYTx3AU8YIm1/kp25LUwoGeMTUZe7LNR38N6rDu/gLZySMBqzEK8+H3dQjNZ+0RG8xFDYpNFChFHioPQDAH8Jo9NBiHRHJgK1XQm4l7LStaLOwNZS6QSeXXvoUIypI/KLAPZQM9uuBLdcpB3nlOpx7Wnhz4T1c+udmErYG3ZrSg3dgwjpmvIUrJX2I4Mlc5GyUmo87Rs86khF5slda6GlaDKd7ZOE0plbGkP2v+6NNpAIozstSIT5fUDk5nQQ4heamjQX3jcyZasP7yulEs/9fycOUR7+V6Jv+SnAAJqtxFYrTd5IAAAAAElFTkSuQmCC') no-repeat; +} + +#pbPlay:hover { + background: url('data:image/png;base64,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%3D%3D') no-repeat; +} + +#pbNext { + background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAvpJREFUeNrsWV1q20AQtmJjiCA0IAgkUDAUAi0ECr1ALpADuNdo39u+pweI39tcoAfoBQKFQAuGgCGQkIAhxUEGkeB+E0ZhWO9IK3llVcYDg2ytdne++dvZ3WA2m7WaTMEawBqARwBBEJQaBGN08dgGb4Hpd6h8GoMT8AR8h/mSkvP5AYC+ER4RC16GCMgY846XCgB9SNsvWds+iCxxifnvKgWAb9t49NhdbO7xl7UaY6xHS9+QrfVCcTMCMDL7egGA72jCVxatk/mvivozx80eu6BpjQuMF3sDwMLvg9uG/47KBqIBpGfEEVlgqIEoBEARnvz11mc6xDw7HFe5IJwBsHbeCOEzNeMBhKksmu+3aeUiAF6LYKtU+AwQlBD+FAaA9xRgu6LfhWua8wBimxNGSteY+8oZALvOgRjgFm2XyywRIAPFw454dZ66kguAnkhvCfvh45IBtDn+0rRNK/YoFwB3fCvGGhVd6j2CiDjFpvSLFCll3rD0kwtLUpfwrNAxe4BNNicAN/9BxXzjDEDUK7I2yTLxIXhLaXvHmUzr+wF8Aj7KASBlCFlG1QKh4T55ZUIf/J2EtbTRu29o6yt99/mb3Rw3Sgw3CrMAbBrVpQuRACesUdMa9D/V9N4CbhQrMs4B6Ijf04KTuFjjqCSAqSKjNYgXoWdrWHZp9P8T2o61uClDnYoyRz+j7ZAtcu9joo1WdTTJaLv3NUlVAAbgU6XtB/g97eKqAPCgRbsjXZNwSH0DxSIf0fYZPCk47qYi41wMTLV860Ck8YEi3Bn4iyyJC1KoZcdORr7tUlntsJhNWLifSvtXtJ0uuGfuautTx1j1qNKLBWLaWGTtfc/YLWxaH7I7DRd0c3mEE5vVqK2clptrKifO66zkIM+BsMDTYUJeOT023CiqUfjIcJ+50n71dmQrsSdu/KnESpwLrcTJnDLoczrzLLz/s9EcEM04nTZANPN+wMjNvVYTb2gsaa55d2TKUt+8W0rFn+u/J24irQHUTf8EGABePUpJ23F8cgAAAABJRU5ErkJggg%3D%3D') no-repeat; +} + +#pbNext:hover { + background: url('data:image/png;base64,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') no-repeat; +} + +.tvshowContainer .seasonPicker { + position: absolute; + right: 5px; + top: 0px; +} + + +.tvshowContainer .active { + font-weight: bold; +} + +.tvshowContainer .episodeListingsContainer { + position: absolute; + top: 40px; + left: 500px; + width: 500px; + padding-bottom: 149px; +} + +.tvshowContainer .episodeListingsContainer ul { + list-style-type: none; + margin: 0; + padding: 0; +} + +.episodeListingsContainer li { + clear: both; +} + +.episodeListingsContainer li img { + height: 30px; + float: left; +} + +.tvshowContainer .showDetails { + text-align: center; + width: 100%; + height: 18px; + position: relative; + padding-top: 5px; + background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAAXCAIAAABF+LJYAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyBpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBXaW5kb3dzIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjk4NTQ0NDZGQ0U1ODExREZCMjM4ODgyQjJEQTE5ODBBIiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOjk4NTQ0NDcwQ0U1ODExREZCMjM4ODgyQjJEQTE5ODBBIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6OTg1NDQ0NkRDRTU4MTFERkIyMzg4ODJCMkRBMTk4MEEiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6OTg1NDQ0NkVDRTU4MTFERkIyMzg4ODJCMkRBMTk4MEEiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz7FuFIdAAAAOklEQVR42kyMUQoAMAhC0+j+J+s2ffXTVtDYA1EUpLsjImhmVFU2IsKqGm1uz8zxX7sBeF1zv44AAwDVBhSDNN7oJQAAAABJRU5ErkJggg%3D%3D') repeat-x; +} + +.contentContainer .toggle { + position: absolute; + font-size: 12px; + font-weight: 500; + left: 5px; + top: 4px; +} + +.tvshowContainer .showDetails p { + margin: 0; + padding: 0; +} + +.tvshowContainer .showDetails .showTitle { + font-size: 12px; + font-weight: 700; +} + +.tvshowContainer .showDetails span.heading { + font-weight: 700; +}
\ No newline at end of file diff --git a/debian/webinterface-default/css/ipad.css b/debian/webinterface-default/css/ipad.css new file mode 100644 index 0000000..9441022 --- /dev/null +++ b/debian/webinterface-default/css/ipad.css @@ -0,0 +1,9 @@ +.contentContainer { + overflow-x: hidden; + overflow-y: auto; + position: absolute; + height: auto; + bottom: auto; + background: #fff; + padding-bottom: 150px; +}
\ No newline at end of file diff --git a/debian/webinterface-default/favicon.ico b/debian/webinterface-default/favicon.ico Binary files differnew file mode 100644 index 0000000..078637f --- /dev/null +++ b/debian/webinterface-default/favicon.ico diff --git a/debian/webinterface-default/icon.png b/debian/webinterface-default/icon.png Binary files differnew file mode 100644 index 0000000..cca2499 --- /dev/null +++ b/debian/webinterface-default/icon.png diff --git a/debian/webinterface-default/images/DefaultAlbumCover.png b/debian/webinterface-default/images/DefaultAlbumCover.png Binary files differnew file mode 100644 index 0000000..bbfd653 --- /dev/null +++ b/debian/webinterface-default/images/DefaultAlbumCover.png diff --git a/debian/webinterface-default/images/DefaultVideo.png b/debian/webinterface-default/images/DefaultVideo.png Binary files differnew file mode 100644 index 0000000..1aa81a1 --- /dev/null +++ b/debian/webinterface-default/images/DefaultVideo.png diff --git a/debian/webinterface-default/images/ajax-loader.gif b/debian/webinterface-default/images/ajax-loader.gif Binary files differnew file mode 100644 index 0000000..4fb7c23 --- /dev/null +++ b/debian/webinterface-default/images/ajax-loader.gif diff --git a/debian/webinterface-default/images/close-button.png b/debian/webinterface-default/images/close-button.png Binary files differnew file mode 100644 index 0000000..628fbf6 --- /dev/null +++ b/debian/webinterface-default/images/close-button.png diff --git a/debian/webinterface-default/images/remote.jpg b/debian/webinterface-default/images/remote.jpg Binary files differnew file mode 100755 index 0000000..8e10d59 --- /dev/null +++ b/debian/webinterface-default/images/remote.jpg diff --git a/debian/webinterface-default/index.html b/debian/webinterface-default/index.html new file mode 100755 index 0000000..40b5303 --- /dev/null +++ b/debian/webinterface-default/index.html @@ -0,0 +1,73 @@ +<!DOCTYPE html> +<html> + <head> + <title>Kodi</title> + <meta http-equiv="Content-Language" content="EN" /> + <meta http-equiv="Content-Type" content="UTF-8" /> + <!-- <link rel="search" href="provider.xml" type="application/opensearchdescription+xml" title="Kodi Library" /> --> + <link rel="icon" href="favicon.ico" type="image/x-icon"> + <link rel="shortcut icon" href="favicon.ico" type="image/x-icon"> + <!-- <link href="/images/logo.png" rel="image_src" /> --> + <meta name="robots" content="NOINDEX, NOFOLLOW"> + <link href="css/core.css?1.3.57" rel="stylesheet" type="text/css"> + <link href="css/ipad.css?1.0.5" rel="stylesheet" media="only screen and (max-device-width: 1024px)" type="text/css"> + </head> + <body> + <div id="header"> + <div id="commsErrorPanel" style="display: none;"></div> + <div id="navigation"> + <ul> + <li id="profiles">Profiles</li> + <li id="remoteControl">Remote</li> + <li id="movieLibrary">Movies</li> + <li id="tvshowLibrary">TV Shows</li> + <li id="musicLibrary">Music</li> + </ul> + </div> + <img src="images/ajax-loader.gif" alt="Loading please wait" id="spinner" style="display: none"> + </div> + <div id="body"> + <div id="topScrollFade" style="display: none;"></div> + <div id="content"></div> + <div id="overlay" style="display: none;"></div> + </div> + <div id="footerPopover"> + <div id="nowPlayingPanel" style="display: none;"> + <div id="nowPlayingContent"> + <div id="audioDescription"> + <div id="audioCoverArt"></div> + <div id="audioTrackWrap"> + <div id="audioArtistTitle"></div> + <div id="audioAlbumTitle"></div> + </div> + <div id="audioTrackTitle"></div> + <div id="audioDuration"></div> + </div> + <div id="videoDescription"> + <div id="videoCoverArt"></div> + <div id="videoTrackWrap"> + <div id="videoShowTitle"></div> + </div> + <div id="videoTitle"></div> + <div id="videoDuration"></div> + </div> + </div> + <div id="playbackControls"> + <span id="pbPrev" title="Previous"></span> + <span id="pbPause" title="Pause"></span> + <span id="pbPlay" title="Play"></span> + <span id="pbStop" title="Stop"></span> + <span id="pbNext" title="Next"></span> + <div id="progressBar"> + <div class="elapsedTime" style="width: 0%"></div> + <span class="progressIndicator"></span> + </div> + </div> + <span id="nextText">Next:</span> + <div id="nextTrack" style="display: none;"></div> + <div id="nowPlayingPlaylist" style="display: none;"></div> + </div> + </div> + <script type="text/javascript" src="js/xbmc.launcher.js?v=2.1.0"></script> + </body> +</html> diff --git a/debian/webinterface-default/js/MediaLibrary.js b/debian/webinterface-default/js/MediaLibrary.js new file mode 100755 index 0000000..3c1a1bc --- /dev/null +++ b/debian/webinterface-default/js/MediaLibrary.js @@ -0,0 +1,1420 @@ +/* + * 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/>. + * + */ + +var MediaLibrary = function () { + this.init(); +}; +MediaLibrary.prototype = { + playlists: {}, + + init: function () { + this.bindControls(); + this.getPlaylists(); + }, + bindControls: function () { + $('#musicLibrary').click(jQuery.proxy(this.musicLibraryOpen, this)); + $('#movieLibrary').click(jQuery.proxy(this.movieLibraryOpen, this)); + $('#tvshowLibrary').click(jQuery.proxy(this.tvshowLibraryOpen, this)); + $('#pictureLibrary').click(jQuery.proxy(this.pictureLibraryOpen, this)); + $('#remoteControl').click(jQuery.proxy(this.remoteControlOpen, this)); + $('#profiles').click(jQuery.proxy(this.profilesOpen, this)); + $('#overlay').click(jQuery.proxy(this.hideOverlay, this)); + $(window).resize(jQuery.proxy(this.updatePlayButtonLocation, this)); + $(document).on('keydown', jQuery.proxy(this.handleKeyPress, this)); + $(document).on('contextmenu', jQuery.proxy(this.handleContextMenu, this)); + }, + resetPage: function () { + $('#musicLibrary').removeClass('selected'); + $('#movieLibrary').removeClass('selected'); + $('#tvshowLibrary').removeClass('selected'); + $('#remoteControl').removeClass('selected'); + $('#pictureLibrary').removeClass('selected'); + $('#profiles').removeClass('selected'); + this.hideOverlay(); + }, + replaceAll: function (haystack, needle, thread) { + return (haystack || '').split(needle || '').join(thread || ''); + }, + getPlaylists: function () { + xbmc.rpc.request({ + 'context': this, + 'method': 'Playlist.GetPlaylists', + 'timeout': 3000, + 'success': function (data) { + if (data && data.result && data.result.length > 0) { + $.each($(data.result), jQuery.proxy(function (i, item) { + this.playlists[item.type] = item.playlistid; + }, this)); + } + }, + 'error': function (data, error) { + xbmc.core.displayCommunicationError(); + setTimeout(jQuery.proxy(this.updateState, this), 2000); + } + }); + }, + remoteControlOpen: function (event) { + this.resetPage(); + this.textBuffer = ''; + $('#remoteControl').addClass('selected'); + $('.contentContainer').hide(); + var libraryContainer = $('#remoteContainer'); + if (!libraryContainer || libraryContainer.length === 0) { + $('#spinner').show(); + libraryContainer = $('<div>'); + libraryContainer.attr('id', 'remoteContainer') + .addClass('contentContainer'); + $('#content').append(libraryContainer); + var keys = [{ + name: 'up', + width: '40px', + height: '30px', + top: '28px', + left: '58px' + }, + { + name: 'down', + width: '40px', + height: '30px', + top: '122px', + left: '58px' + }, + { + name: 'left', + width: '40px', + height: '30px', + top: '74px', + left: '15px' + }, + { + name: 'right', + width: '40px', + height: '30px', + top: '74px', + left: '104px' + }, + { + name: 'ok', + width: '40px', + height: '30px', + top: '74px', + left: '58px' + }, + { + name: 'back', + width: '40px', + height: '30px', + top: '13px', + left: '161px' + }, + { + name: 'home', + width: '40px', + height: '30px', + top: '154px', + left: '8px' + }, + { + name: 'mute', + width: '40px', + height: '30px', + top: '107px', + left: '391px' + }, + { + name: 'power', + width: '30px', + height: '30px', + top: '-3px', + left: '13px' + }, + { + name: 'volumeup', + width: '30px', + height: '30px', + top: '49px', + left: '422px' + }, + { + name: 'volumedown', + width: '30px', + height: '30px', + top: '49px', + left: '367px' + }, + { + name: 'playpause', + width: '32px', + height: '23px', + top: '62px', + left: '260px' + }, + { + name: 'stop', + width: '32px', + height: '23px', + top: '62px', + left: '211px' + }, + { + name: 'next', + width: '38px', + height: '25px', + top: '102px', + left: '304px' + }, + { + name: 'previous', + width: '38px', + height: '25px', + top: '101px', + left: '160px' + }, + { + name: 'forward', + width: '32px', + height: '23px', + top: '102px', + left: '259px' + }, + { + name: 'rewind', + width: '32px', + height: '23px', + top: '101px', + left: '211px' + }, + { + name: 'cleanlib_a', + width: '46px', + height: '26px', + top: '47px', + left: '553px' + }, + { + name: 'updatelib_a', + width: '46px', + height: '26px', + top: '47px', + left: '492px' + }, + { + name: 'cleanlib_v', + width: '46px', + height: '26px', + top: '111px', + left: '553px' + }, + { + name: 'updatelib_v', + width: '46px', + height: '26px', + top: '111px', + left: '492px' + } + ]; + for (var akey in keys) { + var aremotekey = $('<p>').attr('id', keys[akey]['name']); + aremotekey.addClass('remote_key') + .css('height', keys[akey]['height']) + .css('width', keys[akey]['width']) + .css('top', keys[akey]['top']) + .css('left', keys[akey]['left']) + .bind('click', { + key: keys[akey]['name'] + }, jQuery.proxy(this.pressRemoteKey, this)); + libraryContainer.append(aremotekey); + } + } else { + libraryContainer.show(); + libraryContainer.trigger('scroll'); + } + + $('#spinner').hide(); + }, + shouldHandleEvent: function (event) { + var inRemoteControl = $('#remoteControl').hasClass('selected'); + return (!event.ctrlKey && !event.altKey && inRemoteControl); + }, + handleKeyPress: function (event) { + if (!this.shouldHandleEvent(event)) { + return true; + } + + var keys = { + 8: 'back', // Back space + 13: 'ok', // Enter + 27: 'home', // Escape + 32: 'playpause', // Space bar + 37: 'left', // Left + 38: 'up', // Up + 39: 'right', // Right + 40: 'down', // Down + 93: 'contextmenu', // "Right Click" + 107: 'volumeup', // + (num keypad) + 109: 'volumedown', // - (num keypad) + 187: 'volumeup', // + (alnum keypad) + 189: 'volumedown' // - (alnum keypad) + }; + var which = event.which; + var key = keys[which]; + + event.data = { + key: key + }; + + if (!key) { + event.data.key = 'text'; + + if (event.key && event.key.length === 1) { + event.data.text = event.key; + } else { + // Letters + if (which >= 65 && which <= 90) { + var offset = event.shiftKey ? 0 : 32; + event.data.text = String.fromCharCode(which + offset); + } + + // Digits + if (which >= 96 && which <= 105) { + event.data.text = (which - 96) + ""; + } + } + } + + if (event.data.key) { + this.pressRemoteKey(event); + return false; + } + }, + handleContextMenu: function (event) { + if (!this.shouldHandleEvent(event)) { + return true; + } + if ( + (event.target == document) || //Chrome/Opera + (event.clientX === event.clientY && event.clientX === 0) //FF/IE + ) { + return false; + } //keyboard event. cancel it. + return true; + }, + rpcCall: function (method, params) { + var callObj = { + 'method': method + }; + if (params) { + callObj.params = params; + } + return xbmc.rpc.request(callObj); + }, + typeRemoteText: function (event) { + if (event.data.key === 'text' || ((event.data.key === 'playpause' || event.data.key === 'back') && this + .textBuffer.length)) { + if (event.data.key === 'back') { + this.textBuffer = this.textBuffer.substring(0, this.textBuffer.length - 1); + } else if (event.data.key === 'playpause') { + this.textBuffer += ' '; + } else if (event.data.text && event.data.text.length) { + this.textBuffer += event.data.text; + } + console.log(this.textBuffer); + return this.rpcCall('Input.SendText', { + 'text': this.textBuffer, + 'done': false + }); + } else { + this.textBuffer = ''; + } + }, + pressRemoteKey: function (event) { + var player = -1, + keyPressed = event.data.key; + $('#spinner').show(); + if (this.typeRemoteText(event)) { + return true; + } + + switch (keyPressed) { + case 'up': + return this.rpcCall('Input.Up'); + case 'down': + return this.rpcCall('Input.Down'); + case 'left': + return this.rpcCall('Input.Left'); + case 'right': + return this.rpcCall('Input.Right'); + case 'ok': + return this.rpcCall('Input.Select'); + case 'cleanlib_a': + return this.rpcCall('AudioLibrary.Clean'); + case 'updatelib_a': + return this.rpcCall('AudioLibrary.Scan'); + case 'cleanlib_v': + return this.rpcCall('VideoLibrary.Clean'); + case 'updatelib_v': + return this.rpcCall('VideoLibrary.Scan'); + case 'back': + return this.rpcCall('Input.Back'); + case 'home': + return this.rpcCall('Input.Home'); + case 'power': + return this.rpcCall('System.Shutdown'); + case 'contextmenu': + return this.rpcCall('Input.ContextMenu'); + case 'mute': + return this.rpcCall('Application.SetMute', { + 'mute': 'toggle' + }); + case 'volumeup': + return this.rpcCall('Application.SetVolume', { + 'volume': 'increment' + }); + case 'volumedown': + return this.rpcCall('Application.SetVolume', { + 'volume': 'decrement' + }); + } + + // TODO: Get active player + if ($('#videoDescription').is(':visible')) { + player = this.playlists["video"]; + } else if ($('#audioDescription').is(':visible')) { + player = this.playlists["audio"]; + } + + if (player >= 0) { + switch (keyPressed) { + case 'playpause': + return this.rpcCall('Player.PlayPause', { + 'playerid': player + }); + case 'stop': + return this.rpcCall('Player.Stop', { + 'playerid': player + }); + case 'next': + return this.rpcCall('Player.GoTo', { + 'playerid': player, + 'to': 'next' + }); + case 'previous': + return this.rpcCall('Player.GoTo', { + 'playerid': player, + 'to': 'previous' + }); + case 'forward': + return this.rpcCall('Player.SetSpeed', { + 'playerid': player, + 'speed': 'increment' + }); + case 'rewind': + return this.rpcCall('Player.SetSpeed', { + 'playerid': player, + 'speed': 'decrement' + }); + } + } + }, + musicLibraryOpen: function (event) { + this.resetPage(); + $('#musicLibrary').addClass('selected'); + $('.contentContainer').hide(); + var libraryContainer = $('#libraryContainer'); + if (!libraryContainer || libraryContainer.length === 0) { + $('#spinner').show(); + libraryContainer = $('<div>'); + libraryContainer.attr('id', 'libraryContainer') + .addClass('contentContainer'); + $('#content').append(libraryContainer); + xbmc.rpc.request({ + 'context': this, + 'method': 'AudioLibrary.GetAlbums', + 'params': { + 'limits': { + 'start': 0 + }, + 'properties': [ + 'description', + 'theme', + 'mood', + 'style', + 'type', + 'albumlabel', + 'artist', + 'genre', + 'rating', + 'title', + 'year', + 'thumbnail' + ], + 'sort': { + 'method': 'artist' + } + }, + 'success': function (data) { + if (data && data.result && data.result.albums) { + this.albumList = data.result.albums; + $.each($(this.albumList), jQuery.proxy(function (i, item) { + var floatableAlbum = this.generateThumb('album', item + .thumbnail, item.title, item.artist); + floatableAlbum.bind('click', { + album: item + }, jQuery.proxy(this.displayAlbumDetails, this)); + libraryContainer.append(floatableAlbum); + }, this)); + libraryContainer.append($('<div>').addClass('footerPadding')); + $('#spinner').hide(); + libraryContainer.bind('scroll', { + activeLibrary: libraryContainer + }, jQuery.proxy(this.updateScrollEffects, this)); + libraryContainer.trigger('scroll'); + myScroll = new iScroll('libraryContainer'); + } else { + libraryContainer.html(''); + } + } + }); + } else { + libraryContainer.show(); + libraryContainer.trigger('scroll'); + } + }, + getThumbnailPath: function (thumbnail) { + return thumbnail ? ('image/' + encodeURI(thumbnail)) : xbmc.core.DEFAULT_ALBUM_COVER; + }, + generateThumb: function (type, thumbnail, title, artist) { + title = title || ''; + artist = artist || ''; + + var showTitle = title, + showArtist = artist; + var floatableAlbum = $('<div>'); + var path = this.getThumbnailPath(thumbnail); + if (title.length > 21) { + showTitle = $.trim(title.substr(0, 18)) + '...'; + } + if (artist.length > 22) { + showArtist = $.trim(artist.substr(0, 20)) + '...'; + } + var className = ''; + var code = ''; + switch (type) { + case 'album': + className = 'floatableAlbum'; + code = '<p class="album" title="' + title + '">' + showTitle + '</p><p class="artist" title="' + + artist + '">' + artist + '</p>'; + break; + case 'movie': + className = 'floatableMovieCover'; + code = '<p class="album" title="' + title + '">' + showTitle + '</p>'; + break; + case 'tvshow': + className = 'floatableTVShowCover'; + break; + case 'tvshowseason': + className = 'floatableTVShowCoverSeason'; + break; + case 'image': + case 'directory': + className = 'floatableAlbum'; + code = '<p class="album" title="' + title + '">' + showTitle + '</p>'; + break; + case 'profile': + className = 'floatableProfileThumb'; + code = '<p class="album" title="' + title + '">' + showTitle + '</p>'; + break; + } + return floatableAlbum.addClass(className).html('<div class="imgWrapper"><div class="inner"><img src="' + + path + '" alt="' + title + '" /></div></div>' + code); + }, + showAlbumSelectorBlock: function (album) { + if (album) { + var prevAlbum = null, + nextAlbum = null; + $.each($(this.albumList), jQuery.proxy(function (i, item) { + if (item.albumid == album.albumid) { + if (this.albumList.length > 1) { + prevAlbum = this.albumList[i <= 0 ? this.albumList.length - 1 : i - 1]; + nextAlbum = this.albumList[i >= this.albumList.length ? 0 : i + 1]; + } + return false; /* .each break */ + } + }, this)); + var albumSelectorBlock = $('#albumSelector'); + if (!albumSelectorBlock || albumSelectorBlock.length === 0) { + albumSelectorBlock = $('<div>'); + albumSelectorBlock.attr('id', 'albumSelector') + .html( + '<table><tr><td class="allAlbums">All Albums</td><td class="activeAlbumTitle"></td>' + + '<td class="prevAlbum"> </td><td class="nextAlbum"> </td></tr></table>' + ); + $('#content').prepend(albumSelectorBlock); + $('#albumSelector .allAlbums').bind('click', jQuery.proxy(this.hideAlbumDetails, this)); + } + $('#albumSelector .prevAlbum').unbind(); + $('#albumSelector .nextAlbum').unbind(); + if (prevAlbum) { + $('#albumSelector .prevAlbum').bind('click', { + album: prevAlbum + }, jQuery.proxy(this.displayAlbumDetails, this)); + } + if (nextAlbum) { + $('#albumSelector .nextAlbum').bind('click', { + album: nextAlbum + }, jQuery.proxy(this.displayAlbumDetails, this)); + } + $('#albumSelector .activeAlbumTitle').html(album.title || 'Unknown Album'); + albumSelectorBlock.show(); + } + }, + hideAlbumDetails: function () { + $('.contentContainer').hide(); + this.musicLibraryOpen(); + }, + displayAlbumDetails: function (event) { + this.showAlbumSelectorBlock(event.data.album); + var albumDetailsContainer = $('#albumDetails' + event.data.album.albumid); + $('#topScrollFade').hide(); + if (!albumDetailsContainer || albumDetailsContainer.length === 0) { + $('#spinner').show(); + xbmc.rpc.request({ + 'context': this, + 'method': 'AudioLibrary.GetSongs', + 'params': { + 'properties': [ + 'title', + 'artist', + 'genre', + 'track', + 'duration', + 'year', + 'rating', + 'playcount' + ], + 'sort': { + 'method': 'track' + }, + 'filter': { + 'albumid': event.data.album.albumid + } + }, + 'success': function (data) { + albumDetailsContainer = $('<div>'); + albumDetailsContainer.attr('id', 'albumDetails' + event.data.album.albumid) + .addClass('contentContainer') + .addClass('albumContainer') + .html( + '<table class="albumView"><thead><tr class="headerRow"><th>Artwork</th><th> </th>' + + '<th>Name</th><th class="time">Time</th><th>Artist</th><th>Genre</th></tr></thead>' + + '<tbody class="resultSet"></tbody></table>' + ); + $('.contentContainer').hide(); + $('#content').append(albumDetailsContainer); + var albumThumbnail = event.data.album.thumbnail; + var albumTitle = event.data.album.title || 'Unknown Album'; + var albumArtist = event.data.album.artist.join(', ') || 'Unknown Artist'; + var trackCount = data.result.limits.total; + $.each($(data.result.songs), jQuery.proxy(function (i, item) { + var trackRow, trackNumberTD; + if (i === 0) { + trackRow = $('<tr>').addClass('trackRow').addClass('tr' + + i % 2); + trackRow.append($('<td>').attr('rowspan', ++trackCount + 1) + .addClass('albumThumb')); + for (var a = 0; a < 5; a++) { + trackRow.append($('<td>').html(' ').attr('style', + 'display: none')); + } + $('#albumDetails' + event.data.album.albumid + + ' .resultSet').append(trackRow); + } + trackRow = $('<tr>').addClass('trackRow').addClass('tr' + i % 2) + .bind('click', { + album: event.data.album, + itmnbr: i + }, jQuery.proxy(this.playTrack, this)); + trackNumberTD = $('<td>').html(item.track); + + trackRow.append(trackNumberTD); + var trackTitleTD = $('<td>').html(item.title); + + trackRow.append(trackTitleTD); + var trackDurationTD = $('<td>') + .addClass('time') + .html(xbmc.core.durationToString(item.duration)); + + trackRow.append(trackDurationTD); + var trackArtistTD = $('<td>').html(item.artist.join(', ')); + + trackRow.append(trackArtistTD); + var trackGenreTD = $('<td>').html(item.genre.join(', ')); + + trackRow.append(trackGenreTD); + $('#albumDetails' + event.data.album.albumid + ' .resultSet') + .append(trackRow); + }, this)); + if (trackCount > 0) { + var trackRow = $('<tr>').addClass('fillerTrackRow'), + i; + for (i = 0; i < 5; i++) { + trackRow.append($('<td>').html(' ')); + } + $('#albumDetails' + event.data.album.albumid + ' .resultSet').append( + trackRow); + + var trackRow2 = $('<tr>').addClass('fillerTrackRow2'); + trackRow2.append($('<td>').addClass('albumBG').html(' ')); + for (i = 0; i < 5; i++) { + trackRow2.append($('<td>').html(' ')); + } + $('#albumDetails' + event.data.album.albumid + ' .resultSet').append( + trackRow2); + } + $('#albumDetails' + event.data.album.albumid + ' .albumThumb') + .append(this.generateThumb('album', albumThumbnail, albumTitle, + albumArtist)) + .append($('<div>').addClass('footerPadding')); + $('#spinner').hide(); + myScroll = new iScroll('albumDetails' + event.data.album.albumid); + } + }); + } else { + $('.contentContainer').hide(); + $('#albumDetails' + event.data.album.albumid).show(); + } + }, + togglePosterView: function (event) { + var view = event.data.mode; + var wthumblist, hthumblist, hthumbdetails; + $("#toggleBanner").removeClass('activeMode'); + $("#togglePoster").removeClass('activeMode'); + $("#toggleLandscape").removeClass('activeMode'); + switch (view) { + case 'landscape': + xbmc.core.setCookie('TVView', 'landscape'); + wthumblist = '210px'; + hthumblist = '118px'; + hthumbdetails = '213px'; + $("#toggleLandscape").addClass('activeMode'); + break; + case 'banner': + xbmc.core.setCookie('TVView', 'banner'); + wthumblist = '379px'; + hthumblist = '70px'; + hthumbdetails = '70px'; + $("#toggleBanner").addClass('activeMode'); + break; + default: + xbmc.core.setCookie('TVView', 'poster'); + wthumblist = '135px'; + hthumblist = '199px'; + hthumbdetails = '559px'; + $("#togglePoster").addClass('activeMode'); + break; + } + $(".floatableTVShowCover, .floatableTVShowCover div.imgWrapper, .floatableTVShowCover img, " + + ".floatableTVShowCover div.imgWrapper div.inner") + .css('width', wthumblist).css('height', hthumblist); + $(".floatableTVShowCoverSeason div.imgWrapper, .floatableTVShowCoverSeason div.imgWrapper div.inner," + + ".floatableTVShowCoverSeason img, .floatableTVShowCoverSeason") + .css('height', hthumbdetails); + }, + displayTVShowDetails: function (event) { + var tvshowDetailsContainer = $('#tvShowDetails' + event.data.tvshow.tvshowid); + $('#topScrollFade').hide(); + toggle = this.toggle.detach(); + if (!tvshowDetailsContainer || tvshowDetailsContainer.length === 0) { + $('#spinner').show(); + xbmc.rpc.request({ + 'context': this, + 'method': 'VideoLibrary.GetSeasons', + 'params': { + 'properties': [ + 'season', + 'showtitle', + 'playcount', + 'episode', + 'thumbnail', + 'fanart' + ], + 'tvshowid': event.data.tvshow.tvshowid + }, + 'success': function (data) { + tvshowDetailsContainer = $('<div>'); + tvshowDetailsContainer.attr('id', 'tvShowDetails' + event.data.tvshow.tvshowid) + .css('display', 'none') + .addClass('contentContainer') + .addClass('tvshowContainer'); + var showThumb = this.generateThumb('tvshowseason', event.data.tvshow.thumbnail, + event.data.tvshow.title); + if (data && data.result && data.result.seasons && data.result.seasons.length > + 0) { + var showDetails = $('<div>').addClass('showDetails'); + showDetails.append(toggle); + showDetails.append($('<p>').html(data.result.seasons[0].showtitle).addClass( + 'showTitle')); + var seasonSelectionSelect = $('<select>').addClass('seasonPicker'); + this.tvActiveShowContainer = tvshowDetailsContainer; + $.each($(data.result.seasons), function (i, item) { + var season = $('<option>').attr('value', i); + season.text(item.label); + seasonSelectionSelect.append(season); + }); + seasonSelectionSelect.bind('change', { + tvshow: event.data.tvshow.tvshowid, + seasons: data.result.seasons, + element: seasonSelectionSelect + }, jQuery.proxy(this.displaySeasonListings, this)); + showDetails.append(seasonSelectionSelect); + tvshowDetailsContainer.append(showDetails); + tvshowDetailsContainer.append(showThumb); + seasonSelectionSelect.trigger('change'); + $('#content').append(tvshowDetailsContainer); + if (xbmc.core.getCookie('TVView') !== null && + xbmc.core.getCookie('TVView') !== 'banner' + ) { + var view = xbmc.core.getCookie('TVView'); + switch (view) { + case 'poster': + togglePoster.trigger('click'); + break; + case 'landscape': + toggleLandscape.trigger('click'); + break; + } + } + tvshowDetailsContainer.fadeIn(); + } + $('#spinner').hide(); + } + }); + } else { + $('.contentContainer').hide(); + $('#tvShowDetails' + event.data.tvshow.tvshowid).show(); + $('#tvShowDetails' + event.data.tvshow.tvshowid + ' select').trigger('change'); + } + }, + displaySeasonListings: function (event) { + var selectedVal = event.data.element.val(); + var seasons = event.data.seasons; + $('#topScrollFade').hide(); + var oldListings = $('.episodeListingsContainer', this.tvActiveShowContainer).fadeOut(); + this.tvActiveSeason = selectedVal; + xbmc.rpc.request({ + 'context': this, + 'method': 'VideoLibrary.GetEpisodes', + 'params': { + 'properties': [ + 'title', + 'thumbnail', + 'episode', + 'plot', + 'season' + ], + 'season': seasons[selectedVal].season, + 'tvshowid': event.data.tvshow + }, + 'success': function (data) { + var episodeListingsContainer = $('<div>').addClass('episodeListingsContainer'); + var episodeTable = $('<table>').addClass('seasonView').html( + '<thead><tr class="headerRow"><th class="thumbHeader">N°</th><th>Title</th>' + + '<th class="thumbHeader">Thumb</th><th class="thumbHeader">Details</th></tr></thead>' + + '<tbody class="resultSet"></tbody>' + ); + $.each($(data.result.episodes), jQuery.proxy(function (i, item) { + var episodeRow = $('<tr>').addClass('episodeRow').addClass('tr' + + i % 2); + var episodePictureImg = $('<img>').bind('click', { + episode: item + }, jQuery.proxy(this.playTVShow, this)).css('cursor', 'pointer'); + episodePictureImg.attr('src', this.getThumbnailPath(item + .thumbnail)); + var episodePicture = $('<td>').addClass('episodeThumb').append( + episodePictureImg).bind('click', { + episode: item + }, jQuery.proxy(this.playTVShow, this)); + var episodeNumber = $('<td>').addClass('episodeNumber').html(item + .episode).bind('click', { + episode: item + }, jQuery.proxy(this.playTVShow, this)); + var episodeTitle = $('<td>').html(item.title).bind('click', { + episode: item + }, jQuery.proxy(this.playTVShow, this)); + var episodeDetails = $('<td class="info">').html('').bind('click', { + episode: item + }, jQuery.proxy(this.displayEpisodeDetails, this)).css('cursor', + 'pointer'); + episodeRow.append(episodeNumber).append(episodeTitle).append( + episodePicture).append(episodeDetails); + episodeTable.append(episodeRow); + }, this)); + episodeListingsContainer.append(episodeTable); + $(this.tvActiveShowContainer).append(episodeListingsContainer); + } + }); + }, + displayEpisodeDetails: function (event) { + var episodeDetails = $('<div>').attr('id', 'episode-' + event.data.episode.episodeid).addClass( + 'episodePopoverContainer'); + episodeDetails.append($('<img>').attr('src', 'images/close-button.png').addClass('closeButton').bind( + 'click', jQuery.proxy(this.hideOverlay, this))); + episodeDetails.append($('<img>').attr('src', this.getThumbnailPath(event.data.episode.thumbnail)) + .addClass('episodeCover')); + episodeDetails.append($('<div>').addClass('playIcon').bind('click', { + episode: event.data.episode + }, jQuery.proxy(this.playTVShow, this))); + var episodeTitle = $('<p>').addClass('episodeTitle'); + var yearText = event.data.episode.year ? ' <span class="year">(' + event.data.episode.year + + ')</span>' : ''; + episodeTitle.html(event.data.episode.title + yearText); + episodeDetails.append(episodeTitle); + if (event.data.episode.runtime) { + episodeDetails.append($('<p>').addClass('runtime').html('<strong>Runtime:</strong> ' + Math.ceil( + event.data.episode.runtime / 60) + ' minutes')); + } + if (event.data.episode.season) { + episodeDetails.append($('<p>').addClass('season').html('<strong>Season:</strong> ' + event.data + .episode.season)); + } + if (event.data.episode.episode) { + episodeDetails.append($('<p>').addClass('episode').html('<strong>Episode:</strong> ' + event.data + .episode.episode)); + } + if (event.data.episode.plot) { + episodeDetails.append($('<p>').addClass('plot').html('<strong>Plot:</strong> <br/><br/>' + event + .data.episode.plot)); + } + if (event.data.episode.genre) { + episodeDetails.append($('<p>').addClass('genre').html('<strong>Genre:</strong> ' + event.data + .episode.genre)); + } + if (event.data.episode.director) { + episodeDetails.append($('<p>').addClass('director').html('<strong>Directed By:</strong> ' + event + .data.episode.director)); + } + this.activeCover = episodeDetails; + $('body').append(episodeDetails); + $('#overlay').show(); + this.updatePlayButtonLocation(); + }, + playTVShow: function (event) { + xbmc.rpc.request({ + 'context': this, + 'method': 'Player.Open', + 'params': { + 'item': { + 'episodeid': event.data.episode.episodeid + } + }, + 'success': function (data) { + this.hideOverlay(); + } + }); + }, + hideOverlay: function (event) { + if (this.activeCover) { + $(this.activeCover).remove(); + this.activeCover = null; + } + $('#overlay').hide(); + }, + updatePlayButtonLocation: function (event) { + var movieContainer = $('.movieCover'), + playIcon; + if (movieContainer.length > 0) { + playIcon = $('.playIcon'); + if (playIcon.length > 0) { + var heightpi = $(movieContainer[0]).height(); + playIcon.width(Math.floor(0.65 * heightpi)); + playIcon.height(heightpi); + } + } + var episodeContainer = $('.episodeCover'); + if (episodeContainer.length > 0) { + playIcon = $('.playIcon'); + if (playIcon.length > 0) { + var widthpi = $(episodeContainer[0]).width(); + playIcon.width(widthpi); + //assume 16/9 thumb + playIcon.height(Math.floor(widthpi * 9 / 16)); + } + } + }, + playMovie: function (event) { + xbmc.rpc.request({ + 'context': this, + 'method': 'Player.Open', + 'params': { + 'item': { + 'movieid': event.data.movie.movieid + } + }, + 'success': function (data) { + this.hideOverlay(); + } + }); + }, + displayMovieDetails: function (event) { + var movieDetails = $('<div>').attr('id', 'movie-' + event.data.movie.movieid).addClass( + 'moviePopoverContainer'); + movieDetails.append($('<img>').attr('src', 'images/close-button.png').addClass('closeButton').bind( + 'click', jQuery.proxy(this.hideOverlay, this))); + movieDetails.append($('<img>').attr('src', this.getThumbnailPath(event.data.movie.thumbnail)).addClass( + 'movieCover')); + movieDetails.append($('<div>').addClass('playIcon').bind('click', { + movie: event.data.movie + }, jQuery.proxy(this.playMovie, this))); + var movieTitle = $('<p>').addClass('movieTitle'); + var yearText = event.data.movie.year ? ' <span class="year">(' + event.data.movie.year + ')</span>' : + ''; + movieTitle.html(event.data.movie.title + yearText); + movieDetails.append(movieTitle); + if (event.data.movie.runtime) { + movieDetails.append($('<p>').addClass('runtime').html('<strong>Runtime:</strong> ' + Math.ceil(event + .data.movie.runtime / 60) + ' minutes')); + } + if (event.data.movie.plot) { + movieDetails.append($('<p>').addClass('plot').html(event.data.movie.plot)); + } + if (event.data.movie.genre) { + movieDetails.append($('<p>').addClass('genre').html('<strong>Genre:</strong> ' + event.data.movie + .genre)); + } + if (event.data.movie.director) { + movieDetails.append($('<p>').addClass('director').html('<strong>Directed By:</strong> ' + event.data + .movie.director)); + } + this.activeCover = movieDetails; + $('body').append(movieDetails); + $('#overlay').show(); + this.updatePlayButtonLocation(); + }, + playTrack: function (event) { + xbmc.rpc.request({ + 'context': this, + 'method': 'Playlist.Clear', + 'params': { + 'playlistid': this.playlists["audio"] + }, + 'success': function (data) { + xbmc.rpc.request({ + 'context': this, + 'method': 'Playlist.Add', + 'params': { + 'playlistid': this.playlists["audio"], + 'item': { + 'albumid': event.data.album.albumid + } + }, + 'success': function (data) { + xbmc.rpc.request({ + 'method': 'Player.Open', + 'params': { + 'item': { + 'playlistid': this.playlists["audio"], + 'position': event.data.itmnbr + } + }, + 'success': function () {} + }); + } + }); + } + }); + }, + loadProfile: function (event) { + return xbmc.rpc.request({ + 'context': this, + 'method': 'Profiles.LoadProfile', + 'params': { + 'profile': event.data.profile.label + } + }); + }, + movieLibraryOpen: function () { + this.resetPage(); + $('#movieLibrary').addClass('selected'); + $('.contentContainer').hide(); + var libraryContainer = $('#movieLibraryContainer'); + if (!libraryContainer || libraryContainer.length === 0) { + $('#spinner').show(); + xbmc.rpc.request({ + 'context': this, + 'method': 'VideoLibrary.GetMovies', + 'params': { + 'limits': { + 'start': 0 + }, + 'properties': [ + 'genre', + 'director', + 'trailer', + 'tagline', + 'plot', + 'plotoutline', + 'title', + 'originaltitle', + 'lastplayed', + 'runtime', + 'year', + 'playcount', + 'rating', + 'thumbnail', + 'file' + ], + 'sort': { + 'method': 'sorttitle', + 'ignorearticle': true + } + }, + 'success': function (data) { + if (data && data.result && data.result.movies) { + libraryContainer = $('<div>'); + libraryContainer.attr('id', 'movieLibraryContainer') + .addClass('contentContainer'); + $('#content').append(libraryContainer); + } else { + libraryContainer.html(''); + } + $.each($(data.result.movies), jQuery.proxy(function (i, item) { + var floatableMovieCover = this.generateThumb('movie', item + .thumbnail, item.title); + floatableMovieCover.bind('click', { + movie: item + }, jQuery.proxy(this.displayMovieDetails, this)); + libraryContainer.append(floatableMovieCover); + }, this)); + libraryContainer.append($('<div>').addClass('footerPadding')); + $('#spinner').hide(); + libraryContainer.bind('scroll', { + activeLibrary: libraryContainer + }, jQuery.proxy(this.updateScrollEffects, this)); + libraryContainer.trigger('scroll'); + myScroll = new iScroll('movieLibraryContainer'); + } + }); + } else { + libraryContainer.show(); + libraryContainer.trigger('scroll'); + } + }, + tvshowLibraryOpen: function () { + this.resetPage(); + $('#tvshowLibrary').addClass('selected'); + $('.contentContainer').hide(); + var libraryContainer = $('#tvshowLibraryContainer'); + if (!libraryContainer || libraryContainer.length === 0) { + $('#spinner').show(); + toggle = $('<p>').addClass('toggle'); + togglePoster = $('<span>Poster</span>'); + togglePoster.attr('id', 'togglePoster') + .css('cursor', 'pointer') + .bind('click', { + mode: 'poster' + }, jQuery.proxy(this.togglePosterView, this)); + toggleBanner = $('<span>Banner</span>'); + toggleBanner.attr('id', 'toggleBanner') + .css('cursor', 'pointer') + .addClass('activeMode') + .bind('click', { + mode: 'banner' + }, jQuery.proxy(this.togglePosterView, this)); + toggleLandscape = $('<span>Landscape</span>'); + toggleLandscape.attr('id', 'toggleLandscape') + .css('cursor', 'pointer') + .bind('click', { + mode: 'landscape' + }, jQuery.proxy(this.togglePosterView, this)); + toggle.append(toggleBanner).append(' | ').append(togglePoster).append(' | ').append( + toggleLandscape); + this.toggle = toggle; + xbmc.rpc.request({ + 'context': this, + 'method': 'VideoLibrary.GetTVShows', + 'params': { + 'properties': [ + 'genre', + 'plot', + 'title', + 'lastplayed', + 'episode', + 'year', + 'playcount', + 'rating', + 'thumbnail', + 'studio', + 'mpaa', + 'premiered' + ], + 'sort': { + 'method': 'sorttitle', + 'ignorearticle': true + } + }, + 'success': function (data) { + if (data && data.result && data.result.tvshows) { + libraryContainer = $('<div>'); + libraryContainer.append(toggle); + libraryContainer.attr('id', 'tvshowLibraryContainer') + .addClass('contentContainer'); + $('#content').append(libraryContainer); + } else { + libraryContainer.html(''); + } + $.each($(data.result.tvshows), jQuery.proxy(function (i, item) { + var floatableTVShowCover = this.generateThumb('tvshow', item + .thumbnail, item.title); + floatableTVShowCover.bind('click', { + tvshow: item + }, jQuery.proxy(this.displayTVShowDetails, this)); + libraryContainer.append(floatableTVShowCover); + }, this)); + libraryContainer.append($('<div>').addClass('footerPadding')); + $('#spinner').hide(); + libraryContainer.bind('scroll', { + activeLibrary: libraryContainer + }, jQuery.proxy(this.updateScrollEffects, this)); + libraryContainer.trigger('scroll'); + myScroll = new iScroll('tvshowLibraryContainer'); + if (xbmc.core.getCookie('TVView') !== null && + xbmc.core.getCookie('TVView') !== 'banner' + ) { + var view = xbmc.core.getCookie('TVView'); + switch (view) { + case 'poster': + togglePoster.trigger('click'); + break; + case 'landscape': + toggleLandscape.trigger('click'); + break; + } + } + } + }); + } else { + libraryContainer.prepend($(".toggle").detach()).show(); + libraryContainer.trigger('scroll'); + } + }, + profilesOpen: function () { + this.resetPage(); + $('#profiles').addClass('selected'); + $('.contentContainer').hide(); + var libraryContainer = $('#profilesContainer'); + if (!libraryContainer || libraryContainer.length == 0) { + $('#spinner').show(); + var currentProfile = ""; + xbmc.rpc.request({ + 'method': 'Profiles.GetCurrentProfile', + 'params': { + 'properties': [ + 'lockmode' + ] + }, + 'success': function (data) { + if (data) + if (data.result) + currentProfile = data.result.label; + } + }); + xbmc.rpc.request({ + 'context': this, + 'method': 'Profiles.GetProfiles', + 'params': { + 'limits': { + 'start': 0 + }, + 'properties': [ + 'thumbnail' + ], + 'sort': { + 'method': 'sorttitle', + 'ignorearticle': true + } + }, + 'success': function (data) { + if (data && data.result && data.result.profiles) { + libraryContainer = $('<div>'); + libraryContainer.attr('id', 'profilesContainer') + .addClass('contentContainer'); + $('#content').append(libraryContainer); + } else { + libraryContainer.html(''); + } + $.each($(data.result.profiles), jQuery.proxy(function (i, item) { + var itemLabel = item.label; + if (currentProfile == itemLabel) { + itemLabel = itemLabel + "*"; + } + var floatableProfileThumb = this.generateThumb('profile', item + .thumbnail, itemLabel); + floatableProfileThumb.bind('click', { + profile: item + }, jQuery.proxy(this.loadProfile, this)); + libraryContainer.append(floatableProfileThumb); + }, this)); + libraryContainer.append($('<div>').addClass('footerPadding')); + $('#spinner').hide(); + libraryContainer.bind('scroll', { + activeLibrary: libraryContainer + }, jQuery.proxy(this.updateScrollEffects, this)); + libraryContainer.trigger('scroll'); + myScroll = new iScroll('profilesContainer'); + } + }); + } else { + libraryContainer.show(); + libraryContainer.trigger('scroll'); + } + }, + updateScrollEffects: function (event) { + if (event.data.activeLibrary && $(event.data.activeLibrary).scrollTop() > 0) { + $('#topScrollFade').fadeIn(); + } else { + $('#topScrollFade').fadeOut(); + } + }, + startSlideshow: function (event) { + xbmc.rpc.request({ + 'method': 'Player.Open', + 'params': { + 'item': { + 'recursive': 'true', + 'random': 'true', + 'path': this.replaceAll(event.data.directory.file, "\\", "\\\\") + } + }, + 'success': function () {} + }); + }, + showDirectory: function (event) { + var directory = event.data.directory.file; + var jsonDirectory = this.replaceAll(directory, "\\", "\\\\"); + this.resetPage(); + $('#pictureLibrary').addClass('selected'); + $('.contentContainer').hide(); + var libraryContainer = $('#pictureLibraryDirContainer' + directory); + if (!libraryContainer || libraryContainer.length === 0) { + $('#spinner').show(); + xbmc.rpc.request({ + 'context': this, + 'method': 'Files.GetDirectory', + 'params': { + 'media': 'pictures', + 'directory': jsonDirectory + }, + 'success': function (data) { + if (data && data.result && (data.result.directories || data.result.files)) { + libraryContainer = $('<div>'); + libraryContainer.attr('id', 'pictureLibraryDirContainer' + directory) + .addClass('contentContainer'); + $('#content').append(libraryContainer); + var breadcrumb = $('<div>'); + var seperator = '/'; + var item = ''; + var directoryArray = directory.split(seperator); + jQuery.each(directoryArray, function (i, v) { + if (v !== '') { + item += v + seperator; + breadcrumb.append($('<div>').text(' > ' + v).css('float', + 'left').addClass('breadcrumb')); + } + }); + libraryContainer.append(breadcrumb); + libraryContainer.append($('<div>').css('clear', 'both')); + if (data.result.files) { + $.each($(data.result.files), jQuery.proxy(function (i, item) { + if (item.filetype == "file") { + var floatableImage = this.generateThumb('image', + item.file, item.label); + libraryContainer.append(floatableImage); + } else if (item.filetype == "directory") { + var floatableShare = this.generateThumb('directory', + item.thumbnail, item.label); + floatableShare.bind('click', { + directory: item + }, jQuery.proxy(this.showDirectory, this)); + libraryContainer.append(floatableShare); + } + }, this)); + } + libraryContainer.append($('<div>').addClass('footerPadding')); + } else { + libraryContainer.html(''); + } + $('#spinner').hide(); + libraryContainer.bind('scroll', { + activeLibrary: libraryContainer + }, jQuery.proxy(this.updateScrollEffects, this)); + libraryContainer.trigger('scroll'); + myScroll = new iScroll('#pictureLibraryDirContainer' + directory); + } + }); + } else { + libraryContainer.show(); + libraryContainer.trigger('scroll'); + } + }, + pictureLibraryOpen: function () { + this.resetPage(); + $('#pictureLibrary').addClass('selected'); + $('.contentContainer').hide(); + var libraryContainer = $('#pictureLibraryContainer'); + if (!libraryContainer || libraryContainer.length === 0) { + $('#spinner').show(); + xbmc.rpc.request({ + 'context': this, + 'method': 'Files.GetSources', + 'params': { + 'media': 'pictures' + }, + 'success': function (data) { + if (data && data.result && data.result.shares) { + libraryContainer = $('<div>'); + libraryContainer.attr('id', 'pictureLibraryContainer') + .addClass('contentContainer'); + $('#content').append(libraryContainer); + } else { + libraryContainer.html(''); + } + $.each($(data.result.shares), jQuery.proxy(function (i, item) { + var floatableShare = this.generateThumb('directory', item + .thumbnail, item.label); + floatableShare.bind('click', { + directory: item + }, jQuery.proxy(this.showDirectory, this)); + libraryContainer.append(floatableShare); + }, this)); + libraryContainer.append($('<div>').addClass('footerPadding')); + $('#spinner').hide(); + libraryContainer.bind('scroll', { + activeLibrary: libraryContainer + }, jQuery.proxy(this.updateScrollEffects, this)); + libraryContainer.trigger('scroll'); + myScroll = new iScroll('#pictureLibraryContainer'); + } + }); + } else { + libraryContainer.show(); + libraryContainer.trigger('scroll'); + } + } +}; diff --git a/debian/webinterface-default/js/NowPlayingManager.js b/debian/webinterface-default/js/NowPlayingManager.js new file mode 100755 index 0000000..fb34f74 --- /dev/null +++ b/debian/webinterface-default/js/NowPlayingManager.js @@ -0,0 +1,661 @@ +/* + * 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/>. + * + */ + +var NowPlayingManager = function () { + this.init(); + return true; +} + +NowPlayingManager.prototype = { + updateCounter: 0, + activePlayer: "", + activePlayerId: -1, + currentItem: -1, + playing: false, + paused: false, + playlistid: -1, + + init: function () { + $('#pbPause').hide(); /* Assume we are not playing something */ + this.bindPlaybackControls(); + this.updateState(); + $('#nextTrack').bind('click', jQuery.proxy(this.showPlaylist, this)); + $('#nowPlayingPlaylist').bind('click', function () { + return false; + }); + $(window).bind('click', jQuery.proxy(this.hidePlaylist, this)); + }, + updateState: function () { + xbmc.rpc.request({ + 'context': this, + 'method': 'Player.GetActivePlayers', + 'timeout': 3000, + 'success': function (data) { + if (data && data.result && data.result.length > 0) { + if (data.result[0].playerid != this.activePlayerId) { + this.activePlayerId = data.result[0].playerid; + this.activePlayer = data.result[0].type; + if (this.activePlayer == "audio") { + this.stopVideoPlaylistUpdate(); + this.displayAudioNowPlaying(); + } else if (this.activePlayer == "video") { + this.stopAudioPlaylistUpdate(); + this.displayVideoNowPlaying(); + } else { + this.stopVideoPlaylistUpdate(); + this.stopAudioPlaylistUpdate(); + this.activePlayer = ""; + this.activePlayerId = -1; + } + + this.stopRefreshTime(); + this.updatePlayer(); + } + } else if (!data || !data.result || data.result.length <= 0) { + this.stopVideoPlaylistUpdate(); + this.stopAudioPlaylistUpdate(); + this.activePlayer = ""; + this.activePlayerId = -1; + } + + if (this.activePlayerId >= 0) { + this.showFooter(); + } else { + this.stopRefreshTime(); + this.hideFooter(); + } + + setTimeout(jQuery.proxy(this.updateState, this), 1000); + }, + 'error': function (data, error) { + xbmc.core.displayCommunicationError(); + setTimeout(jQuery.proxy(this.updateState, this), 2000); + } + }); + }, + updatePlayer: function () { + xbmc.rpc.request({ + 'context': this, + 'method': 'Player.GetProperties', + 'params': { + 'playerid': this.activePlayerId, + 'properties': [ + 'playlistid', + 'speed', + 'position', + 'totaltime', + 'time' + ] + }, + 'success': function (data) { + if (data && data.result) { + this.playlistid = data.result.playlistid; + this.playing = data.result.speed != 0; + this.paused = data.result.speed == 0; + this.currentItem = data.result.position; + this.trackBaseTime = xbmc.core.timeToDuration(data.result.time); + this.trackDurationTime = xbmc.core.timeToDuration(data.result.totaltime); + if (!this.autoRefreshAudioData && !this.autoRefreshVideoData && this.playing) { + if (this.activePlayer == 'audio') { + this.autoRefreshAudioData = true; + this.refreshAudioData(); + } else if (this.activePlayer == 'video') { + this.autoRefreshVideoData = true; + this.refreshVideoData(); + } + } + } + if ((this.autoRefreshAudioData || this.autoRefreshVideoData) && !this + .activeItemTimer) { + this.activeItemTimer = 1; + setTimeout(jQuery.proxy(this.updateActiveItemDurationLoop, this), 1000); + } + } + }); + }, + bindPlaybackControls: function () { + $('#pbNext').bind('click', jQuery.proxy(this.nextTrack, this)); + $('#pbPrev').bind('click', jQuery.proxy(this.prevTrack, this)); + $('#pbStop').bind('click', jQuery.proxy(this.stopTrack, this)); + $('#pbPlay').bind('click', jQuery.proxy(this.playPauseTrack, this)); + $('#pbPause').bind('click', jQuery.proxy(this.playPauseTrack, this)); + that = this + $(document).keypress(function (event) { + switch (event.which) { + case 32: //spacebar + event.preventDefault() + jQuery.proxy(that.playPauseTrack, that)(); + break; + case 120: //x key + event.preventDefault() + jQuery.proxy(that.stopTrack, that)(); + break; + case 44: //period key + event.preventDefault() + jQuery.proxy(that.nextTrack, that)(); + break; + case 46: //comma key + event.preventDefault() + jQuery.proxy(that.prevTrack, that)(); + break; + } + }); + }, + showPlaylist: function () { + $('#nextText').html('Playlist: '); + $('#nowPlayingPlaylist').show(); + return false; + }, + hidePlaylist: function () { + $('#nextText').html('Next: '); + $('#nowPlayingPlaylist').hide(); + return false; + }, + hideFooter: function () { + $('#footerPopover').hide(); + $('#overlay').css('bottom', '0px'); + }, + showFooter: function () { + $('#footerPopover').show(); + $('#overlay').css('bottom', '150px'); + }, + nextTrack: function () { + if (this.activePlayer) { + xbmc.rpc.request({ + 'method': 'Player.GoTo', + 'params': { + 'playerid': this.activePlayerId, + 'to': 'next' + }, + 'success': function () {} + }); + } + }, + prevTrack: function () { + if (this.activePlayer) { + xbmc.rpc.request({ + 'method': 'Player.GoTo', + 'params': { + 'playerid': this.activePlayerId, + 'to': 'previous' + }, + 'success': function () {} + }); + } + }, + stopTrack: function () { + if (this.activePlayer) { + xbmc.rpc.request({ + 'context': this, + 'method': 'Player.Stop', + 'params': { + 'playerid': this.activePlayerId + }, + 'success': function (data) { + if (data && data.result == 'OK') { + this.playing = false; + this.paused = false; + this.trackBaseTime = 0; + this.trackDurationTime = 0; + this.showPlayButton(); + } + } + }); + } + }, + playPauseTrack: function () { + if (this.activePlayer) { + var method = ((this.playing || this.paused) ? 'Player.PlayPause' : 'Playlist.Play'); + xbmc.rpc.request({ + 'context': this, + 'method': method, + 'params': { + 'playerid': this.activePlayerId + }, + 'success': function (data) { + if (data && data.result) { + this.playing = data.result.speed != 0; + this.paused = data.result.speed == 0; + if (this.playing) { + this.showPauseButton(); + } else { + this.showPlayButton(); + } + } + } + }); + } + }, + showPauseButton: function () { + $('#pbPause').show(); + $('#pbPlay').hide(); + }, + showPlayButton: function () { + $('#pbPause').hide(); + $('#pbPlay').show(); + }, + displayAudioNowPlaying: function () { + if (!this.autoRefreshAudioPlaylist) { + this.autoRefreshAudioPlaylist = true; + this.updateAudioPlaylist(); + } + }, + displayVideoNowPlaying: function () { + if (!this.autoRefreshVideoPlaylist) { + this.autoRefreshVideoPlaylist = true; + this.updateVideoPlaylist(); + } + }, + playPlaylistItem: function (sender) { + var sequenceId = $(sender.currentTarget).attr('seq'); + if (!this.activePlaylistItem || (this.activePlaylistItem !== undefined && sequenceId != this + .activePlaylistItem.seq)) { + xbmc.rpc.request({ + 'method': 'Player.GoTo', + 'params': { + 'playerid': this.activePlayerId, + 'to': sequenceId + }, + 'success': function () {} + }); + } + this.hidePlaylist(); + }, + playlistChanged: function (newPlaylist) { + if (this.activePlaylist && !newPlaylist || !this.activePlaylist && newPlaylist) { + return true; + } + if (!this.activePlaylist && !newPlaylist) { + return false; + } + if (this.activePlaylist.length != newPlaylist.length) { + return true; + } + for (var i = 0; i < newPlaylist.length; i++) { + if (!this.comparePlaylistItems(this.activePlaylist[i], newPlaylist[i])) { + return true; + } + } + return false; + }, + updateAudioPlaylist: function () { + xbmc.rpc.request({ + 'context': this, + 'method': 'Playlist.GetItems', + 'params': { + 'playlistid': this.playlistid, + 'properties': [ + 'title', + 'album', + 'artist', + 'duration', + 'thumbnail' + ] + }, + 'success': function (data) { + if (data && data.result && data.result.items && data.result.items.length > 0 && data + .result.limits.total > 0) { + if (!this.activePlaylistItem || this.playlistChanged(data.result.items) || (this + .activePlaylistItem && (this.activePlaylistItem.seq != this.currentItem) + )) { + var ul = $('<ul>'); + var activeItem; + $.each($(data.result.items), jQuery.proxy(function (i, item) { + var li = $('<li>'); + var code = '<span class="duration">' + xbmc.core + .durationToString(item.duration) + + '</span><div class="trackInfo" title="' + item.title + + ' - ' + item.artist + '"><span class="trackTitle">' + + item.title + '</span> - <span class="trackArtist">' + + item.artist + '</span></div>'; + if (i == this.currentItem) { + activeItem = item; + activeItem.seq = i; + li.addClass('activeItem'); + } + if (i == (this.currentItem + 1)) { + $('#nextTrack').html(code).show(); + } + li.bind('click', jQuery.proxy(this.playPlaylistItem, this)); + ul.append(li.attr('seq', i).html(code)); + }, this)); + if (data.result.limits.total > 1) { + if (activeItem && data.result.limits.total - 1 == activeItem.seq) { + $('#nextTrack').html( + '<div class="trackInfo">Last track in playlist</div>') + .show(); + } + $('#nextText').show(); + $('#nowPlayingPlaylist').html('').append(ul); + } else { + $('#nextText').hide(); + $('#nowPlayingPlaylist').hide(); + $('#nextTrack').hide(); + } + if (!this.comparePlaylistItems(activeItem, this.activePlaylistItem)) { + this.activePlaylistItem = activeItem; + if (!this.updateActiveItemDurationRunOnce) { + this.updateActiveItemDurationRunOnce = true; + this.updatePlayer(); + } + } else if (!activeItem) { + this.stopRefreshTime(); + } + this.activePlaylist = data.result.items; + $('#videoDescription').hide(); + $('#audioDescription').show(); + $('#nowPlayingPanel').show(); + } + } else { + this.activePlaylist = null; + $('#audioDescription').hide(); + $('#nowPlayingPanel').hide(); + } + if (this.autoRefreshAudioPlaylist) { + setTimeout(jQuery.proxy(this.updateAudioPlaylist, this), 1000); + } + }, + 'error': function (data) { + xbmc.core.displayCommunicationError(); + if (this.autoRefreshAudioPlaylist) { + setTimeout(jQuery.proxy(this.updateAudioPlaylist, this), + 2000); /* Slow down request period */ + } + } + }); + }, + stopAudioPlaylistUpdate: function () { + this.autoRefreshAudioPlaylist = false; + this.updateActiveItemDurationRunOnce = false; + }, + stopVideoPlaylistUpdate: function () { + this.autoRefreshVideoPlaylist = false; + this.updateActiveItemDurationRunOnce = false; + }, + updateActiveItemDurationLoop: function () { + this.activeItemTimer = 0; + this.updatePlayer(); + }, + refreshAudioDataLoop: function () { + this.audioRefreshTimer = 0; + this.refreshAudioData(); + }, + refreshAudioData: function () { + if (this.autoRefreshAudioData && !this.audioRefreshTimer) { + this.audioRefreshTimer = 1; + setTimeout(jQuery.proxy(this.refreshAudioDataLoop, this), 1000); + } + if (this.playing && !this.paused) { + this.trackBaseTime++; + } + if (this.paused) { + this.showPlayButton(); + } else if (this.playing) { + this.showPauseButton(); + } + if (this.activePlaylistItem) { + if (this.activePlaylistItem != this.lastPlaylistItem) { + this.lastPlaylistItem = this.activePlaylistItem; + var imgPath = xbmc.core.DEFAULT_ALBUM_COVER; + if (this.activePlaylistItem.thumbnail) { + imgPath = 'image/' + encodeURI(this.activePlaylistItem.thumbnail); + } + $('#audioCoverArt').html('<img src="' + imgPath + '" alt="' + this.activePlaylistItem.album + + ' cover art">'); + $('#audioTrackTitle').html('<span title="' + this.activePlaylistItem.title + '">' + this + .activePlaylistItem.title + '</span>'); + if (this.activePlaylistItem.album) { + $('#audioAlbumTitle').html('<span title="' + this.activePlaylistItem.album + '">' + this + .activePlaylistItem.album + '</span>') + .show(); + } else { + $('#audioAlbumTitle').hide(); + } + $('#audioArtistTitle').html(this.activePlaylistItem.artist); + $('#progressBar').attr('style', ''); + } + $('#audioDuration').html(xbmc.core.durationToString(this.trackBaseTime) + ' / ' + xbmc.core + .durationToString(this.trackDurationTime)); + var buttonWidth = $('#progressBar .progressIndicator').width(); + var progressBarWidth = (this.trackBaseTime / this.trackDurationTime) * 100; + var progressSliderPosition = Math.ceil(($('#progressBar').width() / 100) * progressBarWidth) - + buttonWidth; + if (progressSliderPosition < 0) { + progressSliderPosition = 0; + } + if (progressBarWidth <= 100) { + $('#progressBar .elapsedTime').width(progressBarWidth + '%'); + $('#progressBar .progressIndicator').css('left', progressSliderPosition); + } + } + }, + refreshVideoDataLoop: function () { + this.videoRefreshTimer = 0; + this.refreshVideoData(); + }, + refreshVideoData: function () { + if (this.autoRefreshVideoData && !this.videoRefreshTimer) { + this.videoRefreshTimer = 1; + setTimeout(jQuery.proxy(this.refreshVideoDataLoop, this), 1500); + } + if (this.playing && !this.paused) { + this.trackBaseTime++; + } + if (this.paused) { + this.showPlayButton(); + } else if (this.playing) { + this.showPauseButton(); + } + if (this.activePlaylistItem) { + if (this.activePlaylistItem != this.lastPlaylistItem) { + this.lastPlaylistItem = this.activePlaylistItem; + var imgPath = xbmc.core.DEFAULT_VIDEO_COVER; + if (this.activePlaylistItem.thumbnail) { + imgPath = 'image/' + encodeURI(this.activePlaylistItem.thumbnail); + } + $('#videoCoverArt').html('<img src="' + imgPath + '" alt="' + this.activePlaylistItem.title + + ' cover art">'); + $('#videoShowTitle').html(this.activePlaylistItem.showtitle || ' '); + var extra = ''; + if (this.activePlaylistItem.season >= 0 && this.activePlaylistItem.episode >= 0) { + extra = this.activePlaylistItem.season + 'x' + this.activePlaylistItem.episode + ' '; + } + $('#videoTitle').html(extra + this.activePlaylistItem.title); + } + $('#videoDuration').html(xbmc.core.durationToString(this.trackBaseTime) + ' / ' + xbmc.core + .durationToString(this.trackDurationTime)); + var buttonWidth = $('#progressBar .progressIndicator').width(); + var progressBarWidth = (this.trackBaseTime / this.trackDurationTime) * 100; + var progressSliderPosition = Math.ceil(($('#progressBar').width() / 100) * progressBarWidth) - + buttonWidth; + if (progressSliderPosition < 0) { + progressSliderPosition = 0; + } + if (progressBarWidth <= 100) { + $('#progressBar .elapsedTime').width(progressBarWidth + '%'); + $('#progressBar .progressIndicator').css('left', progressSliderPosition); + } + } + }, + stopRefreshTime: function () { + this.autoRefreshAudioData = false; + this.autoRefreshVideoData = false; + }, + comparePlaylistItems: function (item1, item2) { + if (!item1 || !item2) { + if (!item1 && !item2) { + return true; + } + return false; + } + if (item1.title != item2.title) { + return false; + } + if (item1.album != item2.album) { + return false; + } + if (item1.artist != item2.artist) { + return false; + } + if (item1.duration != item2.duration) { + return false; + } + if (item1.label != item2.label) { + return false; + } + if (item1.season != item2.season) { + return false; + } + if (item1.episode != item2.episode) { + return false; + } + return true; + }, + updateVideoPlaylist: function () { + xbmc.rpc.request({ + 'context': this, + 'method': 'Playlist.GetItems', + 'params': { + 'playlistid': this.playlistid, + 'properties': [ + 'title', + 'season', + 'episode', + 'plot', + 'runtime', + 'showtitle', + 'thumbnail' + ] + }, + 'success': function (data) { + if (data && data.result && data.result.items && data.result.items.length > 0 && data + .result.limits.total > 0) { + if (this.playlistChanged(data.result.items)) { + var ul = $('<ul>'); + var activeItem; + $.each($(data.result.items), jQuery.proxy(function (i, item) { + var li = $('<li>'); + var extra = ''; + if (item.season >= 0 && item.episode >= 0) { + extra = item.season + 'x' + item.episode + ' '; + } + var code = '<span class="duration">' + xbmc.core + .durationToString(item.runtime) + + '</span><div class="trackInfo" title="' + extra + item + .title + '"><span class="trackTitle">' + extra + item + .title + '</span></div>'; + if (i == this.currentItem) { + activeItem = item; + activeItem.seq = i; + li.addClass('activeItem'); + } + if (i == (this.currentItem + 1)) { + $('#nextTrack').html(code).show(); + } + li.bind('click', jQuery.proxy(this.playPlaylistItem, this)); + ul.append(li.attr('seq', i).html(code)); + }, this)); + if (data.result.limits.total > 1) { + $('#nextText').show(); + if (activeItem && data.result.limits.total == activeItem.seq) { + $('#nextTrack').html( + '<div class="trackInfo">Last track in playlist</div>') + .show(); + } + $('#nowPlayingPlaylist').html('').append(ul); + } else { + $('#nextText').hide(); + $('#nowPlayingPlaylist').hide(); + $('#nextTrack').hide(); + } + if (!this.comparePlaylistItems(activeItem, this.activePlaylistItem)) { + this.activePlaylistItem = activeItem; + if (!this.updateActiveItemDurationRunOnce) { + this.updateActiveItemDurationRunOnce = true; + this.updatePlayer(); + } + } else if (!activeItem) { + this.stopRefreshTime(); + } + this.activePlaylist = data.result.items; + $('#videoDescription').show(); + $('#audioDescription').hide(); + $('#nowPlayingPanel').show(); + } + } else { + xbmc.rpc.request({ + 'context': this, + 'method': 'Player.GetItem', + 'params': { + 'playerid': this.activePlayerId, + 'properties': [ + 'title', + 'season', + 'episode', + 'plot', + 'runtime', + 'showtitle', + 'thumbnail' + ] + }, + 'success': function (data) { + if (data && data.result && data.result.item) { + this.activePlaylistItem = data.result.item; + if (!this.updateActiveItemDurationRunOnce) { + this.updateActiveItemDurationRunOnce = true; + this.updatePlayer(); + } + + $('#nextText').hide(); + $('#nowPlayingPlaylist').hide(); + $('#nextTrack').hide(); + + $('#videoDescription').show(); + $('#audioDescription').hide(); + $('#nowPlayingPanel').show(); + } else { + this.activePlaylist = null; + $('#videoDescription').hide(); + $('#nowPlayingPanel').hide(); + } + }, + 'error': function (data) { + xbmc.core.displayCommunicationError(); + if (this.autoRefreshVideoPlaylist) { + setTimeout(jQuery.proxy(this.updateVideoPlaylist, this), + 2000); /* Slow down request period */ + } + } + }); + } + if (this.autoRefreshVideoPlaylist) { + setTimeout(jQuery.proxy(this.updateVideoPlaylist, this), 1000); + } + }, + 'error': function (data) { + xbmc.core.displayCommunicationError(); + if (this.autoRefreshVideoPlaylist) { + setTimeout(jQuery.proxy(this.updateVideoPlaylist, this), + 2000); /* Slow down request period */ + } + } + }); + } +}
\ No newline at end of file diff --git a/debian/webinterface-default/js/json2.js b/debian/webinterface-default/js/json2.js new file mode 100644 index 0000000..edb7751 --- /dev/null +++ b/debian/webinterface-default/js/json2.js @@ -0,0 +1,492 @@ +/* + json2.js + 2012-10-08 + + Public Domain. + + NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. + + See http://www.JSON.org/js.html + + + This code should be minified before deployment. + See http://javascript.crockford.com/jsmin.html + + USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO + NOT CONTROL. + + + This file creates a global JSON object containing two methods: stringify + and parse. + + JSON.stringify(value, replacer, space) + value any JavaScript value, usually an object or array. + + replacer an optional parameter that determines how object + values are stringified for objects. It can be a + function or an array of strings. + + space an optional parameter that specifies the indentation + of nested structures. If it is omitted, the text will + be packed without extra whitespace. If it is a number, + it will specify the number of spaces to indent at each + level. If it is a string (such as '\t' or ' '), + it contains the characters used to indent at each level. + + This method produces a JSON text from a JavaScript value. + + When an object value is found, if the object contains a toJSON + method, its toJSON method will be called and the result will be + stringified. A toJSON method does not serialize: it returns the + value represented by the name/value pair that should be serialized, + or undefined if nothing should be serialized. The toJSON method + will be passed the key associated with the value, and this will be + bound to the value + + For example, this would serialize Dates as ISO strings. + + Date.prototype.toJSON = function (key) { + function f(n) { + // Format integers to have at least two digits. + return n < 10 ? '0' + n : n; + } + + return this.getUTCFullYear() + '-' + + f(this.getUTCMonth() + 1) + '-' + + f(this.getUTCDate()) + 'T' + + f(this.getUTCHours()) + ':' + + f(this.getUTCMinutes()) + ':' + + f(this.getUTCSeconds()) + 'Z'; + }; + + You can provide an optional replacer method. It will be passed the + key and value of each member, with this bound to the containing + object. The value that is returned from your method will be + serialized. If your method returns undefined, then the member will + be excluded from the serialization. + + If the replacer parameter is an array of strings, then it will be + used to select the members to be serialized. It filters the results + such that only members with keys listed in the replacer array are + stringified. + + Values that do not have JSON representations, such as undefined or + functions, will not be serialized. Such values in objects will be + dropped; in arrays they will be replaced with null. You can use + a replacer function to replace those with JSON values. + JSON.stringify(undefined) returns undefined. + + The optional space parameter produces a stringification of the + value that is filled with line breaks and indentation to make it + easier to read. + + If the space parameter is a non-empty string, then that string will + be used for indentation. If the space parameter is a number, then + the indentation will be that many spaces. + + Example: + + text = JSON.stringify(['e', {pluribus: 'unum'}]); + // text is '["e",{"pluribus":"unum"}]' + + + text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t'); + // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]' + + text = JSON.stringify([new Date()], function (key, value) { + return this[key] instanceof Date ? + 'Date(' + this[key] + ')' : value; + }); + // text is '["Date(---current time---)"]' + + + JSON.parse(text, reviver) + This method parses a JSON text to produce an object or array. + It can throw a SyntaxError exception. + + The optional reviver parameter is a function that can filter and + transform the results. It receives each of the keys and values, + and its return value is used instead of the original value. + If it returns what it received, then the structure is not modified. + If it returns undefined then the member is deleted. + + Example: + + // Parse the text. Values that look like ISO date strings will + // be converted to Date objects. + + myData = JSON.parse(text, function (key, value) { + var a; + if (typeof value === 'string') { + a = +/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value); + if (a) { + return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4], + +a[5], +a[6])); + } + } + return value; + }); + + myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) { + var d; + if (typeof value === 'string' && + value.slice(0, 5) === 'Date(' && + value.slice(-1) === ')') { + d = new Date(value.slice(5, -1)); + if (d) { + return d; + } + } + return value; + }); + + + This is a reference implementation. You are free to copy, modify, or + redistribute. +*/ + +/*jslint evil: true, regexp: true */ + +/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply, + call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours, + getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join, + lastIndex, length, parse, prototype, push, replace, slice, stringify, + test, toJSON, toString, valueOf +*/ + + +// Create a JSON object only if one does not already exist. We create the +// methods in a closure to avoid creating global variables. + +if (typeof JSON !== 'object') { + JSON = {}; +} + +(function () { + 'use strict'; + + function f(n) { + // Format integers to have at least two digits. + return n < 10 ? '0' + n : n; + } + + if (typeof Date.prototype.toJSON !== 'function') { + + Date.prototype.toJSON = function (key) { + + return isFinite(this.valueOf()) ? + this.getUTCFullYear() + '-' + + f(this.getUTCMonth() + 1) + '-' + + f(this.getUTCDate()) + 'T' + + f(this.getUTCHours()) + ':' + + f(this.getUTCMinutes()) + ':' + + f(this.getUTCSeconds()) + 'Z' : + null; + }; + + String.prototype.toJSON = + Number.prototype.toJSON = + Boolean.prototype.toJSON = function (key) { + return this.valueOf(); + }; + } + + var cx = + /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, + escapable = + /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, + gap, + indent, + meta = { // table of character substitutions + '\b': '\\b', + '\t': '\\t', + '\n': '\\n', + '\f': '\\f', + '\r': '\\r', + '"': '\\"', + '\\': '\\\\' + }, + rep; + + + function quote(string) { + + // If the string contains no control characters, no quote characters, and no + // backslash characters, then we can safely slap some quotes around it. + // Otherwise we must also replace the offending characters with safe escape + // sequences. + + escapable.lastIndex = 0; + return escapable.test(string) ? '"' + string.replace(escapable, function (a) { + var c = meta[a]; + return typeof c === 'string' ? + c : + '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); + }) + '"' : '"' + string + '"'; + } + + + function str(key, holder) { + + // Produce a string from holder[key]. + + var i, // The loop counter. + k, // The member key. + v, // The member value. + length, + mind = gap, + partial, + value = holder[key]; + + // If the value has a toJSON method, call it to obtain a replacement value. + + if (value && typeof value === 'object' && + typeof value.toJSON === 'function') { + value = value.toJSON(key); + } + + // If we were called with a replacer function, then call the replacer to + // obtain a replacement value. + + if (typeof rep === 'function') { + value = rep.call(holder, key, value); + } + + // What happens next depends on the value's type. + + switch (typeof value) { + case 'string': + return quote(value); + + case 'number': + + // JSON numbers must be finite. Encode non-finite numbers as null. + + return isFinite(value) ? String(value) : 'null'; + + case 'boolean': + case 'null': + + // If the value is a boolean or null, convert it to a string. Note: + // typeof null does not produce 'null'. The case is included here in + // the remote chance that this gets fixed someday. + + return String(value); + + // If the type is 'object', we might be dealing with an object or an array or + // null. + + case 'object': + + // Due to a specification blunder in ECMAScript, typeof null is 'object', + // so watch out for that case. + + if (!value) { + return 'null'; + } + + // Make an array to hold the partial results of stringifying this object value. + + gap += indent; + partial = []; + + // Is the value an array? + + if (Object.prototype.toString.apply(value) === '[object Array]') { + + // The value is an array. Stringify every element. Use null as a placeholder + // for non-JSON values. + + length = value.length; + for (i = 0; i < length; i += 1) { + partial[i] = str(i, value) || 'null'; + } + + // Join all of the elements together, separated with commas, and wrap them in + // brackets. + + v = partial.length === 0 ? + '[]' : + gap ? + '[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']' : + '[' + partial.join(',') + ']'; + gap = mind; + return v; + } + + // If the replacer is an array, use it to select the members to be stringified. + + if (rep && typeof rep === 'object') { + length = rep.length; + for (i = 0; i < length; i += 1) { + if (typeof rep[i] === 'string') { + k = rep[i]; + v = str(k, value); + if (v) { + partial.push(quote(k) + (gap ? ': ' : ':') + v); + } + } + } + } else { + + // Otherwise, iterate through all of the keys in the object. + + for (k in value) { + if (Object.prototype.hasOwnProperty.call(value, k)) { + v = str(k, value); + if (v) { + partial.push(quote(k) + (gap ? ': ' : ':') + v); + } + } + } + } + + // Join all of the member texts together, separated with commas, + // and wrap them in braces. + + v = partial.length === 0 ? + '{}' : + gap ? + '{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}' : + '{' + partial.join(',') + '}'; + gap = mind; + return v; + } + } + + // If the JSON object does not yet have a stringify method, give it one. + + if (typeof JSON.stringify !== 'function') { + JSON.stringify = function (value, replacer, space) { + + // The stringify method takes a value and an optional replacer, and an optional + // space parameter, and returns a JSON text. The replacer can be a function + // that can replace values, or an array of strings that will select the keys. + // A default replacer method can be provided. Use of the space parameter can + // produce text that is more easily readable. + + var i; + gap = ''; + indent = ''; + + // If the space parameter is a number, make an indent string containing that + // many spaces. + + if (typeof space === 'number') { + for (i = 0; i < space; i += 1) { + indent += ' '; + } + + // If the space parameter is a string, it will be used as the indent string. + + } else if (typeof space === 'string') { + indent = space; + } + + // If there is a replacer, it must be a function or an array. + // Otherwise, throw an error. + + rep = replacer; + if (replacer && typeof replacer !== 'function' && + (typeof replacer !== 'object' || + typeof replacer.length !== 'number')) { + throw new Error('JSON.stringify'); + } + + // Make a fake root object containing our value under the key of ''. + // Return the result of stringifying the value. + + return str('', { + '': value + }); + }; + } + + + // If the JSON object does not yet have a parse method, give it one. + + if (typeof JSON.parse !== 'function') { + JSON.parse = function (text, reviver) { + + // The parse method takes a text and an optional reviver function, and returns + // a JavaScript value if the text is a valid JSON text. + + var j; + + function walk(holder, key) { + + // The walk method is used to recursively walk the resulting structure so + // that modifications can be made. + + var k, v, value = holder[key]; + if (value && typeof value === 'object') { + for (k in value) { + if (Object.prototype.hasOwnProperty.call(value, k)) { + v = walk(value, k); + if (v !== undefined) { + value[k] = v; + } else { + delete value[k]; + } + } + } + } + return reviver.call(holder, key, value); + } + + + // Parsing happens in four stages. In the first stage, we replace certain + // Unicode characters with escape sequences. JavaScript handles many characters + // incorrectly, either silently deleting them, or treating them as line endings. + + text = String(text); + cx.lastIndex = 0; + if (cx.test(text)) { + text = text.replace(cx, function (a) { + return '\\u' + + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); + }); + } + + // In the second stage, we run the text against regular expressions that look + // for non-JSON patterns. We are especially concerned with '()' and 'new' + // because they can cause invocation, and '=' because it can cause mutation. + // But just to be safe, we want to reject all unexpected forms. + + // We split the second stage into 4 regexp operations in order to work around + // crippling inefficiencies in IE's and Safari's regexp engines. First we + // replace the JSON backslash pairs with '@' (a non-JSON character). Second, we + // replace all simple value tokens with ']' characters. Third, we delete all + // open brackets that follow a colon or comma or that begin the text. Finally, + // we look to see that the remaining characters are only whitespace or ']' or + // ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval. + + if (/^[\],:{}\s]*$/ + .test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@') + .replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']') + .replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) { + + // In the third stage we use the eval function to compile the text into a + // JavaScript structure. The '{' operator is subject to a syntactic ambiguity + // in JavaScript: it can begin a block or an object literal. We wrap the text + // in parens to eliminate the ambiguity. + + j = eval('(' + text + ')'); + + // In the optional fourth stage, we recursively walk the new structure, passing + // each name/value pair to a reviver function for possible transformation. + + return typeof reviver === 'function' ? + walk({ + '': j + }, '') : + j; + } + + // If the text is not JSON parseable, then a SyntaxError is thrown. + + throw new SyntaxError('JSON.parse'); + }; + } +}());
\ No newline at end of file diff --git a/debian/webinterface-default/js/xbmc.core.js b/debian/webinterface-default/js/xbmc.core.js new file mode 100644 index 0000000..2be141c --- /dev/null +++ b/debian/webinterface-default/js/xbmc.core.js @@ -0,0 +1,90 @@ +/* + * 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/>. + * + */ + +(function (window) { + "use strict"; + + var xbmc = window.xbmc || {}; + xbmc.core = { + 'DEFAULT_ALBUM_COVER': 'images/DefaultAlbumCover.png', + 'DEFAULT_VIDEO_COVER': 'images/DefaultVideo.png', + 'JSON_RPC': 'jsonrpc', + 'applyDeviceFixes': function () { + window.document.addEventListener('touchmove', function (e) { + e.preventDefault(); + }); + }, + 'displayCommunicationError': function (m) { + window.clearTimeout(xbmc.core.commsErrorTimeout); + var message = m || 'Connection to server lost'; + $('#commsErrorPanel').html(message).show(); + xbmc.core.commsErrorTimeout = window.setTimeout('xbmc.core.hideCommunicationError()', 5000); + }, + 'durationToString': function (duration) { + var total_seconds = duration || 0, + seconds = total_seconds % 60, + minutes = Math.floor(total_seconds / 60) % 60, + hours = Math.floor(total_seconds / 3600), + result = ((hours > 0 && ((hours < 10 ? '0' : '') + hours + ':')) || ''); + result += (minutes < 10 ? '0' : '') + minutes + ':'; + result += (seconds < 10 ? '0' : '') + seconds; + return result; + }, + 'getCookie': function (name) { + var i, + match, + haystack = window.document.cookie.split(';'); + for (i = 0; i < haystack.length; i += 1) { + match = haystack[i].match(/^\s*[\S\s]*=([\s\S]*)\s*$/); + if (match && match.length === 2) { + return match[1]; + } + } + return null; + }, + 'hideCommunicationError': function () { + $('#commsErrorPanel').hide(); + }, + 'setCookie': function (name, value, days) { + var date, + expires; + if (name) { + if (days) { + date = new Date(); + date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000)); + expires = "; expires=" + date.toGMTString(); + } else { + expires = ''; + } + window.document.cookie = name + "=" + value + expires + "; path=/"; + } + }, + 'timeToDuration': function (time) { + var duration; + time = time || {}; + duration = ((time.hours || 0) * 3600); + duration += ((time.minutes || 0) * 60); + duration += (time.seconds || 0); + return duration; + } + }; + + window.xbmc = xbmc; +}(window));
\ No newline at end of file diff --git a/debian/webinterface-default/js/xbmc.init.js b/debian/webinterface-default/js/xbmc.init.js new file mode 100644 index 0000000..c61a81f --- /dev/null +++ b/debian/webinterface-default/js/xbmc.init.js @@ -0,0 +1,27 @@ +/* + * 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/>. + * + */ + +(function () { + "use strict" + + var mediaLibrary = new MediaLibrary(), + nowPlayingManager = new NowPlayingManager(); + xbmc.core.applyDeviceFixes(); +}());
\ No newline at end of file diff --git a/debian/webinterface-default/js/xbmc.launcher.js b/debian/webinterface-default/js/xbmc.launcher.js new file mode 100644 index 0000000..4f039d6 --- /dev/null +++ b/debian/webinterface-default/js/xbmc.launcher.js @@ -0,0 +1,46 @@ +/* + * 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/>. + * + */ + +(function (document) { + "use strict"; + + var i, + script, + debug = false, + /* Set to true to disable cached javascript */ + version = (debug ? Math.random() : '2.1.0'), + scripts = [ + "js/jquery-1.8.2.min.js", + "js/json2.js", + "js/iscroll-min.js", + "js/xbmc.core.js", + "js/xbmc.rpc.js", + "js/MediaLibrary.js", + "js/NowPlayingManager.js", + "js/xbmc.init.js" + ]; + + for (i = 0; i < scripts.length; i += 1) { + script = '<script type="text/javascript" src="'; + script += scripts[i] + '?' + version; + script += '"><\/script>'; + document.write(script); + } +}(window.document));
\ No newline at end of file diff --git a/debian/webinterface-default/js/xbmc.rpc.js b/debian/webinterface-default/js/xbmc.rpc.js new file mode 100644 index 0000000..60b1d8b --- /dev/null +++ b/debian/webinterface-default/js/xbmc.rpc.js @@ -0,0 +1,49 @@ +/* + * 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/>. + * + */ + +(function (window) { + + var xbmc = window.xbmc || {}; + + xbmc.rpc = { + 'default_options': { + 'contentType': 'application/json', + 'dataType': 'json', + 'type': 'POST', + 'success': function () { + $('#spinner').hide(); + } + }, + 'request': function (options) { + var request_options = jQuery.extend({}, this.default_options, options); + request_options.url = xbmc.core.JSON_RPC + '?' + options.method; + request_options.data = JSON.stringify({ + 'jsonrpc': '2.0', + 'method': options.method, + 'id': 1, + 'params': request_options.params + }); + return jQuery.ajax(request_options) + } + }; + + window.xbmc = xbmc; + +}(window));
\ No newline at end of file |