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