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