MythTV  master
videodisplayprofile.cpp
Go to the documentation of this file.
1 // MythTV
2 #include "videodisplayprofile.h"
3 #include "mythcorecontext.h"
4 #include "mythdb.h"
5 #include "mythlogging.h"
6 #include "mythvideoout.h"
7 #include "avformatdecoder.h"
8 
9 // Std
10 #include <algorithm>
11 #include <utility>
12 
14 {
15  m_pref.clear();
16 }
17 
19 {
20  m_profileid = Id;
21 }
22 
23 void ProfileItem::Set(const QString &Value, const QString &Data)
24 {
25  m_pref[Value] = Data;
26 }
27 
29 {
30  return m_profileid;
31 }
32 
33 QMap<QString,QString> ProfileItem::GetAll(void) const
34 {
35  return m_pref;
36 }
37 
38 QString ProfileItem::Get(const QString &Value) const
39 {
40  QMap<QString,QString>::const_iterator it = m_pref.find(Value);
41  if (it != m_pref.end())
42  return *it;
43  return QString();
44 }
45 
47 {
48  QString tmp = Get("pref_priority");
49  return tmp.isEmpty() ? 0 : tmp.toUInt();
50 }
51 
52 // options are NNN NNN-MMM 0-MMM NNN-99999 >NNN >=NNN <MMM <=MMM or blank
53 // If string is blank then assumes a match.
54 // If value is 0 or negative assume a match (i.e. value unknown assumes a match)
55 // float values must be no more than 3 decimals.
56 bool ProfileItem::CheckRange(const QString &Key, float Value, bool *Ok) const
57 {
58  return CheckRange(Key, Value, 0, true, Ok);
59 }
60 
61 bool ProfileItem::CheckRange(const QString &Key, int Value, bool *Ok) const
62 {
63  return CheckRange(Key, 0.0, Value, false, Ok);
64 }
65 
66 bool ProfileItem::CheckRange(const QString& Key,
67  float FValue, int IValue, bool IsFloat, bool *Ok) const
68 {
69  bool match = true;
70  bool isOK = true;
71  if (IsFloat)
72  IValue = int(FValue * 1000.0F);
73  QString cmp = Get(Key);
74  if (!cmp.isEmpty())
75  {
76  cmp.replace(QLatin1String(" "),QLatin1String(""));
77  QStringList expr = cmp.split("&");
78  for (int ix = 0; ix < expr.size(); ++ix)
79  {
80  if (expr[ix].isEmpty())
81  {
82  isOK = false;
83  continue;
84  }
85  if (IValue > 0)
86  {
87  QRegularExpression regex("^([0-9.]*)([^0-9.]*)([0-9.]*)$");
88  QRegularExpressionMatch rmatch = regex.match(expr[ix]);
89 
90  int value1 = 0;
91  int value2 = 0;
92  QString oper;
93  QString capture1 = rmatch.captured(1);
94  QString capture3;
95  if (!capture1.isEmpty())
96  {
97  if (IsFloat)
98  {
99  int dec=capture1.indexOf('.');
100  if (dec > -1 && (capture1.length()-dec) > 4)
101  isOK = false;
102  if (isOK)
103  {
104  double double1 = capture1.toDouble(&isOK);
105  if (double1 > 2000000.0 || double1 < 0.0)
106  isOK = false;
107  value1 = int(double1 * 1000.0);
108  }
109  }
110  else
111  value1 = capture1.toInt(&isOK);
112  }
113  if (isOK)
114  {
115  oper = rmatch.captured(2);
116  capture3 = rmatch.captured(3);
117  if (!capture3.isEmpty())
118  {
119  if (IsFloat)
120  {
121  int dec=capture3.indexOf('.');
122  if (dec > -1 && (capture3.length()-dec) > 4)
123  isOK = false;
124  if (isOK)
125  {
126  double double1 = capture3.toDouble(&isOK);
127  if (double1 > 2000000.0 || double1 < 0.0)
128  isOK = false;
129  value2 = int(double1 * 1000.0);
130  }
131  }
132  else
133  value2 = capture3.toInt(&isOK);
134  }
135  }
136  if (isOK)
137  {
138  // Invalid string
139  if (value1 == 0 && value2 == 0 && oper.isEmpty())
140  isOK=false;
141  }
142  if (isOK)
143  {
144  // Case NNN
145  if (value1 != 0 && oper.isEmpty() && value2 == 0)
146  {
147  value2 = value1;
148  oper = "-";
149  }
150  // NNN-MMM 0-MMM NNN-99999 NNN- -MMM
151  else if (oper == "-")
152  {
153  // NNN- or -NNN
154  if (capture1.isEmpty() || capture3.isEmpty())
155  isOK = false;
156  // NNN-MMM
157  if (value2 < value1)
158  isOK = false;
159  }
160  else if (capture1.isEmpty())
161  {
162  // Other operators == > < >= <=
163  // Convert to a range
164  if (oper == "==")
165  value1 = value2;
166  else if (oper == ">")
167  {
168  value1 = value2 + 1;
169  value2 = 99999999;
170  }
171  else if (oper == ">=")
172  {
173  value1 = value2;
174  value2 = 99999999;
175  }
176  else if (oper == "<")
177  value2 = value2 - 1;
178  else if (oper == "<=")
179  ;
180  else isOK = false;
181  oper = "-";
182  }
183  }
184  if (isOK)
185  {
186  if (oper == "-")
187  match = match && (IValue >= value1 && IValue <= value2);
188  else isOK = false;
189  }
190  }
191  }
192  }
193  if (Ok != nullptr)
194  *Ok = isOK;
195  if (!isOK)
196  match=false;
197  return match;
198 }
199 
200 bool ProfileItem::IsMatch(const QSize &Size,
201  float Framerate, const QString &CodecName) const
202 {
203  bool match = true;
204 
205  QString cmp;
206 
207  // cond_width, cond_height, cond_codecs, cond_framerate.
208  // These replace old settings pref_cmp0 and pref_cmp1
209  match &= CheckRange("cond_width",Size.width());
210  match &= CheckRange("cond_height",Size.height());
211  match &= CheckRange("cond_framerate",Framerate);
212  // codec
213  cmp = Get(QString("cond_codecs"));
214  if (!cmp.isEmpty())
215  {
216  QStringList clist = cmp.split(" ", QString::SkipEmptyParts);
217  if (!clist.empty())
218  match &= clist.contains(CodecName,Qt::CaseInsensitive);
219  }
220 
221  return match;
222 }
223 
224 bool ProfileItem::IsValid(QString *Reason) const
225 {
226 
227  bool isOK = true;
228  CheckRange("cond_width",1,&isOK);
229  if (!isOK)
230  {
231  if (Reason)
232  *Reason = QString("Invalid width condition");
233  return false;
234  }
235  CheckRange("cond_height",1,&isOK);
236  if (!isOK)
237  {
238  if (Reason)
239  *Reason = QString("Invalid height condition");
240  return false;
241  }
242  CheckRange("cond_framerate",1.0F,&isOK);
243  if (!isOK)
244  {
245  if (Reason)
246  *Reason = QString("Invalid framerate condition");
247  return false;
248  }
249 
250  QString decoder = Get("pref_decoder");
251  QString renderer = Get("pref_videorenderer");
252  if (decoder.isEmpty() || renderer.isEmpty())
253  {
254  if (Reason)
255  *Reason = "Need a decoder and renderer";
256  return false;
257  }
258 
259  QStringList decoders = VideoDisplayProfile::GetDecoders();
260  if (!decoders.contains(decoder))
261  {
262  if (Reason)
263  *Reason = QString("decoder %1 is not available").arg(decoder);
264  return false;
265  }
266 
267  QStringList renderers = VideoDisplayProfile::GetVideoRenderers(decoder);
268  if (!renderers.contains(renderer))
269  {
270  if (Reason)
271  *Reason = QString("renderer %1 is not supported with decoder %2")
272  .arg(renderer).arg(decoder);
273  return false;
274  }
275 
276  if (Reason)
277  *Reason = QString();
278 
279  return true;
280 }
281 
282 bool ProfileItem::operator< (const ProfileItem &Other) const
283 {
284  return GetPriority() < Other.GetPriority();
285 }
286 
287 QString ProfileItem::toString(void) const
288 {
289  QString cmp0 = Get("pref_cmp0");
290  QString cmp1 = Get("pref_cmp1");
291  QString width = Get("cond_width");
292  QString height = Get("cond_height");
293  QString framerate = Get("cond_framerate");
294  QString codecs = Get("cond_codecs");
295  QString decoder = Get("pref_decoder");
296  uint max_cpus = Get("pref_max_cpus").toUInt();
297  bool skiploop = Get("pref_skiploop").toInt() != 0;
298  QString renderer = Get("pref_videorenderer");
299  QString deint0 = Get("pref_deint0");
300  QString deint1 = Get("pref_deint1");
301 
302  QString cond = QString("w(%1) h(%2) framerate(%3) codecs(%4)")
303  .arg(width).arg(height).arg(framerate).arg(codecs);
304  QString str = QString("cmp(%1%2) %7 dec(%3) cpus(%4) skiploop(%5) rend(%6) ")
305  .arg(cmp0).arg(QString(cmp1.isEmpty() ? "" : ",") + cmp1)
306  .arg(decoder).arg(max_cpus).arg((skiploop) ? "enabled" : "disabled").arg(renderer)
307  .arg(cond);
308  str += QString("deint(%1,%2)").arg(deint0).arg(deint1);
309 
310  return str;
311 }
312 
314 
315 #define LOC QString("VDP: ")
316 
317 QMutex VideoDisplayProfile::s_safe_lock(QMutex::Recursive);
319 QMap<QString,QStringList> VideoDisplayProfile::s_safe_renderer;
320 QMap<QString,QStringList> VideoDisplayProfile::s_safe_renderer_group;
321 QMap<QString,QStringList> VideoDisplayProfile::s_safe_equiv_dec;
324 QMap<QString,QString> VideoDisplayProfile::s_dec_name;
325 QMap<QString,QString> VideoDisplayProfile::s_rend_name;
327 QList<QPair<QString,QString> > VideoDisplayProfile::s_deinterlacer_options;
328 
330 {
331  QMutexLocker locker(&s_safe_lock);
332  InitStatics();
333 
334  QString hostname = gCoreContext->GetHostName();
335  QString cur_profile = GetDefaultProfileName(hostname);
336  uint groupid = GetProfileGroupID(cur_profile, hostname);
337 
338  vector<ProfileItem> items = LoadDB(groupid);
339  vector<ProfileItem>::const_iterator it;
340  for (it = items.begin(); it != items.end(); ++it)
341  {
342  QString err;
343  if (!(*it).IsValid(&err))
344  {
345  LOG(VB_GENERAL, LOG_ERR, LOC + "Rejecting: " + (*it).toString() + "\n\t\t\t" + err);
346  continue;
347  }
348 
349  LOG(VB_PLAYBACK, LOG_INFO, LOC + "Accepting: " + (*it).toString());
350  m_allowedPreferences.push_back(*it);
351  }
352 }
353 
354 void VideoDisplayProfile::SetInput(const QSize &Size, float Framerate, const QString &CodecName)
355 {
356  QMutexLocker locker(&m_lock);
357  bool change = false;
358 
359  if (Size != m_lastSize)
360  {
361  m_lastSize = Size;
362  change = true;
363  }
364  if (Framerate > 0.0F && !qFuzzyCompare(Framerate + 1.0F, m_lastRate + 1.0F))
365  {
366  m_lastRate = Framerate;
367  change = true;
368  }
369  if (!CodecName.isEmpty() && CodecName != m_lastCodecName)
370  {
371  m_lastCodecName = CodecName;
372  change = true;
373  }
374  if (change)
376 }
377 
378 void VideoDisplayProfile::SetOutput(float Framerate)
379 {
380  QMutexLocker locker(&m_lock);
381  if (!qFuzzyCompare(Framerate + 1.0F, m_lastRate + 1.0F))
382  {
383  m_lastRate = Framerate;
385  }
386 }
387 
389 {
390  return m_lastRate;
391 }
392 
394 {
395  return GetPreference("pref_decoder");
396 }
397 
399 {
400  return GetPreference("pref_deint0");
401 }
402 
404 {
405  return GetPreference("pref_deint1");
406 }
407 
409 {
410  return GetPreference("pref_max_cpus").toUInt();
411 }
412 
414 {
415  return GetPreference("pref_skiploop").toInt();
416 }
417 
419 {
420  return GetPreference("pref_videorenderer");
421 }
422 
424 {
425  return m_lastVideoRenderer;
426 }
427 
428 void VideoDisplayProfile::SetVideoRenderer(const QString &VideoRenderer)
429 {
430  QMutexLocker locker(&m_lock);
431 
432  LOG(VB_PLAYBACK, LOG_INFO, LOC +
433  QString("SetVideoRenderer(%1)").arg(VideoRenderer));
434 
435  m_lastVideoRenderer = VideoRenderer;
436  if (VideoRenderer == GetVideoRenderer())
437  {
438  LOG(VB_PLAYBACK, LOG_INFO, LOC +
439  QString("SetVideoRender(%1) == GetVideoRenderer()").arg(VideoRenderer));
440  return; // already made preferences safe...
441  }
442 
443  // Make preferences safe...
444  LOG(VB_PLAYBACK, LOG_INFO, LOC + "Old preferences: " + toString());
445 
446  SetPreference("pref_videorenderer", VideoRenderer);
447 
448  LOG(VB_PLAYBACK, LOG_INFO, LOC + "New preferences: " + toString());
449 }
450 
451 bool VideoDisplayProfile::CheckVideoRendererGroup(const QString &Renderer)
452 {
453  if (m_lastVideoRenderer == Renderer || m_lastVideoRenderer == "null")
454  return true;
455 
456  LOG(VB_PLAYBACK, LOG_INFO, LOC +
457  QString("Preferred video renderer: %1 (current: %2)")
458  .arg(Renderer).arg(m_lastVideoRenderer));
459 
460  QMap<QString,QStringList>::const_iterator it = s_safe_renderer_group.begin();
461  for (; it != s_safe_renderer_group.end(); ++it)
462  if (it->contains(m_lastVideoRenderer) && it->contains(Renderer))
463  return true;
464  return false;
465 }
466 
468 {
469  const QString dec = GetDecoder();
470  if (dec == Decoder)
471  return true;
472 
473  QMutexLocker locker(&s_safe_lock);
474  return (s_safe_equiv_dec[dec].contains(Decoder));
475 }
476 
477 QString VideoDisplayProfile::GetPreference(const QString &Key) const
478 {
479  QMutexLocker locker(&m_lock);
480 
481  if (Key.isEmpty())
482  return QString();
483 
484  QMap<QString,QString>::const_iterator it = m_currentPreferences.find(Key);
485  if (it == m_currentPreferences.end())
486  return QString();
487 
488  return *it;
489 }
490 
491 void VideoDisplayProfile::SetPreference(const QString &Key, const QString &Value)
492 {
493  QMutexLocker locker(&m_lock);
494 
495  if (!Key.isEmpty())
496  m_currentPreferences[Key] = Value;
497 }
498 
499 vector<ProfileItem>::const_iterator VideoDisplayProfile::FindMatch
500  (const QSize &Size, float Framerate, const QString &CodecName)
501 {
502  vector<ProfileItem>::const_iterator it = m_allowedPreferences.begin();
503  for (; it != m_allowedPreferences.end(); ++it)
504  if ((*it).IsMatch(Size, Framerate, CodecName))
505  return it;
506  return m_allowedPreferences.end();
507 }
508 
510  (const QSize &Size, float Framerate, const QString &CodecName)
511 {
512  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("LoadBestPreferences(%1x%2, %3, %4)")
513  .arg(Size.width()).arg(Size.height())
514  .arg(static_cast<double>(Framerate), 0, 'f', 3).arg(CodecName));
515 
516  m_currentPreferences.clear();
517  auto it = FindMatch(Size, Framerate, CodecName);
518  if (it != m_allowedPreferences.end())
519  m_currentPreferences = (*it).GetAll();
520 
521  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("LoadBestPreferences Result "
522  "prio:%1, w:%2, h:%3, fps:%4,"
523  " codecs:%5, decoder:%6, renderer:%7, deint:%8")
524  .arg(GetPreference("pref_priority")).arg(GetPreference("cond_width"))
525  .arg(GetPreference("cond_height")).arg(GetPreference("cond_framerate"))
526  .arg(GetPreference("cond_codecs")).arg(GetPreference("pref_decoder"))
527  .arg(GetPreference("pref_videorenderer")).arg(GetPreference("pref_deint0"))
528  );
529 }
530 
531 vector<ProfileItem> VideoDisplayProfile::LoadDB(uint GroupId)
532 {
534  vector<ProfileItem> list;
535 
536  MSqlQuery query(MSqlQuery::InitCon());
537  query.prepare(
538  "SELECT profileid, value, data "
539  "FROM displayprofiles "
540  "WHERE profilegroupid = :GROUPID "
541  "ORDER BY profileid");
542  query.bindValue(":GROUPID", GroupId);
543  if (!query.exec())
544  {
545  MythDB::DBError("loaddb 1", query);
546  return list;
547  }
548 
549  uint profileid = 0;
550  while (query.next())
551  {
552  if (query.value(0).toUInt() != profileid)
553  {
554  if (profileid)
555  {
556  tmp.SetProfileID(profileid);
557  QString error;
558  bool valid = tmp.IsValid(&error);
559  if (valid)
560  list.push_back(tmp);
561  else
562  LOG(VB_PLAYBACK, LOG_NOTICE, LOC + QString("Ignoring profile %1 (%2)")
563  .arg(profileid).arg(error));
564  }
565  tmp.Clear();
566  profileid = query.value(0).toUInt();
567  }
568  tmp.Set(query.value(1).toString(), query.value(2).toString());
569  }
570  if (profileid)
571  {
572  tmp.SetProfileID(profileid);
573  QString error;
574  bool valid = tmp.IsValid(&error);
575  if (valid)
576  list.push_back(tmp);
577  else
578  LOG(VB_PLAYBACK, LOG_NOTICE, LOC + QString("Ignoring profile %1 (%2)")
579  .arg(profileid).arg(error));
580  }
581 
582  sort(list.begin(), list.end());
583  return list;
584 }
585 
586 bool VideoDisplayProfile::DeleteDB(uint GroupId, const vector<ProfileItem> &Items)
587 {
588  MSqlQuery query(MSqlQuery::InitCon());
589  query.prepare(
590  "DELETE FROM displayprofiles "
591  "WHERE profilegroupid = :GROUPID AND "
592  " profileid = :PROFILEID");
593 
594  bool ok = true;
595  auto it = Items.cbegin();
596  for (; it != Items.cend(); ++it)
597  {
598  if (!(*it).GetProfileID())
599  continue;
600 
601  query.bindValue(":GROUPID", GroupId);
602  query.bindValue(":PROFILEID", (*it).GetProfileID());
603  if (!query.exec())
604  {
605  MythDB::DBError("vdp::deletedb", query);
606  ok = false;
607  }
608  }
609 
610  return ok;
611 }
612 
613 bool VideoDisplayProfile::SaveDB(uint GroupId, vector<ProfileItem> &Items)
614 {
615  MSqlQuery query(MSqlQuery::InitCon());
616 
617  MSqlQuery update(MSqlQuery::InitCon());
618  update.prepare(
619  "UPDATE displayprofiles "
620  "SET data = :DATA "
621  "WHERE profilegroupid = :GROUPID AND "
622  " profileid = :PROFILEID AND "
623  " value = :VALUE");
624 
625  MSqlQuery insert(MSqlQuery::InitCon());
626  insert.prepare(
627  "INSERT INTO displayprofiles "
628  " ( profilegroupid, profileid, value, data) "
629  "VALUES "
630  " (:GROUPID, :PROFILEID, :VALUE, :DATA) ");
631 
632  MSqlQuery sqldelete(MSqlQuery::InitCon());
633  sqldelete.prepare(
634  "DELETE FROM displayprofiles "
635  "WHERE profilegroupid = :GROUPID AND "
636  " profileid = :PROFILEID AND "
637  " value = :VALUE");
638 
639  bool ok = true;
640  auto it = Items.begin();
641  for (; it != Items.end(); ++it)
642  {
643  QMap<QString,QString> list = (*it).GetAll();
644  if (list.begin() == list.end())
645  continue;
646 
647  QMap<QString,QString>::const_iterator lit = list.begin();
648 
649  if (!(*it).GetProfileID())
650  {
651  // create new profileid
652  if (!query.exec("SELECT MAX(profileid) FROM displayprofiles"))
653  {
654  MythDB::DBError("save_profile 1", query);
655  ok = false;
656  continue;
657  }
658  if (query.next())
659  {
660  (*it).SetProfileID(query.value(0).toUInt() + 1);
661  }
662 
663  for (; lit != list.end(); ++lit)
664  {
665  if ((*lit).isEmpty())
666  continue;
667 
668  insert.bindValue(":GROUPID", GroupId);
669  insert.bindValue(":PROFILEID", (*it).GetProfileID());
670  insert.bindValue(":VALUE", lit.key());
671  insert.bindValue(":DATA", ((*lit).isNull()) ? "" : (*lit));
672  if (!insert.exec())
673  {
674  MythDB::DBError("save_profile 2", insert);
675  ok = false;
676  continue;
677  }
678  }
679  continue;
680  }
681 
682  for (; lit != list.end(); ++lit)
683  {
684  query.prepare(
685  "SELECT count(*) "
686  "FROM displayprofiles "
687  "WHERE profilegroupid = :GROUPID AND "
688  " profileid = :PROFILEID AND "
689  " value = :VALUE");
690  query.bindValue(":GROUPID", GroupId);
691  query.bindValue(":PROFILEID", (*it).GetProfileID());
692  query.bindValue(":VALUE", lit.key());
693 
694  if (!query.exec())
695  {
696  MythDB::DBError("save_profile 3", query);
697  ok = false;
698  continue;
699  }
700  if (query.next() && (1 == query.value(0).toUInt()))
701  {
702  if (lit->isEmpty())
703  {
704  sqldelete.bindValue(":GROUPID", GroupId);
705  sqldelete.bindValue(":PROFILEID", (*it).GetProfileID());
706  sqldelete.bindValue(":VALUE", lit.key());
707  if (!sqldelete.exec())
708  {
709  MythDB::DBError("save_profile 5a", sqldelete);
710  ok = false;
711  continue;
712  }
713  }
714  else
715  {
716  update.bindValue(":GROUPID", GroupId);
717  update.bindValue(":PROFILEID", (*it).GetProfileID());
718  update.bindValue(":VALUE", lit.key());
719  update.bindValue(":DATA", ((*lit).isNull()) ? "" : (*lit));
720  if (!update.exec())
721  {
722  MythDB::DBError("save_profile 5b", update);
723  ok = false;
724  continue;
725  }
726  }
727  }
728  else
729  {
730  insert.bindValue(":GROUPID", GroupId);
731  insert.bindValue(":PROFILEID", (*it).GetProfileID());
732  insert.bindValue(":VALUE", lit.key());
733  insert.bindValue(":DATA", ((*lit).isNull()) ? "" : (*lit));
734  if (!insert.exec())
735  {
736  MythDB::DBError("save_profile 4", insert);
737  ok = false;
738  continue;
739  }
740  }
741  }
742  }
743 
744  return ok;
745 }
746 
748 {
749  InitStatics();
750  return s_safe_decoders;
751 }
752 
754 {
755  InitStatics();
756  QStringList list;
757 
758  const QStringList decs = GetDecoders();
759  QStringList::const_iterator it = decs.begin();
760  for (; it != decs.end(); ++it)
761  list += GetDecoderName(*it);
762 
763  return list;
764 }
765 
767 {
768  if (Decoder.isEmpty())
769  return "";
770 
771  QMutexLocker locker(&s_safe_lock);
772  if (s_dec_name.empty())
773  {
774  s_dec_name["ffmpeg"] = QObject::tr("Standard");
775  s_dec_name["vdpau"] = QObject::tr("NVIDIA VDPAU acceleration");
776  s_dec_name["vdpau-dec"] = QObject::tr("NVIDIA VDPAU acceleration (decode only)");
777  s_dec_name["vaapi"] = QObject::tr("VAAPI acceleration");
778  s_dec_name["vaapi-dec"] = QObject::tr("VAAPI acceleration (decode only)");
779  s_dec_name["dxva2"] = QObject::tr("Windows hardware acceleration");
780  s_dec_name["mediacodec"] = QObject::tr("Android MediaCodec acceleration");
781  s_dec_name["mediacodec-dec"] = QObject::tr("Android MediaCodec acceleration (decode only)");
782  s_dec_name["nvdec"] = QObject::tr("NVIDIA NVDEC acceleration");
783  s_dec_name["nvdec-dec"] = QObject::tr("NVIDIA NVDEC acceleration (decode only)");
784  s_dec_name["vtb"] = QObject::tr("VideoToolbox acceleration");
785  s_dec_name["vtb-dec"] = QObject::tr("VideoToolbox acceleration (decode only)");
786  s_dec_name["v4l2"] = QObject::tr("V4L2 acceleration");
787  s_dec_name["v4l2-dec"] = QObject::tr("V4L2 acceleration (decode only)");
788  s_dec_name["mmal"] = QObject::tr("MMAL acceleration");
789  s_dec_name["mmal-dec"] = QObject::tr("MMAL acceleration (decode only)");
790  s_dec_name["drmprime"] = QObject::tr("DRM PRIME acceleration");
791  }
792 
793  QString ret = Decoder;
794  QMap<QString,QString>::const_iterator it = s_dec_name.find(Decoder);
795  if (it != s_dec_name.end())
796  ret = *it;
797  return ret;
798 }
799 
800 
802 {
803  QString msg = QObject::tr("Processing method used to decode video.");
804 
805  if (Decoder.isEmpty())
806  return msg;
807 
808  msg += "\n";
809 
810  if (Decoder == "ffmpeg")
811  msg += QObject::tr("Standard will use the FFmpeg library for software decoding.");
812 
813  if (Decoder.startsWith("vdpau"))
814  msg += QObject::tr(
815  "VDPAU will attempt to use the graphics hardware to "
816  "accelerate video decoding.");
817 
818  if (Decoder.startsWith("vaapi"))
819  msg += QObject::tr(
820  "VAAPI will attempt to use the graphics hardware to "
821  "accelerate video decoding and playback.");
822 
823  if (Decoder.startsWith("dxva2"))
824  msg += QObject::tr(
825  "DXVA2 will use the graphics hardware to "
826  "accelerate video decoding and playback. ");
827 
828  if (Decoder.startsWith("mediacodec"))
829  msg += QObject::tr(
830  "Mediacodec will use Android graphics hardware to "
831  "accelerate video decoding and playback. ");
832 
833  if (Decoder.startsWith("nvdec"))
834  msg += QObject::tr(
835  "Nvdec uses the NVDEC API to "
836  "accelerate video decoding and playback with NVIDIA Graphics Adapters. ");
837 
838  if (Decoder.startsWith("vtb"))
839  msg += QObject::tr(
840  "The VideoToolbox library is used to accelerate video decoding. ");
841 
842  if (Decoder.startsWith("mmal"))
843  msg += QObject::tr(
844  "MMAL is used to accelerated video decoding (Raspberry Pi only). ");
845 
846  if (Decoder == "v4l2")
847  msg += "Highly experimental: ";
848 
849  if (Decoder.startsWith("v4l2"))
850  msg += QObject::tr(
851  "Video4Linux codecs are used to accelerate video decoding on "
852  "supported platforms. ");
853 
854  if (Decoder == "drmprime")
855  msg += QObject::tr(
856  "DRM-PRIME decoders are used to accelerate video decoding on "
857  "supported platforms. ");
858 
859  if (Decoder.endsWith("-dec"))
860  msg += QObject::tr("The decoder will transfer frames back to system memory "
861  "which will significantly reduce performance but may allow "
862  "other functionality to be used (such as automatic "
863  "letterbox detection). ");
864  return msg;
865 }
866 
867 QString VideoDisplayProfile::GetVideoRendererName(const QString &Renderer)
868 {
869  QMutexLocker locker(&s_safe_lock);
870  if (s_rend_name.empty())
871  {
872  s_rend_name["opengl"] = QObject::tr("OpenGL");
873  s_rend_name["opengl-yv12"] = QObject::tr("OpenGL YV12");
874  s_rend_name["opengl-hw"] = QObject::tr("OpenGL Hardware");
875  }
876 
877  QString ret = Renderer;
878  QMap<QString,QString>::const_iterator it = s_rend_name.find(Renderer);
879  if (it != s_rend_name.end())
880  ret = *it;
881  return ret;
882 }
883 
884 QStringList VideoDisplayProfile::GetProfiles(const QString &HostName)
885 {
886  InitStatics();
887  QStringList list;
888  MSqlQuery query(MSqlQuery::InitCon());
889  query.prepare(
890  "SELECT name "
891  "FROM displayprofilegroups "
892  "WHERE hostname = :HOST ");
893  query.bindValue(":HOST", HostName);
894  if (!query.exec() || !query.isActive())
895  MythDB::DBError("get_profiles", query);
896  else
897  {
898  while (query.next())
899  list += query.value(0).toString();
900  }
901  return list;
902 }
903 
904 QString VideoDisplayProfile::GetDefaultProfileName(const QString &HostName)
905 {
906  QString tmp =
907  gCoreContext->GetSettingOnHost("DefaultVideoPlaybackProfile", HostName);
908 
909  QStringList profiles = GetProfiles(HostName);
910 
911  tmp = (profiles.contains(tmp)) ? tmp : QString();
912 
913  if (tmp.isEmpty())
914  {
915  if (!profiles.empty())
916  tmp = profiles[0];
917 
918  tmp = (profiles.contains("Normal")) ? "Normal" : tmp;
919 
920  if (!tmp.isEmpty())
921  {
923  "DefaultVideoPlaybackProfile", tmp, HostName);
924  }
925  }
926 
927  return tmp;
928 }
929 
930 void VideoDisplayProfile::SetDefaultProfileName(const QString &ProfileName, const QString &HostName)
931 {
932  gCoreContext->SaveSettingOnHost("DefaultVideoPlaybackProfile", ProfileName, HostName);
933 }
934 
935 uint VideoDisplayProfile::GetProfileGroupID(const QString &ProfileName,
936  const QString &HostName)
937 {
938  MSqlQuery query(MSqlQuery::InitCon());
939  query.prepare(
940  "SELECT profilegroupid "
941  "FROM displayprofilegroups "
942  "WHERE name = :NAME AND "
943  " hostname = :HOST ");
944  query.bindValue(":NAME", ProfileName);
945  query.bindValue(":HOST", HostName);
946 
947  if (!query.exec() || !query.isActive())
948  MythDB::DBError("get_profile_group_id", query);
949  else if (query.next())
950  return query.value(0).toUInt();
951 
952  return 0;
953 }
954 
956  const QString& Width, const QString& Height, const QString& Codecs,
957  const QString& Decoder, uint MaxCpus, bool SkipLoop, const QString& VideoRenderer,
958  const QString& Deint1, const QString& Deint2)
959 {
960  MSqlQuery query(MSqlQuery::InitCon());
961 
962  // create new profileid
963  uint profileid = 1;
964  if (!query.exec("SELECT MAX(profileid) FROM displayprofiles"))
965  MythDB::DBError("create_profile 1", query);
966  else if (query.next())
967  profileid = query.value(0).toUInt() + 1;
968 
969  query.prepare(
970  "INSERT INTO displayprofiles "
971  "VALUES (:GRPID, :PROFID, 'pref_priority', :PRIORITY)");
972  query.bindValue(":GRPID", GroupId);
973  query.bindValue(":PROFID", profileid);
974  query.bindValue(":PRIORITY", Priority);
975  if (!query.exec())
976  MythDB::DBError("create_profile 2", query);
977 
978  QStringList queryValue;
979  QStringList queryData;
980 
981  queryValue += "cond_width";
982  queryData += Width;
983 
984  queryValue += "cond_height";
985  queryData += Height;
986 
987  queryValue += "cond_codecs";
988  queryData += Codecs;
989 
990  queryValue += "pref_decoder";
991  queryData += Decoder;
992 
993  queryValue += "pref_max_cpus";
994  queryData += QString::number(MaxCpus);
995 
996  queryValue += "pref_skiploop";
997  queryData += (SkipLoop) ? "1" : "0";
998 
999  queryValue += "pref_videorenderer";
1000  queryData += VideoRenderer;
1001 
1002  queryValue += "pref_deint0";
1003  queryData += Deint1;
1004 
1005  queryValue += "pref_deint1";
1006  queryData += Deint2;
1007 
1008  QStringList::const_iterator itV = queryValue.begin();
1009  QStringList::const_iterator itD = queryData.begin();
1010  for (; itV != queryValue.end() && itD != queryData.end(); ++itV,++itD)
1011  {
1012  if (itD->isEmpty())
1013  continue;
1014  query.prepare(
1015  "INSERT INTO displayprofiles "
1016  "VALUES (:GRPID, :PROFID, :VALUE, :DATA)");
1017  query.bindValue(":GRPID", GroupId);
1018  query.bindValue(":PROFID", profileid);
1019  query.bindValue(":VALUE", *itV);
1020  query.bindValue(":DATA", *itD);
1021  if (!query.exec())
1022  MythDB::DBError("create_profile 3", query);
1023  }
1024 }
1025 
1026 uint VideoDisplayProfile::CreateProfileGroup(const QString &ProfileName, const QString &HostName)
1027 {
1028  MSqlQuery query(MSqlQuery::InitCon());
1029  query.prepare(
1030  "INSERT INTO displayprofilegroups (name, hostname) "
1031  "VALUES (:NAME,:HOST)");
1032 
1033  query.bindValue(":NAME", ProfileName);
1034  query.bindValue(":HOST", HostName);
1035 
1036  if (!query.exec())
1037  {
1038  MythDB::DBError("create_profile_group", query);
1039  return 0;
1040  }
1041 
1042  return GetProfileGroupID(ProfileName, HostName);
1043 }
1044 
1045 bool VideoDisplayProfile::DeleteProfileGroup(const QString &GroupName, const QString &HostName)
1046 {
1047  bool ok = true;
1048  MSqlQuery query(MSqlQuery::InitCon());
1049  MSqlQuery query2(MSqlQuery::InitCon());
1050 
1051  query.prepare(
1052  "SELECT profilegroupid "
1053  "FROM displayprofilegroups "
1054  "WHERE name = :NAME AND "
1055  " hostname = :HOST ");
1056 
1057  query.bindValue(":NAME", GroupName);
1058  query.bindValue(":HOST", HostName);
1059 
1060  if (!query.exec() || !query.isActive())
1061  {
1062  MythDB::DBError("delete_profile_group 1", query);
1063  ok = false;
1064  }
1065  else
1066  {
1067  while (query.next())
1068  {
1069  query2.prepare("DELETE FROM displayprofiles "
1070  "WHERE profilegroupid = :PROFID");
1071  query2.bindValue(":PROFID", query.value(0).toUInt());
1072  if (!query2.exec())
1073  {
1074  MythDB::DBError("delete_profile_group 2", query2);
1075  ok = false;
1076  }
1077  }
1078  }
1079 
1080  query.prepare(
1081  "DELETE FROM displayprofilegroups "
1082  "WHERE name = :NAME AND "
1083  " hostname = :HOST");
1084 
1085  query.bindValue(":NAME", GroupName);
1086  query.bindValue(":HOST", HostName);
1087 
1088  if (!query.exec())
1089  {
1090  MythDB::DBError("delete_profile_group 3", query);
1091  ok = false;
1092  }
1093 
1094  return ok;
1095 }
1096 
1097 void VideoDisplayProfile::CreateProfiles(const QString &HostName)
1098 {
1099  QStringList profiles = GetProfiles(HostName);
1100  uint groupid;
1101 
1102 #ifdef USING_OPENGL
1103  if (!profiles.contains("OpenGL High Quality"))
1104  {
1105  (void) QObject::tr("OpenGL High Quality",
1106  "Sample: OpenGL high quality");
1107  groupid = CreateProfileGroup("OpenGL High Quality", HostName);
1108  CreateProfile(groupid, 1, "", "", "",
1109  "ffmpeg", 2, true, "opengl-yv12",
1110  "shader:high", "shader:high");
1111  }
1112 
1113  if (!profiles.contains("OpenGL Normal"))
1114  {
1115  (void) QObject::tr("OpenGL Normal", "Sample: OpenGL medium quality");
1116  groupid = CreateProfileGroup("OpenGL Normal", HostName);
1117  CreateProfile(groupid, 1, "", "", "",
1118  "ffmpeg", 2, true, "opengl-yv12",
1119  "shader:medium", "shader:medium");
1120  }
1121 
1122  if (!profiles.contains("OpenGL Slim"))
1123  {
1124  (void) QObject::tr("OpenGL Slim", "Sample: OpenGL low power GPU");
1125  groupid = CreateProfileGroup("OpenGL Slim", HostName);
1126  CreateProfile(groupid, 1, "", "", "",
1127  "ffmpeg", 1, true, "opengl",
1128  "medium", "medium");
1129  }
1130 #endif
1131 
1132 #ifdef USING_VAAPI
1133  if (!profiles.contains("VAAPI Normal"))
1134  {
1135  (void) QObject::tr("VAAPI Normal", "Sample: VAAPI average quality");
1136  groupid = CreateProfileGroup("VAAPI Normal", HostName);
1137  CreateProfile(groupid, 1, "", "", "",
1138  "vaapi", 2, true, "opengl-hw",
1139  "shader:driver:high", "shader:driver:high");
1140  CreateProfile(groupid, 1, "", "", "",
1141  "ffmpeg", 1, true, "opengl-yv12",
1142  "shader:high", "shader:high");
1143  }
1144 #endif
1145 
1146 #ifdef USING_VDPAU
1147  if (!profiles.contains("VDPAU Normal"))
1148  {
1149  (void) QObject::tr("VDPAU Normal", "Sample: VDPAU medium quality");
1150  groupid = CreateProfileGroup("VDPAU Normal", HostName);
1151  CreateProfile(groupid, 1, "", "", "",
1152  "vdpau", 1, true, "opengl-hw",
1153  "driver:medium", "driver:medium");
1154  }
1155 #endif
1156 
1157 #ifdef USING_MEDIACODEC
1158  if (!profiles.contains("MediaCodec Normal"))
1159  {
1160  (void) QObject::tr("MediaCodec Normal",
1161  "Sample: MediaCodec Normal");
1162  groupid = CreateProfileGroup("MediaCodec Normal", HostName);
1163  CreateProfile(groupid, 1, "", "", "",
1164  "mediacodec-dec", 4, true, "opengl-yv12",
1165  "shader:driver:medium", "shader:driver:medium");
1166  }
1167 #endif
1168 
1169 #if defined(USING_NVDEC) && defined(USING_OPENGL)
1170  if (!profiles.contains("NVDEC Normal"))
1171  {
1172  (void) QObject::tr("NVDEC Normal", "Sample: NVDEC Normal");
1173  groupid = CreateProfileGroup("NVDEC Normal", HostName);
1174  CreateProfile(groupid, 1, "", "", "",
1175  "nvdec", 1, true, "opengl-hw",
1176  "shader:driver:high", "shader:driver:high");
1177  }
1178 #endif
1179 
1180 #if defined(USING_VTB) && defined(USING_OPENGL)
1181  if (!profiles.contains("VideoToolBox Normal")) {
1182  (void) QObject::tr("VideoToolBox Normal", "Sample: VideoToolBox Normal");
1183  groupid = CreateProfileGroup("VideoToolBox Normal", HostName);
1184  CreateProfile(groupid, 1, "", "", "",
1185  "vtb", 1, true, "opengl-hw",
1186  "shader:driver:medium", "shader:driver:medium");
1187  }
1188 #endif
1189 
1190 #if defined(USING_MMAL) && defined(USING_OPENGL)
1191  if (!profiles.contains("MMAL"))
1192  {
1193  (void) QObject::tr("MMAL", "Sample: MMAL");
1194  groupid = CreateProfileGroup("MMAL", HostName);
1195  CreateProfile(groupid, 1, "", "", "",
1196  "mmal", 1, true, "opengl-hw",
1197  "shader:driver:medium", "shader:driver:medium");
1198  }
1199 #endif
1200 
1201 #if defined(USING_V4L2)
1202  if (!profiles.contains("V4L2 Codecs"))
1203  {
1204  (void) QObject::tr("V4L2 Codecs", "Sample: V4L2");
1205  groupid = CreateProfileGroup("V4L2 Codecs", HostName);
1206  CreateProfile(groupid, 1, "", "", "",
1207  "v4l2-dec", 1, true, "opengl-yv12",
1208  "shader:driver:medium", "shader:driver:medium");
1209  CreateProfile(groupid, 2, "", "", "",
1210  "v4l2", 1, true, "opengl-hw",
1211  "shader:driver:medium", "shader:driver:medium");
1212  }
1213 #endif
1214 }
1215 
1217 {
1218  QMutexLocker locker(&s_safe_lock);
1219  InitStatics();
1220 
1221  QMap<QString,QStringList>::const_iterator it = s_safe_renderer.find(Decoder);
1222  QStringList tmp;
1223  if (it != s_safe_renderer.end())
1224  tmp = *it;
1225  return tmp;
1226 }
1227 
1228 QString VideoDisplayProfile::GetVideoRendererHelp(const QString &Renderer)
1229 {
1230  QString msg = QObject::tr("Video rendering method");
1231 
1232  if (Renderer.isEmpty())
1233  return msg;
1234 
1235  if (Renderer == "null")
1236  msg = QObject::tr(
1237  "Render video offscreen. Used internally.");
1238 
1239  if (Renderer == "direct3d")
1240  msg = QObject::tr(
1241  "Windows video renderer based on Direct3D. Requires "
1242  "video card compatible with Direct3D 9. This is the preferred "
1243  "renderer for current Windows systems.");
1244 
1245  if (Renderer == "opengl")
1246  {
1247  msg = QObject::tr(
1248  "Video is converted to an intermediate format by the CPU (YUV2) "
1249  "before OpenGL is used for color conversion, scaling, picture controls"
1250  " and optionally deinterlacing. Processing is balanced between the CPU "
1251  "and GPU.");
1252  }
1253 
1254  if (Renderer == "opengl-yv12")
1255  {
1256  msg = QObject::tr(
1257  "OpenGL is used for all color conversion, scaling, picture "
1258  "controls and optionally deinterlacing. CPU load is low but a slightly more "
1259  "powerful GPU is needed for deinterlacing.");
1260  }
1261 
1262  if (Renderer == "opengl-hw")
1263  {
1264  msg = QObject::tr(
1265  "This video renderer is used by hardware decoders to display "
1266  "frames using OpenGL.");
1267  }
1268 
1269  return msg;
1270 }
1271 
1273 {
1275 }
1276 
1277 bool VideoDisplayProfile::IsFilterAllowed(const QString &VideoRenderer)
1278 {
1279  QMutexLocker locker(&s_safe_lock);
1280  InitStatics();
1281  return s_safe_custom.contains(VideoRenderer);
1282 }
1283 
1284 QStringList VideoDisplayProfile::GetFilteredRenderers(const QString &Decoder, const QStringList &Renderers)
1285 {
1286  const QStringList dec_list = GetVideoRenderers(Decoder);
1287  QStringList new_list;
1288 
1289  QStringList::const_iterator it = dec_list.begin();
1290  for (; it != dec_list.end(); ++it)
1291  if (Renderers.contains(*it))
1292  new_list.push_back(*it);
1293 
1294  return new_list;
1295 }
1296 
1297 QString VideoDisplayProfile::GetBestVideoRenderer(const QStringList &Renderers)
1298 {
1299  QMutexLocker locker(&s_safe_lock);
1300  InitStatics();
1301 
1302  uint top_priority = 0;
1303  QString top_renderer;
1304 
1305  QStringList::const_iterator it = Renderers.begin();
1306  for (; it != Renderers.end(); ++it)
1307  {
1308  QMap<QString,uint>::const_iterator p = s_safe_renderer_priority.find(*it);
1309  if ((p != s_safe_renderer_priority.end()) && (*p >= top_priority))
1310  {
1311  top_priority = *p;
1312  top_renderer = *it;
1313  }
1314  }
1315 
1316  return top_renderer;
1317 }
1318 
1320 {
1321  QString renderer = GetPreference("pref_videorenderer");
1322  QString osd = GetPreference("pref_osdrenderer");
1323  QString deint0 = GetPreference("pref_deint0");
1324  QString deint1 = GetPreference("pref_deint1");
1325  return QString("rend(%4) osd(%5) deint(%6,%7) filt(%8)")
1326  .arg(renderer).arg(osd).arg(deint0).arg(deint1);
1327 }
1328 
1329 QList<QPair<QString,QString> > VideoDisplayProfile::GetDeinterlacers(void)
1330 {
1331  InitStatics();
1332  return s_deinterlacer_options;
1333 }
1334 
1335 void VideoDisplayProfile::InitStatics(bool Reinit /*= false*/)
1336 {
1337  if (Reinit)
1338  {
1339  s_safe_custom.clear();
1340  s_safe_renderer.clear();
1341  s_safe_renderer_group.clear();
1342  s_safe_renderer_priority.clear();
1343  s_safe_decoders.clear();
1344  s_safe_equiv_dec.clear();
1345  s_deinterlacer_options.clear();
1346  }
1347  else if (s_safe_initialized)
1348  {
1349  return;
1350  }
1351  s_safe_initialized = true;
1352 
1354  options.renderers = &s_safe_custom;
1355  options.safe_renderers = &s_safe_renderer;
1356  options.render_group = &s_safe_renderer_group;
1357  options.priorities = &s_safe_renderer_priority;
1358  options.decoders = &s_safe_decoders;
1359  options.equiv_decoders = &s_safe_equiv_dec;
1360 
1361  // N.B. assumes NuppelDecoder and DummyDecoder always present
1364 
1365  foreach(QString decoder, s_safe_decoders)
1366  LOG(VB_PLAYBACK, LOG_INFO, LOC +
1367  QString("decoder<->render support: %1%2")
1368  .arg(decoder, -12).arg(GetVideoRenderers(decoder).join(" ")));
1369 
1370  s_deinterlacer_options.append(QPair<QString,QString>(DEINT_QUALITY_NONE, QObject::tr("None")));
1371  s_deinterlacer_options.append(QPair<QString,QString>(DEINT_QUALITY_LOW, QObject::tr("Low quality")));
1372  s_deinterlacer_options.append(QPair<QString,QString>(DEINT_QUALITY_MEDIUM, QObject::tr("Medium quality")));
1373  s_deinterlacer_options.append(QPair<QString,QString>(DEINT_QUALITY_HIGH, QObject::tr("High quality")));
1374 }
bool CheckRange(const QString &Key, float Value, bool *Ok=nullptr) const
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
Definition: mythdbcon.cpp:781
QMap< QString, QString > m_pref
static QString GetPreferredVideoRenderer(const QString &Decoder)
static QStringList GetDecoders(void)
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
Definition: mythdbcon.cpp:862
void SetInput(const QSize &Size, float Framerate=0, const QString &CodecName=QString())
static uint CreateProfileGroup(const QString &ProfileName, const QString &HostName)
static QMap< QString, QStringList > s_safe_equiv_dec
static QMap< QString, QString > s_dec_name
static bool DeleteDB(uint GroupId, const vector< ProfileItem > &Items)
uint GetProfileID(void) const
static QList< QPair< QString, QString > > s_deinterlacer_options
static void GetDecoders(RenderOptions &opts)
static vector< ProfileItem > LoadDB(uint GroupId)
uint GetPriority(void) const
static QStringList GetFilteredRenderers(const QString &Decoder, const QStringList &Renderers)
vector< ProfileItem > m_allowedPreferences
static QString GetDecoderHelp(const QString &Decoder=QString())
static QStringList GetDecoderNames(void)
static QMap< QString, uint > s_safe_renderer_priority
void SetOutput(float Framerate)
static void error(const char *str,...)
Definition: vbi.c:42
QMap< QString, QString > m_currentPreferences
static QList< QPair< QString, QString > > GetDeinterlacers(void)
QSqlQuery wrapper that fetches a DB connection from the connection pool.
Definition: mythdbcon.h:125
float GetOutput(void) const
bool CheckVideoRendererGroup(const QString &Renderer)
static void SetDefaultProfileName(const QString &ProfileName, const QString &HostName)
QString GetSettingOnHost(const QString &key, const QString &host, const QString &defaultval="")
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
#define DEINT_QUALITY_HIGH
static void CreateProfile(uint GroupId, uint Priority, const QString &Width, const QString &Height, const QString &Codecs, const QString &Decoder, uint MaxCpus, bool SkipLoop, const QString &VideoRenderer, const QString &Deint1, const QString &Deint2)
static guint32 * tmp
Definition: goom_core.c:35
QVariant value(int i) const
Definition: mythdbcon.h:198
static QMap< QString, QString > s_rend_name
static QMap< QString, QStringList > s_safe_renderer_group
#define LOC
void LoadBestPreferences(const QSize &Size, float Framerate, const QString &CodecName)
static void CreateProfiles(const QString &HostName)
QString GetPreference(const QString &Key) const
void Set(const QString &Value, const QString &Data)
QString GetDecoder(void) const
vector< ProfileItem >::const_iterator FindMatch(const QSize &Size, float Framerate, const QString &CodecName)
static QString GetDefaultProfileName(const QString &HostName)
bool isActive(void) const
Definition: mythdbcon.h:204
static void InitStatics(bool Reinit=false)
static QString GetDecoderName(const QString &Decoder)
#define DEINT_QUALITY_NONE
QString toString(void) const
void SetProfileID(uint Id)
QMap< QString, QString > GetAll(void) const
string hostname
Definition: caa.py:17
void SetPreference(const QString &Key, const QString &Value)
unsigned int uint
Definition: compat.h:140
static MSqlQueryInfo InitCon(ConnectionReuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:534
static bool DeleteProfileGroup(const QString &GroupName, const QString &HostName)
QString GetActualVideoRenderer(void) const
static QString GetVideoRendererName(const QString &Renderer)
bool IsSkipLoopEnabled(void) const
QString Get(const QString &Value) const
static QStringList s_safe_decoders
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
Definition: mythdbcon.cpp:806
static QStringList GetVideoRenderers(const QString &Decoder)
static bool IsFilterAllowed(const QString &VideoRenderer)
static void GetRenderOptions(RenderOptions &Options)
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
uint GetMaxCPUs(void) const
static QMap< QString, QStringList > s_safe_renderer
static bool SaveDB(uint GroupId, vector< ProfileItem > &Items)
bool IsValid(QString *Reason=nullptr) const
QString GetSingleRatePreferences(void) const
static QStringList GetProfiles(const QString &HostName)
static QString GetBestVideoRenderer(const QStringList &Renderers)
static QStringList s_safe_custom
QString GetVideoRenderer(void) const
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
Definition: mythdbcon.cpp:602
bool SaveSettingOnHost(const QString &key, const QString &newValue, const QString &host)
static void DBError(const QString &where, const MSqlQuery &query)
Definition: mythdb.cpp:179
QString toString(void) const
bool IsMatch(const QSize &Size, float Framerate, const QString &CodecName) const
static uint GetProfileGroupID(const QString &ProfileName, const QString &HostName)
bool operator<(const ProfileItem &Other) const
#define DEINT_QUALITY_MEDIUM
#define DEINT_QUALITY_LOW
QString GetHostName(void)
static QString GetVideoRendererHelp(const QString &Renderer)
QString GetDoubleRatePreferences(void) const
bool IsDecoderCompatible(const QString &Decoder)
void SetVideoRenderer(const QString &VideoRenderer)