MythTV master
recordingprofile.cpp
Go to the documentation of this file.
1
2#include "recordingprofile.h"
3
4#include "cardutil.h"
8#include "v4l2util.h"
9#include <algorithm>
10#include <utility>
11
13{
14 QString idTag(":WHEREID");
15 QString query("id = " + idTag);
16
17 bindings.insert(idTag, m_parent.getProfileNum());
18
19 return query;
20}
21
23{
24 protected:
26 const RecordingProfile &parentProfile,
27 const QString& name) :
28 SimpleDBStorage(_setting, "codecparams", "value"),
29 m_parent(parentProfile), m_codecName(name)
30 {
31 _setting->setName(name);
32 }
33
34 QString GetSetClause(MSqlBindings &bindings) const override; // SimpleDBStorage
35 QString GetWhereClause(MSqlBindings &bindings) const override; // SimpleDBStorage
36
38 QString m_codecName;
39};
40
42{
43 QString profileTag(":SETPROFILE");
44 QString nameTag(":SETNAME");
45 QString valueTag(":SETVALUE");
46
47 QString query("profile = " + profileTag + ", name = " + nameTag
48 + ", value = " + valueTag);
49
50 bindings.insert(profileTag, m_parent.getProfileNum());
51 bindings.insert(nameTag, m_codecName);
52 bindings.insert(valueTag, m_user->GetDBValue());
53
54 return query;
55}
56
58{
59 QString profileTag(":WHEREPROFILE");
60 QString nameTag(":WHERENAME");
61
62 QString query("profile = " + profileTag + " AND name = " + nameTag);
63
64 bindings.insert(profileTag, m_parent.getProfileNum());
65 bindings.insert(nameTag, m_codecName);
66
67 return query;
68}
69
71{
72 public:
73 explicit AudioCodecName(const RecordingProfile &parent) :
75 new RecordingProfileStorage(this, parent, "audiocodec"))
76 {
77 setLabel(QObject::tr("Codec"));
78 setName("audiocodec");
79 }
80};
81
83{
84 public:
85 explicit MP3Quality(const RecordingProfile &parent) :
86 MythUISpinBoxSetting(this, 1, 9, 1),
87 CodecParamStorage(this, parent, "mp3quality")
88 {
89 setLabel(QObject::tr("MP3 quality"));
90 setValue(7);
91 setHelpText(QObject::tr("The higher the slider number, the lower the "
92 "quality of the audio. Better quality audio (lower "
93 "numbers) requires more CPU."));
94 };
95};
96
98{
99 public:
100 explicit BTTVVolume(const RecordingProfile& parent) :
101 MythUISpinBoxSetting(this, 0, 100, 1),
102 CodecParamStorage(this, parent, "volume")
103 {
104 setLabel(QObject::tr("Volume (%)"));
105 setValue(90);
106 setHelpText(QObject::tr("Recording volume of the capture card."));
107 };
108};
109
111{
112 public:
113 explicit SampleRate(const RecordingProfile &parent, bool analog = true) :
114 MythUIComboBoxSetting(this), CodecParamStorage(this, parent, "samplerate")
115 {
116 setLabel(QObject::tr("Sampling rate"));
117 setHelpText(QObject::tr("Sets the audio sampling rate for your DSP. "
118 "Ensure that you choose a sampling rate appropriate "
119 "for your device. btaudio may only allow 32000."));
120
121 m_rates.push_back(32000);
122 m_rates.push_back(44100);
123 m_rates.push_back(48000);
124
125 m_allowedRate[48000] = true;
126 for (uint i = 0; analog && (i < m_rates.size()); i++)
127 m_allowedRate[m_rates[i]] = true;
128
129 };
130
131 void Load(void) override // StandardSetting
132 {
134 QString val = getValue();
135
137 for (uint rate : m_rates)
138 {
139 if (m_allowedRate[rate])
140 addSelection(QString::number(rate));
141 }
142
143 int which = getValueIndex(val);
144 setValue(std::max(which,0));
145
146 if (m_allowedRate.size() <= 1)
147 setEnabled(false);
148 }
149
150 void addSelection(const QString &label,
151 const QString& value = QString(),
152 bool select = false)
153 {
154 QString val = value.isEmpty() ? label : value;
155 uint rate = val.toUInt();
156 if (m_allowedRate[rate])
157 {
158 MythUIComboBoxSetting::addSelection(label, value, select);
159 }
160 else
161 {
162 LOG(VB_GENERAL, LOG_ERR, QString("SampleRate: ") +
163 QString("Attempted to add a rate %1 Hz, which is "
164 "not in the list of allowed rates.").arg(rate));
165 }
166 }
167
168 std::vector<uint> m_rates;
169 QMap<uint,bool> m_allowedRate;
170};
171
173{
174 public:
176 bool layer1, bool layer2, bool layer3) :
177 MythUIComboBoxSetting(this), CodecParamStorage(this, parent, "mpeg2audtype"),
178 m_allowLayer1(layer1), m_allowLayer2(layer2), m_allowLayer3(layer3)
179 {
180 setLabel(QObject::tr("Type"));
181
182 if (m_allowLayer1)
183 addSelection("Layer I");
184 if (m_allowLayer2)
185 addSelection("Layer II");
186 if (m_allowLayer3)
187 addSelection("Layer III");
188
189 uint allowed_cnt = 0;
190 allowed_cnt += ((m_allowLayer1) ? 1 : 0);
191 allowed_cnt += ((m_allowLayer2) ? 1 : 0);
192 allowed_cnt += ((m_allowLayer3) ? 1 : 0);
193
194 if (1 == allowed_cnt)
195 setEnabled(false);
196
197 setHelpText(QObject::tr("Sets the audio type"));
198 }
199
200 void Load(void) override // StandardSetting
201 {
203 QString val = getValue();
204
205 if ((val == "Layer I") && !m_allowLayer1)
206 {
207 if (m_allowLayer2)
208 val = "Layer II";
209 else if (m_allowLayer3)
210 val = "Layer III";
211 }
212
213 if ((val == "Layer II") && !m_allowLayer2)
214 {
215 if (m_allowLayer3)
216 val = "Layer III";
217 else if (m_allowLayer1)
218 val = "Layer I";
219 }
220
221 if ((val == "Layer III") && !m_allowLayer3)
222 {
223 if (m_allowLayer2)
224 val = "Layer II";
225 else if (m_allowLayer1)
226 val = "Layer I";
227 }
228
229 if (getValue() != val)
230 {
231 int which = getValueIndex(val);
232 if (which >= 0)
233 setValue(which);
234 }
235 }
236
237 private:
241};
242
244{
245 public:
246 explicit MPEG2audBitrateL1(const RecordingProfile &parent) :
248 CodecParamStorage(this, parent, "mpeg2audbitratel1")
249 {
250 setLabel(QObject::tr("Bitrate"));
251
252 addSelection("32 kbps", "32");
253 addSelection("64 kbps", "64");
254 addSelection("96 kbps", "96");
255 addSelection("128 kbps", "128");
256 addSelection("160 kbps", "160");
257 addSelection("192 kbps", "192");
258 addSelection("224 kbps", "224");
259 addSelection("256 kbps", "256");
260 addSelection("288 kbps", "288");
261 addSelection("320 kbps", "320");
262 addSelection("352 kbps", "352");
263 addSelection("384 kbps", "384");
264 addSelection("416 kbps", "416");
265 addSelection("448 kbps", "448");
266 setValue(13);
267 setHelpText(QObject::tr("Sets the audio bitrate"));
268 };
269};
270
272{
273 public:
274 explicit MPEG2audBitrateL2(const RecordingProfile &parent) :
276 CodecParamStorage(this, parent, "mpeg2audbitratel2")
277 {
278 setLabel(QObject::tr("Bitrate"));
279
280 addSelection("32 kbps", "32");
281 addSelection("48 kbps", "48");
282 addSelection("56 kbps", "56");
283 addSelection("64 kbps", "64");
284 addSelection("80 kbps", "80");
285 addSelection("96 kbps", "96");
286 addSelection("112 kbps", "112");
287 addSelection("128 kbps", "128");
288 addSelection("160 kbps", "160");
289 addSelection("192 kbps", "192");
290 addSelection("224 kbps", "224");
291 addSelection("256 kbps", "256");
292 addSelection("320 kbps", "320");
293 addSelection("384 kbps", "384");
294 setValue(13);
295 setHelpText(QObject::tr("Sets the audio bitrate"));
296 };
297};
298
300{
301 public:
302 explicit MPEG2audBitrateL3(const RecordingProfile &parent) :
304 CodecParamStorage(this, parent, "mpeg2audbitratel3")
305 {
306 setLabel(QObject::tr("Bitrate"));
307
308 addSelection("32 kbps", "32");
309 addSelection("40 kbps", "40");
310 addSelection("48 kbps", "48");
311 addSelection("56 kbps", "56");
312 addSelection("64 kbps", "64");
313 addSelection("80 kbps", "80");
314 addSelection("96 kbps", "96");
315 addSelection("112 kbps", "112");
316 addSelection("128 kbps", "128");
317 addSelection("160 kbps", "160");
318 addSelection("192 kbps", "192");
319 addSelection("224 kbps", "224");
320 addSelection("256 kbps", "256");
321 addSelection("320 kbps", "320");
322 setValue(10);
323 setHelpText(QObject::tr("Sets the audio bitrate"));
324 };
325};
326
328{
329 public:
330 explicit MPEG2audVolume(const RecordingProfile &parent) :
331 MythUISpinBoxSetting(this, 0, 100, 1),
332 CodecParamStorage(this, parent, "mpeg2audvolume")
333 {
334
335 setLabel(QObject::tr("Volume (%)"));
336 setValue(90);
337 setHelpText(QObject::tr("Volume of the recording "));
338 };
339};
340
342{
343 public:
345 bool layer1, bool layer2, bool layer3,
346 uint default_layer)
347 {
348 const std::array<const QString,3> layers { "Layer I", "Layer II", "Layer III", };
349
350 setLabel(QObject::tr("Bitrate Settings"));
351
352 auto *audType = new MPEG2audType(parent, layer1, layer2, layer3);
353
354 addChild(audType);
355
356 addTargetedChild(layers[0], new MPEG2audBitrateL1(parent));
357 addTargetedChild(layers[1], new MPEG2audBitrateL2(parent));
358 addTargetedChild(layers[2], new MPEG2audBitrateL3(parent));
359
360 uint desired_layer = std::clamp(default_layer, 1U, 3U) - 1;
361 int which = audType->getValueIndex(layers[desired_layer]);
362 if (which >= 0)
363 audType->setValue(which);
364 };
365};
366
368{
369 public:
370 explicit MPEG2Language(const RecordingProfile &parent) :
371 MythUIComboBoxSetting(this), CodecParamStorage(this, parent, "mpeg2language")
372 {
373 setLabel(QObject::tr("SAP/Bilingual"));
374
375 addSelection(QObject::tr("Main Language"), "0");
376 addSelection(QObject::tr("SAP Language"), "1");
377 addSelection(QObject::tr("Dual"), "2");
378
379 setValue(0);
380 setHelpText(QObject::tr(
381 "Chooses the language(s) to record when "
382 "two languages are broadcast. Only Layer II "
383 "supports the recording of two languages (Dual)."
384 "Requires ivtv 0.4.0 or later."));
385 };
386};
387
389{
390 public:
391 explicit BitrateMode(const RecordingProfile& parent,
392 const QString& setting = "mpeg2bitratemode") :
394 CodecParamStorage(this, parent, setting)
395 {
396 setLabel(QObject::tr("Bitrate Mode"));
397
398 addSelection("Variable Bitrate", "0");
399 addSelection("Constant Bitrate", "1");
400 setValue(0);
401 setHelpText(QObject::tr("Bitrate mode"));
402 }
403};
404
406{
407 public:
409 [[maybe_unused]] V4L2util* v4l2) :
410 m_parent(parentProfile),
412 {
413 setName(QObject::tr("Audio Quality"));
414
416
417 QString label("MP3");
421
422 label = "MPEG-2 Hardware Encoder";
423 m_codecName->addTargetedChild(label, new SampleRate(m_parent, false));
426 (m_parent, false, true, false, 2));
429
430 label = "Uncompressed";
433
434 m_codecName->addTargetedChild("AC3 Hardware Encoder",
435 new GroupSetting());
436
437 m_codecName->addTargetedChild("AAC Hardware Encoder",
438 new GroupSetting());
439
440#if CONFIG_V4L2
441 if (v4l2)
442 {
443 // Dynamically create user options based on the
444 // capabilties the driver reports.
445
447
448 if (v4l2->GetOptions(options))
449 {
450 /* StandardSetting cannot handle multiple 'targets' pointing
451 * to the same setting configuration, so we need to do
452 * this in two passes. */
453
454 for (const auto & option : std::as_const(options))
455 {
456 if (option.m_category == DriverOption::AUDIO_ENCODING)
457 {
458 for (const auto & Imenu : std::as_const(option.m_menu))
459 {
460 if (!Imenu.isEmpty())
461 m_v4l2codecs << "V4L2:" + Imenu;
462 }
463 }
464 }
465
466 for (auto Icodec = m_v4l2codecs.begin(); Icodec < m_v4l2codecs.end(); ++Icodec)
467 {
468 for (const auto & option : std::as_const(options))
469 {
470 if (option.m_category == DriverOption::AUDIO_BITRATE_MODE)
471 {
473 new BitrateMode(m_parent, "audbitratemode"));
474 }
475 else if (option.m_category ==
477 {
479 new SampleRate(m_parent, false));
480 }
481 else if (option.m_category ==
483 {
486 }
487 else if (option.m_category == DriverOption::AUDIO_BITRATE)
488 {
489 bool layer1 = false;
490 bool layer2 = false;
491 bool layer3 = false;
492
493 for (const auto & Imenu : std::as_const(option.m_menu))
494 {
495 if (Imenu.indexOf("Layer III") >= 0)
496 layer3 = true;
497 else if (Imenu.indexOf("Layer II") >= 0)
498 layer2 = true;
499 else if (Imenu.indexOf("Layer I") >= 0)
500 layer1 = true;
501 }
502
503 if (layer1 || layer2 || layer3)
504 {
507 layer1,
508 layer2,
509 layer3, 2));
510 }
511 }
512 else if (option.m_category == DriverOption::VOLUME)
513 {
516 }
517 }
518 }
519 }
520 }
521#endif // CONFIG_V4L2
522 }
523
524 void selectCodecs(const QString & groupType)
525 {
526 if (!groupType.isNull())
527 {
528 if (groupType == "MPEG")
529 m_codecName->addSelection("MPEG-2 Hardware Encoder");
530 else if (groupType == "HDPVR")
531 {
532 m_codecName->addSelection("AC3 Hardware Encoder");
533 m_codecName->addSelection("AAC Hardware Encoder");
534 }
535 else if (groupType.startsWith("V4L2:"))
536 {
537 for (const auto & codec : std::as_const(m_v4l2codecs))
539 }
540 else
541 {
542 // V4L, TRANSCODE (and any undefined types)
544 m_codecName->addSelection("Uncompressed");
545 }
546 }
547 else
548 {
550 m_codecName->addSelection("Uncompressed");
551 m_codecName->addSelection("MPEG-2 Hardware Encoder");
552 }
553 }
554private:
557 QStringList m_v4l2codecs;
558};
559
561{
562 public:
563 explicit VideoCodecName(const RecordingProfile &parent) :
565 new RecordingProfileStorage(this, parent, "videocodec"))
566 {
567 setLabel(QObject::tr("Codec"));
568 setName("videocodec");
569 }
570};
571
573{
574 public:
575 explicit RTjpegQuality(const RecordingProfile &parent) :
576 MythUISpinBoxSetting(this, 1, 255, 1),
577 CodecParamStorage(this, parent, "rtjpegquality")
578 {
579 setLabel(QObject::tr("RTjpeg Quality"));
580 setValue(170);
581 setHelpText(QObject::tr("Higher is better quality."));
582 };
583};
584
586{
587 public:
588 explicit RTjpegLumaFilter(const RecordingProfile &parent) :
589 MythUISpinBoxSetting(this, 0, 31, 1),
590 CodecParamStorage(this, parent, "rtjpeglumafilter")
591 {
592 setLabel(QObject::tr("Luma filter"));
593 setValue(0);
594 setHelpText(QObject::tr("Lower is better."));
595 };
596};
597
599{
600 public:
601 explicit RTjpegChromaFilter(const RecordingProfile &parent) :
602 MythUISpinBoxSetting(this, 0, 31, 1),
603 CodecParamStorage(this, parent, "rtjpegchromafilter")
604 {
605 setLabel(QObject::tr("Chroma filter"));
606 setValue(0);
607 setHelpText(QObject::tr("Lower is better."));
608 };
609};
610
612{
613 public:
614 explicit MPEG4bitrate(const RecordingProfile &parent) :
615 MythUISpinBoxSetting(this, 100, 8000, 100),
616 CodecParamStorage(this, parent, "mpeg4bitrate")
617 {
618 setLabel(QObject::tr("Bitrate (kb/s)"));
619 setValue(2200);
620 setHelpText(QObject::tr("Bitrate in kilobits/second. As a guide, "
621 "2200 kb/s is approximately 1 GB/hr."));
622 };
623};
624
626{
627 public:
628 explicit ScaleBitrate(const RecordingProfile &parent) :
630 CodecParamStorage(this, parent, "scalebitrate")
631 {
632 setLabel(QObject::tr("Scale bitrate for frame size"));
633 setValue(true);
634 setHelpText(QObject::tr("If set, the bitrate specified will be used "
635 "for 640x480. If other resolutions are used, the "
636 "bitrate will be scaled appropriately."));
637 };
638};
639
641{
642 public:
643 explicit MPEG4MinQuality(const RecordingProfile &parent) :
644 MythUISpinBoxSetting(this, 1, 31, 1),
645 CodecParamStorage(this, parent, "mpeg4minquality")
646 {
647 setLabel(QObject::tr("Minimum quality"));
648 setValue(15);
649 setHelpText(QObject::tr("Modifying the default may have severe "
650 "consequences."));
651 };
652};
653
655{
656 public:
657 explicit MPEG4MaxQuality(const RecordingProfile &parent) :
658 MythUISpinBoxSetting(this, 1, 31, 1),
659 CodecParamStorage(this, parent, "mpeg4maxquality")
660 {
661 setLabel(QObject::tr("Maximum quality"));
662 setValue(2);
663 setHelpText(QObject::tr("Modifying the default may have severe "
664 "consequences."));
665 };
666};
667
669{
670 public:
671 explicit MPEG4QualDiff(const RecordingProfile &parent) :
672 MythUISpinBoxSetting(this, 1, 31, 1),
673 CodecParamStorage(this, parent, "mpeg4qualdiff")
674 {
675
676 setLabel(QObject::tr("Max quality difference between frames"));
677 setValue(3);
678 setHelpText(QObject::tr("Modifying the default may have severe "
679 "consequences."));
680 };
681};
682
684{
685 public:
686 explicit MPEG4OptionIDCT(const RecordingProfile &parent) :
688 CodecParamStorage(this, parent, "mpeg4optionidct")
689 {
690 setLabel(QObject::tr("Enable interlaced DCT encoding"));
691 setValue(false);
692 setHelpText(QObject::tr("If set, the MPEG4 encoder will use "
693 "interlaced DCT encoding. You may want this when encoding "
694 "interlaced video; however, this is experimental and may "
695 "cause damaged video."));
696 };
697};
698
700{
701 public:
702 explicit MPEG4OptionIME(const RecordingProfile &parent) :
704 CodecParamStorage(this, parent, "mpeg4optionime")
705 {
706 setLabel(QObject::tr("Enable interlaced motion estimation"));
707 setValue(false);
708 setHelpText(QObject::tr("If set, the MPEG4 encoder will use "
709 "interlaced motion estimation. You may want this when "
710 "encoding interlaced video; however, this is experimental "
711 "and may cause damaged video."));
712 };
713};
714
716{
717 public:
718 explicit MPEG4OptionVHQ(const RecordingProfile &parent) :
720 CodecParamStorage(this, parent, "mpeg4optionvhq")
721 {
722 setLabel(QObject::tr("Enable high-quality encoding"));
723 setValue(false);
724 setHelpText(QObject::tr("If set, the MPEG4 encoder will use "
725 "'high-quality' encoding options. This requires much "
726 "more processing, but can result in better video."));
727 };
728};
729
731{
732 public:
733 explicit MPEG4Option4MV(const RecordingProfile &parent) :
735 CodecParamStorage(this, parent, "mpeg4option4mv")
736 {
737 setLabel(QObject::tr("Enable 4MV encoding"));
738 setValue(false);
739 setHelpText(QObject::tr("If set, the MPEG4 encoder will use '4MV' "
740 "motion-vector encoding. This requires "
741 "much more processing, but can result in better "
742 "video. It is highly recommended that the HQ option is "
743 "enabled if 4MV is enabled."));
744 };
745};
746
748{
749 public:
750 explicit EncodingThreadCount(const RecordingProfile &parent) :
751 MythUISpinBoxSetting(this, 1, 8, 1),
752 CodecParamStorage(this, parent, "encodingthreadcount")
753 {
754
755 setLabel(QObject::tr("Number of threads"));
756 setValue(1);
758 QObject::tr("Threads to use for software encoding.") + " " +
759 QObject::tr("Set to a value less than or equal to the "
760 "number of processors on the backend that "
761 "will be doing the encoding."));
762 };
763};
764
766{
767 public:
768 explicit AverageBitrate(const RecordingProfile &parent,
769 const QString& setting = "mpeg2bitrate",
770 uint min_br = 1000, uint max_br = 16000,
771 uint default_br = 4500, uint increment = 100,
772 QString label = QString()) :
773 MythUISpinBoxSetting(this, min_br, max_br, increment),
774 CodecParamStorage(this, parent, setting)
775 {
776 if (label.isEmpty())
777 label = QObject::tr("Avg. Bitrate (kb/s)");
778 setLabel(label);
779 setValue(default_br);
780 setHelpText(QObject::tr(
781 "Average bitrate in kilobits/second. As a guide, "
782 "2200 kb/s is approximately 1 GB/hour."));
783 };
784};
785
787{
788 public:
789 explicit PeakBitrate(const RecordingProfile &parent,
790 const QString& setting = "mpeg2maxbitrate",
791 uint min_br = 1000, uint max_br = 16000,
792 uint default_br = 6000, uint increment = 100,
793 QString label = QString()) :
794 MythUISpinBoxSetting(this, min_br, max_br, increment),
795 CodecParamStorage(this, parent, setting)
796 {
797 if (label.isEmpty())
798 label = QObject::tr("Max. Bitrate (kb/s)");
799 setLabel(label);
800 setValue(default_br);
801 setHelpText(QObject::tr("Maximum bitrate in kilobits/second. "
802 "As a guide, 2200 kb/s is approximately 1 GB/hour."));
803 };
804};
805
807{
808 public:
809 explicit MPEG2streamType(const RecordingProfile &parent,
810 uint minopt = 0, uint maxopt = 8, uint defopt = 0) :
812 CodecParamStorage(this, parent, "mpeg2streamtype")
813 {
814 maxopt = std::min<uint>(maxopt, 8);
815
816 setLabel(QObject::tr("Stream Type"));
817
818 const std::array<const QString,9> options { "MPEG-2 PS", "MPEG-2 TS",
819 "MPEG-1 VCD", "PES AV",
820 "PES V", "PES A",
821 "DVD", "DVD-Special 1", "DVD-Special 2" };
822
823 for (uint idx = minopt; idx <= maxopt; ++idx)
824 addSelection(options[idx]);
825
826 setValue(defopt - minopt);
827 setHelpText(QObject::tr("Sets the type of stream generated by "
828 "your PVR."));
829 };
830};
831
833{
834 public:
835 explicit MPEG2aspectRatio(const RecordingProfile &parent,
836 uint minopt = 0, uint maxopt = 8, uint defopt = 0) :
838 CodecParamStorage(this, parent, "mpeg2aspectratio")
839 {
840 maxopt = std::min<uint>(maxopt, 3);
841
842 setLabel(QObject::tr("Aspect Ratio"));
843
844 const std::array<const QString,4> options { QObject::tr("Square"), "4:3",
845 "16:9", "2.21:1" };
846
847 for (uint idx = minopt; idx <= maxopt; ++idx)
848 addSelection(options[idx]);
849
850 setValue(defopt);
851 setHelpText(QObject::tr("Sets the aspect ratio of stream generated "
852 "by your PVR."));
853 };
854};
855
857{
858 public:
859 explicit HardwareMJPEGQuality(const RecordingProfile &parent) :
860 MythUISpinBoxSetting(this, 0, 100, 1),
861 CodecParamStorage(this, parent, "hardwaremjpegquality")
862 {
863 setLabel(QObject::tr("Quality"));
864 setValue("100");
865 };
866};
867
869 public CodecParamStorage
870{
871 public:
874 CodecParamStorage(this, parent, "hardwaremjpeghdecimation")
875 {
876 setLabel(QObject::tr("Horizontal Decimation"));
877 addSelection("1");
878 addSelection("2");
879 addSelection("4");
880 setValue(2);
881 };
882};
883
885 public CodecParamStorage
886{
887 public:
890 CodecParamStorage(this, parent, "hardwaremjpegvdecimation") {
891 setLabel(QObject::tr("Vertical Decimation"));
892 addSelection("1");
893 addSelection("2");
894 addSelection("4");
895 setValue(2);
896 };
897};
898
900{
901 public:
903 [[maybe_unused]] V4L2util* v4l2) :
904 m_parent(parentProfile),
906 {
907 setName(QObject::tr("Video Compression"));
908
910
911 QString label("RTjpeg");
915
916 label = "MPEG-4";
922
925
929
930 label = "MPEG-2";
933 //m_codecName->addTargetedChild(label, new MPEG4MaxQuality(m_parent));
934 //m_codecName->addTargetedChild(label, new MPEG4MinQuality(m_parent));
935 //m_codecName->addTargetedChild(label, new MPEG4QualDiff(m_parent));
936 //m_codecName->addTargetedChild(label, new MPEG4OptionVHQ(m_parent));
937 //m_codecName->addTargetedChild(label, new MPEG4Option4MV(m_parent));
939
940 label = "Hardware MJPEG";
944
945 label = "MPEG-2 Hardware Encoder";
950
951 label = "MPEG-4 AVC Hardware Encoder";
952 auto *h0 = new GroupSetting();
953 h0->setLabel(QObject::tr("Low Resolution"));
954 h0->addChild(new AverageBitrate(m_parent, "low_mpeg4avgbitrate",
955 1000, 13500, 4500, 500));
956 h0->addChild(new PeakBitrate(m_parent, "low_mpeg4peakbitrate",
957 1100, 20200, 6000, 500));
958 m_codecName->addTargetedChild(label, h0);
959
960 auto *h1 = new GroupSetting();
961 h1->setLabel(QObject::tr("Medium Resolution"));
962 h1->addChild(new AverageBitrate(m_parent, "medium_mpeg4avgbitrate",
963 1000, 13500, 9000, 500));
964 h1->addChild(new PeakBitrate(m_parent, "medium_mpeg4peakbitrate",
965 1100, 20200, 11000, 500));
966 m_codecName->addTargetedChild(label, h1);
967
968 auto *h2 = new GroupSetting();
969 h2->setLabel(QObject::tr("High Resolution"));
970 h2->addChild(new AverageBitrate(m_parent, "high_mpeg4avgbitrate",
971 1000, 13500, 13500, 500));
972 h2->addChild(new PeakBitrate(m_parent, "high_mpeg4peakbitrate",
973 1100, 20200, 20200, 500));
974 m_codecName->addTargetedChild(label, h2);
975
976#if CONFIG_V4L2
977 if (v4l2)
978 {
980
981 if (v4l2->GetOptions(options))
982 {
983 /* StandardSetting cannot handle multiple 'targets' pointing
984 * to the same setting configuration, so we need to do
985 * this in two passes. */
986
987 for (const auto & option : std::as_const(options))
988 {
989 if (option.m_category == DriverOption::VIDEO_ENCODING)
990 {
991 for (const auto & Imenu : std::as_const(option.m_menu))
992 {
993 if (!Imenu.isEmpty())
994 m_v4l2codecs << "V4L2:" + Imenu;
995 }
996 }
997 }
998
999 for (auto Icodec = m_v4l2codecs.begin(); Icodec < m_v4l2codecs.end(); ++Icodec)
1000 {
1001 auto* bit_low = new GroupSetting();
1002 auto* bit_medium = new GroupSetting();
1003 auto* bit_high = new GroupSetting();
1004 bool dynamic_res = !v4l2->UserAdjustableResolution();
1005
1006 for (auto & option : options)
1007 {
1008 if (option.m_category == DriverOption::STREAM_TYPE)
1009 {
1012 option.m_minimum,
1013 option.m_maximum,
1014 option.m_defaultValue));
1015 }
1016 else if (option.m_category == DriverOption::VIDEO_ASPECT)
1017 {
1020 option.m_minimum,
1021 option.m_maximum,
1022 option.m_defaultValue));
1023 }
1024 else if (option.m_category ==
1026 {
1027 if (dynamic_res)
1028 {
1029 bit_low->addChild(new BitrateMode(m_parent,
1030 "low_mpegbitratemode"));
1031 bit_medium->addChild(new BitrateMode(m_parent,
1032 "medium_mpegbitratemode"));
1033 bit_high->addChild(new BitrateMode(m_parent,
1034 "medium_mpegbitratemode"));
1035 }
1036 else
1037 {
1038 bit_low->addChild(new BitrateMode(m_parent));
1039 }
1040 }
1041 else if (option.m_category == DriverOption::VIDEO_BITRATE)
1042 {
1043 if (dynamic_res)
1044 {
1045 bit_low->setLabel(QObject::tr("Low Resolution"));
1046 bit_low->addChild(new AverageBitrate(m_parent,
1047 "low_mpegavgbitrate",
1048 option.m_minimum / 1000,
1049 option.m_maximum / 1000,
1050 option.m_defaultValue / 1000,
1051 option.m_step / 1000));
1052
1053 bit_medium->setLabel(QObject::
1054 tr("Medium Resolution"));
1055 bit_medium->addChild(new AverageBitrate(m_parent,
1056 "medium_mpegavgbitrate",
1057 option.m_minimum / 1000,
1058 option.m_maximum / 1000,
1059 option.m_defaultValue / 1000,
1060 option.m_step / 1000));
1061
1062 bit_high->setLabel(QObject::
1063 tr("High Resolution"));
1064 bit_high->addChild(new AverageBitrate(m_parent,
1065 "high_mpegavgbitrate",
1066 option.m_minimum / 1000,
1067 option.m_maximum / 1000,
1068 option.m_defaultValue / 1000,
1069 option.m_step / 1000));
1070 }
1071 else
1072 {
1073 bit_low->setLabel(QObject::tr("Bitrate"));
1074 bit_low->addChild(new AverageBitrate(m_parent,
1075 "mpeg2bitrate",
1076 option.m_minimum / 1000,
1077 option.m_maximum / 1000,
1078 option.m_defaultValue / 1000,
1079 option.m_step / 1000));
1080 }
1081 }
1082 else if (option.m_category ==
1084 {
1085 if (dynamic_res)
1086 {
1087 bit_low->addChild(new PeakBitrate(m_parent,
1088 "low_mpegpeakbitrate",
1089 option.m_minimum / 1000,
1090 option.m_maximum / 1000,
1091 option.m_defaultValue / 1000,
1092 option.m_step / 1000));
1093 bit_medium->addChild(new PeakBitrate(m_parent,
1094 "medium_mpegpeakbitrate",
1095 option.m_minimum / 1000,
1096 option.m_maximum / 1000,
1097 option.m_defaultValue / 1000,
1098 option.m_step / 1000));
1099 bit_high->addChild(new PeakBitrate(m_parent,
1100 "high_mpegpeakbitrate",
1101 option.m_minimum / 1000,
1102 option.m_maximum / 1000,
1103 option.m_defaultValue / 1000,
1104 option.m_step / 1000));
1105 }
1106 else
1107 {
1108 bit_low->addChild(new PeakBitrate(m_parent,
1109 "mpeg2maxbitrate",
1110 option.m_minimum / 1000,
1111 option.m_maximum / 1000,
1112 option.m_defaultValue / 1000,
1113 option.m_step / 1000));
1114 }
1115 }
1116 }
1117
1118 m_codecName->addTargetedChild(*Icodec, bit_low);
1119 if (dynamic_res)
1120 {
1121 m_codecName->addTargetedChild(*Icodec, bit_medium);
1122 m_codecName->addTargetedChild(*Icodec, bit_high);
1123 }
1124 else
1125 {
1126 // These are only referenced when dynamic_res is true.
1127 delete bit_medium;
1128 delete bit_high;
1129 }
1130 }
1131 }
1132 }
1133#endif // CONFIG_V4L2
1134 }
1135
1136 void selectCodecs(const QString& groupType)
1137 {
1138 if (!groupType.isNull())
1139 {
1140 if (groupType == "HDPVR")
1141 m_codecName->addSelection("MPEG-4 AVC Hardware Encoder");
1142 else if (groupType.startsWith("V4L2:"))
1143 {
1144 for (const auto & codec : std::as_const(m_v4l2codecs))
1145 m_codecName->addSelection(codec);
1146 }
1147 else if (groupType == "MPEG")
1148 {
1149 m_codecName->addSelection("MPEG-2 Hardware Encoder");
1150 }
1151 else if (groupType == "MJPEG")
1152 {
1153 m_codecName->addSelection("Hardware MJPEG");
1154 }
1155 else if (groupType == "GO7007")
1156 {
1157 m_codecName->addSelection("MPEG-4");
1158 m_codecName->addSelection("MPEG-2");
1159 }
1160 else
1161 {
1162 // V4L, TRANSCODE (and any undefined types)
1163 m_codecName->addSelection("RTjpeg");
1164 m_codecName->addSelection("MPEG-4");
1165 }
1166 }
1167 else
1168 {
1169 m_codecName->addSelection("RTjpeg");
1170 m_codecName->addSelection("MPEG-4");
1171 m_codecName->addSelection("Hardware MJPEG");
1172 m_codecName->addSelection("MPEG-2 Hardware Encoder");
1173 }
1174 }
1175
1176private:
1179 QStringList m_v4l2codecs;
1180};
1181
1183{
1184 public:
1185 explicit AutoTranscode(const RecordingProfile &parent) :
1187 CodecParamStorage(this, parent, "autotranscode")
1188 {
1189 setLabel(QObject::tr("Enable auto-transcode after recording"));
1190 setValue(false);
1191 setHelpText(QObject::tr("Automatically transcode when a recording is "
1192 "made using this profile and the recording's "
1193 "schedule is configured to allow transcoding."));
1194 };
1195};
1196
1198{
1199 public:
1200 explicit TranscodeResize(const RecordingProfile &parent) :
1202 CodecParamStorage(this, parent, "transcoderesize")
1203 {
1204 setLabel(QObject::tr("Resize video while transcoding"));
1205 setValue(false);
1206 setHelpText(QObject::tr("Allows the transcoder to "
1207 "resize the video during transcoding."));
1208 };
1209};
1210
1212{
1213 public:
1214 explicit TranscodeLossless(const RecordingProfile &parent) :
1216 CodecParamStorage(this, parent, "transcodelossless")
1217 {
1218 setLabel(QObject::tr("Lossless transcoding"));
1219 setValue(false);
1220 setHelpText(QObject::tr("Only reencode where absolutely needed "
1221 "(normally only around cutpoints). Otherwise "
1222 "keep audio and video formats identical to "
1223 "the source. This should result in the "
1224 "highest quality, but won't save as much "
1225 "space."));
1226 };
1227};
1228
1230{
1231 public:
1232 explicit RecordingTypeStream(const RecordingProfile &parent) :
1233 MythUIComboBoxSetting(this), CodecParamStorage(this, parent, "recordingtype")
1234 {
1235 setLabel(QObject::tr("Recording Type"));
1236
1237 QString msg = QObject::tr(
1238 "This option allows you to filter out unwanted streams. "
1239 "'Normal' will record all relevant streams including "
1240 "interactive television data. 'TV Only' will record only "
1241 "audio, video and subtitle streams. ");
1242 setHelpText(msg);
1243
1244 addSelection(QObject::tr("Normal"), "all");
1245 addSelection(QObject::tr("TV Only"), "tv");
1246 addSelection(QObject::tr("Audio Only"), "audio");
1247 setValue(0);
1248 };
1249};
1250
1252{
1253 public:
1254 explicit RecordFullTSStream(const RecordingProfile &parent) :
1255 MythUIComboBoxSetting(this), CodecParamStorage(this, parent, "recordmpts")
1256 {
1257 setLabel(QObject::tr("Record Full TS?"));
1258
1259 QString msg = QObject::tr(
1260 "If set, extra files will be created for each recording with "
1261 "the name of the recording followed by '.ts.raw'. "
1262 "These extra files represent the full contents of the transport "
1263 "stream used to generate the recording. (For debugging purposes)");
1264 setHelpText(msg);
1265
1266 addSelection(QObject::tr("Yes"), "1");
1267 addSelection(QObject::tr("No"), "0");
1268 setValue(1);
1269 };
1270};
1271
1273{
1274 public:
1275 explicit TranscodeFilters(const RecordingProfile &parent) :
1277 CodecParamStorage(this, parent, "transcodefilters")
1278 {
1279 setLabel(QObject::tr("Custom filters"));
1280 setHelpText(QObject::tr("Filters used when transcoding with this "
1281 "profile. This value must be blank to perform "
1282 "lossless transcoding. Format: "
1283 "[[<filter>=<options>,]...]"
1284 ));
1285 };
1286};
1287
1289{
1290 public:
1292 {
1293 public:
1295 uint defaultwidth, uint maxwidth,
1296 bool transcoding = false) :
1297 MythUISpinBoxSetting(this, transcoding ? 0 : 160,
1298 maxwidth, 16, 0,
1299 transcoding ? QObject::tr("Auto") : QString()),
1300 CodecParamStorage(this, parent, "width")
1301 {
1302 setLabel(QObject::tr("Width"));
1303 setValue(defaultwidth);
1304
1305 QString help = (transcoding) ?
1306 QObject::tr("If the width is set to 'Auto', the width "
1307 "will be calculated based on the height and "
1308 "the recording's physical aspect ratio.") :
1309 QObject::tr("Width to use for encoding. "
1310 "Note: PVR-x50 cards may produce ghosting if "
1311 "this is not set to 720 or 768 for NTSC and "
1312 "PAL, respectively.");
1313
1315 };
1316 };
1317
1319 {
1320 public:
1322 uint defaultheight, uint maxheight,
1323 bool transcoding = false):
1324 MythUISpinBoxSetting(this, transcoding ? 0 : 160,
1325 maxheight, 16, 0,
1326 transcoding ? QObject::tr("Auto") : QString()),
1327 CodecParamStorage(this, parent, "height")
1328 {
1329 setLabel(QObject::tr("Height"));
1330 setValue(defaultheight);
1331
1332 QString help = (transcoding) ?
1333 QObject::tr("If the height is set to 'Auto', the height "
1334 "will be calculated based on the width and "
1335 "the recording's physical aspect ratio.") :
1336 QObject::tr("Height to use for encoding. "
1337 "Note: PVR-x50 cards may produce ghosting if "
1338 "this is not set to 480 or 576 for NTSC and "
1339 "PAL, respectively.");
1340
1342 };
1343 };
1344
1346 const QString& tvFormat, const QString& profName)
1347 {
1348 setLabel(QObject::tr("Image size"));
1349
1350 QSize defaultsize(768, 576);
1351 QSize maxsize(768, 576);
1352 bool transcoding = profName.startsWith("Transcoders");
1353 bool ivtv = profName.startsWith("IVTV MPEG-2 Encoders");
1354
1355 if (transcoding)
1356 {
1357 maxsize = QSize(1920, 1088);
1358 if (tvFormat.toLower() == "ntsc" || tvFormat.toLower() == "atsc")
1359 defaultsize = QSize(480, 480);
1360 else
1361 defaultsize = QSize(480, 576);
1362 }
1363 else if (tvFormat.startsWith("ntsc", Qt::CaseInsensitive))
1364 {
1365 maxsize = QSize(720, 480);
1366 defaultsize = (ivtv) ? QSize(720, 480) : QSize(480, 480);
1367 }
1368 else if (tvFormat.toLower() == "atsc")
1369 {
1370 maxsize = QSize(1920, 1088);
1371 defaultsize = QSize(1920, 1088);
1372 }
1373 else
1374 {
1375 maxsize = QSize(768, 576);
1376 defaultsize = (ivtv) ? QSize(720, 576) : QSize(480, 576);
1377 }
1378
1379 addChild(new Width(parent, defaultsize.width(),
1380 maxsize.width(), transcoding));
1381 addChild(new Height(parent, defaultsize.height(),
1382 maxsize.height(), transcoding));
1383 };
1384};
1385
1386// id and name will be deleted by ConfigurationGroup's destructor
1388 : m_id(new ID()),
1389 m_name(new Name(*this)),
1390 m_profileName(profName)
1391{
1392 // This must be first because it is needed to load/save the other settings
1393 addChild(m_id);
1394
1395 setLabel(profName);
1397
1398 if (!profName.isEmpty())
1399 {
1400 if (profName.startsWith("Transcoders"))
1401 {
1402 m_trFilters = new TranscodeFilters(*this);
1403 m_trLossless = new TranscodeLossless(*this);
1404 m_trResize = new TranscodeResize(*this);
1408 }
1409 else
1410 {
1411 addChild(new AutoTranscode(*this));
1412 }
1413 }
1414 else
1415 {
1416 m_trFilters = new TranscodeFilters(*this);
1417 m_trLossless = new TranscodeLossless(*this);
1418 m_trResize = new TranscodeResize(*this);
1422 addChild(new AutoTranscode(*this));
1423 }
1424};
1425
1427{
1428#if CONFIG_V4L2
1429 delete m_v4l2util;
1430 m_v4l2util = nullptr;
1431#endif
1432}
1433
1434void RecordingProfile::ResizeTranscode(const QString & /*val*/)
1435{
1436 if (m_imageSize)
1438}
1439
1440void RecordingProfile::SetLosslessTranscode(const QString & /*val*/)
1441{
1442 bool lossless = m_trLossless->boolValue();
1443 bool show_size = (lossless) ? false : m_trResize->boolValue();
1444 if (m_imageSize)
1445 m_imageSize->setEnabled(show_size);
1446 m_videoSettings->setEnabled(! lossless);
1447 m_audioSettings->setEnabled(! lossless);
1448 m_trResize->setEnabled(! lossless);
1449 m_trFilters->setEnabled(! lossless);
1450}
1451
1453{
1454 MSqlQuery result(MSqlQuery::InitCon());
1455 result.prepare(
1456 "SELECT cardtype, profilegroups.name "
1457 "FROM profilegroups, recordingprofiles "
1458 "WHERE profilegroups.id = recordingprofiles.profilegroup AND "
1459 " recordingprofiles.id = :PROFILEID");
1460 result.bindValue(":PROFILEID", profileId);
1461
1462 QString type;
1463 QString name;
1464 if (!result.exec())
1465 {
1466 MythDB::DBError("RecordingProfile::loadByID -- cardtype", result);
1467 }
1468 else if (result.next())
1469 {
1470 type = result.value(0).toString();
1471 name = result.value(1).toString();
1472 }
1473
1474 CompleteLoad(profileId, type, name);
1475}
1476
1477void RecordingProfile::FiltersChanged(const QString &val)
1478{
1479 // If there are filters, we cannot do lossless transcoding
1480 if (!val.trimmed().isEmpty())
1481 {
1482 m_trLossless->setValue(false);
1483 m_trLossless->setEnabled(false);
1484 }
1485 else
1486 {
1487 m_trLossless->setEnabled(true);
1488 }
1489}
1490
1491bool RecordingProfile::loadByType(const QString &name, const QString &card,
1492 [[maybe_unused]] const QString &videodev)
1493{
1494 QString hostname = gCoreContext->GetHostName().toLower();
1495 QString cardtype = card;
1496 uint profileId = 0;
1497
1498#if CONFIG_V4L2
1499 if (cardtype == "V4L2ENC")
1500 {
1501 m_v4l2util = new V4L2util(videodev);
1502 if (m_v4l2util->IsOpen())
1503 cardtype = m_v4l2util->ProfileName();
1504 }
1505#endif
1506
1507 MSqlQuery result(MSqlQuery::InitCon());
1508 result.prepare(
1509 "SELECT recordingprofiles.id, profilegroups.hostname, "
1510 " profilegroups.is_default "
1511 "FROM recordingprofiles, profilegroups "
1512 "WHERE profilegroups.id = recordingprofiles.profilegroup AND "
1513 " profilegroups.cardtype = :CARDTYPE AND "
1514 " recordingprofiles.name = :NAME");
1515 result.bindValue(":CARDTYPE", cardtype);
1516 result.bindValue(":NAME", name);
1517
1518 if (!result.exec())
1519 {
1520 MythDB::DBError("RecordingProfile::loadByType()", result);
1521 return false;
1522 }
1523
1524 while (result.next())
1525 {
1526 if (result.value(1).toString().toLower() == hostname)
1527 {
1528 profileId = result.value(0).toUInt();
1529 }
1530 else if (result.value(2).toInt() == 1)
1531 {
1532 profileId = result.value(0).toUInt();
1533 break;
1534 }
1535 }
1536
1537 if (profileId)
1538 {
1539 CompleteLoad(profileId, cardtype, name);
1540 return true;
1541 }
1542
1543 return false;
1544}
1545
1546bool RecordingProfile::loadByGroup(const QString &name, const QString &group)
1547{
1548 MSqlQuery result(MSqlQuery::InitCon());
1549 result.prepare(
1550 "SELECT recordingprofiles.id, cardtype "
1551 "FROM recordingprofiles, profilegroups "
1552 "WHERE recordingprofiles.profilegroup = profilegroups.id AND "
1553 " profilegroups.name = :GROUPNAME AND "
1554 " recordingprofiles.name = :NAME");
1555 result.bindValue(":GROUPNAME", group);
1556 result.bindValue(":NAME", name);
1557
1558 if (!result.exec())
1559 {
1560 MythDB::DBError("RecordingProfile::loadByGroup()", result);
1561 return false;
1562 }
1563
1564 if (result.next())
1565 {
1566 uint profileId = result.value(0).toUInt();
1567 QString type = result.value(1).toString();
1568
1569 CompleteLoad(profileId, type, name);
1570 return true;
1571 }
1572
1573 return false;
1574}
1575
1576void RecordingProfile::CompleteLoad(int profileId, const QString &type,
1577 const QString &name)
1578{
1579 if (m_profileName.isEmpty())
1580 m_profileName = name;
1581
1583
1584 if (m_isEncoder)
1585 {
1586#if CONFIG_V4L2
1587 if (type.startsWith("V4L2:"))
1588 {
1589 QStringList devices = CardUtil::GetVideoDevices("V4L2ENC");
1590 if (!devices.isEmpty())
1591 {
1592 for (const auto & device : std::as_const(devices))
1593 {
1594 delete m_v4l2util;
1595 m_v4l2util = new V4L2util(device);
1596 if (m_v4l2util->IsOpen() &&
1597 m_v4l2util->DriverName() == type.mid(5))
1598 break;
1599 delete m_v4l2util;
1600 m_v4l2util = nullptr;
1601 }
1602 }
1603 }
1604#endif
1605
1606 QString tvFormat = gCoreContext->GetSetting("TVFormat");
1607 // TODO: When mpegrecorder is removed, don't check for "HDPVR' anymore...
1608 if (type != "HDPVR" &&
1609 (!m_v4l2util
1610#if CONFIG_V4L2
1612#endif
1613 ))
1614 {
1615 addChild(new ImageSize(*this, tvFormat, m_profileName));
1616 }
1618 m_v4l2util);
1620
1622 m_v4l2util);
1624
1625 if (!m_profileName.isEmpty() && m_profileName.startsWith("Transcoders"))
1626 {
1627 connect(m_trResize, qOverload<const QString&>(&StandardSetting::valueChanged),
1629 connect(m_trLossless, qOverload<const QString&>(&StandardSetting::valueChanged),
1631 connect(m_trFilters, qOverload<const QString&>(&StandardSetting::valueChanged),
1633 }
1634 }
1635
1636 // Cards that can receive additional streams such as EIT and MHEG
1638 {
1639 addChild(new RecordingTypeStream(*this));
1640 }
1641
1643 {
1644 addChild(new RecordFullTSStream(*this));
1645 }
1646
1647 m_id->setValue(profileId);
1648 Load();
1649}
1650
1652{
1653 if (m_videoSettings)
1655 if (m_audioSettings)
1657}
1658
1660 m_group(id), m_labelName(std::move(profName))
1661{
1662 if (!m_labelName.isEmpty())
1664}
1665
1667{
1668 clearSettings();
1669 auto *newProfile = new ButtonStandardSetting(tr("(Create new profile)"));
1671 addChild(newProfile);
1674}
1675
1677{
1678 MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
1679 auto *settingdialog = new MythTextInputDialog(popupStack,
1680 tr("Enter the name of the new profile"));
1681
1682 if (settingdialog->Create())
1683 {
1684 connect(settingdialog, &MythTextInputDialog::haveResult,
1686 popupStack->AddScreen(settingdialog);
1687 }
1688 else
1689 {
1690 delete settingdialog;
1691 }
1692}
1693
1694void RecordingProfileEditor::CreateNewProfile(const QString& profName)
1695{
1697 query.prepare(
1698 "INSERT INTO recordingprofiles "
1699 "(name, videocodec, audiocodec, profilegroup) "
1700 "VALUES "
1701 "(:NAME, :VIDEOCODEC, :AUDIOCODEC, :PROFILEGROUP);");
1702 query.bindValue(":NAME", profName);
1703 query.bindValue(":VIDEOCODEC", "MPEG-4");
1704 query.bindValue(":AUDIOCODEC", "MP3");
1705 query.bindValue(":PROFILEGROUP", m_group);
1706 if (!query.exec())
1707 {
1708 MythDB::DBError("RecordingProfileEditor::open", query);
1709 }
1710 else
1711 {
1712 query.prepare(
1713 "SELECT id "
1714 "FROM recordingprofiles "
1715 "WHERE name = :NAME AND profilegroup = :PROFILEGROUP;");
1716 query.bindValue(":NAME", profName);
1717 query.bindValue(":PROFILEGROUP", m_group);
1718 if (!query.exec())
1719 {
1720 MythDB::DBError("RecordingProfileEditor::open", query);
1721 }
1722 else
1723 {
1724 if (query.next())
1725 {
1726 auto* profile = new RecordingProfile(profName);
1727
1728 profile->loadByID(query.value(0).toInt());
1729 profile->setCodecTypes();
1731 emit settingsChanged(this);
1732 }
1733 }
1734 }
1735}
1736
1738 bool foldautodetect)
1739{
1740 if (!group)
1741 {
1742 for (const auto & name : kAvailProfiles)
1743 {
1744 auto *profile = new GroupSetting();
1745 profile->setLabel(name);
1746 setting->addChild(profile);
1747 }
1748 return;
1749 }
1750
1751 MSqlQuery result(MSqlQuery::InitCon());
1752 result.prepare(
1753 "SELECT name, id "
1754 "FROM recordingprofiles "
1755 "WHERE profilegroup = :GROUP "
1756 "ORDER BY id");
1757 result.bindValue(":GROUP", group);
1758
1759 if (!result.exec())
1760 {
1761 MythDB::DBError("RecordingProfile::fillSelections 1", result);
1762 return;
1763 }
1764
1765 while (result.next())
1766 {
1767 if ((result.at() == 0) && foldautodetect &&
1769 {
1770 auto *autodetect = new GroupSetting();
1771 autodetect->setLabel(QObject::tr("Autodetect"));
1772 setting->addChild(autodetect);
1773 }
1774
1775 QString name = result.value(0).toString();
1776 QString id = result.value(1).toString();
1777
1778 if ((group == RecordingProfile::TranscoderGroup) &&
1779 (name == "RTjpeg/MPEG4" || name == "MPEG2") &&
1780 !foldautodetect) {
1781 name = QObject::tr("Autodetect from %1").arg(name);
1782 }
1783
1784 auto *profile = new RecordingProfile(name);
1785 profile->loadByID(id.toInt());
1786 profile->setCodecTypes();
1787 setting->addChild(profile);
1788 }
1789}
1790
1792{
1793 QMap<int, QString> profiles;
1794
1795 if (!group)
1796 {
1797 for (uint i = 0; !kAvailProfiles[i].isEmpty(); i++)
1798 profiles[i] = kAvailProfiles[i];
1799 return profiles;
1800 }
1801
1803 query.prepare(
1804 "SELECT name, id "
1805 "FROM recordingprofiles "
1806 "WHERE profilegroup = :GROUPID "
1807 "ORDER BY id");
1808 query.bindValue(":GROUPID", group);
1809
1810 if (!query.exec())
1811 {
1812 MythDB::DBError("RecordingProfile::GetProfileMap()", query);
1813 return profiles;
1814 }
1815
1816 while (query.next())
1817 {
1818 if ((query.at() == 0) && (group == RecordingProfile::TranscoderGroup))
1819 {
1821 profiles[id] = QObject::tr("Transcode using Autodetect");
1822 }
1823
1824 QString name = query.value(0).toString();
1825 int id = query.value(1).toInt();
1826
1828 {
1829 /* RTjpeg/MPEG4 and MPEG2 are used by "Autodetect". */
1830 if (name != "RTjpeg/MPEG4" && name != "MPEG2")
1831 {
1832 QString lbl = QObject::tr("Transcode using \"%1\"").arg(name);
1833 profiles[id] = lbl;
1834 }
1835 continue;
1836 }
1837
1838 QString lbl = QObject::tr("Record using the \"%1\" profile").arg(name);
1839 profiles[id] = lbl;
1840 }
1841
1842 if (query.at() == QSql::BeforeFirstRow)
1843 {
1844 LOG(VB_GENERAL, LOG_WARNING,
1845 "RecordingProfile::fillselections, Warning: "
1846 "Failed to locate recording id for recording group.");
1847 }
1848
1849 return profiles;
1850}
1851
1853{
1855}
1856
1858{
1859 MSqlQuery result(MSqlQuery::InitCon());
1860 result.prepare(
1861 "SELECT profilegroups.cardtype "
1862 "FROM profilegroups, recordingprofiles "
1863 "WHERE profilegroups.id = recordingprofiles.profilegroup AND "
1864 " recordingprofiles.id = :ID");
1865 result.bindValue(":ID", getProfileNum());
1866
1867 if (!result.exec())
1868 MythDB::DBError("RecordingProfile::groupType", result);
1869 else if (result.next())
1870 return result.value(0).toString();
1871
1872 return {};
1873}
1874
1876{
1877 MSqlQuery result(MSqlQuery::InitCon());
1878 result.prepare(
1879 "SELECT name "
1880 "FROM recordingprofiles "
1881 "WHERE id = :ID");
1882
1883 result.bindValue(":ID", id);
1884
1885 if (!result.exec())
1886 MythDB::DBError("RecordingProfile::getName", result);
1887 else if (result.next())
1888 return result.value(0).toString();
1889
1890 return {};
1891}
1892
1894{
1895 return true;
1896}
1897
1899{
1900 MSqlQuery result(MSqlQuery::InitCon());
1901 result.prepare(
1902 "DELETE "
1903 "FROM recordingprofiles "
1904 "WHERE id = :ID");
1905
1906 result.bindValue(":ID", m_id->getValue());
1907
1908 if (!result.exec())
1909 MythDB::DBError("RecordingProfile::deleteEntry", result);
1910
1911}
1912
1913
1914/* vim: set expandtab tabstop=4 shiftwidth=4: */
AudioCodecName(const RecordingProfile &parent)
const RecordingProfile & m_parent
void selectCodecs(const QString &groupType)
AudioCompressionSettings(const RecordingProfile &parentProfile, V4L2util *v4l2)
AutoTranscode(const RecordingProfile &parent)
AverageBitrate(const RecordingProfile &parent, const QString &setting="mpeg2bitrate", uint min_br=1000, uint max_br=16000, uint default_br=4500, uint increment=100, QString label=QString())
BTTVVolume(const RecordingProfile &parent)
BitrateMode(const RecordingProfile &parent, const QString &setting="mpeg2bitratemode")
static bool IsTunerSharingCapable(const QString &rawtype)
Definition: cardutil.h:177
static QStringList GetVideoDevices(const QString &rawtype, QString hostname=QString())
Returns the videodevices of the matching inputs, duplicates removed.
Definition: cardutil.cpp:402
static bool IsEITCapable(const QString &rawtype)
Definition: cardutil.h:170
static bool IsEncoder(const QString &rawtype)
Definition: cardutil.h:135
const RecordingProfile & m_parent
QString GetSetClause(MSqlBindings &bindings) const override
QString GetWhereClause(MSqlBindings &bindings) const override
CodecParamStorage(StandardSetting *_setting, const RecordingProfile &parentProfile, const QString &name)
StorageUser * m_user
Definition: mythstorage.h:50
EncodingThreadCount(const RecordingProfile &parent)
GroupSetting()=default
HardwareMJPEGHDecimation(const RecordingProfile &parent)
HardwareMJPEGQuality(const RecordingProfile &parent)
HardwareMJPEGVDecimation(const RecordingProfile &parent)
Height(const RecordingProfile &parent, uint defaultheight, uint maxheight, bool transcoding=false)
Width(const RecordingProfile &parent, uint defaultwidth, uint maxwidth, bool transcoding=false)
ImageSize(const RecordingProfile &parent, const QString &tvFormat, const QString &profName)
MP3Quality(const RecordingProfile &parent)
MPEG2AudioBitrateSettings(const RecordingProfile &parent, bool layer1, bool layer2, bool layer3, uint default_layer)
MPEG2Language(const RecordingProfile &parent)
MPEG2aspectRatio(const RecordingProfile &parent, uint minopt=0, uint maxopt=8, uint defopt=0)
MPEG2audBitrateL1(const RecordingProfile &parent)
MPEG2audBitrateL2(const RecordingProfile &parent)
MPEG2audBitrateL3(const RecordingProfile &parent)
MPEG2audType(const RecordingProfile &parent, bool layer1, bool layer2, bool layer3)
void Load(void) override
MPEG2audVolume(const RecordingProfile &parent)
MPEG2streamType(const RecordingProfile &parent, uint minopt=0, uint maxopt=8, uint defopt=0)
MPEG4MaxQuality(const RecordingProfile &parent)
MPEG4MinQuality(const RecordingProfile &parent)
MPEG4Option4MV(const RecordingProfile &parent)
MPEG4OptionIDCT(const RecordingProfile &parent)
MPEG4OptionIME(const RecordingProfile &parent)
MPEG4OptionVHQ(const RecordingProfile &parent)
MPEG4QualDiff(const RecordingProfile &parent)
MPEG4bitrate(const RecordingProfile &parent)
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 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
int at(void) const
Definition: mythdbcon.h:221
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
QString GetHostName(void)
QString GetSetting(const QString &key, const QString &defaultval="")
static void DBError(const QString &where, const MSqlQuery &query)
Definition: mythdb.cpp:226
MythScreenStack * GetStack(const QString &Stackname)
virtual void AddScreen(MythScreenType *screen, bool allowFade=true)
Dialog prompting the user to enter a text string.
void haveResult(QString)
void setValue(const QString &newValue) override
void addSelection(const QString &label, QString value=QString(), bool select=false)
void setValue(int value) override
int getValueIndex(const QString &value) const
PeakBitrate(const RecordingProfile &parent, const QString &setting="mpeg2maxbitrate", uint min_br=1000, uint max_br=16000, uint default_br=6000, uint increment=100, QString label=QString())
RTjpegChromaFilter(const RecordingProfile &parent)
RTjpegLumaFilter(const RecordingProfile &parent)
RTjpegQuality(const RecordingProfile &parent)
RecordFullTSStream(const RecordingProfile &parent)
void CreateNewProfile(const QString &profName)
void Load(void) override
RecordingProfileEditor(int id, QString profName)
QString GetWhereClause(MSqlBindings &bindings) const override
const RecordingProfile & m_parent
~RecordingProfile(void) override
int getProfileNum(void) const
static const uint kTranscoderAutodetect
sentinel value
void FiltersChanged(const QString &val)
QString getName(void) const
RecordingProfile(const QString &profName=QString())
TranscodeResize * m_trResize
bool canDelete(void) override
void SetLosslessTranscode(const QString &val)
virtual void CompleteLoad(int profileId, const QString &type, const QString &name)
static QMap< int, QString > GetTranscodingProfiles()
ImageSize * m_imageSize
virtual bool loadByType(const QString &name, const QString &cardtype, const QString &videodev)
TranscodeFilters * m_trFilters
static QMap< int, QString > GetProfiles(RecProfileGroup group=AllGroups)
static void fillSelections(GroupSetting *setting, int group, bool foldautodetect=false)
void ResizeTranscode(const QString &val)
TranscodeLossless * m_trLossless
VideoCompressionSettings * m_videoSettings
virtual void loadByID(int id)
QString groupType(void) const
AudioCompressionSettings * m_audioSettings
virtual bool loadByGroup(const QString &name, const QString &group)
void deleteEntry(void) override
RecordingTypeStream(const RecordingProfile &parent)
QMap< uint, bool > m_allowedRate
void addSelection(const QString &label, const QString &value=QString(), bool select=false)
SampleRate(const RecordingProfile &parent, bool analog=true)
void Load(void) override
std::vector< uint > m_rates
ScaleBitrate(const RecordingProfile &parent)
void Load(void) override
Definition: mythstorage.cpp:9
virtual void addChild(StandardSetting *child)
virtual void Load(void)
virtual void setName(const QString &name)
void addTargetedChild(const QString &value, StandardSetting *setting)
virtual void clearSettings()
void settingsChanged(StandardSetting *selectedSetting=nullptr)
virtual void setHelpText(const QString &str)
virtual void setValue(const QString &newValue)
void valueChanged(const QString &newValue)
virtual QString getValue(void) const
virtual void setEnabled(bool enabled)
virtual void setLabel(QString str)
virtual QString GetDBValue(void) const =0
TranscodeFilters(const RecordingProfile &parent)
TranscodeLossless(const RecordingProfile &parent)
TranscodeResize(const RecordingProfile &parent)
bool UserAdjustableResolution(void) const
Definition: v4l2util.cpp:708
QString DriverName(void) const
Definition: v4l2util.h:50
bool IsOpen(void) const
Definition: v4l2util.h:31
QString ProfileName(void) const
Definition: v4l2util.h:52
VideoCodecName(const RecordingProfile &parent)
VideoCompressionSettings(const RecordingProfile &parentProfile, V4L2util *v4l2)
void selectCodecs(const QString &groupType)
const RecordingProfile & m_parent
unsigned int uint
Definition: compat.h:68
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
QMap< QString, QVariant > MSqlBindings
typedef for a map of string -> string bindings for generic queries.
Definition: mythdbcon.h:100
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
MythMainWindow * GetMythMainWindow(void)
string hostname
Definition: caa.py:17
STL namespace.
static eu8 clamp(eu8 value, eu8 low, eu8 high)
Definition: pxsup2dast.c:206
const std::array< QString, 4 > kAvailProfiles
QMap< category_t, DriverOption > Options
Definition: driveroption.h:22