aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorquietvoid <39477805+quietvoid@users.noreply.github.com>2023-07-16 09:55:06 -0400
committerquietvoid <39477805+quietvoid@users.noreply.github.com>2023-09-02 08:29:42 -0400
commitcfcb8a2798fa3d84c765f0683121974d0113f584 (patch)
tree71b480bbce23d1d8501a992e3c1381881e03385c
parent1c52605c272aa57b5d47107a9023ac58ee7e7aee (diff)
downloadxbmc-cfcb8a2798fa3d84c765f0683121974d0113f584.tar.xz
[Android] Add Dolby Vision compatibility mode setting
For Dolby Vision profile 7 video files, the metadata is converted automatically to improve compatibility on certain Android devices
-rw-r--r--addons/resource.language.en_gb/resources/strings.po12
-rwxr-xr-xsystem/settings/settings.xml11
-rw-r--r--xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecAndroidMediaCodec.cpp15
-rw-r--r--xbmc/settings/SettingConditions.cpp9
-rw-r--r--xbmc/settings/Settings.h1
-rw-r--r--xbmc/utils/BitstreamConverter.cpp76
-rw-r--r--xbmc/utils/BitstreamConverter.h2
7 files changed, 125 insertions, 1 deletions
diff --git a/addons/resource.language.en_gb/resources/strings.po b/addons/resource.language.en_gb/resources/strings.po
index 8c2dcfa3a1..80e144370b 100644
--- a/addons/resource.language.en_gb/resources/strings.po
+++ b/addons/resource.language.en_gb/resources/strings.po
@@ -23481,3 +23481,15 @@ msgstr ""
msgctxt "#39195"
msgid "Enable this option for the best picture quality. Disabling reduces the load on resource-limited systems."
msgstr ""
+
+#. Title of Dolby Vision RPU conversion setting
+#: system/settings/settings.xml
+msgctxt "#39196"
+msgid "Dolby Vision compatibility mode"
+msgstr ""
+
+#. Help text for setting "Convert Dolby Vision for compatibility" of label #39196
+#: system/settings/settings.xml
+msgctxt "#39197"
+msgid "If enabled, Dolby Vision profile 7 will be converted to profile 8.1, which is more commonly supported by devices. Enable if your device supports Dolby Vision, but has issues with some videos."
+msgstr ""
diff --git a/system/settings/settings.xml b/system/settings/settings.xml
index 60539c9b0d..d9218c470d 100755
--- a/system/settings/settings.xml
+++ b/system/settings/settings.xml
@@ -179,6 +179,17 @@
<default>true</default>
<control type="toggle" />
</setting>
+ <setting id="videoplayer.convertdovi" type="boolean" label="39196" help="39197">
+ <requirement>HAS_MEDIACODEC</requirement>
+ <dependencies>
+ <dependency type="visible">
+ <condition on="property" name="supportsdolbyvision" />
+ </dependency>
+ </dependencies>
+ <level>2</level>
+ <default>false</default>
+ <control type="toggle" />
+ </setting>
</group>
<group id="4" label="14232">
<setting id="videoplayer.stereoscopicplaybackmode" type="integer" label="36520" help="36537">
diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecAndroidMediaCodec.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecAndroidMediaCodec.cpp
index 31bf35bfe5..68203861fc 100644
--- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecAndroidMediaCodec.cpp
+++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecAndroidMediaCodec.cpp
@@ -560,7 +560,22 @@ bool CDVDVideoCodecAndroidMediaCodec::Open(CDVDStreamInfo &hints, CDVDCodecOptio
{
m_bitstream.reset();
}
+
+ // Only set for profile 7, container hint allows to skip parsing unnecessarily
+ if (m_bitstream && m_hints.dovi.dv_profile == 7)
+ {
+ bool convertDovi = CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(
+ CSettings::SETTING_VIDEOPLAYER_CONVERTDOVI);
+
+ CLog::Log(LOGDEBUG,
+ "CDVDVideoCodecAndroidMediaCodec::Open Dolby Vision compatibility mode "
+ "enabled: {}",
+ convertDovi);
+
+ m_bitstream->SetConvertDovi(convertDovi);
+ }
}
+
break;
}
case AV_CODEC_ID_WMV3:
diff --git a/xbmc/settings/SettingConditions.cpp b/xbmc/settings/SettingConditions.cpp
index d9710c0e0c..45997a36a4 100644
--- a/xbmc/settings/SettingConditions.cpp
+++ b/xbmc/settings/SettingConditions.cpp
@@ -118,6 +118,14 @@ bool SupportsVideoSuperResolution(const std::string& condition,
return CServiceBroker::GetWinSystem()->SupportsVideoSuperResolution();
}
+bool SupportsDolbyVision(const std::string& condition,
+ const std::string& value,
+ const SettingConstPtr& setting,
+ void* data)
+{
+ return CServiceBroker::GetWinSystem()->GetDisplayHDRCapabilities().SupportsDolbyVision();
+}
+
bool SupportsScreenMove(const std::string& condition,
const std::string& value,
const SettingConstPtr& setting,
@@ -470,6 +478,7 @@ void CSettingConditions::Initialize()
m_complexConditions.emplace("hassystemsdrpeakluminance", HasSystemSdrPeakLuminance);
m_complexConditions.emplace("supportsscreenmove", SupportsScreenMove);
m_complexConditions.emplace("supportsvideosuperresolution", SupportsVideoSuperResolution);
+ m_complexConditions.emplace("supportsdolbyvision", SupportsDolbyVision);
m_complexConditions.emplace("ishdrdisplay", IsHDRDisplay);
m_complexConditions.emplace("ismasteruser", IsMasterUser);
m_complexConditions.emplace("hassubtitlesfontextensions", HasSubtitlesFontExtensions);
diff --git a/xbmc/settings/Settings.h b/xbmc/settings/Settings.h
index 23206f3439..349a153065 100644
--- a/xbmc/settings/Settings.h
+++ b/xbmc/settings/Settings.h
@@ -129,6 +129,7 @@ public:
static constexpr auto SETTING_VIDEOPLAYER_USESTAGEFRIGHT = "videoplayer.usestagefright";
static constexpr auto SETTING_VIDEOPLAYER_LIMITGUIUPDATE = "videoplayer.limitguiupdate";
static constexpr auto SETTING_VIDEOPLAYER_SUPPORTMVC = "videoplayer.supportmvc";
+ static constexpr auto SETTING_VIDEOPLAYER_CONVERTDOVI = "videoplayer.convertdovi";
static constexpr auto SETTING_MYVIDEOS_SELECTACTION = "myvideos.selectaction";
static constexpr auto SETTING_MYVIDEOS_USETAGS = "myvideos.usetags";
static constexpr auto SETTING_MYVIDEOS_EXTRACTFLAGS = "myvideos.extractflags";
diff --git a/xbmc/utils/BitstreamConverter.cpp b/xbmc/utils/BitstreamConverter.cpp
index 1bca7d14d8..5fb96d4ed5 100644
--- a/xbmc/utils/BitstreamConverter.cpp
+++ b/xbmc/utils/BitstreamConverter.cpp
@@ -20,6 +20,13 @@
#include <algorithm>
+extern "C"
+{
+#ifdef HAVE_LIBDOVI
+#include <libdovi/rpu_parser.h>
+#endif
+}
+
enum {
AVC_NAL_SLICE=1,
AVC_NAL_DPA,
@@ -257,6 +264,32 @@ static bool has_sei_recovery_point(const uint8_t *p, const uint8_t *end)
return false;
}
+#ifdef HAVE_LIBDOVI
+// The returned data must be freed with `dovi_data_free`
+// May be NULL if no conversion was done
+static const DoviData* convert_dovi_rpu_nal(uint8_t* buf, uint32_t nal_size)
+{
+ DoviRpuOpaque* rpu = dovi_parse_unspec62_nalu(buf, nal_size);
+ const DoviRpuDataHeader* header = dovi_rpu_get_header(rpu);
+ const DoviData* rpu_data = NULL;
+
+ if (header && header->guessed_profile == 7)
+ {
+ int ret = dovi_convert_rpu_with_mode(rpu, 2);
+ if (ret < 0)
+ goto done;
+
+ rpu_data = dovi_write_unspec62_nalu(rpu);
+ }
+
+done:
+ dovi_rpu_free_header(header);
+ dovi_rpu_free(rpu);
+
+ return rpu_data;
+}
+#endif
+
////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////
CBitstreamParser::CBitstreamParser() = default;
@@ -322,6 +355,7 @@ CBitstreamConverter::CBitstreamConverter()
m_convert_bytestream = false;
m_sps_pps_context.sps_pps_data = NULL;
m_start_decode = true;
+ m_convert_dovi = false;
}
CBitstreamConverter::~CBitstreamConverter()
@@ -875,6 +909,10 @@ bool CBitstreamConverter::BitstreamConvert(uint8_t* pData, int iSize, uint8_t **
uint32_t cumul_size = 0;
const uint8_t *buf_end = buf + buf_size;
+#ifdef HAVE_LIBDOVI
+ const DoviData* rpu_data = NULL;
+#endif
+
switch (m_codec)
{
case AV_CODEC_ID_H264:
@@ -928,12 +966,48 @@ bool CBitstreamConverter::BitstreamConvert(uint8_t* pData, int iSize, uint8_t **
}
else
{
- BitstreamAllocAndCopy(poutbuf, poutbuf_size, NULL, 0, buf, nal_size, unit_type);
+ bool write_buf = true;
+ const uint8_t* buf_to_write = buf;
+ int32_t final_nal_size = nal_size;
+
if (!m_sps_pps_context.first_idr && IsSlice(unit_type))
{
m_sps_pps_context.first_idr = 1;
m_sps_pps_context.idr_sps_pps_seen = 0;
}
+
+ if (m_convert_dovi)
+ {
+ if (unit_type == HEVC_NAL_UNSPEC62)
+ {
+#ifdef HAVE_LIBDOVI
+ // Convert the RPU itself
+ rpu_data = convert_dovi_rpu_nal(buf, nal_size);
+ if (rpu_data)
+ {
+ buf_to_write = rpu_data->data;
+ final_nal_size = rpu_data->len;
+ }
+#endif
+ }
+ else if (unit_type == HEVC_NAL_UNSPEC63)
+ {
+ // Ignore the enhancement layer, may or may not help
+ write_buf = false;
+ }
+ }
+
+ if (write_buf)
+ BitstreamAllocAndCopy(poutbuf, poutbuf_size, NULL, 0, buf_to_write, final_nal_size,
+ unit_type);
+
+#ifdef HAVE_LIBDOVI
+ if (rpu_data)
+ {
+ dovi_data_free(rpu_data);
+ rpu_data = NULL;
+ }
+#endif
}
buf += nal_size;
diff --git a/xbmc/utils/BitstreamConverter.h b/xbmc/utils/BitstreamConverter.h
index be63b7590c..1920212a2a 100644
--- a/xbmc/utils/BitstreamConverter.h
+++ b/xbmc/utils/BitstreamConverter.h
@@ -99,6 +99,7 @@ public:
int GetExtraSize() const;
void ResetStartDecode(void);
bool CanStartDecode() const;
+ void SetConvertDovi(bool value) { m_convert_dovi = value; }
static bool mpeg2_sequence_header(const uint8_t *data, const uint32_t size, mpeg2_sequence *sequence);
@@ -143,4 +144,5 @@ protected:
bool m_convert_bytestream;
AVCodecID m_codec;
bool m_start_decode;
+ bool m_convert_dovi;
};