2 * Copyright (C) 2011-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
8 #include "AndroidUtils.h"
10 #include "ServiceBroker.h"
11 #include "settings/DisplaySettings.h"
12 #include "settings/Settings.h"
13 #include "settings/SettingsComponent.h"
14 #include "settings/lib/SettingsManager.h"
15 #include "utils/StringUtils.h"
16 #include "utils/log.h"
17 #include "windowing/GraphicContext.h"
19 #include "platform/android/activity/XBMCApp.h"
21 #include <androidjni/MediaCodecInfo.h>
22 #include <androidjni/MediaCodecList.h>
23 #include <androidjni/View.h>
24 #include <androidjni/Window.h>
26 static std::vector
<RESOLUTION_INFO
> s_res_displayModes
;
27 static RESOLUTION_INFO s_res_cur_displayMode
;
29 static void fetchDisplayModes()
31 s_res_displayModes
.clear();
33 CJNIDisplay display
= CXBMCApp::getWindow().getDecorView().getDisplay();
37 CJNIDisplayMode m
= display
.getMode();
40 const bool landscape
= m
.getPhysicalWidth() > m
.getPhysicalHeight();
41 CLog::Log(LOGDEBUG
, "CAndroidUtils: current mode: {}: {}x{}@{:f}", m
.getModeId(),
42 m
.getPhysicalWidth(), m
.getPhysicalHeight(), m
.getRefreshRate());
43 s_res_cur_displayMode
.strId
= std::to_string(m
.getModeId());
44 s_res_cur_displayMode
.iWidth
= s_res_cur_displayMode
.iScreenWidth
=
45 landscape
? m
.getPhysicalWidth() : m
.getPhysicalHeight();
46 s_res_cur_displayMode
.iHeight
= s_res_cur_displayMode
.iScreenHeight
=
47 landscape
? m
.getPhysicalHeight() : m
.getPhysicalWidth();
48 s_res_cur_displayMode
.fRefreshRate
= m
.getRefreshRate();
49 s_res_cur_displayMode
.dwFlags
= D3DPRESENTFLAG_PROGRESSIVE
;
50 s_res_cur_displayMode
.bFullScreen
= true;
51 s_res_cur_displayMode
.iSubtitles
= s_res_cur_displayMode
.iHeight
;
52 s_res_cur_displayMode
.fPixelRatio
= 1.0f
;
53 s_res_cur_displayMode
.strMode
= StringUtils::Format(
54 "{}x{} @ {:.6f}{} - Full Screen", s_res_cur_displayMode
.iScreenWidth
,
55 s_res_cur_displayMode
.iScreenHeight
, s_res_cur_displayMode
.fRefreshRate
,
56 s_res_cur_displayMode
.dwFlags
& D3DPRESENTFLAG_INTERLACED
? "i" : "");
58 std::vector
<CJNIDisplayMode
> modes
= display
.getSupportedModes();
59 for (CJNIDisplayMode
& m
: modes
)
61 CLog::Log(LOGDEBUG
, "CAndroidUtils: available mode: {}: {}x{}@{:f}", m
.getModeId(),
62 m
.getPhysicalWidth(), m
.getPhysicalHeight(), m
.getRefreshRate());
65 res
.strId
= std::to_string(m
.getModeId());
66 res
.iWidth
= res
.iScreenWidth
= landscape
? m
.getPhysicalWidth() : m
.getPhysicalHeight();
67 res
.iHeight
= res
.iScreenHeight
= landscape
? m
.getPhysicalHeight() : m
.getPhysicalWidth();
68 res
.fRefreshRate
= m
.getRefreshRate();
69 res
.dwFlags
= D3DPRESENTFLAG_PROGRESSIVE
;
70 res
.bFullScreen
= true;
71 res
.iSubtitles
= res
.iHeight
;
72 res
.fPixelRatio
= 1.0f
;
73 res
.strMode
= StringUtils::Format("{}x{} @ {:.6f}{} - Full Screen", res
.iScreenWidth
,
74 res
.iScreenHeight
, res
.fRefreshRate
,
75 res
.dwFlags
& D3DPRESENTFLAG_INTERLACED
? "i" : "");
77 s_res_displayModes
.push_back(res
);
85 std::string
HdrTypeString(int type
)
87 const std::map
<int, std::string
> hdrTypeMap
= {
88 {CJNIDisplayHdrCapabilities::HDR_TYPE_HDR10
, "HDR10"},
89 {CJNIDisplayHdrCapabilities::HDR_TYPE_HLG
, "HLG"},
90 {CJNIDisplayHdrCapabilities::HDR_TYPE_HDR10_PLUS
, "HDR10+"},
91 {CJNIDisplayHdrCapabilities::HDR_TYPE_DOLBY_VISION
, "Dolby Vision"}};
93 auto hdr
= hdrTypeMap
.find(type
);
94 if (hdr
!= hdrTypeMap
.end())
99 } // unnamed namespace
101 const std::string
CAndroidUtils::SETTING_LIMITGUI
= "videoscreen.limitgui";
103 CAndroidUtils::CAndroidUtils()
105 m_width
= m_height
= 0;
108 for (const RESOLUTION_INFO
& res
: s_res_displayModes
)
110 if (res
.iWidth
> m_width
|| res
.iHeight
> m_height
)
112 m_width
= res
.iWidth
;
113 m_height
= res
.iHeight
;
117 CLog::Log(LOGDEBUG
, "CAndroidUtils: maximum/current resolution: {}x{}", m_width
, m_height
);
118 int limit
= CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(
119 CAndroidUtils::SETTING_LIMITGUI
);
127 case 9999: // unlimited
146 CLog::Log(LOGDEBUG
, "CAndroidUtils: selected resolution: {}x{}", m_width
, m_height
);
148 CServiceBroker::GetSettingsComponent()->GetSettings()->GetSettingsManager()->RegisterCallback(
149 this, {CAndroidUtils::SETTING_LIMITGUI
});
151 LogDisplaySupportedHdrTypes();
154 bool CAndroidUtils::GetNativeResolution(RESOLUTION_INFO
* res
) const
156 const std::shared_ptr
<CNativeWindow
> nativeWindow
= CXBMCApp::Get().GetNativeWindow(30000);
160 if (!m_width
|| !m_height
)
162 m_width
= nativeWindow
->GetWidth();
163 m_height
= nativeWindow
->GetHeight();
164 CLog::Log(LOGINFO
, "CAndroidUtils: window resolution: {}x{}", m_width
, m_height
);
167 *res
= s_res_cur_displayMode
;
168 res
->iWidth
= m_width
;
169 res
->iHeight
= m_height
;
170 res
->iSubtitles
= res
->iHeight
;
172 StringUtils::Format("{}x{} @ {:.6f}{} - Full Screen", res
->iScreenWidth
, res
->iScreenHeight
,
173 res
->fRefreshRate
, res
->dwFlags
& D3DPRESENTFLAG_INTERLACED
? "i" : "");
174 CLog::Log(LOGINFO
, "CAndroidUtils: Current resolution: {}x{} {}", res
->iWidth
, res
->iHeight
,
179 bool CAndroidUtils::SetNativeResolution(const RESOLUTION_INFO
& res
)
181 CLog::Log(LOGINFO
, "CAndroidUtils: SetNativeResolution: {}: {}x{} {}x{}@{:f}", res
.strId
,
182 res
.iWidth
, res
.iHeight
, res
.iScreenWidth
, res
.iScreenHeight
, res
.fRefreshRate
);
184 CXBMCApp::Get().SetDisplayMode(std::atoi(res
.strId
.c_str()), res
.fRefreshRate
);
185 s_res_cur_displayMode
= res
;
186 CXBMCApp::Get().SetBuffersGeometry(res
.iWidth
, res
.iHeight
, 0);
191 bool CAndroidUtils::ProbeResolutions(std::vector
<RESOLUTION_INFO
>& resolutions
)
193 RESOLUTION_INFO cur_res
;
194 GetNativeResolution(&cur_res
);
196 CLog::Log(LOGDEBUG
, "CAndroidUtils: ProbeResolutions: {}x{}", m_width
, m_height
);
198 for (RESOLUTION_INFO res
: s_res_displayModes
)
200 if (m_width
&& m_height
)
202 res
.iWidth
= std::min(res
.iWidth
, m_width
);
203 res
.iHeight
= std::min(res
.iHeight
, m_height
);
204 res
.iSubtitles
= res
.iHeight
;
206 resolutions
.push_back(res
);
211 bool CAndroidUtils::UpdateDisplayModes()
217 bool CAndroidUtils::IsHDRDisplay()
219 CJNIWindow window
= CXBMCApp::getWindow();
224 CJNIView view
= window
.getDecorView();
227 CJNIDisplay display
= view
.getDisplay();
229 ret
= display
.isHdr();
232 CLog::Log(LOGDEBUG
, "CAndroidUtils: IsHDRDisplay: {}", ret
? "true" : "false");
236 void CAndroidUtils::OnSettingChanged(const std::shared_ptr
<const CSetting
>& setting
)
238 const std::string
& settingId
= setting
->GetId();
239 /* Calibration (overscan / subtitles) are based on GUI size -> reset required */
240 if (settingId
== CAndroidUtils::SETTING_LIMITGUI
)
241 CDisplaySettings::GetInstance().ClearCalibrations();
244 std::vector
<int> CAndroidUtils::GetDisplaySupportedHdrTypes()
246 CJNIWindow window
= CXBMCApp::getWindow();
250 CJNIView view
= window
.getDecorView();
253 CJNIDisplay display
= view
.getDisplay();
256 CJNIDisplayHdrCapabilities caps
= display
.getHdrCapabilities();
258 return caps
.getSupportedHdrTypes();
266 void CAndroidUtils::LogDisplaySupportedHdrTypes()
268 const std::vector
<int> hdrTypes
= GetDisplaySupportedHdrTypes();
271 for (const int& type
: hdrTypes
)
273 text
+= " " + HdrTypeString(type
);
276 CLog::Log(LOGDEBUG
, "CAndroidUtils: Display supported HDR types:{}",
277 text
.empty() ? " None" : text
);
280 CHDRCapabilities
CAndroidUtils::GetDisplayHDRCapabilities()
282 CHDRCapabilities caps
;
283 const std::vector
<int> types
= GetDisplaySupportedHdrTypes();
285 if (std::find(types
.begin(), types
.end(), CJNIDisplayHdrCapabilities::HDR_TYPE_HDR10
) !=
289 if (std::find(types
.begin(), types
.end(), CJNIDisplayHdrCapabilities::HDR_TYPE_HLG
) !=
293 if (std::find(types
.begin(), types
.end(), CJNIDisplayHdrCapabilities::HDR_TYPE_HDR10_PLUS
) !=
297 if (std::find(types
.begin(), types
.end(), CJNIDisplayHdrCapabilities::HDR_TYPE_DOLBY_VISION
) !=
299 caps
.SetDolbyVision();
304 bool CAndroidUtils::SupportsMediaCodecMimeType(const std::string
& mimeType
)
306 const std::vector
<CJNIMediaCodecInfo
> codecInfos
=
307 CJNIMediaCodecList(CJNIMediaCodecList::REGULAR_CODECS
).getCodecInfos();
309 for (const CJNIMediaCodecInfo
& codec_info
: codecInfos
)
311 if (codec_info
.isEncoder())
314 std::vector
<std::string
> types
= codec_info
.getSupportedTypes();
315 if (std::find(types
.begin(), types
.end(), mimeType
) != types
.end())
322 std::pair
<bool, bool> CAndroidUtils::GetDolbyVisionCapabilities()
324 const bool displaySupportsDovi
= GetDisplayHDRCapabilities().SupportsDolbyVision();
325 const bool mediaCodecSupportsDovi
= SupportsMediaCodecMimeType("video/dolby-vision");
327 CLog::Log(LOGDEBUG
, "CAndroidUtils::GetDolbyVisionCapabilities Display: {}, MediaCodec: {}",
328 displaySupportsDovi
, mediaCodecSupportsDovi
);
330 return std::make_pair(displaySupportsDovi
, mediaCodecSupportsDovi
);