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; };