From 151ff19dce818674d309be487cdb3ac9f491b367 Mon Sep 17 00:00:00 2001
From: quietvoid <39477805+quietvoid@users.noreply.github.com>
Date: Sat, 21 Jan 2023 19:11:24 -0500
Subject: [PATCH] [Android] Optionally convert Dolby Vision
To improve compatibility
---
.../resources/strings.po | 12 +++
system/settings/settings.xml | 9 ++
.../Video/DVDVideoCodecAndroidMediaCodec.cpp | 4 +
xbmc/settings/Settings.cpp | 1 +
xbmc/settings/Settings.h | 1 +
xbmc/utils/BitstreamConverter.cpp | 82 ++++++++++++++++++-
xbmc/utils/BitstreamConverter.h | 2 +
7 files changed, 110 insertions(+), 1 deletion(-)
diff --git a/addons/resource.language.en_gb/resources/strings.po b/addons/resource.language.en_gb/resources/strings.po
index cbbfe514fe4f1..efed2e0cca410 100644
--- a/addons/resource.language.en_gb/resources/strings.po
+++ b/addons/resource.language.en_gb/resources/strings.po
@@ -23405,3 +23405,15 @@ msgstr ""
msgctxt "#39189"
msgid "Available only with manual subtitle position"
msgstr ""
+
+#. Title of Dolby Vision RPU conversion setting
+#: system/settings/settings.xml
+msgctxt "#39190"
+msgid "Convert Dolby Vision for compatibility"
+msgstr ""
+
+#. Help text for setting "Convert Dolby Vision for compatibility" of label #39190
+#: system/settings/settings.xml
+msgctxt "#39191"
+msgid "Converts Dolby Vision profile 7 to profile 8.1, ignores enhancement layer"
+msgstr ""
diff --git a/system/settings/settings.xml b/system/settings/settings.xml
index 1b998bcc66f0c..6a14fae729b4d 100755
--- a/system/settings/settings.xml
+++ b/system/settings/settings.xml
@@ -153,6 +153,15 @@
true
+
+ HAS_MEDIACODEC
+ 2
+ false
+
+
+
+
+
diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecAndroidMediaCodec.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecAndroidMediaCodec.cpp
index 571fab311f475..f509c22643c3b 100644
--- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecAndroidMediaCodec.cpp
+++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecAndroidMediaCodec.cpp
@@ -537,6 +537,10 @@ bool CDVDVideoCodecAndroidMediaCodec::Open(CDVDStreamInfo &hints, CDVDCodecOptio
{
m_bitstream.reset();
}
+
+ bool convertDovi = CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(
+ CSettings::SETTING_VIDEOPLAYER_CONVERTDOVI);
+ m_bitstream->SetConvertDovi(convertDovi);
}
break;
}
diff --git a/xbmc/settings/Settings.cpp b/xbmc/settings/Settings.cpp
index b403b63bdfd5b..c11975af6bfcc 100644
--- a/xbmc/settings/Settings.cpp
+++ b/xbmc/settings/Settings.cpp
@@ -153,6 +153,7 @@ constexpr const char* CSettings::SETTING_VIDEOPLAYER_USEPRIMEDECODER;
constexpr const char* CSettings::SETTING_VIDEOPLAYER_USESTAGEFRIGHT;
constexpr const char* CSettings::SETTING_VIDEOPLAYER_LIMITGUIUPDATE;
constexpr const char* CSettings::SETTING_VIDEOPLAYER_SUPPORTMVC;
+constexpr const char* CSettings::SETTING_VIDEOPLAYER_CONVERTDOVI;
constexpr const char* CSettings::SETTING_MYVIDEOS_SELECTACTION;
constexpr const char* CSettings::SETTING_MYVIDEOS_USETAGS;
constexpr const char* CSettings::SETTING_MYVIDEOS_EXTRACTFLAGS;
diff --git a/xbmc/settings/Settings.h b/xbmc/settings/Settings.h
index cdd2d31ae3a7a..bbd65ce139116 100644
--- a/xbmc/settings/Settings.h
+++ b/xbmc/settings/Settings.h
@@ -129,6 +129,7 @@ class CSettings : public CSettingsBase, public CSettingCreator, public CSettingC
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 f2224a5457939..775a296d6e986 100644
--- a/xbmc/utils/BitstreamConverter.cpp
+++ b/xbmc/utils/BitstreamConverter.cpp
@@ -20,6 +20,13 @@
#include
+extern "C"
+{
+#ifdef HAVE_LIBDOVI
+#include
+#endif
+}
+
enum {
AVC_NAL_SLICE=1,
AVC_NAL_DPA,
@@ -257,6 +264,38 @@ 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 fail;
+
+ ret = dovi_rpu_remove_mapping(rpu);
+ if (ret < 0)
+ goto fail;
+
+ rpu_data = dovi_write_unspec62_nalu(rpu);
+ }
+
+fail:
+ if (header)
+ dovi_rpu_free_header(header);
+
+ dovi_rpu_free(rpu);
+
+ return rpu_data;
+}
+#endif
+
////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////
CBitstreamParser::CBitstreamParser() = default;
@@ -324,6 +363,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()
@@ -882,6 +922,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:
@@ -935,12 +979,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 3c57e14057ecd..d0fc1858d0961 100644
--- a/xbmc/utils/BitstreamConverter.h
+++ b/xbmc/utils/BitstreamConverter.h
@@ -96,6 +96,7 @@ class CBitstreamConverter
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);
@@ -141,4 +142,5 @@ class CBitstreamConverter
bool m_convert_bytestream;
AVCodecID m_codec;
bool m_start_decode;
+ bool m_convert_dovi;
};