MythTV  master
videodisplayprofile.cpp
Go to the documentation of this file.
1 // -*- Mode: c++ -*-
2 #include <algorithm>
3 using namespace std;
4 
5 #include "videodisplayprofile.h"
6 #include "mythcorecontext.h"
7 #include "mythdb.h"
8 #include "mythlogging.h"
9 #include "videooutbase.h"
10 #include "avformatdecoder.h"
11 #include "mythcodeccontext.h"
12 
13 
14 // options are NNN NNN-MMM 0-MMM NNN-99999 >NNN >=NNN <MMM <=MMM or blank
15 // If string is blank then assumes a match.
16 // If value is 0 or negative assume a match (i.e. value unknown assumes a match)
17 // float values must be no more than 3 decimals.
18 
19 bool ProfileItem::checkRange(QString key, float fvalue, bool *ok) const
20 {
21  return checkRange(key, fvalue, 0, true, ok);
22 }
23 
24 bool ProfileItem::checkRange(QString key, int ivalue, bool *ok) const
25 {
26  return checkRange(key, 0.0, ivalue, false, ok);
27 }
28 
29 bool ProfileItem::checkRange(QString key,
30  float fvalue, int ivalue, bool isFloat, bool *ok) const
31 {
32  bool match = true;
33  bool isOK = true;
34  if (isFloat)
35  ivalue = int(fvalue * 1000.0f);
36  QString cmp = Get(key);
37  if (!cmp.isEmpty())
38  {
39  cmp.replace(QLatin1String(" "),QLatin1String(""));
40  QStringList expr = cmp.split("&");
41  for (int ix = 0; ix < expr.size(); ++ix)
42  {
43  if (expr[ix].isEmpty())
44  {
45  isOK = false;
46  continue;
47  }
48  if (ivalue > 0)
49  {
50  QRegularExpression regex("^([0-9.]*)([^0-9.]*)([0-9.]*)$");
51  QRegularExpressionMatch rmatch = regex.match(expr[ix]);
52 
53  int value1 = 0;
54  int value2 = 0;
55  QString oper;
56  QString capture1 = rmatch.captured(1);
57  QString capture3;
58  if (!capture1.isEmpty())
59  {
60  if (isFloat)
61  {
62  int dec=capture1.indexOf('.');
63  if (dec > -1 && (capture1.length()-dec) > 4)
64  isOK = false;
65  if (isOK)
66  {
67  double double1 = capture1.toDouble(&isOK);
68  if (double1 > 2000000.0 || double1 < 0.0)
69  isOK = false;
70  value1 = int(double1 * 1000.0);
71  }
72  }
73  else
74  value1 = capture1.toInt(&isOK);
75  }
76  if (isOK)
77  {
78  oper = rmatch.captured(2);
79  capture3 = rmatch.captured(3);
80  if (!capture3.isEmpty())
81  {
82  if (isFloat)
83  {
84  int dec=capture3.indexOf('.');
85  if (dec > -1 && (capture3.length()-dec) > 4)
86  isOK = false;
87  if (isOK)
88  {
89  double double1 = capture3.toDouble(&isOK);
90  if (double1 > 2000000.0 || double1 < 0.0)
91  isOK = false;
92  value2 = int(double1 * 1000.0);
93  }
94  }
95  else
96  value2 = capture3.toInt(&isOK);
97  }
98  }
99  if (isOK)
100  {
101  // Invalid string
102  if (value1 == 0 && value2 == 0 && oper.isEmpty())
103  isOK=false;
104  }
105  if (isOK)
106  {
107  // Case NNN
108  if (value1 != 0 && oper.isEmpty() && value2 == 0)
109  {
110  value2 = value1;
111  oper = "-";
112  }
113  // NNN-MMM 0-MMM NNN-99999 NNN- -MMM
114  else if (oper == "-")
115  {
116  // NNN- or -NNN
117  if (capture1.isEmpty() || capture3.isEmpty())
118  isOK = false;
119  // NNN-MMM
120  if (value2 < value1)
121  isOK = false;
122  }
123  else if (capture1.isEmpty())
124  {
125  // Other operators == > < >= <=
126  // Convert to a range
127  if (oper == "==")
128  value1 = value2;
129  else if (oper == ">")
130  {
131  value1 = value2 + 1;
132  value2 = 99999999;
133  }
134  else if (oper == ">=")
135  {
136  value1 = value2;
137  value2 = 99999999;
138  }
139  else if (oper == "<")
140  value2 = value2 - 1;
141  else if (oper == "<=")
142  ;
143  else isOK = false;
144  oper = "-";
145  }
146  }
147  if (isOK)
148  {
149  if (oper == "-")
150  match = match && (ivalue >= value1 && ivalue <= value2);
151  else isOK = false;
152  }
153  }
154  }
155  }
156  if (ok != nullptr)
157  *ok = isOK;
158  if (!isOK)
159  match=false;
160  return match;
161 }
162 
163 bool ProfileItem::IsMatch(const QSize &size,
164  float framerate, const QString &codecName) const
165 {
166  bool match = true;
167 
168  QString cmp;
169 
170  // cond_width, cond_height, cond_codecs, cond_framerate.
171  // These replace old settings pref_cmp0 and pref_cmp1
172  match &= checkRange("cond_width",size.width());
173  match &= checkRange("cond_height",size.height());
174  match &= checkRange("cond_framerate",framerate);
175  // codec
176  cmp = Get(QString("cond_codecs"));
177  if (!cmp.isEmpty())
178  {
179  QStringList clist = cmp.split(" ", QString::SkipEmptyParts);
180  if (clist.size() > 0)
181  match &= clist.contains(codecName,Qt::CaseInsensitive);
182  }
183 
184  return match;
185 }
186 
187 
188 static QString toCommaList(const QStringList &list)
189 {
190  QString ret = "";
191  for (QStringList::const_iterator it = list.begin(); it != list.end(); ++it)
192  ret += *it + ",";
193 
194  if (ret.length())
195  return ret.left(ret.length()-1);
196 
197  return "";
198 }
199 
200 bool ProfileItem::IsValid(QString *reason) const
201 {
202 
203  bool isOK = true;
204  checkRange("cond_width",1,&isOK);
205  if (!isOK)
206  {
207  if (reason)
208  *reason = QString("Invalid width condition");
209  return false;
210  }
211  checkRange("cond_height",1,&isOK);
212  if (!isOK)
213  {
214  if (reason)
215  *reason = QString("Invalid height condition");
216  return false;
217  }
218  checkRange("cond_framerate",1.0f,&isOK);
219  if (!isOK)
220  {
221  if (reason)
222  *reason = QString("Invalid framerate condition");
223  return false;
224  }
225 
226  QString decoder = Get("pref_decoder");
227  QString renderer = Get("pref_videorenderer");
228  if (decoder.isEmpty() || renderer.isEmpty())
229  {
230  if (reason)
231  *reason = "Need a decoder and renderer";
232 
233  return false;
234  }
235 
236  QStringList decoders = VideoDisplayProfile::GetDecoders();
237  if (!decoders.contains(decoder))
238  {
239  if (reason)
240  {
241  *reason = QString("decoder %1 is not supported (supported: %2)")
242  .arg(decoder).arg(toCommaList(decoders));
243  }
244 
245  return false;
246  }
247 
248  QStringList renderers = VideoDisplayProfile::GetVideoRenderers(decoder);
249  if (!renderers.contains(renderer))
250  {
251  if (reason)
252  {
253  *reason = QString("renderer %1 is not supported "
254  "w/decoder %2 (supported: %3)")
255  .arg(renderer).arg(decoder).arg(toCommaList(renderers));
256  }
257 
258  return false;
259  }
260 
261  QStringList deints = VideoDisplayProfile::GetDeinterlacers(renderer);
262  QStringList decoderdeints = MythCodecContext::GetDeinterlacers(decoder);
263  deints.append(decoderdeints);
264  QString deint0 = Get("pref_deint0");
265  QString deint1 = Get("pref_deint1");
266  if (!deint0.isEmpty() && !deints.contains(deint0))
267  {
268  if (reason)
269  {
270  *reason = QString("deinterlacer %1 is not supported "
271  "w/renderer %2 (supported: %3)")
272  .arg(deint0).arg(renderer).arg(toCommaList(deints));
273  }
274 
275  return false;
276  }
277 
278  if (!deint1.isEmpty() &&
279  (!deints.contains(deint1) ||
280  deint1.contains("bobdeint") ||
281  deint1.contains("doublerate") ||
282  deint1.contains("doubleprocess")))
283  {
284  if (reason)
285  {
286  if (deint1.contains("bobdeint") ||
287  deint1.contains("doublerate") ||
288  deint1.contains("doubleprocess"))
289  deints.removeAll(deint1);
290 
291  *reason = QString("deinterlacer %1 is not supported w/renderer %2 "
292  "as second deinterlacer (supported: %3)")
293  .arg(deint1).arg(renderer).arg(toCommaList(deints));
294  }
295 
296  return false;
297  }
298 
299  QStringList osds = VideoDisplayProfile::GetOSDs(renderer);
300  QString osd = Get("pref_osdrenderer");
301  if (!osds.contains(osd))
302  {
303  if (reason)
304  {
305  *reason = QString("OSD Renderer %1 is not supported "
306  "w/renderer %2 (supported: %3)")
307  .arg(osd).arg(renderer).arg(toCommaList(osds));
308  }
309 
310  return false;
311  }
312 
313  QString filter = Get("pref_filters");
314  if (!filter.isEmpty() && !VideoDisplayProfile::IsFilterAllowed(renderer))
315  {
316  if (reason)
317  {
318  *reason = QString("Filter %1 is not supported w/renderer %2")
319  .arg(filter).arg(renderer);
320  }
321 
322  return false;
323  }
324 
325  if (reason)
326  *reason = QString();
327 
328  return true;
329 }
330 
331 bool ProfileItem::operator< (const ProfileItem &other) const
332 {
333  return GetPriority() < other.GetPriority();
334 }
335 
336 QString ProfileItem::toString(void) const
337 {
338  QString cmp0 = Get("pref_cmp0");
339  QString cmp1 = Get("pref_cmp1");
340  QString width = Get("cond_width");
341  QString height = Get("cond_height");
342  QString framerate = Get("cond_framerate");
343  QString codecs = Get("cond_codecs");
344  QString decoder = Get("pref_decoder");
345  uint max_cpus = Get("pref_max_cpus").toUInt();
346  bool skiploop = Get("pref_skiploop").toInt();
347  QString renderer = Get("pref_videorenderer");
348  QString osd = Get("pref_osdrenderer");
349  QString deint0 = Get("pref_deint0");
350  QString deint1 = Get("pref_deint1");
351  QString filter = Get("pref_filters");
352  bool osdfade = Get("pref_osdfade").toInt();
353 
354  QString cond = QString("w(%1) h(%2) framerate(%3) codecs(%4)")
355  .arg(width).arg(height).arg(framerate).arg(codecs);
356  QString str = QString("cmp(%1%2) %7 dec(%3) cpus(%4) skiploop(%5) rend(%6) ")
357  .arg(cmp0).arg(QString(cmp1.isEmpty() ? "" : ",") + cmp1)
358  .arg(decoder).arg(max_cpus).arg((skiploop) ? "enabled" : "disabled").arg(renderer)
359  .arg(cond);
360  str += QString("osd(%1) osdfade(%2) deint(%3,%4) filt(%5)")
361  .arg(osd).arg((osdfade) ? "enabled" : "disabled")
362  .arg(deint0).arg(deint1).arg(filter);
363 
364  return str;
365 }
366 
368 
369 #define LOC QString("VDP: ")
370 
371 QMutex VideoDisplayProfile::safe_lock(QMutex::Recursive);
382 
384  : lock(QMutex::Recursive), last_size(0,0), last_rate(0.0f)
385 {
386  QMutexLocker locker(&safe_lock);
387  init_statics();
388 
389  QString hostname = gCoreContext->GetHostName();
390  QString cur_profile = GetDefaultProfileName(hostname);
391  uint groupid = GetProfileGroupID(cur_profile, hostname);
392 
393  item_list_t items = LoadDB(groupid);
394  item_list_t::const_iterator it;
395  for (it = items.begin(); it != items.end(); ++it)
396  {
397  QString err;
398  if (!(*it).IsValid(&err))
399  {
400  LOG(VB_GENERAL, LOG_ERR, LOC + "Rejecting: " + (*it).toString() +
401  "\n\t\t\t" + err);
402 
403  continue;
404  }
405  LOG(VB_PLAYBACK, LOG_INFO, LOC + "Accepting: " + (*it).toString());
406  all_pref.push_back(*it);
407  }
408 }
409 
410 void VideoDisplayProfile::SetInput(const QSize &size,
411  float framerate, const QString &codecName)
412 {
413  QMutexLocker locker(&lock);
414  bool change = false;
415 
416  if (size != last_size)
417  {
418  last_size = size;
419  change = true;
420  }
421  if (framerate > 0.0f && framerate != last_rate)
422  {
423  last_rate = framerate;
424  change = true;
425  }
426  if (!codecName.isEmpty() && codecName != last_codecName)
427  {
428  last_codecName = codecName;
429  change = true;
430  }
431  if (change)
433 }
434 
435 void VideoDisplayProfile::SetOutput(float framerate)
436 {
437  QMutexLocker locker(&lock);
438  if (framerate != last_rate)
439  {
440  last_rate = framerate;
442  }
443 }
444 
445 void VideoDisplayProfile::SetVideoRenderer(const QString &video_renderer)
446 {
447  QMutexLocker locker(&lock);
448 
449  LOG(VB_PLAYBACK, LOG_INFO, LOC +
450  QString("SetVideoRenderer(%1)").arg(video_renderer));
451 
452  last_video_renderer = video_renderer;
453  if (video_renderer == GetVideoRenderer())
454  {
455  LOG(VB_PLAYBACK, LOG_INFO, LOC +
456  QString("SetVideoRender(%1) == GetVideoRenderer()")
457  .arg(video_renderer));
458  return; // already made preferences safe...
459  }
460 
461  // Make preferences safe...
462 
463  LOG(VB_PLAYBACK, LOG_INFO, LOC + "Old preferences: " + toString());
464 
465  SetPreference("pref_videorenderer", video_renderer);
466 
467  QStringList osds = GetOSDs(video_renderer);
468  if (!osds.contains(GetOSDRenderer()))
469  SetPreference("pref_osdrenderer", osds[0]);
470 
471  QStringList deints = GetDeinterlacers(video_renderer);
472  if (!deints.contains(GetDeinterlacer()))
473  SetPreference("pref_deint0", deints[0]);
474  if (!deints.contains(GetFallbackDeinterlacer()))
475  SetPreference("pref_deint1", deints[0]);
476  if (GetFallbackDeinterlacer().contains("bobdeint") ||
477  GetFallbackDeinterlacer().contains("doublerate") ||
478  GetFallbackDeinterlacer().contains("doubleprocess"))
479  {
480  SetPreference("pref_deint1", deints[1]);
481  }
482 
483  SetPreference("pref_filters", "");
484 
485  LOG(VB_PLAYBACK, LOG_INFO, LOC + "New preferences: " + toString());
486 }
487 
488 bool VideoDisplayProfile::CheckVideoRendererGroup(const QString &renderer)
489 {
490  if (last_video_renderer == renderer ||
491  last_video_renderer == "null")
492  return true;
493 
494  LOG(VB_PLAYBACK, LOG_INFO, LOC +
495  QString("Preferred video renderer: %1 (current: %2)")
496  .arg(renderer).arg(last_video_renderer));
497 
498  safe_map_t::const_iterator it = safe_renderer_group.begin();
499  for (; it != safe_renderer_group.end(); ++it)
500  if (it->contains(last_video_renderer) &&
501  it->contains(renderer))
502  return true;
503  return false;
504 }
505 
506 bool VideoDisplayProfile::IsDecoderCompatible(const QString &decoder)
507 {
508  const QString dec = GetDecoder();
509  if (dec == decoder)
510  return true;
511 
512  QMutexLocker locker(&safe_lock);
513  return (safe_equiv_dec[dec].contains(decoder));
514 }
515 
516 QString VideoDisplayProfile::GetFilteredDeint(const QString &override)
517 {
518  QString renderer = GetActualVideoRenderer();
519  QString deint = GetDeinterlacer();
520 
521  QMutexLocker locker(&lock);
522 
523  if (!override.isEmpty() && GetDeinterlacers(renderer).contains(override))
524  deint = override;
525 
526  LOG(VB_PLAYBACK, LOG_INFO,
527  LOC + QString("GetFilteredDeint(%1) : %2 -> '%3'")
528  .arg(override).arg(renderer).arg(deint));
529 
530  return deint;
531 }
532 
533 QString VideoDisplayProfile::GetPreference(const QString &key) const
534 {
535  QMutexLocker locker(&lock);
536 
537  if (key.isEmpty())
538  return QString();
539 
540  pref_map_t::const_iterator it = pref.find(key);
541  if (it == pref.end())
542  return QString();
543 
544  return *it;
545 }
546 
548  const QString &key, const QString &value)
549 {
550  QMutexLocker locker(&lock);
551 
552  if (!key.isEmpty())
553  {
554  pref[key] = value;
555  }
556 }
557 
558 item_list_t::const_iterator VideoDisplayProfile::FindMatch
559  (const QSize &size, float framerate, const QString &codecName)
560 {
561  item_list_t::const_iterator it = all_pref.begin();
562  for (; it != all_pref.end(); ++it)
563  {
564  if ((*it).IsMatch(size, framerate, codecName))
565  return it;
566  }
567 
568  return all_pref.end();
569 }
570 
572  (const QSize &size, float framerate, const QString &codecName)
573 {
574  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("LoadBestPreferences(%1x%2, %3, %4)")
575  .arg(size.width()).arg(size.height()).arg(framerate,0,'f',3).arg(codecName));
576 
577  pref.clear();
578  item_list_t::const_iterator it = FindMatch(size, framerate, codecName);
579  if (it != all_pref.end())
580  pref = (*it).GetAll();
581 
582  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("LoadBestPreferences Result "
583  "prio:%1, w:%2, h:%3, fps:%4,"
584  " codecs:%5, decoder:%6, renderer:%7, deint:%8")
585  .arg(GetPreference("pref_priority")).arg(GetPreference("cond_width"))
586  .arg(GetPreference("cond_height")).arg(GetPreference("cond_framerate"))
587  .arg(GetPreference("cond_codecs")).arg(GetPreference("pref_decoder"))
588  .arg(GetPreference("pref_videorenderer")).arg(GetPreference("pref_deint0"))
589  );
590 }
591 
593 // static methods
594 
596 {
598  item_list_t list;
599 
600  MSqlQuery query(MSqlQuery::InitCon());
601  query.prepare(
602  "SELECT profileid, value, data "
603  "FROM displayprofiles "
604  "WHERE profilegroupid = :GROUPID "
605  "ORDER BY profileid");
606  query.bindValue(":GROUPID", groupid);
607  if (!query.exec())
608  {
609  MythDB::DBError("loaddb 1", query);
610  return list;
611  }
612 
613  uint profileid = 0;
614  while (query.next())
615  {
616  if (query.value(0).toUInt() != profileid)
617  {
618  if (profileid)
619  {
620  tmp.SetProfileID(profileid);
621  QString error;
622  bool valid = tmp.IsValid(&error);
623  if (valid)
624  list.push_back(tmp);
625  else
626  LOG(VB_PLAYBACK, LOG_NOTICE, LOC +
627  QString("Ignoring profile item %1 (%2)")
628  .arg(profileid).arg(error));
629  }
630  tmp.Clear();
631  profileid = query.value(0).toUInt();
632  }
633  tmp.Set(query.value(1).toString(), query.value(2).toString());
634  }
635  if (profileid)
636  {
637  tmp.SetProfileID(profileid);
638  QString error;
639  bool valid = tmp.IsValid(&error);
640  if (valid)
641  list.push_back(tmp);
642  else
643  LOG(VB_PLAYBACK, LOG_NOTICE, LOC +
644  QString("Ignoring profile item %1 (%2)")
645  .arg(profileid).arg(error));
646  }
647 
648  sort(list.begin(), list.end());
649  return list;
650 }
651 
652 bool VideoDisplayProfile::DeleteDB(uint groupid, const item_list_t &items)
653 {
654  MSqlQuery query(MSqlQuery::InitCon());
655  query.prepare(
656  "DELETE FROM displayprofiles "
657  "WHERE profilegroupid = :GROUPID AND "
658  " profileid = :PROFILEID");
659 
660  bool ok = true;
661  item_list_t::const_iterator it = items.begin();
662  for (; it != items.end(); ++it)
663  {
664  if (!(*it).GetProfileID())
665  continue;
666 
667  query.bindValue(":GROUPID", groupid);
668  query.bindValue(":PROFILEID", (*it).GetProfileID());
669  if (!query.exec())
670  {
671  MythDB::DBError("vdp::deletedb", query);
672  ok = false;
673  }
674  }
675 
676  return ok;
677 }
678 
680 {
681  MSqlQuery query(MSqlQuery::InitCon());
682 
683  MSqlQuery update(MSqlQuery::InitCon());
684  update.prepare(
685  "UPDATE displayprofiles "
686  "SET data = :DATA "
687  "WHERE profilegroupid = :GROUPID AND "
688  " profileid = :PROFILEID AND "
689  " value = :VALUE");
690 
691  MSqlQuery insert(MSqlQuery::InitCon());
692  insert.prepare(
693  "INSERT INTO displayprofiles "
694  " ( profilegroupid, profileid, value, data) "
695  "VALUES "
696  " (:GROUPID, :PROFILEID, :VALUE, :DATA) ");
697 
698  MSqlQuery sqldelete(MSqlQuery::InitCon());
699  sqldelete.prepare(
700  "DELETE FROM displayprofiles "
701  "WHERE profilegroupid = :GROUPID AND "
702  " profileid = :PROFILEID AND "
703  " value = :VALUE");
704 
705  bool ok = true;
706  item_list_t::iterator it = items.begin();
707  for (; it != items.end(); ++it)
708  {
709  pref_map_t list = (*it).GetAll();
710  if (list.begin() == list.end())
711  continue;
712 
713  pref_map_t::const_iterator lit = list.begin();
714 
715  if (!(*it).GetProfileID())
716  {
717  // create new profileid
718  if (!query.exec("SELECT MAX(profileid) FROM displayprofiles"))
719  {
720  MythDB::DBError("save_profile 1", query);
721  ok = false;
722  continue;
723  }
724  else if (query.next())
725  {
726  (*it).SetProfileID(query.value(0).toUInt() + 1);
727  }
728 
729  for (; lit != list.end(); ++lit)
730  {
731  if ((*lit).isEmpty())
732  continue;
733 
734  insert.bindValue(":GROUPID", groupid);
735  insert.bindValue(":PROFILEID", (*it).GetProfileID());
736  insert.bindValue(":VALUE", lit.key());
737  insert.bindValue(":DATA", ((*lit).isNull()) ? "" : (*lit));
738  if (!insert.exec())
739  {
740  MythDB::DBError("save_profile 2", insert);
741  ok = false;
742  continue;
743  }
744  }
745  continue;
746  }
747 
748  for (; lit != list.end(); ++lit)
749  {
750  query.prepare(
751  "SELECT count(*) "
752  "FROM displayprofiles "
753  "WHERE profilegroupid = :GROUPID AND "
754  " profileid = :PROFILEID AND "
755  " value = :VALUE");
756  query.bindValue(":GROUPID", groupid);
757  query.bindValue(":PROFILEID", (*it).GetProfileID());
758  query.bindValue(":VALUE", lit.key());
759 
760  if (!query.exec())
761  {
762  MythDB::DBError("save_profile 3", query);
763  ok = false;
764  continue;
765  }
766  else if (query.next() && (1 == query.value(0).toUInt()))
767  {
768  if (lit->isEmpty())
769  {
770  sqldelete.bindValue(":GROUPID", groupid);
771  sqldelete.bindValue(":PROFILEID", (*it).GetProfileID());
772  sqldelete.bindValue(":VALUE", lit.key());
773  if (!sqldelete.exec())
774  {
775  MythDB::DBError("save_profile 5a", sqldelete);
776  ok = false;
777  continue;
778  }
779  }
780  else
781  {
782  update.bindValue(":GROUPID", groupid);
783  update.bindValue(":PROFILEID", (*it).GetProfileID());
784  update.bindValue(":VALUE", lit.key());
785  update.bindValue(":DATA", ((*lit).isNull()) ? "" : (*lit));
786  if (!update.exec())
787  {
788  MythDB::DBError("save_profile 5b", update);
789  ok = false;
790  continue;
791  }
792  }
793  }
794  else
795  {
796  insert.bindValue(":GROUPID", groupid);
797  insert.bindValue(":PROFILEID", (*it).GetProfileID());
798  insert.bindValue(":VALUE", lit.key());
799  insert.bindValue(":DATA", ((*lit).isNull()) ? "" : (*lit));
800  if (!insert.exec())
801  {
802  MythDB::DBError("save_profile 4", insert);
803  ok = false;
804  continue;
805  }
806  }
807  }
808  }
809 
810  return ok;
811 }
812 
814 {
815  init_statics();
816  return safe_decoders;
817 }
818 
820 {
821  init_statics();
822  QStringList list;
823 
824  const QStringList decs = GetDecoders();
825  QStringList::const_iterator it = decs.begin();
826  for (; it != decs.end(); ++it)
827  list += GetDecoderName(*it);
828 
829  return list;
830 }
831 
832 QString VideoDisplayProfile::GetDecoderName(const QString &decoder)
833 {
834  if (decoder.isEmpty())
835  return "";
836 
837  QMutexLocker locker(&safe_lock);
838  if (dec_name.empty())
839  {
840  dec_name["ffmpeg"] = QObject::tr("Standard");
841  dec_name["macaccel"] = QObject::tr("Mac hardware acceleration");
842  dec_name["vdpau"] = QObject::tr("NVidia VDPAU acceleration");
843  dec_name["vaapi"] = QObject::tr("VAAPI acceleration");
844  dec_name["dxva2"] = QObject::tr("Windows hardware acceleration");
845  dec_name["vda"] = QObject::tr("Mac VDA hardware acceleration");
846  dec_name["mediacodec"] = QObject::tr("Android MediaCodec decoder");
847  dec_name["vaapi2"] = QObject::tr("VAAPI2 acceleration");
848  }
849 
850  QString ret = decoder;
851  pref_map_t::const_iterator it = dec_name.find(decoder);
852  if (it != dec_name.end())
853  ret = *it;
854  return ret;
855 }
856 
857 
858 QString VideoDisplayProfile::GetDecoderHelp(QString decoder)
859 {
860  QString msg = QObject::tr("Processing method used to decode video.");
861 
862  if (decoder.isEmpty())
863  return msg;
864 
865  msg += "\n";
866 
867  if (decoder == "ffmpeg")
868  msg += QObject::tr("Standard will use ffmpeg library.");
869 
870  if (decoder == "macaccel")
871  msg += QObject::tr(
872  "Mac hardware will try to use the graphics "
873  "processor - this may hang or crash your Mac!");
874 
875  if (decoder == "vdpau")
876  msg += QObject::tr(
877  "VDPAU will attempt to use the graphics hardware to "
878  "accelerate video decoding and playback.");
879 
880  if (decoder == "dxva2")
881  msg += QObject::tr(
882  "DXVA2 will use the graphics hardware to "
883  "accelerate video decoding and playback "
884  "(requires Windows Vista or later).");
885 
886  if (decoder == "vaapi")
887  msg += QObject::tr(
888  "VAAPI will attempt to use the graphics hardware to "
889  "accelerate video decoding. REQUIRES OPENGL PAINTER.");
890 
891  if (decoder == "vda")
892  msg += QObject::tr(
893  "VDA will attempt to use the graphics hardware to "
894  "accelerate video decoding. "
895  "(H264 only, requires Mac OS 10.6.3)");
896 
897  if (decoder == "openmax")
898  msg += QObject::tr(
899  "Openmax will use the graphics hardware to "
900  "accelerate video decoding on Raspberry Pi. ");
901 
902  if (decoder == "mediacodec")
903  msg += QObject::tr(
904  "Mediacodec will use the graphics hardware to "
905  "accelerate video decoding on Android. ");
906 
907  if (decoder == "vaapi2")
908  msg += QObject::tr(
909  "VAAPI2 is a new implementation of VAAPI to will use the graphics hardware to "
910  "accelerate video decoding on Intel CPUs. ");
911 
912  return msg;
913 }
914 
915 QString VideoDisplayProfile::GetDeinterlacerName(const QString &short_name)
916 {
917  if ("none" == short_name)
918  return QObject::tr("None");
919  else if ("linearblend" == short_name)
920  return QObject::tr("Linear blend");
921  else if ("kerneldeint" == short_name)
922  return QObject::tr("Kernel");
923  else if ("kerneldoubleprocessdeint" == short_name)
924  return QObject::tr("Kernel (2x)");
925  else if ("greedyhdeint" == short_name)
926  return QObject::tr("Greedy HighMotion");
927  else if ("greedyhdoubleprocessdeint" == short_name)
928  return QObject::tr("Greedy HighMotion (2x)");
929  else if ("yadifdeint" == short_name)
930  return QObject::tr("Yadif");
931  else if ("yadifdoubleprocessdeint" == short_name)
932  return QObject::tr("Yadif (2x)");
933  else if ("bobdeint" == short_name)
934  return QObject::tr("Bob (2x)");
935  else if ("onefield" == short_name)
936  return QObject::tr("One field");
937  else if ("fieldorderdoubleprocessdeint" == short_name)
938  return QObject::tr("Interlaced (2x)");
939  else if ("opengllinearblend" == short_name)
940  return QObject::tr("Linear blend (HW-GL)");
941  else if ("openglkerneldeint" == short_name)
942  return QObject::tr("Kernel (HW-GL)");
943  else if ("openglbobdeint" == short_name)
944  return QObject::tr("Bob (2x, HW-GL)");
945  else if ("openglonefield" == short_name)
946  return QObject::tr("One field (HW-GL)");
947  else if ("opengldoubleratekerneldeint" == short_name)
948  return QObject::tr("Kernel (2x, HW-GL)");
949  else if ("opengldoubleratelinearblend" == short_name)
950  return QObject::tr("Linear blend (2x, HW-GL)");
951  else if ("opengldoubleratefieldorder" == short_name)
952  return QObject::tr("Interlaced (2x, HW-GL)");
953  else if ("vdpauonefield" == short_name)
954  return QObject::tr("One Field (1x, HW)");
955  else if ("vdpaubobdeint" == short_name)
956  return QObject::tr("Bob (2x, HW)");
957  else if ("vdpaubasic" == short_name)
958  return QObject::tr("Temporal (1x, HW)");
959  else if ("vdpaubasicdoublerate" == short_name)
960  return QObject::tr("Temporal (2x, HW)");
961  else if ("vdpauadvanced" == short_name)
962  return QObject::tr("Advanced (1x, HW)");
963  else if ("vdpauadvanceddoublerate" == short_name)
964  return QObject::tr("Advanced (2x, HW)");
965  else if ("vaapionefield" == short_name)
966  return QObject::tr("One Field (1x, HW)");
967  else if ("vaapibobdeint" == short_name)
968  return QObject::tr("Bob (2x, HW)");
969 #ifdef USING_OPENMAX
970  else if ("openmaxadvanced" == short_name)
971  return QObject::tr("Advanced (HW)");
972  else if ("openmaxfast" == short_name)
973  return QObject::tr("Fast (HW)");
974  else if ("openmaxlinedouble" == short_name)
975  return QObject::tr("Line double (HW)");
976 #endif // def USING_OPENMAX
977 #ifdef USING_VAAPI2
978  else if ("vaapi2default" == short_name)
979  return QObject::tr("Advanced (HW-VA)");
980  else if ("vaapi2bob" == short_name)
981  return QObject::tr("Bob (HW-VA)");
982  else if ("vaapi2weave" == short_name)
983  return QObject::tr("Weave (HW-VA)");
984  else if ("vaapi2motion_adaptive" == short_name)
985  return QObject::tr("Motion Adaptive (HW-VA)");
986  else if ("vaapi2motion_compensated" == short_name)
987  return QObject::tr("Motion Compensated (HW-VA)");
988  else if ("vaapi2doubleratedefault" == short_name)
989  return QObject::tr("Advanced (2x, HW-VA)");
990  else if ("vaapi2doubleratebob" == short_name)
991  return QObject::tr("Bob (2x, HW-VA)");
992  else if ("vaapi2doublerateweave" == short_name)
993  return QObject::tr("Weave (2x, HW-VA)");
994  else if ("vaapi2doubleratemotion_adaptive" == short_name)
995  return QObject::tr("Motion Adaptive (2x, HW-VA)");
996  else if ("vaapi2doubleratemotion_compensated" == short_name)
997  return QObject::tr("Motion Compensated (2x, HW-VA)");
998 #endif
999 
1000  return "";
1001 }
1002 
1003 QStringList VideoDisplayProfile::GetProfiles(const QString &hostname)
1004 {
1005  init_statics();
1006  QStringList list;
1007  MSqlQuery query(MSqlQuery::InitCon());
1008  query.prepare(
1009  "SELECT name "
1010  "FROM displayprofilegroups "
1011  "WHERE hostname = :HOST ");
1012  query.bindValue(":HOST", hostname);
1013  if (!query.exec() || !query.isActive())
1014  MythDB::DBError("get_profiles", query);
1015  else
1016  {
1017  while (query.next())
1018  list += query.value(0).toString();
1019  }
1020  return list;
1021 }
1022 
1024 {
1025  QString tmp =
1026  gCoreContext->GetSettingOnHost("DefaultVideoPlaybackProfile", hostname);
1027 
1028  QStringList profiles = GetProfiles(hostname);
1029 
1030  tmp = (profiles.contains(tmp)) ? tmp : QString();
1031 
1032  if (tmp.isEmpty())
1033  {
1034  if (profiles.size())
1035  tmp = profiles[0];
1036 
1037  tmp = (profiles.contains("Normal")) ? "Normal" : tmp;
1038 
1039  if (!tmp.isEmpty())
1040  {
1042  "DefaultVideoPlaybackProfile", tmp, hostname);
1043  }
1044  }
1045 
1046  return tmp;
1047 }
1048 
1050  const QString &profilename, const QString &hostname)
1051 {
1053  "DefaultVideoPlaybackProfile", profilename, hostname);
1054 }
1055 
1057  const QString &hostname)
1058 {
1059  MSqlQuery query(MSqlQuery::InitCon());
1060  query.prepare(
1061  "SELECT profilegroupid "
1062  "FROM displayprofilegroups "
1063  "WHERE name = :NAME AND "
1064  " hostname = :HOST ");
1065  query.bindValue(":NAME", profilename);
1066  query.bindValue(":HOST", hostname);
1067 
1068  if (!query.exec() || !query.isActive())
1069  MythDB::DBError("get_profile_group_id", query);
1070  else if (query.next())
1071  return query.value(0).toUInt();
1072 
1073  return 0;
1074 }
1075 
1077 {
1078  MSqlQuery query(MSqlQuery::InitCon());
1079  MSqlQuery query2(MSqlQuery::InitCon());
1080  query.prepare(
1081  "SELECT profilegroupid "
1082  "FROM displayprofilegroups "
1083  "WHERE hostname = :HOST ");
1084  query.bindValue(":HOST", hostname);
1085  if (!query.exec() || !query.isActive())
1086  MythDB::DBError("delete_profiles 1", query);
1087  else
1088  {
1089  while (query.next())
1090  {
1091  query2.prepare("DELETE FROM displayprofiles "
1092  "WHERE profilegroupid = :PROFID");
1093  query2.bindValue(":PROFID", query.value(0).toUInt());
1094  if (!query2.exec())
1095  MythDB::DBError("delete_profiles 2", query2);
1096  }
1097  }
1098  query.prepare("DELETE FROM displayprofilegroups WHERE hostname = :HOST");
1099  query.bindValue(":HOST", hostname);
1100  if (!query.exec() || !query.isActive())
1101  MythDB::DBError("delete_profiles 3", query);
1102 }
1103 
1104 //displayprofilegroups pk(name, hostname), uk(profilegroupid)
1105 //displayprofiles k(profilegroupid), k(profileid), value, data
1106 
1107 // Old style
1109  uint groupid, uint priority,
1110  QString cmp0, uint width0, uint height0,
1111  QString cmp1, uint width1, uint height1,
1112  QString decoder, uint max_cpus, bool skiploop, QString videorenderer,
1113  QString osdrenderer, bool osdfade,
1114  QString deint0, QString deint1, QString filters)
1115 {
1116  QString width;
1117  QString height;
1118  if (!cmp0.isEmpty()
1119  && ! (cmp0 == ">" && width0 == 0 && height0 == 0))
1120  {
1121  width.append(QString("%1%2").arg(cmp0).arg(width0));
1122  height.append(QString("%1%2").arg(cmp0).arg(height0));
1123  if (!cmp1.isEmpty())
1124  {
1125  width.append("&");
1126  height.append("&");
1127  }
1128  }
1129  if (!cmp1.isEmpty()
1130  && ! (cmp1 == ">" && width1 == 0 && height1 == 0))
1131  {
1132  width.append(QString("%1%2").arg(cmp1).arg(width1));
1133  height.append(QString("%1%2").arg(cmp1).arg(height1));
1134  }
1135  CreateProfile(
1136  groupid, priority,
1137  width, height, QString(),
1138  decoder, max_cpus, skiploop, videorenderer,
1139  osdrenderer, osdfade,
1140  deint0, deint1, filters);
1141 }
1142 
1143 // New Style
1145  uint groupid, uint priority,
1146  QString width, QString height, QString codecs,
1147  QString decoder, uint max_cpus, bool skiploop, QString videorenderer,
1148  QString osdrenderer, bool osdfade,
1149  QString deint0, QString deint1, QString filters)
1150 {
1151  MSqlQuery query(MSqlQuery::InitCon());
1152 
1153  // create new profileid
1154  uint profileid = 1;
1155  if (!query.exec("SELECT MAX(profileid) FROM displayprofiles"))
1156  MythDB::DBError("create_profile 1", query);
1157  else if (query.next())
1158  profileid = query.value(0).toUInt() + 1;
1159 
1160  query.prepare(
1161  "INSERT INTO displayprofiles "
1162  "VALUES (:GRPID, :PROFID, 'pref_priority', :PRIORITY)");
1163  query.bindValue(":GRPID", groupid);
1164  query.bindValue(":PROFID", profileid);
1165  query.bindValue(":PRIORITY", priority);
1166  if (!query.exec())
1167  MythDB::DBError("create_profile 2", query);
1168 
1169  QStringList queryValue;
1170  QStringList queryData;
1171 
1172  queryValue += "cond_width";
1173  queryData += width;
1174 
1175  queryValue += "cond_height";
1176  queryData += height;
1177 
1178  queryValue += "cond_codecs";
1179  queryData += codecs;
1180 
1181  queryValue += "pref_decoder";
1182  queryData += decoder;
1183 
1184  queryValue += "pref_max_cpus";
1185  queryData += QString::number(max_cpus);
1186 
1187  queryValue += "pref_skiploop";
1188  queryData += (skiploop) ? "1" : "0";
1189 
1190  queryValue += "pref_videorenderer";
1191  queryData += videorenderer;
1192 
1193  queryValue += "pref_osdrenderer";
1194  queryData += osdrenderer;
1195 
1196  queryValue += "pref_osdfade";
1197  queryData += (osdfade) ? "1" : "0";
1198 
1199  queryValue += "pref_deint0";
1200  queryData += deint0;
1201 
1202  queryValue += "pref_deint1";
1203  queryData += deint1;
1204 
1205  queryValue += "pref_filters";
1206  queryData += filters;
1207 
1208  QStringList::const_iterator itV = queryValue.begin();
1209  QStringList::const_iterator itD = queryData.begin();
1210  for (; itV != queryValue.end() && itD != queryData.end(); ++itV,++itD)
1211  {
1212  if (itD->isEmpty())
1213  continue;
1214  query.prepare(
1215  "INSERT INTO displayprofiles "
1216  "VALUES (:GRPID, :PROFID, :VALUE, :DATA)");
1217  query.bindValue(":GRPID", groupid);
1218  query.bindValue(":PROFID", profileid);
1219  query.bindValue(":VALUE", *itV);
1220  query.bindValue(":DATA", *itD);
1221  if (!query.exec())
1222  MythDB::DBError("create_profile 3", query);
1223  }
1224 }
1225 
1227  const QString &profilename, const QString &hostname)
1228 {
1229  MSqlQuery query(MSqlQuery::InitCon());
1230  query.prepare(
1231  "INSERT INTO displayprofilegroups (name, hostname) "
1232  "VALUES (:NAME,:HOST)");
1233 
1234  query.bindValue(":NAME", profilename);
1235  query.bindValue(":HOST", hostname);
1236 
1237  if (!query.exec())
1238  {
1239  MythDB::DBError("create_profile_group", query);
1240  return 0;
1241  }
1242 
1243  return GetProfileGroupID(profilename, hostname);
1244 }
1245 
1247  const QString &groupname, const QString &hostname)
1248 {
1249  bool ok = true;
1250  MSqlQuery query(MSqlQuery::InitCon());
1251  MSqlQuery query2(MSqlQuery::InitCon());
1252 
1253  query.prepare(
1254  "SELECT profilegroupid "
1255  "FROM displayprofilegroups "
1256  "WHERE name = :NAME AND "
1257  " hostname = :HOST ");
1258 
1259  query.bindValue(":NAME", groupname);
1260  query.bindValue(":HOST", hostname);
1261 
1262  if (!query.exec() || !query.isActive())
1263  {
1264  MythDB::DBError("delete_profile_group 1", query);
1265  ok = false;
1266  }
1267  else
1268  {
1269  while (query.next())
1270  {
1271  query2.prepare("DELETE FROM displayprofiles "
1272  "WHERE profilegroupid = :PROFID");
1273  query2.bindValue(":PROFID", query.value(0).toUInt());
1274  if (!query2.exec())
1275  {
1276  MythDB::DBError("delete_profile_group 2", query2);
1277  ok = false;
1278  }
1279  }
1280  }
1281 
1282  query.prepare(
1283  "DELETE FROM displayprofilegroups "
1284  "WHERE name = :NAME AND "
1285  " hostname = :HOST");
1286 
1287  query.bindValue(":NAME", groupname);
1288  query.bindValue(":HOST", hostname);
1289 
1290  if (!query.exec())
1291  {
1292  MythDB::DBError("delete_profile_group 3", query);
1293  ok = false;
1294  }
1295 
1296  return ok;
1297 }
1298 
1300 {
1301  QStringList profiles = GetProfiles(hostname);
1302  uint groupid;
1303 
1304 #ifdef USING_XV
1305  if (!profiles.contains("High Quality")) {
1306  (void) QObject::tr("High Quality", "Sample: high quality");
1307  groupid = CreateProfileGroup("High Quality", hostname);
1308  CreateProfile(groupid, 1, ">=", 1920, 1080, "", 0, 0,
1309  "ffmpeg", 2, true, "xv-blit", "softblend", true,
1310  "linearblend", "linearblend", "");
1311  CreateProfile(groupid, 2, ">", 0, 0, "", 0, 0,
1312  "ffmpeg", 1, true, "xv-blit", "softblend", true,
1313  "yadifdoubleprocessdeint", "yadifdeint", "");
1314  }
1315 
1316  if (!profiles.contains("Normal")) {
1317  (void) QObject::tr("Normal", "Sample: average quality");
1318  groupid = CreateProfileGroup("Normal", hostname);
1319  CreateProfile(groupid, 1, ">=", 1280, 720, "", 0, 0,
1320  "ffmpeg", 1, true, "xv-blit", "softblend", false,
1321  "linearblend", "linearblend", "");
1322  CreateProfile(groupid, 2, ">", 0, 0, "", 0, 0,
1323  "ffmpeg", 1, true, "xv-blit", "softblend", true,
1324  "greedyhdoubleprocessdeint", "kerneldeint", "");
1325  }
1326 
1327  if (!profiles.contains("Slim")) {
1328  (void) QObject::tr("Slim", "Sample: low CPU usage");
1329  groupid = CreateProfileGroup("Slim", hostname);
1330  CreateProfile(groupid, 1, ">=", 1280, 720, "", 0, 0,
1331  "ffmpeg", 1, true, "xv-blit", "softblend", false,
1332  "onefield", "onefield", "");
1333  CreateProfile(groupid, 2, ">", 0, 0, "", 0, 0,
1334  "ffmpeg", 1, true, "xv-blit", "softblend", false,
1335  "linearblend", "linearblend", "");
1336  }
1337 #endif
1338 
1339 #ifdef USING_VDPAU
1340  if (!profiles.contains("VDPAU High Quality")) {
1341  (void) QObject::tr("VDPAU High Quality", "Sample: VDPAU high quality");
1342  groupid = CreateProfileGroup("VDPAU High Quality", hostname);
1343  CreateProfile(groupid, 1, ">", 0, 0, "", 0, 0,
1344  "vdpau", 1, true, "vdpau", "vdpau", true,
1345  "vdpauadvanceddoublerate", "vdpauadvanced",
1346  "vdpaucolorspace=auto");
1347  }
1348 
1349  if (!profiles.contains("VDPAU Normal")) {
1350  (void) QObject::tr("VDPAU Normal", "Sample: VDPAU average quality");
1351  groupid = CreateProfileGroup("VDPAU Normal", hostname);
1352  CreateProfile(groupid, 1, ">=", 0, 720, "", 0, 0,
1353  "vdpau", 1, true, "vdpau", "vdpau", true,
1354  "vdpaubasicdoublerate", "vdpaubasic",
1355  "vdpaucolorspace=auto");
1356  CreateProfile(groupid, 2, ">", 0, 0, "", 0, 0,
1357  "vdpau", 1, true, "vdpau", "vdpau", true,
1358  "vdpauadvanceddoublerate", "vdpauadvanced",
1359  "vdpaucolorspace=auto");
1360  }
1361 
1362  if (!profiles.contains("VDPAU Slim")) {
1363  (void) QObject::tr("VDPAU Slim", "Sample: VDPAU low power GPU");
1364  groupid = CreateProfileGroup("VDPAU Slim", hostname);
1365  CreateProfile(groupid, 1, ">", 0, 0, "", 0, 0,
1366  "vdpau", 1, true, "vdpau", "vdpau", true,
1367  "vdpaubobdeint", "vdpauonefield",
1368  "vdpauskipchroma,vdpaucolorspace=auto");
1369  }
1370 #endif
1371 
1372 #if defined(Q_OS_MACX)
1373  if (!profiles.contains("VDA High Quality")) {
1374  (void) QObject::tr("VDA High Quality", "Sample: VDA high quality");
1375  groupid = CreateProfileGroup("VDA High Quality", hostname);
1376  CreateProfile(groupid, 1, ">", 0, 0, "", 0, 0,
1377  "vda", 2, true, "opengl", "opengl2", true,
1378  "greedyhdoubleprocessdeint", "greedyhdeint",
1379  "");
1380  CreateProfile(groupid, 1, ">", 0, 0, "", 0, 0,
1381  "ffmpeg", 2, true, "opengl", "opengl2", true,
1382  "greedyhdoubleprocessdeint", "greedyhdeint",
1383  "");
1384  }
1385 
1386  if (!profiles.contains("VDA Normal")) {
1387  (void) QObject::tr("VDA Normal", "Sample: VDA average quality");
1388  groupid = CreateProfileGroup("VDA Normal", hostname);
1389  CreateProfile(groupid, 1, ">", 0, 0, "", 0, 0,
1390  "vda", 2, true, "opengl", "opengl2", true,
1391  "opengldoubleratekerneldeint", "openglkerneldeint",
1392  "");
1393  CreateProfile(groupid, 2, ">", 0, 0, "", 0, 0,
1394  "ffmpeg", 2, true, "opengl", "opengl2", true,
1395  "opengldoubleratekerneldeint", "openglkerneldeint",
1396  "");
1397  }
1398 
1399  if (!profiles.contains("VDA Slim")) {
1400  (void) QObject::tr("VDA Slim", "Sample: VDA low power GPU");
1401  groupid = CreateProfileGroup("VDA Slim", hostname);
1402  CreateProfile(groupid, 1, ">", 0, 0, "", 0, 0,
1403  "vda", 2, true, "opengl", "opengl2", true,
1404  "opengldoubleratelinearblend", "opengllinearblend",
1405  "");
1406  CreateProfile(groupid, 2, ">", 0, 0, "", 0, 0,
1407  "ffmpeg", 2, true, "opengl", "opengl2", true,
1408  "opengldoubleratelinearblend", "opengllinearblend",
1409  "");
1410  }
1411 #endif
1412 
1413 #ifdef USING_OPENGL_VIDEO
1414  if (!profiles.contains("OpenGL High Quality")) {
1415  (void) QObject::tr("OpenGL High Quality",
1416  "Sample: OpenGL high quality");
1417  groupid = CreateProfileGroup("OpenGL High Quality", hostname);
1418  CreateProfile(groupid, 1, ">", 0, 0, "", 0, 0,
1419  "ffmpeg", 2, true, "opengl", "opengl2", true,
1420  "greedyhdoubleprocessdeint", "greedyhdeint",
1421  "");
1422  }
1423 
1424  if (!profiles.contains("OpenGL Normal")) {
1425  (void) QObject::tr("OpenGL Normal", "Sample: OpenGL average quality");
1426  groupid = CreateProfileGroup("OpenGL Normal", hostname);
1427  CreateProfile(groupid, 1, ">", 0, 0, "", 0, 0,
1428  "ffmpeg", 2, true, "opengl", "opengl2", true,
1429  "opengldoubleratekerneldeint", "openglkerneldeint",
1430  "");
1431  }
1432 
1433  if (!profiles.contains("OpenGL Slim")) {
1434  (void) QObject::tr("OpenGL Slim", "Sample: OpenGL low power GPU");
1435  groupid = CreateProfileGroup("OpenGL Slim", hostname);
1436  CreateProfile(groupid, 1, ">", 0, 0, "", 0, 0,
1437  "ffmpeg", 1, true, "opengl", "opengl2", true,
1438  "opengldoubleratelinearblend", "opengllinearblend",
1439  "");
1440  }
1441 #endif
1442 
1443 #ifdef USING_GLVAAPI
1444  if (!profiles.contains("VAAPI Normal")) {
1445  (void) QObject::tr("VAAPI Normal", "Sample: VAAPI average quality");
1446  groupid = CreateProfileGroup("VAAPI Normal", hostname);
1447  CreateProfile(groupid, 1, ">", 0, 0, "", 0, 0,
1448  "vaapi", 2, true, "openglvaapi", "opengl2", true,
1449  "vaapibobdeint", "vaapionefield",
1450  "");
1451  CreateProfile(groupid, 2, ">", 0, 0, "", 0, 0,
1452  "ffmpeg", 2, true, "opengl", "opengl2", true,
1453  "opengldoubleratekerneldeint", "openglkerneldeint",
1454  "");
1455  }
1456 #endif
1457 
1458 #ifdef USING_OPENMAX
1459 #ifdef USING_OPENGLES
1460  if (!profiles.contains("OpenMAX High Quality")) {
1461  (void) QObject::tr("OpenMAX High Quality",
1462  "Sample: OpenMAX High Quality");
1463  groupid = CreateProfileGroup("OpenMAX High Quality", hostname);
1464  CreateProfile(groupid, 1, ">", 0, 0, "", 0, 0,
1465  "openmax", 4, true, "openmax", "opengl", true,
1466  "openmaxadvanced", "onefield",
1467  "");
1468  }
1469 #endif
1470 
1471  if (!profiles.contains("OpenMAX Normal")) {
1472  (void) QObject::tr("OpenMAX Normal", "Sample: OpenMAX Normal");
1473  groupid = CreateProfileGroup("OpenMAX Normal", hostname);
1474  CreateProfile(groupid, 1, ">", 0, 0, "", 0, 0,
1475  "openmax", 4, true, "openmax", "softblend", false,
1476  "openmaxadvanced", "onefield",
1477  "");
1478  }
1479 #endif
1480 
1481 #ifdef USING_MEDIACODEC
1482  if (!profiles.contains("MediaCodec Normal")) {
1483  (void) QObject::tr("MediaCodec Normal",
1484  "Sample: MediaCodec Normal");
1485  groupid = CreateProfileGroup("MediaCodec Normal", hostname);
1486  CreateProfile(groupid, 1, "", "", "",
1487  "mediacodec", 4, true, "opengl",
1488  "opengl2", true,
1489  "opengldoubleratelinearblend", "opengllinearblend",
1490  "");
1491  }
1492 #endif
1493 
1494 #if defined(USING_VAAPI2) && defined(USING_OPENGL_VIDEO)
1495  if (!profiles.contains("VAAPI2 Normal")) {
1496  (void) QObject::tr("VAAPI2 Normal",
1497  "Sample: VAAPI2 Normal");
1498  groupid = CreateProfileGroup("VAAPI2 Normal", hostname);
1499  CreateProfile(groupid, 1, "", "", "",
1500  "vaapi2", 4, true, "opengl",
1501  "opengl2", true,
1502  "vaapi2doubleratedefault", "vaapi2default",
1503  "");
1504  }
1505 #endif
1506 
1507 }
1508 
1509 QStringList VideoDisplayProfile::GetVideoRenderers(const QString &decoder)
1510 {
1511  QMutexLocker locker(&safe_lock);
1512  init_statics();
1513 
1514  safe_map_t::const_iterator it = safe_renderer.find(decoder);
1515  QStringList tmp;
1516  if (it != safe_renderer.end())
1517  tmp = *it;
1518  return tmp;
1519 }
1520 
1521 QString VideoDisplayProfile::GetVideoRendererHelp(const QString &renderer)
1522 {
1523  QString msg = QObject::tr("Video rendering method");
1524 
1525  if (renderer.isEmpty())
1526  return msg;
1527 
1528  if ((renderer == "null") || (renderer == "nullvaapi") ||
1529  (renderer == "nullvdpau"))
1530  msg = QObject::tr(
1531  "Render video offscreen. Used internally.");
1532 
1533  if (renderer == "xlib")
1534  msg = QObject::tr(
1535  "Use X11 pixel copy to render video. This is not recommended if "
1536  "any other option is available. The video will not be scaled to "
1537  "fit the screen. This will work with all X11 servers, local "
1538  "and remote.");
1539 
1540  if (renderer == "xshm")
1541  msg = QObject::tr(
1542  "Use X11 shared memory pixel transfer to render video. This is "
1543  "only recommended over the X11 pixel copy renderer. The video "
1544  "will not be scaled to fit the screen. This works with most "
1545  "local X11 servers.");
1546 
1547  if (renderer == "xv-blit")
1548  msg = QObject::tr(
1549  "This is the standard video renderer for X11 systems. It uses "
1550  "XVideo hardware assist for scaling, color conversion. If the "
1551  "hardware offers picture controls the renderer supports them.");
1552 
1553  if (renderer == "direct3d")
1554  msg = QObject::tr(
1555  "Windows video renderer based on Direct3D. Requires "
1556  "video card compatible with Direct3D 9. This is the preferred "
1557  "renderer for current Windows systems.");
1558 
1559  if (renderer == "opengl")
1560  {
1561  msg = QObject::tr(
1562  "Video is converted to an intermediate format by the CPU (UYVY) "
1563  "before OpenGL is used for color conversion, scaling, picture controls"
1564  " and optionally deinterlacing. Processing is balanced between the CPU"
1565  "and GPU.");
1566  }
1567 
1568  if (renderer == "opengl-lite")
1569  msg = QObject::tr(
1570  "OpenGL is used for scaling and color conversion. "
1571  "It uses faster OpenGL functionality when available but at the "
1572  "expense of picture controls and GPU based deinterlacing.");
1573 
1574  if (renderer == "opengl-yv12")
1575  {
1576  msg = QObject::tr(
1577  "OpenGL is used for all color conversion, scaling, picture "
1578  "controls and optionally deinterlacing. CPU load is low but a more "
1579  "powerful GPU is needed for deinterlacing.");
1580  }
1581 
1582  if (renderer == "opengl-hquyv")
1583  {
1584  msg = QObject::tr(
1585  "This renderer uses a higher quality CPU conversion for interlaced "
1586  "content before using OpenGL for color conversion, scaling, picture"
1587  " controls and optionally deinterlacing. CPU load is higher "
1588  "particularly on embedded systems.");
1589  }
1590 
1591  if (renderer == "opengl-rgba")
1592  {
1593  msg = QObject::tr(
1594  "All video processing is performed by the CPU. OpenGL is used "
1595  "for display only. Does not support picture controls or GPU "
1596  "deinterlacing. Requires a significantly faster CPU.");
1597  }
1598 
1599  if (renderer == "vdpau")
1600  {
1601  msg = QObject::tr(
1602  "This is the only video renderer for NVidia VDPAU decoding.");
1603  }
1604 
1605  if (renderer == "openglvaapi")
1606  {
1607  msg = QObject::tr(
1608  "This video renderer uses VAAPI for video decoding and "
1609  "OpenGL for scaling and color conversion.");
1610  }
1611 
1612  return msg;
1613 }
1614 
1615 QString VideoDisplayProfile::GetPreferredVideoRenderer(const QString &decoder)
1616 {
1617  return GetBestVideoRenderer(GetVideoRenderers(decoder));
1618 }
1619 
1621  const QString &video_renderer)
1622 {
1623  QMutexLocker locker(&safe_lock);
1624  init_statics();
1625 
1626  safe_map_t::const_iterator it = safe_deint.find(video_renderer);
1627  QStringList tmp;
1628  if (it != safe_deint.end())
1629  tmp = *it;
1630  return tmp;
1631 }
1632 
1633 QString VideoDisplayProfile::GetDeinterlacerHelp(const QString &deint)
1634 {
1635  if (deint.isEmpty())
1636  return "";
1637 
1638  QString msg = "";
1639 
1640  QString kDoubleRateMsg =
1641  QObject::tr(
1642  "This deinterlacer requires the display to be capable "
1643  "of twice the frame rate as the source video.");
1644 
1645  QString kNoneMsg =
1646  QObject::tr("Perform no deinterlacing.") + " " +
1647  QObject::tr(
1648  "Use this with an interlaced display whose "
1649  "resolution exactly matches the video size. "
1650  "This is incompatible with MythTV zoom modes.");
1651 
1652  QString kOneFieldMsg = QObject::tr(
1653  "Shows only one of the two fields in the frame. "
1654  "This looks good when displaying a high motion "
1655  "1080i video on a 720p display.");
1656 
1657  QString kBobMsg = QObject::tr(
1658  "Shows one field of the frame followed by the "
1659  "other field displaced vertically.") + " " +
1660  kDoubleRateMsg;
1661 
1662  QString kLinearBlendMsg = QObject::tr(
1663  "Blends the odd and even fields linearly into one frame.");
1664 
1665  QString kKernelMsg = QObject::tr(
1666  "This filter disables deinterlacing when the two fields are "
1667  "similar, and performs linear deinterlacing otherwise.");
1668 
1669  QString kUsingGPU = QObject::tr("(Hardware Accelerated)");
1670 
1671  QString kUsingVA = QObject::tr("(VAAPI Hardware Accelerated)");
1672 
1673  QString kUsingGL = QObject::tr("(OpenGL Hardware Accelerated)");
1674 
1675  QString kGreedyHMsg = QObject::tr(
1676  "This deinterlacer uses several fields to reduce motion blur. "
1677  "It has increased CPU requirements.");
1678 
1679  QString kYadifMsg = QObject::tr(
1680  "This deinterlacer uses several fields to reduce motion blur. "
1681  "It has increased CPU requirements.");
1682 
1683  QString kFieldOrderMsg = QObject::tr(
1684  "This deinterlacer attempts to synchronize with interlaced displays "
1685  "whose size and refresh rate exactly match the video source. "
1686  "It has low CPU requirements.");
1687 
1688  QString kBasicMsg = QObject::tr(
1689  "This deinterlacer uses several fields to reduce motion blur. ");
1690 
1691  QString kAdvMsg = QObject::tr(
1692  "This deinterlacer uses multiple fields to reduce motion blur "
1693  "and smooth edges. ");
1694 
1695  QString kMostAdvMsg = QObject::tr(
1696  "Use the most advanced hardware deinterlacing algorithm available. ");
1697 
1698  QString kWeaveMsg = QObject::tr(
1699  "Use the weave deinterlacing algorithm. ");
1700 
1701  QString kMAMsg = QObject::tr(
1702  "Use the motion adaptive deinterlacing algorithm. ");
1703 
1704  QString kMCMsg = QObject::tr(
1705  "Use the motion compensated deinterlacing algorithm. ");
1706 
1707  if (deint == "none")
1708  msg = kNoneMsg;
1709  else if (deint == "onefield")
1710  msg = kOneFieldMsg;
1711  else if (deint == "bobdeint")
1712  msg = kBobMsg;
1713  else if (deint == "linearblend")
1714  msg = kLinearBlendMsg;
1715  else if (deint == "kerneldeint")
1716  msg = kKernelMsg;
1717  else if (deint == "kerneldoubleprocessdeint")
1718  msg = kKernelMsg + " " + kDoubleRateMsg;
1719  else if (deint == "openglonefield")
1720  msg = kOneFieldMsg + " " + kUsingGL;
1721  else if (deint == "openglbobdeint")
1722  msg = kBobMsg + " " + kUsingGL;
1723  else if (deint == "opengllinearblend")
1724  msg = kLinearBlendMsg + " " + kUsingGL;
1725  else if (deint == "openglkerneldeint")
1726  msg = kKernelMsg + " " + kUsingGL;
1727  else if (deint == "opengldoubleratelinearblend")
1728  msg = kLinearBlendMsg + " " + kDoubleRateMsg + " " + kUsingGL;
1729  else if (deint == "opengldoubleratekerneldeint")
1730  msg = kKernelMsg + " " + kDoubleRateMsg + " " + kUsingGL;
1731  else if (deint == "opengldoubleratefieldorder")
1732  msg = kFieldOrderMsg + " " + kDoubleRateMsg + " " + kUsingGL;
1733  else if (deint == "greedyhdeint")
1734  msg = kGreedyHMsg;
1735  else if (deint == "greedyhdoubleprocessdeint")
1736  msg = kGreedyHMsg + " " + kDoubleRateMsg;
1737  else if (deint == "yadifdeint")
1738  msg = kYadifMsg;
1739  else if (deint == "yadifdoubleprocessdeint")
1740  msg = kYadifMsg + " " + kDoubleRateMsg;
1741  else if (deint == "fieldorderdoubleprocessdeint")
1742  msg = kFieldOrderMsg + " " + kDoubleRateMsg;
1743  else if (deint == "vdpauonefield")
1744  msg = kOneFieldMsg + " " + kUsingGPU;
1745  else if (deint == "vdpaubobdeint")
1746  msg = kBobMsg + " " + kUsingGPU;
1747  else if (deint == "vdpaubasic")
1748  msg = kBasicMsg + " " + kUsingGPU;
1749  else if (deint == "vdpauadvanced")
1750  msg = kAdvMsg + " " + kUsingGPU;
1751  else if (deint == "vdpaubasicdoublerate")
1752  msg = kBasicMsg + " " + kDoubleRateMsg + " " + kUsingGPU;
1753  else if (deint == "vdpauadvanceddoublerate")
1754  msg = kAdvMsg + " " + kDoubleRateMsg + " " + kUsingGPU;
1755  else if (deint == "vaapionefield")
1756  msg = kOneFieldMsg + " " + kUsingGPU;
1757  else if (deint == "vaapibobdeint")
1758  msg = kBobMsg + " " + kUsingGPU;
1759 
1760  else if (deint == "vaapi2default")
1761  msg = kMostAdvMsg + " " + kUsingVA;
1762  else if (deint == "vaapi2bob")
1763  msg = kBobMsg + " " + kUsingVA;
1764  else if (deint == "vaapi2weave")
1765  msg = kWeaveMsg + " " + kUsingVA;
1766  else if (deint == "vaapi2motion_adaptive")
1767  msg = kMAMsg + " " + kUsingVA;
1768  else if (deint == "vaapi2motion_compensated")
1769  msg = kMCMsg + " " + kUsingVA;
1770  else if (deint == "vaapi2doubleratedefault")
1771  msg = kMostAdvMsg + " " + kDoubleRateMsg + " " + kUsingVA;
1772  else if (deint == "vaapi2doubleratebob")
1773  msg = kBobMsg + " " + kDoubleRateMsg + " " + kUsingVA;
1774  else if (deint == "vaapi2doublerateweave")
1775  msg = kWeaveMsg + " " + kDoubleRateMsg + " " + kUsingVA;
1776  else if (deint == "vaapi2doubleratemotion_adaptive")
1777  msg = kMAMsg + " " + kDoubleRateMsg + " " + kUsingVA;
1778  else if (deint == "vaapi2doubleratemotion_compensated")
1779  msg = kMCMsg + " " + kDoubleRateMsg + " " + kUsingVA;
1780  else
1781  msg = QObject::tr("'%1' has not been documented yet.").arg(deint);
1782 
1783  return msg;
1784 }
1785 
1786 QStringList VideoDisplayProfile::GetOSDs(const QString &video_renderer)
1787 {
1788  QMutexLocker locker(&safe_lock);
1789  init_statics();
1790 
1791  safe_map_t::const_iterator it = safe_osd.find(video_renderer);
1792  QStringList tmp;
1793  if (it != safe_osd.end())
1794  tmp = *it;
1795  return tmp;
1796 }
1797 
1798 QString VideoDisplayProfile::GetOSDHelp(const QString &osd)
1799 {
1800 
1801  QString msg = QObject::tr("OSD rendering method");
1802 
1803  if (osd.isEmpty())
1804  return msg;
1805 
1806  if (osd == "chromakey")
1807  msg = QObject::tr(
1808  "Render the OSD using the XVideo chromakey feature."
1809  "This renderer does not alpha blend but is the fastest "
1810  "OSD renderer for XVideo.") + "\n" +
1811  QObject::tr(
1812  "Note: nVidia hardware after the 5xxx series does not "
1813  "have XVideo chromakey support.");
1814 
1815 
1816  if (osd == "softblend")
1817  {
1818  msg = QObject::tr(
1819  "Software OSD rendering uses your CPU to alpha blend the OSD.");
1820  }
1821 
1822  if (osd.contains("opengl"))
1823  {
1824  msg = QObject::tr(
1825  "Uses OpenGL to alpha blend the OSD onto the video.");
1826  }
1827 
1828  if (osd =="threaded")
1829  {
1830  msg = QObject::tr(
1831  "Uses OpenGL in a separate thread to overlay the OSD onto the video.");
1832  }
1833 
1834 #ifdef USING_OPENMAX
1835  if (osd.contains("openmax"))
1836  {
1837  msg = QObject::tr(
1838  "Uses OpenMAX to alpha blend the OSD onto the video.");
1839  }
1840 #endif
1841 
1842  return msg;
1843 }
1844 
1845 bool VideoDisplayProfile::IsFilterAllowed(const QString &video_renderer)
1846 {
1847  QMutexLocker locker(&safe_lock);
1848  init_statics();
1849  return safe_custom.contains(video_renderer);
1850 }
1851 
1853  const QString &decoder, const QStringList &renderers)
1854 {
1855  const QStringList dec_list = GetVideoRenderers(decoder);
1856  QStringList new_list;
1857 
1858  QStringList::const_iterator it = dec_list.begin();
1859  for (; it != dec_list.end(); ++it)
1860  {
1861  if (renderers.contains(*it))
1862  new_list.push_back(*it); // deep copy not needed
1863  }
1864 
1865  return new_list;
1866 }
1867 
1868 QString VideoDisplayProfile::GetBestVideoRenderer(const QStringList &renderers)
1869 {
1870  QMutexLocker locker(&safe_lock);
1871  init_statics();
1872 
1873  uint top_priority = 0;
1874  QString top_renderer;
1875 
1876  QStringList::const_iterator it = renderers.begin();
1877  for (; it != renderers.end(); ++it)
1878  {
1879  priority_map_t::const_iterator p = safe_renderer_priority.find(*it);
1880  if ((p != safe_renderer_priority.end()) && (*p >= top_priority))
1881  {
1882  top_priority = *p;
1883  top_renderer = *it;
1884  }
1885  }
1886 
1887  return top_renderer;
1888 }
1889 
1891 {
1892  QString renderer = GetPreference("pref_videorenderer");
1893  QString osd = GetPreference("pref_osdrenderer");
1894  QString deint0 = GetPreference("pref_deint0");
1895  QString deint1 = GetPreference("pref_deint1");
1896  QString filter = GetPreference("pref_filters");
1897  return QString("rend(%4) osd(%5) deint(%6,%7) filt(%8)")
1898  .arg(renderer).arg(osd).arg(deint0).arg(deint1).arg(filter);
1899 }
1900 
1902 {
1903  if (safe_initialized)
1904  return;
1905 
1906  safe_initialized = true;
1907 
1908  render_opts options;
1909  options.renderers = &safe_custom;
1910  options.safe_renderers = &safe_renderer;
1911  options.deints = &safe_deint;
1912  options.osds = &safe_osd;
1913  options.render_group = &safe_renderer_group;
1915  options.decoders = &safe_decoders;
1916  options.equiv_decoders = &safe_equiv_dec;
1917 
1918  // N.B. assumes NuppelDecoder and DummyDecoder always present
1921 
1922  foreach(QString decoder, safe_decoders)
1923  LOG(VB_PLAYBACK, LOG_INFO, LOC +
1924  QString("decoder<->render support: %1%2")
1925  .arg(decoder, -12).arg(GetVideoRenderers(decoder).join(" ")));
1926 }
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
Definition: mythdbcon.cpp:794
static QStringList GetDecoders(void)
void SetVideoRenderer(const QString &video_renderer)
void bindValue(const QString &placeholder, const QVariant &val)
Definition: mythdbcon.cpp:875
static void init_statics(void)
static QString GetDeinterlacerName(const QString &short_name)
static QStringList GetOSDs(const QString &video_renderer)
static uint GetProfileGroupID(const QString &profilename, const QString &hostname)
priority_map_t * priorities
item_list_t::const_iterator FindMatch(const QSize &size, float framerate, const QString &codecName)
static void CreateProfiles(const QString &hostname)
QMap< QString, QStringList > safe_map_t
uint GetPriority(void) const
static safe_map_t safe_renderer_group
static QStringList GetDecoderNames(void)
void LoadBestPreferences(const QSize &size, float framerate, const QString &codecName)
static void SetDefaultProfileName(const QString &profilename, const QString &hostname)
static void error(const char *str,...)
Definition: vbi.c:41
safe_list_t * renderers
QSqlQuery wrapper that fetches a DB connection from the connection pool.
Definition: mythdbcon.h:125
QString GetDeinterlacer(void) const
bool checkRange(QString key, float fvalue, bool *ok=nullptr) const
QString GetFilteredDeint(const QString &override)
static QString GetDecoderName(const QString &decoder)
safe_map_t * deints
static QString GetDecoderHelp(QString decoder=QString())
static item_list_t LoadDB(uint groupid)
static bool IsFilterAllowed(const QString &video_renderer)
QString GetSettingOnHost(const QString &key, const QString &host, const QString &defaultval="")
QString GetFallbackDeinterlacer(void) const
unsigned int uint
Definition: compat.h:140
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
static bool DeleteDB(uint groupid, const item_list_t &)
static QString GetOSDHelp(const QString &osd)
void SetOutput(float framerate)
static QString toCommaList(const QStringList &list)
static guint32 * tmp
Definition: goom_core.c:35
safe_map_t * render_group
QStringList safe_list_t
static QStringList GetDeinterlacers(const QString &video_renderer)
QVariant value(int i) const
Definition: mythdbcon.h:182
safe_list_t * decoders
bool IsMatch(const QSize &size, float framerate, const QString &codecName) const
safe_map_t * osds
static QString GetBestVideoRenderer(const QStringList &renderers)
#define LOC
bool CheckVideoRendererGroup(const QString &renderer)
bool IsValid(QString *reason=nullptr) const
vector< ProfileItem > item_list_t
static safe_list_t safe_decoders
bool operator<(const ProfileItem &other) const
QString GetDecoder(void) const
static void GetRenderOptions(render_opts &opts)
QMap< QString, QString > pref_map_t
static void GetDecoders(render_opts &opts)
bool isActive(void) const
Definition: mythdbcon.h:188
static safe_map_t safe_equiv_dec
static QString GetDefaultProfileName(const QString &hostname)
static QString GetPreferredVideoRenderer(const QString &decoder)
safe_map_t * equiv_decoders
QString GetPreference(const QString &key) const
QString toString(void) const
string hostname
Definition: caa.py:17
static safe_list_t safe_custom
static MSqlQueryInfo InitCon(ConnectionReuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:547
static uint CreateProfileGroup(const QString &groupname, const QString &hostname)
void SetInput(const QSize &size, float framerate=0, const QString &codecName=QString())
virtual QStringList GetDeinterlacers(void)
static void DeleteProfiles(const QString &hostname)
static safe_map_t safe_renderer
QString GetActualVideoRenderer(void) const
static QStringList GetFilteredRenderers(const QString &decoder, const QStringList &renderers)
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
Definition: mythdbcon.cpp:819
QMap< QString, uint > priority_map_t
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
static QString GetDeinterlacerHelp(const QString &deint)
QString GetOSDRenderer(void) const
safe_map_t * safe_renderers
static QString GetVideoRendererHelp(const QString &renderer)
static pref_map_t dec_name
static safe_map_t safe_osd
static safe_map_t safe_deint
static void CreateProfile(uint grpid, uint priority, QString cmp0, uint width0, uint height0, QString cmp1, uint width1, uint height1, QString decoder, uint max_cpus, bool skiploop, QString videorenderer, QString osdrenderer, bool osdfade, QString deint0, QString deint1, QString filters)
static bool DeleteProfileGroup(const QString &groupname, const QString &hostname)
void SetPreference(const QString &key, const QString &value)
QString GetVideoRenderer(void) const
static bool SaveDB(uint groupid, item_list_t &)
static QStringList GetProfiles(const QString &hostname)
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
Definition: mythdbcon.cpp:615
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
static QStringList GetVideoRenderers(const QString &decoder)
static priority_map_t safe_renderer_priority
QString GetHostName(void)
bool IsDecoderCompatible(const QString &decoder)