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
928#ifdef USING_FFMPEG_THREADS
930#endif
931
932 label = "MPEG-2";
935 //m_codecName->addTargetedChild(label, new MPEG4MaxQuality(m_parent));
936 //m_codecName->addTargetedChild(label, new MPEG4MinQuality(m_parent));
937 //m_codecName->addTargetedChild(label, new MPEG4QualDiff(m_parent));
938 //m_codecName->addTargetedChild(label, new MPEG4OptionVHQ(m_parent));
939 //m_codecName->addTargetedChild(label, new MPEG4Option4MV(m_parent));
940#ifdef USING_FFMPEG_THREADS
942#endif
943
944 label = "Hardware MJPEG";
948
949 label = "MPEG-2 Hardware Encoder";
954
955 label = "MPEG-4 AVC Hardware Encoder";
956 auto *h0 = new GroupSetting();
957 h0->setLabel(QObject::tr("Low Resolution"));
958 h0->addChild(new AverageBitrate(m_parent, "low_mpeg4avgbitrate",
959 1000, 13500, 4500, 500));
960 h0->addChild(new PeakBitrate(m_parent, "low_mpeg4peakbitrate",
961 1100, 20200, 6000, 500));
962 m_codecName->addTargetedChild(label, h0);
963
964 auto *h1 = new GroupSetting();
965 h1->setLabel(QObject::tr("Medium Resolution"));
966 h1->addChild(new AverageBitrate(m_parent, "medium_mpeg4avgbitrate",
967 1000, 13500, 9000, 500));
968 h1->addChild(new PeakBitrate(m_parent, "medium_mpeg4peakbitrate",
969 1100, 20200, 11000, 500));
970 m_codecName->addTargetedChild(label, h1);
971
972 auto *h2 = new GroupSetting();
973 h2->setLabel(QObject::tr("High Resolution"));
974 h2->addChild(new AverageBitrate(m_parent, "high_mpeg4avgbitrate",
975 1000, 13500, 13500, 500));
976 h2->addChild(new PeakBitrate(m_parent, "high_mpeg4peakbitrate",
977 1100, 20200, 20200, 500));
978 m_codecName->addTargetedChild(label, h2);
979
980#if CONFIG_V4L2
981 if (v4l2)
982 {
984
985 if (v4l2->GetOptions(options))
986 {
987 /* StandardSetting cannot handle multiple 'targets' pointing
988 * to the same setting configuration, so we need to do
989 * this in two passes. */
990
991 for (const auto & option : std::as_const(options))
992 {
993 if (option.m_category == DriverOption::VIDEO_ENCODING)
994 {
995 for (const auto & Imenu : std::as_const(option.m_menu))
996 {
997 if (!Imenu.isEmpty())
998 m_v4l2codecs << "V4L2:" + Imenu;
999 }
1000 }
1001 }
1002
1003 for (auto Icodec = m_v4l2codecs.begin(); Icodec < m_v4l2codecs.end(); ++Icodec)
1004 {
1005 auto* bit_low = new GroupSetting();
1006 auto* bit_medium = new GroupSetting();
1007 auto* bit_high = new GroupSetting();
1008 bool dynamic_res = !v4l2->UserAdjustableResolution();
1009
1010 for (auto & option : options)
1011 {
1012 if (option.m_category == DriverOption::STREAM_TYPE)
1013 {
1016 option.m_minimum,
1017 option.m_maximum,
1018 option.m_defaultValue));
1019 }
1020 else if (option.m_category == DriverOption::VIDEO_ASPECT)
1021 {
1024 option.m_minimum,
1025 option.m_maximum,
1026 option.m_defaultValue));
1027 }
1028 else if (option.m_category ==
1030 {
1031 if (dynamic_res)
1032 {
1033 bit_low->addChild(new BitrateMode(m_parent,
1034 "low_mpegbitratemode"));
1035 bit_medium->addChild(new BitrateMode(m_parent,
1036 "medium_mpegbitratemode"));
1037 bit_high->addChild(new BitrateMode(m_parent,
1038 "medium_mpegbitratemode"));
1039 }
1040 else
1041 {
1042 bit_low->addChild(new BitrateMode(m_parent));
1043 }
1044 }
1045 else if (option.m_category == DriverOption::VIDEO_BITRATE)
1046 {
1047 if (dynamic_res)
1048 {
1049 bit_low->setLabel(QObject::tr("Low Resolution"));
1050 bit_low->addChild(new AverageBitrate(m_parent,
1051 "low_mpegavgbitrate",
1052 option.m_minimum / 1000,
1053 option.m_maximum / 1000,
1054 option.m_defaultValue / 1000,
1055 option.m_step / 1000));
1056
1057 bit_medium->setLabel(QObject::
1058 tr("Medium Resolution"));
1059 bit_medium->addChild(new AverageBitrate(m_parent,
1060 "medium_mpegavgbitrate",
1061 option.m_minimum / 1000,
1062 option.m_maximum / 1000,
1063 option.m_defaultValue / 1000,
1064 option.m_step / 1000));
1065
1066 bit_high->setLabel(QObject::
1067 tr("High Resolution"));
1068 bit_high->addChild(new AverageBitrate(m_parent,
1069 "high_mpegavgbitrate",
1070 option.m_minimum / 1000,
1071 option.m_maximum / 1000,
1072 option.m_defaultValue / 1000,
1073 option.m_step / 1000));
1074 }
1075 else
1076 {
1077 bit_low->setLabel(QObject::tr("Bitrate"));
1078 bit_low->addChild(new AverageBitrate(m_parent,
1079 "mpeg2bitrate",
1080 option.m_minimum / 1000,
1081 option.m_maximum / 1000,
1082 option.m_defaultValue / 1000,
1083 option.m_step / 1000));
1084 }
1085 }
1086 else if (option.m_category ==
1088 {
1089 if (dynamic_res)
1090 {
1091 bit_low->addChild(new PeakBitrate(m_parent,
1092 "low_mpegpeakbitrate",
1093 option.m_minimum / 1000,
1094 option.m_maximum / 1000,
1095 option.m_defaultValue / 1000,
1096 option.m_step / 1000));
1097 bit_medium->addChild(new PeakBitrate(m_parent,
1098 "medium_mpegpeakbitrate",
1099 option.m_minimum / 1000,
1100 option.m_maximum / 1000,
1101 option.m_defaultValue / 1000,
1102 option.m_step / 1000));
1103 bit_high->addChild(new PeakBitrate(m_parent,
1104 "high_mpegpeakbitrate",
1105 option.m_minimum / 1000,
1106 option.m_maximum / 1000,
1107 option.m_defaultValue / 1000,
1108 option.m_step / 1000));
1109 }
1110 else
1111 {
1112 bit_low->addChild(new PeakBitrate(m_parent,
1113 "mpeg2maxbitrate",
1114 option.m_minimum / 1000,
1115 option.m_maximum / 1000,
1116 option.m_defaultValue / 1000,
1117 option.m_step / 1000));
1118 }
1119 }
1120 }
1121
1122 m_codecName->addTargetedChild(*Icodec, bit_low);
1123 if (dynamic_res)
1124 {
1125 m_codecName->addTargetedChild(*Icodec, bit_medium);
1126 m_codecName->addTargetedChild(*Icodec, bit_high);
1127 }
1128 else
1129 {
1130 // These are only referenced when dynamic_res is true.
1131 delete bit_medium;
1132 delete bit_high;
1133 }
1134 }
1135 }
1136 }
1137#endif // CONFIG_V4L2
1138 }
1139
1140 void selectCodecs(const QString& groupType)
1141 {
1142 if (!groupType.isNull())
1143 {
1144 if (groupType == "HDPVR")
1145 m_codecName->addSelection("MPEG-4 AVC Hardware Encoder");
1146 else if (groupType.startsWith("V4L2:"))
1147 {
1148 for (const auto & codec : std::as_const(m_v4l2codecs))
1149 m_codecName->addSelection(codec);
1150 }
1151 else if (groupType == "MPEG")
1152 {
1153 m_codecName->addSelection("MPEG-2 Hardware Encoder");
1154 }
1155 else if (groupType == "MJPEG")
1156 {
1157 m_codecName->addSelection("Hardware MJPEG");
1158 }
1159 else if (groupType == "GO7007")
1160 {
1161 m_codecName->addSelection("MPEG-4");
1162 m_codecName->addSelection("MPEG-2");
1163 }
1164 else
1165 {
1166 // V4L, TRANSCODE (and any undefined types)
1167 m_codecName->addSelection("RTjpeg");
1168 m_codecName->addSelection("MPEG-4");
1169 }
1170 }
1171 else
1172 {
1173 m_codecName->addSelection("RTjpeg");
1174 m_codecName->addSelection("MPEG-4");
1175 m_codecName->addSelection("Hardware MJPEG");
1176 m_codecName->addSelection("MPEG-2 Hardware Encoder");
1177 }
1178 }
1179
1180private:
1183 QStringList m_v4l2codecs;
1184};
1185
1187{
1188 public:
1189 explicit AutoTranscode(const RecordingProfile &parent) :
1191 CodecParamStorage(this, parent, "autotranscode")
1192 {
1193 setLabel(QObject::tr("Enable auto-transcode after recording"));
1194 setValue(false);
1195 setHelpText(QObject::tr("Automatically transcode when a recording is "
1196 "made using this profile and the recording's "
1197 "schedule is configured to allow transcoding."));
1198 };
1199};
1200
1202{
1203 public:
1204 explicit TranscodeResize(const RecordingProfile &parent) :
1206 CodecParamStorage(this, parent, "transcoderesize")
1207 {
1208 setLabel(QObject::tr("Resize video while transcoding"));
1209 setValue(false);
1210 setHelpText(QObject::tr("Allows the transcoder to "
1211 "resize the video during transcoding."));
1212 };
1213};
1214
1216{
1217 public:
1218 explicit TranscodeLossless(const RecordingProfile &parent) :
1220 CodecParamStorage(this, parent, "transcodelossless")
1221 {
1222 setLabel(QObject::tr("Lossless transcoding"));
1223 setValue(false);
1224 setHelpText(QObject::tr("Only reencode where absolutely needed "
1225 "(normally only around cutpoints). Otherwise "
1226 "keep audio and video formats identical to "
1227 "the source. This should result in the "
1228 "highest quality, but won't save as much "
1229 "space."));
1230 };
1231};
1232
1234{
1235 public:
1236 explicit RecordingTypeStream(const RecordingProfile &parent) :
1237 MythUIComboBoxSetting(this), CodecParamStorage(this, parent, "recordingtype")
1238 {
1239 setLabel(QObject::tr("Recording Type"));
1240
1241 QString msg = QObject::tr(
1242 "This option allows you to filter out unwanted streams. "
1243 "'Normal' will record all relevant streams including "
1244 "interactive television data. 'TV Only' will record only "
1245 "audio, video and subtitle streams. ");
1246 setHelpText(msg);
1247
1248 addSelection(QObject::tr("Normal"), "all");
1249 addSelection(QObject::tr("TV Only"), "tv");
1250 addSelection(QObject::tr("Audio Only"), "audio");
1251 setValue(0);
1252 };
1253};
1254
1256{
1257 public:
1258 explicit RecordFullTSStream(const RecordingProfile &parent) :
1259 MythUIComboBoxSetting(this), CodecParamStorage(this, parent, "recordmpts")
1260 {
1261 setLabel(QObject::tr("Record Full TS?"));
1262
1263 QString msg = QObject::tr(
1264 "If set, extra files will be created for each recording with "
1265 "the name of the recording followed by '.ts.raw'. "
1266 "These extra files represent the full contents of the transport "
1267 "stream used to generate the recording. (For debugging purposes)");
1268 setHelpText(msg);
1269
1270 addSelection(QObject::tr("Yes"), "1");
1271 addSelection(QObject::tr("No"), "0");
1272 setValue(1);
1273 };
1274};
1275
1277{
1278 public:
1279 explicit TranscodeFilters(const RecordingProfile &parent) :
1281 CodecParamStorage(this, parent, "transcodefilters")
1282 {
1283 setLabel(QObject::tr("Custom filters"));
1284 setHelpText(QObject::tr("Filters used when transcoding with this "
1285 "profile. This value must be blank to perform "
1286 "lossless transcoding. Format: "
1287 "[[<filter>=<options>,]...]"
1288 ));
1289 };
1290};
1291
1293{
1294 public:
1296 {
1297 public:
1299 uint defaultwidth, uint maxwidth,
1300 bool transcoding = false) :
1301 MythUISpinBoxSetting(this, transcoding ? 0 : 160,
1302 maxwidth, 16, 0,
1303 transcoding ? QObject::tr("Auto") : QString()),
1304 CodecParamStorage(this, parent, "width")
1305 {
1306 setLabel(QObject::tr("Width"));
1307 setValue(defaultwidth);
1308
1309 QString help = (transcoding) ?
1310 QObject::tr("If the width is set to 'Auto', the width "
1311 "will be calculated based on the height and "
1312 "the recording's physical aspect ratio.") :
1313 QObject::tr("Width to use for encoding. "
1314 "Note: PVR-x50 cards may produce ghosting if "
1315 "this is not set to 720 or 768 for NTSC and "
1316 "PAL, respectively.");
1317
1319 };
1320 };
1321
1323 {
1324 public:
1326 uint defaultheight, uint maxheight,
1327 bool transcoding = false):
1328 MythUISpinBoxSetting(this, transcoding ? 0 : 160,
1329 maxheight, 16, 0,
1330 transcoding ? QObject::tr("Auto") : QString()),
1331 CodecParamStorage(this, parent, "height")
1332 {
1333 setLabel(QObject::tr("Height"));
1334 setValue(defaultheight);
1335
1336 QString help = (transcoding) ?
1337 QObject::tr("If the height is set to 'Auto', the height "
1338 "will be calculated based on the width and "
1339 "the recording's physical aspect ratio.") :
1340 QObject::tr("Height to use for encoding. "
1341 "Note: PVR-x50 cards may produce ghosting if "
1342 "this is not set to 480 or 576 for NTSC and "
1343 "PAL, respectively.");
1344
1346 };
1347 };
1348
1350 const QString& tvFormat, const QString& profName)
1351 {
1352 setLabel(QObject::tr("Image size"));
1353
1354 QSize defaultsize(768, 576);
1355 QSize maxsize(768, 576);
1356 bool transcoding = profName.startsWith("Transcoders");
1357 bool ivtv = profName.startsWith("IVTV MPEG-2 Encoders");
1358
1359 if (transcoding)
1360 {
1361 maxsize = QSize(1920, 1088);
1362 if (tvFormat.toLower() == "ntsc" || tvFormat.toLower() == "atsc")
1363 defaultsize = QSize(480, 480);
1364 else
1365 defaultsize = QSize(480, 576);
1366 }
1367 else if (tvFormat.startsWith("ntsc", Qt::CaseInsensitive))
1368 {
1369 maxsize = QSize(720, 480);
1370 defaultsize = (ivtv) ? QSize(720, 480) : QSize(480, 480);
1371 }
1372 else if (tvFormat.toLower() == "atsc")
1373 {
1374 maxsize = QSize(1920, 1088);
1375 defaultsize = QSize(1920, 1088);
1376 }
1377 else
1378 {
1379 maxsize = QSize(768, 576);
1380 defaultsize = (ivtv) ? QSize(720, 576) : QSize(480, 576);
1381 }
1382
1383 addChild(new Width(parent, defaultsize.width(),
1384 maxsize.width(), transcoding));
1385 addChild(new Height(parent, defaultsize.height(),
1386 maxsize.height(), transcoding));
1387 };
1388};
1389
1390// id and name will be deleted by ConfigurationGroup's destructor
1392 : m_id(new ID()),
1393 m_name(new Name(*this)),
1394 m_profileName(profName)
1395{
1396 // This must be first because it is needed to load/save the other settings
1397 addChild(m_id);
1398
1399 setLabel(profName);
1401
1402 if (!profName.isEmpty())
1403 {
1404 if (profName.startsWith("Transcoders"))
1405 {
1406 m_trFilters = new TranscodeFilters(*this);
1407 m_trLossless = new TranscodeLossless(*this);
1408 m_trResize = new TranscodeResize(*this);
1412 }
1413 else
1414 {
1415 addChild(new AutoTranscode(*this));
1416 }
1417 }
1418 else
1419 {
1420 m_trFilters = new TranscodeFilters(*this);
1421 m_trLossless = new TranscodeLossless(*this);
1422 m_trResize = new TranscodeResize(*this);
1426 addChild(new AutoTranscode(*this));
1427 }
1428};
1429
1431{
1432#if CONFIG_V4L2
1433 delete m_v4l2util;
1434 m_v4l2util = nullptr;
1435#endif
1436}
1437
1438void RecordingProfile::ResizeTranscode(const QString & /*val*/)
1439{
1440 if (m_imageSize)
1442}
1443
1444void RecordingProfile::SetLosslessTranscode(const QString & /*val*/)
1445{
1446 bool lossless = m_trLossless->boolValue();
1447 bool show_size = (lossless) ? false : m_trResize->boolValue();
1448 if (m_imageSize)
1449 m_imageSize->setEnabled(show_size);
1450 m_videoSettings->setEnabled(! lossless);
1451 m_audioSettings->setEnabled(! lossless);
1452 m_trResize->setEnabled(! lossless);
1453 m_trFilters->setEnabled(! lossless);
1454}
1455
1457{
1458 MSqlQuery result(MSqlQuery::InitCon());
1459 result.prepare(
1460 "SELECT cardtype, profilegroups.name "
1461 "FROM profilegroups, recordingprofiles "
1462 "WHERE profilegroups.id = recordingprofiles.profilegroup AND "
1463 " recordingprofiles.id = :PROFILEID");
1464 result.bindValue(":PROFILEID", profileId);
1465
1466 QString type;
1467 QString name;
1468 if (!result.exec())
1469 {
1470 MythDB::DBError("RecordingProfile::loadByID -- cardtype", result);
1471 }
1472 else if (result.next())
1473 {
1474 type = result.value(0).toString();
1475 name = result.value(1).toString();
1476 }
1477
1478 CompleteLoad(profileId, type, name);
1479}
1480
1481void RecordingProfile::FiltersChanged(const QString &val)
1482{
1483 // If there are filters, we cannot do lossless transcoding
1484 if (!val.trimmed().isEmpty())
1485 {
1486 m_trLossless->setValue(false);
1487 m_trLossless->setEnabled(false);
1488 }
1489 else
1490 {
1491 m_trLossless->setEnabled(true);
1492 }
1493}
1494
1495bool RecordingProfile::loadByType(const QString &name, const QString &card,
1496 [[maybe_unused]] const QString &videodev)
1497{
1498 QString hostname = gCoreContext->GetHostName().toLower();
1499 QString cardtype = card;
1500 uint profileId = 0;
1501
1502#if CONFIG_V4L2
1503 if (cardtype == "V4L2ENC")
1504 {
1505 m_v4l2util = new V4L2util(videodev);
1506 if (m_v4l2util->IsOpen())
1507 cardtype = m_v4l2util->ProfileName();
1508 }
1509#endif
1510
1511 MSqlQuery result(MSqlQuery::InitCon());
1512 result.prepare(
1513 "SELECT recordingprofiles.id, profilegroups.hostname, "
1514 " profilegroups.is_default "
1515 "FROM recordingprofiles, profilegroups "
1516 "WHERE profilegroups.id = recordingprofiles.profilegroup AND "
1517 " profilegroups.cardtype = :CARDTYPE AND "
1518 " recordingprofiles.name = :NAME");
1519 result.bindValue(":CARDTYPE", cardtype);
1520 result.bindValue(":NAME", name);
1521
1522 if (!result.exec())
1523 {
1524 MythDB::DBError("RecordingProfile::loadByType()", result);
1525 return false;
1526 }
1527
1528 while (result.next())
1529 {
1530 if (result.value(1).toString().toLower() == hostname)
1531 {
1532 profileId = result.value(0).toUInt();
1533 }
1534 else if (result.value(2).toInt() == 1)
1535 {
1536 profileId = result.value(0).toUInt();
1537 break;
1538 }
1539 }
1540
1541 if (profileId)
1542 {
1543 CompleteLoad(profileId, cardtype, name);
1544 return true;
1545 }
1546
1547 return false;
1548}
1549
1550bool RecordingProfile::loadByGroup(const QString &name, const QString &group)
1551{
1552 MSqlQuery result(MSqlQuery::InitCon());
1553 result.prepare(
1554 "SELECT recordingprofiles.id, cardtype "
1555 "FROM recordingprofiles, profilegroups "
1556 "WHERE recordingprofiles.profilegroup = profilegroups.id AND "
1557 " profilegroups.name = :GROUPNAME AND "
1558 " recordingprofiles.name = :NAME");
1559 result.bindValue(":GROUPNAME", group);
1560 result.bindValue(":NAME", name);
1561
1562 if (!result.exec())
1563 {
1564 MythDB::DBError("RecordingProfile::loadByGroup()", result);
1565 return false;
1566 }
1567
1568 if (result.next())
1569 {
1570 uint profileId = result.value(0).toUInt();
1571 QString type = result.value(1).toString();
1572
1573 CompleteLoad(profileId, type, name);
1574 return true;
1575 }
1576
1577 return false;
1578}
1579
1580void RecordingProfile::CompleteLoad(int profileId, const QString &type,
1581 const QString &name)
1582{
1583 if (m_profileName.isEmpty())
1584 m_profileName = name;
1585
1587
1588 if (m_isEncoder)
1589 {
1590#if CONFIG_V4L2
1591 if (type.startsWith("V4L2:"))
1592 {
1593 QStringList devices = CardUtil::GetVideoDevices("V4L2ENC");
1594 if (!devices.isEmpty())
1595 {
1596 for (const auto & device : std::as_const(devices))
1597 {
1598 delete m_v4l2util;
1599 m_v4l2util = new V4L2util(device);
1600 if (m_v4l2util->IsOpen() &&
1601 m_v4l2util->DriverName() == type.mid(5))
1602 break;
1603 delete m_v4l2util;
1604 m_v4l2util = nullptr;
1605 }
1606 }
1607 }
1608#endif
1609
1610 QString tvFormat = gCoreContext->GetSetting("TVFormat");
1611 // TODO: When mpegrecorder is removed, don't check for "HDPVR' anymore...
1612 if (type != "HDPVR" &&
1613 (!m_v4l2util
1614#if CONFIG_V4L2
1616#endif
1617 ))
1618 {
1619 addChild(new ImageSize(*this, tvFormat, m_profileName));
1620 }
1622 m_v4l2util);
1624
1626 m_v4l2util);
1628
1629 if (!m_profileName.isEmpty() && m_profileName.startsWith("Transcoders"))
1630 {
1631 connect(m_trResize, qOverload<const QString&>(&StandardSetting::valueChanged),
1633 connect(m_trLossless, qOverload<const QString&>(&StandardSetting::valueChanged),
1635 connect(m_trFilters, qOverload<const QString&>(&StandardSetting::valueChanged),
1637 }
1638 }
1639
1640 // Cards that can receive additional streams such as EIT and MHEG
1642 {
1643 addChild(new RecordingTypeStream(*this));
1644 }
1645
1647 {
1648 addChild(new RecordFullTSStream(*this));
1649 }
1650
1651 m_id->setValue(profileId);
1652 Load();
1653}
1654
1656{
1657 if (m_videoSettings)
1659 if (m_audioSettings)
1661}
1662
1664 m_group(id), m_labelName(std::move(profName))
1665{
1666 if (!m_labelName.isEmpty())
1668}
1669
1671{
1672 clearSettings();
1673 auto *newProfile = new ButtonStandardSetting(tr("(Create new profile)"));
1675 addChild(newProfile);
1678}
1679
1681{
1682 MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
1683 auto *settingdialog = new MythTextInputDialog(popupStack,
1684 tr("Enter the name of the new profile"));
1685
1686 if (settingdialog->Create())
1687 {
1688 connect(settingdialog, &MythTextInputDialog::haveResult,
1690 popupStack->AddScreen(settingdialog);
1691 }
1692 else
1693 {
1694 delete settingdialog;
1695 }
1696}
1697
1698void RecordingProfileEditor::CreateNewProfile(const QString& profName)
1699{
1701 query.prepare(
1702 "INSERT INTO recordingprofiles "
1703 "(name, videocodec, audiocodec, profilegroup) "
1704 "VALUES "
1705 "(:NAME, :VIDEOCODEC, :AUDIOCODEC, :PROFILEGROUP);");
1706 query.bindValue(":NAME", profName);
1707 query.bindValue(":VIDEOCODEC", "MPEG-4");
1708 query.bindValue(":AUDIOCODEC", "MP3");
1709 query.bindValue(":PROFILEGROUP", m_group);
1710 if (!query.exec())
1711 {
1712 MythDB::DBError("RecordingProfileEditor::open", query);
1713 }
1714 else
1715 {
1716 query.prepare(
1717 "SELECT id "
1718 "FROM recordingprofiles "
1719 "WHERE name = :NAME AND profilegroup = :PROFILEGROUP;");
1720 query.bindValue(":NAME", profName);
1721 query.bindValue(":PROFILEGROUP", m_group);
1722 if (!query.exec())
1723 {
1724 MythDB::DBError("RecordingProfileEditor::open", query);
1725 }
1726 else
1727 {
1728 if (query.next())
1729 {
1730 auto* profile = new RecordingProfile(profName);
1731
1732 profile->loadByID(query.value(0).toInt());
1733 profile->setCodecTypes();
1735 emit settingsChanged(this);
1736 }
1737 }
1738 }
1739}
1740
1742 bool foldautodetect)
1743{
1744 if (!group)
1745 {
1746 for (const auto & name : kAvailProfiles)
1747 {
1748 auto *profile = new GroupSetting();
1749 profile->setLabel(name);
1750 setting->addChild(profile);
1751 }
1752 return;
1753 }
1754
1755 MSqlQuery result(MSqlQuery::InitCon());
1756 result.prepare(
1757 "SELECT name, id "
1758 "FROM recordingprofiles "
1759 "WHERE profilegroup = :GROUP "
1760 "ORDER BY id");
1761 result.bindValue(":GROUP", group);
1762
1763 if (!result.exec())
1764 {
1765 MythDB::DBError("RecordingProfile::fillSelections 1", result);
1766 return;
1767 }
1768
1769 while (result.next())
1770 {
1771 if ((result.at() == 0) && foldautodetect &&
1773 {
1774 auto *autodetect = new GroupSetting();
1775 autodetect->setLabel(QObject::tr("Autodetect"));
1776 setting->addChild(autodetect);
1777 }
1778
1779 QString name = result.value(0).toString();
1780 QString id = result.value(1).toString();
1781
1782 if ((group == RecordingProfile::TranscoderGroup) &&
1783 (name == "RTjpeg/MPEG4" || name == "MPEG2") &&
1784 !foldautodetect) {
1785 name = QObject::tr("Autodetect from %1").arg(name);
1786 }
1787
1788 auto *profile = new RecordingProfile(name);
1789 profile->loadByID(id.toInt());
1790 profile->setCodecTypes();
1791 setting->addChild(profile);
1792 }
1793}
1794
1796{
1797 QMap<int, QString> profiles;
1798
1799 if (!group)
1800 {
1801 for (uint i = 0; !kAvailProfiles[i].isEmpty(); i++)
1802 profiles[i] = kAvailProfiles[i];
1803 return profiles;
1804 }
1805
1807 query.prepare(
1808 "SELECT name, id "
1809 "FROM recordingprofiles "
1810 "WHERE profilegroup = :GROUPID "
1811 "ORDER BY id");
1812 query.bindValue(":GROUPID", group);
1813
1814 if (!query.exec())
1815 {
1816 MythDB::DBError("RecordingProfile::GetProfileMap()", query);
1817 return profiles;
1818 }
1819
1820 while (query.next())
1821 {
1822 if ((query.at() == 0) && (group == RecordingProfile::TranscoderGroup))
1823 {
1825 profiles[id] = QObject::tr("Transcode using Autodetect");
1826 }
1827
1828 QString name = query.value(0).toString();
1829 int id = query.value(1).toInt();
1830
1832 {
1833 /* RTjpeg/MPEG4 and MPEG2 are used by "Autodetect". */
1834 if (name != "RTjpeg/MPEG4" && name != "MPEG2")
1835 {
1836 QString lbl = QObject::tr("Transcode using \"%1\"").arg(name);
1837 profiles[id] = lbl;
1838 }
1839 continue;
1840 }
1841
1842 QString lbl = QObject::tr("Record using the \"%1\" profile").arg(name);
1843 profiles[id] = lbl;
1844 }
1845
1846 if (query.at() == QSql::BeforeFirstRow)
1847 {
1848 LOG(VB_GENERAL, LOG_WARNING,
1849 "RecordingProfile::fillselections, Warning: "
1850 "Failed to locate recording id for recording group.");
1851 }
1852
1853 return profiles;
1854}
1855
1857{
1859}
1860
1862{
1863 MSqlQuery result(MSqlQuery::InitCon());
1864 result.prepare(
1865 "SELECT profilegroups.cardtype "
1866 "FROM profilegroups, recordingprofiles "
1867 "WHERE profilegroups.id = recordingprofiles.profilegroup AND "
1868 " recordingprofiles.id = :ID");
1869 result.bindValue(":ID", getProfileNum());
1870
1871 if (!result.exec())
1872 MythDB::DBError("RecordingProfile::groupType", result);
1873 else if (result.next())
1874 return result.value(0).toString();
1875
1876 return {};
1877}
1878
1880{
1881 MSqlQuery result(MSqlQuery::InitCon());
1882 result.prepare(
1883 "SELECT name "
1884 "FROM recordingprofiles "
1885 "WHERE id = :ID");
1886
1887 result.bindValue(":ID", id);
1888
1889 if (!result.exec())
1890 MythDB::DBError("RecordingProfile::getName", result);
1891 else if (result.next())
1892 return result.value(0).toString();
1893
1894 return {};
1895}
1896
1898{
1899 return true;
1900}
1901
1903{
1904 MSqlQuery result(MSqlQuery::InitCon());
1905 result.prepare(
1906 "DELETE "
1907 "FROM recordingprofiles "
1908 "WHERE id = :ID");
1909
1910 result.bindValue(":ID", m_id->getValue());
1911
1912 if (!result.exec())
1913 MythDB::DBError("RecordingProfile::deleteEntry", result);
1914
1915}
1916
1917
1918/* 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:398
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: freesurround.h:24
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