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