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