MythTV master
mythdisplaymode.cpp
Go to the documentation of this file.
1// QT
2#include <QObject>
3#include <QStringList>
4
5// MythTV
6#include "mythdisplaymode.h"
7
8// Std
9#include <algorithm>
10#include <cmath>
11
12MythDisplayMode::MythDisplayMode(QSize Resolution, QSize PhysicalSize,
13 double AspectRatio, double RefreshRate)
14 : m_width(Resolution.width()),
15 m_height(Resolution.height()),
16 m_widthMM(PhysicalSize.width()),
17 m_heightMM(PhysicalSize.height())
18{
20 if (RefreshRate > 0)
21 m_refreshRates.push_back(RefreshRate);
22}
23MythDisplayMode::MythDisplayMode(int Width, int Height, int MMWidth, int MMHeight,
24 double AspectRatio, double RefreshRate)
25 : m_width(Width),
26 m_height(Height),
27 m_widthMM(MMWidth),
28 m_heightMM(MMHeight)
29{
31 if (RefreshRate > 0)
32 m_refreshRates.push_back(RefreshRate);
33}
34
36{
37 if (m_width < Other.m_width)
38 return true;
39 if (m_height < Other.m_height)
40 return true;
41 return false;
42}
43
45{
46 return m_width == Other.m_width && m_height == Other.m_height;
47}
48
50{
52 m_aspect = -1.0;
53}
54
56{
57 return { m_width, m_height };
58}
59
61{
62 return m_width;
63}
64
66{
67 return m_height;
68}
69
71{
72 return m_widthMM;
73}
74
76{
77 return m_heightMM;
78}
79
81{
82 return m_refreshRates;
83}
84
86{
87 if (m_aspect <= 0.0)
88 {
89 if (0 == m_heightMM)
90 return 1.0;
91 return static_cast<double>(m_widthMM) / m_heightMM;
92 }
93 return m_aspect;
94}
95
97{
98 if (!m_refreshRates.empty())
99 return m_refreshRates[0];
100 return 0.0;
101}
102
103void MythDisplayMode::SetAspectRatio(double AspectRatio)
104{
105 if (AspectRatio > 0.0)
107 else if (HeightMM())
108 m_aspect = static_cast<double>(m_widthMM) / m_heightMM;
109}
110
112{
113 m_refreshRates.push_back(Rate);
114 std::ranges::sort(m_refreshRates);
115}
116
118{
119 m_refreshRates.clear();
120}
121
123{
125 AddRefreshRate(Rate);
126}
127
128uint64_t MythDisplayMode::CalcKey(QSize Size, double Rate)
129{
130 return (static_cast<uint64_t>(Size.width()) << 34) |
131 (static_cast<uint64_t>(Size.height()) << 18) |
132 (static_cast<uint64_t>(Rate * 1000.0));
133}
134
136bool MythDisplayMode::CompareRates(double First, double Second, double Precision)
137{
138 return qAbs(First - Second) < Precision;
139}
140
142 const MythDisplayMode& Mode, double &TargetRate)
143{
144 double videorate = Mode.RefreshRate();
145 bool rate2x = false;
146 bool end = false;
147
148 // We will give priority to refresh rates that are twice what is looked for
149 if ((videorate > 24.5) && (videorate < 30.5))
150 {
151 rate2x = true;
152 videorate *= 2.0;
153 }
154
155 // Amend vector with custom list
156 for (size_t i = 0; i < Modes.size(); ++i)
157 {
158 if (Modes[i].Width() == Mode.Width() && Modes[i].Height() == Mode.Height())
159 {
160 auto rates = Modes[i].RefreshRates();
161 if (!rates.empty() && !qFuzzyCompare(videorate + 1.0, 1.0))
162 {
163 while (!end)
164 {
165 for (double precision : { 0.001, 0.01, 0.1 })
166 {
167 for (double rate : rates)
168 {
169 // Multiple of target_rate will do
170 if (CompareRates(videorate, rate, precision) ||
171 (qAbs(videorate - fmod(rate, videorate))
172 <= precision) ||
173 (fmod(rate,videorate) <= precision))
174 {
175 TargetRate = rate;
176 return static_cast<int>(i);
177 }
178 }
179 }
180 // Can't find exact frame rate, so try rounding to the
181 // nearest integer, so 23.97Hz will work with 24Hz etc
182 for (double precision : { 0.01, 0.1, 1.0 })
183 {
184 double rounded = round(videorate);
185 for (double rate : rates)
186 {
187 // Multiple of target_rate will do
188 if (CompareRates(rounded, rate, precision) ||
189 (qAbs(rounded - fmod(rate, rounded)) <= precision) ||
190 (fmod(rate,rounded) <= precision))
191 {
192 TargetRate = rate;
193 return static_cast<int>(i);
194 }
195 }
196 }
197 if (rate2x)
198 {
199 videorate /= 2.0;
200 rate2x = false;
201 }
202 else
203 {
204 end = true;
205 }
206 }
207 TargetRate = rates[rates.size() - 1];
208 }
209 else if (!rates.empty())
210 {
211 TargetRate = rates[rates.size() - 1];
212 }
213 return static_cast<int>(i);
214 }
215 }
216 return -1;
217}
218
219static void extract_key(uint64_t key, double& rate, int& height, int& width)
220{
221 rate = (key & ((1 << 18) - 1)) / 1000.0;
222 height = (key >> 18) & ((1 << 16) - 1);
223 width = (key >> 34) & ((1 << 16) - 1);
224}
225
227 int Width, int Height, double Rate)
228{
229 // 1. search for exact match (width, height, rate)
230 // 2. search for resolution, ignoring rate
231 // 3. search for matching height and rate (or any rate if rate = 0)
232 // 4. search for 2x rate
233 // 5. search for 1x rate
234
235 for (const auto & it : Map)
236 {
237 double rate { 0.0 };
238 int height { 0 };
239 int width { 0 };
240 extract_key(it.first, rate, height, width);
241 if (width == Width && height == Height && CompareRates(Rate, rate, 0.01))
242 return it.first;
243 }
244
245 for (const auto & it : Map)
246 {
247 double rate { 0.0 };
248 int height { 0 };
249 int width { 0 };
250 extract_key(it.first, rate, height, width);
251 if (width == Width && height == Height && qFuzzyCompare(rate + 1.0, 1.0))
252 return it.first;
253 }
254
255 for (const auto & it : Map)
256 {
257 double rate { 0.0 };
258 int height { 0 };
259 int width { 0 };
260 extract_key(it.first, rate, height, width);
261 if ((width == 0 && height == Height &&
262 (CompareRates(Rate, rate, 0.01) || qFuzzyCompare(rate + 1.0, 1.0))) ||
263 (width == 0 && height == 0 && CompareRates(Rate, rate * 2.0, 0.01)) ||
264 (width == 0 && height == 0 && CompareRates(Rate, rate, 0.01)))
265 {
266 return it.first;
267 }
268 }
269
270 return 0;
271}
272
274{
275 QStringList rates;
276 for (auto rate : m_refreshRates)
277 rates << QString::number(rate, 'f', 2);
278 return QObject::tr("%1x%2@%3Hz").arg(m_width).arg(m_height).arg(rates.join(", "));
279}
int Height() const
static bool CompareRates(double First, double Second, double Precision=0.01)
Determine whether two rates are considered equal with the given precision.
QString ToString() const
bool operator<(const MythDisplayMode &Other) const
static int FindBestMatch(const MythDisplayModes &Modes, const MythDisplayMode &Mode, double &TargetRate)
void SetRefreshRate(double Rate)
void AddRefreshRate(double Rate)
MythDisplayRates m_refreshRates
void SetAspectRatio(double AspectRatio)
double AspectRatio() const
int HeightMM() const
int WidthMM() const
double RefreshRate() const
static uint64_t FindBestScreen(const DisplayModeMap &Map, int Width, int Height, double Rate)
bool operator==(const MythDisplayMode &Other) const
const MythDisplayRates & RefreshRates() const
static uint64_t CalcKey(QSize Size, double Rate)
MythDisplayMode()=default
QSize Resolution() const
static void extract_key(uint64_t key, double &rate, int &height, int &width)
std::map< uint64_t, MythDisplayMode > DisplayModeMap
std::vector< MythDisplayMode > MythDisplayModes
std::vector< double > MythDisplayRates
Mode
Definition: synaesthesia.h:20