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