Merge pull request #26362 from ksooo/estuary-rework-pvr-info-dialog
[xbmc.git] / xbmc / windowing / android / AndroidUtils.cpp
blob35ee48b4b2c1d3c47f50fe0782ced809bc6abc0b
1 /*
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.
7 */
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();
35 if (display)
37 CJNIDisplayMode m = display.getMode();
38 if (m)
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());
64 RESOLUTION_INFO res;
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);
83 namespace
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())
95 return hdr->second;
97 return "Unknown";
99 } // unnamed namespace
101 const std::string CAndroidUtils::SETTING_LIMITGUI = "videoscreen.limitgui";
103 CAndroidUtils::CAndroidUtils()
105 m_width = m_height = 0;
107 fetchDisplayModes();
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);
120 switch (limit)
122 case 0: // auto
123 m_width = 0;
124 m_height = 0;
125 break;
127 case 9999: // unlimited
128 break;
130 case 720:
131 if (m_height > 720)
133 m_width = 1280;
134 m_height = 720;
136 break;
138 case 1080:
139 if (m_height > 1080)
141 m_width = 1920;
142 m_height = 1080;
144 break;
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);
157 if (!nativeWindow)
158 return false;
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;
171 res->strMode =
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,
175 res->strMode);
176 return true;
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);
188 return true;
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);
208 return true;
211 bool CAndroidUtils::UpdateDisplayModes()
213 fetchDisplayModes();
214 return true;
217 bool CAndroidUtils::IsHDRDisplay()
219 CJNIWindow window = CXBMCApp::getWindow();
220 bool ret = false;
222 if (window)
224 CJNIView view = window.getDecorView();
225 if (view)
227 CJNIDisplay display = view.getDisplay();
228 if (display)
229 ret = display.isHdr();
232 CLog::Log(LOGDEBUG, "CAndroidUtils: IsHDRDisplay: {}", ret ? "true" : "false");
233 return ret;
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();
248 if (window)
250 CJNIView view = window.getDecorView();
251 if (view)
253 CJNIDisplay display = view.getDisplay();
254 if (display)
256 CJNIDisplayHdrCapabilities caps = display.getHdrCapabilities();
257 if (caps)
258 return caps.getSupportedHdrTypes();
263 return {};
266 void CAndroidUtils::LogDisplaySupportedHdrTypes()
268 const std::vector<int> hdrTypes = GetDisplaySupportedHdrTypes();
269 std::string text;
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) !=
286 types.end())
287 caps.SetHDR10();
289 if (std::find(types.begin(), types.end(), CJNIDisplayHdrCapabilities::HDR_TYPE_HLG) !=
290 types.end())
291 caps.SetHLG();
293 if (std::find(types.begin(), types.end(), CJNIDisplayHdrCapabilities::HDR_TYPE_HDR10_PLUS) !=
294 types.end())
295 caps.SetHDR10Plus();
297 if (std::find(types.begin(), types.end(), CJNIDisplayHdrCapabilities::HDR_TYPE_DOLBY_VISION) !=
298 types.end())
299 caps.SetDolbyVision();
301 return caps;
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())
312 continue;
314 std::vector<std::string> types = codec_info.getSupportedTypes();
315 if (std::find(types.begin(), types.end(), mimeType) != types.end())
316 return true;
319 return false;
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);