## Description
Adds a "Prefer Dolby Vision over HDR10+" switch (off by default) under
Experimental settings. That screen only shows up once "Experimental
settings" is enabled under Advanced, and until then the switch is read
as off: it goes through `experimentalPreferences.get {}`, so nothing is
wrapped and the playback path is untouched.
Most current 4K web releases carry both Dolby Vision (profile 8.1) RPUs
and HDR10+ dynamic metadata in the same HEVC stream. Some MediaTek based
devices (Philips and TCL TVs, some Fire TV models) latch onto the HDR10+
metadata on those files and never engage Dolby Vision, even though a
Dolby Vision decoder is selected.
I isolated this on my Philips 55OLED810 by playing the same episode
three ways, direct play in all three cases:
| | Stream | TV shows |
|---|---|---|
| A | MKV with DV 8.1 + HDR10+ | HDR10+ |
| B | Same MKV with the HDR10+ metadata removed using
[hdr10plus_tool](https://github.com/quietvoid/hdr10plus_tool), DV
untouched | Dolby Vision |
| C | Same stream remuxed to MP4, both kinds of metadata present |
HDR10+ |
The container doesn't matter and the Dolby Vision signaling is picked up
correctly. The only thing the app can do is keep the HDR10+ metadata
away from the decoder.
When the switch is on, and only when a Dolby Vision decoder was actually
selected, the HDR10+ SEI messages (SMPTE ST 2094-40, recognized by their
ITU-T T.35 header `B5 003C 0001`) are masked in each access unit before
it is queued to MediaCodec. The SEI payload type byte is overwritten
with an unused value (254), so the decoder skips the message. That is
one byte rewritten in place per message: the masking filter returns the
size it was given, so the access unit is queued exactly as long as it
came out of the extractor, which is what makes it safe with both the
synchronous and asynchronous MediaCodec adapters. media3 does the same
thing for HAGC metadata in `HevcSeiUtil`; this filter only targets ST
2094-40, so other T.35 SEI such as CEA-708 captions are not affected.
The filter was written from the H.265 spec, no Kodi or media3 code was
copied.
The hook is generic rather than HDR10+ specific, as asked in the thread.
`BitstreamFilteringCodecAdapterFactory` wraps the codec adapter with a
`List<BitstreamFilter>`, and a filter is `(ByteBuffer, offset, size) ->
Int` where the returned `Int` is the new size of the access unit: the
adapter queues the size the chain reports, and hands each filter the
size the previous one reported. A filter which only overwrites bytes
returns the size unchanged, which is what the HDR10+ masking does; a
filter which drops NAL units compacts what it keeps and reports the
shorter size. A reported size which is negative or larger than the one
the filter was given is ignored rather than queued. That is what lets
the Dolby Vision profile 7 to 8.1 conversion of #244 arrive later as one
more filter instead of a second copy of the adapter plumbing.
When the switch is off, the playback path is unchanged. On a device
without a Dolby Vision decoder (or a display without DV support) the
wrapper is never installed, so HDR10+ only devices keep their metadata.
Encrypted samples, codec config buffers and empty buffers are passed
through untouched.
Kodi has an equivalent option for the same reason: xbmc/xbmc@032cbfeb
and xbmc/xbmc@e2c54e7f.
### Related issues
Implements what was requested in #1855. The filter list is what #244
(Dolby Vision profile 7 direct play) needs, so that conversion can be
added as another filter. #1895 implemented the same masking
independently and was closed in favour of this PR; the device profile
part of it was not carried over, see the note under Testing. Upstream:
androidx/media#1895, where the maintainers say the bug is in the device
codecs and that they don't plan a workaround in ExoPlayer itself.
## AI or LLM usage
The implementation (bitstream filter, MediaCodecAdapter wiring, unit
tests) were written with AI assistance (Claude). I reviewed the changes
and validated the behavior myself on a real MediaTek TV (Philips
55OLED810), with the setting on and off, on hybrid and DV-only content.
---------
Co-authored-by: Jycreyn <github.2ilp7@passmail.com>
|
||
|---|---|---|
| .github | ||
| app | ||
| gradle | ||
| wholphin-mpv-stub | ||
| .editorconfig | ||
| .gitignore | ||
| .pre-commit-config.yaml | ||
| build.gradle.kts | ||
| CONTRIBUTING.md | ||
| DEVELOPMENT.md | ||
| gradle.properties | ||
| gradlew | ||
| gradlew.bat | ||
| Intents.md | ||
| LICENSE | ||
| lint.xml | ||
| README.md | ||
| renovate.json | ||
| settings.gradle.kts | ||
Wholphin - an OSS Android TV client for Jellyfin
"Never half-phin two jellies. Always wholphin one jelly."
Wholphin is an open-source Android TV client for Jellyfin. It aims to provide a different app UI that's inspired by Plex for users interested in migrating to Jellyfin.
This is not a fork of the official client. Wholphin's user interface and controls have been written completely from scratch. Wholphin supports playing media using either ExoPlayer or MPV.
Features
User interface
- Customize the home page to see the content you are interested in
- Use poster or thumb images, show/hide titles, add/remove/re-order different types of rows!
- Option to combine the Continue Watching & Next Up into a single row
- Pin collections, playlists, favorites, genres, and studios
- Remove series from next up
- A navigation drawer for quick access to libraries, favorites, search, and settings from almost anywhere in the app
- Integration with Seerr to discover new movies and TV shows
- Note: only available when installed from GitHub or the Play store
- Customize library display
- Option to show Movie/TV Show titles
- Choose image types & size
- Choose from grid or list layouts
- Play theme music, if available
- Customize subtitle style for plain text subtitles with separate HDR settings
- Search & download subtitles (requires compatible server plugin such as OpenSubtitles)
- Multiple app color themes
- Protect user profile switches with PIN code or require server login
- Change the user interface language per user
- In-app & Android OS screensaver support
Playback
- Different media playback engines:
- ExoPlayer w/ optional extra audio, SSA/ASS, & AV1 software decoding
- MPV for direct playing anything with great SSA/ASS subtitle support
- Plex inspired playback controls:
- Using D-Pad left/right for seeking during playback
- Quickly access video chapters & queue during playback
- Optionally skip back a few seconds when resuming playback
- Live TV & DVR support
- Music & music video support
- Cinema mode/pre-roll intro support (requires compatible server plugin such as Intros)
- Auto play next episodes with pass out protection
- Option for automatic refresh rate & resolution switching on supported displays
- Trickplay (video preview) support
- Subtly show playback position along the bottom of the screen while seeking w/ D-Pad
Roadmap
Installation
Using Google Play or Amazon appstore are the fastest way to install. But you can follow these instructions to install without needing an app store
Downloader Code: 8668671
- Enable side-loading "unknown" apps
- https://androidtvnews.com/unknown-sources-chromecast-google-tv/
- https://www.xda-developers.com/how-to-sideload-apps-android-tv/
- https://developer.android.com/distribute/marketing-tools/alternative-distribution#unknown-sources
- https://www.aftvnews.com/how-to-enable-apps-from-unknown-sources-on-an-amazon-fire-tv-or-fire-tv-stick/
- Install the APK on your Android TV device with one of these options:
- Install a browser program such as Downloader, use it to get the latest apk with short code
8668671or URL: http://aftv.news/8668671 - Download the latest APK release from the releases page or http://aftv.news/8668671
- Put the APK on an SD Card/USB stick/network share and use a file manager app from the Google Play Store / Amazon AppStore (e.g.
FX File Explorer). Android's preinstalled file manager probably will not work! - Use
Send files to TVfrom the Google Play Store on your phone & TV - (Expert) Use ADB to install the APK from your computer (guide)
- Put the APK on an SD Card/USB stick/network share and use a file manager app from the Google Play Store / Amazon AppStore (e.g.
- Install a browser program such as Downloader, use it to get the latest apk with short code
Upgrading the app
After the initial install above, the app will automatically check for updates. The updates can be installed in settings.
The first time you attempt an update, the OS should guide you through enabling the required additional permissions for the app to install updates.
Note: if installed via an app store, the app store will handle updates.
Compatibility
Requires Android 6+ (or Fire TV OS 6+) and Jellyfin server 10.10.x or 10.11.x (tested on primarily 10.11).
The app is tested on a variety of Android TV/Fire TV OS devices, but if you encounter issues, please file an issue!
Seerr integration is generally tested with the latest stable version. Older versions may not work as expected. The Seerr server should configured with integration to your Jellyfin server for full compatibility.
Contributions
Issues and pull requests are always welcome! Please check before submitting that your issue or pull request is not a duplicate.
If you plan to contribute, please read the contributing guide!
You can help translate Wholphin!
Acknowledgements
- Thanks to the Jellyfin team for creating and maintaining such a great open-source media server
- Thanks to the official Jellyfin Android TV client developers, some code for creating the device direct play profile is adapted from there
- Thanks to the Jellyfin Kotlin SDK developers for making it easier to interact with the Jellyfin server API
- Thanks to numerous other libraries that make app development even possible